win32u: Move NtUserTranslateMessage implementation from user32.
[wine.git] / dlls / winemac.drv / window.c
blobb00514d30bf22bd2f25c1d79d3a8a0c67612e32a
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 <IOKit/pwr_mgt/IOPMLib.h>
27 #define GetCurrentThread Mac_GetCurrentThread
28 #define LoadResource Mac_LoadResource
29 #include <CoreServices/CoreServices.h>
30 #undef GetCurrentThread
31 #undef LoadResource
33 #include "macdrv.h"
34 #include "winuser.h"
35 #include "wine/unicode.h"
36 #include "wine/server.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
41 static CRITICAL_SECTION win_data_section;
42 static CRITICAL_SECTION_DEBUG critsect_debug =
44 0, 0, &win_data_section,
45 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
46 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
48 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
50 static CFMutableDictionaryRef win_datas;
52 static DWORD activate_on_focus_time;
55 /***********************************************************************
56 * get_cocoa_window_features
58 static void get_cocoa_window_features(struct macdrv_win_data *data,
59 DWORD style, DWORD ex_style,
60 struct macdrv_window_features* wf,
61 const RECT *window_rect,
62 const RECT *client_rect)
64 memset(wf, 0, sizeof(*wf));
66 if (ex_style & WS_EX_NOACTIVATE) wf->prevents_app_activation = TRUE;
68 if (disable_window_decorations) return;
69 if (IsRectEmpty(window_rect)) return;
70 if (EqualRect(window_rect, client_rect)) return;
72 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
74 wf->shadow = TRUE;
75 if (!data->shaped)
77 wf->title_bar = TRUE;
78 if (style & WS_SYSMENU) wf->close_button = TRUE;
79 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
80 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
81 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
84 if (style & WS_THICKFRAME)
86 wf->shadow = TRUE;
87 if (!data->shaped) wf->resizable = TRUE;
89 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
90 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
94 /*******************************************************************
95 * can_window_become_foreground
97 * Check if the specified window can become the foreground/key
98 * window.
100 static inline BOOL can_window_become_foreground(HWND hwnd)
102 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
104 if (!(style & WS_VISIBLE)) return FALSE;
105 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
106 if (hwnd == GetDesktopWindow()) return FALSE;
107 return !(style & WS_DISABLED);
111 /***********************************************************************
112 * get_cocoa_window_state
114 static void get_cocoa_window_state(struct macdrv_win_data *data,
115 DWORD style, DWORD ex_style,
116 struct macdrv_window_state* state)
118 memset(state, 0, sizeof(*state));
119 state->disabled = (style & WS_DISABLED) != 0;
120 state->no_foreground = !can_window_become_foreground(data->hwnd);
121 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
122 state->excluded_by_expose = state->excluded_by_cycle =
123 (!(ex_style & WS_EX_APPWINDOW) &&
124 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
125 if (IsRectEmpty(&data->window_rect))
126 state->excluded_by_expose = TRUE;
127 state->minimized = (style & WS_MINIMIZE) != 0;
128 state->minimized_valid = state->minimized != data->minimized;
129 state->maximized = (style & WS_MAXIMIZE) != 0;
133 /***********************************************************************
134 * get_mac_rect_offset
136 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
138 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect,
139 const RECT *window_rect, const RECT *client_rect)
141 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
143 rect->top = rect->bottom = rect->left = rect->right = 0;
145 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
147 if (!data->shaped)
149 struct macdrv_window_features wf;
150 get_cocoa_window_features(data, style, ex_style, &wf, window_rect, client_rect);
152 if (wf.title_bar)
154 style_mask |= WS_CAPTION;
155 ex_style_mask |= WS_EX_TOOLWINDOW;
157 if (wf.shadow)
159 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
160 ex_style_mask |= WS_EX_DLGMODALFRAME;
164 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
166 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
167 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
171 /***********************************************************************
172 * macdrv_window_to_mac_rect
174 * Convert a rect from client to Mac window coordinates
176 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect,
177 const RECT *window_rect, const RECT *client_rect)
179 RECT rc;
181 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
182 if (IsRectEmpty(rect)) return;
184 get_mac_rect_offset(data, style, &rc, window_rect, client_rect);
186 rect->left -= rc.left;
187 rect->right -= rc.right;
188 rect->top -= rc.top;
189 rect->bottom -= rc.bottom;
190 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
191 if (rect->left >= rect->right) rect->right = rect->left + 1;
195 /***********************************************************************
196 * macdrv_mac_to_window_rect
198 * Opposite of macdrv_window_to_mac_rect
200 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
202 RECT rc;
203 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
205 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
206 if (IsRectEmpty(rect)) return;
208 get_mac_rect_offset(data, style, &rc, &data->window_rect, &data->client_rect);
210 rect->left += rc.left;
211 rect->right += rc.right;
212 rect->top += rc.top;
213 rect->bottom += rc.bottom;
214 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
215 if (rect->left >= rect->right) rect->right = rect->left + 1;
219 /***********************************************************************
220 * constrain_window_frame
222 * Alter a window frame rectangle to fit within a) Cocoa's documented
223 * limits, and b) sane sizes, like twice the desktop rect.
225 static void constrain_window_frame(CGRect* frame)
227 CGRect desktop_rect = macdrv_get_desktop_rect();
228 int max_width, max_height;
230 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
231 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
233 if (frame->origin.x < -16000) frame->origin.x = -16000;
234 if (frame->origin.y < -16000) frame->origin.y = -16000;
235 if (frame->origin.x > 16000) frame->origin.x = 16000;
236 if (frame->origin.y > 16000) frame->origin.y = 16000;
237 if (frame->size.width > max_width) frame->size.width = max_width;
238 if (frame->size.height > max_height) frame->size.height = max_height;
242 /***********************************************************************
243 * alloc_win_data
245 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
247 struct macdrv_win_data *data;
249 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
251 data->hwnd = hwnd;
252 data->color_key = CLR_INVALID;
253 data->swap_interval = 1;
254 EnterCriticalSection(&win_data_section);
255 if (!win_datas)
256 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
257 CFDictionarySetValue(win_datas, hwnd, data);
259 return data;
263 /***********************************************************************
264 * get_win_data
266 * Lock and return the data structure associated with a window.
268 struct macdrv_win_data *get_win_data(HWND hwnd)
270 struct macdrv_win_data *data;
272 if (!hwnd) return NULL;
273 EnterCriticalSection(&win_data_section);
274 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
275 return data;
276 LeaveCriticalSection(&win_data_section);
277 return NULL;
281 /***********************************************************************
282 * release_win_data
284 * Release the data returned by get_win_data.
286 void release_win_data(struct macdrv_win_data *data)
288 if (data) LeaveCriticalSection(&win_data_section);
292 /***********************************************************************
293 * macdrv_get_cocoa_window
295 * Return the Mac window associated with the full area of a window
297 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
299 struct macdrv_win_data *data = get_win_data(hwnd);
300 macdrv_window ret = NULL;
301 if (data && (data->on_screen || !require_on_screen))
302 ret = data->cocoa_window;
303 release_win_data(data);
304 return ret;
308 /***********************************************************************
309 * macdrv_get_cocoa_view
311 * Return the Cocoa view associated with a window
313 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
315 struct macdrv_win_data *data = get_win_data(hwnd);
316 macdrv_view ret = data ? data->cocoa_view : NULL;
318 release_win_data(data);
319 return ret;
323 /***********************************************************************
324 * macdrv_get_client_cocoa_view
326 * Return the Cocoa view associated with a window's client area
328 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
330 struct macdrv_win_data *data = get_win_data(hwnd);
331 macdrv_view ret = data ? data->client_cocoa_view : NULL;
333 release_win_data(data);
334 return ret;
338 /***********************************************************************
339 * set_cocoa_window_properties
341 * Set the window properties for a Cocoa window based on its Windows
342 * properties.
344 static void set_cocoa_window_properties(struct macdrv_win_data *data)
346 DWORD style, ex_style;
347 HWND owner;
348 macdrv_window owner_win;
349 struct macdrv_window_features wf;
350 struct macdrv_window_state state;
352 style = GetWindowLongW(data->hwnd, GWL_STYLE);
353 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
355 owner = GetWindow(data->hwnd, GW_OWNER);
356 if (owner)
357 owner = GetAncestor(owner, GA_ROOT);
358 owner_win = macdrv_get_cocoa_window(owner, TRUE);
359 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
361 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
362 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
364 get_cocoa_window_state(data, style, ex_style, &state);
365 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
366 if (state.minimized_valid)
367 data->minimized = state.minimized;
371 /***********************************************************************
372 * sync_window_region
374 * Update the window region.
376 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
378 HRGN hrgn = win_region;
379 RGNDATA *region_data;
380 const CGRect* rects;
381 int count;
383 if (!data->cocoa_window) return;
384 data->shaped = FALSE;
386 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
388 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
389 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
390 return;
393 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
395 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
396 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
398 DeleteObject(hrgn);
399 hrgn = 0;
403 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
404 MirrorRgn(data->hwnd, hrgn);
405 if (hrgn)
407 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
408 data->window_rect.top - data->whole_rect.top);
410 region_data = get_region_data(hrgn, 0);
411 if (region_data)
413 rects = (CGRect*)region_data->Buffer;
414 count = region_data->rdh.nCount;
415 /* Special case optimization. If the region entirely encloses the Cocoa
416 window, it's the same as there being no region. It's potentially
417 hard/slow to test this for arbitrary regions, so we just check for
418 very simple regions. */
419 if (count == 1 && CGRectContainsRect(rects[0],
420 CGRectOffset(cgrect_from_rect(data->whole_rect), -data->whole_rect.left, -data->whole_rect.top)))
422 TRACE("optimizing for simple region that contains Cocoa content rect\n");
423 rects = NULL;
424 count = 0;
427 else
429 rects = NULL;
430 count = 0;
433 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
434 macdrv_set_window_shape(data->cocoa_window, rects, count);
436 HeapFree(GetProcessHeap(), 0, region_data);
437 data->shaped = (region_data != NULL);
439 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
443 /***********************************************************************
444 * add_bounds_rect
446 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
448 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
449 bounds->left = min(bounds->left, rect->left);
450 bounds->top = min(bounds->top, rect->top);
451 bounds->right = max(bounds->right, rect->right);
452 bounds->bottom = max(bounds->bottom, rect->bottom);
456 /***********************************************************************
457 * sync_window_opacity
459 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
460 BOOL per_pixel_alpha, DWORD flags)
462 CGFloat opacity = 1.0;
463 BOOL needs_flush = FALSE;
465 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
467 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
468 macdrv_set_window_alpha(data->cocoa_window, opacity);
470 if (flags & LWA_COLORKEY)
472 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
473 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
474 key = RGB(0, 0, 0);
476 else
477 key = CLR_INVALID;
479 if (data->color_key != key)
481 if (key == CLR_INVALID)
483 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
484 macdrv_clear_window_color_key(data->cocoa_window);
486 else
488 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
489 GetRValue(key), GetGValue(key), GetBValue(key));
490 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
493 data->color_key = key;
494 needs_flush = TRUE;
497 if (!data->per_pixel_alpha != !per_pixel_alpha)
499 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
500 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
501 data->per_pixel_alpha = per_pixel_alpha;
502 needs_flush = TRUE;
505 if (needs_flush && data->surface)
507 RECT *bounds;
508 RECT rect;
510 rect = data->whole_rect;
511 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
512 data->surface->funcs->lock(data->surface);
513 bounds = data->surface->funcs->get_bounds(data->surface);
514 add_bounds_rect(bounds, &rect);
515 data->surface->funcs->unlock(data->surface);
520 /***********************************************************************
521 * sync_window_min_max_info
523 static void sync_window_min_max_info(HWND hwnd)
525 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
526 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
527 RECT win_rect, primary_monitor_rect;
528 MINMAXINFO minmax;
529 LONG adjustedStyle;
530 INT xinc, yinc;
531 WINDOWPLACEMENT wpl;
532 HMONITOR monitor;
533 struct macdrv_win_data *data;
535 TRACE("win %p\n", hwnd);
537 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
539 GetWindowRect(hwnd, &win_rect);
540 minmax.ptReserved.x = win_rect.left;
541 minmax.ptReserved.y = win_rect.top;
543 if ((style & WS_CAPTION) == WS_CAPTION)
544 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
545 else
546 adjustedStyle = style;
548 primary_monitor_rect.left = primary_monitor_rect.top = 0;
549 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
550 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
551 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
553 xinc = -primary_monitor_rect.left;
554 yinc = -primary_monitor_rect.top;
556 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
557 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
558 minmax.ptMaxPosition.x = -xinc;
559 minmax.ptMaxPosition.y = -yinc;
560 if (style & (WS_DLGFRAME | WS_BORDER))
562 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
563 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
565 else
567 minmax.ptMinTrackSize.x = 2 * xinc;
568 minmax.ptMinTrackSize.y = 2 * yinc;
570 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
571 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
573 wpl.length = sizeof(wpl);
574 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
576 minmax.ptMaxPosition = wpl.ptMaxPosition;
578 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
579 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
580 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
583 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
584 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
586 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
588 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
589 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
591 /* if the app didn't change the values, adapt them for the window's monitor */
592 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
594 MONITORINFO mon_info;
595 RECT monitor_rect;
597 mon_info.cbSize = sizeof(mon_info);
598 GetMonitorInfoW(monitor, &mon_info);
600 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
601 monitor_rect = mon_info.rcWork;
602 else
603 monitor_rect = mon_info.rcMonitor;
605 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
606 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
608 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
609 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
611 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
613 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
614 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
618 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
619 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
621 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
622 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
624 if ((data = get_win_data(hwnd)) && data->cocoa_window)
626 RECT min_rect, max_rect;
627 CGSize min_size, max_size;
629 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
630 macdrv_window_to_mac_rect(data, style, &min_rect, &data->window_rect, &data->client_rect);
631 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
633 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
634 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
635 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
636 else
638 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
639 macdrv_window_to_mac_rect(data, style, &max_rect, &data->window_rect, &data->client_rect);
640 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
643 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
644 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
647 release_win_data(data);
651 /**********************************************************************
652 * create_client_cocoa_view
654 * Create the Cocoa view for a window's client area
656 static void create_client_cocoa_view(struct macdrv_win_data *data)
658 RECT rect = data->client_rect;
659 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
661 if (data->client_cocoa_view)
662 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
663 else
665 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
666 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
668 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
672 /**********************************************************************
673 * create_cocoa_window
675 * Create the whole Mac window for a given window
677 static void create_cocoa_window(struct macdrv_win_data *data)
679 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
680 WCHAR text[1024];
681 struct macdrv_window_features wf;
682 CGRect frame;
683 DWORD style, ex_style;
684 HRGN win_rgn;
685 COLORREF key;
686 BYTE alpha;
687 DWORD layered_flags;
689 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
690 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
692 DeleteObject(win_rgn);
693 win_rgn = 0;
695 data->shaped = (win_rgn != 0);
697 style = GetWindowLongW(data->hwnd, GWL_STYLE);
698 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
700 data->whole_rect = data->window_rect;
701 macdrv_window_to_mac_rect(data, style, &data->whole_rect, &data->window_rect, &data->client_rect);
703 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
705 frame = cgrect_from_rect(data->whole_rect);
706 constrain_window_frame(&frame);
707 if (frame.size.width < 1 || frame.size.height < 1)
708 frame.size.width = frame.size.height = 1;
710 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
711 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
713 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
714 if (!data->cocoa_window) goto done;
715 create_client_cocoa_view(data);
717 set_cocoa_window_properties(data);
719 /* set the window text */
720 if (!InternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) text[0] = 0;
721 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
723 /* set the window region */
724 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
726 /* set the window opacity */
727 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
728 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
730 done:
731 if (win_rgn) DeleteObject(win_rgn);
735 /**********************************************************************
736 * destroy_cocoa_window
738 * Destroy the whole Mac window for a given window.
740 static void destroy_cocoa_window(struct macdrv_win_data *data)
742 if (!data->cocoa_window) return;
744 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
746 macdrv_destroy_cocoa_window(data->cocoa_window);
747 data->cocoa_window = 0;
748 data->on_screen = FALSE;
749 data->color_key = CLR_INVALID;
750 if (data->surface) window_surface_release(data->surface);
751 data->surface = NULL;
752 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
753 data->unminimized_surface = NULL;
757 /**********************************************************************
758 * create_cocoa_view
760 * Create the Cocoa view for a given Windows child window
762 static void create_cocoa_view(struct macdrv_win_data *data)
764 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
765 CGRect frame = cgrect_from_rect(data->window_rect);
767 data->shaped = FALSE;
768 data->whole_rect = data->window_rect;
770 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
771 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
773 if (!equal)
774 data->cocoa_view = macdrv_create_view(frame);
775 create_client_cocoa_view(data);
776 if (equal)
778 data->cocoa_view = data->client_cocoa_view;
779 macdrv_set_view_hidden(data->cocoa_view, TRUE);
780 macdrv_set_view_frame(data->cocoa_view, frame);
785 /**********************************************************************
786 * destroy_cocoa_view
788 * Destroy the Cocoa view for a given window.
790 static void destroy_cocoa_view(struct macdrv_win_data *data)
792 if (!data->cocoa_view) return;
794 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
796 if (data->cocoa_view != data->client_cocoa_view)
797 macdrv_dispose_view(data->cocoa_view);
798 data->cocoa_view = NULL;
799 data->on_screen = FALSE;
803 /***********************************************************************
804 * set_cocoa_view_parent
806 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
808 struct macdrv_win_data *parent_data = get_win_data(parent);
809 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
810 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
812 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
814 if (!cocoa_window && !superview)
815 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
817 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
818 release_win_data(parent_data);
822 /***********************************************************************
823 * macdrv_create_win_data
825 * Create a Mac data window structure for an existing window.
827 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
828 const RECT *client_rect)
830 struct macdrv_win_data *data;
831 HWND parent;
833 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
835 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
837 macdrv_init_thread_data();
838 return NULL;
841 /* don't create win data for HWND_MESSAGE windows */
842 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
844 if (!(data = alloc_win_data(hwnd))) return NULL;
846 data->whole_rect = data->window_rect = *window_rect;
847 data->client_rect = *client_rect;
849 if (parent == GetDesktopWindow())
851 create_cocoa_window(data);
852 TRACE("win %p/%p window %s whole %s client %s\n",
853 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
854 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
856 else
858 create_cocoa_view(data);
859 TRACE("win %p/%p window %s whole %s client %s\n",
860 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
861 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
863 set_cocoa_view_parent(data, parent);
866 return data;
870 /**********************************************************************
871 * is_owned_by
873 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
875 while (1)
877 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
878 if (!hwnd2)
879 hwnd2 = GetAncestor(hwnd, GA_ROOT);
880 if (!hwnd2 || hwnd2 == hwnd)
881 break;
882 if (hwnd2 == maybe_owner)
883 return TRUE;
884 hwnd = hwnd2;
887 return FALSE;
891 /**********************************************************************
892 * is_all_the_way_front
894 static BOOL is_all_the_way_front(HWND hwnd)
896 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
897 HWND prev = hwnd;
899 while ((prev = GetWindow(prev, GW_HWNDPREV)))
901 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
902 return TRUE;
903 if (!is_owned_by(prev, hwnd))
904 return FALSE;
907 return TRUE;
911 /***********************************************************************
912 * set_focus
914 static void set_focus(HWND hwnd, BOOL raise)
916 struct macdrv_win_data *data;
918 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
920 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
921 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
923 if (!(data = get_win_data(hwnd))) return;
925 if (data->cocoa_window && data->on_screen)
927 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
928 /* Set Mac focus */
929 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
930 activate_on_focus_time = 0;
933 release_win_data(data);
936 /***********************************************************************
937 * show_window
939 static void show_window(struct macdrv_win_data *data)
941 if (data->cocoa_window)
943 HWND prev = NULL;
944 HWND next = NULL;
945 macdrv_window prev_window = NULL;
946 macdrv_window next_window = NULL;
947 BOOL activate = FALSE;
948 GUITHREADINFO info;
950 /* find window that this one must be after */
951 prev = GetWindow(data->hwnd, GW_HWNDPREV);
952 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
953 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
954 prev = GetWindow(prev, GW_HWNDPREV);
955 if (!prev_window)
957 /* find window that this one must be before */
958 next = GetWindow(data->hwnd, GW_HWNDNEXT);
959 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
960 (next_window = macdrv_get_cocoa_window(next, TRUE))))
961 next = GetWindow(next, GW_HWNDNEXT);
964 TRACE("win %p/%p below %p/%p above %p/%p\n",
965 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
967 if (!prev_window)
968 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
969 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
970 data->on_screen = TRUE;
972 info.cbSize = sizeof(info);
973 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
974 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
975 set_focus(info.hwndFocus, FALSE);
976 if (activate)
977 activate_on_focus_time = 0;
979 else
981 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
983 macdrv_set_view_hidden(data->cocoa_view, FALSE);
984 data->on_screen = TRUE;
989 /***********************************************************************
990 * hide_window
992 static void hide_window(struct macdrv_win_data *data)
994 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
996 if (data->cocoa_window)
997 macdrv_hide_cocoa_window(data->cocoa_window);
998 else
999 macdrv_set_view_hidden(data->cocoa_view, TRUE);
1000 data->on_screen = FALSE;
1004 /***********************************************************************
1005 * sync_window_z_order
1007 static void sync_window_z_order(struct macdrv_win_data *data)
1009 if (data->cocoa_view)
1011 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
1012 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
1013 macdrv_window window = NULL;
1014 HWND prev;
1015 HWND next = NULL;
1016 macdrv_view prev_view = NULL;
1017 macdrv_view next_view = NULL;
1019 if (!superview)
1021 window = macdrv_get_cocoa_window(parent, FALSE);
1022 if (!window)
1023 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1026 /* find window that this one must be after */
1027 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1028 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1029 prev = GetWindow(prev, GW_HWNDPREV);
1030 if (!prev_view)
1032 /* find window that this one must be before */
1033 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1034 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1035 next = GetWindow(next, GW_HWNDNEXT);
1038 TRACE("win %p/%p below %p/%p above %p/%p\n",
1039 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1041 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1043 else if (data->on_screen)
1044 show_window(data);
1048 /***********************************************************************
1049 * get_region_data
1051 * Calls GetRegionData on the given region and converts the rectangle
1052 * array to CGRect format. The returned buffer must be freed by
1053 * caller using HeapFree(GetProcessHeap(),...).
1054 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1056 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1058 RGNDATA *data;
1059 DWORD size;
1060 int i;
1061 RECT *rect;
1062 CGRect *cgrect;
1064 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
1065 if (sizeof(CGRect) > sizeof(RECT))
1067 /* add extra size for CGRect array */
1068 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1069 size += count * (sizeof(CGRect) - sizeof(RECT));
1071 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1072 if (!GetRegionData(hrgn, size, data))
1074 HeapFree(GetProcessHeap(), 0, data);
1075 return NULL;
1078 rect = (RECT *)data->Buffer;
1079 cgrect = (CGRect *)data->Buffer;
1080 if (hdc_lptodp) /* map to device coordinates */
1082 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1083 for (i = 0; i < data->rdh.nCount; i++)
1085 if (rect[i].right < rect[i].left)
1087 INT tmp = rect[i].right;
1088 rect[i].right = rect[i].left;
1089 rect[i].left = tmp;
1091 if (rect[i].bottom < rect[i].top)
1093 INT tmp = rect[i].bottom;
1094 rect[i].bottom = rect[i].top;
1095 rect[i].top = tmp;
1100 if (sizeof(CGRect) > sizeof(RECT))
1102 /* need to start from the end */
1103 for (i = data->rdh.nCount-1; i >= 0; i--)
1104 cgrect[i] = cgrect_from_rect(rect[i]);
1106 else
1108 for (i = 0; i < data->rdh.nCount; i++)
1109 cgrect[i] = cgrect_from_rect(rect[i]);
1111 return data;
1115 /***********************************************************************
1116 * sync_client_view_position
1118 static void sync_client_view_position(struct macdrv_win_data *data)
1120 if (data->cocoa_view != data->client_cocoa_view)
1122 RECT rect = data->client_rect;
1123 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1124 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1125 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1130 /***********************************************************************
1131 * sync_window_position
1133 * Synchronize the Mac window position with the Windows one
1135 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1136 const RECT *old_whole_rect)
1138 CGRect frame = cgrect_from_rect(data->whole_rect);
1139 BOOL force_z_order = FALSE;
1141 if (data->cocoa_window)
1143 if (data->minimized) return;
1145 constrain_window_frame(&frame);
1146 if (frame.size.width < 1 || frame.size.height < 1)
1147 frame.size.width = frame.size.height = 1;
1149 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1151 else
1153 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1154 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1156 if (were_equal && !now_equal)
1158 data->cocoa_view = macdrv_create_view(frame);
1159 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1160 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1161 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1162 force_z_order = TRUE;
1164 else if (!were_equal && now_equal)
1166 macdrv_dispose_view(data->cocoa_view);
1167 data->cocoa_view = data->client_cocoa_view;
1168 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1169 macdrv_set_view_frame(data->cocoa_view, frame);
1170 force_z_order = TRUE;
1172 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1173 macdrv_set_view_frame(data->cocoa_view, frame);
1176 sync_client_view_position(data);
1178 if (old_window_rect && old_whole_rect &&
1179 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1180 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1181 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1182 sync_window_region(data, (HRGN)1);
1184 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1185 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1186 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1188 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1189 sync_window_z_order(data);
1193 /***********************************************************************
1194 * move_window_bits
1196 * Move the window bits when a window is moved.
1198 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1199 const RECT *old_client_rect, const RECT *new_client_rect,
1200 const RECT *new_window_rect)
1202 RECT src_rect = *old_rect;
1203 RECT dst_rect = *new_rect;
1204 HDC hdc_src, hdc_dst;
1205 HRGN rgn;
1206 HWND parent = 0;
1208 if (!window)
1210 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1211 parent = GetAncestor(hwnd, GA_PARENT);
1212 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1213 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1215 else
1217 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1218 /* make src rect relative to the old position of the window */
1219 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1220 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1221 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1224 rgn = CreateRectRgnIndirect(&dst_rect);
1225 SelectClipRgn(hdc_dst, rgn);
1226 DeleteObject(rgn);
1227 ExcludeUpdateRgn(hdc_dst, hwnd);
1229 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1230 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1231 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1232 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1233 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1235 ReleaseDC(hwnd, hdc_dst);
1236 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1240 /**********************************************************************
1241 * activate_on_following_focus
1243 void activate_on_following_focus(void)
1245 activate_on_focus_time = GetTickCount();
1246 if (!activate_on_focus_time) activate_on_focus_time = 1;
1250 /***********************************************************************
1251 * set_app_icon
1253 static void set_app_icon(void)
1255 CFArrayRef images = create_app_icon_images();
1256 if (images)
1258 macdrv_set_application_icon(images);
1259 CFRelease(images);
1264 /**********************************************************************
1265 * set_capture_window_for_move
1267 static BOOL set_capture_window_for_move(HWND hwnd)
1269 HWND previous = 0;
1270 BOOL ret;
1272 SERVER_START_REQ(set_capture_window)
1274 req->handle = wine_server_user_handle(hwnd);
1275 req->flags = CAPTURE_MOVESIZE;
1276 if ((ret = !wine_server_call_err(req)))
1278 previous = wine_server_ptr_handle(reply->previous);
1279 hwnd = wine_server_ptr_handle(reply->full_handle);
1282 SERVER_END_REQ;
1284 if (ret)
1286 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1288 if (previous && previous != hwnd)
1289 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1291 return ret;
1295 /***********************************************************************
1296 * move_window
1298 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1299 * moving top-level windows and enforcing Mac-style constraints like
1300 * keeping the top of the window within the work area.
1302 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1304 MSG msg;
1305 RECT origRect, movedRect, desktopRect;
1306 LONG hittest = (LONG)(wparam & 0x0f);
1307 POINT capturePoint;
1308 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1309 BOOL moved = FALSE;
1310 DWORD dwPoint = GetMessagePos();
1311 INT captionHeight;
1312 HMONITOR mon = 0;
1313 MONITORINFO info;
1315 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1316 if (hittest && hittest != HTCAPTION) return -1;
1318 capturePoint.x = (short)LOWORD(dwPoint);
1319 capturePoint.y = (short)HIWORD(dwPoint);
1320 ClipCursor(NULL);
1322 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1324 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1325 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1326 captionHeight = -origRect.top;
1327 else
1328 captionHeight = 0;
1330 GetWindowRect(hwnd, &origRect);
1331 movedRect = origRect;
1333 if (!hittest)
1335 /* Move pointer to the center of the caption */
1336 RECT rect = origRect;
1338 /* Note: to be exactly centered we should take the different types
1339 * of border into account, but it shouldn't make more than a few pixels
1340 * of difference so let's not bother with that */
1341 rect.top += GetSystemMetrics(SM_CYBORDER);
1342 if (style & WS_SYSMENU)
1343 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1344 if (style & WS_MINIMIZEBOX)
1345 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1346 if (style & WS_MAXIMIZEBOX)
1347 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1348 capturePoint.x = (rect.right + rect.left) / 2;
1349 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1351 SetCursorPos(capturePoint.x, capturePoint.y);
1352 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1355 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1356 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1357 info.cbSize = sizeof(info);
1358 if (mon && !GetMonitorInfoW(mon, &info))
1359 mon = 0;
1361 /* repaint the window before moving it around */
1362 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1364 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1365 set_capture_window_for_move(hwnd);
1367 while(1)
1369 POINT pt;
1370 int dx = 0, dy = 0;
1371 HMONITOR newmon;
1373 if (!GetMessageW(&msg, 0, 0, 0)) break;
1374 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1376 /* Exit on button-up, Return, or Esc */
1377 if (msg.message == WM_LBUTTONUP ||
1378 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1379 break;
1381 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1383 TranslateMessage(&msg);
1384 DispatchMessageW(&msg);
1385 continue; /* We are not interested in other messages */
1388 pt = msg.pt;
1390 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1392 case VK_UP: pt.y -= 8; break;
1393 case VK_DOWN: pt.y += 8; break;
1394 case VK_LEFT: pt.x -= 8; break;
1395 case VK_RIGHT: pt.x += 8; break;
1398 pt.x = max(pt.x, desktopRect.left);
1399 pt.x = min(pt.x, desktopRect.right - 1);
1400 pt.y = max(pt.y, desktopRect.top);
1401 pt.y = min(pt.y, desktopRect.bottom - 1);
1403 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1405 if (GetMonitorInfoW(newmon, &info))
1406 mon = newmon;
1407 else
1408 mon = 0;
1411 if (mon)
1413 /* wineserver clips the cursor position to the virtual desktop rect but,
1414 if the display configuration is non-rectangular, that could still
1415 leave the logical cursor position outside of any display. The window
1416 could keep moving as you push the cursor against a display edge, even
1417 though the visible cursor doesn't keep moving. The following keeps
1418 the window movement in sync with the visible cursor. */
1419 pt.x = max(pt.x, info.rcMonitor.left);
1420 pt.x = min(pt.x, info.rcMonitor.right - 1);
1421 pt.y = max(pt.y, info.rcMonitor.top);
1422 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1424 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1425 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1426 we want to enforce these constraints:
1427 movedRect.left + dx < info.rcWork.right
1428 movedRect.right + dx > info.rcWork.left
1429 movedRect.top + captionHeight + dy < info.rcWork.bottom
1430 movedRect.bottom + dy > info.rcWork.top
1431 movedRect.top + dy >= info.rcWork.top
1432 The first four keep at least one edge barely in the work area.
1433 The last keeps the top (i.e. the title bar) in the work area.
1434 The fourth is redundant with the last, so can be ignored.
1436 Substituting for dx and dy and rearranging gives us...
1438 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1439 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1440 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1441 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1444 dx = pt.x - capturePoint.x;
1445 dy = pt.y - capturePoint.y;
1447 if (dx || dy)
1449 moved = TRUE;
1451 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1452 else
1454 OffsetRect(&movedRect, dx, dy);
1455 capturePoint = pt;
1457 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1458 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1459 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1464 set_capture_window_for_move(0);
1466 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1467 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1469 /* if the move is canceled, restore the previous position */
1470 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1472 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1473 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1476 return 0;
1480 /***********************************************************************
1481 * perform_window_command
1483 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1485 DWORD style;
1487 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1488 hwnd, style_any, style_none, command, hittest);
1490 style = GetWindowLongW(hwnd, GWL_STYLE);
1491 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1493 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1494 return;
1497 if (GetActiveWindow() != hwnd)
1499 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1500 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1501 switch (ma)
1503 case MA_NOACTIVATEANDEAT:
1504 case MA_ACTIVATEANDEAT:
1505 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1506 return;
1507 case MA_NOACTIVATE:
1508 break;
1509 case MA_ACTIVATE:
1510 case 0:
1511 SetActiveWindow(hwnd);
1512 break;
1513 default:
1514 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1515 break;
1519 TRACE("changing win %p\n", hwnd);
1520 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1524 /**********************************************************************
1525 * CreateDesktopWindow (MACDRV.@)
1527 BOOL macdrv_CreateDesktopWindow(HWND hwnd)
1529 unsigned int width, height;
1531 TRACE("%p\n", hwnd);
1533 /* retrieve the real size of the desktop */
1534 SERVER_START_REQ(get_window_rectangles)
1536 req->handle = wine_server_user_handle(hwnd);
1537 req->relative = COORDS_CLIENT;
1538 wine_server_call(req);
1539 width = reply->window.right;
1540 height = reply->window.bottom;
1542 SERVER_END_REQ;
1544 if (!width && !height) /* not initialized yet */
1546 CGRect rect = macdrv_get_desktop_rect();
1548 SERVER_START_REQ(set_window_pos)
1550 req->handle = wine_server_user_handle(hwnd);
1551 req->previous = 0;
1552 req->swp_flags = SWP_NOZORDER;
1553 req->window.left = CGRectGetMinX(rect);
1554 req->window.top = CGRectGetMinY(rect);
1555 req->window.right = CGRectGetMaxX(rect);
1556 req->window.bottom = CGRectGetMaxY(rect);
1557 req->client = req->window;
1558 wine_server_call(req);
1560 SERVER_END_REQ;
1563 set_app_icon();
1564 return TRUE;
1568 static WNDPROC desktop_orig_wndproc;
1570 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
1572 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1574 switch (msg)
1576 case WM_WINE_NOTIFY_ACTIVITY:
1578 /* This wakes from display sleep, but doesn't affect the screen saver. */
1579 static IOPMAssertionID assertion;
1580 IOPMAssertionDeclareUserActivity(CFSTR("Wine user input"), kIOPMUserActiveLocal, &assertion);
1582 /* This prevents the screen saver, but doesn't wake from display sleep. */
1583 /* It's deprecated, but there's no better alternative. */
1584 #pragma clang diagnostic push
1585 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1586 UpdateSystemActivity(UsrActivity);
1587 #pragma clang diagnostic pop
1588 break;
1591 return desktop_orig_wndproc( hwnd, msg, wp, lp );
1594 /**********************************************************************
1595 * CreateWindow (MACDRV.@)
1597 BOOL macdrv_CreateWindow(HWND hwnd)
1599 if (hwnd == GetDesktopWindow())
1601 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( GetDesktopWindow(),
1602 GWLP_WNDPROC, (LONG_PTR)desktop_wndproc_wrapper );
1604 macdrv_init_clipboard();
1606 return TRUE;
1610 /***********************************************************************
1611 * DestroyWindow (MACDRV.@)
1613 void macdrv_DestroyWindow(HWND hwnd)
1615 struct macdrv_win_data *data;
1617 TRACE("%p\n", hwnd);
1619 if (!(data = get_win_data(hwnd))) return;
1621 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1622 if (data->drag_event) SetEvent(data->drag_event);
1624 destroy_cocoa_window(data);
1625 destroy_cocoa_view(data);
1626 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1628 CFDictionaryRemoveValue(win_datas, hwnd);
1629 release_win_data(data);
1630 HeapFree(GetProcessHeap(), 0, data);
1634 /*****************************************************************
1635 * SetFocus (MACDRV.@)
1637 * Set the Mac focus.
1639 void macdrv_SetFocus(HWND hwnd)
1641 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1643 TRACE("%p\n", hwnd);
1645 if (!thread_data) return;
1646 thread_data->dead_key_state = 0;
1647 set_focus(hwnd, TRUE);
1651 /***********************************************************************
1652 * SetLayeredWindowAttributes (MACDRV.@)
1654 * Set transparency attributes for a layered window.
1656 void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1658 struct macdrv_win_data *data = get_win_data(hwnd);
1660 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1662 if (data)
1664 data->layered = TRUE;
1665 data->ulw_layered = FALSE;
1666 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1667 if (data->cocoa_window)
1669 sync_window_opacity(data, key, alpha, FALSE, flags);
1670 /* since layered attributes are now set, can now show the window */
1671 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1672 show_window(data);
1674 release_win_data(data);
1676 else
1677 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1681 /*****************************************************************
1682 * SetParent (MACDRV.@)
1684 void macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1686 struct macdrv_win_data *data;
1688 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1690 if (parent == old_parent) return;
1691 if (!(data = get_win_data(hwnd))) return;
1693 if (parent != GetDesktopWindow()) /* a child window */
1695 if (old_parent == GetDesktopWindow())
1697 /* destroy the old Mac window */
1698 destroy_cocoa_window(data);
1699 create_cocoa_view(data);
1702 set_cocoa_view_parent(data, parent);
1704 else /* new top level window */
1706 destroy_cocoa_view(data);
1707 create_cocoa_window(data);
1709 release_win_data(data);
1713 /***********************************************************************
1714 * SetWindowRgn (MACDRV.@)
1716 * Assign specified region to window (for non-rectangular windows)
1718 void macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1720 struct macdrv_win_data *data;
1722 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1724 if ((data = get_win_data(hwnd)))
1726 sync_window_region(data, hrgn);
1727 release_win_data(data);
1729 else
1731 DWORD procid;
1733 GetWindowThreadProcessId(hwnd, &procid);
1734 if (procid != GetCurrentProcessId())
1735 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1740 /***********************************************************************
1741 * SetWindowStyle (MACDRV.@)
1743 * Update the state of the Cocoa window to reflect a style change
1745 void macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1747 struct macdrv_win_data *data;
1749 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1751 if (hwnd == GetDesktopWindow()) return;
1752 if (!(data = get_win_data(hwnd))) return;
1754 if (data->cocoa_window)
1756 DWORD changed = style->styleNew ^ style->styleOld;
1758 set_cocoa_window_properties(data);
1760 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1762 data->layered = FALSE;
1763 data->ulw_layered = FALSE;
1764 sync_window_opacity(data, 0, 0, FALSE, 0);
1765 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1768 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1769 sync_window_region(data, (HRGN)1);
1772 release_win_data(data);
1776 /*****************************************************************
1777 * SetWindowText (MACDRV.@)
1779 void macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1781 macdrv_window win;
1783 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1785 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1786 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1790 /***********************************************************************
1791 * ShowWindow (MACDRV.@)
1793 UINT macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1795 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1796 struct macdrv_win_data *data = get_win_data(hwnd);
1797 CGRect frame;
1799 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1800 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1802 if (!data || !data->cocoa_window) goto done;
1803 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1805 if (rect->left != -32000 || rect->top != -32000)
1807 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1808 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1810 goto done;
1812 if (!data->on_screen) goto done;
1814 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1816 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1817 goto done;
1819 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1820 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1821 goto done;
1823 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1824 *rect = rect_from_cgrect(frame);
1825 macdrv_mac_to_window_rect(data, rect);
1826 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1827 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1829 done:
1830 release_win_data(data);
1831 return swp;
1835 /***********************************************************************
1836 * SysCommand (MACDRV.@)
1838 * Perform WM_SYSCOMMAND handling.
1840 LRESULT macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1842 struct macdrv_win_data *data;
1843 LRESULT ret = -1;
1844 WPARAM command = wparam & 0xfff0;
1846 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1848 if (!(data = get_win_data(hwnd))) goto done;
1849 if (!data->cocoa_window || !data->on_screen) goto done;
1851 /* prevent a simple ALT press+release from activating the system menu,
1852 as that can get confusing */
1853 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1854 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1856 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1857 ret = 0;
1860 if (command == SC_MOVE)
1862 release_win_data(data);
1863 return move_window(hwnd, wparam);
1866 done:
1867 release_win_data(data);
1868 return ret;
1872 /***********************************************************************
1873 * UpdateLayeredWindow (MACDRV.@)
1875 BOOL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1876 const RECT *window_rect)
1878 struct window_surface *surface;
1879 struct macdrv_win_data *data;
1880 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1881 BYTE alpha;
1882 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1883 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1884 void *src_bits, *dst_bits;
1885 RECT rect, src_rect;
1886 HDC hdc = 0;
1887 HBITMAP dib;
1888 BOOL ret = FALSE;
1890 if (!(data = get_win_data(hwnd))) return FALSE;
1892 data->layered = TRUE;
1893 data->ulw_layered = TRUE;
1895 rect = *window_rect;
1896 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1898 surface = data->surface;
1899 if (!surface || !EqualRect(&surface->rect, &rect))
1901 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1902 set_window_surface(data->cocoa_window, data->surface);
1903 if (surface) window_surface_release(surface);
1904 surface = data->surface;
1905 if (data->unminimized_surface)
1907 window_surface_release(data->unminimized_surface);
1908 data->unminimized_surface = NULL;
1911 else set_surface_use_alpha(surface, TRUE);
1913 if (surface) window_surface_add_ref(surface);
1914 release_win_data(data);
1916 if (!surface) return FALSE;
1917 if (!info->hdcSrc)
1919 window_surface_release(surface);
1920 return TRUE;
1923 if (info->dwFlags & ULW_ALPHA)
1925 /* Apply SourceConstantAlpha via window alpha, not blend. */
1926 alpha = info->pblend->SourceConstantAlpha;
1927 blend = *info->pblend;
1928 blend.SourceConstantAlpha = 0xff;
1930 else
1931 alpha = 0xff;
1933 dst_bits = surface->funcs->get_info(surface, bmi);
1935 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1936 if (!(hdc = CreateCompatibleDC(0))) goto done;
1938 SelectObject(hdc, dib);
1939 if (info->prcDirty)
1941 IntersectRect(&rect, &rect, info->prcDirty);
1942 surface->funcs->lock(surface);
1943 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1944 surface->funcs->unlock(surface);
1945 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1947 src_rect = rect;
1948 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1949 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1951 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1952 info->hdcSrc, src_rect.left, src_rect.top,
1953 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1954 blend)))
1955 goto done;
1957 if ((data = get_win_data(hwnd)))
1959 if (surface == data->surface)
1961 surface->funcs->lock(surface);
1962 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1963 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1964 surface->funcs->unlock(surface);
1965 surface->funcs->flush(surface);
1968 /* The ULW flags are a superset of the LWA flags. */
1969 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1971 release_win_data(data);
1974 done:
1975 window_surface_release(surface);
1976 if (hdc) DeleteDC(hdc);
1977 if (dib) DeleteObject(dib);
1978 return ret;
1982 /**********************************************************************
1983 * WindowMessage (MACDRV.@)
1985 LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1987 struct macdrv_win_data *data;
1989 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1991 switch(msg)
1993 case WM_MACDRV_SET_WIN_REGION:
1994 if ((data = get_win_data(hwnd)))
1996 sync_window_region(data, (HRGN)1);
1997 release_win_data(data);
1999 return 0;
2000 case WM_MACDRV_UPDATE_DESKTOP_RECT:
2001 if (hwnd == GetDesktopWindow())
2003 CGRect new_desktop_rect;
2004 RECT current_desktop_rect;
2006 macdrv_reset_device_metrics();
2007 new_desktop_rect = macdrv_get_desktop_rect();
2008 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
2009 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
2011 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
2012 SMTO_ABORTIFHUNG, 2000, NULL);
2013 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
2014 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
2015 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
2016 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
2017 SMTO_ABORTIFHUNG, 2000, NULL);
2020 return 0;
2021 case WM_MACDRV_RESET_DEVICE_METRICS:
2022 macdrv_reset_device_metrics();
2023 return 0;
2024 case WM_MACDRV_DISPLAYCHANGE:
2025 macdrv_reassert_window_position(hwnd);
2026 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
2027 return 0;
2028 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
2029 activate_on_following_focus();
2030 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
2031 return 0;
2034 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
2035 return 0;
2039 static inline RECT get_surface_rect(const RECT *visible_rect)
2041 RECT rect;
2042 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
2044 IntersectRect(&rect, visible_rect, &desktop_rect);
2045 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2046 rect.left &= ~127;
2047 rect.top &= ~127;
2048 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2049 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2050 return rect;
2054 /***********************************************************************
2055 * WindowPosChanging (MACDRV.@)
2057 BOOL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2058 const RECT *window_rect, const RECT *client_rect,
2059 RECT *visible_rect, struct window_surface **surface)
2061 struct macdrv_win_data *data = get_win_data(hwnd);
2062 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2063 RECT surface_rect;
2065 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2066 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2067 wine_dbgstr_rect(visible_rect), surface);
2069 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return TRUE;
2071 *visible_rect = *window_rect;
2072 macdrv_window_to_mac_rect(data, style, visible_rect, window_rect, client_rect);
2073 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2074 wine_dbgstr_rect(visible_rect));
2076 /* create the window surface if necessary */
2077 if (!data->cocoa_window) goto done;
2078 if (swp_flags & SWP_HIDEWINDOW) goto done;
2079 if (data->ulw_layered) goto done;
2081 if (*surface) window_surface_release(*surface);
2082 *surface = NULL;
2084 surface_rect = get_surface_rect(visible_rect);
2085 if (data->surface)
2087 if (EqualRect(&data->surface->rect, &surface_rect))
2089 /* existing surface is good enough */
2090 surface_clip_to_visible_rect(data->surface, visible_rect);
2091 window_surface_add_ref(data->surface);
2092 *surface = data->surface;
2093 goto done;
2096 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2098 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2100 done:
2101 release_win_data(data);
2102 return TRUE;
2106 /***********************************************************************
2107 * WindowPosChanged (MACDRV.@)
2109 void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2110 const RECT *window_rect, const RECT *client_rect,
2111 const RECT *visible_rect, const RECT *valid_rects,
2112 struct window_surface *surface)
2114 struct macdrv_thread_data *thread_data;
2115 struct macdrv_win_data *data;
2116 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2117 RECT old_window_rect, old_whole_rect, old_client_rect;
2119 if (!(data = get_win_data(hwnd))) return;
2121 thread_data = macdrv_thread_data();
2123 old_window_rect = data->window_rect;
2124 old_whole_rect = data->whole_rect;
2125 old_client_rect = data->client_rect;
2126 data->window_rect = *window_rect;
2127 data->whole_rect = *visible_rect;
2128 data->client_rect = *client_rect;
2129 if (data->cocoa_window && !data->ulw_layered)
2131 if (surface) window_surface_add_ref(surface);
2132 if (new_style & WS_MINIMIZE)
2134 if (!data->unminimized_surface && data->surface)
2136 data->unminimized_surface = data->surface;
2137 window_surface_add_ref(data->unminimized_surface);
2140 else
2142 set_window_surface(data->cocoa_window, surface);
2143 if (data->unminimized_surface)
2145 window_surface_release(data->unminimized_surface);
2146 data->unminimized_surface = NULL;
2149 if (data->surface) window_surface_release(data->surface);
2150 data->surface = surface;
2153 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2154 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2155 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2156 new_style, swp_flags, surface);
2158 if (!IsRectEmpty(&valid_rects[0]))
2160 macdrv_window window = data->cocoa_window;
2161 int x_offset = old_whole_rect.left - data->whole_rect.left;
2162 int y_offset = old_whole_rect.top - data->whole_rect.top;
2164 /* if all that happened is that the whole window moved, copy everything */
2165 if (!(swp_flags & SWP_FRAMECHANGED) &&
2166 old_whole_rect.right - data->whole_rect.right == x_offset &&
2167 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2168 old_client_rect.left - data->client_rect.left == x_offset &&
2169 old_client_rect.right - data->client_rect.right == x_offset &&
2170 old_client_rect.top - data->client_rect.top == y_offset &&
2171 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2172 EqualRect(&valid_rects[0], &data->client_rect))
2174 /* A Cocoa window's bits are moved automatically */
2175 if (!window && (x_offset != 0 || y_offset != 0))
2177 release_win_data(data);
2178 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2179 &old_client_rect, client_rect, window_rect);
2180 if (!(data = get_win_data(hwnd))) return;
2183 else
2185 release_win_data(data);
2186 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2187 &old_client_rect, client_rect, window_rect);
2188 if (!(data = get_win_data(hwnd))) return;
2192 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2194 if (!data->cocoa_window && !data->cocoa_view) goto done;
2196 if (data->on_screen)
2198 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2199 hide_window(data);
2202 /* check if we are currently processing an event relevant to this window */
2203 if (thread_data && thread_data->current_event &&
2204 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2205 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2206 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2208 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2209 sync_client_view_position(data);
2211 else
2213 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2214 if (data->cocoa_window)
2215 set_cocoa_window_properties(data);
2218 if (new_style & WS_VISIBLE)
2220 if (data->cocoa_window)
2222 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2223 set_cocoa_window_properties(data);
2225 /* layered windows are not shown until their attributes are set */
2226 if (!data->on_screen &&
2227 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2228 show_window(data);
2230 else if (!data->on_screen)
2231 show_window(data);
2234 done:
2235 release_win_data(data);
2239 /***********************************************************************
2240 * macdrv_window_close_requested
2242 * Handler for WINDOW_CLOSE_REQUESTED events.
2244 void macdrv_window_close_requested(HWND hwnd)
2246 HMENU sysmenu;
2248 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2250 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2251 return;
2254 sysmenu = GetSystemMenu(hwnd, FALSE);
2255 if (sysmenu)
2257 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2258 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2260 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2261 return;
2265 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2269 /***********************************************************************
2270 * macdrv_window_frame_changed
2272 * Handler for WINDOW_FRAME_CHANGED events.
2274 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2276 struct macdrv_win_data *data;
2277 RECT rect;
2278 HWND parent;
2279 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2280 int width, height;
2281 BOOL being_dragged;
2283 if (!hwnd) return;
2284 if (!(data = get_win_data(hwnd))) return;
2285 if (!data->on_screen || data->minimized)
2287 release_win_data(data);
2288 return;
2291 /* Get geometry */
2293 parent = GetAncestor(hwnd, GA_PARENT);
2295 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2296 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2297 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2299 rect = rect_from_cgrect(event->window_frame_changed.frame);
2300 macdrv_mac_to_window_rect(data, &rect);
2301 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2303 width = rect.right - rect.left;
2304 height = rect.bottom - rect.top;
2306 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2307 flags |= SWP_NOMOVE;
2308 else
2309 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2310 data->window_rect.top, rect.left, rect.top);
2312 if ((data->window_rect.right - data->window_rect.left == width &&
2313 data->window_rect.bottom - data->window_rect.top == height) ||
2314 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2315 flags |= SWP_NOSIZE;
2316 else
2317 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2318 data->window_rect.bottom - data->window_rect.top, width, height);
2320 being_dragged = data->drag_event != NULL;
2321 release_win_data(data);
2323 if (event->window_frame_changed.fullscreen)
2324 flags |= SWP_NOSENDCHANGING;
2325 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2327 int send_sizemove = !event->window_frame_changed.in_resize && !being_dragged && !event->window_frame_changed.skip_size_move_loop;
2328 if (send_sizemove)
2329 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2330 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2331 if (send_sizemove)
2332 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2337 /***********************************************************************
2338 * macdrv_window_got_focus
2340 * Handler for WINDOW_GOT_FOCUS events.
2342 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2344 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2346 if (!hwnd) return;
2348 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2349 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2350 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2352 if (can_window_become_foreground(hwnd) && !(style & WS_MINIMIZE))
2354 /* simulate a mouse click on the menu to find out
2355 * whether the window wants to be activated */
2356 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2357 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2358 MAKELONG(HTMENU, WM_LBUTTONDOWN));
2359 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2361 TRACE("setting foreground window to %p\n", hwnd);
2362 SetForegroundWindow(hwnd);
2363 return;
2367 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2368 macdrv_window_rejected_focus(event);
2372 /***********************************************************************
2373 * macdrv_window_lost_focus
2375 * Handler for WINDOW_LOST_FOCUS events.
2377 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2379 if (!hwnd) return;
2381 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2383 if (hwnd == GetForegroundWindow())
2385 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2386 if (hwnd == GetForegroundWindow())
2387 SetForegroundWindow(GetDesktopWindow());
2392 /***********************************************************************
2393 * macdrv_app_activated
2395 * Handler for APP_ACTIVATED events.
2397 void macdrv_app_activated(void)
2399 TRACE("\n");
2400 macdrv_UpdateClipboard();
2404 /***********************************************************************
2405 * macdrv_app_deactivated
2407 * Handler for APP_DEACTIVATED events.
2409 void macdrv_app_deactivated(void)
2411 ClipCursor(NULL);
2413 if (GetActiveWindow() == GetForegroundWindow())
2415 TRACE("setting fg to desktop\n");
2416 SetForegroundWindow(GetDesktopWindow());
2421 /***********************************************************************
2422 * macdrv_window_maximize_requested
2424 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2426 void macdrv_window_maximize_requested(HWND hwnd)
2428 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2432 /***********************************************************************
2433 * macdrv_window_minimize_requested
2435 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2437 void macdrv_window_minimize_requested(HWND hwnd)
2439 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2443 /***********************************************************************
2444 * macdrv_window_did_minimize
2446 * Handler for WINDOW_DID_MINIMIZE events.
2448 void macdrv_window_did_minimize(HWND hwnd)
2450 TRACE("win %p\n", hwnd);
2452 /* If all our windows are minimized, disable cursor clipping. */
2453 if (!macdrv_is_any_wine_window_visible())
2454 ClipCursor(NULL);
2458 /***********************************************************************
2459 * macdrv_window_did_unminimize
2461 * Handler for WINDOW_DID_UNMINIMIZE events.
2463 void macdrv_window_did_unminimize(HWND hwnd)
2465 struct macdrv_win_data *data;
2466 DWORD style;
2468 TRACE("win %p\n", hwnd);
2470 if (!(data = get_win_data(hwnd))) return;
2471 if (!data->minimized) goto done;
2473 style = GetWindowLongW(hwnd, GWL_STYLE);
2475 data->minimized = FALSE;
2476 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2478 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2479 release_win_data(data);
2480 SetActiveWindow(hwnd);
2481 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2482 return;
2485 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2487 done:
2488 release_win_data(data);
2492 /***********************************************************************
2493 * macdrv_window_brought_forward
2495 * Handler for WINDOW_BROUGHT_FORWARD events.
2497 void macdrv_window_brought_forward(HWND hwnd)
2499 TRACE("win %p\n", hwnd);
2500 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2504 /***********************************************************************
2505 * macdrv_window_resize_ended
2507 * Handler for WINDOW_RESIZE_ENDED events.
2509 void macdrv_window_resize_ended(HWND hwnd)
2511 TRACE("hwnd %p\n", hwnd);
2512 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2516 /***********************************************************************
2517 * macdrv_window_restore_requested
2519 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2520 * for restoring from maximized, not from minimized.
2522 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2524 if (event->window_restore_requested.keep_frame && hwnd)
2526 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2527 struct macdrv_win_data *data;
2529 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2531 RECT rect;
2532 HWND parent = GetAncestor(hwnd, GA_PARENT);
2534 rect = rect_from_cgrect(event->window_restore_requested.frame);
2535 macdrv_mac_to_window_rect(data, &rect);
2536 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2538 release_win_data(data);
2540 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2544 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2548 /***********************************************************************
2549 * macdrv_window_drag_begin
2551 * Handler for WINDOW_DRAG_BEGIN events.
2553 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2555 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2556 struct macdrv_win_data *data;
2557 HANDLE drag_event = NULL;
2558 BOOL loop = TRUE;
2559 MSG msg;
2561 TRACE("win %p\n", hwnd);
2563 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2564 if (!(style & WS_VISIBLE)) return;
2566 if (!(data = get_win_data(hwnd))) return;
2567 if (data->drag_event) goto done;
2569 drag_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2570 if (!drag_event) goto done;
2572 data->drag_event = drag_event;
2573 release_win_data(data);
2575 if (!event->window_drag_begin.no_activate && can_window_become_foreground(hwnd) && GetForegroundWindow() != hwnd)
2577 /* ask whether the window wants to be activated */
2578 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2579 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2580 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2582 TRACE("setting foreground window to %p\n", hwnd);
2583 SetForegroundWindow(hwnd);
2587 ClipCursor(NULL);
2588 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2589 ReleaseCapture();
2591 while (loop)
2593 while (!PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
2595 DWORD result = MsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
2596 if (result == WAIT_OBJECT_0)
2598 loop = FALSE;
2599 break;
2602 if (!loop)
2603 break;
2605 if (msg.message == WM_QUIT)
2606 break;
2608 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2609 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2611 TranslateMessage(&msg);
2612 DispatchMessageW(&msg);
2616 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2618 TRACE("done\n");
2620 if ((data = get_win_data(hwnd)))
2621 data->drag_event = NULL;
2623 done:
2624 release_win_data(data);
2625 if (drag_event) CloseHandle(drag_event);
2629 /***********************************************************************
2630 * macdrv_window_drag_end
2632 * Handler for WINDOW_DRAG_END events.
2634 void macdrv_window_drag_end(HWND hwnd)
2636 struct macdrv_win_data *data;
2638 TRACE("win %p\n", hwnd);
2640 if (!(data = get_win_data(hwnd))) return;
2641 if (data->drag_event)
2642 SetEvent(data->drag_event);
2643 release_win_data(data);
2647 /***********************************************************************
2648 * macdrv_reassert_window_position
2650 * Handler for REASSERT_WINDOW_POSITION events.
2652 void macdrv_reassert_window_position(HWND hwnd)
2654 struct macdrv_win_data *data = get_win_data(hwnd);
2655 if (data)
2657 if (data->cocoa_window && data->on_screen)
2658 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2659 release_win_data(data);
2664 struct quit_info {
2665 HWND *wins;
2666 UINT capacity;
2667 UINT count;
2668 UINT done;
2669 DWORD flags;
2670 BOOL result;
2671 BOOL replied;
2675 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2677 struct quit_info *qi = (struct quit_info*)lp;
2678 DWORD pid;
2680 GetWindowThreadProcessId(hwnd, &pid);
2681 if (pid == GetCurrentProcessId())
2683 if (qi->count >= qi->capacity)
2685 UINT new_cap = qi->capacity * 2;
2686 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2687 new_cap * sizeof(*qi->wins));
2688 if (!new_wins) return FALSE;
2689 qi->wins = new_wins;
2690 qi->capacity = new_cap;
2693 qi->wins[qi->count++] = hwnd;
2696 return TRUE;
2700 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2702 struct quit_info *qi = (struct quit_info*)data;
2704 qi->done++;
2706 if (msg == WM_QUERYENDSESSION)
2708 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2709 hwnd, qi->done, qi->count);
2711 if (!result && !IsWindow(hwnd))
2713 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2714 result = TRUE;
2717 if (!result && qi->result)
2719 qi->result = FALSE;
2721 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2722 ultimate reply. Might as well tell Cocoa now. */
2723 if (!qi->replied)
2725 qi->replied = TRUE;
2726 TRACE("giving quit reply %d\n", qi->result);
2727 macdrv_quit_reply(qi->result);
2731 if (qi->done >= qi->count)
2733 UINT i;
2735 qi->done = 0;
2736 for (i = 0; i < qi->count; i++)
2738 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2739 qi->result, qi->flags);
2740 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2741 quit_callback, (ULONG_PTR)qi))
2743 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2744 qi->wins[i], GetLastError());
2745 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2750 else /* WM_ENDSESSION */
2752 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2754 if (qi->done >= qi->count)
2756 if (!qi->replied)
2758 TRACE("giving quit reply %d\n", qi->result);
2759 macdrv_quit_reply(qi->result);
2762 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2763 if (qi->result)
2764 TerminateProcess(GetCurrentProcess(), 0);
2766 HeapFree(GetProcessHeap(), 0, qi->wins);
2767 HeapFree(GetProcessHeap(), 0, qi);
2773 /***********************************************************************
2774 * macdrv_app_quit_requested
2776 * Handler for APP_QUIT_REQUESTED events.
2778 void macdrv_app_quit_requested(const macdrv_event *event)
2780 struct quit_info *qi;
2781 UINT i;
2783 TRACE("reason %d\n", event->app_quit_requested.reason);
2785 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2786 if (!qi)
2787 goto fail;
2789 qi->capacity = 32;
2790 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2791 qi->count = qi->done = 0;
2793 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2794 goto fail;
2796 switch (event->app_quit_requested.reason)
2798 case QUIT_REASON_LOGOUT:
2799 default:
2800 qi->flags = ENDSESSION_LOGOFF;
2801 break;
2802 case QUIT_REASON_RESTART:
2803 case QUIT_REASON_SHUTDOWN:
2804 qi->flags = 0;
2805 break;
2808 qi->result = TRUE;
2809 qi->replied = FALSE;
2811 for (i = 0; i < qi->count; i++)
2813 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2814 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2815 quit_callback, (ULONG_PTR)qi))
2817 DWORD error = GetLastError();
2818 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2819 if (invalid)
2820 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2821 qi->wins[i]);
2822 else
2823 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2824 qi->wins[i], error);
2825 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2829 /* quit_callback() will clean up qi */
2830 return;
2832 fail:
2833 WARN("failed to allocate window list\n");
2834 if (qi)
2836 HeapFree(GetProcessHeap(), 0, qi->wins);
2837 HeapFree(GetProcessHeap(), 0, qi);
2839 macdrv_quit_reply(FALSE);
2843 /***********************************************************************
2844 * query_resize_size
2846 * Handler for QUERY_RESIZE_SIZE query.
2848 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2850 struct macdrv_win_data *data = get_win_data(hwnd);
2851 RECT rect = rect_from_cgrect(query->resize_size.rect);
2852 int corner;
2853 BOOL ret = FALSE;
2855 if (!data) return FALSE;
2857 macdrv_mac_to_window_rect(data, &rect);
2859 if (query->resize_size.from_left)
2861 if (query->resize_size.from_top)
2862 corner = WMSZ_TOPLEFT;
2863 else
2864 corner = WMSZ_BOTTOMLEFT;
2866 else if (query->resize_size.from_top)
2867 corner = WMSZ_TOPRIGHT;
2868 else
2869 corner = WMSZ_BOTTOMRIGHT;
2871 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2873 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect,
2874 &data->window_rect, &data->client_rect);
2875 query->resize_size.rect = cgrect_from_rect(rect);
2876 ret = TRUE;
2879 release_win_data(data);
2880 return ret;
2884 /***********************************************************************
2885 * query_resize_start
2887 * Handler for QUERY_RESIZE_START query.
2889 BOOL query_resize_start(HWND hwnd)
2891 TRACE("hwnd %p\n", hwnd);
2893 ClipCursor(NULL);
2895 sync_window_min_max_info(hwnd);
2896 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2898 return TRUE;
2902 /***********************************************************************
2903 * query_min_max_info
2905 * Handler for QUERY_MIN_MAX_INFO query.
2907 BOOL query_min_max_info(HWND hwnd)
2909 TRACE("hwnd %p\n", hwnd);
2910 sync_window_min_max_info(hwnd);
2911 return TRUE;