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
)
734 if (data
->cocoa_window
)
738 macdrv_window prev_window
= NULL
;
739 macdrv_window next_window
= NULL
;
740 BOOL activate
= FALSE
;
743 /* find window that this one must be after */
744 prev
= GetWindow(data
->hwnd
, GW_HWNDPREV
);
745 while (prev
&& !((GetWindowLongW(prev
, GWL_STYLE
) & (WS_VISIBLE
| WS_MINIMIZE
)) == WS_VISIBLE
&&
746 (prev_window
= macdrv_get_cocoa_window(prev
, TRUE
))))
747 prev
= GetWindow(prev
, GW_HWNDPREV
);
750 /* find window that this one must be before */
751 next
= GetWindow(data
->hwnd
, GW_HWNDNEXT
);
752 while (next
&& !((GetWindowLongW(next
, GWL_STYLE
) & (WS_VISIBLE
| WS_MINIMIZE
)) == WS_VISIBLE
&&
753 (next_window
= macdrv_get_cocoa_window(next
, TRUE
))))
754 next
= GetWindow(next
, GW_HWNDNEXT
);
757 TRACE("win %p/%p below %p/%p above %p/%p\n",
758 data
->hwnd
, data
->cocoa_window
, prev
, prev_window
, next
, next_window
);
761 activate
= activate_on_focus_time
&& (GetTickCount() - activate_on_focus_time
< 2000);
762 macdrv_order_cocoa_window(data
->cocoa_window
, prev_window
, next_window
, activate
);
763 data
->on_screen
= TRUE
;
765 hwndFocus
= GetFocus();
766 if (hwndFocus
&& (data
->hwnd
== hwndFocus
|| IsChild(data
->hwnd
, hwndFocus
)))
767 macdrv_SetFocus(hwndFocus
);
769 activate_on_focus_time
= 0;
774 /***********************************************************************
777 static void hide_window(struct macdrv_win_data
*data
)
779 TRACE("win %p/%p\n", data
->hwnd
, data
->cocoa_window
);
781 if (data
->cocoa_window
)
782 macdrv_hide_cocoa_window(data
->cocoa_window
);
783 data
->on_screen
= FALSE
;
787 /***********************************************************************
790 * Calls GetRegionData on the given region and converts the rectangle
791 * array to CGRect format. The returned buffer must be freed by
792 * caller using HeapFree(GetProcessHeap(),...).
793 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
795 RGNDATA
*get_region_data(HRGN hrgn
, HDC hdc_lptodp
)
803 if (!hrgn
|| !(size
= GetRegionData(hrgn
, 0, NULL
))) return NULL
;
804 if (sizeof(CGRect
) > sizeof(RECT
))
806 /* add extra size for CGRect array */
807 int count
= (size
- sizeof(RGNDATAHEADER
)) / sizeof(RECT
);
808 size
+= count
* (sizeof(CGRect
) - sizeof(RECT
));
810 if (!(data
= HeapAlloc(GetProcessHeap(), 0, size
))) return NULL
;
811 if (!GetRegionData(hrgn
, size
, data
))
813 HeapFree(GetProcessHeap(), 0, data
);
817 rect
= (RECT
*)data
->Buffer
;
818 cgrect
= (CGRect
*)data
->Buffer
;
819 if (hdc_lptodp
) /* map to device coordinates */
821 LPtoDP(hdc_lptodp
, (POINT
*)rect
, data
->rdh
.nCount
* 2);
822 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
824 if (rect
[i
].right
< rect
[i
].left
)
826 INT tmp
= rect
[i
].right
;
827 rect
[i
].right
= rect
[i
].left
;
830 if (rect
[i
].bottom
< rect
[i
].top
)
832 INT tmp
= rect
[i
].bottom
;
833 rect
[i
].bottom
= rect
[i
].top
;
839 if (sizeof(CGRect
) > sizeof(RECT
))
841 /* need to start from the end */
842 for (i
= data
->rdh
.nCount
-1; i
>= 0; i
--)
843 cgrect
[i
] = cgrect_from_rect(rect
[i
]);
847 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
848 cgrect
[i
] = cgrect_from_rect(rect
[i
]);
854 /***********************************************************************
855 * sync_window_position
857 * Synchronize the Mac window position with the Windows one
859 static void sync_window_position(struct macdrv_win_data
*data
, UINT swp_flags
, const RECT
*old_window_rect
,
860 const RECT
*old_whole_rect
)
864 if (data
->minimized
) return;
866 frame
= cgrect_from_rect(data
->whole_rect
);
867 constrain_window_frame(&frame
);
868 if (frame
.size
.width
< 1 || frame
.size
.height
< 1)
869 frame
.size
.width
= frame
.size
.height
= 1;
871 macdrv_set_cocoa_window_frame(data
->cocoa_window
, &frame
);
872 if (old_window_rect
&& old_whole_rect
&&
873 (IsRectEmpty(old_window_rect
) != IsRectEmpty(&data
->window_rect
) ||
874 old_window_rect
->left
- old_whole_rect
->left
!= data
->window_rect
.left
- data
->whole_rect
.left
||
875 old_window_rect
->top
- old_whole_rect
->top
!= data
->window_rect
.top
- data
->whole_rect
.top
))
876 sync_window_region(data
, (HRGN
)1);
878 TRACE("win %p/%p whole_rect %s frame %s\n", data
->hwnd
, data
->cocoa_window
,
879 wine_dbgstr_rect(&data
->whole_rect
), wine_dbgstr_cgrect(frame
));
881 if (data
->on_screen
&& (!(swp_flags
& SWP_NOZORDER
) || (swp_flags
& SWP_SHOWWINDOW
)))
886 /***********************************************************************
889 * Move the window bits when a window is moved.
891 static void move_window_bits(HWND hwnd
, macdrv_window window
, const RECT
*old_rect
, const RECT
*new_rect
,
892 const RECT
*old_client_rect
, const RECT
*new_client_rect
,
893 const RECT
*new_window_rect
)
895 RECT src_rect
= *old_rect
;
896 RECT dst_rect
= *new_rect
;
897 HDC hdc_src
, hdc_dst
;
903 OffsetRect(&dst_rect
, -new_window_rect
->left
, -new_window_rect
->top
);
904 parent
= GetAncestor(hwnd
, GA_PARENT
);
905 hdc_src
= GetDCEx(parent
, 0, DCX_CACHE
);
906 hdc_dst
= GetDCEx(hwnd
, 0, DCX_CACHE
| DCX_WINDOW
);
910 OffsetRect(&dst_rect
, -new_client_rect
->left
, -new_client_rect
->top
);
911 /* make src rect relative to the old position of the window */
912 OffsetRect(&src_rect
, -old_client_rect
->left
, -old_client_rect
->top
);
913 if (dst_rect
.left
== src_rect
.left
&& dst_rect
.top
== src_rect
.top
) return;
914 hdc_src
= hdc_dst
= GetDCEx(hwnd
, 0, DCX_CACHE
);
917 rgn
= CreateRectRgnIndirect(&dst_rect
);
918 SelectClipRgn(hdc_dst
, rgn
);
920 ExcludeUpdateRgn(hdc_dst
, hwnd
);
922 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd
, window
,
923 wine_dbgstr_rect(&src_rect
), wine_dbgstr_rect(&dst_rect
));
924 BitBlt(hdc_dst
, dst_rect
.left
, dst_rect
.top
,
925 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
,
926 hdc_src
, src_rect
.left
, src_rect
.top
, SRCCOPY
);
928 ReleaseDC(hwnd
, hdc_dst
);
929 if (hdc_src
!= hdc_dst
) ReleaseDC(parent
, hdc_src
);
933 /**********************************************************************
934 * activate_on_following_focus
936 void activate_on_following_focus(void)
938 activate_on_focus_time
= GetTickCount();
939 if (!activate_on_focus_time
) activate_on_focus_time
= 1;
943 /***********************************************************************
946 static void set_app_icon(void)
948 CFArrayRef images
= create_app_icon_images();
951 macdrv_set_application_icon(images
);
957 /**********************************************************************
958 * set_capture_window_for_move
960 static BOOL
set_capture_window_for_move(HWND hwnd
)
965 SERVER_START_REQ(set_capture_window
)
967 req
->handle
= wine_server_user_handle(hwnd
);
968 req
->flags
= CAPTURE_MOVESIZE
;
969 if ((ret
= !wine_server_call_err(req
)))
971 previous
= wine_server_ptr_handle(reply
->previous
);
972 hwnd
= wine_server_ptr_handle(reply
->full_handle
);
979 macdrv_SetCapture(hwnd
, GUI_INMOVESIZE
);
981 if (previous
&& previous
!= hwnd
)
982 SendMessageW(previous
, WM_CAPTURECHANGED
, 0, (LPARAM
)hwnd
);
988 /***********************************************************************
991 * Based on user32's WINPOS_SysCommandSizeMove() specialized just for
992 * moving top-level windows and enforcing Mac-style constraints like
993 * keeping the top of the window within the work area.
995 static LRESULT
move_window(HWND hwnd
, WPARAM wparam
)
998 RECT origRect
, movedRect
, desktopRect
;
999 LONG hittest
= (LONG
)(wparam
& 0x0f);
1001 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1003 DWORD dwPoint
= GetMessagePos();
1008 if ((style
& (WS_MINIMIZE
| WS_MAXIMIZE
)) || !IsWindowVisible(hwnd
)) return -1;
1009 if (hittest
&& hittest
!= HTCAPTION
) return -1;
1011 capturePoint
.x
= (short)LOWORD(dwPoint
);
1012 capturePoint
.y
= (short)HIWORD(dwPoint
);
1015 TRACE("hwnd %p hittest %d, pos %d,%d\n", hwnd
, hittest
, capturePoint
.x
, capturePoint
.y
);
1017 origRect
.left
= origRect
.right
= origRect
.top
= origRect
.bottom
= 0;
1018 if (AdjustWindowRectEx(&origRect
, style
, FALSE
, GetWindowLongW(hwnd
, GWL_EXSTYLE
)))
1019 captionHeight
= -origRect
.top
;
1023 GetWindowRect(hwnd
, &origRect
);
1024 movedRect
= origRect
;
1028 /* Move pointer to the center of the caption */
1029 RECT rect
= origRect
;
1031 /* Note: to be exactly centered we should take the different types
1032 * of border into account, but it shouldn't make more than a few pixels
1033 * of difference so let's not bother with that */
1034 rect
.top
+= GetSystemMetrics(SM_CYBORDER
);
1035 if (style
& WS_SYSMENU
)
1036 rect
.left
+= GetSystemMetrics(SM_CXSIZE
) + 1;
1037 if (style
& WS_MINIMIZEBOX
)
1038 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
1039 if (style
& WS_MAXIMIZEBOX
)
1040 rect
.right
-= GetSystemMetrics(SM_CXSIZE
) + 1;
1041 capturePoint
.x
= (rect
.right
+ rect
.left
) / 2;
1042 capturePoint
.y
= rect
.top
+ GetSystemMetrics(SM_CYSIZE
)/2;
1044 SetCursorPos(capturePoint
.x
, capturePoint
.y
);
1045 SendMessageW(hwnd
, WM_SETCURSOR
, (WPARAM
)hwnd
, MAKELONG(HTCAPTION
, WM_MOUSEMOVE
));
1048 desktopRect
= rect_from_cgrect(macdrv_get_desktop_rect());
1049 mon
= MonitorFromPoint(capturePoint
, MONITOR_DEFAULTTONEAREST
);
1050 info
.cbSize
= sizeof(info
);
1051 if (mon
&& !GetMonitorInfoW(mon
, &info
))
1054 /* repaint the window before moving it around */
1055 RedrawWindow(hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
1057 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
1058 set_capture_window_for_move(hwnd
);
1066 if (!GetMessageW(&msg
, 0, 0, 0)) break;
1067 if (CallMsgFilterW(&msg
, MSGF_SIZE
)) continue;
1069 /* Exit on button-up, Return, or Esc */
1070 if (msg
.message
== WM_LBUTTONUP
||
1071 (msg
.message
== WM_KEYDOWN
&& (msg
.wParam
== VK_RETURN
|| msg
.wParam
== VK_ESCAPE
)))
1074 if (msg
.message
!= WM_KEYDOWN
&& msg
.message
!= WM_MOUSEMOVE
)
1076 TranslateMessage(&msg
);
1077 DispatchMessageW(&msg
);
1078 continue; /* We are not interested in other messages */
1083 if (msg
.message
== WM_KEYDOWN
) switch(msg
.wParam
)
1085 case VK_UP
: pt
.y
-= 8; break;
1086 case VK_DOWN
: pt
.y
+= 8; break;
1087 case VK_LEFT
: pt
.x
-= 8; break;
1088 case VK_RIGHT
: pt
.x
+= 8; break;
1091 pt
.x
= max(pt
.x
, desktopRect
.left
);
1092 pt
.x
= min(pt
.x
, desktopRect
.right
- 1);
1093 pt
.y
= max(pt
.y
, desktopRect
.top
);
1094 pt
.y
= min(pt
.y
, desktopRect
.bottom
- 1);
1096 if ((newmon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
)) && newmon
!= mon
)
1098 if (GetMonitorInfoW(newmon
, &info
))
1106 /* wineserver clips the cursor position to the virtual desktop rect but,
1107 if the display configuration is non-rectangular, that could still
1108 leave the logical cursor position outside of any display. The window
1109 could keep moving as you push the cursor against a display edge, even
1110 though the visible cursor doesn't keep moving. The following keeps
1111 the window movement in sync with the visible cursor. */
1112 pt
.x
= max(pt
.x
, info
.rcMonitor
.left
);
1113 pt
.x
= min(pt
.x
, info
.rcMonitor
.right
- 1);
1114 pt
.y
= max(pt
.y
, info
.rcMonitor
.top
);
1115 pt
.y
= min(pt
.y
, info
.rcMonitor
.bottom
- 1);
1117 /* Assuming that dx will be calculated below as pt.x - capturePoint.x,
1118 dy will be pt.y - capturePoint.y, and movedRect will be offset by those,
1119 we want to enforce these constraints:
1120 movedRect.left + dx < info.rcWork.right
1121 movedRect.right + dx > info.rcWork.left
1122 movedRect.top + captionHeight + dy < info.rcWork.bottom
1123 movedRect.bottom + dy > info.rcWork.top
1124 movedRect.top + dy >= info.rcWork.top
1125 The first four keep at least one edge barely in the work area.
1126 The last keeps the top (i.e. the title bar) in the work area.
1127 The fourth is redundant with the last, so can be ignored.
1129 Substituting for dx and dy and rearranging gives us...
1131 pt
.x
= min(pt
.x
, info
.rcWork
.right
- 1 + capturePoint
.x
- movedRect
.left
);
1132 pt
.x
= max(pt
.x
, info
.rcWork
.left
+ 1 + capturePoint
.x
- movedRect
.right
);
1133 pt
.y
= min(pt
.y
, info
.rcWork
.bottom
- 1 + capturePoint
.y
- movedRect
.top
- captionHeight
);
1134 pt
.y
= max(pt
.y
, info
.rcWork
.top
+ capturePoint
.y
- movedRect
.top
);
1137 dx
= pt
.x
- capturePoint
.x
;
1138 dy
= pt
.y
- capturePoint
.y
;
1144 if (msg
.message
== WM_KEYDOWN
) SetCursorPos(pt
.x
, pt
.y
);
1147 OffsetRect(&movedRect
, dx
, dy
);
1150 SendMessageW(hwnd
, WM_MOVING
, 0, (LPARAM
)&movedRect
);
1151 SetWindowPos(hwnd
, 0, movedRect
.left
, movedRect
.top
, 0, 0,
1152 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOZORDER
);
1157 set_capture_window_for_move(0);
1159 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
1160 SendMessageW(hwnd
, WM_SETVISIBLE
, TRUE
, 0L);
1162 /* if the move is canceled, restore the previous position */
1163 if (moved
&& msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_ESCAPE
)
1165 SetWindowPos(hwnd
, 0, origRect
.left
, origRect
.top
, 0, 0,
1166 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOZORDER
);
1173 /***********************************************************************
1174 * perform_window_command
1176 static void perform_window_command(HWND hwnd
, DWORD style_any
, DWORD style_none
, WORD command
, WORD hittest
)
1180 TRACE("win %p style_any 0x%08x style_none 0x%08x command 0x%04x hittest 0x%04x\n",
1181 hwnd
, style_any
, style_none
, command
, hittest
);
1183 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1184 if ((style_any
&& !(style
& style_any
)) || (style
& (WS_DISABLED
| style_none
)))
1186 TRACE("not changing win %p style 0x%08x\n", hwnd
, style
);
1190 if (GetActiveWindow() != hwnd
)
1192 LRESULT ma
= SendMessageW(hwnd
, WM_MOUSEACTIVATE
, (WPARAM
)GetAncestor(hwnd
, GA_ROOT
),
1193 MAKELPARAM(hittest
, WM_NCLBUTTONDOWN
));
1196 case MA_NOACTIVATEANDEAT
:
1197 case MA_ACTIVATEANDEAT
:
1198 TRACE("not changing win %p mouse-activate result %ld\n", hwnd
, ma
);
1204 SetActiveWindow(hwnd
);
1207 WARN("unknown WM_MOUSEACTIVATE code %ld\n", ma
);
1212 TRACE("changing win %p\n", hwnd
);
1213 PostMessageW(hwnd
, WM_SYSCOMMAND
, command
, 0);
1217 /**********************************************************************
1218 * CreateDesktopWindow (MACDRV.@)
1220 BOOL CDECL
macdrv_CreateDesktopWindow(HWND hwnd
)
1222 unsigned int width
, height
;
1224 TRACE("%p\n", hwnd
);
1226 /* retrieve the real size of the desktop */
1227 SERVER_START_REQ(get_window_rectangles
)
1229 req
->handle
= wine_server_user_handle(hwnd
);
1230 req
->relative
= COORDS_CLIENT
;
1231 wine_server_call(req
);
1232 width
= reply
->window
.right
;
1233 height
= reply
->window
.bottom
;
1237 if (!width
&& !height
) /* not initialized yet */
1239 CGRect rect
= macdrv_get_desktop_rect();
1241 SERVER_START_REQ(set_window_pos
)
1243 req
->handle
= wine_server_user_handle(hwnd
);
1245 req
->swp_flags
= SWP_NOZORDER
;
1246 req
->window
.left
= CGRectGetMinX(rect
);
1247 req
->window
.top
= CGRectGetMinY(rect
);
1248 req
->window
.right
= CGRectGetMaxX(rect
);
1249 req
->window
.bottom
= CGRectGetMaxY(rect
);
1250 req
->client
= req
->window
;
1251 wine_server_call(req
);
1261 /**********************************************************************
1262 * CreateWindow (MACDRV.@)
1264 BOOL CDECL
macdrv_CreateWindow(HWND hwnd
)
1270 /***********************************************************************
1271 * DestroyWindow (MACDRV.@)
1273 void CDECL
macdrv_DestroyWindow(HWND hwnd
)
1275 struct macdrv_win_data
*data
;
1277 TRACE("%p\n", hwnd
);
1279 if (!(data
= get_win_data(hwnd
))) return;
1281 if (hwnd
== GetCapture()) macdrv_SetCapture(0, 0);
1283 if (data
->gl_view
) macdrv_dispose_view(data
->gl_view
);
1284 destroy_cocoa_window(data
);
1286 CFDictionaryRemoveValue(win_datas
, hwnd
);
1287 release_win_data(data
);
1288 HeapFree(GetProcessHeap(), 0, data
);
1292 /*****************************************************************
1293 * SetFocus (MACDRV.@)
1295 * Set the Mac focus.
1297 void CDECL
macdrv_SetFocus(HWND hwnd
)
1299 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
1300 struct macdrv_win_data
*data
;
1302 TRACE("%p\n", hwnd
);
1304 if (!thread_data
) return;
1305 thread_data
->dead_key_state
= 0;
1307 if (!(hwnd
= GetAncestor(hwnd
, GA_ROOT
))) return;
1308 if (!(data
= get_win_data(hwnd
))) return;
1310 if (data
->cocoa_window
&& data
->on_screen
)
1312 BOOL activate
= activate_on_focus_time
&& (GetTickCount() - activate_on_focus_time
< 2000);
1314 macdrv_give_cocoa_window_focus(data
->cocoa_window
, activate
);
1315 activate_on_focus_time
= 0;
1318 release_win_data(data
);
1322 /***********************************************************************
1323 * SetLayeredWindowAttributes (MACDRV.@)
1325 * Set transparency attributes for a layered window.
1327 void CDECL
macdrv_SetLayeredWindowAttributes(HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
1329 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1331 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd
, key
, alpha
, flags
);
1335 data
->layered
= TRUE
;
1336 if (data
->cocoa_window
)
1338 sync_window_opacity(data
, key
, alpha
, FALSE
, flags
);
1339 /* since layered attributes are now set, can now show the window */
1340 if ((GetWindowLongW(hwnd
, GWL_STYLE
) & WS_VISIBLE
) && !data
->on_screen
)
1343 release_win_data(data
);
1346 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd
);
1350 /*****************************************************************
1351 * SetParent (MACDRV.@)
1353 void CDECL
macdrv_SetParent(HWND hwnd
, HWND parent
, HWND old_parent
)
1355 struct macdrv_win_data
*data
;
1357 TRACE("%p, %p, %p\n", hwnd
, parent
, old_parent
);
1359 if (parent
== old_parent
) return;
1360 if (!(data
= get_win_data(hwnd
))) return;
1362 if (parent
!= GetDesktopWindow()) /* a child window */
1364 if (old_parent
== GetDesktopWindow())
1366 /* destroy the old Mac window */
1367 destroy_cocoa_window(data
);
1370 else /* new top level window */
1371 create_cocoa_window(data
);
1372 release_win_data(data
);
1374 set_gl_view_parent(hwnd
, parent
);
1378 /***********************************************************************
1379 * SetWindowRgn (MACDRV.@)
1381 * Assign specified region to window (for non-rectangular windows)
1383 void CDECL
macdrv_SetWindowRgn(HWND hwnd
, HRGN hrgn
, BOOL redraw
)
1385 struct macdrv_win_data
*data
;
1387 TRACE("%p, %p, %d\n", hwnd
, hrgn
, redraw
);
1389 if ((data
= get_win_data(hwnd
)))
1391 sync_window_region(data
, hrgn
);
1392 release_win_data(data
);
1398 GetWindowThreadProcessId(hwnd
, &procid
);
1399 if (procid
!= GetCurrentProcessId())
1400 SendMessageW(hwnd
, WM_MACDRV_SET_WIN_REGION
, 0, 0);
1405 /***********************************************************************
1406 * SetWindowStyle (MACDRV.@)
1408 * Update the state of the Cocoa window to reflect a style change
1410 void CDECL
macdrv_SetWindowStyle(HWND hwnd
, INT offset
, STYLESTRUCT
*style
)
1412 struct macdrv_win_data
*data
;
1414 TRACE("hwnd %p offset %d styleOld 0x%08x styleNew 0x%08x\n", hwnd
, offset
, style
->styleOld
, style
->styleNew
);
1416 if (hwnd
== GetDesktopWindow()) return;
1417 if (!(data
= get_win_data(hwnd
))) return;
1419 if (data
->cocoa_window
)
1421 DWORD changed
= style
->styleNew
^ style
->styleOld
;
1423 set_cocoa_window_properties(data
);
1425 if (offset
== GWL_EXSTYLE
&& (changed
& WS_EX_LAYERED
)) /* changing WS_EX_LAYERED resets attributes */
1427 data
->layered
= FALSE
;
1428 data
->ulw_layered
= FALSE
;
1429 sync_window_opacity(data
, 0, 0, FALSE
, 0);
1430 if (data
->surface
) set_surface_use_alpha(data
->surface
, FALSE
);
1433 if (offset
== GWL_EXSTYLE
&& (changed
& WS_EX_LAYOUTRTL
))
1434 sync_window_region(data
, (HRGN
)1);
1437 release_win_data(data
);
1441 /*****************************************************************
1442 * SetWindowText (MACDRV.@)
1444 void CDECL
macdrv_SetWindowText(HWND hwnd
, LPCWSTR text
)
1448 TRACE("%p, %s\n", hwnd
, debugstr_w(text
));
1450 if ((win
= macdrv_get_cocoa_window(hwnd
, FALSE
)))
1451 macdrv_set_cocoa_window_title(win
, text
, strlenW(text
));
1455 /***********************************************************************
1456 * ShowWindow (MACDRV.@)
1458 UINT CDECL
macdrv_ShowWindow(HWND hwnd
, INT cmd
, RECT
*rect
, UINT swp
)
1460 struct macdrv_thread_data
*thread_data
= macdrv_thread_data();
1461 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1464 TRACE("win %p/%p cmd %d at %s flags %08x\n",
1465 hwnd
, data
? data
->cocoa_window
: NULL
, cmd
, wine_dbgstr_rect(rect
), swp
);
1467 if (!data
|| !data
->cocoa_window
) goto done
;
1468 if (IsRectEmpty(rect
)) goto done
;
1469 if (GetWindowLongW(hwnd
, GWL_STYLE
) & WS_MINIMIZE
)
1471 if (rect
->left
!= -32000 || rect
->top
!= -32000)
1473 OffsetRect(rect
, -32000 - rect
->left
, -32000 - rect
->top
);
1474 swp
&= ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
1478 if (!data
->on_screen
) goto done
;
1480 /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1482 if (!thread_data
->current_event
|| thread_data
->current_event
->window
!= data
->cocoa_window
)
1485 if (thread_data
->current_event
->type
!= WINDOW_FRAME_CHANGED
&&
1486 thread_data
->current_event
->type
!= WINDOW_DID_UNMINIMIZE
)
1489 macdrv_get_cocoa_window_frame(data
->cocoa_window
, &frame
);
1490 *rect
= rect_from_cgrect(frame
);
1491 macdrv_mac_to_window_rect(data
, rect
);
1492 TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame
), wine_dbgstr_rect(rect
));
1493 swp
&= ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
| SWP_NOSIZE
| SWP_NOCLIENTSIZE
);
1496 release_win_data(data
);
1501 /***********************************************************************
1502 * SysCommand (MACDRV.@)
1504 * Perform WM_SYSCOMMAND handling.
1506 LRESULT CDECL
macdrv_SysCommand(HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
1508 struct macdrv_win_data
*data
;
1510 WPARAM command
= wparam
& 0xfff0;
1512 TRACE("%p, %x, %lx\n", hwnd
, (unsigned)wparam
, lparam
);
1514 if (!(data
= get_win_data(hwnd
))) goto done
;
1515 if (!data
->cocoa_window
|| !data
->on_screen
) goto done
;
1517 /* prevent a simple ALT press+release from activating the system menu,
1518 as that can get confusing */
1519 if (command
== SC_KEYMENU
&& !(WCHAR
)lparam
&& !GetMenu(hwnd
) &&
1520 (GetWindowLongW(hwnd
, GWL_STYLE
) & WS_SYSMENU
))
1522 TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam
, lparam
);
1526 if (command
== SC_MOVE
)
1528 release_win_data(data
);
1529 return move_window(hwnd
, wparam
);
1533 release_win_data(data
);
1538 /***********************************************************************
1539 * UpdateLayeredWindow (MACDRV.@)
1541 BOOL CDECL
macdrv_UpdateLayeredWindow(HWND hwnd
, const UPDATELAYEREDWINDOWINFO
*info
,
1542 const RECT
*window_rect
)
1544 struct window_surface
*surface
;
1545 struct macdrv_win_data
*data
;
1546 BLENDFUNCTION blend
= { AC_SRC_OVER
, 0, 255, 0 };
1548 char buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1549 BITMAPINFO
*bmi
= (BITMAPINFO
*)buffer
;
1550 void *src_bits
, *dst_bits
;
1556 if (!(data
= get_win_data(hwnd
))) return FALSE
;
1558 data
->layered
= TRUE
;
1559 data
->ulw_layered
= TRUE
;
1561 rect
= *window_rect
;
1562 OffsetRect(&rect
, -window_rect
->left
, -window_rect
->top
);
1564 surface
= data
->surface
;
1565 if (!surface
|| memcmp(&surface
->rect
, &rect
, sizeof(RECT
)))
1567 data
->surface
= create_surface(data
->cocoa_window
, &rect
, NULL
, TRUE
);
1568 set_window_surface(data
->cocoa_window
, data
->surface
);
1569 if (surface
) window_surface_release(surface
);
1570 surface
= data
->surface
;
1571 if (data
->unminimized_surface
)
1573 window_surface_release(data
->unminimized_surface
);
1574 data
->unminimized_surface
= NULL
;
1577 else set_surface_use_alpha(surface
, TRUE
);
1579 if (surface
) window_surface_add_ref(surface
);
1580 release_win_data(data
);
1582 if (!surface
) return FALSE
;
1585 window_surface_release(surface
);
1589 if (info
->dwFlags
& ULW_ALPHA
)
1591 /* Apply SourceConstantAlpha via window alpha, not blend. */
1592 alpha
= info
->pblend
->SourceConstantAlpha
;
1593 blend
= *info
->pblend
;
1594 blend
.SourceConstantAlpha
= 0xff;
1599 dst_bits
= surface
->funcs
->get_info(surface
, bmi
);
1601 if (!(dib
= CreateDIBSection(info
->hdcDst
, bmi
, DIB_RGB_COLORS
, &src_bits
, NULL
, 0))) goto done
;
1602 if (!(hdc
= CreateCompatibleDC(0))) goto done
;
1604 SelectObject(hdc
, dib
);
1607 IntersectRect(&rect
, &rect
, info
->prcDirty
);
1608 surface
->funcs
->lock(surface
);
1609 memcpy(src_bits
, dst_bits
, bmi
->bmiHeader
.biSizeImage
);
1610 surface
->funcs
->unlock(surface
);
1611 PatBlt(hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, BLACKNESS
);
1613 if (!(ret
= GdiAlphaBlend(hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1615 rect
.left
+ (info
->pptSrc
? info
->pptSrc
->x
: 0),
1616 rect
.top
+ (info
->pptSrc
? info
->pptSrc
->y
: 0),
1617 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
1621 if ((data
= get_win_data(hwnd
)))
1623 if (surface
== data
->surface
)
1625 surface
->funcs
->lock(surface
);
1626 memcpy(dst_bits
, src_bits
, bmi
->bmiHeader
.biSizeImage
);
1627 add_bounds_rect(surface
->funcs
->get_bounds(surface
), &rect
);
1628 surface
->funcs
->unlock(surface
);
1629 surface
->funcs
->flush(surface
);
1632 /* The ULW flags are a superset of the LWA flags. */
1633 sync_window_opacity(data
, info
->crKey
, alpha
, TRUE
, info
->dwFlags
);
1635 release_win_data(data
);
1639 window_surface_release(surface
);
1640 if (hdc
) DeleteDC(hdc
);
1641 if (dib
) DeleteObject(dib
);
1646 /**********************************************************************
1647 * WindowMessage (MACDRV.@)
1649 LRESULT CDECL
macdrv_WindowMessage(HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1651 struct macdrv_win_data
*data
;
1653 TRACE("%p, %u, %u, %lu\n", hwnd
, msg
, (unsigned)wp
, lp
);
1657 case WM_MACDRV_SET_WIN_REGION
:
1658 if ((data
= get_win_data(hwnd
)))
1660 sync_window_region(data
, (HRGN
)1);
1661 release_win_data(data
);
1664 case WM_MACDRV_UPDATE_DESKTOP_RECT
:
1665 if (hwnd
== GetDesktopWindow())
1667 CGRect new_desktop_rect
;
1668 RECT current_desktop_rect
;
1670 macdrv_reset_device_metrics();
1671 new_desktop_rect
= macdrv_get_desktop_rect();
1672 if (!GetWindowRect(hwnd
, ¤t_desktop_rect
) ||
1673 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect
), new_desktop_rect
))
1675 SendMessageTimeoutW(HWND_BROADCAST
, WM_MACDRV_RESET_DEVICE_METRICS
, 0, 0,
1676 SMTO_ABORTIFHUNG
, 2000, NULL
);
1677 SetWindowPos(hwnd
, 0, CGRectGetMinX(new_desktop_rect
), CGRectGetMinY(new_desktop_rect
),
1678 CGRectGetWidth(new_desktop_rect
), CGRectGetHeight(new_desktop_rect
),
1679 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_DEFERERASE
);
1680 SendMessageTimeoutW(HWND_BROADCAST
, WM_MACDRV_DISPLAYCHANGE
, wp
, lp
,
1681 SMTO_ABORTIFHUNG
, 2000, NULL
);
1685 case WM_MACDRV_RESET_DEVICE_METRICS
:
1686 macdrv_reset_device_metrics();
1688 case WM_MACDRV_DISPLAYCHANGE
:
1689 macdrv_reassert_window_position(hwnd
);
1690 SendMessageW(hwnd
, WM_DISPLAYCHANGE
, wp
, lp
);
1692 case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS
:
1693 activate_on_following_focus();
1694 TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time
);
1698 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1703 static inline RECT
get_surface_rect(const RECT
*visible_rect
)
1706 RECT desktop_rect
= rect_from_cgrect(macdrv_get_desktop_rect());
1708 IntersectRect(&rect
, visible_rect
, &desktop_rect
);
1709 OffsetRect(&rect
, -visible_rect
->left
, -visible_rect
->top
);
1712 rect
.right
= max(rect
.left
+ 128, (rect
.right
+ 127) & ~127);
1713 rect
.bottom
= max(rect
.top
+ 128, (rect
.bottom
+ 127) & ~127);
1718 /***********************************************************************
1719 * WindowPosChanging (MACDRV.@)
1721 void CDECL
macdrv_WindowPosChanging(HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1722 const RECT
*window_rect
, const RECT
*client_rect
,
1723 RECT
*visible_rect
, struct window_surface
**surface
)
1725 struct macdrv_win_data
*data
= get_win_data(hwnd
);
1726 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1729 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd
, insert_after
,
1730 swp_flags
, wine_dbgstr_rect(window_rect
), wine_dbgstr_rect(client_rect
),
1731 wine_dbgstr_rect(visible_rect
), surface
);
1733 if (!data
&& !(data
= macdrv_create_win_data(hwnd
, window_rect
, client_rect
))) return;
1735 *visible_rect
= *window_rect
;
1736 macdrv_window_to_mac_rect(data
, style
, visible_rect
);
1737 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect
),
1738 wine_dbgstr_rect(visible_rect
));
1740 /* create the window surface if necessary */
1741 if (!data
->cocoa_window
) goto done
;
1742 if (swp_flags
& SWP_HIDEWINDOW
) goto done
;
1743 if (data
->ulw_layered
) goto done
;
1745 if (*surface
) window_surface_release(*surface
);
1748 surface_rect
= get_surface_rect(visible_rect
);
1751 if (!memcmp(&data
->surface
->rect
, &surface_rect
, sizeof(surface_rect
)))
1753 /* existing surface is good enough */
1754 surface_clip_to_visible_rect(data
->surface
, visible_rect
);
1755 window_surface_add_ref(data
->surface
);
1756 *surface
= data
->surface
;
1760 else if (!(swp_flags
& SWP_SHOWWINDOW
) && !(style
& WS_VISIBLE
)) goto done
;
1762 *surface
= create_surface(data
->cocoa_window
, &surface_rect
, data
->surface
, FALSE
);
1765 release_win_data(data
);
1769 /***********************************************************************
1770 * WindowPosChanged (MACDRV.@)
1772 void CDECL
macdrv_WindowPosChanged(HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1773 const RECT
*window_rect
, const RECT
*client_rect
,
1774 const RECT
*visible_rect
, const RECT
*valid_rects
,
1775 struct window_surface
*surface
)
1777 struct macdrv_thread_data
*thread_data
;
1778 struct macdrv_win_data
*data
;
1779 DWORD new_style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1780 RECT old_window_rect
, old_whole_rect
, old_client_rect
;
1782 if (!(data
= get_win_data(hwnd
))) return;
1784 thread_data
= macdrv_thread_data();
1786 old_window_rect
= data
->window_rect
;
1787 old_whole_rect
= data
->whole_rect
;
1788 old_client_rect
= data
->client_rect
;
1789 data
->window_rect
= *window_rect
;
1790 data
->whole_rect
= *visible_rect
;
1791 data
->client_rect
= *client_rect
;
1792 if (!data
->ulw_layered
)
1794 if (surface
) window_surface_add_ref(surface
);
1795 if (new_style
& WS_MINIMIZE
)
1797 if (!data
->unminimized_surface
&& data
->surface
)
1799 data
->unminimized_surface
= data
->surface
;
1800 window_surface_add_ref(data
->unminimized_surface
);
1805 set_window_surface(data
->cocoa_window
, surface
);
1806 if (data
->unminimized_surface
)
1808 window_surface_release(data
->unminimized_surface
);
1809 data
->unminimized_surface
= NULL
;
1812 if (data
->surface
) window_surface_release(data
->surface
);
1813 data
->surface
= surface
;
1816 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1817 hwnd
, data
->cocoa_window
, wine_dbgstr_rect(window_rect
),
1818 wine_dbgstr_rect(visible_rect
), wine_dbgstr_rect(client_rect
),
1819 new_style
, swp_flags
, surface
);
1821 if (!IsRectEmpty(&valid_rects
[0]))
1823 macdrv_window window
= data
->cocoa_window
;
1824 int x_offset
= old_whole_rect
.left
- data
->whole_rect
.left
;
1825 int y_offset
= old_whole_rect
.top
- data
->whole_rect
.top
;
1827 /* if all that happened is that the whole window moved, copy everything */
1828 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
1829 old_whole_rect
.right
- data
->whole_rect
.right
== x_offset
&&
1830 old_whole_rect
.bottom
- data
->whole_rect
.bottom
== y_offset
&&
1831 old_client_rect
.left
- data
->client_rect
.left
== x_offset
&&
1832 old_client_rect
.right
- data
->client_rect
.right
== x_offset
&&
1833 old_client_rect
.top
- data
->client_rect
.top
== y_offset
&&
1834 old_client_rect
.bottom
- data
->client_rect
.bottom
== y_offset
&&
1835 !memcmp(&valid_rects
[0], &data
->client_rect
, sizeof(RECT
)))
1837 /* A Cocoa window's bits are moved automatically */
1838 if (!window
&& (x_offset
!= 0 || y_offset
!= 0))
1840 release_win_data(data
);
1841 move_window_bits(hwnd
, window
, &old_whole_rect
, visible_rect
,
1842 &old_client_rect
, client_rect
, window_rect
);
1843 if (!(data
= get_win_data(hwnd
))) return;
1848 release_win_data(data
);
1849 move_window_bits(hwnd
, window
, &valid_rects
[1], &valid_rects
[0],
1850 &old_client_rect
, client_rect
, window_rect
);
1851 if (!(data
= get_win_data(hwnd
))) return;
1857 if (!data
->cocoa_window
) goto done
;
1859 if (data
->on_screen
)
1861 if ((swp_flags
& SWP_HIDEWINDOW
) && !(new_style
& WS_VISIBLE
))
1865 /* check if we are currently processing an event relevant to this window */
1866 if (!thread_data
|| !thread_data
->current_event
||
1867 thread_data
->current_event
->window
!= data
->cocoa_window
||
1868 (thread_data
->current_event
->type
!= WINDOW_FRAME_CHANGED
&&
1869 thread_data
->current_event
->type
!= WINDOW_DID_UNMINIMIZE
))
1871 sync_window_position(data
, swp_flags
, &old_window_rect
, &old_whole_rect
);
1872 set_cocoa_window_properties(data
);
1875 if (new_style
& WS_VISIBLE
)
1877 if (!data
->on_screen
|| (swp_flags
& (SWP_FRAMECHANGED
|SWP_STATECHANGED
)))
1878 set_cocoa_window_properties(data
);
1880 /* layered windows are not shown until their attributes are set */
1881 if (!data
->on_screen
&&
1882 (data
->layered
|| !(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
)))
1887 release_win_data(data
);
1891 /***********************************************************************
1892 * macdrv_window_close_requested
1894 * Handler for WINDOW_CLOSE_REQUESTED events.
1896 void macdrv_window_close_requested(HWND hwnd
)
1900 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
)
1902 TRACE("not closing win %p class style CS_NOCLOSE\n", hwnd
);
1906 sysmenu
= GetSystemMenu(hwnd
, FALSE
);
1909 UINT state
= GetMenuState(sysmenu
, SC_CLOSE
, MF_BYCOMMAND
);
1910 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
1912 TRACE("not closing win %p menu state 0x%08x\n", hwnd
, state
);
1917 perform_window_command(hwnd
, 0, 0, SC_CLOSE
, HTCLOSE
);
1921 /***********************************************************************
1922 * macdrv_window_frame_changed
1924 * Handler for WINDOW_FRAME_CHANGED events.
1926 void macdrv_window_frame_changed(HWND hwnd
, const macdrv_event
*event
)
1928 struct macdrv_win_data
*data
;
1931 UINT flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1936 if (!(data
= get_win_data(hwnd
))) return;
1937 if (!data
->on_screen
|| data
->minimized
)
1939 release_win_data(data
);
1945 parent
= GetAncestor(hwnd
, GA_PARENT
);
1947 TRACE("win %p/%p new Cocoa frame %s fullscreen %d in_resize %d\n", hwnd
, data
->cocoa_window
,
1948 wine_dbgstr_cgrect(event
->window_frame_changed
.frame
),
1949 event
->window_frame_changed
.fullscreen
, event
->window_frame_changed
.in_resize
);
1951 rect
= rect_from_cgrect(event
->window_frame_changed
.frame
);
1952 macdrv_mac_to_window_rect(data
, &rect
);
1953 MapWindowPoints(0, parent
, (POINT
*)&rect
, 2);
1955 width
= rect
.right
- rect
.left
;
1956 height
= rect
.bottom
- rect
.top
;
1958 if (data
->window_rect
.left
== rect
.left
&& data
->window_rect
.top
== rect
.top
)
1959 flags
|= SWP_NOMOVE
;
1961 TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd
, data
->window_rect
.left
,
1962 data
->window_rect
.top
, rect
.left
, rect
.top
);
1964 if ((data
->window_rect
.right
- data
->window_rect
.left
== width
&&
1965 data
->window_rect
.bottom
- data
->window_rect
.top
== height
) ||
1966 (IsRectEmpty(&data
->window_rect
) && width
== 1 && height
== 1))
1967 flags
|= SWP_NOSIZE
;
1969 TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1970 data
->window_rect
.bottom
- data
->window_rect
.top
, width
, height
);
1972 being_dragged
= data
->being_dragged
;
1973 release_win_data(data
);
1975 if (event
->window_frame_changed
.fullscreen
)
1976 flags
|= SWP_NOSENDCHANGING
;
1977 if (!(flags
& SWP_NOSIZE
) || !(flags
& SWP_NOMOVE
))
1979 if (!event
->window_frame_changed
.in_resize
&& !being_dragged
)
1980 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
1981 SetWindowPos(hwnd
, 0, rect
.left
, rect
.top
, width
, height
, flags
);
1982 if (!event
->window_frame_changed
.in_resize
&& !being_dragged
)
1983 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
1988 /***********************************************************************
1989 * macdrv_window_got_focus
1991 * Handler for WINDOW_GOT_FOCUS events.
1993 void macdrv_window_got_focus(HWND hwnd
, const macdrv_event
*event
)
1995 LONG style
= GetWindowLongW(hwnd
, GWL_STYLE
);
1999 TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
2000 hwnd
, event
->window
, event
->window_got_focus
.serial
, IsWindowEnabled(hwnd
),
2001 IsWindowVisible(hwnd
), style
, GetFocus(), GetActiveWindow(), GetForegroundWindow());
2003 if (can_activate_window(hwnd
) && !(style
& WS_MINIMIZE
))
2005 /* simulate a mouse click on the caption to find out
2006 * whether the window wants to be activated */
2007 LRESULT ma
= SendMessageW(hwnd
, WM_MOUSEACTIVATE
,
2008 (WPARAM
)GetAncestor(hwnd
, GA_ROOT
),
2009 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
));
2010 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
2012 TRACE("setting foreground window to %p\n", hwnd
);
2013 SetForegroundWindow(hwnd
);
2018 TRACE("win %p/%p rejecting focus\n", hwnd
, event
->window
);
2019 macdrv_window_rejected_focus(event
);
2023 /***********************************************************************
2024 * macdrv_window_lost_focus
2026 * Handler for WINDOW_LOST_FOCUS events.
2028 void macdrv_window_lost_focus(HWND hwnd
, const macdrv_event
*event
)
2032 TRACE("win %p/%p fg %p\n", hwnd
, event
->window
, GetForegroundWindow());
2034 if (hwnd
== GetForegroundWindow())
2036 SendMessageW(hwnd
, WM_CANCELMODE
, 0, 0);
2037 if (hwnd
== GetForegroundWindow())
2038 SetForegroundWindow(GetDesktopWindow());
2043 /***********************************************************************
2044 * macdrv_app_deactivated
2046 * Handler for APP_DEACTIVATED events.
2048 void macdrv_app_deactivated(void)
2050 if (GetActiveWindow() == GetForegroundWindow())
2052 TRACE("setting fg to desktop\n");
2053 SetForegroundWindow(GetDesktopWindow());
2058 /***********************************************************************
2059 * macdrv_window_maximize_requested
2061 * Handler for WINDOW_MAXIMIZE_REQUESTED events.
2063 void macdrv_window_maximize_requested(HWND hwnd
)
2065 perform_window_command(hwnd
, WS_MAXIMIZEBOX
, WS_MAXIMIZE
, SC_MAXIMIZE
, HTMAXBUTTON
);
2069 /***********************************************************************
2070 * macdrv_window_minimize_requested
2072 * Handler for WINDOW_MINIMIZE_REQUESTED events.
2074 void macdrv_window_minimize_requested(HWND hwnd
)
2076 perform_window_command(hwnd
, WS_MINIMIZEBOX
, WS_MINIMIZE
, SC_MINIMIZE
, HTMINBUTTON
);
2080 /***********************************************************************
2081 * macdrv_window_did_unminimize
2083 * Handler for WINDOW_DID_UNMINIMIZE events.
2085 void macdrv_window_did_unminimize(HWND hwnd
)
2087 struct macdrv_win_data
*data
;
2090 TRACE("win %p\n", hwnd
);
2092 if (!(data
= get_win_data(hwnd
))) return;
2093 if (!data
->minimized
) goto done
;
2095 style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2097 data
->minimized
= FALSE
;
2098 if ((style
& (WS_MINIMIZE
| WS_VISIBLE
)) == (WS_MINIMIZE
| WS_VISIBLE
))
2100 TRACE("restoring win %p/%p\n", hwnd
, data
->cocoa_window
);
2101 release_win_data(data
);
2102 SendMessageW(hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0);
2106 TRACE("not restoring win %p/%p style %08x\n", hwnd
, data
->cocoa_window
, style
);
2109 release_win_data(data
);
2113 /***********************************************************************
2114 * macdrv_window_brought_forward
2116 * Handler for WINDOW_BROUGHT_FORWARD events.
2118 void macdrv_window_brought_forward(HWND hwnd
)
2120 TRACE("win %p\n", hwnd
);
2121 SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2125 /***********************************************************************
2126 * macdrv_window_resize_ended
2128 * Handler for WINDOW_RESIZE_ENDED events.
2130 void macdrv_window_resize_ended(HWND hwnd
)
2132 TRACE("hwnd %p\n", hwnd
);
2133 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2137 /***********************************************************************
2138 * macdrv_window_restore_requested
2140 * Handler for WINDOW_RESTORE_REQUESTED events. This is specifically
2141 * for restoring from maximized, not from minimized.
2143 void macdrv_window_restore_requested(HWND hwnd
, const macdrv_event
*event
)
2145 if (event
->window_restore_requested
.keep_frame
&& hwnd
)
2147 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2148 struct macdrv_win_data
*data
;
2150 if ((style
& WS_MAXIMIZE
) && (style
& WS_VISIBLE
) && (data
= get_win_data(hwnd
)))
2153 HWND parent
= GetAncestor(hwnd
, GA_PARENT
);
2155 rect
= rect_from_cgrect(event
->window_restore_requested
.frame
);
2156 macdrv_mac_to_window_rect(data
, &rect
);
2157 MapWindowPoints(0, parent
, (POINT
*)&rect
, 2);
2159 release_win_data(data
);
2161 SetInternalWindowPos(hwnd
, SW_SHOW
, &rect
, NULL
);
2165 perform_window_command(hwnd
, WS_MAXIMIZE
, 0, SC_RESTORE
, HTMAXBUTTON
);
2169 /***********************************************************************
2170 * macdrv_window_drag_begin
2172 * Handler for WINDOW_DRAG_BEGIN events.
2174 void macdrv_window_drag_begin(HWND hwnd
)
2176 DWORD style
= GetWindowLongW(hwnd
, GWL_STYLE
);
2177 struct macdrv_win_data
*data
;
2180 TRACE("win %p\n", hwnd
);
2182 if (style
& (WS_DISABLED
| WS_MAXIMIZE
| WS_MINIMIZE
)) return;
2183 if (!(style
& WS_VISIBLE
)) return;
2185 if (!(data
= get_win_data(hwnd
))) return;
2186 if (data
->being_dragged
) goto done
;
2188 data
->being_dragged
= TRUE
;
2189 release_win_data(data
);
2192 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
2195 while (GetMessageW(&msg
, 0, 0, 0))
2197 if (msg
.message
== WM_EXITSIZEMOVE
)
2199 SendMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2203 if (!CallMsgFilterW(&msg
, MSGF_SIZE
) && msg
.message
!= WM_KEYDOWN
&&
2204 msg
.message
!= WM_MOUSEMOVE
&& msg
.message
!= WM_LBUTTONDOWN
&& msg
.message
!= WM_LBUTTONUP
)
2206 TranslateMessage(&msg
);
2207 DispatchMessageW(&msg
);
2213 if ((data
= get_win_data(hwnd
)))
2214 data
->being_dragged
= FALSE
;
2217 release_win_data(data
);
2221 /***********************************************************************
2222 * macdrv_window_drag_end
2224 * Handler for WINDOW_DRAG_END events.
2226 void macdrv_window_drag_end(HWND hwnd
)
2228 struct macdrv_win_data
*data
;
2231 TRACE("win %p\n", hwnd
);
2233 if (!(data
= get_win_data(hwnd
))) return;
2234 being_dragged
= data
->being_dragged
;
2235 release_win_data(data
);
2239 /* Post this rather than sending it, so that the message loop in
2240 macdrv_window_drag_begin() will see it. */
2241 PostMessageW(hwnd
, WM_EXITSIZEMOVE
, 0, 0);
2246 /***********************************************************************
2247 * macdrv_reassert_window_position
2249 * Handler for REASSERT_WINDOW_POSITION events.
2251 void macdrv_reassert_window_position(HWND hwnd
)
2253 struct macdrv_win_data
*data
= get_win_data(hwnd
);
2256 if (data
->cocoa_window
&& data
->on_screen
)
2257 sync_window_position(data
, SWP_NOZORDER
| SWP_NOACTIVATE
, NULL
, NULL
);
2258 release_win_data(data
);
2274 static BOOL CALLBACK
get_process_windows(HWND hwnd
, LPARAM lp
)
2276 struct quit_info
*qi
= (struct quit_info
*)lp
;
2279 GetWindowThreadProcessId(hwnd
, &pid
);
2280 if (pid
== GetCurrentProcessId())
2282 if (qi
->count
>= qi
->capacity
)
2284 UINT new_cap
= qi
->capacity
* 2;
2285 HWND
*new_wins
= HeapReAlloc(GetProcessHeap(), 0, qi
->wins
,
2286 new_cap
* sizeof(*qi
->wins
));
2287 if (!new_wins
) return FALSE
;
2288 qi
->wins
= new_wins
;
2289 qi
->capacity
= new_cap
;
2292 qi
->wins
[qi
->count
++] = hwnd
;
2299 static void CALLBACK
quit_callback(HWND hwnd
, UINT msg
, ULONG_PTR data
, LRESULT result
)
2301 struct quit_info
*qi
= (struct quit_info
*)data
;
2305 if (msg
== WM_QUERYENDSESSION
)
2307 TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result
,
2308 hwnd
, qi
->done
, qi
->count
);
2310 if (!result
&& !IsWindow(hwnd
))
2312 TRACE("win %p no longer exists; ignoring apparent refusal\n", hwnd
);
2316 if (!result
&& qi
->result
)
2320 /* On the first FALSE from WM_QUERYENDSESSION, we already know the
2321 ultimate reply. Might as well tell Cocoa now. */
2325 TRACE("giving quit reply %d\n", qi
->result
);
2326 macdrv_quit_reply(qi
->result
);
2330 if (qi
->done
>= qi
->count
)
2335 for (i
= 0; i
< qi
->count
; i
++)
2337 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi
->wins
[i
],
2338 qi
->result
, qi
->flags
);
2339 if (!SendMessageCallbackW(qi
->wins
[i
], WM_ENDSESSION
, qi
->result
, qi
->flags
,
2340 quit_callback
, (ULONG_PTR
)qi
))
2342 WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
2343 qi
->wins
[i
], GetLastError());
2344 quit_callback(qi
->wins
[i
], WM_ENDSESSION
, (ULONG_PTR
)qi
, 0);
2349 else /* WM_ENDSESSION */
2351 TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd
, qi
->done
, qi
->count
);
2353 if (qi
->done
>= qi
->count
)
2357 TRACE("giving quit reply %d\n", qi
->result
);
2358 macdrv_quit_reply(qi
->result
);
2361 TRACE("%sterminating process\n", qi
->result
? "" : "not ");
2363 TerminateProcess(GetCurrentProcess(), 0);
2365 HeapFree(GetProcessHeap(), 0, qi
->wins
);
2366 HeapFree(GetProcessHeap(), 0, qi
);
2372 /***********************************************************************
2373 * macdrv_app_quit_requested
2375 * Handler for APP_QUIT_REQUESTED events.
2377 void macdrv_app_quit_requested(const macdrv_event
*event
)
2379 struct quit_info
*qi
;
2382 TRACE("reason %d\n", event
->app_quit_requested
.reason
);
2384 qi
= HeapAlloc(GetProcessHeap(), 0, sizeof(*qi
));
2389 qi
->wins
= HeapAlloc(GetProcessHeap(), 0, qi
->capacity
* sizeof(*qi
->wins
));
2390 qi
->count
= qi
->done
= 0;
2392 if (!qi
->wins
|| !EnumWindows(get_process_windows
, (LPARAM
)qi
))
2395 switch (event
->app_quit_requested
.reason
)
2397 case QUIT_REASON_LOGOUT
:
2399 qi
->flags
= ENDSESSION_LOGOFF
;
2401 case QUIT_REASON_RESTART
:
2402 case QUIT_REASON_SHUTDOWN
:
2408 qi
->replied
= FALSE
;
2410 for (i
= 0; i
< qi
->count
; i
++)
2412 TRACE("sending WM_QUERYENDSESSION to win %p\n", qi
->wins
[i
]);
2413 if (!SendMessageCallbackW(qi
->wins
[i
], WM_QUERYENDSESSION
, 0, qi
->flags
,
2414 quit_callback
, (ULONG_PTR
)qi
))
2416 DWORD error
= GetLastError();
2417 BOOL invalid
= (error
== ERROR_INVALID_WINDOW_HANDLE
);
2419 TRACE("failed to send WM_QUERYENDSESSION to win %p because it's invalid; assuming success\n",
2422 WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
2423 qi
->wins
[i
], error
);
2424 quit_callback(qi
->wins
[i
], WM_QUERYENDSESSION
, (ULONG_PTR
)qi
, invalid
);
2428 /* quit_callback() will clean up qi */
2432 WARN("failed to allocate window list\n");
2435 HeapFree(GetProcessHeap(), 0, qi
->wins
);
2436 HeapFree(GetProcessHeap(), 0, qi
);
2438 macdrv_quit_reply(FALSE
);
2442 /***********************************************************************
2445 * Handler for QUERY_RESIZE_SIZE query.
2447 BOOL
query_resize_size(HWND hwnd
, macdrv_query
*query
)
2449 struct macdrv_win_data
*data
= get_win_data(hwnd
);
2450 RECT rect
= rect_from_cgrect(query
->resize_size
.rect
);
2454 if (!data
) return FALSE
;
2456 macdrv_mac_to_window_rect(data
, &rect
);
2458 if (query
->resize_size
.from_left
)
2460 if (query
->resize_size
.from_top
)
2461 corner
= WMSZ_TOPLEFT
;
2463 corner
= WMSZ_BOTTOMLEFT
;
2465 else if (query
->resize_size
.from_top
)
2466 corner
= WMSZ_TOPRIGHT
;
2468 corner
= WMSZ_BOTTOMRIGHT
;
2470 if (SendMessageW(hwnd
, WM_SIZING
, corner
, (LPARAM
)&rect
))
2472 macdrv_window_to_mac_rect(data
, GetWindowLongW(hwnd
, GWL_STYLE
), &rect
);
2473 query
->resize_size
.rect
= cgrect_from_rect(rect
);
2477 release_win_data(data
);
2482 /***********************************************************************
2483 * query_resize_start
2485 * Handler for QUERY_RESIZE_START query.
2487 BOOL
query_resize_start(HWND hwnd
)
2489 TRACE("hwnd %p\n", hwnd
);
2491 sync_window_min_max_info(hwnd
);
2492 SendMessageW(hwnd
, WM_ENTERSIZEMOVE
, 0, 0);
2498 /***********************************************************************
2499 * query_min_max_info
2501 * Handler for QUERY_MIN_MAX_INFO query.
2503 BOOL
query_min_max_info(HWND hwnd
)
2505 TRACE("hwnd %p\n", hwnd
);
2506 sync_window_min_max_info(hwnd
);