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