winemac: Run a single clipboard manager thread per window station, inside the explore...
[wine.git] / dlls / winemac.drv / window.c
blob07d0f2323b601bfe3a8ecdb6a68fb7d26c65e6ac
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 if (hwnd == GetDesktopWindow())
1484 macdrv_init_clipboard();
1485 return TRUE;
1489 /***********************************************************************
1490 * DestroyWindow (MACDRV.@)
1492 void CDECL macdrv_DestroyWindow(HWND hwnd)
1494 struct macdrv_win_data *data;
1496 TRACE("%p\n", hwnd);
1498 if (!(data = get_win_data(hwnd))) return;
1500 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1502 destroy_cocoa_window(data);
1503 destroy_cocoa_view(data);
1504 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1506 CFDictionaryRemoveValue(win_datas, hwnd);
1507 release_win_data(data);
1508 HeapFree(GetProcessHeap(), 0, data);
1512 /*****************************************************************
1513 * SetFocus (MACDRV.@)
1515 * Set the Mac focus.
1517 void CDECL macdrv_SetFocus(HWND hwnd)
1519 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1521 TRACE("%p\n", hwnd);
1523 if (!thread_data) return;
1524 thread_data->dead_key_state = 0;
1525 set_focus(hwnd);
1529 /***********************************************************************
1530 * SetLayeredWindowAttributes (MACDRV.@)
1532 * Set transparency attributes for a layered window.
1534 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1536 struct macdrv_win_data *data = get_win_data(hwnd);
1538 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1540 if (data)
1542 data->layered = TRUE;
1543 if (data->cocoa_window)
1545 sync_window_opacity(data, key, alpha, FALSE, flags);
1546 /* since layered attributes are now set, can now show the window */
1547 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1548 show_window(data);
1550 release_win_data(data);
1552 else
1553 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1557 /*****************************************************************
1558 * SetParent (MACDRV.@)
1560 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1562 struct macdrv_win_data *data;
1564 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1566 if (parent == old_parent) return;
1567 if (!(data = get_win_data(hwnd))) return;
1569 if (parent != GetDesktopWindow()) /* a child window */
1571 if (old_parent == GetDesktopWindow())
1573 /* destroy the old Mac window */
1574 destroy_cocoa_window(data);
1575 create_cocoa_view(data);
1577 else
1579 struct macdrv_win_data *parent_data = get_win_data(parent);
1580 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
1581 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
1583 if (!cocoa_window && !superview)
1584 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", hwnd, parent);
1586 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
1587 release_win_data(parent_data);
1590 else /* new top level window */
1592 destroy_cocoa_view(data);
1593 create_cocoa_window(data);
1595 release_win_data(data);
1599 /***********************************************************************
1600 * SetWindowRgn (MACDRV.@)
1602 * Assign specified region to window (for non-rectangular windows)
1604 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1606 struct macdrv_win_data *data;
1608 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1610 if ((data = get_win_data(hwnd)))
1612 sync_window_region(data, hrgn);
1613 release_win_data(data);
1615 else
1617 DWORD procid;
1619 GetWindowThreadProcessId(hwnd, &procid);
1620 if (procid != GetCurrentProcessId())
1621 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1626 /***********************************************************************
1627 * SetWindowStyle (MACDRV.@)
1629 * Update the state of the Cocoa window to reflect a style change
1631 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1633 struct macdrv_win_data *data;
1635 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1637 if (hwnd == GetDesktopWindow()) return;
1638 if (!(data = get_win_data(hwnd))) return;
1640 if (data->cocoa_window)
1642 DWORD changed = style->styleNew ^ style->styleOld;
1644 set_cocoa_window_properties(data);
1646 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1648 data->layered = FALSE;
1649 data->ulw_layered = FALSE;
1650 sync_window_opacity(data, 0, 0, FALSE, 0);
1651 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1654 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1655 sync_window_region(data, (HRGN)1);
1658 release_win_data(data);
1662 /*****************************************************************
1663 * SetWindowText (MACDRV.@)
1665 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1667 macdrv_window win;
1669 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1671 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1672 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1676 /***********************************************************************
1677 * ShowWindow (MACDRV.@)
1679 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1681 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1682 struct macdrv_win_data *data = get_win_data(hwnd);
1683 CGRect frame;
1685 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1686 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1688 if (!data || !data->cocoa_window) goto done;
1689 if (IsRectEmpty(rect)) goto done;
1690 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1692 if (rect->left != -32000 || rect->top != -32000)
1694 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1695 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1697 goto done;
1699 if (!data->on_screen) goto done;
1701 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1703 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1704 goto done;
1706 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1707 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1708 goto done;
1710 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1711 *rect = rect_from_cgrect(frame);
1712 macdrv_mac_to_window_rect(data, rect);
1713 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1714 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1716 done:
1717 release_win_data(data);
1718 return swp;
1722 /***********************************************************************
1723 * SysCommand (MACDRV.@)
1725 * Perform WM_SYSCOMMAND handling.
1727 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1729 struct macdrv_win_data *data;
1730 LRESULT ret = -1;
1731 WPARAM command = wparam & 0xfff0;
1733 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1735 if (!(data = get_win_data(hwnd))) goto done;
1736 if (!data->cocoa_window || !data->on_screen) goto done;
1738 /* prevent a simple ALT press+release from activating the system menu,
1739 as that can get confusing */
1740 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1741 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1743 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1744 ret = 0;
1747 if (command == SC_MOVE)
1749 release_win_data(data);
1750 return move_window(hwnd, wparam);
1753 done:
1754 release_win_data(data);
1755 return ret;
1759 /***********************************************************************
1760 * UpdateLayeredWindow (MACDRV.@)
1762 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1763 const RECT *window_rect)
1765 struct window_surface *surface;
1766 struct macdrv_win_data *data;
1767 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1768 BYTE alpha;
1769 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1770 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1771 void *src_bits, *dst_bits;
1772 RECT rect;
1773 HDC hdc = 0;
1774 HBITMAP dib;
1775 BOOL ret = FALSE;
1777 if (!(data = get_win_data(hwnd))) return FALSE;
1779 data->layered = TRUE;
1780 data->ulw_layered = TRUE;
1782 rect = *window_rect;
1783 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1785 surface = data->surface;
1786 if (!surface || !EqualRect(&surface->rect, &rect))
1788 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1789 set_window_surface(data->cocoa_window, data->surface);
1790 if (surface) window_surface_release(surface);
1791 surface = data->surface;
1792 if (data->unminimized_surface)
1794 window_surface_release(data->unminimized_surface);
1795 data->unminimized_surface = NULL;
1798 else set_surface_use_alpha(surface, TRUE);
1800 if (surface) window_surface_add_ref(surface);
1801 release_win_data(data);
1803 if (!surface) return FALSE;
1804 if (!info->hdcSrc)
1806 window_surface_release(surface);
1807 return TRUE;
1810 if (info->dwFlags & ULW_ALPHA)
1812 /* Apply SourceConstantAlpha via window alpha, not blend. */
1813 alpha = info->pblend->SourceConstantAlpha;
1814 blend = *info->pblend;
1815 blend.SourceConstantAlpha = 0xff;
1817 else
1818 alpha = 0xff;
1820 dst_bits = surface->funcs->get_info(surface, bmi);
1822 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1823 if (!(hdc = CreateCompatibleDC(0))) goto done;
1825 SelectObject(hdc, dib);
1826 if (info->prcDirty)
1828 IntersectRect(&rect, &rect, info->prcDirty);
1829 surface->funcs->lock(surface);
1830 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1831 surface->funcs->unlock(surface);
1832 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1834 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1835 info->hdcSrc,
1836 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1837 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1838 rect.right - rect.left, rect.bottom - rect.top,
1839 blend)))
1840 goto done;
1842 if ((data = get_win_data(hwnd)))
1844 if (surface == data->surface)
1846 surface->funcs->lock(surface);
1847 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1848 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1849 surface->funcs->unlock(surface);
1850 surface->funcs->flush(surface);
1853 /* The ULW flags are a superset of the LWA flags. */
1854 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1856 release_win_data(data);
1859 done:
1860 window_surface_release(surface);
1861 if (hdc) DeleteDC(hdc);
1862 if (dib) DeleteObject(dib);
1863 return ret;
1867 /**********************************************************************
1868 * WindowMessage (MACDRV.@)
1870 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1872 struct macdrv_win_data *data;
1874 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1876 switch(msg)
1878 case WM_MACDRV_SET_WIN_REGION:
1879 if ((data = get_win_data(hwnd)))
1881 sync_window_region(data, (HRGN)1);
1882 release_win_data(data);
1884 return 0;
1885 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1886 if (hwnd == GetDesktopWindow())
1888 CGRect new_desktop_rect;
1889 RECT current_desktop_rect;
1891 macdrv_reset_device_metrics();
1892 new_desktop_rect = macdrv_get_desktop_rect();
1893 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1894 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1896 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1897 SMTO_ABORTIFHUNG, 2000, NULL);
1898 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1899 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1900 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1901 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1902 SMTO_ABORTIFHUNG, 2000, NULL);
1905 return 0;
1906 case WM_MACDRV_RESET_DEVICE_METRICS:
1907 macdrv_reset_device_metrics();
1908 return 0;
1909 case WM_MACDRV_DISPLAYCHANGE:
1910 macdrv_reassert_window_position(hwnd);
1911 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1912 return 0;
1913 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1914 activate_on_following_focus();
1915 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1916 return 0;
1919 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1920 return 0;
1924 static inline RECT get_surface_rect(const RECT *visible_rect)
1926 RECT rect;
1927 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1929 IntersectRect(&rect, visible_rect, &desktop_rect);
1930 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1931 rect.left &= ~127;
1932 rect.top &= ~127;
1933 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1934 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1935 return rect;
1939 /***********************************************************************
1940 * WindowPosChanging (MACDRV.@)
1942 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1943 const RECT *window_rect, const RECT *client_rect,
1944 RECT *visible_rect, struct window_surface **surface)
1946 struct macdrv_win_data *data = get_win_data(hwnd);
1947 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1948 RECT surface_rect;
1950 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1951 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1952 wine_dbgstr_rect(visible_rect), surface);
1954 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1956 *visible_rect = *window_rect;
1957 macdrv_window_to_mac_rect(data, style, visible_rect);
1958 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1959 wine_dbgstr_rect(visible_rect));
1961 /* create the window surface if necessary */
1962 if (!data->cocoa_window) goto done;
1963 if (swp_flags & SWP_HIDEWINDOW) goto done;
1964 if (data->ulw_layered) goto done;
1966 if (*surface) window_surface_release(*surface);
1967 *surface = NULL;
1969 surface_rect = get_surface_rect(visible_rect);
1970 if (data->surface)
1972 if (EqualRect(&data->surface->rect, &surface_rect))
1974 /* existing surface is good enough */
1975 surface_clip_to_visible_rect(data->surface, visible_rect);
1976 window_surface_add_ref(data->surface);
1977 *surface = data->surface;
1978 goto done;
1981 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1983 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1985 done:
1986 release_win_data(data);
1990 /***********************************************************************
1991 * WindowPosChanged (MACDRV.@)
1993 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1994 const RECT *window_rect, const RECT *client_rect,
1995 const RECT *visible_rect, const RECT *valid_rects,
1996 struct window_surface *surface)
1998 struct macdrv_thread_data *thread_data;
1999 struct macdrv_win_data *data;
2000 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
2001 RECT old_window_rect, old_whole_rect, old_client_rect;
2003 if (!(data = get_win_data(hwnd))) return;
2005 thread_data = macdrv_thread_data();
2007 old_window_rect = data->window_rect;
2008 old_whole_rect = data->whole_rect;
2009 old_client_rect = data->client_rect;
2010 data->window_rect = *window_rect;
2011 data->whole_rect = *visible_rect;
2012 data->client_rect = *client_rect;
2013 if (!data->ulw_layered)
2015 if (surface) window_surface_add_ref(surface);
2016 if (new_style & WS_MINIMIZE)
2018 if (!data->unminimized_surface && data->surface)
2020 data->unminimized_surface = data->surface;
2021 window_surface_add_ref(data->unminimized_surface);
2024 else
2026 set_window_surface(data->cocoa_window, surface);
2027 if (data->unminimized_surface)
2029 window_surface_release(data->unminimized_surface);
2030 data->unminimized_surface = NULL;
2033 if (data->surface) window_surface_release(data->surface);
2034 data->surface = surface;
2037 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2038 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2039 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2040 new_style, swp_flags, surface);
2042 if (!IsRectEmpty(&valid_rects[0]))
2044 macdrv_window window = data->cocoa_window;
2045 int x_offset = old_whole_rect.left - data->whole_rect.left;
2046 int y_offset = old_whole_rect.top - data->whole_rect.top;
2048 /* if all that happened is that the whole window moved, copy everything */
2049 if (!(swp_flags & SWP_FRAMECHANGED) &&
2050 old_whole_rect.right - data->whole_rect.right == x_offset &&
2051 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2052 old_client_rect.left - data->client_rect.left == x_offset &&
2053 old_client_rect.right - data->client_rect.right == x_offset &&
2054 old_client_rect.top - data->client_rect.top == y_offset &&
2055 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2056 EqualRect(&valid_rects[0], &data->client_rect))
2058 /* A Cocoa window's bits are moved automatically */
2059 if (!window && (x_offset != 0 || y_offset != 0))
2061 release_win_data(data);
2062 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2063 &old_client_rect, client_rect, window_rect);
2064 if (!(data = get_win_data(hwnd))) return;
2067 else
2069 release_win_data(data);
2070 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2071 &old_client_rect, client_rect, window_rect);
2072 if (!(data = get_win_data(hwnd))) return;
2076 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2078 if (!data->cocoa_window && !data->cocoa_view) goto done;
2080 if (data->on_screen)
2082 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2083 hide_window(data);
2086 /* check if we are currently processing an event relevant to this window */
2087 if (!thread_data || !thread_data->current_event ||
2088 !data->cocoa_window || thread_data->current_event->window != data->cocoa_window ||
2089 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
2090 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
2092 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2093 if (data->cocoa_window)
2094 set_cocoa_window_properties(data);
2097 if (new_style & WS_VISIBLE)
2099 if (data->cocoa_window)
2101 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2102 set_cocoa_window_properties(data);
2104 /* layered windows are not shown until their attributes are set */
2105 if (!data->on_screen &&
2106 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2107 show_window(data);
2109 else if (!data->on_screen)
2110 show_window(data);
2113 done:
2114 release_win_data(data);
2118 /***********************************************************************
2119 * macdrv_window_close_requested
2121 * Handler for WINDOW_CLOSE_REQUESTED events.
2123 void macdrv_window_close_requested(HWND hwnd)
2125 HMENU sysmenu;
2127 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2129 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2130 return;
2133 sysmenu = GetSystemMenu(hwnd, FALSE);
2134 if (sysmenu)
2136 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2137 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2139 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2140 return;
2144 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2148 /***********************************************************************
2149 * macdrv_window_frame_changed
2151 * Handler for WINDOW_FRAME_CHANGED events.
2153 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2155 struct macdrv_win_data *data;
2156 RECT rect;
2157 HWND parent;
2158 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2159 int width, height;
2160 BOOL being_dragged;
2162 if (!hwnd) return;
2163 if (!(data = get_win_data(hwnd))) return;
2164 if (!data->on_screen || data->minimized)
2166 release_win_data(data);
2167 return;
2170 /* Get geometry */
2172 parent = GetAncestor(hwnd, GA_PARENT);
2174 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2175 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2176 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2178 rect = rect_from_cgrect(event->window_frame_changed.frame);
2179 macdrv_mac_to_window_rect(data, &rect);
2180 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2182 width = rect.right - rect.left;
2183 height = rect.bottom - rect.top;
2185 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2186 flags |= SWP_NOMOVE;
2187 else
2188 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2189 data->window_rect.top, rect.left, rect.top);
2191 if ((data->window_rect.right - data->window_rect.left == width &&
2192 data->window_rect.bottom - data->window_rect.top == height) ||
2193 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2194 flags |= SWP_NOSIZE;
2195 else
2196 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2197 data->window_rect.bottom - data->window_rect.top, width, height);
2199 being_dragged = data->being_dragged;
2200 release_win_data(data);
2202 if (event->window_frame_changed.fullscreen)
2203 flags |= SWP_NOSENDCHANGING;
2204 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2206 if (!event->window_frame_changed.in_resize && !being_dragged)
2207 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2208 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2209 if (!event->window_frame_changed.in_resize && !being_dragged)
2210 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2215 /***********************************************************************
2216 * macdrv_window_got_focus
2218 * Handler for WINDOW_GOT_FOCUS events.
2220 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2222 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2224 if (!hwnd) return;
2226 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2227 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2228 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2230 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2232 /* simulate a mouse click on the caption to find out
2233 * whether the window wants to be activated */
2234 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2235 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2236 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2237 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2239 TRACE("setting foreground window to %p\n", hwnd);
2240 SetForegroundWindow(hwnd);
2241 return;
2245 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2246 macdrv_window_rejected_focus(event);
2250 /***********************************************************************
2251 * macdrv_window_lost_focus
2253 * Handler for WINDOW_LOST_FOCUS events.
2255 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2257 if (!hwnd) return;
2259 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2261 if (hwnd == GetForegroundWindow())
2263 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2264 if (hwnd == GetForegroundWindow())
2265 SetForegroundWindow(GetDesktopWindow());
2270 /***********************************************************************
2271 * macdrv_app_deactivated
2273 * Handler for APP_DEACTIVATED events.
2275 void macdrv_app_deactivated(void)
2277 if (GetActiveWindow() == GetForegroundWindow())
2279 TRACE("setting fg to desktop\n");
2280 SetForegroundWindow(GetDesktopWindow());
2285 /***********************************************************************
2286 * macdrv_window_maximize_requested
2288 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2290 void macdrv_window_maximize_requested(HWND hwnd)
2292 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2296 /***********************************************************************
2297 * macdrv_window_minimize_requested
2299 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2301 void macdrv_window_minimize_requested(HWND hwnd)
2303 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2307 /***********************************************************************
2308 * macdrv_window_did_unminimize
2310 * Handler for WINDOW_DID_UNMINIMIZE events.
2312 void macdrv_window_did_unminimize(HWND hwnd)
2314 struct macdrv_win_data *data;
2315 DWORD style;
2317 TRACE("win %p\n", hwnd);
2319 if (!(data = get_win_data(hwnd))) return;
2320 if (!data->minimized) goto done;
2322 style = GetWindowLongW(hwnd, GWL_STYLE);
2324 data->minimized = FALSE;
2325 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2327 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2328 release_win_data(data);
2329 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2330 return;
2333 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2335 done:
2336 release_win_data(data);
2340 /***********************************************************************
2341 * macdrv_window_brought_forward
2343 * Handler for WINDOW_BROUGHT_FORWARD events.
2345 void macdrv_window_brought_forward(HWND hwnd)
2347 TRACE("win %p\n", hwnd);
2348 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2352 /***********************************************************************
2353 * macdrv_window_resize_ended
2355 * Handler for WINDOW_RESIZE_ENDED events.
2357 void macdrv_window_resize_ended(HWND hwnd)
2359 TRACE("hwnd %p\n", hwnd);
2360 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2364 /***********************************************************************
2365 * macdrv_window_restore_requested
2367 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2368 * for restoring from maximized, not from minimized.
2370 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2372 if (event->window_restore_requested.keep_frame && hwnd)
2374 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2375 struct macdrv_win_data *data;
2377 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2379 RECT rect;
2380 HWND parent = GetAncestor(hwnd, GA_PARENT);
2382 rect = rect_from_cgrect(event->window_restore_requested.frame);
2383 macdrv_mac_to_window_rect(data, &rect);
2384 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2386 release_win_data(data);
2388 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2392 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2396 /***********************************************************************
2397 * macdrv_window_drag_begin
2399 * Handler for WINDOW_DRAG_BEGIN events.
2401 void macdrv_window_drag_begin(HWND hwnd)
2403 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2404 struct macdrv_win_data *data;
2405 MSG msg;
2407 TRACE("win %p\n", hwnd);
2409 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2410 if (!(style & WS_VISIBLE)) return;
2412 if (!(data = get_win_data(hwnd))) return;
2413 if (data->being_dragged) goto done;
2415 data->being_dragged = TRUE;
2416 release_win_data(data);
2418 ClipCursor(NULL);
2419 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2420 ReleaseCapture();
2422 while (GetMessageW(&msg, 0, 0, 0))
2424 if (msg.message == WM_EXITSIZEMOVE)
2426 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2427 break;
2430 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2431 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2433 TranslateMessage(&msg);
2434 DispatchMessageW(&msg);
2438 TRACE("done\n");
2440 if ((data = get_win_data(hwnd)))
2441 data->being_dragged = FALSE;
2443 done:
2444 release_win_data(data);
2448 /***********************************************************************
2449 * macdrv_window_drag_end
2451 * Handler for WINDOW_DRAG_END events.
2453 void macdrv_window_drag_end(HWND hwnd)
2455 struct macdrv_win_data *data;
2456 BOOL being_dragged;
2458 TRACE("win %p\n", hwnd);
2460 if (!(data = get_win_data(hwnd))) return;
2461 being_dragged = data->being_dragged;
2462 release_win_data(data);
2464 if (being_dragged)
2466 /* Post this rather than sending it, so that the message loop in
2467 macdrv_window_drag_begin() will see it. */
2468 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2473 /***********************************************************************
2474 * macdrv_reassert_window_position
2476 * Handler for REASSERT_WINDOW_POSITION events.
2478 void macdrv_reassert_window_position(HWND hwnd)
2480 struct macdrv_win_data *data = get_win_data(hwnd);
2481 if (data)
2483 if (data->cocoa_window && data->on_screen)
2484 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2485 release_win_data(data);
2490 struct quit_info {
2491 HWND *wins;
2492 UINT capacity;
2493 UINT count;
2494 UINT done;
2495 DWORD flags;
2496 BOOL result;
2497 BOOL replied;
2501 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2503 struct quit_info *qi = (struct quit_info*)lp;
2504 DWORD pid;
2506 GetWindowThreadProcessId(hwnd, &pid);
2507 if (pid == GetCurrentProcessId())
2509 if (qi->count >= qi->capacity)
2511 UINT new_cap = qi->capacity * 2;
2512 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2513 new_cap * sizeof(*qi->wins));
2514 if (!new_wins) return FALSE;
2515 qi->wins = new_wins;
2516 qi->capacity = new_cap;
2519 qi->wins[qi->count++] = hwnd;
2522 return TRUE;
2526 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2528 struct quit_info *qi = (struct quit_info*)data;
2530 qi->done++;
2532 if (msg == WM_QUERYENDSESSION)
2534 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2535 hwnd, qi->done, qi->count);
2537 if (!result && !IsWindow(hwnd))
2539 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2540 result = TRUE;
2543 if (!result && qi->result)
2545 qi->result = FALSE;
2547 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2548 ultimate reply. Might as well tell Cocoa now. */
2549 if (!qi->replied)
2551 qi->replied = TRUE;
2552 TRACE("giving quit reply %d\n", qi->result);
2553 macdrv_quit_reply(qi->result);
2557 if (qi->done >= qi->count)
2559 UINT i;
2561 qi->done = 0;
2562 for (i = 0; i < qi->count; i++)
2564 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2565 qi->result, qi->flags);
2566 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2567 quit_callback, (ULONG_PTR)qi))
2569 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2570 qi->wins[i], GetLastError());
2571 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2576 else /* WM_ENDSESSION */
2578 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2580 if (qi->done >= qi->count)
2582 if (!qi->replied)
2584 TRACE("giving quit reply %d\n", qi->result);
2585 macdrv_quit_reply(qi->result);
2588 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2589 if (qi->result)
2590 TerminateProcess(GetCurrentProcess(), 0);
2592 HeapFree(GetProcessHeap(), 0, qi->wins);
2593 HeapFree(GetProcessHeap(), 0, qi);
2599 /***********************************************************************
2600 * macdrv_app_quit_requested
2602 * Handler for APP_QUIT_REQUESTED events.
2604 void macdrv_app_quit_requested(const macdrv_event *event)
2606 struct quit_info *qi;
2607 UINT i;
2609 TRACE("reason %d\n", event->app_quit_requested.reason);
2611 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2612 if (!qi)
2613 goto fail;
2615 qi->capacity = 32;
2616 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2617 qi->count = qi->done = 0;
2619 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2620 goto fail;
2622 switch (event->app_quit_requested.reason)
2624 case QUIT_REASON_LOGOUT:
2625 default:
2626 qi->flags = ENDSESSION_LOGOFF;
2627 break;
2628 case QUIT_REASON_RESTART:
2629 case QUIT_REASON_SHUTDOWN:
2630 qi->flags = 0;
2631 break;
2634 qi->result = TRUE;
2635 qi->replied = FALSE;
2637 for (i = 0; i < qi->count; i++)
2639 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2640 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2641 quit_callback, (ULONG_PTR)qi))
2643 DWORD error = GetLastError();
2644 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2645 if (invalid)
2646 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2647 qi->wins[i]);
2648 else
2649 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2650 qi->wins[i], error);
2651 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2655 /* quit_callback() will clean up qi */
2656 return;
2658 fail:
2659 WARN("failed to allocate window list\n");
2660 if (qi)
2662 HeapFree(GetProcessHeap(), 0, qi->wins);
2663 HeapFree(GetProcessHeap(), 0, qi);
2665 macdrv_quit_reply(FALSE);
2669 /***********************************************************************
2670 * query_resize_size
2672 * Handler for QUERY_RESIZE_SIZE query.
2674 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2676 struct macdrv_win_data *data = get_win_data(hwnd);
2677 RECT rect = rect_from_cgrect(query->resize_size.rect);
2678 int corner;
2679 BOOL ret = FALSE;
2681 if (!data) return FALSE;
2683 macdrv_mac_to_window_rect(data, &rect);
2685 if (query->resize_size.from_left)
2687 if (query->resize_size.from_top)
2688 corner = WMSZ_TOPLEFT;
2689 else
2690 corner = WMSZ_BOTTOMLEFT;
2692 else if (query->resize_size.from_top)
2693 corner = WMSZ_TOPRIGHT;
2694 else
2695 corner = WMSZ_BOTTOMRIGHT;
2697 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2699 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2700 query->resize_size.rect = cgrect_from_rect(rect);
2701 ret = TRUE;
2704 release_win_data(data);
2705 return ret;
2709 /***********************************************************************
2710 * query_resize_start
2712 * Handler for QUERY_RESIZE_START query.
2714 BOOL query_resize_start(HWND hwnd)
2716 TRACE("hwnd %p\n", hwnd);
2718 sync_window_min_max_info(hwnd);
2719 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2721 return TRUE;
2725 /***********************************************************************
2726 * query_min_max_info
2728 * Handler for QUERY_MIN_MAX_INFO query.
2730 BOOL query_min_max_info(HWND hwnd)
2732 TRACE("hwnd %p\n", hwnd);
2733 sync_window_min_max_info(hwnd);
2734 return TRUE;