winemac: Directly use win32u for GDI functions in window.c.
[wine.git] / dlls / winemac.drv / window.c
blobe0dc2352d37b5054214be3d2e8c79c74c0a03a67
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 pthread_mutex_t win_data_mutex;
42 static CFMutableDictionaryRef win_datas;
44 static DWORD activate_on_focus_time;
47 /***********************************************************************
48 * get_cocoa_window_features
50 static void get_cocoa_window_features(struct macdrv_win_data *data,
51 DWORD style, DWORD ex_style,
52 struct macdrv_window_features* wf,
53 const RECT *window_rect,
54 const RECT *client_rect)
56 memset(wf, 0, sizeof(*wf));
58 if (ex_style & WS_EX_NOACTIVATE) wf->prevents_app_activation = TRUE;
60 if (disable_window_decorations) return;
61 if (IsRectEmpty(window_rect)) return;
62 if (EqualRect(window_rect, client_rect)) return;
64 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
66 wf->shadow = TRUE;
67 if (!data->shaped)
69 wf->title_bar = TRUE;
70 if (style & WS_SYSMENU) wf->close_button = TRUE;
71 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
72 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
73 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
76 if (style & WS_THICKFRAME)
78 wf->shadow = TRUE;
79 if (!data->shaped) wf->resizable = TRUE;
81 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
82 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
86 /*******************************************************************
87 * can_window_become_foreground
89 * Check if the specified window can become the foreground/key
90 * window.
92 static inline BOOL can_window_become_foreground(HWND hwnd)
94 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
96 if (!(style & WS_VISIBLE)) return FALSE;
97 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
98 if (hwnd == GetDesktopWindow()) return FALSE;
99 return !(style & WS_DISABLED);
103 /***********************************************************************
104 * get_cocoa_window_state
106 static void get_cocoa_window_state(struct macdrv_win_data *data,
107 DWORD style, DWORD ex_style,
108 struct macdrv_window_state* state)
110 memset(state, 0, sizeof(*state));
111 state->disabled = (style & WS_DISABLED) != 0;
112 state->no_foreground = !can_window_become_foreground(data->hwnd);
113 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
114 state->excluded_by_expose = state->excluded_by_cycle =
115 (!(ex_style & WS_EX_APPWINDOW) &&
116 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
117 if (IsRectEmpty(&data->window_rect))
118 state->excluded_by_expose = TRUE;
119 state->minimized = (style & WS_MINIMIZE) != 0;
120 state->minimized_valid = state->minimized != data->minimized;
121 state->maximized = (style & WS_MAXIMIZE) != 0;
125 /***********************************************************************
126 * get_mac_rect_offset
128 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
130 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect,
131 const RECT *window_rect, const RECT *client_rect)
133 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
135 rect->top = rect->bottom = rect->left = rect->right = 0;
137 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
139 if (!data->shaped)
141 struct macdrv_window_features wf;
142 get_cocoa_window_features(data, style, ex_style, &wf, window_rect, client_rect);
144 if (wf.title_bar)
146 style_mask |= WS_CAPTION;
147 ex_style_mask |= WS_EX_TOOLWINDOW;
149 if (wf.shadow)
151 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
152 ex_style_mask |= WS_EX_DLGMODALFRAME;
156 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
158 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
159 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
163 /***********************************************************************
164 * macdrv_window_to_mac_rect
166 * Convert a rect from client to Mac window coordinates
168 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect,
169 const RECT *window_rect, const RECT *client_rect)
171 RECT rc;
173 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
174 if (IsRectEmpty(rect)) return;
176 get_mac_rect_offset(data, style, &rc, window_rect, client_rect);
178 rect->left -= rc.left;
179 rect->right -= rc.right;
180 rect->top -= rc.top;
181 rect->bottom -= rc.bottom;
182 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
183 if (rect->left >= rect->right) rect->right = rect->left + 1;
187 /***********************************************************************
188 * macdrv_mac_to_window_rect
190 * Opposite of macdrv_window_to_mac_rect
192 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
194 RECT rc;
195 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
197 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
198 if (IsRectEmpty(rect)) return;
200 get_mac_rect_offset(data, style, &rc, &data->window_rect, &data->client_rect);
202 rect->left += rc.left;
203 rect->right += rc.right;
204 rect->top += rc.top;
205 rect->bottom += rc.bottom;
206 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
207 if (rect->left >= rect->right) rect->right = rect->left + 1;
211 /***********************************************************************
212 * constrain_window_frame
214 * Alter a window frame rectangle to fit within a) Cocoa's documented
215 * limits, and b) sane sizes, like twice the desktop rect.
217 static void constrain_window_frame(CGRect* frame)
219 CGRect desktop_rect = macdrv_get_desktop_rect();
220 int max_width, max_height;
222 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
223 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
225 if (frame->origin.x < -16000) frame->origin.x = -16000;
226 if (frame->origin.y < -16000) frame->origin.y = -16000;
227 if (frame->origin.x > 16000) frame->origin.x = 16000;
228 if (frame->origin.y > 16000) frame->origin.y = 16000;
229 if (frame->size.width > max_width) frame->size.width = max_width;
230 if (frame->size.height > max_height) frame->size.height = max_height;
234 /***********************************************************************
235 * alloc_win_data
237 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
239 struct macdrv_win_data *data;
241 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
243 data->hwnd = hwnd;
244 data->color_key = CLR_INVALID;
245 data->swap_interval = 1;
246 pthread_mutex_lock(&win_data_mutex);
247 if (!win_datas)
248 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
249 CFDictionarySetValue(win_datas, hwnd, data);
251 return data;
255 /***********************************************************************
256 * get_win_data
258 * Lock and return the data structure associated with a window.
260 struct macdrv_win_data *get_win_data(HWND hwnd)
262 struct macdrv_win_data *data;
264 if (!hwnd) return NULL;
265 pthread_mutex_lock(&win_data_mutex);
266 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
267 return data;
268 pthread_mutex_unlock(&win_data_mutex);
269 return NULL;
273 /***********************************************************************
274 * release_win_data
276 * Release the data returned by get_win_data.
278 void release_win_data(struct macdrv_win_data *data)
280 if (data) pthread_mutex_unlock(&win_data_mutex);
284 /***********************************************************************
285 * macdrv_get_cocoa_window
287 * Return the Mac window associated with the full area of a window
289 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
291 struct macdrv_win_data *data = get_win_data(hwnd);
292 macdrv_window ret = NULL;
293 if (data && (data->on_screen || !require_on_screen))
294 ret = data->cocoa_window;
295 release_win_data(data);
296 return ret;
300 /***********************************************************************
301 * macdrv_get_cocoa_view
303 * Return the Cocoa view associated with a window
305 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
307 struct macdrv_win_data *data = get_win_data(hwnd);
308 macdrv_view ret = data ? data->cocoa_view : NULL;
310 release_win_data(data);
311 return ret;
315 /***********************************************************************
316 * macdrv_get_client_cocoa_view
318 * Return the Cocoa view associated with a window's client area
320 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
322 struct macdrv_win_data *data = get_win_data(hwnd);
323 macdrv_view ret = data ? data->client_cocoa_view : NULL;
325 release_win_data(data);
326 return ret;
330 /***********************************************************************
331 * set_cocoa_window_properties
333 * Set the window properties for a Cocoa window based on its Windows
334 * properties.
336 static void set_cocoa_window_properties(struct macdrv_win_data *data)
338 DWORD style, ex_style;
339 HWND owner;
340 macdrv_window owner_win;
341 struct macdrv_window_features wf;
342 struct macdrv_window_state state;
344 style = GetWindowLongW(data->hwnd, GWL_STYLE);
345 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
347 owner = GetWindow(data->hwnd, GW_OWNER);
348 if (owner)
349 owner = GetAncestor(owner, GA_ROOT);
350 owner_win = macdrv_get_cocoa_window(owner, TRUE);
351 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
353 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
354 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
356 get_cocoa_window_state(data, style, ex_style, &state);
357 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
358 if (state.minimized_valid)
359 data->minimized = state.minimized;
363 /***********************************************************************
364 * sync_window_region
366 * Update the window region.
368 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
370 HRGN hrgn = win_region;
371 RGNDATA *region_data;
372 const CGRect* rects;
373 int count;
375 if (!data->cocoa_window) return;
376 data->shaped = FALSE;
378 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
380 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
381 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
382 return;
385 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
387 if (!(hrgn = NtGdiCreateRectRgn(0, 0, 0, 0))) return;
388 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
390 NtGdiDeleteObjectApp(hrgn);
391 hrgn = 0;
395 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
396 NtUserMirrorRgn(data->hwnd, hrgn);
397 if (hrgn)
399 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
400 data->window_rect.top - data->whole_rect.top);
402 region_data = get_region_data(hrgn, 0);
403 if (region_data)
405 rects = (CGRect*)region_data->Buffer;
406 count = region_data->rdh.nCount;
407 /* Special case optimization. If the region entirely encloses the Cocoa
408 window, it's the same as there being no region. It's potentially
409 hard/slow to test this for arbitrary regions, so we just check for
410 very simple regions. */
411 if (count == 1 && CGRectContainsRect(rects[0],
412 CGRectOffset(cgrect_from_rect(data->whole_rect), -data->whole_rect.left, -data->whole_rect.top)))
414 TRACE("optimizing for simple region that contains Cocoa content rect\n");
415 rects = NULL;
416 count = 0;
419 else
421 rects = NULL;
422 count = 0;
425 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
426 macdrv_set_window_shape(data->cocoa_window, rects, count);
428 HeapFree(GetProcessHeap(), 0, region_data);
429 data->shaped = (region_data != NULL);
431 if (hrgn && hrgn != win_region) NtGdiDeleteObjectApp(hrgn);
435 /***********************************************************************
436 * add_bounds_rect
438 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
440 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
441 bounds->left = min(bounds->left, rect->left);
442 bounds->top = min(bounds->top, rect->top);
443 bounds->right = max(bounds->right, rect->right);
444 bounds->bottom = max(bounds->bottom, rect->bottom);
448 /***********************************************************************
449 * sync_window_opacity
451 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
452 BOOL per_pixel_alpha, DWORD flags)
454 CGFloat opacity = 1.0;
455 BOOL needs_flush = FALSE;
457 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
459 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
460 macdrv_set_window_alpha(data->cocoa_window, opacity);
462 if (flags & LWA_COLORKEY)
464 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
465 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
466 key = RGB(0, 0, 0);
468 else
469 key = CLR_INVALID;
471 if (data->color_key != key)
473 if (key == CLR_INVALID)
475 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
476 macdrv_clear_window_color_key(data->cocoa_window);
478 else
480 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
481 GetRValue(key), GetGValue(key), GetBValue(key));
482 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
485 data->color_key = key;
486 needs_flush = TRUE;
489 if (!data->per_pixel_alpha != !per_pixel_alpha)
491 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
492 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
493 data->per_pixel_alpha = per_pixel_alpha;
494 needs_flush = TRUE;
497 if (needs_flush && data->surface)
499 RECT *bounds;
500 RECT rect;
502 rect = data->whole_rect;
503 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
504 data->surface->funcs->lock(data->surface);
505 bounds = data->surface->funcs->get_bounds(data->surface);
506 add_bounds_rect(bounds, &rect);
507 data->surface->funcs->unlock(data->surface);
512 /***********************************************************************
513 * sync_window_min_max_info
515 static void sync_window_min_max_info(HWND hwnd)
517 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
518 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
519 RECT win_rect, primary_monitor_rect;
520 MINMAXINFO minmax;
521 LONG adjustedStyle;
522 INT xinc, yinc;
523 WINDOWPLACEMENT wpl;
524 HMONITOR monitor;
525 struct macdrv_win_data *data;
527 TRACE("win %p\n", hwnd);
529 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
531 GetWindowRect(hwnd, &win_rect);
532 minmax.ptReserved.x = win_rect.left;
533 minmax.ptReserved.y = win_rect.top;
535 if ((style & WS_CAPTION) == WS_CAPTION)
536 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
537 else
538 adjustedStyle = style;
540 primary_monitor_rect.left = primary_monitor_rect.top = 0;
541 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
542 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
543 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
545 xinc = -primary_monitor_rect.left;
546 yinc = -primary_monitor_rect.top;
548 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
549 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
550 minmax.ptMaxPosition.x = -xinc;
551 minmax.ptMaxPosition.y = -yinc;
552 if (style & (WS_DLGFRAME | WS_BORDER))
554 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
555 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
557 else
559 minmax.ptMinTrackSize.x = 2 * xinc;
560 minmax.ptMinTrackSize.y = 2 * yinc;
562 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
563 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
565 wpl.length = sizeof(wpl);
566 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
568 minmax.ptMaxPosition = wpl.ptMaxPosition;
570 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
571 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
572 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
575 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
576 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
578 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
580 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
581 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
583 /* if the app didn't change the values, adapt them for the window's monitor */
584 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
586 MONITORINFO mon_info;
587 RECT monitor_rect;
589 mon_info.cbSize = sizeof(mon_info);
590 GetMonitorInfoW(monitor, &mon_info);
592 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
593 monitor_rect = mon_info.rcWork;
594 else
595 monitor_rect = mon_info.rcMonitor;
597 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
598 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
600 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
601 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
603 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
605 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
606 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
610 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
611 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
613 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
614 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
616 if ((data = get_win_data(hwnd)) && data->cocoa_window)
618 RECT min_rect, max_rect;
619 CGSize min_size, max_size;
621 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
622 macdrv_window_to_mac_rect(data, style, &min_rect, &data->window_rect, &data->client_rect);
623 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
625 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
626 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
627 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
628 else
630 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
631 macdrv_window_to_mac_rect(data, style, &max_rect, &data->window_rect, &data->client_rect);
632 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
635 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
636 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
639 release_win_data(data);
643 /**********************************************************************
644 * create_client_cocoa_view
646 * Create the Cocoa view for a window's client area
648 static void create_client_cocoa_view(struct macdrv_win_data *data)
650 RECT rect = data->client_rect;
651 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
653 if (data->client_cocoa_view)
654 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
655 else
657 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
658 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
660 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
664 /**********************************************************************
665 * create_cocoa_window
667 * Create the whole Mac window for a given window
669 static void create_cocoa_window(struct macdrv_win_data *data)
671 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
672 WCHAR text[1024];
673 struct macdrv_window_features wf;
674 CGRect frame;
675 DWORD style, ex_style;
676 HRGN win_rgn;
677 COLORREF key;
678 BYTE alpha;
679 DWORD layered_flags;
681 if ((win_rgn = NtGdiCreateRectRgn(0, 0, 0, 0)) &&
682 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
684 NtGdiDeleteObjectApp(win_rgn);
685 win_rgn = 0;
687 data->shaped = (win_rgn != 0);
689 style = GetWindowLongW(data->hwnd, GWL_STYLE);
690 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
692 data->whole_rect = data->window_rect;
693 macdrv_window_to_mac_rect(data, style, &data->whole_rect, &data->window_rect, &data->client_rect);
695 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
697 frame = cgrect_from_rect(data->whole_rect);
698 constrain_window_frame(&frame);
699 if (frame.size.width < 1 || frame.size.height < 1)
700 frame.size.width = frame.size.height = 1;
702 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
703 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
705 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
706 if (!data->cocoa_window) goto done;
707 create_client_cocoa_view(data);
709 set_cocoa_window_properties(data);
711 /* set the window text */
712 if (!InternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) text[0] = 0;
713 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
715 /* set the window region */
716 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
718 /* set the window opacity */
719 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
720 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
722 done:
723 if (win_rgn) NtGdiDeleteObjectApp(win_rgn);
727 /**********************************************************************
728 * destroy_cocoa_window
730 * Destroy the whole Mac window for a given window.
732 static void destroy_cocoa_window(struct macdrv_win_data *data)
734 if (!data->cocoa_window) return;
736 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
738 macdrv_destroy_cocoa_window(data->cocoa_window);
739 data->cocoa_window = 0;
740 data->on_screen = FALSE;
741 data->color_key = CLR_INVALID;
742 if (data->surface) window_surface_release(data->surface);
743 data->surface = NULL;
744 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
745 data->unminimized_surface = NULL;
749 /**********************************************************************
750 * create_cocoa_view
752 * Create the Cocoa view for a given Windows child window
754 static void create_cocoa_view(struct macdrv_win_data *data)
756 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
757 CGRect frame = cgrect_from_rect(data->window_rect);
759 data->shaped = FALSE;
760 data->whole_rect = data->window_rect;
762 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
763 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
765 if (!equal)
766 data->cocoa_view = macdrv_create_view(frame);
767 create_client_cocoa_view(data);
768 if (equal)
770 data->cocoa_view = data->client_cocoa_view;
771 macdrv_set_view_hidden(data->cocoa_view, TRUE);
772 macdrv_set_view_frame(data->cocoa_view, frame);
777 /**********************************************************************
778 * destroy_cocoa_view
780 * Destroy the Cocoa view for a given window.
782 static void destroy_cocoa_view(struct macdrv_win_data *data)
784 if (!data->cocoa_view) return;
786 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
788 if (data->cocoa_view != data->client_cocoa_view)
789 macdrv_dispose_view(data->cocoa_view);
790 data->cocoa_view = NULL;
791 data->on_screen = FALSE;
795 /***********************************************************************
796 * set_cocoa_view_parent
798 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
800 struct macdrv_win_data *parent_data = get_win_data(parent);
801 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
802 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
804 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
806 if (!cocoa_window && !superview)
807 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
809 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
810 release_win_data(parent_data);
814 /***********************************************************************
815 * macdrv_create_win_data
817 * Create a Mac data window structure for an existing window.
819 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
820 const RECT *client_rect)
822 struct macdrv_win_data *data;
823 HWND parent;
825 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
827 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
829 macdrv_init_thread_data();
830 return NULL;
833 /* don't create win data for HWND_MESSAGE windows */
834 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
836 if (!(data = alloc_win_data(hwnd))) return NULL;
838 data->whole_rect = data->window_rect = *window_rect;
839 data->client_rect = *client_rect;
841 if (parent == GetDesktopWindow())
843 create_cocoa_window(data);
844 TRACE("win %p/%p window %s whole %s client %s\n",
845 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
846 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
848 else
850 create_cocoa_view(data);
851 TRACE("win %p/%p window %s whole %s client %s\n",
852 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
853 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
855 set_cocoa_view_parent(data, parent);
858 return data;
862 /**********************************************************************
863 * is_owned_by
865 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
867 while (1)
869 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
870 if (!hwnd2)
871 hwnd2 = GetAncestor(hwnd, GA_ROOT);
872 if (!hwnd2 || hwnd2 == hwnd)
873 break;
874 if (hwnd2 == maybe_owner)
875 return TRUE;
876 hwnd = hwnd2;
879 return FALSE;
883 /**********************************************************************
884 * is_all_the_way_front
886 static BOOL is_all_the_way_front(HWND hwnd)
888 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
889 HWND prev = hwnd;
891 while ((prev = GetWindow(prev, GW_HWNDPREV)))
893 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
894 return TRUE;
895 if (!is_owned_by(prev, hwnd))
896 return FALSE;
899 return TRUE;
903 /***********************************************************************
904 * set_focus
906 static void set_focus(HWND hwnd, BOOL raise)
908 struct macdrv_win_data *data;
910 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
912 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
913 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
915 if (!(data = get_win_data(hwnd))) return;
917 if (data->cocoa_window && data->on_screen)
919 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
920 /* Set Mac focus */
921 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
922 activate_on_focus_time = 0;
925 release_win_data(data);
928 /***********************************************************************
929 * show_window
931 static void show_window(struct macdrv_win_data *data)
933 if (data->cocoa_window)
935 HWND prev = NULL;
936 HWND next = NULL;
937 macdrv_window prev_window = NULL;
938 macdrv_window next_window = NULL;
939 BOOL activate = FALSE;
940 GUITHREADINFO info;
942 /* find window that this one must be after */
943 prev = GetWindow(data->hwnd, GW_HWNDPREV);
944 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
945 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
946 prev = GetWindow(prev, GW_HWNDPREV);
947 if (!prev_window)
949 /* find window that this one must be before */
950 next = GetWindow(data->hwnd, GW_HWNDNEXT);
951 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
952 (next_window = macdrv_get_cocoa_window(next, TRUE))))
953 next = GetWindow(next, GW_HWNDNEXT);
956 TRACE("win %p/%p below %p/%p above %p/%p\n",
957 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
959 if (!prev_window)
960 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
961 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
962 data->on_screen = TRUE;
964 info.cbSize = sizeof(info);
965 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
966 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
967 set_focus(info.hwndFocus, FALSE);
968 if (activate)
969 activate_on_focus_time = 0;
971 else
973 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
975 macdrv_set_view_hidden(data->cocoa_view, FALSE);
976 data->on_screen = TRUE;
981 /***********************************************************************
982 * hide_window
984 static void hide_window(struct macdrv_win_data *data)
986 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
988 if (data->cocoa_window)
989 macdrv_hide_cocoa_window(data->cocoa_window);
990 else
991 macdrv_set_view_hidden(data->cocoa_view, TRUE);
992 data->on_screen = FALSE;
996 /***********************************************************************
997 * sync_window_z_order
999 static void sync_window_z_order(struct macdrv_win_data *data)
1001 if (data->cocoa_view)
1003 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
1004 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
1005 macdrv_window window = NULL;
1006 HWND prev;
1007 HWND next = NULL;
1008 macdrv_view prev_view = NULL;
1009 macdrv_view next_view = NULL;
1011 if (!superview)
1013 window = macdrv_get_cocoa_window(parent, FALSE);
1014 if (!window)
1015 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1018 /* find window that this one must be after */
1019 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1020 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1021 prev = GetWindow(prev, GW_HWNDPREV);
1022 if (!prev_view)
1024 /* find window that this one must be before */
1025 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1026 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1027 next = GetWindow(next, GW_HWNDNEXT);
1030 TRACE("win %p/%p below %p/%p above %p/%p\n",
1031 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1033 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1035 else if (data->on_screen)
1036 show_window(data);
1040 /***********************************************************************
1041 * get_region_data
1043 * Calls GetRegionData on the given region and converts the rectangle
1044 * array to CGRect format. The returned buffer must be freed by
1045 * caller using HeapFree(GetProcessHeap(),...).
1046 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1048 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1050 RGNDATA *data;
1051 DWORD size;
1052 int i;
1053 RECT *rect;
1054 CGRect *cgrect;
1056 if (!hrgn || !(size = NtGdiGetRegionData(hrgn, 0, NULL))) return NULL;
1057 if (sizeof(CGRect) > sizeof(RECT))
1059 /* add extra size for CGRect array */
1060 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1061 size += count * (sizeof(CGRect) - sizeof(RECT));
1063 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1064 if (!NtGdiGetRegionData(hrgn, size, data))
1066 HeapFree(GetProcessHeap(), 0, data);
1067 return NULL;
1070 rect = (RECT *)data->Buffer;
1071 cgrect = (CGRect *)data->Buffer;
1072 if (hdc_lptodp) /* map to device coordinates */
1074 NtGdiTransformPoints(hdc_lptodp, (POINT *)rect, (POINT *)rect,
1075 data->rdh.nCount * 2, NtGdiLPtoDP);
1076 for (i = 0; i < data->rdh.nCount; i++)
1078 if (rect[i].right < rect[i].left)
1080 INT tmp = rect[i].right;
1081 rect[i].right = rect[i].left;
1082 rect[i].left = tmp;
1084 if (rect[i].bottom < rect[i].top)
1086 INT tmp = rect[i].bottom;
1087 rect[i].bottom = rect[i].top;
1088 rect[i].top = tmp;
1093 if (sizeof(CGRect) > sizeof(RECT))
1095 /* need to start from the end */
1096 for (i = data->rdh.nCount-1; i >= 0; i--)
1097 cgrect[i] = cgrect_from_rect(rect[i]);
1099 else
1101 for (i = 0; i < data->rdh.nCount; i++)
1102 cgrect[i] = cgrect_from_rect(rect[i]);
1104 return data;
1108 /***********************************************************************
1109 * sync_client_view_position
1111 static void sync_client_view_position(struct macdrv_win_data *data)
1113 if (data->cocoa_view != data->client_cocoa_view)
1115 RECT rect = data->client_rect;
1116 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1117 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1118 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1123 /***********************************************************************
1124 * sync_window_position
1126 * Synchronize the Mac window position with the Windows one
1128 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1129 const RECT *old_whole_rect)
1131 CGRect frame = cgrect_from_rect(data->whole_rect);
1132 BOOL force_z_order = FALSE;
1134 if (data->cocoa_window)
1136 if (data->minimized) return;
1138 constrain_window_frame(&frame);
1139 if (frame.size.width < 1 || frame.size.height < 1)
1140 frame.size.width = frame.size.height = 1;
1142 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1144 else
1146 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1147 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1149 if (were_equal && !now_equal)
1151 data->cocoa_view = macdrv_create_view(frame);
1152 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1153 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1154 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1155 force_z_order = TRUE;
1157 else if (!were_equal && now_equal)
1159 macdrv_dispose_view(data->cocoa_view);
1160 data->cocoa_view = data->client_cocoa_view;
1161 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1162 macdrv_set_view_frame(data->cocoa_view, frame);
1163 force_z_order = TRUE;
1165 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1166 macdrv_set_view_frame(data->cocoa_view, frame);
1169 sync_client_view_position(data);
1171 if (old_window_rect && old_whole_rect &&
1172 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1173 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1174 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1175 sync_window_region(data, (HRGN)1);
1177 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1178 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1179 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1181 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1182 sync_window_z_order(data);
1186 /***********************************************************************
1187 * move_window_bits
1189 * Move the window bits when a window is moved.
1191 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1192 const RECT *old_client_rect, const RECT *new_client_rect,
1193 const RECT *new_window_rect)
1195 RECT src_rect = *old_rect;
1196 RECT dst_rect = *new_rect;
1197 HDC hdc_src, hdc_dst;
1198 HRGN rgn;
1199 HWND parent = 0;
1201 if (!window)
1203 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1204 parent = GetAncestor(hwnd, GA_PARENT);
1205 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1206 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1208 else
1210 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1211 /* make src rect relative to the old position of the window */
1212 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1213 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1214 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1217 rgn = NtGdiCreateRectRgn(dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom);
1218 NtGdiExtSelectClipRgn(hdc_dst, rgn, RGN_COPY);
1219 NtGdiDeleteObjectApp(rgn);
1220 ExcludeUpdateRgn(hdc_dst, hwnd);
1222 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1223 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1224 NtGdiBitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1225 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1226 hdc_src, src_rect.left, src_rect.top, SRCCOPY, 0, 0);
1228 ReleaseDC(hwnd, hdc_dst);
1229 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1233 /**********************************************************************
1234 * activate_on_following_focus
1236 void activate_on_following_focus(void)
1238 activate_on_focus_time = GetTickCount();
1239 if (!activate_on_focus_time) activate_on_focus_time = 1;
1243 /***********************************************************************
1244 * set_app_icon
1246 static void set_app_icon(void)
1248 CFArrayRef images = create_app_icon_images();
1249 if (images)
1251 macdrv_set_application_icon(images);
1252 CFRelease(images);
1257 /**********************************************************************
1258 * set_capture_window_for_move
1260 static BOOL set_capture_window_for_move(HWND hwnd)
1262 HWND previous = 0;
1263 BOOL ret;
1265 SERVER_START_REQ(set_capture_window)
1267 req->handle = wine_server_user_handle(hwnd);
1268 req->flags = CAPTURE_MOVESIZE;
1269 if ((ret = !wine_server_call_err(req)))
1271 previous = wine_server_ptr_handle(reply->previous);
1272 hwnd = wine_server_ptr_handle(reply->full_handle);
1275 SERVER_END_REQ;
1277 if (ret)
1279 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1281 if (previous && previous != hwnd)
1282 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1284 return ret;
1288 /***********************************************************************
1289 * move_window
1291 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1292 * moving top-level windows and enforcing Mac-style constraints like
1293 * keeping the top of the window within the work area.
1295 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1297 MSG msg;
1298 RECT origRect, movedRect, desktopRect;
1299 LONG hittest = (LONG)(wparam & 0x0f);
1300 POINT capturePoint;
1301 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1302 BOOL moved = FALSE;
1303 DWORD dwPoint = GetMessagePos();
1304 INT captionHeight;
1305 HMONITOR mon = 0;
1306 MONITORINFO info;
1308 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1309 if (hittest && hittest != HTCAPTION) return -1;
1311 capturePoint.x = (short)LOWORD(dwPoint);
1312 capturePoint.y = (short)HIWORD(dwPoint);
1313 ClipCursor(NULL);
1315 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1317 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1318 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1319 captionHeight = -origRect.top;
1320 else
1321 captionHeight = 0;
1323 GetWindowRect(hwnd, &origRect);
1324 movedRect = origRect;
1326 if (!hittest)
1328 /* Move pointer to the center of the caption */
1329 RECT rect = origRect;
1331 /* Note: to be exactly centered we should take the different types
1332 * of border into account, but it shouldn't make more than a few pixels
1333 * of difference so let's not bother with that */
1334 rect.top += GetSystemMetrics(SM_CYBORDER);
1335 if (style & WS_SYSMENU)
1336 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1337 if (style & WS_MINIMIZEBOX)
1338 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1339 if (style & WS_MAXIMIZEBOX)
1340 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1341 capturePoint.x = (rect.right + rect.left) / 2;
1342 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1344 SetCursorPos(capturePoint.x, capturePoint.y);
1345 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1348 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1349 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1350 info.cbSize = sizeof(info);
1351 if (mon && !GetMonitorInfoW(mon, &info))
1352 mon = 0;
1354 /* repaint the window before moving it around */
1355 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1357 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1358 set_capture_window_for_move(hwnd);
1360 while(1)
1362 POINT pt;
1363 int dx = 0, dy = 0;
1364 HMONITOR newmon;
1366 if (!GetMessageW(&msg, 0, 0, 0)) break;
1367 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1369 /* Exit on button-up, Return, or Esc */
1370 if (msg.message == WM_LBUTTONUP ||
1371 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1372 break;
1374 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1376 TranslateMessage(&msg);
1377 DispatchMessageW(&msg);
1378 continue; /* We are not interested in other messages */
1381 pt = msg.pt;
1383 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1385 case VK_UP: pt.y -= 8; break;
1386 case VK_DOWN: pt.y += 8; break;
1387 case VK_LEFT: pt.x -= 8; break;
1388 case VK_RIGHT: pt.x += 8; break;
1391 pt.x = max(pt.x, desktopRect.left);
1392 pt.x = min(pt.x, desktopRect.right - 1);
1393 pt.y = max(pt.y, desktopRect.top);
1394 pt.y = min(pt.y, desktopRect.bottom - 1);
1396 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1398 if (GetMonitorInfoW(newmon, &info))
1399 mon = newmon;
1400 else
1401 mon = 0;
1404 if (mon)
1406 /* wineserver clips the cursor position to the virtual desktop rect but,
1407 if the display configuration is non-rectangular, that could still
1408 leave the logical cursor position outside of any display. The window
1409 could keep moving as you push the cursor against a display edge, even
1410 though the visible cursor doesn't keep moving. The following keeps
1411 the window movement in sync with the visible cursor. */
1412 pt.x = max(pt.x, info.rcMonitor.left);
1413 pt.x = min(pt.x, info.rcMonitor.right - 1);
1414 pt.y = max(pt.y, info.rcMonitor.top);
1415 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1417 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1418 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1419 we want to enforce these constraints:
1420 movedRect.left + dx < info.rcWork.right
1421 movedRect.right + dx > info.rcWork.left
1422 movedRect.top + captionHeight + dy < info.rcWork.bottom
1423 movedRect.bottom + dy > info.rcWork.top
1424 movedRect.top + dy >= info.rcWork.top
1425 The first four keep at least one edge barely in the work area.
1426 The last keeps the top (i.e. the title bar) in the work area.
1427 The fourth is redundant with the last, so can be ignored.
1429 Substituting for dx and dy and rearranging gives us...
1431 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1432 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1433 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1434 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1437 dx = pt.x - capturePoint.x;
1438 dy = pt.y - capturePoint.y;
1440 if (dx || dy)
1442 moved = TRUE;
1444 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1445 else
1447 OffsetRect(&movedRect, dx, dy);
1448 capturePoint = pt;
1450 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1451 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1452 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1457 set_capture_window_for_move(0);
1459 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1460 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1462 /* if the move is canceled, restore the previous position */
1463 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1465 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1466 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1469 return 0;
1473 /***********************************************************************
1474 * perform_window_command
1476 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1478 DWORD style;
1480 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1481 hwnd, style_any, style_none, command, hittest);
1483 style = GetWindowLongW(hwnd, GWL_STYLE);
1484 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1486 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1487 return;
1490 if (GetActiveWindow() != hwnd)
1492 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1493 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1494 switch (ma)
1496 case MA_NOACTIVATEANDEAT:
1497 case MA_ACTIVATEANDEAT:
1498 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1499 return;
1500 case MA_NOACTIVATE:
1501 break;
1502 case MA_ACTIVATE:
1503 case 0:
1504 SetActiveWindow(hwnd);
1505 break;
1506 default:
1507 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1508 break;
1512 TRACE("changing win %p\n", hwnd);
1513 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1517 /**********************************************************************
1518 * CreateDesktopWindow (MACDRV.@)
1520 BOOL macdrv_CreateDesktopWindow(HWND hwnd)
1522 unsigned int width, height;
1524 TRACE("%p\n", hwnd);
1526 /* retrieve the real size of the desktop */
1527 SERVER_START_REQ(get_window_rectangles)
1529 req->handle = wine_server_user_handle(hwnd);
1530 req->relative = COORDS_CLIENT;
1531 wine_server_call(req);
1532 width = reply->window.right;
1533 height = reply->window.bottom;
1535 SERVER_END_REQ;
1537 if (!width && !height) /* not initialized yet */
1539 CGRect rect = macdrv_get_desktop_rect();
1541 SERVER_START_REQ(set_window_pos)
1543 req->handle = wine_server_user_handle(hwnd);
1544 req->previous = 0;
1545 req->swp_flags = SWP_NOZORDER;
1546 req->window.left = CGRectGetMinX(rect);
1547 req->window.top = CGRectGetMinY(rect);
1548 req->window.right = CGRectGetMaxX(rect);
1549 req->window.bottom = CGRectGetMaxY(rect);
1550 req->client = req->window;
1551 wine_server_call(req);
1553 SERVER_END_REQ;
1556 set_app_icon();
1557 return TRUE;
1561 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
1563 LRESULT macdrv_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1565 switch (msg)
1567 case WM_WINE_NOTIFY_ACTIVITY:
1569 /* This wakes from display sleep, but doesn't affect the screen saver. */
1570 static IOPMAssertionID assertion;
1571 IOPMAssertionDeclareUserActivity(CFSTR("Wine user input"), kIOPMUserActiveLocal, &assertion);
1573 /* This prevents the screen saver, but doesn't wake from display sleep. */
1574 /* It's deprecated, but there's no better alternative. */
1575 #pragma clang diagnostic push
1576 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1577 UpdateSystemActivity(UsrActivity);
1578 #pragma clang diagnostic pop
1579 break;
1582 return NtUserMessageCall(hwnd, msg, wp, lp, 0, NtUserDefWindowProc, FALSE);
1585 /**********************************************************************
1586 * CreateWindow (MACDRV.@)
1588 BOOL macdrv_CreateWindow(HWND hwnd)
1590 if (hwnd == GetDesktopWindow())
1592 macdrv_init_clipboard();
1594 return TRUE;
1598 /***********************************************************************
1599 * DestroyWindow (MACDRV.@)
1601 void macdrv_DestroyWindow(HWND hwnd)
1603 struct macdrv_win_data *data;
1605 TRACE("%p\n", hwnd);
1607 if (!(data = get_win_data(hwnd))) return;
1609 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1610 if (data->drag_event) SetEvent(data->drag_event);
1612 destroy_cocoa_window(data);
1613 destroy_cocoa_view(data);
1614 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1616 CFDictionaryRemoveValue(win_datas, hwnd);
1617 release_win_data(data);
1618 HeapFree(GetProcessHeap(), 0, data);
1622 /*****************************************************************
1623 * SetFocus (MACDRV.@)
1625 * Set the Mac focus.
1627 void macdrv_SetFocus(HWND hwnd)
1629 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1631 TRACE("%p\n", hwnd);
1633 if (!thread_data) return;
1634 thread_data->dead_key_state = 0;
1635 set_focus(hwnd, TRUE);
1639 /***********************************************************************
1640 * SetLayeredWindowAttributes (MACDRV.@)
1642 * Set transparency attributes for a layered window.
1644 void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1646 struct macdrv_win_data *data = get_win_data(hwnd);
1648 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1650 if (data)
1652 data->layered = TRUE;
1653 data->ulw_layered = FALSE;
1654 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1655 if (data->cocoa_window)
1657 sync_window_opacity(data, key, alpha, FALSE, flags);
1658 /* since layered attributes are now set, can now show the window */
1659 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1660 show_window(data);
1662 release_win_data(data);
1664 else
1665 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1669 /*****************************************************************
1670 * SetParent (MACDRV.@)
1672 void macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1674 struct macdrv_win_data *data;
1676 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1678 if (parent == old_parent) return;
1679 if (!(data = get_win_data(hwnd))) return;
1681 if (parent != GetDesktopWindow()) /* a child window */
1683 if (old_parent == GetDesktopWindow())
1685 /* destroy the old Mac window */
1686 destroy_cocoa_window(data);
1687 create_cocoa_view(data);
1690 set_cocoa_view_parent(data, parent);
1692 else /* new top level window */
1694 destroy_cocoa_view(data);
1695 create_cocoa_window(data);
1697 release_win_data(data);
1701 /***********************************************************************
1702 * SetWindowRgn (MACDRV.@)
1704 * Assign specified region to window (for non-rectangular windows)
1706 void macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1708 struct macdrv_win_data *data;
1710 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1712 if ((data = get_win_data(hwnd)))
1714 sync_window_region(data, hrgn);
1715 release_win_data(data);
1717 else
1719 DWORD procid;
1721 GetWindowThreadProcessId(hwnd, &procid);
1722 if (procid != GetCurrentProcessId())
1723 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1728 /***********************************************************************
1729 * SetWindowStyle (MACDRV.@)
1731 * Update the state of the Cocoa window to reflect a style change
1733 void macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1735 struct macdrv_win_data *data;
1737 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1739 if (hwnd == GetDesktopWindow()) return;
1740 if (!(data = get_win_data(hwnd))) return;
1742 if (data->cocoa_window)
1744 DWORD changed = style->styleNew ^ style->styleOld;
1746 set_cocoa_window_properties(data);
1748 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1750 data->layered = FALSE;
1751 data->ulw_layered = FALSE;
1752 sync_window_opacity(data, 0, 0, FALSE, 0);
1753 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1756 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1757 sync_window_region(data, (HRGN)1);
1760 release_win_data(data);
1764 /*****************************************************************
1765 * SetWindowText (MACDRV.@)
1767 void macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1769 macdrv_window win;
1771 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1773 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1774 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1778 /***********************************************************************
1779 * ShowWindow (MACDRV.@)
1781 UINT macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1783 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1784 struct macdrv_win_data *data = get_win_data(hwnd);
1785 CGRect frame;
1787 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1788 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1790 if (!data || !data->cocoa_window) goto done;
1791 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1793 if (rect->left != -32000 || rect->top != -32000)
1795 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1796 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1798 goto done;
1800 if (!data->on_screen) goto done;
1802 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1804 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1805 goto done;
1807 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1808 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1809 goto done;
1811 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1812 *rect = rect_from_cgrect(frame);
1813 macdrv_mac_to_window_rect(data, rect);
1814 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1815 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1817 done:
1818 release_win_data(data);
1819 return swp;
1823 /***********************************************************************
1824 * SysCommand (MACDRV.@)
1826 * Perform WM_SYSCOMMAND handling.
1828 LRESULT macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1830 struct macdrv_win_data *data;
1831 LRESULT ret = -1;
1832 WPARAM command = wparam & 0xfff0;
1834 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1836 if (!(data = get_win_data(hwnd))) goto done;
1837 if (!data->cocoa_window || !data->on_screen) goto done;
1839 /* prevent a simple ALT press+release from activating the system menu,
1840 as that can get confusing */
1841 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1842 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1844 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1845 ret = 0;
1848 if (command == SC_MOVE)
1850 release_win_data(data);
1851 return move_window(hwnd, wparam);
1854 done:
1855 release_win_data(data);
1856 return ret;
1860 /***********************************************************************
1861 * UpdateLayeredWindow (MACDRV.@)
1863 BOOL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1864 const RECT *window_rect)
1866 struct window_surface *surface;
1867 struct macdrv_win_data *data;
1868 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1869 BYTE alpha;
1870 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1871 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1872 void *src_bits, *dst_bits;
1873 RECT rect, src_rect;
1874 HDC hdc = 0;
1875 HBITMAP dib;
1876 BOOL ret = FALSE;
1878 if (!(data = get_win_data(hwnd))) return FALSE;
1880 data->layered = TRUE;
1881 data->ulw_layered = TRUE;
1883 rect = *window_rect;
1884 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1886 surface = data->surface;
1887 if (!surface || !EqualRect(&surface->rect, &rect))
1889 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1890 set_window_surface(data->cocoa_window, data->surface);
1891 if (surface) window_surface_release(surface);
1892 surface = data->surface;
1893 if (data->unminimized_surface)
1895 window_surface_release(data->unminimized_surface);
1896 data->unminimized_surface = NULL;
1899 else set_surface_use_alpha(surface, TRUE);
1901 if (surface) window_surface_add_ref(surface);
1902 release_win_data(data);
1904 if (!surface) return FALSE;
1905 if (!info->hdcSrc)
1907 window_surface_release(surface);
1908 return TRUE;
1911 if (info->dwFlags & ULW_ALPHA)
1913 /* Apply SourceConstantAlpha via window alpha, not blend. */
1914 alpha = info->pblend->SourceConstantAlpha;
1915 blend = *info->pblend;
1916 blend.SourceConstantAlpha = 0xff;
1918 else
1919 alpha = 0xff;
1921 dst_bits = surface->funcs->get_info(surface, bmi);
1923 if (!(dib = NtGdiCreateDIBSection(info->hdcDst, NULL, 0, bmi, DIB_RGB_COLORS,
1924 0, 0, 0, &src_bits))) goto done;
1925 if (!(hdc = NtGdiCreateCompatibleDC(0))) goto done;
1927 NtGdiSelectBitmap(hdc, dib);
1928 if (info->prcDirty)
1930 IntersectRect(&rect, &rect, info->prcDirty);
1931 surface->funcs->lock(surface);
1932 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1933 surface->funcs->unlock(surface);
1934 NtGdiPatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1936 src_rect = rect;
1937 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1938 NtGdiTransformPoints(info->hdcSrc, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP);
1940 if (!(ret = NtGdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1941 info->hdcSrc, src_rect.left, src_rect.top,
1942 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1943 blend, 0)))
1944 goto done;
1946 if ((data = get_win_data(hwnd)))
1948 if (surface == data->surface)
1950 surface->funcs->lock(surface);
1951 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1952 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1953 surface->funcs->unlock(surface);
1954 surface->funcs->flush(surface);
1957 /* The ULW flags are a superset of the LWA flags. */
1958 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1960 release_win_data(data);
1963 done:
1964 window_surface_release(surface);
1965 if (hdc) NtGdiDeleteObjectApp(hdc);
1966 if (dib) NtGdiDeleteObjectApp(dib);
1967 return ret;
1971 /**********************************************************************
1972 * WindowMessage (MACDRV.@)
1974 LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1976 struct macdrv_win_data *data;
1978 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1980 switch(msg)
1982 case WM_MACDRV_SET_WIN_REGION:
1983 if ((data = get_win_data(hwnd)))
1985 sync_window_region(data, (HRGN)1);
1986 release_win_data(data);
1988 return 0;
1989 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1990 if (hwnd == GetDesktopWindow())
1992 CGRect new_desktop_rect;
1993 RECT current_desktop_rect;
1995 macdrv_reset_device_metrics();
1996 new_desktop_rect = macdrv_get_desktop_rect();
1997 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1998 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
2000 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
2001 SMTO_ABORTIFHUNG, 2000, NULL);
2002 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
2003 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
2004 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
2005 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
2006 SMTO_ABORTIFHUNG, 2000, NULL);
2009 return 0;
2010 case WM_MACDRV_RESET_DEVICE_METRICS:
2011 macdrv_reset_device_metrics();
2012 return 0;
2013 case WM_MACDRV_DISPLAYCHANGE:
2014 macdrv_reassert_window_position(hwnd);
2015 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
2016 return 0;
2017 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
2018 activate_on_following_focus();
2019 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
2020 return 0;
2023 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
2024 return 0;
2028 static inline RECT get_surface_rect(const RECT *visible_rect)
2030 RECT rect;
2031 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
2033 IntersectRect(&rect, visible_rect, &desktop_rect);
2034 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2035 rect.left &= ~127;
2036 rect.top &= ~127;
2037 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2038 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2039 return rect;
2043 /***********************************************************************
2044 * WindowPosChanging (MACDRV.@)
2046 BOOL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2047 const RECT *window_rect, const RECT *client_rect,
2048 RECT *visible_rect, struct window_surface **surface)
2050 struct macdrv_win_data *data = get_win_data(hwnd);
2051 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2052 RECT surface_rect;
2054 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2055 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2056 wine_dbgstr_rect(visible_rect), surface);
2058 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return TRUE;
2060 *visible_rect = *window_rect;
2061 macdrv_window_to_mac_rect(data, style, visible_rect, window_rect, client_rect);
2062 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2063 wine_dbgstr_rect(visible_rect));
2065 /* create the window surface if necessary */
2066 if (!data->cocoa_window) goto done;
2067 if (swp_flags & SWP_HIDEWINDOW) goto done;
2068 if (data->ulw_layered) goto done;
2070 if (*surface) window_surface_release(*surface);
2071 *surface = NULL;
2073 surface_rect = get_surface_rect(visible_rect);
2074 if (data->surface)
2076 if (EqualRect(&data->surface->rect, &surface_rect))
2078 /* existing surface is good enough */
2079 surface_clip_to_visible_rect(data->surface, visible_rect);
2080 window_surface_add_ref(data->surface);
2081 *surface = data->surface;
2082 goto done;
2085 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2087 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2089 done:
2090 release_win_data(data);
2091 return TRUE;
2095 /***********************************************************************
2096 * WindowPosChanged (MACDRV.@)
2098 void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2099 const RECT *window_rect, const RECT *client_rect,
2100 const RECT *visible_rect, const RECT *valid_rects,
2101 struct window_surface *surface)
2103 struct macdrv_thread_data *thread_data;
2104 struct macdrv_win_data *data;
2105 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2106 RECT old_window_rect, old_whole_rect, old_client_rect;
2108 if (!(data = get_win_data(hwnd))) return;
2110 thread_data = macdrv_thread_data();
2112 old_window_rect = data->window_rect;
2113 old_whole_rect = data->whole_rect;
2114 old_client_rect = data->client_rect;
2115 data->window_rect = *window_rect;
2116 data->whole_rect = *visible_rect;
2117 data->client_rect = *client_rect;
2118 if (data->cocoa_window && !data->ulw_layered)
2120 if (surface) window_surface_add_ref(surface);
2121 if (new_style & WS_MINIMIZE)
2123 if (!data->unminimized_surface && data->surface)
2125 data->unminimized_surface = data->surface;
2126 window_surface_add_ref(data->unminimized_surface);
2129 else
2131 set_window_surface(data->cocoa_window, surface);
2132 if (data->unminimized_surface)
2134 window_surface_release(data->unminimized_surface);
2135 data->unminimized_surface = NULL;
2138 if (data->surface) window_surface_release(data->surface);
2139 data->surface = surface;
2142 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2143 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2144 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2145 new_style, swp_flags, surface);
2147 if (!IsRectEmpty(&valid_rects[0]))
2149 macdrv_window window = data->cocoa_window;
2150 int x_offset = old_whole_rect.left - data->whole_rect.left;
2151 int y_offset = old_whole_rect.top - data->whole_rect.top;
2153 /* if all that happened is that the whole window moved, copy everything */
2154 if (!(swp_flags & SWP_FRAMECHANGED) &&
2155 old_whole_rect.right - data->whole_rect.right == x_offset &&
2156 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2157 old_client_rect.left - data->client_rect.left == x_offset &&
2158 old_client_rect.right - data->client_rect.right == x_offset &&
2159 old_client_rect.top - data->client_rect.top == y_offset &&
2160 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2161 EqualRect(&valid_rects[0], &data->client_rect))
2163 /* A Cocoa window's bits are moved automatically */
2164 if (!window && (x_offset != 0 || y_offset != 0))
2166 release_win_data(data);
2167 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2168 &old_client_rect, client_rect, window_rect);
2169 if (!(data = get_win_data(hwnd))) return;
2172 else
2174 release_win_data(data);
2175 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2176 &old_client_rect, client_rect, window_rect);
2177 if (!(data = get_win_data(hwnd))) return;
2181 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2183 if (!data->cocoa_window && !data->cocoa_view) goto done;
2185 if (data->on_screen)
2187 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2188 hide_window(data);
2191 /* check if we are currently processing an event relevant to this window */
2192 if (thread_data && thread_data->current_event &&
2193 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2194 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2195 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2197 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2198 sync_client_view_position(data);
2200 else
2202 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2203 if (data->cocoa_window)
2204 set_cocoa_window_properties(data);
2207 if (new_style & WS_VISIBLE)
2209 if (data->cocoa_window)
2211 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2212 set_cocoa_window_properties(data);
2214 /* layered windows are not shown until their attributes are set */
2215 if (!data->on_screen &&
2216 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2217 show_window(data);
2219 else if (!data->on_screen)
2220 show_window(data);
2223 done:
2224 release_win_data(data);
2228 /***********************************************************************
2229 * macdrv_window_close_requested
2231 * Handler for WINDOW_CLOSE_REQUESTED events.
2233 void macdrv_window_close_requested(HWND hwnd)
2235 HMENU sysmenu;
2237 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2239 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2240 return;
2243 sysmenu = GetSystemMenu(hwnd, FALSE);
2244 if (sysmenu)
2246 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2247 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2249 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2250 return;
2254 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2258 /***********************************************************************
2259 * macdrv_window_frame_changed
2261 * Handler for WINDOW_FRAME_CHANGED events.
2263 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2265 struct macdrv_win_data *data;
2266 RECT rect;
2267 HWND parent;
2268 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2269 int width, height;
2270 BOOL being_dragged;
2272 if (!hwnd) return;
2273 if (!(data = get_win_data(hwnd))) return;
2274 if (!data->on_screen || data->minimized)
2276 release_win_data(data);
2277 return;
2280 /* Get geometry */
2282 parent = GetAncestor(hwnd, GA_PARENT);
2284 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2285 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2286 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2288 rect = rect_from_cgrect(event->window_frame_changed.frame);
2289 macdrv_mac_to_window_rect(data, &rect);
2290 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2292 width = rect.right - rect.left;
2293 height = rect.bottom - rect.top;
2295 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2296 flags |= SWP_NOMOVE;
2297 else
2298 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2299 data->window_rect.top, rect.left, rect.top);
2301 if ((data->window_rect.right - data->window_rect.left == width &&
2302 data->window_rect.bottom - data->window_rect.top == height) ||
2303 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2304 flags |= SWP_NOSIZE;
2305 else
2306 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2307 data->window_rect.bottom - data->window_rect.top, width, height);
2309 being_dragged = data->drag_event != NULL;
2310 release_win_data(data);
2312 if (event->window_frame_changed.fullscreen)
2313 flags |= SWP_NOSENDCHANGING;
2314 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2316 int send_sizemove = !event->window_frame_changed.in_resize && !being_dragged && !event->window_frame_changed.skip_size_move_loop;
2317 if (send_sizemove)
2318 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2319 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2320 if (send_sizemove)
2321 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2326 /***********************************************************************
2327 * macdrv_window_got_focus
2329 * Handler for WINDOW_GOT_FOCUS events.
2331 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2333 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2335 if (!hwnd) return;
2337 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2338 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2339 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2341 if (can_window_become_foreground(hwnd) && !(style & WS_MINIMIZE))
2343 /* simulate a mouse click on the menu to find out
2344 * whether the window wants to be activated */
2345 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2346 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2347 MAKELONG(HTMENU, WM_LBUTTONDOWN));
2348 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2350 TRACE("setting foreground window to %p\n", hwnd);
2351 SetForegroundWindow(hwnd);
2352 return;
2356 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2357 macdrv_window_rejected_focus(event);
2361 /***********************************************************************
2362 * macdrv_window_lost_focus
2364 * Handler for WINDOW_LOST_FOCUS events.
2366 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2368 if (!hwnd) return;
2370 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2372 if (hwnd == GetForegroundWindow())
2374 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2375 if (hwnd == GetForegroundWindow())
2376 SetForegroundWindow(GetDesktopWindow());
2381 /***********************************************************************
2382 * macdrv_app_activated
2384 * Handler for APP_ACTIVATED events.
2386 void macdrv_app_activated(void)
2388 TRACE("\n");
2389 macdrv_UpdateClipboard();
2393 /***********************************************************************
2394 * macdrv_app_deactivated
2396 * Handler for APP_DEACTIVATED events.
2398 void macdrv_app_deactivated(void)
2400 ClipCursor(NULL);
2402 if (GetActiveWindow() == GetForegroundWindow())
2404 TRACE("setting fg to desktop\n");
2405 SetForegroundWindow(GetDesktopWindow());
2410 /***********************************************************************
2411 * macdrv_window_maximize_requested
2413 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2415 void macdrv_window_maximize_requested(HWND hwnd)
2417 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2421 /***********************************************************************
2422 * macdrv_window_minimize_requested
2424 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2426 void macdrv_window_minimize_requested(HWND hwnd)
2428 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2432 /***********************************************************************
2433 * macdrv_window_did_minimize
2435 * Handler for WINDOW_DID_MINIMIZE events.
2437 void macdrv_window_did_minimize(HWND hwnd)
2439 TRACE("win %p\n", hwnd);
2441 /* If all our windows are minimized, disable cursor clipping. */
2442 if (!macdrv_is_any_wine_window_visible())
2443 ClipCursor(NULL);
2447 /***********************************************************************
2448 * macdrv_window_did_unminimize
2450 * Handler for WINDOW_DID_UNMINIMIZE events.
2452 void macdrv_window_did_unminimize(HWND hwnd)
2454 struct macdrv_win_data *data;
2455 DWORD style;
2457 TRACE("win %p\n", hwnd);
2459 if (!(data = get_win_data(hwnd))) return;
2460 if (!data->minimized) goto done;
2462 style = GetWindowLongW(hwnd, GWL_STYLE);
2464 data->minimized = FALSE;
2465 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2467 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2468 release_win_data(data);
2469 SetActiveWindow(hwnd);
2470 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2471 return;
2474 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2476 done:
2477 release_win_data(data);
2481 /***********************************************************************
2482 * macdrv_window_brought_forward
2484 * Handler for WINDOW_BROUGHT_FORWARD events.
2486 void macdrv_window_brought_forward(HWND hwnd)
2488 TRACE("win %p\n", hwnd);
2489 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2493 /***********************************************************************
2494 * macdrv_window_resize_ended
2496 * Handler for WINDOW_RESIZE_ENDED events.
2498 void macdrv_window_resize_ended(HWND hwnd)
2500 TRACE("hwnd %p\n", hwnd);
2501 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2505 /***********************************************************************
2506 * macdrv_window_restore_requested
2508 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2509 * for restoring from maximized, not from minimized.
2511 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2513 if (event->window_restore_requested.keep_frame && hwnd)
2515 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2516 struct macdrv_win_data *data;
2518 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2520 RECT rect;
2521 HWND parent = GetAncestor(hwnd, GA_PARENT);
2523 rect = rect_from_cgrect(event->window_restore_requested.frame);
2524 macdrv_mac_to_window_rect(data, &rect);
2525 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2527 release_win_data(data);
2529 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2533 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2537 /***********************************************************************
2538 * macdrv_window_drag_begin
2540 * Handler for WINDOW_DRAG_BEGIN events.
2542 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2544 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2545 struct macdrv_win_data *data;
2546 HANDLE drag_event = NULL;
2547 BOOL loop = TRUE;
2548 MSG msg;
2550 TRACE("win %p\n", hwnd);
2552 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2553 if (!(style & WS_VISIBLE)) return;
2555 if (!(data = get_win_data(hwnd))) return;
2556 if (data->drag_event) goto done;
2558 drag_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2559 if (!drag_event) goto done;
2561 data->drag_event = drag_event;
2562 release_win_data(data);
2564 if (!event->window_drag_begin.no_activate && can_window_become_foreground(hwnd) && GetForegroundWindow() != hwnd)
2566 /* ask whether the window wants to be activated */
2567 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2568 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2569 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2571 TRACE("setting foreground window to %p\n", hwnd);
2572 SetForegroundWindow(hwnd);
2576 ClipCursor(NULL);
2577 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2578 ReleaseCapture();
2580 while (loop)
2582 while (!PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
2584 DWORD result = MsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
2585 if (result == WAIT_OBJECT_0)
2587 loop = FALSE;
2588 break;
2591 if (!loop)
2592 break;
2594 if (msg.message == WM_QUIT)
2595 break;
2597 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2598 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2600 TranslateMessage(&msg);
2601 DispatchMessageW(&msg);
2605 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2607 TRACE("done\n");
2609 if ((data = get_win_data(hwnd)))
2610 data->drag_event = NULL;
2612 done:
2613 release_win_data(data);
2614 if (drag_event) CloseHandle(drag_event);
2618 /***********************************************************************
2619 * macdrv_window_drag_end
2621 * Handler for WINDOW_DRAG_END events.
2623 void macdrv_window_drag_end(HWND hwnd)
2625 struct macdrv_win_data *data;
2627 TRACE("win %p\n", hwnd);
2629 if (!(data = get_win_data(hwnd))) return;
2630 if (data->drag_event)
2631 SetEvent(data->drag_event);
2632 release_win_data(data);
2636 /***********************************************************************
2637 * macdrv_reassert_window_position
2639 * Handler for REASSERT_WINDOW_POSITION events.
2641 void macdrv_reassert_window_position(HWND hwnd)
2643 struct macdrv_win_data *data = get_win_data(hwnd);
2644 if (data)
2646 if (data->cocoa_window && data->on_screen)
2647 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2648 release_win_data(data);
2653 struct quit_info {
2654 HWND *wins;
2655 UINT capacity;
2656 UINT count;
2657 UINT done;
2658 DWORD flags;
2659 BOOL result;
2660 BOOL replied;
2664 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2666 struct quit_info *qi = (struct quit_info*)lp;
2667 DWORD pid;
2669 GetWindowThreadProcessId(hwnd, &pid);
2670 if (pid == GetCurrentProcessId())
2672 if (qi->count >= qi->capacity)
2674 UINT new_cap = qi->capacity * 2;
2675 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2676 new_cap * sizeof(*qi->wins));
2677 if (!new_wins) return FALSE;
2678 qi->wins = new_wins;
2679 qi->capacity = new_cap;
2682 qi->wins[qi->count++] = hwnd;
2685 return TRUE;
2689 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2691 struct quit_info *qi = (struct quit_info*)data;
2693 qi->done++;
2695 if (msg == WM_QUERYENDSESSION)
2697 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2698 hwnd, qi->done, qi->count);
2700 if (!result && !IsWindow(hwnd))
2702 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2703 result = TRUE;
2706 if (!result && qi->result)
2708 qi->result = FALSE;
2710 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2711 ultimate reply. Might as well tell Cocoa now. */
2712 if (!qi->replied)
2714 qi->replied = TRUE;
2715 TRACE("giving quit reply %d\n", qi->result);
2716 macdrv_quit_reply(qi->result);
2720 if (qi->done >= qi->count)
2722 UINT i;
2724 qi->done = 0;
2725 for (i = 0; i < qi->count; i++)
2727 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2728 qi->result, qi->flags);
2729 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2730 quit_callback, (ULONG_PTR)qi))
2732 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2733 qi->wins[i], GetLastError());
2734 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2739 else /* WM_ENDSESSION */
2741 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2743 if (qi->done >= qi->count)
2745 if (!qi->replied)
2747 TRACE("giving quit reply %d\n", qi->result);
2748 macdrv_quit_reply(qi->result);
2751 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2752 if (qi->result)
2753 TerminateProcess(GetCurrentProcess(), 0);
2755 HeapFree(GetProcessHeap(), 0, qi->wins);
2756 HeapFree(GetProcessHeap(), 0, qi);
2762 /***********************************************************************
2763 * macdrv_app_quit_requested
2765 * Handler for APP_QUIT_REQUESTED events.
2767 void macdrv_app_quit_requested(const macdrv_event *event)
2769 struct quit_info *qi;
2770 UINT i;
2772 TRACE("reason %d\n", event->app_quit_requested.reason);
2774 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2775 if (!qi)
2776 goto fail;
2778 qi->capacity = 32;
2779 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2780 qi->count = qi->done = 0;
2782 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2783 goto fail;
2785 switch (event->app_quit_requested.reason)
2787 case QUIT_REASON_LOGOUT:
2788 default:
2789 qi->flags = ENDSESSION_LOGOFF;
2790 break;
2791 case QUIT_REASON_RESTART:
2792 case QUIT_REASON_SHUTDOWN:
2793 qi->flags = 0;
2794 break;
2797 qi->result = TRUE;
2798 qi->replied = FALSE;
2800 for (i = 0; i < qi->count; i++)
2802 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2803 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2804 quit_callback, (ULONG_PTR)qi))
2806 DWORD error = GetLastError();
2807 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2808 if (invalid)
2809 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2810 qi->wins[i]);
2811 else
2812 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2813 qi->wins[i], error);
2814 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2818 /* quit_callback() will clean up qi */
2819 return;
2821 fail:
2822 WARN("failed to allocate window list\n");
2823 if (qi)
2825 HeapFree(GetProcessHeap(), 0, qi->wins);
2826 HeapFree(GetProcessHeap(), 0, qi);
2828 macdrv_quit_reply(FALSE);
2832 /***********************************************************************
2833 * query_resize_size
2835 * Handler for QUERY_RESIZE_SIZE query.
2837 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2839 struct macdrv_win_data *data = get_win_data(hwnd);
2840 RECT rect = rect_from_cgrect(query->resize_size.rect);
2841 int corner;
2842 BOOL ret = FALSE;
2844 if (!data) return FALSE;
2846 macdrv_mac_to_window_rect(data, &rect);
2848 if (query->resize_size.from_left)
2850 if (query->resize_size.from_top)
2851 corner = WMSZ_TOPLEFT;
2852 else
2853 corner = WMSZ_BOTTOMLEFT;
2855 else if (query->resize_size.from_top)
2856 corner = WMSZ_TOPRIGHT;
2857 else
2858 corner = WMSZ_BOTTOMRIGHT;
2860 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2862 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect,
2863 &data->window_rect, &data->client_rect);
2864 query->resize_size.rect = cgrect_from_rect(rect);
2865 ret = TRUE;
2868 release_win_data(data);
2869 return ret;
2873 /***********************************************************************
2874 * query_resize_start
2876 * Handler for QUERY_RESIZE_START query.
2878 BOOL query_resize_start(HWND hwnd)
2880 TRACE("hwnd %p\n", hwnd);
2882 ClipCursor(NULL);
2884 sync_window_min_max_info(hwnd);
2885 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2887 return TRUE;
2891 /***********************************************************************
2892 * query_min_max_info
2894 * Handler for QUERY_MIN_MAX_INFO query.
2896 BOOL query_min_max_info(HWND hwnd)
2898 TRACE("hwnd %p\n", hwnd);
2899 sync_window_min_max_info(hwnd);
2900 return TRUE;
2904 /***********************************************************************
2905 * init_win_context
2907 void init_win_context(void)
2909 pthread_mutexattr_t attr;
2911 pthread_mutexattr_init(&attr);
2912 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
2913 pthread_mutex_init(&win_data_mutex, &attr);
2914 pthread_mutexattr_destroy(&attr);