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