winemac: Ignore window dragging if window is disabled, maximized, minimized, or hidden.
[wine/multimedia.git] / dlls / winemac.drv / window.c
blob259552e41644ab70d83953923e7d63bf8ca9a99b
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 EnterCriticalSection(&win_data_section);
243 if (!win_datas)
244 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
245 CFDictionarySetValue(win_datas, hwnd, data);
247 return data;
251 /***********************************************************************
252 * get_win_data
254 * Lock and return the data structure associated with a window.
256 struct macdrv_win_data *get_win_data(HWND hwnd)
258 struct macdrv_win_data *data;
260 if (!hwnd) return NULL;
261 EnterCriticalSection(&win_data_section);
262 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
263 return data;
264 LeaveCriticalSection(&win_data_section);
265 return NULL;
269 /***********************************************************************
270 * release_win_data
272 * Release the data returned by get_win_data.
274 void release_win_data(struct macdrv_win_data *data)
276 if (data) LeaveCriticalSection(&win_data_section);
280 /***********************************************************************
281 * macdrv_get_cocoa_window
283 * Return the Mac window associated with the full area of a window
285 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
287 struct macdrv_win_data *data = get_win_data(hwnd);
288 macdrv_window ret = NULL;
289 if (data && (data->on_screen || !require_on_screen))
290 ret = data->cocoa_window;
291 release_win_data(data);
292 return ret;
296 /***********************************************************************
297 * set_cocoa_window_properties
299 * Set the window properties for a Cocoa window based on its Windows
300 * properties.
302 static void set_cocoa_window_properties(struct macdrv_win_data *data)
304 DWORD style, ex_style;
305 HWND owner;
306 macdrv_window owner_win;
307 struct macdrv_window_features wf;
308 struct macdrv_window_state state;
310 style = GetWindowLongW(data->hwnd, GWL_STYLE);
311 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
313 owner = GetWindow(data->hwnd, GW_OWNER);
314 owner_win = macdrv_get_cocoa_window(owner, TRUE);
315 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
317 get_cocoa_window_features(data, style, ex_style, &wf);
318 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
320 get_cocoa_window_state(data, style, ex_style, &state);
321 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
322 if (state.minimized_valid)
323 data->minimized = state.minimized;
327 /***********************************************************************
328 * sync_window_region
330 * Update the window region.
332 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
334 HRGN hrgn = win_region;
335 RGNDATA *region_data;
336 const CGRect* rects;
337 int count;
339 if (!data->cocoa_window) return;
340 data->shaped = FALSE;
342 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
344 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
345 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
346 return;
349 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
351 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
352 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
354 DeleteObject(hrgn);
355 hrgn = 0;
359 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
360 MirrorRgn(data->hwnd, hrgn);
361 if (hrgn)
363 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
364 data->window_rect.top - data->whole_rect.top);
366 region_data = get_region_data(hrgn, 0);
367 if (region_data)
369 rects = (CGRect*)region_data->Buffer;
370 count = region_data->rdh.nCount;
371 /* Special case optimization. If the region entirely encloses the Cocoa
372 window, it's the same as there being no region. It's potentially
373 hard/slow to test this for arbitrary regions, so we just check for
374 very simple regions. */
375 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
377 TRACE("optimizing for simple region that contains Cocoa content rect\n");
378 rects = NULL;
379 count = 0;
382 else
384 rects = NULL;
385 count = 0;
388 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
389 macdrv_set_window_shape(data->cocoa_window, rects, count);
391 HeapFree(GetProcessHeap(), 0, region_data);
392 data->shaped = (region_data != NULL);
394 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
398 /***********************************************************************
399 * add_bounds_rect
401 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
403 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
404 bounds->left = min(bounds->left, rect->left);
405 bounds->top = min(bounds->top, rect->top);
406 bounds->right = max(bounds->right, rect->right);
407 bounds->bottom = max(bounds->bottom, rect->bottom);
411 /***********************************************************************
412 * sync_window_opacity
414 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
415 BOOL per_pixel_alpha, DWORD flags)
417 CGFloat opacity = 1.0;
418 BOOL needs_flush = FALSE;
420 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
422 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
423 macdrv_set_window_alpha(data->cocoa_window, opacity);
425 if (flags & LWA_COLORKEY)
427 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
428 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
429 key = RGB(0, 0, 0);
431 else
432 key = CLR_INVALID;
434 if (data->color_key != key)
436 if (key == CLR_INVALID)
438 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
439 macdrv_clear_window_color_key(data->cocoa_window);
441 else
443 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
444 GetRValue(key), GetGValue(key), GetBValue(key));
445 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
448 data->color_key = key;
449 needs_flush = TRUE;
452 if (!data->per_pixel_alpha != !per_pixel_alpha)
454 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
455 data->per_pixel_alpha = per_pixel_alpha;
456 needs_flush = TRUE;
459 if (needs_flush && data->surface)
461 RECT *bounds;
462 RECT rect;
464 rect = data->whole_rect;
465 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
466 data->surface->funcs->lock(data->surface);
467 bounds = data->surface->funcs->get_bounds(data->surface);
468 add_bounds_rect(bounds, &rect);
469 data->surface->funcs->unlock(data->surface);
474 /***********************************************************************
475 * sync_window_min_max_info
477 static void sync_window_min_max_info(HWND hwnd)
479 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
480 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
481 RECT win_rect, primary_monitor_rect;
482 MINMAXINFO minmax;
483 LONG adjustedStyle;
484 INT xinc, yinc;
485 WINDOWPLACEMENT wpl;
486 HMONITOR monitor;
487 struct macdrv_win_data *data;
489 TRACE("win %p\n", hwnd);
491 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
493 GetWindowRect(hwnd, &win_rect);
494 minmax.ptReserved.x = win_rect.left;
495 minmax.ptReserved.y = win_rect.top;
497 if ((style & WS_CAPTION) == WS_CAPTION)
498 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
499 else
500 adjustedStyle = style;
502 primary_monitor_rect.left = primary_monitor_rect.top = 0;
503 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
504 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
505 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
507 xinc = -primary_monitor_rect.left;
508 yinc = -primary_monitor_rect.top;
510 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
511 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
512 minmax.ptMaxPosition.x = -xinc;
513 minmax.ptMaxPosition.y = -yinc;
514 if (style & (WS_DLGFRAME | WS_BORDER))
516 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
517 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
519 else
521 minmax.ptMinTrackSize.x = 2 * xinc;
522 minmax.ptMinTrackSize.y = 2 * yinc;
524 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
525 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
527 wpl.length = sizeof(wpl);
528 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
530 minmax.ptMaxPosition = wpl.ptMaxPosition;
532 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
533 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
534 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
537 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
538 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
540 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
542 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
543 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
545 /* if the app didn't change the values, adapt them for the window's monitor */
546 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
548 MONITORINFO mon_info;
549 RECT monitor_rect;
551 mon_info.cbSize = sizeof(mon_info);
552 GetMonitorInfoW(monitor, &mon_info);
554 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
555 monitor_rect = mon_info.rcWork;
556 else
557 monitor_rect = mon_info.rcMonitor;
559 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
560 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
562 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
563 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
565 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
567 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
568 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
572 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
573 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
575 TRACE("adjusted 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 ((data = get_win_data(hwnd)) && data->cocoa_window)
580 RECT min_rect, max_rect;
581 CGSize min_size, max_size;
583 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
584 macdrv_window_to_mac_rect(data, style, &min_rect);
585 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
587 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
588 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
589 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
590 else
592 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
593 macdrv_window_to_mac_rect(data, style, &max_rect);
594 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
597 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
598 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
601 release_win_data(data);
605 /**********************************************************************
606 * create_cocoa_window
608 * Create the whole Mac window for a given window
610 static void create_cocoa_window(struct macdrv_win_data *data)
612 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
613 WCHAR text[1024];
614 struct macdrv_window_features wf;
615 CGRect frame;
616 DWORD style, ex_style;
617 HRGN win_rgn;
618 COLORREF key;
619 BYTE alpha;
620 DWORD layered_flags;
622 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
623 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
625 DeleteObject(win_rgn);
626 win_rgn = 0;
628 data->shaped = (win_rgn != 0);
630 style = GetWindowLongW(data->hwnd, GWL_STYLE);
631 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
633 data->whole_rect = data->window_rect;
634 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
636 get_cocoa_window_features(data, style, ex_style, &wf);
638 frame = cgrect_from_rect(data->whole_rect);
639 constrain_window_frame(&frame);
640 if (frame.size.width < 1 || frame.size.height < 1)
641 frame.size.width = frame.size.height = 1;
643 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
644 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
646 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
647 if (!data->cocoa_window) goto done;
649 set_cocoa_window_properties(data);
651 /* set the window text */
652 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
653 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
655 /* set the window region */
656 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
658 /* set the window opacity */
659 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
660 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
662 done:
663 if (win_rgn) DeleteObject(win_rgn);
667 /**********************************************************************
668 * destroy_cocoa_window
670 * Destroy the whole Mac window for a given window.
672 static void destroy_cocoa_window(struct macdrv_win_data *data)
674 if (!data->cocoa_window) return;
676 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
678 macdrv_destroy_cocoa_window(data->cocoa_window);
679 data->cocoa_window = 0;
680 data->on_screen = FALSE;
681 data->color_key = CLR_INVALID;
682 if (data->surface) window_surface_release(data->surface);
683 data->surface = NULL;
684 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
685 data->unminimized_surface = NULL;
689 /***********************************************************************
690 * macdrv_create_win_data
692 * Create a Mac data window structure for an existing window.
694 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
695 const RECT *client_rect)
697 struct macdrv_win_data *data;
698 HWND parent;
700 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
702 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
704 macdrv_init_thread_data();
705 return NULL;
708 /* don't create win data for HWND_MESSAGE windows */
709 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
711 if (!(data = alloc_win_data(hwnd))) return NULL;
713 data->whole_rect = data->window_rect = *window_rect;
714 data->client_rect = *client_rect;
716 if (parent == GetDesktopWindow())
718 create_cocoa_window(data);
719 TRACE("win %p/%p window %s whole %s client %s\n",
720 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
721 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
724 return data;
728 /***********************************************************************
729 * show_window
731 static void show_window(struct macdrv_win_data *data)
733 HWND prev = NULL;
734 HWND next = NULL;
735 macdrv_window prev_window = NULL;
736 macdrv_window next_window = NULL;
737 BOOL activate = FALSE;
738 HWND hwndFocus;
740 /* find window that this one must be after */
741 prev = GetWindow(data->hwnd, GW_HWNDPREV);
742 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
743 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
744 prev = GetWindow(prev, GW_HWNDPREV);
745 if (!prev_window)
747 /* find window that this one must be before */
748 next = GetWindow(data->hwnd, GW_HWNDNEXT);
749 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
750 (next_window = macdrv_get_cocoa_window(next, TRUE))))
751 next = GetWindow(next, GW_HWNDNEXT);
754 TRACE("win %p/%p below %p/%p above %p/%p\n",
755 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
757 if (!prev_window)
758 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
759 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
760 data->on_screen = TRUE;
762 hwndFocus = GetFocus();
763 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
764 macdrv_SetFocus(hwndFocus);
765 if (activate)
766 activate_on_focus_time = 0;
770 /***********************************************************************
771 * hide_window
773 static void hide_window(struct macdrv_win_data *data)
775 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
777 macdrv_hide_cocoa_window(data->cocoa_window);
778 data->on_screen = FALSE;
782 /***********************************************************************
783 * get_region_data
785 * Calls GetRegionData on the given region and converts the rectangle
786 * array to CGRect format. The returned buffer must be freed by
787 * caller using HeapFree(GetProcessHeap(),...).
788 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
790 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
792 RGNDATA *data;
793 DWORD size;
794 int i;
795 RECT *rect;
796 CGRect *cgrect;
798 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
799 if (sizeof(CGRect) > sizeof(RECT))
801 /* add extra size for CGRect array */
802 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
803 size += count * (sizeof(CGRect) - sizeof(RECT));
805 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
806 if (!GetRegionData(hrgn, size, data))
808 HeapFree(GetProcessHeap(), 0, data);
809 return NULL;
812 rect = (RECT *)data->Buffer;
813 cgrect = (CGRect *)data->Buffer;
814 if (hdc_lptodp) /* map to device coordinates */
816 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
817 for (i = 0; i < data->rdh.nCount; i++)
819 if (rect[i].right < rect[i].left)
821 INT tmp = rect[i].right;
822 rect[i].right = rect[i].left;
823 rect[i].left = tmp;
825 if (rect[i].bottom < rect[i].top)
827 INT tmp = rect[i].bottom;
828 rect[i].bottom = rect[i].top;
829 rect[i].top = tmp;
834 if (sizeof(CGRect) > sizeof(RECT))
836 /* need to start from the end */
837 for (i = data->rdh.nCount-1; i >= 0; i--)
838 cgrect[i] = cgrect_from_rect(rect[i]);
840 else
842 for (i = 0; i < data->rdh.nCount; i++)
843 cgrect[i] = cgrect_from_rect(rect[i]);
845 return data;
849 /***********************************************************************
850 * sync_window_position
852 * Synchronize the Mac window position with the Windows one
854 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
855 const RECT *old_whole_rect)
857 CGRect frame;
859 if (data->minimized) return;
861 frame = cgrect_from_rect(data->whole_rect);
862 constrain_window_frame(&frame);
863 if (frame.size.width < 1 || frame.size.height < 1)
864 frame.size.width = frame.size.height = 1;
866 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
867 if (old_window_rect && old_whole_rect &&
868 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
869 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
870 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
871 sync_window_region(data, (HRGN)1);
873 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd, data->cocoa_window,
874 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
876 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
877 show_window(data);
881 /***********************************************************************
882 * move_window_bits
884 * Move the window bits when a window is moved.
886 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
887 const RECT *old_client_rect, const RECT *new_client_rect,
888 const RECT *new_window_rect)
890 RECT src_rect = *old_rect;
891 RECT dst_rect = *new_rect;
892 HDC hdc_src, hdc_dst;
893 HRGN rgn;
894 HWND parent = 0;
896 if (!window)
898 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
899 parent = GetAncestor(hwnd, GA_PARENT);
900 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
901 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
903 else
905 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
906 /* make src rect relative to the old position of the window */
907 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
908 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
909 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
912 rgn = CreateRectRgnIndirect(&dst_rect);
913 SelectClipRgn(hdc_dst, rgn);
914 DeleteObject(rgn);
915 ExcludeUpdateRgn(hdc_dst, hwnd);
917 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
918 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
919 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
920 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
921 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
923 ReleaseDC(hwnd, hdc_dst);
924 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
928 /**********************************************************************
929 * activate_on_following_focus
931 void activate_on_following_focus(void)
933 activate_on_focus_time = GetTickCount();
934 if (!activate_on_focus_time) activate_on_focus_time = 1;
938 /***********************************************************************
939 * set_app_icon
941 static void set_app_icon(void)
943 CFArrayRef images = create_app_icon_images();
944 if (images)
946 macdrv_set_application_icon(images);
947 CFRelease(images);
952 /**********************************************************************
953 * set_capture_window_for_move
955 static BOOL set_capture_window_for_move(HWND hwnd)
957 HWND previous = 0;
958 BOOL ret;
960 SERVER_START_REQ(set_capture_window)
962 req->handle = wine_server_user_handle(hwnd);
963 req->flags = CAPTURE_MOVESIZE;
964 if ((ret = !wine_server_call_err(req)))
966 previous = wine_server_ptr_handle(reply->previous);
967 hwnd = wine_server_ptr_handle(reply->full_handle);
970 SERVER_END_REQ;
972 if (ret)
974 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
976 if (previous && previous != hwnd)
977 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
979 return ret;
983 /***********************************************************************
984 * move_window
986 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
987 * moving top-level windows and enforcing Mac-style constraints like
988 * keeping the top of the window within the work area.
990 static LRESULT move_window(HWND hwnd, WPARAM wparam)
992 MSG msg;
993 RECT origRect, movedRect, desktopRect;
994 LONG hittest = (LONG)(wparam & 0x0f);
995 POINT capturePoint;
996 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
997 BOOL moved = FALSE;
998 DWORD dwPoint = GetMessagePos();
999 INT captionHeight;
1000 HMONITOR mon = 0;
1001 MONITORINFO info;
1003 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1004 if (hittest && hittest != HTCAPTION) return -1;
1006 capturePoint.x = (short)LOWORD(dwPoint);
1007 capturePoint.y = (short)HIWORD(dwPoint);
1008 ClipCursor(NULL);
1010 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1012 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1013 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1014 captionHeight = -origRect.top;
1015 else
1016 captionHeight = 0;
1018 GetWindowRect(hwnd, &origRect);
1019 movedRect = origRect;
1021 if (!hittest)
1023 /* Move pointer to the center of the caption */
1024 RECT rect = origRect;
1026 /* Note: to be exactly centered we should take the different types
1027 * of border into account, but it shouldn't make more than a few pixels
1028 * of difference so let's not bother with that */
1029 rect.top += GetSystemMetrics(SM_CYBORDER);
1030 if (style & WS_SYSMENU)
1031 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1032 if (style & WS_MINIMIZEBOX)
1033 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1034 if (style & WS_MAXIMIZEBOX)
1035 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1036 capturePoint.x = (rect.right + rect.left) / 2;
1037 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1039 SetCursorPos(capturePoint.x, capturePoint.y);
1040 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1043 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1044 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1045 info.cbSize = sizeof(info);
1046 if (mon && !GetMonitorInfoW(mon, &info))
1047 mon = 0;
1049 /* repaint the window before moving it around */
1050 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1052 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1053 set_capture_window_for_move(hwnd);
1055 while(1)
1057 POINT pt;
1058 int dx = 0, dy = 0;
1059 HMONITOR newmon;
1061 if (!GetMessageW(&msg, 0, 0, 0)) break;
1062 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1064 /* Exit on button-up, Return, or Esc */
1065 if (msg.message == WM_LBUTTONUP ||
1066 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1067 break;
1069 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1071 TranslateMessage(&msg);
1072 DispatchMessageW(&msg);
1073 continue; /* We are not interested in other messages */
1076 pt = msg.pt;
1078 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1080 case VK_UP: pt.y -= 8; break;
1081 case VK_DOWN: pt.y += 8; break;
1082 case VK_LEFT: pt.x -= 8; break;
1083 case VK_RIGHT: pt.x += 8; break;
1086 pt.x = max(pt.x, desktopRect.left);
1087 pt.x = min(pt.x, desktopRect.right - 1);
1088 pt.y = max(pt.y, desktopRect.top);
1089 pt.y = min(pt.y, desktopRect.bottom - 1);
1091 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1093 if (GetMonitorInfoW(newmon, &info))
1094 mon = newmon;
1095 else
1096 mon = 0;
1099 if (mon)
1101 /* wineserver clips the cursor position to the virtual desktop rect but,
1102 if the display configuration is non-rectangular, that could still
1103 leave the logical cursor position outside of any display. The window
1104 could keep moving as you push the cursor against a display edge, even
1105 though the visible cursor doesn't keep moving. The following keeps
1106 the window movement in sync with the visible cursor. */
1107 pt.x = max(pt.x, info.rcMonitor.left);
1108 pt.x = min(pt.x, info.rcMonitor.right - 1);
1109 pt.y = max(pt.y, info.rcMonitor.top);
1110 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1112 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1113 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1114 we want to enforce these constraints:
1115 movedRect.left + dx < info.rcWork.right
1116 movedRect.right + dx > info.rcWork.left
1117 movedRect.top + captionHeight + dy < info.rcWork.bottom
1118 movedRect.bottom + dy > info.rcWork.top
1119 movedRect.top + dy >= info.rcWork.top
1120 The first four keep at least one edge barely in the work area.
1121 The last keeps the top (i.e. the title bar) in the work area.
1122 The fourth is redundant with the last, so can be ignored.
1124 Substituting for dx and dy and rearranging gives us...
1126 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1127 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1128 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1129 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1132 dx = pt.x - capturePoint.x;
1133 dy = pt.y - capturePoint.y;
1135 if (dx || dy)
1137 moved = TRUE;
1139 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1140 else
1142 OffsetRect(&movedRect, dx, dy);
1143 capturePoint = pt;
1145 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1146 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1147 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1152 set_capture_window_for_move(0);
1154 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1155 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1157 /* if the move is canceled, restore the previous position */
1158 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1160 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1161 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1164 return 0;
1168 /***********************************************************************
1169 * perform_window_command
1171 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1173 DWORD style;
1175 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1176 hwnd, style_any, style_none, command, hittest);
1178 style = GetWindowLongW(hwnd, GWL_STYLE);
1179 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1181 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1182 return;
1185 if (GetActiveWindow() != hwnd)
1187 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1188 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1189 switch (ma)
1191 case MA_NOACTIVATEANDEAT:
1192 case MA_ACTIVATEANDEAT:
1193 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1194 return;
1195 case MA_NOACTIVATE:
1196 break;
1197 case MA_ACTIVATE:
1198 case 0:
1199 SetActiveWindow(hwnd);
1200 break;
1201 default:
1202 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1203 break;
1207 TRACE("changing win %p\n", hwnd);
1208 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1212 /**********************************************************************
1213 * CreateDesktopWindow (MACDRV.@)
1215 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1217 unsigned int width, height;
1219 TRACE("%p\n", hwnd);
1221 /* retrieve the real size of the desktop */
1222 SERVER_START_REQ(get_window_rectangles)
1224 req->handle = wine_server_user_handle(hwnd);
1225 req->relative = COORDS_CLIENT;
1226 wine_server_call(req);
1227 width = reply->window.right;
1228 height = reply->window.bottom;
1230 SERVER_END_REQ;
1232 if (!width && !height) /* not initialized yet */
1234 CGRect rect = macdrv_get_desktop_rect();
1236 SERVER_START_REQ(set_window_pos)
1238 req->handle = wine_server_user_handle(hwnd);
1239 req->previous = 0;
1240 req->swp_flags = SWP_NOZORDER;
1241 req->window.left = CGRectGetMinX(rect);
1242 req->window.top = CGRectGetMinY(rect);
1243 req->window.right = CGRectGetMaxX(rect);
1244 req->window.bottom = CGRectGetMaxY(rect);
1245 req->client = req->window;
1246 wine_server_call(req);
1248 SERVER_END_REQ;
1251 set_app_icon();
1252 return TRUE;
1256 /**********************************************************************
1257 * CreateWindow (MACDRV.@)
1259 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1261 return TRUE;
1265 /***********************************************************************
1266 * DestroyWindow (MACDRV.@)
1268 void CDECL macdrv_DestroyWindow(HWND hwnd)
1270 struct macdrv_win_data *data;
1272 TRACE("%p\n", hwnd);
1274 if (!(data = get_win_data(hwnd))) return;
1276 if (data->gl_view) macdrv_dispose_view(data->gl_view);
1277 destroy_cocoa_window(data);
1279 CFDictionaryRemoveValue(win_datas, hwnd);
1280 release_win_data(data);
1281 HeapFree(GetProcessHeap(), 0, data);
1285 /*****************************************************************
1286 * SetFocus (MACDRV.@)
1288 * Set the Mac focus.
1290 void CDECL macdrv_SetFocus(HWND hwnd)
1292 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1293 struct macdrv_win_data *data;
1295 TRACE("%p\n", hwnd);
1297 if (!thread_data) return;
1298 thread_data->dead_key_state = 0;
1300 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
1301 if (!(data = get_win_data(hwnd))) return;
1303 if (data->cocoa_window && data->on_screen)
1305 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
1306 /* Set Mac focus */
1307 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
1308 activate_on_focus_time = 0;
1311 release_win_data(data);
1315 /***********************************************************************
1316 * SetLayeredWindowAttributes (MACDRV.@)
1318 * Set transparency attributes for a layered window.
1320 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1322 struct macdrv_win_data *data = get_win_data(hwnd);
1324 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1326 if (data)
1328 data->layered = TRUE;
1329 if (data->cocoa_window)
1331 sync_window_opacity(data, key, alpha, FALSE, flags);
1332 /* since layered attributes are now set, can now show the window */
1333 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1334 show_window(data);
1336 release_win_data(data);
1338 else
1339 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1343 /*****************************************************************
1344 * SetParent (MACDRV.@)
1346 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1348 struct macdrv_win_data *data;
1350 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1352 if (parent == old_parent) return;
1353 if (!(data = get_win_data(hwnd))) return;
1355 if (parent != GetDesktopWindow()) /* a child window */
1357 if (old_parent == GetDesktopWindow())
1359 /* destroy the old Mac window */
1360 destroy_cocoa_window(data);
1363 else /* new top level window */
1364 create_cocoa_window(data);
1365 release_win_data(data);
1367 set_gl_view_parent(hwnd, parent);
1371 /***********************************************************************
1372 * SetWindowRgn (MACDRV.@)
1374 * Assign specified region to window (for non-rectangular windows)
1376 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1378 struct macdrv_win_data *data;
1380 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1382 if ((data = get_win_data(hwnd)))
1384 sync_window_region(data, hrgn);
1385 release_win_data(data);
1387 else
1389 DWORD procid;
1391 GetWindowThreadProcessId(hwnd, &procid);
1392 if (procid != GetCurrentProcessId())
1393 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1396 return TRUE;
1400 /***********************************************************************
1401 * SetWindowStyle (MACDRV.@)
1403 * Update the state of the Cocoa window to reflect a style change
1405 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1407 struct macdrv_win_data *data;
1409 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1411 if (hwnd == GetDesktopWindow()) return;
1412 if (!(data = get_win_data(hwnd))) return;
1414 if (data->cocoa_window)
1416 DWORD changed = style->styleNew ^ style->styleOld;
1418 set_cocoa_window_properties(data);
1420 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1422 data->layered = FALSE;
1423 data->ulw_layered = FALSE;
1424 sync_window_opacity(data, 0, 0, FALSE, 0);
1425 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1428 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1429 sync_window_region(data, (HRGN)1);
1432 release_win_data(data);
1436 /*****************************************************************
1437 * SetWindowText (MACDRV.@)
1439 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1441 macdrv_window win;
1443 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1445 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1446 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1450 /***********************************************************************
1451 * ShowWindow (MACDRV.@)
1453 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1455 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1456 struct macdrv_win_data *data = get_win_data(hwnd);
1457 CGRect frame;
1459 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1460 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1462 if (!data || !data->cocoa_window) goto done;
1463 if (IsRectEmpty(rect)) goto done;
1464 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1466 if (rect->left != -32000 || rect->top != -32000)
1468 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1469 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1471 goto done;
1473 if (!data->on_screen) goto done;
1475 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1477 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1478 goto done;
1480 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1481 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1482 goto done;
1484 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1485 *rect = rect_from_cgrect(frame);
1486 macdrv_mac_to_window_rect(data, rect);
1487 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1488 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1490 done:
1491 release_win_data(data);
1492 return swp;
1496 /***********************************************************************
1497 * SysCommand (MACDRV.@)
1499 * Perform WM_SYSCOMMAND handling.
1501 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1503 struct macdrv_win_data *data;
1504 LRESULT ret = -1;
1505 WPARAM command = wparam & 0xfff0;
1507 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1509 if (!(data = get_win_data(hwnd))) goto done;
1510 if (!data->cocoa_window || !data->on_screen) goto done;
1512 /* prevent a simple ALT press+release from activating the system menu,
1513 as that can get confusing */
1514 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1515 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1517 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1518 ret = 0;
1521 if (command == SC_MOVE)
1523 release_win_data(data);
1524 return move_window(hwnd, wparam);
1527 done:
1528 release_win_data(data);
1529 return ret;
1533 /***********************************************************************
1534 * UpdateLayeredWindow (MACDRV.@)
1536 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1537 const RECT *window_rect)
1539 struct window_surface *surface;
1540 struct macdrv_win_data *data;
1541 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1542 BYTE alpha;
1543 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1544 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1545 void *src_bits, *dst_bits;
1546 RECT rect;
1547 HDC hdc = 0;
1548 HBITMAP dib;
1549 BOOL ret = FALSE;
1551 if (!(data = get_win_data(hwnd))) return FALSE;
1553 data->layered = TRUE;
1554 data->ulw_layered = TRUE;
1556 rect = *window_rect;
1557 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1559 surface = data->surface;
1560 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1562 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1563 set_window_surface(data->cocoa_window, data->surface);
1564 if (surface) window_surface_release(surface);
1565 surface = data->surface;
1566 if (data->unminimized_surface)
1568 window_surface_release(data->unminimized_surface);
1569 data->unminimized_surface = NULL;
1572 else set_surface_use_alpha(surface, TRUE);
1574 if (surface) window_surface_add_ref(surface);
1575 release_win_data(data);
1577 if (!surface) return FALSE;
1578 if (!info->hdcSrc)
1580 window_surface_release(surface);
1581 return TRUE;
1584 if (info->dwFlags & ULW_ALPHA)
1586 /* Apply SourceConstantAlpha via window alpha, not blend. */
1587 alpha = info->pblend->SourceConstantAlpha;
1588 blend = *info->pblend;
1589 blend.SourceConstantAlpha = 0xff;
1591 else
1592 alpha = 0xff;
1594 dst_bits = surface->funcs->get_info(surface, bmi);
1596 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1597 if (!(hdc = CreateCompatibleDC(0))) goto done;
1599 SelectObject(hdc, dib);
1600 if (info->prcDirty)
1602 IntersectRect(&rect, &rect, info->prcDirty);
1603 surface->funcs->lock(surface);
1604 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1605 surface->funcs->unlock(surface);
1606 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1608 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1609 info->hdcSrc,
1610 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1611 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1612 rect.right - rect.left, rect.bottom - rect.top,
1613 blend)))
1614 goto done;
1616 if ((data = get_win_data(hwnd)))
1618 if (surface == data->surface)
1620 surface->funcs->lock(surface);
1621 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1622 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1623 surface->funcs->unlock(surface);
1624 surface->funcs->flush(surface);
1627 /* The ULW flags are a superset of the LWA flags. */
1628 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1630 release_win_data(data);
1633 done:
1634 window_surface_release(surface);
1635 if (hdc) DeleteDC(hdc);
1636 if (dib) DeleteObject(dib);
1637 return ret;
1641 /**********************************************************************
1642 * WindowMessage (MACDRV.@)
1644 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1646 struct macdrv_win_data *data;
1648 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1650 switch(msg)
1652 case WM_MACDRV_SET_WIN_REGION:
1653 if ((data = get_win_data(hwnd)))
1655 sync_window_region(data, (HRGN)1);
1656 release_win_data(data);
1658 return 0;
1659 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1660 if (hwnd == GetDesktopWindow())
1662 CGRect new_desktop_rect;
1663 RECT current_desktop_rect;
1665 macdrv_reset_device_metrics();
1666 new_desktop_rect = macdrv_get_desktop_rect();
1667 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1668 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1670 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1671 SMTO_ABORTIFHUNG, 2000, NULL);
1672 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1673 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1674 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1675 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1676 SMTO_ABORTIFHUNG, 2000, NULL);
1679 return 0;
1680 case WM_MACDRV_RESET_DEVICE_METRICS:
1681 macdrv_reset_device_metrics();
1682 return 0;
1683 case WM_MACDRV_DISPLAYCHANGE:
1684 if ((data = get_win_data(hwnd)))
1686 if (data->cocoa_window && data->on_screen)
1687 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
1688 release_win_data(data);
1690 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1691 return 0;
1692 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1693 activate_on_following_focus();
1694 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1695 return 0;
1698 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1699 return 0;
1703 static inline RECT get_surface_rect(const RECT *visible_rect)
1705 RECT rect;
1706 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1708 IntersectRect(&rect, visible_rect, &desktop_rect);
1709 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1710 rect.left &= ~127;
1711 rect.top &= ~127;
1712 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1713 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1714 return rect;
1718 /***********************************************************************
1719 * WindowPosChanging (MACDRV.@)
1721 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1722 const RECT *window_rect, const RECT *client_rect,
1723 RECT *visible_rect, struct window_surface **surface)
1725 struct macdrv_win_data *data = get_win_data(hwnd);
1726 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1727 RECT surface_rect;
1729 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1730 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1731 wine_dbgstr_rect(visible_rect), surface);
1733 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1735 *visible_rect = *window_rect;
1736 macdrv_window_to_mac_rect(data, style, visible_rect);
1737 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1738 wine_dbgstr_rect(visible_rect));
1740 /* create the window surface if necessary */
1741 if (!data->cocoa_window) goto done;
1742 if (swp_flags & SWP_HIDEWINDOW) goto done;
1743 if (data->ulw_layered) goto done;
1745 if (*surface) window_surface_release(*surface);
1746 *surface = NULL;
1748 surface_rect = get_surface_rect(visible_rect);
1749 if (data->surface)
1751 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1753 /* existing surface is good enough */
1754 surface_clip_to_visible_rect(data->surface, visible_rect);
1755 window_surface_add_ref(data->surface);
1756 *surface = data->surface;
1757 goto done;
1760 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1762 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1764 done:
1765 release_win_data(data);
1769 /***********************************************************************
1770 * WindowPosChanged (MACDRV.@)
1772 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1773 const RECT *window_rect, const RECT *client_rect,
1774 const RECT *visible_rect, const RECT *valid_rects,
1775 struct window_surface *surface)
1777 struct macdrv_thread_data *thread_data;
1778 struct macdrv_win_data *data;
1779 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1780 RECT old_window_rect, old_whole_rect, old_client_rect;
1782 if (!(data = get_win_data(hwnd))) return;
1784 thread_data = macdrv_thread_data();
1786 old_window_rect = data->window_rect;
1787 old_whole_rect = data->whole_rect;
1788 old_client_rect = data->client_rect;
1789 data->window_rect = *window_rect;
1790 data->whole_rect = *visible_rect;
1791 data->client_rect = *client_rect;
1792 if (!data->ulw_layered)
1794 if (surface) window_surface_add_ref(surface);
1795 if (new_style & WS_MINIMIZE)
1797 if (!data->unminimized_surface && data->surface)
1799 data->unminimized_surface = data->surface;
1800 window_surface_add_ref(data->unminimized_surface);
1803 else
1805 set_window_surface(data->cocoa_window, surface);
1806 if (data->unminimized_surface)
1808 window_surface_release(data->unminimized_surface);
1809 data->unminimized_surface = NULL;
1812 if (data->surface) window_surface_release(data->surface);
1813 data->surface = surface;
1816 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1817 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1818 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1819 new_style, swp_flags, surface);
1821 if (!IsRectEmpty(&valid_rects[0]))
1823 macdrv_window window = data->cocoa_window;
1824 int x_offset = old_whole_rect.left - data->whole_rect.left;
1825 int y_offset = old_whole_rect.top - data->whole_rect.top;
1827 /* if all that happened is that the whole window moved, copy everything */
1828 if (!(swp_flags & SWP_FRAMECHANGED) &&
1829 old_whole_rect.right - data->whole_rect.right == x_offset &&
1830 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1831 old_client_rect.left - data->client_rect.left == x_offset &&
1832 old_client_rect.right - data->client_rect.right == x_offset &&
1833 old_client_rect.top - data->client_rect.top == y_offset &&
1834 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1835 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1837 /* A Cocoa window's bits are moved automatically */
1838 if (!window && (x_offset != 0 || y_offset != 0))
1840 release_win_data(data);
1841 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1842 &old_client_rect, client_rect, window_rect);
1843 if (!(data = get_win_data(hwnd))) return;
1846 else
1848 release_win_data(data);
1849 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1850 &old_client_rect, client_rect, window_rect);
1851 if (!(data = get_win_data(hwnd))) return;
1855 sync_gl_view(data);
1857 if (!data->cocoa_window) goto done;
1859 if (data->on_screen)
1861 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1862 hide_window(data);
1865 /* check if we are currently processing an event relevant to this window */
1866 if (!thread_data || !thread_data->current_event ||
1867 thread_data->current_event->window != data->cocoa_window ||
1868 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1869 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1871 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
1872 set_cocoa_window_properties(data);
1875 if (new_style & WS_VISIBLE)
1877 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1878 set_cocoa_window_properties(data);
1880 /* layered windows are not shown until their attributes are set */
1881 if (!data->on_screen &&
1882 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1883 show_window(data);
1886 done:
1887 release_win_data(data);
1891 /***********************************************************************
1892 * macdrv_window_close_requested
1894 * Handler for WINDOW_CLOSE_REQUESTED events.
1896 void macdrv_window_close_requested(HWND hwnd)
1898 HMENU sysmenu;
1900 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1902 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
1903 return;
1906 sysmenu = GetSystemMenu(hwnd, FALSE);
1907 if (sysmenu)
1909 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
1910 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1912 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
1913 return;
1917 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
1921 /***********************************************************************
1922 * macdrv_window_frame_changed
1924 * Handler for WINDOW_FRAME_CHANGED events.
1926 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
1928 struct macdrv_win_data *data;
1929 RECT rect;
1930 HWND parent;
1931 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1932 int width, height;
1933 BOOL being_dragged;
1935 if (!hwnd) return;
1936 if (!(data = get_win_data(hwnd))) return;
1937 if (!data->on_screen || data->minimized)
1939 release_win_data(data);
1940 return;
1943 /* Get geometry */
1945 parent = GetAncestor(hwnd, GA_PARENT);
1947 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
1948 wine_dbgstr_cgrect(event->window_frame_changed.frame),
1949 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
1951 rect = rect_from_cgrect(event->window_frame_changed.frame);
1952 macdrv_mac_to_window_rect(data, &rect);
1953 MapWindowPoints(0, parent, (POINT *)&rect, 2);
1955 width = rect.right - rect.left;
1956 height = rect.bottom - rect.top;
1958 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1959 flags |= SWP_NOMOVE;
1960 else
1961 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1962 data->window_rect.top, rect.left, rect.top);
1964 if ((data->window_rect.right - data->window_rect.left == width &&
1965 data->window_rect.bottom - data->window_rect.top == height) ||
1966 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
1967 flags |= SWP_NOSIZE;
1968 else
1969 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1970 data->window_rect.bottom - data->window_rect.top, width, height);
1972 being_dragged = data->being_dragged;
1973 release_win_data(data);
1975 if (event->window_frame_changed.fullscreen)
1976 flags |= SWP_NOSENDCHANGING;
1977 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1979 if (!event->window_frame_changed.in_resize && !being_dragged)
1980 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1981 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1982 if (!event->window_frame_changed.in_resize && !being_dragged)
1983 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1988 /***********************************************************************
1989 * macdrv_window_got_focus
1991 * Handler for WINDOW_GOT_FOCUS events.
1993 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1995 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1997 if (!hwnd) return;
1999 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2000 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2001 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2003 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2005 /* simulate a mouse click on the caption to find out
2006 * whether the window wants to be activated */
2007 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2008 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2009 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2010 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2012 TRACE("setting foreground window to %p\n", hwnd);
2013 SetForegroundWindow(hwnd);
2014 return;
2018 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2019 macdrv_window_rejected_focus(event);
2023 /***********************************************************************
2024 * macdrv_window_lost_focus
2026 * Handler for WINDOW_LOST_FOCUS events.
2028 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2030 if (!hwnd) return;
2032 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2034 if (hwnd == GetForegroundWindow())
2036 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2037 if (hwnd == GetForegroundWindow())
2038 SetForegroundWindow(GetDesktopWindow());
2043 /***********************************************************************
2044 * macdrv_app_deactivated
2046 * Handler for APP_DEACTIVATED events.
2048 void macdrv_app_deactivated(void)
2050 if (GetActiveWindow() == GetForegroundWindow())
2052 TRACE("setting fg to desktop\n");
2053 SetForegroundWindow(GetDesktopWindow());
2058 /***********************************************************************
2059 * macdrv_window_maximize_requested
2061 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2063 void macdrv_window_maximize_requested(HWND hwnd)
2065 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2069 /***********************************************************************
2070 * macdrv_window_minimize_requested
2072 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2074 void macdrv_window_minimize_requested(HWND hwnd)
2076 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2080 /***********************************************************************
2081 * macdrv_window_did_unminimize
2083 * Handler for WINDOW_DID_UNMINIMIZE events.
2085 void macdrv_window_did_unminimize(HWND hwnd)
2087 struct macdrv_win_data *data;
2088 DWORD style;
2090 TRACE("win %p\n", hwnd);
2092 if (!(data = get_win_data(hwnd))) return;
2093 if (!data->minimized) goto done;
2095 style = GetWindowLongW(hwnd, GWL_STYLE);
2097 data->minimized = FALSE;
2098 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2100 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2101 release_win_data(data);
2102 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2103 return;
2106 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2108 done:
2109 release_win_data(data);
2113 /***********************************************************************
2114 * macdrv_window_brought_forward
2116 * Handler for WINDOW_BROUGHT_FORWARD events.
2118 void macdrv_window_brought_forward(HWND hwnd)
2120 TRACE("win %p\n", hwnd);
2121 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2125 /***********************************************************************
2126 * macdrv_window_resize_ended
2128 * Handler for WINDOW_RESIZE_ENDED events.
2130 void macdrv_window_resize_ended(HWND hwnd)
2132 TRACE("hwnd %p\n", hwnd);
2133 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2137 /***********************************************************************
2138 * macdrv_window_restore_requested
2140 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2141 * for restoring from maximized, not from minimized.
2143 void macdrv_window_restore_requested(HWND hwnd)
2145 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2149 /***********************************************************************
2150 * macdrv_window_drag_begin
2152 * Handler for WINDOW_DRAG_BEGIN events.
2154 void macdrv_window_drag_begin(HWND hwnd)
2156 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2157 struct macdrv_win_data *data;
2158 MSG msg;
2160 TRACE("win %p\n", hwnd);
2162 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2163 if (!(style & WS_VISIBLE)) return;
2165 if (!(data = get_win_data(hwnd))) return;
2166 if (data->being_dragged) goto done;
2168 data->being_dragged = TRUE;
2169 release_win_data(data);
2171 ClipCursor(NULL);
2172 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2173 ReleaseCapture();
2175 while (GetMessageW(&msg, 0, 0, 0))
2177 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2178 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2180 TranslateMessage(&msg);
2181 DispatchMessageW(&msg);
2184 if (msg.message == WM_EXITSIZEMOVE) break;
2187 TRACE("done\n");
2189 if ((data = get_win_data(hwnd)))
2190 data->being_dragged = FALSE;
2192 done:
2193 release_win_data(data);
2197 /***********************************************************************
2198 * macdrv_window_drag_end
2200 * Handler for WINDOW_DRAG_END events.
2202 void macdrv_window_drag_end(HWND hwnd)
2204 struct macdrv_win_data *data;
2205 BOOL being_dragged;
2207 TRACE("win %p\n", hwnd);
2209 if (!(data = get_win_data(hwnd))) return;
2210 being_dragged = data->being_dragged;
2211 release_win_data(data);
2213 if (being_dragged)
2215 /* Post this rather than sending it, so that the message loop in
2216 macdrv_window_drag_begin() will see it. */
2217 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2222 struct quit_info {
2223 HWND *wins;
2224 UINT capacity;
2225 UINT count;
2226 UINT done;
2227 DWORD flags;
2228 BOOL result;
2229 BOOL replied;
2233 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2235 struct quit_info *qi = (struct quit_info*)lp;
2236 DWORD pid;
2238 GetWindowThreadProcessId(hwnd, &pid);
2239 if (pid == GetCurrentProcessId())
2241 if (qi->count >= qi->capacity)
2243 UINT new_cap = qi->capacity * 2;
2244 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2245 new_cap * sizeof(*qi->wins));
2246 if (!new_wins) return FALSE;
2247 qi->wins = new_wins;
2248 qi->capacity = new_cap;
2251 qi->wins[qi->count++] = hwnd;
2254 return TRUE;
2258 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2260 struct quit_info *qi = (struct quit_info*)data;
2262 qi->done++;
2264 if (msg == WM_QUERYENDSESSION)
2266 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2267 hwnd, qi->done, qi->count);
2269 if (!result && !IsWindow(hwnd))
2271 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2272 result = TRUE;
2275 if (!result && qi->result)
2277 qi->result = FALSE;
2279 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2280 ultimate reply. Might as well tell Cocoa now. */
2281 if (!qi->replied)
2283 qi->replied = TRUE;
2284 TRACE("giving quit reply %d\n", qi->result);
2285 macdrv_quit_reply(qi->result);
2289 if (qi->done >= qi->count)
2291 UINT i;
2293 qi->done = 0;
2294 for (i = 0; i < qi->count; i++)
2296 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2297 qi->result, qi->flags);
2298 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2299 quit_callback, (ULONG_PTR)qi))
2301 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2302 qi->wins[i], GetLastError());
2303 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2308 else /* WM_ENDSESSION */
2310 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2312 if (qi->done >= qi->count)
2314 if (!qi->replied)
2316 TRACE("giving quit reply %d\n", qi->result);
2317 macdrv_quit_reply(qi->result);
2320 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2321 if (qi->result)
2322 TerminateProcess(GetCurrentProcess(), 0);
2324 HeapFree(GetProcessHeap(), 0, qi->wins);
2325 HeapFree(GetProcessHeap(), 0, qi);
2331 /***********************************************************************
2332 * macdrv_app_quit_requested
2334 * Handler for APP_QUIT_REQUESTED events.
2336 void macdrv_app_quit_requested(const macdrv_event *event)
2338 struct quit_info *qi;
2339 UINT i;
2341 TRACE("reason %d\n", event->app_quit_requested.reason);
2343 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2344 if (!qi)
2345 goto fail;
2347 qi->capacity = 32;
2348 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2349 qi->count = qi->done = 0;
2351 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2352 goto fail;
2354 switch (event->app_quit_requested.reason)
2356 case QUIT_REASON_LOGOUT:
2357 default:
2358 qi->flags = ENDSESSION_LOGOFF;
2359 break;
2360 case QUIT_REASON_RESTART:
2361 case QUIT_REASON_SHUTDOWN:
2362 qi->flags = 0;
2363 break;
2366 qi->result = TRUE;
2367 qi->replied = FALSE;
2369 for (i = 0; i < qi->count; i++)
2371 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2372 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2373 quit_callback, (ULONG_PTR)qi))
2375 DWORD error = GetLastError();
2376 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2377 if (invalid)
2378 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2379 qi->wins[i]);
2380 else
2381 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2382 qi->wins[i], error);
2383 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2387 /* quit_callback() will clean up qi */
2388 return;
2390 fail:
2391 WARN("failed to allocate window list\n");
2392 if (qi)
2394 HeapFree(GetProcessHeap(), 0, qi->wins);
2395 HeapFree(GetProcessHeap(), 0, qi);
2397 macdrv_quit_reply(FALSE);
2401 /***********************************************************************
2402 * query_resize_start
2404 * Handler for QUERY_RESIZE_START query.
2406 BOOL query_resize_start(HWND hwnd)
2408 TRACE("hwnd %p\n", hwnd);
2410 sync_window_min_max_info(hwnd);
2411 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2413 return TRUE;
2417 /***********************************************************************
2418 * query_min_max_info
2420 * Handler for QUERY_MIN_MAX_INFO query.
2422 BOOL query_min_max_info(HWND hwnd)
2424 TRACE("hwnd %p\n", hwnd);
2425 sync_window_min_max_info(hwnd);
2426 return TRUE;