wined3d: Explicitly calculate the sub-resource level in wined3d_surface_upload_data().
[wine.git] / dlls / winemac.drv / window.c
blobe49a445f1a7dfb026a00c76a5a9bda6d74feb809
1 /*
2 * MACDRV windowing driver
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
7 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
26 #include "macdrv.h"
27 #include "winuser.h"
28 #include "wine/unicode.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
34 static CRITICAL_SECTION win_data_section;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
37 0, 0, &win_data_section,
38 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
41 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
43 static CFMutableDictionaryRef win_datas;
45 static DWORD activate_on_focus_time;
48 /***********************************************************************
49 * get_cocoa_window_features
51 static void get_cocoa_window_features(struct macdrv_win_data *data,
52 DWORD style, DWORD ex_style,
53 struct macdrv_window_features* wf)
55 memset(wf, 0, sizeof(*wf));
57 if (disable_window_decorations) return;
58 if (IsRectEmpty(&data->window_rect)) return;
60 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
62 wf->shadow = TRUE;
63 if (!data->shaped)
65 wf->title_bar = TRUE;
66 if (style & WS_SYSMENU) wf->close_button = TRUE;
67 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
68 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
69 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
72 if (style & WS_THICKFRAME)
74 wf->shadow = TRUE;
75 if (!data->shaped) wf->resizable = TRUE;
77 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
78 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
82 /*******************************************************************
83 * can_activate_window
85 * Check if we can activate the specified window.
87 static inline BOOL can_activate_window(HWND hwnd)
89 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
91 if (!(style & WS_VISIBLE)) return FALSE;
92 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
93 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
94 if (hwnd == GetDesktopWindow()) return FALSE;
95 return !(style & WS_DISABLED);
99 /***********************************************************************
100 * get_cocoa_window_state
102 static void get_cocoa_window_state(struct macdrv_win_data *data,
103 DWORD style, DWORD ex_style,
104 struct macdrv_window_state* state)
106 memset(state, 0, sizeof(*state));
107 state->disabled = (style & WS_DISABLED) != 0;
108 state->no_activate = !can_activate_window(data->hwnd);
109 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
110 state->excluded_by_expose = state->excluded_by_cycle =
111 (!(ex_style & WS_EX_APPWINDOW) &&
112 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
113 if (IsRectEmpty(&data->window_rect))
114 state->excluded_by_expose = TRUE;
115 state->minimized = (style & WS_MINIMIZE) != 0;
116 state->minimized_valid = state->minimized != data->minimized;
117 state->maximized = (style & WS_MAXIMIZE) != 0;
121 /***********************************************************************
122 * get_mac_rect_offset
124 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
126 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
128 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
130 rect->top = rect->bottom = rect->left = rect->right = 0;
132 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
134 if (!data->shaped)
136 struct macdrv_window_features wf;
137 get_cocoa_window_features(data, style, ex_style, &wf);
139 if (wf.title_bar)
141 style_mask |= WS_CAPTION;
142 ex_style_mask |= WS_EX_TOOLWINDOW;
144 if (wf.shadow)
146 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
147 ex_style_mask |= WS_EX_DLGMODALFRAME;
151 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
153 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
154 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
158 /***********************************************************************
159 * macdrv_window_to_mac_rect
161 * Convert a rect from client to Mac window coordinates
163 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
165 RECT rc;
167 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
168 if (IsRectEmpty(rect)) return;
170 get_mac_rect_offset(data, style, &rc);
172 rect->left -= rc.left;
173 rect->right -= rc.right;
174 rect->top -= rc.top;
175 rect->bottom -= rc.bottom;
176 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
177 if (rect->left >= rect->right) rect->right = rect->left + 1;
181 /***********************************************************************
182 * macdrv_mac_to_window_rect
184 * Opposite of macdrv_window_to_mac_rect
186 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
188 RECT rc;
189 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
191 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
192 if (IsRectEmpty(rect)) return;
194 get_mac_rect_offset(data, style, &rc);
196 rect->left += rc.left;
197 rect->right += rc.right;
198 rect->top += rc.top;
199 rect->bottom += rc.bottom;
200 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
201 if (rect->left >= rect->right) rect->right = rect->left + 1;
205 /***********************************************************************
206 * constrain_window_frame
208 * Alter a window frame rectangle to fit within a) Cocoa's documented
209 * limits, and b) sane sizes, like twice the desktop rect.
211 static void constrain_window_frame(CGRect* frame)
213 CGRect desktop_rect = macdrv_get_desktop_rect();
214 int max_width, max_height;
216 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
217 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
219 if (frame->origin.x < -16000) frame->origin.x = -16000;
220 if (frame->origin.y < -16000) frame->origin.y = -16000;
221 if (frame->origin.x > 16000) frame->origin.x = 16000;
222 if (frame->origin.y > 16000) frame->origin.y = 16000;
223 if (frame->size.width > max_width) frame->size.width = max_width;
224 if (frame->size.height > max_height) frame->size.height = max_height;
228 /***********************************************************************
229 * alloc_win_data
231 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
233 struct macdrv_win_data *data;
235 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
237 data->hwnd = hwnd;
238 data->color_key = CLR_INVALID;
239 data->swap_interval = 1;
240 EnterCriticalSection(&win_data_section);
241 if (!win_datas)
242 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
243 CFDictionarySetValue(win_datas, hwnd, data);
245 return data;
249 /***********************************************************************
250 * get_win_data
252 * Lock and return the data structure associated with a window.
254 struct macdrv_win_data *get_win_data(HWND hwnd)
256 struct macdrv_win_data *data;
258 if (!hwnd) return NULL;
259 EnterCriticalSection(&win_data_section);
260 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
261 return data;
262 LeaveCriticalSection(&win_data_section);
263 return NULL;
267 /***********************************************************************
268 * release_win_data
270 * Release the data returned by get_win_data.
272 void release_win_data(struct macdrv_win_data *data)
274 if (data) LeaveCriticalSection(&win_data_section);
278 /***********************************************************************
279 * macdrv_get_cocoa_window
281 * Return the Mac window associated with the full area of a window
283 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
285 struct macdrv_win_data *data = get_win_data(hwnd);
286 macdrv_window ret = NULL;
287 if (data && (data->on_screen || !require_on_screen))
288 ret = data->cocoa_window;
289 release_win_data(data);
290 return ret;
294 /***********************************************************************
295 * macdrv_get_cocoa_view
297 * Return the Cocoa view associated with a window
299 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
301 struct macdrv_win_data *data = get_win_data(hwnd);
302 macdrv_view ret = data ? data->cocoa_view : NULL;
304 release_win_data(data);
305 return ret;
309 /***********************************************************************
310 * macdrv_get_client_cocoa_view
312 * Return the Cocoa view associated with a window's client area
314 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
316 struct macdrv_win_data *data = get_win_data(hwnd);
317 macdrv_view ret = data ? data->client_cocoa_view : NULL;
319 release_win_data(data);
320 return ret;
324 /***********************************************************************
325 * set_cocoa_window_properties
327 * Set the window properties for a Cocoa window based on its Windows
328 * properties.
330 static void set_cocoa_window_properties(struct macdrv_win_data *data)
332 DWORD style, ex_style;
333 HWND owner;
334 macdrv_window owner_win;
335 struct macdrv_window_features wf;
336 struct macdrv_window_state state;
338 style = GetWindowLongW(data->hwnd, GWL_STYLE);
339 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
341 owner = GetWindow(data->hwnd, GW_OWNER);
342 if (owner)
343 owner = GetAncestor(owner, GA_ROOT);
344 owner_win = macdrv_get_cocoa_window(owner, TRUE);
345 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
347 get_cocoa_window_features(data, style, ex_style, &wf);
348 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
350 get_cocoa_window_state(data, style, ex_style, &state);
351 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
352 if (state.minimized_valid)
353 data->minimized = state.minimized;
357 /***********************************************************************
358 * sync_window_region
360 * Update the window region.
362 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
364 HRGN hrgn = win_region;
365 RGNDATA *region_data;
366 const CGRect* rects;
367 int count;
369 if (!data->cocoa_window) return;
370 data->shaped = FALSE;
372 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
374 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
375 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
376 return;
379 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
381 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
382 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
384 DeleteObject(hrgn);
385 hrgn = 0;
389 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
390 MirrorRgn(data->hwnd, hrgn);
391 if (hrgn)
393 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
394 data->window_rect.top - data->whole_rect.top);
396 region_data = get_region_data(hrgn, 0);
397 if (region_data)
399 rects = (CGRect*)region_data->Buffer;
400 count = region_data->rdh.nCount;
401 /* Special case optimization. If the region entirely encloses the Cocoa
402 window, it's the same as there being no region. It's potentially
403 hard/slow to test this for arbitrary regions, so we just check for
404 very simple regions. */
405 if (count == 1 && CGRectContainsRect(rects[0],
406 CGRectOffset(cgrect_from_rect(data->whole_rect), -data->whole_rect.left, -data->whole_rect.top)))
408 TRACE("optimizing for simple region that contains Cocoa content rect\n");
409 rects = NULL;
410 count = 0;
413 else
415 rects = NULL;
416 count = 0;
419 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
420 macdrv_set_window_shape(data->cocoa_window, rects, count);
422 HeapFree(GetProcessHeap(), 0, region_data);
423 data->shaped = (region_data != NULL);
425 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
429 /***********************************************************************
430 * add_bounds_rect
432 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
434 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
435 bounds->left = min(bounds->left, rect->left);
436 bounds->top = min(bounds->top, rect->top);
437 bounds->right = max(bounds->right, rect->right);
438 bounds->bottom = max(bounds->bottom, rect->bottom);
442 /***********************************************************************
443 * sync_window_opacity
445 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
446 BOOL per_pixel_alpha, DWORD flags)
448 CGFloat opacity = 1.0;
449 BOOL needs_flush = FALSE;
451 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
453 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
454 macdrv_set_window_alpha(data->cocoa_window, opacity);
456 if (flags & LWA_COLORKEY)
458 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
459 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
460 key = RGB(0, 0, 0);
462 else
463 key = CLR_INVALID;
465 if (data->color_key != key)
467 if (key == CLR_INVALID)
469 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
470 macdrv_clear_window_color_key(data->cocoa_window);
472 else
474 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
475 GetRValue(key), GetGValue(key), GetBValue(key));
476 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
479 data->color_key = key;
480 needs_flush = TRUE;
483 if (!data->per_pixel_alpha != !per_pixel_alpha)
485 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
486 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
487 data->per_pixel_alpha = per_pixel_alpha;
488 needs_flush = TRUE;
491 if (needs_flush && data->surface)
493 RECT *bounds;
494 RECT rect;
496 rect = data->whole_rect;
497 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
498 data->surface->funcs->lock(data->surface);
499 bounds = data->surface->funcs->get_bounds(data->surface);
500 add_bounds_rect(bounds, &rect);
501 data->surface->funcs->unlock(data->surface);
506 /***********************************************************************
507 * sync_window_min_max_info
509 static void sync_window_min_max_info(HWND hwnd)
511 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
512 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
513 RECT win_rect, primary_monitor_rect;
514 MINMAXINFO minmax;
515 LONG adjustedStyle;
516 INT xinc, yinc;
517 WINDOWPLACEMENT wpl;
518 HMONITOR monitor;
519 struct macdrv_win_data *data;
521 TRACE("win %p\n", hwnd);
523 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
525 GetWindowRect(hwnd, &win_rect);
526 minmax.ptReserved.x = win_rect.left;
527 minmax.ptReserved.y = win_rect.top;
529 if ((style & WS_CAPTION) == WS_CAPTION)
530 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
531 else
532 adjustedStyle = style;
534 primary_monitor_rect.left = primary_monitor_rect.top = 0;
535 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
536 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
537 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
539 xinc = -primary_monitor_rect.left;
540 yinc = -primary_monitor_rect.top;
542 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
543 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
544 minmax.ptMaxPosition.x = -xinc;
545 minmax.ptMaxPosition.y = -yinc;
546 if (style & (WS_DLGFRAME | WS_BORDER))
548 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
549 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
551 else
553 minmax.ptMinTrackSize.x = 2 * xinc;
554 minmax.ptMinTrackSize.y = 2 * yinc;
556 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
557 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
559 wpl.length = sizeof(wpl);
560 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
562 minmax.ptMaxPosition = wpl.ptMaxPosition;
564 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
565 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
566 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
569 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
570 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
572 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
574 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
575 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
577 /* if the app didn't change the values, adapt them for the window's monitor */
578 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
580 MONITORINFO mon_info;
581 RECT monitor_rect;
583 mon_info.cbSize = sizeof(mon_info);
584 GetMonitorInfoW(monitor, &mon_info);
586 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
587 monitor_rect = mon_info.rcWork;
588 else
589 monitor_rect = mon_info.rcMonitor;
591 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
592 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
594 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
595 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
597 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
599 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
600 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
604 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
605 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
607 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
608 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
610 if ((data = get_win_data(hwnd)) && data->cocoa_window)
612 RECT min_rect, max_rect;
613 CGSize min_size, max_size;
615 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
616 macdrv_window_to_mac_rect(data, style, &min_rect);
617 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
619 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
620 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
621 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
622 else
624 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
625 macdrv_window_to_mac_rect(data, style, &max_rect);
626 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
629 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
630 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
633 release_win_data(data);
637 /**********************************************************************
638 * create_client_cocoa_view
640 * Create the Cocoa view for a window's client area
642 static void create_client_cocoa_view(struct macdrv_win_data *data)
644 RECT rect = data->client_rect;
645 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
647 if (data->client_cocoa_view)
648 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
649 else
651 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
652 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
654 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
658 /**********************************************************************
659 * create_cocoa_window
661 * Create the whole Mac window for a given window
663 static void create_cocoa_window(struct macdrv_win_data *data)
665 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
666 WCHAR text[1024];
667 struct macdrv_window_features wf;
668 CGRect frame;
669 DWORD style, ex_style;
670 HRGN win_rgn;
671 COLORREF key;
672 BYTE alpha;
673 DWORD layered_flags;
675 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
676 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
678 DeleteObject(win_rgn);
679 win_rgn = 0;
681 data->shaped = (win_rgn != 0);
683 style = GetWindowLongW(data->hwnd, GWL_STYLE);
684 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
686 data->whole_rect = data->window_rect;
687 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
689 get_cocoa_window_features(data, style, ex_style, &wf);
691 frame = cgrect_from_rect(data->whole_rect);
692 constrain_window_frame(&frame);
693 if (frame.size.width < 1 || frame.size.height < 1)
694 frame.size.width = frame.size.height = 1;
696 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
697 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
699 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
700 if (!data->cocoa_window) goto done;
701 create_client_cocoa_view(data);
703 set_cocoa_window_properties(data);
705 /* set the window text */
706 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
707 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
709 /* set the window region */
710 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
712 /* set the window opacity */
713 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
714 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
716 done:
717 if (win_rgn) DeleteObject(win_rgn);
721 /**********************************************************************
722 * destroy_cocoa_window
724 * Destroy the whole Mac window for a given window.
726 static void destroy_cocoa_window(struct macdrv_win_data *data)
728 if (!data->cocoa_window) return;
730 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
732 macdrv_destroy_cocoa_window(data->cocoa_window);
733 data->cocoa_window = 0;
734 data->on_screen = FALSE;
735 data->color_key = CLR_INVALID;
736 if (data->surface) window_surface_release(data->surface);
737 data->surface = NULL;
738 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
739 data->unminimized_surface = NULL;
743 /**********************************************************************
744 * create_cocoa_view
746 * Create the Cocoa view for a given Windows child window
748 static void create_cocoa_view(struct macdrv_win_data *data)
750 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
751 CGRect frame = cgrect_from_rect(data->window_rect);
753 data->shaped = FALSE;
754 data->whole_rect = data->window_rect;
756 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
757 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
759 if (!equal)
760 data->cocoa_view = macdrv_create_view(frame);
761 create_client_cocoa_view(data);
762 if (equal)
764 data->cocoa_view = data->client_cocoa_view;
765 macdrv_set_view_hidden(data->cocoa_view, TRUE);
766 macdrv_set_view_frame(data->cocoa_view, frame);
771 /**********************************************************************
772 * destroy_cocoa_view
774 * Destroy the Cocoa view for a given window.
776 static void destroy_cocoa_view(struct macdrv_win_data *data)
778 if (!data->cocoa_view) return;
780 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
782 if (data->cocoa_view != data->client_cocoa_view)
783 macdrv_dispose_view(data->cocoa_view);
784 data->cocoa_view = NULL;
785 data->on_screen = FALSE;
789 /***********************************************************************
790 * set_cocoa_view_parent
792 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
794 struct macdrv_win_data *parent_data = get_win_data(parent);
795 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
796 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
798 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
800 if (!cocoa_window && !superview)
801 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
803 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
804 release_win_data(parent_data);
808 /***********************************************************************
809 * macdrv_create_win_data
811 * Create a Mac data window structure for an existing window.
813 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
814 const RECT *client_rect)
816 struct macdrv_win_data *data;
817 HWND parent;
819 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
821 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
823 macdrv_init_thread_data();
824 return NULL;
827 /* don't create win data for HWND_MESSAGE windows */
828 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
830 if (!(data = alloc_win_data(hwnd))) return NULL;
832 data->whole_rect = data->window_rect = *window_rect;
833 data->client_rect = *client_rect;
835 if (parent == GetDesktopWindow())
837 create_cocoa_window(data);
838 TRACE("win %p/%p window %s whole %s client %s\n",
839 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
840 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
842 else
844 create_cocoa_view(data);
845 TRACE("win %p/%p window %s whole %s client %s\n",
846 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
847 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
849 set_cocoa_view_parent(data, parent);
852 return data;
856 /**********************************************************************
857 * is_owned_by
859 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
861 while (1)
863 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
864 if (!hwnd2)
865 hwnd2 = GetAncestor(hwnd, GA_ROOT);
866 if (!hwnd2 || hwnd2 == hwnd)
867 break;
868 if (hwnd2 == maybe_owner)
869 return TRUE;
870 hwnd = hwnd2;
873 return FALSE;
877 /**********************************************************************
878 * is_all_the_way_front
880 static BOOL is_all_the_way_front(HWND hwnd)
882 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
883 HWND prev = hwnd;
885 while ((prev = GetWindow(prev, GW_HWNDPREV)))
887 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
888 return TRUE;
889 if (!is_owned_by(prev, hwnd))
890 return FALSE;
893 return TRUE;
897 /***********************************************************************
898 * set_focus
900 static void set_focus(HWND hwnd, BOOL raise)
902 struct macdrv_win_data *data;
904 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
906 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
907 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
909 if (!(data = get_win_data(hwnd))) return;
911 if (data->cocoa_window && data->on_screen)
913 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
914 /* Set Mac focus */
915 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
916 activate_on_focus_time = 0;
919 release_win_data(data);
922 /***********************************************************************
923 * show_window
925 static void show_window(struct macdrv_win_data *data)
927 if (data->cocoa_window)
929 HWND prev = NULL;
930 HWND next = NULL;
931 macdrv_window prev_window = NULL;
932 macdrv_window next_window = NULL;
933 BOOL activate = FALSE;
934 GUITHREADINFO info;
936 /* find window that this one must be after */
937 prev = GetWindow(data->hwnd, GW_HWNDPREV);
938 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
939 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
940 prev = GetWindow(prev, GW_HWNDPREV);
941 if (!prev_window)
943 /* find window that this one must be before */
944 next = GetWindow(data->hwnd, GW_HWNDNEXT);
945 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
946 (next_window = macdrv_get_cocoa_window(next, TRUE))))
947 next = GetWindow(next, GW_HWNDNEXT);
950 TRACE("win %p/%p below %p/%p above %p/%p\n",
951 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
953 if (!prev_window)
954 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
955 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
956 data->on_screen = TRUE;
958 info.cbSize = sizeof(info);
959 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
960 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
961 set_focus(info.hwndFocus, FALSE);
962 if (activate)
963 activate_on_focus_time = 0;
965 else
967 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
969 macdrv_set_view_hidden(data->cocoa_view, FALSE);
970 data->on_screen = TRUE;
975 /***********************************************************************
976 * hide_window
978 static void hide_window(struct macdrv_win_data *data)
980 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
982 if (data->cocoa_window)
983 macdrv_hide_cocoa_window(data->cocoa_window);
984 else
985 macdrv_set_view_hidden(data->cocoa_view, TRUE);
986 data->on_screen = FALSE;
990 /***********************************************************************
991 * sync_window_z_order
993 static void sync_window_z_order(struct macdrv_win_data *data)
995 if (data->cocoa_view)
997 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
998 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
999 macdrv_window window = NULL;
1000 HWND prev;
1001 HWND next = NULL;
1002 macdrv_view prev_view = NULL;
1003 macdrv_view next_view = NULL;
1005 if (!superview)
1007 window = macdrv_get_cocoa_window(parent, FALSE);
1008 if (!window)
1009 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1012 /* find window that this one must be after */
1013 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1014 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1015 prev = GetWindow(prev, GW_HWNDPREV);
1016 if (!prev_view)
1018 /* find window that this one must be before */
1019 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1020 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1021 next = GetWindow(next, GW_HWNDNEXT);
1024 TRACE("win %p/%p below %p/%p above %p/%p\n",
1025 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1027 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1029 else if (data->on_screen)
1030 show_window(data);
1034 /***********************************************************************
1035 * get_region_data
1037 * Calls GetRegionData on the given region and converts the rectangle
1038 * array to CGRect format. The returned buffer must be freed by
1039 * caller using HeapFree(GetProcessHeap(),...).
1040 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1042 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1044 RGNDATA *data;
1045 DWORD size;
1046 int i;
1047 RECT *rect;
1048 CGRect *cgrect;
1050 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
1051 if (sizeof(CGRect) > sizeof(RECT))
1053 /* add extra size for CGRect array */
1054 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1055 size += count * (sizeof(CGRect) - sizeof(RECT));
1057 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1058 if (!GetRegionData(hrgn, size, data))
1060 HeapFree(GetProcessHeap(), 0, data);
1061 return NULL;
1064 rect = (RECT *)data->Buffer;
1065 cgrect = (CGRect *)data->Buffer;
1066 if (hdc_lptodp) /* map to device coordinates */
1068 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1069 for (i = 0; i < data->rdh.nCount; i++)
1071 if (rect[i].right < rect[i].left)
1073 INT tmp = rect[i].right;
1074 rect[i].right = rect[i].left;
1075 rect[i].left = tmp;
1077 if (rect[i].bottom < rect[i].top)
1079 INT tmp = rect[i].bottom;
1080 rect[i].bottom = rect[i].top;
1081 rect[i].top = tmp;
1086 if (sizeof(CGRect) > sizeof(RECT))
1088 /* need to start from the end */
1089 for (i = data->rdh.nCount-1; i >= 0; i--)
1090 cgrect[i] = cgrect_from_rect(rect[i]);
1092 else
1094 for (i = 0; i < data->rdh.nCount; i++)
1095 cgrect[i] = cgrect_from_rect(rect[i]);
1097 return data;
1101 /***********************************************************************
1102 * sync_client_view_position
1104 static void sync_client_view_position(struct macdrv_win_data *data)
1106 if (data->cocoa_view != data->client_cocoa_view)
1108 RECT rect = data->client_rect;
1109 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1110 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1111 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1116 /***********************************************************************
1117 * sync_window_position
1119 * Synchronize the Mac window position with the Windows one
1121 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1122 const RECT *old_whole_rect)
1124 CGRect frame = cgrect_from_rect(data->whole_rect);
1125 BOOL force_z_order = FALSE;
1127 if (data->cocoa_window)
1129 if (data->minimized) return;
1131 constrain_window_frame(&frame);
1132 if (frame.size.width < 1 || frame.size.height < 1)
1133 frame.size.width = frame.size.height = 1;
1135 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1137 else
1139 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1140 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1142 if (were_equal && !now_equal)
1144 data->cocoa_view = macdrv_create_view(frame);
1145 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1146 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1147 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1148 force_z_order = TRUE;
1150 else if (!were_equal && now_equal)
1152 macdrv_dispose_view(data->cocoa_view);
1153 data->cocoa_view = data->client_cocoa_view;
1154 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1155 macdrv_set_view_frame(data->cocoa_view, frame);
1156 force_z_order = TRUE;
1158 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1159 macdrv_set_view_frame(data->cocoa_view, frame);
1162 sync_client_view_position(data);
1164 if (old_window_rect && old_whole_rect &&
1165 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1166 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1167 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1168 sync_window_region(data, (HRGN)1);
1170 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1171 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1172 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1174 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1175 sync_window_z_order(data);
1179 /***********************************************************************
1180 * move_window_bits
1182 * Move the window bits when a window is moved.
1184 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1185 const RECT *old_client_rect, const RECT *new_client_rect,
1186 const RECT *new_window_rect)
1188 RECT src_rect = *old_rect;
1189 RECT dst_rect = *new_rect;
1190 HDC hdc_src, hdc_dst;
1191 HRGN rgn;
1192 HWND parent = 0;
1194 if (!window)
1196 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1197 parent = GetAncestor(hwnd, GA_PARENT);
1198 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1199 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1201 else
1203 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1204 /* make src rect relative to the old position of the window */
1205 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1206 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1207 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1210 rgn = CreateRectRgnIndirect(&dst_rect);
1211 SelectClipRgn(hdc_dst, rgn);
1212 DeleteObject(rgn);
1213 ExcludeUpdateRgn(hdc_dst, hwnd);
1215 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1216 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1217 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1218 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1219 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1221 ReleaseDC(hwnd, hdc_dst);
1222 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1226 /**********************************************************************
1227 * activate_on_following_focus
1229 void activate_on_following_focus(void)
1231 activate_on_focus_time = GetTickCount();
1232 if (!activate_on_focus_time) activate_on_focus_time = 1;
1236 /***********************************************************************
1237 * set_app_icon
1239 static void set_app_icon(void)
1241 CFArrayRef images = create_app_icon_images();
1242 if (images)
1244 macdrv_set_application_icon(images);
1245 CFRelease(images);
1250 /**********************************************************************
1251 * set_capture_window_for_move
1253 static BOOL set_capture_window_for_move(HWND hwnd)
1255 HWND previous = 0;
1256 BOOL ret;
1258 SERVER_START_REQ(set_capture_window)
1260 req->handle = wine_server_user_handle(hwnd);
1261 req->flags = CAPTURE_MOVESIZE;
1262 if ((ret = !wine_server_call_err(req)))
1264 previous = wine_server_ptr_handle(reply->previous);
1265 hwnd = wine_server_ptr_handle(reply->full_handle);
1268 SERVER_END_REQ;
1270 if (ret)
1272 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1274 if (previous && previous != hwnd)
1275 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1277 return ret;
1281 /***********************************************************************
1282 * move_window
1284 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1285 * moving top-level windows and enforcing Mac-style constraints like
1286 * keeping the top of the window within the work area.
1288 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1290 MSG msg;
1291 RECT origRect, movedRect, desktopRect;
1292 LONG hittest = (LONG)(wparam & 0x0f);
1293 POINT capturePoint;
1294 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1295 BOOL moved = FALSE;
1296 DWORD dwPoint = GetMessagePos();
1297 INT captionHeight;
1298 HMONITOR mon = 0;
1299 MONITORINFO info;
1301 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1302 if (hittest && hittest != HTCAPTION) return -1;
1304 capturePoint.x = (short)LOWORD(dwPoint);
1305 capturePoint.y = (short)HIWORD(dwPoint);
1306 ClipCursor(NULL);
1308 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1310 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1311 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1312 captionHeight = -origRect.top;
1313 else
1314 captionHeight = 0;
1316 GetWindowRect(hwnd, &origRect);
1317 movedRect = origRect;
1319 if (!hittest)
1321 /* Move pointer to the center of the caption */
1322 RECT rect = origRect;
1324 /* Note: to be exactly centered we should take the different types
1325 * of border into account, but it shouldn't make more than a few pixels
1326 * of difference so let's not bother with that */
1327 rect.top += GetSystemMetrics(SM_CYBORDER);
1328 if (style & WS_SYSMENU)
1329 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1330 if (style & WS_MINIMIZEBOX)
1331 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1332 if (style & WS_MAXIMIZEBOX)
1333 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1334 capturePoint.x = (rect.right + rect.left) / 2;
1335 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1337 SetCursorPos(capturePoint.x, capturePoint.y);
1338 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1341 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1342 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1343 info.cbSize = sizeof(info);
1344 if (mon && !GetMonitorInfoW(mon, &info))
1345 mon = 0;
1347 /* repaint the window before moving it around */
1348 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1350 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1351 set_capture_window_for_move(hwnd);
1353 while(1)
1355 POINT pt;
1356 int dx = 0, dy = 0;
1357 HMONITOR newmon;
1359 if (!GetMessageW(&msg, 0, 0, 0)) break;
1360 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1362 /* Exit on button-up, Return, or Esc */
1363 if (msg.message == WM_LBUTTONUP ||
1364 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1365 break;
1367 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1369 TranslateMessage(&msg);
1370 DispatchMessageW(&msg);
1371 continue; /* We are not interested in other messages */
1374 pt = msg.pt;
1376 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1378 case VK_UP: pt.y -= 8; break;
1379 case VK_DOWN: pt.y += 8; break;
1380 case VK_LEFT: pt.x -= 8; break;
1381 case VK_RIGHT: pt.x += 8; break;
1384 pt.x = max(pt.x, desktopRect.left);
1385 pt.x = min(pt.x, desktopRect.right - 1);
1386 pt.y = max(pt.y, desktopRect.top);
1387 pt.y = min(pt.y, desktopRect.bottom - 1);
1389 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1391 if (GetMonitorInfoW(newmon, &info))
1392 mon = newmon;
1393 else
1394 mon = 0;
1397 if (mon)
1399 /* wineserver clips the cursor position to the virtual desktop rect but,
1400 if the display configuration is non-rectangular, that could still
1401 leave the logical cursor position outside of any display. The window
1402 could keep moving as you push the cursor against a display edge, even
1403 though the visible cursor doesn't keep moving. The following keeps
1404 the window movement in sync with the visible cursor. */
1405 pt.x = max(pt.x, info.rcMonitor.left);
1406 pt.x = min(pt.x, info.rcMonitor.right - 1);
1407 pt.y = max(pt.y, info.rcMonitor.top);
1408 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1410 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1411 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1412 we want to enforce these constraints:
1413 movedRect.left + dx < info.rcWork.right
1414 movedRect.right + dx > info.rcWork.left
1415 movedRect.top + captionHeight + dy < info.rcWork.bottom
1416 movedRect.bottom + dy > info.rcWork.top
1417 movedRect.top + dy >= info.rcWork.top
1418 The first four keep at least one edge barely in the work area.
1419 The last keeps the top (i.e. the title bar) in the work area.
1420 The fourth is redundant with the last, so can be ignored.
1422 Substituting for dx and dy and rearranging gives us...
1424 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1425 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1426 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1427 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1430 dx = pt.x - capturePoint.x;
1431 dy = pt.y - capturePoint.y;
1433 if (dx || dy)
1435 moved = TRUE;
1437 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1438 else
1440 OffsetRect(&movedRect, dx, dy);
1441 capturePoint = pt;
1443 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1444 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1445 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1450 set_capture_window_for_move(0);
1452 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1453 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1455 /* if the move is canceled, restore the previous position */
1456 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1458 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1459 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1462 return 0;
1466 /***********************************************************************
1467 * perform_window_command
1469 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1471 DWORD style;
1473 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1474 hwnd, style_any, style_none, command, hittest);
1476 style = GetWindowLongW(hwnd, GWL_STYLE);
1477 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1479 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1480 return;
1483 if (GetActiveWindow() != hwnd)
1485 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1486 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1487 switch (ma)
1489 case MA_NOACTIVATEANDEAT:
1490 case MA_ACTIVATEANDEAT:
1491 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1492 return;
1493 case MA_NOACTIVATE:
1494 break;
1495 case MA_ACTIVATE:
1496 case 0:
1497 SetActiveWindow(hwnd);
1498 break;
1499 default:
1500 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1501 break;
1505 TRACE("changing win %p\n", hwnd);
1506 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1510 /**********************************************************************
1511 * CreateDesktopWindow (MACDRV.@)
1513 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1515 unsigned int width, height;
1517 TRACE("%p\n", hwnd);
1519 /* retrieve the real size of the desktop */
1520 SERVER_START_REQ(get_window_rectangles)
1522 req->handle = wine_server_user_handle(hwnd);
1523 req->relative = COORDS_CLIENT;
1524 wine_server_call(req);
1525 width = reply->window.right;
1526 height = reply->window.bottom;
1528 SERVER_END_REQ;
1530 if (!width && !height) /* not initialized yet */
1532 CGRect rect = macdrv_get_desktop_rect();
1534 SERVER_START_REQ(set_window_pos)
1536 req->handle = wine_server_user_handle(hwnd);
1537 req->previous = 0;
1538 req->swp_flags = SWP_NOZORDER;
1539 req->window.left = CGRectGetMinX(rect);
1540 req->window.top = CGRectGetMinY(rect);
1541 req->window.right = CGRectGetMaxX(rect);
1542 req->window.bottom = CGRectGetMaxY(rect);
1543 req->client = req->window;
1544 wine_server_call(req);
1546 SERVER_END_REQ;
1549 set_app_icon();
1550 return TRUE;
1554 /**********************************************************************
1555 * CreateWindow (MACDRV.@)
1557 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1559 if (hwnd == GetDesktopWindow())
1560 macdrv_init_clipboard();
1561 return TRUE;
1565 /***********************************************************************
1566 * DestroyWindow (MACDRV.@)
1568 void CDECL macdrv_DestroyWindow(HWND hwnd)
1570 struct macdrv_win_data *data;
1572 TRACE("%p\n", hwnd);
1574 if (!(data = get_win_data(hwnd))) return;
1576 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1577 if (data->drag_event) SetEvent(data->drag_event);
1579 destroy_cocoa_window(data);
1580 destroy_cocoa_view(data);
1581 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1583 CFDictionaryRemoveValue(win_datas, hwnd);
1584 release_win_data(data);
1585 HeapFree(GetProcessHeap(), 0, data);
1589 /*****************************************************************
1590 * SetFocus (MACDRV.@)
1592 * Set the Mac focus.
1594 void CDECL macdrv_SetFocus(HWND hwnd)
1596 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1598 TRACE("%p\n", hwnd);
1600 if (!thread_data) return;
1601 thread_data->dead_key_state = 0;
1602 set_focus(hwnd, TRUE);
1606 /***********************************************************************
1607 * SetLayeredWindowAttributes (MACDRV.@)
1609 * Set transparency attributes for a layered window.
1611 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1613 struct macdrv_win_data *data = get_win_data(hwnd);
1615 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1617 if (data)
1619 data->layered = TRUE;
1620 data->ulw_layered = FALSE;
1621 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1622 if (data->cocoa_window)
1624 sync_window_opacity(data, key, alpha, FALSE, flags);
1625 /* since layered attributes are now set, can now show the window */
1626 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1627 show_window(data);
1629 release_win_data(data);
1631 else
1632 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1636 /*****************************************************************
1637 * SetParent (MACDRV.@)
1639 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1641 struct macdrv_win_data *data;
1643 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1645 if (parent == old_parent) return;
1646 if (!(data = get_win_data(hwnd))) return;
1648 if (parent != GetDesktopWindow()) /* a child window */
1650 if (old_parent == GetDesktopWindow())
1652 /* destroy the old Mac window */
1653 destroy_cocoa_window(data);
1654 create_cocoa_view(data);
1657 set_cocoa_view_parent(data, parent);
1659 else /* new top level window */
1661 destroy_cocoa_view(data);
1662 create_cocoa_window(data);
1664 release_win_data(data);
1668 /***********************************************************************
1669 * SetWindowRgn (MACDRV.@)
1671 * Assign specified region to window (for non-rectangular windows)
1673 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1675 struct macdrv_win_data *data;
1677 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1679 if ((data = get_win_data(hwnd)))
1681 sync_window_region(data, hrgn);
1682 release_win_data(data);
1684 else
1686 DWORD procid;
1688 GetWindowThreadProcessId(hwnd, &procid);
1689 if (procid != GetCurrentProcessId())
1690 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1695 /***********************************************************************
1696 * SetWindowStyle (MACDRV.@)
1698 * Update the state of the Cocoa window to reflect a style change
1700 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1702 struct macdrv_win_data *data;
1704 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1706 if (hwnd == GetDesktopWindow()) return;
1707 if (!(data = get_win_data(hwnd))) return;
1709 if (data->cocoa_window)
1711 DWORD changed = style->styleNew ^ style->styleOld;
1713 set_cocoa_window_properties(data);
1715 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1717 data->layered = FALSE;
1718 data->ulw_layered = FALSE;
1719 sync_window_opacity(data, 0, 0, FALSE, 0);
1720 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1723 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1724 sync_window_region(data, (HRGN)1);
1727 release_win_data(data);
1731 /*****************************************************************
1732 * SetWindowText (MACDRV.@)
1734 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1736 macdrv_window win;
1738 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1740 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1741 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1745 /***********************************************************************
1746 * ShowWindow (MACDRV.@)
1748 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1750 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1751 struct macdrv_win_data *data = get_win_data(hwnd);
1752 CGRect frame;
1754 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1755 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1757 if (!data || !data->cocoa_window) goto done;
1758 if (IsRectEmpty(rect)) goto done;
1759 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1761 if (rect->left != -32000 || rect->top != -32000)
1763 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1764 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1766 goto done;
1768 if (!data->on_screen) goto done;
1770 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1772 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1773 goto done;
1775 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1776 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1777 goto done;
1779 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1780 *rect = rect_from_cgrect(frame);
1781 macdrv_mac_to_window_rect(data, rect);
1782 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1783 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1785 done:
1786 release_win_data(data);
1787 return swp;
1791 /***********************************************************************
1792 * SysCommand (MACDRV.@)
1794 * Perform WM_SYSCOMMAND handling.
1796 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1798 struct macdrv_win_data *data;
1799 LRESULT ret = -1;
1800 WPARAM command = wparam & 0xfff0;
1802 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1804 if (!(data = get_win_data(hwnd))) goto done;
1805 if (!data->cocoa_window || !data->on_screen) goto done;
1807 /* prevent a simple ALT press+release from activating the system menu,
1808 as that can get confusing */
1809 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1810 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1812 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1813 ret = 0;
1816 if (command == SC_MOVE)
1818 release_win_data(data);
1819 return move_window(hwnd, wparam);
1822 done:
1823 release_win_data(data);
1824 return ret;
1828 /***********************************************************************
1829 * UpdateLayeredWindow (MACDRV.@)
1831 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1832 const RECT *window_rect)
1834 struct window_surface *surface;
1835 struct macdrv_win_data *data;
1836 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1837 BYTE alpha;
1838 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1839 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1840 void *src_bits, *dst_bits;
1841 RECT rect, src_rect;
1842 HDC hdc = 0;
1843 HBITMAP dib;
1844 BOOL ret = FALSE;
1846 if (!(data = get_win_data(hwnd))) return FALSE;
1848 data->layered = TRUE;
1849 data->ulw_layered = TRUE;
1851 rect = *window_rect;
1852 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1854 surface = data->surface;
1855 if (!surface || !EqualRect(&surface->rect, &rect))
1857 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1858 set_window_surface(data->cocoa_window, data->surface);
1859 if (surface) window_surface_release(surface);
1860 surface = data->surface;
1861 if (data->unminimized_surface)
1863 window_surface_release(data->unminimized_surface);
1864 data->unminimized_surface = NULL;
1867 else set_surface_use_alpha(surface, TRUE);
1869 if (surface) window_surface_add_ref(surface);
1870 release_win_data(data);
1872 if (!surface) return FALSE;
1873 if (!info->hdcSrc)
1875 window_surface_release(surface);
1876 return TRUE;
1879 if (info->dwFlags & ULW_ALPHA)
1881 /* Apply SourceConstantAlpha via window alpha, not blend. */
1882 alpha = info->pblend->SourceConstantAlpha;
1883 blend = *info->pblend;
1884 blend.SourceConstantAlpha = 0xff;
1886 else
1887 alpha = 0xff;
1889 dst_bits = surface->funcs->get_info(surface, bmi);
1891 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1892 if (!(hdc = CreateCompatibleDC(0))) goto done;
1894 SelectObject(hdc, dib);
1895 if (info->prcDirty)
1897 IntersectRect(&rect, &rect, info->prcDirty);
1898 surface->funcs->lock(surface);
1899 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1900 surface->funcs->unlock(surface);
1901 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1903 src_rect = rect;
1904 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1905 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1907 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1908 info->hdcSrc, src_rect.left, src_rect.top,
1909 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1910 blend)))
1911 goto done;
1913 if ((data = get_win_data(hwnd)))
1915 if (surface == data->surface)
1917 surface->funcs->lock(surface);
1918 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1919 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1920 surface->funcs->unlock(surface);
1921 surface->funcs->flush(surface);
1924 /* The ULW flags are a superset of the LWA flags. */
1925 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1927 release_win_data(data);
1930 done:
1931 window_surface_release(surface);
1932 if (hdc) DeleteDC(hdc);
1933 if (dib) DeleteObject(dib);
1934 return ret;
1938 /**********************************************************************
1939 * WindowMessage (MACDRV.@)
1941 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1943 struct macdrv_win_data *data;
1945 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1947 switch(msg)
1949 case WM_MACDRV_SET_WIN_REGION:
1950 if ((data = get_win_data(hwnd)))
1952 sync_window_region(data, (HRGN)1);
1953 release_win_data(data);
1955 return 0;
1956 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1957 if (hwnd == GetDesktopWindow())
1959 CGRect new_desktop_rect;
1960 RECT current_desktop_rect;
1962 macdrv_reset_device_metrics();
1963 new_desktop_rect = macdrv_get_desktop_rect();
1964 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1965 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1967 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1968 SMTO_ABORTIFHUNG, 2000, NULL);
1969 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1970 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1971 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1972 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1973 SMTO_ABORTIFHUNG, 2000, NULL);
1976 return 0;
1977 case WM_MACDRV_RESET_DEVICE_METRICS:
1978 macdrv_reset_device_metrics();
1979 return 0;
1980 case WM_MACDRV_DISPLAYCHANGE:
1981 macdrv_reassert_window_position(hwnd);
1982 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1983 return 0;
1984 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1985 activate_on_following_focus();
1986 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1987 return 0;
1990 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1991 return 0;
1995 static inline RECT get_surface_rect(const RECT *visible_rect)
1997 RECT rect;
1998 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
2000 IntersectRect(&rect, visible_rect, &desktop_rect);
2001 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2002 rect.left &= ~127;
2003 rect.top &= ~127;
2004 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2005 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2006 return rect;
2010 /***********************************************************************
2011 * WindowPosChanging (MACDRV.@)
2013 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2014 const RECT *window_rect, const RECT *client_rect,
2015 RECT *visible_rect, struct window_surface **surface)
2017 struct macdrv_win_data *data = get_win_data(hwnd);
2018 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2019 RECT surface_rect;
2021 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2022 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2023 wine_dbgstr_rect(visible_rect), surface);
2025 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
2027 *visible_rect = *window_rect;
2028 macdrv_window_to_mac_rect(data, style, visible_rect);
2029 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2030 wine_dbgstr_rect(visible_rect));
2032 /* create the window surface if necessary */
2033 if (!data->cocoa_window) goto done;
2034 if (swp_flags & SWP_HIDEWINDOW) goto done;
2035 if (data->ulw_layered) goto done;
2037 if (*surface) window_surface_release(*surface);
2038 *surface = NULL;
2040 surface_rect = get_surface_rect(visible_rect);
2041 if (data->surface)
2043 if (EqualRect(&data->surface->rect, &surface_rect))
2045 /* existing surface is good enough */
2046 surface_clip_to_visible_rect(data->surface, visible_rect);
2047 window_surface_add_ref(data->surface);
2048 *surface = data->surface;
2049 goto done;
2052 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2054 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2056 done:
2057 release_win_data(data);
2061 /***********************************************************************
2062 * WindowPosChanged (MACDRV.@)
2064 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2065 const RECT *window_rect, const RECT *client_rect,
2066 const RECT *visible_rect, const RECT *valid_rects,
2067 struct window_surface *surface)
2069 struct macdrv_thread_data *thread_data;
2070 struct macdrv_win_data *data;
2071 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2072 RECT old_window_rect, old_whole_rect, old_client_rect;
2074 if (!(data = get_win_data(hwnd))) return;
2076 thread_data = macdrv_thread_data();
2078 old_window_rect = data->window_rect;
2079 old_whole_rect = data->whole_rect;
2080 old_client_rect = data->client_rect;
2081 data->window_rect = *window_rect;
2082 data->whole_rect = *visible_rect;
2083 data->client_rect = *client_rect;
2084 if (data->cocoa_window && !data->ulw_layered)
2086 if (surface) window_surface_add_ref(surface);
2087 if (new_style & WS_MINIMIZE)
2089 if (!data->unminimized_surface && data->surface)
2091 data->unminimized_surface = data->surface;
2092 window_surface_add_ref(data->unminimized_surface);
2095 else
2097 set_window_surface(data->cocoa_window, surface);
2098 if (data->unminimized_surface)
2100 window_surface_release(data->unminimized_surface);
2101 data->unminimized_surface = NULL;
2104 if (data->surface) window_surface_release(data->surface);
2105 data->surface = surface;
2108 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2109 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2110 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2111 new_style, swp_flags, surface);
2113 if (!IsRectEmpty(&valid_rects[0]))
2115 macdrv_window window = data->cocoa_window;
2116 int x_offset = old_whole_rect.left - data->whole_rect.left;
2117 int y_offset = old_whole_rect.top - data->whole_rect.top;
2119 /* if all that happened is that the whole window moved, copy everything */
2120 if (!(swp_flags & SWP_FRAMECHANGED) &&
2121 old_whole_rect.right - data->whole_rect.right == x_offset &&
2122 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2123 old_client_rect.left - data->client_rect.left == x_offset &&
2124 old_client_rect.right - data->client_rect.right == x_offset &&
2125 old_client_rect.top - data->client_rect.top == y_offset &&
2126 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2127 EqualRect(&valid_rects[0], &data->client_rect))
2129 /* A Cocoa window's bits are moved automatically */
2130 if (!window && (x_offset != 0 || y_offset != 0))
2132 release_win_data(data);
2133 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2134 &old_client_rect, client_rect, window_rect);
2135 if (!(data = get_win_data(hwnd))) return;
2138 else
2140 release_win_data(data);
2141 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2142 &old_client_rect, client_rect, window_rect);
2143 if (!(data = get_win_data(hwnd))) return;
2147 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2149 if (!data->cocoa_window && !data->cocoa_view) goto done;
2151 if (data->on_screen)
2153 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2154 hide_window(data);
2157 /* check if we are currently processing an event relevant to this window */
2158 if (thread_data && thread_data->current_event &&
2159 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2160 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2161 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2163 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2164 sync_client_view_position(data);
2166 else
2168 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2169 if (data->cocoa_window)
2170 set_cocoa_window_properties(data);
2173 if (new_style & WS_VISIBLE)
2175 if (data->cocoa_window)
2177 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2178 set_cocoa_window_properties(data);
2180 /* layered windows are not shown until their attributes are set */
2181 if (!data->on_screen &&
2182 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2183 show_window(data);
2185 else if (!data->on_screen)
2186 show_window(data);
2189 done:
2190 release_win_data(data);
2194 /***********************************************************************
2195 * macdrv_window_close_requested
2197 * Handler for WINDOW_CLOSE_REQUESTED events.
2199 void macdrv_window_close_requested(HWND hwnd)
2201 HMENU sysmenu;
2203 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2205 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2206 return;
2209 sysmenu = GetSystemMenu(hwnd, FALSE);
2210 if (sysmenu)
2212 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2213 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2215 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2216 return;
2220 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2224 /***********************************************************************
2225 * macdrv_window_frame_changed
2227 * Handler for WINDOW_FRAME_CHANGED events.
2229 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2231 struct macdrv_win_data *data;
2232 RECT rect;
2233 HWND parent;
2234 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2235 int width, height;
2236 BOOL being_dragged;
2238 if (!hwnd) return;
2239 if (!(data = get_win_data(hwnd))) return;
2240 if (!data->on_screen || data->minimized)
2242 release_win_data(data);
2243 return;
2246 /* Get geometry */
2248 parent = GetAncestor(hwnd, GA_PARENT);
2250 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2251 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2252 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2254 rect = rect_from_cgrect(event->window_frame_changed.frame);
2255 macdrv_mac_to_window_rect(data, &rect);
2256 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2258 width = rect.right - rect.left;
2259 height = rect.bottom - rect.top;
2261 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2262 flags |= SWP_NOMOVE;
2263 else
2264 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2265 data->window_rect.top, rect.left, rect.top);
2267 if ((data->window_rect.right - data->window_rect.left == width &&
2268 data->window_rect.bottom - data->window_rect.top == height) ||
2269 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2270 flags |= SWP_NOSIZE;
2271 else
2272 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2273 data->window_rect.bottom - data->window_rect.top, width, height);
2275 being_dragged = data->drag_event != NULL;
2276 release_win_data(data);
2278 if (event->window_frame_changed.fullscreen)
2279 flags |= SWP_NOSENDCHANGING;
2280 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2282 if (!event->window_frame_changed.in_resize && !being_dragged)
2283 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2284 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2285 if (!event->window_frame_changed.in_resize && !being_dragged)
2286 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2291 /***********************************************************************
2292 * macdrv_window_got_focus
2294 * Handler for WINDOW_GOT_FOCUS events.
2296 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2298 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2300 if (!hwnd) return;
2302 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2303 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2304 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2306 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2308 /* simulate a mouse click on the caption to find out
2309 * whether the window wants to be activated */
2310 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2311 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2312 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2313 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2315 TRACE("setting foreground window to %p\n", hwnd);
2316 SetForegroundWindow(hwnd);
2317 return;
2321 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2322 macdrv_window_rejected_focus(event);
2326 /***********************************************************************
2327 * macdrv_window_lost_focus
2329 * Handler for WINDOW_LOST_FOCUS events.
2331 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2333 if (!hwnd) return;
2335 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2337 if (hwnd == GetForegroundWindow())
2339 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2340 if (hwnd == GetForegroundWindow())
2341 SetForegroundWindow(GetDesktopWindow());
2346 /***********************************************************************
2347 * macdrv_app_activated
2349 * Handler for APP_ACTIVATED events.
2351 void macdrv_app_activated(void)
2353 TRACE("\n");
2354 macdrv_UpdateClipboard();
2358 /***********************************************************************
2359 * macdrv_app_deactivated
2361 * Handler for APP_DEACTIVATED events.
2363 void macdrv_app_deactivated(void)
2365 if (GetActiveWindow() == GetForegroundWindow())
2367 TRACE("setting fg to desktop\n");
2368 SetForegroundWindow(GetDesktopWindow());
2373 /***********************************************************************
2374 * macdrv_window_maximize_requested
2376 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2378 void macdrv_window_maximize_requested(HWND hwnd)
2380 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2384 /***********************************************************************
2385 * macdrv_window_minimize_requested
2387 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2389 void macdrv_window_minimize_requested(HWND hwnd)
2391 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2395 /***********************************************************************
2396 * macdrv_window_did_unminimize
2398 * Handler for WINDOW_DID_UNMINIMIZE events.
2400 void macdrv_window_did_unminimize(HWND hwnd)
2402 struct macdrv_win_data *data;
2403 DWORD style;
2405 TRACE("win %p\n", hwnd);
2407 if (!(data = get_win_data(hwnd))) return;
2408 if (!data->minimized) goto done;
2410 style = GetWindowLongW(hwnd, GWL_STYLE);
2412 data->minimized = FALSE;
2413 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2415 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2416 release_win_data(data);
2417 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2418 return;
2421 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2423 done:
2424 release_win_data(data);
2428 /***********************************************************************
2429 * macdrv_window_brought_forward
2431 * Handler for WINDOW_BROUGHT_FORWARD events.
2433 void macdrv_window_brought_forward(HWND hwnd)
2435 TRACE("win %p\n", hwnd);
2436 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2440 /***********************************************************************
2441 * macdrv_window_resize_ended
2443 * Handler for WINDOW_RESIZE_ENDED events.
2445 void macdrv_window_resize_ended(HWND hwnd)
2447 TRACE("hwnd %p\n", hwnd);
2448 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2452 /***********************************************************************
2453 * macdrv_window_restore_requested
2455 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2456 * for restoring from maximized, not from minimized.
2458 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2460 if (event->window_restore_requested.keep_frame && hwnd)
2462 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2463 struct macdrv_win_data *data;
2465 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2467 RECT rect;
2468 HWND parent = GetAncestor(hwnd, GA_PARENT);
2470 rect = rect_from_cgrect(event->window_restore_requested.frame);
2471 macdrv_mac_to_window_rect(data, &rect);
2472 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2474 release_win_data(data);
2476 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2480 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2484 /***********************************************************************
2485 * macdrv_window_drag_begin
2487 * Handler for WINDOW_DRAG_BEGIN events.
2489 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2491 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2492 struct macdrv_win_data *data;
2493 HANDLE drag_event = NULL;
2494 BOOL loop = TRUE;
2495 MSG msg;
2497 TRACE("win %p\n", hwnd);
2499 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2500 if (!(style & WS_VISIBLE)) return;
2502 if (!(data = get_win_data(hwnd))) return;
2503 if (data->drag_event) goto done;
2505 drag_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2506 if (!drag_event) goto done;
2508 data->drag_event = drag_event;
2509 release_win_data(data);
2511 if (!event->window_drag_begin.no_activate && can_activate_window(hwnd) && GetForegroundWindow() != hwnd)
2513 /* ask whether the window wants to be activated */
2514 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2515 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2516 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2518 TRACE("setting foreground window to %p\n", hwnd);
2519 SetForegroundWindow(hwnd);
2523 ClipCursor(NULL);
2524 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2525 ReleaseCapture();
2527 while (loop)
2529 while (!PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
2531 DWORD result = MsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
2532 if (result == WAIT_OBJECT_0)
2534 loop = FALSE;
2535 break;
2538 if (!loop)
2539 break;
2541 if (msg.message == WM_QUIT)
2542 break;
2544 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2545 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2547 TranslateMessage(&msg);
2548 DispatchMessageW(&msg);
2552 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2554 TRACE("done\n");
2556 if ((data = get_win_data(hwnd)))
2557 data->drag_event = NULL;
2559 done:
2560 release_win_data(data);
2561 if (drag_event) CloseHandle(drag_event);
2565 /***********************************************************************
2566 * macdrv_window_drag_end
2568 * Handler for WINDOW_DRAG_END events.
2570 void macdrv_window_drag_end(HWND hwnd)
2572 struct macdrv_win_data *data;
2574 TRACE("win %p\n", hwnd);
2576 if (!(data = get_win_data(hwnd))) return;
2577 if (data->drag_event)
2578 SetEvent(data->drag_event);
2579 release_win_data(data);
2583 /***********************************************************************
2584 * macdrv_reassert_window_position
2586 * Handler for REASSERT_WINDOW_POSITION events.
2588 void macdrv_reassert_window_position(HWND hwnd)
2590 struct macdrv_win_data *data = get_win_data(hwnd);
2591 if (data)
2593 if (data->cocoa_window && data->on_screen)
2594 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2595 release_win_data(data);
2600 struct quit_info {
2601 HWND *wins;
2602 UINT capacity;
2603 UINT count;
2604 UINT done;
2605 DWORD flags;
2606 BOOL result;
2607 BOOL replied;
2611 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2613 struct quit_info *qi = (struct quit_info*)lp;
2614 DWORD pid;
2616 GetWindowThreadProcessId(hwnd, &pid);
2617 if (pid == GetCurrentProcessId())
2619 if (qi->count >= qi->capacity)
2621 UINT new_cap = qi->capacity * 2;
2622 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2623 new_cap * sizeof(*qi->wins));
2624 if (!new_wins) return FALSE;
2625 qi->wins = new_wins;
2626 qi->capacity = new_cap;
2629 qi->wins[qi->count++] = hwnd;
2632 return TRUE;
2636 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2638 struct quit_info *qi = (struct quit_info*)data;
2640 qi->done++;
2642 if (msg == WM_QUERYENDSESSION)
2644 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2645 hwnd, qi->done, qi->count);
2647 if (!result && !IsWindow(hwnd))
2649 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2650 result = TRUE;
2653 if (!result && qi->result)
2655 qi->result = FALSE;
2657 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2658 ultimate reply. Might as well tell Cocoa now. */
2659 if (!qi->replied)
2661 qi->replied = TRUE;
2662 TRACE("giving quit reply %d\n", qi->result);
2663 macdrv_quit_reply(qi->result);
2667 if (qi->done >= qi->count)
2669 UINT i;
2671 qi->done = 0;
2672 for (i = 0; i < qi->count; i++)
2674 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2675 qi->result, qi->flags);
2676 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2677 quit_callback, (ULONG_PTR)qi))
2679 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2680 qi->wins[i], GetLastError());
2681 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2686 else /* WM_ENDSESSION */
2688 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2690 if (qi->done >= qi->count)
2692 if (!qi->replied)
2694 TRACE("giving quit reply %d\n", qi->result);
2695 macdrv_quit_reply(qi->result);
2698 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2699 if (qi->result)
2700 TerminateProcess(GetCurrentProcess(), 0);
2702 HeapFree(GetProcessHeap(), 0, qi->wins);
2703 HeapFree(GetProcessHeap(), 0, qi);
2709 /***********************************************************************
2710 * macdrv_app_quit_requested
2712 * Handler for APP_QUIT_REQUESTED events.
2714 void macdrv_app_quit_requested(const macdrv_event *event)
2716 struct quit_info *qi;
2717 UINT i;
2719 TRACE("reason %d\n", event->app_quit_requested.reason);
2721 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2722 if (!qi)
2723 goto fail;
2725 qi->capacity = 32;
2726 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2727 qi->count = qi->done = 0;
2729 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2730 goto fail;
2732 switch (event->app_quit_requested.reason)
2734 case QUIT_REASON_LOGOUT:
2735 default:
2736 qi->flags = ENDSESSION_LOGOFF;
2737 break;
2738 case QUIT_REASON_RESTART:
2739 case QUIT_REASON_SHUTDOWN:
2740 qi->flags = 0;
2741 break;
2744 qi->result = TRUE;
2745 qi->replied = FALSE;
2747 for (i = 0; i < qi->count; i++)
2749 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2750 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2751 quit_callback, (ULONG_PTR)qi))
2753 DWORD error = GetLastError();
2754 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2755 if (invalid)
2756 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2757 qi->wins[i]);
2758 else
2759 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2760 qi->wins[i], error);
2761 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2765 /* quit_callback() will clean up qi */
2766 return;
2768 fail:
2769 WARN("failed to allocate window list\n");
2770 if (qi)
2772 HeapFree(GetProcessHeap(), 0, qi->wins);
2773 HeapFree(GetProcessHeap(), 0, qi);
2775 macdrv_quit_reply(FALSE);
2779 /***********************************************************************
2780 * query_resize_size
2782 * Handler for QUERY_RESIZE_SIZE query.
2784 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2786 struct macdrv_win_data *data = get_win_data(hwnd);
2787 RECT rect = rect_from_cgrect(query->resize_size.rect);
2788 int corner;
2789 BOOL ret = FALSE;
2791 if (!data) return FALSE;
2793 macdrv_mac_to_window_rect(data, &rect);
2795 if (query->resize_size.from_left)
2797 if (query->resize_size.from_top)
2798 corner = WMSZ_TOPLEFT;
2799 else
2800 corner = WMSZ_BOTTOMLEFT;
2802 else if (query->resize_size.from_top)
2803 corner = WMSZ_TOPRIGHT;
2804 else
2805 corner = WMSZ_BOTTOMRIGHT;
2807 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2809 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2810 query->resize_size.rect = cgrect_from_rect(rect);
2811 ret = TRUE;
2814 release_win_data(data);
2815 return ret;
2819 /***********************************************************************
2820 * query_resize_start
2822 * Handler for QUERY_RESIZE_START query.
2824 BOOL query_resize_start(HWND hwnd)
2826 TRACE("hwnd %p\n", hwnd);
2828 sync_window_min_max_info(hwnd);
2829 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2831 return TRUE;
2835 /***********************************************************************
2836 * query_min_max_info
2838 * Handler for QUERY_MIN_MAX_INFO query.
2840 BOOL query_min_max_info(HWND hwnd)
2842 TRACE("hwnd %p\n", hwnd);
2843 sync_window_min_max_info(hwnd);
2844 return TRUE;