version: Use the string value length when converting strings.
[wine.git] / dlls / winemac.drv / window.c
blob2e244050625b2e8ef013d6cccbd31724ad2ef51d
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], cgrect_from_rect(data->whole_rect)))
407 TRACE("optimizing for simple region that contains Cocoa content rect\n");
408 rects = NULL;
409 count = 0;
412 else
414 rects = NULL;
415 count = 0;
418 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
419 macdrv_set_window_shape(data->cocoa_window, rects, count);
421 HeapFree(GetProcessHeap(), 0, region_data);
422 data->shaped = (region_data != NULL);
424 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
428 /***********************************************************************
429 * add_bounds_rect
431 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
433 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
434 bounds->left = min(bounds->left, rect->left);
435 bounds->top = min(bounds->top, rect->top);
436 bounds->right = max(bounds->right, rect->right);
437 bounds->bottom = max(bounds->bottom, rect->bottom);
441 /***********************************************************************
442 * sync_window_opacity
444 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
445 BOOL per_pixel_alpha, DWORD flags)
447 CGFloat opacity = 1.0;
448 BOOL needs_flush = FALSE;
450 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
452 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
453 macdrv_set_window_alpha(data->cocoa_window, opacity);
455 if (flags & LWA_COLORKEY)
457 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
458 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
459 key = RGB(0, 0, 0);
461 else
462 key = CLR_INVALID;
464 if (data->color_key != key)
466 if (key == CLR_INVALID)
468 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
469 macdrv_clear_window_color_key(data->cocoa_window);
471 else
473 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
474 GetRValue(key), GetGValue(key), GetBValue(key));
475 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
478 data->color_key = key;
479 needs_flush = TRUE;
482 if (!data->per_pixel_alpha != !per_pixel_alpha)
484 TRACE("setting window %p/%p per-pixel-alpha to %d\n", data->hwnd, data->cocoa_window, per_pixel_alpha);
485 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
486 data->per_pixel_alpha = per_pixel_alpha;
487 needs_flush = TRUE;
490 if (needs_flush && data->surface)
492 RECT *bounds;
493 RECT rect;
495 rect = data->whole_rect;
496 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
497 data->surface->funcs->lock(data->surface);
498 bounds = data->surface->funcs->get_bounds(data->surface);
499 add_bounds_rect(bounds, &rect);
500 data->surface->funcs->unlock(data->surface);
505 /***********************************************************************
506 * sync_window_min_max_info
508 static void sync_window_min_max_info(HWND hwnd)
510 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
511 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
512 RECT win_rect, primary_monitor_rect;
513 MINMAXINFO minmax;
514 LONG adjustedStyle;
515 INT xinc, yinc;
516 WINDOWPLACEMENT wpl;
517 HMONITOR monitor;
518 struct macdrv_win_data *data;
520 TRACE("win %p\n", hwnd);
522 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
524 GetWindowRect(hwnd, &win_rect);
525 minmax.ptReserved.x = win_rect.left;
526 minmax.ptReserved.y = win_rect.top;
528 if ((style & WS_CAPTION) == WS_CAPTION)
529 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
530 else
531 adjustedStyle = style;
533 primary_monitor_rect.left = primary_monitor_rect.top = 0;
534 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
535 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
536 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
538 xinc = -primary_monitor_rect.left;
539 yinc = -primary_monitor_rect.top;
541 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
542 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
543 minmax.ptMaxPosition.x = -xinc;
544 minmax.ptMaxPosition.y = -yinc;
545 if (style & (WS_DLGFRAME | WS_BORDER))
547 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
548 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
550 else
552 minmax.ptMinTrackSize.x = 2 * xinc;
553 minmax.ptMinTrackSize.y = 2 * yinc;
555 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
556 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
558 wpl.length = sizeof(wpl);
559 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
561 minmax.ptMaxPosition = wpl.ptMaxPosition;
563 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
564 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
565 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
568 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
569 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
571 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
573 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
574 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
576 /* if the app didn't change the values, adapt them for the window's monitor */
577 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
579 MONITORINFO mon_info;
580 RECT monitor_rect;
582 mon_info.cbSize = sizeof(mon_info);
583 GetMonitorInfoW(monitor, &mon_info);
585 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
586 monitor_rect = mon_info.rcWork;
587 else
588 monitor_rect = mon_info.rcMonitor;
590 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
591 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
593 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
594 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
596 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
598 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
599 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
603 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
604 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
606 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
607 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
609 if ((data = get_win_data(hwnd)) && data->cocoa_window)
611 RECT min_rect, max_rect;
612 CGSize min_size, max_size;
614 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
615 macdrv_window_to_mac_rect(data, style, &min_rect);
616 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
618 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
619 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
620 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
621 else
623 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
624 macdrv_window_to_mac_rect(data, style, &max_rect);
625 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
628 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
629 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
632 release_win_data(data);
636 /**********************************************************************
637 * create_client_cocoa_view
639 * Create the Cocoa view for a window's client area
641 static void create_client_cocoa_view(struct macdrv_win_data *data)
643 RECT rect = data->client_rect;
644 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
646 if (data->client_cocoa_view)
647 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
648 else
650 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
651 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
653 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
657 /**********************************************************************
658 * create_cocoa_window
660 * Create the whole Mac window for a given window
662 static void create_cocoa_window(struct macdrv_win_data *data)
664 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
665 WCHAR text[1024];
666 struct macdrv_window_features wf;
667 CGRect frame;
668 DWORD style, ex_style;
669 HRGN win_rgn;
670 COLORREF key;
671 BYTE alpha;
672 DWORD layered_flags;
674 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
675 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
677 DeleteObject(win_rgn);
678 win_rgn = 0;
680 data->shaped = (win_rgn != 0);
682 style = GetWindowLongW(data->hwnd, GWL_STYLE);
683 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
685 data->whole_rect = data->window_rect;
686 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
688 get_cocoa_window_features(data, style, ex_style, &wf);
690 frame = cgrect_from_rect(data->whole_rect);
691 constrain_window_frame(&frame);
692 if (frame.size.width < 1 || frame.size.height < 1)
693 frame.size.width = frame.size.height = 1;
695 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
696 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
698 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
699 if (!data->cocoa_window) goto done;
700 create_client_cocoa_view(data);
702 set_cocoa_window_properties(data);
704 /* set the window text */
705 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
706 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
708 /* set the window region */
709 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
711 /* set the window opacity */
712 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
713 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
715 done:
716 if (win_rgn) DeleteObject(win_rgn);
720 /**********************************************************************
721 * destroy_cocoa_window
723 * Destroy the whole Mac window for a given window.
725 static void destroy_cocoa_window(struct macdrv_win_data *data)
727 if (!data->cocoa_window) return;
729 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
731 macdrv_destroy_cocoa_window(data->cocoa_window);
732 data->cocoa_window = 0;
733 data->on_screen = FALSE;
734 data->color_key = CLR_INVALID;
735 if (data->surface) window_surface_release(data->surface);
736 data->surface = NULL;
737 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
738 data->unminimized_surface = NULL;
742 /**********************************************************************
743 * create_cocoa_view
745 * Create the Cocoa view for a given Windows child window
747 static void create_cocoa_view(struct macdrv_win_data *data)
749 BOOL equal = EqualRect(&data->window_rect, &data->client_rect);
750 CGRect frame = cgrect_from_rect(data->window_rect);
752 data->shaped = FALSE;
753 data->whole_rect = data->window_rect;
755 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
756 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
758 if (!equal)
759 data->cocoa_view = macdrv_create_view(frame);
760 create_client_cocoa_view(data);
761 if (equal)
763 data->cocoa_view = data->client_cocoa_view;
764 macdrv_set_view_hidden(data->cocoa_view, TRUE);
765 macdrv_set_view_frame(data->cocoa_view, frame);
770 /**********************************************************************
771 * destroy_cocoa_view
773 * Destroy the Cocoa view for a given window.
775 static void destroy_cocoa_view(struct macdrv_win_data *data)
777 if (!data->cocoa_view) return;
779 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
781 if (data->cocoa_view != data->client_cocoa_view)
782 macdrv_dispose_view(data->cocoa_view);
783 data->cocoa_view = NULL;
784 data->on_screen = FALSE;
788 /***********************************************************************
789 * set_cocoa_view_parent
791 static void set_cocoa_view_parent(struct macdrv_win_data *data, HWND parent)
793 struct macdrv_win_data *parent_data = get_win_data(parent);
794 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
795 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
797 TRACE("win %p/%p parent %p/%p\n", data->hwnd, data->cocoa_view, parent, cocoa_window ? (void*)cocoa_window : (void*)superview);
799 if (!cocoa_window && !superview)
800 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", data->hwnd, parent);
802 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
803 release_win_data(parent_data);
807 /***********************************************************************
808 * macdrv_create_win_data
810 * Create a Mac data window structure for an existing window.
812 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
813 const RECT *client_rect)
815 struct macdrv_win_data *data;
816 HWND parent;
818 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
820 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
822 macdrv_init_thread_data();
823 return NULL;
826 /* don't create win data for HWND_MESSAGE windows */
827 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
829 if (!(data = alloc_win_data(hwnd))) return NULL;
831 data->whole_rect = data->window_rect = *window_rect;
832 data->client_rect = *client_rect;
834 if (parent == GetDesktopWindow())
836 create_cocoa_window(data);
837 TRACE("win %p/%p window %s whole %s client %s\n",
838 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
839 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
841 else
843 create_cocoa_view(data);
844 TRACE("win %p/%p window %s whole %s client %s\n",
845 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
846 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
848 set_cocoa_view_parent(data, parent);
851 return data;
855 /**********************************************************************
856 * is_owned_by
858 static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
860 while (1)
862 HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
863 if (!hwnd2)
864 hwnd2 = GetAncestor(hwnd, GA_ROOT);
865 if (!hwnd2 || hwnd2 == hwnd)
866 break;
867 if (hwnd2 == maybe_owner)
868 return TRUE;
869 hwnd = hwnd2;
872 return FALSE;
876 /**********************************************************************
877 * is_all_the_way_front
879 static BOOL is_all_the_way_front(HWND hwnd)
881 BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
882 HWND prev = hwnd;
884 while ((prev = GetWindow(prev, GW_HWNDPREV)))
886 if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
887 return TRUE;
888 if (!is_owned_by(prev, hwnd))
889 return FALSE;
892 return TRUE;
896 /***********************************************************************
897 * set_focus
899 static void set_focus(HWND hwnd, BOOL raise)
901 struct macdrv_win_data *data;
903 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
905 if (raise && hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
906 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
908 if (!(data = get_win_data(hwnd))) return;
910 if (data->cocoa_window && data->on_screen)
912 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
913 /* Set Mac focus */
914 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
915 activate_on_focus_time = 0;
918 release_win_data(data);
921 /***********************************************************************
922 * show_window
924 static void show_window(struct macdrv_win_data *data)
926 if (data->cocoa_window)
928 HWND prev = NULL;
929 HWND next = NULL;
930 macdrv_window prev_window = NULL;
931 macdrv_window next_window = NULL;
932 BOOL activate = FALSE;
933 GUITHREADINFO info;
935 /* find window that this one must be after */
936 prev = GetWindow(data->hwnd, GW_HWNDPREV);
937 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
938 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
939 prev = GetWindow(prev, GW_HWNDPREV);
940 if (!prev_window)
942 /* find window that this one must be before */
943 next = GetWindow(data->hwnd, GW_HWNDNEXT);
944 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
945 (next_window = macdrv_get_cocoa_window(next, TRUE))))
946 next = GetWindow(next, GW_HWNDNEXT);
949 TRACE("win %p/%p below %p/%p above %p/%p\n",
950 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
952 if (!prev_window)
953 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
954 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
955 data->on_screen = TRUE;
957 info.cbSize = sizeof(info);
958 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
959 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
960 set_focus(info.hwndFocus, FALSE);
961 if (activate)
962 activate_on_focus_time = 0;
964 else
966 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
968 macdrv_set_view_hidden(data->cocoa_view, FALSE);
969 data->on_screen = TRUE;
974 /***********************************************************************
975 * hide_window
977 static void hide_window(struct macdrv_win_data *data)
979 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
981 if (data->cocoa_window)
982 macdrv_hide_cocoa_window(data->cocoa_window);
983 else
984 macdrv_set_view_hidden(data->cocoa_view, TRUE);
985 data->on_screen = FALSE;
989 /***********************************************************************
990 * sync_window_z_order
992 static void sync_window_z_order(struct macdrv_win_data *data)
994 if (data->cocoa_view)
996 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
997 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
998 macdrv_window window = NULL;
999 HWND prev;
1000 HWND next = NULL;
1001 macdrv_view prev_view = NULL;
1002 macdrv_view next_view = NULL;
1004 if (!superview)
1006 window = macdrv_get_cocoa_window(parent, FALSE);
1007 if (!window)
1008 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
1011 /* find window that this one must be after */
1012 prev = GetWindow(data->hwnd, GW_HWNDPREV);
1013 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
1014 prev = GetWindow(prev, GW_HWNDPREV);
1015 if (!prev_view)
1017 /* find window that this one must be before */
1018 next = GetWindow(data->hwnd, GW_HWNDNEXT);
1019 while (next && !(next_view = macdrv_get_cocoa_view(next)))
1020 next = GetWindow(next, GW_HWNDNEXT);
1023 TRACE("win %p/%p below %p/%p above %p/%p\n",
1024 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
1026 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
1028 else if (data->on_screen)
1029 show_window(data);
1033 /***********************************************************************
1034 * get_region_data
1036 * Calls GetRegionData on the given region and converts the rectangle
1037 * array to CGRect format. The returned buffer must be freed by
1038 * caller using HeapFree(GetProcessHeap(),...).
1039 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
1041 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
1043 RGNDATA *data;
1044 DWORD size;
1045 int i;
1046 RECT *rect;
1047 CGRect *cgrect;
1049 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
1050 if (sizeof(CGRect) > sizeof(RECT))
1052 /* add extra size for CGRect array */
1053 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
1054 size += count * (sizeof(CGRect) - sizeof(RECT));
1056 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
1057 if (!GetRegionData(hrgn, size, data))
1059 HeapFree(GetProcessHeap(), 0, data);
1060 return NULL;
1063 rect = (RECT *)data->Buffer;
1064 cgrect = (CGRect *)data->Buffer;
1065 if (hdc_lptodp) /* map to device coordinates */
1067 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1068 for (i = 0; i < data->rdh.nCount; i++)
1070 if (rect[i].right < rect[i].left)
1072 INT tmp = rect[i].right;
1073 rect[i].right = rect[i].left;
1074 rect[i].left = tmp;
1076 if (rect[i].bottom < rect[i].top)
1078 INT tmp = rect[i].bottom;
1079 rect[i].bottom = rect[i].top;
1080 rect[i].top = tmp;
1085 if (sizeof(CGRect) > sizeof(RECT))
1087 /* need to start from the end */
1088 for (i = data->rdh.nCount-1; i >= 0; i--)
1089 cgrect[i] = cgrect_from_rect(rect[i]);
1091 else
1093 for (i = 0; i < data->rdh.nCount; i++)
1094 cgrect[i] = cgrect_from_rect(rect[i]);
1096 return data;
1100 /***********************************************************************
1101 * sync_client_view_position
1103 static void sync_client_view_position(struct macdrv_win_data *data)
1105 if (data->cocoa_view != data->client_cocoa_view)
1107 RECT rect = data->client_rect;
1108 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1109 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1110 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1115 /***********************************************************************
1116 * sync_window_position
1118 * Synchronize the Mac window position with the Windows one
1120 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1121 const RECT *old_whole_rect)
1123 CGRect frame = cgrect_from_rect(data->whole_rect);
1124 BOOL force_z_order = FALSE;
1126 if (data->cocoa_window)
1128 if (data->minimized) return;
1130 constrain_window_frame(&frame);
1131 if (frame.size.width < 1 || frame.size.height < 1)
1132 frame.size.width = frame.size.height = 1;
1134 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1136 else
1138 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1139 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1141 if (were_equal && !now_equal)
1143 data->cocoa_view = macdrv_create_view(frame);
1144 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1145 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1146 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1147 force_z_order = TRUE;
1149 else if (!were_equal && now_equal)
1151 macdrv_dispose_view(data->cocoa_view);
1152 data->cocoa_view = data->client_cocoa_view;
1153 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1154 macdrv_set_view_frame(data->cocoa_view, frame);
1155 force_z_order = TRUE;
1157 else if (!EqualRect(&data->whole_rect, old_whole_rect))
1158 macdrv_set_view_frame(data->cocoa_view, frame);
1161 sync_client_view_position(data);
1163 if (old_window_rect && old_whole_rect &&
1164 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1165 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1166 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1167 sync_window_region(data, (HRGN)1);
1169 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1170 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1171 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1173 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1174 sync_window_z_order(data);
1178 /***********************************************************************
1179 * move_window_bits
1181 * Move the window bits when a window is moved.
1183 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1184 const RECT *old_client_rect, const RECT *new_client_rect,
1185 const RECT *new_window_rect)
1187 RECT src_rect = *old_rect;
1188 RECT dst_rect = *new_rect;
1189 HDC hdc_src, hdc_dst;
1190 HRGN rgn;
1191 HWND parent = 0;
1193 if (!window)
1195 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1196 parent = GetAncestor(hwnd, GA_PARENT);
1197 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1198 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1200 else
1202 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1203 /* make src rect relative to the old position of the window */
1204 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1205 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1206 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1209 rgn = CreateRectRgnIndirect(&dst_rect);
1210 SelectClipRgn(hdc_dst, rgn);
1211 DeleteObject(rgn);
1212 ExcludeUpdateRgn(hdc_dst, hwnd);
1214 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1215 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1216 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1217 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1218 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1220 ReleaseDC(hwnd, hdc_dst);
1221 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1225 /**********************************************************************
1226 * activate_on_following_focus
1228 void activate_on_following_focus(void)
1230 activate_on_focus_time = GetTickCount();
1231 if (!activate_on_focus_time) activate_on_focus_time = 1;
1235 /***********************************************************************
1236 * set_app_icon
1238 static void set_app_icon(void)
1240 CFArrayRef images = create_app_icon_images();
1241 if (images)
1243 macdrv_set_application_icon(images);
1244 CFRelease(images);
1249 /**********************************************************************
1250 * set_capture_window_for_move
1252 static BOOL set_capture_window_for_move(HWND hwnd)
1254 HWND previous = 0;
1255 BOOL ret;
1257 SERVER_START_REQ(set_capture_window)
1259 req->handle = wine_server_user_handle(hwnd);
1260 req->flags = CAPTURE_MOVESIZE;
1261 if ((ret = !wine_server_call_err(req)))
1263 previous = wine_server_ptr_handle(reply->previous);
1264 hwnd = wine_server_ptr_handle(reply->full_handle);
1267 SERVER_END_REQ;
1269 if (ret)
1271 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1273 if (previous && previous != hwnd)
1274 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1276 return ret;
1280 /***********************************************************************
1281 * move_window
1283 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1284 * moving top-level windows and enforcing Mac-style constraints like
1285 * keeping the top of the window within the work area.
1287 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1289 MSG msg;
1290 RECT origRect, movedRect, desktopRect;
1291 LONG hittest = (LONG)(wparam & 0x0f);
1292 POINT capturePoint;
1293 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1294 BOOL moved = FALSE;
1295 DWORD dwPoint = GetMessagePos();
1296 INT captionHeight;
1297 HMONITOR mon = 0;
1298 MONITORINFO info;
1300 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1301 if (hittest && hittest != HTCAPTION) return -1;
1303 capturePoint.x = (short)LOWORD(dwPoint);
1304 capturePoint.y = (short)HIWORD(dwPoint);
1305 ClipCursor(NULL);
1307 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1309 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1310 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1311 captionHeight = -origRect.top;
1312 else
1313 captionHeight = 0;
1315 GetWindowRect(hwnd, &origRect);
1316 movedRect = origRect;
1318 if (!hittest)
1320 /* Move pointer to the center of the caption */
1321 RECT rect = origRect;
1323 /* Note: to be exactly centered we should take the different types
1324 * of border into account, but it shouldn't make more than a few pixels
1325 * of difference so let's not bother with that */
1326 rect.top += GetSystemMetrics(SM_CYBORDER);
1327 if (style & WS_SYSMENU)
1328 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1329 if (style & WS_MINIMIZEBOX)
1330 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1331 if (style & WS_MAXIMIZEBOX)
1332 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1333 capturePoint.x = (rect.right + rect.left) / 2;
1334 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1336 SetCursorPos(capturePoint.x, capturePoint.y);
1337 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1340 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1341 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1342 info.cbSize = sizeof(info);
1343 if (mon && !GetMonitorInfoW(mon, &info))
1344 mon = 0;
1346 /* repaint the window before moving it around */
1347 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1349 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1350 set_capture_window_for_move(hwnd);
1352 while(1)
1354 POINT pt;
1355 int dx = 0, dy = 0;
1356 HMONITOR newmon;
1358 if (!GetMessageW(&msg, 0, 0, 0)) break;
1359 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1361 /* Exit on button-up, Return, or Esc */
1362 if (msg.message == WM_LBUTTONUP ||
1363 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1364 break;
1366 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1368 TranslateMessage(&msg);
1369 DispatchMessageW(&msg);
1370 continue; /* We are not interested in other messages */
1373 pt = msg.pt;
1375 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1377 case VK_UP: pt.y -= 8; break;
1378 case VK_DOWN: pt.y += 8; break;
1379 case VK_LEFT: pt.x -= 8; break;
1380 case VK_RIGHT: pt.x += 8; break;
1383 pt.x = max(pt.x, desktopRect.left);
1384 pt.x = min(pt.x, desktopRect.right - 1);
1385 pt.y = max(pt.y, desktopRect.top);
1386 pt.y = min(pt.y, desktopRect.bottom - 1);
1388 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1390 if (GetMonitorInfoW(newmon, &info))
1391 mon = newmon;
1392 else
1393 mon = 0;
1396 if (mon)
1398 /* wineserver clips the cursor position to the virtual desktop rect but,
1399 if the display configuration is non-rectangular, that could still
1400 leave the logical cursor position outside of any display. The window
1401 could keep moving as you push the cursor against a display edge, even
1402 though the visible cursor doesn't keep moving. The following keeps
1403 the window movement in sync with the visible cursor. */
1404 pt.x = max(pt.x, info.rcMonitor.left);
1405 pt.x = min(pt.x, info.rcMonitor.right - 1);
1406 pt.y = max(pt.y, info.rcMonitor.top);
1407 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1409 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1410 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1411 we want to enforce these constraints:
1412 movedRect.left + dx < info.rcWork.right
1413 movedRect.right + dx > info.rcWork.left
1414 movedRect.top + captionHeight + dy < info.rcWork.bottom
1415 movedRect.bottom + dy > info.rcWork.top
1416 movedRect.top + dy >= info.rcWork.top
1417 The first four keep at least one edge barely in the work area.
1418 The last keeps the top (i.e. the title bar) in the work area.
1419 The fourth is redundant with the last, so can be ignored.
1421 Substituting for dx and dy and rearranging gives us...
1423 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1424 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1425 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1426 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1429 dx = pt.x - capturePoint.x;
1430 dy = pt.y - capturePoint.y;
1432 if (dx || dy)
1434 moved = TRUE;
1436 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1437 else
1439 OffsetRect(&movedRect, dx, dy);
1440 capturePoint = pt;
1442 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1443 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1444 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1449 set_capture_window_for_move(0);
1451 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1452 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1454 /* if the move is canceled, restore the previous position */
1455 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1457 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1458 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1461 return 0;
1465 /***********************************************************************
1466 * perform_window_command
1468 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1470 DWORD style;
1472 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1473 hwnd, style_any, style_none, command, hittest);
1475 style = GetWindowLongW(hwnd, GWL_STYLE);
1476 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1478 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1479 return;
1482 if (GetActiveWindow() != hwnd)
1484 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1485 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1486 switch (ma)
1488 case MA_NOACTIVATEANDEAT:
1489 case MA_ACTIVATEANDEAT:
1490 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1491 return;
1492 case MA_NOACTIVATE:
1493 break;
1494 case MA_ACTIVATE:
1495 case 0:
1496 SetActiveWindow(hwnd);
1497 break;
1498 default:
1499 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1500 break;
1504 TRACE("changing win %p\n", hwnd);
1505 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1509 /**********************************************************************
1510 * CreateDesktopWindow (MACDRV.@)
1512 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1514 unsigned int width, height;
1516 TRACE("%p\n", hwnd);
1518 /* retrieve the real size of the desktop */
1519 SERVER_START_REQ(get_window_rectangles)
1521 req->handle = wine_server_user_handle(hwnd);
1522 req->relative = COORDS_CLIENT;
1523 wine_server_call(req);
1524 width = reply->window.right;
1525 height = reply->window.bottom;
1527 SERVER_END_REQ;
1529 if (!width && !height) /* not initialized yet */
1531 CGRect rect = macdrv_get_desktop_rect();
1533 SERVER_START_REQ(set_window_pos)
1535 req->handle = wine_server_user_handle(hwnd);
1536 req->previous = 0;
1537 req->swp_flags = SWP_NOZORDER;
1538 req->window.left = CGRectGetMinX(rect);
1539 req->window.top = CGRectGetMinY(rect);
1540 req->window.right = CGRectGetMaxX(rect);
1541 req->window.bottom = CGRectGetMaxY(rect);
1542 req->client = req->window;
1543 wine_server_call(req);
1545 SERVER_END_REQ;
1548 set_app_icon();
1549 return TRUE;
1553 /**********************************************************************
1554 * CreateWindow (MACDRV.@)
1556 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1558 if (hwnd == GetDesktopWindow())
1559 macdrv_init_clipboard();
1560 return TRUE;
1564 /***********************************************************************
1565 * DestroyWindow (MACDRV.@)
1567 void CDECL macdrv_DestroyWindow(HWND hwnd)
1569 struct macdrv_win_data *data;
1571 TRACE("%p\n", hwnd);
1573 if (!(data = get_win_data(hwnd))) return;
1575 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1576 if (data->drag_event) SetEvent(data->drag_event);
1578 destroy_cocoa_window(data);
1579 destroy_cocoa_view(data);
1580 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1582 CFDictionaryRemoveValue(win_datas, hwnd);
1583 release_win_data(data);
1584 HeapFree(GetProcessHeap(), 0, data);
1588 /*****************************************************************
1589 * SetFocus (MACDRV.@)
1591 * Set the Mac focus.
1593 void CDECL macdrv_SetFocus(HWND hwnd)
1595 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1597 TRACE("%p\n", hwnd);
1599 if (!thread_data) return;
1600 thread_data->dead_key_state = 0;
1601 set_focus(hwnd, TRUE);
1605 /***********************************************************************
1606 * SetLayeredWindowAttributes (MACDRV.@)
1608 * Set transparency attributes for a layered window.
1610 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1612 struct macdrv_win_data *data = get_win_data(hwnd);
1614 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1616 if (data)
1618 data->layered = TRUE;
1619 data->ulw_layered = FALSE;
1620 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1621 if (data->cocoa_window)
1623 sync_window_opacity(data, key, alpha, FALSE, flags);
1624 /* since layered attributes are now set, can now show the window */
1625 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1626 show_window(data);
1628 release_win_data(data);
1630 else
1631 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1635 /*****************************************************************
1636 * SetParent (MACDRV.@)
1638 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1640 struct macdrv_win_data *data;
1642 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1644 if (parent == old_parent) return;
1645 if (!(data = get_win_data(hwnd))) return;
1647 if (parent != GetDesktopWindow()) /* a child window */
1649 if (old_parent == GetDesktopWindow())
1651 /* destroy the old Mac window */
1652 destroy_cocoa_window(data);
1653 create_cocoa_view(data);
1656 set_cocoa_view_parent(data, parent);
1658 else /* new top level window */
1660 destroy_cocoa_view(data);
1661 create_cocoa_window(data);
1663 release_win_data(data);
1667 /***********************************************************************
1668 * SetWindowRgn (MACDRV.@)
1670 * Assign specified region to window (for non-rectangular windows)
1672 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1674 struct macdrv_win_data *data;
1676 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1678 if ((data = get_win_data(hwnd)))
1680 sync_window_region(data, hrgn);
1681 release_win_data(data);
1683 else
1685 DWORD procid;
1687 GetWindowThreadProcessId(hwnd, &procid);
1688 if (procid != GetCurrentProcessId())
1689 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1694 /***********************************************************************
1695 * SetWindowStyle (MACDRV.@)
1697 * Update the state of the Cocoa window to reflect a style change
1699 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1701 struct macdrv_win_data *data;
1703 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1705 if (hwnd == GetDesktopWindow()) return;
1706 if (!(data = get_win_data(hwnd))) return;
1708 if (data->cocoa_window)
1710 DWORD changed = style->styleNew ^ style->styleOld;
1712 set_cocoa_window_properties(data);
1714 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1716 data->layered = FALSE;
1717 data->ulw_layered = FALSE;
1718 sync_window_opacity(data, 0, 0, FALSE, 0);
1719 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1722 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1723 sync_window_region(data, (HRGN)1);
1726 release_win_data(data);
1730 /*****************************************************************
1731 * SetWindowText (MACDRV.@)
1733 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1735 macdrv_window win;
1737 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1739 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1740 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1744 /***********************************************************************
1745 * ShowWindow (MACDRV.@)
1747 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1749 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1750 struct macdrv_win_data *data = get_win_data(hwnd);
1751 CGRect frame;
1753 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1754 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1756 if (!data || !data->cocoa_window) goto done;
1757 if (IsRectEmpty(rect)) goto done;
1758 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1760 if (rect->left != -32000 || rect->top != -32000)
1762 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1763 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1765 goto done;
1767 if (!data->on_screen) goto done;
1769 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1771 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1772 goto done;
1774 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1775 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1776 goto done;
1778 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1779 *rect = rect_from_cgrect(frame);
1780 macdrv_mac_to_window_rect(data, rect);
1781 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1782 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1784 done:
1785 release_win_data(data);
1786 return swp;
1790 /***********************************************************************
1791 * SysCommand (MACDRV.@)
1793 * Perform WM_SYSCOMMAND handling.
1795 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1797 struct macdrv_win_data *data;
1798 LRESULT ret = -1;
1799 WPARAM command = wparam & 0xfff0;
1801 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1803 if (!(data = get_win_data(hwnd))) goto done;
1804 if (!data->cocoa_window || !data->on_screen) goto done;
1806 /* prevent a simple ALT press+release from activating the system menu,
1807 as that can get confusing */
1808 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1809 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1811 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1812 ret = 0;
1815 if (command == SC_MOVE)
1817 release_win_data(data);
1818 return move_window(hwnd, wparam);
1821 done:
1822 release_win_data(data);
1823 return ret;
1827 /***********************************************************************
1828 * UpdateLayeredWindow (MACDRV.@)
1830 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1831 const RECT *window_rect)
1833 struct window_surface *surface;
1834 struct macdrv_win_data *data;
1835 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1836 BYTE alpha;
1837 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1838 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1839 void *src_bits, *dst_bits;
1840 RECT rect, src_rect;
1841 HDC hdc = 0;
1842 HBITMAP dib;
1843 BOOL ret = FALSE;
1845 if (!(data = get_win_data(hwnd))) return FALSE;
1847 data->layered = TRUE;
1848 data->ulw_layered = TRUE;
1850 rect = *window_rect;
1851 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1853 surface = data->surface;
1854 if (!surface || !EqualRect(&surface->rect, &rect))
1856 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1857 set_window_surface(data->cocoa_window, data->surface);
1858 if (surface) window_surface_release(surface);
1859 surface = data->surface;
1860 if (data->unminimized_surface)
1862 window_surface_release(data->unminimized_surface);
1863 data->unminimized_surface = NULL;
1866 else set_surface_use_alpha(surface, TRUE);
1868 if (surface) window_surface_add_ref(surface);
1869 release_win_data(data);
1871 if (!surface) return FALSE;
1872 if (!info->hdcSrc)
1874 window_surface_release(surface);
1875 return TRUE;
1878 if (info->dwFlags & ULW_ALPHA)
1880 /* Apply SourceConstantAlpha via window alpha, not blend. */
1881 alpha = info->pblend->SourceConstantAlpha;
1882 blend = *info->pblend;
1883 blend.SourceConstantAlpha = 0xff;
1885 else
1886 alpha = 0xff;
1888 dst_bits = surface->funcs->get_info(surface, bmi);
1890 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1891 if (!(hdc = CreateCompatibleDC(0))) goto done;
1893 SelectObject(hdc, dib);
1894 if (info->prcDirty)
1896 IntersectRect(&rect, &rect, info->prcDirty);
1897 surface->funcs->lock(surface);
1898 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1899 surface->funcs->unlock(surface);
1900 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1902 src_rect = rect;
1903 if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y );
1904 DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 );
1906 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1907 info->hdcSrc, src_rect.left, src_rect.top,
1908 src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,
1909 blend)))
1910 goto done;
1912 if ((data = get_win_data(hwnd)))
1914 if (surface == data->surface)
1916 surface->funcs->lock(surface);
1917 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1918 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1919 surface->funcs->unlock(surface);
1920 surface->funcs->flush(surface);
1923 /* The ULW flags are a superset of the LWA flags. */
1924 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1926 release_win_data(data);
1929 done:
1930 window_surface_release(surface);
1931 if (hdc) DeleteDC(hdc);
1932 if (dib) DeleteObject(dib);
1933 return ret;
1937 /**********************************************************************
1938 * WindowMessage (MACDRV.@)
1940 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1942 struct macdrv_win_data *data;
1944 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1946 switch(msg)
1948 case WM_MACDRV_SET_WIN_REGION:
1949 if ((data = get_win_data(hwnd)))
1951 sync_window_region(data, (HRGN)1);
1952 release_win_data(data);
1954 return 0;
1955 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1956 if (hwnd == GetDesktopWindow())
1958 CGRect new_desktop_rect;
1959 RECT current_desktop_rect;
1961 macdrv_reset_device_metrics();
1962 new_desktop_rect = macdrv_get_desktop_rect();
1963 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1964 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1966 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1967 SMTO_ABORTIFHUNG, 2000, NULL);
1968 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1969 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1970 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1971 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1972 SMTO_ABORTIFHUNG, 2000, NULL);
1975 return 0;
1976 case WM_MACDRV_RESET_DEVICE_METRICS:
1977 macdrv_reset_device_metrics();
1978 return 0;
1979 case WM_MACDRV_DISPLAYCHANGE:
1980 macdrv_reassert_window_position(hwnd);
1981 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1982 return 0;
1983 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1984 activate_on_following_focus();
1985 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1986 return 0;
1989 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1990 return 0;
1994 static inline RECT get_surface_rect(const RECT *visible_rect)
1996 RECT rect;
1997 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1999 IntersectRect(&rect, visible_rect, &desktop_rect);
2000 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
2001 rect.left &= ~127;
2002 rect.top &= ~127;
2003 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
2004 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
2005 return rect;
2009 /***********************************************************************
2010 * WindowPosChanging (MACDRV.@)
2012 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
2013 const RECT *window_rect, const RECT *client_rect,
2014 RECT *visible_rect, struct window_surface **surface)
2016 struct macdrv_win_data *data = get_win_data(hwnd);
2017 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2018 RECT surface_rect;
2020 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
2021 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
2022 wine_dbgstr_rect(visible_rect), surface);
2024 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
2026 *visible_rect = *window_rect;
2027 macdrv_window_to_mac_rect(data, style, visible_rect);
2028 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
2029 wine_dbgstr_rect(visible_rect));
2031 /* create the window surface if necessary */
2032 if (!data->cocoa_window) goto done;
2033 if (swp_flags & SWP_HIDEWINDOW) goto done;
2034 if (data->ulw_layered) goto done;
2036 if (*surface) window_surface_release(*surface);
2037 *surface = NULL;
2039 surface_rect = get_surface_rect(visible_rect);
2040 if (data->surface)
2042 if (EqualRect(&data->surface->rect, &surface_rect))
2044 /* existing surface is good enough */
2045 surface_clip_to_visible_rect(data->surface, visible_rect);
2046 window_surface_add_ref(data->surface);
2047 *surface = data->surface;
2048 goto done;
2051 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
2053 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
2055 done:
2056 release_win_data(data);
2060 /***********************************************************************
2061 * WindowPosChanged (MACDRV.@)
2063 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
2064 const RECT *window_rect, const RECT *client_rect,
2065 const RECT *visible_rect, const RECT *valid_rects,
2066 struct window_surface *surface)
2068 struct macdrv_thread_data *thread_data;
2069 struct macdrv_win_data *data;
2070 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2071 RECT old_window_rect, old_whole_rect, old_client_rect;
2073 if (!(data = get_win_data(hwnd))) return;
2075 thread_data = macdrv_thread_data();
2077 old_window_rect = data->window_rect;
2078 old_whole_rect = data->whole_rect;
2079 old_client_rect = data->client_rect;
2080 data->window_rect = *window_rect;
2081 data->whole_rect = *visible_rect;
2082 data->client_rect = *client_rect;
2083 if (data->cocoa_window && !data->ulw_layered)
2085 if (surface) window_surface_add_ref(surface);
2086 if (new_style & WS_MINIMIZE)
2088 if (!data->unminimized_surface && data->surface)
2090 data->unminimized_surface = data->surface;
2091 window_surface_add_ref(data->unminimized_surface);
2094 else
2096 set_window_surface(data->cocoa_window, surface);
2097 if (data->unminimized_surface)
2099 window_surface_release(data->unminimized_surface);
2100 data->unminimized_surface = NULL;
2103 if (data->surface) window_surface_release(data->surface);
2104 data->surface = surface;
2107 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2108 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2109 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2110 new_style, swp_flags, surface);
2112 if (!IsRectEmpty(&valid_rects[0]))
2114 macdrv_window window = data->cocoa_window;
2115 int x_offset = old_whole_rect.left - data->whole_rect.left;
2116 int y_offset = old_whole_rect.top - data->whole_rect.top;
2118 /* if all that happened is that the whole window moved, copy everything */
2119 if (!(swp_flags & SWP_FRAMECHANGED) &&
2120 old_whole_rect.right - data->whole_rect.right == x_offset &&
2121 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2122 old_client_rect.left - data->client_rect.left == x_offset &&
2123 old_client_rect.right - data->client_rect.right == x_offset &&
2124 old_client_rect.top - data->client_rect.top == y_offset &&
2125 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2126 EqualRect(&valid_rects[0], &data->client_rect))
2128 /* A Cocoa window's bits are moved automatically */
2129 if (!window && (x_offset != 0 || y_offset != 0))
2131 release_win_data(data);
2132 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2133 &old_client_rect, client_rect, window_rect);
2134 if (!(data = get_win_data(hwnd))) return;
2137 else
2139 release_win_data(data);
2140 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2141 &old_client_rect, client_rect, window_rect);
2142 if (!(data = get_win_data(hwnd))) return;
2146 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2148 if (!data->cocoa_window && !data->cocoa_view) goto done;
2150 if (data->on_screen)
2152 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2153 hide_window(data);
2156 /* check if we are currently processing an event relevant to this window */
2157 if (thread_data && thread_data->current_event &&
2158 data->cocoa_window && thread_data->current_event->window == data->cocoa_window &&
2159 (thread_data->current_event->type == WINDOW_FRAME_CHANGED ||
2160 thread_data->current_event->type == WINDOW_DID_UNMINIMIZE))
2162 if (thread_data->current_event->type == WINDOW_FRAME_CHANGED)
2163 sync_client_view_position(data);
2165 else
2167 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2168 if (data->cocoa_window)
2169 set_cocoa_window_properties(data);
2172 if (new_style & WS_VISIBLE)
2174 if (data->cocoa_window)
2176 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2177 set_cocoa_window_properties(data);
2179 /* layered windows are not shown until their attributes are set */
2180 if (!data->on_screen &&
2181 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2182 show_window(data);
2184 else if (!data->on_screen)
2185 show_window(data);
2188 done:
2189 release_win_data(data);
2193 /***********************************************************************
2194 * macdrv_window_close_requested
2196 * Handler for WINDOW_CLOSE_REQUESTED events.
2198 void macdrv_window_close_requested(HWND hwnd)
2200 HMENU sysmenu;
2202 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2204 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2205 return;
2208 sysmenu = GetSystemMenu(hwnd, FALSE);
2209 if (sysmenu)
2211 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2212 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2214 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2215 return;
2219 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2223 /***********************************************************************
2224 * macdrv_window_frame_changed
2226 * Handler for WINDOW_FRAME_CHANGED events.
2228 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2230 struct macdrv_win_data *data;
2231 RECT rect;
2232 HWND parent;
2233 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2234 int width, height;
2235 BOOL being_dragged;
2237 if (!hwnd) return;
2238 if (!(data = get_win_data(hwnd))) return;
2239 if (!data->on_screen || data->minimized)
2241 release_win_data(data);
2242 return;
2245 /* Get geometry */
2247 parent = GetAncestor(hwnd, GA_PARENT);
2249 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2250 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2251 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2253 rect = rect_from_cgrect(event->window_frame_changed.frame);
2254 macdrv_mac_to_window_rect(data, &rect);
2255 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2257 width = rect.right - rect.left;
2258 height = rect.bottom - rect.top;
2260 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2261 flags |= SWP_NOMOVE;
2262 else
2263 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2264 data->window_rect.top, rect.left, rect.top);
2266 if ((data->window_rect.right - data->window_rect.left == width &&
2267 data->window_rect.bottom - data->window_rect.top == height) ||
2268 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2269 flags |= SWP_NOSIZE;
2270 else
2271 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2272 data->window_rect.bottom - data->window_rect.top, width, height);
2274 being_dragged = data->drag_event != NULL;
2275 release_win_data(data);
2277 if (event->window_frame_changed.fullscreen)
2278 flags |= SWP_NOSENDCHANGING;
2279 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2281 if (!event->window_frame_changed.in_resize && !being_dragged)
2282 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2283 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2284 if (!event->window_frame_changed.in_resize && !being_dragged)
2285 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2290 /***********************************************************************
2291 * macdrv_window_got_focus
2293 * Handler for WINDOW_GOT_FOCUS events.
2295 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2297 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2299 if (!hwnd) return;
2301 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2302 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2303 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2305 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2307 /* simulate a mouse click on the caption to find out
2308 * whether the window wants to be activated */
2309 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2310 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2311 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2312 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2314 TRACE("setting foreground window to %p\n", hwnd);
2315 SetForegroundWindow(hwnd);
2316 return;
2320 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2321 macdrv_window_rejected_focus(event);
2325 /***********************************************************************
2326 * macdrv_window_lost_focus
2328 * Handler for WINDOW_LOST_FOCUS events.
2330 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2332 if (!hwnd) return;
2334 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2336 if (hwnd == GetForegroundWindow())
2338 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2339 if (hwnd == GetForegroundWindow())
2340 SetForegroundWindow(GetDesktopWindow());
2345 /***********************************************************************
2346 * macdrv_app_activated
2348 * Handler for APP_ACTIVATED events.
2350 void macdrv_app_activated(void)
2352 TRACE("\n");
2353 macdrv_UpdateClipboard();
2357 /***********************************************************************
2358 * macdrv_app_deactivated
2360 * Handler for APP_DEACTIVATED events.
2362 void macdrv_app_deactivated(void)
2364 if (GetActiveWindow() == GetForegroundWindow())
2366 TRACE("setting fg to desktop\n");
2367 SetForegroundWindow(GetDesktopWindow());
2372 /***********************************************************************
2373 * macdrv_window_maximize_requested
2375 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2377 void macdrv_window_maximize_requested(HWND hwnd)
2379 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2383 /***********************************************************************
2384 * macdrv_window_minimize_requested
2386 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2388 void macdrv_window_minimize_requested(HWND hwnd)
2390 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2394 /***********************************************************************
2395 * macdrv_window_did_unminimize
2397 * Handler for WINDOW_DID_UNMINIMIZE events.
2399 void macdrv_window_did_unminimize(HWND hwnd)
2401 struct macdrv_win_data *data;
2402 DWORD style;
2404 TRACE("win %p\n", hwnd);
2406 if (!(data = get_win_data(hwnd))) return;
2407 if (!data->minimized) goto done;
2409 style = GetWindowLongW(hwnd, GWL_STYLE);
2411 data->minimized = FALSE;
2412 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2414 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2415 release_win_data(data);
2416 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2417 return;
2420 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2422 done:
2423 release_win_data(data);
2427 /***********************************************************************
2428 * macdrv_window_brought_forward
2430 * Handler for WINDOW_BROUGHT_FORWARD events.
2432 void macdrv_window_brought_forward(HWND hwnd)
2434 TRACE("win %p\n", hwnd);
2435 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2439 /***********************************************************************
2440 * macdrv_window_resize_ended
2442 * Handler for WINDOW_RESIZE_ENDED events.
2444 void macdrv_window_resize_ended(HWND hwnd)
2446 TRACE("hwnd %p\n", hwnd);
2447 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2451 /***********************************************************************
2452 * macdrv_window_restore_requested
2454 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2455 * for restoring from maximized, not from minimized.
2457 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2459 if (event->window_restore_requested.keep_frame && hwnd)
2461 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2462 struct macdrv_win_data *data;
2464 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2466 RECT rect;
2467 HWND parent = GetAncestor(hwnd, GA_PARENT);
2469 rect = rect_from_cgrect(event->window_restore_requested.frame);
2470 macdrv_mac_to_window_rect(data, &rect);
2471 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2473 release_win_data(data);
2475 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2479 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2483 /***********************************************************************
2484 * macdrv_window_drag_begin
2486 * Handler for WINDOW_DRAG_BEGIN events.
2488 void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event)
2490 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2491 struct macdrv_win_data *data;
2492 HANDLE drag_event = NULL;
2493 BOOL loop = TRUE;
2494 MSG msg;
2496 TRACE("win %p\n", hwnd);
2498 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2499 if (!(style & WS_VISIBLE)) return;
2501 if (!(data = get_win_data(hwnd))) return;
2502 if (data->drag_event) goto done;
2504 drag_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2505 if (!drag_event) goto done;
2507 data->drag_event = drag_event;
2508 release_win_data(data);
2510 if (!event->window_drag_begin.no_activate && can_activate_window(hwnd) && GetForegroundWindow() != hwnd)
2512 /* ask whether the window wants to be activated */
2513 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
2514 MAKELONG(HTCAPTION, WM_LBUTTONDOWN));
2515 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2517 TRACE("setting foreground window to %p\n", hwnd);
2518 SetForegroundWindow(hwnd);
2522 ClipCursor(NULL);
2523 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2524 ReleaseCapture();
2526 while (loop)
2528 while (!PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
2530 DWORD result = MsgWaitForMultipleObjectsEx(1, &drag_event, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
2531 if (result == WAIT_OBJECT_0)
2533 loop = FALSE;
2534 break;
2537 if (!loop)
2538 break;
2540 if (msg.message == WM_QUIT)
2541 break;
2543 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2544 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2546 TranslateMessage(&msg);
2547 DispatchMessageW(&msg);
2551 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2553 TRACE("done\n");
2555 if ((data = get_win_data(hwnd)))
2556 data->drag_event = NULL;
2558 done:
2559 release_win_data(data);
2560 if (drag_event) CloseHandle(drag_event);
2564 /***********************************************************************
2565 * macdrv_window_drag_end
2567 * Handler for WINDOW_DRAG_END events.
2569 void macdrv_window_drag_end(HWND hwnd)
2571 struct macdrv_win_data *data;
2573 TRACE("win %p\n", hwnd);
2575 if (!(data = get_win_data(hwnd))) return;
2576 if (data->drag_event)
2577 SetEvent(data->drag_event);
2578 release_win_data(data);
2582 /***********************************************************************
2583 * macdrv_reassert_window_position
2585 * Handler for REASSERT_WINDOW_POSITION events.
2587 void macdrv_reassert_window_position(HWND hwnd)
2589 struct macdrv_win_data *data = get_win_data(hwnd);
2590 if (data)
2592 if (data->cocoa_window && data->on_screen)
2593 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2594 release_win_data(data);
2599 struct quit_info {
2600 HWND *wins;
2601 UINT capacity;
2602 UINT count;
2603 UINT done;
2604 DWORD flags;
2605 BOOL result;
2606 BOOL replied;
2610 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2612 struct quit_info *qi = (struct quit_info*)lp;
2613 DWORD pid;
2615 GetWindowThreadProcessId(hwnd, &pid);
2616 if (pid == GetCurrentProcessId())
2618 if (qi->count >= qi->capacity)
2620 UINT new_cap = qi->capacity * 2;
2621 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2622 new_cap * sizeof(*qi->wins));
2623 if (!new_wins) return FALSE;
2624 qi->wins = new_wins;
2625 qi->capacity = new_cap;
2628 qi->wins[qi->count++] = hwnd;
2631 return TRUE;
2635 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2637 struct quit_info *qi = (struct quit_info*)data;
2639 qi->done++;
2641 if (msg == WM_QUERYENDSESSION)
2643 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2644 hwnd, qi->done, qi->count);
2646 if (!result && !IsWindow(hwnd))
2648 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2649 result = TRUE;
2652 if (!result && qi->result)
2654 qi->result = FALSE;
2656 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2657 ultimate reply. Might as well tell Cocoa now. */
2658 if (!qi->replied)
2660 qi->replied = TRUE;
2661 TRACE("giving quit reply %d\n", qi->result);
2662 macdrv_quit_reply(qi->result);
2666 if (qi->done >= qi->count)
2668 UINT i;
2670 qi->done = 0;
2671 for (i = 0; i < qi->count; i++)
2673 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2674 qi->result, qi->flags);
2675 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2676 quit_callback, (ULONG_PTR)qi))
2678 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2679 qi->wins[i], GetLastError());
2680 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2685 else /* WM_ENDSESSION */
2687 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2689 if (qi->done >= qi->count)
2691 if (!qi->replied)
2693 TRACE("giving quit reply %d\n", qi->result);
2694 macdrv_quit_reply(qi->result);
2697 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2698 if (qi->result)
2699 TerminateProcess(GetCurrentProcess(), 0);
2701 HeapFree(GetProcessHeap(), 0, qi->wins);
2702 HeapFree(GetProcessHeap(), 0, qi);
2708 /***********************************************************************
2709 * macdrv_app_quit_requested
2711 * Handler for APP_QUIT_REQUESTED events.
2713 void macdrv_app_quit_requested(const macdrv_event *event)
2715 struct quit_info *qi;
2716 UINT i;
2718 TRACE("reason %d\n", event->app_quit_requested.reason);
2720 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2721 if (!qi)
2722 goto fail;
2724 qi->capacity = 32;
2725 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2726 qi->count = qi->done = 0;
2728 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2729 goto fail;
2731 switch (event->app_quit_requested.reason)
2733 case QUIT_REASON_LOGOUT:
2734 default:
2735 qi->flags = ENDSESSION_LOGOFF;
2736 break;
2737 case QUIT_REASON_RESTART:
2738 case QUIT_REASON_SHUTDOWN:
2739 qi->flags = 0;
2740 break;
2743 qi->result = TRUE;
2744 qi->replied = FALSE;
2746 for (i = 0; i < qi->count; i++)
2748 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2749 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2750 quit_callback, (ULONG_PTR)qi))
2752 DWORD error = GetLastError();
2753 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2754 if (invalid)
2755 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2756 qi->wins[i]);
2757 else
2758 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2759 qi->wins[i], error);
2760 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2764 /* quit_callback() will clean up qi */
2765 return;
2767 fail:
2768 WARN("failed to allocate window list\n");
2769 if (qi)
2771 HeapFree(GetProcessHeap(), 0, qi->wins);
2772 HeapFree(GetProcessHeap(), 0, qi);
2774 macdrv_quit_reply(FALSE);
2778 /***********************************************************************
2779 * query_resize_size
2781 * Handler for QUERY_RESIZE_SIZE query.
2783 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2785 struct macdrv_win_data *data = get_win_data(hwnd);
2786 RECT rect = rect_from_cgrect(query->resize_size.rect);
2787 int corner;
2788 BOOL ret = FALSE;
2790 if (!data) return FALSE;
2792 macdrv_mac_to_window_rect(data, &rect);
2794 if (query->resize_size.from_left)
2796 if (query->resize_size.from_top)
2797 corner = WMSZ_TOPLEFT;
2798 else
2799 corner = WMSZ_BOTTOMLEFT;
2801 else if (query->resize_size.from_top)
2802 corner = WMSZ_TOPRIGHT;
2803 else
2804 corner = WMSZ_BOTTOMRIGHT;
2806 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2808 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2809 query->resize_size.rect = cgrect_from_rect(rect);
2810 ret = TRUE;
2813 release_win_data(data);
2814 return ret;
2818 /***********************************************************************
2819 * query_resize_start
2821 * Handler for QUERY_RESIZE_START query.
2823 BOOL query_resize_start(HWND hwnd)
2825 TRACE("hwnd %p\n", hwnd);
2827 sync_window_min_max_info(hwnd);
2828 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2830 return TRUE;
2834 /***********************************************************************
2835 * query_min_max_info
2837 * Handler for QUERY_MIN_MAX_INFO query.
2839 BOOL query_min_max_info(HWND hwnd)
2841 TRACE("hwnd %p\n", hwnd);
2842 sync_window_min_max_info(hwnd);
2843 return TRUE;