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