Release 1.5.29.
[wine] / dlls / winemac.drv / window.c
1 /*
2  * MACDRV windowing driver
3  *
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.
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25
26 #include "macdrv.h"
27 #include "winuser.h"
28 #include "wine/unicode.h"
29 #include "wine/server.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
32
33
34 static CRITICAL_SECTION win_data_section;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
36 {
37     0, 0, &win_data_section,
38     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39       0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
40 };
41 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
42
43 static CFMutableDictionaryRef win_datas;
44
45 DWORD activate_on_focus_time;
46
47
48 void CDECL macdrv_SetFocus(HWND hwnd);
49
50
51 /***********************************************************************
52  *              get_cocoa_window_features
53  */
54 static void get_cocoa_window_features(struct macdrv_win_data *data,
55                                       DWORD style, DWORD ex_style,
56                                       struct macdrv_window_features* wf)
57 {
58     memset(wf, 0, sizeof(*wf));
59
60     if (IsRectEmpty(&data->window_rect)) return;
61
62     if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
63     {
64         wf->shadow = 1;
65         if (!data->shaped)
66         {
67             wf->title_bar = 1;
68             if (style & WS_SYSMENU) wf->close_button = 1;
69             if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
70             if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
71             if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
72         }
73     }
74     if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
75     else if (style & WS_THICKFRAME)
76     {
77         wf->shadow = 1;
78         if (!data->shaped) wf->resizable = 1;
79     }
80     else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
81 }
82
83
84 /*******************************************************************
85  *              can_activate_window
86  *
87  * Check if we can activate the specified window.
88  */
89 static inline BOOL can_activate_window(HWND hwnd)
90 {
91     LONG style = GetWindowLongW(hwnd, GWL_STYLE);
92     RECT rect;
93
94     if (!(style & WS_VISIBLE)) return FALSE;
95     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
96     if (style & WS_MINIMIZE) return FALSE;
97     if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
98     if (hwnd == GetDesktopWindow()) return FALSE;
99     if (GetWindowRect(hwnd, &rect) && IsRectEmpty(&rect)) return FALSE;
100     return !(style & WS_DISABLED);
101 }
102
103
104 /***********************************************************************
105  *              get_cocoa_window_state
106  */
107 static void get_cocoa_window_state(struct macdrv_win_data *data,
108                                    DWORD style, DWORD ex_style,
109                                    struct macdrv_window_state* state)
110 {
111     memset(state, 0, sizeof(*state));
112     state->disabled = (style & WS_DISABLED) != 0;
113     state->no_activate = !can_activate_window(data->hwnd);
114     state->floating = (ex_style & WS_EX_TOPMOST) != 0;
115     state->excluded_by_expose = state->excluded_by_cycle =
116         !(ex_style & WS_EX_APPWINDOW) &&
117         (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE)));
118     state->minimized = (style & WS_MINIMIZE) != 0;
119 }
120
121
122 /***********************************************************************
123  *              get_mac_rect_offset
124  *
125  * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
126  */
127 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
128 {
129     DWORD ex_style, style_mask = 0, ex_style_mask = 0;
130
131     rect->top = rect->bottom = rect->left = rect->right = 0;
132
133     ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
134
135     if (!data->shaped)
136     {
137         struct macdrv_window_features wf;
138         get_cocoa_window_features(data, style, ex_style, &wf);
139
140         if (wf.title_bar) style_mask |= WS_CAPTION;
141         if (wf.shadow)
142         {
143             style_mask |= WS_DLGFRAME | WS_THICKFRAME;
144             ex_style_mask |= WS_EX_DLGMODALFRAME;
145         }
146     }
147
148     AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
149
150     TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
151           style, ex_style, data->shaped, wine_dbgstr_rect(rect));
152 }
153
154
155 /***********************************************************************
156  *              macdrv_window_to_mac_rect
157  *
158  * Convert a rect from client to Mac window coordinates
159  */
160 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
161 {
162     RECT rc;
163
164     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
165     if (IsRectEmpty(rect)) return;
166
167     get_mac_rect_offset(data, style, &rc);
168
169     rect->left   -= rc.left;
170     rect->right  -= rc.right;
171     rect->top    -= rc.top;
172     rect->bottom -= rc.bottom;
173     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
174     if (rect->left >= rect->right) rect->right = rect->left + 1;
175 }
176
177
178 /***********************************************************************
179  *              macdrv_mac_to_window_rect
180  *
181  * Opposite of macdrv_window_to_mac_rect
182  */
183 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
184 {
185     RECT rc;
186     DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
187
188     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
189     if (IsRectEmpty(rect)) return;
190
191     get_mac_rect_offset(data, style, &rc);
192
193     rect->left   += rc.left;
194     rect->right  += rc.right;
195     rect->top    += rc.top;
196     rect->bottom += rc.bottom;
197     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
198     if (rect->left >= rect->right) rect->right = rect->left + 1;
199 }
200
201
202 /***********************************************************************
203  *              constrain_window_frame
204  *
205  * Alter a window frame rectangle to fit within a) Cocoa's documented
206  * limits, and b) sane sizes, like twice the desktop rect.
207  */
208 static void constrain_window_frame(CGRect* frame)
209 {
210     CGRect desktop_rect = macdrv_get_desktop_rect();
211     int max_width, max_height;
212
213     max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
214     max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
215
216     if (frame->origin.x < -16000) frame->origin.x = -16000;
217     if (frame->origin.y < -16000) frame->origin.y = -16000;
218     if (frame->origin.x > 16000) frame->origin.x = 16000;
219     if (frame->origin.y > 16000) frame->origin.y = 16000;
220     if (frame->size.width > max_width) frame->size.width = max_width;
221     if (frame->size.height > max_height) frame->size.height = max_height;
222 }
223
224
225 /***********************************************************************
226  *              alloc_win_data
227  */
228 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
229 {
230     struct macdrv_win_data *data;
231
232     if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
233     {
234         data->hwnd = hwnd;
235         data->color_key = CLR_INVALID;
236         EnterCriticalSection(&win_data_section);
237         if (!win_datas)
238             win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
239         CFDictionarySetValue(win_datas, hwnd, data);
240     }
241     return data;
242 }
243
244
245 /***********************************************************************
246  *              get_win_data
247  *
248  * Lock and return the data structure associated with a window.
249  */
250 struct macdrv_win_data *get_win_data(HWND hwnd)
251 {
252     struct macdrv_win_data *data;
253
254     if (!hwnd) return NULL;
255     EnterCriticalSection(&win_data_section);
256     if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
257         return data;
258     LeaveCriticalSection(&win_data_section);
259     return NULL;
260 }
261
262
263 /***********************************************************************
264  *              release_win_data
265  *
266  * Release the data returned by get_win_data.
267  */
268 void release_win_data(struct macdrv_win_data *data)
269 {
270     if (data) LeaveCriticalSection(&win_data_section);
271 }
272
273
274 /***********************************************************************
275  *              macdrv_get_cocoa_window
276  *
277  * Return the Mac window associated with the full area of a window
278  */
279 macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
280 {
281     struct macdrv_win_data *data = get_win_data(hwnd);
282     macdrv_window ret = NULL;
283     if (data && (data->on_screen || !require_on_screen))
284         ret = data->cocoa_window;
285     release_win_data(data);
286     return ret;
287 }
288
289
290 /***********************************************************************
291  *              set_cocoa_window_properties
292  *
293  * Set the window properties for a Cocoa window based on its Windows
294  * properties.
295  */
296 static void set_cocoa_window_properties(struct macdrv_win_data *data)
297 {
298     DWORD style, ex_style;
299     HWND owner;
300     macdrv_window owner_win;
301     struct macdrv_window_features wf;
302     struct macdrv_window_state state;
303
304     style = GetWindowLongW(data->hwnd, GWL_STYLE);
305     ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
306
307     owner = GetWindow(data->hwnd, GW_OWNER);
308     owner_win = macdrv_get_cocoa_window(owner, TRUE);
309     macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
310
311     get_cocoa_window_features(data, style, ex_style, &wf);
312     macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
313
314     get_cocoa_window_state(data, style, ex_style, &state);
315     macdrv_set_cocoa_window_state(data->cocoa_window, &state);
316     data->minimized = state.minimized;
317 }
318
319
320 /***********************************************************************
321  *              sync_window_region
322  *
323  * Update the window region.
324  */
325 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
326 {
327     HRGN hrgn = win_region;
328     RGNDATA *region_data;
329     const CGRect* rects;
330     int count;
331
332     if (!data->cocoa_window) return;
333     data->shaped = FALSE;
334
335     if (hrgn == (HRGN)1)  /* hack: win_region == 1 means retrieve region from server */
336     {
337         if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
338         if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
339         {
340             DeleteObject(hrgn);
341             hrgn = 0;
342         }
343     }
344
345     if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
346         MirrorRgn(data->hwnd, hrgn);
347     if (hrgn)
348     {
349         OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
350                   data->window_rect.top - data->whole_rect.top);
351     }
352     region_data = get_region_data(hrgn, 0);
353     if (region_data)
354     {
355         rects = (CGRect*)region_data->Buffer;
356         count = region_data->rdh.nCount;
357         /* Special case optimization.  If the region entirely encloses the Cocoa
358            window, it's the same as there being no region.  It's potentially
359            hard/slow to test this for arbitrary regions, so we just check for
360            very simple regions. */
361         if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
362         {
363             TRACE("optimizing for simple region that contains Cocoa content rect\n");
364             rects = NULL;
365             count = 0;
366         }
367     }
368     else
369     {
370         rects = NULL;
371         count = 0;
372     }
373
374     TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
375     macdrv_set_window_shape(data->cocoa_window, rects, count);
376
377     HeapFree(GetProcessHeap(), 0, region_data);
378     data->shaped = (region_data != NULL);
379
380     if (hrgn && hrgn != win_region) DeleteObject(hrgn);
381 }
382
383
384 /***********************************************************************
385  *              add_bounds_rect
386  */
387 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
388 {
389     if (rect->left >= rect->right || rect->top >= rect->bottom) return;
390     bounds->left   = min(bounds->left, rect->left);
391     bounds->top    = min(bounds->top, rect->top);
392     bounds->right  = max(bounds->right, rect->right);
393     bounds->bottom = max(bounds->bottom, rect->bottom);
394 }
395
396
397 /***********************************************************************
398  *              sync_window_opacity
399  */
400 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
401                                 BOOL per_pixel_alpha, DWORD flags)
402 {
403     CGFloat opacity = 1.0;
404     BOOL needs_flush = FALSE;
405
406     if (flags & LWA_ALPHA) opacity = alpha / 255.0;
407
408     TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
409     macdrv_set_window_alpha(data->cocoa_window, opacity);
410
411     if (flags & LWA_COLORKEY)
412     {
413         /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
414         if ((key & (1 << 24)) || key >> 16 == 0x10ff)
415             key = RGB(0, 0, 0);
416     }
417     else
418         key = CLR_INVALID;
419
420     if (data->color_key != key)
421     {
422         if (key == CLR_INVALID)
423         {
424             TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
425             macdrv_clear_window_color_key(data->cocoa_window);
426         }
427         else
428         {
429             TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
430                   GetRValue(key), GetGValue(key), GetBValue(key));
431             macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
432         }
433
434         data->color_key = key;
435         needs_flush = TRUE;
436     }
437
438     if (!data->per_pixel_alpha != !per_pixel_alpha)
439     {
440         macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
441         data->per_pixel_alpha = per_pixel_alpha;
442         needs_flush = TRUE;
443     }
444
445     if (needs_flush && data->surface)
446     {
447         RECT *bounds;
448         RECT rect;
449
450         rect = data->whole_rect;
451         OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
452         data->surface->funcs->lock(data->surface);
453         bounds = data->surface->funcs->get_bounds(data->surface);
454         add_bounds_rect(bounds, &rect);
455         data->surface->funcs->unlock(data->surface);
456     }
457 }
458
459
460 /**********************************************************************
461  *              create_cocoa_window
462  *
463  * Create the whole Mac window for a given window
464  */
465 static void create_cocoa_window(struct macdrv_win_data *data)
466 {
467     struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
468     WCHAR text[1024];
469     struct macdrv_window_features wf;
470     CGRect frame;
471     DWORD style, ex_style;
472     HRGN win_rgn;
473     COLORREF key;
474     BYTE alpha;
475     DWORD layered_flags;
476
477     if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
478         GetWindowRgn(data->hwnd, win_rgn) == ERROR)
479     {
480         DeleteObject(win_rgn);
481         win_rgn = 0;
482     }
483     data->shaped = (win_rgn != 0);
484
485     style = GetWindowLongW(data->hwnd, GWL_STYLE);
486     ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
487
488     data->whole_rect = data->window_rect;
489     macdrv_window_to_mac_rect(data, style, &data->whole_rect);
490
491     memset(&wf, 0, sizeof(wf));
492     get_cocoa_window_features(data, style, ex_style, &wf);
493
494     frame = cgrect_from_rect(data->whole_rect);
495     constrain_window_frame(&frame);
496
497     TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
498           wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
499
500     data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, data->hwnd, thread_data->queue);
501     if (!data->cocoa_window) goto done;
502
503     set_cocoa_window_properties(data);
504
505     /* set the window text */
506     if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
507     macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
508
509     /* set the window region */
510     if (win_rgn) sync_window_region(data, win_rgn);
511
512     /* set the window opacity */
513     if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
514     sync_window_opacity(data, key, alpha, FALSE, layered_flags);
515
516 done:
517     if (win_rgn) DeleteObject(win_rgn);
518 }
519
520
521 /**********************************************************************
522  *              destroy_cocoa_window
523  *
524  * Destroy the whole Mac window for a given window.
525  */
526 static void destroy_cocoa_window(struct macdrv_win_data *data)
527 {
528     if (!data->cocoa_window) return;
529
530     TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
531
532     macdrv_destroy_cocoa_window(data->cocoa_window);
533     data->cocoa_window = 0;
534     data->on_screen = FALSE;
535     data->color_key = CLR_INVALID;
536     if (data->surface) window_surface_release(data->surface);
537     data->surface = NULL;
538 }
539
540
541 /***********************************************************************
542  *              macdrv_create_win_data
543  *
544  * Create a Mac data window structure for an existing window.
545  */
546 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
547                                                       const RECT *client_rect)
548 {
549     struct macdrv_win_data *data;
550     HWND parent;
551
552     if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
553
554     if (!(parent = GetAncestor(hwnd, GA_PARENT)))  /* desktop */
555     {
556         macdrv_init_thread_data();
557         return NULL;
558     }
559
560     /* don't create win data for HWND_MESSAGE windows */
561     if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
562
563     if (!(data = alloc_win_data(hwnd))) return NULL;
564
565     data->whole_rect = data->window_rect = *window_rect;
566     data->client_rect = *client_rect;
567
568     if (parent == GetDesktopWindow())
569     {
570         create_cocoa_window(data);
571         TRACE("win %p/%p window %s whole %s client %s\n",
572                hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
573                wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
574     }
575
576     return data;
577 }
578
579
580 /***********************************************************************
581  *              show_window
582  */
583 static void show_window(struct macdrv_win_data *data)
584 {
585     HWND prev = NULL;
586     HWND next = NULL;
587     macdrv_window prev_window = NULL;
588     macdrv_window next_window = NULL;
589
590     /* find window that this one must be after */
591     prev = GetWindow(data->hwnd, GW_HWNDPREV);
592     while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
593                      (prev_window = macdrv_get_cocoa_window(prev, TRUE))))
594         prev = GetWindow(prev, GW_HWNDPREV);
595     if (!prev_window)
596     {
597         /* find window that this one must be before */
598         next = GetWindow(data->hwnd, GW_HWNDNEXT);
599         while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
600                          (next_window = macdrv_get_cocoa_window(next, TRUE))))
601             next = GetWindow(next, GW_HWNDNEXT);
602     }
603
604     TRACE("win %p/%p below %p/%p above %p/%p\n",
605           data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
606
607     data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window);
608     if (data->on_screen)
609     {
610         HWND hwndFocus = GetFocus();
611         if (hwndFocus && (data->hwnd == hwndFocus || IsChild(data->hwnd, hwndFocus)))
612             macdrv_SetFocus(hwndFocus);
613     }
614 }
615
616
617 /***********************************************************************
618  *              hide_window
619  */
620 static void hide_window(struct macdrv_win_data *data)
621 {
622     TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
623
624     macdrv_hide_cocoa_window(data->cocoa_window);
625     data->on_screen = FALSE;
626 }
627
628
629 /***********************************************************************
630  *              get_region_data
631  *
632  * Calls GetRegionData on the given region and converts the rectangle
633  * array to CGRect format. The returned buffer must be freed by
634  * caller using HeapFree(GetProcessHeap(),...).
635  * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
636  */
637 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
638 {
639     RGNDATA *data;
640     DWORD size;
641     int i;
642     RECT *rect;
643     CGRect *cgrect;
644
645     if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
646     if (sizeof(CGRect) > sizeof(RECT))
647     {
648         /* add extra size for CGRect array */
649         int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
650         size += count * (sizeof(CGRect) - sizeof(RECT));
651     }
652     if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
653     if (!GetRegionData(hrgn, size, data))
654     {
655         HeapFree(GetProcessHeap(), 0, data);
656         return NULL;
657     }
658
659     rect = (RECT *)data->Buffer;
660     cgrect = (CGRect *)data->Buffer;
661     if (hdc_lptodp)  /* map to device coordinates */
662     {
663         LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
664         for (i = 0; i < data->rdh.nCount; i++)
665         {
666             if (rect[i].right < rect[i].left)
667             {
668                 INT tmp = rect[i].right;
669                 rect[i].right = rect[i].left;
670                 rect[i].left = tmp;
671             }
672             if (rect[i].bottom < rect[i].top)
673             {
674                 INT tmp = rect[i].bottom;
675                 rect[i].bottom = rect[i].top;
676                 rect[i].top = tmp;
677             }
678         }
679     }
680
681     if (sizeof(CGRect) > sizeof(RECT))
682     {
683         /* need to start from the end */
684         for (i = data->rdh.nCount-1; i >= 0; i--)
685             cgrect[i] = cgrect_from_rect(rect[i]);
686     }
687     else
688     {
689         for (i = 0; i < data->rdh.nCount; i++)
690             cgrect[i] = cgrect_from_rect(rect[i]);
691     }
692     return data;
693 }
694
695
696 /***********************************************************************
697  *              sync_window_position
698  *
699  * Synchronize the Mac window position with the Windows one
700  */
701 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
702 {
703     CGRect frame;
704
705     if (data->minimized) return;
706
707     frame = cgrect_from_rect(data->whole_rect);
708     constrain_window_frame(&frame);
709
710     data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
711     if (data->shaped) sync_window_region(data, (HRGN)1);
712
713     TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
714           wine_dbgstr_rect(&data->whole_rect));
715
716     if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
717         show_window(data);
718 }
719
720
721 /***********************************************************************
722  *              move_window_bits
723  *
724  * Move the window bits when a window is moved.
725  */
726 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
727                              const RECT *old_client_rect, const RECT *new_client_rect,
728                              const RECT *new_window_rect)
729 {
730     RECT src_rect = *old_rect;
731     RECT dst_rect = *new_rect;
732     HDC hdc_src, hdc_dst;
733     HRGN rgn;
734     HWND parent = 0;
735
736     if (!window)
737     {
738         OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
739         parent = GetAncestor(hwnd, GA_PARENT);
740         hdc_src = GetDCEx(parent, 0, DCX_CACHE);
741         hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
742     }
743     else
744     {
745         OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
746         /* make src rect relative to the old position of the window */
747         OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
748         if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
749         hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
750     }
751
752     rgn = CreateRectRgnIndirect(&dst_rect);
753     SelectClipRgn(hdc_dst, rgn);
754     DeleteObject(rgn);
755     ExcludeUpdateRgn(hdc_dst, hwnd);
756
757     TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
758           wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
759     BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
760            dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
761            hdc_src, src_rect.left, src_rect.top, SRCCOPY);
762
763     ReleaseDC(hwnd, hdc_dst);
764     if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
765 }
766
767
768 /**********************************************************************
769  *              CreateDesktopWindow   (MACDRV.@)
770  */
771 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
772 {
773     unsigned int width, height;
774
775     TRACE("%p\n", hwnd);
776
777     /* retrieve the real size of the desktop */
778     SERVER_START_REQ(get_window_rectangles)
779     {
780         req->handle = wine_server_user_handle(hwnd);
781         req->relative = COORDS_CLIENT;
782         wine_server_call(req);
783         width  = reply->window.right;
784         height = reply->window.bottom;
785     }
786     SERVER_END_REQ;
787
788     if (!width && !height)  /* not initialized yet */
789     {
790         CGRect rect = macdrv_get_desktop_rect();
791
792         SERVER_START_REQ(set_window_pos)
793         {
794             req->handle        = wine_server_user_handle(hwnd);
795             req->previous      = 0;
796             req->swp_flags     = SWP_NOZORDER;
797             req->window.left   = CGRectGetMinX(rect);
798             req->window.top    = CGRectGetMinY(rect);
799             req->window.right  = CGRectGetMaxX(rect);
800             req->window.bottom = CGRectGetMaxY(rect);
801             req->client        = req->window;
802             wine_server_call(req);
803         }
804         SERVER_END_REQ;
805     }
806
807     return TRUE;
808 }
809
810
811 /**********************************************************************
812  *              CreateWindow   (MACDRV.@)
813  */
814 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
815 {
816     return TRUE;
817 }
818
819
820 /***********************************************************************
821  *              DestroyWindow   (MACDRV.@)
822  */
823 void CDECL macdrv_DestroyWindow(HWND hwnd)
824 {
825     struct macdrv_win_data *data;
826
827     TRACE("%p\n", hwnd);
828
829     if (!(data = get_win_data(hwnd))) return;
830
831     if (data->gl_view) macdrv_dispose_view(data->gl_view);
832     destroy_cocoa_window(data);
833
834     CFDictionaryRemoveValue(win_datas, hwnd);
835     release_win_data(data);
836     HeapFree(GetProcessHeap(), 0, data);
837 }
838
839
840 /*****************************************************************
841  *              SetFocus   (MACDRV.@)
842  *
843  * Set the Mac focus.
844  */
845 void CDECL macdrv_SetFocus(HWND hwnd)
846 {
847     struct macdrv_thread_data *thread_data = macdrv_thread_data();
848     struct macdrv_win_data *data;
849
850     TRACE("%p\n", hwnd);
851
852     if (!thread_data) return;
853     thread_data->dead_key_state = 0;
854
855     if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
856     if (!(data = get_win_data(hwnd))) return;
857
858     if (data->cocoa_window && data->on_screen)
859     {
860         BOOL activate = activate_on_focus_time && (GetTickCount() - activate_on_focus_time < 2000);
861         /* Set Mac focus */
862         macdrv_give_cocoa_window_focus(data->cocoa_window, activate);
863     }
864
865     release_win_data(data);
866 }
867
868
869 /***********************************************************************
870  *              SetLayeredWindowAttributes  (MACDRV.@)
871  *
872  * Set transparency attributes for a layered window.
873  */
874 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
875 {
876     struct macdrv_win_data *data = get_win_data(hwnd);
877
878     TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
879
880     if (data)
881     {
882         data->layered = TRUE;
883         if (data->cocoa_window)
884         {
885             sync_window_opacity(data, key, alpha, FALSE, flags);
886             /* since layered attributes are now set, can now show the window */
887             if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
888                 show_window(data);
889         }
890         release_win_data(data);
891     }
892     else
893         FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
894 }
895
896
897 /*****************************************************************
898  *              SetParent   (MACDRV.@)
899  */
900 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
901 {
902     struct macdrv_win_data *data;
903
904     TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
905
906     if (parent == old_parent) return;
907     if (!(data = get_win_data(hwnd))) return;
908
909     if (parent != GetDesktopWindow()) /* a child window */
910     {
911         if (old_parent == GetDesktopWindow())
912         {
913             /* destroy the old Mac window */
914             destroy_cocoa_window(data);
915         }
916     }
917     else  /* new top level window */
918         create_cocoa_window(data);
919     release_win_data(data);
920
921     set_gl_view_parent(hwnd, parent);
922 }
923
924
925 /***********************************************************************
926  *              SetWindowRgn  (MACDRV.@)
927  *
928  * Assign specified region to window (for non-rectangular windows)
929  */
930 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
931 {
932     struct macdrv_win_data *data;
933
934     TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
935
936     if ((data = get_win_data(hwnd)))
937     {
938         sync_window_region(data, hrgn);
939         release_win_data(data);
940     }
941     else
942     {
943         DWORD procid;
944
945         GetWindowThreadProcessId(hwnd, &procid);
946         if (procid != GetCurrentProcessId())
947             SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
948     }
949
950     return TRUE;
951 }
952
953
954 /***********************************************************************
955  *              SetWindowStyle   (MACDRV.@)
956  *
957  * Update the state of the Cocoa window to reflect a style change
958  */
959 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
960 {
961     struct macdrv_win_data *data;
962
963     TRACE("%p, %d, %p\n", hwnd, offset, style);
964
965     if (hwnd == GetDesktopWindow()) return;
966     if (!(data = get_win_data(hwnd))) return;
967
968     if (data->cocoa_window)
969     {
970         DWORD changed = style->styleNew ^ style->styleOld;
971
972         set_cocoa_window_properties(data);
973
974         if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
975         {
976             data->layered = FALSE;
977             data->ulw_layered = FALSE;
978             sync_window_opacity(data, 0, 0, FALSE, 0);
979             if (data->surface) set_surface_use_alpha(data->surface, FALSE);
980         }
981     }
982
983     release_win_data(data);
984 }
985
986
987 /*****************************************************************
988  *              SetWindowText   (MACDRV.@)
989  */
990 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
991 {
992     macdrv_window win;
993
994     TRACE("%p, %s\n", hwnd, debugstr_w(text));
995
996     if ((win = macdrv_get_cocoa_window(hwnd, FALSE)))
997         macdrv_set_cocoa_window_title(win, text, strlenW(text));
998 }
999
1000
1001 /***********************************************************************
1002  *              ShowWindow   (MACDRV.@)
1003  */
1004 UINT CDECL macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp)
1005 {
1006     struct macdrv_thread_data *thread_data = macdrv_thread_data();
1007     struct macdrv_win_data *data = get_win_data(hwnd);
1008     CGRect frame;
1009
1010     if (!data || !data->cocoa_window) goto done;
1011     if (IsRectEmpty(rect)) goto done;
1012     if (GetWindowLongW(hwnd, GWL_STYLE) & WS_MINIMIZE)
1013     {
1014         if (rect->left != -32000 || rect->top != -32000)
1015         {
1016             OffsetRect(rect, -32000 - rect->left, -32000 - rect->top);
1017             swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1018         }
1019         goto done;
1020     }
1021     if (!data->on_screen) goto done;
1022
1023     /* only fetch the new rectangle if the ShowWindow was a result of an external event */
1024
1025     if (!thread_data->current_event || thread_data->current_event->window != data->cocoa_window)
1026         goto done;
1027
1028     if (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1029         thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1030         thread_data->current_event->type != WINDOW_DID_UNMINIMIZE)
1031         goto done;
1032
1033     TRACE("win %p/%p cmd %d at %s flags %08x\n",
1034           hwnd, data->cocoa_window, cmd, wine_dbgstr_rect(rect), swp);
1035
1036     macdrv_get_cocoa_window_frame(data->cocoa_window, &frame);
1037     *rect = rect_from_cgrect(frame);
1038     macdrv_mac_to_window_rect(data, rect);
1039     TRACE("rect %s -> %s\n", wine_dbgstr_cgrect(frame), wine_dbgstr_rect(rect));
1040     swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
1041
1042 done:
1043     release_win_data(data);
1044     return swp;
1045 }
1046
1047
1048 /***********************************************************************
1049  *              SysCommand   (MACDRV.@)
1050  *
1051  * Perform WM_SYSCOMMAND handling.
1052  */
1053 LRESULT CDECL macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam)
1054 {
1055     struct macdrv_win_data *data;
1056     LRESULT ret = -1;
1057
1058     TRACE("%p, %x, %lx\n", hwnd, (unsigned)wparam, lparam);
1059
1060     if (!(data = get_win_data(hwnd))) goto done;
1061     if (!data->cocoa_window || !data->on_screen) goto done;
1062
1063     /* prevent a simple ALT press+release from activating the system menu,
1064        as that can get confusing */
1065     if ((wparam & 0xfff0) == SC_KEYMENU && !(WCHAR)lparam && !GetMenu(hwnd) &&
1066         (GetWindowLongW(hwnd, GWL_STYLE) & WS_SYSMENU))
1067     {
1068         TRACE("ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam);
1069         ret = 0;
1070     }
1071
1072 done:
1073     release_win_data(data);
1074     return ret;
1075 }
1076
1077
1078 /***********************************************************************
1079  *              UpdateLayeredWindow   (MACDRV.@)
1080  */
1081 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
1082                                       const RECT *window_rect)
1083 {
1084     struct window_surface *surface;
1085     struct macdrv_win_data *data;
1086     BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
1087     BYTE alpha;
1088     char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1089     BITMAPINFO *bmi = (BITMAPINFO *)buffer;
1090     void *src_bits, *dst_bits;
1091     RECT rect;
1092     HDC hdc = 0;
1093     HBITMAP dib;
1094     BOOL ret = FALSE;
1095
1096     if (!(data = get_win_data(hwnd))) return FALSE;
1097
1098     data->layered = TRUE;
1099     data->ulw_layered = TRUE;
1100
1101     rect = *window_rect;
1102     OffsetRect(&rect, -window_rect->left, -window_rect->top);
1103
1104     surface = data->surface;
1105     if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
1106     {
1107         data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE);
1108         set_window_surface(data->cocoa_window, data->surface);
1109         if (surface) window_surface_release(surface);
1110         surface = data->surface;
1111     }
1112     else set_surface_use_alpha(surface, TRUE);
1113
1114     if (surface) window_surface_add_ref(surface);
1115     release_win_data(data);
1116
1117     if (!surface) return FALSE;
1118     if (!info->hdcSrc)
1119     {
1120         window_surface_release(surface);
1121         return TRUE;
1122     }
1123
1124     if (info->dwFlags & ULW_ALPHA)
1125     {
1126         /* Apply SourceConstantAlpha via window alpha, not blend. */
1127         alpha = info->pblend->SourceConstantAlpha;
1128         blend = *info->pblend;
1129         blend.SourceConstantAlpha = 0xff;
1130     }
1131     else
1132         alpha = 0xff;
1133
1134     dst_bits = surface->funcs->get_info(surface, bmi);
1135
1136     if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1137     if (!(hdc = CreateCompatibleDC(0))) goto done;
1138
1139     SelectObject(hdc, dib);
1140     if (info->prcDirty)
1141     {
1142         IntersectRect(&rect, &rect, info->prcDirty);
1143         surface->funcs->lock(surface);
1144         memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1145         surface->funcs->unlock(surface);
1146         PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1147     }
1148     if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1149                               info->hdcSrc,
1150                               rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1151                               rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1152                               rect.right - rect.left, rect.bottom - rect.top,
1153                               blend)))
1154         goto done;
1155
1156     if ((data = get_win_data(hwnd)))
1157     {
1158         if (surface == data->surface)
1159         {
1160             surface->funcs->lock(surface);
1161             memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1162             add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1163             surface->funcs->unlock(surface);
1164             surface->funcs->flush(surface);
1165         }
1166
1167         /* The ULW flags are a superset of the LWA flags. */
1168         sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1169
1170         release_win_data(data);
1171     }
1172
1173 done:
1174     window_surface_release(surface);
1175     if (hdc) DeleteDC(hdc);
1176     if (dib) DeleteObject(dib);
1177     return ret;
1178 }
1179
1180
1181 /**********************************************************************
1182  *              WindowMessage   (MACDRV.@)
1183  */
1184 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1185 {
1186     struct macdrv_win_data *data;
1187
1188     TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1189
1190     switch(msg)
1191     {
1192     case WM_MACDRV_SET_WIN_REGION:
1193         if ((data = get_win_data(hwnd)))
1194         {
1195             sync_window_region(data, (HRGN)1);
1196             release_win_data(data);
1197         }
1198         return 0;
1199     case WM_MACDRV_UPDATE_DESKTOP_RECT:
1200         if (hwnd == GetDesktopWindow())
1201         {
1202             CGRect new_desktop_rect;
1203             RECT current_desktop_rect;
1204
1205             macdrv_reset_device_metrics();
1206             new_desktop_rect = macdrv_get_desktop_rect();
1207             if (!GetWindowRect(hwnd, &current_desktop_rect) ||
1208                 !CGRectEqualToRect(cgrect_from_rect(current_desktop_rect), new_desktop_rect))
1209             {
1210                 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_RESET_DEVICE_METRICS, 0, 0,
1211                                     SMTO_ABORTIFHUNG, 2000, NULL);
1212                 SetWindowPos(hwnd, 0, CGRectGetMinX(new_desktop_rect), CGRectGetMinY(new_desktop_rect),
1213                              CGRectGetWidth(new_desktop_rect), CGRectGetHeight(new_desktop_rect),
1214                              SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE);
1215                 SendMessageTimeoutW(HWND_BROADCAST, WM_MACDRV_DISPLAYCHANGE, wp, lp,
1216                                     SMTO_ABORTIFHUNG, 2000, NULL);
1217             }
1218         }
1219         return 0;
1220     case WM_MACDRV_RESET_DEVICE_METRICS:
1221         macdrv_reset_device_metrics();
1222         return 0;
1223     case WM_MACDRV_DISPLAYCHANGE:
1224         if ((data = get_win_data(hwnd)))
1225         {
1226             if (data->cocoa_window && data->on_screen)
1227                 sync_window_position(data, SWP_NOZORDER | SWP_NOACTIVATE);
1228             release_win_data(data);
1229         }
1230         SendMessageW(hwnd, WM_DISPLAYCHANGE, wp, lp);
1231         return 0;
1232     case WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS:
1233         activate_on_focus_time = GetTickCount();
1234         if (!activate_on_focus_time) activate_on_focus_time = 1;
1235         TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time);
1236         break;
1237     }
1238
1239     FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1240     return 0;
1241 }
1242
1243
1244 static inline RECT get_surface_rect(const RECT *visible_rect)
1245 {
1246     RECT rect;
1247     RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1248
1249     IntersectRect(&rect, visible_rect, &desktop_rect);
1250     OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1251     rect.left &= ~127;
1252     rect.top  &= ~127;
1253     rect.right  = max(rect.left + 128, (rect.right + 127) & ~127);
1254     rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1255     return rect;
1256 }
1257
1258
1259 /***********************************************************************
1260  *              WindowPosChanging   (MACDRV.@)
1261  */
1262 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1263                                     const RECT *window_rect, const RECT *client_rect,
1264                                     RECT *visible_rect, struct window_surface **surface)
1265 {
1266     struct macdrv_win_data *data = get_win_data(hwnd);
1267     DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1268     RECT surface_rect;
1269
1270     TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1271           swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1272           wine_dbgstr_rect(visible_rect), surface);
1273
1274     if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1275
1276     *visible_rect = *window_rect;
1277     macdrv_window_to_mac_rect(data, style, visible_rect);
1278     TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1279           wine_dbgstr_rect(visible_rect));
1280
1281     /* create the window surface if necessary */
1282     if (!data->cocoa_window) goto done;
1283     if (swp_flags & SWP_HIDEWINDOW) goto done;
1284     if (data->ulw_layered) goto done;
1285
1286     if (*surface) window_surface_release(*surface);
1287     *surface = NULL;
1288
1289     surface_rect = get_surface_rect(visible_rect);
1290     if (data->surface)
1291     {
1292         if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1293         {
1294             /* existing surface is good enough */
1295             surface_clip_to_visible_rect(data->surface, visible_rect);
1296             window_surface_add_ref(data->surface);
1297             *surface = data->surface;
1298             goto done;
1299         }
1300     }
1301     else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1302
1303     *surface = create_surface(data->cocoa_window, &surface_rect, data->surface, FALSE);
1304
1305 done:
1306     release_win_data(data);
1307 }
1308
1309
1310 /***********************************************************************
1311  *              WindowPosChanged   (MACDRV.@)
1312  */
1313 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1314                                    const RECT *window_rect, const RECT *client_rect,
1315                                    const RECT *visible_rect, const RECT *valid_rects,
1316                                    struct window_surface *surface)
1317 {
1318     struct macdrv_thread_data *thread_data;
1319     struct macdrv_win_data *data;
1320     DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1321     RECT old_window_rect, old_whole_rect, old_client_rect;
1322
1323     if (!(data = get_win_data(hwnd))) return;
1324
1325     thread_data = macdrv_thread_data();
1326
1327     old_window_rect = data->window_rect;
1328     old_whole_rect  = data->whole_rect;
1329     old_client_rect = data->client_rect;
1330     data->window_rect = *window_rect;
1331     data->whole_rect  = *visible_rect;
1332     data->client_rect = *client_rect;
1333     if (!data->ulw_layered)
1334     {
1335         if (surface) window_surface_add_ref(surface);
1336         set_window_surface(data->cocoa_window, surface);
1337         if (data->surface) window_surface_release(data->surface);
1338         data->surface = surface;
1339     }
1340
1341     TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1342            hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1343            wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1344            new_style, swp_flags, surface);
1345
1346     if (!IsRectEmpty(&valid_rects[0]))
1347     {
1348         macdrv_window window = data->cocoa_window;
1349         int x_offset = old_whole_rect.left - data->whole_rect.left;
1350         int y_offset = old_whole_rect.top - data->whole_rect.top;
1351
1352         /* if all that happened is that the whole window moved, copy everything */
1353         if (!(swp_flags & SWP_FRAMECHANGED) &&
1354             old_whole_rect.right   - data->whole_rect.right   == x_offset &&
1355             old_whole_rect.bottom  - data->whole_rect.bottom  == y_offset &&
1356             old_client_rect.left   - data->client_rect.left   == x_offset &&
1357             old_client_rect.right  - data->client_rect.right  == x_offset &&
1358             old_client_rect.top    - data->client_rect.top    == y_offset &&
1359             old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1360             !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1361         {
1362             /* A Cocoa window's bits are moved automatically */
1363             if (!window && (x_offset != 0 || y_offset != 0))
1364             {
1365                 release_win_data(data);
1366                 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1367                                  &old_client_rect, client_rect, window_rect);
1368                 if (!(data = get_win_data(hwnd))) return;
1369             }
1370         }
1371         else
1372         {
1373             release_win_data(data);
1374             move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1375                              &old_client_rect, client_rect, window_rect);
1376             if (!(data = get_win_data(hwnd))) return;
1377         }
1378     }
1379
1380     sync_gl_view(data);
1381
1382     if (!data->cocoa_window) goto done;
1383
1384     if (data->on_screen)
1385     {
1386         if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1387             hide_window(data);
1388     }
1389
1390     /* check if we are currently processing an event relevant to this window */
1391     if (!thread_data || !thread_data->current_event ||
1392         thread_data->current_event->window != data->cocoa_window ||
1393         (thread_data->current_event->type != WINDOW_FRAME_CHANGED &&
1394          thread_data->current_event->type != WINDOW_DID_MINIMIZE &&
1395          thread_data->current_event->type != WINDOW_DID_UNMINIMIZE))
1396     {
1397         sync_window_position(data, swp_flags);
1398         set_cocoa_window_properties(data);
1399     }
1400
1401     if (new_style & WS_VISIBLE)
1402     {
1403         if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1404             set_cocoa_window_properties(data);
1405
1406         /* layered windows are not shown until their attributes are set */
1407         if (!data->on_screen &&
1408             (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1409             show_window(data);
1410     }
1411
1412 done:
1413     release_win_data(data);
1414 }
1415
1416
1417 /***********************************************************************
1418  *              macdrv_window_close_requested
1419  *
1420  * Handler for WINDOW_CLOSE_REQUESTED events.
1421  */
1422 void macdrv_window_close_requested(HWND hwnd)
1423 {
1424     /* Ignore the delete window request if the window has been disabled. This
1425      * is to disallow applications from being closed while in a modal state.
1426      */
1427     if (IsWindowEnabled(hwnd))
1428     {
1429         HMENU hSysMenu;
1430
1431         if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
1432         hSysMenu = GetSystemMenu(hwnd, FALSE);
1433         if (hSysMenu)
1434         {
1435             UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1436             if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
1437                 return;
1438         }
1439         if (GetActiveWindow() != hwnd)
1440         {
1441             LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1442                                       (WPARAM)GetAncestor(hwnd, GA_ROOT),
1443                                       MAKELPARAM(HTCLOSE, WM_NCLBUTTONDOWN));
1444             switch(ma)
1445             {
1446                 case MA_NOACTIVATEANDEAT:
1447                 case MA_ACTIVATEANDEAT:
1448                     return;
1449                 case MA_NOACTIVATE:
1450                     break;
1451                 case MA_ACTIVATE:
1452                 case 0:
1453                     SetActiveWindow(hwnd);
1454                     break;
1455                 default:
1456                     WARN("unknown WM_MOUSEACTIVATE code %d\n", (int) ma);
1457                     break;
1458             }
1459         }
1460
1461         PostMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1462     }
1463 }
1464
1465
1466 /***********************************************************************
1467  *              macdrv_window_frame_changed
1468  *
1469  * Handler for WINDOW_FRAME_CHANGED events.
1470  */
1471 void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
1472 {
1473     struct macdrv_win_data *data;
1474     RECT rect;
1475     HWND parent;
1476     UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
1477     int width, height;
1478
1479     if (!hwnd) return;
1480     if (!(data = get_win_data(hwnd))) return;
1481     if (!data->on_screen)
1482     {
1483         release_win_data(data);
1484         return;
1485     }
1486
1487     /* Get geometry */
1488
1489     parent = GetAncestor(hwnd, GA_PARENT);
1490
1491     TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
1492
1493     rect = rect_from_cgrect(frame);
1494     macdrv_mac_to_window_rect(data, &rect);
1495     MapWindowPoints(0, parent, (POINT *)&rect, 2);
1496
1497     width = rect.right - rect.left;
1498     height = rect.bottom - rect.top;
1499
1500     if (data->window_rect.left == rect.left && data->window_rect.top == rect.top)
1501         flags |= SWP_NOMOVE;
1502     else
1503         TRACE("%p moving from (%d,%d) to (%d,%d)\n", hwnd, data->window_rect.left,
1504               data->window_rect.top, rect.left, rect.top);
1505
1506     if ((data->window_rect.right - data->window_rect.left == width &&
1507          data->window_rect.bottom - data->window_rect.top == height) ||
1508         (IsRectEmpty(&data->window_rect) && width <= 0 && height <= 0))
1509         flags |= SWP_NOSIZE;
1510     else
1511         TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left,
1512               data->window_rect.bottom - data->window_rect.top, width, height);
1513
1514     release_win_data(data);
1515
1516     if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
1517         SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
1518 }
1519
1520
1521 /***********************************************************************
1522  *              macdrv_window_got_focus
1523  *
1524  * Handler for WINDOW_GOT_FOCUS events.
1525  */
1526 void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event)
1527 {
1528     if (!hwnd) return;
1529
1530     TRACE("win %p/%p serial %lu enabled %d visible %d style %08x focus %p active %p fg %p\n",
1531           hwnd, event->window, event->window_got_focus.serial, IsWindowEnabled(hwnd),
1532           IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE), GetFocus(),
1533           GetActiveWindow(), GetForegroundWindow());
1534
1535     if (can_activate_window(hwnd))
1536     {
1537         /* simulate a mouse click on the caption to find out
1538          * whether the window wants to be activated */
1539         LRESULT ma = SendMessageW(hwnd, WM_MOUSEACTIVATE,
1540                                   (WPARAM)GetAncestor(hwnd, GA_ROOT),
1541                                   MAKELONG(HTCAPTION,WM_LBUTTONDOWN));
1542         if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE)
1543         {
1544             TRACE("setting foreground window to %p\n", hwnd);
1545             SetForegroundWindow(hwnd);
1546             return;
1547         }
1548     }
1549
1550     TRACE("win %p/%p rejecting focus\n", hwnd, event->window);
1551     macdrv_window_rejected_focus(event);
1552 }
1553
1554
1555 /***********************************************************************
1556  *              macdrv_window_lost_focus
1557  *
1558  * Handler for WINDOW_LOST_FOCUS events.
1559  */
1560 void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event)
1561 {
1562     if (!hwnd) return;
1563
1564     TRACE("win %p/%p fg %p\n", hwnd, event->window, GetForegroundWindow());
1565
1566     if (hwnd == GetForegroundWindow())
1567         SendMessageW(hwnd, WM_CANCELMODE, 0, 0);
1568 }
1569
1570
1571 /***********************************************************************
1572  *              macdrv_app_deactivated
1573  *
1574  * Handler for APP_DEACTIVATED events.
1575  */
1576 void macdrv_app_deactivated(void)
1577 {
1578     if (GetActiveWindow() == GetForegroundWindow())
1579     {
1580         TRACE("setting fg to desktop\n");
1581         SetForegroundWindow(GetDesktopWindow());
1582     }
1583 }
1584
1585
1586 /***********************************************************************
1587  *              macdrv_window_did_minimize
1588  *
1589  * Handler for WINDOW_DID_MINIMIZE events.
1590  */
1591 void macdrv_window_did_minimize(HWND hwnd)
1592 {
1593     struct macdrv_win_data *data;
1594     DWORD style;
1595
1596     TRACE("win %p\n", hwnd);
1597
1598     if (!(data = get_win_data(hwnd))) return;
1599     if (data->minimized) goto done;
1600
1601     style = GetWindowLongW(hwnd, GWL_STYLE);
1602
1603     data->minimized = TRUE;
1604     if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED))
1605     {
1606         TRACE("minimizing win %p/%p\n", hwnd, data->cocoa_window);
1607         release_win_data(data);
1608         SendMessageW(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
1609         return;
1610     }
1611     TRACE("not minimizing win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1612
1613 done:
1614     release_win_data(data);
1615 }
1616
1617
1618 /***********************************************************************
1619  *              macdrv_window_did_unminimize
1620  *
1621  * Handler for WINDOW_DID_UNMINIMIZE events.
1622  */
1623 void macdrv_window_did_unminimize(HWND hwnd)
1624 {
1625     struct macdrv_win_data *data;
1626     DWORD style;
1627
1628     TRACE("win %p\n", hwnd);
1629
1630     if (!(data = get_win_data(hwnd))) return;
1631     if (!data->minimized) goto done;
1632
1633     style = GetWindowLongW(hwnd, GWL_STYLE);
1634
1635     data->minimized = FALSE;
1636     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1637     {
1638         TRACE("restoring win %p/%p\n", hwnd, data->cocoa_window);
1639         release_win_data(data);
1640         SendMessageW(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1641         return;
1642     }
1643
1644     TRACE("not restoring win %p/%p style %08x\n", hwnd, data->cocoa_window, style);
1645
1646 done:
1647     release_win_data(data);
1648 }
1649
1650
1651 struct quit_info {
1652     HWND               *wins;
1653     UINT                capacity;
1654     UINT                count;
1655     UINT                done;
1656     DWORD               flags;
1657     BOOL                result;
1658     BOOL                replied;
1659 };
1660
1661
1662 static BOOL CALLBACK get_process_windows(HWND hwnd, LPARAM lp)
1663 {
1664     struct quit_info *qi = (struct quit_info*)lp;
1665     DWORD pid;
1666
1667     GetWindowThreadProcessId(hwnd, &pid);
1668     if (pid == GetCurrentProcessId())
1669     {
1670         if (qi->count >= qi->capacity)
1671         {
1672             UINT new_cap = qi->capacity * 2;
1673             HWND *new_wins = HeapReAlloc(GetProcessHeap(), 0, qi->wins,
1674                                          new_cap * sizeof(*qi->wins));
1675             if (!new_wins) return FALSE;
1676             qi->wins = new_wins;
1677             qi->capacity = new_cap;
1678         }
1679
1680         qi->wins[qi->count++] = hwnd;
1681     }
1682
1683     return TRUE;
1684 }
1685
1686
1687 static void CALLBACK quit_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT result)
1688 {
1689     struct quit_info *qi = (struct quit_info*)data;
1690
1691     qi->done++;
1692
1693     if (msg == WM_QUERYENDSESSION)
1694     {
1695         TRACE("got WM_QUERYENDSESSION result %ld from win %p (%u of %u done)\n", result,
1696               hwnd, qi->done, qi->count);
1697
1698         if (!result && qi->result)
1699         {
1700             qi->result = FALSE;
1701
1702             /* On the first FALSE from WM_QUERYENDSESSION, we already know the
1703                ultimate reply.  Might as well tell Cocoa now. */
1704             if (!qi->replied)
1705             {
1706                 qi->replied = TRUE;
1707                 TRACE("giving quit reply %d\n", qi->result);
1708                 macdrv_quit_reply(qi->result);
1709             }
1710         }
1711
1712         if (qi->done >= qi->count)
1713         {
1714             UINT i;
1715
1716             qi->done = 0;
1717             for (i = 0; i < qi->count; i++)
1718             {
1719                 TRACE("sending WM_ENDSESSION to win %p result %d flags 0x%08x\n", qi->wins[i],
1720                       qi->result, qi->flags);
1721                 if (!SendMessageCallbackW(qi->wins[i], WM_ENDSESSION, qi->result, qi->flags,
1722                                           quit_callback, (ULONG_PTR)qi))
1723                 {
1724                     WARN("failed to send WM_ENDSESSION to win %p; error 0x%08x\n",
1725                          qi->wins[i], GetLastError());
1726                     quit_callback(qi->wins[i], WM_ENDSESSION, (ULONG_PTR)qi, 0);
1727                 }
1728             }
1729         }
1730     }
1731     else /* WM_ENDSESSION */
1732     {
1733         TRACE("finished WM_ENDSESSION for win %p (%u of %u done)\n", hwnd, qi->done, qi->count);
1734
1735         if (qi->done >= qi->count)
1736         {
1737             if (!qi->replied)
1738             {
1739                 TRACE("giving quit reply %d\n", qi->result);
1740                 macdrv_quit_reply(qi->result);
1741             }
1742
1743             TRACE("%sterminating process\n", qi->result ? "" : "not ");
1744             if (qi->result)
1745                 TerminateProcess(GetCurrentProcess(), 0);
1746
1747             HeapFree(GetProcessHeap(), 0, qi->wins);
1748             HeapFree(GetProcessHeap(), 0, qi);
1749         }
1750     }
1751 }
1752
1753
1754 /***********************************************************************
1755  *              macdrv_app_quit_requested
1756  *
1757  * Handler for APP_QUIT_REQUESTED events.
1758  */
1759 void macdrv_app_quit_requested(const macdrv_event *event)
1760 {
1761     struct quit_info *qi;
1762     UINT i;
1763
1764     TRACE("reason %d\n", event->app_quit_requested.reason);
1765
1766     qi = HeapAlloc(GetProcessHeap(), 0, sizeof(*qi));
1767     if (!qi)
1768         goto fail;
1769
1770     qi->capacity = 32;
1771     qi->wins = HeapAlloc(GetProcessHeap(), 0, qi->capacity * sizeof(*qi->wins));
1772     qi->count = qi->done = 0;
1773
1774     if (!qi->wins || !EnumWindows(get_process_windows, (LPARAM)qi))
1775         goto fail;
1776
1777     switch (event->app_quit_requested.reason)
1778     {
1779         case QUIT_REASON_LOGOUT:
1780         default:
1781             qi->flags = ENDSESSION_LOGOFF;
1782             break;
1783         case QUIT_REASON_RESTART:
1784         case QUIT_REASON_SHUTDOWN:
1785             qi->flags = 0;
1786             break;
1787     }
1788
1789     qi->result = TRUE;
1790     qi->replied = FALSE;
1791
1792     for (i = 0; i < qi->count; i++)
1793     {
1794         TRACE("sending WM_QUERYENDSESSION to win %p\n", qi->wins[i]);
1795         if (!SendMessageCallbackW(qi->wins[i], WM_QUERYENDSESSION, 0, qi->flags,
1796                                   quit_callback, (ULONG_PTR)qi))
1797         {
1798             WARN("failed to send WM_QUERYENDSESSION to win %p; error 0x%08x; assuming refusal\n",
1799                  qi->wins[i], GetLastError());
1800             quit_callback(qi->wins[i], WM_QUERYENDSESSION, (ULONG_PTR)qi, FALSE);
1801         }
1802     }
1803
1804     /* quit_callback() will clean up qi */
1805     return;
1806
1807 fail:
1808     WARN("failed to allocate window list\n");
1809     if (qi)
1810     {
1811         HeapFree(GetProcessHeap(), 0, qi->wins);
1812         HeapFree(GetProcessHeap(), 0, qi);
1813     }
1814     macdrv_quit_reply(FALSE);
1815 }