wined3d: Use wined3d_texture_prepare_location() in wined3d_texture_update_desc().
[wine.git] / dlls / winemac.drv / window.c
blob0d507f4611f6dec9505fb23e949496dacbb7cf40
1 /*
2 * MACDRV windowing driver
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
7 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
26 #include "macdrv.h"
27 #include "winuser.h"
28 #include "wine/unicode.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
34 static CRITICAL_SECTION win_data_section;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
37 0, 0, &win_data_section,
38 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
41 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
43 static CFMutableDictionaryRef win_datas;
45 static DWORD activate_on_focus_time;
48 void CDECL macdrv_SetFocus(HWND hwnd);
51 /***********************************************************************
52 * get_cocoa_window_features
54 static void get_cocoa_window_features(struct macdrv_win_data *data,
55 DWORD style, DWORD ex_style,
56 struct macdrv_window_features* wf)
58 memset(wf, 0, sizeof(*wf));
60 if (disable_window_decorations) return;
61 if (IsRectEmpty(&data->window_rect)) return;
63 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
65 wf->shadow = TRUE;
66 if (!data->shaped)
68 wf->title_bar = TRUE;
69 if (style & WS_SYSMENU) wf->close_button = TRUE;
70 if (style & WS_MINIMIZEBOX) wf->minimize_button = TRUE;
71 if (style & WS_MAXIMIZEBOX) wf->maximize_button = TRUE;
72 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = TRUE;
75 if (style & WS_THICKFRAME)
77 wf->shadow = TRUE;
78 if (!data->shaped) wf->resizable = TRUE;
80 else if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = TRUE;
81 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = TRUE;
85 /*******************************************************************
86 * can_activate_window
88 * Check if we can activate the specified window.
90 static inline BOOL can_activate_window(HWND hwnd)
92 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
94 if (!(style & WS_VISIBLE)) return FALSE;
95 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
96 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
97 if (hwnd == GetDesktopWindow()) return FALSE;
98 return !(style & WS_DISABLED);
102 /***********************************************************************
103 * get_cocoa_window_state
105 static void get_cocoa_window_state(struct macdrv_win_data *data,
106 DWORD style, DWORD ex_style,
107 struct macdrv_window_state* state)
109 memset(state, 0, sizeof(*state));
110 state->disabled = (style & WS_DISABLED) != 0;
111 state->no_activate = !can_activate_window(data->hwnd);
112 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
113 state->excluded_by_expose = state->excluded_by_cycle =
114 (!(ex_style & WS_EX_APPWINDOW) &&
115 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
116 if (IsRectEmpty(&data->window_rect))
117 state->excluded_by_expose = TRUE;
118 state->minimized = (style & WS_MINIMIZE) != 0;
119 state->minimized_valid = state->minimized != data->minimized;
120 state->maximized = (style & WS_MAXIMIZE) != 0;
124 /***********************************************************************
125 * get_mac_rect_offset
127 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
129 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
131 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
133 rect->top = rect->bottom = rect->left = rect->right = 0;
135 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
137 if (!data->shaped)
139 struct macdrv_window_features wf;
140 get_cocoa_window_features(data, style, ex_style, &wf);
142 if (wf.title_bar)
144 style_mask |= WS_CAPTION;
145 ex_style_mask |= WS_EX_TOOLWINDOW;
147 if (wf.shadow)
149 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
150 ex_style_mask |= WS_EX_DLGMODALFRAME;
154 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
156 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
157 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
161 /***********************************************************************
162 * macdrv_window_to_mac_rect
164 * Convert a rect from client to Mac window coordinates
166 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
168 RECT rc;
170 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
171 if (IsRectEmpty(rect)) return;
173 get_mac_rect_offset(data, style, &rc);
175 rect->left -= rc.left;
176 rect->right -= rc.right;
177 rect->top -= rc.top;
178 rect->bottom -= rc.bottom;
179 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
180 if (rect->left >= rect->right) rect->right = rect->left + 1;
184 /***********************************************************************
185 * macdrv_mac_to_window_rect
187 * Opposite of macdrv_window_to_mac_rect
189 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
191 RECT rc;
192 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
194 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
195 if (IsRectEmpty(rect)) return;
197 get_mac_rect_offset(data, style, &rc);
199 rect->left += rc.left;
200 rect->right += rc.right;
201 rect->top += rc.top;
202 rect->bottom += rc.bottom;
203 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
204 if (rect->left >= rect->right) rect->right = rect->left + 1;
208 /***********************************************************************
209 * constrain_window_frame
211 * Alter a window frame rectangle to fit within a) Cocoa's documented
212 * limits, and b) sane sizes, like twice the desktop rect.
214 static void constrain_window_frame(CGRect* frame)
216 CGRect desktop_rect = macdrv_get_desktop_rect();
217 int max_width, max_height;
219 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
220 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
222 if (frame->origin.x < -16000) frame->origin.x = -16000;
223 if (frame->origin.y < -16000) frame->origin.y = -16000;
224 if (frame->origin.x > 16000) frame->origin.x = 16000;
225 if (frame->origin.y > 16000) frame->origin.y = 16000;
226 if (frame->size.width > max_width) frame->size.width = max_width;
227 if (frame->size.height > max_height) frame->size.height = max_height;
231 /***********************************************************************
232 * alloc_win_data
234 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
236 struct macdrv_win_data *data;
238 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
240 data->hwnd = hwnd;
241 data->color_key = CLR_INVALID;
242 data->swap_interval = 1;
243 EnterCriticalSection(&win_data_section);
244 if (!win_datas)
245 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
246 CFDictionarySetValue(win_datas, hwnd, data);
248 return data;
252 /***********************************************************************
253 * get_win_data
255 * Lock and return the data structure associated with a window.
257 struct macdrv_win_data *get_win_data(HWND hwnd)
259 struct macdrv_win_data *data;
261 if (!hwnd) return NULL;
262 EnterCriticalSection(&win_data_section);
263 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
264 return data;
265 LeaveCriticalSection(&win_data_section);
266 return NULL;
270 /***********************************************************************
271 * release_win_data
273 * Release the data returned by get_win_data.
275 void release_win_data(struct macdrv_win_data *data)
277 if (data) LeaveCriticalSection(&win_data_section);
281 /***********************************************************************
282 * macdrv_get_cocoa_window
284 * Return the Mac window associated with the full area of a window
286 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
288 struct macdrv_win_data *data = get_win_data(hwnd);
289 macdrv_window ret = NULL;
290 if (data && (data->on_screen || !require_on_screen))
291 ret = data->cocoa_window;
292 release_win_data(data);
293 return ret;
297 /***********************************************************************
298 * macdrv_get_cocoa_view
300 * Return the Cocoa view associated with a window
302 macdrv_view macdrv_get_cocoa_view(HWND hwnd)
304 struct macdrv_win_data *data = get_win_data(hwnd);
305 macdrv_view ret = data ? data->cocoa_view : NULL;
307 release_win_data(data);
308 return ret;
312 /***********************************************************************
313 * macdrv_get_client_cocoa_view
315 * Return the Cocoa view associated with a window's client area
317 macdrv_view macdrv_get_client_cocoa_view(HWND hwnd)
319 struct macdrv_win_data *data = get_win_data(hwnd);
320 macdrv_view ret = data ? data->client_cocoa_view : NULL;
322 release_win_data(data);
323 return ret;
327 /***********************************************************************
328 * set_cocoa_window_properties
330 * Set the window properties for a Cocoa window based on its Windows
331 * properties.
333 static void set_cocoa_window_properties(struct macdrv_win_data *data)
335 DWORD style, ex_style;
336 HWND owner;
337 macdrv_window owner_win;
338 struct macdrv_window_features wf;
339 struct macdrv_window_state state;
341 style = GetWindowLongW(data->hwnd, GWL_STYLE);
342 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
344 owner = GetWindow(data->hwnd, GW_OWNER);
345 owner_win = macdrv_get_cocoa_window(owner, TRUE);
346 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
348 get_cocoa_window_features(data, style, ex_style, &wf);
349 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
351 get_cocoa_window_state(data, style, ex_style, &state);
352 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
353 if (state.minimized_valid)
354 data->minimized = state.minimized;
358 /***********************************************************************
359 * sync_window_region
361 * Update the window region.
363 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
365 HRGN hrgn = win_region;
366 RGNDATA *region_data;
367 const CGRect* rects;
368 int count;
370 if (!data->cocoa_window) return;
371 data->shaped = FALSE;
373 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
375 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
376 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
377 return;
380 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
382 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
383 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
385 DeleteObject(hrgn);
386 hrgn = 0;
390 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
391 MirrorRgn(data->hwnd, hrgn);
392 if (hrgn)
394 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
395 data->window_rect.top - data->whole_rect.top);
397 region_data = get_region_data(hrgn, 0);
398 if (region_data)
400 rects = (CGRect*)region_data->Buffer;
401 count = region_data->rdh.nCount;
402 /* Special case optimization. If the region entirely encloses the Cocoa
403 window, it's the same as there being no region. It's potentially
404 hard/slow to test this for arbitrary regions, so we just check for
405 very simple regions. */
406 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
408 TRACE("optimizing for simple region that contains Cocoa content rect\n");
409 rects = NULL;
410 count = 0;
413 else
415 rects = NULL;
416 count = 0;
419 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
420 macdrv_set_window_shape(data->cocoa_window, rects, count);
422 HeapFree(GetProcessHeap(), 0, region_data);
423 data->shaped = (region_data != NULL);
425 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
429 /***********************************************************************
430 * add_bounds_rect
432 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
434 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
435 bounds->left = min(bounds->left, rect->left);
436 bounds->top = min(bounds->top, rect->top);
437 bounds->right = max(bounds->right, rect->right);
438 bounds->bottom = max(bounds->bottom, rect->bottom);
442 /***********************************************************************
443 * sync_window_opacity
445 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
446 BOOL per_pixel_alpha, DWORD flags)
448 CGFloat opacity = 1.0;
449 BOOL needs_flush = FALSE;
451 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
453 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
454 macdrv_set_window_alpha(data->cocoa_window, opacity);
456 if (flags & LWA_COLORKEY)
458 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
459 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
460 key = RGB(0, 0, 0);
462 else
463 key = CLR_INVALID;
465 if (data->color_key != key)
467 if (key == CLR_INVALID)
469 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
470 macdrv_clear_window_color_key(data->cocoa_window);
472 else
474 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
475 GetRValue(key), GetGValue(key), GetBValue(key));
476 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
479 data->color_key = key;
480 needs_flush = TRUE;
483 if (!data->per_pixel_alpha != !per_pixel_alpha)
485 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
486 data->per_pixel_alpha = per_pixel_alpha;
487 needs_flush = TRUE;
490 if (needs_flush && data->surface)
492 RECT *bounds;
493 RECT rect;
495 rect = data->whole_rect;
496 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
497 data->surface->funcs->lock(data->surface);
498 bounds = data->surface->funcs->get_bounds(data->surface);
499 add_bounds_rect(bounds, &rect);
500 data->surface->funcs->unlock(data->surface);
505 /***********************************************************************
506 * sync_window_min_max_info
508 static void sync_window_min_max_info(HWND hwnd)
510 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
511 LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
512 RECT win_rect, primary_monitor_rect;
513 MINMAXINFO minmax;
514 LONG adjustedStyle;
515 INT xinc, yinc;
516 WINDOWPLACEMENT wpl;
517 HMONITOR monitor;
518 struct macdrv_win_data *data;
520 TRACE("win %p\n", hwnd);
522 if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
524 GetWindowRect(hwnd, &win_rect);
525 minmax.ptReserved.x = win_rect.left;
526 minmax.ptReserved.y = win_rect.top;
528 if ((style & WS_CAPTION) == WS_CAPTION)
529 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
530 else
531 adjustedStyle = style;
533 primary_monitor_rect.left = primary_monitor_rect.top = 0;
534 primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
535 primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
536 AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
538 xinc = -primary_monitor_rect.left;
539 yinc = -primary_monitor_rect.top;
541 minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
542 minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
543 minmax.ptMaxPosition.x = -xinc;
544 minmax.ptMaxPosition.y = -yinc;
545 if (style & (WS_DLGFRAME | WS_BORDER))
547 minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
548 minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
550 else
552 minmax.ptMinTrackSize.x = 2 * xinc;
553 minmax.ptMinTrackSize.y = 2 * yinc;
555 minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
556 minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
558 wpl.length = sizeof(wpl);
559 if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
561 minmax.ptMaxPosition = wpl.ptMaxPosition;
563 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
564 minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
565 minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
568 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
569 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
571 SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
573 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
574 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
576 /* if the app didn't change the values, adapt them for the window's monitor */
577 if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
579 MONITORINFO mon_info;
580 RECT monitor_rect;
582 mon_info.cbSize = sizeof(mon_info);
583 GetMonitorInfoW(monitor, &mon_info);
585 if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
586 monitor_rect = mon_info.rcWork;
587 else
588 monitor_rect = mon_info.rcMonitor;
590 if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
591 minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
593 minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
594 minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
596 if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
598 minmax.ptMaxPosition.x = monitor_rect.left - xinc;
599 minmax.ptMaxPosition.y = monitor_rect.top - yinc;
603 minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
604 minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
606 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
607 wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
609 if ((data = get_win_data(hwnd)) && data->cocoa_window)
611 RECT min_rect, max_rect;
612 CGSize min_size, max_size;
614 SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
615 macdrv_window_to_mac_rect(data, style, &min_rect);
616 min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
618 if (minmax.ptMaxTrackSize.x == GetSystemMetrics(SM_CXMAXTRACK) &&
619 minmax.ptMaxTrackSize.y == GetSystemMetrics(SM_CYMAXTRACK))
620 max_size = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
621 else
623 SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
624 macdrv_window_to_mac_rect(data, style, &max_rect);
625 max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
628 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
629 macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
632 release_win_data(data);
636 /**********************************************************************
637 * create_client_cocoa_view
639 * Create the Cocoa view for a window's client area
641 static void create_client_cocoa_view(struct macdrv_win_data *data)
643 RECT rect = data->client_rect;
644 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
646 if (data->client_cocoa_view)
647 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
648 else
650 data->client_cocoa_view = macdrv_create_view(cgrect_from_rect(rect));
651 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
653 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, data->cocoa_window, NULL, NULL);
657 /**********************************************************************
658 * create_cocoa_window
660 * Create the whole Mac window for a given window
662 static void create_cocoa_window(struct macdrv_win_data *data)
664 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
665 WCHAR text[1024];
666 struct macdrv_window_features wf;
667 CGRect frame;
668 DWORD style, ex_style;
669 HRGN win_rgn;
670 COLORREF key;
671 BYTE alpha;
672 DWORD layered_flags;
674 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
675 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
677 DeleteObject(win_rgn);
678 win_rgn = 0;
680 data->shaped = (win_rgn != 0);
682 style = GetWindowLongW(data->hwnd, GWL_STYLE);
683 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
685 data->whole_rect = data->window_rect;
686 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
688 get_cocoa_window_features(data, style, ex_style, &wf);
690 frame = cgrect_from_rect(data->whole_rect);
691 constrain_window_frame(&frame);
692 if (frame.size.width < 1 || frame.size.height < 1)
693 frame.size.width = frame.size.height = 1;
695 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
696 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
698 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
699 if (!data->cocoa_window) goto done;
700 create_client_cocoa_view(data);
702 set_cocoa_window_properties(data);
704 /* set the window text */
705 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
706 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
708 /* set the window region */
709 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
711 /* set the window opacity */
712 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
713 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
715 done:
716 if (win_rgn) DeleteObject(win_rgn);
720 /**********************************************************************
721 * destroy_cocoa_window
723 * Destroy the whole Mac window for a given window.
725 static void destroy_cocoa_window(struct macdrv_win_data *data)
727 if (!data->cocoa_window) return;
729 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
731 macdrv_destroy_cocoa_window(data->cocoa_window);
732 data->cocoa_window = 0;
733 data->on_screen = FALSE;
734 data->color_key = CLR_INVALID;
735 if (data->surface) window_surface_release(data->surface);
736 data->surface = NULL;
737 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
738 data->unminimized_surface = NULL;
742 /**********************************************************************
743 * create_cocoa_view
745 * Create the Cocoa view for a given Windows child window
747 static void create_cocoa_view(struct macdrv_win_data *data)
749 BOOL equal = !memcmp(&data->window_rect, &data->client_rect, sizeof(data->whole_rect));
750 CGRect frame = cgrect_from_rect(data->window_rect);
752 data->shaped = FALSE;
753 data->whole_rect = data->window_rect;
755 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
756 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
758 if (!equal)
759 data->cocoa_view = macdrv_create_view(frame);
760 create_client_cocoa_view(data);
761 if (equal)
763 data->cocoa_view = data->client_cocoa_view;
764 macdrv_set_view_hidden(data->cocoa_view, TRUE);
765 macdrv_set_view_frame(data->cocoa_view, frame);
770 /**********************************************************************
771 * destroy_cocoa_view
773 * Destroy the Cocoa view for a given window.
775 static void destroy_cocoa_view(struct macdrv_win_data *data)
777 if (!data->cocoa_view) return;
779 TRACE("win %p Cocoa view %p\n", data->hwnd, data->cocoa_view);
781 if (data->cocoa_view != data->client_cocoa_view)
782 macdrv_dispose_view(data->cocoa_view);
783 data->cocoa_view = NULL;
784 data->on_screen = FALSE;
788 /***********************************************************************
789 * macdrv_create_win_data
791 * Create a Mac data window structure for an existing window.
793 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
794 const RECT *client_rect)
796 struct macdrv_win_data *data;
797 HWND parent;
799 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
801 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
803 macdrv_init_thread_data();
804 return NULL;
807 /* don't create win data for HWND_MESSAGE windows */
808 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
810 if (!(data = alloc_win_data(hwnd))) return NULL;
812 data->whole_rect = data->window_rect = *window_rect;
813 data->client_rect = *client_rect;
815 if (parent == GetDesktopWindow())
817 create_cocoa_window(data);
818 TRACE("win %p/%p window %s whole %s client %s\n",
819 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
820 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
822 else
824 create_cocoa_view(data);
825 TRACE("win %p/%p window %s whole %s client %s\n",
826 hwnd, data->cocoa_view, wine_dbgstr_rect(&data->window_rect),
827 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
830 return data;
834 /***********************************************************************
835 * show_window
837 static void show_window(struct macdrv_win_data *data)
839 if (data->cocoa_window)
841 HWND prev = NULL;
842 HWND next = NULL;
843 macdrv_window prev_window = NULL;
844 macdrv_window next_window = NULL;
845 BOOL activate = FALSE;
846 HWND hwndFocus;
848 /* find window that this one must be after */
849 prev = GetWindow(data->hwnd, GW_HWNDPREV);
850 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
851 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
852 prev = GetWindow(prev, GW_HWNDPREV);
853 if (!prev_window)
855 /* find window that this one must be before */
856 next = GetWindow(data->hwnd, GW_HWNDNEXT);
857 while (next && !((GetWindowLongW(next, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
858 (next_window = macdrv_get_cocoa_window(next, TRUE))))
859 next = GetWindow(next, GW_HWNDNEXT);
862 TRACE("win %p/%p below %p/%p above %p/%p\n",
863 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
865 if (!prev_window)
866 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
867 macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
868 data->on_screen = TRUE;
870 hwndFocus = GetFocus();
871 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
872 macdrv_SetFocus(hwndFocus);
873 if (activate)
874 activate_on_focus_time = 0;
876 else
878 TRACE("win %p/%p showing view\n", data->hwnd, data->cocoa_view);
880 macdrv_set_view_hidden(data->cocoa_view, FALSE);
881 data->on_screen = TRUE;
886 /***********************************************************************
887 * hide_window
889 static void hide_window(struct macdrv_win_data *data)
891 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
893 if (data->cocoa_window)
894 macdrv_hide_cocoa_window(data->cocoa_window);
895 else
896 macdrv_set_view_hidden(data->cocoa_view, TRUE);
897 data->on_screen = FALSE;
901 /***********************************************************************
902 * sync_window_z_order
904 static void sync_window_z_order(struct macdrv_win_data *data)
906 if (data->cocoa_view)
908 HWND parent = GetAncestor(data->hwnd, GA_PARENT);
909 macdrv_view superview = macdrv_get_client_cocoa_view(parent);
910 macdrv_window window = NULL;
911 HWND prev;
912 HWND next = NULL;
913 macdrv_view prev_view = NULL;
914 macdrv_view next_view = NULL;
916 if (!superview)
918 window = macdrv_get_cocoa_window(parent, FALSE);
919 if (!window)
920 WARN("hwnd %p/%p parent %p has no Cocoa window or view in this process\n", data->hwnd, data->cocoa_view, parent);
923 /* find window that this one must be after */
924 prev = GetWindow(data->hwnd, GW_HWNDPREV);
925 while (prev && !(prev_view = macdrv_get_cocoa_view(prev)))
926 prev = GetWindow(prev, GW_HWNDPREV);
927 if (!prev_view)
929 /* find window that this one must be before */
930 next = GetWindow(data->hwnd, GW_HWNDNEXT);
931 while (next && !(next_view = macdrv_get_cocoa_view(next)))
932 next = GetWindow(next, GW_HWNDNEXT);
935 TRACE("win %p/%p below %p/%p above %p/%p\n",
936 data->hwnd, data->cocoa_view, prev, prev_view, next, next_view);
938 macdrv_set_view_superview(data->cocoa_view, superview, window, prev_view, next_view);
940 else if (data->on_screen)
941 show_window(data);
945 /***********************************************************************
946 * get_region_data
948 * Calls GetRegionData on the given region and converts the rectangle
949 * array to CGRect format. The returned buffer must be freed by
950 * caller using HeapFree(GetProcessHeap(),...).
951 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
953 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
955 RGNDATA *data;
956 DWORD size;
957 int i;
958 RECT *rect;
959 CGRect *cgrect;
961 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
962 if (sizeof(CGRect) > sizeof(RECT))
964 /* add extra size for CGRect array */
965 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
966 size += count * (sizeof(CGRect) - sizeof(RECT));
968 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
969 if (!GetRegionData(hrgn, size, data))
971 HeapFree(GetProcessHeap(), 0, data);
972 return NULL;
975 rect = (RECT *)data->Buffer;
976 cgrect = (CGRect *)data->Buffer;
977 if (hdc_lptodp) /* map to device coordinates */
979 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
980 for (i = 0; i < data->rdh.nCount; i++)
982 if (rect[i].right < rect[i].left)
984 INT tmp = rect[i].right;
985 rect[i].right = rect[i].left;
986 rect[i].left = tmp;
988 if (rect[i].bottom < rect[i].top)
990 INT tmp = rect[i].bottom;
991 rect[i].bottom = rect[i].top;
992 rect[i].top = tmp;
997 if (sizeof(CGRect) > sizeof(RECT))
999 /* need to start from the end */
1000 for (i = data->rdh.nCount-1; i >= 0; i--)
1001 cgrect[i] = cgrect_from_rect(rect[i]);
1003 else
1005 for (i = 0; i < data->rdh.nCount; i++)
1006 cgrect[i] = cgrect_from_rect(rect[i]);
1008 return data;
1012 /***********************************************************************
1013 * sync_window_position
1015 * Synchronize the Mac window position with the Windows one
1017 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect,
1018 const RECT *old_whole_rect)
1020 CGRect frame = cgrect_from_rect(data->whole_rect);
1021 BOOL force_z_order = FALSE;
1023 if (data->cocoa_window)
1025 if (data->minimized) return;
1027 constrain_window_frame(&frame);
1028 if (frame.size.width < 1 || frame.size.height < 1)
1029 frame.size.width = frame.size.height = 1;
1031 macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
1033 else
1035 BOOL were_equal = (data->cocoa_view == data->client_cocoa_view);
1036 BOOL now_equal = !memcmp(&data->whole_rect, &data->client_rect, sizeof(data->whole_rect));
1038 if (were_equal && !now_equal)
1040 data->cocoa_view = macdrv_create_view(frame);
1041 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1042 macdrv_set_view_superview(data->client_cocoa_view, data->cocoa_view, NULL, NULL, NULL);
1043 macdrv_set_view_hidden(data->client_cocoa_view, FALSE);
1044 force_z_order = TRUE;
1046 else if (!were_equal && now_equal)
1048 macdrv_dispose_view(data->cocoa_view);
1049 data->cocoa_view = data->client_cocoa_view;
1050 macdrv_set_view_hidden(data->cocoa_view, !data->on_screen);
1051 macdrv_set_view_frame(data->cocoa_view, frame);
1052 force_z_order = TRUE;
1054 else
1055 macdrv_set_view_frame(data->cocoa_view, frame);
1058 if (data->cocoa_view != data->client_cocoa_view)
1060 RECT rect = data->client_rect;
1061 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
1062 macdrv_set_view_frame(data->client_cocoa_view, cgrect_from_rect(rect));
1063 TRACE("win %p/%p client %s\n", data->hwnd, data->client_cocoa_view, wine_dbgstr_rect(&rect));
1066 if (old_window_rect && old_whole_rect &&
1067 (IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect) ||
1068 old_window_rect->left - old_whole_rect->left != data->window_rect.left - data->whole_rect.left ||
1069 old_window_rect->top - old_whole_rect->top != data->window_rect.top - data->whole_rect.top))
1070 sync_window_region(data, (HRGN)1);
1072 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd,
1073 data->cocoa_window ? (void*)data->cocoa_window : (void*)data->cocoa_view,
1074 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
1076 if (force_z_order || !(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1077 sync_window_z_order(data);
1081 /***********************************************************************
1082 * move_window_bits
1084 * Move the window bits when a window is moved.
1086 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
1087 const RECT *old_client_rect, const RECT *new_client_rect,
1088 const RECT *new_window_rect)
1090 RECT src_rect = *old_rect;
1091 RECT dst_rect = *new_rect;
1092 HDC hdc_src, hdc_dst;
1093 HRGN rgn;
1094 HWND parent = 0;
1096 if (!window)
1098 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
1099 parent = GetAncestor(hwnd, GA_PARENT);
1100 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
1101 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
1103 else
1105 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
1106 /* make src rect relative to the old position of the window */
1107 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
1108 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1109 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
1112 rgn = CreateRectRgnIndirect(&dst_rect);
1113 SelectClipRgn(hdc_dst, rgn);
1114 DeleteObject(rgn);
1115 ExcludeUpdateRgn(hdc_dst, hwnd);
1117 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
1118 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
1119 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
1120 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1121 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
1123 ReleaseDC(hwnd, hdc_dst);
1124 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
1128 /**********************************************************************
1129 * activate_on_following_focus
1131 void activate_on_following_focus(void)
1133 activate_on_focus_time = GetTickCount();
1134 if (!activate_on_focus_time) activate_on_focus_time = 1;
1138 /***********************************************************************
1139 * set_app_icon
1141 static void set_app_icon(void)
1143 CFArrayRef images = create_app_icon_images();
1144 if (images)
1146 macdrv_set_application_icon(images);
1147 CFRelease(images);
1152 /**********************************************************************
1153 * set_capture_window_for_move
1155 static BOOL set_capture_window_for_move(HWND hwnd)
1157 HWND previous = 0;
1158 BOOL ret;
1160 SERVER_START_REQ(set_capture_window)
1162 req->handle = wine_server_user_handle(hwnd);
1163 req->flags = CAPTURE_MOVESIZE;
1164 if ((ret = !wine_server_call_err(req)))
1166 previous = wine_server_ptr_handle(reply->previous);
1167 hwnd = wine_server_ptr_handle(reply->full_handle);
1170 SERVER_END_REQ;
1172 if (ret)
1174 macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
1176 if (previous && previous != hwnd)
1177 SendMessageW(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
1179 return ret;
1183 /***********************************************************************
1184 * move_window
1186 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
1187 * moving top-level windows and enforcing Mac-style constraints like
1188 * keeping the top of the window within the work area.
1190 static LRESULT move_window(HWND hwnd, WPARAM wparam)
1192 MSG msg;
1193 RECT origRect, movedRect, desktopRect;
1194 LONG hittest = (LONG)(wparam & 0x0f);
1195 POINT capturePoint;
1196 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1197 BOOL moved = FALSE;
1198 DWORD dwPoint = GetMessagePos();
1199 INT captionHeight;
1200 HMONITOR mon = 0;
1201 MONITORINFO info;
1203 if ((style & (WS_MINIMIZE | WS_MAXIMIZE)) || !IsWindowVisible(hwnd)) return -1;
1204 if (hittest && hittest != HTCAPTION) return -1;
1206 capturePoint.x = (short)LOWORD(dwPoint);
1207 capturePoint.y = (short)HIWORD(dwPoint);
1208 ClipCursor(NULL);
1210 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd, hittest, capturePoint.x, capturePoint.y);
1212 origRect.left = origRect.right = origRect.top = origRect.bottom = 0;
1213 if (AdjustWindowRectEx(&origRect, style, FALSE, GetWindowLongW(hwnd, GWL_EXSTYLE)))
1214 captionHeight = -origRect.top;
1215 else
1216 captionHeight = 0;
1218 GetWindowRect(hwnd, &origRect);
1219 movedRect = origRect;
1221 if (!hittest)
1223 /* Move pointer to the center of the caption */
1224 RECT rect = origRect;
1226 /* Note: to be exactly centered we should take the different types
1227 * of border into account, but it shouldn't make more than a few pixels
1228 * of difference so let's not bother with that */
1229 rect.top += GetSystemMetrics(SM_CYBORDER);
1230 if (style & WS_SYSMENU)
1231 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1232 if (style & WS_MINIMIZEBOX)
1233 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1234 if (style & WS_MAXIMIZEBOX)
1235 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1236 capturePoint.x = (rect.right + rect.left) / 2;
1237 capturePoint.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1239 SetCursorPos(capturePoint.x, capturePoint.y);
1240 SendMessageW(hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG(HTCAPTION, WM_MOUSEMOVE));
1243 desktopRect = rect_from_cgrect(macdrv_get_desktop_rect());
1244 mon = MonitorFromPoint(capturePoint, MONITOR_DEFAULTTONEAREST);
1245 info.cbSize = sizeof(info);
1246 if (mon && !GetMonitorInfoW(mon, &info))
1247 mon = 0;
1249 /* repaint the window before moving it around */
1250 RedrawWindow(hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
1252 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
1253 set_capture_window_for_move(hwnd);
1255 while(1)
1257 POINT pt;
1258 int dx = 0, dy = 0;
1259 HMONITOR newmon;
1261 if (!GetMessageW(&msg, 0, 0, 0)) break;
1262 if (CallMsgFilterW(&msg, MSGF_SIZE)) continue;
1264 /* Exit on button-up, Return, or Esc */
1265 if (msg.message == WM_LBUTTONUP ||
1266 (msg.message == WM_KEYDOWN && (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)))
1267 break;
1269 if (msg.message != WM_KEYDOWN && msg.message != WM_MOUSEMOVE)
1271 TranslateMessage(&msg);
1272 DispatchMessageW(&msg);
1273 continue; /* We are not interested in other messages */
1276 pt = msg.pt;
1278 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1280 case VK_UP: pt.y -= 8; break;
1281 case VK_DOWN: pt.y += 8; break;
1282 case VK_LEFT: pt.x -= 8; break;
1283 case VK_RIGHT: pt.x += 8; break;
1286 pt.x = max(pt.x, desktopRect.left);
1287 pt.x = min(pt.x, desktopRect.right - 1);
1288 pt.y = max(pt.y, desktopRect.top);
1289 pt.y = min(pt.y, desktopRect.bottom - 1);
1291 if ((newmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) && newmon != mon)
1293 if (GetMonitorInfoW(newmon, &info))
1294 mon = newmon;
1295 else
1296 mon = 0;
1299 if (mon)
1301 /* wineserver clips the cursor position to the virtual desktop rect but,
1302 if the display configuration is non-rectangular, that could still
1303 leave the logical cursor position outside of any display. The window
1304 could keep moving as you push the cursor against a display edge, even
1305 though the visible cursor doesn't keep moving. The following keeps
1306 the window movement in sync with the visible cursor. */
1307 pt.x = max(pt.x, info.rcMonitor.left);
1308 pt.x = min(pt.x, info.rcMonitor.right - 1);
1309 pt.y = max(pt.y, info.rcMonitor.top);
1310 pt.y = min(pt.y, info.rcMonitor.bottom - 1);
1312 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1313 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1314 we want to enforce these constraints:
1315 movedRect.left + dx < info.rcWork.right
1316 movedRect.right + dx > info.rcWork.left
1317 movedRect.top + captionHeight + dy < info.rcWork.bottom
1318 movedRect.bottom + dy > info.rcWork.top
1319 movedRect.top + dy >= info.rcWork.top
1320 The first four keep at least one edge barely in the work area.
1321 The last keeps the top (i.e. the title bar) in the work area.
1322 The fourth is redundant with the last, so can be ignored.
1324 Substituting for dx and dy and rearranging gives us...
1326 pt.x = min(pt.x, info.rcWork.right - 1 + capturePoint.x - movedRect.left);
1327 pt.x = max(pt.x, info.rcWork.left + 1 + capturePoint.x - movedRect.right);
1328 pt.y = min(pt.y, info.rcWork.bottom - 1 + capturePoint.y - movedRect.top - captionHeight);
1329 pt.y = max(pt.y, info.rcWork.top + capturePoint.y - movedRect.top);
1332 dx = pt.x - capturePoint.x;
1333 dy = pt.y - capturePoint.y;
1335 if (dx || dy)
1337 moved = TRUE;
1339 if (msg.message == WM_KEYDOWN) SetCursorPos(pt.x, pt.y);
1340 else
1342 OffsetRect(&movedRect, dx, dy);
1343 capturePoint = pt;
1345 SendMessageW(hwnd, WM_MOVING, 0, (LPARAM)&movedRect);
1346 SetWindowPos(hwnd, 0, movedRect.left, movedRect.top, 0, 0,
1347 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1352 set_capture_window_for_move(0);
1354 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
1355 SendMessageW(hwnd, WM_SETVISIBLE, TRUE, 0L);
1357 /* if the move is canceled, restore the previous position */
1358 if (moved && msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
1360 SetWindowPos(hwnd, 0, origRect.left, origRect.top, 0, 0,
1361 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
1364 return 0;
1368 /***********************************************************************
1369 * perform_window_command
1371 static void perform_window_command(HWND hwnd, DWORD style_any, DWORD style_none, WORD command, WORD hittest)
1373 DWORD style;
1375 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1376 hwnd, style_any, style_none, command, hittest);
1378 style = GetWindowLongW(hwnd, GWL_STYLE);
1379 if ((style_any && !(style & style_any)) || (style & (WS_DISABLED | style_none)))
1381 TRACE("not changing win %p style 0x%08x\n", hwnd, style);
1382 return;
1385 if (GetActiveWindow() != hwnd)
1387 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE, (WPARAM)GetAncestor(hwnd, GA_ROOT),
1388 MAKELPARAM(hittest, WM_NCLBUTTONDOWN));
1389 switch (ma)
1391 case MA_NOACTIVATEANDEAT:
1392 case MA_ACTIVATEANDEAT:
1393 TRACE("not changing win %p mouse-activate result %ld\n", hwnd, ma);
1394 return;
1395 case MA_NOACTIVATE:
1396 break;
1397 case MA_ACTIVATE:
1398 case 0:
1399 SetActiveWindow(hwnd);
1400 break;
1401 default:
1402 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma);
1403 break;
1407 TRACE("changing win %p\n", hwnd);
1408 PostMessageW(hwnd, WM_SYSCOMMAND, command, 0);
1412 /**********************************************************************
1413 * CreateDesktopWindow (MACDRV.@)
1415 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
1417 unsigned int width, height;
1419 TRACE("%p\n", hwnd);
1421 /* retrieve the real size of the desktop */
1422 SERVER_START_REQ(get_window_rectangles)
1424 req->handle = wine_server_user_handle(hwnd);
1425 req->relative = COORDS_CLIENT;
1426 wine_server_call(req);
1427 width = reply->window.right;
1428 height = reply->window.bottom;
1430 SERVER_END_REQ;
1432 if (!width && !height) /* not initialized yet */
1434 CGRect rect = macdrv_get_desktop_rect();
1436 SERVER_START_REQ(set_window_pos)
1438 req->handle = wine_server_user_handle(hwnd);
1439 req->previous = 0;
1440 req->swp_flags = SWP_NOZORDER;
1441 req->window.left = CGRectGetMinX(rect);
1442 req->window.top = CGRectGetMinY(rect);
1443 req->window.right = CGRectGetMaxX(rect);
1444 req->window.bottom = CGRectGetMaxY(rect);
1445 req->client = req->window;
1446 wine_server_call(req);
1448 SERVER_END_REQ;
1451 set_app_icon();
1452 return TRUE;
1456 /**********************************************************************
1457 * CreateWindow (MACDRV.@)
1459 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
1461 return TRUE;
1465 /***********************************************************************
1466 * DestroyWindow (MACDRV.@)
1468 void CDECL macdrv_DestroyWindow(HWND hwnd)
1470 struct macdrv_win_data *data;
1472 TRACE("%p\n", hwnd);
1474 if (!(data = get_win_data(hwnd))) return;
1476 if (hwnd == GetCapture()) macdrv_SetCapture(0, 0);
1478 destroy_cocoa_window(data);
1479 destroy_cocoa_view(data);
1480 if (data->client_cocoa_view) macdrv_dispose_view(data->client_cocoa_view);
1482 CFDictionaryRemoveValue(win_datas, hwnd);
1483 release_win_data(data);
1484 HeapFree(GetProcessHeap(), 0, data);
1488 /*****************************************************************
1489 * SetFocus (MACDRV.@)
1491 * Set the Mac focus.
1493 void CDECL macdrv_SetFocus(HWND hwnd)
1495 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1496 struct macdrv_win_data *data;
1498 TRACE("%p\n", hwnd);
1500 if (!thread_data) return;
1501 thread_data->dead_key_state = 0;
1503 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
1504 if (!(data = get_win_data(hwnd))) return;
1506 if (data->cocoa_window && data->on_screen)
1508 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
1509 /* Set Mac focus */
1510 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
1511 activate_on_focus_time = 0;
1514 release_win_data(data);
1518 /***********************************************************************
1519 * SetLayeredWindowAttributes (MACDRV.@)
1521 * Set transparency attributes for a layered window.
1523 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
1525 struct macdrv_win_data *data = get_win_data(hwnd);
1527 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
1529 if (data)
1531 data->layered = TRUE;
1532 if (data->cocoa_window)
1534 sync_window_opacity(data, key, alpha, FALSE, flags);
1535 /* since layered attributes are now set, can now show the window */
1536 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
1537 show_window(data);
1539 release_win_data(data);
1541 else
1542 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
1546 /*****************************************************************
1547 * SetParent (MACDRV.@)
1549 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
1551 struct macdrv_win_data *data;
1553 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
1555 if (parent == old_parent) return;
1556 if (!(data = get_win_data(hwnd))) return;
1558 if (parent != GetDesktopWindow()) /* a child window */
1560 if (old_parent == GetDesktopWindow())
1562 /* destroy the old Mac window */
1563 destroy_cocoa_window(data);
1564 create_cocoa_view(data);
1566 else
1568 struct macdrv_win_data *parent_data = get_win_data(parent);
1569 macdrv_window cocoa_window = parent_data ? parent_data->cocoa_window : NULL;
1570 macdrv_view superview = parent_data ? parent_data->client_cocoa_view : NULL;
1572 if (!cocoa_window && !superview)
1573 WARN("hwnd %p new parent %p has no Cocoa window or view in this process\n", hwnd, parent);
1575 macdrv_set_view_superview(data->cocoa_view, superview, cocoa_window, NULL, NULL);
1576 release_win_data(parent_data);
1579 else /* new top level window */
1581 destroy_cocoa_view(data);
1582 create_cocoa_window(data);
1584 release_win_data(data);
1588 /***********************************************************************
1589 * SetWindowRgn (MACDRV.@)
1591 * Assign specified region to window (for non-rectangular windows)
1593 void CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
1595 struct macdrv_win_data *data;
1597 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
1599 if ((data = get_win_data(hwnd)))
1601 sync_window_region(data, hrgn);
1602 release_win_data(data);
1604 else
1606 DWORD procid;
1608 GetWindowThreadProcessId(hwnd, &procid);
1609 if (procid != GetCurrentProcessId())
1610 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
1615 /***********************************************************************
1616 * SetWindowStyle (MACDRV.@)
1618 * Update the state of the Cocoa window to reflect a style change
1620 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
1622 struct macdrv_win_data *data;
1624 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
1626 if (hwnd == GetDesktopWindow()) return;
1627 if (!(data = get_win_data(hwnd))) return;
1629 if (data->cocoa_window)
1631 DWORD changed = style->styleNew ^ style->styleOld;
1633 set_cocoa_window_properties(data);
1635 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
1637 data->layered = FALSE;
1638 data->ulw_layered = FALSE;
1639 sync_window_opacity(data, 0, 0, FALSE, 0);
1640 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1643 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYOUTRTL))
1644 sync_window_region(data, (HRGN)1);
1647 release_win_data(data);
1651 /*****************************************************************
1652 * SetWindowText (MACDRV.@)
1654 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1656 macdrv_window win;
1658 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1660 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1661 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1665 /***********************************************************************
1666 * ShowWindow (MACDRV.@)
1668 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1670 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1671 struct macdrv_win_data *data = get_win_data(hwnd);
1672 CGRect frame;
1674 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1675 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1677 if (!data || !data->cocoa_window) goto done;
1678 if (IsRectEmpty(rect)) goto done;
1679 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1681 if (rect->left != -32000 || rect->top != -32000)
1683 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1684 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1686 goto done;
1688 if (!data->on_screen) goto done;
1690 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1692 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1693 goto done;
1695 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1696 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1697 goto done;
1699 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1700 *rect = rect_from_cgrect(frame);
1701 macdrv_mac_to_window_rect(data, rect);
1702 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1703 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1705 done:
1706 release_win_data(data);
1707 return swp;
1711 /***********************************************************************
1712 * SysCommand (MACDRV.@)
1714 * Perform WM_SYSCOMMAND handling.
1716 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1718 struct macdrv_win_data *data;
1719 LRESULT ret = -1;
1720 WPARAM command = wparam & 0xfff0;
1722 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1724 if (!(data = get_win_data(hwnd))) goto done;
1725 if (!data->cocoa_window || !data->on_screen) goto done;
1727 /* prevent a simple ALT press+release from activating the system menu,
1728 as that can get confusing */
1729 if (command == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1730 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1732 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1733 ret = 0;
1736 if (command == SC_MOVE)
1738 release_win_data(data);
1739 return move_window(hwnd, wparam);
1742 done:
1743 release_win_data(data);
1744 return ret;
1748 /***********************************************************************
1749 * UpdateLayeredWindow (MACDRV.@)
1751 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1752 const RECT *window_rect)
1754 struct window_surface *surface;
1755 struct macdrv_win_data *data;
1756 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1757 BYTE alpha;
1758 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1759 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1760 void *src_bits, *dst_bits;
1761 RECT rect;
1762 HDC hdc = 0;
1763 HBITMAP dib;
1764 BOOL ret = FALSE;
1766 if (!(data = get_win_data(hwnd))) return FALSE;
1768 data->layered = TRUE;
1769 data->ulw_layered = TRUE;
1771 rect = *window_rect;
1772 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1774 surface = data->surface;
1775 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1777 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1778 set_window_surface(data->cocoa_window, data->surface);
1779 if (surface) window_surface_release(surface);
1780 surface = data->surface;
1781 if (data->unminimized_surface)
1783 window_surface_release(data->unminimized_surface);
1784 data->unminimized_surface = NULL;
1787 else set_surface_use_alpha(surface, TRUE);
1789 if (surface) window_surface_add_ref(surface);
1790 release_win_data(data);
1792 if (!surface) return FALSE;
1793 if (!info->hdcSrc)
1795 window_surface_release(surface);
1796 return TRUE;
1799 if (info->dwFlags & ULW_ALPHA)
1801 /* Apply SourceConstantAlpha via window alpha, not blend. */
1802 alpha = info->pblend->SourceConstantAlpha;
1803 blend = *info->pblend;
1804 blend.SourceConstantAlpha = 0xff;
1806 else
1807 alpha = 0xff;
1809 dst_bits = surface->funcs->get_info(surface, bmi);
1811 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1812 if (!(hdc = CreateCompatibleDC(0))) goto done;
1814 SelectObject(hdc, dib);
1815 if (info->prcDirty)
1817 IntersectRect(&rect, &rect, info->prcDirty);
1818 surface->funcs->lock(surface);
1819 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1820 surface->funcs->unlock(surface);
1821 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1823 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1824 info->hdcSrc,
1825 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1826 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1827 rect.right - rect.left, rect.bottom - rect.top,
1828 blend)))
1829 goto done;
1831 if ((data = get_win_data(hwnd)))
1833 if (surface == data->surface)
1835 surface->funcs->lock(surface);
1836 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1837 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1838 surface->funcs->unlock(surface);
1839 surface->funcs->flush(surface);
1842 /* The ULW flags are a superset of the LWA flags. */
1843 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1845 release_win_data(data);
1848 done:
1849 window_surface_release(surface);
1850 if (hdc) DeleteDC(hdc);
1851 if (dib) DeleteObject(dib);
1852 return ret;
1856 /**********************************************************************
1857 * WindowMessage (MACDRV.@)
1859 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1861 struct macdrv_win_data *data;
1863 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1865 switch(msg)
1867 case WM_MACDRV_SET_WIN_REGION:
1868 if ((data = get_win_data(hwnd)))
1870 sync_window_region(data, (HRGN)1);
1871 release_win_data(data);
1873 return 0;
1874 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1875 if (hwnd == GetDesktopWindow())
1877 CGRect new_desktop_rect;
1878 RECT current_desktop_rect;
1880 macdrv_reset_device_metrics();
1881 new_desktop_rect = macdrv_get_desktop_rect();
1882 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1883 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1885 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1886 SMTO_ABORTIFHUNG, 2000, NULL);
1887 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1888 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1889 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1890 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1891 SMTO_ABORTIFHUNG, 2000, NULL);
1894 return 0;
1895 case WM_MACDRV_RESET_DEVICE_METRICS:
1896 macdrv_reset_device_metrics();
1897 return 0;
1898 case WM_MACDRV_DISPLAYCHANGE:
1899 macdrv_reassert_window_position(hwnd);
1900 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1901 return 0;
1902 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1903 activate_on_following_focus();
1904 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1905 return 0;
1908 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1909 return 0;
1913 static inline RECT get_surface_rect(const RECT *visible_rect)
1915 RECT rect;
1916 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1918 IntersectRect(&rect, visible_rect, &desktop_rect);
1919 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1920 rect.left &= ~127;
1921 rect.top &= ~127;
1922 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1923 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1924 return rect;
1928 /***********************************************************************
1929 * WindowPosChanging (MACDRV.@)
1931 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1932 const RECT *window_rect, const RECT *client_rect,
1933 RECT *visible_rect, struct window_surface **surface)
1935 struct macdrv_win_data *data = get_win_data(hwnd);
1936 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1937 RECT surface_rect;
1939 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1940 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1941 wine_dbgstr_rect(visible_rect), surface);
1943 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1945 *visible_rect = *window_rect;
1946 macdrv_window_to_mac_rect(data, style, visible_rect);
1947 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1948 wine_dbgstr_rect(visible_rect));
1950 /* create the window surface if necessary */
1951 if (!data->cocoa_window) goto done;
1952 if (swp_flags & SWP_HIDEWINDOW) goto done;
1953 if (data->ulw_layered) goto done;
1955 if (*surface) window_surface_release(*surface);
1956 *surface = NULL;
1958 surface_rect = get_surface_rect(visible_rect);
1959 if (data->surface)
1961 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1963 /* existing surface is good enough */
1964 surface_clip_to_visible_rect(data->surface, visible_rect);
1965 window_surface_add_ref(data->surface);
1966 *surface = data->surface;
1967 goto done;
1970 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1972 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1974 done:
1975 release_win_data(data);
1979 /***********************************************************************
1980 * WindowPosChanged (MACDRV.@)
1982 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1983 const RECT *window_rect, const RECT *client_rect,
1984 const RECT *visible_rect, const RECT *valid_rects,
1985 struct window_surface *surface)
1987 struct macdrv_thread_data *thread_data;
1988 struct macdrv_win_data *data;
1989 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1990 RECT old_window_rect, old_whole_rect, old_client_rect;
1992 if (!(data = get_win_data(hwnd))) return;
1994 thread_data = macdrv_thread_data();
1996 old_window_rect = data->window_rect;
1997 old_whole_rect = data->whole_rect;
1998 old_client_rect = data->client_rect;
1999 data->window_rect = *window_rect;
2000 data->whole_rect = *visible_rect;
2001 data->client_rect = *client_rect;
2002 if (!data->ulw_layered)
2004 if (surface) window_surface_add_ref(surface);
2005 if (new_style & WS_MINIMIZE)
2007 if (!data->unminimized_surface && data->surface)
2009 data->unminimized_surface = data->surface;
2010 window_surface_add_ref(data->unminimized_surface);
2013 else
2015 set_window_surface(data->cocoa_window, surface);
2016 if (data->unminimized_surface)
2018 window_surface_release(data->unminimized_surface);
2019 data->unminimized_surface = NULL;
2022 if (data->surface) window_surface_release(data->surface);
2023 data->surface = surface;
2026 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
2027 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
2028 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
2029 new_style, swp_flags, surface);
2031 if (!IsRectEmpty(&valid_rects[0]))
2033 macdrv_window window = data->cocoa_window;
2034 int x_offset = old_whole_rect.left - data->whole_rect.left;
2035 int y_offset = old_whole_rect.top - data->whole_rect.top;
2037 /* if all that happened is that the whole window moved, copy everything */
2038 if (!(swp_flags & SWP_FRAMECHANGED) &&
2039 old_whole_rect.right - data->whole_rect.right == x_offset &&
2040 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2041 old_client_rect.left - data->client_rect.left == x_offset &&
2042 old_client_rect.right - data->client_rect.right == x_offset &&
2043 old_client_rect.top - data->client_rect.top == y_offset &&
2044 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2045 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
2047 /* A Cocoa window's bits are moved automatically */
2048 if (!window && (x_offset != 0 || y_offset != 0))
2050 release_win_data(data);
2051 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
2052 &old_client_rect, client_rect, window_rect);
2053 if (!(data = get_win_data(hwnd))) return;
2056 else
2058 release_win_data(data);
2059 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
2060 &old_client_rect, client_rect, window_rect);
2061 if (!(data = get_win_data(hwnd))) return;
2065 sync_gl_view(data, &old_whole_rect, &old_client_rect);
2067 if (!data->cocoa_window && !data->cocoa_view) goto done;
2069 if (data->on_screen)
2071 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
2072 hide_window(data);
2075 /* check if we are currently processing an event relevant to this window */
2076 if (!thread_data || !thread_data->current_event ||
2077 !data->cocoa_window || thread_data->current_event->window != data->cocoa_window ||
2078 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
2079 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
2081 sync_window_position(data, swp_flags, &old_window_rect, &old_whole_rect);
2082 if (data->cocoa_window)
2083 set_cocoa_window_properties(data);
2086 if (new_style & WS_VISIBLE)
2088 if (data->cocoa_window)
2090 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2091 set_cocoa_window_properties(data);
2093 /* layered windows are not shown until their attributes are set */
2094 if (!data->on_screen &&
2095 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
2096 show_window(data);
2098 else if (!data->on_screen)
2099 show_window(data);
2102 done:
2103 release_win_data(data);
2107 /***********************************************************************
2108 * macdrv_window_close_requested
2110 * Handler for WINDOW_CLOSE_REQUESTED events.
2112 void macdrv_window_close_requested(HWND hwnd)
2114 HMENU sysmenu;
2116 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
2118 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd);
2119 return;
2122 sysmenu = GetSystemMenu(hwnd, FALSE);
2123 if (sysmenu)
2125 UINT state = GetMenuState(sysmenu, SC_CLOSE, MF_BYCOMMAND);
2126 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
2128 TRACE("not closing win %p menu state 0x%08x\n", hwnd, state);
2129 return;
2133 perform_window_command(hwnd, 0, 0, SC_CLOSE, HTCLOSE);
2137 /***********************************************************************
2138 * macdrv_window_frame_changed
2140 * Handler for WINDOW_FRAME_CHANGED events.
2142 void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
2144 struct macdrv_win_data *data;
2145 RECT rect;
2146 HWND parent;
2147 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
2148 int width, height;
2149 BOOL being_dragged;
2151 if (!hwnd) return;
2152 if (!(data = get_win_data(hwnd))) return;
2153 if (!data->on_screen || data->minimized)
2155 release_win_data(data);
2156 return;
2159 /* Get geometry */
2161 parent = GetAncestor(hwnd, GA_PARENT);
2163 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd, data->cocoa_window,
2164 wine_dbgstr_cgrect(event->window_frame_changed.frame),
2165 event->window_frame_changed.fullscreen, event->window_frame_changed.in_resize);
2167 rect = rect_from_cgrect(event->window_frame_changed.frame);
2168 macdrv_mac_to_window_rect(data, &rect);
2169 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2171 width = rect.right - rect.left;
2172 height = rect.bottom - rect.top;
2174 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
2175 flags |= SWP_NOMOVE;
2176 else
2177 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
2178 data->window_rect.top, rect.left, rect.top);
2180 if ((data->window_rect.right - data->window_rect.left == width &&
2181 data->window_rect.bottom - data->window_rect.top == height) ||
2182 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
2183 flags |= SWP_NOSIZE;
2184 else
2185 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
2186 data->window_rect.bottom - data->window_rect.top, width, height);
2188 being_dragged = data->being_dragged;
2189 release_win_data(data);
2191 if (event->window_frame_changed.fullscreen)
2192 flags |= SWP_NOSENDCHANGING;
2193 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
2195 if (!event->window_frame_changed.in_resize && !being_dragged)
2196 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2197 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
2198 if (!event->window_frame_changed.in_resize && !being_dragged)
2199 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2204 /***********************************************************************
2205 * macdrv_window_got_focus
2207 * Handler for WINDOW_GOT_FOCUS events.
2209 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
2211 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
2213 if (!hwnd) return;
2215 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2216 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
2217 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2219 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
2221 /* simulate a mouse click on the caption to find out
2222 * whether the window wants to be activated */
2223 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
2224 (WPARAM)GetAncestor(hwnd, GA_ROOT),
2225 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
2226 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
2228 TRACE("setting foreground window to %p\n", hwnd);
2229 SetForegroundWindow(hwnd);
2230 return;
2234 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
2235 macdrv_window_rejected_focus(event);
2239 /***********************************************************************
2240 * macdrv_window_lost_focus
2242 * Handler for WINDOW_LOST_FOCUS events.
2244 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
2246 if (!hwnd) return;
2248 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
2250 if (hwnd == GetForegroundWindow())
2252 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
2253 if (hwnd == GetForegroundWindow())
2254 SetForegroundWindow(GetDesktopWindow());
2259 /***********************************************************************
2260 * macdrv_app_deactivated
2262 * Handler for APP_DEACTIVATED events.
2264 void macdrv_app_deactivated(void)
2266 if (GetActiveWindow() == GetForegroundWindow())
2268 TRACE("setting fg to desktop\n");
2269 SetForegroundWindow(GetDesktopWindow());
2274 /***********************************************************************
2275 * macdrv_window_maximize_requested
2277 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2279 void macdrv_window_maximize_requested(HWND hwnd)
2281 perform_window_command(hwnd, WS_MAXIMIZEBOX, WS_MAXIMIZE, SC_MAXIMIZE, HTMAXBUTTON);
2285 /***********************************************************************
2286 * macdrv_window_minimize_requested
2288 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2290 void macdrv_window_minimize_requested(HWND hwnd)
2292 perform_window_command(hwnd, WS_MINIMIZEBOX, WS_MINIMIZE, SC_MINIMIZE, HTMINBUTTON);
2296 /***********************************************************************
2297 * macdrv_window_did_unminimize
2299 * Handler for WINDOW_DID_UNMINIMIZE events.
2301 void macdrv_window_did_unminimize(HWND hwnd)
2303 struct macdrv_win_data *data;
2304 DWORD style;
2306 TRACE("win %p\n", hwnd);
2308 if (!(data = get_win_data(hwnd))) return;
2309 if (!data->minimized) goto done;
2311 style = GetWindowLongW(hwnd, GWL_STYLE);
2313 data->minimized = FALSE;
2314 if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE))
2316 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
2317 release_win_data(data);
2318 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
2319 return;
2322 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
2324 done:
2325 release_win_data(data);
2329 /***********************************************************************
2330 * macdrv_window_brought_forward
2332 * Handler for WINDOW_BROUGHT_FORWARD events.
2334 void macdrv_window_brought_forward(HWND hwnd)
2336 TRACE("win %p\n", hwnd);
2337 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
2341 /***********************************************************************
2342 * macdrv_window_resize_ended
2344 * Handler for WINDOW_RESIZE_ENDED events.
2346 void macdrv_window_resize_ended(HWND hwnd)
2348 TRACE("hwnd %p\n", hwnd);
2349 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2353 /***********************************************************************
2354 * macdrv_window_restore_requested
2356 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2357 * for restoring from maximized, not from minimized.
2359 void macdrv_window_restore_requested(HWND hwnd, const macdrv_event *event)
2361 if (event->window_restore_requested.keep_frame && hwnd)
2363 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2364 struct macdrv_win_data *data;
2366 if ((style & WS_MAXIMIZE) && (style & WS_VISIBLE) && (data = get_win_data(hwnd)))
2368 RECT rect;
2369 HWND parent = GetAncestor(hwnd, GA_PARENT);
2371 rect = rect_from_cgrect(event->window_restore_requested.frame);
2372 macdrv_mac_to_window_rect(data, &rect);
2373 MapWindowPoints(0, parent, (POINT *)&rect, 2);
2375 release_win_data(data);
2377 SetInternalWindowPos(hwnd, SW_SHOW, &rect, NULL);
2381 perform_window_command(hwnd, WS_MAXIMIZE, 0, SC_RESTORE, HTMAXBUTTON);
2385 /***********************************************************************
2386 * macdrv_window_drag_begin
2388 * Handler for WINDOW_DRAG_BEGIN events.
2390 void macdrv_window_drag_begin(HWND hwnd)
2392 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
2393 struct macdrv_win_data *data;
2394 MSG msg;
2396 TRACE("win %p\n", hwnd);
2398 if (style & (WS_DISABLED | WS_MAXIMIZE | WS_MINIMIZE)) return;
2399 if (!(style & WS_VISIBLE)) return;
2401 if (!(data = get_win_data(hwnd))) return;
2402 if (data->being_dragged) goto done;
2404 data->being_dragged = TRUE;
2405 release_win_data(data);
2407 ClipCursor(NULL);
2408 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2409 ReleaseCapture();
2411 while (GetMessageW(&msg, 0, 0, 0))
2413 if (msg.message == WM_EXITSIZEMOVE)
2415 SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2416 break;
2419 if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN &&
2420 msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP)
2422 TranslateMessage(&msg);
2423 DispatchMessageW(&msg);
2427 TRACE("done\n");
2429 if ((data = get_win_data(hwnd)))
2430 data->being_dragged = FALSE;
2432 done:
2433 release_win_data(data);
2437 /***********************************************************************
2438 * macdrv_window_drag_end
2440 * Handler for WINDOW_DRAG_END events.
2442 void macdrv_window_drag_end(HWND hwnd)
2444 struct macdrv_win_data *data;
2445 BOOL being_dragged;
2447 TRACE("win %p\n", hwnd);
2449 if (!(data = get_win_data(hwnd))) return;
2450 being_dragged = data->being_dragged;
2451 release_win_data(data);
2453 if (being_dragged)
2455 /* Post this rather than sending it, so that the message loop in
2456 macdrv_window_drag_begin() will see it. */
2457 PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0);
2462 /***********************************************************************
2463 * macdrv_reassert_window_position
2465 * Handler for REASSERT_WINDOW_POSITION events.
2467 void macdrv_reassert_window_position(HWND hwnd)
2469 struct macdrv_win_data *data = get_win_data(hwnd);
2470 if (data)
2472 if (data->cocoa_window && data->on_screen)
2473 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL, NULL);
2474 release_win_data(data);
2479 struct quit_info {
2480 HWND *wins;
2481 UINT capacity;
2482 UINT count;
2483 UINT done;
2484 DWORD flags;
2485 BOOL result;
2486 BOOL replied;
2490 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
2492 struct quit_info *qi = (struct quit_info*)lp;
2493 DWORD pid;
2495 GetWindowThreadProcessId(hwnd, &pid);
2496 if (pid == GetCurrentProcessId())
2498 if (qi->count >= qi->capacity)
2500 UINT new_cap = qi->capacity * 2;
2501 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
2502 new_cap * sizeof(*qi->wins));
2503 if (!new_wins) return FALSE;
2504 qi->wins = new_wins;
2505 qi->capacity = new_cap;
2508 qi->wins[qi->count++] = hwnd;
2511 return TRUE;
2515 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
2517 struct quit_info *qi = (struct quit_info*)data;
2519 qi->done++;
2521 if (msg == WM_QUERYENDSESSION)
2523 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
2524 hwnd, qi->done, qi->count);
2526 if (!result && !IsWindow(hwnd))
2528 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd);
2529 result = TRUE;
2532 if (!result && qi->result)
2534 qi->result = FALSE;
2536 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2537 ultimate reply. Might as well tell Cocoa now. */
2538 if (!qi->replied)
2540 qi->replied = TRUE;
2541 TRACE("giving quit reply %d\n", qi->result);
2542 macdrv_quit_reply(qi->result);
2546 if (qi->done >= qi->count)
2548 UINT i;
2550 qi->done = 0;
2551 for (i = 0; i < qi->count; i++)
2553 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
2554 qi->result, qi->flags);
2555 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
2556 quit_callback, (ULONG_PTR)qi))
2558 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2559 qi->wins[i], GetLastError());
2560 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
2565 else /* WM_ENDSESSION */
2567 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
2569 if (qi->done >= qi->count)
2571 if (!qi->replied)
2573 TRACE("giving quit reply %d\n", qi->result);
2574 macdrv_quit_reply(qi->result);
2577 TRACE("%sterminating process\n", qi->result ? "" : "not ");
2578 if (qi->result)
2579 TerminateProcess(GetCurrentProcess(), 0);
2581 HeapFree(GetProcessHeap(), 0, qi->wins);
2582 HeapFree(GetProcessHeap(), 0, qi);
2588 /***********************************************************************
2589 * macdrv_app_quit_requested
2591 * Handler for APP_QUIT_REQUESTED events.
2593 void macdrv_app_quit_requested(const macdrv_event *event)
2595 struct quit_info *qi;
2596 UINT i;
2598 TRACE("reason %d\n", event->app_quit_requested.reason);
2600 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
2601 if (!qi)
2602 goto fail;
2604 qi->capacity = 32;
2605 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
2606 qi->count = qi->done = 0;
2608 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
2609 goto fail;
2611 switch (event->app_quit_requested.reason)
2613 case QUIT_REASON_LOGOUT:
2614 default:
2615 qi->flags = ENDSESSION_LOGOFF;
2616 break;
2617 case QUIT_REASON_RESTART:
2618 case QUIT_REASON_SHUTDOWN:
2619 qi->flags = 0;
2620 break;
2623 qi->result = TRUE;
2624 qi->replied = FALSE;
2626 for (i = 0; i < qi->count; i++)
2628 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
2629 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
2630 quit_callback, (ULONG_PTR)qi))
2632 DWORD error = GetLastError();
2633 BOOL invalid = (error == ERROR_INVALID_WINDOW_HANDLE);
2634 if (invalid)
2635 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2636 qi->wins[i]);
2637 else
2638 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2639 qi->wins[i], error);
2640 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, invalid);
2644 /* quit_callback() will clean up qi */
2645 return;
2647 fail:
2648 WARN("failed to allocate window list\n");
2649 if (qi)
2651 HeapFree(GetProcessHeap(), 0, qi->wins);
2652 HeapFree(GetProcessHeap(), 0, qi);
2654 macdrv_quit_reply(FALSE);
2658 /***********************************************************************
2659 * query_resize_size
2661 * Handler for QUERY_RESIZE_SIZE query.
2663 BOOL query_resize_size(HWND hwnd, macdrv_query *query)
2665 struct macdrv_win_data *data = get_win_data(hwnd);
2666 RECT rect = rect_from_cgrect(query->resize_size.rect);
2667 int corner;
2668 BOOL ret = FALSE;
2670 if (!data) return FALSE;
2672 macdrv_mac_to_window_rect(data, &rect);
2674 if (query->resize_size.from_left)
2676 if (query->resize_size.from_top)
2677 corner = WMSZ_TOPLEFT;
2678 else
2679 corner = WMSZ_BOTTOMLEFT;
2681 else if (query->resize_size.from_top)
2682 corner = WMSZ_TOPRIGHT;
2683 else
2684 corner = WMSZ_BOTTOMRIGHT;
2686 if (SendMessageW(hwnd, WM_SIZING, corner, (LPARAM)&rect))
2688 macdrv_window_to_mac_rect(data, GetWindowLongW(hwnd, GWL_STYLE), &rect);
2689 query->resize_size.rect = cgrect_from_rect(rect);
2690 ret = TRUE;
2693 release_win_data(data);
2694 return ret;
2698 /***********************************************************************
2699 * query_resize_start
2701 * Handler for QUERY_RESIZE_START query.
2703 BOOL query_resize_start(HWND hwnd)
2705 TRACE("hwnd %p\n", hwnd);
2707 sync_window_min_max_info(hwnd);
2708 SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
2710 return TRUE;
2714 /***********************************************************************
2715 * query_min_max_info
2717 * Handler for QUERY_MIN_MAX_INFO query.
2719 BOOL query_min_max_info(HWND hwnd)
2721 TRACE("hwnd %p\n", hwnd);
2722 sync_window_min_max_info(hwnd);
2723 return TRUE;