winemac.drv: Allow foregrounding WS_EX_NOACTIVATE windows.
[wine.git] / dlls / winemac.drv / window.c
blob6d735bb4ed22102ed74f367bd5b633d1e335079e
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 (disable_window_decorations) return;
67 if (IsRectEmpty(window_rect)) return;
68 if (EqualRect(window_rect, client_rect)) return;
70 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
72 wf->shadow = TRUE;
73 if (!data->shaped)
75 wf->title_bar = TRUE;
76 if (style & WS_SYSMENU) wf->close_button = TRUE;
77 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
78 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
79 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
82 if (style & WS_THICKFRAME)
84 wf->shadow = TRUE;
85 if (!data->shaped) wf->resizable = TRUE;
87 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
88 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
92 /*******************************************************************
93 * can_window_become_foreground
95 * Check if the specified window can become the foreground/key
96 * window.
98 static inline BOOL can_window_become_foreground(HWND hwnd)
100 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
102 if (!(style & WS_VISIBLE)) return FALSE;
103 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
104 if (hwnd == GetDesktopWindow()) return FALSE;
105 return !(style & WS_DISABLED);
109 /***********************************************************************
110 * get_cocoa_window_state
112 static void get_cocoa_window_state(struct macdrv_win_data *data,
113 DWORD style, DWORD ex_style,
114 struct macdrv_window_state* state)
116 memset(state, 0, sizeof(*state));
117 state->disabled = (style & WS_DISABLED) != 0;
118 state->no_foreground = !can_window_become_foreground(data->hwnd);
119 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
120 state->excluded_by_expose = state->excluded_by_cycle =
121 (!(ex_style & WS_EX_APPWINDOW) &&
122 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
123 if (IsRectEmpty(&data->window_rect))
124 state->excluded_by_expose = TRUE;
125 state->minimized = (style & WS_MINIMIZE) != 0;
126 state->minimized_valid = state->minimized != data->minimized;
127 state->maximized = (style & WS_MAXIMIZE) != 0;
131 /***********************************************************************
132 * get_mac_rect_offset
134 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
136 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect,
137 const RECT *window_rect, const RECT *client_rect)
139 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
141 rect->top = rect->bottom = rect->left = rect->right = 0;
143 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
145 if (!data->shaped)
147 struct macdrv_window_features wf;
148 get_cocoa_window_features(data, style, ex_style, &wf, window_rect, client_rect);
150 if (wf.title_bar)
152 style_mask |= WS_CAPTION;
153 ex_style_mask |= WS_EX_TOOLWINDOW;
155 if (wf.shadow)
157 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
158 ex_style_mask |= WS_EX_DLGMODALFRAME;
162 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
164 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
165 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
169 /***********************************************************************
170 * macdrv_window_to_mac_rect
172 * Convert a rect from client to Mac window coordinates
174 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect,
175 const RECT *window_rect, const RECT *client_rect)
177 RECT rc;
179 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
180 if (IsRectEmpty(rect)) return;
182 get_mac_rect_offset(data, style, &rc, window_rect, client_rect);
184 rect->left -= rc.left;
185 rect->right -= rc.right;
186 rect->top -= rc.top;
187 rect->bottom -= rc.bottom;
188 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
189 if (rect->left >= rect->right) rect->right = rect->left + 1;
193 /***********************************************************************
194 * macdrv_mac_to_window_rect
196 * Opposite of macdrv_window_to_mac_rect
198 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
200 RECT rc;
201 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
203 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
204 if (IsRectEmpty(rect)) return;
206 get_mac_rect_offset(data, style, &rc, &data->window_rect, &data->client_rect);
208 rect->left += rc.left;
209 rect->right += rc.right;
210 rect->top += rc.top;
211 rect->bottom += rc.bottom;
212 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
213 if (rect->left >= rect->right) rect->right = rect->left + 1;
217 /***********************************************************************
218 * constrain_window_frame
220 * Alter a window frame rectangle to fit within a) Cocoa's documented
221 * limits, and b) sane sizes, like twice the desktop rect.
223 static void constrain_window_frame(CGRect* frame)
225 CGRect desktop_rect = macdrv_get_desktop_rect();
226 int max_width, max_height;
228 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
229 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
231 if (frame->origin.x < -16000) frame->origin.x = -16000;
232 if (frame->origin.y < -16000) frame->origin.y = -16000;
233 if (frame->origin.x > 16000) frame->origin.x = 16000;
234 if (frame->origin.y > 16000) frame->origin.y = 16000;
235 if (frame->size.width > max_width) frame->size.width = max_width;
236 if (frame->size.height > max_height) frame->size.height = max_height;
240 /***********************************************************************
241 * alloc_win_data
243 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
245 struct macdrv_win_data *data;
247 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
249 data->hwnd = hwnd;
250 data->color_key = CLR_INVALID;
251 data->swap_interval = 1;
252 EnterCriticalSection(&win_data_section);
253 if (!win_datas)
254 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
255 CFDictionarySetValue(win_datas, hwnd, data);
257 return data;
261 /***********************************************************************
262 * get_win_data
264 * Lock and return the data structure associated with a window.
266 struct macdrv_win_data *get_win_data(HWND hwnd)
268 struct macdrv_win_data *data;
270 if (!hwnd) return NULL;
271 EnterCriticalSection(&win_data_section);
272 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
273 return data;
274 LeaveCriticalSection(&win_data_section);
275 return NULL;
279 /***********************************************************************
280 * release_win_data
282 * Release the data returned by get_win_data.
284 void release_win_data(struct macdrv_win_data *data)
286 if (data) LeaveCriticalSection(&win_data_section);
290 /***********************************************************************
291 * macdrv_get_cocoa_window
293 * Return the Mac window associated with the full area of a window
295 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
297 struct macdrv_win_data *data = get_win_data(hwnd);
298 macdrv_window ret = NULL;
299 if (data && (data->on_screen || !require_on_screen))
300 ret = data->cocoa_window;
301 release_win_data(data);
302 return ret;
306 /***********************************************************************
307 * macdrv_get_cocoa_view
309 * Return the Cocoa view associated with a window
311 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
313 struct macdrv_win_data *data = get_win_data(hwnd);
314 macdrv_view ret = data ? data->cocoa_view : NULL;
316 release_win_data(data);
317 return ret;
321 /***********************************************************************
322 * macdrv_get_client_cocoa_view
324 * Return the Cocoa view associated with a window's client area
326 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
328 struct macdrv_win_data *data = get_win_data(hwnd);
329 macdrv_view ret = data ? data->client_cocoa_view : NULL;
331 release_win_data(data);
332 return ret;
336 /***********************************************************************
337 * set_cocoa_window_properties
339 * Set the window properties for a Cocoa window based on its Windows
340 * properties.
342 static void set_cocoa_window_properties(struct macdrv_win_data *data)
344 DWORD style, ex_style;
345 HWND owner;
346 macdrv_window owner_win;
347 struct macdrv_window_features wf;
348 struct macdrv_window_state state;
350 style = GetWindowLongW(data->hwnd, GWL_STYLE);
351 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
353 owner = GetWindow(data->hwnd, GW_OWNER);
354 if (owner)
355 owner = GetAncestor(owner, GA_ROOT);
356 owner_win = macdrv_get_cocoa_window(owner, TRUE);
357 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
359 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
360 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
362 get_cocoa_window_state(data, style, ex_style, &state);
363 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
364 if (state.minimized_valid)
365 data->minimized = state.minimized;
369 /***********************************************************************
370 * sync_window_region
372 * Update the window region.
374 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
376 HRGN hrgn = win_region;
377 RGNDATA *region_data;
378 const CGRect* rects;
379 int count;
381 if (!data->cocoa_window) return;
382 data->shaped = FALSE;
384 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
386 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
387 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
388 return;
391 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
393 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
394 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
396 DeleteObject(hrgn);
397 hrgn = 0;
401 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
402 MirrorRgn(data->hwnd, hrgn);
403 if (hrgn)
405 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
406 data->window_rect.top - data->whole_rect.top);
408 region_data = get_region_data(hrgn, 0);
409 if (region_data)
411 rects = (CGRect*)region_data->Buffer;
412 count = region_data->rdh.nCount;
413 /* Special case optimization. If the region entirely encloses the Cocoa
414 window, it's the same as there being no region. It's potentially
415 hard/slow to test this for arbitrary regions, so we just check for
416 very simple regions. */
417 if (count == 1 && CGRectContainsRect(rects[0],
418 CGRectOffset(cgrect_from_rect(data->whole_rect), -data->whole_rect.left, -data->whole_rect.top)))
420 TRACE("optimizing for simple region that contains Cocoa content rect\n");
421 rects = NULL;
422 count = 0;
425 else
427 rects = NULL;
428 count = 0;
431 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
432 macdrv_set_window_shape(data->cocoa_window, rects, count);
434 HeapFree(GetProcessHeap(), 0, region_data);
435 data->shaped = (region_data != NULL);
437 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
441 /***********************************************************************
442 * add_bounds_rect
444 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
446 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
447 bounds->left = min(bounds->left, rect->left);
448 bounds->top = min(bounds->top, rect->top);
449 bounds->right = max(bounds->right, rect->right);
450 bounds->bottom = max(bounds->bottom, rect->bottom);
454 /***********************************************************************
455 * sync_window_opacity
457 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
458 BOOL per_pixel_alpha, DWORD flags)
460 CGFloat opacity = 1.0;
461 BOOL needs_flush = FALSE;
463 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
465 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
466 macdrv_set_window_alpha(data->cocoa_window, opacity);
468 if (flags & LWA_COLORKEY)
470 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
471 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
472 key = RGB(0, 0, 0);
474 else
475 key = CLR_INVALID;
477 if (data->color_key != key)
479 if (key == CLR_INVALID)
481 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
482 macdrv_clear_window_color_key(data->cocoa_window);
484 else
486 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
487 GetRValue(key), GetGValue(key), GetBValue(key));
488 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
491 data->color_key = key;
492 needs_flush = TRUE;
495 if (!data->per_pixel_alpha != !per_pixel_alpha)
497 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
498 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
499 data->per_pixel_alpha = per_pixel_alpha;
500 needs_flush = TRUE;
503 if (needs_flush && data->surface)
505 RECT *bounds;
506 RECT rect;
508 rect = data->whole_rect;
509 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
510 data->surface->funcs->lock(data->surface);
511 bounds = data->surface->funcs->get_bounds(data->surface);
512 add_bounds_rect(bounds, &rect);
513 data->surface->funcs->unlock(data->surface);
518 /***********************************************************************
519 * sync_window_min_max_info
521 static void sync_window_min_max_info(HWND hwnd)
523 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
524 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
525 RECT win_rect, primary_monitor_rect;
526 MINMAXINFO minmax;
527 LONG adjustedStyle;
528 INT xinc, yinc;
529 WINDOWPLACEMENT wpl;
530 HMONITOR monitor;
531 struct macdrv_win_data *data;
533 TRACE("win %p\n", hwnd);
535 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
537 GetWindowRect(hwnd, &win_rect);
538 minmax.ptReserved.x = win_rect.left;
539 minmax.ptReserved.y = win_rect.top;
541 if ((style & WS_CAPTION) == WS_CAPTION)
542 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
543 else
544 adjustedStyle = style;
546 primary_monitor_rect.left = primary_monitor_rect.top = 0;
547 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
548 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
549 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
551 xinc = -primary_monitor_rect.left;
552 yinc = -primary_monitor_rect.top;
554 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
555 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
556 minmax.ptMaxPosition.x = -xinc;
557 minmax.ptMaxPosition.y = -yinc;
558 if (style & (WS_DLGFRAME | WS_BORDER))
560 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
561 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
563 else
565 minmax.ptMinTrackSize.x = 2 * xinc;
566 minmax.ptMinTrackSize.y = 2 * yinc;
568 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
569 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
571 wpl.length = sizeof(wpl);
572 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
574 minmax.ptMaxPosition = wpl.ptMaxPosition;
576 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
577 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
578 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
581 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
582 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
584 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
586 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
587 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
589 /* if the app didn't change the values, adapt them for the window's monitor */
590 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
592 MONITORINFO mon_info;
593 RECT monitor_rect;
595 mon_info.cbSize = sizeof(mon_info);
596 GetMonitorInfoW(monitor, &mon_info);
598 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
599 monitor_rect = mon_info.rcWork;
600 else
601 monitor_rect = mon_info.rcMonitor;
603 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
604 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
606 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
607 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
609 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
611 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
612 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
616 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
617 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
619 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
620 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
622 if ((data = get_win_data(hwnd)) && data->cocoa_window)
624 RECT min_rect, max_rect;
625 CGSize min_size, max_size;
627 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
628 macdrv_window_to_mac_rect(data, style, &min_rect, &data->window_rect, &data->client_rect);
629 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
631 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
632 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
633 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
634 else
636 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
637 macdrv_window_to_mac_rect(data, style, &max_rect, &data->window_rect, &data->client_rect);
638 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
641 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
642 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
645 release_win_data(data);
649 /**********************************************************************
650 * create_client_cocoa_view
652 * Create the Cocoa view for a window's client area
654 static void create_client_cocoa_view(struct macdrv_win_data *data)
656 RECT rect = data->client_rect;
657 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
659 if (data->client_cocoa_view)
660 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
661 else
663 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
664 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
666 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
670 /**********************************************************************
671 * create_cocoa_window
673 * Create the whole Mac window for a given window
675 static void create_cocoa_window(struct macdrv_win_data *data)
677 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
678 WCHAR text[1024];
679 struct macdrv_window_features wf;
680 CGRect frame;
681 DWORD style, ex_style;
682 HRGN win_rgn;
683 COLORREF key;
684 BYTE alpha;
685 DWORD layered_flags;
687 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
688 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
690 DeleteObject(win_rgn);
691 win_rgn = 0;
693 data->shaped = (win_rgn != 0);
695 style = GetWindowLongW(data->hwnd, GWL_STYLE);
696 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
698 data->whole_rect = data->window_rect;
699 macdrv_window_to_mac_rect(data, style, &data->whole_rect, &data->window_rect, &data->client_rect);
701 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
703 frame = cgrect_from_rect(data->whole_rect);
704 constrain_window_frame(&frame);
705 if (frame.size.width < 1 || frame.size.height < 1)
706 frame.size.width = frame.size.height = 1;
708 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
709 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
711 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
712 if (!data->cocoa_window) goto done;
713 create_client_cocoa_view(data);
715 set_cocoa_window_properties(data);
717 /* set the window text */
718 if (!InternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) text[0] = 0;
719 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
721 /* set the window region */
722 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
724 /* set the window opacity */
725 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
726 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
728 done:
729 if (win_rgn) DeleteObject(win_rgn);
733 /**********************************************************************
734 * destroy_cocoa_window
736 * Destroy the whole Mac window for a given window.
738 static void destroy_cocoa_window(struct macdrv_win_data *data)
740 if (!data->cocoa_window) return;
742 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
744 macdrv_destroy_cocoa_window(data->cocoa_window);
745 data->cocoa_window = 0;
746 data->on_screen = FALSE;
747 data->color_key = CLR_INVALID;
748 if (data->surface) window_surface_release(data->surface);
749 data->surface = NULL;
750 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
751 data->unminimized_surface = NULL;
755 /**********************************************************************
756 * create_cocoa_view
758 * Create the Cocoa view for a given Windows child window
760 static void create_cocoa_view(struct macdrv_win_data *data)
762 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
763 CGRect frame = cgrect_from_rect(data->window_rect);
765 data->shaped = FALSE;
766 data->whole_rect = data->window_rect;
768 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
769 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
771 if (!equal)
772 data->cocoa_view = macdrv_create_view(frame);
773 create_client_cocoa_view(data);
774 if (equal)
776 data->cocoa_view = data->client_cocoa_view;
777 macdrv_set_view_hidden(data->cocoa_view, TRUE);
778 macdrv_set_view_frame(data->cocoa_view, frame);
783 /**********************************************************************
784 * destroy_cocoa_view
786 * Destroy the Cocoa view for a given window.
788 static void destroy_cocoa_view(struct macdrv_win_data *data)
790 if (!data->cocoa_view) return;
792 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
794 if (data->cocoa_view != data->client_cocoa_view)
795 macdrv_dispose_view(data->cocoa_view);
796 data->cocoa_view = NULL;
797 data->on_screen = FALSE;
801 /***********************************************************************
802 * set_cocoa_view_parent
804 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
806 struct macdrv_win_data *parent_data = get_win_data(parent);
807 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
808 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
810 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
812 if (!cocoa_window && !superview)
813 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
815 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
816 release_win_data(parent_data);
820 /***********************************************************************
821 * macdrv_create_win_data
823 * Create a Mac data window structure for an existing window.
825 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
826 const RECT *client_rect)
828 struct macdrv_win_data *data;
829 HWND parent;
831 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
833 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
835 macdrv_init_thread_data();
836 return NULL;
839 /* don't create win data for HWND_MESSAGE windows */
840 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
842 if (!(data = alloc_win_data(hwnd))) return NULL;
844 data->whole_rect = data->window_rect = *window_rect;
845 data->client_rect = *client_rect;
847 if (parent == GetDesktopWindow())
849 create_cocoa_window(data);
850 TRACE("win %p/%p window %s whole %s client %s\n",
851 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
852 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
854 else
856 create_cocoa_view(data);
857 TRACE("win %p/%p window %s whole %s client %s\n",
858 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
859 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
861 set_cocoa_view_parent(data, parent);
864 return data;
868 /**********************************************************************
869 * is_owned_by
871 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
873 while (1)
875 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
876 if (!hwnd2)
877 hwnd2 = GetAncestor(hwnd, GA_ROOT);
878 if (!hwnd2 || hwnd2 == hwnd)
879 break;
880 if (hwnd2 == maybe_owner)
881 return TRUE;
882 hwnd = hwnd2;
885 return FALSE;
889 /**********************************************************************
890 * is_all_the_way_front
892 static BOOL is_all_the_way_front(HWND hwnd)
894 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
895 HWND prev = hwnd;
897 while ((prev = GetWindow(prev, GW_HWNDPREV)))
899 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
900 return TRUE;
901 if (!is_owned_by(prev, hwnd))
902 return FALSE;
905 return TRUE;
909 /***********************************************************************
910 * set_focus
912 static void set_focus(HWND hwnd, BOOL raise)
914 struct macdrv_win_data *data;
916 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
918 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
919 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
921 if (!(data = get_win_data(hwnd))) return;
923 if (data->cocoa_window && data->on_screen)
925 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
926 /* Set Mac focus */
927 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
928 activate_on_focus_time = 0;
931 release_win_data(data);
934 /***********************************************************************
935 * show_window
937 static void show_window(struct macdrv_win_data *data)
939 if (data->cocoa_window)
941 HWND prev = NULL;
942 HWND next = NULL;
943 macdrv_window prev_window = NULL;
944 macdrv_window next_window = NULL;
945 BOOL activate = FALSE;
946 GUITHREADINFO info;
948 /* find window that this one must be after */
949 prev = GetWindow(data->hwnd, GW_HWNDPREV);
950 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
951 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
952 prev = GetWindow(prev, GW_HWNDPREV);
953 if (!prev_window)
955 /* find window that this one must be before */
956 next = GetWindow(data->hwnd, GW_HWNDNEXT);
957 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
958 (next_window = macdrv_get_cocoa_window(next, TRUE))))
959 next = GetWindow(next, GW_HWNDNEXT);
962 TRACE("win %p/%p below %p/%p above %p/%p\n",
963 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
965 if (!prev_window)
966 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
967 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
968 data->on_screen = TRUE;
970 info.cbSize = sizeof(info);
971 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
972 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
973 set_focus(info.hwndFocus, FALSE);
974 if (activate)
975 activate_on_focus_time = 0;
977 else
979 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
981 macdrv_set_view_hidden(data->cocoa_view, FALSE);
982 data->on_screen = TRUE;
987 /***********************************************************************
988 * hide_window
990 static void hide_window(struct macdrv_win_data *data)
992 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
994 if (data->cocoa_window)
995 macdrv_hide_cocoa_window(data->cocoa_window);
996 else
997 macdrv_set_view_hidden(data->cocoa_view, TRUE);
998 data->on_screen = FALSE;
1002 /***********************************************************************
1003 * sync_window_z_order
1005 static void sync_window_z_order(struct macdrv_win_data *data)
1007 if (data->cocoa_view)
1009 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
1010 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
1011 macdrv_window window = NULL;
1012 HWND prev;
1013 HWND next = NULL;
1014 macdrv_view prev_view = NULL;
1015 macdrv_view next_view = NULL;
1017 if (!superview)
1019 window = macdrv_get_cocoa_window(parent, FALSE);
1020 if (!window)
1021 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1024 /* find window that this one must be after */
1025 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1026 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1027 prev = GetWindow(prev, GW_HWNDPREV);
1028 if (!prev_view)
1030 /* find window that this one must be before */
1031 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1032 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1033 next = GetWindow(next, GW_HWNDNEXT);
1036 TRACE("win %p/%p below %p/%p above %p/%p\n",
1037 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1039 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1041 else if (data->on_screen)
1042 show_window(data);
1046 /***********************************************************************
1047 * get_region_data
1049 * Calls GetRegionData on the given region and converts the rectangle
1050 * array to CGRect format. The returned buffer must be freed by
1051 * caller using HeapFree(GetProcessHeap(),...).
1052 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1054 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1056 RGNDATA *data;
1057 DWORD size;
1058 int i;
1059 RECT *rect;
1060 CGRect *cgrect;
1062 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
1063 if (sizeof(CGRect) > sizeof(RECT))
1065 /* add extra size for CGRect array */
1066 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1067 size += count * (sizeof(CGRect) - sizeof(RECT));
1069 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1070 if (!GetRegionData(hrgn, size, data))
1072 HeapFree(GetProcessHeap(), 0, data);
1073 return NULL;
1076 rect = (RECT *)data->Buffer;
1077 cgrect = (CGRect *)data->Buffer;
1078 if (hdc_lptodp) /* map to device coordinates */
1080 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1081 for (i = 0; i < data->rdh.nCount; i++)
1083 if (rect[i].right < rect[i].left)
1085 INT tmp = rect[i].right;
1086 rect[i].right = rect[i].left;
1087 rect[i].left = tmp;
1089 if (rect[i].bottom < rect[i].top)
1091 INT tmp = rect[i].bottom;
1092 rect[i].bottom = rect[i].top;
1093 rect[i].top = tmp;
1098 if (sizeof(CGRect) > sizeof(RECT))
1100 /* need to start from the end */
1101 for (i = data->rdh.nCount-1; i >= 0; i--)
1102 cgrect[i] = cgrect_from_rect(rect[i]);
1104 else
1106 for (i = 0; i < data->rdh.nCount; i++)
1107 cgrect[i] = cgrect_from_rect(rect[i]);
1109 return data;
1113 /***********************************************************************
1114 * sync_client_view_position
1116 static void sync_client_view_position(struct macdrv_win_data *data)
1118 if (data->cocoa_view != data->client_cocoa_view)
1120 RECT rect = data->client_rect;
1121 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1122 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1123 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1128 /***********************************************************************
1129 * sync_window_position
1131 * Synchronize the Mac window position with the Windows one
1133 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1134 const RECT *old_whole_rect)
1136 CGRect frame = cgrect_from_rect(data->whole_rect);
1137 BOOL force_z_order = FALSE;
1139 if (data->cocoa_window)
1141 if (data->minimized) return;
1143 constrain_window_frame(&frame);
1144 if (frame.size.width < 1 || frame.size.height < 1)
1145 frame.size.width = frame.size.height = 1;
1147 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1149 else
1151 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1152 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1154 if (were_equal && !now_equal)
1156 data->cocoa_view = macdrv_create_view(frame);
1157 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1158 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1159 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1160 force_z_order = TRUE;
1162 else if (!were_equal && now_equal)
1164 macdrv_dispose_view(data->cocoa_view);
1165 data->cocoa_view = data->client_cocoa_view;
1166 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1167 macdrv_set_view_frame(data->cocoa_view, frame);
1168 force_z_order = TRUE;
1170 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1171 macdrv_set_view_frame(data->cocoa_view, frame);
1174 sync_client_view_position(data);
1176 if (old_window_rect && old_whole_rect &&
1177 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1178 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1179 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1180 sync_window_region(data, (HRGN)1);
1182 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1183 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1184 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1186 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1187 sync_window_z_order(data);
1191 /***********************************************************************
1192 * move_window_bits
1194 * Move the window bits when a window is moved.
1196 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1197 const RECT *old_client_rect, const RECT *new_client_rect,
1198 const RECT *new_window_rect)
1200 RECT src_rect = *old_rect;
1201 RECT dst_rect = *new_rect;
1202 HDC hdc_src, hdc_dst;
1203 HRGN rgn;
1204 HWND parent = 0;
1206 if (!window)
1208 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1209 parent = GetAncestor(hwnd, GA_PARENT);
1210 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1211 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1213 else
1215 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1216 /* make src rect relative to the old position of the window */
1217 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1218 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1219 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1222 rgn = CreateRectRgnIndirect(&dst_rect);
1223 SelectClipRgn(hdc_dst, rgn);
1224 DeleteObject(rgn);
1225 ExcludeUpdateRgn(hdc_dst, hwnd);
1227 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1228 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1229 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1230 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1231 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1233 ReleaseDC(hwnd, hdc_dst);
1234 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1238 /**********************************************************************
1239 * activate_on_following_focus
1241 void activate_on_following_focus(void)
1243 activate_on_focus_time = GetTickCount();
1244 if (!activate_on_focus_time) activate_on_focus_time = 1;
1248 /***********************************************************************
1249 * set_app_icon
1251 static void set_app_icon(void)
1253 CFArrayRef images = create_app_icon_images();
1254 if (images)
1256 macdrv_set_application_icon(images);
1257 CFRelease(images);
1262 /**********************************************************************
1263 * set_capture_window_for_move
1265 static BOOL set_capture_window_for_move(HWND hwnd)
1267 HWND previous = 0;
1268 BOOL ret;
1270 SERVER_START_REQ(set_capture_window)
1272 req->handle = wine_server_user_handle(hwnd);
1273 req->flags = CAPTURE_MOVESIZE;
1274 if ((ret = !wine_server_call_err(req)))
1276 previous = wine_server_ptr_handle(reply->previous);
1277 hwnd = wine_server_ptr_handle(reply->full_handle);
1280 SERVER_END_REQ;
1282 if (ret)
1284 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1286 if (previous && previous != hwnd)
1287 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1289 return ret;
1293 /***********************************************************************
1294 * move_window
1296 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1297 * moving top-level windows and enforcing Mac-style constraints like
1298 * keeping the top of the window within the work area.
1300 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1302 MSG msg;
1303 RECT origRect, movedRect, desktopRect;
1304 LONG hittest = (LONG)(wparam & 0x0f);
1305 POINT capturePoint;
1306 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1307 BOOL moved = FALSE;
1308 DWORD dwPoint = GetMessagePos();
1309 INT captionHeight;
1310 HMONITOR mon = 0;
1311 MONITORINFO info;
1313 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1314 if (hittest && hittest != HTCAPTION) return -1;
1316 capturePoint.x = (short)LOWORD(dwPoint);
1317 capturePoint.y = (short)HIWORD(dwPoint);
1318 ClipCursor(NULL);
1320 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1322 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1323 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1324 captionHeight = -origRect.top;
1325 else
1326 captionHeight = 0;
1328 GetWindowRect(hwnd, &origRect);
1329 movedRect = origRect;
1331 if (!hittest)
1333 /* Move pointer to the center of the caption */
1334 RECT rect = origRect;
1336 /* Note: to be exactly centered we should take the different types
1337 * of border into account, but it shouldn't make more than a few pixels
1338 * of difference so let's not bother with that */
1339 rect.top += GetSystemMetrics(SM_CYBORDER);
1340 if (style & WS_SYSMENU)
1341 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1342 if (style & WS_MINIMIZEBOX)
1343 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1344 if (style & WS_MAXIMIZEBOX)
1345 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1346 capturePoint.x = (rect.right + rect.left) / 2;
1347 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1349 SetCursorPos(capturePoint.x, capturePoint.y);
1350 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1353 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1354 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1355 info.cbSize = sizeof(info);
1356 if (mon && !GetMonitorInfoW(mon, &info))
1357 mon = 0;
1359 /* repaint the window before moving it around */
1360 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1362 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1363 set_capture_window_for_move(hwnd);
1365 while(1)
1367 POINT pt;
1368 int dx = 0, dy = 0;
1369 HMONITOR newmon;
1371 if (!GetMessageW(&msg, 0, 0, 0)) break;
1372 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1374 /* Exit on button-up, Return, or Esc */
1375 if (msg.message == WM_LBUTTONUP ||
1376 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1377 break;
1379 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1381 TranslateMessage(&msg);
1382 DispatchMessageW(&msg);
1383 continue; /* We are not interested in other messages */
1386 pt = msg.pt;
1388 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1390 case VK_UP: pt.y -= 8; break;
1391 case VK_DOWN: pt.y += 8; break;
1392 case VK_LEFT: pt.x -= 8; break;
1393 case VK_RIGHT: pt.x += 8; break;
1396 pt.x = max(pt.x, desktopRect.left);
1397 pt.x = min(pt.x, desktopRect.right - 1);
1398 pt.y = max(pt.y, desktopRect.top);
1399 pt.y = min(pt.y, desktopRect.bottom - 1);
1401 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1403 if (GetMonitorInfoW(newmon, &info))
1404 mon = newmon;
1405 else
1406 mon = 0;
1409 if (mon)
1411 /* wineserver clips the cursor position to the virtual desktop rect but,
1412 if the display configuration is non-rectangular, that could still
1413 leave the logical cursor position outside of any display. The window
1414 could keep moving as you push the cursor against a display edge, even
1415 though the visible cursor doesn't keep moving. The following keeps
1416 the window movement in sync with the visible cursor. */
1417 pt.x = max(pt.x, info.rcMonitor.left);
1418 pt.x = min(pt.x, info.rcMonitor.right - 1);
1419 pt.y = max(pt.y, info.rcMonitor.top);
1420 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1422 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1423 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1424 we want to enforce these constraints:
1425 movedRect.left + dx < info.rcWork.right
1426 movedRect.right + dx > info.rcWork.left
1427 movedRect.top + captionHeight + dy < info.rcWork.bottom
1428 movedRect.bottom + dy > info.rcWork.top
1429 movedRect.top + dy >= info.rcWork.top
1430 The first four keep at least one edge barely in the work area.
1431 The last keeps the top (i.e. the title bar) in the work area.
1432 The fourth is redundant with the last, so can be ignored.
1434 Substituting for dx and dy and rearranging gives us...
1436 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1437 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1438 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1439 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1442 dx = pt.x - capturePoint.x;
1443 dy = pt.y - capturePoint.y;
1445 if (dx || dy)
1447 moved = TRUE;
1449 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1450 else
1452 OffsetRect(&movedRect, dx, dy);
1453 capturePoint = pt;
1455 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1456 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1457 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1462 set_capture_window_for_move(0);
1464 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1465 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1467 /* if the move is canceled, restore the previous position */
1468 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1470 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1471 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1474 return 0;
1478 /***********************************************************************
1479 * perform_window_command
1481 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1483 DWORD style;
1485 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1486 hwnd, style_any, style_none, command, hittest);
1488 style = GetWindowLongW(hwnd, GWL_STYLE);
1489 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1491 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1492 return;
1495 if (GetActiveWindow() != hwnd)
1497 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1498 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1499 switch (ma)
1501 case MA_NOACTIVATEANDEAT:
1502 case MA_ACTIVATEANDEAT:
1503 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1504 return;
1505 case MA_NOACTIVATE:
1506 break;
1507 case MA_ACTIVATE:
1508 case 0:
1509 SetActiveWindow(hwnd);
1510 break;
1511 default:
1512 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1513 break;
1517 TRACE("changing win %p\n", hwnd);
1518 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1522 /**********************************************************************
1523 * CreateDesktopWindow (MACDRV.@)
1525 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1527 unsigned int width, height;
1529 TRACE("%p\n", hwnd);
1531 /* retrieve the real size of the desktop */
1532 SERVER_START_REQ(get_window_rectangles)
1534 req->handle = wine_server_user_handle(hwnd);
1535 req->relative = COORDS_CLIENT;
1536 wine_server_call(req);
1537 width = reply->window.right;
1538 height = reply->window.bottom;
1540 SERVER_END_REQ;
1542 if (!width && !height) /* not initialized yet */
1544 CGRect rect = macdrv_get_desktop_rect();
1546 SERVER_START_REQ(set_window_pos)
1548 req->handle = wine_server_user_handle(hwnd);
1549 req->previous = 0;
1550 req->swp_flags = SWP_NOZORDER;
1551 req->window.left = CGRectGetMinX(rect);
1552 req->window.top = CGRectGetMinY(rect);
1553 req->window.right = CGRectGetMaxX(rect);
1554 req->window.bottom = CGRectGetMaxY(rect);
1555 req->client = req->window;
1556 wine_server_call(req);
1558 SERVER_END_REQ;
1561 set_app_icon();
1562 return TRUE;
1566 static WNDPROC desktop_orig_wndproc;
1568 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
1570 static LRESULT CALLBACK desktop_wndproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
1572 switch (msg)
1574 case WM_WINE_NOTIFY_ACTIVITY:
1576 /* This wakes from display sleep, but doesn't affect the screen saver. */
1577 static IOPMAssertionID assertion;
1578 IOPMAssertionDeclareUserActivity(CFSTR("Wine user input"), kIOPMUserActiveLocal, &assertion);
1580 /* This prevents the screen saver, but doesn't wake from display sleep. */
1581 /* It's deprecated, but there's no better alternative. */
1582 #pragma clang diagnostic push
1583 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1584 UpdateSystemActivity(UsrActivity);
1585 #pragma clang diagnostic pop
1586 break;
1589 return desktop_orig_wndproc( hwnd, msg, wp, lp );
1592 /**********************************************************************
1593 * CreateWindow (MACDRV.@)
1595 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1597 if (hwnd == GetDesktopWindow())
1599 desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( GetDesktopWindow(),
1600 GWLP_WNDPROC, (LONG_PTR)desktop_wndproc_wrapper );
1602 macdrv_init_clipboard();
1604 return TRUE;
1608 /***********************************************************************
1609 * DestroyWindow (MACDRV.@)
1611 void CDECL macdrv_DestroyWindow(HWND hwnd)
1613 struct macdrv_win_data *data;
1615 TRACE("%p\n", hwnd);
1617 if (!(data = get_win_data(hwnd))) return;
1619 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1620 if (data->drag_event) SetEvent(data->drag_event);
1622 destroy_cocoa_window(data);
1623 destroy_cocoa_view(data);
1624 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1626 CFDictionaryRemoveValue(win_datas, hwnd);
1627 release_win_data(data);
1628 HeapFree(GetProcessHeap(), 0, data);
1632 /*****************************************************************
1633 * SetFocus (MACDRV.@)
1635 * Set the Mac focus.
1637 void CDECL macdrv_SetFocus(HWND hwnd)
1639 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1641 TRACE("%p\n", hwnd);
1643 if (!thread_data) return;
1644 thread_data->dead_key_state = 0;
1645 set_focus(hwnd, TRUE);
1649 /***********************************************************************
1650 * SetLayeredWindowAttributes (MACDRV.@)
1652 * Set transparency attributes for a layered window.
1654 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1656 struct macdrv_win_data *data = get_win_data(hwnd);
1658 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1660 if (data)
1662 data->layered = TRUE;
1663 data->ulw_layered = FALSE;
1664 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1665 if (data->cocoa_window)
1667 sync_window_opacity(data, key, alpha, FALSE, flags);
1668 /* since layered attributes are now set, can now show the window */
1669 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1670 show_window(data);
1672 release_win_data(data);
1674 else
1675 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1679 /*****************************************************************
1680 * SetParent (MACDRV.@)
1682 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1684 struct macdrv_win_data *data;
1686 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1688 if (parent == old_parent) return;
1689 if (!(data = get_win_data(hwnd))) return;
1691 if (parent != GetDesktopWindow()) /* a child window */
1693 if (old_parent == GetDesktopWindow())
1695 /* destroy the old Mac window */
1696 destroy_cocoa_window(data);
1697 create_cocoa_view(data);
1700 set_cocoa_view_parent(data, parent);
1702 else /* new top level window */
1704 destroy_cocoa_view(data);
1705 create_cocoa_window(data);
1707 release_win_data(data);
1711 /***********************************************************************
1712 * SetWindowRgn (MACDRV.@)
1714 * Assign specified region to window (for non-rectangular windows)
1716 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1718 struct macdrv_win_data *data;
1720 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1722 if ((data = get_win_data(hwnd)))
1724 sync_window_region(data, hrgn);
1725 release_win_data(data);
1727 else
1729 DWORD procid;
1731 GetWindowThreadProcessId(hwnd, &procid);
1732 if (procid != GetCurrentProcessId())
1733 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1738 /***********************************************************************
1739 * SetWindowStyle (MACDRV.@)
1741 * Update the state of the Cocoa window to reflect a style change
1743 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1745 struct macdrv_win_data *data;
1747 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1749 if (hwnd == GetDesktopWindow()) return;
1750 if (!(data = get_win_data(hwnd))) return;
1752 if (data->cocoa_window)
1754 DWORD changed = style->styleNew ^ style->styleOld;
1756 set_cocoa_window_properties(data);
1758 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1760 data->layered = FALSE;
1761 data->ulw_layered = FALSE;
1762 sync_window_opacity(data, 0, 0, FALSE, 0);
1763 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1766 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1767 sync_window_region(data, (HRGN)1);
1770 release_win_data(data);
1774 /*****************************************************************
1775 * SetWindowText (MACDRV.@)
1777 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1779 macdrv_window win;
1781 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1783 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1784 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1788 /***********************************************************************
1789 * ShowWindow (MACDRV.@)
1791 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1793 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1794 struct macdrv_win_data *data = get_win_data(hwnd);
1795 CGRect frame;
1797 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1798 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1800 if (!data || !data->cocoa_window) goto done;
1801 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1803 if (rect->left != -32000 || rect->top != -32000)
1805 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1806 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1808 goto done;
1810 if (!data->on_screen) goto done;
1812 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1814 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1815 goto done;
1817 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1818 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1819 goto done;
1821 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1822 *rect = rect_from_cgrect(frame);
1823 macdrv_mac_to_window_rect(data, rect);
1824 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1825 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1827 done:
1828 release_win_data(data);
1829 return swp;
1833 /***********************************************************************
1834 * SysCommand (MACDRV.@)
1836 * Perform WM_SYSCOMMAND handling.
1838 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1840 struct macdrv_win_data *data;
1841 LRESULT ret = -1;
1842 WPARAM command = wparam & 0xfff0;
1844 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1846 if (!(data = get_win_data(hwnd))) goto done;
1847 if (!data->cocoa_window || !data->on_screen) goto done;
1849 /* prevent a simple ALT press+release from activating the system menu,
1850 as that can get confusing */
1851 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1852 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1854 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1855 ret = 0;
1858 if (command == SC_MOVE)
1860 release_win_data(data);
1861 return move_window(hwnd, wparam);
1864 done:
1865 release_win_data(data);
1866 return ret;
1870 /***********************************************************************
1871 * UpdateLayeredWindow (MACDRV.@)
1873 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1874 const RECT *window_rect)
1876 struct window_surface *surface;
1877 struct macdrv_win_data *data;
1878 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1879 BYTE alpha;
1880 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1881 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1882 void *src_bits, *dst_bits;
1883 RECT rect, src_rect;
1884 HDC hdc = 0;
1885 HBITMAP dib;
1886 BOOL ret = FALSE;
1888 if (!(data = get_win_data(hwnd))) return FALSE;
1890 data->layered = TRUE;
1891 data->ulw_layered = TRUE;
1893 rect = *window_rect;
1894 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1896 surface = data->surface;
1897 if (!surface || !EqualRect(&surface->rect, &rect))
1899 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1900 set_window_surface(data->cocoa_window, data->surface);
1901 if (surface) window_surface_release(surface);
1902 surface = data->surface;
1903 if (data->unminimized_surface)
1905 window_surface_release(data->unminimized_surface);
1906 data->unminimized_surface = NULL;
1909 else set_surface_use_alpha(surface, TRUE);
1911 if (surface) window_surface_add_ref(surface);
1912 release_win_data(data);
1914 if (!surface) return FALSE;
1915 if (!info->hdcSrc)
1917 window_surface_release(surface);
1918 return TRUE;
1921 if (info->dwFlags & ULW_ALPHA)
1923 /* Apply SourceConstantAlpha via window alpha, not blend. */
1924 alpha = info->pblend->SourceConstantAlpha;
1925 blend = *info->pblend;
1926 blend.SourceConstantAlpha = 0xff;
1928 else
1929 alpha = 0xff;
1931 dst_bits = surface->funcs->get_info(surface, bmi);
1933 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1934 if (!(hdc = CreateCompatibleDC(0))) goto done;
1936 SelectObject(hdc, dib);
1937 if (info->prcDirty)
1939 IntersectRect(&rect, &rect, info->prcDirty);
1940 surface->funcs->lock(surface);
1941 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1942 surface->funcs->unlock(surface);
1943 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1945 src_rect = rect;
1946 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1947 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1949 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1950 info->hdcSrc, src_rect.left, src_rect.top,
1951 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1952 blend)))
1953 goto done;
1955 if ((data = get_win_data(hwnd)))
1957 if (surface == data->surface)
1959 surface->funcs->lock(surface);
1960 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1961 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1962 surface->funcs->unlock(surface);
1963 surface->funcs->flush(surface);
1966 /* The ULW flags are a superset of the LWA flags. */
1967 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1969 release_win_data(data);
1972 done:
1973 window_surface_release(surface);
1974 if (hdc) DeleteDC(hdc);
1975 if (dib) DeleteObject(dib);
1976 return ret;
1980 /**********************************************************************
1981 * WindowMessage (MACDRV.@)
1983 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1985 struct macdrv_win_data *data;
1987 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1989 switch(msg)
1991 case WM_MACDRV_SET_WIN_REGION:
1992 if ((data = get_win_data(hwnd)))
1994 sync_window_region(data, (HRGN)1);
1995 release_win_data(data);
1997 return 0;
1998 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1999 if (hwnd == GetDesktopWindow())
2001 CGRect new_desktop_rect;
2002 RECT current_desktop_rect;
2004 macdrv_reset_device_metrics();
2005 new_desktop_rect = macdrv_get_desktop_rect();
2006 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
2007 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
2009 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
2010 SMTO_ABORTIFHUNG, 2000, NULL);
2011 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
2012 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
2013 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
2014 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
2015 SMTO_ABORTIFHUNG, 2000, NULL);
2018 return 0;
2019 case WM_MACDRV_RESET_DEVICE_METRICS:
2020 macdrv_reset_device_metrics();
2021 return 0;
2022 case WM_MACDRV_DISPLAYCHANGE:
2023 macdrv_reassert_window_position(hwnd);
2024 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
2025 return 0;
2026 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
2027 activate_on_following_focus();
2028 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
2029 return 0;
2032 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
2033 return 0;
2037 static inline RECT get_surface_rect(const RECT *visible_rect)
2039 RECT rect;
2040 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
2042 IntersectRect(&rect, visible_rect, &desktop_rect);
2043 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2044 rect.left &= ~127;
2045 rect.top &= ~127;
2046 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2047 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2048 return rect;
2052 /***********************************************************************
2053 * WindowPosChanging (MACDRV.@)
2055 BOOL CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2056 const RECT *window_rect, const RECT *client_rect,
2057 RECT *visible_rect, struct window_surface **surface)
2059 struct macdrv_win_data *data = get_win_data(hwnd);
2060 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2061 RECT surface_rect;
2063 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2064 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2065 wine_dbgstr_rect(visible_rect), surface);
2067 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return TRUE;
2069 *visible_rect = *window_rect;
2070 macdrv_window_to_mac_rect(data, style, visible_rect, window_rect, client_rect);
2071 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2072 wine_dbgstr_rect(visible_rect));
2074 /* create the window surface if necessary */
2075 if (!data->cocoa_window) goto done;
2076 if (swp_flags & SWP_HIDEWINDOW) goto done;
2077 if (data->ulw_layered) goto done;
2079 if (*surface) window_surface_release(*surface);
2080 *surface = NULL;
2082 surface_rect = get_surface_rect(visible_rect);
2083 if (data->surface)
2085 if (EqualRect(&data->surface->rect, &surface_rect))
2087 /* existing surface is good enough */
2088 surface_clip_to_visible_rect(data->surface, visible_rect);
2089 window_surface_add_ref(data->surface);
2090 *surface = data->surface;
2091 goto done;
2094 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2096 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2098 done:
2099 release_win_data(data);
2100 return TRUE;
2104 /***********************************************************************
2105 * WindowPosChanged (MACDRV.@)
2107 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2108 const RECT *window_rect, const RECT *client_rect,
2109 const RECT *visible_rect, const RECT *valid_rects,
2110 struct window_surface *surface)
2112 struct macdrv_thread_data *thread_data;
2113 struct macdrv_win_data *data;
2114 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2115 RECT old_window_rect, old_whole_rect, old_client_rect;
2117 if (!(data = get_win_data(hwnd))) return;
2119 thread_data = macdrv_thread_data();
2121 old_window_rect = data->window_rect;
2122 old_whole_rect = data->whole_rect;
2123 old_client_rect = data->client_rect;
2124 data->window_rect = *window_rect;
2125 data->whole_rect = *visible_rect;
2126 data->client_rect = *client_rect;
2127 if (data->cocoa_window && !data->ulw_layered)
2129 if (surface) window_surface_add_ref(surface);
2130 if (new_style & WS_MINIMIZE)
2132 if (!data->unminimized_surface && data->surface)
2134 data->unminimized_surface = data->surface;
2135 window_surface_add_ref(data->unminimized_surface);
2138 else
2140 set_window_surface(data->cocoa_window, surface);
2141 if (data->unminimized_surface)
2143 window_surface_release(data->unminimized_surface);
2144 data->unminimized_surface = NULL;
2147 if (data->surface) window_surface_release(data->surface);
2148 data->surface = surface;
2151 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2152 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2153 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2154 new_style, swp_flags, surface);
2156 if (!IsRectEmpty(&valid_rects[0]))
2158 macdrv_window window = data->cocoa_window;
2159 int x_offset = old_whole_rect.left - data->whole_rect.left;
2160 int y_offset = old_whole_rect.top - data->whole_rect.top;
2162 /* if all that happened is that the whole window moved, copy everything */
2163 if (!(swp_flags & SWP_FRAMECHANGED) &&
2164 old_whole_rect.right - data->whole_rect.right == x_offset &&
2165 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2166 old_client_rect.left - data->client_rect.left == x_offset &&
2167 old_client_rect.right - data->client_rect.right == x_offset &&
2168 old_client_rect.top - data->client_rect.top == y_offset &&
2169 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2170 EqualRect(&valid_rects[0], &data->client_rect))
2172 /* A Cocoa window's bits are moved automatically */
2173 if (!window && (x_offset != 0 || y_offset != 0))
2175 release_win_data(data);
2176 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2177 &old_client_rect, client_rect, window_rect);
2178 if (!(data = get_win_data(hwnd))) return;
2181 else
2183 release_win_data(data);
2184 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2185 &old_client_rect, client_rect, window_rect);
2186 if (!(data = get_win_data(hwnd))) return;
2190 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2192 if (!data->cocoa_window && !data->cocoa_view) goto done;
2194 if (data->on_screen)
2196 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2197 hide_window(data);
2200 /* check if we are currently processing an event relevant to this window */
2201 if (thread_data && thread_data->current_event &&
2202 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2203 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2204 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2206 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2207 sync_client_view_position(data);
2209 else
2211 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2212 if (data->cocoa_window)
2213 set_cocoa_window_properties(data);
2216 if (new_style & WS_VISIBLE)
2218 if (data->cocoa_window)
2220 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2221 set_cocoa_window_properties(data);
2223 /* layered windows are not shown until their attributes are set */
2224 if (!data->on_screen &&
2225 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2226 show_window(data);
2228 else if (!data->on_screen)
2229 show_window(data);
2232 done:
2233 release_win_data(data);
2237 /***********************************************************************
2238 * macdrv_window_close_requested
2240 * Handler for WINDOW_CLOSE_REQUESTED events.
2242 void macdrv_window_close_requested(HWND hwnd)
2244 HMENU sysmenu;
2246 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2248 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2249 return;
2252 sysmenu = GetSystemMenu(hwnd, FALSE);
2253 if (sysmenu)
2255 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2256 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2258 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2259 return;
2263 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2267 /***********************************************************************
2268 * macdrv_window_frame_changed
2270 * Handler for WINDOW_FRAME_CHANGED events.
2272 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2274 struct macdrv_win_data *data;
2275 RECT rect;
2276 HWND parent;
2277 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2278 int width, height;
2279 BOOL being_dragged;
2281 if (!hwnd) return;
2282 if (!(data = get_win_data(hwnd))) return;
2283 if (!data->on_screen || data->minimized)
2285 release_win_data(data);
2286 return;
2289 /* Get geometry */
2291 parent = GetAncestor(hwnd, GA_PARENT);
2293 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2294 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2295 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2297 rect = rect_from_cgrect(event->window_frame_changed.frame);
2298 macdrv_mac_to_window_rect(data, &rect);
2299 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2301 width = rect.right - rect.left;
2302 height = rect.bottom - rect.top;
2304 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2305 flags |= SWP_NOMOVE;
2306 else
2307 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2308 data->window_rect.top, rect.left, rect.top);
2310 if ((data->window_rect.right - data->window_rect.left == width &&
2311 data->window_rect.bottom - data->window_rect.top == height) ||
2312 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2313 flags |= SWP_NOSIZE;
2314 else
2315 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2316 data->window_rect.bottom - data->window_rect.top, width, height);
2318 being_dragged = data->drag_event != NULL;
2319 release_win_data(data);
2321 if (event->window_frame_changed.fullscreen)
2322 flags |= SWP_NOSENDCHANGING;
2323 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2325 int send_sizemove = !event->window_frame_changed.in_resize && !being_dragged && !event->window_frame_changed.skip_size_move_loop;
2326 if (send_sizemove)
2327 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2328 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2329 if (send_sizemove)
2330 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2335 /***********************************************************************
2336 * macdrv_window_got_focus
2338 * Handler for WINDOW_GOT_FOCUS events.
2340 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2342 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2344 if (!hwnd) return;
2346 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2347 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2348 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2350 if (can_window_become_foreground(hwnd) && !(style & WS_MINIMIZE))
2352 /* simulate a mouse click on the menu to find out
2353 * whether the window wants to be activated */
2354 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2355 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2356 MAKELONG(HTMENU, WM_LBUTTONDOWN));
2357 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2359 TRACE("setting foreground window to %p\n", hwnd);
2360 SetForegroundWindow(hwnd);
2361 return;
2365 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2366 macdrv_window_rejected_focus(event);
2370 /***********************************************************************
2371 * macdrv_window_lost_focus
2373 * Handler for WINDOW_LOST_FOCUS events.
2375 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2377 if (!hwnd) return;
2379 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2381 if (hwnd == GetForegroundWindow())
2383 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2384 if (hwnd == GetForegroundWindow())
2385 SetForegroundWindow(GetDesktopWindow());
2390 /***********************************************************************
2391 * macdrv_app_activated
2393 * Handler for APP_ACTIVATED events.
2395 void macdrv_app_activated(void)
2397 TRACE("\n");
2398 macdrv_UpdateClipboard();
2402 /***********************************************************************
2403 * macdrv_app_deactivated
2405 * Handler for APP_DEACTIVATED events.
2407 void macdrv_app_deactivated(void)
2409 ClipCursor(NULL);
2411 if (GetActiveWindow() == GetForegroundWindow())
2413 TRACE("setting fg to desktop\n");
2414 SetForegroundWindow(GetDesktopWindow());
2419 /***********************************************************************
2420 * macdrv_window_maximize_requested
2422 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2424 void macdrv_window_maximize_requested(HWND hwnd)
2426 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2430 /***********************************************************************
2431 * macdrv_window_minimize_requested
2433 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2435 void macdrv_window_minimize_requested(HWND hwnd)
2437 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2441 /***********************************************************************
2442 * macdrv_window_did_minimize
2444 * Handler for WINDOW_DID_MINIMIZE events.
2446 void macdrv_window_did_minimize(HWND hwnd)
2448 TRACE("win %p\n", hwnd);
2450 /* If all our windows are minimized, disable cursor clipping. */
2451 if (!macdrv_is_any_wine_window_visible())
2452 ClipCursor(NULL);
2456 /***********************************************************************
2457 * macdrv_window_did_unminimize
2459 * Handler for WINDOW_DID_UNMINIMIZE events.
2461 void macdrv_window_did_unminimize(HWND hwnd)
2463 struct macdrv_win_data *data;
2464 DWORD style;
2466 TRACE("win %p\n", hwnd);
2468 if (!(data = get_win_data(hwnd))) return;
2469 if (!data->minimized) goto done;
2471 style = GetWindowLongW(hwnd, GWL_STYLE);
2473 data->minimized = FALSE;
2474 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2476 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2477 release_win_data(data);
2478 SetActiveWindow(hwnd);
2479 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2480 return;
2483 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2485 done:
2486 release_win_data(data);
2490 /***********************************************************************
2491 * macdrv_window_brought_forward
2493 * Handler for WINDOW_BROUGHT_FORWARD events.
2495 void macdrv_window_brought_forward(HWND hwnd)
2497 TRACE("win %p\n", hwnd);
2498 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2502 /***********************************************************************
2503 * macdrv_window_resize_ended
2505 * Handler for WINDOW_RESIZE_ENDED events.
2507 void macdrv_window_resize_ended(HWND hwnd)
2509 TRACE("hwnd %p\n", hwnd);
2510 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2514 /***********************************************************************
2515 * macdrv_window_restore_requested
2517 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2518 * for restoring from maximized, not from minimized.
2520 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2522 if (event->window_restore_requested.keep_frame && hwnd)
2524 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2525 struct macdrv_win_data *data;
2527 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2529 RECT rect;
2530 HWND parent = GetAncestor(hwnd, GA_PARENT);
2532 rect = rect_from_cgrect(event->window_restore_requested.frame);
2533 macdrv_mac_to_window_rect(data, &rect);
2534 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2536 release_win_data(data);
2538 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2542 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2546 /***********************************************************************
2547 * macdrv_window_drag_begin
2549 * Handler for WINDOW_DRAG_BEGIN events.
2551 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2553 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2554 struct macdrv_win_data *data;
2555 HANDLE drag_event = NULL;
2556 BOOL loop = TRUE;
2557 MSG msg;
2559 TRACE("win %p\n", hwnd);
2561 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2562 if (!(style & WS_VISIBLE)) return;
2564 if (!(data = get_win_data(hwnd))) return;
2565 if (data->drag_event) goto done;
2567 drag_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2568 if (!drag_event) goto done;
2570 data->drag_event = drag_event;
2571 release_win_data(data);
2573 if (!event->window_drag_begin.no_activate && can_window_become_foreground(hwnd) && GetForegroundWindow() != hwnd)
2575 /* ask whether the window wants to be activated */
2576 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2577 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2578 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2580 TRACE("setting foreground window to %p\n", hwnd);
2581 SetForegroundWindow(hwnd);
2585 ClipCursor(NULL);
2586 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2587 ReleaseCapture();
2589 while (loop)
2591 while (!PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
2593 DWORD result = MsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
2594 if (result == WAIT_OBJECT_0)
2596 loop = FALSE;
2597 break;
2600 if (!loop)
2601 break;
2603 if (msg.message == WM_QUIT)
2604 break;
2606 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2607 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2609 TranslateMessage(&msg);
2610 DispatchMessageW(&msg);
2614 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2616 TRACE("done\n");
2618 if ((data = get_win_data(hwnd)))
2619 data->drag_event = NULL;
2621 done:
2622 release_win_data(data);
2623 if (drag_event) CloseHandle(drag_event);
2627 /***********************************************************************
2628 * macdrv_window_drag_end
2630 * Handler for WINDOW_DRAG_END events.
2632 void macdrv_window_drag_end(HWND hwnd)
2634 struct macdrv_win_data *data;
2636 TRACE("win %p\n", hwnd);
2638 if (!(data = get_win_data(hwnd))) return;
2639 if (data->drag_event)
2640 SetEvent(data->drag_event);
2641 release_win_data(data);
2645 /***********************************************************************
2646 * macdrv_reassert_window_position
2648 * Handler for REASSERT_WINDOW_POSITION events.
2650 void macdrv_reassert_window_position(HWND hwnd)
2652 struct macdrv_win_data *data = get_win_data(hwnd);
2653 if (data)
2655 if (data->cocoa_window && data->on_screen)
2656 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2657 release_win_data(data);
2662 struct quit_info {
2663 HWND *wins;
2664 UINT capacity;
2665 UINT count;
2666 UINT done;
2667 DWORD flags;
2668 BOOL result;
2669 BOOL replied;
2673 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2675 struct quit_info *qi = (struct quit_info*)lp;
2676 DWORD pid;
2678 GetWindowThreadProcessId(hwnd, &pid);
2679 if (pid == GetCurrentProcessId())
2681 if (qi->count >= qi->capacity)
2683 UINT new_cap = qi->capacity * 2;
2684 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2685 new_cap * sizeof(*qi->wins));
2686 if (!new_wins) return FALSE;
2687 qi->wins = new_wins;
2688 qi->capacity = new_cap;
2691 qi->wins[qi->count++] = hwnd;
2694 return TRUE;
2698 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2700 struct quit_info *qi = (struct quit_info*)data;
2702 qi->done++;
2704 if (msg == WM_QUERYENDSESSION)
2706 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2707 hwnd, qi->done, qi->count);
2709 if (!result && !IsWindow(hwnd))
2711 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2712 result = TRUE;
2715 if (!result && qi->result)
2717 qi->result = FALSE;
2719 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2720 ultimate reply. Might as well tell Cocoa now. */
2721 if (!qi->replied)
2723 qi->replied = TRUE;
2724 TRACE("giving quit reply %d\n", qi->result);
2725 macdrv_quit_reply(qi->result);
2729 if (qi->done >= qi->count)
2731 UINT i;
2733 qi->done = 0;
2734 for (i = 0; i < qi->count; i++)
2736 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2737 qi->result, qi->flags);
2738 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2739 quit_callback, (ULONG_PTR)qi))
2741 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2742 qi->wins[i], GetLastError());
2743 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2748 else /* WM_ENDSESSION */
2750 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2752 if (qi->done >= qi->count)
2754 if (!qi->replied)
2756 TRACE("giving quit reply %d\n", qi->result);
2757 macdrv_quit_reply(qi->result);
2760 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2761 if (qi->result)
2762 TerminateProcess(GetCurrentProcess(), 0);
2764 HeapFree(GetProcessHeap(), 0, qi->wins);
2765 HeapFree(GetProcessHeap(), 0, qi);
2771 /***********************************************************************
2772 * macdrv_app_quit_requested
2774 * Handler for APP_QUIT_REQUESTED events.
2776 void macdrv_app_quit_requested(const macdrv_event *event)
2778 struct quit_info *qi;
2779 UINT i;
2781 TRACE("reason %d\n", event->app_quit_requested.reason);
2783 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2784 if (!qi)
2785 goto fail;
2787 qi->capacity = 32;
2788 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2789 qi->count = qi->done = 0;
2791 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2792 goto fail;
2794 switch (event->app_quit_requested.reason)
2796 case QUIT_REASON_LOGOUT:
2797 default:
2798 qi->flags = ENDSESSION_LOGOFF;
2799 break;
2800 case QUIT_REASON_RESTART:
2801 case QUIT_REASON_SHUTDOWN:
2802 qi->flags = 0;
2803 break;
2806 qi->result = TRUE;
2807 qi->replied = FALSE;
2809 for (i = 0; i < qi->count; i++)
2811 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2812 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2813 quit_callback, (ULONG_PTR)qi))
2815 DWORD error = GetLastError();
2816 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2817 if (invalid)
2818 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2819 qi->wins[i]);
2820 else
2821 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2822 qi->wins[i], error);
2823 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2827 /* quit_callback() will clean up qi */
2828 return;
2830 fail:
2831 WARN("failed to allocate window list\n");
2832 if (qi)
2834 HeapFree(GetProcessHeap(), 0, qi->wins);
2835 HeapFree(GetProcessHeap(), 0, qi);
2837 macdrv_quit_reply(FALSE);
2841 /***********************************************************************
2842 * query_resize_size
2844 * Handler for QUERY_RESIZE_SIZE query.
2846 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2848 struct macdrv_win_data *data = get_win_data(hwnd);
2849 RECT rect = rect_from_cgrect(query->resize_size.rect);
2850 int corner;
2851 BOOL ret = FALSE;
2853 if (!data) return FALSE;
2855 macdrv_mac_to_window_rect(data, &rect);
2857 if (query->resize_size.from_left)
2859 if (query->resize_size.from_top)
2860 corner = WMSZ_TOPLEFT;
2861 else
2862 corner = WMSZ_BOTTOMLEFT;
2864 else if (query->resize_size.from_top)
2865 corner = WMSZ_TOPRIGHT;
2866 else
2867 corner = WMSZ_BOTTOMRIGHT;
2869 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2871 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect,
2872 &data->window_rect, &data->client_rect);
2873 query->resize_size.rect = cgrect_from_rect(rect);
2874 ret = TRUE;
2877 release_win_data(data);
2878 return ret;
2882 /***********************************************************************
2883 * query_resize_start
2885 * Handler for QUERY_RESIZE_START query.
2887 BOOL query_resize_start(HWND hwnd)
2889 TRACE("hwnd %p\n", hwnd);
2891 ClipCursor(NULL);
2893 sync_window_min_max_info(hwnd);
2894 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2896 return TRUE;
2900 /***********************************************************************
2901 * query_min_max_info
2903 * Handler for QUERY_MIN_MAX_INFO query.
2905 BOOL query_min_max_info(HWND hwnd)
2907 TRACE("hwnd %p\n", hwnd);
2908 sync_window_min_max_info(hwnd);
2909 return TRUE;