2 * MACDRV windowing driver
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
7 * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/unicode.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
34 static CRITICAL_SECTION win_data_section;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
37 0, 0, &win_data_section,
38 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39 0, 0, { (DWORD_PTR)(__FILE__ ": win_data_section") }
41 static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
43 static CFMutableDictionaryRef win_datas;
46 /***********************************************************************
47 * get_cocoa_window_features
49 static void get_cocoa_window_features(struct macdrv_win_data *data,
50 DWORD style, DWORD ex_style,
51 struct macdrv_window_features* wf)
53 memset(wf, 0, sizeof(*wf));
55 if (IsRectEmpty(&data->window_rect)) return;
57 if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
61 if (style & WS_SYSMENU) wf->close_button = 1;
62 if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
63 if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
64 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
66 if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
67 else if (style & WS_THICKFRAME)
72 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
76 /***********************************************************************
79 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
81 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
83 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
84 struct macdrv_window_features wf;
86 rect->top = rect->bottom = rect->left = rect->right = 0;
88 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
90 get_cocoa_window_features(data, style, ex_style, &wf);
92 if (wf.title_bar) style_mask |= WS_CAPTION;
95 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
96 ex_style_mask |= WS_EX_DLGMODALFRAME;
99 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
101 TRACE("%p/%p style %08x ex_style %08x -> %s\n", data->hwnd, data->cocoa_window,
102 style, ex_style, wine_dbgstr_rect(rect));
106 /***********************************************************************
109 static void show_window(struct macdrv_win_data *data)
111 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
113 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, NULL, NULL);
117 /***********************************************************************
120 static void hide_window(struct macdrv_win_data *data)
122 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
124 macdrv_hide_cocoa_window(data->cocoa_window);
125 data->on_screen = FALSE;
129 /***********************************************************************
130 * macdrv_window_to_mac_rect
132 * Convert a rect from client to Mac window coordinates
134 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
138 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
139 if (IsRectEmpty(rect)) return;
141 get_mac_rect_offset(data, style, &rc);
143 rect->left -= rc.left;
144 rect->right -= rc.right;
146 rect->bottom -= rc.bottom;
147 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
148 if (rect->left >= rect->right) rect->right = rect->left + 1;
152 /***********************************************************************
153 * macdrv_mac_to_window_rect
155 * Opposite of macdrv_window_to_mac_rect
157 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
160 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
162 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
163 if (IsRectEmpty(rect)) return;
165 get_mac_rect_offset(data, style, &rc);
167 rect->left += rc.left;
168 rect->right += rc.right;
170 rect->bottom += rc.bottom;
171 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
172 if (rect->left >= rect->right) rect->right = rect->left + 1;
176 /***********************************************************************
177 * constrain_window_frame
179 * Alter a window frame rectangle to fit within a) Cocoa's documented
180 * limits, and b) sane sizes, like twice the desktop rect.
182 static void constrain_window_frame(CGRect* frame)
184 CGRect desktop_rect = macdrv_get_desktop_rect();
185 int max_width, max_height;
187 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
188 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
190 if (frame->origin.x < -16000) frame->origin.x = -16000;
191 if (frame->origin.y < -16000) frame->origin.y = -16000;
192 if (frame->origin.x > 16000) frame->origin.x = 16000;
193 if (frame->origin.y > 16000) frame->origin.y = 16000;
194 if (frame->size.width > max_width) frame->size.width = max_width;
195 if (frame->size.height > max_height) frame->size.height = max_height;
199 /***********************************************************************
202 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
204 struct macdrv_win_data *data;
206 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
209 EnterCriticalSection(&win_data_section);
211 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
212 CFDictionarySetValue(win_datas, hwnd, data);
218 /***********************************************************************
221 * Lock and return the data structure associated with a window.
223 static struct macdrv_win_data *get_win_data(HWND hwnd)
225 struct macdrv_win_data *data;
227 if (!hwnd) return NULL;
228 EnterCriticalSection(&win_data_section);
229 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
231 LeaveCriticalSection(&win_data_section);
236 /***********************************************************************
239 * Release the data returned by get_win_data.
241 static void release_win_data(struct macdrv_win_data *data)
243 if (data) LeaveCriticalSection(&win_data_section);
247 /***********************************************************************
248 * macdrv_get_cocoa_window
250 * Return the Mac window associated with the full area of a window
252 static macdrv_window macdrv_get_cocoa_window(HWND hwnd)
254 struct macdrv_win_data *data = get_win_data(hwnd);
255 macdrv_window ret = data ? data->cocoa_window : NULL;
256 release_win_data(data);
261 /***********************************************************************
262 * set_cocoa_window_properties
264 * Set the window properties for a Cocoa window based on its Windows
267 static void set_cocoa_window_properties(struct macdrv_win_data *data)
269 DWORD style, ex_style;
270 struct macdrv_window_features wf;
272 style = GetWindowLongW(data->hwnd, GWL_STYLE);
273 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
275 get_cocoa_window_features(data, style, ex_style, &wf);
276 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
280 /**********************************************************************
281 * create_cocoa_window
283 * Create the whole Mac window for a given window
285 static void create_cocoa_window(struct macdrv_win_data *data)
288 struct macdrv_window_features wf;
290 DWORD style, ex_style;
292 style = GetWindowLongW(data->hwnd, GWL_STYLE);
293 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
295 data->whole_rect = data->window_rect;
296 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
298 memset(&wf, 0, sizeof(wf));
299 get_cocoa_window_features(data, style, ex_style, &wf);
301 frame = cgrect_from_rect(data->whole_rect);
302 constrain_window_frame(&frame);
304 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
305 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
307 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame);
308 if (!data->cocoa_window) return;
310 set_cocoa_window_properties(data);
312 /* set the window text */
313 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
314 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
318 /**********************************************************************
319 * destroy_cocoa_window
321 * Destroy the whole Mac window for a given window.
323 static void destroy_cocoa_window(struct macdrv_win_data *data)
325 if (!data->cocoa_window) return;
327 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
329 macdrv_destroy_cocoa_window(data->cocoa_window);
330 data->cocoa_window = 0;
331 data->on_screen = FALSE;
335 /***********************************************************************
336 * macdrv_create_win_data
338 * Create a Mac data window structure for an existing window.
340 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
341 const RECT *client_rect)
343 struct macdrv_win_data *data;
346 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
348 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
351 /* don't create win data for HWND_MESSAGE windows */
352 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
354 if (!(data = alloc_win_data(hwnd))) return NULL;
356 data->whole_rect = data->window_rect = *window_rect;
357 data->client_rect = *client_rect;
359 if (parent == GetDesktopWindow())
361 create_cocoa_window(data);
362 TRACE("win %p/%p window %s whole %s client %s\n",
363 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
364 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
371 /***********************************************************************
372 * sync_window_position
374 * Synchronize the Mac window position with the Windows one
376 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
378 CGRect frame = cgrect_from_rect(data->whole_rect);
379 constrain_window_frame(&frame);
381 data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
383 TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
384 wine_dbgstr_rect(&data->whole_rect));
386 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
389 macdrv_window prev_window = NULL;
390 macdrv_window next_window = NULL;
392 /* find window that this one must be after */
393 HWND prev = GetWindow(data->hwnd, GW_HWNDPREV);
394 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
395 (prev_window = macdrv_get_cocoa_window(prev))))
396 prev = GetWindow(prev, GW_HWNDPREV);
399 /* find window that this one must be before */
400 next = GetWindow(data->hwnd, GW_HWNDNEXT);
401 while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
402 (next_window = macdrv_get_cocoa_window(next))))
403 next = GetWindow(next, GW_HWNDNEXT);
406 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window);
408 TRACE("win %p/%p below %p/%p above %p/%p\n",
409 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
414 /***********************************************************************
417 * Move the window bits when a window is moved.
419 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
420 const RECT *old_client_rect, const RECT *new_client_rect,
421 const RECT *new_window_rect)
423 RECT src_rect = *old_rect;
424 RECT dst_rect = *new_rect;
425 HDC hdc_src, hdc_dst;
431 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
432 parent = GetAncestor(hwnd, GA_PARENT);
433 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
434 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
438 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
439 /* make src rect relative to the old position of the window */
440 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
441 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
442 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
445 rgn = CreateRectRgnIndirect(&dst_rect);
446 SelectClipRgn(hdc_dst, rgn);
448 ExcludeUpdateRgn(hdc_dst, hwnd);
450 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
451 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
452 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
453 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
454 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
456 ReleaseDC(hwnd, hdc_dst);
457 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
461 /**********************************************************************
462 * CreateDesktopWindow (MACDRV.@)
464 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
466 unsigned int width, height;
470 /* retrieve the real size of the desktop */
471 SERVER_START_REQ(get_window_rectangles)
473 req->handle = wine_server_user_handle(hwnd);
474 req->relative = COORDS_CLIENT;
475 wine_server_call(req);
476 width = reply->window.right;
477 height = reply->window.bottom;
481 if (!width && !height) /* not initialized yet */
483 CGRect rect = macdrv_get_desktop_rect();
485 SERVER_START_REQ(set_window_pos)
487 req->handle = wine_server_user_handle(hwnd);
489 req->swp_flags = SWP_NOZORDER;
490 req->window.left = CGRectGetMinX(rect);
491 req->window.top = CGRectGetMinY(rect);
492 req->window.right = CGRectGetMaxX(rect);
493 req->window.bottom = CGRectGetMaxY(rect);
494 req->client = req->window;
495 wine_server_call(req);
504 /**********************************************************************
505 * CreateWindow (MACDRV.@)
507 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
513 /***********************************************************************
514 * DestroyWindow (MACDRV.@)
516 void CDECL macdrv_DestroyWindow(HWND hwnd)
518 struct macdrv_win_data *data;
522 if (!(data = get_win_data(hwnd))) return;
524 destroy_cocoa_window(data);
526 CFDictionaryRemoveValue(win_datas, hwnd);
527 release_win_data(data);
528 HeapFree(GetProcessHeap(), 0, data);
532 /*****************************************************************
533 * SetParent (MACDRV.@)
535 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
537 struct macdrv_win_data *data;
539 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
541 if (parent == old_parent) return;
542 if (!(data = get_win_data(hwnd))) return;
544 if (parent != GetDesktopWindow()) /* a child window */
546 if (old_parent == GetDesktopWindow())
548 /* destroy the old Mac window */
549 destroy_cocoa_window(data);
552 else /* new top level window */
553 create_cocoa_window(data);
554 release_win_data(data);
558 /***********************************************************************
559 * SetWindowStyle (MACDRV.@)
561 * Update the state of the Cocoa window to reflect a style change
563 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
565 struct macdrv_win_data *data;
567 TRACE("%p, %d, %p\n", hwnd, offset, style);
569 if (hwnd == GetDesktopWindow()) return;
570 if (!(data = get_win_data(hwnd))) return;
572 if (data->cocoa_window)
573 set_cocoa_window_properties(data);
575 release_win_data(data);
579 /*****************************************************************
580 * SetWindowText (MACDRV.@)
582 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
586 TRACE("%p, %s\n", hwnd, debugstr_w(text));
588 if ((win = macdrv_get_cocoa_window(hwnd)))
589 macdrv_set_cocoa_window_title(win, text, strlenW(text));
593 /***********************************************************************
594 * WindowPosChanging (MACDRV.@)
596 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
597 const RECT *window_rect, const RECT *client_rect,
598 RECT *visible_rect, struct window_surface **surface)
600 struct macdrv_win_data *data = get_win_data(hwnd);
601 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
603 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
604 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
605 wine_dbgstr_rect(visible_rect), surface);
607 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
609 *visible_rect = *window_rect;
610 macdrv_window_to_mac_rect(data, style, visible_rect);
611 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
612 wine_dbgstr_rect(visible_rect));
614 /* release the window surface if necessary */
615 if (!data->cocoa_window) goto done;
616 if (swp_flags & SWP_HIDEWINDOW) goto done;
618 if (*surface) window_surface_release(*surface);
622 release_win_data(data);
626 /***********************************************************************
627 * WindowPosChanged (MACDRV.@)
629 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
630 const RECT *window_rect, const RECT *client_rect,
631 const RECT *visible_rect, const RECT *valid_rects,
632 struct window_surface *surface)
634 struct macdrv_win_data *data;
635 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
636 RECT old_window_rect, old_whole_rect, old_client_rect;
638 if (!(data = get_win_data(hwnd))) return;
640 old_window_rect = data->window_rect;
641 old_whole_rect = data->whole_rect;
642 old_client_rect = data->client_rect;
643 data->window_rect = *window_rect;
644 data->whole_rect = *visible_rect;
645 data->client_rect = *client_rect;
647 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
648 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
649 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
650 new_style, swp_flags, surface);
652 if (!IsRectEmpty(&valid_rects[0]))
654 macdrv_window window = data->cocoa_window;
655 int x_offset = old_whole_rect.left - data->whole_rect.left;
656 int y_offset = old_whole_rect.top - data->whole_rect.top;
658 /* if all that happened is that the whole window moved, copy everything */
659 if (!(swp_flags & SWP_FRAMECHANGED) &&
660 old_whole_rect.right - data->whole_rect.right == x_offset &&
661 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
662 old_client_rect.left - data->client_rect.left == x_offset &&
663 old_client_rect.right - data->client_rect.right == x_offset &&
664 old_client_rect.top - data->client_rect.top == y_offset &&
665 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
666 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
668 /* A Cocoa window's bits are moved automatically */
669 if (!window && (x_offset != 0 || y_offset != 0))
671 release_win_data(data);
672 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
673 &old_client_rect, client_rect, window_rect);
674 if (!(data = get_win_data(hwnd))) return;
679 release_win_data(data);
680 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
681 &old_client_rect, client_rect, window_rect);
682 if (!(data = get_win_data(hwnd))) return;
686 if (!data->cocoa_window) goto done;
690 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
694 if (new_style & WS_VISIBLE)
696 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
697 set_cocoa_window_properties(data);
699 if (!data->on_screen)
703 sync_window_position(data, swp_flags);
704 set_cocoa_window_properties(data);
707 release_win_data(data);