regedit/tests: Output "(Default)" when referring to the default registry value.
[wine.git] / dlls / winemac.drv / window.c
blobe2de40d9dd764bef782860b15a0fccc7067e59b7
1 /*
2 * MACDRV windowing driver
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
7 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
26 #include "macdrv.h"
27 #include "winuser.h"
28 #include "wine/unicode.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
34 static CRITICAL_SECTION win_data_section;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
37 0, 0, &win_data_section,
38 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
41 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
43 static CFMutableDictionaryRef win_datas;
45 static DWORD activate_on_focus_time;
48 /***********************************************************************
49 * get_cocoa_window_features
51 static void get_cocoa_window_features(struct macdrv_win_data *data,
52 DWORD style, DWORD ex_style,
53 struct macdrv_window_features* wf)
55 memset(wf, 0, sizeof(*wf));
57 if (disable_window_decorations) return;
58 if (IsRectEmpty(&data->window_rect)) return;
60 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
62 wf->shadow = TRUE;
63 if (!data->shaped)
65 wf->title_bar = TRUE;
66 if (style & WS_SYSMENU) wf->close_button = TRUE;
67 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
68 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
69 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
72 if (style & WS_THICKFRAME)
74 wf->shadow = TRUE;
75 if (!data->shaped) wf->resizable = TRUE;
77 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
78 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
82 /*******************************************************************
83 * can_activate_window
85 * Check if we can activate the specified window.
87 static inline BOOL can_activate_window(HWND hwnd)
89 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
91 if (!(style & WS_VISIBLE)) return FALSE;
92 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
93 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
94 if (hwnd == GetDesktopWindow()) return FALSE;
95 return !(style & WS_DISABLED);
99 /***********************************************************************
100 * get_cocoa_window_state
102 static void get_cocoa_window_state(struct macdrv_win_data *data,
103 DWORD style, DWORD ex_style,
104 struct macdrv_window_state* state)
106 memset(state, 0, sizeof(*state));
107 state->disabled = (style & WS_DISABLED) != 0;
108 state->no_activate = !can_activate_window(data->hwnd);
109 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
110 state->excluded_by_expose = state->excluded_by_cycle =
111 (!(ex_style & WS_EX_APPWINDOW) &&
112 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
113 if (IsRectEmpty(&data->window_rect))
114 state->excluded_by_expose = TRUE;
115 state->minimized = (style & WS_MINIMIZE) != 0;
116 state->minimized_valid = state->minimized != data->minimized;
117 state->maximized = (style & WS_MAXIMIZE) != 0;
121 /***********************************************************************
122 * get_mac_rect_offset
124 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
126 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
128 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
130 rect->top = rect->bottom = rect->left = rect->right = 0;
132 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
134 if (!data->shaped)
136 struct macdrv_window_features wf;
137 get_cocoa_window_features(data, style, ex_style, &wf);
139 if (wf.title_bar)
141 style_mask |= WS_CAPTION;
142 ex_style_mask |= WS_EX_TOOLWINDOW;
144 if (wf.shadow)
146 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
147 ex_style_mask |= WS_EX_DLGMODALFRAME;
151 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
153 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
154 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
158 /***********************************************************************
159 * macdrv_window_to_mac_rect
161 * Convert a rect from client to Mac window coordinates
163 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
165 RECT rc;
167 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
168 if (IsRectEmpty(rect)) return;
170 get_mac_rect_offset(data, style, &rc);
172 rect->left -= rc.left;
173 rect->right -= rc.right;
174 rect->top -= rc.top;
175 rect->bottom -= rc.bottom;
176 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
177 if (rect->left >= rect->right) rect->right = rect->left + 1;
181 /***********************************************************************
182 * macdrv_mac_to_window_rect
184 * Opposite of macdrv_window_to_mac_rect
186 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
188 RECT rc;
189 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
191 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
192 if (IsRectEmpty(rect)) return;
194 get_mac_rect_offset(data, style, &rc);
196 rect->left += rc.left;
197 rect->right += rc.right;
198 rect->top += rc.top;
199 rect->bottom += rc.bottom;
200 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
201 if (rect->left >= rect->right) rect->right = rect->left + 1;
205 /***********************************************************************
206 * constrain_window_frame
208 * Alter a window frame rectangle to fit within a) Cocoa's documented
209 * limits, and b) sane sizes, like twice the desktop rect.
211 static void constrain_window_frame(CGRect* frame)
213 CGRect desktop_rect = macdrv_get_desktop_rect();
214 int max_width, max_height;
216 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
217 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
219 if (frame->origin.x < -16000) frame->origin.x = -16000;
220 if (frame->origin.y < -16000) frame->origin.y = -16000;
221 if (frame->origin.x > 16000) frame->origin.x = 16000;
222 if (frame->origin.y > 16000) frame->origin.y = 16000;
223 if (frame->size.width > max_width) frame->size.width = max_width;
224 if (frame->size.height > max_height) frame->size.height = max_height;
228 /***********************************************************************
229 * alloc_win_data
231 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
233 struct macdrv_win_data *data;
235 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
237 data->hwnd = hwnd;
238 data->color_key = CLR_INVALID;
239 data->swap_interval = 1;
240 EnterCriticalSection(&win_data_section);
241 if (!win_datas)
242 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
243 CFDictionarySetValue(win_datas, hwnd, data);
245 return data;
249 /***********************************************************************
250 * get_win_data
252 * Lock and return the data structure associated with a window.
254 struct macdrv_win_data *get_win_data(HWND hwnd)
256 struct macdrv_win_data *data;
258 if (!hwnd) return NULL;
259 EnterCriticalSection(&win_data_section);
260 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
261 return data;
262 LeaveCriticalSection(&win_data_section);
263 return NULL;
267 /***********************************************************************
268 * release_win_data
270 * Release the data returned by get_win_data.
272 void release_win_data(struct macdrv_win_data *data)
274 if (data) LeaveCriticalSection(&win_data_section);
278 /***********************************************************************
279 * macdrv_get_cocoa_window
281 * Return the Mac window associated with the full area of a window
283 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
285 struct macdrv_win_data *data = get_win_data(hwnd);
286 macdrv_window ret = NULL;
287 if (data && (data->on_screen || !require_on_screen))
288 ret = data->cocoa_window;
289 release_win_data(data);
290 return ret;
294 /***********************************************************************
295 * macdrv_get_cocoa_view
297 * Return the Cocoa view associated with a window
299 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
301 struct macdrv_win_data *data = get_win_data(hwnd);
302 macdrv_view ret = data ? data->cocoa_view : NULL;
304 release_win_data(data);
305 return ret;
309 /***********************************************************************
310 * macdrv_get_client_cocoa_view
312 * Return the Cocoa view associated with a window's client area
314 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
316 struct macdrv_win_data *data = get_win_data(hwnd);
317 macdrv_view ret = data ? data->client_cocoa_view : NULL;
319 release_win_data(data);
320 return ret;
324 /***********************************************************************
325 * set_cocoa_window_properties
327 * Set the window properties for a Cocoa window based on its Windows
328 * properties.
330 static void set_cocoa_window_properties(struct macdrv_win_data *data)
332 DWORD style, ex_style;
333 HWND owner;
334 macdrv_window owner_win;
335 struct macdrv_window_features wf;
336 struct macdrv_window_state state;
338 style = GetWindowLongW(data->hwnd, GWL_STYLE);
339 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
341 owner = GetWindow(data->hwnd, GW_OWNER);
342 if (owner)
343 owner = GetAncestor(owner, GA_ROOT);
344 owner_win = macdrv_get_cocoa_window(owner, TRUE);
345 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
347 get_cocoa_window_features(data, style, ex_style, &wf);
348 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
350 get_cocoa_window_state(data, style, ex_style, &state);
351 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
352 if (state.minimized_valid)
353 data->minimized = state.minimized;
357 /***********************************************************************
358 * sync_window_region
360 * Update the window region.
362 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
364 HRGN hrgn = win_region;
365 RGNDATA *region_data;
366 const CGRect* rects;
367 int count;
369 if (!data->cocoa_window) return;
370 data->shaped = FALSE;
372 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
374 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
375 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
376 return;
379 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
381 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
382 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
384 DeleteObject(hrgn);
385 hrgn = 0;
389 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
390 MirrorRgn(data->hwnd, hrgn);
391 if (hrgn)
393 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
394 data->window_rect.top - data->whole_rect.top);
396 region_data = get_region_data(hrgn, 0);
397 if (region_data)
399 rects = (CGRect*)region_data->Buffer;
400 count = region_data->rdh.nCount;
401 /* Special case optimization. If the region entirely encloses the Cocoa
402 window, it's the same as there being no region. It's potentially
403 hard/slow to test this for arbitrary regions, so we just check for
404 very simple regions. */
405 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
407 TRACE("optimizing for simple region that contains Cocoa content rect\n");
408 rects = NULL;
409 count = 0;
412 else
414 rects = NULL;
415 count = 0;
418 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
419 macdrv_set_window_shape(data->cocoa_window, rects, count);
421 HeapFree(GetProcessHeap(), 0, region_data);
422 data->shaped = (region_data != NULL);
424 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
428 /***********************************************************************
429 * add_bounds_rect
431 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
433 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
434 bounds->left = min(bounds->left, rect->left);
435 bounds->top = min(bounds->top, rect->top);
436 bounds->right = max(bounds->right, rect->right);
437 bounds->bottom = max(bounds->bottom, rect->bottom);
441 /***********************************************************************
442 * sync_window_opacity
444 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
445 BOOL per_pixel_alpha, DWORD flags)
447 CGFloat opacity = 1.0;
448 BOOL needs_flush = FALSE;
450 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
452 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
453 macdrv_set_window_alpha(data->cocoa_window, opacity);
455 if (flags & LWA_COLORKEY)
457 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
458 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
459 key = RGB(0, 0, 0);
461 else
462 key = CLR_INVALID;
464 if (data->color_key != key)
466 if (key == CLR_INVALID)
468 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
469 macdrv_clear_window_color_key(data->cocoa_window);
471 else
473 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
474 GetRValue(key), GetGValue(key), GetBValue(key));
475 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
478 data->color_key = key;
479 needs_flush = TRUE;
482 if (!data->per_pixel_alpha != !per_pixel_alpha)
484 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
485 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
486 data->per_pixel_alpha = per_pixel_alpha;
487 needs_flush = TRUE;
490 if (needs_flush && data->surface)
492 RECT *bounds;
493 RECT rect;
495 rect = data->whole_rect;
496 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
497 data->surface->funcs->lock(data->surface);
498 bounds = data->surface->funcs->get_bounds(data->surface);
499 add_bounds_rect(bounds, &rect);
500 data->surface->funcs->unlock(data->surface);
505 /***********************************************************************
506 * sync_window_min_max_info
508 static void sync_window_min_max_info(HWND hwnd)
510 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
511 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
512 RECT win_rect, primary_monitor_rect;
513 MINMAXINFO minmax;
514 LONG adjustedStyle;
515 INT xinc, yinc;
516 WINDOWPLACEMENT wpl;
517 HMONITOR monitor;
518 struct macdrv_win_data *data;
520 TRACE("win %p\n", hwnd);
522 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
524 GetWindowRect(hwnd, &win_rect);
525 minmax.ptReserved.x = win_rect.left;
526 minmax.ptReserved.y = win_rect.top;
528 if ((style & WS_CAPTION) == WS_CAPTION)
529 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
530 else
531 adjustedStyle = style;
533 primary_monitor_rect.left = primary_monitor_rect.top = 0;
534 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
535 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
536 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
538 xinc = -primary_monitor_rect.left;
539 yinc = -primary_monitor_rect.top;
541 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
542 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
543 minmax.ptMaxPosition.x = -xinc;
544 minmax.ptMaxPosition.y = -yinc;
545 if (style & (WS_DLGFRAME | WS_BORDER))
547 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
548 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
550 else
552 minmax.ptMinTrackSize.x = 2 * xinc;
553 minmax.ptMinTrackSize.y = 2 * yinc;
555 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
556 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
558 wpl.length = sizeof(wpl);
559 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
561 minmax.ptMaxPosition = wpl.ptMaxPosition;
563 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
564 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
565 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
568 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
569 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
571 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
573 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
574 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
576 /* if the app didn't change the values, adapt them for the window's monitor */
577 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
579 MONITORINFO mon_info;
580 RECT monitor_rect;
582 mon_info.cbSize = sizeof(mon_info);
583 GetMonitorInfoW(monitor, &mon_info);
585 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
586 monitor_rect = mon_info.rcWork;
587 else
588 monitor_rect = mon_info.rcMonitor;
590 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
591 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
593 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
594 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
596 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
598 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
599 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
603 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
604 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
606 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
607 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
609 if ((data = get_win_data(hwnd)) && data->cocoa_window)
611 RECT min_rect, max_rect;
612 CGSize min_size, max_size;
614 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
615 macdrv_window_to_mac_rect(data, style, &min_rect);
616 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
618 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
619 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
620 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
621 else
623 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
624 macdrv_window_to_mac_rect(data, style, &max_rect);
625 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
628 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
629 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
632 release_win_data(data);
636 /**********************************************************************
637 * create_client_cocoa_view
639 * Create the Cocoa view for a window's client area
641 static void create_client_cocoa_view(struct macdrv_win_data *data)
643 RECT rect = data->client_rect;
644 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
646 if (data->client_cocoa_view)
647 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
648 else
650 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
651 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
653 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
657 /**********************************************************************
658 * create_cocoa_window
660 * Create the whole Mac window for a given window
662 static void create_cocoa_window(struct macdrv_win_data *data)
664 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
665 WCHAR text[1024];
666 struct macdrv_window_features wf;
667 CGRect frame;
668 DWORD style, ex_style;
669 HRGN win_rgn;
670 COLORREF key;
671 BYTE alpha;
672 DWORD layered_flags;
674 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
675 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
677 DeleteObject(win_rgn);
678 win_rgn = 0;
680 data->shaped = (win_rgn != 0);
682 style = GetWindowLongW(data->hwnd, GWL_STYLE);
683 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
685 data->whole_rect = data->window_rect;
686 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
688 get_cocoa_window_features(data, style, ex_style, &wf);
690 frame = cgrect_from_rect(data->whole_rect);
691 constrain_window_frame(&frame);
692 if (frame.size.width < 1 || frame.size.height < 1)
693 frame.size.width = frame.size.height = 1;
695 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
696 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
698 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
699 if (!data->cocoa_window) goto done;
700 create_client_cocoa_view(data);
702 set_cocoa_window_properties(data);
704 /* set the window text */
705 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
706 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
708 /* set the window region */
709 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
711 /* set the window opacity */
712 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
713 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
715 done:
716 if (win_rgn) DeleteObject(win_rgn);
720 /**********************************************************************
721 * destroy_cocoa_window
723 * Destroy the whole Mac window for a given window.
725 static void destroy_cocoa_window(struct macdrv_win_data *data)
727 if (!data->cocoa_window) return;
729 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
731 macdrv_destroy_cocoa_window(data->cocoa_window);
732 data->cocoa_window = 0;
733 data->on_screen = FALSE;
734 data->color_key = CLR_INVALID;
735 if (data->surface) window_surface_release(data->surface);
736 data->surface = NULL;
737 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
738 data->unminimized_surface = NULL;
742 /**********************************************************************
743 * create_cocoa_view
745 * Create the Cocoa view for a given Windows child window
747 static void create_cocoa_view(struct macdrv_win_data *data)
749 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
750 CGRect frame = cgrect_from_rect(data->window_rect);
752 data->shaped = FALSE;
753 data->whole_rect = data->window_rect;
755 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
756 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
758 if (!equal)
759 data->cocoa_view = macdrv_create_view(frame);
760 create_client_cocoa_view(data);
761 if (equal)
763 data->cocoa_view = data->client_cocoa_view;
764 macdrv_set_view_hidden(data->cocoa_view, TRUE);
765 macdrv_set_view_frame(data->cocoa_view, frame);
770 /**********************************************************************
771 * destroy_cocoa_view
773 * Destroy the Cocoa view for a given window.
775 static void destroy_cocoa_view(struct macdrv_win_data *data)
777 if (!data->cocoa_view) return;
779 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
781 if (data->cocoa_view != data->client_cocoa_view)
782 macdrv_dispose_view(data->cocoa_view);
783 data->cocoa_view = NULL;
784 data->on_screen = FALSE;
788 /***********************************************************************
789 * set_cocoa_view_parent
791 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
793 struct macdrv_win_data *parent_data = get_win_data(parent);
794 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
795 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
797 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
799 if (!cocoa_window && !superview)
800 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
802 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
803 release_win_data(parent_data);
807 /***********************************************************************
808 * macdrv_create_win_data
810 * Create a Mac data window structure for an existing window.
812 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
813 const RECT *client_rect)
815 struct macdrv_win_data *data;
816 HWND parent;
818 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
820 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
822 macdrv_init_thread_data();
823 return NULL;
826 /* don't create win data for HWND_MESSAGE windows */
827 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
829 if (!(data = alloc_win_data(hwnd))) return NULL;
831 data->whole_rect = data->window_rect = *window_rect;
832 data->client_rect = *client_rect;
834 if (parent == GetDesktopWindow())
836 create_cocoa_window(data);
837 TRACE("win %p/%p window %s whole %s client %s\n",
838 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
839 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
841 else
843 create_cocoa_view(data);
844 TRACE("win %p/%p window %s whole %s client %s\n",
845 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
846 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
848 set_cocoa_view_parent(data, parent);
851 return data;
855 /**********************************************************************
856 * is_owned_by
858 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
860 while (1)
862 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
863 if (!hwnd2)
864 hwnd2 = GetAncestor(hwnd, GA_ROOT);
865 if (!hwnd2 || hwnd2 == hwnd)
866 break;
867 if (hwnd2 == maybe_owner)
868 return TRUE;
869 hwnd = hwnd2;
872 return FALSE;
876 /**********************************************************************
877 * is_all_the_way_front
879 static BOOL is_all_the_way_front(HWND hwnd)
881 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
882 HWND prev = hwnd;
884 while ((prev = GetWindow(prev, GW_HWNDPREV)))
886 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
887 return TRUE;
888 if (!is_owned_by(prev, hwnd))
889 return FALSE;
892 return TRUE;
896 /***********************************************************************
897 * set_focus
899 static void set_focus(HWND hwnd, BOOL raise)
901 struct macdrv_win_data *data;
903 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
905 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
906 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
908 if (!(data = get_win_data(hwnd))) return;
910 if (data->cocoa_window && data->on_screen)
912 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
913 /* Set Mac focus */
914 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
915 activate_on_focus_time = 0;
918 release_win_data(data);
921 /***********************************************************************
922 * show_window
924 static void show_window(struct macdrv_win_data *data)
926 if (data->cocoa_window)
928 HWND prev = NULL;
929 HWND next = NULL;
930 macdrv_window prev_window = NULL;
931 macdrv_window next_window = NULL;
932 BOOL activate = FALSE;
933 GUITHREADINFO info;
935 /* find window that this one must be after */
936 prev = GetWindow(data->hwnd, GW_HWNDPREV);
937 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
938 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
939 prev = GetWindow(prev, GW_HWNDPREV);
940 if (!prev_window)
942 /* find window that this one must be before */
943 next = GetWindow(data->hwnd, GW_HWNDNEXT);
944 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
945 (next_window = macdrv_get_cocoa_window(next, TRUE))))
946 next = GetWindow(next, GW_HWNDNEXT);
949 TRACE("win %p/%p below %p/%p above %p/%p\n",
950 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
952 if (!prev_window)
953 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
954 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
955 data->on_screen = TRUE;
957 info.cbSize = sizeof(info);
958 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
959 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
960 set_focus(info.hwndFocus, FALSE);
961 if (activate)
962 activate_on_focus_time = 0;
964 else
966 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
968 macdrv_set_view_hidden(data->cocoa_view, FALSE);
969 data->on_screen = TRUE;
974 /***********************************************************************
975 * hide_window
977 static void hide_window(struct macdrv_win_data *data)
979 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
981 if (data->cocoa_window)
982 macdrv_hide_cocoa_window(data->cocoa_window);
983 else
984 macdrv_set_view_hidden(data->cocoa_view, TRUE);
985 data->on_screen = FALSE;
989 /***********************************************************************
990 * sync_window_z_order
992 static void sync_window_z_order(struct macdrv_win_data *data)
994 if (data->cocoa_view)
996 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
997 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
998 macdrv_window window = NULL;
999 HWND prev;
1000 HWND next = NULL;
1001 macdrv_view prev_view = NULL;
1002 macdrv_view next_view = NULL;
1004 if (!superview)
1006 window = macdrv_get_cocoa_window(parent, FALSE);
1007 if (!window)
1008 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1011 /* find window that this one must be after */
1012 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1013 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1014 prev = GetWindow(prev, GW_HWNDPREV);
1015 if (!prev_view)
1017 /* find window that this one must be before */
1018 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1019 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1020 next = GetWindow(next, GW_HWNDNEXT);
1023 TRACE("win %p/%p below %p/%p above %p/%p\n",
1024 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1026 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1028 else if (data->on_screen)
1029 show_window(data);
1033 /***********************************************************************
1034 * get_region_data
1036 * Calls GetRegionData on the given region and converts the rectangle
1037 * array to CGRect format. The returned buffer must be freed by
1038 * caller using HeapFree(GetProcessHeap(),...).
1039 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1041 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1043 RGNDATA *data;
1044 DWORD size;
1045 int i;
1046 RECT *rect;
1047 CGRect *cgrect;
1049 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
1050 if (sizeof(CGRect) > sizeof(RECT))
1052 /* add extra size for CGRect array */
1053 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1054 size += count * (sizeof(CGRect) - sizeof(RECT));
1056 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1057 if (!GetRegionData(hrgn, size, data))
1059 HeapFree(GetProcessHeap(), 0, data);
1060 return NULL;
1063 rect = (RECT *)data->Buffer;
1064 cgrect = (CGRect *)data->Buffer;
1065 if (hdc_lptodp) /* map to device coordinates */
1067 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1068 for (i = 0; i < data->rdh.nCount; i++)
1070 if (rect[i].right < rect[i].left)
1072 INT tmp = rect[i].right;
1073 rect[i].right = rect[i].left;
1074 rect[i].left = tmp;
1076 if (rect[i].bottom < rect[i].top)
1078 INT tmp = rect[i].bottom;
1079 rect[i].bottom = rect[i].top;
1080 rect[i].top = tmp;
1085 if (sizeof(CGRect) > sizeof(RECT))
1087 /* need to start from the end */
1088 for (i = data->rdh.nCount-1; i >= 0; i--)
1089 cgrect[i] = cgrect_from_rect(rect[i]);
1091 else
1093 for (i = 0; i < data->rdh.nCount; i++)
1094 cgrect[i] = cgrect_from_rect(rect[i]);
1096 return data;
1100 /***********************************************************************
1101 * sync_client_view_position
1103 static void sync_client_view_position(struct macdrv_win_data *data)
1105 if (data->cocoa_view != data->client_cocoa_view)
1107 RECT rect = data->client_rect;
1108 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1109 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1110 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1115 /***********************************************************************
1116 * sync_window_position
1118 * Synchronize the Mac window position with the Windows one
1120 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1121 const RECT *old_whole_rect)
1123 CGRect frame = cgrect_from_rect(data->whole_rect);
1124 BOOL force_z_order = FALSE;
1126 if (data->cocoa_window)
1128 if (data->minimized) return;
1130 constrain_window_frame(&frame);
1131 if (frame.size.width < 1 || frame.size.height < 1)
1132 frame.size.width = frame.size.height = 1;
1134 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1136 else
1138 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1139 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1141 if (were_equal && !now_equal)
1143 data->cocoa_view = macdrv_create_view(frame);
1144 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1145 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1146 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1147 force_z_order = TRUE;
1149 else if (!were_equal && now_equal)
1151 macdrv_dispose_view(data->cocoa_view);
1152 data->cocoa_view = data->client_cocoa_view;
1153 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1154 macdrv_set_view_frame(data->cocoa_view, frame);
1155 force_z_order = TRUE;
1157 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1158 macdrv_set_view_frame(data->cocoa_view, frame);
1161 sync_client_view_position(data);
1163 if (old_window_rect && old_whole_rect &&
1164 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1165 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1166 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1167 sync_window_region(data, (HRGN)1);
1169 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1170 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1171 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1173 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1174 sync_window_z_order(data);
1178 /***********************************************************************
1179 * move_window_bits
1181 * Move the window bits when a window is moved.
1183 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1184 const RECT *old_client_rect, const RECT *new_client_rect,
1185 const RECT *new_window_rect)
1187 RECT src_rect = *old_rect;
1188 RECT dst_rect = *new_rect;
1189 HDC hdc_src, hdc_dst;
1190 HRGN rgn;
1191 HWND parent = 0;
1193 if (!window)
1195 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1196 parent = GetAncestor(hwnd, GA_PARENT);
1197 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1198 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1200 else
1202 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1203 /* make src rect relative to the old position of the window */
1204 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1205 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1206 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1209 rgn = CreateRectRgnIndirect(&dst_rect);
1210 SelectClipRgn(hdc_dst, rgn);
1211 DeleteObject(rgn);
1212 ExcludeUpdateRgn(hdc_dst, hwnd);
1214 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1215 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1216 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1217 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1218 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1220 ReleaseDC(hwnd, hdc_dst);
1221 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1225 /**********************************************************************
1226 * activate_on_following_focus
1228 void activate_on_following_focus(void)
1230 activate_on_focus_time = GetTickCount();
1231 if (!activate_on_focus_time) activate_on_focus_time = 1;
1235 /***********************************************************************
1236 * set_app_icon
1238 static void set_app_icon(void)
1240 CFArrayRef images = create_app_icon_images();
1241 if (images)
1243 macdrv_set_application_icon(images);
1244 CFRelease(images);
1249 /**********************************************************************
1250 * set_capture_window_for_move
1252 static BOOL set_capture_window_for_move(HWND hwnd)
1254 HWND previous = 0;
1255 BOOL ret;
1257 SERVER_START_REQ(set_capture_window)
1259 req->handle = wine_server_user_handle(hwnd);
1260 req->flags = CAPTURE_MOVESIZE;
1261 if ((ret = !wine_server_call_err(req)))
1263 previous = wine_server_ptr_handle(reply->previous);
1264 hwnd = wine_server_ptr_handle(reply->full_handle);
1267 SERVER_END_REQ;
1269 if (ret)
1271 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1273 if (previous && previous != hwnd)
1274 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1276 return ret;
1280 /***********************************************************************
1281 * move_window
1283 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1284 * moving top-level windows and enforcing Mac-style constraints like
1285 * keeping the top of the window within the work area.
1287 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1289 MSG msg;
1290 RECT origRect, movedRect, desktopRect;
1291 LONG hittest = (LONG)(wparam & 0x0f);
1292 POINT capturePoint;
1293 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1294 BOOL moved = FALSE;
1295 DWORD dwPoint = GetMessagePos();
1296 INT captionHeight;
1297 HMONITOR mon = 0;
1298 MONITORINFO info;
1300 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1301 if (hittest && hittest != HTCAPTION) return -1;
1303 capturePoint.x = (short)LOWORD(dwPoint);
1304 capturePoint.y = (short)HIWORD(dwPoint);
1305 ClipCursor(NULL);
1307 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1309 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1310 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1311 captionHeight = -origRect.top;
1312 else
1313 captionHeight = 0;
1315 GetWindowRect(hwnd, &origRect);
1316 movedRect = origRect;
1318 if (!hittest)
1320 /* Move pointer to the center of the caption */
1321 RECT rect = origRect;
1323 /* Note: to be exactly centered we should take the different types
1324 * of border into account, but it shouldn't make more than a few pixels
1325 * of difference so let's not bother with that */
1326 rect.top += GetSystemMetrics(SM_CYBORDER);
1327 if (style & WS_SYSMENU)
1328 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1329 if (style & WS_MINIMIZEBOX)
1330 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1331 if (style & WS_MAXIMIZEBOX)
1332 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1333 capturePoint.x = (rect.right + rect.left) / 2;
1334 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1336 SetCursorPos(capturePoint.x, capturePoint.y);
1337 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1340 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1341 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1342 info.cbSize = sizeof(info);
1343 if (mon && !GetMonitorInfoW(mon, &info))
1344 mon = 0;
1346 /* repaint the window before moving it around */
1347 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1349 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1350 set_capture_window_for_move(hwnd);
1352 while(1)
1354 POINT pt;
1355 int dx = 0, dy = 0;
1356 HMONITOR newmon;
1358 if (!GetMessageW(&msg, 0, 0, 0)) break;
1359 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1361 /* Exit on button-up, Return, or Esc */
1362 if (msg.message == WM_LBUTTONUP ||
1363 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1364 break;
1366 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1368 TranslateMessage(&msg);
1369 DispatchMessageW(&msg);
1370 continue; /* We are not interested in other messages */
1373 pt = msg.pt;
1375 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1377 case VK_UP: pt.y -= 8; break;
1378 case VK_DOWN: pt.y += 8; break;
1379 case VK_LEFT: pt.x -= 8; break;
1380 case VK_RIGHT: pt.x += 8; break;
1383 pt.x = max(pt.x, desktopRect.left);
1384 pt.x = min(pt.x, desktopRect.right - 1);
1385 pt.y = max(pt.y, desktopRect.top);
1386 pt.y = min(pt.y, desktopRect.bottom - 1);
1388 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1390 if (GetMonitorInfoW(newmon, &info))
1391 mon = newmon;
1392 else
1393 mon = 0;
1396 if (mon)
1398 /* wineserver clips the cursor position to the virtual desktop rect but,
1399 if the display configuration is non-rectangular, that could still
1400 leave the logical cursor position outside of any display. The window
1401 could keep moving as you push the cursor against a display edge, even
1402 though the visible cursor doesn't keep moving. The following keeps
1403 the window movement in sync with the visible cursor. */
1404 pt.x = max(pt.x, info.rcMonitor.left);
1405 pt.x = min(pt.x, info.rcMonitor.right - 1);
1406 pt.y = max(pt.y, info.rcMonitor.top);
1407 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1409 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1410 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1411 we want to enforce these constraints:
1412 movedRect.left + dx < info.rcWork.right
1413 movedRect.right + dx > info.rcWork.left
1414 movedRect.top + captionHeight + dy < info.rcWork.bottom
1415 movedRect.bottom + dy > info.rcWork.top
1416 movedRect.top + dy >= info.rcWork.top
1417 The first four keep at least one edge barely in the work area.
1418 The last keeps the top (i.e. the title bar) in the work area.
1419 The fourth is redundant with the last, so can be ignored.
1421 Substituting for dx and dy and rearranging gives us...
1423 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1424 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1425 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1426 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1429 dx = pt.x - capturePoint.x;
1430 dy = pt.y - capturePoint.y;
1432 if (dx || dy)
1434 moved = TRUE;
1436 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1437 else
1439 OffsetRect(&movedRect, dx, dy);
1440 capturePoint = pt;
1442 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1443 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1444 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1449 set_capture_window_for_move(0);
1451 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1452 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1454 /* if the move is canceled, restore the previous position */
1455 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1457 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1458 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1461 return 0;
1465 /***********************************************************************
1466 * perform_window_command
1468 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1470 DWORD style;
1472 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1473 hwnd, style_any, style_none, command, hittest);
1475 style = GetWindowLongW(hwnd, GWL_STYLE);
1476 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1478 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1479 return;
1482 if (GetActiveWindow() != hwnd)
1484 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1485 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1486 switch (ma)
1488 case MA_NOACTIVATEANDEAT:
1489 case MA_ACTIVATEANDEAT:
1490 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1491 return;
1492 case MA_NOACTIVATE:
1493 break;
1494 case MA_ACTIVATE:
1495 case 0:
1496 SetActiveWindow(hwnd);
1497 break;
1498 default:
1499 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1500 break;
1504 TRACE("changing win %p\n", hwnd);
1505 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1509 /**********************************************************************
1510 * CreateDesktopWindow (MACDRV.@)
1512 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1514 unsigned int width, height;
1516 TRACE("%p\n", hwnd);
1518 /* retrieve the real size of the desktop */
1519 SERVER_START_REQ(get_window_rectangles)
1521 req->handle = wine_server_user_handle(hwnd);
1522 req->relative = COORDS_CLIENT;
1523 wine_server_call(req);
1524 width = reply->window.right;
1525 height = reply->window.bottom;
1527 SERVER_END_REQ;
1529 if (!width && !height) /* not initialized yet */
1531 CGRect rect = macdrv_get_desktop_rect();
1533 SERVER_START_REQ(set_window_pos)
1535 req->handle = wine_server_user_handle(hwnd);
1536 req->previous = 0;
1537 req->swp_flags = SWP_NOZORDER;
1538 req->window.left = CGRectGetMinX(rect);
1539 req->window.top = CGRectGetMinY(rect);
1540 req->window.right = CGRectGetMaxX(rect);
1541 req->window.bottom = CGRectGetMaxY(rect);
1542 req->client = req->window;
1543 wine_server_call(req);
1545 SERVER_END_REQ;
1548 set_app_icon();
1549 return TRUE;
1553 /**********************************************************************
1554 * CreateWindow (MACDRV.@)
1556 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1558 if (hwnd == GetDesktopWindow())
1559 macdrv_init_clipboard();
1560 return TRUE;
1564 /***********************************************************************
1565 * DestroyWindow (MACDRV.@)
1567 void CDECL macdrv_DestroyWindow(HWND hwnd)
1569 struct macdrv_win_data *data;
1571 TRACE("%p\n", hwnd);
1573 if (!(data = get_win_data(hwnd))) return;
1575 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1577 destroy_cocoa_window(data);
1578 destroy_cocoa_view(data);
1579 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1581 CFDictionaryRemoveValue(win_datas, hwnd);
1582 release_win_data(data);
1583 HeapFree(GetProcessHeap(), 0, data);
1587 /*****************************************************************
1588 * SetFocus (MACDRV.@)
1590 * Set the Mac focus.
1592 void CDECL macdrv_SetFocus(HWND hwnd)
1594 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1596 TRACE("%p\n", hwnd);
1598 if (!thread_data) return;
1599 thread_data->dead_key_state = 0;
1600 set_focus(hwnd, TRUE);
1604 /***********************************************************************
1605 * SetLayeredWindowAttributes (MACDRV.@)
1607 * Set transparency attributes for a layered window.
1609 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1611 struct macdrv_win_data *data = get_win_data(hwnd);
1613 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1615 if (data)
1617 data->layered = TRUE;
1618 data->ulw_layered = FALSE;
1619 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1620 if (data->cocoa_window)
1622 sync_window_opacity(data, key, alpha, FALSE, flags);
1623 /* since layered attributes are now set, can now show the window */
1624 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1625 show_window(data);
1627 release_win_data(data);
1629 else
1630 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1634 /*****************************************************************
1635 * SetParent (MACDRV.@)
1637 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1639 struct macdrv_win_data *data;
1641 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1643 if (parent == old_parent) return;
1644 if (!(data = get_win_data(hwnd))) return;
1646 if (parent != GetDesktopWindow()) /* a child window */
1648 if (old_parent == GetDesktopWindow())
1650 /* destroy the old Mac window */
1651 destroy_cocoa_window(data);
1652 create_cocoa_view(data);
1655 set_cocoa_view_parent(data, parent);
1657 else /* new top level window */
1659 destroy_cocoa_view(data);
1660 create_cocoa_window(data);
1662 release_win_data(data);
1666 /***********************************************************************
1667 * SetWindowRgn (MACDRV.@)
1669 * Assign specified region to window (for non-rectangular windows)
1671 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1673 struct macdrv_win_data *data;
1675 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1677 if ((data = get_win_data(hwnd)))
1679 sync_window_region(data, hrgn);
1680 release_win_data(data);
1682 else
1684 DWORD procid;
1686 GetWindowThreadProcessId(hwnd, &procid);
1687 if (procid != GetCurrentProcessId())
1688 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1693 /***********************************************************************
1694 * SetWindowStyle (MACDRV.@)
1696 * Update the state of the Cocoa window to reflect a style change
1698 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1700 struct macdrv_win_data *data;
1702 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1704 if (hwnd == GetDesktopWindow()) return;
1705 if (!(data = get_win_data(hwnd))) return;
1707 if (data->cocoa_window)
1709 DWORD changed = style->styleNew ^ style->styleOld;
1711 set_cocoa_window_properties(data);
1713 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1715 data->layered = FALSE;
1716 data->ulw_layered = FALSE;
1717 sync_window_opacity(data, 0, 0, FALSE, 0);
1718 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1721 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1722 sync_window_region(data, (HRGN)1);
1725 release_win_data(data);
1729 /*****************************************************************
1730 * SetWindowText (MACDRV.@)
1732 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1734 macdrv_window win;
1736 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1738 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1739 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1743 /***********************************************************************
1744 * ShowWindow (MACDRV.@)
1746 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1748 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1749 struct macdrv_win_data *data = get_win_data(hwnd);
1750 CGRect frame;
1752 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1753 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1755 if (!data || !data->cocoa_window) goto done;
1756 if (IsRectEmpty(rect)) goto done;
1757 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1759 if (rect->left != -32000 || rect->top != -32000)
1761 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1762 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1764 goto done;
1766 if (!data->on_screen) goto done;
1768 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1770 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1771 goto done;
1773 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1774 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1775 goto done;
1777 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1778 *rect = rect_from_cgrect(frame);
1779 macdrv_mac_to_window_rect(data, rect);
1780 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1781 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1783 done:
1784 release_win_data(data);
1785 return swp;
1789 /***********************************************************************
1790 * SysCommand (MACDRV.@)
1792 * Perform WM_SYSCOMMAND handling.
1794 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1796 struct macdrv_win_data *data;
1797 LRESULT ret = -1;
1798 WPARAM command = wparam & 0xfff0;
1800 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1802 if (!(data = get_win_data(hwnd))) goto done;
1803 if (!data->cocoa_window || !data->on_screen) goto done;
1805 /* prevent a simple ALT press+release from activating the system menu,
1806 as that can get confusing */
1807 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1808 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1810 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1811 ret = 0;
1814 if (command == SC_MOVE)
1816 release_win_data(data);
1817 return move_window(hwnd, wparam);
1820 done:
1821 release_win_data(data);
1822 return ret;
1826 /***********************************************************************
1827 * UpdateLayeredWindow (MACDRV.@)
1829 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1830 const RECT *window_rect)
1832 struct window_surface *surface;
1833 struct macdrv_win_data *data;
1834 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1835 BYTE alpha;
1836 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1837 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1838 void *src_bits, *dst_bits;
1839 RECT rect;
1840 HDC hdc = 0;
1841 HBITMAP dib;
1842 BOOL ret = FALSE;
1844 if (!(data = get_win_data(hwnd))) return FALSE;
1846 data->layered = TRUE;
1847 data->ulw_layered = TRUE;
1849 rect = *window_rect;
1850 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1852 surface = data->surface;
1853 if (!surface || !EqualRect(&surface->rect, &rect))
1855 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1856 set_window_surface(data->cocoa_window, data->surface);
1857 if (surface) window_surface_release(surface);
1858 surface = data->surface;
1859 if (data->unminimized_surface)
1861 window_surface_release(data->unminimized_surface);
1862 data->unminimized_surface = NULL;
1865 else set_surface_use_alpha(surface, TRUE);
1867 if (surface) window_surface_add_ref(surface);
1868 release_win_data(data);
1870 if (!surface) return FALSE;
1871 if (!info->hdcSrc)
1873 window_surface_release(surface);
1874 return TRUE;
1877 if (info->dwFlags & ULW_ALPHA)
1879 /* Apply SourceConstantAlpha via window alpha, not blend. */
1880 alpha = info->pblend->SourceConstantAlpha;
1881 blend = *info->pblend;
1882 blend.SourceConstantAlpha = 0xff;
1884 else
1885 alpha = 0xff;
1887 dst_bits = surface->funcs->get_info(surface, bmi);
1889 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1890 if (!(hdc = CreateCompatibleDC(0))) goto done;
1892 SelectObject(hdc, dib);
1893 if (info->prcDirty)
1895 IntersectRect(&rect, &rect, info->prcDirty);
1896 surface->funcs->lock(surface);
1897 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1898 surface->funcs->unlock(surface);
1899 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1901 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1902 info->hdcSrc,
1903 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1904 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1905 rect.right - rect.left, rect.bottom - rect.top,
1906 blend)))
1907 goto done;
1909 if ((data = get_win_data(hwnd)))
1911 if (surface == data->surface)
1913 surface->funcs->lock(surface);
1914 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1915 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1916 surface->funcs->unlock(surface);
1917 surface->funcs->flush(surface);
1920 /* The ULW flags are a superset of the LWA flags. */
1921 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1923 release_win_data(data);
1926 done:
1927 window_surface_release(surface);
1928 if (hdc) DeleteDC(hdc);
1929 if (dib) DeleteObject(dib);
1930 return ret;
1934 /**********************************************************************
1935 * WindowMessage (MACDRV.@)
1937 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1939 struct macdrv_win_data *data;
1941 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1943 switch(msg)
1945 case WM_MACDRV_SET_WIN_REGION:
1946 if ((data = get_win_data(hwnd)))
1948 sync_window_region(data, (HRGN)1);
1949 release_win_data(data);
1951 return 0;
1952 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1953 if (hwnd == GetDesktopWindow())
1955 CGRect new_desktop_rect;
1956 RECT current_desktop_rect;
1958 macdrv_reset_device_metrics();
1959 new_desktop_rect = macdrv_get_desktop_rect();
1960 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1961 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1963 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1964 SMTO_ABORTIFHUNG, 2000, NULL);
1965 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1966 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1967 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1968 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1969 SMTO_ABORTIFHUNG, 2000, NULL);
1972 return 0;
1973 case WM_MACDRV_RESET_DEVICE_METRICS:
1974 macdrv_reset_device_metrics();
1975 return 0;
1976 case WM_MACDRV_DISPLAYCHANGE:
1977 macdrv_reassert_window_position(hwnd);
1978 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1979 return 0;
1980 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1981 activate_on_following_focus();
1982 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1983 return 0;
1986 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1987 return 0;
1991 static inline RECT get_surface_rect(const RECT *visible_rect)
1993 RECT rect;
1994 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1996 IntersectRect(&rect, visible_rect, &desktop_rect);
1997 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1998 rect.left &= ~127;
1999 rect.top &= ~127;
2000 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2001 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2002 return rect;
2006 /***********************************************************************
2007 * WindowPosChanging (MACDRV.@)
2009 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2010 const RECT *window_rect, const RECT *client_rect,
2011 RECT *visible_rect, struct window_surface **surface)
2013 struct macdrv_win_data *data = get_win_data(hwnd);
2014 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2015 RECT surface_rect;
2017 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2018 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2019 wine_dbgstr_rect(visible_rect), surface);
2021 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
2023 *visible_rect = *window_rect;
2024 macdrv_window_to_mac_rect(data, style, visible_rect);
2025 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2026 wine_dbgstr_rect(visible_rect));
2028 /* create the window surface if necessary */
2029 if (!data->cocoa_window) goto done;
2030 if (swp_flags & SWP_HIDEWINDOW) goto done;
2031 if (data->ulw_layered) goto done;
2033 if (*surface) window_surface_release(*surface);
2034 *surface = NULL;
2036 surface_rect = get_surface_rect(visible_rect);
2037 if (data->surface)
2039 if (EqualRect(&data->surface->rect, &surface_rect))
2041 /* existing surface is good enough */
2042 surface_clip_to_visible_rect(data->surface, visible_rect);
2043 window_surface_add_ref(data->surface);
2044 *surface = data->surface;
2045 goto done;
2048 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2050 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2052 done:
2053 release_win_data(data);
2057 /***********************************************************************
2058 * WindowPosChanged (MACDRV.@)
2060 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2061 const RECT *window_rect, const RECT *client_rect,
2062 const RECT *visible_rect, const RECT *valid_rects,
2063 struct window_surface *surface)
2065 struct macdrv_thread_data *thread_data;
2066 struct macdrv_win_data *data;
2067 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2068 RECT old_window_rect, old_whole_rect, old_client_rect;
2070 if (!(data = get_win_data(hwnd))) return;
2072 thread_data = macdrv_thread_data();
2074 old_window_rect = data->window_rect;
2075 old_whole_rect = data->whole_rect;
2076 old_client_rect = data->client_rect;
2077 data->window_rect = *window_rect;
2078 data->whole_rect = *visible_rect;
2079 data->client_rect = *client_rect;
2080 if (data->cocoa_window && !data->ulw_layered)
2082 if (surface) window_surface_add_ref(surface);
2083 if (new_style & WS_MINIMIZE)
2085 if (!data->unminimized_surface && data->surface)
2087 data->unminimized_surface = data->surface;
2088 window_surface_add_ref(data->unminimized_surface);
2091 else
2093 set_window_surface(data->cocoa_window, surface);
2094 if (data->unminimized_surface)
2096 window_surface_release(data->unminimized_surface);
2097 data->unminimized_surface = NULL;
2100 if (data->surface) window_surface_release(data->surface);
2101 data->surface = surface;
2104 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2105 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2106 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2107 new_style, swp_flags, surface);
2109 if (!IsRectEmpty(&valid_rects[0]))
2111 macdrv_window window = data->cocoa_window;
2112 int x_offset = old_whole_rect.left - data->whole_rect.left;
2113 int y_offset = old_whole_rect.top - data->whole_rect.top;
2115 /* if all that happened is that the whole window moved, copy everything */
2116 if (!(swp_flags & SWP_FRAMECHANGED) &&
2117 old_whole_rect.right - data->whole_rect.right == x_offset &&
2118 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2119 old_client_rect.left - data->client_rect.left == x_offset &&
2120 old_client_rect.right - data->client_rect.right == x_offset &&
2121 old_client_rect.top - data->client_rect.top == y_offset &&
2122 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2123 EqualRect(&valid_rects[0], &data->client_rect))
2125 /* A Cocoa window's bits are moved automatically */
2126 if (!window && (x_offset != 0 || y_offset != 0))
2128 release_win_data(data);
2129 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2130 &old_client_rect, client_rect, window_rect);
2131 if (!(data = get_win_data(hwnd))) return;
2134 else
2136 release_win_data(data);
2137 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2138 &old_client_rect, client_rect, window_rect);
2139 if (!(data = get_win_data(hwnd))) return;
2143 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2145 if (!data->cocoa_window && !data->cocoa_view) goto done;
2147 if (data->on_screen)
2149 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2150 hide_window(data);
2153 /* check if we are currently processing an event relevant to this window */
2154 if (thread_data && thread_data->current_event &&
2155 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2156 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2157 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2159 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2160 sync_client_view_position(data);
2162 else
2164 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2165 if (data->cocoa_window)
2166 set_cocoa_window_properties(data);
2169 if (new_style & WS_VISIBLE)
2171 if (data->cocoa_window)
2173 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2174 set_cocoa_window_properties(data);
2176 /* layered windows are not shown until their attributes are set */
2177 if (!data->on_screen &&
2178 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2179 show_window(data);
2181 else if (!data->on_screen)
2182 show_window(data);
2185 done:
2186 release_win_data(data);
2190 /***********************************************************************
2191 * macdrv_window_close_requested
2193 * Handler for WINDOW_CLOSE_REQUESTED events.
2195 void macdrv_window_close_requested(HWND hwnd)
2197 HMENU sysmenu;
2199 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2201 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2202 return;
2205 sysmenu = GetSystemMenu(hwnd, FALSE);
2206 if (sysmenu)
2208 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2209 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2211 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2212 return;
2216 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2220 /***********************************************************************
2221 * macdrv_window_frame_changed
2223 * Handler for WINDOW_FRAME_CHANGED events.
2225 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2227 struct macdrv_win_data *data;
2228 RECT rect;
2229 HWND parent;
2230 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2231 int width, height;
2232 BOOL being_dragged;
2234 if (!hwnd) return;
2235 if (!(data = get_win_data(hwnd))) return;
2236 if (!data->on_screen || data->minimized)
2238 release_win_data(data);
2239 return;
2242 /* Get geometry */
2244 parent = GetAncestor(hwnd, GA_PARENT);
2246 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2247 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2248 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2250 rect = rect_from_cgrect(event->window_frame_changed.frame);
2251 macdrv_mac_to_window_rect(data, &rect);
2252 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2254 width = rect.right - rect.left;
2255 height = rect.bottom - rect.top;
2257 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2258 flags |= SWP_NOMOVE;
2259 else
2260 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2261 data->window_rect.top, rect.left, rect.top);
2263 if ((data->window_rect.right - data->window_rect.left == width &&
2264 data->window_rect.bottom - data->window_rect.top == height) ||
2265 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2266 flags |= SWP_NOSIZE;
2267 else
2268 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2269 data->window_rect.bottom - data->window_rect.top, width, height);
2271 being_dragged = data->being_dragged;
2272 release_win_data(data);
2274 if (event->window_frame_changed.fullscreen)
2275 flags |= SWP_NOSENDCHANGING;
2276 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2278 if (!event->window_frame_changed.in_resize && !being_dragged)
2279 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2280 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2281 if (!event->window_frame_changed.in_resize && !being_dragged)
2282 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2287 /***********************************************************************
2288 * macdrv_window_got_focus
2290 * Handler for WINDOW_GOT_FOCUS events.
2292 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2294 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2296 if (!hwnd) return;
2298 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2299 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2300 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2302 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2304 /* simulate a mouse click on the caption to find out
2305 * whether the window wants to be activated */
2306 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2307 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2308 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2309 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2311 TRACE("setting foreground window to %p\n", hwnd);
2312 SetForegroundWindow(hwnd);
2313 return;
2317 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2318 macdrv_window_rejected_focus(event);
2322 /***********************************************************************
2323 * macdrv_window_lost_focus
2325 * Handler for WINDOW_LOST_FOCUS events.
2327 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2329 if (!hwnd) return;
2331 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2333 if (hwnd == GetForegroundWindow())
2335 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2336 if (hwnd == GetForegroundWindow())
2337 SetForegroundWindow(GetDesktopWindow());
2342 /***********************************************************************
2343 * macdrv_app_activated
2345 * Handler for APP_ACTIVATED events.
2347 void macdrv_app_activated(void)
2349 TRACE("\n");
2350 macdrv_UpdateClipboard();
2354 /***********************************************************************
2355 * macdrv_app_deactivated
2357 * Handler for APP_DEACTIVATED events.
2359 void macdrv_app_deactivated(void)
2361 if (GetActiveWindow() == GetForegroundWindow())
2363 TRACE("setting fg to desktop\n");
2364 SetForegroundWindow(GetDesktopWindow());
2369 /***********************************************************************
2370 * macdrv_window_maximize_requested
2372 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2374 void macdrv_window_maximize_requested(HWND hwnd)
2376 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2380 /***********************************************************************
2381 * macdrv_window_minimize_requested
2383 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2385 void macdrv_window_minimize_requested(HWND hwnd)
2387 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2391 /***********************************************************************
2392 * macdrv_window_did_unminimize
2394 * Handler for WINDOW_DID_UNMINIMIZE events.
2396 void macdrv_window_did_unminimize(HWND hwnd)
2398 struct macdrv_win_data *data;
2399 DWORD style;
2401 TRACE("win %p\n", hwnd);
2403 if (!(data = get_win_data(hwnd))) return;
2404 if (!data->minimized) goto done;
2406 style = GetWindowLongW(hwnd, GWL_STYLE);
2408 data->minimized = FALSE;
2409 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2411 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2412 release_win_data(data);
2413 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2414 return;
2417 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2419 done:
2420 release_win_data(data);
2424 /***********************************************************************
2425 * macdrv_window_brought_forward
2427 * Handler for WINDOW_BROUGHT_FORWARD events.
2429 void macdrv_window_brought_forward(HWND hwnd)
2431 TRACE("win %p\n", hwnd);
2432 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2436 /***********************************************************************
2437 * macdrv_window_resize_ended
2439 * Handler for WINDOW_RESIZE_ENDED events.
2441 void macdrv_window_resize_ended(HWND hwnd)
2443 TRACE("hwnd %p\n", hwnd);
2444 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2448 /***********************************************************************
2449 * macdrv_window_restore_requested
2451 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2452 * for restoring from maximized, not from minimized.
2454 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2456 if (event->window_restore_requested.keep_frame && hwnd)
2458 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2459 struct macdrv_win_data *data;
2461 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2463 RECT rect;
2464 HWND parent = GetAncestor(hwnd, GA_PARENT);
2466 rect = rect_from_cgrect(event->window_restore_requested.frame);
2467 macdrv_mac_to_window_rect(data, &rect);
2468 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2470 release_win_data(data);
2472 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2476 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2480 /***********************************************************************
2481 * macdrv_window_drag_begin
2483 * Handler for WINDOW_DRAG_BEGIN events.
2485 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2487 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2488 struct macdrv_win_data *data;
2489 MSG msg;
2491 TRACE("win %p\n", hwnd);
2493 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2494 if (!(style & WS_VISIBLE)) return;
2496 if (!(data = get_win_data(hwnd))) return;
2497 if (data->being_dragged) goto done;
2499 data->being_dragged = TRUE;
2500 release_win_data(data);
2502 if (!event->window_drag_begin.no_activate && can_activate_window(hwnd) && GetForegroundWindow() != hwnd)
2504 /* ask whether the window wants to be activated */
2505 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2506 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2507 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2509 TRACE("setting foreground window to %p\n", hwnd);
2510 SetForegroundWindow(hwnd);
2514 ClipCursor(NULL);
2515 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2516 ReleaseCapture();
2518 while (GetMessageW(&msg, 0, 0, 0))
2520 if (msg.message == WM_EXITSIZEMOVE)
2522 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2523 break;
2526 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2527 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2529 TranslateMessage(&msg);
2530 DispatchMessageW(&msg);
2534 TRACE("done\n");
2536 if ((data = get_win_data(hwnd)))
2537 data->being_dragged = FALSE;
2539 done:
2540 release_win_data(data);
2544 /***********************************************************************
2545 * macdrv_window_drag_end
2547 * Handler for WINDOW_DRAG_END events.
2549 void macdrv_window_drag_end(HWND hwnd)
2551 struct macdrv_win_data *data;
2552 BOOL being_dragged;
2554 TRACE("win %p\n", hwnd);
2556 if (!(data = get_win_data(hwnd))) return;
2557 being_dragged = data->being_dragged;
2558 release_win_data(data);
2560 if (being_dragged)
2562 /* Post this rather than sending it, so that the message loop in
2563 macdrv_window_drag_begin() will see it. */
2564 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2569 /***********************************************************************
2570 * macdrv_reassert_window_position
2572 * Handler for REASSERT_WINDOW_POSITION events.
2574 void macdrv_reassert_window_position(HWND hwnd)
2576 struct macdrv_win_data *data = get_win_data(hwnd);
2577 if (data)
2579 if (data->cocoa_window && data->on_screen)
2580 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2581 release_win_data(data);
2586 struct quit_info {
2587 HWND *wins;
2588 UINT capacity;
2589 UINT count;
2590 UINT done;
2591 DWORD flags;
2592 BOOL result;
2593 BOOL replied;
2597 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2599 struct quit_info *qi = (struct quit_info*)lp;
2600 DWORD pid;
2602 GetWindowThreadProcessId(hwnd, &pid);
2603 if (pid == GetCurrentProcessId())
2605 if (qi->count >= qi->capacity)
2607 UINT new_cap = qi->capacity * 2;
2608 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2609 new_cap * sizeof(*qi->wins));
2610 if (!new_wins) return FALSE;
2611 qi->wins = new_wins;
2612 qi->capacity = new_cap;
2615 qi->wins[qi->count++] = hwnd;
2618 return TRUE;
2622 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2624 struct quit_info *qi = (struct quit_info*)data;
2626 qi->done++;
2628 if (msg == WM_QUERYENDSESSION)
2630 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2631 hwnd, qi->done, qi->count);
2633 if (!result && !IsWindow(hwnd))
2635 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2636 result = TRUE;
2639 if (!result && qi->result)
2641 qi->result = FALSE;
2643 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2644 ultimate reply. Might as well tell Cocoa now. */
2645 if (!qi->replied)
2647 qi->replied = TRUE;
2648 TRACE("giving quit reply %d\n", qi->result);
2649 macdrv_quit_reply(qi->result);
2653 if (qi->done >= qi->count)
2655 UINT i;
2657 qi->done = 0;
2658 for (i = 0; i < qi->count; i++)
2660 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2661 qi->result, qi->flags);
2662 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2663 quit_callback, (ULONG_PTR)qi))
2665 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2666 qi->wins[i], GetLastError());
2667 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2672 else /* WM_ENDSESSION */
2674 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2676 if (qi->done >= qi->count)
2678 if (!qi->replied)
2680 TRACE("giving quit reply %d\n", qi->result);
2681 macdrv_quit_reply(qi->result);
2684 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2685 if (qi->result)
2686 TerminateProcess(GetCurrentProcess(), 0);
2688 HeapFree(GetProcessHeap(), 0, qi->wins);
2689 HeapFree(GetProcessHeap(), 0, qi);
2695 /***********************************************************************
2696 * macdrv_app_quit_requested
2698 * Handler for APP_QUIT_REQUESTED events.
2700 void macdrv_app_quit_requested(const macdrv_event *event)
2702 struct quit_info *qi;
2703 UINT i;
2705 TRACE("reason %d\n", event->app_quit_requested.reason);
2707 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2708 if (!qi)
2709 goto fail;
2711 qi->capacity = 32;
2712 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2713 qi->count = qi->done = 0;
2715 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2716 goto fail;
2718 switch (event->app_quit_requested.reason)
2720 case QUIT_REASON_LOGOUT:
2721 default:
2722 qi->flags = ENDSESSION_LOGOFF;
2723 break;
2724 case QUIT_REASON_RESTART:
2725 case QUIT_REASON_SHUTDOWN:
2726 qi->flags = 0;
2727 break;
2730 qi->result = TRUE;
2731 qi->replied = FALSE;
2733 for (i = 0; i < qi->count; i++)
2735 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2736 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2737 quit_callback, (ULONG_PTR)qi))
2739 DWORD error = GetLastError();
2740 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2741 if (invalid)
2742 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2743 qi->wins[i]);
2744 else
2745 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2746 qi->wins[i], error);
2747 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2751 /* quit_callback() will clean up qi */
2752 return;
2754 fail:
2755 WARN("failed to allocate window list\n");
2756 if (qi)
2758 HeapFree(GetProcessHeap(), 0, qi->wins);
2759 HeapFree(GetProcessHeap(), 0, qi);
2761 macdrv_quit_reply(FALSE);
2765 /***********************************************************************
2766 * query_resize_size
2768 * Handler for QUERY_RESIZE_SIZE query.
2770 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2772 struct macdrv_win_data *data = get_win_data(hwnd);
2773 RECT rect = rect_from_cgrect(query->resize_size.rect);
2774 int corner;
2775 BOOL ret = FALSE;
2777 if (!data) return FALSE;
2779 macdrv_mac_to_window_rect(data, &rect);
2781 if (query->resize_size.from_left)
2783 if (query->resize_size.from_top)
2784 corner = WMSZ_TOPLEFT;
2785 else
2786 corner = WMSZ_BOTTOMLEFT;
2788 else if (query->resize_size.from_top)
2789 corner = WMSZ_TOPRIGHT;
2790 else
2791 corner = WMSZ_BOTTOMRIGHT;
2793 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2795 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2796 query->resize_size.rect = cgrect_from_rect(rect);
2797 ret = TRUE;
2800 release_win_data(data);
2801 return ret;
2805 /***********************************************************************
2806 * query_resize_start
2808 * Handler for QUERY_RESIZE_START query.
2810 BOOL query_resize_start(HWND hwnd)
2812 TRACE("hwnd %p\n", hwnd);
2814 sync_window_min_max_info(hwnd);
2815 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2817 return TRUE;
2821 /***********************************************************************
2822 * query_min_max_info
2824 * Handler for QUERY_MIN_MAX_INFO query.
2826 BOOL query_min_max_info(HWND hwnd)
2828 TRACE("hwnd %p\n", hwnd);
2829 sync_window_min_max_info(hwnd);
2830 return TRUE;