quartz: Clarify debug strings.
[wine.git] / dlls / winemac.drv / window.c
blob0359ef767f4461eb2ba1e0a0e7717efcbb7a1267
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 * macdrv_create_win_data
791 * Create a Mac data window structure for an existing window.
793 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
794 const RECT *client_rect)
796 struct macdrv_win_data *data;
797 HWND parent;
799 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
801 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
803 macdrv_init_thread_data();
804 return NULL;
807 /* don't create win data for HWND_MESSAGE windows */
808 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
810 if (!(data = alloc_win_data(hwnd))) return NULL;
812 data->whole_rect = data->window_rect = *window_rect;
813 data->client_rect = *client_rect;
815 if (parent == GetDesktopWindow())
817 create_cocoa_window(data);
818 TRACE("win %p/%p window %s whole %s client %s\n",
819 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
820 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
822 else
824 create_cocoa_view(data);
825 TRACE("win %p/%p window %s whole %s client %s\n",
826 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
827 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
830 return data;
834 /***********************************************************************
835 * set_focus
837 static void set_focus(HWND hwnd)
839 struct macdrv_win_data *data;
841 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
842 if (!(data = get_win_data(hwnd))) return;
844 if (data->cocoa_window && data->on_screen)
846 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
847 /* Set Mac focus */
848 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
849 activate_on_focus_time = 0;
852 release_win_data(data);
855 /***********************************************************************
856 * show_window
858 static void show_window(struct macdrv_win_data *data)
860 if (data->cocoa_window)
862 HWND prev = NULL;
863 HWND next = NULL;
864 macdrv_window prev_window = NULL;
865 macdrv_window next_window = NULL;
866 BOOL activate = FALSE;
867 GUITHREADINFO info;
869 /* find window that this one must be after */
870 prev = GetWindow(data->hwnd, GW_HWNDPREV);
871 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
872 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
873 prev = GetWindow(prev, GW_HWNDPREV);
874 if (!prev_window)
876 /* find window that this one must be before */
877 next = GetWindow(data->hwnd, GW_HWNDNEXT);
878 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
879 (next_window = macdrv_get_cocoa_window(next, TRUE))))
880 next = GetWindow(next, GW_HWNDNEXT);
883 TRACE("win %p/%p below %p/%p above %p/%p\n",
884 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
886 if (!prev_window)
887 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
888 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
889 data->on_screen = TRUE;
891 info.cbSize = sizeof(info);
892 if (GetGUIThreadInfo(GetWindowThreadProcessId(data->hwnd, NULL), &info) && info.hwndFocus &&
893 (data->hwnd == info.hwndFocus || IsChild(data->hwnd, info.hwndFocus)))
894 set_focus(info.hwndFocus);
895 if (activate)
896 activate_on_focus_time = 0;
898 else
900 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
902 macdrv_set_view_hidden(data->cocoa_view, FALSE);
903 data->on_screen = TRUE;
908 /***********************************************************************
909 * hide_window
911 static void hide_window(struct macdrv_win_data *data)
913 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
915 if (data->cocoa_window)
916 macdrv_hide_cocoa_window(data->cocoa_window);
917 else
918 macdrv_set_view_hidden(data->cocoa_view, TRUE);
919 data->on_screen = FALSE;
923 /***********************************************************************
924 * sync_window_z_order
926 static void sync_window_z_order(struct macdrv_win_data *data)
928 if (data->cocoa_view)
930 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
931 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
932 macdrv_window window = NULL;
933 HWND prev;
934 HWND next = NULL;
935 macdrv_view prev_view = NULL;
936 macdrv_view next_view = NULL;
938 if (!superview)
940 window = macdrv_get_cocoa_window(parent, FALSE);
941 if (!window)
942 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
945 /* find window that this one must be after */
946 prev = GetWindow(data->hwnd, GW_HWNDPREV);
947 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
948 prev = GetWindow(prev, GW_HWNDPREV);
949 if (!prev_view)
951 /* find window that this one must be before */
952 next = GetWindow(data->hwnd, GW_HWNDNEXT);
953 while (next && !(next_view = macdrv_get_cocoa_view(next)))
954 next = GetWindow(next, GW_HWNDNEXT);
957 TRACE("win %p/%p below %p/%p above %p/%p\n",
958 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
960 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
962 else if (data->on_screen)
963 show_window(data);
967 /***********************************************************************
968 * get_region_data
970 * Calls GetRegionData on the given region and converts the rectangle
971 * array to CGRect format. The returned buffer must be freed by
972 * caller using HeapFree(GetProcessHeap(),...).
973 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
975 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
977 RGNDATA *data;
978 DWORD size;
979 int i;
980 RECT *rect;
981 CGRect *cgrect;
983 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
984 if (sizeof(CGRect) > sizeof(RECT))
986 /* add extra size for CGRect array */
987 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
988 size += count * (sizeof(CGRect) - sizeof(RECT));
990 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
991 if (!GetRegionData(hrgn, size, data))
993 HeapFree(GetProcessHeap(), 0, data);
994 return NULL;
997 rect = (RECT *)data->Buffer;
998 cgrect = (CGRect *)data->Buffer;
999 if (hdc_lptodp) /* map to device coordinates */
1001 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
1002 for (i = 0; i < data->rdh.nCount; i++)
1004 if (rect[i].right < rect[i].left)
1006 INT tmp = rect[i].right;
1007 rect[i].right = rect[i].left;
1008 rect[i].left = tmp;
1010 if (rect[i].bottom < rect[i].top)
1012 INT tmp = rect[i].bottom;
1013 rect[i].bottom = rect[i].top;
1014 rect[i].top = tmp;
1019 if (sizeof(CGRect) > sizeof(RECT))
1021 /* need to start from the end */
1022 for (i = data->rdh.nCount-1; i >= 0; i--)
1023 cgrect[i] = cgrect_from_rect(rect[i]);
1025 else
1027 for (i = 0; i < data->rdh.nCount; i++)
1028 cgrect[i] = cgrect_from_rect(rect[i]);
1030 return data;
1034 /***********************************************************************
1035 * sync_window_position
1037 * Synchronize the Mac window position with the Windows one
1039 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1040 const RECT *old_whole_rect)
1042 CGRect frame = cgrect_from_rect(data->whole_rect);
1043 BOOL force_z_order = FALSE;
1045 if (data->cocoa_window)
1047 if (data->minimized) return;
1049 constrain_window_frame(&frame);
1050 if (frame.size.width < 1 || frame.size.height < 1)
1051 frame.size.width = frame.size.height = 1;
1053 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1055 else
1057 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1058 BOOL now_equal = EqualRect(&data->whole_rect, &data->client_rect);
1060 if (were_equal && !now_equal)
1062 data->cocoa_view = macdrv_create_view(frame);
1063 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1064 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1065 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1066 force_z_order = TRUE;
1068 else if (!were_equal && now_equal)
1070 macdrv_dispose_view(data->cocoa_view);
1071 data->cocoa_view = data->client_cocoa_view;
1072 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1073 macdrv_set_view_frame(data->cocoa_view, frame);
1074 force_z_order = TRUE;
1076 else
1077 macdrv_set_view_frame(data->cocoa_view, frame);
1080 if (data->cocoa_view != data->client_cocoa_view)
1082 RECT rect = data->client_rect;
1083 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1084 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1085 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1088 if (old_window_rect && old_whole_rect &&
1089 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1090 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1091 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1092 sync_window_region(data, (HRGN)1);
1094 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1095 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1096 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1098 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1099 sync_window_z_order(data);
1103 /***********************************************************************
1104 * move_window_bits
1106 * Move the window bits when a window is moved.
1108 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1109 const RECT *old_client_rect, const RECT *new_client_rect,
1110 const RECT *new_window_rect)
1112 RECT src_rect = *old_rect;
1113 RECT dst_rect = *new_rect;
1114 HDC hdc_src, hdc_dst;
1115 HRGN rgn;
1116 HWND parent = 0;
1118 if (!window)
1120 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1121 parent = GetAncestor(hwnd, GA_PARENT);
1122 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1123 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1125 else
1127 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1128 /* make src rect relative to the old position of the window */
1129 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1130 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1131 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1134 rgn = CreateRectRgnIndirect(&dst_rect);
1135 SelectClipRgn(hdc_dst, rgn);
1136 DeleteObject(rgn);
1137 ExcludeUpdateRgn(hdc_dst, hwnd);
1139 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1140 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1141 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1142 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1143 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1145 ReleaseDC(hwnd, hdc_dst);
1146 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1150 /**********************************************************************
1151 * activate_on_following_focus
1153 void activate_on_following_focus(void)
1155 activate_on_focus_time = GetTickCount();
1156 if (!activate_on_focus_time) activate_on_focus_time = 1;
1160 /***********************************************************************
1161 * set_app_icon
1163 static void set_app_icon(void)
1165 CFArrayRef images = create_app_icon_images();
1166 if (images)
1168 macdrv_set_application_icon(images);
1169 CFRelease(images);
1174 /**********************************************************************
1175 * set_capture_window_for_move
1177 static BOOL set_capture_window_for_move(HWND hwnd)
1179 HWND previous = 0;
1180 BOOL ret;
1182 SERVER_START_REQ(set_capture_window)
1184 req->handle = wine_server_user_handle(hwnd);
1185 req->flags = CAPTURE_MOVESIZE;
1186 if ((ret = !wine_server_call_err(req)))
1188 previous = wine_server_ptr_handle(reply->previous);
1189 hwnd = wine_server_ptr_handle(reply->full_handle);
1192 SERVER_END_REQ;
1194 if (ret)
1196 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1198 if (previous && previous != hwnd)
1199 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1201 return ret;
1205 /***********************************************************************
1206 * move_window
1208 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1209 * moving top-level windows and enforcing Mac-style constraints like
1210 * keeping the top of the window within the work area.
1212 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1214 MSG msg;
1215 RECT origRect, movedRect, desktopRect;
1216 LONG hittest = (LONG)(wparam & 0x0f);
1217 POINT capturePoint;
1218 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1219 BOOL moved = FALSE;
1220 DWORD dwPoint = GetMessagePos();
1221 INT captionHeight;
1222 HMONITOR mon = 0;
1223 MONITORINFO info;
1225 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1226 if (hittest && hittest != HTCAPTION) return -1;
1228 capturePoint.x = (short)LOWORD(dwPoint);
1229 capturePoint.y = (short)HIWORD(dwPoint);
1230 ClipCursor(NULL);
1232 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1234 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1235 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1236 captionHeight = -origRect.top;
1237 else
1238 captionHeight = 0;
1240 GetWindowRect(hwnd, &origRect);
1241 movedRect = origRect;
1243 if (!hittest)
1245 /* Move pointer to the center of the caption */
1246 RECT rect = origRect;
1248 /* Note: to be exactly centered we should take the different types
1249 * of border into account, but it shouldn't make more than a few pixels
1250 * of difference so let's not bother with that */
1251 rect.top += GetSystemMetrics(SM_CYBORDER);
1252 if (style & WS_SYSMENU)
1253 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1254 if (style & WS_MINIMIZEBOX)
1255 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1256 if (style & WS_MAXIMIZEBOX)
1257 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1258 capturePoint.x = (rect.right + rect.left) / 2;
1259 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1261 SetCursorPos(capturePoint.x, capturePoint.y);
1262 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1265 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1266 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1267 info.cbSize = sizeof(info);
1268 if (mon && !GetMonitorInfoW(mon, &info))
1269 mon = 0;
1271 /* repaint the window before moving it around */
1272 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1274 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1275 set_capture_window_for_move(hwnd);
1277 while(1)
1279 POINT pt;
1280 int dx = 0, dy = 0;
1281 HMONITOR newmon;
1283 if (!GetMessageW(&msg, 0, 0, 0)) break;
1284 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1286 /* Exit on button-up, Return, or Esc */
1287 if (msg.message == WM_LBUTTONUP ||
1288 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1289 break;
1291 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1293 TranslateMessage(&msg);
1294 DispatchMessageW(&msg);
1295 continue; /* We are not interested in other messages */
1298 pt = msg.pt;
1300 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1302 case VK_UP: pt.y -= 8; break;
1303 case VK_DOWN: pt.y += 8; break;
1304 case VK_LEFT: pt.x -= 8; break;
1305 case VK_RIGHT: pt.x += 8; break;
1308 pt.x = max(pt.x, desktopRect.left);
1309 pt.x = min(pt.x, desktopRect.right - 1);
1310 pt.y = max(pt.y, desktopRect.top);
1311 pt.y = min(pt.y, desktopRect.bottom - 1);
1313 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1315 if (GetMonitorInfoW(newmon, &info))
1316 mon = newmon;
1317 else
1318 mon = 0;
1321 if (mon)
1323 /* wineserver clips the cursor position to the virtual desktop rect but,
1324 if the display configuration is non-rectangular, that could still
1325 leave the logical cursor position outside of any display. The window
1326 could keep moving as you push the cursor against a display edge, even
1327 though the visible cursor doesn't keep moving. The following keeps
1328 the window movement in sync with the visible cursor. */
1329 pt.x = max(pt.x, info.rcMonitor.left);
1330 pt.x = min(pt.x, info.rcMonitor.right - 1);
1331 pt.y = max(pt.y, info.rcMonitor.top);
1332 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1334 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1335 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1336 we want to enforce these constraints:
1337 movedRect.left + dx < info.rcWork.right
1338 movedRect.right + dx > info.rcWork.left
1339 movedRect.top + captionHeight + dy < info.rcWork.bottom
1340 movedRect.bottom + dy > info.rcWork.top
1341 movedRect.top + dy >= info.rcWork.top
1342 The first four keep at least one edge barely in the work area.
1343 The last keeps the top (i.e. the title bar) in the work area.
1344 The fourth is redundant with the last, so can be ignored.
1346 Substituting for dx and dy and rearranging gives us...
1348 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1349 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1350 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1351 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1354 dx = pt.x - capturePoint.x;
1355 dy = pt.y - capturePoint.y;
1357 if (dx || dy)
1359 moved = TRUE;
1361 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1362 else
1364 OffsetRect(&movedRect, dx, dy);
1365 capturePoint = pt;
1367 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1368 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1369 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1374 set_capture_window_for_move(0);
1376 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1377 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1379 /* if the move is canceled, restore the previous position */
1380 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1382 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1383 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1386 return 0;
1390 /***********************************************************************
1391 * perform_window_command
1393 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1395 DWORD style;
1397 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1398 hwnd, style_any, style_none, command, hittest);
1400 style = GetWindowLongW(hwnd, GWL_STYLE);
1401 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1403 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1404 return;
1407 if (GetActiveWindow() != hwnd)
1409 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1410 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1411 switch (ma)
1413 case MA_NOACTIVATEANDEAT:
1414 case MA_ACTIVATEANDEAT:
1415 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1416 return;
1417 case MA_NOACTIVATE:
1418 break;
1419 case MA_ACTIVATE:
1420 case 0:
1421 SetActiveWindow(hwnd);
1422 break;
1423 default:
1424 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1425 break;
1429 TRACE("changing win %p\n", hwnd);
1430 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1434 /**********************************************************************
1435 * CreateDesktopWindow (MACDRV.@)
1437 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1439 unsigned int width, height;
1441 TRACE("%p\n", hwnd);
1443 /* retrieve the real size of the desktop */
1444 SERVER_START_REQ(get_window_rectangles)
1446 req->handle = wine_server_user_handle(hwnd);
1447 req->relative = COORDS_CLIENT;
1448 wine_server_call(req);
1449 width = reply->window.right;
1450 height = reply->window.bottom;
1452 SERVER_END_REQ;
1454 if (!width && !height) /* not initialized yet */
1456 CGRect rect = macdrv_get_desktop_rect();
1458 SERVER_START_REQ(set_window_pos)
1460 req->handle = wine_server_user_handle(hwnd);
1461 req->previous = 0;
1462 req->swp_flags = SWP_NOZORDER;
1463 req->window.left = CGRectGetMinX(rect);
1464 req->window.top = CGRectGetMinY(rect);
1465 req->window.right = CGRectGetMaxX(rect);
1466 req->window.bottom = CGRectGetMaxY(rect);
1467 req->client = req->window;
1468 wine_server_call(req);
1470 SERVER_END_REQ;
1473 set_app_icon();
1474 return TRUE;
1478 /**********************************************************************
1479 * CreateWindow (MACDRV.@)
1481 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1483 return TRUE;
1487 /***********************************************************************
1488 * DestroyWindow (MACDRV.@)
1490 void CDECL macdrv_DestroyWindow(HWND hwnd)
1492 struct macdrv_win_data *data;
1494 TRACE("%p\n", hwnd);
1496 if (!(data = get_win_data(hwnd))) return;
1498 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1500 destroy_cocoa_window(data);
1501 destroy_cocoa_view(data);
1502 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1504 CFDictionaryRemoveValue(win_datas, hwnd);
1505 release_win_data(data);
1506 HeapFree(GetProcessHeap(), 0, data);
1510 /*****************************************************************
1511 * SetFocus (MACDRV.@)
1513 * Set the Mac focus.
1515 void CDECL macdrv_SetFocus(HWND hwnd)
1517 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1519 TRACE("%p\n", hwnd);
1521 if (!thread_data) return;
1522 thread_data->dead_key_state = 0;
1523 set_focus(hwnd);
1527 /***********************************************************************
1528 * SetLayeredWindowAttributes (MACDRV.@)
1530 * Set transparency attributes for a layered window.
1532 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1534 struct macdrv_win_data *data = get_win_data(hwnd);
1536 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1538 if (data)
1540 data->layered = TRUE;
1541 if (data->cocoa_window)
1543 sync_window_opacity(data, key, alpha, FALSE, flags);
1544 /* since layered attributes are now set, can now show the window */
1545 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1546 show_window(data);
1548 release_win_data(data);
1550 else
1551 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1555 /*****************************************************************
1556 * SetParent (MACDRV.@)
1558 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1560 struct macdrv_win_data *data;
1562 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1564 if (parent == old_parent) return;
1565 if (!(data = get_win_data(hwnd))) return;
1567 if (parent != GetDesktopWindow()) /* a child window */
1569 if (old_parent == GetDesktopWindow())
1571 /* destroy the old Mac window */
1572 destroy_cocoa_window(data);
1573 create_cocoa_view(data);
1575 else
1577 struct macdrv_win_data *parent_data = get_win_data(parent);
1578 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
1579 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
1581 if (!cocoa_window && !superview)
1582 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", hwnd, parent);
1584 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
1585 release_win_data(parent_data);
1588 else /* new top level window */
1590 destroy_cocoa_view(data);
1591 create_cocoa_window(data);
1593 release_win_data(data);
1597 /***********************************************************************
1598 * SetWindowRgn (MACDRV.@)
1600 * Assign specified region to window (for non-rectangular windows)
1602 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1604 struct macdrv_win_data *data;
1606 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1608 if ((data = get_win_data(hwnd)))
1610 sync_window_region(data, hrgn);
1611 release_win_data(data);
1613 else
1615 DWORD procid;
1617 GetWindowThreadProcessId(hwnd, &procid);
1618 if (procid != GetCurrentProcessId())
1619 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1624 /***********************************************************************
1625 * SetWindowStyle (MACDRV.@)
1627 * Update the state of the Cocoa window to reflect a style change
1629 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1631 struct macdrv_win_data *data;
1633 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1635 if (hwnd == GetDesktopWindow()) return;
1636 if (!(data = get_win_data(hwnd))) return;
1638 if (data->cocoa_window)
1640 DWORD changed = style->styleNew ^ style->styleOld;
1642 set_cocoa_window_properties(data);
1644 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1646 data->layered = FALSE;
1647 data->ulw_layered = FALSE;
1648 sync_window_opacity(data, 0, 0, FALSE, 0);
1649 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1652 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1653 sync_window_region(data, (HRGN)1);
1656 release_win_data(data);
1660 /*****************************************************************
1661 * SetWindowText (MACDRV.@)
1663 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1665 macdrv_window win;
1667 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1669 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1670 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1674 /***********************************************************************
1675 * ShowWindow (MACDRV.@)
1677 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1679 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1680 struct macdrv_win_data *data = get_win_data(hwnd);
1681 CGRect frame;
1683 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1684 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1686 if (!data || !data->cocoa_window) goto done;
1687 if (IsRectEmpty(rect)) goto done;
1688 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1690 if (rect->left != -32000 || rect->top != -32000)
1692 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1693 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1695 goto done;
1697 if (!data->on_screen) goto done;
1699 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1701 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1702 goto done;
1704 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1705 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1706 goto done;
1708 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1709 *rect = rect_from_cgrect(frame);
1710 macdrv_mac_to_window_rect(data, rect);
1711 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1712 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1714 done:
1715 release_win_data(data);
1716 return swp;
1720 /***********************************************************************
1721 * SysCommand (MACDRV.@)
1723 * Perform WM_SYSCOMMAND handling.
1725 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1727 struct macdrv_win_data *data;
1728 LRESULT ret = -1;
1729 WPARAM command = wparam & 0xfff0;
1731 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1733 if (!(data = get_win_data(hwnd))) goto done;
1734 if (!data->cocoa_window || !data->on_screen) goto done;
1736 /* prevent a simple ALT press+release from activating the system menu,
1737 as that can get confusing */
1738 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1739 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1741 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1742 ret = 0;
1745 if (command == SC_MOVE)
1747 release_win_data(data);
1748 return move_window(hwnd, wparam);
1751 done:
1752 release_win_data(data);
1753 return ret;
1757 /***********************************************************************
1758 * UpdateLayeredWindow (MACDRV.@)
1760 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1761 const RECT *window_rect)
1763 struct window_surface *surface;
1764 struct macdrv_win_data *data;
1765 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1766 BYTE alpha;
1767 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1768 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1769 void *src_bits, *dst_bits;
1770 RECT rect;
1771 HDC hdc = 0;
1772 HBITMAP dib;
1773 BOOL ret = FALSE;
1775 if (!(data = get_win_data(hwnd))) return FALSE;
1777 data->layered = TRUE;
1778 data->ulw_layered = TRUE;
1780 rect = *window_rect;
1781 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1783 surface = data->surface;
1784 if (!surface || !EqualRect(&surface->rect, &rect))
1786 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1787 set_window_surface(data->cocoa_window, data->surface);
1788 if (surface) window_surface_release(surface);
1789 surface = data->surface;
1790 if (data->unminimized_surface)
1792 window_surface_release(data->unminimized_surface);
1793 data->unminimized_surface = NULL;
1796 else set_surface_use_alpha(surface, TRUE);
1798 if (surface) window_surface_add_ref(surface);
1799 release_win_data(data);
1801 if (!surface) return FALSE;
1802 if (!info->hdcSrc)
1804 window_surface_release(surface);
1805 return TRUE;
1808 if (info->dwFlags & ULW_ALPHA)
1810 /* Apply SourceConstantAlpha via window alpha, not blend. */
1811 alpha = info->pblend->SourceConstantAlpha;
1812 blend = *info->pblend;
1813 blend.SourceConstantAlpha = 0xff;
1815 else
1816 alpha = 0xff;
1818 dst_bits = surface->funcs->get_info(surface, bmi);
1820 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1821 if (!(hdc = CreateCompatibleDC(0))) goto done;
1823 SelectObject(hdc, dib);
1824 if (info->prcDirty)
1826 IntersectRect(&rect, &rect, info->prcDirty);
1827 surface->funcs->lock(surface);
1828 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1829 surface->funcs->unlock(surface);
1830 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1832 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1833 info->hdcSrc,
1834 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1835 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1836 rect.right - rect.left, rect.bottom - rect.top,
1837 blend)))
1838 goto done;
1840 if ((data = get_win_data(hwnd)))
1842 if (surface == data->surface)
1844 surface->funcs->lock(surface);
1845 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1846 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1847 surface->funcs->unlock(surface);
1848 surface->funcs->flush(surface);
1851 /* The ULW flags are a superset of the LWA flags. */
1852 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1854 release_win_data(data);
1857 done:
1858 window_surface_release(surface);
1859 if (hdc) DeleteDC(hdc);
1860 if (dib) DeleteObject(dib);
1861 return ret;
1865 /**********************************************************************
1866 * WindowMessage (MACDRV.@)
1868 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1870 struct macdrv_win_data *data;
1872 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1874 switch(msg)
1876 case WM_MACDRV_SET_WIN_REGION:
1877 if ((data = get_win_data(hwnd)))
1879 sync_window_region(data, (HRGN)1);
1880 release_win_data(data);
1882 return 0;
1883 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1884 if (hwnd == GetDesktopWindow())
1886 CGRect new_desktop_rect;
1887 RECT current_desktop_rect;
1889 macdrv_reset_device_metrics();
1890 new_desktop_rect = macdrv_get_desktop_rect();
1891 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1892 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1894 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1895 SMTO_ABORTIFHUNG, 2000, NULL);
1896 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1897 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1898 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1899 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1900 SMTO_ABORTIFHUNG, 2000, NULL);
1903 return 0;
1904 case WM_MACDRV_RESET_DEVICE_METRICS:
1905 macdrv_reset_device_metrics();
1906 return 0;
1907 case WM_MACDRV_DISPLAYCHANGE:
1908 macdrv_reassert_window_position(hwnd);
1909 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1910 return 0;
1911 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1912 activate_on_following_focus();
1913 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1914 return 0;
1917 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1918 return 0;
1922 static inline RECT get_surface_rect(const RECT *visible_rect)
1924 RECT rect;
1925 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1927 IntersectRect(&rect, visible_rect, &desktop_rect);
1928 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1929 rect.left &= ~127;
1930 rect.top &= ~127;
1931 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1932 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1933 return rect;
1937 /***********************************************************************
1938 * WindowPosChanging (MACDRV.@)
1940 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1941 const RECT *window_rect, const RECT *client_rect,
1942 RECT *visible_rect, struct window_surface **surface)
1944 struct macdrv_win_data *data = get_win_data(hwnd);
1945 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1946 RECT surface_rect;
1948 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1949 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1950 wine_dbgstr_rect(visible_rect), surface);
1952 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1954 *visible_rect = *window_rect;
1955 macdrv_window_to_mac_rect(data, style, visible_rect);
1956 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1957 wine_dbgstr_rect(visible_rect));
1959 /* create the window surface if necessary */
1960 if (!data->cocoa_window) goto done;
1961 if (swp_flags & SWP_HIDEWINDOW) goto done;
1962 if (data->ulw_layered) goto done;
1964 if (*surface) window_surface_release(*surface);
1965 *surface = NULL;
1967 surface_rect = get_surface_rect(visible_rect);
1968 if (data->surface)
1970 if (EqualRect(&data->surface->rect, &surface_rect))
1972 /* existing surface is good enough */
1973 surface_clip_to_visible_rect(data->surface, visible_rect);
1974 window_surface_add_ref(data->surface);
1975 *surface = data->surface;
1976 goto done;
1979 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1981 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1983 done:
1984 release_win_data(data);
1988 /***********************************************************************
1989 * WindowPosChanged (MACDRV.@)
1991 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1992 const RECT *window_rect, const RECT *client_rect,
1993 const RECT *visible_rect, const RECT *valid_rects,
1994 struct window_surface *surface)
1996 struct macdrv_thread_data *thread_data;
1997 struct macdrv_win_data *data;
1998 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1999 RECT old_window_rect, old_whole_rect, old_client_rect;
2001 if (!(data = get_win_data(hwnd))) return;
2003 thread_data = macdrv_thread_data();
2005 old_window_rect = data->window_rect;
2006 old_whole_rect = data->whole_rect;
2007 old_client_rect = data->client_rect;
2008 data->window_rect = *window_rect;
2009 data->whole_rect = *visible_rect;
2010 data->client_rect = *client_rect;
2011 if (!data->ulw_layered)
2013 if (surface) window_surface_add_ref(surface);
2014 if (new_style & WS_MINIMIZE)
2016 if (!data->unminimized_surface && data->surface)
2018 data->unminimized_surface = data->surface;
2019 window_surface_add_ref(data->unminimized_surface);
2022 else
2024 set_window_surface(data->cocoa_window, surface);
2025 if (data->unminimized_surface)
2027 window_surface_release(data->unminimized_surface);
2028 data->unminimized_surface = NULL;
2031 if (data->surface) window_surface_release(data->surface);
2032 data->surface = surface;
2035 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2036 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2037 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2038 new_style, swp_flags, surface);
2040 if (!IsRectEmpty(&valid_rects[0]))
2042 macdrv_window window = data->cocoa_window;
2043 int x_offset = old_whole_rect.left - data->whole_rect.left;
2044 int y_offset = old_whole_rect.top - data->whole_rect.top;
2046 /* if all that happened is that the whole window moved, copy everything */
2047 if (!(swp_flags & SWP_FRAMECHANGED) &&
2048 old_whole_rect.right - data->whole_rect.right == x_offset &&
2049 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2050 old_client_rect.left - data->client_rect.left == x_offset &&
2051 old_client_rect.right - data->client_rect.right == x_offset &&
2052 old_client_rect.top - data->client_rect.top == y_offset &&
2053 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2054 EqualRect(&valid_rects[0], &data->client_rect))
2056 /* A Cocoa window's bits are moved automatically */
2057 if (!window && (x_offset != 0 || y_offset != 0))
2059 release_win_data(data);
2060 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2061 &old_client_rect, client_rect, window_rect);
2062 if (!(data = get_win_data(hwnd))) return;
2065 else
2067 release_win_data(data);
2068 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2069 &old_client_rect, client_rect, window_rect);
2070 if (!(data = get_win_data(hwnd))) return;
2074 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2076 if (!data->cocoa_window && !data->cocoa_view) goto done;
2078 if (data->on_screen)
2080 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2081 hide_window(data);
2084 /* check if we are currently processing an event relevant to this window */
2085 if (!thread_data || !thread_data->current_event ||
2086 !data->cocoa_window || thread_data->current_event->window != data->cocoa_window ||
2087 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
2088 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
2090 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2091 if (data->cocoa_window)
2092 set_cocoa_window_properties(data);
2095 if (new_style & WS_VISIBLE)
2097 if (data->cocoa_window)
2099 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2100 set_cocoa_window_properties(data);
2102 /* layered windows are not shown until their attributes are set */
2103 if (!data->on_screen &&
2104 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2105 show_window(data);
2107 else if (!data->on_screen)
2108 show_window(data);
2111 done:
2112 release_win_data(data);
2116 /***********************************************************************
2117 * macdrv_window_close_requested
2119 * Handler for WINDOW_CLOSE_REQUESTED events.
2121 void macdrv_window_close_requested(HWND hwnd)
2123 HMENU sysmenu;
2125 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2127 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2128 return;
2131 sysmenu = GetSystemMenu(hwnd, FALSE);
2132 if (sysmenu)
2134 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2135 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2137 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2138 return;
2142 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2146 /***********************************************************************
2147 * macdrv_window_frame_changed
2149 * Handler for WINDOW_FRAME_CHANGED events.
2151 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2153 struct macdrv_win_data *data;
2154 RECT rect;
2155 HWND parent;
2156 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2157 int width, height;
2158 BOOL being_dragged;
2160 if (!hwnd) return;
2161 if (!(data = get_win_data(hwnd))) return;
2162 if (!data->on_screen || data->minimized)
2164 release_win_data(data);
2165 return;
2168 /* Get geometry */
2170 parent = GetAncestor(hwnd, GA_PARENT);
2172 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2173 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2174 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2176 rect = rect_from_cgrect(event->window_frame_changed.frame);
2177 macdrv_mac_to_window_rect(data, &rect);
2178 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2180 width = rect.right - rect.left;
2181 height = rect.bottom - rect.top;
2183 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2184 flags |= SWP_NOMOVE;
2185 else
2186 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2187 data->window_rect.top, rect.left, rect.top);
2189 if ((data->window_rect.right - data->window_rect.left == width &&
2190 data->window_rect.bottom - data->window_rect.top == height) ||
2191 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2192 flags |= SWP_NOSIZE;
2193 else
2194 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2195 data->window_rect.bottom - data->window_rect.top, width, height);
2197 being_dragged = data->being_dragged;
2198 release_win_data(data);
2200 if (event->window_frame_changed.fullscreen)
2201 flags |= SWP_NOSENDCHANGING;
2202 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2204 if (!event->window_frame_changed.in_resize && !being_dragged)
2205 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2206 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2207 if (!event->window_frame_changed.in_resize && !being_dragged)
2208 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2213 /***********************************************************************
2214 * macdrv_window_got_focus
2216 * Handler for WINDOW_GOT_FOCUS events.
2218 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2220 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2222 if (!hwnd) return;
2224 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2225 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2226 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2228 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2230 /* simulate a mouse click on the caption to find out
2231 * whether the window wants to be activated */
2232 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2233 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2234 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2235 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2237 TRACE("setting foreground window to %p\n", hwnd);
2238 SetForegroundWindow(hwnd);
2239 return;
2243 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2244 macdrv_window_rejected_focus(event);
2248 /***********************************************************************
2249 * macdrv_window_lost_focus
2251 * Handler for WINDOW_LOST_FOCUS events.
2253 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2255 if (!hwnd) return;
2257 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2259 if (hwnd == GetForegroundWindow())
2261 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2262 if (hwnd == GetForegroundWindow())
2263 SetForegroundWindow(GetDesktopWindow());
2268 /***********************************************************************
2269 * macdrv_app_deactivated
2271 * Handler for APP_DEACTIVATED events.
2273 void macdrv_app_deactivated(void)
2275 if (GetActiveWindow() == GetForegroundWindow())
2277 TRACE("setting fg to desktop\n");
2278 SetForegroundWindow(GetDesktopWindow());
2283 /***********************************************************************
2284 * macdrv_window_maximize_requested
2286 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2288 void macdrv_window_maximize_requested(HWND hwnd)
2290 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2294 /***********************************************************************
2295 * macdrv_window_minimize_requested
2297 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2299 void macdrv_window_minimize_requested(HWND hwnd)
2301 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2305 /***********************************************************************
2306 * macdrv_window_did_unminimize
2308 * Handler for WINDOW_DID_UNMINIMIZE events.
2310 void macdrv_window_did_unminimize(HWND hwnd)
2312 struct macdrv_win_data *data;
2313 DWORD style;
2315 TRACE("win %p\n", hwnd);
2317 if (!(data = get_win_data(hwnd))) return;
2318 if (!data->minimized) goto done;
2320 style = GetWindowLongW(hwnd, GWL_STYLE);
2322 data->minimized = FALSE;
2323 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2325 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2326 release_win_data(data);
2327 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2328 return;
2331 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2333 done:
2334 release_win_data(data);
2338 /***********************************************************************
2339 * macdrv_window_brought_forward
2341 * Handler for WINDOW_BROUGHT_FORWARD events.
2343 void macdrv_window_brought_forward(HWND hwnd)
2345 TRACE("win %p\n", hwnd);
2346 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2350 /***********************************************************************
2351 * macdrv_window_resize_ended
2353 * Handler for WINDOW_RESIZE_ENDED events.
2355 void macdrv_window_resize_ended(HWND hwnd)
2357 TRACE("hwnd %p\n", hwnd);
2358 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2362 /***********************************************************************
2363 * macdrv_window_restore_requested
2365 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2366 * for restoring from maximized, not from minimized.
2368 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2370 if (event->window_restore_requested.keep_frame && hwnd)
2372 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2373 struct macdrv_win_data *data;
2375 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2377 RECT rect;
2378 HWND parent = GetAncestor(hwnd, GA_PARENT);
2380 rect = rect_from_cgrect(event->window_restore_requested.frame);
2381 macdrv_mac_to_window_rect(data, &rect);
2382 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2384 release_win_data(data);
2386 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2390 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2394 /***********************************************************************
2395 * macdrv_window_drag_begin
2397 * Handler for WINDOW_DRAG_BEGIN events.
2399 void macdrv_window_drag_begin(HWND hwnd)
2401 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2402 struct macdrv_win_data *data;
2403 MSG msg;
2405 TRACE("win %p\n", hwnd);
2407 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2408 if (!(style & WS_VISIBLE)) return;
2410 if (!(data = get_win_data(hwnd))) return;
2411 if (data->being_dragged) goto done;
2413 data->being_dragged = TRUE;
2414 release_win_data(data);
2416 ClipCursor(NULL);
2417 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2418 ReleaseCapture();
2420 while (GetMessageW(&msg, 0, 0, 0))
2422 if (msg.message == WM_EXITSIZEMOVE)
2424 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2425 break;
2428 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2429 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2431 TranslateMessage(&msg);
2432 DispatchMessageW(&msg);
2436 TRACE("done\n");
2438 if ((data = get_win_data(hwnd)))
2439 data->being_dragged = FALSE;
2441 done:
2442 release_win_data(data);
2446 /***********************************************************************
2447 * macdrv_window_drag_end
2449 * Handler for WINDOW_DRAG_END events.
2451 void macdrv_window_drag_end(HWND hwnd)
2453 struct macdrv_win_data *data;
2454 BOOL being_dragged;
2456 TRACE("win %p\n", hwnd);
2458 if (!(data = get_win_data(hwnd))) return;
2459 being_dragged = data->being_dragged;
2460 release_win_data(data);
2462 if (being_dragged)
2464 /* Post this rather than sending it, so that the message loop in
2465 macdrv_window_drag_begin() will see it. */
2466 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2471 /***********************************************************************
2472 * macdrv_reassert_window_position
2474 * Handler for REASSERT_WINDOW_POSITION events.
2476 void macdrv_reassert_window_position(HWND hwnd)
2478 struct macdrv_win_data *data = get_win_data(hwnd);
2479 if (data)
2481 if (data->cocoa_window && data->on_screen)
2482 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2483 release_win_data(data);
2488 struct quit_info {
2489 HWND *wins;
2490 UINT capacity;
2491 UINT count;
2492 UINT done;
2493 DWORD flags;
2494 BOOL result;
2495 BOOL replied;
2499 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2501 struct quit_info *qi = (struct quit_info*)lp;
2502 DWORD pid;
2504 GetWindowThreadProcessId(hwnd, &pid);
2505 if (pid == GetCurrentProcessId())
2507 if (qi->count >= qi->capacity)
2509 UINT new_cap = qi->capacity * 2;
2510 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2511 new_cap * sizeof(*qi->wins));
2512 if (!new_wins) return FALSE;
2513 qi->wins = new_wins;
2514 qi->capacity = new_cap;
2517 qi->wins[qi->count++] = hwnd;
2520 return TRUE;
2524 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2526 struct quit_info *qi = (struct quit_info*)data;
2528 qi->done++;
2530 if (msg == WM_QUERYENDSESSION)
2532 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2533 hwnd, qi->done, qi->count);
2535 if (!result && !IsWindow(hwnd))
2537 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2538 result = TRUE;
2541 if (!result && qi->result)
2543 qi->result = FALSE;
2545 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2546 ultimate reply. Might as well tell Cocoa now. */
2547 if (!qi->replied)
2549 qi->replied = TRUE;
2550 TRACE("giving quit reply %d\n", qi->result);
2551 macdrv_quit_reply(qi->result);
2555 if (qi->done >= qi->count)
2557 UINT i;
2559 qi->done = 0;
2560 for (i = 0; i < qi->count; i++)
2562 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2563 qi->result, qi->flags);
2564 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2565 quit_callback, (ULONG_PTR)qi))
2567 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2568 qi->wins[i], GetLastError());
2569 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2574 else /* WM_ENDSESSION */
2576 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2578 if (qi->done >= qi->count)
2580 if (!qi->replied)
2582 TRACE("giving quit reply %d\n", qi->result);
2583 macdrv_quit_reply(qi->result);
2586 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2587 if (qi->result)
2588 TerminateProcess(GetCurrentProcess(), 0);
2590 HeapFree(GetProcessHeap(), 0, qi->wins);
2591 HeapFree(GetProcessHeap(), 0, qi);
2597 /***********************************************************************
2598 * macdrv_app_quit_requested
2600 * Handler for APP_QUIT_REQUESTED events.
2602 void macdrv_app_quit_requested(const macdrv_event *event)
2604 struct quit_info *qi;
2605 UINT i;
2607 TRACE("reason %d\n", event->app_quit_requested.reason);
2609 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2610 if (!qi)
2611 goto fail;
2613 qi->capacity = 32;
2614 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2615 qi->count = qi->done = 0;
2617 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2618 goto fail;
2620 switch (event->app_quit_requested.reason)
2622 case QUIT_REASON_LOGOUT:
2623 default:
2624 qi->flags = ENDSESSION_LOGOFF;
2625 break;
2626 case QUIT_REASON_RESTART:
2627 case QUIT_REASON_SHUTDOWN:
2628 qi->flags = 0;
2629 break;
2632 qi->result = TRUE;
2633 qi->replied = FALSE;
2635 for (i = 0; i < qi->count; i++)
2637 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2638 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2639 quit_callback, (ULONG_PTR)qi))
2641 DWORD error = GetLastError();
2642 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2643 if (invalid)
2644 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2645 qi->wins[i]);
2646 else
2647 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2648 qi->wins[i], error);
2649 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2653 /* quit_callback() will clean up qi */
2654 return;
2656 fail:
2657 WARN("failed to allocate window list\n");
2658 if (qi)
2660 HeapFree(GetProcessHeap(), 0, qi->wins);
2661 HeapFree(GetProcessHeap(), 0, qi);
2663 macdrv_quit_reply(FALSE);
2667 /***********************************************************************
2668 * query_resize_size
2670 * Handler for QUERY_RESIZE_SIZE query.
2672 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2674 struct macdrv_win_data *data = get_win_data(hwnd);
2675 RECT rect = rect_from_cgrect(query->resize_size.rect);
2676 int corner;
2677 BOOL ret = FALSE;
2679 if (!data) return FALSE;
2681 macdrv_mac_to_window_rect(data, &rect);
2683 if (query->resize_size.from_left)
2685 if (query->resize_size.from_top)
2686 corner = WMSZ_TOPLEFT;
2687 else
2688 corner = WMSZ_BOTTOMLEFT;
2690 else if (query->resize_size.from_top)
2691 corner = WMSZ_TOPRIGHT;
2692 else
2693 corner = WMSZ_BOTTOMRIGHT;
2695 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2697 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2698 query->resize_size.rect = cgrect_from_rect(rect);
2699 ret = TRUE;
2702 release_win_data(data);
2703 return ret;
2707 /***********************************************************************
2708 * query_resize_start
2710 * Handler for QUERY_RESIZE_START query.
2712 BOOL query_resize_start(HWND hwnd)
2714 TRACE("hwnd %p\n", hwnd);
2716 sync_window_min_max_info(hwnd);
2717 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2719 return TRUE;
2723 /***********************************************************************
2724 * query_min_max_info
2726 * Handler for QUERY_MIN_MAX_INFO query.
2728 BOOL query_min_max_info(HWND hwnd)
2730 TRACE("hwnd %p\n", hwnd);
2731 sync_window_min_max_info(hwnd);
2732 return TRUE;