wbemdisp: Added WinMGMTS object stub implementation.
[wine/wine-gecko.git] / dlls / winemac.drv / window.c
blobc4da8709f5a2334fd1bd7eb2f54fc703a76522a7
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);
92 RECT rect;
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 if (GetWindowRect(hwnd, &rect) && IsRectEmpty(&rect)) return FALSE;
99 return !(style & WS_DISABLED);
103 /***********************************************************************
104 * get_cocoa_window_state
106 static void get_cocoa_window_state(struct macdrv_win_data *data,
107 DWORD style, DWORD ex_style,
108 struct macdrv_window_state* state)
110 memset(state, 0, sizeof(*state));
111 state->disabled = (style & WS_DISABLED) != 0;
112 state->no_activate = !can_activate_window(data->hwnd);
113 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
114 state->excluded_by_expose = state->excluded_by_cycle =
115 IsRectEmpty(&data->window_rect) ||
116 (!(ex_style & WS_EX_APPWINDOW) &&
117 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE))));
118 state->minimized = (style & WS_MINIMIZE) != 0;
122 /***********************************************************************
123 * get_mac_rect_offset
125 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
127 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
129 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
131 rect->top = rect->bottom = rect->left = rect->right = 0;
133 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
135 if (!data->shaped)
137 struct macdrv_window_features wf;
138 get_cocoa_window_features(data, style, ex_style, &wf);
140 if (wf.title_bar) style_mask |= WS_CAPTION;
141 if (wf.shadow)
143 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
144 ex_style_mask |= WS_EX_DLGMODALFRAME;
148 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
150 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
151 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
155 /***********************************************************************
156 * macdrv_window_to_mac_rect
158 * Convert a rect from client to Mac window coordinates
160 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
162 RECT rc;
164 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
165 if (IsRectEmpty(rect)) return;
167 get_mac_rect_offset(data, style, &rc);
169 rect->left -= rc.left;
170 rect->right -= rc.right;
171 rect->top -= rc.top;
172 rect->bottom -= rc.bottom;
173 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
174 if (rect->left >= rect->right) rect->right = rect->left + 1;
178 /***********************************************************************
179 * macdrv_mac_to_window_rect
181 * Opposite of macdrv_window_to_mac_rect
183 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
185 RECT rc;
186 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
188 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
189 if (IsRectEmpty(rect)) return;
191 get_mac_rect_offset(data, style, &rc);
193 rect->left += rc.left;
194 rect->right += rc.right;
195 rect->top += rc.top;
196 rect->bottom += rc.bottom;
197 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
198 if (rect->left >= rect->right) rect->right = rect->left + 1;
202 /***********************************************************************
203 * constrain_window_frame
205 * Alter a window frame rectangle to fit within a) Cocoa's documented
206 * limits, and b) sane sizes, like twice the desktop rect.
208 static void constrain_window_frame(CGRect* frame)
210 CGRect desktop_rect = macdrv_get_desktop_rect();
211 int max_width, max_height;
213 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
214 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
216 if (frame->origin.x < -16000) frame->origin.x = -16000;
217 if (frame->origin.y < -16000) frame->origin.y = -16000;
218 if (frame->origin.x > 16000) frame->origin.x = 16000;
219 if (frame->origin.y > 16000) frame->origin.y = 16000;
220 if (frame->size.width > max_width) frame->size.width = max_width;
221 if (frame->size.height > max_height) frame->size.height = max_height;
225 /***********************************************************************
226 * alloc_win_data
228 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
230 struct macdrv_win_data *data;
232 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
234 data->hwnd = hwnd;
235 data->color_key = CLR_INVALID;
236 EnterCriticalSection(&win_data_section);
237 if (!win_datas)
238 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
239 CFDictionarySetValue(win_datas, hwnd, data);
241 return data;
245 /***********************************************************************
246 * get_win_data
248 * Lock and return the data structure associated with a window.
250 struct macdrv_win_data *get_win_data(HWND hwnd)
252 struct macdrv_win_data *data;
254 if (!hwnd) return NULL;
255 EnterCriticalSection(&win_data_section);
256 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
257 return data;
258 LeaveCriticalSection(&win_data_section);
259 return NULL;
263 /***********************************************************************
264 * release_win_data
266 * Release the data returned by get_win_data.
268 void release_win_data(struct macdrv_win_data *data)
270 if (data) LeaveCriticalSection(&win_data_section);
274 /***********************************************************************
275 * macdrv_get_cocoa_window
277 * Return the Mac window associated with the full area of a window
279 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
281 struct macdrv_win_data *data = get_win_data(hwnd);
282 macdrv_window ret = NULL;
283 if (data && (data->on_screen || !require_on_screen))
284 ret = data->cocoa_window;
285 release_win_data(data);
286 return ret;
290 /***********************************************************************
291 * set_cocoa_window_properties
293 * Set the window properties for a Cocoa window based on its Windows
294 * properties.
296 static void set_cocoa_window_properties(struct macdrv_win_data *data)
298 DWORD style, ex_style;
299 HWND owner;
300 macdrv_window owner_win;
301 struct macdrv_window_features wf;
302 struct macdrv_window_state state;
304 style = GetWindowLongW(data->hwnd, GWL_STYLE);
305 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
307 owner = GetWindow(data->hwnd, GW_OWNER);
308 owner_win = macdrv_get_cocoa_window(owner, TRUE);
309 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
311 get_cocoa_window_features(data, style, ex_style, &wf);
312 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
314 get_cocoa_window_state(data, style, ex_style, &state);
315 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
316 data->minimized = state.minimized;
320 /***********************************************************************
321 * sync_window_region
323 * Update the window region.
325 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
327 HRGN hrgn = win_region;
328 RGNDATA *region_data;
329 const CGRect* rects;
330 int count;
332 if (!data->cocoa_window) return;
333 data->shaped = FALSE;
335 if (IsRectEmpty(&data->window_rect)) /* set an empty shape */
337 TRACE("win %p/%p setting empty shape for zero-sized window\n", data->hwnd, data->cocoa_window);
338 macdrv_set_window_shape(data->cocoa_window, &CGRectZero, 1);
339 return;
342 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
344 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
345 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
347 DeleteObject(hrgn);
348 hrgn = 0;
352 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
353 MirrorRgn(data->hwnd, hrgn);
354 if (hrgn)
356 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
357 data->window_rect.top - data->whole_rect.top);
359 region_data = get_region_data(hrgn, 0);
360 if (region_data)
362 rects = (CGRect*)region_data->Buffer;
363 count = region_data->rdh.nCount;
364 /* Special case optimization. If the region entirely encloses the Cocoa
365 window, it's the same as there being no region. It's potentially
366 hard/slow to test this for arbitrary regions, so we just check for
367 very simple regions. */
368 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
370 TRACE("optimizing for simple region that contains Cocoa content rect\n");
371 rects = NULL;
372 count = 0;
375 else
377 rects = NULL;
378 count = 0;
381 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
382 macdrv_set_window_shape(data->cocoa_window, rects, count);
384 HeapFree(GetProcessHeap(), 0, region_data);
385 data->shaped = (region_data != NULL);
387 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
391 /***********************************************************************
392 * add_bounds_rect
394 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
396 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
397 bounds->left = min(bounds->left, rect->left);
398 bounds->top = min(bounds->top, rect->top);
399 bounds->right = max(bounds->right, rect->right);
400 bounds->bottom = max(bounds->bottom, rect->bottom);
404 /***********************************************************************
405 * sync_window_opacity
407 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
408 BOOL per_pixel_alpha, DWORD flags)
410 CGFloat opacity = 1.0;
411 BOOL needs_flush = FALSE;
413 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
415 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
416 macdrv_set_window_alpha(data->cocoa_window, opacity);
418 if (flags & LWA_COLORKEY)
420 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
421 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
422 key = RGB(0, 0, 0);
424 else
425 key = CLR_INVALID;
427 if (data->color_key != key)
429 if (key == CLR_INVALID)
431 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
432 macdrv_clear_window_color_key(data->cocoa_window);
434 else
436 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
437 GetRValue(key), GetGValue(key), GetBValue(key));
438 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
441 data->color_key = key;
442 needs_flush = TRUE;
445 if (!data->per_pixel_alpha != !per_pixel_alpha)
447 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
448 data->per_pixel_alpha = per_pixel_alpha;
449 needs_flush = TRUE;
452 if (needs_flush && data->surface)
454 RECT *bounds;
455 RECT rect;
457 rect = data->whole_rect;
458 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
459 data->surface->funcs->lock(data->surface);
460 bounds = data->surface->funcs->get_bounds(data->surface);
461 add_bounds_rect(bounds, &rect);
462 data->surface->funcs->unlock(data->surface);
467 /**********************************************************************
468 * create_cocoa_window
470 * Create the whole Mac window for a given window
472 static void create_cocoa_window(struct macdrv_win_data *data)
474 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
475 WCHAR text[1024];
476 struct macdrv_window_features wf;
477 CGRect frame;
478 DWORD style, ex_style;
479 HRGN win_rgn;
480 COLORREF key;
481 BYTE alpha;
482 DWORD layered_flags;
484 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
485 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
487 DeleteObject(win_rgn);
488 win_rgn = 0;
490 data->shaped = (win_rgn != 0);
492 style = GetWindowLongW(data->hwnd, GWL_STYLE);
493 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
495 data->whole_rect = data->window_rect;
496 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
498 get_cocoa_window_features(data, style, ex_style, &wf);
500 frame = cgrect_from_rect(data->whole_rect);
501 constrain_window_frame(&frame);
502 if (frame.size.width < 1 || frame.size.height < 1)
503 frame.size.width = frame.size.height = 1;
505 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
506 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
508 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
509 if (!data->cocoa_window) goto done;
511 set_cocoa_window_properties(data);
513 /* set the window text */
514 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
515 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
517 /* set the window region */
518 if (win_rgn || IsRectEmpty(&data->window_rect)) sync_window_region(data, win_rgn);
520 /* set the window opacity */
521 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
522 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
524 done:
525 if (win_rgn) DeleteObject(win_rgn);
529 /**********************************************************************
530 * destroy_cocoa_window
532 * Destroy the whole Mac window for a given window.
534 static void destroy_cocoa_window(struct macdrv_win_data *data)
536 if (!data->cocoa_window) return;
538 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
540 macdrv_destroy_cocoa_window(data->cocoa_window);
541 data->cocoa_window = 0;
542 data->on_screen = FALSE;
543 data->color_key = CLR_INVALID;
544 if (data->surface) window_surface_release(data->surface);
545 data->surface = NULL;
546 if (data->unminimized_surface) window_surface_release(data->unminimized_surface);
547 data->unminimized_surface = NULL;
551 /***********************************************************************
552 * macdrv_create_win_data
554 * Create a Mac data window structure for an existing window.
556 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
557 const RECT *client_rect)
559 struct macdrv_win_data *data;
560 HWND parent;
562 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
564 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
566 macdrv_init_thread_data();
567 return NULL;
570 /* don't create win data for HWND_MESSAGE windows */
571 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
573 if (!(data = alloc_win_data(hwnd))) return NULL;
575 data->whole_rect = data->window_rect = *window_rect;
576 data->client_rect = *client_rect;
578 if (parent == GetDesktopWindow())
580 create_cocoa_window(data);
581 TRACE("win %p/%p window %s whole %s client %s\n",
582 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
583 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
586 return data;
590 /***********************************************************************
591 * show_window
593 static void show_window(struct macdrv_win_data *data)
595 HWND prev = NULL;
596 HWND next = NULL;
597 macdrv_window prev_window = NULL;
598 macdrv_window next_window = NULL;
599 BOOL activate = FALSE;
601 /* find window that this one must be after */
602 prev = GetWindow(data->hwnd, GW_HWNDPREV);
603 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
604 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
605 prev = GetWindow(prev, GW_HWNDPREV);
606 if (!prev_window)
608 /* find window that this one must be before */
609 next = GetWindow(data->hwnd, GW_HWNDNEXT);
610 while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
611 (next_window = macdrv_get_cocoa_window(next, TRUE))))
612 next = GetWindow(next, GW_HWNDNEXT);
615 TRACE("win %p/%p below %p/%p above %p/%p\n",
616 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
618 if (!prev_window)
619 activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
620 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window, activate);
621 if (data->on_screen)
623 HWND hwndFocus = GetFocus();
624 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
625 macdrv_SetFocus(hwndFocus);
626 if (activate)
627 activate_on_focus_time = 0;
632 /***********************************************************************
633 * hide_window
635 static void hide_window(struct macdrv_win_data *data)
637 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
639 macdrv_hide_cocoa_window(data->cocoa_window);
640 data->on_screen = FALSE;
644 /***********************************************************************
645 * get_region_data
647 * Calls GetRegionData on the given region and converts the rectangle
648 * array to CGRect format. The returned buffer must be freed by
649 * caller using HeapFree(GetProcessHeap(),...).
650 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
652 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
654 RGNDATA *data;
655 DWORD size;
656 int i;
657 RECT *rect;
658 CGRect *cgrect;
660 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
661 if (sizeof(CGRect) > sizeof(RECT))
663 /* add extra size for CGRect array */
664 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
665 size += count * (sizeof(CGRect) - sizeof(RECT));
667 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
668 if (!GetRegionData(hrgn, size, data))
670 HeapFree(GetProcessHeap(), 0, data);
671 return NULL;
674 rect = (RECT *)data->Buffer;
675 cgrect = (CGRect *)data->Buffer;
676 if (hdc_lptodp) /* map to device coordinates */
678 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
679 for (i = 0; i < data->rdh.nCount; i++)
681 if (rect[i].right < rect[i].left)
683 INT tmp = rect[i].right;
684 rect[i].right = rect[i].left;
685 rect[i].left = tmp;
687 if (rect[i].bottom < rect[i].top)
689 INT tmp = rect[i].bottom;
690 rect[i].bottom = rect[i].top;
691 rect[i].top = tmp;
696 if (sizeof(CGRect) > sizeof(RECT))
698 /* need to start from the end */
699 for (i = data->rdh.nCount-1; i >= 0; i--)
700 cgrect[i] = cgrect_from_rect(rect[i]);
702 else
704 for (i = 0; i < data->rdh.nCount; i++)
705 cgrect[i] = cgrect_from_rect(rect[i]);
707 return data;
711 /***********************************************************************
712 * sync_window_position
714 * Synchronize the Mac window position with the Windows one
716 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags, const RECT *old_window_rect)
718 CGRect frame;
720 if (data->minimized) return;
722 frame = cgrect_from_rect(data->whole_rect);
723 constrain_window_frame(&frame);
724 if (frame.size.width < 1 || frame.size.height < 1)
725 frame.size.width = frame.size.height = 1;
727 data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
728 if (old_window_rect && IsRectEmpty(old_window_rect) != IsRectEmpty(&data->window_rect))
729 sync_window_region(data, (HRGN)1);
731 TRACE("win %p/%p whole_rect %s frame %s\n", data->hwnd, data->cocoa_window,
732 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_cgrect(frame));
734 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
735 show_window(data);
739 /***********************************************************************
740 * move_window_bits
742 * Move the window bits when a window is moved.
744 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
745 const RECT *old_client_rect, const RECT *new_client_rect,
746 const RECT *new_window_rect)
748 RECT src_rect = *old_rect;
749 RECT dst_rect = *new_rect;
750 HDC hdc_src, hdc_dst;
751 HRGN rgn;
752 HWND parent = 0;
754 if (!window)
756 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
757 parent = GetAncestor(hwnd, GA_PARENT);
758 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
759 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
761 else
763 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
764 /* make src rect relative to the old position of the window */
765 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
766 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
767 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
770 rgn = CreateRectRgnIndirect(&dst_rect);
771 SelectClipRgn(hdc_dst, rgn);
772 DeleteObject(rgn);
773 ExcludeUpdateRgn(hdc_dst, hwnd);
775 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
776 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
777 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
778 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
779 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
781 ReleaseDC(hwnd, hdc_dst);
782 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
786 /**********************************************************************
787 * CreateDesktopWindow (MACDRV.@)
789 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
791 unsigned int width, height;
793 TRACE("%p\n", hwnd);
795 /* retrieve the real size of the desktop */
796 SERVER_START_REQ(get_window_rectangles)
798 req->handle = wine_server_user_handle(hwnd);
799 req->relative = COORDS_CLIENT;
800 wine_server_call(req);
801 width = reply->window.right;
802 height = reply->window.bottom;
804 SERVER_END_REQ;
806 if (!width && !height) /* not initialized yet */
808 CGRect rect = macdrv_get_desktop_rect();
810 SERVER_START_REQ(set_window_pos)
812 req->handle = wine_server_user_handle(hwnd);
813 req->previous = 0;
814 req->swp_flags = SWP_NOZORDER;
815 req->window.left = CGRectGetMinX(rect);
816 req->window.top = CGRectGetMinY(rect);
817 req->window.right = CGRectGetMaxX(rect);
818 req->window.bottom = CGRectGetMaxY(rect);
819 req->client = req->window;
820 wine_server_call(req);
822 SERVER_END_REQ;
825 return TRUE;
829 /**********************************************************************
830 * CreateWindow (MACDRV.@)
832 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
834 return TRUE;
838 /***********************************************************************
839 * DestroyWindow (MACDRV.@)
841 void CDECL macdrv_DestroyWindow(HWND hwnd)
843 struct macdrv_win_data *data;
845 TRACE("%p\n", hwnd);
847 if (!(data = get_win_data(hwnd))) return;
849 if (data->gl_view) macdrv_dispose_view(data->gl_view);
850 destroy_cocoa_window(data);
852 CFDictionaryRemoveValue(win_datas, hwnd);
853 release_win_data(data);
854 HeapFree(GetProcessHeap(), 0, data);
858 /*****************************************************************
859 * SetFocus (MACDRV.@)
861 * Set the Mac focus.
863 void CDECL macdrv_SetFocus(HWND hwnd)
865 struct macdrv_thread_data *thread_data = macdrv_thread_data();
866 struct macdrv_win_data *data;
868 TRACE("%p\n", hwnd);
870 if (!thread_data) return;
871 thread_data->dead_key_state = 0;
873 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
874 if (!(data = get_win_data(hwnd))) return;
876 if (data->cocoa_window && data->on_screen)
878 BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
879 /* Set Mac focus */
880 macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
881 activate_on_focus_time = 0;
884 release_win_data(data);
888 /***********************************************************************
889 * SetLayeredWindowAttributes (MACDRV.@)
891 * Set transparency attributes for a layered window.
893 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
895 struct macdrv_win_data *data = get_win_data(hwnd);
897 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
899 if (data)
901 data->layered = TRUE;
902 if (data->cocoa_window)
904 sync_window_opacity(data, key, alpha, FALSE, flags);
905 /* since layered attributes are now set, can now show the window */
906 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
907 show_window(data);
909 release_win_data(data);
911 else
912 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
916 /*****************************************************************
917 * SetParent (MACDRV.@)
919 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
921 struct macdrv_win_data *data;
923 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
925 if (parent == old_parent) return;
926 if (!(data = get_win_data(hwnd))) return;
928 if (parent != GetDesktopWindow()) /* a child window */
930 if (old_parent == GetDesktopWindow())
932 /* destroy the old Mac window */
933 destroy_cocoa_window(data);
936 else /* new top level window */
937 create_cocoa_window(data);
938 release_win_data(data);
940 set_gl_view_parent(hwnd, parent);
944 /***********************************************************************
945 * SetWindowRgn (MACDRV.@)
947 * Assign specified region to window (for non-rectangular windows)
949 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
951 struct macdrv_win_data *data;
953 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
955 if ((data = get_win_data(hwnd)))
957 sync_window_region(data, hrgn);
958 release_win_data(data);
960 else
962 DWORD procid;
964 GetWindowThreadProcessId(hwnd, &procid);
965 if (procid != GetCurrentProcessId())
966 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
969 return TRUE;
973 /***********************************************************************
974 * SetWindowStyle (MACDRV.@)
976 * Update the state of the Cocoa window to reflect a style change
978 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
980 struct macdrv_win_data *data;
982 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd, offset, style->styleOld, style->styleNew);
984 if (hwnd == GetDesktopWindow()) return;
985 if (!(data = get_win_data(hwnd))) return;
987 if (data->cocoa_window)
989 DWORD changed = style->styleNew ^ style->styleOld;
991 set_cocoa_window_properties(data);
993 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
995 data->layered = FALSE;
996 data->ulw_layered = FALSE;
997 sync_window_opacity(data, 0, 0, FALSE, 0);
998 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
1002 release_win_data(data);
1006 /*****************************************************************
1007 * SetWindowText (MACDRV.@)
1009 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
1011 macdrv_window win;
1013 TRACE("%p, %s\n", hwnd, debugstr_w(text));
1015 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
1016 macdrv_set_cocoa_window_title(win, text, strlenW(text));
1020 /***********************************************************************
1021 * ShowWindow (MACDRV.@)
1023 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1025 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1026 struct macdrv_win_data *data = get_win_data(hwnd);
1027 CGRect frame;
1029 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1030 hwnd, data ? data->cocoa_window : NULL, cmd, wine_dbgstr_rect(rect), swp);
1032 if (!data || !data->cocoa_window) goto done;
1033 if (IsRectEmpty(rect)) goto done;
1034 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1036 if (rect->left != -32000 || rect->top != -32000)
1038 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1039 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1041 goto done;
1043 if (!data->on_screen) goto done;
1045 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1047 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1048 goto done;
1050 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1051 thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1052 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1053 goto done;
1055 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1056 *rect = rect_from_cgrect(frame);
1057 macdrv_mac_to_window_rect(data, rect);
1058 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1059 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1061 done:
1062 release_win_data(data);
1063 return swp;
1067 /***********************************************************************
1068 * SysCommand (MACDRV.@)
1070 * Perform WM_SYSCOMMAND handling.
1072 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1074 struct macdrv_win_data *data;
1075 LRESULT ret = -1;
1077 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1079 if (!(data = get_win_data(hwnd))) goto done;
1080 if (!data->cocoa_window || !data->on_screen) goto done;
1082 /* prevent a simple ALT press+release from activating the system menu,
1083 as that can get confusing */
1084 if ((wparam & 0xfff0) == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1085 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1087 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1088 ret = 0;
1091 done:
1092 release_win_data(data);
1093 return ret;
1097 /***********************************************************************
1098 * UpdateLayeredWindow (MACDRV.@)
1100 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1101 const RECT *window_rect)
1103 struct window_surface *surface;
1104 struct macdrv_win_data *data;
1105 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1106 BYTE alpha;
1107 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1108 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1109 void *src_bits, *dst_bits;
1110 RECT rect;
1111 HDC hdc = 0;
1112 HBITMAP dib;
1113 BOOL ret = FALSE;
1115 if (!(data = get_win_data(hwnd))) return FALSE;
1117 data->layered = TRUE;
1118 data->ulw_layered = TRUE;
1120 rect = *window_rect;
1121 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1123 surface = data->surface;
1124 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1126 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1127 set_window_surface(data->cocoa_window, data->surface);
1128 if (surface) window_surface_release(surface);
1129 surface = data->surface;
1130 if (data->unminimized_surface)
1132 window_surface_release(data->unminimized_surface);
1133 data->unminimized_surface = NULL;
1136 else set_surface_use_alpha(surface, TRUE);
1138 if (surface) window_surface_add_ref(surface);
1139 release_win_data(data);
1141 if (!surface) return FALSE;
1142 if (!info->hdcSrc)
1144 window_surface_release(surface);
1145 return TRUE;
1148 if (info->dwFlags & ULW_ALPHA)
1150 /* Apply SourceConstantAlpha via window alpha, not blend. */
1151 alpha = info->pblend->SourceConstantAlpha;
1152 blend = *info->pblend;
1153 blend.SourceConstantAlpha = 0xff;
1155 else
1156 alpha = 0xff;
1158 dst_bits = surface->funcs->get_info(surface, bmi);
1160 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1161 if (!(hdc = CreateCompatibleDC(0))) goto done;
1163 SelectObject(hdc, dib);
1164 if (info->prcDirty)
1166 IntersectRect(&rect, &rect, info->prcDirty);
1167 surface->funcs->lock(surface);
1168 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1169 surface->funcs->unlock(surface);
1170 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1172 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1173 info->hdcSrc,
1174 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1175 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1176 rect.right - rect.left, rect.bottom - rect.top,
1177 blend)))
1178 goto done;
1180 if ((data = get_win_data(hwnd)))
1182 if (surface == data->surface)
1184 surface->funcs->lock(surface);
1185 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1186 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1187 surface->funcs->unlock(surface);
1188 surface->funcs->flush(surface);
1191 /* The ULW flags are a superset of the LWA flags. */
1192 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1194 release_win_data(data);
1197 done:
1198 window_surface_release(surface);
1199 if (hdc) DeleteDC(hdc);
1200 if (dib) DeleteObject(dib);
1201 return ret;
1205 /**********************************************************************
1206 * WindowMessage (MACDRV.@)
1208 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1210 struct macdrv_win_data *data;
1212 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1214 switch(msg)
1216 case WM_MACDRV_SET_WIN_REGION:
1217 if ((data = get_win_data(hwnd)))
1219 sync_window_region(data, (HRGN)1);
1220 release_win_data(data);
1222 return 0;
1223 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1224 if (hwnd == GetDesktopWindow())
1226 CGRect new_desktop_rect;
1227 RECT current_desktop_rect;
1229 macdrv_reset_device_metrics();
1230 new_desktop_rect = macdrv_get_desktop_rect();
1231 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1232 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1234 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1235 SMTO_ABORTIFHUNG, 2000, NULL);
1236 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1237 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1238 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1239 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1240 SMTO_ABORTIFHUNG, 2000, NULL);
1243 return 0;
1244 case WM_MACDRV_RESET_DEVICE_METRICS:
1245 macdrv_reset_device_metrics();
1246 return 0;
1247 case WM_MACDRV_DISPLAYCHANGE:
1248 if ((data = get_win_data(hwnd)))
1250 if (data->cocoa_window && data->on_screen)
1251 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE, NULL);
1252 release_win_data(data);
1254 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1255 return 0;
1256 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1257 activate_on_focus_time = GetTickCount();
1258 if (!activate_on_focus_time) activate_on_focus_time = 1;
1259 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1260 return 0;
1263 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1264 return 0;
1268 static inline RECT get_surface_rect(const RECT *visible_rect)
1270 RECT rect;
1271 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1273 IntersectRect(&rect, visible_rect, &desktop_rect);
1274 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1275 rect.left &= ~127;
1276 rect.top &= ~127;
1277 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1278 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1279 return rect;
1283 /***********************************************************************
1284 * WindowPosChanging (MACDRV.@)
1286 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1287 const RECT *window_rect, const RECT *client_rect,
1288 RECT *visible_rect, struct window_surface **surface)
1290 struct macdrv_win_data *data = get_win_data(hwnd);
1291 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1292 RECT surface_rect;
1294 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1295 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1296 wine_dbgstr_rect(visible_rect), surface);
1298 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1300 *visible_rect = *window_rect;
1301 macdrv_window_to_mac_rect(data, style, visible_rect);
1302 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1303 wine_dbgstr_rect(visible_rect));
1305 /* create the window surface if necessary */
1306 if (!data->cocoa_window) goto done;
1307 if (swp_flags & SWP_HIDEWINDOW) goto done;
1308 if (data->ulw_layered) goto done;
1310 if (*surface) window_surface_release(*surface);
1311 *surface = NULL;
1313 surface_rect = get_surface_rect(visible_rect);
1314 if (data->surface)
1316 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1318 /* existing surface is good enough */
1319 surface_clip_to_visible_rect(data->surface, visible_rect);
1320 window_surface_add_ref(data->surface);
1321 *surface = data->surface;
1322 goto done;
1325 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1327 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1329 done:
1330 release_win_data(data);
1334 /***********************************************************************
1335 * WindowPosChanged (MACDRV.@)
1337 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1338 const RECT *window_rect, const RECT *client_rect,
1339 const RECT *visible_rect, const RECT *valid_rects,
1340 struct window_surface *surface)
1342 struct macdrv_thread_data *thread_data;
1343 struct macdrv_win_data *data;
1344 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1345 RECT old_window_rect, old_whole_rect, old_client_rect;
1347 if (!(data = get_win_data(hwnd))) return;
1349 thread_data = macdrv_thread_data();
1351 old_window_rect = data->window_rect;
1352 old_whole_rect = data->whole_rect;
1353 old_client_rect = data->client_rect;
1354 data->window_rect = *window_rect;
1355 data->whole_rect = *visible_rect;
1356 data->client_rect = *client_rect;
1357 if (!data->ulw_layered)
1359 if (surface) window_surface_add_ref(surface);
1360 if (new_style & WS_MINIMIZE)
1362 if (!data->unminimized_surface && data->surface)
1364 data->unminimized_surface = data->surface;
1365 window_surface_add_ref(data->unminimized_surface);
1368 else
1370 set_window_surface(data->cocoa_window, surface);
1371 if (data->unminimized_surface)
1373 window_surface_release(data->unminimized_surface);
1374 data->unminimized_surface = NULL;
1377 if (data->surface) window_surface_release(data->surface);
1378 data->surface = surface;
1381 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1382 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1383 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1384 new_style, swp_flags, surface);
1386 if (!IsRectEmpty(&valid_rects[0]))
1388 macdrv_window window = data->cocoa_window;
1389 int x_offset = old_whole_rect.left - data->whole_rect.left;
1390 int y_offset = old_whole_rect.top - data->whole_rect.top;
1392 /* if all that happened is that the whole window moved, copy everything */
1393 if (!(swp_flags & SWP_FRAMECHANGED) &&
1394 old_whole_rect.right - data->whole_rect.right == x_offset &&
1395 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1396 old_client_rect.left - data->client_rect.left == x_offset &&
1397 old_client_rect.right - data->client_rect.right == x_offset &&
1398 old_client_rect.top - data->client_rect.top == y_offset &&
1399 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1400 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1402 /* A Cocoa window's bits are moved automatically */
1403 if (!window && (x_offset != 0 || y_offset != 0))
1405 release_win_data(data);
1406 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1407 &old_client_rect, client_rect, window_rect);
1408 if (!(data = get_win_data(hwnd))) return;
1411 else
1413 release_win_data(data);
1414 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1415 &old_client_rect, client_rect, window_rect);
1416 if (!(data = get_win_data(hwnd))) return;
1420 sync_gl_view(data);
1422 if (!data->cocoa_window) goto done;
1424 if (data->on_screen)
1426 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1427 hide_window(data);
1430 /* check if we are currently processing an event relevant to this window */
1431 if (!thread_data || !thread_data->current_event ||
1432 thread_data->current_event->window != data->cocoa_window ||
1433 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1434 thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1435 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1437 sync_window_position(data, swp_flags, &old_window_rect);
1438 set_cocoa_window_properties(data);
1441 if (new_style & WS_VISIBLE)
1443 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1444 set_cocoa_window_properties(data);
1446 /* layered windows are not shown until their attributes are set */
1447 if (!data->on_screen &&
1448 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1449 show_window(data);
1452 done:
1453 release_win_data(data);
1457 /***********************************************************************
1458 * macdrv_window_close_requested
1460 * Handler for WINDOW_CLOSE_REQUESTED events.
1462 void macdrv_window_close_requested(HWND hwnd)
1464 /* Ignore the delete window request if the window has been disabled. This
1465 * is to disallow applications from being closed while in a modal state.
1467 if (IsWindowEnabled(hwnd))
1469 HMENU hSysMenu;
1471 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
1472 hSysMenu = GetSystemMenu(hwnd, FALSE);
1473 if (hSysMenu)
1475 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1476 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1477 return;
1479 if (GetActiveWindow() != hwnd)
1481 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1482 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1483 MAKELPARAM(HTCLOSE, WM_NCLBUTTONDOWN));
1484 switch(ma)
1486 case MA_NOACTIVATEANDEAT:
1487 case MA_ACTIVATEANDEAT:
1488 return;
1489 case MA_NOACTIVATE:
1490 break;
1491 case MA_ACTIVATE:
1492 case 0:
1493 SetActiveWindow(hwnd);
1494 break;
1495 default:
1496 WARN("unknown WM_MOUSEACTIVATE code %d\n", (int) ma);
1497 break;
1501 PostMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1506 /***********************************************************************
1507 * macdrv_window_frame_changed
1509 * Handler for WINDOW_FRAME_CHANGED events.
1511 void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
1513 struct macdrv_win_data *data;
1514 RECT rect;
1515 HWND parent;
1516 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1517 int width, height;
1519 if (!hwnd) return;
1520 if (!(data = get_win_data(hwnd))) return;
1521 if (!data->on_screen || data->minimized)
1523 release_win_data(data);
1524 return;
1527 /* Get geometry */
1529 parent = GetAncestor(hwnd, GA_PARENT);
1531 TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
1533 rect = rect_from_cgrect(frame);
1534 macdrv_mac_to_window_rect(data, &rect);
1535 MapWindowPoints(0, parent, (POINT *)&rect, 2);
1537 width = rect.right - rect.left;
1538 height = rect.bottom - rect.top;
1540 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1541 flags |= SWP_NOMOVE;
1542 else
1543 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1544 data->window_rect.top, rect.left, rect.top);
1546 if ((data->window_rect.right - data->window_rect.left == width &&
1547 data->window_rect.bottom - data->window_rect.top == height) ||
1548 (IsRectEmpty(&data->window_rect) && width == 1 && height == 1))
1549 flags |= SWP_NOSIZE;
1550 else
1551 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1552 data->window_rect.bottom - data->window_rect.top, width, height);
1554 release_win_data(data);
1556 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1557 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1561 /***********************************************************************
1562 * macdrv_window_got_focus
1564 * Handler for WINDOW_GOT_FOCUS events.
1566 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1568 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
1570 if (!hwnd) return;
1572 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1573 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
1574 IsWindowVisible(hwnd), style, GetFocus(), GetActiveWindow(), GetForegroundWindow());
1576 if (can_activate_window(hwnd) && !(style & WS_MINIMIZE))
1578 /* simulate a mouse click on the caption to find out
1579 * whether the window wants to be activated */
1580 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1581 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1582 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
1583 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
1585 TRACE("setting foreground window to %p\n", hwnd);
1586 SetForegroundWindow(hwnd);
1587 return;
1591 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
1592 macdrv_window_rejected_focus(event);
1596 /***********************************************************************
1597 * macdrv_window_lost_focus
1599 * Handler for WINDOW_LOST_FOCUS events.
1601 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
1603 if (!hwnd) return;
1605 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
1607 if (hwnd == GetForegroundWindow())
1609 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
1610 if (hwnd == GetForegroundWindow())
1611 SetForegroundWindow(GetDesktopWindow());
1616 /***********************************************************************
1617 * macdrv_app_deactivated
1619 * Handler for APP_DEACTIVATED events.
1621 void macdrv_app_deactivated(void)
1623 if (GetActiveWindow() == GetForegroundWindow())
1625 TRACE("setting fg to desktop\n");
1626 SetForegroundWindow(GetDesktopWindow());
1631 /***********************************************************************
1632 * macdrv_window_did_minimize
1634 * Handler for WINDOW_DID_MINIMIZE events.
1636 void macdrv_window_did_minimize(HWND hwnd)
1638 struct macdrv_win_data *data;
1639 DWORD style;
1641 TRACE("win %p\n", hwnd);
1643 if (!(data = get_win_data(hwnd))) return;
1644 if (data->minimized) goto done;
1646 style = GetWindowLongW(hwnd, GWL_STYLE);
1648 data->minimized = TRUE;
1649 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1651 TRACE("minimizing win %p/%p\n", hwnd, data->cocoa_window);
1652 release_win_data(data);
1653 SendMessageW(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1654 return;
1656 TRACE("not minimizing win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1658 done:
1659 release_win_data(data);
1663 /***********************************************************************
1664 * macdrv_window_did_unminimize
1666 * Handler for WINDOW_DID_UNMINIMIZE events.
1668 void macdrv_window_did_unminimize(HWND hwnd)
1670 struct macdrv_win_data *data;
1671 DWORD style;
1673 TRACE("win %p\n", hwnd);
1675 if (!(data = get_win_data(hwnd))) return;
1676 if (!data->minimized) goto done;
1678 style = GetWindowLongW(hwnd, GWL_STYLE);
1680 data->minimized = FALSE;
1681 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1683 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
1684 release_win_data(data);
1685 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1686 return;
1689 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1691 done:
1692 release_win_data(data);
1696 struct quit_info {
1697 HWND *wins;
1698 UINT capacity;
1699 UINT count;
1700 UINT done;
1701 DWORD flags;
1702 BOOL result;
1703 BOOL replied;
1707 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
1709 struct quit_info *qi = (struct quit_info*)lp;
1710 DWORD pid;
1712 GetWindowThreadProcessId(hwnd, &pid);
1713 if (pid == GetCurrentProcessId())
1715 if (qi->count >= qi->capacity)
1717 UINT new_cap = qi->capacity * 2;
1718 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
1719 new_cap * sizeof(*qi->wins));
1720 if (!new_wins) return FALSE;
1721 qi->wins = new_wins;
1722 qi->capacity = new_cap;
1725 qi->wins[qi->count++] = hwnd;
1728 return TRUE;
1732 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
1734 struct quit_info *qi = (struct quit_info*)data;
1736 qi->done++;
1738 if (msg == WM_QUERYENDSESSION)
1740 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
1741 hwnd, qi->done, qi->count);
1743 if (!result && qi->result)
1745 qi->result = FALSE;
1747 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
1748 ultimate reply. Might as well tell Cocoa now. */
1749 if (!qi->replied)
1751 qi->replied = TRUE;
1752 TRACE("giving quit reply %d\n", qi->result);
1753 macdrv_quit_reply(qi->result);
1757 if (qi->done >= qi->count)
1759 UINT i;
1761 qi->done = 0;
1762 for (i = 0; i < qi->count; i++)
1764 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
1765 qi->result, qi->flags);
1766 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
1767 quit_callback, (ULONG_PTR)qi))
1769 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
1770 qi->wins[i], GetLastError());
1771 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
1776 else /* WM_ENDSESSION */
1778 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
1780 if (qi->done >= qi->count)
1782 if (!qi->replied)
1784 TRACE("giving quit reply %d\n", qi->result);
1785 macdrv_quit_reply(qi->result);
1788 TRACE("%sterminating process\n", qi->result ? "" : "not ");
1789 if (qi->result)
1790 TerminateProcess(GetCurrentProcess(), 0);
1792 HeapFree(GetProcessHeap(), 0, qi->wins);
1793 HeapFree(GetProcessHeap(), 0, qi);
1799 /***********************************************************************
1800 * macdrv_app_quit_requested
1802 * Handler for APP_QUIT_REQUESTED events.
1804 void macdrv_app_quit_requested(const macdrv_event *event)
1806 struct quit_info *qi;
1807 UINT i;
1809 TRACE("reason %d\n", event->app_quit_requested.reason);
1811 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
1812 if (!qi)
1813 goto fail;
1815 qi->capacity = 32;
1816 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
1817 qi->count = qi->done = 0;
1819 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
1820 goto fail;
1822 switch (event->app_quit_requested.reason)
1824 case QUIT_REASON_LOGOUT:
1825 default:
1826 qi->flags = ENDSESSION_LOGOFF;
1827 break;
1828 case QUIT_REASON_RESTART:
1829 case QUIT_REASON_SHUTDOWN:
1830 qi->flags = 0;
1831 break;
1834 qi->result = TRUE;
1835 qi->replied = FALSE;
1837 for (i = 0; i < qi->count; i++)
1839 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
1840 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
1841 quit_callback, (ULONG_PTR)qi))
1843 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
1844 qi->wins[i], GetLastError());
1845 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, FALSE);
1849 /* quit_callback() will clean up qi */
1850 return;
1852 fail:
1853 WARN("failed to allocate window list\n");
1854 if (qi)
1856 HeapFree(GetProcessHeap(), 0, qi->wins);
1857 HeapFree(GetProcessHeap(), 0, qi);
1859 macdrv_quit_reply(FALSE);