winemac: Handle failure to get clipboard format name; don't use uninitialized buffer.
[wine.git] / dlls / winemac.drv / window.c
blob987aa348d8c3e68140c1dbb95397684c2d93100e
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;
46 void CDECL macdrv_SetFocus(HWND hwnd);
49 /***********************************************************************
50 * get_cocoa_window_features
52 static void get_cocoa_window_features(struct macdrv_win_data *data,
53 DWORD style, DWORD ex_style,
54 struct macdrv_window_features* wf)
56 memset(wf, 0, sizeof(*wf));
58 if (IsRectEmpty(&data->window_rect)) return;
60 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
62 wf->shadow = 1;
63 if (!data->shaped)
65 wf->title_bar = 1;
66 if (style & WS_SYSMENU) wf->close_button = 1;
67 if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
68 if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
69 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
72 if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
73 else if (style & WS_THICKFRAME)
75 wf->shadow = 1;
76 if (!data->shaped) wf->resizable = 1;
78 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
82 /*******************************************************************
83 * can_activate_window
85 * Check if we can activate the specified window.
87 static inline BOOL can_activate_window(HWND hwnd)
89 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
90 RECT rect;
92 if (!(style & WS_VISIBLE)) return FALSE;
93 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
94 if (style & WS_MINIMIZE) return FALSE;
95 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
96 if (hwnd == GetDesktopWindow()) return FALSE;
97 if (GetWindowRect(hwnd, &rect) && IsRectEmpty(&rect)) 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 state->minimized = (style & WS_MINIMIZE) != 0;
120 /***********************************************************************
121 * get_mac_rect_offset
123 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
125 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
127 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
129 rect->top = rect->bottom = rect->left = rect->right = 0;
131 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
133 if (!data->shaped)
135 struct macdrv_window_features wf;
136 get_cocoa_window_features(data, style, ex_style, &wf);
138 if (wf.title_bar) style_mask |= WS_CAPTION;
139 if (wf.shadow)
141 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
142 ex_style_mask |= WS_EX_DLGMODALFRAME;
146 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
148 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
149 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
153 /***********************************************************************
154 * macdrv_window_to_mac_rect
156 * Convert a rect from client to Mac window coordinates
158 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
160 RECT rc;
162 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
163 if (IsRectEmpty(rect)) return;
165 get_mac_rect_offset(data, style, &rc);
167 rect->left -= rc.left;
168 rect->right -= rc.right;
169 rect->top -= rc.top;
170 rect->bottom -= rc.bottom;
171 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
172 if (rect->left >= rect->right) rect->right = rect->left + 1;
176 /***********************************************************************
177 * macdrv_mac_to_window_rect
179 * Opposite of macdrv_window_to_mac_rect
181 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
183 RECT rc;
184 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
186 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
187 if (IsRectEmpty(rect)) return;
189 get_mac_rect_offset(data, style, &rc);
191 rect->left += rc.left;
192 rect->right += rc.right;
193 rect->top += rc.top;
194 rect->bottom += rc.bottom;
195 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
196 if (rect->left >= rect->right) rect->right = rect->left + 1;
200 /***********************************************************************
201 * constrain_window_frame
203 * Alter a window frame rectangle to fit within a) Cocoa's documented
204 * limits, and b) sane sizes, like twice the desktop rect.
206 static void constrain_window_frame(CGRect* frame)
208 CGRect desktop_rect = macdrv_get_desktop_rect();
209 int max_width, max_height;
211 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
212 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
214 if (frame->origin.x < -16000) frame->origin.x = -16000;
215 if (frame->origin.y < -16000) frame->origin.y = -16000;
216 if (frame->origin.x > 16000) frame->origin.x = 16000;
217 if (frame->origin.y > 16000) frame->origin.y = 16000;
218 if (frame->size.width > max_width) frame->size.width = max_width;
219 if (frame->size.height > max_height) frame->size.height = max_height;
223 /***********************************************************************
224 * alloc_win_data
226 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
228 struct macdrv_win_data *data;
230 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
232 data->hwnd = hwnd;
233 data->color_key = CLR_INVALID;
234 EnterCriticalSection(&win_data_section);
235 if (!win_datas)
236 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
237 CFDictionarySetValue(win_datas, hwnd, data);
239 return data;
243 /***********************************************************************
244 * get_win_data
246 * Lock and return the data structure associated with a window.
248 struct macdrv_win_data *get_win_data(HWND hwnd)
250 struct macdrv_win_data *data;
252 if (!hwnd) return NULL;
253 EnterCriticalSection(&win_data_section);
254 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
255 return data;
256 LeaveCriticalSection(&win_data_section);
257 return NULL;
261 /***********************************************************************
262 * release_win_data
264 * Release the data returned by get_win_data.
266 void release_win_data(struct macdrv_win_data *data)
268 if (data) LeaveCriticalSection(&win_data_section);
272 /***********************************************************************
273 * macdrv_get_cocoa_window
275 * Return the Mac window associated with the full area of a window
277 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
279 struct macdrv_win_data *data = get_win_data(hwnd);
280 macdrv_window ret = NULL;
281 if (data && (data->on_screen || !require_on_screen))
282 ret = data->cocoa_window;
283 release_win_data(data);
284 return ret;
288 /***********************************************************************
289 * set_cocoa_window_properties
291 * Set the window properties for a Cocoa window based on its Windows
292 * properties.
294 static void set_cocoa_window_properties(struct macdrv_win_data *data)
296 DWORD style, ex_style;
297 HWND owner;
298 macdrv_window owner_win;
299 struct macdrv_window_features wf;
300 struct macdrv_window_state state;
302 style = GetWindowLongW(data->hwnd, GWL_STYLE);
303 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
305 owner = GetWindow(data->hwnd, GW_OWNER);
306 owner_win = macdrv_get_cocoa_window(owner, TRUE);
307 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
309 get_cocoa_window_features(data, style, ex_style, &wf);
310 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
312 get_cocoa_window_state(data, style, ex_style, &state);
313 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
314 data->minimized = state.minimized;
318 /***********************************************************************
319 * sync_window_region
321 * Update the window region.
323 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
325 HRGN hrgn = win_region;
326 RGNDATA *region_data;
327 const CGRect* rects;
328 int count;
330 if (!data->cocoa_window) return;
331 data->shaped = FALSE;
333 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
335 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
336 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
338 DeleteObject(hrgn);
339 hrgn = 0;
343 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
344 MirrorRgn(data->hwnd, hrgn);
345 if (hrgn)
347 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
348 data->window_rect.top - data->whole_rect.top);
350 region_data = get_region_data(hrgn, 0);
351 if (region_data)
353 rects = (CGRect*)region_data->Buffer;
354 count = region_data->rdh.nCount;
355 /* Special case optimization. If the region entirely encloses the Cocoa
356 window, it's the same as there being no region. It's potentially
357 hard/slow to test this for arbitrary regions, so we just check for
358 very simple regions. */
359 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
361 TRACE("optimizing for simple region that contains Cocoa content rect\n");
362 rects = NULL;
363 count = 0;
366 else
368 rects = NULL;
369 count = 0;
372 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
373 macdrv_set_window_shape(data->cocoa_window, rects, count);
375 HeapFree(GetProcessHeap(), 0, region_data);
376 data->shaped = (region_data != NULL);
378 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
382 /***********************************************************************
383 * add_bounds_rect
385 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
387 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
388 bounds->left = min(bounds->left, rect->left);
389 bounds->top = min(bounds->top, rect->top);
390 bounds->right = max(bounds->right, rect->right);
391 bounds->bottom = max(bounds->bottom, rect->bottom);
395 /***********************************************************************
396 * sync_window_opacity
398 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
399 BOOL per_pixel_alpha, DWORD flags)
401 CGFloat opacity = 1.0;
402 BOOL needs_flush = FALSE;
404 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
406 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
407 macdrv_set_window_alpha(data->cocoa_window, opacity);
409 if (flags & LWA_COLORKEY)
411 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
412 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
413 key = RGB(0, 0, 0);
415 else
416 key = CLR_INVALID;
418 if (data->color_key != key)
420 if (key == CLR_INVALID)
422 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
423 macdrv_clear_window_color_key(data->cocoa_window);
425 else
427 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
428 GetRValue(key), GetGValue(key), GetBValue(key));
429 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
432 data->color_key = key;
433 needs_flush = TRUE;
436 if (!data->per_pixel_alpha != !per_pixel_alpha)
438 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
439 data->per_pixel_alpha = per_pixel_alpha;
440 needs_flush = TRUE;
443 if (needs_flush && data->surface)
445 RECT *bounds;
446 RECT rect;
448 rect = data->whole_rect;
449 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
450 data->surface->funcs->lock(data->surface);
451 bounds = data->surface->funcs->get_bounds(data->surface);
452 add_bounds_rect(bounds, &rect);
453 data->surface->funcs->unlock(data->surface);
458 /**********************************************************************
459 * create_cocoa_window
461 * Create the whole Mac window for a given window
463 static void create_cocoa_window(struct macdrv_win_data *data)
465 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
466 WCHAR text[1024];
467 struct macdrv_window_features wf;
468 CGRect frame;
469 DWORD style, ex_style;
470 HRGN win_rgn;
471 COLORREF key;
472 BYTE alpha;
473 DWORD layered_flags;
475 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
476 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
478 DeleteObject(win_rgn);
479 win_rgn = 0;
481 data->shaped = (win_rgn != 0);
483 style = GetWindowLongW(data->hwnd, GWL_STYLE);
484 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
486 data->whole_rect = data->window_rect;
487 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
489 memset(&wf, 0, sizeof(wf));
490 get_cocoa_window_features(data, style, ex_style, &wf);
492 frame = cgrect_from_rect(data->whole_rect);
493 constrain_window_frame(&frame);
495 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
496 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
498 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
499 if (!data->cocoa_window) goto done;
501 set_cocoa_window_properties(data);
503 /* set the window text */
504 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
505 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
507 /* set the window region */
508 if (win_rgn) sync_window_region(data, win_rgn);
510 /* set the window opacity */
511 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
512 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
514 done:
515 if (win_rgn) DeleteObject(win_rgn);
519 /**********************************************************************
520 * destroy_cocoa_window
522 * Destroy the whole Mac window for a given window.
524 static void destroy_cocoa_window(struct macdrv_win_data *data)
526 if (!data->cocoa_window) return;
528 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
530 macdrv_destroy_cocoa_window(data->cocoa_window);
531 data->cocoa_window = 0;
532 data->on_screen = FALSE;
533 data->color_key = CLR_INVALID;
534 if (data->surface) window_surface_release(data->surface);
535 data->surface = NULL;
539 /***********************************************************************
540 * macdrv_create_win_data
542 * Create a Mac data window structure for an existing window.
544 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
545 const RECT *client_rect)
547 struct macdrv_win_data *data;
548 HWND parent;
550 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
552 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
554 macdrv_init_thread_data();
555 return NULL;
558 /* don't create win data for HWND_MESSAGE windows */
559 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
561 if (!(data = alloc_win_data(hwnd))) return NULL;
563 data->whole_rect = data->window_rect = *window_rect;
564 data->client_rect = *client_rect;
566 if (parent == GetDesktopWindow())
568 create_cocoa_window(data);
569 TRACE("win %p/%p window %s whole %s client %s\n",
570 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
571 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
574 return data;
578 /***********************************************************************
579 * show_window
581 static void show_window(struct macdrv_win_data *data)
583 HWND prev = NULL;
584 HWND next = NULL;
585 macdrv_window prev_window = NULL;
586 macdrv_window next_window = NULL;
588 /* find window that this one must be after */
589 prev = GetWindow(data->hwnd, GW_HWNDPREV);
590 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
591 (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
592 prev = GetWindow(prev, GW_HWNDPREV);
593 if (!prev_window)
595 /* find window that this one must be before */
596 next = GetWindow(data->hwnd, GW_HWNDNEXT);
597 while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
598 (next_window = macdrv_get_cocoa_window(next, TRUE))))
599 next = GetWindow(next, GW_HWNDNEXT);
602 TRACE("win %p/%p below %p/%p above %p/%p\n",
603 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
605 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window);
606 if (data->on_screen)
608 HWND hwndFocus = GetFocus();
609 if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
610 macdrv_SetFocus(hwndFocus);
615 /***********************************************************************
616 * hide_window
618 static void hide_window(struct macdrv_win_data *data)
620 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
622 macdrv_hide_cocoa_window(data->cocoa_window);
623 data->on_screen = FALSE;
627 /***********************************************************************
628 * get_region_data
630 * Calls GetRegionData on the given region and converts the rectangle
631 * array to CGRect format. The returned buffer must be freed by
632 * caller using HeapFree(GetProcessHeap(),...).
633 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
635 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
637 RGNDATA *data;
638 DWORD size;
639 int i;
640 RECT *rect;
641 CGRect *cgrect;
643 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
644 if (sizeof(CGRect) > sizeof(RECT))
646 /* add extra size for CGRect array */
647 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
648 size += count * (sizeof(CGRect) - sizeof(RECT));
650 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
651 if (!GetRegionData(hrgn, size, data))
653 HeapFree(GetProcessHeap(), 0, data);
654 return NULL;
657 rect = (RECT *)data->Buffer;
658 cgrect = (CGRect *)data->Buffer;
659 if (hdc_lptodp) /* map to device coordinates */
661 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
662 for (i = 0; i < data->rdh.nCount; i++)
664 if (rect[i].right < rect[i].left)
666 INT tmp = rect[i].right;
667 rect[i].right = rect[i].left;
668 rect[i].left = tmp;
670 if (rect[i].bottom < rect[i].top)
672 INT tmp = rect[i].bottom;
673 rect[i].bottom = rect[i].top;
674 rect[i].top = tmp;
679 if (sizeof(CGRect) > sizeof(RECT))
681 /* need to start from the end */
682 for (i = data->rdh.nCount-1; i >= 0; i--)
683 cgrect[i] = cgrect_from_rect(rect[i]);
685 else
687 for (i = 0; i < data->rdh.nCount; i++)
688 cgrect[i] = cgrect_from_rect(rect[i]);
690 return data;
694 /***********************************************************************
695 * sync_window_position
697 * Synchronize the Mac window position with the Windows one
699 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
701 CGRect frame;
703 if (data->minimized) return;
705 frame = cgrect_from_rect(data->whole_rect);
706 constrain_window_frame(&frame);
708 data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
709 if (data->shaped) sync_window_region(data, (HRGN)1);
711 TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
712 wine_dbgstr_rect(&data->whole_rect));
714 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
715 show_window(data);
719 /***********************************************************************
720 * move_window_bits
722 * Move the window bits when a window is moved.
724 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
725 const RECT *old_client_rect, const RECT *new_client_rect,
726 const RECT *new_window_rect)
728 RECT src_rect = *old_rect;
729 RECT dst_rect = *new_rect;
730 HDC hdc_src, hdc_dst;
731 HRGN rgn;
732 HWND parent = 0;
734 if (!window)
736 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
737 parent = GetAncestor(hwnd, GA_PARENT);
738 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
739 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
741 else
743 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
744 /* make src rect relative to the old position of the window */
745 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
746 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
747 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
750 rgn = CreateRectRgnIndirect(&dst_rect);
751 SelectClipRgn(hdc_dst, rgn);
752 DeleteObject(rgn);
753 ExcludeUpdateRgn(hdc_dst, hwnd);
755 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
756 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
757 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
758 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
759 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
761 ReleaseDC(hwnd, hdc_dst);
762 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
766 /**********************************************************************
767 * CreateDesktopWindow (MACDRV.@)
769 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
771 unsigned int width, height;
773 TRACE("%p\n", hwnd);
775 /* retrieve the real size of the desktop */
776 SERVER_START_REQ(get_window_rectangles)
778 req->handle = wine_server_user_handle(hwnd);
779 req->relative = COORDS_CLIENT;
780 wine_server_call(req);
781 width = reply->window.right;
782 height = reply->window.bottom;
784 SERVER_END_REQ;
786 if (!width && !height) /* not initialized yet */
788 CGRect rect = macdrv_get_desktop_rect();
790 SERVER_START_REQ(set_window_pos)
792 req->handle = wine_server_user_handle(hwnd);
793 req->previous = 0;
794 req->swp_flags = SWP_NOZORDER;
795 req->window.left = CGRectGetMinX(rect);
796 req->window.top = CGRectGetMinY(rect);
797 req->window.right = CGRectGetMaxX(rect);
798 req->window.bottom = CGRectGetMaxY(rect);
799 req->client = req->window;
800 wine_server_call(req);
802 SERVER_END_REQ;
805 return TRUE;
809 /**********************************************************************
810 * CreateWindow (MACDRV.@)
812 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
814 return TRUE;
818 /***********************************************************************
819 * DestroyWindow (MACDRV.@)
821 void CDECL macdrv_DestroyWindow(HWND hwnd)
823 struct macdrv_win_data *data;
825 TRACE("%p\n", hwnd);
827 if (!(data = get_win_data(hwnd))) return;
829 if (data->gl_view) macdrv_dispose_view(data->gl_view);
830 destroy_cocoa_window(data);
832 CFDictionaryRemoveValue(win_datas, hwnd);
833 release_win_data(data);
834 HeapFree(GetProcessHeap(), 0, data);
838 /*****************************************************************
839 * SetFocus (MACDRV.@)
841 * Set the Mac focus.
843 void CDECL macdrv_SetFocus(HWND hwnd)
845 struct macdrv_thread_data *thread_data = macdrv_thread_data();
846 struct macdrv_win_data *data;
848 TRACE("%p\n", hwnd);
850 if (!thread_data) return;
851 thread_data->dead_key_state = 0;
853 if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
854 if (!(data = get_win_data(hwnd))) return;
856 if (data->cocoa_window && data->on_screen)
858 /* Set Mac focus */
859 macdrv_give_cocoa_window_focus(data->cocoa_window);
862 release_win_data(data);
866 /***********************************************************************
867 * SetLayeredWindowAttributes (MACDRV.@)
869 * Set transparency attributes for a layered window.
871 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
873 struct macdrv_win_data *data = get_win_data(hwnd);
875 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
877 if (data)
879 data->layered = TRUE;
880 if (data->cocoa_window)
882 sync_window_opacity(data, key, alpha, FALSE, flags);
883 /* since layered attributes are now set, can now show the window */
884 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
885 show_window(data);
887 release_win_data(data);
889 else
890 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
894 /*****************************************************************
895 * SetParent (MACDRV.@)
897 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
899 struct macdrv_win_data *data;
901 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
903 if (parent == old_parent) return;
904 if (!(data = get_win_data(hwnd))) return;
906 if (parent != GetDesktopWindow()) /* a child window */
908 if (old_parent == GetDesktopWindow())
910 /* destroy the old Mac window */
911 destroy_cocoa_window(data);
914 else /* new top level window */
915 create_cocoa_window(data);
916 release_win_data(data);
918 set_gl_view_parent(hwnd, parent);
922 /***********************************************************************
923 * SetWindowRgn (MACDRV.@)
925 * Assign specified region to window (for non-rectangular windows)
927 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
929 struct macdrv_win_data *data;
931 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
933 if ((data = get_win_data(hwnd)))
935 sync_window_region(data, hrgn);
936 release_win_data(data);
938 else
940 DWORD procid;
942 GetWindowThreadProcessId(hwnd, &procid);
943 if (procid != GetCurrentProcessId())
944 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
947 return TRUE;
951 /***********************************************************************
952 * SetWindowStyle (MACDRV.@)
954 * Update the state of the Cocoa window to reflect a style change
956 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
958 struct macdrv_win_data *data;
960 TRACE("%p, %d, %p\n", hwnd, offset, style);
962 if (hwnd == GetDesktopWindow()) return;
963 if (!(data = get_win_data(hwnd))) return;
965 if (data->cocoa_window)
967 DWORD changed = style->styleNew ^ style->styleOld;
969 set_cocoa_window_properties(data);
971 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
973 data->layered = FALSE;
974 data->ulw_layered = FALSE;
975 sync_window_opacity(data, 0, 0, FALSE, 0);
976 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
980 release_win_data(data);
984 /*****************************************************************
985 * SetWindowText (MACDRV.@)
987 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
989 macdrv_window win;
991 TRACE("%p, %s\n", hwnd, debugstr_w(text));
993 if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
994 macdrv_set_cocoa_window_title(win, text, strlenW(text));
998 /***********************************************************************
999 * ShowWindow (MACDRV.@)
1001 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1003 struct macdrv_thread_data *thread_data = macdrv_thread_data();
1004 struct macdrv_win_data *data = get_win_data(hwnd);
1005 CGRect frame;
1007 if (!data || !data->cocoa_window) goto done;
1008 if (IsRectEmpty(rect)) goto done;
1009 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1011 if (rect->left != -32000 || rect->top != -32000)
1013 OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1014 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1016 goto done;
1018 if (!data->on_screen) goto done;
1020 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1022 if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1023 goto done;
1025 if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1026 thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1027 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1028 goto done;
1030 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1031 hwnd, data->cocoa_window, cmd, wine_dbgstr_rect(rect), swp);
1033 macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1034 *rect = rect_from_cgrect(frame);
1035 macdrv_mac_to_window_rect(data, rect);
1036 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1037 swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1039 done:
1040 release_win_data(data);
1041 return swp;
1045 /***********************************************************************
1046 * SysCommand (MACDRV.@)
1048 * Perform WM_SYSCOMMAND handling.
1050 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1052 struct macdrv_win_data *data;
1053 LRESULT ret = -1;
1055 TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1057 if (!(data = get_win_data(hwnd))) goto done;
1058 if (!data->cocoa_window || !data->on_screen) goto done;
1060 /* prevent a simple ALT press+release from activating the system menu,
1061 as that can get confusing */
1062 if ((wparam & 0xfff0) == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1063 (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1065 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1066 ret = 0;
1069 done:
1070 release_win_data(data);
1071 return ret;
1075 /***********************************************************************
1076 * UpdateLayeredWindow (MACDRV.@)
1078 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1079 const RECT *window_rect)
1081 struct window_surface *surface;
1082 struct macdrv_win_data *data;
1083 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1084 BYTE alpha;
1085 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1086 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1087 void *src_bits, *dst_bits;
1088 RECT rect;
1089 HDC hdc = 0;
1090 HBITMAP dib;
1091 BOOL ret = FALSE;
1093 if (!(data = get_win_data(hwnd))) return FALSE;
1095 data->layered = TRUE;
1096 data->ulw_layered = TRUE;
1098 rect = *window_rect;
1099 OffsetRect(&rect, -window_rect->left, -window_rect->top);
1101 surface = data->surface;
1102 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1104 data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1105 set_window_surface(data->cocoa_window, data->surface);
1106 if (surface) window_surface_release(surface);
1107 surface = data->surface;
1109 else set_surface_use_alpha(surface, TRUE);
1111 if (surface) window_surface_add_ref(surface);
1112 release_win_data(data);
1114 if (!surface) return FALSE;
1115 if (!info->hdcSrc)
1117 window_surface_release(surface);
1118 return TRUE;
1121 if (info->dwFlags & ULW_ALPHA)
1123 /* Apply SourceConstantAlpha via window alpha, not blend. */
1124 alpha = info->pblend->SourceConstantAlpha;
1125 blend = *info->pblend;
1126 blend.SourceConstantAlpha = 0xff;
1128 else
1129 alpha = 0xff;
1131 dst_bits = surface->funcs->get_info(surface, bmi);
1133 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1134 if (!(hdc = CreateCompatibleDC(0))) goto done;
1136 SelectObject(hdc, dib);
1137 if (info->prcDirty)
1139 IntersectRect(&rect, &rect, info->prcDirty);
1140 surface->funcs->lock(surface);
1141 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1142 surface->funcs->unlock(surface);
1143 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1145 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1146 info->hdcSrc,
1147 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1148 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1149 rect.right - rect.left, rect.bottom - rect.top,
1150 blend)))
1151 goto done;
1153 if ((data = get_win_data(hwnd)))
1155 if (surface == data->surface)
1157 surface->funcs->lock(surface);
1158 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1159 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1160 surface->funcs->unlock(surface);
1161 surface->funcs->flush(surface);
1164 /* The ULW flags are a superset of the LWA flags. */
1165 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1167 release_win_data(data);
1170 done:
1171 window_surface_release(surface);
1172 if (hdc) DeleteDC(hdc);
1173 if (dib) DeleteObject(dib);
1174 return ret;
1178 /**********************************************************************
1179 * WindowMessage (MACDRV.@)
1181 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1183 struct macdrv_win_data *data;
1185 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1187 switch(msg)
1189 case WM_MACDRV_SET_WIN_REGION:
1190 if ((data = get_win_data(hwnd)))
1192 sync_window_region(data, (HRGN)1);
1193 release_win_data(data);
1195 return 0;
1196 case WM_MACDRV_UPDATE_DESKTOP_RECT:
1197 if (hwnd == GetDesktopWindow())
1199 CGRect new_desktop_rect;
1200 RECT current_desktop_rect;
1202 macdrv_reset_device_metrics();
1203 new_desktop_rect = macdrv_get_desktop_rect();
1204 if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1205 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1207 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1208 SMTO_ABORTIFHUNG, 2000, NULL);
1209 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1210 CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1211 SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1212 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1213 SMTO_ABORTIFHUNG, 2000, NULL);
1216 return 0;
1217 case WM_MACDRV_RESET_DEVICE_METRICS:
1218 macdrv_reset_device_metrics();
1219 return 0;
1220 case WM_MACDRV_DISPLAYCHANGE:
1221 if ((data = get_win_data(hwnd)))
1223 if (data->cocoa_window && data->on_screen)
1224 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE);
1225 release_win_data(data);
1227 SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1228 return 0;
1231 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1232 return 0;
1236 static inline RECT get_surface_rect(const RECT *visible_rect)
1238 RECT rect;
1239 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1241 IntersectRect(&rect, visible_rect, &desktop_rect);
1242 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1243 rect.left &= ~127;
1244 rect.top &= ~127;
1245 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1246 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1247 return rect;
1251 /***********************************************************************
1252 * WindowPosChanging (MACDRV.@)
1254 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1255 const RECT *window_rect, const RECT *client_rect,
1256 RECT *visible_rect, struct window_surface **surface)
1258 struct macdrv_win_data *data = get_win_data(hwnd);
1259 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1260 RECT surface_rect;
1262 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1263 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1264 wine_dbgstr_rect(visible_rect), surface);
1266 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1268 *visible_rect = *window_rect;
1269 macdrv_window_to_mac_rect(data, style, visible_rect);
1270 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1271 wine_dbgstr_rect(visible_rect));
1273 /* create the window surface if necessary */
1274 if (!data->cocoa_window) goto done;
1275 if (swp_flags & SWP_HIDEWINDOW) goto done;
1276 if (data->ulw_layered) goto done;
1278 if (*surface) window_surface_release(*surface);
1279 *surface = NULL;
1281 surface_rect = get_surface_rect(visible_rect);
1282 if (data->surface)
1284 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1286 /* existing surface is good enough */
1287 surface_clip_to_visible_rect(data->surface, visible_rect);
1288 window_surface_add_ref(data->surface);
1289 *surface = data->surface;
1290 goto done;
1293 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1295 *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1297 done:
1298 release_win_data(data);
1302 /***********************************************************************
1303 * WindowPosChanged (MACDRV.@)
1305 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1306 const RECT *window_rect, const RECT *client_rect,
1307 const RECT *visible_rect, const RECT *valid_rects,
1308 struct window_surface *surface)
1310 struct macdrv_thread_data *thread_data;
1311 struct macdrv_win_data *data;
1312 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1313 RECT old_window_rect, old_whole_rect, old_client_rect;
1315 if (!(data = get_win_data(hwnd))) return;
1317 thread_data = macdrv_thread_data();
1319 old_window_rect = data->window_rect;
1320 old_whole_rect = data->whole_rect;
1321 old_client_rect = data->client_rect;
1322 data->window_rect = *window_rect;
1323 data->whole_rect = *visible_rect;
1324 data->client_rect = *client_rect;
1325 if (!data->ulw_layered)
1327 if (surface) window_surface_add_ref(surface);
1328 set_window_surface(data->cocoa_window, surface);
1329 if (data->surface) window_surface_release(data->surface);
1330 data->surface = surface;
1333 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1334 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1335 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1336 new_style, swp_flags, surface);
1338 if (!IsRectEmpty(&valid_rects[0]))
1340 macdrv_window window = data->cocoa_window;
1341 int x_offset = old_whole_rect.left - data->whole_rect.left;
1342 int y_offset = old_whole_rect.top - data->whole_rect.top;
1344 /* if all that happened is that the whole window moved, copy everything */
1345 if (!(swp_flags & SWP_FRAMECHANGED) &&
1346 old_whole_rect.right - data->whole_rect.right == x_offset &&
1347 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1348 old_client_rect.left - data->client_rect.left == x_offset &&
1349 old_client_rect.right - data->client_rect.right == x_offset &&
1350 old_client_rect.top - data->client_rect.top == y_offset &&
1351 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1352 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1354 /* A Cocoa window's bits are moved automatically */
1355 if (!window && (x_offset != 0 || y_offset != 0))
1357 release_win_data(data);
1358 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1359 &old_client_rect, client_rect, window_rect);
1360 if (!(data = get_win_data(hwnd))) return;
1363 else
1365 release_win_data(data);
1366 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1367 &old_client_rect, client_rect, window_rect);
1368 if (!(data = get_win_data(hwnd))) return;
1372 sync_gl_view(data);
1374 if (!data->cocoa_window) goto done;
1376 if (data->on_screen)
1378 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1379 hide_window(data);
1382 /* check if we are currently processing an event relevant to this window */
1383 if (!thread_data || !thread_data->current_event ||
1384 thread_data->current_event->window != data->cocoa_window ||
1385 (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1386 thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1387 thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1389 sync_window_position(data, swp_flags);
1390 set_cocoa_window_properties(data);
1393 if (new_style & WS_VISIBLE)
1395 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1396 set_cocoa_window_properties(data);
1398 /* layered windows are not shown until their attributes are set */
1399 if (!data->on_screen &&
1400 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1401 show_window(data);
1404 done:
1405 release_win_data(data);
1409 /***********************************************************************
1410 * macdrv_window_close_requested
1412 * Handler for WINDOW_CLOSE_REQUESTED events.
1414 void macdrv_window_close_requested(HWND hwnd)
1416 /* Ignore the delete window request if the window has been disabled. This
1417 * is to disallow applications from being closed while in a modal state.
1419 if (IsWindowEnabled(hwnd))
1421 HMENU hSysMenu;
1423 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
1424 hSysMenu = GetSystemMenu(hwnd, FALSE);
1425 if (hSysMenu)
1427 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1428 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1429 return;
1431 if (GetActiveWindow() != hwnd)
1433 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1434 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1435 MAKELPARAM(HTCLOSE, WM_NCLBUTTONDOWN));
1436 switch(ma)
1438 case MA_NOACTIVATEANDEAT:
1439 case MA_ACTIVATEANDEAT:
1440 return;
1441 case MA_NOACTIVATE:
1442 break;
1443 case MA_ACTIVATE:
1444 case 0:
1445 SetActiveWindow(hwnd);
1446 break;
1447 default:
1448 WARN("unknown WM_MOUSEACTIVATE code %d\n", (int) ma);
1449 break;
1453 PostMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1458 /***********************************************************************
1459 * macdrv_window_frame_changed
1461 * Handler for WINDOW_FRAME_CHANGED events.
1463 void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
1465 struct macdrv_win_data *data;
1466 RECT rect;
1467 HWND parent;
1468 UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1469 int width, height;
1471 if (!hwnd) return;
1472 if (!(data = get_win_data(hwnd))) return;
1473 if (!data->on_screen)
1475 release_win_data(data);
1476 return;
1479 /* Get geometry */
1481 parent = GetAncestor(hwnd, GA_PARENT);
1483 TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
1485 rect = rect_from_cgrect(frame);
1486 macdrv_mac_to_window_rect(data, &rect);
1487 MapWindowPoints(0, parent, (POINT *)&rect, 2);
1489 width = rect.right - rect.left;
1490 height = rect.bottom - rect.top;
1492 if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1493 flags |= SWP_NOMOVE;
1494 else
1495 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1496 data->window_rect.top, rect.left, rect.top);
1498 if ((data->window_rect.right - data->window_rect.left == width &&
1499 data->window_rect.bottom - data->window_rect.top == height) ||
1500 (IsRectEmpty(&data->window_rect) && width <= 0 && height <= 0))
1501 flags |= SWP_NOSIZE;
1502 else
1503 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1504 data->window_rect.bottom - data->window_rect.top, width, height);
1506 release_win_data(data);
1508 if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1509 SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1513 /***********************************************************************
1514 * macdrv_window_got_focus
1516 * Handler for WINDOW_GOT_FOCUS events.
1518 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1520 if (!hwnd) return;
1522 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1523 hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
1524 IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE), GetFocus(),
1525 GetActiveWindow(), GetForegroundWindow());
1527 if (can_activate_window(hwnd))
1529 /* simulate a mouse click on the caption to find out
1530 * whether the window wants to be activated */
1531 LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1532 (WPARAM)GetAncestor(hwnd, GA_ROOT),
1533 MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
1534 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
1536 TRACE("setting foreground window to %p\n", hwnd);
1537 SetForegroundWindow(hwnd);
1538 return;
1542 TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
1543 macdrv_window_rejected_focus(event);
1547 /***********************************************************************
1548 * macdrv_window_lost_focus
1550 * Handler for WINDOW_LOST_FOCUS events.
1552 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
1554 if (!hwnd) return;
1556 TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
1558 if (hwnd == GetForegroundWindow())
1559 SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
1563 /***********************************************************************
1564 * macdrv_app_deactivated
1566 * Handler for APP_DEACTIVATED events.
1568 void macdrv_app_deactivated(void)
1570 if (GetActiveWindow() == GetForegroundWindow())
1572 TRACE("setting fg to desktop\n");
1573 SetForegroundWindow(GetDesktopWindow());
1578 /***********************************************************************
1579 * macdrv_window_did_minimize
1581 * Handler for WINDOW_DID_MINIMIZE events.
1583 void macdrv_window_did_minimize(HWND hwnd)
1585 struct macdrv_win_data *data;
1586 DWORD style;
1588 TRACE("win %p\n", hwnd);
1590 if (!(data = get_win_data(hwnd))) return;
1591 if (data->minimized) goto done;
1593 style = GetWindowLongW(hwnd, GWL_STYLE);
1595 data->minimized = TRUE;
1596 if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1598 TRACE("minimizing win %p/%p\n", hwnd, data->cocoa_window);
1599 release_win_data(data);
1600 SendMessageW(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1601 return;
1603 TRACE("not minimizing win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1605 done:
1606 release_win_data(data);
1610 /***********************************************************************
1611 * macdrv_window_did_unminimize
1613 * Handler for WINDOW_DID_UNMINIMIZE events.
1615 void macdrv_window_did_unminimize(HWND hwnd)
1617 struct macdrv_win_data *data;
1618 DWORD style;
1620 TRACE("win %p\n", hwnd);
1622 if (!(data = get_win_data(hwnd))) return;
1623 if (!data->minimized) goto done;
1625 style = GetWindowLongW(hwnd, GWL_STYLE);
1627 data->minimized = FALSE;
1628 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1630 TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
1631 release_win_data(data);
1632 SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1633 return;
1636 TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1638 done:
1639 release_win_data(data);
1643 struct quit_info {
1644 HWND *wins;
1645 UINT capacity;
1646 UINT count;
1647 UINT done;
1648 DWORD flags;
1649 BOOL result;
1650 BOOL replied;
1654 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
1656 struct quit_info *qi = (struct quit_info*)lp;
1657 DWORD pid;
1659 GetWindowThreadProcessId(hwnd, &pid);
1660 if (pid == GetCurrentProcessId())
1662 if (qi->count >= qi->capacity)
1664 UINT new_cap = qi->capacity * 2;
1665 HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
1666 new_cap * sizeof(*qi->wins));
1667 if (!new_wins) return FALSE;
1668 qi->wins = new_wins;
1669 qi->capacity = new_cap;
1672 qi->wins[qi->count++] = hwnd;
1675 return TRUE;
1679 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
1681 struct quit_info *qi = (struct quit_info*)data;
1683 qi->done++;
1685 if (msg == WM_QUERYENDSESSION)
1687 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
1688 hwnd, qi->done, qi->count);
1690 if (!result && qi->result)
1692 qi->result = FALSE;
1694 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
1695 ultimate reply. Might as well tell Cocoa now. */
1696 if (!qi->replied)
1698 qi->replied = TRUE;
1699 TRACE("giving quit reply %d\n", qi->result);
1700 macdrv_quit_reply(qi->result);
1704 if (qi->done >= qi->count)
1706 UINT i;
1708 qi->done = 0;
1709 for (i = 0; i < qi->count; i++)
1711 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
1712 qi->result, qi->flags);
1713 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
1714 quit_callback, (ULONG_PTR)qi))
1716 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
1717 qi->wins[i], GetLastError());
1718 quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
1723 else /* WM_ENDSESSION */
1725 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
1727 if (qi->done >= qi->count)
1729 if (!qi->replied)
1731 TRACE("giving quit reply %d\n", qi->result);
1732 macdrv_quit_reply(qi->result);
1735 TRACE("%sterminating process\n", qi->result ? "" : "not ");
1736 if (qi->result)
1737 TerminateProcess(GetCurrentProcess(), 0);
1739 HeapFree(GetProcessHeap(), 0, qi->wins);
1740 HeapFree(GetProcessHeap(), 0, qi);
1746 /***********************************************************************
1747 * macdrv_app_quit_requested
1749 * Handler for APP_QUIT_REQUESTED events.
1751 void macdrv_app_quit_requested(const macdrv_event *event)
1753 struct quit_info *qi;
1754 UINT i;
1756 TRACE("reason %d\n", event->app_quit_requested.reason);
1758 qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
1759 if (!qi)
1760 goto fail;
1762 qi->capacity = 32;
1763 qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
1764 qi->count = qi->done = 0;
1766 if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
1767 goto fail;
1769 switch (event->app_quit_requested.reason)
1771 case QUIT_REASON_LOGOUT:
1772 default:
1773 qi->flags = ENDSESSION_LOGOFF;
1774 break;
1775 case QUIT_REASON_RESTART:
1776 case QUIT_REASON_SHUTDOWN:
1777 qi->flags = 0;
1778 break;
1781 qi->result = TRUE;
1782 qi->replied = FALSE;
1784 for (i = 0; i < qi->count; i++)
1786 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
1787 if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
1788 quit_callback, (ULONG_PTR)qi))
1790 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
1791 qi->wins[i], GetLastError());
1792 quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, FALSE);
1796 /* quit_callback() will clean up qi */
1797 return;
1799 fail:
1800 WARN("failed to allocate window list\n");
1801 if (qi)
1803 HeapFree(GetProcessHeap(), 0, qi->wins);
1804 HeapFree(GetProcessHeap(), 0, qi);
1806 macdrv_quit_reply(FALSE);