maintainers: D3dxof is a D3D helper library too.
[wine.git] / dlls / winemac.drv / window.c
blobdb1e528cafb459be91e37f45a1097a6e822ac2e2
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 void CDECL macdrv_SetFocus(HWND hwnd);
51 /***********************************************************************
52 * get_cocoa_window_features
54 static void get_cocoa_window_features(struct macdrv_win_data *data,
55 DWORD style, DWORD ex_style,
56 struct macdrv_window_features* wf)
58 memset(wf, 0, sizeof(*wf));
60 if (disable_window_decorations) return;
61 if (IsRectEmpty(&data->window_rect)) return;
63 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
65 wf->shadow = TRUE;
66 if (!data->shaped)
68 wf->title_bar = TRUE;
69 if (style & WS_SYSMENU) wf->close_button = TRUE;
70 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
71 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
72 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
75 if (style & WS_THICKFRAME)
77 wf->shadow = TRUE;
78 if (!data->shaped) wf->resizable = TRUE;
80 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
81 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
85 /*******************************************************************
86 * can_activate_window
88 * Check if we can activate the specified window.
90 static inline BOOL can_activate_window(HWND hwnd)
92 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
94 if (!(style & WS_VISIBLE)) return FALSE;
95 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
96 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
97 if (hwnd == GetDesktopWindow()) return FALSE;
98 return !(style & WS_DISABLED);
102 /***********************************************************************
103 * get_cocoa_window_state
105 static void get_cocoa_window_state(struct macdrv_win_data *data,
106 DWORD style, DWORD ex_style,
107 struct macdrv_window_state* state)
109 memset(state, 0, sizeof(*state));
110 state->disabled = (style & WS_DISABLED) != 0;
111 state->no_activate = !can_activate_window(data->hwnd);
112 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
113 state->excluded_by_expose = state->excluded_by_cycle =
114 (!(ex_style & WS_EX_APPWINDOW) &&
115 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
116 if (IsRectEmpty(&data->window_rect))
117 state->excluded_by_expose = TRUE;
118 state->minimized = (style & WS_MINIMIZE) != 0;
119 state->minimized_valid = state->minimized != data->minimized;
120 state->maximized = (style & WS_MAXIMIZE) != 0;
124 /***********************************************************************
125 * get_mac_rect_offset
127 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
129 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
131 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
133 rect->top = rect->bottom = rect->left = rect->right = 0;
135 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
137 if (!data->shaped)
139 struct macdrv_window_features wf;
140 get_cocoa_window_features(data, style, ex_style, &wf);
142 if (wf.title_bar)
144 style_mask |= WS_CAPTION;
145 ex_style_mask |= WS_EX_TOOLWINDOW;
147 if (wf.shadow)
149 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
150 ex_style_mask |= WS_EX_DLGMODALFRAME;
154 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
156 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
157 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
161 /***********************************************************************
162 * macdrv_window_to_mac_rect
164 * Convert a rect from client to Mac window coordinates
166 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
168 RECT rc;
170 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
171 if (IsRectEmpty(rect)) return;
173 get_mac_rect_offset(data, style, &rc);
175 rect->left -= rc.left;
176 rect->right -= rc.right;
177 rect->top -= rc.top;
178 rect->bottom -= rc.bottom;
179 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
180 if (rect->left >= rect->right) rect->right = rect->left + 1;
184 /***********************************************************************
185 * macdrv_mac_to_window_rect
187 * Opposite of macdrv_window_to_mac_rect
189 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
191 RECT rc;
192 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
194 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
195 if (IsRectEmpty(rect)) return;
197 get_mac_rect_offset(data, style, &rc);
199 rect->left += rc.left;
200 rect->right += rc.right;
201 rect->top += rc.top;
202 rect->bottom += rc.bottom;
203 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
204 if (rect->left >= rect->right) rect->right = rect->left + 1;
208 /***********************************************************************
209 * constrain_window_frame
211 * Alter a window frame rectangle to fit within a) Cocoa's documented
212 * limits, and b) sane sizes, like twice the desktop rect.
214 static void constrain_window_frame(CGRect* frame)
216 CGRect desktop_rect = macdrv_get_desktop_rect();
217 int max_width, max_height;
219 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
220 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
222 if (frame->origin.x < -16000) frame->origin.x = -16000;
223 if (frame->origin.y < -16000) frame->origin.y = -16000;
224 if (frame->origin.x > 16000) frame->origin.x = 16000;
225 if (frame->origin.y > 16000) frame->origin.y = 16000;
226 if (frame->size.width > max_width) frame->size.width = max_width;
227 if (frame->size.height > max_height) frame->size.height = max_height;
231 /***********************************************************************
232 * alloc_win_data
234 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
236 struct macdrv_win_data *data;
238 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
240 data->hwnd = hwnd;
241 data->color_key = CLR_INVALID;
242 data->swap_interval = 1;
243 EnterCriticalSection(&win_data_section);
244 if (!win_datas)
245 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
246 CFDictionarySetValue(win_datas, hwnd, data);
248 return data;
252 /***********************************************************************
253 * get_win_data
255 * Lock and return the data structure associated with a window.
257 struct macdrv_win_data *get_win_data(HWND hwnd)
259 struct macdrv_win_data *data;
261 if (!hwnd) return NULL;
262 EnterCriticalSection(&win_data_section);
263 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
264 return data;
265 LeaveCriticalSection(&win_data_section);
266 return NULL;
270 /***********************************************************************
271 * release_win_data
273 * Release the data returned by get_win_data.
275 void release_win_data(struct macdrv_win_data *data)
277 if (data) LeaveCriticalSection(&win_data_section);
281 /***********************************************************************
282 * macdrv_get_cocoa_window
284 * Return the Mac window associated with the full area of a window
286 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
288 struct macdrv_win_data *data = get_win_data(hwnd);
289 macdrv_window ret = NULL;
290 if (data && (data->on_screen || !require_on_screen))
291 ret = data->cocoa_window;
292 release_win_data(data);
293 return ret;
297 /***********************************************************************
298 * macdrv_get_cocoa_view
300 * Return the Cocoa view associated with a window
302 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
304 struct macdrv_win_data *data = get_win_data(hwnd);
305 macdrv_view ret = data ? data->cocoa_view : NULL;
307 release_win_data(data);
308 return ret;
312 /***********************************************************************
313 * macdrv_get_client_cocoa_view
315 * Return the Cocoa view associated with a window's client area
317 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
319 struct macdrv_win_data *data = get_win_data(hwnd);
320 macdrv_view ret = data ? data->client_cocoa_view : NULL;
322 release_win_data(data);
323 return ret;
327 /***********************************************************************
328 * set_cocoa_window_properties
330 * Set the window properties for a Cocoa window based on its Windows
331 * properties.
333 static void set_cocoa_window_properties(struct macdrv_win_data *data)
335 DWORD style, ex_style;
336 HWND owner;
337 macdrv_window owner_win;
338 struct macdrv_window_features wf;
339 struct macdrv_window_state state;
341 style = GetWindowLongW(data->hwnd, GWL_STYLE);
342 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
344 owner = GetWindow(data->hwnd, GW_OWNER);
345 if (owner)
346 owner = GetAncestor(owner, GA_ROOT);
347 owner_win = macdrv_get_cocoa_window(owner, TRUE);
348 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
350 get_cocoa_window_features(data, style, ex_style, &wf);
351 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
353 get_cocoa_window_state(data, style, ex_style, &state);
354 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
355 if (state.minimized_valid)
356 data->minimized = state.minimized;
360 /***********************************************************************
361 * sync_window_region
363 * Update the window region.
365 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
367 HRGN hrgn = win_region;
368 RGNDATA *region_data;
369 const CGRect* rects;
370 int count;
372 if (!data->cocoa_window) return;
373 data->shaped = FALSE;
375 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
377 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
378 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
379 return;
382 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
384 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
385 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
387 DeleteObject(hrgn);
388 hrgn = 0;
392 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
393 MirrorRgn(data->hwnd, hrgn);
394 if (hrgn)
396 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
397 data->window_rect.top - data->whole_rect.top);
399 region_data = get_region_data(hrgn, 0);
400 if (region_data)
402 rects = (CGRect*)region_data->Buffer;
403 count = region_data->rdh.nCount;
404 /* Special case optimization. If the region entirely encloses the Cocoa
405 window, it's the same as there being no region. It's potentially
406 hard/slow to test this for arbitrary regions, so we just check for
407 very simple regions. */
408 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
410 TRACE("optimizing for simple region that contains Cocoa content rect\n");
411 rects = NULL;
412 count = 0;
415 else
417 rects = NULL;
418 count = 0;
421 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
422 macdrv_set_window_shape(data->cocoa_window, rects, count);
424 HeapFree(GetProcessHeap(), 0, region_data);
425 data->shaped = (region_data != NULL);
427 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
431 /***********************************************************************
432 * add_bounds_rect
434 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
436 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
437 bounds->left = min(bounds->left, rect->left);
438 bounds->top = min(bounds->top, rect->top);
439 bounds->right = max(bounds->right, rect->right);
440 bounds->bottom = max(bounds->bottom, rect->bottom);
444 /***********************************************************************
445 * sync_window_opacity
447 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
448 BOOL per_pixel_alpha, DWORD flags)
450 CGFloat opacity = 1.0;
451 BOOL needs_flush = FALSE;
453 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
455 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
456 macdrv_set_window_alpha(data->cocoa_window, opacity);
458 if (flags & LWA_COLORKEY)
460 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
461 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
462 key = RGB(0, 0, 0);
464 else
465 key = CLR_INVALID;
467 if (data->color_key != key)
469 if (key == CLR_INVALID)
471 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
472 macdrv_clear_window_color_key(data->cocoa_window);
474 else
476 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
477 GetRValue(key), GetGValue(key), GetBValue(key));
478 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
481 data->color_key = key;
482 needs_flush = TRUE;
485 if (!data->per_pixel_alpha != !per_pixel_alpha)
487 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
488 data->per_pixel_alpha = per_pixel_alpha;
489 needs_flush = TRUE;
492 if (needs_flush && data->surface)
494 RECT *bounds;
495 RECT rect;
497 rect = data->whole_rect;
498 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
499 data->surface->funcs->lock(data->surface);
500 bounds = data->surface->funcs->get_bounds(data->surface);
501 add_bounds_rect(bounds, &rect);
502 data->surface->funcs->unlock(data->surface);
507 /***********************************************************************
508 * sync_window_min_max_info
510 static void sync_window_min_max_info(HWND hwnd)
512 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
513 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
514 RECT win_rect, primary_monitor_rect;
515 MINMAXINFO minmax;
516 LONG adjustedStyle;
517 INT xinc, yinc;
518 WINDOWPLACEMENT wpl;
519 HMONITOR monitor;
520 struct macdrv_win_data *data;
522 TRACE("win %p\n", hwnd);
524 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
526 GetWindowRect(hwnd, &win_rect);
527 minmax.ptReserved.x = win_rect.left;
528 minmax.ptReserved.y = win_rect.top;
530 if ((style & WS_CAPTION) == WS_CAPTION)
531 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
532 else
533 adjustedStyle = style;
535 primary_monitor_rect.left = primary_monitor_rect.top = 0;
536 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
537 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
538 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
540 xinc = -primary_monitor_rect.left;
541 yinc = -primary_monitor_rect.top;
543 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
544 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
545 minmax.ptMaxPosition.x = -xinc;
546 minmax.ptMaxPosition.y = -yinc;
547 if (style & (WS_DLGFRAME | WS_BORDER))
549 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
550 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
552 else
554 minmax.ptMinTrackSize.x = 2 * xinc;
555 minmax.ptMinTrackSize.y = 2 * yinc;
557 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
558 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
560 wpl.length = sizeof(wpl);
561 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
563 minmax.ptMaxPosition = wpl.ptMaxPosition;
565 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
566 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
567 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
570 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
571 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
573 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
575 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
576 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
578 /* if the app didn't change the values, adapt them for the window's monitor */
579 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
581 MONITORINFO mon_info;
582 RECT monitor_rect;
584 mon_info.cbSize = sizeof(mon_info);
585 GetMonitorInfoW(monitor, &mon_info);
587 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
588 monitor_rect = mon_info.rcWork;
589 else
590 monitor_rect = mon_info.rcMonitor;
592 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
593 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
595 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
596 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
598 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
600 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
601 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
605 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
606 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
608 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
609 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
611 if ((data = get_win_data(hwnd)) && data->cocoa_window)
613 RECT min_rect, max_rect;
614 CGSize min_size, max_size;
616 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
617 macdrv_window_to_mac_rect(data, style, &min_rect);
618 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
620 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
621 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
622 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
623 else
625 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
626 macdrv_window_to_mac_rect(data, style, &max_rect);
627 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
630 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
631 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
634 release_win_data(data);
638 /**********************************************************************
639 * create_client_cocoa_view
641 * Create the Cocoa view for a window's client area
643 static void create_client_cocoa_view(struct macdrv_win_data *data)
645 RECT rect = data->client_rect;
646 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
648 if (data->client_cocoa_view)
649 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
650 else
652 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
653 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
655 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
659 /**********************************************************************
660 * create_cocoa_window
662 * Create the whole Mac window for a given window
664 static void create_cocoa_window(struct macdrv_win_data *data)
666 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
667 WCHAR text[1024];
668 struct macdrv_window_features wf;
669 CGRect frame;
670 DWORD style, ex_style;
671 HRGN win_rgn;
672 COLORREF key;
673 BYTE alpha;
674 DWORD layered_flags;
676 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
677 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
679 DeleteObject(win_rgn);
680 win_rgn = 0;
682 data->shaped = (win_rgn != 0);
684 style = GetWindowLongW(data->hwnd, GWL_STYLE);
685 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
687 data->whole_rect = data->window_rect;
688 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
690 get_cocoa_window_features(data, style, ex_style, &wf);
692 frame = cgrect_from_rect(data->whole_rect);
693 constrain_window_frame(&frame);
694 if (frame.size.width < 1 || frame.size.height < 1)
695 frame.size.width = frame.size.height = 1;
697 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
698 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
700 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
701 if (!data->cocoa_window) goto done;
702 create_client_cocoa_view(data);
704 set_cocoa_window_properties(data);
706 /* set the window text */
707 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
708 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
710 /* set the window region */
711 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
713 /* set the window opacity */
714 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
715 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
717 done:
718 if (win_rgn) DeleteObject(win_rgn);
722 /**********************************************************************
723 * destroy_cocoa_window
725 * Destroy the whole Mac window for a given window.
727 static void destroy_cocoa_window(struct macdrv_win_data *data)
729 if (!data->cocoa_window) return;
731 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
733 macdrv_destroy_cocoa_window(data->cocoa_window);
734 data->cocoa_window = 0;
735 data->on_screen = FALSE;
736 data->color_key = CLR_INVALID;
737 if (data->surface) window_surface_release(data->surface);
738 data->surface = NULL;
739 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
740 data->unminimized_surface = NULL;
744 /**********************************************************************
745 * create_cocoa_view
747 * Create the Cocoa view for a given Windows child window
749 static void create_cocoa_view(struct macdrv_win_data *data)
751 BOOL equal = !memcmp(&data->window_rect, &data->client_rect, sizeof(data->whole_rect));
752 CGRect frame = cgrect_from_rect(data->window_rect);
754 data->shaped = FALSE;
755 data->whole_rect = data->window_rect;
757 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
758 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
760 if (!equal)
761 data->cocoa_view = macdrv_create_view(frame);
762 create_client_cocoa_view(data);
763 if (equal)
765 data->cocoa_view = data->client_cocoa_view;
766 macdrv_set_view_hidden(data->cocoa_view, TRUE);
767 macdrv_set_view_frame(data->cocoa_view, frame);
772 /**********************************************************************
773 * destroy_cocoa_view
775 * Destroy the Cocoa view for a given window.
777 static void destroy_cocoa_view(struct macdrv_win_data *data)
779 if (!data->cocoa_view) return;
781 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
783 if (data->cocoa_view != data->client_cocoa_view)
784 macdrv_dispose_view(data->cocoa_view);
785 data->cocoa_view = NULL;
786 data->on_screen = FALSE;
790 /***********************************************************************
791 * macdrv_create_win_data
793 * Create a Mac data window structure for an existing window.
795 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
796 const RECT *client_rect)
798 struct macdrv_win_data *data;
799 HWND parent;
801 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
803 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
805 macdrv_init_thread_data();
806 return NULL;
809 /* don't create win data for HWND_MESSAGE windows */
810 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
812 if (!(data = alloc_win_data(hwnd))) return NULL;
814 data->whole_rect = data->window_rect = *window_rect;
815 data->client_rect = *client_rect;
817 if (parent == GetDesktopWindow())
819 create_cocoa_window(data);
820 TRACE("win %p/%p window %s whole %s client %s\n",
821 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
822 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
824 else
826 create_cocoa_view(data);
827 TRACE("win %p/%p window %s whole %s client %s\n",
828 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
829 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
832 return data;
836 /***********************************************************************
837 * show_window
839 static void show_window(struct macdrv_win_data *data)
841 if (data->cocoa_window)
843 HWND prev = NULL;
844 HWND next = NULL;
845 macdrv_window prev_window = NULL;
846 macdrv_window next_window = NULL;
847 BOOL activate = FALSE;
848 HWND hwndFocus;
850 /* find window that this one must be after */
851 prev = GetWindow(data->hwnd, GW_HWNDPREV);
852 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
853 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
854 prev = GetWindow(prev, GW_HWNDPREV);
855 if (!prev_window)
857 /* find window that this one must be before */
858 next = GetWindow(data->hwnd, GW_HWNDNEXT);
859 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
860 (next_window = macdrv_get_cocoa_window(next, TRUE))))
861 next = GetWindow(next, GW_HWNDNEXT);
864 TRACE("win %p/%p below %p/%p above %p/%p\n",
865 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
867 if (!prev_window)
868 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
869 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
870 data->on_screen = TRUE;
872 hwndFocus = GetFocus();
873 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
874 macdrv_SetFocus(hwndFocus);
875 if (activate)
876 activate_on_focus_time = 0;
878 else
880 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
882 macdrv_set_view_hidden(data->cocoa_view, FALSE);
883 data->on_screen = TRUE;
888 /***********************************************************************
889 * hide_window
891 static void hide_window(struct macdrv_win_data *data)
893 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
895 if (data->cocoa_window)
896 macdrv_hide_cocoa_window(data->cocoa_window);
897 else
898 macdrv_set_view_hidden(data->cocoa_view, TRUE);
899 data->on_screen = FALSE;
903 /***********************************************************************
904 * sync_window_z_order
906 static void sync_window_z_order(struct macdrv_win_data *data)
908 if (data->cocoa_view)
910 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
911 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
912 macdrv_window window = NULL;
913 HWND prev;
914 HWND next = NULL;
915 macdrv_view prev_view = NULL;
916 macdrv_view next_view = NULL;
918 if (!superview)
920 window = macdrv_get_cocoa_window(parent, FALSE);
921 if (!window)
922 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
925 /* find window that this one must be after */
926 prev = GetWindow(data->hwnd, GW_HWNDPREV);
927 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
928 prev = GetWindow(prev, GW_HWNDPREV);
929 if (!prev_view)
931 /* find window that this one must be before */
932 next = GetWindow(data->hwnd, GW_HWNDNEXT);
933 while (next && !(next_view = macdrv_get_cocoa_view(next)))
934 next = GetWindow(next, GW_HWNDNEXT);
937 TRACE("win %p/%p below %p/%p above %p/%p\n",
938 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
940 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
942 else if (data->on_screen)
943 show_window(data);
947 /***********************************************************************
948 * get_region_data
950 * Calls GetRegionData on the given region and converts the rectangle
951 * array to CGRect format. The returned buffer must be freed by
952 * caller using HeapFree(GetProcessHeap(),...).
953 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
955 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
957 RGNDATA *data;
958 DWORD size;
959 int i;
960 RECT *rect;
961 CGRect *cgrect;
963 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
964 if (sizeof(CGRect) > sizeof(RECT))
966 /* add extra size for CGRect array */
967 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
968 size += count * (sizeof(CGRect) - sizeof(RECT));
970 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
971 if (!GetRegionData(hrgn, size, data))
973 HeapFree(GetProcessHeap(), 0, data);
974 return NULL;
977 rect = (RECT *)data->Buffer;
978 cgrect = (CGRect *)data->Buffer;
979 if (hdc_lptodp) /* map to device coordinates */
981 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
982 for (i = 0; i < data->rdh.nCount; i++)
984 if (rect[i].right < rect[i].left)
986 INT tmp = rect[i].right;
987 rect[i].right = rect[i].left;
988 rect[i].left = tmp;
990 if (rect[i].bottom < rect[i].top)
992 INT tmp = rect[i].bottom;
993 rect[i].bottom = rect[i].top;
994 rect[i].top = tmp;
999 if (sizeof(CGRect) > sizeof(RECT))
1001 /* need to start from the end */
1002 for (i = data->rdh.nCount-1; i >= 0; i--)
1003 cgrect[i] = cgrect_from_rect(rect[i]);
1005 else
1007 for (i = 0; i < data->rdh.nCount; i++)
1008 cgrect[i] = cgrect_from_rect(rect[i]);
1010 return data;
1014 /***********************************************************************
1015 * sync_window_position
1017 * Synchronize the Mac window position with the Windows one
1019 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1020 const RECT *old_whole_rect)
1022 CGRect frame = cgrect_from_rect(data->whole_rect);
1023 BOOL force_z_order = FALSE;
1025 if (data->cocoa_window)
1027 if (data->minimized) return;
1029 constrain_window_frame(&frame);
1030 if (frame.size.width < 1 || frame.size.height < 1)
1031 frame.size.width = frame.size.height = 1;
1033 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1035 else
1037 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1038 BOOL now_equal = !memcmp(&data->whole_rect, &data->client_rect, sizeof(data->whole_rect));
1040 if (were_equal && !now_equal)
1042 data->cocoa_view = macdrv_create_view(frame);
1043 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1044 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1045 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1046 force_z_order = TRUE;
1048 else if (!were_equal && now_equal)
1050 macdrv_dispose_view(data->cocoa_view);
1051 data->cocoa_view = data->client_cocoa_view;
1052 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1053 macdrv_set_view_frame(data->cocoa_view, frame);
1054 force_z_order = TRUE;
1056 else
1057 macdrv_set_view_frame(data->cocoa_view, frame);
1060 if (data->cocoa_view != data->client_cocoa_view)
1062 RECT rect = data->client_rect;
1063 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1064 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1065 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1068 if (old_window_rect && old_whole_rect &&
1069 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1070 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1071 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1072 sync_window_region(data, (HRGN)1);
1074 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1075 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1076 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1078 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1079 sync_window_z_order(data);
1083 /***********************************************************************
1084 * move_window_bits
1086 * Move the window bits when a window is moved.
1088 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1089 const RECT *old_client_rect, const RECT *new_client_rect,
1090 const RECT *new_window_rect)
1092 RECT src_rect = *old_rect;
1093 RECT dst_rect = *new_rect;
1094 HDC hdc_src, hdc_dst;
1095 HRGN rgn;
1096 HWND parent = 0;
1098 if (!window)
1100 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1101 parent = GetAncestor(hwnd, GA_PARENT);
1102 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1103 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1105 else
1107 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1108 /* make src rect relative to the old position of the window */
1109 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1110 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1111 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1114 rgn = CreateRectRgnIndirect(&dst_rect);
1115 SelectClipRgn(hdc_dst, rgn);
1116 DeleteObject(rgn);
1117 ExcludeUpdateRgn(hdc_dst, hwnd);
1119 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1120 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1121 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1122 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1123 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1125 ReleaseDC(hwnd, hdc_dst);
1126 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1130 /**********************************************************************
1131 * activate_on_following_focus
1133 void activate_on_following_focus(void)
1135 activate_on_focus_time = GetTickCount();
1136 if (!activate_on_focus_time) activate_on_focus_time = 1;
1140 /***********************************************************************
1141 * set_app_icon
1143 static void set_app_icon(void)
1145 CFArrayRef images = create_app_icon_images();
1146 if (images)
1148 macdrv_set_application_icon(images);
1149 CFRelease(images);
1154 /**********************************************************************
1155 * set_capture_window_for_move
1157 static BOOL set_capture_window_for_move(HWND hwnd)
1159 HWND previous = 0;
1160 BOOL ret;
1162 SERVER_START_REQ(set_capture_window)
1164 req->handle = wine_server_user_handle(hwnd);
1165 req->flags = CAPTURE_MOVESIZE;
1166 if ((ret = !wine_server_call_err(req)))
1168 previous = wine_server_ptr_handle(reply->previous);
1169 hwnd = wine_server_ptr_handle(reply->full_handle);
1172 SERVER_END_REQ;
1174 if (ret)
1176 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1178 if (previous && previous != hwnd)
1179 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1181 return ret;
1185 /***********************************************************************
1186 * move_window
1188 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1189 * moving top-level windows and enforcing Mac-style constraints like
1190 * keeping the top of the window within the work area.
1192 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1194 MSG msg;
1195 RECT origRect, movedRect, desktopRect;
1196 LONG hittest = (LONG)(wparam & 0x0f);
1197 POINT capturePoint;
1198 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1199 BOOL moved = FALSE;
1200 DWORD dwPoint = GetMessagePos();
1201 INT captionHeight;
1202 HMONITOR mon = 0;
1203 MONITORINFO info;
1205 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1206 if (hittest && hittest != HTCAPTION) return -1;
1208 capturePoint.x = (short)LOWORD(dwPoint);
1209 capturePoint.y = (short)HIWORD(dwPoint);
1210 ClipCursor(NULL);
1212 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1214 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1215 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1216 captionHeight = -origRect.top;
1217 else
1218 captionHeight = 0;
1220 GetWindowRect(hwnd, &origRect);
1221 movedRect = origRect;
1223 if (!hittest)
1225 /* Move pointer to the center of the caption */
1226 RECT rect = origRect;
1228 /* Note: to be exactly centered we should take the different types
1229 * of border into account, but it shouldn't make more than a few pixels
1230 * of difference so let's not bother with that */
1231 rect.top += GetSystemMetrics(SM_CYBORDER);
1232 if (style & WS_SYSMENU)
1233 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1234 if (style & WS_MINIMIZEBOX)
1235 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1236 if (style & WS_MAXIMIZEBOX)
1237 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1238 capturePoint.x = (rect.right + rect.left) / 2;
1239 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1241 SetCursorPos(capturePoint.x, capturePoint.y);
1242 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1245 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1246 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1247 info.cbSize = sizeof(info);
1248 if (mon && !GetMonitorInfoW(mon, &info))
1249 mon = 0;
1251 /* repaint the window before moving it around */
1252 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1254 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1255 set_capture_window_for_move(hwnd);
1257 while(1)
1259 POINT pt;
1260 int dx = 0, dy = 0;
1261 HMONITOR newmon;
1263 if (!GetMessageW(&msg, 0, 0, 0)) break;
1264 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1266 /* Exit on button-up, Return, or Esc */
1267 if (msg.message == WM_LBUTTONUP ||
1268 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1269 break;
1271 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1273 TranslateMessage(&msg);
1274 DispatchMessageW(&msg);
1275 continue; /* We are not interested in other messages */
1278 pt = msg.pt;
1280 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1282 case VK_UP: pt.y -= 8; break;
1283 case VK_DOWN: pt.y += 8; break;
1284 case VK_LEFT: pt.x -= 8; break;
1285 case VK_RIGHT: pt.x += 8; break;
1288 pt.x = max(pt.x, desktopRect.left);
1289 pt.x = min(pt.x, desktopRect.right - 1);
1290 pt.y = max(pt.y, desktopRect.top);
1291 pt.y = min(pt.y, desktopRect.bottom - 1);
1293 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1295 if (GetMonitorInfoW(newmon, &info))
1296 mon = newmon;
1297 else
1298 mon = 0;
1301 if (mon)
1303 /* wineserver clips the cursor position to the virtual desktop rect but,
1304 if the display configuration is non-rectangular, that could still
1305 leave the logical cursor position outside of any display. The window
1306 could keep moving as you push the cursor against a display edge, even
1307 though the visible cursor doesn't keep moving. The following keeps
1308 the window movement in sync with the visible cursor. */
1309 pt.x = max(pt.x, info.rcMonitor.left);
1310 pt.x = min(pt.x, info.rcMonitor.right - 1);
1311 pt.y = max(pt.y, info.rcMonitor.top);
1312 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1314 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1315 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1316 we want to enforce these constraints:
1317 movedRect.left + dx < info.rcWork.right
1318 movedRect.right + dx > info.rcWork.left
1319 movedRect.top + captionHeight + dy < info.rcWork.bottom
1320 movedRect.bottom + dy > info.rcWork.top
1321 movedRect.top + dy >= info.rcWork.top
1322 The first four keep at least one edge barely in the work area.
1323 The last keeps the top (i.e. the title bar) in the work area.
1324 The fourth is redundant with the last, so can be ignored.
1326 Substituting for dx and dy and rearranging gives us...
1328 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1329 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1330 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1331 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1334 dx = pt.x - capturePoint.x;
1335 dy = pt.y - capturePoint.y;
1337 if (dx || dy)
1339 moved = TRUE;
1341 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1342 else
1344 OffsetRect(&movedRect, dx, dy);
1345 capturePoint = pt;
1347 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1348 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1349 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1354 set_capture_window_for_move(0);
1356 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1357 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1359 /* if the move is canceled, restore the previous position */
1360 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1362 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1363 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1366 return 0;
1370 /***********************************************************************
1371 * perform_window_command
1373 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1375 DWORD style;
1377 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1378 hwnd, style_any, style_none, command, hittest);
1380 style = GetWindowLongW(hwnd, GWL_STYLE);
1381 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1383 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1384 return;
1387 if (GetActiveWindow() != hwnd)
1389 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1390 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1391 switch (ma)
1393 case MA_NOACTIVATEANDEAT:
1394 case MA_ACTIVATEANDEAT:
1395 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1396 return;
1397 case MA_NOACTIVATE:
1398 break;
1399 case MA_ACTIVATE:
1400 case 0:
1401 SetActiveWindow(hwnd);
1402 break;
1403 default:
1404 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1405 break;
1409 TRACE("changing win %p\n", hwnd);
1410 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1414 /**********************************************************************
1415 * CreateDesktopWindow (MACDRV.@)
1417 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1419 unsigned int width, height;
1421 TRACE("%p\n", hwnd);
1423 /* retrieve the real size of the desktop */
1424 SERVER_START_REQ(get_window_rectangles)
1426 req->handle = wine_server_user_handle(hwnd);
1427 req->relative = COORDS_CLIENT;
1428 wine_server_call(req);
1429 width = reply->window.right;
1430 height = reply->window.bottom;
1432 SERVER_END_REQ;
1434 if (!width && !height) /* not initialized yet */
1436 CGRect rect = macdrv_get_desktop_rect();
1438 SERVER_START_REQ(set_window_pos)
1440 req->handle = wine_server_user_handle(hwnd);
1441 req->previous = 0;
1442 req->swp_flags = SWP_NOZORDER;
1443 req->window.left = CGRectGetMinX(rect);
1444 req->window.top = CGRectGetMinY(rect);
1445 req->window.right = CGRectGetMaxX(rect);
1446 req->window.bottom = CGRectGetMaxY(rect);
1447 req->client = req->window;
1448 wine_server_call(req);
1450 SERVER_END_REQ;
1453 set_app_icon();
1454 return TRUE;
1458 /**********************************************************************
1459 * CreateWindow (MACDRV.@)
1461 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1463 return TRUE;
1467 /***********************************************************************
1468 * DestroyWindow (MACDRV.@)
1470 void CDECL macdrv_DestroyWindow(HWND hwnd)
1472 struct macdrv_win_data *data;
1474 TRACE("%p\n", hwnd);
1476 if (!(data = get_win_data(hwnd))) return;
1478 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1480 destroy_cocoa_window(data);
1481 destroy_cocoa_view(data);
1482 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1484 CFDictionaryRemoveValue(win_datas, hwnd);
1485 release_win_data(data);
1486 HeapFree(GetProcessHeap(), 0, data);
1490 /*****************************************************************
1491 * SetFocus (MACDRV.@)
1493 * Set the Mac focus.
1495 void CDECL macdrv_SetFocus(HWND hwnd)
1497 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1498 struct macdrv_win_data *data;
1500 TRACE("%p\n", hwnd);
1502 if (!thread_data) return;
1503 thread_data->dead_key_state = 0;
1505 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
1506 if (!(data = get_win_data(hwnd))) return;
1508 if (data->cocoa_window && data->on_screen)
1510 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
1511 /* Set Mac focus */
1512 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
1513 activate_on_focus_time = 0;
1516 release_win_data(data);
1520 /***********************************************************************
1521 * SetLayeredWindowAttributes (MACDRV.@)
1523 * Set transparency attributes for a layered window.
1525 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1527 struct macdrv_win_data *data = get_win_data(hwnd);
1529 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1531 if (data)
1533 data->layered = TRUE;
1534 if (data->cocoa_window)
1536 sync_window_opacity(data, key, alpha, FALSE, flags);
1537 /* since layered attributes are now set, can now show the window */
1538 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1539 show_window(data);
1541 release_win_data(data);
1543 else
1544 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1548 /*****************************************************************
1549 * SetParent (MACDRV.@)
1551 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1553 struct macdrv_win_data *data;
1555 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1557 if (parent == old_parent) return;
1558 if (!(data = get_win_data(hwnd))) return;
1560 if (parent != GetDesktopWindow()) /* a child window */
1562 if (old_parent == GetDesktopWindow())
1564 /* destroy the old Mac window */
1565 destroy_cocoa_window(data);
1566 create_cocoa_view(data);
1568 else
1570 struct macdrv_win_data *parent_data = get_win_data(parent);
1571 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
1572 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
1574 if (!cocoa_window && !superview)
1575 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", hwnd, parent);
1577 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
1578 release_win_data(parent_data);
1581 else /* new top level window */
1583 destroy_cocoa_view(data);
1584 create_cocoa_window(data);
1586 release_win_data(data);
1590 /***********************************************************************
1591 * SetWindowRgn (MACDRV.@)
1593 * Assign specified region to window (for non-rectangular windows)
1595 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1597 struct macdrv_win_data *data;
1599 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1601 if ((data = get_win_data(hwnd)))
1603 sync_window_region(data, hrgn);
1604 release_win_data(data);
1606 else
1608 DWORD procid;
1610 GetWindowThreadProcessId(hwnd, &procid);
1611 if (procid != GetCurrentProcessId())
1612 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1617 /***********************************************************************
1618 * SetWindowStyle (MACDRV.@)
1620 * Update the state of the Cocoa window to reflect a style change
1622 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1624 struct macdrv_win_data *data;
1626 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1628 if (hwnd == GetDesktopWindow()) return;
1629 if (!(data = get_win_data(hwnd))) return;
1631 if (data->cocoa_window)
1633 DWORD changed = style->styleNew ^ style->styleOld;
1635 set_cocoa_window_properties(data);
1637 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1639 data->layered = FALSE;
1640 data->ulw_layered = FALSE;
1641 sync_window_opacity(data, 0, 0, FALSE, 0);
1642 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1645 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1646 sync_window_region(data, (HRGN)1);
1649 release_win_data(data);
1653 /*****************************************************************
1654 * SetWindowText (MACDRV.@)
1656 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1658 macdrv_window win;
1660 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1662 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1663 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1667 /***********************************************************************
1668 * ShowWindow (MACDRV.@)
1670 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1672 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1673 struct macdrv_win_data *data = get_win_data(hwnd);
1674 CGRect frame;
1676 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1677 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1679 if (!data || !data->cocoa_window) goto done;
1680 if (IsRectEmpty(rect)) goto done;
1681 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1683 if (rect->left != -32000 || rect->top != -32000)
1685 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1686 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1688 goto done;
1690 if (!data->on_screen) goto done;
1692 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1694 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1695 goto done;
1697 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1698 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1699 goto done;
1701 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1702 *rect = rect_from_cgrect(frame);
1703 macdrv_mac_to_window_rect(data, rect);
1704 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1705 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1707 done:
1708 release_win_data(data);
1709 return swp;
1713 /***********************************************************************
1714 * SysCommand (MACDRV.@)
1716 * Perform WM_SYSCOMMAND handling.
1718 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1720 struct macdrv_win_data *data;
1721 LRESULT ret = -1;
1722 WPARAM command = wparam & 0xfff0;
1724 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1726 if (!(data = get_win_data(hwnd))) goto done;
1727 if (!data->cocoa_window || !data->on_screen) goto done;
1729 /* prevent a simple ALT press+release from activating the system menu,
1730 as that can get confusing */
1731 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1732 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1734 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1735 ret = 0;
1738 if (command == SC_MOVE)
1740 release_win_data(data);
1741 return move_window(hwnd, wparam);
1744 done:
1745 release_win_data(data);
1746 return ret;
1750 /***********************************************************************
1751 * UpdateLayeredWindow (MACDRV.@)
1753 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1754 const RECT *window_rect)
1756 struct window_surface *surface;
1757 struct macdrv_win_data *data;
1758 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1759 BYTE alpha;
1760 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1761 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1762 void *src_bits, *dst_bits;
1763 RECT rect;
1764 HDC hdc = 0;
1765 HBITMAP dib;
1766 BOOL ret = FALSE;
1768 if (!(data = get_win_data(hwnd))) return FALSE;
1770 data->layered = TRUE;
1771 data->ulw_layered = TRUE;
1773 rect = *window_rect;
1774 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1776 surface = data->surface;
1777 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1779 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1780 set_window_surface(data->cocoa_window, data->surface);
1781 if (surface) window_surface_release(surface);
1782 surface = data->surface;
1783 if (data->unminimized_surface)
1785 window_surface_release(data->unminimized_surface);
1786 data->unminimized_surface = NULL;
1789 else set_surface_use_alpha(surface, TRUE);
1791 if (surface) window_surface_add_ref(surface);
1792 release_win_data(data);
1794 if (!surface) return FALSE;
1795 if (!info->hdcSrc)
1797 window_surface_release(surface);
1798 return TRUE;
1801 if (info->dwFlags & ULW_ALPHA)
1803 /* Apply SourceConstantAlpha via window alpha, not blend. */
1804 alpha = info->pblend->SourceConstantAlpha;
1805 blend = *info->pblend;
1806 blend.SourceConstantAlpha = 0xff;
1808 else
1809 alpha = 0xff;
1811 dst_bits = surface->funcs->get_info(surface, bmi);
1813 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1814 if (!(hdc = CreateCompatibleDC(0))) goto done;
1816 SelectObject(hdc, dib);
1817 if (info->prcDirty)
1819 IntersectRect(&rect, &rect, info->prcDirty);
1820 surface->funcs->lock(surface);
1821 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1822 surface->funcs->unlock(surface);
1823 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1825 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1826 info->hdcSrc,
1827 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1828 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1829 rect.right - rect.left, rect.bottom - rect.top,
1830 blend)))
1831 goto done;
1833 if ((data = get_win_data(hwnd)))
1835 if (surface == data->surface)
1837 surface->funcs->lock(surface);
1838 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1839 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1840 surface->funcs->unlock(surface);
1841 surface->funcs->flush(surface);
1844 /* The ULW flags are a superset of the LWA flags. */
1845 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1847 release_win_data(data);
1850 done:
1851 window_surface_release(surface);
1852 if (hdc) DeleteDC(hdc);
1853 if (dib) DeleteObject(dib);
1854 return ret;
1858 /**********************************************************************
1859 * WindowMessage (MACDRV.@)
1861 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1863 struct macdrv_win_data *data;
1865 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1867 switch(msg)
1869 case WM_MACDRV_SET_WIN_REGION:
1870 if ((data = get_win_data(hwnd)))
1872 sync_window_region(data, (HRGN)1);
1873 release_win_data(data);
1875 return 0;
1876 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1877 if (hwnd == GetDesktopWindow())
1879 CGRect new_desktop_rect;
1880 RECT current_desktop_rect;
1882 macdrv_reset_device_metrics();
1883 new_desktop_rect = macdrv_get_desktop_rect();
1884 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1885 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1887 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1888 SMTO_ABORTIFHUNG, 2000, NULL);
1889 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1890 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1891 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1892 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1893 SMTO_ABORTIFHUNG, 2000, NULL);
1896 return 0;
1897 case WM_MACDRV_RESET_DEVICE_METRICS:
1898 macdrv_reset_device_metrics();
1899 return 0;
1900 case WM_MACDRV_DISPLAYCHANGE:
1901 macdrv_reassert_window_position(hwnd);
1902 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1903 return 0;
1904 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1905 activate_on_following_focus();
1906 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1907 return 0;
1910 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1911 return 0;
1915 static inline RECT get_surface_rect(const RECT *visible_rect)
1917 RECT rect;
1918 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1920 IntersectRect(&rect, visible_rect, &desktop_rect);
1921 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1922 rect.left &= ~127;
1923 rect.top &= ~127;
1924 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1925 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1926 return rect;
1930 /***********************************************************************
1931 * WindowPosChanging (MACDRV.@)
1933 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1934 const RECT *window_rect, const RECT *client_rect,
1935 RECT *visible_rect, struct window_surface **surface)
1937 struct macdrv_win_data *data = get_win_data(hwnd);
1938 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1939 RECT surface_rect;
1941 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1942 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1943 wine_dbgstr_rect(visible_rect), surface);
1945 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1947 *visible_rect = *window_rect;
1948 macdrv_window_to_mac_rect(data, style, visible_rect);
1949 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1950 wine_dbgstr_rect(visible_rect));
1952 /* create the window surface if necessary */
1953 if (!data->cocoa_window) goto done;
1954 if (swp_flags & SWP_HIDEWINDOW) goto done;
1955 if (data->ulw_layered) goto done;
1957 if (*surface) window_surface_release(*surface);
1958 *surface = NULL;
1960 surface_rect = get_surface_rect(visible_rect);
1961 if (data->surface)
1963 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1965 /* existing surface is good enough */
1966 surface_clip_to_visible_rect(data->surface, visible_rect);
1967 window_surface_add_ref(data->surface);
1968 *surface = data->surface;
1969 goto done;
1972 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1974 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1976 done:
1977 release_win_data(data);
1981 /***********************************************************************
1982 * WindowPosChanged (MACDRV.@)
1984 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1985 const RECT *window_rect, const RECT *client_rect,
1986 const RECT *visible_rect, const RECT *valid_rects,
1987 struct window_surface *surface)
1989 struct macdrv_thread_data *thread_data;
1990 struct macdrv_win_data *data;
1991 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1992 RECT old_window_rect, old_whole_rect, old_client_rect;
1994 if (!(data = get_win_data(hwnd))) return;
1996 thread_data = macdrv_thread_data();
1998 old_window_rect = data->window_rect;
1999 old_whole_rect = data->whole_rect;
2000 old_client_rect = data->client_rect;
2001 data->window_rect = *window_rect;
2002 data->whole_rect = *visible_rect;
2003 data->client_rect = *client_rect;
2004 if (!data->ulw_layered)
2006 if (surface) window_surface_add_ref(surface);
2007 if (new_style & WS_MINIMIZE)
2009 if (!data->unminimized_surface && data->surface)
2011 data->unminimized_surface = data->surface;
2012 window_surface_add_ref(data->unminimized_surface);
2015 else
2017 set_window_surface(data->cocoa_window, surface);
2018 if (data->unminimized_surface)
2020 window_surface_release(data->unminimized_surface);
2021 data->unminimized_surface = NULL;
2024 if (data->surface) window_surface_release(data->surface);
2025 data->surface = surface;
2028 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2029 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2030 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2031 new_style, swp_flags, surface);
2033 if (!IsRectEmpty(&valid_rects[0]))
2035 macdrv_window window = data->cocoa_window;
2036 int x_offset = old_whole_rect.left - data->whole_rect.left;
2037 int y_offset = old_whole_rect.top - data->whole_rect.top;
2039 /* if all that happened is that the whole window moved, copy everything */
2040 if (!(swp_flags & SWP_FRAMECHANGED) &&
2041 old_whole_rect.right - data->whole_rect.right == x_offset &&
2042 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2043 old_client_rect.left - data->client_rect.left == x_offset &&
2044 old_client_rect.right - data->client_rect.right == x_offset &&
2045 old_client_rect.top - data->client_rect.top == y_offset &&
2046 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2047 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
2049 /* A Cocoa window's bits are moved automatically */
2050 if (!window && (x_offset != 0 || y_offset != 0))
2052 release_win_data(data);
2053 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2054 &old_client_rect, client_rect, window_rect);
2055 if (!(data = get_win_data(hwnd))) return;
2058 else
2060 release_win_data(data);
2061 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2062 &old_client_rect, client_rect, window_rect);
2063 if (!(data = get_win_data(hwnd))) return;
2067 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2069 if (!data->cocoa_window && !data->cocoa_view) goto done;
2071 if (data->on_screen)
2073 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2074 hide_window(data);
2077 /* check if we are currently processing an event relevant to this window */
2078 if (!thread_data || !thread_data->current_event ||
2079 !data->cocoa_window || thread_data->current_event->window != data->cocoa_window ||
2080 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
2081 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
2083 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2084 if (data->cocoa_window)
2085 set_cocoa_window_properties(data);
2088 if (new_style & WS_VISIBLE)
2090 if (data->cocoa_window)
2092 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2093 set_cocoa_window_properties(data);
2095 /* layered windows are not shown until their attributes are set */
2096 if (!data->on_screen &&
2097 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2098 show_window(data);
2100 else if (!data->on_screen)
2101 show_window(data);
2104 done:
2105 release_win_data(data);
2109 /***********************************************************************
2110 * macdrv_window_close_requested
2112 * Handler for WINDOW_CLOSE_REQUESTED events.
2114 void macdrv_window_close_requested(HWND hwnd)
2116 HMENU sysmenu;
2118 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2120 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2121 return;
2124 sysmenu = GetSystemMenu(hwnd, FALSE);
2125 if (sysmenu)
2127 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2128 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2130 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2131 return;
2135 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2139 /***********************************************************************
2140 * macdrv_window_frame_changed
2142 * Handler for WINDOW_FRAME_CHANGED events.
2144 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2146 struct macdrv_win_data *data;
2147 RECT rect;
2148 HWND parent;
2149 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2150 int width, height;
2151 BOOL being_dragged;
2153 if (!hwnd) return;
2154 if (!(data = get_win_data(hwnd))) return;
2155 if (!data->on_screen || data->minimized)
2157 release_win_data(data);
2158 return;
2161 /* Get geometry */
2163 parent = GetAncestor(hwnd, GA_PARENT);
2165 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2166 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2167 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2169 rect = rect_from_cgrect(event->window_frame_changed.frame);
2170 macdrv_mac_to_window_rect(data, &rect);
2171 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2173 width = rect.right - rect.left;
2174 height = rect.bottom - rect.top;
2176 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2177 flags |= SWP_NOMOVE;
2178 else
2179 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2180 data->window_rect.top, rect.left, rect.top);
2182 if ((data->window_rect.right - data->window_rect.left == width &&
2183 data->window_rect.bottom - data->window_rect.top == height) ||
2184 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2185 flags |= SWP_NOSIZE;
2186 else
2187 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2188 data->window_rect.bottom - data->window_rect.top, width, height);
2190 being_dragged = data->being_dragged;
2191 release_win_data(data);
2193 if (event->window_frame_changed.fullscreen)
2194 flags |= SWP_NOSENDCHANGING;
2195 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2197 if (!event->window_frame_changed.in_resize && !being_dragged)
2198 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2199 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2200 if (!event->window_frame_changed.in_resize && !being_dragged)
2201 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2206 /***********************************************************************
2207 * macdrv_window_got_focus
2209 * Handler for WINDOW_GOT_FOCUS events.
2211 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2213 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2215 if (!hwnd) return;
2217 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2218 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2219 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2221 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2223 /* simulate a mouse click on the caption to find out
2224 * whether the window wants to be activated */
2225 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2226 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2227 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2228 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2230 TRACE("setting foreground window to %p\n", hwnd);
2231 SetForegroundWindow(hwnd);
2232 return;
2236 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2237 macdrv_window_rejected_focus(event);
2241 /***********************************************************************
2242 * macdrv_window_lost_focus
2244 * Handler for WINDOW_LOST_FOCUS events.
2246 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2248 if (!hwnd) return;
2250 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2252 if (hwnd == GetForegroundWindow())
2254 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2255 if (hwnd == GetForegroundWindow())
2256 SetForegroundWindow(GetDesktopWindow());
2261 /***********************************************************************
2262 * macdrv_app_deactivated
2264 * Handler for APP_DEACTIVATED events.
2266 void macdrv_app_deactivated(void)
2268 if (GetActiveWindow() == GetForegroundWindow())
2270 TRACE("setting fg to desktop\n");
2271 SetForegroundWindow(GetDesktopWindow());
2276 /***********************************************************************
2277 * macdrv_window_maximize_requested
2279 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2281 void macdrv_window_maximize_requested(HWND hwnd)
2283 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2287 /***********************************************************************
2288 * macdrv_window_minimize_requested
2290 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2292 void macdrv_window_minimize_requested(HWND hwnd)
2294 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2298 /***********************************************************************
2299 * macdrv_window_did_unminimize
2301 * Handler for WINDOW_DID_UNMINIMIZE events.
2303 void macdrv_window_did_unminimize(HWND hwnd)
2305 struct macdrv_win_data *data;
2306 DWORD style;
2308 TRACE("win %p\n", hwnd);
2310 if (!(data = get_win_data(hwnd))) return;
2311 if (!data->minimized) goto done;
2313 style = GetWindowLongW(hwnd, GWL_STYLE);
2315 data->minimized = FALSE;
2316 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2318 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2319 release_win_data(data);
2320 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2321 return;
2324 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2326 done:
2327 release_win_data(data);
2331 /***********************************************************************
2332 * macdrv_window_brought_forward
2334 * Handler for WINDOW_BROUGHT_FORWARD events.
2336 void macdrv_window_brought_forward(HWND hwnd)
2338 TRACE("win %p\n", hwnd);
2339 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2343 /***********************************************************************
2344 * macdrv_window_resize_ended
2346 * Handler for WINDOW_RESIZE_ENDED events.
2348 void macdrv_window_resize_ended(HWND hwnd)
2350 TRACE("hwnd %p\n", hwnd);
2351 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2355 /***********************************************************************
2356 * macdrv_window_restore_requested
2358 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2359 * for restoring from maximized, not from minimized.
2361 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2363 if (event->window_restore_requested.keep_frame && hwnd)
2365 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2366 struct macdrv_win_data *data;
2368 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2370 RECT rect;
2371 HWND parent = GetAncestor(hwnd, GA_PARENT);
2373 rect = rect_from_cgrect(event->window_restore_requested.frame);
2374 macdrv_mac_to_window_rect(data, &rect);
2375 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2377 release_win_data(data);
2379 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2383 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2387 /***********************************************************************
2388 * macdrv_window_drag_begin
2390 * Handler for WINDOW_DRAG_BEGIN events.
2392 void macdrv_window_drag_begin(HWND hwnd)
2394 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2395 struct macdrv_win_data *data;
2396 MSG msg;
2398 TRACE("win %p\n", hwnd);
2400 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2401 if (!(style & WS_VISIBLE)) return;
2403 if (!(data = get_win_data(hwnd))) return;
2404 if (data->being_dragged) goto done;
2406 data->being_dragged = TRUE;
2407 release_win_data(data);
2409 ClipCursor(NULL);
2410 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2411 ReleaseCapture();
2413 while (GetMessageW(&msg, 0, 0, 0))
2415 if (msg.message == WM_EXITSIZEMOVE)
2417 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2418 break;
2421 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2422 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2424 TranslateMessage(&msg);
2425 DispatchMessageW(&msg);
2429 TRACE("done\n");
2431 if ((data = get_win_data(hwnd)))
2432 data->being_dragged = FALSE;
2434 done:
2435 release_win_data(data);
2439 /***********************************************************************
2440 * macdrv_window_drag_end
2442 * Handler for WINDOW_DRAG_END events.
2444 void macdrv_window_drag_end(HWND hwnd)
2446 struct macdrv_win_data *data;
2447 BOOL being_dragged;
2449 TRACE("win %p\n", hwnd);
2451 if (!(data = get_win_data(hwnd))) return;
2452 being_dragged = data->being_dragged;
2453 release_win_data(data);
2455 if (being_dragged)
2457 /* Post this rather than sending it, so that the message loop in
2458 macdrv_window_drag_begin() will see it. */
2459 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2464 /***********************************************************************
2465 * macdrv_reassert_window_position
2467 * Handler for REASSERT_WINDOW_POSITION events.
2469 void macdrv_reassert_window_position(HWND hwnd)
2471 struct macdrv_win_data *data = get_win_data(hwnd);
2472 if (data)
2474 if (data->cocoa_window && data->on_screen)
2475 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2476 release_win_data(data);
2481 struct quit_info {
2482 HWND *wins;
2483 UINT capacity;
2484 UINT count;
2485 UINT done;
2486 DWORD flags;
2487 BOOL result;
2488 BOOL replied;
2492 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2494 struct quit_info *qi = (struct quit_info*)lp;
2495 DWORD pid;
2497 GetWindowThreadProcessId(hwnd, &pid);
2498 if (pid == GetCurrentProcessId())
2500 if (qi->count >= qi->capacity)
2502 UINT new_cap = qi->capacity * 2;
2503 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2504 new_cap * sizeof(*qi->wins));
2505 if (!new_wins) return FALSE;
2506 qi->wins = new_wins;
2507 qi->capacity = new_cap;
2510 qi->wins[qi->count++] = hwnd;
2513 return TRUE;
2517 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2519 struct quit_info *qi = (struct quit_info*)data;
2521 qi->done++;
2523 if (msg == WM_QUERYENDSESSION)
2525 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2526 hwnd, qi->done, qi->count);
2528 if (!result && !IsWindow(hwnd))
2530 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2531 result = TRUE;
2534 if (!result && qi->result)
2536 qi->result = FALSE;
2538 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2539 ultimate reply. Might as well tell Cocoa now. */
2540 if (!qi->replied)
2542 qi->replied = TRUE;
2543 TRACE("giving quit reply %d\n", qi->result);
2544 macdrv_quit_reply(qi->result);
2548 if (qi->done >= qi->count)
2550 UINT i;
2552 qi->done = 0;
2553 for (i = 0; i < qi->count; i++)
2555 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2556 qi->result, qi->flags);
2557 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2558 quit_callback, (ULONG_PTR)qi))
2560 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2561 qi->wins[i], GetLastError());
2562 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2567 else /* WM_ENDSESSION */
2569 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2571 if (qi->done >= qi->count)
2573 if (!qi->replied)
2575 TRACE("giving quit reply %d\n", qi->result);
2576 macdrv_quit_reply(qi->result);
2579 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2580 if (qi->result)
2581 TerminateProcess(GetCurrentProcess(), 0);
2583 HeapFree(GetProcessHeap(), 0, qi->wins);
2584 HeapFree(GetProcessHeap(), 0, qi);
2590 /***********************************************************************
2591 * macdrv_app_quit_requested
2593 * Handler for APP_QUIT_REQUESTED events.
2595 void macdrv_app_quit_requested(const macdrv_event *event)
2597 struct quit_info *qi;
2598 UINT i;
2600 TRACE("reason %d\n", event->app_quit_requested.reason);
2602 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2603 if (!qi)
2604 goto fail;
2606 qi->capacity = 32;
2607 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2608 qi->count = qi->done = 0;
2610 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2611 goto fail;
2613 switch (event->app_quit_requested.reason)
2615 case QUIT_REASON_LOGOUT:
2616 default:
2617 qi->flags = ENDSESSION_LOGOFF;
2618 break;
2619 case QUIT_REASON_RESTART:
2620 case QUIT_REASON_SHUTDOWN:
2621 qi->flags = 0;
2622 break;
2625 qi->result = TRUE;
2626 qi->replied = FALSE;
2628 for (i = 0; i < qi->count; i++)
2630 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2631 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2632 quit_callback, (ULONG_PTR)qi))
2634 DWORD error = GetLastError();
2635 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2636 if (invalid)
2637 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2638 qi->wins[i]);
2639 else
2640 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2641 qi->wins[i], error);
2642 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2646 /* quit_callback() will clean up qi */
2647 return;
2649 fail:
2650 WARN("failed to allocate window list\n");
2651 if (qi)
2653 HeapFree(GetProcessHeap(), 0, qi->wins);
2654 HeapFree(GetProcessHeap(), 0, qi);
2656 macdrv_quit_reply(FALSE);
2660 /***********************************************************************
2661 * query_resize_size
2663 * Handler for QUERY_RESIZE_SIZE query.
2665 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2667 struct macdrv_win_data *data = get_win_data(hwnd);
2668 RECT rect = rect_from_cgrect(query->resize_size.rect);
2669 int corner;
2670 BOOL ret = FALSE;
2672 if (!data) return FALSE;
2674 macdrv_mac_to_window_rect(data, &rect);
2676 if (query->resize_size.from_left)
2678 if (query->resize_size.from_top)
2679 corner = WMSZ_TOPLEFT;
2680 else
2681 corner = WMSZ_BOTTOMLEFT;
2683 else if (query->resize_size.from_top)
2684 corner = WMSZ_TOPRIGHT;
2685 else
2686 corner = WMSZ_BOTTOMRIGHT;
2688 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2690 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2691 query->resize_size.rect = cgrect_from_rect(rect);
2692 ret = TRUE;
2695 release_win_data(data);
2696 return ret;
2700 /***********************************************************************
2701 * query_resize_start
2703 * Handler for QUERY_RESIZE_START query.
2705 BOOL query_resize_start(HWND hwnd)
2707 TRACE("hwnd %p\n", hwnd);
2709 sync_window_min_max_info(hwnd);
2710 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2712 return TRUE;
2716 /***********************************************************************
2717 * query_min_max_info
2719 * Handler for QUERY_MIN_MAX_INFO query.
2721 BOOL query_min_max_info(HWND hwnd)
2723 TRACE("hwnd %p\n", hwnd);
2724 sync_window_min_max_info(hwnd);
2725 return TRUE;