propsys: Forward corresponding methods to exports.
[wine.git] / dlls / winemac.drv / window.c
blobe61a5172c025d3a605c0c3a32a7391b318f52402
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 (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
76 else if (style & WS_THICKFRAME)
78 wf->shadow = TRUE;
79 if (!data->shaped) wf->resizable = 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 * set_cocoa_window_properties
300 * Set the window properties for a Cocoa window based on its Windows
301 * properties.
303 static void set_cocoa_window_properties(struct macdrv_win_data *data)
305 DWORD style, ex_style;
306 HWND owner;
307 macdrv_window owner_win;
308 struct macdrv_window_features wf;
309 struct macdrv_window_state state;
311 style = GetWindowLongW(data->hwnd, GWL_STYLE);
312 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
314 owner = GetWindow(data->hwnd, GW_OWNER);
315 owner_win = macdrv_get_cocoa_window(owner, TRUE);
316 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
318 get_cocoa_window_features(data, style, ex_style, &wf);
319 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
321 get_cocoa_window_state(data, style, ex_style, &state);
322 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
323 if (state.minimized_valid)
324 data->minimized = state.minimized;
328 /***********************************************************************
329 * sync_window_region
331 * Update the window region.
333 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
335 HRGN hrgn = win_region;
336 RGNDATA *region_data;
337 const CGRect* rects;
338 int count;
340 if (!data->cocoa_window) return;
341 data->shaped = FALSE;
343 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
345 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
346 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
347 return;
350 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
352 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
353 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
355 DeleteObject(hrgn);
356 hrgn = 0;
360 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
361 MirrorRgn(data->hwnd, hrgn);
362 if (hrgn)
364 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
365 data->window_rect.top - data->whole_rect.top);
367 region_data = get_region_data(hrgn, 0);
368 if (region_data)
370 rects = (CGRect*)region_data->Buffer;
371 count = region_data->rdh.nCount;
372 /* Special case optimization. If the region entirely encloses the Cocoa
373 window, it's the same as there being no region. It's potentially
374 hard/slow to test this for arbitrary regions, so we just check for
375 very simple regions. */
376 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
378 TRACE("optimizing for simple region that contains Cocoa content rect\n");
379 rects = NULL;
380 count = 0;
383 else
385 rects = NULL;
386 count = 0;
389 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
390 macdrv_set_window_shape(data->cocoa_window, rects, count);
392 HeapFree(GetProcessHeap(), 0, region_data);
393 data->shaped = (region_data != NULL);
395 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
399 /***********************************************************************
400 * add_bounds_rect
402 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
404 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
405 bounds->left = min(bounds->left, rect->left);
406 bounds->top = min(bounds->top, rect->top);
407 bounds->right = max(bounds->right, rect->right);
408 bounds->bottom = max(bounds->bottom, rect->bottom);
412 /***********************************************************************
413 * sync_window_opacity
415 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
416 BOOL per_pixel_alpha, DWORD flags)
418 CGFloat opacity = 1.0;
419 BOOL needs_flush = FALSE;
421 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
423 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
424 macdrv_set_window_alpha(data->cocoa_window, opacity);
426 if (flags & LWA_COLORKEY)
428 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
429 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
430 key = RGB(0, 0, 0);
432 else
433 key = CLR_INVALID;
435 if (data->color_key != key)
437 if (key == CLR_INVALID)
439 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
440 macdrv_clear_window_color_key(data->cocoa_window);
442 else
444 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
445 GetRValue(key), GetGValue(key), GetBValue(key));
446 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
449 data->color_key = key;
450 needs_flush = TRUE;
453 if (!data->per_pixel_alpha != !per_pixel_alpha)
455 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
456 data->per_pixel_alpha = per_pixel_alpha;
457 needs_flush = TRUE;
460 if (needs_flush && data->surface)
462 RECT *bounds;
463 RECT rect;
465 rect = data->whole_rect;
466 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
467 data->surface->funcs->lock(data->surface);
468 bounds = data->surface->funcs->get_bounds(data->surface);
469 add_bounds_rect(bounds, &rect);
470 data->surface->funcs->unlock(data->surface);
475 /***********************************************************************
476 * sync_window_min_max_info
478 static void sync_window_min_max_info(HWND hwnd)
480 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
481 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
482 RECT win_rect, primary_monitor_rect;
483 MINMAXINFO minmax;
484 LONG adjustedStyle;
485 INT xinc, yinc;
486 WINDOWPLACEMENT wpl;
487 HMONITOR monitor;
488 struct macdrv_win_data *data;
490 TRACE("win %p\n", hwnd);
492 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
494 GetWindowRect(hwnd, &win_rect);
495 minmax.ptReserved.x = win_rect.left;
496 minmax.ptReserved.y = win_rect.top;
498 if ((style & WS_CAPTION) == WS_CAPTION)
499 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
500 else
501 adjustedStyle = style;
503 primary_monitor_rect.left = primary_monitor_rect.top = 0;
504 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
505 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
506 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
508 xinc = -primary_monitor_rect.left;
509 yinc = -primary_monitor_rect.top;
511 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
512 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
513 minmax.ptMaxPosition.x = -xinc;
514 minmax.ptMaxPosition.y = -yinc;
515 if (style & (WS_DLGFRAME | WS_BORDER))
517 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
518 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
520 else
522 minmax.ptMinTrackSize.x = 2 * xinc;
523 minmax.ptMinTrackSize.y = 2 * yinc;
525 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
526 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
528 wpl.length = sizeof(wpl);
529 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
531 minmax.ptMaxPosition = wpl.ptMaxPosition;
533 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
534 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
535 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
538 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
539 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
541 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
543 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
544 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
546 /* if the app didn't change the values, adapt them for the window's monitor */
547 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
549 MONITORINFO mon_info;
550 RECT monitor_rect;
552 mon_info.cbSize = sizeof(mon_info);
553 GetMonitorInfoW(monitor, &mon_info);
555 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
556 monitor_rect = mon_info.rcWork;
557 else
558 monitor_rect = mon_info.rcMonitor;
560 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
561 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
563 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
564 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
566 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
568 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
569 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
573 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
574 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
576 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
577 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
579 if ((data = get_win_data(hwnd)) && data->cocoa_window)
581 RECT min_rect, max_rect;
582 CGSize min_size, max_size;
584 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
585 macdrv_window_to_mac_rect(data, style, &min_rect);
586 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
588 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
589 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
590 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
591 else
593 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
594 macdrv_window_to_mac_rect(data, style, &max_rect);
595 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
598 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
599 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
602 release_win_data(data);
606 /**********************************************************************
607 * create_cocoa_window
609 * Create the whole Mac window for a given window
611 static void create_cocoa_window(struct macdrv_win_data *data)
613 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
614 WCHAR text[1024];
615 struct macdrv_window_features wf;
616 CGRect frame;
617 DWORD style, ex_style;
618 HRGN win_rgn;
619 COLORREF key;
620 BYTE alpha;
621 DWORD layered_flags;
623 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
624 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
626 DeleteObject(win_rgn);
627 win_rgn = 0;
629 data->shaped = (win_rgn != 0);
631 style = GetWindowLongW(data->hwnd, GWL_STYLE);
632 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
634 data->whole_rect = data->window_rect;
635 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
637 get_cocoa_window_features(data, style, ex_style, &wf);
639 frame = cgrect_from_rect(data->whole_rect);
640 constrain_window_frame(&frame);
641 if (frame.size.width < 1 || frame.size.height < 1)
642 frame.size.width = frame.size.height = 1;
644 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
645 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
647 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
648 if (!data->cocoa_window) goto done;
650 set_cocoa_window_properties(data);
652 /* set the window text */
653 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
654 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
656 /* set the window region */
657 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
659 /* set the window opacity */
660 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
661 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
663 done:
664 if (win_rgn) DeleteObject(win_rgn);
668 /**********************************************************************
669 * destroy_cocoa_window
671 * Destroy the whole Mac window for a given window.
673 static void destroy_cocoa_window(struct macdrv_win_data *data)
675 if (!data->cocoa_window) return;
677 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
679 macdrv_destroy_cocoa_window(data->cocoa_window);
680 data->cocoa_window = 0;
681 data->on_screen = FALSE;
682 data->color_key = CLR_INVALID;
683 if (data->surface) window_surface_release(data->surface);
684 data->surface = NULL;
685 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
686 data->unminimized_surface = NULL;
690 /***********************************************************************
691 * macdrv_create_win_data
693 * Create a Mac data window structure for an existing window.
695 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
696 const RECT *client_rect)
698 struct macdrv_win_data *data;
699 HWND parent;
701 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
703 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
705 macdrv_init_thread_data();
706 return NULL;
709 /* don't create win data for HWND_MESSAGE windows */
710 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
712 if (!(data = alloc_win_data(hwnd))) return NULL;
714 data->whole_rect = data->window_rect = *window_rect;
715 data->client_rect = *client_rect;
717 if (parent == GetDesktopWindow())
719 create_cocoa_window(data);
720 TRACE("win %p/%p window %s whole %s client %s\n",
721 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
722 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
725 return data;
729 /***********************************************************************
730 * show_window
732 static void show_window(struct macdrv_win_data *data)
734 HWND prev = NULL;
735 HWND next = NULL;
736 macdrv_window prev_window = NULL;
737 macdrv_window next_window = NULL;
738 BOOL activate = FALSE;
739 HWND hwndFocus;
741 /* find window that this one must be after */
742 prev = GetWindow(data->hwnd, GW_HWNDPREV);
743 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
744 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
745 prev = GetWindow(prev, GW_HWNDPREV);
746 if (!prev_window)
748 /* find window that this one must be before */
749 next = GetWindow(data->hwnd, GW_HWNDNEXT);
750 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
751 (next_window = macdrv_get_cocoa_window(next, TRUE))))
752 next = GetWindow(next, GW_HWNDNEXT);
755 TRACE("win %p/%p below %p/%p above %p/%p\n",
756 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
758 if (!prev_window)
759 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
760 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
761 data->on_screen = TRUE;
763 hwndFocus = GetFocus();
764 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
765 macdrv_SetFocus(hwndFocus);
766 if (activate)
767 activate_on_focus_time = 0;
771 /***********************************************************************
772 * hide_window
774 static void hide_window(struct macdrv_win_data *data)
776 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
778 macdrv_hide_cocoa_window(data->cocoa_window);
779 data->on_screen = FALSE;
783 /***********************************************************************
784 * get_region_data
786 * Calls GetRegionData on the given region and converts the rectangle
787 * array to CGRect format. The returned buffer must be freed by
788 * caller using HeapFree(GetProcessHeap(),...).
789 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
791 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
793 RGNDATA *data;
794 DWORD size;
795 int i;
796 RECT *rect;
797 CGRect *cgrect;
799 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
800 if (sizeof(CGRect) > sizeof(RECT))
802 /* add extra size for CGRect array */
803 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
804 size += count * (sizeof(CGRect) - sizeof(RECT));
806 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
807 if (!GetRegionData(hrgn, size, data))
809 HeapFree(GetProcessHeap(), 0, data);
810 return NULL;
813 rect = (RECT *)data->Buffer;
814 cgrect = (CGRect *)data->Buffer;
815 if (hdc_lptodp) /* map to device coordinates */
817 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
818 for (i = 0; i < data->rdh.nCount; i++)
820 if (rect[i].right < rect[i].left)
822 INT tmp = rect[i].right;
823 rect[i].right = rect[i].left;
824 rect[i].left = tmp;
826 if (rect[i].bottom < rect[i].top)
828 INT tmp = rect[i].bottom;
829 rect[i].bottom = rect[i].top;
830 rect[i].top = tmp;
835 if (sizeof(CGRect) > sizeof(RECT))
837 /* need to start from the end */
838 for (i = data->rdh.nCount-1; i >= 0; i--)
839 cgrect[i] = cgrect_from_rect(rect[i]);
841 else
843 for (i = 0; i < data->rdh.nCount; i++)
844 cgrect[i] = cgrect_from_rect(rect[i]);
846 return data;
850 /***********************************************************************
851 * sync_window_position
853 * Synchronize the Mac window position with the Windows one
855 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
856 const RECT *old_whole_rect)
858 CGRect frame;
860 if (data->minimized) return;
862 frame = cgrect_from_rect(data->whole_rect);
863 constrain_window_frame(&frame);
864 if (frame.size.width < 1 || frame.size.height < 1)
865 frame.size.width = frame.size.height = 1;
867 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
868 if (old_window_rect && old_whole_rect &&
869 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
870 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
871 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
872 sync_window_region(data, (HRGN)1);
874 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd, data->cocoa_window,
875 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
877 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
878 show_window(data);
882 /***********************************************************************
883 * move_window_bits
885 * Move the window bits when a window is moved.
887 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
888 const RECT *old_client_rect, const RECT *new_client_rect,
889 const RECT *new_window_rect)
891 RECT src_rect = *old_rect;
892 RECT dst_rect = *new_rect;
893 HDC hdc_src, hdc_dst;
894 HRGN rgn;
895 HWND parent = 0;
897 if (!window)
899 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
900 parent = GetAncestor(hwnd, GA_PARENT);
901 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
902 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
904 else
906 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
907 /* make src rect relative to the old position of the window */
908 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
909 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
910 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
913 rgn = CreateRectRgnIndirect(&dst_rect);
914 SelectClipRgn(hdc_dst, rgn);
915 DeleteObject(rgn);
916 ExcludeUpdateRgn(hdc_dst, hwnd);
918 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
919 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
920 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
921 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
922 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
924 ReleaseDC(hwnd, hdc_dst);
925 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
929 /**********************************************************************
930 * activate_on_following_focus
932 void activate_on_following_focus(void)
934 activate_on_focus_time = GetTickCount();
935 if (!activate_on_focus_time) activate_on_focus_time = 1;
939 /***********************************************************************
940 * set_app_icon
942 static void set_app_icon(void)
944 CFArrayRef images = create_app_icon_images();
945 if (images)
947 macdrv_set_application_icon(images);
948 CFRelease(images);
953 /**********************************************************************
954 * set_capture_window_for_move
956 static BOOL set_capture_window_for_move(HWND hwnd)
958 HWND previous = 0;
959 BOOL ret;
961 SERVER_START_REQ(set_capture_window)
963 req->handle = wine_server_user_handle(hwnd);
964 req->flags = CAPTURE_MOVESIZE;
965 if ((ret = !wine_server_call_err(req)))
967 previous = wine_server_ptr_handle(reply->previous);
968 hwnd = wine_server_ptr_handle(reply->full_handle);
971 SERVER_END_REQ;
973 if (ret)
975 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
977 if (previous && previous != hwnd)
978 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
980 return ret;
984 /***********************************************************************
985 * move_window
987 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
988 * moving top-level windows and enforcing Mac-style constraints like
989 * keeping the top of the window within the work area.
991 static LRESULT move_window(HWND hwnd, WPARAM wparam)
993 MSG msg;
994 RECT origRect, movedRect, desktopRect;
995 LONG hittest = (LONG)(wparam & 0x0f);
996 POINT capturePoint;
997 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
998 BOOL moved = FALSE;
999 DWORD dwPoint = GetMessagePos();
1000 INT captionHeight;
1001 HMONITOR mon = 0;
1002 MONITORINFO info;
1004 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1005 if (hittest && hittest != HTCAPTION) return -1;
1007 capturePoint.x = (short)LOWORD(dwPoint);
1008 capturePoint.y = (short)HIWORD(dwPoint);
1009 ClipCursor(NULL);
1011 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1013 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1014 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1015 captionHeight = -origRect.top;
1016 else
1017 captionHeight = 0;
1019 GetWindowRect(hwnd, &origRect);
1020 movedRect = origRect;
1022 if (!hittest)
1024 /* Move pointer to the center of the caption */
1025 RECT rect = origRect;
1027 /* Note: to be exactly centered we should take the different types
1028 * of border into account, but it shouldn't make more than a few pixels
1029 * of difference so let's not bother with that */
1030 rect.top += GetSystemMetrics(SM_CYBORDER);
1031 if (style & WS_SYSMENU)
1032 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1033 if (style & WS_MINIMIZEBOX)
1034 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1035 if (style & WS_MAXIMIZEBOX)
1036 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1037 capturePoint.x = (rect.right + rect.left) / 2;
1038 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1040 SetCursorPos(capturePoint.x, capturePoint.y);
1041 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1044 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1045 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1046 info.cbSize = sizeof(info);
1047 if (mon && !GetMonitorInfoW(mon, &info))
1048 mon = 0;
1050 /* repaint the window before moving it around */
1051 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1053 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1054 set_capture_window_for_move(hwnd);
1056 while(1)
1058 POINT pt;
1059 int dx = 0, dy = 0;
1060 HMONITOR newmon;
1062 if (!GetMessageW(&msg, 0, 0, 0)) break;
1063 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1065 /* Exit on button-up, Return, or Esc */
1066 if (msg.message == WM_LBUTTONUP ||
1067 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1068 break;
1070 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1072 TranslateMessage(&msg);
1073 DispatchMessageW(&msg);
1074 continue; /* We are not interested in other messages */
1077 pt = msg.pt;
1079 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1081 case VK_UP: pt.y -= 8; break;
1082 case VK_DOWN: pt.y += 8; break;
1083 case VK_LEFT: pt.x -= 8; break;
1084 case VK_RIGHT: pt.x += 8; break;
1087 pt.x = max(pt.x, desktopRect.left);
1088 pt.x = min(pt.x, desktopRect.right - 1);
1089 pt.y = max(pt.y, desktopRect.top);
1090 pt.y = min(pt.y, desktopRect.bottom - 1);
1092 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1094 if (GetMonitorInfoW(newmon, &info))
1095 mon = newmon;
1096 else
1097 mon = 0;
1100 if (mon)
1102 /* wineserver clips the cursor position to the virtual desktop rect but,
1103 if the display configuration is non-rectangular, that could still
1104 leave the logical cursor position outside of any display. The window
1105 could keep moving as you push the cursor against a display edge, even
1106 though the visible cursor doesn't keep moving. The following keeps
1107 the window movement in sync with the visible cursor. */
1108 pt.x = max(pt.x, info.rcMonitor.left);
1109 pt.x = min(pt.x, info.rcMonitor.right - 1);
1110 pt.y = max(pt.y, info.rcMonitor.top);
1111 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1113 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1114 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1115 we want to enforce these constraints:
1116 movedRect.left + dx < info.rcWork.right
1117 movedRect.right + dx > info.rcWork.left
1118 movedRect.top + captionHeight + dy < info.rcWork.bottom
1119 movedRect.bottom + dy > info.rcWork.top
1120 movedRect.top + dy >= info.rcWork.top
1121 The first four keep at least one edge barely in the work area.
1122 The last keeps the top (i.e. the title bar) in the work area.
1123 The fourth is redundant with the last, so can be ignored.
1125 Substituting for dx and dy and rearranging gives us...
1127 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1128 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1129 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1130 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1133 dx = pt.x - capturePoint.x;
1134 dy = pt.y - capturePoint.y;
1136 if (dx || dy)
1138 moved = TRUE;
1140 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1141 else
1143 OffsetRect(&movedRect, dx, dy);
1144 capturePoint = pt;
1146 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1147 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1148 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1153 set_capture_window_for_move(0);
1155 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1156 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1158 /* if the move is canceled, restore the previous position */
1159 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1161 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1162 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1165 return 0;
1169 /***********************************************************************
1170 * perform_window_command
1172 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1174 DWORD style;
1176 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1177 hwnd, style_any, style_none, command, hittest);
1179 style = GetWindowLongW(hwnd, GWL_STYLE);
1180 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1182 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1183 return;
1186 if (GetActiveWindow() != hwnd)
1188 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1189 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1190 switch (ma)
1192 case MA_NOACTIVATEANDEAT:
1193 case MA_ACTIVATEANDEAT:
1194 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1195 return;
1196 case MA_NOACTIVATE:
1197 break;
1198 case MA_ACTIVATE:
1199 case 0:
1200 SetActiveWindow(hwnd);
1201 break;
1202 default:
1203 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1204 break;
1208 TRACE("changing win %p\n", hwnd);
1209 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1213 /**********************************************************************
1214 * CreateDesktopWindow (MACDRV.@)
1216 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1218 unsigned int width, height;
1220 TRACE("%p\n", hwnd);
1222 /* retrieve the real size of the desktop */
1223 SERVER_START_REQ(get_window_rectangles)
1225 req->handle = wine_server_user_handle(hwnd);
1226 req->relative = COORDS_CLIENT;
1227 wine_server_call(req);
1228 width = reply->window.right;
1229 height = reply->window.bottom;
1231 SERVER_END_REQ;
1233 if (!width && !height) /* not initialized yet */
1235 CGRect rect = macdrv_get_desktop_rect();
1237 SERVER_START_REQ(set_window_pos)
1239 req->handle = wine_server_user_handle(hwnd);
1240 req->previous = 0;
1241 req->swp_flags = SWP_NOZORDER;
1242 req->window.left = CGRectGetMinX(rect);
1243 req->window.top = CGRectGetMinY(rect);
1244 req->window.right = CGRectGetMaxX(rect);
1245 req->window.bottom = CGRectGetMaxY(rect);
1246 req->client = req->window;
1247 wine_server_call(req);
1249 SERVER_END_REQ;
1252 set_app_icon();
1253 return TRUE;
1257 /**********************************************************************
1258 * CreateWindow (MACDRV.@)
1260 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1262 return TRUE;
1266 /***********************************************************************
1267 * DestroyWindow (MACDRV.@)
1269 void CDECL macdrv_DestroyWindow(HWND hwnd)
1271 struct macdrv_win_data *data;
1273 TRACE("%p\n", hwnd);
1275 if (!(data = get_win_data(hwnd))) return;
1277 if (data->gl_view) macdrv_dispose_view(data->gl_view);
1278 destroy_cocoa_window(data);
1280 CFDictionaryRemoveValue(win_datas, hwnd);
1281 release_win_data(data);
1282 HeapFree(GetProcessHeap(), 0, data);
1286 /*****************************************************************
1287 * SetFocus (MACDRV.@)
1289 * Set the Mac focus.
1291 void CDECL macdrv_SetFocus(HWND hwnd)
1293 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1294 struct macdrv_win_data *data;
1296 TRACE("%p\n", hwnd);
1298 if (!thread_data) return;
1299 thread_data->dead_key_state = 0;
1301 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
1302 if (!(data = get_win_data(hwnd))) return;
1304 if (data->cocoa_window && data->on_screen)
1306 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
1307 /* Set Mac focus */
1308 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
1309 activate_on_focus_time = 0;
1312 release_win_data(data);
1316 /***********************************************************************
1317 * SetLayeredWindowAttributes (MACDRV.@)
1319 * Set transparency attributes for a layered window.
1321 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1323 struct macdrv_win_data *data = get_win_data(hwnd);
1325 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1327 if (data)
1329 data->layered = TRUE;
1330 if (data->cocoa_window)
1332 sync_window_opacity(data, key, alpha, FALSE, flags);
1333 /* since layered attributes are now set, can now show the window */
1334 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1335 show_window(data);
1337 release_win_data(data);
1339 else
1340 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1344 /*****************************************************************
1345 * SetParent (MACDRV.@)
1347 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1349 struct macdrv_win_data *data;
1351 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1353 if (parent == old_parent) return;
1354 if (!(data = get_win_data(hwnd))) return;
1356 if (parent != GetDesktopWindow()) /* a child window */
1358 if (old_parent == GetDesktopWindow())
1360 /* destroy the old Mac window */
1361 destroy_cocoa_window(data);
1364 else /* new top level window */
1365 create_cocoa_window(data);
1366 release_win_data(data);
1368 set_gl_view_parent(hwnd, parent);
1372 /***********************************************************************
1373 * SetWindowRgn (MACDRV.@)
1375 * Assign specified region to window (for non-rectangular windows)
1377 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1379 struct macdrv_win_data *data;
1381 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1383 if ((data = get_win_data(hwnd)))
1385 sync_window_region(data, hrgn);
1386 release_win_data(data);
1388 else
1390 DWORD procid;
1392 GetWindowThreadProcessId(hwnd, &procid);
1393 if (procid != GetCurrentProcessId())
1394 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1399 /***********************************************************************
1400 * SetWindowStyle (MACDRV.@)
1402 * Update the state of the Cocoa window to reflect a style change
1404 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1406 struct macdrv_win_data *data;
1408 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1410 if (hwnd == GetDesktopWindow()) return;
1411 if (!(data = get_win_data(hwnd))) return;
1413 if (data->cocoa_window)
1415 DWORD changed = style->styleNew ^ style->styleOld;
1417 set_cocoa_window_properties(data);
1419 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1421 data->layered = FALSE;
1422 data->ulw_layered = FALSE;
1423 sync_window_opacity(data, 0, 0, FALSE, 0);
1424 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1427 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1428 sync_window_region(data, (HRGN)1);
1431 release_win_data(data);
1435 /*****************************************************************
1436 * SetWindowText (MACDRV.@)
1438 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1440 macdrv_window win;
1442 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1444 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1445 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1449 /***********************************************************************
1450 * ShowWindow (MACDRV.@)
1452 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1454 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1455 struct macdrv_win_data *data = get_win_data(hwnd);
1456 CGRect frame;
1458 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1459 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1461 if (!data || !data->cocoa_window) goto done;
1462 if (IsRectEmpty(rect)) goto done;
1463 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1465 if (rect->left != -32000 || rect->top != -32000)
1467 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1468 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1470 goto done;
1472 if (!data->on_screen) goto done;
1474 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1476 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1477 goto done;
1479 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1480 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1481 goto done;
1483 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1484 *rect = rect_from_cgrect(frame);
1485 macdrv_mac_to_window_rect(data, rect);
1486 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1487 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1489 done:
1490 release_win_data(data);
1491 return swp;
1495 /***********************************************************************
1496 * SysCommand (MACDRV.@)
1498 * Perform WM_SYSCOMMAND handling.
1500 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1502 struct macdrv_win_data *data;
1503 LRESULT ret = -1;
1504 WPARAM command = wparam & 0xfff0;
1506 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1508 if (!(data = get_win_data(hwnd))) goto done;
1509 if (!data->cocoa_window || !data->on_screen) goto done;
1511 /* prevent a simple ALT press+release from activating the system menu,
1512 as that can get confusing */
1513 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1514 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1516 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1517 ret = 0;
1520 if (command == SC_MOVE)
1522 release_win_data(data);
1523 return move_window(hwnd, wparam);
1526 done:
1527 release_win_data(data);
1528 return ret;
1532 /***********************************************************************
1533 * UpdateLayeredWindow (MACDRV.@)
1535 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1536 const RECT *window_rect)
1538 struct window_surface *surface;
1539 struct macdrv_win_data *data;
1540 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1541 BYTE alpha;
1542 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1543 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1544 void *src_bits, *dst_bits;
1545 RECT rect;
1546 HDC hdc = 0;
1547 HBITMAP dib;
1548 BOOL ret = FALSE;
1550 if (!(data = get_win_data(hwnd))) return FALSE;
1552 data->layered = TRUE;
1553 data->ulw_layered = TRUE;
1555 rect = *window_rect;
1556 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1558 surface = data->surface;
1559 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1561 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1562 set_window_surface(data->cocoa_window, data->surface);
1563 if (surface) window_surface_release(surface);
1564 surface = data->surface;
1565 if (data->unminimized_surface)
1567 window_surface_release(data->unminimized_surface);
1568 data->unminimized_surface = NULL;
1571 else set_surface_use_alpha(surface, TRUE);
1573 if (surface) window_surface_add_ref(surface);
1574 release_win_data(data);
1576 if (!surface) return FALSE;
1577 if (!info->hdcSrc)
1579 window_surface_release(surface);
1580 return TRUE;
1583 if (info->dwFlags & ULW_ALPHA)
1585 /* Apply SourceConstantAlpha via window alpha, not blend. */
1586 alpha = info->pblend->SourceConstantAlpha;
1587 blend = *info->pblend;
1588 blend.SourceConstantAlpha = 0xff;
1590 else
1591 alpha = 0xff;
1593 dst_bits = surface->funcs->get_info(surface, bmi);
1595 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1596 if (!(hdc = CreateCompatibleDC(0))) goto done;
1598 SelectObject(hdc, dib);
1599 if (info->prcDirty)
1601 IntersectRect(&rect, &rect, info->prcDirty);
1602 surface->funcs->lock(surface);
1603 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1604 surface->funcs->unlock(surface);
1605 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1607 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1608 info->hdcSrc,
1609 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1610 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1611 rect.right - rect.left, rect.bottom - rect.top,
1612 blend)))
1613 goto done;
1615 if ((data = get_win_data(hwnd)))
1617 if (surface == data->surface)
1619 surface->funcs->lock(surface);
1620 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1621 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1622 surface->funcs->unlock(surface);
1623 surface->funcs->flush(surface);
1626 /* The ULW flags are a superset of the LWA flags. */
1627 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1629 release_win_data(data);
1632 done:
1633 window_surface_release(surface);
1634 if (hdc) DeleteDC(hdc);
1635 if (dib) DeleteObject(dib);
1636 return ret;
1640 /**********************************************************************
1641 * WindowMessage (MACDRV.@)
1643 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1645 struct macdrv_win_data *data;
1647 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1649 switch(msg)
1651 case WM_MACDRV_SET_WIN_REGION:
1652 if ((data = get_win_data(hwnd)))
1654 sync_window_region(data, (HRGN)1);
1655 release_win_data(data);
1657 return 0;
1658 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1659 if (hwnd == GetDesktopWindow())
1661 CGRect new_desktop_rect;
1662 RECT current_desktop_rect;
1664 macdrv_reset_device_metrics();
1665 new_desktop_rect = macdrv_get_desktop_rect();
1666 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1667 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1669 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1670 SMTO_ABORTIFHUNG, 2000, NULL);
1671 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1672 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1673 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1674 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1675 SMTO_ABORTIFHUNG, 2000, NULL);
1678 return 0;
1679 case WM_MACDRV_RESET_DEVICE_METRICS:
1680 macdrv_reset_device_metrics();
1681 return 0;
1682 case WM_MACDRV_DISPLAYCHANGE:
1683 if ((data = get_win_data(hwnd)))
1685 if (data->cocoa_window && data->on_screen)
1686 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
1687 release_win_data(data);
1689 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1690 return 0;
1691 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1692 activate_on_following_focus();
1693 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1694 return 0;
1697 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1698 return 0;
1702 static inline RECT get_surface_rect(const RECT *visible_rect)
1704 RECT rect;
1705 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1707 IntersectRect(&rect, visible_rect, &desktop_rect);
1708 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1709 rect.left &= ~127;
1710 rect.top &= ~127;
1711 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1712 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1713 return rect;
1717 /***********************************************************************
1718 * WindowPosChanging (MACDRV.@)
1720 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1721 const RECT *window_rect, const RECT *client_rect,
1722 RECT *visible_rect, struct window_surface **surface)
1724 struct macdrv_win_data *data = get_win_data(hwnd);
1725 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1726 RECT surface_rect;
1728 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1729 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1730 wine_dbgstr_rect(visible_rect), surface);
1732 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1734 *visible_rect = *window_rect;
1735 macdrv_window_to_mac_rect(data, style, visible_rect);
1736 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1737 wine_dbgstr_rect(visible_rect));
1739 /* create the window surface if necessary */
1740 if (!data->cocoa_window) goto done;
1741 if (swp_flags & SWP_HIDEWINDOW) goto done;
1742 if (data->ulw_layered) goto done;
1744 if (*surface) window_surface_release(*surface);
1745 *surface = NULL;
1747 surface_rect = get_surface_rect(visible_rect);
1748 if (data->surface)
1750 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1752 /* existing surface is good enough */
1753 surface_clip_to_visible_rect(data->surface, visible_rect);
1754 window_surface_add_ref(data->surface);
1755 *surface = data->surface;
1756 goto done;
1759 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1761 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1763 done:
1764 release_win_data(data);
1768 /***********************************************************************
1769 * WindowPosChanged (MACDRV.@)
1771 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1772 const RECT *window_rect, const RECT *client_rect,
1773 const RECT *visible_rect, const RECT *valid_rects,
1774 struct window_surface *surface)
1776 struct macdrv_thread_data *thread_data;
1777 struct macdrv_win_data *data;
1778 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1779 RECT old_window_rect, old_whole_rect, old_client_rect;
1781 if (!(data = get_win_data(hwnd))) return;
1783 thread_data = macdrv_thread_data();
1785 old_window_rect = data->window_rect;
1786 old_whole_rect = data->whole_rect;
1787 old_client_rect = data->client_rect;
1788 data->window_rect = *window_rect;
1789 data->whole_rect = *visible_rect;
1790 data->client_rect = *client_rect;
1791 if (!data->ulw_layered)
1793 if (surface) window_surface_add_ref(surface);
1794 if (new_style & WS_MINIMIZE)
1796 if (!data->unminimized_surface && data->surface)
1798 data->unminimized_surface = data->surface;
1799 window_surface_add_ref(data->unminimized_surface);
1802 else
1804 set_window_surface(data->cocoa_window, surface);
1805 if (data->unminimized_surface)
1807 window_surface_release(data->unminimized_surface);
1808 data->unminimized_surface = NULL;
1811 if (data->surface) window_surface_release(data->surface);
1812 data->surface = surface;
1815 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1816 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1817 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1818 new_style, swp_flags, surface);
1820 if (!IsRectEmpty(&valid_rects[0]))
1822 macdrv_window window = data->cocoa_window;
1823 int x_offset = old_whole_rect.left - data->whole_rect.left;
1824 int y_offset = old_whole_rect.top - data->whole_rect.top;
1826 /* if all that happened is that the whole window moved, copy everything */
1827 if (!(swp_flags & SWP_FRAMECHANGED) &&
1828 old_whole_rect.right - data->whole_rect.right == x_offset &&
1829 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1830 old_client_rect.left - data->client_rect.left == x_offset &&
1831 old_client_rect.right - data->client_rect.right == x_offset &&
1832 old_client_rect.top - data->client_rect.top == y_offset &&
1833 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1834 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1836 /* A Cocoa window's bits are moved automatically */
1837 if (!window && (x_offset != 0 || y_offset != 0))
1839 release_win_data(data);
1840 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1841 &old_client_rect, client_rect, window_rect);
1842 if (!(data = get_win_data(hwnd))) return;
1845 else
1847 release_win_data(data);
1848 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1849 &old_client_rect, client_rect, window_rect);
1850 if (!(data = get_win_data(hwnd))) return;
1854 sync_gl_view(data);
1856 if (!data->cocoa_window) goto done;
1858 if (data->on_screen)
1860 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1861 hide_window(data);
1864 /* check if we are currently processing an event relevant to this window */
1865 if (!thread_data || !thread_data->current_event ||
1866 thread_data->current_event->window != data->cocoa_window ||
1867 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1868 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1870 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
1871 set_cocoa_window_properties(data);
1874 if (new_style & WS_VISIBLE)
1876 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1877 set_cocoa_window_properties(data);
1879 /* layered windows are not shown until their attributes are set */
1880 if (!data->on_screen &&
1881 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1882 show_window(data);
1885 done:
1886 release_win_data(data);
1890 /***********************************************************************
1891 * macdrv_window_close_requested
1893 * Handler for WINDOW_CLOSE_REQUESTED events.
1895 void macdrv_window_close_requested(HWND hwnd)
1897 HMENU sysmenu;
1899 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1901 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
1902 return;
1905 sysmenu = GetSystemMenu(hwnd, FALSE);
1906 if (sysmenu)
1908 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
1909 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1911 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
1912 return;
1916 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
1920 /***********************************************************************
1921 * macdrv_window_frame_changed
1923 * Handler for WINDOW_FRAME_CHANGED events.
1925 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
1927 struct macdrv_win_data *data;
1928 RECT rect;
1929 HWND parent;
1930 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1931 int width, height;
1932 BOOL being_dragged;
1934 if (!hwnd) return;
1935 if (!(data = get_win_data(hwnd))) return;
1936 if (!data->on_screen || data->minimized)
1938 release_win_data(data);
1939 return;
1942 /* Get geometry */
1944 parent = GetAncestor(hwnd, GA_PARENT);
1946 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
1947 wine_dbgstr_cgrect(event->window_frame_changed.frame),
1948 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
1950 rect = rect_from_cgrect(event->window_frame_changed.frame);
1951 macdrv_mac_to_window_rect(data, &rect);
1952 MapWindowPoints(0, parent, (POINT *)&rect, 2);
1954 width = rect.right - rect.left;
1955 height = rect.bottom - rect.top;
1957 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1958 flags |= SWP_NOMOVE;
1959 else
1960 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1961 data->window_rect.top, rect.left, rect.top);
1963 if ((data->window_rect.right - data->window_rect.left == width &&
1964 data->window_rect.bottom - data->window_rect.top == height) ||
1965 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
1966 flags |= SWP_NOSIZE;
1967 else
1968 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1969 data->window_rect.bottom - data->window_rect.top, width, height);
1971 being_dragged = data->being_dragged;
1972 release_win_data(data);
1974 if (event->window_frame_changed.fullscreen)
1975 flags |= SWP_NOSENDCHANGING;
1976 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1978 if (!event->window_frame_changed.in_resize && !being_dragged)
1979 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1980 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1981 if (!event->window_frame_changed.in_resize && !being_dragged)
1982 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1987 /***********************************************************************
1988 * macdrv_window_got_focus
1990 * Handler for WINDOW_GOT_FOCUS events.
1992 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1994 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1996 if (!hwnd) return;
1998 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1999 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2000 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2002 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2004 /* simulate a mouse click on the caption to find out
2005 * whether the window wants to be activated */
2006 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2007 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2008 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2009 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2011 TRACE("setting foreground window to %p\n", hwnd);
2012 SetForegroundWindow(hwnd);
2013 return;
2017 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2018 macdrv_window_rejected_focus(event);
2022 /***********************************************************************
2023 * macdrv_window_lost_focus
2025 * Handler for WINDOW_LOST_FOCUS events.
2027 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2029 if (!hwnd) return;
2031 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2033 if (hwnd == GetForegroundWindow())
2035 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2036 if (hwnd == GetForegroundWindow())
2037 SetForegroundWindow(GetDesktopWindow());
2042 /***********************************************************************
2043 * macdrv_app_deactivated
2045 * Handler for APP_DEACTIVATED events.
2047 void macdrv_app_deactivated(void)
2049 if (GetActiveWindow() == GetForegroundWindow())
2051 TRACE("setting fg to desktop\n");
2052 SetForegroundWindow(GetDesktopWindow());
2057 /***********************************************************************
2058 * macdrv_window_maximize_requested
2060 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2062 void macdrv_window_maximize_requested(HWND hwnd)
2064 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2068 /***********************************************************************
2069 * macdrv_window_minimize_requested
2071 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2073 void macdrv_window_minimize_requested(HWND hwnd)
2075 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2079 /***********************************************************************
2080 * macdrv_window_did_unminimize
2082 * Handler for WINDOW_DID_UNMINIMIZE events.
2084 void macdrv_window_did_unminimize(HWND hwnd)
2086 struct macdrv_win_data *data;
2087 DWORD style;
2089 TRACE("win %p\n", hwnd);
2091 if (!(data = get_win_data(hwnd))) return;
2092 if (!data->minimized) goto done;
2094 style = GetWindowLongW(hwnd, GWL_STYLE);
2096 data->minimized = FALSE;
2097 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2099 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2100 release_win_data(data);
2101 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2102 return;
2105 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2107 done:
2108 release_win_data(data);
2112 /***********************************************************************
2113 * macdrv_window_brought_forward
2115 * Handler for WINDOW_BROUGHT_FORWARD events.
2117 void macdrv_window_brought_forward(HWND hwnd)
2119 TRACE("win %p\n", hwnd);
2120 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2124 /***********************************************************************
2125 * macdrv_window_resize_ended
2127 * Handler for WINDOW_RESIZE_ENDED events.
2129 void macdrv_window_resize_ended(HWND hwnd)
2131 TRACE("hwnd %p\n", hwnd);
2132 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2136 /***********************************************************************
2137 * macdrv_window_restore_requested
2139 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2140 * for restoring from maximized, not from minimized.
2142 void macdrv_window_restore_requested(HWND hwnd)
2144 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2148 /***********************************************************************
2149 * macdrv_window_drag_begin
2151 * Handler for WINDOW_DRAG_BEGIN events.
2153 void macdrv_window_drag_begin(HWND hwnd)
2155 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2156 struct macdrv_win_data *data;
2157 MSG msg;
2159 TRACE("win %p\n", hwnd);
2161 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2162 if (!(style & WS_VISIBLE)) return;
2164 if (!(data = get_win_data(hwnd))) return;
2165 if (data->being_dragged) goto done;
2167 data->being_dragged = TRUE;
2168 release_win_data(data);
2170 ClipCursor(NULL);
2171 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2172 ReleaseCapture();
2174 while (GetMessageW(&msg, 0, 0, 0))
2176 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2177 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2179 TranslateMessage(&msg);
2180 DispatchMessageW(&msg);
2183 if (msg.message == WM_EXITSIZEMOVE) break;
2186 TRACE("done\n");
2188 if ((data = get_win_data(hwnd)))
2189 data->being_dragged = FALSE;
2191 done:
2192 release_win_data(data);
2196 /***********************************************************************
2197 * macdrv_window_drag_end
2199 * Handler for WINDOW_DRAG_END events.
2201 void macdrv_window_drag_end(HWND hwnd)
2203 struct macdrv_win_data *data;
2204 BOOL being_dragged;
2206 TRACE("win %p\n", hwnd);
2208 if (!(data = get_win_data(hwnd))) return;
2209 being_dragged = data->being_dragged;
2210 release_win_data(data);
2212 if (being_dragged)
2214 /* Post this rather than sending it, so that the message loop in
2215 macdrv_window_drag_begin() will see it. */
2216 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2221 struct quit_info {
2222 HWND *wins;
2223 UINT capacity;
2224 UINT count;
2225 UINT done;
2226 DWORD flags;
2227 BOOL result;
2228 BOOL replied;
2232 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2234 struct quit_info *qi = (struct quit_info*)lp;
2235 DWORD pid;
2237 GetWindowThreadProcessId(hwnd, &pid);
2238 if (pid == GetCurrentProcessId())
2240 if (qi->count >= qi->capacity)
2242 UINT new_cap = qi->capacity * 2;
2243 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2244 new_cap * sizeof(*qi->wins));
2245 if (!new_wins) return FALSE;
2246 qi->wins = new_wins;
2247 qi->capacity = new_cap;
2250 qi->wins[qi->count++] = hwnd;
2253 return TRUE;
2257 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2259 struct quit_info *qi = (struct quit_info*)data;
2261 qi->done++;
2263 if (msg == WM_QUERYENDSESSION)
2265 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2266 hwnd, qi->done, qi->count);
2268 if (!result && !IsWindow(hwnd))
2270 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2271 result = TRUE;
2274 if (!result && qi->result)
2276 qi->result = FALSE;
2278 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2279 ultimate reply. Might as well tell Cocoa now. */
2280 if (!qi->replied)
2282 qi->replied = TRUE;
2283 TRACE("giving quit reply %d\n", qi->result);
2284 macdrv_quit_reply(qi->result);
2288 if (qi->done >= qi->count)
2290 UINT i;
2292 qi->done = 0;
2293 for (i = 0; i < qi->count; i++)
2295 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2296 qi->result, qi->flags);
2297 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2298 quit_callback, (ULONG_PTR)qi))
2300 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2301 qi->wins[i], GetLastError());
2302 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2307 else /* WM_ENDSESSION */
2309 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2311 if (qi->done >= qi->count)
2313 if (!qi->replied)
2315 TRACE("giving quit reply %d\n", qi->result);
2316 macdrv_quit_reply(qi->result);
2319 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2320 if (qi->result)
2321 TerminateProcess(GetCurrentProcess(), 0);
2323 HeapFree(GetProcessHeap(), 0, qi->wins);
2324 HeapFree(GetProcessHeap(), 0, qi);
2330 /***********************************************************************
2331 * macdrv_app_quit_requested
2333 * Handler for APP_QUIT_REQUESTED events.
2335 void macdrv_app_quit_requested(const macdrv_event *event)
2337 struct quit_info *qi;
2338 UINT i;
2340 TRACE("reason %d\n", event->app_quit_requested.reason);
2342 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2343 if (!qi)
2344 goto fail;
2346 qi->capacity = 32;
2347 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2348 qi->count = qi->done = 0;
2350 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2351 goto fail;
2353 switch (event->app_quit_requested.reason)
2355 case QUIT_REASON_LOGOUT:
2356 default:
2357 qi->flags = ENDSESSION_LOGOFF;
2358 break;
2359 case QUIT_REASON_RESTART:
2360 case QUIT_REASON_SHUTDOWN:
2361 qi->flags = 0;
2362 break;
2365 qi->result = TRUE;
2366 qi->replied = FALSE;
2368 for (i = 0; i < qi->count; i++)
2370 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2371 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2372 quit_callback, (ULONG_PTR)qi))
2374 DWORD error = GetLastError();
2375 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2376 if (invalid)
2377 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2378 qi->wins[i]);
2379 else
2380 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2381 qi->wins[i], error);
2382 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2386 /* quit_callback() will clean up qi */
2387 return;
2389 fail:
2390 WARN("failed to allocate window list\n");
2391 if (qi)
2393 HeapFree(GetProcessHeap(), 0, qi->wins);
2394 HeapFree(GetProcessHeap(), 0, qi);
2396 macdrv_quit_reply(FALSE);
2400 /***********************************************************************
2401 * query_resize_size
2403 * Handler for QUERY_RESIZE_SIZE query.
2405 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2407 struct macdrv_win_data *data = get_win_data(hwnd);
2408 RECT rect = rect_from_cgrect(query->resize_size.rect);
2409 int corner;
2410 BOOL ret = FALSE;
2412 if (!data) return FALSE;
2414 macdrv_mac_to_window_rect(data, &rect);
2416 if (query->resize_size.from_left)
2418 if (query->resize_size.from_top)
2419 corner = WMSZ_TOPLEFT;
2420 else
2421 corner = WMSZ_BOTTOMLEFT;
2423 else if (query->resize_size.from_top)
2424 corner = WMSZ_TOPRIGHT;
2425 else
2426 corner = WMSZ_BOTTOMRIGHT;
2428 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2430 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2431 query->resize_size.rect = cgrect_from_rect(rect);
2432 ret = TRUE;
2435 release_win_data(data);
2436 return ret;
2440 /***********************************************************************
2441 * query_resize_start
2443 * Handler for QUERY_RESIZE_START query.
2445 BOOL query_resize_start(HWND hwnd)
2447 TRACE("hwnd %p\n", hwnd);
2449 sync_window_min_max_info(hwnd);
2450 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2452 return TRUE;
2456 /***********************************************************************
2457 * query_min_max_info
2459 * Handler for QUERY_MIN_MAX_INFO query.
2461 BOOL query_min_max_info(HWND hwnd)
2463 TRACE("hwnd %p\n", hwnd);
2464 sync_window_min_max_info(hwnd);
2465 return TRUE;