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
28 #include "wine/unicode.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv
);
34 static CRITICAL_SECTION win_data_section
;
35 static CRITICAL_SECTION_DEBUG critsect_debug
=
37 0, 0, &win_data_section
,
38 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
39 0, 0, { (DWORD_PTR
)(__FILE__
": win_data_section") }
41 static CRITICAL_SECTION win_data_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
43 static CFMutableDictionaryRef win_datas
;
45 static DWORD activate_on_focus_time
;
48 void CDECL
macdrv_SetFocus(HWND hwnd
);
51 /***********************************************************************
52 * get_cocoa_window_features
54 static void get_cocoa_window_features(struct macdrv_win_data
*data
,
55 DWORD style
, DWORD ex_style
,
56 struct macdrv_window_features
* wf
)
58 memset(wf
, 0, sizeof(*wf
));
60 if (disable_window_decorations
) return;
61 if (IsRectEmpty(&data
->window_rect
)) return;
63 if ((style
& WS_CAPTION
) == WS_CAPTION
&& !(ex_style
& WS_EX_LAYERED
))
69 if (style
& WS_SYSMENU
) wf
->close_button
= TRUE
;
70 if (style
& WS_MINIMIZEBOX
) wf
->minimize_button
= TRUE
;
71 if (style
& WS_MAXIMIZEBOX
) wf
->maximize_button
= TRUE
;
72 if (ex_style
& WS_EX_TOOLWINDOW
) wf
->utility
= TRUE
;
75 if (style
& WS_THICKFRAME
)
78 if (!data
->shaped
) wf
->resizable
= TRUE
;
80 else if (ex_style
& WS_EX_DLGMODALFRAME
) wf
->shadow
= TRUE
;
81 else if ((style
& (WS_DLGFRAME
|WS_BORDER
)) == WS_DLGFRAME
) wf
->shadow
= TRUE
;
85 /*******************************************************************
88 * Check if we can activate the specified window.
90 static inline BOOL
can_activate_window(HWND hwnd
)
92 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
94 if (!(style
& WS_VISIBLE
)) return FALSE
;
95 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
96 if (GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
97 if (hwnd
== GetDesktopWindow()) return FALSE
;
98 return !(style
& WS_DISABLED
);
102 /***********************************************************************
103 * get_cocoa_window_state
105 static void get_cocoa_window_state(struct macdrv_win_data
*data
,
106 DWORD style
, DWORD ex_style
,
107 struct macdrv_window_state
* state
)
109 memset(state
, 0, sizeof(*state
));
110 state
->disabled
= (style
& WS_DISABLED
) != 0;
111 state
->no_activate
= !can_activate_window(data
->hwnd
);
112 state
->floating
= (ex_style
& WS_EX_TOPMOST
) != 0;
113 state
->excluded_by_expose
= state
->excluded_by_cycle
=
114 (!(ex_style
& WS_EX_APPWINDOW
) &&
115 (GetWindow(data
->hwnd
, GW_OWNER
) || (ex_style
& (WS_EX_TOOLWINDOW
| WS_EX_NOACTIVATE
))));
116 if (IsRectEmpty(&data
->window_rect
))
117 state
->excluded_by_expose
= TRUE
;
118 state
->minimized
= (style
& WS_MINIMIZE
) != 0;
119 state
->minimized_valid
= state
->minimized
!= data
->minimized
;
120 state
->maximized
= (style
& WS_MAXIMIZE
) != 0;
124 /***********************************************************************
125 * get_mac_rect_offset
127 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
129 static void get_mac_rect_offset(struct macdrv_win_data
*data
, DWORD style
, RECT
*rect
)
131 DWORD ex_style
, style_mask
= 0, ex_style_mask
= 0;
133 rect
->top
= rect
->bottom
= rect
->left
= rect
->right
= 0;
135 ex_style
= GetWindowLongW(data
->hwnd
, GWL_EXSTYLE
);
139 struct macdrv_window_features wf
;
140 get_cocoa_window_features(data
, style
, ex_style
, &wf
);
144 style_mask
|= WS_CAPTION
;
145 ex_style_mask
|= WS_EX_TOOLWINDOW
;
149 style_mask
|= WS_DLGFRAME
| WS_THICKFRAME
;
150 ex_style_mask
|= WS_EX_DLGMODALFRAME
;
154 AdjustWindowRectEx(rect
, style
& style_mask
, FALSE
, ex_style
& ex_style_mask
);
156 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data
->hwnd
, data
->cocoa_window
,
157 style
, ex_style
, data
->shaped
, wine_dbgstr_rect(rect
));
161 /***********************************************************************
162 * macdrv_window_to_mac_rect
164 * Convert a rect from client to Mac window coordinates
166 static void macdrv_window_to_mac_rect(struct macdrv_win_data
*data
, DWORD style
, RECT
*rect
)
170 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return;
171 if (IsRectEmpty(rect
)) return;
173 get_mac_rect_offset(data
, style
, &rc
);
175 rect
->left
-= rc
.left
;
176 rect
->right
-= rc
.right
;
178 rect
->bottom
-= rc
.bottom
;
179 if (rect
->top
>= rect
->bottom
) rect
->bottom
= rect
->top
+ 1;
180 if (rect
->left
>= rect
->right
) rect
->right
= rect
->left
+ 1;
184 /***********************************************************************
185 * macdrv_mac_to_window_rect
187 * Opposite of macdrv_window_to_mac_rect
189 static void macdrv_mac_to_window_rect(struct macdrv_win_data
*data
, RECT
*rect
)
192 DWORD style
= GetWindowLongW(data
->hwnd
, GWL_STYLE
);
194 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return;
195 if (IsRectEmpty(rect
)) return;
197 get_mac_rect_offset(data
, style
, &rc
);
199 rect
->left
+= rc
.left
;
200 rect
->right
+= rc
.right
;
202 rect
->bottom
+= rc
.bottom
;
203 if (rect
->top
>= rect
->bottom
) rect
->bottom
= rect
->top
+ 1;
204 if (rect
->left
>= rect
->right
) rect
->right
= rect
->left
+ 1;
208 /***********************************************************************
209 * constrain_window_frame
211 * Alter a window frame rectangle to fit within a) Cocoa's documented
212 * limits, and b) sane sizes, like twice the desktop rect.
214 static void constrain_window_frame(CGRect
* frame
)
216 CGRect desktop_rect
= macdrv_get_desktop_rect();
217 int max_width
, max_height
;
219 max_width
= min(32000, 2 * CGRectGetWidth(desktop_rect
));
220 max_height
= min(32000, 2 * CGRectGetHeight(desktop_rect
));
222 if (frame
->origin
.x
< -16000) frame
->origin
.x
= -16000;
223 if (frame
->origin
.y
< -16000) frame
->origin
.y
= -16000;
224 if (frame
->origin
.x
> 16000) frame
->origin
.x
= 16000;
225 if (frame
->origin
.y
> 16000) frame
->origin
.y
= 16000;
226 if (frame
->size
.width
> max_width
) frame
->size
.width
= max_width
;
227 if (frame
->size
.height
> max_height
) frame
->size
.height
= max_height
;
231 /***********************************************************************
234 static struct macdrv_win_data
*alloc_win_data(HWND hwnd
)
236 struct macdrv_win_data
*data
;
238 if ((data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
))))
241 data
->color_key
= CLR_INVALID
;
242 data
->swap_interval
= 1;
243 EnterCriticalSection(&win_data_section
);
245 win_datas
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
246 CFDictionarySetValue(win_datas
, hwnd
, data
);
252 /***********************************************************************
255 * Lock and return the data structure associated with a window.
257 struct macdrv_win_data
*get_win_data(HWND hwnd
)
259 struct macdrv_win_data
*data
;
261 if (!hwnd
) return NULL
;
262 EnterCriticalSection(&win_data_section
);
263 if (win_datas
&& (data
= (struct macdrv_win_data
*)CFDictionaryGetValue(win_datas
, hwnd
)))
265 LeaveCriticalSection(&win_data_section
);
270 /***********************************************************************
273 * Release the data returned by get_win_data.
275 void release_win_data(struct macdrv_win_data
*data
)
277 if (data
) LeaveCriticalSection(&win_data_section
);
281 /***********************************************************************
282 * macdrv_get_cocoa_window
284 * Return the Mac window associated with the full area of a window
286 macdrv_window
macdrv_get_cocoa_window(HWND hwnd
, BOOL require_on_screen
)
288 struct macdrv_win_data
*data
= get_win_data(hwnd
);
289 macdrv_window ret
= NULL
;
290 if (data
&& (data
->on_screen
|| !require_on_screen
))
291 ret
= data
->cocoa_window
;
292 release_win_data(data
);
297 /***********************************************************************
298 * set_cocoa_window_properties
300 * Set the window properties for a Cocoa window based on its Windows
303 static void set_cocoa_window_properties(struct macdrv_win_data
*data
)
305 DWORD style
, ex_style
;
307 macdrv_window owner_win
;
308 struct macdrv_window_features wf
;
309 struct macdrv_window_state state
;
311 style
= GetWindowLongW(data
->hwnd
, GWL_STYLE
);
312 ex_style
= GetWindowLongW(data
->hwnd
, GWL_EXSTYLE
);
314 owner
= GetWindow(data
->hwnd
, GW_OWNER
);
315 owner_win
= macdrv_get_cocoa_window(owner
, TRUE
);
316 macdrv_set_cocoa_parent_window(data
->cocoa_window
, owner_win
);
318 get_cocoa_window_features(data
, style
, ex_style
, &wf
);
319 macdrv_set_cocoa_window_features(data
->cocoa_window
, &wf
);
321 get_cocoa_window_state(data
, style
, ex_style
, &state
);
322 macdrv_set_cocoa_window_state(data
->cocoa_window
, &state
);
323 if (state
.minimized_valid
)
324 data
->minimized
= state
.minimized
;
328 /***********************************************************************
331 * Update the window region.
333 static void sync_window_region(struct macdrv_win_data
*data
, HRGN win_region
)
335 HRGN hrgn
= win_region
;
336 RGNDATA
*region_data
;
340 if (!data
->cocoa_window
) return;
341 data
->shaped
= FALSE
;
343 if (IsRectEmpty(&data
->window_rect
)) /* set an empty shape */
345 TRACE("win %p/%p setting empty shape for zero-sized window\n", data
->hwnd
, data
->cocoa_window
);
346 macdrv_set_window_shape(data
->cocoa_window
, &CGRectZero
, 1);
350 if (hrgn
== (HRGN
)1) /* hack: win_region == 1 means retrieve region from server */
352 if (!(hrgn
= CreateRectRgn(0, 0, 0, 0))) return;
353 if (GetWindowRgn(data
->hwnd
, hrgn
) == ERROR
)
360 if (hrgn
&& GetWindowLongW(data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
361 MirrorRgn(data
->hwnd
, hrgn
);
364 OffsetRgn(hrgn
, data
->window_rect
.left
- data
->whole_rect
.left
,
365 data
->window_rect
.top
- data
->whole_rect
.top
);
367 region_data
= get_region_data(hrgn
, 0);
370 rects
= (CGRect
*)region_data
->Buffer
;
371 count
= region_data
->rdh
.nCount
;
372 /* Special case optimization. If the region entirely encloses the Cocoa
373 window, it's the same as there being no region. It's potentially
374 hard/slow to test this for arbitrary regions, so we just check for
375 very simple regions. */
376 if (count
== 1 && CGRectContainsRect(rects
[0], cgrect_from_rect(data
->whole_rect
)))
378 TRACE("optimizing for simple region that contains Cocoa content rect\n");
389 TRACE("win %p/%p win_region %p rects %p count %d\n", data
->hwnd
, data
->cocoa_window
, win_region
, rects
, count
);
390 macdrv_set_window_shape(data
->cocoa_window
, rects
, count
);
392 HeapFree(GetProcessHeap(), 0, region_data
);
393 data
->shaped
= (region_data
!= NULL
);
395 if (hrgn
&& hrgn
!= win_region
) DeleteObject(hrgn
);
399 /***********************************************************************
402 static inline void add_bounds_rect(RECT
*bounds
, const RECT
*rect
)
404 if (rect
->left
>= rect
->right
|| rect
->top
>= rect
->bottom
) return;
405 bounds
->left
= min(bounds
->left
, rect
->left
);
406 bounds
->top
= min(bounds
->top
, rect
->top
);
407 bounds
->right
= max(bounds
->right
, rect
->right
);
408 bounds
->bottom
= max(bounds
->bottom
, rect
->bottom
);
412 /***********************************************************************
413 * sync_window_opacity
415 static void sync_window_opacity(struct macdrv_win_data
*data
, COLORREF key
, BYTE alpha
,
416 BOOL per_pixel_alpha
, DWORD flags
)
418 CGFloat opacity
= 1.0;
419 BOOL needs_flush
= FALSE
;
421 if (flags
& LWA_ALPHA
) opacity
= alpha
/ 255.0;
423 TRACE("setting window %p/%p alpha to %g\n", data
->hwnd
, data
->cocoa_window
, opacity
);
424 macdrv_set_window_alpha(data
->cocoa_window
, opacity
);
426 if (flags
& LWA_COLORKEY
)
428 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
429 if ((key
& (1 << 24)) || key
>> 16 == 0x10ff)
435 if (data
->color_key
!= key
)
437 if (key
== CLR_INVALID
)
439 TRACE("clearing color-key for window %p/%p\n", data
->hwnd
, data
->cocoa_window
);
440 macdrv_clear_window_color_key(data
->cocoa_window
);
444 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data
->hwnd
, data
->cocoa_window
,
445 GetRValue(key
), GetGValue(key
), GetBValue(key
));
446 macdrv_set_window_color_key(data
->cocoa_window
, GetRValue(key
), GetGValue(key
), GetBValue(key
));
449 data
->color_key
= key
;
453 if (!data
->per_pixel_alpha
!= !per_pixel_alpha
)
455 macdrv_window_use_per_pixel_alpha(data
->cocoa_window
, per_pixel_alpha
);
456 data
->per_pixel_alpha
= per_pixel_alpha
;
460 if (needs_flush
&& data
->surface
)
465 rect
= data
->whole_rect
;
466 OffsetRect(&rect
, -data
->whole_rect
.left
, -data
->whole_rect
.top
);
467 data
->surface
->funcs
->lock(data
->surface
);
468 bounds
= data
->surface
->funcs
->get_bounds(data
->surface
);
469 add_bounds_rect(bounds
, &rect
);
470 data
->surface
->funcs
->unlock(data
->surface
);
475 /***********************************************************************
476 * sync_window_min_max_info
478 static void sync_window_min_max_info(HWND hwnd
)
480 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
481 LONG exstyle
= GetWindowLongW(hwnd
, GWL_EXSTYLE
);
482 RECT win_rect
, primary_monitor_rect
;
488 struct macdrv_win_data
*data
;
490 TRACE("win %p\n", hwnd
);
492 if (!macdrv_get_cocoa_window(hwnd
, FALSE
)) return;
494 GetWindowRect(hwnd
, &win_rect
);
495 minmax
.ptReserved
.x
= win_rect
.left
;
496 minmax
.ptReserved
.y
= win_rect
.top
;
498 if ((style
& WS_CAPTION
) == WS_CAPTION
)
499 adjustedStyle
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
501 adjustedStyle
= style
;
503 primary_monitor_rect
.left
= primary_monitor_rect
.top
= 0;
504 primary_monitor_rect
.right
= GetSystemMetrics(SM_CXSCREEN
);
505 primary_monitor_rect
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
506 AdjustWindowRectEx(&primary_monitor_rect
, adjustedStyle
, ((style
& WS_POPUP
) && GetMenu(hwnd
)), exstyle
);
508 xinc
= -primary_monitor_rect
.left
;
509 yinc
= -primary_monitor_rect
.top
;
511 minmax
.ptMaxSize
.x
= primary_monitor_rect
.right
- primary_monitor_rect
.left
;
512 minmax
.ptMaxSize
.y
= primary_monitor_rect
.bottom
- primary_monitor_rect
.top
;
513 minmax
.ptMaxPosition
.x
= -xinc
;
514 minmax
.ptMaxPosition
.y
= -yinc
;
515 if (style
& (WS_DLGFRAME
| WS_BORDER
))
517 minmax
.ptMinTrackSize
.x
= GetSystemMetrics(SM_CXMINTRACK
);
518 minmax
.ptMinTrackSize
.y
= GetSystemMetrics(SM_CYMINTRACK
);
522 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
523 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
525 minmax
.ptMaxTrackSize
.x
= GetSystemMetrics(SM_CXMAXTRACK
);
526 minmax
.ptMaxTrackSize
.y
= GetSystemMetrics(SM_CYMAXTRACK
);
528 wpl
.length
= sizeof(wpl
);
529 if (GetWindowPlacement(hwnd
, &wpl
) && (wpl
.ptMaxPosition
.x
!= -1 || wpl
.ptMaxPosition
.y
!= -1))
531 minmax
.ptMaxPosition
= wpl
.ptMaxPosition
;
533 /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
534 minmax
.ptMaxPosition
.x
-= wpl
.rcNormalPosition
.left
- win_rect
.left
;
535 minmax
.ptMaxPosition
.y
-= wpl
.rcNormalPosition
.top
- win_rect
.top
;
538 TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax
.ptMaxSize
),
539 wine_dbgstr_point(&minmax
.ptMaxPosition
), wine_dbgstr_point(&minmax
.ptMinTrackSize
), wine_dbgstr_point(&minmax
.ptMaxTrackSize
));
541 SendMessageW(hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
543 TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax
.ptMaxSize
),
544 wine_dbgstr_point(&minmax
.ptMaxPosition
), wine_dbgstr_point(&minmax
.ptMinTrackSize
), wine_dbgstr_point(&minmax
.ptMaxTrackSize
));
546 /* if the app didn't change the values, adapt them for the window's monitor */
547 if ((monitor
= MonitorFromWindow(hwnd
, MONITOR_DEFAULTTOPRIMARY
)))
549 MONITORINFO mon_info
;
552 mon_info
.cbSize
= sizeof(mon_info
);
553 GetMonitorInfoW(monitor
, &mon_info
);
555 if ((style
& WS_MAXIMIZEBOX
) && ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& WS_POPUP
)))
556 monitor_rect
= mon_info
.rcWork
;
558 monitor_rect
= mon_info
.rcMonitor
;
560 if (minmax
.ptMaxSize
.x
== primary_monitor_rect
.right
- primary_monitor_rect
.left
&&
561 minmax
.ptMaxSize
.y
== primary_monitor_rect
.bottom
- primary_monitor_rect
.top
)
563 minmax
.ptMaxSize
.x
= (monitor_rect
.right
- monitor_rect
.left
) + 2 * xinc
;
564 minmax
.ptMaxSize
.y
= (monitor_rect
.bottom
- monitor_rect
.top
) + 2 * yinc
;
566 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
568 minmax
.ptMaxPosition
.x
= monitor_rect
.left
- xinc
;
569 minmax
.ptMaxPosition
.y
= monitor_rect
.top
- yinc
;
573 minmax
.ptMaxTrackSize
.x
= max(minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
574 minmax
.ptMaxTrackSize
.y
= max(minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
576 TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax
.ptMaxSize
),
577 wine_dbgstr_point(&minmax
.ptMaxPosition
), wine_dbgstr_point(&minmax
.ptMinTrackSize
), wine_dbgstr_point(&minmax
.ptMaxTrackSize
));
579 if ((data
= get_win_data(hwnd
)) && data
->cocoa_window
)
581 RECT min_rect
, max_rect
;
582 CGSize min_size
, max_size
;
584 SetRect(&min_rect
, 0, 0, minmax
.ptMinTrackSize
.x
, minmax
.ptMinTrackSize
.y
);
585 macdrv_window_to_mac_rect(data
, style
, &min_rect
);
586 min_size
= CGSizeMake(min_rect
.right
- min_rect
.left
, min_rect
.bottom
- min_rect
.top
);
588 if (minmax
.ptMaxTrackSize
.x
== GetSystemMetrics(SM_CXMAXTRACK
) &&
589 minmax
.ptMaxTrackSize
.y
== GetSystemMetrics(SM_CYMAXTRACK
))
590 max_size
= CGSizeMake(CGFLOAT_MAX
, CGFLOAT_MAX
);
593 SetRect(&max_rect
, 0, 0, minmax
.ptMaxTrackSize
.x
, minmax
.ptMaxTrackSize
.y
);
594 macdrv_window_to_mac_rect(data
, style
, &max_rect
);
595 max_size
= CGSizeMake(max_rect
.right
- max_rect
.left
, max_rect
.bottom
- max_rect
.top
);
598 TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size
.width
, min_size
.height
, max_size
.width
, max_size
.height
);
599 macdrv_set_window_min_max_sizes(data
->cocoa_window
, min_size
, max_size
);
602 release_win_data(data
);
606 /**********************************************************************
607 * create_cocoa_window
609 * Create the whole Mac window for a given window
611 static void create_cocoa_window(struct macdrv_win_data
*data
)
613 struct macdrv_thread_data
*thread_data
= macdrv_init_thread_data();
615 struct macdrv_window_features wf
;
617 DWORD style
, ex_style
;
623 if ((win_rgn
= CreateRectRgn(0, 0, 0, 0)) &&
624 GetWindowRgn(data
->hwnd
, win_rgn
) == ERROR
)
626 DeleteObject(win_rgn
);
629 data
->shaped
= (win_rgn
!= 0);
631 style
= GetWindowLongW(data
->hwnd
, GWL_STYLE
);
632 ex_style
= GetWindowLongW(data
->hwnd
, GWL_EXSTYLE
);
634 data
->whole_rect
= data
->window_rect
;
635 macdrv_window_to_mac_rect(data
, style
, &data
->whole_rect
);
637 get_cocoa_window_features(data
, style
, ex_style
, &wf
);
639 frame
= cgrect_from_rect(data
->whole_rect
);
640 constrain_window_frame(&frame
);
641 if (frame
.size
.width
< 1 || frame
.size
.height
< 1)
642 frame
.size
.width
= frame
.size
.height
= 1;
644 TRACE("creating %p window %s whole %s client %s\n", data
->hwnd
, wine_dbgstr_rect(&data
->window_rect
),
645 wine_dbgstr_rect(&data
->whole_rect
), wine_dbgstr_rect(&data
->client_rect
));
647 data
->cocoa_window
= macdrv_create_cocoa_window(&wf
, frame
, data
->hwnd
, thread_data
->queue
);
648 if (!data
->cocoa_window
) goto done
;
650 set_cocoa_window_properties(data
);
652 /* set the window text */
653 if (!InternalGetWindowText(data
->hwnd
, text
, sizeof(text
)/sizeof(WCHAR
))) text
[0] = 0;
654 macdrv_set_cocoa_window_title(data
->cocoa_window
, text
, strlenW(text
));
656 /* set the window region */
657 if (win_rgn
|| IsRectEmpty(&data
->window_rect
)) sync_window_region(data
, win_rgn
);
659 /* set the window opacity */
660 if (!GetLayeredWindowAttributes(data
->hwnd
, &key
, &alpha
, &layered_flags
)) layered_flags
= 0;
661 sync_window_opacity(data
, key
, alpha
, FALSE
, layered_flags
);
664 if (win_rgn
) DeleteObject(win_rgn
);
668 /**********************************************************************
669 * destroy_cocoa_window
671 * Destroy the whole Mac window for a given window.
673 static void destroy_cocoa_window(struct macdrv_win_data
*data
)
675 if (!data
->cocoa_window
) return;
677 TRACE("win %p Cocoa win %p\n", data
->hwnd
, data
->cocoa_window
);
679 macdrv_destroy_cocoa_window(data
->cocoa_window
);
680 data
->cocoa_window
= 0;
681 data
->on_screen
= FALSE
;
682 data
->color_key
= CLR_INVALID
;
683 if (data
->surface
) window_surface_release(data
->surface
);
684 data
->surface
= NULL
;
685 if (data
->unminimized_surface
) window_surface_release(data
->unminimized_surface
);
686 data
->unminimized_surface
= NULL
;
690 /***********************************************************************
691 * macdrv_create_win_data
693 * Create a Mac data window structure for an existing window.
695 static struct macdrv_win_data
*macdrv_create_win_data(HWND hwnd
, const RECT
*window_rect
,
696 const RECT
*client_rect
)
698 struct macdrv_win_data
*data
;
701 if (GetWindowThreadProcessId(hwnd
, NULL
) != GetCurrentThreadId()) return NULL
;
703 if (!(parent
= GetAncestor(hwnd
, GA_PARENT
))) /* desktop */
705 macdrv_init_thread_data();
709 /* don't create win data for HWND_MESSAGE windows */
710 if (parent
!= GetDesktopWindow() && !GetAncestor(parent
, GA_PARENT
)) return NULL
;
712 if (!(data
= alloc_win_data(hwnd
))) return NULL
;
714 data
->whole_rect
= data
->window_rect
= *window_rect
;
715 data
->client_rect
= *client_rect
;
717 if (parent
== GetDesktopWindow())
719 create_cocoa_window(data
);
720 TRACE("win %p/%p window %s whole %s client %s\n",
721 hwnd
, data
->cocoa_window
, wine_dbgstr_rect(&data
->window_rect
),
722 wine_dbgstr_rect(&data
->whole_rect
), wine_dbgstr_rect(&data
->client_rect
));
729 /***********************************************************************
732 static void show_window(struct macdrv_win_data
*data
)
736 macdrv_window prev_window
= NULL
;
737 macdrv_window next_window
= NULL
;
738 BOOL activate
= FALSE
;
741 /* find window that this one must be after */
742 prev
= GetWindow(data
->hwnd
, GW_HWNDPREV
);
743 while (prev
&& !((GetWindowLongW(prev
, GWL_STYLE
) & (WS_VISIBLE
| WS_MINIMIZE
)) == WS_VISIBLE
&&
744 (prev_window
= macdrv_get_cocoa_window(prev
, TRUE
))))
745 prev
= GetWindow(prev
, GW_HWNDPREV
);
748 /* find window that this one must be before */
749 next
= GetWindow(data
->hwnd
, GW_HWNDNEXT
);
750 while (next
&& !((GetWindowLongW(next
, GWL_STYLE
) & (WS_VISIBLE
| WS_MINIMIZE
)) == WS_VISIBLE
&&
751 (next_window
= macdrv_get_cocoa_window(next
, TRUE
))))
752 next
= GetWindow(next
, GW_HWNDNEXT
);
755 TRACE("win %p/%p below %p/%p above %p/%p\n",
756 data
->hwnd
, data
->cocoa_window
, prev
, prev_window
, next
, next_window
);
759 activate
= activate_on_focus_time
&& (GetTickCount() - activate_on_focus_time
< 2000);
760 macdrv_order_cocoa_window(data
->cocoa_window
, prev_window
, next_window
, activate
);
761 data
->on_screen
= TRUE
;
763 hwndFocus
= GetFocus();
764 if (hwndFocus
&& (data
->hwnd
== hwndFocus
|| IsChild(data
->hwnd
, hwndFocus
)))
765 macdrv_SetFocus(hwndFocus
);
767 activate_on_focus_time
= 0;
771 /***********************************************************************
774 static void hide_window(struct macdrv_win_data
*data
)
776 TRACE("win %p/%p\n", data
->hwnd
, data
->cocoa_window
);
778 macdrv_hide_cocoa_window(data
->cocoa_window
);
779 data
->on_screen
= FALSE
;
783 /***********************************************************************
786 * Calls GetRegionData on the given region and converts the rectangle
787 * array to CGRect format. The returned buffer must be freed by
788 * caller using HeapFree(GetProcessHeap(),...).
789 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
791 RGNDATA
*get_region_data(HRGN hrgn
, HDC hdc_lptodp
)
799 if (!hrgn
|| !(size
= GetRegionData(hrgn
, 0, NULL
))) return NULL
;
800 if (sizeof(CGRect
) > sizeof(RECT
))
802 /* add extra size for CGRect array */
803 int count
= (size
- sizeof(RGNDATAHEADER
)) / sizeof(RECT
);
804 size
+= count
* (sizeof(CGRect
) - sizeof(RECT
));
806 if (!(data
= HeapAlloc(GetProcessHeap(), 0, size
))) return NULL
;
807 if (!GetRegionData(hrgn
, size
, data
))
809 HeapFree(GetProcessHeap(), 0, data
);
813 rect
= (RECT
*)data
->Buffer
;
814 cgrect
= (CGRect
*)data
->Buffer
;
815 if (hdc_lptodp
) /* map to device coordinates */
817 LPtoDP(hdc_lptodp
, (POINT
*)rect
, data
->rdh
.nCount
* 2);
818 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
820 if (rect
[i
].right
< rect
[i
].left
)
822 INT tmp
= rect
[i
].right
;
823 rect
[i
].right
= rect
[i
].left
;
826 if (rect
[i
].bottom
< rect
[i
].top
)
828 INT tmp
= rect
[i
].bottom
;
829 rect
[i
].bottom
= rect
[i
].top
;
835 if (sizeof(CGRect
) > sizeof(RECT
))
837 /* need to start from the end */
838 for (i
= data
->rdh
.nCount
-1; i
>= 0; i
--)
839 cgrect
[i
] = cgrect_from_rect(rect
[i
]);
843 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
844 cgrect
[i
] = cgrect_from_rect(rect
[i
]);
850 /***********************************************************************
851 * sync_window_position
853 * Synchronize the Mac window position with the Windows one
855 static void sync_window_position(struct macdrv_win_data
*data
, UINT swp_flags
, const RECT
*old_window_rect
,
856 const RECT
*old_whole_rect
)
860 if (data
->minimized
) return;
862 frame
= cgrect_from_rect(data
->whole_rect
);
863 constrain_window_frame(&frame
);
864 if (frame
.size
.width
< 1 || frame
.size
.height
< 1)
865 frame
.size
.width
= frame
.size
.height
= 1;
867 macdrv_set_cocoa_window_frame(data
->cocoa_window
, &frame
);
868 if (old_window_rect
&& old_whole_rect
&&
869 (IsRectEmpty(old_window_rect
) != IsRectEmpty(&data
->window_rect
) ||
870 old_window_rect
->left
- old_whole_rect
->left
!= data
->window_rect
.left
- data
->whole_rect
.left
||
871 old_window_rect
->top
- old_whole_rect
->top
!= data
->window_rect
.top
- data
->whole_rect
.top
))
872 sync_window_region(data
, (HRGN
)1);
874 TRACE("win %p/%p whole_rect %s frame %s\n", data
->hwnd
, data
->cocoa_window
,
875 wine_dbgstr_rect(&data
->whole_rect
), wine_dbgstr_cgrect(frame
));
877 if (data
->on_screen
&& (!(swp_flags
& SWP_NOZORDER
) || (swp_flags
& SWP_SHOWWINDOW
)))
882 /***********************************************************************
885 * Move the window bits when a window is moved.
887 static void move_window_bits(HWND hwnd
, macdrv_window window
, const RECT
*old_rect
, const RECT
*new_rect
,
888 const RECT
*old_client_rect
, const RECT
*new_client_rect
,
889 const RECT
*new_window_rect
)
891 RECT src_rect
= *old_rect
;
892 RECT dst_rect
= *new_rect
;
893 HDC hdc_src
, hdc_dst
;
899 OffsetRect(&dst_rect
, -new_window_rect
->left
, -new_window_rect
->top
);
900 parent
= GetAncestor(hwnd
, GA_PARENT
);
901 hdc_src
= GetDCEx(parent
, 0, DCX_CACHE
);
902 hdc_dst
= GetDCEx(hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
906 OffsetRect(&dst_rect
, -new_client_rect
->left
, -new_client_rect
->top
);
907 /* make src rect relative to the old position of the window */
908 OffsetRect(&src_rect
, -old_client_rect
->left
, -old_client_rect
->top
);
909 if (dst_rect
.left
== src_rect
.left
&& dst_rect
.top
== src_rect
.top
) return;
910 hdc_src
= hdc_dst
= GetDCEx(hwnd
, 0, DCX_CACHE
);
913 rgn
= CreateRectRgnIndirect(&dst_rect
);
914 SelectClipRgn(hdc_dst
, rgn
);
916 ExcludeUpdateRgn(hdc_dst
, hwnd
);
918 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd
, window
,
919 wine_dbgstr_rect(&src_rect
), wine_dbgstr_rect(&dst_rect
));
920 BitBlt(hdc_dst
, dst_rect
.left
, dst_rect
.top
,
921 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
,
922 hdc_src
, src_rect
.left
, src_rect
.top
, SRCCOPY
);
924 ReleaseDC(hwnd
, hdc_dst
);
925 if (hdc_src
!= hdc_dst
) ReleaseDC(parent
, hdc_src
);
929 /**********************************************************************
930 * activate_on_following_focus
932 void activate_on_following_focus(void)
934 activate_on_focus_time
= GetTickCount();
935 if (!activate_on_focus_time
) activate_on_focus_time
= 1;
939 /***********************************************************************
942 static void set_app_icon(void)
944 CFArrayRef images
= create_app_icon_images();
947 macdrv_set_application_icon(images
);
953 /**********************************************************************
954 * set_capture_window_for_move
956 static BOOL
set_capture_window_for_move(HWND hwnd
)
961 SERVER_START_REQ(set_capture_window
)
963 req
->handle
= wine_server_user_handle(hwnd
);
964 req
->flags
= CAPTURE_MOVESIZE
;
965 if ((ret
= !wine_server_call_err(req
)))
967 previous
= wine_server_ptr_handle(reply
->previous
);
968 hwnd
= wine_server_ptr_handle(reply
->full_handle
);
975 macdrv_SetCapture(hwnd
, GUI_INMOVESIZE
);
977 if (previous
&& previous
!= hwnd
)
978 SendMessageW(previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
984 /***********************************************************************
987 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
988 * moving top-level windows and enforcing Mac-style constraints like
989 * keeping the top of the window within the work area.
991 static LRESULT
move_window(HWND hwnd
, WPARAM wparam
)
994 RECT origRect
, movedRect
, desktopRect
;
995 LONG hittest
= (LONG
)(wparam
& 0x0f);
997 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
999 DWORD dwPoint
= GetMessagePos();
1004 if ((style
& (WS_MINIMIZE
| WS_MAXIMIZE
)) || !IsWindowVisible(hwnd
)) return -1;
1005 if (hittest
&& hittest
!= HTCAPTION
) return -1;
1007 capturePoint
.x
= (short)LOWORD(dwPoint
);
1008 capturePoint
.y
= (short)HIWORD(dwPoint
);
1011 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd
, hittest
, capturePoint
.x
, capturePoint
.y
);
1013 origRect
.left
= origRect
.right
= origRect
.top
= origRect
.bottom
= 0;
1014 if (AdjustWindowRectEx(&origRect
, style
, FALSE
, GetWindowLongW(hwnd
, GWL_EXSTYLE
)))
1015 captionHeight
= -origRect
.top
;
1019 GetWindowRect(hwnd
, &origRect
);
1020 movedRect
= origRect
;
1024 /* Move pointer to the center of the caption */
1025 RECT rect
= origRect
;
1027 /* Note: to be exactly centered we should take the different types
1028 * of border into account, but it shouldn't make more than a few pixels
1029 * of difference so let's not bother with that */
1030 rect
.top
+= GetSystemMetrics(SM_CYBORDER
);
1031 if (style
& WS_SYSMENU
)
1032 rect
.left
+= GetSystemMetrics(SM_CXSIZE
) + 1;
1033 if (style
& WS_MINIMIZEBOX
)
1034 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
1035 if (style
& WS_MAXIMIZEBOX
)
1036 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
1037 capturePoint
.x
= (rect
.right
+ rect
.left
) / 2;
1038 capturePoint
.y
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
)/2;
1040 SetCursorPos(capturePoint
.x
, capturePoint
.y
);
1041 SendMessageW(hwnd
, WM_SETCURSOR
, (WPARAM
)hwnd
, MAKELONG(HTCAPTION
, WM_MOUSEMOVE
));
1044 desktopRect
= rect_from_cgrect(macdrv_get_desktop_rect());
1045 mon
= MonitorFromPoint(capturePoint
, MONITOR_DEFAULTTONEAREST
);
1046 info
.cbSize
= sizeof(info
);
1047 if (mon
&& !GetMonitorInfoW(mon
, &info
))
1050 /* repaint the window before moving it around */
1051 RedrawWindow(hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
1053 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
1054 set_capture_window_for_move(hwnd
);
1062 if (!GetMessageW(&msg
, 0, 0, 0)) break;
1063 if (CallMsgFilterW(&msg
, MSGF_SIZE
)) continue;
1065 /* Exit on button-up, Return, or Esc */
1066 if (msg
.message
== WM_LBUTTONUP
||
1067 (msg
.message
== WM_KEYDOWN
&& (msg
.wParam
== VK_RETURN
|| msg
.wParam
== VK_ESCAPE
)))
1070 if (msg
.message
!= WM_KEYDOWN
&& msg
.message
!= WM_MOUSEMOVE
)
1072 TranslateMessage(&msg
);
1073 DispatchMessageW(&msg
);
1074 continue; /* We are not interested in other messages */
1079 if (msg
.message
== WM_KEYDOWN
) switch(msg
.wParam
)
1081 case VK_UP
: pt
.y
-= 8; break;
1082 case VK_DOWN
: pt
.y
+= 8; break;
1083 case VK_LEFT
: pt
.x
-= 8; break;
1084 case VK_RIGHT
: pt
.x
+= 8; break;
1087 pt
.x
= max(pt
.x
, desktopRect
.left
);
1088 pt
.x
= min(pt
.x
, desktopRect
.right
- 1);
1089 pt
.y
= max(pt
.y
, desktopRect
.top
);
1090 pt
.y
= min(pt
.y
, desktopRect
.bottom
- 1);
1092 if ((newmon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
)) && newmon
!= mon
)
1094 if (GetMonitorInfoW(newmon
, &info
))
1102 /* wineserver clips the cursor position to the virtual desktop rect but,
1103 if the display configuration is non-rectangular, that could still
1104 leave the logical cursor position outside of any display. The window
1105 could keep moving as you push the cursor against a display edge, even
1106 though the visible cursor doesn't keep moving. The following keeps
1107 the window movement in sync with the visible cursor. */
1108 pt
.x
= max(pt
.x
, info
.rcMonitor
.left
);
1109 pt
.x
= min(pt
.x
, info
.rcMonitor
.right
- 1);
1110 pt
.y
= max(pt
.y
, info
.rcMonitor
.top
);
1111 pt
.y
= min(pt
.y
, info
.rcMonitor
.bottom
- 1);
1113 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1114 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1115 we want to enforce these constraints:
1116 movedRect.left + dx < info.rcWork.right
1117 movedRect.right + dx > info.rcWork.left
1118 movedRect.top + captionHeight + dy < info.rcWork.bottom
1119 movedRect.bottom + dy > info.rcWork.top
1120 movedRect.top + dy >= info.rcWork.top
1121 The first four keep at least one edge barely in the work area.
1122 The last keeps the top (i.e. the title bar) in the work area.
1123 The fourth is redundant with the last, so can be ignored.
1125 Substituting for dx and dy and rearranging gives us...
1127 pt
.x
= min(pt
.x
, info
.rcWork
.right
- 1 + capturePoint
.x
- movedRect
.left
);
1128 pt
.x
= max(pt
.x
, info
.rcWork
.left
+ 1 + capturePoint
.x
- movedRect
.right
);
1129 pt
.y
= min(pt
.y
, info
.rcWork
.bottom
- 1 + capturePoint
.y
- movedRect
.top
- captionHeight
);
1130 pt
.y
= max(pt
.y
, info
.rcWork
.top
+ capturePoint
.y
- movedRect
.top
);
1133 dx
= pt
.x
- capturePoint
.x
;
1134 dy
= pt
.y
- capturePoint
.y
;
1140 if (msg
.message
== WM_KEYDOWN
) SetCursorPos(pt
.x
, pt
.y
);
1143 OffsetRect(&movedRect
, dx
, dy
);
1146 SendMessageW(hwnd
, WM_MOVING
, 0, (LPARAM
)&movedRect
);
1147 SetWindowPos(hwnd
, 0, movedRect
.left
, movedRect
.top
, 0, 0,
1148 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOZORDER
);
1153 set_capture_window_for_move(0);
1155 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
1156 SendMessageW(hwnd
, WM_SETVISIBLE
, TRUE
, 0L);
1158 /* if the move is canceled, restore the previous position */
1159 if (moved
&& msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_ESCAPE
)
1161 SetWindowPos(hwnd
, 0, origRect
.left
, origRect
.top
, 0, 0,
1162 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOZORDER
);
1169 /***********************************************************************
1170 * perform_window_command
1172 static void perform_window_command(HWND hwnd
, DWORD style_any
, DWORD style_none
, WORD command
, WORD hittest
)
1176 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1177 hwnd
, style_any
, style_none
, command
, hittest
);
1179 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1180 if ((style_any
&& !(style
& style_any
)) || (style
& (WS_DISABLED
| style_none
)))
1182 TRACE("not changing win %p style 0x%08x\n", hwnd
, style
);
1186 if (GetActiveWindow() != hwnd
)
1188 LRESULT ma
= SendMessageW(hwnd
, WM_MOUSEACTIVATE
, (WPARAM
)GetAncestor(hwnd
, GA_ROOT
),
1189 MAKELPARAM(hittest
, WM_NCLBUTTONDOWN
));
1192 case MA_NOACTIVATEANDEAT
:
1193 case MA_ACTIVATEANDEAT
:
1194 TRACE("not changing win %p mouse-activate result %ld\n", hwnd
, ma
);
1200 SetActiveWindow(hwnd
);
1203 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma
);
1208 TRACE("changing win %p\n", hwnd
);
1209 PostMessageW(hwnd
, WM_SYSCOMMAND
, command
, 0);
1213 /**********************************************************************
1214 * CreateDesktopWindow (MACDRV.@)
1216 BOOL CDECL
macdrv_CreateDesktopWindow(HWND hwnd
)
1218 unsigned int width
, height
;
1220 TRACE("%p\n", hwnd
);
1222 /* retrieve the real size of the desktop */
1223 SERVER_START_REQ(get_window_rectangles
)
1225 req
->handle
= wine_server_user_handle(hwnd
);
1226 req
->relative
= COORDS_CLIENT
;
1227 wine_server_call(req
);
1228 width
= reply
->window
.right
;
1229 height
= reply
->window
.bottom
;
1233 if (!width
&& !height
) /* not initialized yet */
1235 CGRect rect
= macdrv_get_desktop_rect();
1237 SERVER_START_REQ(set_window_pos
)
1239 req
->handle
= wine_server_user_handle(hwnd
);
1241 req
->swp_flags
= SWP_NOZORDER
;
1242 req
->window
.left
= CGRectGetMinX(rect
);
1243 req
->window
.top
= CGRectGetMinY(rect
);
1244 req
->window
.right
= CGRectGetMaxX(rect
);
1245 req
->window
.bottom
= CGRectGetMaxY(rect
);
1246 req
->client
= req
->window
;
1247 wine_server_call(req
);
1257 /**********************************************************************
1258 * CreateWindow (MACDRV.@)
1260 BOOL CDECL
macdrv_CreateWindow(HWND hwnd
)
1266 /***********************************************************************
1267 * DestroyWindow (MACDRV.@)
1269 void CDECL
macdrv_DestroyWindow(HWND hwnd
)
1271 struct macdrv_win_data
*data
;
1273 TRACE("%p\n", hwnd
);
1275 if (!(data
= get_win_data(hwnd
))) return;
1277 if (hwnd
== GetCapture()) macdrv_SetCapture(0, 0);
1279 if (data
->gl_view
) macdrv_dispose_view(data
->gl_view
);
1280 destroy_cocoa_window(data
);
1282 CFDictionaryRemoveValue(win_datas
, hwnd
);
1283 release_win_data(data
);
1284 HeapFree(GetProcessHeap(), 0, data
);
1288 /*****************************************************************
1289 * SetFocus (MACDRV.@)
1291 * Set the Mac focus.
1293 void CDECL
macdrv_SetFocus(HWND hwnd
)
1295 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
1296 struct macdrv_win_data
*data
;
1298 TRACE("%p\n", hwnd
);
1300 if (!thread_data
) return;
1301 thread_data
->dead_key_state
= 0;
1303 if (!(hwnd
= GetAncestor(hwnd
, GA_ROOT
))) return;
1304 if (!(data
= get_win_data(hwnd
))) return;
1306 if (data
->cocoa_window
&& data
->on_screen
)
1308 BOOL activate
= activate_on_focus_time
&& (GetTickCount() - activate_on_focus_time
< 2000);
1310 macdrv_give_cocoa_window_focus(data
->cocoa_window
, activate
);
1311 activate_on_focus_time
= 0;
1314 release_win_data(data
);
1318 /***********************************************************************
1319 * SetLayeredWindowAttributes (MACDRV.@)
1321 * Set transparency attributes for a layered window.
1323 void CDECL
macdrv_SetLayeredWindowAttributes(HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
1325 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1327 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd
, key
, alpha
, flags
);
1331 data
->layered
= TRUE
;
1332 if (data
->cocoa_window
)
1334 sync_window_opacity(data
, key
, alpha
, FALSE
, flags
);
1335 /* since layered attributes are now set, can now show the window */
1336 if ((GetWindowLongW(hwnd
, GWL_STYLE
) & WS_VISIBLE
) && !data
->on_screen
)
1339 release_win_data(data
);
1342 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd
);
1346 /*****************************************************************
1347 * SetParent (MACDRV.@)
1349 void CDECL
macdrv_SetParent(HWND hwnd
, HWND parent
, HWND old_parent
)
1351 struct macdrv_win_data
*data
;
1353 TRACE("%p, %p, %p\n", hwnd
, parent
, old_parent
);
1355 if (parent
== old_parent
) return;
1356 if (!(data
= get_win_data(hwnd
))) return;
1358 if (parent
!= GetDesktopWindow()) /* a child window */
1360 if (old_parent
== GetDesktopWindow())
1362 /* destroy the old Mac window */
1363 destroy_cocoa_window(data
);
1366 else /* new top level window */
1367 create_cocoa_window(data
);
1368 release_win_data(data
);
1370 set_gl_view_parent(hwnd
, parent
);
1374 /***********************************************************************
1375 * SetWindowRgn (MACDRV.@)
1377 * Assign specified region to window (for non-rectangular windows)
1379 void CDECL
macdrv_SetWindowRgn(HWND hwnd
, HRGN hrgn
, BOOL redraw
)
1381 struct macdrv_win_data
*data
;
1383 TRACE("%p, %p, %d\n", hwnd
, hrgn
, redraw
);
1385 if ((data
= get_win_data(hwnd
)))
1387 sync_window_region(data
, hrgn
);
1388 release_win_data(data
);
1394 GetWindowThreadProcessId(hwnd
, &procid
);
1395 if (procid
!= GetCurrentProcessId())
1396 SendMessageW(hwnd
, WM_MACDRV_SET_WIN_REGION
, 0, 0);
1401 /***********************************************************************
1402 * SetWindowStyle (MACDRV.@)
1404 * Update the state of the Cocoa window to reflect a style change
1406 void CDECL
macdrv_SetWindowStyle(HWND hwnd
, INT offset
, STYLESTRUCT
*style
)
1408 struct macdrv_win_data
*data
;
1410 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd
, offset
, style
->styleOld
, style
->styleNew
);
1412 if (hwnd
== GetDesktopWindow()) return;
1413 if (!(data
= get_win_data(hwnd
))) return;
1415 if (data
->cocoa_window
)
1417 DWORD changed
= style
->styleNew
^ style
->styleOld
;
1419 set_cocoa_window_properties(data
);
1421 if (offset
== GWL_EXSTYLE
&& (changed
& WS_EX_LAYERED
)) /* changing WS_EX_LAYERED resets attributes */
1423 data
->layered
= FALSE
;
1424 data
->ulw_layered
= FALSE
;
1425 sync_window_opacity(data
, 0, 0, FALSE
, 0);
1426 if (data
->surface
) set_surface_use_alpha(data
->surface
, FALSE
);
1429 if (offset
== GWL_EXSTYLE
&& (changed
& WS_EX_LAYOUTRTL
))
1430 sync_window_region(data
, (HRGN
)1);
1433 release_win_data(data
);
1437 /*****************************************************************
1438 * SetWindowText (MACDRV.@)
1440 void CDECL
macdrv_SetWindowText(HWND hwnd
, LPCWSTR text
)
1444 TRACE("%p, %s\n", hwnd
, debugstr_w(text
));
1446 if ((win
= macdrv_get_cocoa_window(hwnd
, FALSE
)))
1447 macdrv_set_cocoa_window_title(win
, text
, strlenW(text
));
1451 /***********************************************************************
1452 * ShowWindow (MACDRV.@)
1454 UINT CDECL
macdrv_ShowWindow(HWND hwnd
, INT cmd
, RECT
*rect
, UINT swp
)
1456 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
1457 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1460 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1461 hwnd
, data
? data
->cocoa_window
: NULL
, cmd
, wine_dbgstr_rect(rect
), swp
);
1463 if (!data
|| !data
->cocoa_window
) goto done
;
1464 if (IsRectEmpty(rect
)) goto done
;
1465 if (GetWindowLongW(hwnd
, GWL_STYLE
) & WS_MINIMIZE
)
1467 if (rect
->left
!= -32000 || rect
->top
!= -32000)
1469 OffsetRect(rect
, -32000 - rect
->left
, -32000 - rect
->top
);
1470 swp
&= ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
1474 if (!data
->on_screen
) goto done
;
1476 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1478 if (!thread_data
->current_event
|| thread_data
->current_event
->window
!= data
->cocoa_window
)
1481 if (thread_data
->current_event
->type
!= WINDOW_FRAME_CHANGED
&&
1482 thread_data
->current_event
->type
!= WINDOW_DID_UNMINIMIZE
)
1485 macdrv_get_cocoa_window_frame(data
->cocoa_window
, &frame
);
1486 *rect
= rect_from_cgrect(frame
);
1487 macdrv_mac_to_window_rect(data
, rect
);
1488 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame
), wine_dbgstr_rect(rect
));
1489 swp
&= ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
| SWP_NOSIZE
| SWP_NOCLIENTSIZE
);
1492 release_win_data(data
);
1497 /***********************************************************************
1498 * SysCommand (MACDRV.@)
1500 * Perform WM_SYSCOMMAND handling.
1502 LRESULT CDECL
macdrv_SysCommand(HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
1504 struct macdrv_win_data
*data
;
1506 WPARAM command
= wparam
& 0xfff0;
1508 TRACE("%p, %x, %lx\n", hwnd
, (unsigned)wparam
, lparam
);
1510 if (!(data
= get_win_data(hwnd
))) goto done
;
1511 if (!data
->cocoa_window
|| !data
->on_screen
) goto done
;
1513 /* prevent a simple ALT press+release from activating the system menu,
1514 as that can get confusing */
1515 if (command
== SC_KEYMENU
&& !(WCHAR
)lparam
&& !GetMenu(hwnd
) &&
1516 (GetWindowLongW(hwnd
, GWL_STYLE
) & WS_SYSMENU
))
1518 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam
, lparam
);
1522 if (command
== SC_MOVE
)
1524 release_win_data(data
);
1525 return move_window(hwnd
, wparam
);
1529 release_win_data(data
);
1534 /***********************************************************************
1535 * UpdateLayeredWindow (MACDRV.@)
1537 BOOL CDECL
macdrv_UpdateLayeredWindow(HWND hwnd
, const UPDATELAYEREDWINDOWINFO
*info
,
1538 const RECT
*window_rect
)
1540 struct window_surface
*surface
;
1541 struct macdrv_win_data
*data
;
1542 BLENDFUNCTION blend
= { AC_SRC_OVER
, 0, 255, 0 };
1544 char buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1545 BITMAPINFO
*bmi
= (BITMAPINFO
*)buffer
;
1546 void *src_bits
, *dst_bits
;
1552 if (!(data
= get_win_data(hwnd
))) return FALSE
;
1554 data
->layered
= TRUE
;
1555 data
->ulw_layered
= TRUE
;
1557 rect
= *window_rect
;
1558 OffsetRect(&rect
, -window_rect
->left
, -window_rect
->top
);
1560 surface
= data
->surface
;
1561 if (!surface
|| memcmp(&surface
->rect
, &rect
, sizeof(RECT
)))
1563 data
->surface
= create_surface(data
->cocoa_window
, &rect
, NULL
, TRUE
);
1564 set_window_surface(data
->cocoa_window
, data
->surface
);
1565 if (surface
) window_surface_release(surface
);
1566 surface
= data
->surface
;
1567 if (data
->unminimized_surface
)
1569 window_surface_release(data
->unminimized_surface
);
1570 data
->unminimized_surface
= NULL
;
1573 else set_surface_use_alpha(surface
, TRUE
);
1575 if (surface
) window_surface_add_ref(surface
);
1576 release_win_data(data
);
1578 if (!surface
) return FALSE
;
1581 window_surface_release(surface
);
1585 if (info
->dwFlags
& ULW_ALPHA
)
1587 /* Apply SourceConstantAlpha via window alpha, not blend. */
1588 alpha
= info
->pblend
->SourceConstantAlpha
;
1589 blend
= *info
->pblend
;
1590 blend
.SourceConstantAlpha
= 0xff;
1595 dst_bits
= surface
->funcs
->get_info(surface
, bmi
);
1597 if (!(dib
= CreateDIBSection(info
->hdcDst
, bmi
, DIB_RGB_COLORS
, &src_bits
, NULL
, 0))) goto done
;
1598 if (!(hdc
= CreateCompatibleDC(0))) goto done
;
1600 SelectObject(hdc
, dib
);
1603 IntersectRect(&rect
, &rect
, info
->prcDirty
);
1604 surface
->funcs
->lock(surface
);
1605 memcpy(src_bits
, dst_bits
, bmi
->bmiHeader
.biSizeImage
);
1606 surface
->funcs
->unlock(surface
);
1607 PatBlt(hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, BLACKNESS
);
1609 if (!(ret
= GdiAlphaBlend(hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1611 rect
.left
+ (info
->pptSrc
? info
->pptSrc
->x
: 0),
1612 rect
.top
+ (info
->pptSrc
? info
->pptSrc
->y
: 0),
1613 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1617 if ((data
= get_win_data(hwnd
)))
1619 if (surface
== data
->surface
)
1621 surface
->funcs
->lock(surface
);
1622 memcpy(dst_bits
, src_bits
, bmi
->bmiHeader
.biSizeImage
);
1623 add_bounds_rect(surface
->funcs
->get_bounds(surface
), &rect
);
1624 surface
->funcs
->unlock(surface
);
1625 surface
->funcs
->flush(surface
);
1628 /* The ULW flags are a superset of the LWA flags. */
1629 sync_window_opacity(data
, info
->crKey
, alpha
, TRUE
, info
->dwFlags
);
1631 release_win_data(data
);
1635 window_surface_release(surface
);
1636 if (hdc
) DeleteDC(hdc
);
1637 if (dib
) DeleteObject(dib
);
1642 /**********************************************************************
1643 * WindowMessage (MACDRV.@)
1645 LRESULT CDECL
macdrv_WindowMessage(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1647 struct macdrv_win_data
*data
;
1649 TRACE("%p, %u, %u, %lu\n", hwnd
, msg
, (unsigned)wp
, lp
);
1653 case WM_MACDRV_SET_WIN_REGION
:
1654 if ((data
= get_win_data(hwnd
)))
1656 sync_window_region(data
, (HRGN
)1);
1657 release_win_data(data
);
1660 case WM_MACDRV_UPDATE_DESKTOP_RECT
:
1661 if (hwnd
== GetDesktopWindow())
1663 CGRect new_desktop_rect
;
1664 RECT current_desktop_rect
;
1666 macdrv_reset_device_metrics();
1667 new_desktop_rect
= macdrv_get_desktop_rect();
1668 if (!GetWindowRect(hwnd
, ¤t_desktop_rect
) ||
1669 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect
), new_desktop_rect
))
1671 SendMessageTimeoutW(HWND_BROADCAST
, WM_MACDRV_RESET_DEVICE_METRICS
, 0, 0,
1672 SMTO_ABORTIFHUNG
, 2000, NULL
);
1673 SetWindowPos(hwnd
, 0, CGRectGetMinX(new_desktop_rect
), CGRectGetMinY(new_desktop_rect
),
1674 CGRectGetWidth(new_desktop_rect
), CGRectGetHeight(new_desktop_rect
),
1675 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_DEFERERASE
);
1676 SendMessageTimeoutW(HWND_BROADCAST
, WM_MACDRV_DISPLAYCHANGE
, wp
, lp
,
1677 SMTO_ABORTIFHUNG
, 2000, NULL
);
1681 case WM_MACDRV_RESET_DEVICE_METRICS
:
1682 macdrv_reset_device_metrics();
1684 case WM_MACDRV_DISPLAYCHANGE
:
1685 macdrv_reassert_window_position(hwnd
);
1686 SendMessageW(hwnd
, WM_DISPLAYCHANGE
, wp
, lp
);
1688 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS
:
1689 activate_on_following_focus();
1690 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time
);
1694 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1699 static inline RECT
get_surface_rect(const RECT
*visible_rect
)
1702 RECT desktop_rect
= rect_from_cgrect(macdrv_get_desktop_rect());
1704 IntersectRect(&rect
, visible_rect
, &desktop_rect
);
1705 OffsetRect(&rect
, -visible_rect
->left
, -visible_rect
->top
);
1708 rect
.right
= max(rect
.left
+ 128, (rect
.right
+ 127) & ~127);
1709 rect
.bottom
= max(rect
.top
+ 128, (rect
.bottom
+ 127) & ~127);
1714 /***********************************************************************
1715 * WindowPosChanging (MACDRV.@)
1717 void CDECL
macdrv_WindowPosChanging(HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1718 const RECT
*window_rect
, const RECT
*client_rect
,
1719 RECT
*visible_rect
, struct window_surface
**surface
)
1721 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1722 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1725 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd
, insert_after
,
1726 swp_flags
, wine_dbgstr_rect(window_rect
), wine_dbgstr_rect(client_rect
),
1727 wine_dbgstr_rect(visible_rect
), surface
);
1729 if (!data
&& !(data
= macdrv_create_win_data(hwnd
, window_rect
, client_rect
))) return;
1731 *visible_rect
= *window_rect
;
1732 macdrv_window_to_mac_rect(data
, style
, visible_rect
);
1733 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect
),
1734 wine_dbgstr_rect(visible_rect
));
1736 /* create the window surface if necessary */
1737 if (!data
->cocoa_window
) goto done
;
1738 if (swp_flags
& SWP_HIDEWINDOW
) goto done
;
1739 if (data
->ulw_layered
) goto done
;
1741 if (*surface
) window_surface_release(*surface
);
1744 surface_rect
= get_surface_rect(visible_rect
);
1747 if (!memcmp(&data
->surface
->rect
, &surface_rect
, sizeof(surface_rect
)))
1749 /* existing surface is good enough */
1750 surface_clip_to_visible_rect(data
->surface
, visible_rect
);
1751 window_surface_add_ref(data
->surface
);
1752 *surface
= data
->surface
;
1756 else if (!(swp_flags
& SWP_SHOWWINDOW
) && !(style
& WS_VISIBLE
)) goto done
;
1758 *surface
= create_surface(data
->cocoa_window
, &surface_rect
, data
->surface
, FALSE
);
1761 release_win_data(data
);
1765 /***********************************************************************
1766 * WindowPosChanged (MACDRV.@)
1768 void CDECL
macdrv_WindowPosChanged(HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1769 const RECT
*window_rect
, const RECT
*client_rect
,
1770 const RECT
*visible_rect
, const RECT
*valid_rects
,
1771 struct window_surface
*surface
)
1773 struct macdrv_thread_data
*thread_data
;
1774 struct macdrv_win_data
*data
;
1775 DWORD new_style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1776 RECT old_window_rect
, old_whole_rect
, old_client_rect
;
1778 if (!(data
= get_win_data(hwnd
))) return;
1780 thread_data
= macdrv_thread_data();
1782 old_window_rect
= data
->window_rect
;
1783 old_whole_rect
= data
->whole_rect
;
1784 old_client_rect
= data
->client_rect
;
1785 data
->window_rect
= *window_rect
;
1786 data
->whole_rect
= *visible_rect
;
1787 data
->client_rect
= *client_rect
;
1788 if (!data
->ulw_layered
)
1790 if (surface
) window_surface_add_ref(surface
);
1791 if (new_style
& WS_MINIMIZE
)
1793 if (!data
->unminimized_surface
&& data
->surface
)
1795 data
->unminimized_surface
= data
->surface
;
1796 window_surface_add_ref(data
->unminimized_surface
);
1801 set_window_surface(data
->cocoa_window
, surface
);
1802 if (data
->unminimized_surface
)
1804 window_surface_release(data
->unminimized_surface
);
1805 data
->unminimized_surface
= NULL
;
1808 if (data
->surface
) window_surface_release(data
->surface
);
1809 data
->surface
= surface
;
1812 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1813 hwnd
, data
->cocoa_window
, wine_dbgstr_rect(window_rect
),
1814 wine_dbgstr_rect(visible_rect
), wine_dbgstr_rect(client_rect
),
1815 new_style
, swp_flags
, surface
);
1817 if (!IsRectEmpty(&valid_rects
[0]))
1819 macdrv_window window
= data
->cocoa_window
;
1820 int x_offset
= old_whole_rect
.left
- data
->whole_rect
.left
;
1821 int y_offset
= old_whole_rect
.top
- data
->whole_rect
.top
;
1823 /* if all that happened is that the whole window moved, copy everything */
1824 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
1825 old_whole_rect
.right
- data
->whole_rect
.right
== x_offset
&&
1826 old_whole_rect
.bottom
- data
->whole_rect
.bottom
== y_offset
&&
1827 old_client_rect
.left
- data
->client_rect
.left
== x_offset
&&
1828 old_client_rect
.right
- data
->client_rect
.right
== x_offset
&&
1829 old_client_rect
.top
- data
->client_rect
.top
== y_offset
&&
1830 old_client_rect
.bottom
- data
->client_rect
.bottom
== y_offset
&&
1831 !memcmp(&valid_rects
[0], &data
->client_rect
, sizeof(RECT
)))
1833 /* A Cocoa window's bits are moved automatically */
1834 if (!window
&& (x_offset
!= 0 || y_offset
!= 0))
1836 release_win_data(data
);
1837 move_window_bits(hwnd
, window
, &old_whole_rect
, visible_rect
,
1838 &old_client_rect
, client_rect
, window_rect
);
1839 if (!(data
= get_win_data(hwnd
))) return;
1844 release_win_data(data
);
1845 move_window_bits(hwnd
, window
, &valid_rects
[1], &valid_rects
[0],
1846 &old_client_rect
, client_rect
, window_rect
);
1847 if (!(data
= get_win_data(hwnd
))) return;
1853 if (!data
->cocoa_window
) goto done
;
1855 if (data
->on_screen
)
1857 if ((swp_flags
& SWP_HIDEWINDOW
) && !(new_style
& WS_VISIBLE
))
1861 /* check if we are currently processing an event relevant to this window */
1862 if (!thread_data
|| !thread_data
->current_event
||
1863 thread_data
->current_event
->window
!= data
->cocoa_window
||
1864 (thread_data
->current_event
->type
!= WINDOW_FRAME_CHANGED
&&
1865 thread_data
->current_event
->type
!= WINDOW_DID_UNMINIMIZE
))
1867 sync_window_position(data
, swp_flags
, &old_window_rect
, &old_whole_rect
);
1868 set_cocoa_window_properties(data
);
1871 if (new_style
& WS_VISIBLE
)
1873 if (!data
->on_screen
|| (swp_flags
& (SWP_FRAMECHANGED
|SWP_STATECHANGED
)))
1874 set_cocoa_window_properties(data
);
1876 /* layered windows are not shown until their attributes are set */
1877 if (!data
->on_screen
&&
1878 (data
->layered
|| !(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
)))
1883 release_win_data(data
);
1887 /***********************************************************************
1888 * macdrv_window_close_requested
1890 * Handler for WINDOW_CLOSE_REQUESTED events.
1892 void macdrv_window_close_requested(HWND hwnd
)
1896 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
)
1898 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd
);
1902 sysmenu
= GetSystemMenu(hwnd
, FALSE
);
1905 UINT state
= GetMenuState(sysmenu
, SC_CLOSE
, MF_BYCOMMAND
);
1906 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
1908 TRACE("not closing win %p menu state 0x%08x\n", hwnd
, state
);
1913 perform_window_command(hwnd
, 0, 0, SC_CLOSE
, HTCLOSE
);
1917 /***********************************************************************
1918 * macdrv_window_frame_changed
1920 * Handler for WINDOW_FRAME_CHANGED events.
1922 void macdrv_window_frame_changed(HWND hwnd
, const macdrv_event
*event
)
1924 struct macdrv_win_data
*data
;
1927 UINT flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1932 if (!(data
= get_win_data(hwnd
))) return;
1933 if (!data
->on_screen
|| data
->minimized
)
1935 release_win_data(data
);
1941 parent
= GetAncestor(hwnd
, GA_PARENT
);
1943 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd
, data
->cocoa_window
,
1944 wine_dbgstr_cgrect(event
->window_frame_changed
.frame
),
1945 event
->window_frame_changed
.fullscreen
, event
->window_frame_changed
.in_resize
);
1947 rect
= rect_from_cgrect(event
->window_frame_changed
.frame
);
1948 macdrv_mac_to_window_rect(data
, &rect
);
1949 MapWindowPoints(0, parent
, (POINT
*)&rect
, 2);
1951 width
= rect
.right
- rect
.left
;
1952 height
= rect
.bottom
- rect
.top
;
1954 if (data
->window_rect
.left
== rect
.left
&& data
->window_rect
.top
== rect
.top
)
1955 flags
|= SWP_NOMOVE
;
1957 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd
, data
->window_rect
.left
,
1958 data
->window_rect
.top
, rect
.left
, rect
.top
);
1960 if ((data
->window_rect
.right
- data
->window_rect
.left
== width
&&
1961 data
->window_rect
.bottom
- data
->window_rect
.top
== height
) ||
1962 (IsRectEmpty(&data
->window_rect
) && width
== 1 && height
== 1))
1963 flags
|= SWP_NOSIZE
;
1965 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1966 data
->window_rect
.bottom
- data
->window_rect
.top
, width
, height
);
1968 being_dragged
= data
->being_dragged
;
1969 release_win_data(data
);
1971 if (event
->window_frame_changed
.fullscreen
)
1972 flags
|= SWP_NOSENDCHANGING
;
1973 if (!(flags
& SWP_NOSIZE
) || !(flags
& SWP_NOMOVE
))
1975 if (!event
->window_frame_changed
.in_resize
&& !being_dragged
)
1976 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
1977 SetWindowPos(hwnd
, 0, rect
.left
, rect
.top
, width
, height
, flags
);
1978 if (!event
->window_frame_changed
.in_resize
&& !being_dragged
)
1979 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
1984 /***********************************************************************
1985 * macdrv_window_got_focus
1987 * Handler for WINDOW_GOT_FOCUS events.
1989 void macdrv_window_got_focus(HWND hwnd
, const macdrv_event
*event
)
1991 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1995 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1996 hwnd
, event
->window
, event
->window_got_focus
.serial
, IsWindowEnabled(hwnd
),
1997 IsWindowVisible(hwnd
), style
, GetFocus(), GetActiveWindow(), GetForegroundWindow());
1999 if (can_activate_window(hwnd
) && !(style
& WS_MINIMIZE
))
2001 /* simulate a mouse click on the caption to find out
2002 * whether the window wants to be activated */
2003 LRESULT ma
= SendMessageW(hwnd
, WM_MOUSEACTIVATE
,
2004 (WPARAM
)GetAncestor(hwnd
, GA_ROOT
),
2005 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
));
2006 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
2008 TRACE("setting foreground window to %p\n", hwnd
);
2009 SetForegroundWindow(hwnd
);
2014 TRACE("win %p/%p rejecting focus\n", hwnd
, event
->window
);
2015 macdrv_window_rejected_focus(event
);
2019 /***********************************************************************
2020 * macdrv_window_lost_focus
2022 * Handler for WINDOW_LOST_FOCUS events.
2024 void macdrv_window_lost_focus(HWND hwnd
, const macdrv_event
*event
)
2028 TRACE("win %p/%p fg %p\n", hwnd
, event
->window
, GetForegroundWindow());
2030 if (hwnd
== GetForegroundWindow())
2032 SendMessageW(hwnd
, WM_CANCELMODE
, 0, 0);
2033 if (hwnd
== GetForegroundWindow())
2034 SetForegroundWindow(GetDesktopWindow());
2039 /***********************************************************************
2040 * macdrv_app_deactivated
2042 * Handler for APP_DEACTIVATED events.
2044 void macdrv_app_deactivated(void)
2046 if (GetActiveWindow() == GetForegroundWindow())
2048 TRACE("setting fg to desktop\n");
2049 SetForegroundWindow(GetDesktopWindow());
2054 /***********************************************************************
2055 * macdrv_window_maximize_requested
2057 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2059 void macdrv_window_maximize_requested(HWND hwnd
)
2061 perform_window_command(hwnd
, WS_MAXIMIZEBOX
, WS_MAXIMIZE
, SC_MAXIMIZE
, HTMAXBUTTON
);
2065 /***********************************************************************
2066 * macdrv_window_minimize_requested
2068 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2070 void macdrv_window_minimize_requested(HWND hwnd
)
2072 perform_window_command(hwnd
, WS_MINIMIZEBOX
, WS_MINIMIZE
, SC_MINIMIZE
, HTMINBUTTON
);
2076 /***********************************************************************
2077 * macdrv_window_did_unminimize
2079 * Handler for WINDOW_DID_UNMINIMIZE events.
2081 void macdrv_window_did_unminimize(HWND hwnd
)
2083 struct macdrv_win_data
*data
;
2086 TRACE("win %p\n", hwnd
);
2088 if (!(data
= get_win_data(hwnd
))) return;
2089 if (!data
->minimized
) goto done
;
2091 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2093 data
->minimized
= FALSE
;
2094 if ((style
& (WS_MINIMIZE
| WS_VISIBLE
)) == (WS_MINIMIZE
| WS_VISIBLE
))
2096 TRACE("restoring win %p/%p\n", hwnd
, data
->cocoa_window
);
2097 release_win_data(data
);
2098 SendMessageW(hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0);
2102 TRACE("not restoring win %p/%p style %08x\n", hwnd
, data
->cocoa_window
, style
);
2105 release_win_data(data
);
2109 /***********************************************************************
2110 * macdrv_window_brought_forward
2112 * Handler for WINDOW_BROUGHT_FORWARD events.
2114 void macdrv_window_brought_forward(HWND hwnd
)
2116 TRACE("win %p\n", hwnd
);
2117 SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2121 /***********************************************************************
2122 * macdrv_window_resize_ended
2124 * Handler for WINDOW_RESIZE_ENDED events.
2126 void macdrv_window_resize_ended(HWND hwnd
)
2128 TRACE("hwnd %p\n", hwnd
);
2129 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2133 /***********************************************************************
2134 * macdrv_window_restore_requested
2136 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2137 * for restoring from maximized, not from minimized.
2139 void macdrv_window_restore_requested(HWND hwnd
, const macdrv_event
*event
)
2141 if (event
->window_restore_requested
.keep_frame
&& hwnd
)
2143 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2144 struct macdrv_win_data
*data
;
2146 if ((style
& WS_MAXIMIZE
) && (style
& WS_VISIBLE
) && (data
= get_win_data(hwnd
)))
2149 HWND parent
= GetAncestor(hwnd
, GA_PARENT
);
2151 rect
= rect_from_cgrect(event
->window_restore_requested
.frame
);
2152 macdrv_mac_to_window_rect(data
, &rect
);
2153 MapWindowPoints(0, parent
, (POINT
*)&rect
, 2);
2155 release_win_data(data
);
2157 SetInternalWindowPos(hwnd
, SW_SHOW
, &rect
, NULL
);
2161 perform_window_command(hwnd
, WS_MAXIMIZE
, 0, SC_RESTORE
, HTMAXBUTTON
);
2165 /***********************************************************************
2166 * macdrv_window_drag_begin
2168 * Handler for WINDOW_DRAG_BEGIN events.
2170 void macdrv_window_drag_begin(HWND hwnd
)
2172 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2173 struct macdrv_win_data
*data
;
2176 TRACE("win %p\n", hwnd
);
2178 if (style
& (WS_DISABLED
| WS_MAXIMIZE
| WS_MINIMIZE
)) return;
2179 if (!(style
& WS_VISIBLE
)) return;
2181 if (!(data
= get_win_data(hwnd
))) return;
2182 if (data
->being_dragged
) goto done
;
2184 data
->being_dragged
= TRUE
;
2185 release_win_data(data
);
2188 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
2191 while (GetMessageW(&msg
, 0, 0, 0))
2193 if (msg
.message
== WM_EXITSIZEMOVE
)
2195 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2199 if (!CallMsgFilterW(&msg
, MSGF_SIZE
) && msg
.message
!= WM_KEYDOWN
&&
2200 msg
.message
!= WM_MOUSEMOVE
&& msg
.message
!= WM_LBUTTONDOWN
&& msg
.message
!= WM_LBUTTONUP
)
2202 TranslateMessage(&msg
);
2203 DispatchMessageW(&msg
);
2209 if ((data
= get_win_data(hwnd
)))
2210 data
->being_dragged
= FALSE
;
2213 release_win_data(data
);
2217 /***********************************************************************
2218 * macdrv_window_drag_end
2220 * Handler for WINDOW_DRAG_END events.
2222 void macdrv_window_drag_end(HWND hwnd
)
2224 struct macdrv_win_data
*data
;
2227 TRACE("win %p\n", hwnd
);
2229 if (!(data
= get_win_data(hwnd
))) return;
2230 being_dragged
= data
->being_dragged
;
2231 release_win_data(data
);
2235 /* Post this rather than sending it, so that the message loop in
2236 macdrv_window_drag_begin() will see it. */
2237 PostMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2242 /***********************************************************************
2243 * macdrv_reassert_window_position
2245 * Handler for REASSERT_WINDOW_POSITION events.
2247 void macdrv_reassert_window_position(HWND hwnd
)
2249 struct macdrv_win_data
*data
= get_win_data(hwnd
);
2252 if (data
->cocoa_window
&& data
->on_screen
)
2253 sync_window_position(data
, SWP_NOZORDER
| SWP_NOACTIVATE
, NULL
, NULL
);
2254 release_win_data(data
);
2270 static BOOL CALLBACK
get_process_windows(HWND hwnd
, LPARAM lp
)
2272 struct quit_info
*qi
= (struct quit_info
*)lp
;
2275 GetWindowThreadProcessId(hwnd
, &pid
);
2276 if (pid
== GetCurrentProcessId())
2278 if (qi
->count
>= qi
->capacity
)
2280 UINT new_cap
= qi
->capacity
* 2;
2281 HWND
*new_wins
= HeapReAlloc(GetProcessHeap(), 0, qi
->wins
,
2282 new_cap
* sizeof(*qi
->wins
));
2283 if (!new_wins
) return FALSE
;
2284 qi
->wins
= new_wins
;
2285 qi
->capacity
= new_cap
;
2288 qi
->wins
[qi
->count
++] = hwnd
;
2295 static void CALLBACK
quit_callback(HWND hwnd
, UINT msg
, ULONG_PTR data
, LRESULT result
)
2297 struct quit_info
*qi
= (struct quit_info
*)data
;
2301 if (msg
== WM_QUERYENDSESSION
)
2303 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result
,
2304 hwnd
, qi
->done
, qi
->count
);
2306 if (!result
&& !IsWindow(hwnd
))
2308 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd
);
2312 if (!result
&& qi
->result
)
2316 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2317 ultimate reply. Might as well tell Cocoa now. */
2321 TRACE("giving quit reply %d\n", qi
->result
);
2322 macdrv_quit_reply(qi
->result
);
2326 if (qi
->done
>= qi
->count
)
2331 for (i
= 0; i
< qi
->count
; i
++)
2333 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi
->wins
[i
],
2334 qi
->result
, qi
->flags
);
2335 if (!SendMessageCallbackW(qi
->wins
[i
], WM_ENDSESSION
, qi
->result
, qi
->flags
,
2336 quit_callback
, (ULONG_PTR
)qi
))
2338 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2339 qi
->wins
[i
], GetLastError());
2340 quit_callback(qi
->wins
[i
], WM_ENDSESSION
, (ULONG_PTR
)qi
, 0);
2345 else /* WM_ENDSESSION */
2347 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd
, qi
->done
, qi
->count
);
2349 if (qi
->done
>= qi
->count
)
2353 TRACE("giving quit reply %d\n", qi
->result
);
2354 macdrv_quit_reply(qi
->result
);
2357 TRACE("%sterminating process\n", qi
->result
? "" : "not ");
2359 TerminateProcess(GetCurrentProcess(), 0);
2361 HeapFree(GetProcessHeap(), 0, qi
->wins
);
2362 HeapFree(GetProcessHeap(), 0, qi
);
2368 /***********************************************************************
2369 * macdrv_app_quit_requested
2371 * Handler for APP_QUIT_REQUESTED events.
2373 void macdrv_app_quit_requested(const macdrv_event
*event
)
2375 struct quit_info
*qi
;
2378 TRACE("reason %d\n", event
->app_quit_requested
.reason
);
2380 qi
= HeapAlloc(GetProcessHeap(), 0, sizeof(*qi
));
2385 qi
->wins
= HeapAlloc(GetProcessHeap(), 0, qi
->capacity
* sizeof(*qi
->wins
));
2386 qi
->count
= qi
->done
= 0;
2388 if (!qi
->wins
|| !EnumWindows(get_process_windows
, (LPARAM
)qi
))
2391 switch (event
->app_quit_requested
.reason
)
2393 case QUIT_REASON_LOGOUT
:
2395 qi
->flags
= ENDSESSION_LOGOFF
;
2397 case QUIT_REASON_RESTART
:
2398 case QUIT_REASON_SHUTDOWN
:
2404 qi
->replied
= FALSE
;
2406 for (i
= 0; i
< qi
->count
; i
++)
2408 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi
->wins
[i
]);
2409 if (!SendMessageCallbackW(qi
->wins
[i
], WM_QUERYENDSESSION
, 0, qi
->flags
,
2410 quit_callback
, (ULONG_PTR
)qi
))
2412 DWORD error
= GetLastError();
2413 BOOL invalid
= (error
== ERROR_INVALID_WINDOW_HANDLE
);
2415 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2418 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2419 qi
->wins
[i
], error
);
2420 quit_callback(qi
->wins
[i
], WM_QUERYENDSESSION
, (ULONG_PTR
)qi
, invalid
);
2424 /* quit_callback() will clean up qi */
2428 WARN("failed to allocate window list\n");
2431 HeapFree(GetProcessHeap(), 0, qi
->wins
);
2432 HeapFree(GetProcessHeap(), 0, qi
);
2434 macdrv_quit_reply(FALSE
);
2438 /***********************************************************************
2441 * Handler for QUERY_RESIZE_SIZE query.
2443 BOOL
query_resize_size(HWND hwnd
, macdrv_query
*query
)
2445 struct macdrv_win_data
*data
= get_win_data(hwnd
);
2446 RECT rect
= rect_from_cgrect(query
->resize_size
.rect
);
2450 if (!data
) return FALSE
;
2452 macdrv_mac_to_window_rect(data
, &rect
);
2454 if (query
->resize_size
.from_left
)
2456 if (query
->resize_size
.from_top
)
2457 corner
= WMSZ_TOPLEFT
;
2459 corner
= WMSZ_BOTTOMLEFT
;
2461 else if (query
->resize_size
.from_top
)
2462 corner
= WMSZ_TOPRIGHT
;
2464 corner
= WMSZ_BOTTOMRIGHT
;
2466 if (SendMessageW(hwnd
, WM_SIZING
, corner
, (LPARAM
)&rect
))
2468 macdrv_window_to_mac_rect(data
, GetWindowLongW(hwnd
, GWL_STYLE
), &rect
);
2469 query
->resize_size
.rect
= cgrect_from_rect(rect
);
2473 release_win_data(data
);
2478 /***********************************************************************
2479 * query_resize_start
2481 * Handler for QUERY_RESIZE_START query.
2483 BOOL
query_resize_start(HWND hwnd
)
2485 TRACE("hwnd %p\n", hwnd
);
2487 sync_window_min_max_info(hwnd
);
2488 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
2494 /***********************************************************************
2495 * query_min_max_info
2497 * Handler for QUERY_MIN_MAX_INFO query.
2499 BOOL
query_min_max_info(HWND hwnd
)
2501 TRACE("hwnd %p\n", hwnd
);
2502 sync_window_min_max_info(hwnd
);