winemac: Allow zero-sized windows to be selected from the Mac Window menu.
[wine.git] / dlls / winemac.drv / window.c
blob2c71a1e39d67aed6569175b5070656bdfa4d3aa9
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 (IsRectEmpty(&data->window_rect)) return;
62 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
64 wf->shadow = 1;
65 if (!data->shaped)
67 wf->title_bar = 1;
68 if (style & WS_SYSMENU) wf->close_button = 1;
69 if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
70 if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
71 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
74 if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
75 else if (style & WS_THICKFRAME)
77 wf->shadow = 1;
78 if (!data->shaped) wf->resizable = 1;
80 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
84 /*******************************************************************
85 * can_activate_window
87 * Check if we can activate the specified window.
89 static inline BOOL can_activate_window(HWND hwnd)
91 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
93 if (!(style & WS_VISIBLE)) return FALSE;
94 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
95 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
96 if (hwnd == GetDesktopWindow()) return FALSE;
97 return !(style & WS_DISABLED);
101 /***********************************************************************
102 * get_cocoa_window_state
104 static void get_cocoa_window_state(struct macdrv_win_data *data,
105 DWORD style, DWORD ex_style,
106 struct macdrv_window_state* state)
108 memset(state, 0, sizeof(*state));
109 state->disabled = (style & WS_DISABLED) != 0;
110 state->no_activate = !can_activate_window(data->hwnd);
111 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
112 state->excluded_by_expose = state->excluded_by_cycle =
113 (!(ex_style & WS_EX_APPWINDOW) &&
114 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
115 if (IsRectEmpty(&data->window_rect))
116 state->excluded_by_expose = TRUE;
117 state->minimized = (style & WS_MINIMIZE) != 0;
121 /***********************************************************************
122 * get_mac_rect_offset
124 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
126 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
128 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
130 rect->top = rect->bottom = rect->left = rect->right = 0;
132 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
134 if (!data->shaped)
136 struct macdrv_window_features wf;
137 get_cocoa_window_features(data, style, ex_style, &wf);
139 if (wf.title_bar) style_mask |= WS_CAPTION;
140 if (wf.shadow)
142 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
143 ex_style_mask |= WS_EX_DLGMODALFRAME;
147 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
149 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
150 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
154 /***********************************************************************
155 * macdrv_window_to_mac_rect
157 * Convert a rect from client to Mac window coordinates
159 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
161 RECT rc;
163 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
164 if (IsRectEmpty(rect)) return;
166 get_mac_rect_offset(data, style, &rc);
168 rect->left -= rc.left;
169 rect->right -= rc.right;
170 rect->top -= rc.top;
171 rect->bottom -= rc.bottom;
172 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
173 if (rect->left >= rect->right) rect->right = rect->left + 1;
177 /***********************************************************************
178 * macdrv_mac_to_window_rect
180 * Opposite of macdrv_window_to_mac_rect
182 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
184 RECT rc;
185 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
187 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
188 if (IsRectEmpty(rect)) return;
190 get_mac_rect_offset(data, style, &rc);
192 rect->left += rc.left;
193 rect->right += rc.right;
194 rect->top += rc.top;
195 rect->bottom += rc.bottom;
196 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
197 if (rect->left >= rect->right) rect->right = rect->left + 1;
201 /***********************************************************************
202 * constrain_window_frame
204 * Alter a window frame rectangle to fit within a) Cocoa's documented
205 * limits, and b) sane sizes, like twice the desktop rect.
207 static void constrain_window_frame(CGRect* frame)
209 CGRect desktop_rect = macdrv_get_desktop_rect();
210 int max_width, max_height;
212 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
213 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
215 if (frame->origin.x < -16000) frame->origin.x = -16000;
216 if (frame->origin.y < -16000) frame->origin.y = -16000;
217 if (frame->origin.x > 16000) frame->origin.x = 16000;
218 if (frame->origin.y > 16000) frame->origin.y = 16000;
219 if (frame->size.width > max_width) frame->size.width = max_width;
220 if (frame->size.height > max_height) frame->size.height = max_height;
224 /***********************************************************************
225 * alloc_win_data
227 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
229 struct macdrv_win_data *data;
231 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
233 data->hwnd = hwnd;
234 data->color_key = CLR_INVALID;
235 EnterCriticalSection(&win_data_section);
236 if (!win_datas)
237 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
238 CFDictionarySetValue(win_datas, hwnd, data);
240 return data;
244 /***********************************************************************
245 * get_win_data
247 * Lock and return the data structure associated with a window.
249 struct macdrv_win_data *get_win_data(HWND hwnd)
251 struct macdrv_win_data *data;
253 if (!hwnd) return NULL;
254 EnterCriticalSection(&win_data_section);
255 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
256 return data;
257 LeaveCriticalSection(&win_data_section);
258 return NULL;
262 /***********************************************************************
263 * release_win_data
265 * Release the data returned by get_win_data.
267 void release_win_data(struct macdrv_win_data *data)
269 if (data) LeaveCriticalSection(&win_data_section);
273 /***********************************************************************
274 * macdrv_get_cocoa_window
276 * Return the Mac window associated with the full area of a window
278 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
280 struct macdrv_win_data *data = get_win_data(hwnd);
281 macdrv_window ret = NULL;
282 if (data && (data->on_screen || !require_on_screen))
283 ret = data->cocoa_window;
284 release_win_data(data);
285 return ret;
289 /***********************************************************************
290 * set_cocoa_window_properties
292 * Set the window properties for a Cocoa window based on its Windows
293 * properties.
295 static void set_cocoa_window_properties(struct macdrv_win_data *data)
297 DWORD style, ex_style;
298 HWND owner;
299 macdrv_window owner_win;
300 struct macdrv_window_features wf;
301 struct macdrv_window_state state;
303 style = GetWindowLongW(data->hwnd, GWL_STYLE);
304 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
306 owner = GetWindow(data->hwnd, GW_OWNER);
307 owner_win = macdrv_get_cocoa_window(owner, TRUE);
308 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
310 get_cocoa_window_features(data, style, ex_style, &wf);
311 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
313 get_cocoa_window_state(data, style, ex_style, &state);
314 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
315 data->minimized = state.minimized;
319 /***********************************************************************
320 * sync_window_region
322 * Update the window region.
324 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
326 HRGN hrgn = win_region;
327 RGNDATA *region_data;
328 const CGRect* rects;
329 int count;
331 if (!data->cocoa_window) return;
332 data->shaped = FALSE;
334 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
336 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
337 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
338 return;
341 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
343 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
344 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
346 DeleteObject(hrgn);
347 hrgn = 0;
351 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
352 MirrorRgn(data->hwnd, hrgn);
353 if (hrgn)
355 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
356 data->window_rect.top - data->whole_rect.top);
358 region_data = get_region_data(hrgn, 0);
359 if (region_data)
361 rects = (CGRect*)region_data->Buffer;
362 count = region_data->rdh.nCount;
363 /* Special case optimization. If the region entirely encloses the Cocoa
364 window, it's the same as there being no region. It's potentially
365 hard/slow to test this for arbitrary regions, so we just check for
366 very simple regions. */
367 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
369 TRACE("optimizing for simple region that contains Cocoa content rect\n");
370 rects = NULL;
371 count = 0;
374 else
376 rects = NULL;
377 count = 0;
380 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
381 macdrv_set_window_shape(data->cocoa_window, rects, count);
383 HeapFree(GetProcessHeap(), 0, region_data);
384 data->shaped = (region_data != NULL);
386 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
390 /***********************************************************************
391 * add_bounds_rect
393 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
395 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
396 bounds->left = min(bounds->left, rect->left);
397 bounds->top = min(bounds->top, rect->top);
398 bounds->right = max(bounds->right, rect->right);
399 bounds->bottom = max(bounds->bottom, rect->bottom);
403 /***********************************************************************
404 * sync_window_opacity
406 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
407 BOOL per_pixel_alpha, DWORD flags)
409 CGFloat opacity = 1.0;
410 BOOL needs_flush = FALSE;
412 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
414 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
415 macdrv_set_window_alpha(data->cocoa_window, opacity);
417 if (flags & LWA_COLORKEY)
419 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
420 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
421 key = RGB(0, 0, 0);
423 else
424 key = CLR_INVALID;
426 if (data->color_key != key)
428 if (key == CLR_INVALID)
430 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
431 macdrv_clear_window_color_key(data->cocoa_window);
433 else
435 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
436 GetRValue(key), GetGValue(key), GetBValue(key));
437 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
440 data->color_key = key;
441 needs_flush = TRUE;
444 if (!data->per_pixel_alpha != !per_pixel_alpha)
446 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
447 data->per_pixel_alpha = per_pixel_alpha;
448 needs_flush = TRUE;
451 if (needs_flush && data->surface)
453 RECT *bounds;
454 RECT rect;
456 rect = data->whole_rect;
457 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
458 data->surface->funcs->lock(data->surface);
459 bounds = data->surface->funcs->get_bounds(data->surface);
460 add_bounds_rect(bounds, &rect);
461 data->surface->funcs->unlock(data->surface);
466 /***********************************************************************
467 * sync_window_min_max_info
469 static void sync_window_min_max_info(HWND hwnd)
471 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
472 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
473 RECT win_rect, primary_monitor_rect;
474 MINMAXINFO minmax;
475 LONG adjustedStyle;
476 INT xinc, yinc;
477 WINDOWPLACEMENT wpl;
478 HMONITOR monitor;
479 struct macdrv_win_data *data;
480 RECT min_rect, max_rect;
481 CGSize min_size, max_size;
483 TRACE("win %p\n", hwnd);
485 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
487 GetWindowRect(hwnd, &win_rect);
488 minmax.ptReserved.x = win_rect.left;
489 minmax.ptReserved.y = win_rect.top;
491 if ((style & WS_CAPTION) == WS_CAPTION)
492 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
493 else
494 adjustedStyle = style;
496 primary_monitor_rect.left = primary_monitor_rect.top = 0;
497 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
498 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
499 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
501 xinc = -primary_monitor_rect.left;
502 yinc = -primary_monitor_rect.top;
504 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
505 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
506 minmax.ptMaxPosition.x = -xinc;
507 minmax.ptMaxPosition.y = -yinc;
508 if (style & (WS_DLGFRAME | WS_BORDER))
510 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
511 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
513 else
515 minmax.ptMinTrackSize.x = 2 * xinc;
516 minmax.ptMinTrackSize.y = 2 * yinc;
518 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
519 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
521 wpl.length = sizeof(wpl);
522 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
524 minmax.ptMaxPosition = wpl.ptMaxPosition;
526 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
527 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
528 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
531 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
532 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
534 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
536 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
537 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
539 /* if the app didn't change the values, adapt them for the window's monitor */
540 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
542 MONITORINFO mon_info;
543 RECT monitor_rect;
545 mon_info.cbSize = sizeof(mon_info);
546 GetMonitorInfoW(monitor, &mon_info);
548 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
549 monitor_rect = mon_info.rcWork;
550 else
551 monitor_rect = mon_info.rcMonitor;
553 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
554 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
556 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
557 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
559 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
561 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
562 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
566 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
567 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
569 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
570 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
572 if ((data = get_win_data(hwnd)) && data->cocoa_window)
574 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
575 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
576 macdrv_window_to_mac_rect(data, style, &min_rect);
577 macdrv_window_to_mac_rect(data, style, &max_rect);
578 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
579 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
581 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
582 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
585 release_win_data(data);
589 /**********************************************************************
590 * create_cocoa_window
592 * Create the whole Mac window for a given window
594 static void create_cocoa_window(struct macdrv_win_data *data)
596 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
597 WCHAR text[1024];
598 struct macdrv_window_features wf;
599 CGRect frame;
600 DWORD style, ex_style;
601 HRGN win_rgn;
602 COLORREF key;
603 BYTE alpha;
604 DWORD layered_flags;
606 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
607 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
609 DeleteObject(win_rgn);
610 win_rgn = 0;
612 data->shaped = (win_rgn != 0);
614 style = GetWindowLongW(data->hwnd, GWL_STYLE);
615 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
617 data->whole_rect = data->window_rect;
618 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
620 get_cocoa_window_features(data, style, ex_style, &wf);
622 frame = cgrect_from_rect(data->whole_rect);
623 constrain_window_frame(&frame);
624 if (frame.size.width < 1 || frame.size.height < 1)
625 frame.size.width = frame.size.height = 1;
627 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
628 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
630 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
631 if (!data->cocoa_window) goto done;
633 set_cocoa_window_properties(data);
635 /* set the window text */
636 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
637 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
639 /* set the window region */
640 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
642 /* set the window opacity */
643 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
644 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
646 done:
647 if (win_rgn) DeleteObject(win_rgn);
651 /**********************************************************************
652 * destroy_cocoa_window
654 * Destroy the whole Mac window for a given window.
656 static void destroy_cocoa_window(struct macdrv_win_data *data)
658 if (!data->cocoa_window) return;
660 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
662 macdrv_destroy_cocoa_window(data->cocoa_window);
663 data->cocoa_window = 0;
664 data->on_screen = FALSE;
665 data->color_key = CLR_INVALID;
666 if (data->surface) window_surface_release(data->surface);
667 data->surface = NULL;
668 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
669 data->unminimized_surface = NULL;
673 /***********************************************************************
674 * macdrv_create_win_data
676 * Create a Mac data window structure for an existing window.
678 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
679 const RECT *client_rect)
681 struct macdrv_win_data *data;
682 HWND parent;
684 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
686 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
688 macdrv_init_thread_data();
689 return NULL;
692 /* don't create win data for HWND_MESSAGE windows */
693 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
695 if (!(data = alloc_win_data(hwnd))) return NULL;
697 data->whole_rect = data->window_rect = *window_rect;
698 data->client_rect = *client_rect;
700 if (parent == GetDesktopWindow())
702 create_cocoa_window(data);
703 TRACE("win %p/%p window %s whole %s client %s\n",
704 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
705 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
708 return data;
712 /***********************************************************************
713 * show_window
715 static void show_window(struct macdrv_win_data *data)
717 HWND prev = NULL;
718 HWND next = NULL;
719 macdrv_window prev_window = NULL;
720 macdrv_window next_window = NULL;
721 BOOL activate = FALSE;
723 /* find window that this one must be after */
724 prev = GetWindow(data->hwnd, GW_HWNDPREV);
725 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
726 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
727 prev = GetWindow(prev, GW_HWNDPREV);
728 if (!prev_window)
730 /* find window that this one must be before */
731 next = GetWindow(data->hwnd, GW_HWNDNEXT);
732 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
733 (next_window = macdrv_get_cocoa_window(next, TRUE))))
734 next = GetWindow(next, GW_HWNDNEXT);
737 TRACE("win %p/%p below %p/%p above %p/%p\n",
738 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
740 if (!prev_window)
741 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
742 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
743 if (data->on_screen)
745 HWND hwndFocus = GetFocus();
746 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
747 macdrv_SetFocus(hwndFocus);
748 if (activate)
749 activate_on_focus_time = 0;
754 /***********************************************************************
755 * hide_window
757 static void hide_window(struct macdrv_win_data *data)
759 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
761 macdrv_hide_cocoa_window(data->cocoa_window);
762 data->on_screen = FALSE;
766 /***********************************************************************
767 * get_region_data
769 * Calls GetRegionData on the given region and converts the rectangle
770 * array to CGRect format. The returned buffer must be freed by
771 * caller using HeapFree(GetProcessHeap(),...).
772 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
774 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
776 RGNDATA *data;
777 DWORD size;
778 int i;
779 RECT *rect;
780 CGRect *cgrect;
782 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
783 if (sizeof(CGRect) > sizeof(RECT))
785 /* add extra size for CGRect array */
786 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
787 size += count * (sizeof(CGRect) - sizeof(RECT));
789 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
790 if (!GetRegionData(hrgn, size, data))
792 HeapFree(GetProcessHeap(), 0, data);
793 return NULL;
796 rect = (RECT *)data->Buffer;
797 cgrect = (CGRect *)data->Buffer;
798 if (hdc_lptodp) /* map to device coordinates */
800 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
801 for (i = 0; i < data->rdh.nCount; i++)
803 if (rect[i].right < rect[i].left)
805 INT tmp = rect[i].right;
806 rect[i].right = rect[i].left;
807 rect[i].left = tmp;
809 if (rect[i].bottom < rect[i].top)
811 INT tmp = rect[i].bottom;
812 rect[i].bottom = rect[i].top;
813 rect[i].top = tmp;
818 if (sizeof(CGRect) > sizeof(RECT))
820 /* need to start from the end */
821 for (i = data->rdh.nCount-1; i >= 0; i--)
822 cgrect[i] = cgrect_from_rect(rect[i]);
824 else
826 for (i = 0; i < data->rdh.nCount; i++)
827 cgrect[i] = cgrect_from_rect(rect[i]);
829 return data;
833 /***********************************************************************
834 * sync_window_position
836 * Synchronize the Mac window position with the Windows one
838 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
839 const RECT *old_whole_rect)
841 CGRect frame;
843 if (data->minimized) return;
845 frame = cgrect_from_rect(data->whole_rect);
846 constrain_window_frame(&frame);
847 if (frame.size.width < 1 || frame.size.height < 1)
848 frame.size.width = frame.size.height = 1;
850 data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
851 if (old_window_rect && old_whole_rect &&
852 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
853 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
854 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
855 sync_window_region(data, (HRGN)1);
857 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd, data->cocoa_window,
858 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
860 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
861 show_window(data);
865 /***********************************************************************
866 * move_window_bits
868 * Move the window bits when a window is moved.
870 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
871 const RECT *old_client_rect, const RECT *new_client_rect,
872 const RECT *new_window_rect)
874 RECT src_rect = *old_rect;
875 RECT dst_rect = *new_rect;
876 HDC hdc_src, hdc_dst;
877 HRGN rgn;
878 HWND parent = 0;
880 if (!window)
882 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
883 parent = GetAncestor(hwnd, GA_PARENT);
884 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
885 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
887 else
889 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
890 /* make src rect relative to the old position of the window */
891 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
892 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
893 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
896 rgn = CreateRectRgnIndirect(&dst_rect);
897 SelectClipRgn(hdc_dst, rgn);
898 DeleteObject(rgn);
899 ExcludeUpdateRgn(hdc_dst, hwnd);
901 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
902 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
903 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
904 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
905 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
907 ReleaseDC(hwnd, hdc_dst);
908 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
912 /**********************************************************************
913 * activate_on_following_focus
915 void activate_on_following_focus(void)
917 activate_on_focus_time = GetTickCount();
918 if (!activate_on_focus_time) activate_on_focus_time = 1;
922 /**********************************************************************
923 * CreateDesktopWindow (MACDRV.@)
925 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
927 unsigned int width, height;
929 TRACE("%p\n", hwnd);
931 /* retrieve the real size of the desktop */
932 SERVER_START_REQ(get_window_rectangles)
934 req->handle = wine_server_user_handle(hwnd);
935 req->relative = COORDS_CLIENT;
936 wine_server_call(req);
937 width = reply->window.right;
938 height = reply->window.bottom;
940 SERVER_END_REQ;
942 if (!width && !height) /* not initialized yet */
944 CGRect rect = macdrv_get_desktop_rect();
946 SERVER_START_REQ(set_window_pos)
948 req->handle = wine_server_user_handle(hwnd);
949 req->previous = 0;
950 req->swp_flags = SWP_NOZORDER;
951 req->window.left = CGRectGetMinX(rect);
952 req->window.top = CGRectGetMinY(rect);
953 req->window.right = CGRectGetMaxX(rect);
954 req->window.bottom = CGRectGetMaxY(rect);
955 req->client = req->window;
956 wine_server_call(req);
958 SERVER_END_REQ;
961 return TRUE;
965 /**********************************************************************
966 * CreateWindow (MACDRV.@)
968 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
970 return TRUE;
974 /***********************************************************************
975 * DestroyWindow (MACDRV.@)
977 void CDECL macdrv_DestroyWindow(HWND hwnd)
979 struct macdrv_win_data *data;
981 TRACE("%p\n", hwnd);
983 if (!(data = get_win_data(hwnd))) return;
985 if (data->gl_view) macdrv_dispose_view(data->gl_view);
986 destroy_cocoa_window(data);
988 CFDictionaryRemoveValue(win_datas, hwnd);
989 release_win_data(data);
990 HeapFree(GetProcessHeap(), 0, data);
994 /*****************************************************************
995 * SetFocus (MACDRV.@)
997 * Set the Mac focus.
999 void CDECL macdrv_SetFocus(HWND hwnd)
1001 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1002 struct macdrv_win_data *data;
1004 TRACE("%p\n", hwnd);
1006 if (!thread_data) return;
1007 thread_data->dead_key_state = 0;
1009 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
1010 if (!(data = get_win_data(hwnd))) return;
1012 if (data->cocoa_window && data->on_screen)
1014 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
1015 /* Set Mac focus */
1016 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
1017 activate_on_focus_time = 0;
1020 release_win_data(data);
1024 /***********************************************************************
1025 * SetLayeredWindowAttributes (MACDRV.@)
1027 * Set transparency attributes for a layered window.
1029 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1031 struct macdrv_win_data *data = get_win_data(hwnd);
1033 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1035 if (data)
1037 data->layered = TRUE;
1038 if (data->cocoa_window)
1040 sync_window_opacity(data, key, alpha, FALSE, flags);
1041 /* since layered attributes are now set, can now show the window */
1042 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1043 show_window(data);
1045 release_win_data(data);
1047 else
1048 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1052 /*****************************************************************
1053 * SetParent (MACDRV.@)
1055 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1057 struct macdrv_win_data *data;
1059 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1061 if (parent == old_parent) return;
1062 if (!(data = get_win_data(hwnd))) return;
1064 if (parent != GetDesktopWindow()) /* a child window */
1066 if (old_parent == GetDesktopWindow())
1068 /* destroy the old Mac window */
1069 destroy_cocoa_window(data);
1072 else /* new top level window */
1073 create_cocoa_window(data);
1074 release_win_data(data);
1076 set_gl_view_parent(hwnd, parent);
1080 /***********************************************************************
1081 * SetWindowRgn (MACDRV.@)
1083 * Assign specified region to window (for non-rectangular windows)
1085 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1087 struct macdrv_win_data *data;
1089 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1091 if ((data = get_win_data(hwnd)))
1093 sync_window_region(data, hrgn);
1094 release_win_data(data);
1096 else
1098 DWORD procid;
1100 GetWindowThreadProcessId(hwnd, &procid);
1101 if (procid != GetCurrentProcessId())
1102 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1105 return TRUE;
1109 /***********************************************************************
1110 * SetWindowStyle (MACDRV.@)
1112 * Update the state of the Cocoa window to reflect a style change
1114 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1116 struct macdrv_win_data *data;
1118 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1120 if (hwnd == GetDesktopWindow()) return;
1121 if (!(data = get_win_data(hwnd))) return;
1123 if (data->cocoa_window)
1125 DWORD changed = style->styleNew ^ style->styleOld;
1127 set_cocoa_window_properties(data);
1129 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1131 data->layered = FALSE;
1132 data->ulw_layered = FALSE;
1133 sync_window_opacity(data, 0, 0, FALSE, 0);
1134 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1137 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1138 sync_window_region(data, (HRGN)1);
1141 release_win_data(data);
1145 /*****************************************************************
1146 * SetWindowText (MACDRV.@)
1148 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1150 macdrv_window win;
1152 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1154 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1155 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1159 /***********************************************************************
1160 * ShowWindow (MACDRV.@)
1162 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1164 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1165 struct macdrv_win_data *data = get_win_data(hwnd);
1166 CGRect frame;
1168 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1169 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1171 if (!data || !data->cocoa_window) goto done;
1172 if (IsRectEmpty(rect)) goto done;
1173 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1175 if (rect->left != -32000 || rect->top != -32000)
1177 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1178 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1180 goto done;
1182 if (!data->on_screen) goto done;
1184 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1186 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1187 goto done;
1189 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1190 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1191 goto done;
1193 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1194 *rect = rect_from_cgrect(frame);
1195 macdrv_mac_to_window_rect(data, rect);
1196 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1197 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1199 done:
1200 release_win_data(data);
1201 return swp;
1205 /***********************************************************************
1206 * SysCommand (MACDRV.@)
1208 * Perform WM_SYSCOMMAND handling.
1210 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1212 struct macdrv_win_data *data;
1213 LRESULT ret = -1;
1215 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1217 if (!(data = get_win_data(hwnd))) goto done;
1218 if (!data->cocoa_window || !data->on_screen) goto done;
1220 /* prevent a simple ALT press+release from activating the system menu,
1221 as that can get confusing */
1222 if ((wparam & 0xfff0) == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1223 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1225 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1226 ret = 0;
1229 done:
1230 release_win_data(data);
1231 return ret;
1235 /***********************************************************************
1236 * UpdateLayeredWindow (MACDRV.@)
1238 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1239 const RECT *window_rect)
1241 struct window_surface *surface;
1242 struct macdrv_win_data *data;
1243 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1244 BYTE alpha;
1245 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1246 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1247 void *src_bits, *dst_bits;
1248 RECT rect;
1249 HDC hdc = 0;
1250 HBITMAP dib;
1251 BOOL ret = FALSE;
1253 if (!(data = get_win_data(hwnd))) return FALSE;
1255 data->layered = TRUE;
1256 data->ulw_layered = TRUE;
1258 rect = *window_rect;
1259 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1261 surface = data->surface;
1262 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1264 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1265 set_window_surface(data->cocoa_window, data->surface);
1266 if (surface) window_surface_release(surface);
1267 surface = data->surface;
1268 if (data->unminimized_surface)
1270 window_surface_release(data->unminimized_surface);
1271 data->unminimized_surface = NULL;
1274 else set_surface_use_alpha(surface, TRUE);
1276 if (surface) window_surface_add_ref(surface);
1277 release_win_data(data);
1279 if (!surface) return FALSE;
1280 if (!info->hdcSrc)
1282 window_surface_release(surface);
1283 return TRUE;
1286 if (info->dwFlags & ULW_ALPHA)
1288 /* Apply SourceConstantAlpha via window alpha, not blend. */
1289 alpha = info->pblend->SourceConstantAlpha;
1290 blend = *info->pblend;
1291 blend.SourceConstantAlpha = 0xff;
1293 else
1294 alpha = 0xff;
1296 dst_bits = surface->funcs->get_info(surface, bmi);
1298 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1299 if (!(hdc = CreateCompatibleDC(0))) goto done;
1301 SelectObject(hdc, dib);
1302 if (info->prcDirty)
1304 IntersectRect(&rect, &rect, info->prcDirty);
1305 surface->funcs->lock(surface);
1306 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1307 surface->funcs->unlock(surface);
1308 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1310 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1311 info->hdcSrc,
1312 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1313 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1314 rect.right - rect.left, rect.bottom - rect.top,
1315 blend)))
1316 goto done;
1318 if ((data = get_win_data(hwnd)))
1320 if (surface == data->surface)
1322 surface->funcs->lock(surface);
1323 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1324 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1325 surface->funcs->unlock(surface);
1326 surface->funcs->flush(surface);
1329 /* The ULW flags are a superset of the LWA flags. */
1330 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1332 release_win_data(data);
1335 done:
1336 window_surface_release(surface);
1337 if (hdc) DeleteDC(hdc);
1338 if (dib) DeleteObject(dib);
1339 return ret;
1343 /**********************************************************************
1344 * WindowMessage (MACDRV.@)
1346 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1348 struct macdrv_win_data *data;
1350 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1352 switch(msg)
1354 case WM_MACDRV_SET_WIN_REGION:
1355 if ((data = get_win_data(hwnd)))
1357 sync_window_region(data, (HRGN)1);
1358 release_win_data(data);
1360 return 0;
1361 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1362 if (hwnd == GetDesktopWindow())
1364 CGRect new_desktop_rect;
1365 RECT current_desktop_rect;
1367 macdrv_reset_device_metrics();
1368 new_desktop_rect = macdrv_get_desktop_rect();
1369 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1370 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1372 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1373 SMTO_ABORTIFHUNG, 2000, NULL);
1374 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1375 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1376 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1377 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1378 SMTO_ABORTIFHUNG, 2000, NULL);
1381 return 0;
1382 case WM_MACDRV_RESET_DEVICE_METRICS:
1383 macdrv_reset_device_metrics();
1384 return 0;
1385 case WM_MACDRV_DISPLAYCHANGE:
1386 if ((data = get_win_data(hwnd)))
1388 if (data->cocoa_window && data->on_screen)
1389 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
1390 release_win_data(data);
1392 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1393 return 0;
1394 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1395 activate_on_following_focus();
1396 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1397 return 0;
1400 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1401 return 0;
1405 static inline RECT get_surface_rect(const RECT *visible_rect)
1407 RECT rect;
1408 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1410 IntersectRect(&rect, visible_rect, &desktop_rect);
1411 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1412 rect.left &= ~127;
1413 rect.top &= ~127;
1414 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1415 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1416 return rect;
1420 /***********************************************************************
1421 * WindowPosChanging (MACDRV.@)
1423 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1424 const RECT *window_rect, const RECT *client_rect,
1425 RECT *visible_rect, struct window_surface **surface)
1427 struct macdrv_win_data *data = get_win_data(hwnd);
1428 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1429 RECT surface_rect;
1431 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1432 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1433 wine_dbgstr_rect(visible_rect), surface);
1435 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1437 *visible_rect = *window_rect;
1438 macdrv_window_to_mac_rect(data, style, visible_rect);
1439 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1440 wine_dbgstr_rect(visible_rect));
1442 /* create the window surface if necessary */
1443 if (!data->cocoa_window) goto done;
1444 if (swp_flags & SWP_HIDEWINDOW) goto done;
1445 if (data->ulw_layered) goto done;
1447 if (*surface) window_surface_release(*surface);
1448 *surface = NULL;
1450 surface_rect = get_surface_rect(visible_rect);
1451 if (data->surface)
1453 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1455 /* existing surface is good enough */
1456 surface_clip_to_visible_rect(data->surface, visible_rect);
1457 window_surface_add_ref(data->surface);
1458 *surface = data->surface;
1459 goto done;
1462 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1464 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1466 done:
1467 release_win_data(data);
1471 /***********************************************************************
1472 * WindowPosChanged (MACDRV.@)
1474 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1475 const RECT *window_rect, const RECT *client_rect,
1476 const RECT *visible_rect, const RECT *valid_rects,
1477 struct window_surface *surface)
1479 struct macdrv_thread_data *thread_data;
1480 struct macdrv_win_data *data;
1481 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1482 RECT old_window_rect, old_whole_rect, old_client_rect;
1484 if (!(data = get_win_data(hwnd))) return;
1486 thread_data = macdrv_thread_data();
1488 old_window_rect = data->window_rect;
1489 old_whole_rect = data->whole_rect;
1490 old_client_rect = data->client_rect;
1491 data->window_rect = *window_rect;
1492 data->whole_rect = *visible_rect;
1493 data->client_rect = *client_rect;
1494 if (!data->ulw_layered)
1496 if (surface) window_surface_add_ref(surface);
1497 if (new_style & WS_MINIMIZE)
1499 if (!data->unminimized_surface && data->surface)
1501 data->unminimized_surface = data->surface;
1502 window_surface_add_ref(data->unminimized_surface);
1505 else
1507 set_window_surface(data->cocoa_window, surface);
1508 if (data->unminimized_surface)
1510 window_surface_release(data->unminimized_surface);
1511 data->unminimized_surface = NULL;
1514 if (data->surface) window_surface_release(data->surface);
1515 data->surface = surface;
1518 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1519 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1520 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1521 new_style, swp_flags, surface);
1523 if (!IsRectEmpty(&valid_rects[0]))
1525 macdrv_window window = data->cocoa_window;
1526 int x_offset = old_whole_rect.left - data->whole_rect.left;
1527 int y_offset = old_whole_rect.top - data->whole_rect.top;
1529 /* if all that happened is that the whole window moved, copy everything */
1530 if (!(swp_flags & SWP_FRAMECHANGED) &&
1531 old_whole_rect.right - data->whole_rect.right == x_offset &&
1532 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1533 old_client_rect.left - data->client_rect.left == x_offset &&
1534 old_client_rect.right - data->client_rect.right == x_offset &&
1535 old_client_rect.top - data->client_rect.top == y_offset &&
1536 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1537 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1539 /* A Cocoa window's bits are moved automatically */
1540 if (!window && (x_offset != 0 || y_offset != 0))
1542 release_win_data(data);
1543 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1544 &old_client_rect, client_rect, window_rect);
1545 if (!(data = get_win_data(hwnd))) return;
1548 else
1550 release_win_data(data);
1551 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1552 &old_client_rect, client_rect, window_rect);
1553 if (!(data = get_win_data(hwnd))) return;
1557 sync_gl_view(data);
1559 if (!data->cocoa_window) goto done;
1561 if (data->on_screen)
1563 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1564 hide_window(data);
1567 /* check if we are currently processing an event relevant to this window */
1568 if (!thread_data || !thread_data->current_event ||
1569 thread_data->current_event->window != data->cocoa_window ||
1570 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1571 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1573 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
1574 set_cocoa_window_properties(data);
1577 if (new_style & WS_VISIBLE)
1579 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1580 set_cocoa_window_properties(data);
1582 /* layered windows are not shown until their attributes are set */
1583 if (!data->on_screen &&
1584 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1585 show_window(data);
1588 done:
1589 release_win_data(data);
1593 /***********************************************************************
1594 * macdrv_window_close_requested
1596 * Handler for WINDOW_CLOSE_REQUESTED events.
1598 void macdrv_window_close_requested(HWND hwnd)
1600 /* Ignore the delete window request if the window has been disabled. This
1601 * is to disallow applications from being closed while in a modal state.
1603 if (IsWindowEnabled(hwnd))
1605 HMENU hSysMenu;
1607 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
1608 hSysMenu = GetSystemMenu(hwnd, FALSE);
1609 if (hSysMenu)
1611 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1612 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1613 return;
1615 if (GetActiveWindow() != hwnd)
1617 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1618 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1619 MAKELPARAM(HTCLOSE, WM_NCLBUTTONDOWN));
1620 switch(ma)
1622 case MA_NOACTIVATEANDEAT:
1623 case MA_ACTIVATEANDEAT:
1624 return;
1625 case MA_NOACTIVATE:
1626 break;
1627 case MA_ACTIVATE:
1628 case 0:
1629 SetActiveWindow(hwnd);
1630 break;
1631 default:
1632 WARN("unknown WM_MOUSEACTIVATE code %d\n", (int) ma);
1633 break;
1637 PostMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1642 /***********************************************************************
1643 * macdrv_window_frame_changed
1645 * Handler for WINDOW_FRAME_CHANGED events.
1647 void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
1649 struct macdrv_win_data *data;
1650 RECT rect;
1651 HWND parent;
1652 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1653 int width, height;
1655 if (!hwnd) return;
1656 if (!(data = get_win_data(hwnd))) return;
1657 if (!data->on_screen || data->minimized)
1659 release_win_data(data);
1660 return;
1663 /* Get geometry */
1665 parent = GetAncestor(hwnd, GA_PARENT);
1667 TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
1669 rect = rect_from_cgrect(frame);
1670 macdrv_mac_to_window_rect(data, &rect);
1671 MapWindowPoints(0, parent, (POINT *)&rect, 2);
1673 width = rect.right - rect.left;
1674 height = rect.bottom - rect.top;
1676 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1677 flags |= SWP_NOMOVE;
1678 else
1679 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1680 data->window_rect.top, rect.left, rect.top);
1682 if ((data->window_rect.right - data->window_rect.left == width &&
1683 data->window_rect.bottom - data->window_rect.top == height) ||
1684 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
1685 flags |= SWP_NOSIZE;
1686 else
1687 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1688 data->window_rect.bottom - data->window_rect.top, width, height);
1690 release_win_data(data);
1692 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1693 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1697 /***********************************************************************
1698 * macdrv_window_got_focus
1700 * Handler for WINDOW_GOT_FOCUS events.
1702 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1704 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1706 if (!hwnd) return;
1708 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1709 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
1710 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
1712 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
1714 /* simulate a mouse click on the caption to find out
1715 * whether the window wants to be activated */
1716 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1717 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1718 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
1719 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
1721 TRACE("setting foreground window to %p\n", hwnd);
1722 SetForegroundWindow(hwnd);
1723 return;
1727 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
1728 macdrv_window_rejected_focus(event);
1732 /***********************************************************************
1733 * macdrv_window_lost_focus
1735 * Handler for WINDOW_LOST_FOCUS events.
1737 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
1739 if (!hwnd) return;
1741 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
1743 if (hwnd == GetForegroundWindow())
1745 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
1746 if (hwnd == GetForegroundWindow())
1747 SetForegroundWindow(GetDesktopWindow());
1752 /***********************************************************************
1753 * macdrv_app_deactivated
1755 * Handler for APP_DEACTIVATED events.
1757 void macdrv_app_deactivated(void)
1759 if (GetActiveWindow() == GetForegroundWindow())
1761 TRACE("setting fg to desktop\n");
1762 SetForegroundWindow(GetDesktopWindow());
1767 /***********************************************************************
1768 * macdrv_window_minimize_requested
1770 * Handler for WINDOW_MINIMIZE_REQUESTED events.
1772 void macdrv_window_minimize_requested(HWND hwnd)
1774 DWORD style;
1775 HMENU hSysMenu;
1777 style = GetWindowLongW(hwnd, GWL_STYLE);
1778 if (!(style & WS_MINIMIZEBOX) || (style & (WS_DISABLED | WS_MINIMIZE)))
1780 TRACE("not minimizing win %p style 0x%08x\n", hwnd, style);
1781 return;
1784 hSysMenu = GetSystemMenu(hwnd, FALSE);
1785 if (hSysMenu)
1787 UINT state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1788 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1790 TRACE("not minimizing win %p menu state 0x%08x\n", hwnd, state);
1791 return;
1795 if (GetActiveWindow() != hwnd)
1797 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1798 MAKELPARAM(HTMINBUTTON, WM_NCLBUTTONDOWN));
1799 switch (ma)
1801 case MA_NOACTIVATEANDEAT:
1802 case MA_ACTIVATEANDEAT:
1803 TRACE("not minimizing win %p mouse-activate result %ld\n", hwnd, ma);
1804 return;
1805 case MA_NOACTIVATE:
1806 break;
1807 case MA_ACTIVATE:
1808 case 0:
1809 SetActiveWindow(hwnd);
1810 break;
1811 default:
1812 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1813 break;
1817 TRACE("minimizing win %p\n", hwnd);
1818 SendMessageW(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1822 /***********************************************************************
1823 * macdrv_window_did_unminimize
1825 * Handler for WINDOW_DID_UNMINIMIZE events.
1827 void macdrv_window_did_unminimize(HWND hwnd)
1829 struct macdrv_win_data *data;
1830 DWORD style;
1832 TRACE("win %p\n", hwnd);
1834 if (!(data = get_win_data(hwnd))) return;
1835 if (!data->minimized) goto done;
1837 style = GetWindowLongW(hwnd, GWL_STYLE);
1839 data->minimized = FALSE;
1840 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1842 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
1843 release_win_data(data);
1844 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1845 return;
1848 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1850 done:
1851 release_win_data(data);
1855 struct quit_info {
1856 HWND *wins;
1857 UINT capacity;
1858 UINT count;
1859 UINT done;
1860 DWORD flags;
1861 BOOL result;
1862 BOOL replied;
1866 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
1868 struct quit_info *qi = (struct quit_info*)lp;
1869 DWORD pid;
1871 GetWindowThreadProcessId(hwnd, &pid);
1872 if (pid == GetCurrentProcessId())
1874 if (qi->count >= qi->capacity)
1876 UINT new_cap = qi->capacity * 2;
1877 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
1878 new_cap * sizeof(*qi->wins));
1879 if (!new_wins) return FALSE;
1880 qi->wins = new_wins;
1881 qi->capacity = new_cap;
1884 qi->wins[qi->count++] = hwnd;
1887 return TRUE;
1891 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
1893 struct quit_info *qi = (struct quit_info*)data;
1895 qi->done++;
1897 if (msg == WM_QUERYENDSESSION)
1899 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
1900 hwnd, qi->done, qi->count);
1902 if (!result && qi->result)
1904 qi->result = FALSE;
1906 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
1907 ultimate reply. Might as well tell Cocoa now. */
1908 if (!qi->replied)
1910 qi->replied = TRUE;
1911 TRACE("giving quit reply %d\n", qi->result);
1912 macdrv_quit_reply(qi->result);
1916 if (qi->done >= qi->count)
1918 UINT i;
1920 qi->done = 0;
1921 for (i = 0; i < qi->count; i++)
1923 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
1924 qi->result, qi->flags);
1925 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
1926 quit_callback, (ULONG_PTR)qi))
1928 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
1929 qi->wins[i], GetLastError());
1930 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
1935 else /* WM_ENDSESSION */
1937 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
1939 if (qi->done >= qi->count)
1941 if (!qi->replied)
1943 TRACE("giving quit reply %d\n", qi->result);
1944 macdrv_quit_reply(qi->result);
1947 TRACE("%sterminating process\n", qi->result ? "" : "not ");
1948 if (qi->result)
1949 TerminateProcess(GetCurrentProcess(), 0);
1951 HeapFree(GetProcessHeap(), 0, qi->wins);
1952 HeapFree(GetProcessHeap(), 0, qi);
1958 /***********************************************************************
1959 * macdrv_app_quit_requested
1961 * Handler for APP_QUIT_REQUESTED events.
1963 void macdrv_app_quit_requested(const macdrv_event *event)
1965 struct quit_info *qi;
1966 UINT i;
1968 TRACE("reason %d\n", event->app_quit_requested.reason);
1970 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
1971 if (!qi)
1972 goto fail;
1974 qi->capacity = 32;
1975 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
1976 qi->count = qi->done = 0;
1978 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
1979 goto fail;
1981 switch (event->app_quit_requested.reason)
1983 case QUIT_REASON_LOGOUT:
1984 default:
1985 qi->flags = ENDSESSION_LOGOFF;
1986 break;
1987 case QUIT_REASON_RESTART:
1988 case QUIT_REASON_SHUTDOWN:
1989 qi->flags = 0;
1990 break;
1993 qi->result = TRUE;
1994 qi->replied = FALSE;
1996 for (i = 0; i < qi->count; i++)
1998 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
1999 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2000 quit_callback, (ULONG_PTR)qi))
2002 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2003 qi->wins[i], GetLastError());
2004 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, FALSE);
2008 /* quit_callback() will clean up qi */
2009 return;
2011 fail:
2012 WARN("failed to allocate window list\n");
2013 if (qi)
2015 HeapFree(GetProcessHeap(), 0, qi->wins);
2016 HeapFree(GetProcessHeap(), 0, qi);
2018 macdrv_quit_reply(FALSE);
2022 /***********************************************************************
2023 * query_resize_start
2025 * Handler for QUERY_RESIZE_START query.
2027 BOOL query_resize_start(HWND hwnd)
2029 TRACE("hwnd %p\n", hwnd);
2031 sync_window_min_max_info(hwnd);
2032 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2034 return TRUE;
2038 /***********************************************************************
2039 * query_resize_end
2041 * Handler for QUERY_RESIZE_END query.
2043 BOOL query_resize_end(HWND hwnd)
2045 TRACE("hwnd %p\n", hwnd);
2046 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2047 return TRUE;