winemac: Use unixlib interface for dragdrop.c calls.
[wine.git] / dlls / winemac.drv / window.c
blob2f473730b2f557583c94c7dddc8fe4b88451b319
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 = NtUserGetWindowLongW(hwnd, GWL_STYLE);
96 if (!(style & WS_VISIBLE)) return FALSE;
97 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
98 if (hwnd == NtUserGetDesktopWindow()) 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 (NtUserGetWindowRelative(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 = NtUserGetWindowLongW(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 = NtUserGetWindowLongW(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 = calloc(1, 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 = NtUserGetWindowLongW(data->hwnd, GWL_STYLE);
345 ex_style = NtUserGetWindowLongW(data->hwnd, GWL_EXSTYLE);
347 owner = NtUserGetWindowRelative(data->hwnd, GW_OWNER);
348 if (owner)
349 owner = NtUserGetAncestor(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 (NtUserGetWindowRgnEx(data->hwnd, hrgn, 0) == ERROR)
390 NtGdiDeleteObjectApp(hrgn);
391 hrgn = 0;
395 if (hrgn && NtUserGetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
396 NtUserMirrorRgn(data->hwnd, hrgn);
397 if (hrgn)
399 NtGdiOffsetRgn(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 free(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 = NtUserGetWindowLongW(hwnd, GWL_STYLE);
518 LONG exstyle = NtUserGetWindowLongW(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 NtUserGetWindowRect(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 = NtUserGetSystemMetrics(SM_CXSCREEN);
542 primary_monitor_rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
543 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle,
544 ((style & WS_POPUP) && NtUserGetWindowLongPtrW(hwnd, GWLP_ID)), exstyle);
546 xinc = -primary_monitor_rect.left;
547 yinc = -primary_monitor_rect.top;
549 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
550 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
551 minmax.ptMaxPosition.x = -xinc;
552 minmax.ptMaxPosition.y = -yinc;
553 if (style & (WS_DLGFRAME | WS_BORDER))
555 minmax.ptMinTrackSize.x = NtUserGetSystemMetrics(SM_CXMINTRACK);
556 minmax.ptMinTrackSize.y = NtUserGetSystemMetrics(SM_CYMINTRACK);
558 else
560 minmax.ptMinTrackSize.x = 2 * xinc;
561 minmax.ptMinTrackSize.y = 2 * yinc;
563 minmax.ptMaxTrackSize.x = NtUserGetSystemMetrics(SM_CXMAXTRACK);
564 minmax.ptMaxTrackSize.y = NtUserGetSystemMetrics(SM_CYMAXTRACK);
566 wpl.length = sizeof(wpl);
567 if (NtUserGetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
569 minmax.ptMaxPosition = wpl.ptMaxPosition;
571 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
572 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
573 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
576 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
577 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
579 send_message(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
581 TRACE("app's 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 /* if the app didn't change the values, adapt them for the window's monitor */
585 if ((monitor = NtUserMonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
587 MONITORINFO mon_info;
588 RECT monitor_rect;
590 mon_info.cbSize = sizeof(mon_info);
591 NtUserGetMonitorInfo(monitor, &mon_info);
593 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
594 monitor_rect = mon_info.rcWork;
595 else
596 monitor_rect = mon_info.rcMonitor;
598 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
599 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
601 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
602 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
604 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
606 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
607 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
611 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
612 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
614 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
615 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
617 if ((data = get_win_data(hwnd)) && data->cocoa_window)
619 RECT min_rect, max_rect;
620 CGSize min_size, max_size;
622 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
623 macdrv_window_to_mac_rect(data, style, &min_rect, &data->window_rect, &data->client_rect);
624 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
626 if (minmax.ptMaxTrackSize.x == NtUserGetSystemMetrics(SM_CXMAXTRACK) &&
627 minmax.ptMaxTrackSize.y == NtUserGetSystemMetrics(SM_CYMAXTRACK))
628 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
629 else
631 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
632 macdrv_window_to_mac_rect(data, style, &max_rect, &data->window_rect, &data->client_rect);
633 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
636 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
637 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
640 release_win_data(data);
644 /**********************************************************************
645 * create_client_cocoa_view
647 * Create the Cocoa view for a window's client area
649 static void create_client_cocoa_view(struct macdrv_win_data *data)
651 RECT rect = data->client_rect;
652 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
654 if (data->client_cocoa_view)
655 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
656 else
658 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
659 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
661 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
665 /**********************************************************************
666 * create_cocoa_window
668 * Create the whole Mac window for a given window
670 static void create_cocoa_window(struct macdrv_win_data *data)
672 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
673 WCHAR text[1024];
674 struct macdrv_window_features wf;
675 CGRect frame;
676 DWORD style, ex_style;
677 HRGN win_rgn;
678 COLORREF key;
679 BYTE alpha;
680 DWORD layered_flags;
682 if ((win_rgn = NtGdiCreateRectRgn(0, 0, 0, 0)) &&
683 NtUserGetWindowRgnEx(data->hwnd, win_rgn, 0) == ERROR)
685 NtGdiDeleteObjectApp(win_rgn);
686 win_rgn = 0;
688 data->shaped = (win_rgn != 0);
690 style = NtUserGetWindowLongW(data->hwnd, GWL_STYLE);
691 ex_style = NtUserGetWindowLongW(data->hwnd, GWL_EXSTYLE);
693 data->whole_rect = data->window_rect;
694 macdrv_window_to_mac_rect(data, style, &data->whole_rect, &data->window_rect, &data->client_rect);
696 get_cocoa_window_features(data, style, ex_style, &wf, &data->window_rect, &data->client_rect);
698 frame = cgrect_from_rect(data->whole_rect);
699 constrain_window_frame(&frame);
700 if (frame.size.width < 1 || frame.size.height < 1)
701 frame.size.width = frame.size.height = 1;
703 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
704 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
706 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
707 if (!data->cocoa_window) goto done;
708 create_client_cocoa_view(data);
710 set_cocoa_window_properties(data);
712 /* set the window text */
713 if (!NtUserInternalGetWindowText(data->hwnd, text, ARRAY_SIZE(text))) text[0] = 0;
714 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
716 /* set the window region */
717 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
719 /* set the window opacity */
720 if (!NtUserGetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
721 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
723 done:
724 if (win_rgn) NtGdiDeleteObjectApp(win_rgn);
728 /**********************************************************************
729 * destroy_cocoa_window
731 * Destroy the whole Mac window for a given window.
733 static void destroy_cocoa_window(struct macdrv_win_data *data)
735 if (!data->cocoa_window) return;
737 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
739 macdrv_destroy_cocoa_window(data->cocoa_window);
740 data->cocoa_window = 0;
741 data->on_screen = FALSE;
742 data->color_key = CLR_INVALID;
743 if (data->surface) window_surface_release(data->surface);
744 data->surface = NULL;
745 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
746 data->unminimized_surface = NULL;
750 /**********************************************************************
751 * create_cocoa_view
753 * Create the Cocoa view for a given Windows child window
755 static void create_cocoa_view(struct macdrv_win_data *data)
757 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
758 CGRect frame = cgrect_from_rect(data->window_rect);
760 data->shaped = FALSE;
761 data->whole_rect = data->window_rect;
763 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
764 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
766 if (!equal)
767 data->cocoa_view = macdrv_create_view(frame);
768 create_client_cocoa_view(data);
769 if (equal)
771 data->cocoa_view = data->client_cocoa_view;
772 macdrv_set_view_hidden(data->cocoa_view, TRUE);
773 macdrv_set_view_frame(data->cocoa_view, frame);
778 /**********************************************************************
779 * destroy_cocoa_view
781 * Destroy the Cocoa view for a given window.
783 static void destroy_cocoa_view(struct macdrv_win_data *data)
785 if (!data->cocoa_view) return;
787 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
789 if (data->cocoa_view != data->client_cocoa_view)
790 macdrv_dispose_view(data->cocoa_view);
791 data->cocoa_view = NULL;
792 data->on_screen = FALSE;
796 /***********************************************************************
797 * set_cocoa_view_parent
799 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
801 struct macdrv_win_data *parent_data = get_win_data(parent);
802 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
803 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
805 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
807 if (!cocoa_window && !superview)
808 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
810 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
811 release_win_data(parent_data);
815 /***********************************************************************
816 * macdrv_create_win_data
818 * Create a Mac data window structure for an existing window.
820 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
821 const RECT *client_rect)
823 struct macdrv_win_data *data;
824 HWND parent;
826 if (NtUserGetWindowThread(hwnd, NULL) != GetCurrentThreadId()) return NULL;
828 if (!(parent = NtUserGetAncestor(hwnd, GA_PARENT))) /* desktop */
830 macdrv_init_thread_data();
831 return NULL;
834 /* don't create win data for HWND_MESSAGE windows */
835 if (parent != NtUserGetDesktopWindow() && !NtUserGetAncestor(parent, GA_PARENT)) return NULL;
837 if (!(data = alloc_win_data(hwnd))) return NULL;
839 data->whole_rect = data->window_rect = *window_rect;
840 data->client_rect = *client_rect;
842 if (parent == NtUserGetDesktopWindow())
844 create_cocoa_window(data);
845 TRACE("win %p/%p window %s whole %s client %s\n",
846 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
847 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
849 else
851 create_cocoa_view(data);
852 TRACE("win %p/%p window %s whole %s client %s\n",
853 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
854 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
856 set_cocoa_view_parent(data, parent);
859 return data;
863 /**********************************************************************
864 * is_owned_by
866 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
868 while (1)
870 HWND hwnd2 = NtUserGetWindowRelative(hwnd, GW_OWNER);
871 if (!hwnd2)
872 hwnd2 = NtUserGetAncestor(hwnd, GA_ROOT);
873 if (!hwnd2 || hwnd2 == hwnd)
874 break;
875 if (hwnd2 == maybe_owner)
876 return TRUE;
877 hwnd = hwnd2;
880 return FALSE;
884 /**********************************************************************
885 * is_all_the_way_front
887 static BOOL is_all_the_way_front(HWND hwnd)
889 BOOL topmost = (NtUserGetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
890 HWND prev = hwnd;
892 while ((prev = NtUserGetWindowRelative(prev, GW_HWNDPREV)))
894 if (!topmost && (NtUserGetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
895 return TRUE;
896 if (!is_owned_by(prev, hwnd))
897 return FALSE;
900 return TRUE;
904 /***********************************************************************
905 * set_focus
907 static void set_focus(HWND hwnd, BOOL raise)
909 struct macdrv_win_data *data;
911 if (!(hwnd = NtUserGetAncestor(hwnd, GA_ROOT))) return;
913 if (raise && hwnd == NtUserGetForegroundWindow() && hwnd != NtUserGetDesktopWindow() &&
914 !is_all_the_way_front(hwnd))
915 NtUserSetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
916 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
918 if (!(data = get_win_data(hwnd))) return;
920 if (data->cocoa_window && data->on_screen)
922 BOOL activate = activate_on_focus_time && (NtGetTickCount() - activate_on_focus_time < 2000);
923 /* Set Mac focus */
924 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
925 activate_on_focus_time = 0;
928 release_win_data(data);
931 /***********************************************************************
932 * show_window
934 static void show_window(struct macdrv_win_data *data)
936 if (data->cocoa_window)
938 HWND prev = NULL;
939 HWND next = NULL;
940 macdrv_window prev_window = NULL;
941 macdrv_window next_window = NULL;
942 BOOL activate = FALSE;
943 GUITHREADINFO info;
945 /* find window that this one must be after */
946 prev = NtUserGetWindowRelative(data->hwnd, GW_HWNDPREV);
947 while (prev && !((NtUserGetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
948 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
949 prev = NtUserGetWindowRelative(prev, GW_HWNDPREV);
950 if (!prev_window)
952 /* find window that this one must be before */
953 next = NtUserGetWindowRelative(data->hwnd, GW_HWNDNEXT);
954 while (next && !((NtUserGetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
955 (next_window = macdrv_get_cocoa_window(next, TRUE))))
956 next = NtUserGetWindowRelative(next, GW_HWNDNEXT);
959 TRACE("win %p/%p below %p/%p above %p/%p\n",
960 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
962 if (!prev_window)
963 activate = activate_on_focus_time && (NtGetTickCount() - activate_on_focus_time < 2000);
964 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
965 data->on_screen = TRUE;
967 info.cbSize = sizeof(info);
968 if (NtUserGetGUIThreadInfo(NtUserGetWindowThread(data->hwnd, NULL), &info) && info.hwndFocus &&
969 (data->hwnd == info.hwndFocus || NtUserIsChild(data->hwnd, info.hwndFocus)))
970 set_focus(info.hwndFocus, FALSE);
971 if (activate)
972 activate_on_focus_time = 0;
974 else
976 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
978 macdrv_set_view_hidden(data->cocoa_view, FALSE);
979 data->on_screen = TRUE;
984 /***********************************************************************
985 * hide_window
987 static void hide_window(struct macdrv_win_data *data)
989 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
991 if (data->cocoa_window)
992 macdrv_hide_cocoa_window(data->cocoa_window);
993 else
994 macdrv_set_view_hidden(data->cocoa_view, TRUE);
995 data->on_screen = FALSE;
999 /***********************************************************************
1000 * sync_window_z_order
1002 static void sync_window_z_order(struct macdrv_win_data *data)
1004 if (data->cocoa_view)
1006 HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT);
1007 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
1008 macdrv_window window = NULL;
1009 HWND prev;
1010 HWND next = NULL;
1011 macdrv_view prev_view = NULL;
1012 macdrv_view next_view = NULL;
1014 if (!superview)
1016 window = macdrv_get_cocoa_window(parent, FALSE);
1017 if (!window)
1018 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1021 /* find window that this one must be after */
1022 prev = NtUserGetWindowRelative(data->hwnd, GW_HWNDPREV);
1023 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1024 prev = NtUserGetWindowRelative(prev, GW_HWNDPREV);
1025 if (!prev_view)
1027 /* find window that this one must be before */
1028 next = NtUserGetWindowRelative(data->hwnd, GW_HWNDNEXT);
1029 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1030 next = NtUserGetWindowRelative(next, GW_HWNDNEXT);
1033 TRACE("win %p/%p below %p/%p above %p/%p\n",
1034 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1036 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1038 else if (data->on_screen)
1039 show_window(data);
1043 /***********************************************************************
1044 * get_region_data
1046 * Calls GetRegionData on the given region and converts the rectangle
1047 * array to CGRect format. The returned buffer must be freed by caller.
1048 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1050 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1052 RGNDATA *data;
1053 DWORD size;
1054 int i;
1055 RECT *rect;
1056 CGRect *cgrect;
1058 if (!hrgn || !(size = NtGdiGetRegionData(hrgn, 0, NULL))) return NULL;
1059 if (sizeof(CGRect) > sizeof(RECT))
1061 /* add extra size for CGRect array */
1062 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1063 size += count * (sizeof(CGRect) - sizeof(RECT));
1065 if (!(data = malloc(size))) return NULL;
1066 if (!NtGdiGetRegionData(hrgn, size, data))
1068 free(data);
1069 return NULL;
1072 rect = (RECT *)data->Buffer;
1073 cgrect = (CGRect *)data->Buffer;
1074 if (hdc_lptodp) /* map to device coordinates */
1076 NtGdiTransformPoints(hdc_lptodp, (POINT *)rect, (POINT *)rect,
1077 data->rdh.nCount * 2, NtGdiLPtoDP);
1078 for (i = 0; i < data->rdh.nCount; i++)
1080 if (rect[i].right < rect[i].left)
1082 INT tmp = rect[i].right;
1083 rect[i].right = rect[i].left;
1084 rect[i].left = tmp;
1086 if (rect[i].bottom < rect[i].top)
1088 INT tmp = rect[i].bottom;
1089 rect[i].bottom = rect[i].top;
1090 rect[i].top = tmp;
1095 if (sizeof(CGRect) > sizeof(RECT))
1097 /* need to start from the end */
1098 for (i = data->rdh.nCount-1; i >= 0; i--)
1099 cgrect[i] = cgrect_from_rect(rect[i]);
1101 else
1103 for (i = 0; i < data->rdh.nCount; i++)
1104 cgrect[i] = cgrect_from_rect(rect[i]);
1106 return data;
1110 /***********************************************************************
1111 * sync_client_view_position
1113 static void sync_client_view_position(struct macdrv_win_data *data)
1115 if (data->cocoa_view != data->client_cocoa_view)
1117 RECT rect = data->client_rect;
1118 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1119 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1120 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1125 /***********************************************************************
1126 * sync_window_position
1128 * Synchronize the Mac window position with the Windows one
1130 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1131 const RECT *old_whole_rect)
1133 CGRect frame = cgrect_from_rect(data->whole_rect);
1134 BOOL force_z_order = FALSE;
1136 if (data->cocoa_window)
1138 if (data->minimized) return;
1140 constrain_window_frame(&frame);
1141 if (frame.size.width < 1 || frame.size.height < 1)
1142 frame.size.width = frame.size.height = 1;
1144 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1146 else
1148 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1149 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1151 if (were_equal && !now_equal)
1153 data->cocoa_view = macdrv_create_view(frame);
1154 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1155 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1156 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1157 force_z_order = TRUE;
1159 else if (!were_equal && now_equal)
1161 macdrv_dispose_view(data->cocoa_view);
1162 data->cocoa_view = data->client_cocoa_view;
1163 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1164 macdrv_set_view_frame(data->cocoa_view, frame);
1165 force_z_order = TRUE;
1167 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1168 macdrv_set_view_frame(data->cocoa_view, frame);
1171 sync_client_view_position(data);
1173 if (old_window_rect && old_whole_rect &&
1174 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1175 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1176 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1177 sync_window_region(data, (HRGN)1);
1179 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1180 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1181 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1183 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1184 sync_window_z_order(data);
1188 /***********************************************************************
1189 * move_window_bits
1191 * Move the window bits when a window is moved.
1193 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1194 const RECT *old_client_rect, const RECT *new_client_rect,
1195 const RECT *new_window_rect)
1197 RECT src_rect = *old_rect;
1198 RECT dst_rect = *new_rect;
1199 HDC hdc_src, hdc_dst;
1200 HRGN rgn;
1201 HWND parent = 0;
1203 if (!window)
1205 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1206 parent = NtUserGetAncestor(hwnd, GA_PARENT);
1207 hdc_src = NtUserGetDCEx(parent, 0, DCX_CACHE);
1208 hdc_dst = NtUserGetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1210 else
1212 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1213 /* make src rect relative to the old position of the window */
1214 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1215 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1216 hdc_src = hdc_dst = NtUserGetDCEx(hwnd, 0, DCX_CACHE);
1219 rgn = NtGdiCreateRectRgn(dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom);
1220 NtGdiExtSelectClipRgn(hdc_dst, rgn, RGN_COPY);
1221 NtGdiDeleteObjectApp(rgn);
1222 NtUserExcludeUpdateRgn(hdc_dst, hwnd);
1224 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1225 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1226 NtGdiBitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1227 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1228 hdc_src, src_rect.left, src_rect.top, SRCCOPY, 0, 0);
1230 NtUserReleaseDC(hwnd, hdc_dst);
1231 if (hdc_src != hdc_dst) NtUserReleaseDC(parent, hdc_src);
1235 /**********************************************************************
1236 * activate_on_following_focus
1238 void activate_on_following_focus(void)
1240 activate_on_focus_time = NtGetTickCount();
1241 if (!activate_on_focus_time) activate_on_focus_time = 1;
1245 /***********************************************************************
1246 * set_app_icon
1248 static void set_app_icon(void)
1250 CFArrayRef images = create_app_icon_images();
1251 if (images)
1253 macdrv_set_application_icon(images);
1254 CFRelease(images);
1259 /**********************************************************************
1260 * set_capture_window_for_move
1262 static BOOL set_capture_window_for_move(HWND hwnd)
1264 HWND previous = 0;
1265 BOOL ret;
1267 SERVER_START_REQ(set_capture_window)
1269 req->handle = wine_server_user_handle(hwnd);
1270 req->flags = CAPTURE_MOVESIZE;
1271 if ((ret = !wine_server_call_err(req)))
1273 previous = wine_server_ptr_handle(reply->previous);
1274 hwnd = wine_server_ptr_handle(reply->full_handle);
1277 SERVER_END_REQ;
1279 if (ret)
1281 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1283 if (previous && previous != hwnd)
1284 send_message(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1286 return ret;
1290 static HMONITOR monitor_from_point(POINT pt, UINT flags)
1292 RECT rect;
1294 SetRect(&rect, pt.x, pt.y, pt.x + 1, pt.y + 1);
1295 return NtUserMonitorFromRect(&rect, flags);
1299 /***********************************************************************
1300 * move_window
1302 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1303 * moving top-level windows and enforcing Mac-style constraints like
1304 * keeping the top of the window within the work area.
1306 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1308 MSG msg;
1309 RECT origRect, movedRect, desktopRect;
1310 LONG hittest = (LONG)(wparam & 0x0f);
1311 POINT capturePoint;
1312 LONG style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
1313 BOOL moved = FALSE;
1314 DWORD dwPoint = NtUserGetThreadInfo()->message_pos;
1315 INT captionHeight;
1316 HMONITOR mon = 0;
1317 MONITORINFO info;
1319 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1320 if (hittest && hittest != HTCAPTION) return -1;
1322 capturePoint.x = (short)LOWORD(dwPoint);
1323 capturePoint.y = (short)HIWORD(dwPoint);
1324 NtUserClipCursor(NULL);
1326 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1328 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1329 if (AdjustWindowRectEx(&origRect, style, FALSE, NtUserGetWindowLongW(hwnd, GWL_EXSTYLE)))
1330 captionHeight = -origRect.top;
1331 else
1332 captionHeight = 0;
1334 NtUserGetWindowRect(hwnd, &origRect);
1335 movedRect = origRect;
1337 if (!hittest)
1339 /* Move pointer to the center of the caption */
1340 RECT rect = origRect;
1342 /* Note: to be exactly centered we should take the different types
1343 * of border into account, but it shouldn't make more than a few pixels
1344 * of difference so let's not bother with that */
1345 rect.top += NtUserGetSystemMetrics(SM_CYBORDER);
1346 if (style & WS_SYSMENU)
1347 rect.left += NtUserGetSystemMetrics(SM_CXSIZE) + 1;
1348 if (style & WS_MINIMIZEBOX)
1349 rect.right -= NtUserGetSystemMetrics(SM_CXSIZE) + 1;
1350 if (style & WS_MAXIMIZEBOX)
1351 rect.right -= NtUserGetSystemMetrics(SM_CXSIZE) + 1;
1352 capturePoint.x = (rect.right + rect.left) / 2;
1353 capturePoint.y = rect.top + NtUserGetSystemMetrics(SM_CYSIZE)/2;
1355 NtUserSetCursorPos(capturePoint.x, capturePoint.y);
1356 send_message(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1359 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1360 mon = monitor_from_point(capturePoint, MONITOR_DEFAULTTONEAREST);
1361 info.cbSize = sizeof(info);
1362 if (mon && !NtUserGetMonitorInfo(mon, &info))
1363 mon = 0;
1365 /* repaint the window before moving it around */
1366 NtUserRedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1368 send_message(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1369 set_capture_window_for_move(hwnd);
1371 while(1)
1373 POINT pt;
1374 int dx = 0, dy = 0;
1375 HMONITOR newmon;
1377 if (!NtUserGetMessage(&msg, 0, 0, 0)) break;
1378 if (NtUserCallMsgFilter(&msg, MSGF_SIZE)) continue;
1380 /* Exit on button-up, Return, or Esc */
1381 if (msg.message == WM_LBUTTONUP ||
1382 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1383 break;
1385 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1387 NtUserTranslateMessage(&msg, 0);
1388 NtUserDispatchMessage(&msg);
1389 continue; /* We are not interested in other messages */
1392 pt = msg.pt;
1394 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1396 case VK_UP: pt.y -= 8; break;
1397 case VK_DOWN: pt.y += 8; break;
1398 case VK_LEFT: pt.x -= 8; break;
1399 case VK_RIGHT: pt.x += 8; break;
1402 pt.x = max(pt.x, desktopRect.left);
1403 pt.x = min(pt.x, desktopRect.right - 1);
1404 pt.y = max(pt.y, desktopRect.top);
1405 pt.y = min(pt.y, desktopRect.bottom - 1);
1407 if ((newmon = monitor_from_point(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1409 if (NtUserGetMonitorInfo(newmon, &info))
1410 mon = newmon;
1411 else
1412 mon = 0;
1415 if (mon)
1417 /* wineserver clips the cursor position to the virtual desktop rect but,
1418 if the display configuration is non-rectangular, that could still
1419 leave the logical cursor position outside of any display. The window
1420 could keep moving as you push the cursor against a display edge, even
1421 though the visible cursor doesn't keep moving. The following keeps
1422 the window movement in sync with the visible cursor. */
1423 pt.x = max(pt.x, info.rcMonitor.left);
1424 pt.x = min(pt.x, info.rcMonitor.right - 1);
1425 pt.y = max(pt.y, info.rcMonitor.top);
1426 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1428 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1429 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1430 we want to enforce these constraints:
1431 movedRect.left + dx < info.rcWork.right
1432 movedRect.right + dx > info.rcWork.left
1433 movedRect.top + captionHeight + dy < info.rcWork.bottom
1434 movedRect.bottom + dy > info.rcWork.top
1435 movedRect.top + dy >= info.rcWork.top
1436 The first four keep at least one edge barely in the work area.
1437 The last keeps the top (i.e. the title bar) in the work area.
1438 The fourth is redundant with the last, so can be ignored.
1440 Substituting for dx and dy and rearranging gives us...
1442 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1443 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1444 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1445 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1448 dx = pt.x - capturePoint.x;
1449 dy = pt.y - capturePoint.y;
1451 if (dx || dy)
1453 moved = TRUE;
1455 if (msg.message == WM_KEYDOWN) NtUserSetCursorPos(pt.x, pt.y);
1456 else
1458 OffsetRect(&movedRect, dx, dy);
1459 capturePoint = pt;
1461 send_message(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1462 NtUserSetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1463 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1468 set_capture_window_for_move(0);
1470 send_message(hwnd, WM_EXITSIZEMOVE, 0, 0);
1471 send_message(hwnd, WM_SETVISIBLE, TRUE, 0L);
1473 /* if the move is canceled, restore the previous position */
1474 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1476 NtUserSetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1477 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1480 return 0;
1484 /***********************************************************************
1485 * perform_window_command
1487 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1489 DWORD style;
1491 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1492 hwnd, style_any, style_none, command, hittest);
1494 style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
1495 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1497 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1498 return;
1501 if (get_active_window() != hwnd)
1503 LRESULT ma = send_message(hwnd, WM_MOUSEACTIVATE, (WPARAM)NtUserGetAncestor(hwnd, GA_ROOT),
1504 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1505 switch (ma)
1507 case MA_NOACTIVATEANDEAT:
1508 case MA_ACTIVATEANDEAT:
1509 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1510 return;
1511 case MA_NOACTIVATE:
1512 break;
1513 case MA_ACTIVATE:
1514 case 0:
1515 NtUserSetActiveWindow(hwnd);
1516 break;
1517 default:
1518 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1519 break;
1523 TRACE("changing win %p\n", hwnd);
1524 NtUserPostMessage(hwnd, WM_SYSCOMMAND, command, 0);
1528 /**********************************************************************
1529 * CreateDesktopWindow (MACDRV.@)
1531 BOOL macdrv_CreateDesktopWindow(HWND hwnd)
1533 unsigned int width, height;
1535 TRACE("%p\n", hwnd);
1537 /* retrieve the real size of the desktop */
1538 SERVER_START_REQ(get_window_rectangles)
1540 req->handle = wine_server_user_handle(hwnd);
1541 req->relative = COORDS_CLIENT;
1542 wine_server_call(req);
1543 width = reply->window.right;
1544 height = reply->window.bottom;
1546 SERVER_END_REQ;
1548 if (!width && !height) /* not initialized yet */
1550 CGRect rect = macdrv_get_desktop_rect();
1552 SERVER_START_REQ(set_window_pos)
1554 req->handle = wine_server_user_handle(hwnd);
1555 req->previous = 0;
1556 req->swp_flags = SWP_NOZORDER;
1557 req->window.left = CGRectGetMinX(rect);
1558 req->window.top = CGRectGetMinY(rect);
1559 req->window.right = CGRectGetMaxX(rect);
1560 req->window.bottom = CGRectGetMaxY(rect);
1561 req->client = req->window;
1562 wine_server_call(req);
1564 SERVER_END_REQ;
1567 set_app_icon();
1568 return TRUE;
1572 #define WM_WINE_NOTIFY_ACTIVITY WM_USER
1574 LRESULT macdrv_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1576 switch (msg)
1578 case WM_WINE_NOTIFY_ACTIVITY:
1580 /* This wakes from display sleep, but doesn't affect the screen saver. */
1581 static IOPMAssertionID assertion;
1582 IOPMAssertionDeclareUserActivity(CFSTR("Wine user input"), kIOPMUserActiveLocal, &assertion);
1584 /* This prevents the screen saver, but doesn't wake from display sleep. */
1585 /* It's deprecated, but there's no better alternative. */
1586 #pragma clang diagnostic push
1587 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1588 UpdateSystemActivity(UsrActivity);
1589 #pragma clang diagnostic pop
1590 break;
1593 return NtUserMessageCall(hwnd, msg, wp, lp, 0, NtUserDefWindowProc, FALSE);
1596 /***********************************************************************
1597 * DestroyWindow (MACDRV.@)
1599 void macdrv_DestroyWindow(HWND hwnd)
1601 struct macdrv_win_data *data;
1603 TRACE("%p\n", hwnd);
1605 if (!(data = get_win_data(hwnd))) return;
1607 if (hwnd == get_capture()) macdrv_SetCapture(0, 0);
1608 if (data->drag_event) NtSetEvent(data->drag_event, NULL);
1610 destroy_cocoa_window(data);
1611 destroy_cocoa_view(data);
1612 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1614 CFDictionaryRemoveValue(win_datas, hwnd);
1615 release_win_data(data);
1616 free(data);
1620 /*****************************************************************
1621 * SetFocus (MACDRV.@)
1623 * Set the Mac focus.
1625 void macdrv_SetFocus(HWND hwnd)
1627 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1629 TRACE("%p\n", hwnd);
1631 if (!thread_data) return;
1632 thread_data->dead_key_state = 0;
1633 set_focus(hwnd, TRUE);
1637 /***********************************************************************
1638 * SetLayeredWindowAttributes (MACDRV.@)
1640 * Set transparency attributes for a layered window.
1642 void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1644 struct macdrv_win_data *data = get_win_data(hwnd);
1646 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1648 if (data)
1650 data->layered = TRUE;
1651 data->ulw_layered = FALSE;
1652 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1653 if (data->cocoa_window)
1655 sync_window_opacity(data, key, alpha, FALSE, flags);
1656 /* since layered attributes are now set, can now show the window */
1657 if ((NtUserGetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1658 show_window(data);
1660 release_win_data(data);
1662 else
1663 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1667 /*****************************************************************
1668 * SetParent (MACDRV.@)
1670 void macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1672 struct macdrv_win_data *data;
1674 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1676 if (parent == old_parent) return;
1677 if (!(data = get_win_data(hwnd))) return;
1679 if (parent != NtUserGetDesktopWindow()) /* a child window */
1681 if (old_parent == NtUserGetDesktopWindow())
1683 /* destroy the old Mac window */
1684 destroy_cocoa_window(data);
1685 create_cocoa_view(data);
1688 set_cocoa_view_parent(data, parent);
1690 else /* new top level window */
1692 destroy_cocoa_view(data);
1693 create_cocoa_window(data);
1695 release_win_data(data);
1699 /***********************************************************************
1700 * SetWindowRgn (MACDRV.@)
1702 * Assign specified region to window (for non-rectangular windows)
1704 void macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1706 struct macdrv_win_data *data;
1708 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1710 if ((data = get_win_data(hwnd)))
1712 sync_window_region(data, hrgn);
1713 release_win_data(data);
1715 else
1717 DWORD procid;
1719 NtUserGetWindowThread(hwnd, &procid);
1720 if (procid != GetCurrentProcessId())
1721 send_message(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1726 /***********************************************************************
1727 * SetWindowStyle (MACDRV.@)
1729 * Update the state of the Cocoa window to reflect a style change
1731 void macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1733 struct macdrv_win_data *data;
1735 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1737 if (hwnd == NtUserGetDesktopWindow()) return;
1738 if (!(data = get_win_data(hwnd))) return;
1740 if (data->cocoa_window)
1742 DWORD changed = style->styleNew ^ style->styleOld;
1744 set_cocoa_window_properties(data);
1746 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1748 data->layered = FALSE;
1749 data->ulw_layered = FALSE;
1750 sync_window_opacity(data, 0, 0, FALSE, 0);
1751 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1754 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1755 sync_window_region(data, (HRGN)1);
1758 release_win_data(data);
1762 /*****************************************************************
1763 * SetWindowText (MACDRV.@)
1765 void macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1767 macdrv_window win;
1769 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1771 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1772 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1776 /***********************************************************************
1777 * ShowWindow (MACDRV.@)
1779 UINT macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1781 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1782 struct macdrv_win_data *data = get_win_data(hwnd);
1783 CGRect frame;
1785 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1786 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1788 if (!data || !data->cocoa_window) goto done;
1789 if (NtUserGetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1791 if (rect->left != -32000 || rect->top != -32000)
1793 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1794 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1796 goto done;
1798 if (!data->on_screen) goto done;
1800 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1802 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1803 goto done;
1805 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1806 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1807 goto done;
1809 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1810 *rect = rect_from_cgrect(frame);
1811 macdrv_mac_to_window_rect(data, rect);
1812 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1813 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1815 done:
1816 release_win_data(data);
1817 return swp;
1821 /***********************************************************************
1822 * SysCommand (MACDRV.@)
1824 * Perform WM_SYSCOMMAND handling.
1826 LRESULT macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1828 struct macdrv_win_data *data;
1829 LRESULT ret = -1;
1830 WPARAM command = wparam & 0xfff0;
1832 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1834 if (!(data = get_win_data(hwnd))) goto done;
1835 if (!data->cocoa_window || !data->on_screen) goto done;
1837 /* prevent a simple ALT press+release from activating the system menu,
1838 as that can get confusing */
1839 if (command == SC_KEYMENU && !(WCHAR)lparam &&
1840 !NtUserGetWindowLongPtrW(hwnd, GWLP_ID) &&
1841 (NtUserGetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1843 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1844 ret = 0;
1847 if (command == SC_MOVE)
1849 release_win_data(data);
1850 return move_window(hwnd, wparam);
1853 done:
1854 release_win_data(data);
1855 return ret;
1859 /***********************************************************************
1860 * UpdateLayeredWindow (MACDRV.@)
1862 BOOL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1863 const RECT *window_rect)
1865 struct window_surface *surface;
1866 struct macdrv_win_data *data;
1867 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1868 BYTE alpha;
1869 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1870 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1871 void *src_bits, *dst_bits;
1872 RECT rect, src_rect;
1873 HDC hdc = 0;
1874 HBITMAP dib;
1875 BOOL ret = FALSE;
1877 if (!(data = get_win_data(hwnd))) return FALSE;
1879 data->layered = TRUE;
1880 data->ulw_layered = TRUE;
1882 rect = *window_rect;
1883 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1885 surface = data->surface;
1886 if (!surface || !EqualRect(&surface->rect, &rect))
1888 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1889 set_window_surface(data->cocoa_window, data->surface);
1890 if (surface) window_surface_release(surface);
1891 surface = data->surface;
1892 if (data->unminimized_surface)
1894 window_surface_release(data->unminimized_surface);
1895 data->unminimized_surface = NULL;
1898 else set_surface_use_alpha(surface, TRUE);
1900 if (surface) window_surface_add_ref(surface);
1901 release_win_data(data);
1903 if (!surface) return FALSE;
1904 if (!info->hdcSrc)
1906 window_surface_release(surface);
1907 return TRUE;
1910 if (info->dwFlags & ULW_ALPHA)
1912 /* Apply SourceConstantAlpha via window alpha, not blend. */
1913 alpha = info->pblend->SourceConstantAlpha;
1914 blend = *info->pblend;
1915 blend.SourceConstantAlpha = 0xff;
1917 else
1918 alpha = 0xff;
1920 dst_bits = surface->funcs->get_info(surface, bmi);
1922 if (!(dib = NtGdiCreateDIBSection(info->hdcDst, NULL, 0, bmi, DIB_RGB_COLORS,
1923 0, 0, 0, &src_bits))) goto done;
1924 if (!(hdc = NtGdiCreateCompatibleDC(0))) goto done;
1926 NtGdiSelectBitmap(hdc, dib);
1927 if (info->prcDirty)
1929 intersect_rect(&rect, &rect, info->prcDirty);
1930 surface->funcs->lock(surface);
1931 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1932 surface->funcs->unlock(surface);
1933 NtGdiPatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1935 src_rect = rect;
1936 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1937 NtGdiTransformPoints(info->hdcSrc, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP);
1939 if (!(ret = NtGdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1940 info->hdcSrc, src_rect.left, src_rect.top,
1941 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1942 blend, 0)))
1943 goto done;
1945 if ((data = get_win_data(hwnd)))
1947 if (surface == data->surface)
1949 surface->funcs->lock(surface);
1950 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1951 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1952 surface->funcs->unlock(surface);
1953 surface->funcs->flush(surface);
1956 /* The ULW flags are a superset of the LWA flags. */
1957 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1959 release_win_data(data);
1962 done:
1963 window_surface_release(surface);
1964 if (hdc) NtGdiDeleteObjectApp(hdc);
1965 if (dib) NtGdiDeleteObjectApp(dib);
1966 return ret;
1970 /**********************************************************************
1971 * WindowMessage (MACDRV.@)
1973 LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1975 struct macdrv_win_data *data;
1977 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1979 switch(msg)
1981 case WM_MACDRV_SET_WIN_REGION:
1982 if ((data = get_win_data(hwnd)))
1984 sync_window_region(data, (HRGN)1);
1985 release_win_data(data);
1987 return 0;
1988 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1989 if (hwnd == NtUserGetDesktopWindow())
1991 CGRect new_desktop_rect;
1992 RECT current_desktop_rect;
1994 macdrv_reset_device_metrics();
1995 new_desktop_rect = macdrv_get_desktop_rect();
1996 if (!NtUserGetWindowRect(hwnd, &current_desktop_rect) ||
1997 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1999 send_message_timeout(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
2000 SMTO_ABORTIFHUNG, 2000, NULL);
2001 NtUserSetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
2002 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
2003 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
2004 send_message_timeout(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
2005 SMTO_ABORTIFHUNG, 2000, NULL);
2008 return 0;
2009 case WM_MACDRV_RESET_DEVICE_METRICS:
2010 macdrv_reset_device_metrics();
2011 return 0;
2012 case WM_MACDRV_DISPLAYCHANGE:
2013 macdrv_reassert_window_position(hwnd);
2014 send_message(hwnd, WM_DISPLAYCHANGE, wp, lp);
2015 return 0;
2016 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
2017 activate_on_following_focus();
2018 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
2019 return 0;
2022 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
2023 return 0;
2027 static inline RECT get_surface_rect(const RECT *visible_rect)
2029 RECT rect;
2030 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
2032 intersect_rect(&rect, visible_rect, &desktop_rect);
2033 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2034 rect.left &= ~127;
2035 rect.top &= ~127;
2036 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2037 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2038 return rect;
2042 /***********************************************************************
2043 * WindowPosChanging (MACDRV.@)
2045 BOOL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2046 const RECT *window_rect, const RECT *client_rect,
2047 RECT *visible_rect, struct window_surface **surface)
2049 struct macdrv_win_data *data = get_win_data(hwnd);
2050 DWORD style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
2051 RECT surface_rect;
2053 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2054 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2055 wine_dbgstr_rect(visible_rect), surface);
2057 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return TRUE;
2059 *visible_rect = *window_rect;
2060 macdrv_window_to_mac_rect(data, style, visible_rect, window_rect, client_rect);
2061 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2062 wine_dbgstr_rect(visible_rect));
2064 /* create the window surface if necessary */
2065 if (!data->cocoa_window) goto done;
2066 if (swp_flags & SWP_HIDEWINDOW) goto done;
2067 if (data->ulw_layered) goto done;
2069 if (*surface) window_surface_release(*surface);
2070 *surface = NULL;
2072 surface_rect = get_surface_rect(visible_rect);
2073 if (data->surface)
2075 if (EqualRect(&data->surface->rect, &surface_rect))
2077 /* existing surface is good enough */
2078 surface_clip_to_visible_rect(data->surface, visible_rect);
2079 window_surface_add_ref(data->surface);
2080 *surface = data->surface;
2081 goto done;
2084 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2086 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2088 done:
2089 release_win_data(data);
2090 return TRUE;
2094 /***********************************************************************
2095 * WindowPosChanged (MACDRV.@)
2097 void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2098 const RECT *window_rect, const RECT *client_rect,
2099 const RECT *visible_rect, const RECT *valid_rects,
2100 struct window_surface *surface)
2102 struct macdrv_thread_data *thread_data;
2103 struct macdrv_win_data *data;
2104 DWORD new_style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
2105 RECT old_window_rect, old_whole_rect, old_client_rect;
2107 if (!(data = get_win_data(hwnd))) return;
2109 thread_data = macdrv_thread_data();
2111 old_window_rect = data->window_rect;
2112 old_whole_rect = data->whole_rect;
2113 old_client_rect = data->client_rect;
2114 data->window_rect = *window_rect;
2115 data->whole_rect = *visible_rect;
2116 data->client_rect = *client_rect;
2117 if (data->cocoa_window && !data->ulw_layered)
2119 if (surface) window_surface_add_ref(surface);
2120 if (new_style & WS_MINIMIZE)
2122 if (!data->unminimized_surface && data->surface)
2124 data->unminimized_surface = data->surface;
2125 window_surface_add_ref(data->unminimized_surface);
2128 else
2130 set_window_surface(data->cocoa_window, surface);
2131 if (data->unminimized_surface)
2133 window_surface_release(data->unminimized_surface);
2134 data->unminimized_surface = NULL;
2137 if (data->surface) window_surface_release(data->surface);
2138 data->surface = surface;
2141 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2142 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2143 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2144 new_style, swp_flags, surface);
2146 if (!IsRectEmpty(&valid_rects[0]))
2148 macdrv_window window = data->cocoa_window;
2149 int x_offset = old_whole_rect.left - data->whole_rect.left;
2150 int y_offset = old_whole_rect.top - data->whole_rect.top;
2152 /* if all that happened is that the whole window moved, copy everything */
2153 if (!(swp_flags & SWP_FRAMECHANGED) &&
2154 old_whole_rect.right - data->whole_rect.right == x_offset &&
2155 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2156 old_client_rect.left - data->client_rect.left == x_offset &&
2157 old_client_rect.right - data->client_rect.right == x_offset &&
2158 old_client_rect.top - data->client_rect.top == y_offset &&
2159 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2160 EqualRect(&valid_rects[0], &data->client_rect))
2162 /* A Cocoa window's bits are moved automatically */
2163 if (!window && (x_offset != 0 || y_offset != 0))
2165 release_win_data(data);
2166 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2167 &old_client_rect, client_rect, window_rect);
2168 if (!(data = get_win_data(hwnd))) return;
2171 else
2173 release_win_data(data);
2174 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2175 &old_client_rect, client_rect, window_rect);
2176 if (!(data = get_win_data(hwnd))) return;
2180 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2182 if (!data->cocoa_window && !data->cocoa_view) goto done;
2184 if (data->on_screen)
2186 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2187 hide_window(data);
2190 /* check if we are currently processing an event relevant to this window */
2191 if (thread_data && thread_data->current_event &&
2192 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2193 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2194 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2196 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2197 sync_client_view_position(data);
2199 else
2201 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2202 if (data->cocoa_window)
2203 set_cocoa_window_properties(data);
2206 if (new_style & WS_VISIBLE)
2208 if (data->cocoa_window)
2210 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2211 set_cocoa_window_properties(data);
2213 /* layered windows are not shown until their attributes are set */
2214 if (!data->on_screen &&
2215 (data->layered || !(NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2216 show_window(data);
2218 else if (!data->on_screen)
2219 show_window(data);
2222 done:
2223 release_win_data(data);
2227 /***********************************************************************
2228 * macdrv_window_close_requested
2230 * Handler for WINDOW_CLOSE_REQUESTED events.
2232 void macdrv_window_close_requested(HWND hwnd)
2234 HMENU sysmenu;
2236 if (NtUserGetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2238 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2239 return;
2242 sysmenu = NtUserGetSystemMenu(hwnd, FALSE);
2243 if (sysmenu)
2245 UINT state = NtUserThunkedMenuItemInfo(sysmenu, SC_CLOSE, MF_BYCOMMAND,
2246 NtUserGetMenuState, NULL, NULL);
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 = NtUserGetAncestor(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 NtUserMapWindowPoints(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 send_message(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2319 NtUserSetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2320 if (send_sizemove)
2321 send_message(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 = NtUserGetWindowLongW(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, NtUserIsWindowEnabled(hwnd),
2339 NtUserIsWindowVisible(hwnd), style, get_focus(), get_active_window(), NtUserGetForegroundWindow());
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 = send_message(hwnd, WM_MOUSEACTIVATE,
2346 (WPARAM)NtUserGetAncestor(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 NtUserSetForegroundWindow(hwnd, FALSE);
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, NtUserGetForegroundWindow());
2372 if (hwnd == NtUserGetForegroundWindow())
2374 send_message(hwnd, WM_CANCELMODE, 0, 0);
2375 if (hwnd == NtUserGetForegroundWindow())
2376 NtUserSetForegroundWindow(NtUserGetDesktopWindow(), FALSE);
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 NtUserClipCursor(NULL);
2402 if (get_active_window() == NtUserGetForegroundWindow())
2404 TRACE("setting fg to desktop\n");
2405 NtUserSetForegroundWindow(NtUserGetDesktopWindow(), FALSE);
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 NtUserClipCursor(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 = NtUserGetWindowLongW(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 NtUserSetActiveWindow(hwnd);
2470 send_message(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 NtUserSetWindowPos(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 send_message(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 = NtUserGetWindowLongW(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 = NtUserGetAncestor(hwnd, GA_PARENT);
2523 rect = rect_from_cgrect(event->window_restore_requested.frame);
2524 macdrv_mac_to_window_rect(data, &rect);
2525 NtUserMapWindowPoints(0, parent, (POINT *)&rect, 2);
2527 release_win_data(data);
2529 NtUserSetInternalWindowPos(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 = NtUserGetWindowLongW(hwnd, GWL_STYLE);
2545 struct macdrv_win_data *data;
2546 HANDLE drag_event = NULL;
2547 OBJECT_ATTRIBUTES attr;
2548 BOOL loop = TRUE;
2549 MSG msg;
2551 TRACE("win %p\n", hwnd);
2553 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2554 if (!(style & WS_VISIBLE)) return;
2556 if (!(data = get_win_data(hwnd))) return;
2557 if (data->drag_event) goto done;
2559 InitializeObjectAttributes(&attr, NULL, OBJ_OPENIF, NULL, NULL);
2560 if (NtCreateEvent(&drag_event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE)) goto done;
2562 data->drag_event = drag_event;
2563 release_win_data(data);
2565 if (!event->window_drag_begin.no_activate && can_window_become_foreground(hwnd) &&
2566 NtUserGetForegroundWindow() != hwnd)
2568 /* ask whether the window wants to be activated */
2569 LRESULT ma = send_message(hwnd, WM_MOUSEACTIVATE, (WPARAM)NtUserGetAncestor(hwnd, GA_ROOT),
2570 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2571 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2573 TRACE("setting foreground window to %p\n", hwnd);
2574 NtUserSetForegroundWindow(hwnd, FALSE);
2578 NtUserClipCursor(NULL);
2579 send_message(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2580 NtUserReleaseCapture();
2582 while (loop)
2584 while (!NtUserPeekMessage(&msg, 0, 0, 0, PM_REMOVE))
2586 DWORD result = NtUserMsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT,
2587 MWMO_INPUTAVAILABLE);
2588 if (result == WAIT_OBJECT_0)
2590 loop = FALSE;
2591 break;
2594 if (!loop)
2595 break;
2597 if (msg.message == WM_QUIT)
2598 break;
2600 if (!NtUserCallMsgFilter(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2601 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2603 NtUserTranslateMessage(&msg, 0);
2604 NtUserDispatchMessage(&msg);
2608 send_message(hwnd, WM_EXITSIZEMOVE, 0, 0);
2610 TRACE("done\n");
2612 if ((data = get_win_data(hwnd)))
2613 data->drag_event = NULL;
2615 done:
2616 release_win_data(data);
2617 if (drag_event) NtClose(drag_event);
2621 /***********************************************************************
2622 * macdrv_window_drag_end
2624 * Handler for WINDOW_DRAG_END events.
2626 void macdrv_window_drag_end(HWND hwnd)
2628 struct macdrv_win_data *data;
2630 TRACE("win %p\n", hwnd);
2632 if (!(data = get_win_data(hwnd))) return;
2633 if (data->drag_event)
2634 NtSetEvent(data->drag_event, NULL);
2635 release_win_data(data);
2639 /***********************************************************************
2640 * macdrv_reassert_window_position
2642 * Handler for REASSERT_WINDOW_POSITION events.
2644 void macdrv_reassert_window_position(HWND hwnd)
2646 struct macdrv_win_data *data = get_win_data(hwnd);
2647 if (data)
2649 if (data->cocoa_window && data->on_screen)
2650 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2651 release_win_data(data);
2656 struct quit_info {
2657 HWND *wins;
2658 UINT capacity;
2659 UINT count;
2660 UINT done;
2661 DWORD flags;
2662 BOOL result;
2663 BOOL replied;
2667 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2669 struct quit_info *qi = (struct quit_info*)lp;
2670 DWORD pid;
2672 NtUserGetWindowThread(hwnd, &pid);
2673 if (pid == GetCurrentProcessId())
2675 if (qi->count >= qi->capacity)
2677 UINT new_cap = qi->capacity * 2;
2678 HWND *new_wins = realloc(qi->wins, new_cap * sizeof(*qi->wins));
2679 if (!new_wins) return FALSE;
2680 qi->wins = new_wins;
2681 qi->capacity = new_cap;
2684 qi->wins[qi->count++] = hwnd;
2687 return TRUE;
2691 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2693 struct quit_info *qi = (struct quit_info*)data;
2695 qi->done++;
2697 if (msg == WM_QUERYENDSESSION)
2699 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2700 hwnd, qi->done, qi->count);
2702 if (!result && !IsWindow(hwnd))
2704 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2705 result = TRUE;
2708 if (!result && qi->result)
2710 qi->result = FALSE;
2712 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2713 ultimate reply. Might as well tell Cocoa now. */
2714 if (!qi->replied)
2716 qi->replied = TRUE;
2717 TRACE("giving quit reply %d\n", qi->result);
2718 macdrv_quit_reply(qi->result);
2722 if (qi->done >= qi->count)
2724 UINT i;
2726 qi->done = 0;
2727 for (i = 0; i < qi->count; i++)
2729 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2730 qi->result, qi->flags);
2731 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2732 quit_callback, (ULONG_PTR)qi))
2734 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2735 qi->wins[i], GetLastError());
2736 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2741 else /* WM_ENDSESSION */
2743 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2745 if (qi->done >= qi->count)
2747 if (!qi->replied)
2749 TRACE("giving quit reply %d\n", qi->result);
2750 macdrv_quit_reply(qi->result);
2753 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2754 if (qi->result)
2755 TerminateProcess(GetCurrentProcess(), 0);
2757 free(qi->wins);
2758 free(qi);
2764 /***********************************************************************
2765 * macdrv_app_quit_requested
2767 * Handler for APP_QUIT_REQUESTED events.
2769 void macdrv_app_quit_requested(const macdrv_event *event)
2771 struct quit_info *qi;
2772 UINT i;
2774 TRACE("reason %d\n", event->app_quit_requested.reason);
2776 qi = malloc(sizeof(*qi));
2777 if (!qi)
2778 goto fail;
2780 qi->capacity = 32;
2781 qi->wins = malloc(qi->capacity * sizeof(*qi->wins));
2782 qi->count = qi->done = 0;
2784 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2785 goto fail;
2787 switch (event->app_quit_requested.reason)
2789 case QUIT_REASON_LOGOUT:
2790 default:
2791 qi->flags = ENDSESSION_LOGOFF;
2792 break;
2793 case QUIT_REASON_RESTART:
2794 case QUIT_REASON_SHUTDOWN:
2795 qi->flags = 0;
2796 break;
2799 qi->result = TRUE;
2800 qi->replied = FALSE;
2802 for (i = 0; i < qi->count; i++)
2804 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2805 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2806 quit_callback, (ULONG_PTR)qi))
2808 DWORD error = GetLastError();
2809 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2810 if (invalid)
2811 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2812 qi->wins[i]);
2813 else
2814 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2815 qi->wins[i], error);
2816 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2820 /* quit_callback() will clean up qi */
2821 return;
2823 fail:
2824 WARN("failed to allocate window list\n");
2825 if (qi)
2827 free(qi->wins);
2828 free(qi);
2830 macdrv_quit_reply(FALSE);
2834 /***********************************************************************
2835 * query_resize_size
2837 * Handler for QUERY_RESIZE_SIZE query.
2839 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2841 struct macdrv_win_data *data = get_win_data(hwnd);
2842 RECT rect = rect_from_cgrect(query->resize_size.rect);
2843 int corner;
2844 BOOL ret = FALSE;
2846 if (!data) return FALSE;
2848 macdrv_mac_to_window_rect(data, &rect);
2850 if (query->resize_size.from_left)
2852 if (query->resize_size.from_top)
2853 corner = WMSZ_TOPLEFT;
2854 else
2855 corner = WMSZ_BOTTOMLEFT;
2857 else if (query->resize_size.from_top)
2858 corner = WMSZ_TOPRIGHT;
2859 else
2860 corner = WMSZ_BOTTOMRIGHT;
2862 if (send_message(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2864 macdrv_window_to_mac_rect(data, NtUserGetWindowLongW(hwnd, GWL_STYLE), &rect,
2865 &data->window_rect, &data->client_rect);
2866 query->resize_size.rect = cgrect_from_rect(rect);
2867 ret = TRUE;
2870 release_win_data(data);
2871 return ret;
2875 /***********************************************************************
2876 * query_resize_start
2878 * Handler for QUERY_RESIZE_START query.
2880 BOOL query_resize_start(HWND hwnd)
2882 TRACE("hwnd %p\n", hwnd);
2884 NtUserClipCursor(NULL);
2886 sync_window_min_max_info(hwnd);
2887 send_message(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2889 return TRUE;
2893 /***********************************************************************
2894 * query_min_max_info
2896 * Handler for QUERY_MIN_MAX_INFO query.
2898 BOOL query_min_max_info(HWND hwnd)
2900 TRACE("hwnd %p\n", hwnd);
2901 sync_window_min_max_info(hwnd);
2902 return TRUE;
2906 /***********************************************************************
2907 * init_win_context
2909 void init_win_context(void)
2911 pthread_mutexattr_t attr;
2913 pthread_mutexattr_init(&attr);
2914 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
2915 pthread_mutex_init(&win_data_mutex, &attr);
2916 pthread_mutexattr_destroy(&attr);