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))
63 if (style & WS_SYSMENU) wf->close_button = 1;
64 if (style & WS_MINIMIZEBOX) wf->minimize_button = 1;
65 if (style & WS_MAXIMIZEBOX) wf->resizable = 1;
66 if (ex_style & WS_EX_TOOLWINDOW) wf->utility = 1;
69 if (ex_style & WS_EX_DLGMODALFRAME) wf->shadow = 1;
70 else if (style & WS_THICKFRAME)
73 if (!data->shaped) wf->resizable = 1;
75 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) wf->shadow = 1;
79 /*******************************************************************
82 * Check if we can activate the specified window.
84 static inline BOOL can_activate_window(HWND hwnd)
86 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
89 if (!(style & WS_VISIBLE)) return FALSE;
90 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
91 if (style & WS_MINIMIZE) return FALSE;
92 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) return FALSE;
93 if (hwnd == GetDesktopWindow()) return FALSE;
94 if (GetWindowRect(hwnd, &rect) && IsRectEmpty(&rect)) return FALSE;
95 return !(style & WS_DISABLED);
99 /***********************************************************************
100 * get_cocoa_window_state
102 static void get_cocoa_window_state(struct macdrv_win_data *data,
103 DWORD style, DWORD ex_style,
104 struct macdrv_window_state* state)
106 memset(state, 0, sizeof(*state));
107 state->disabled = (style & WS_DISABLED) != 0;
108 state->no_activate = !can_activate_window(data->hwnd);
109 state->floating = (ex_style & WS_EX_TOPMOST) != 0;
110 state->excluded_by_expose = state->excluded_by_cycle =
111 !(ex_style & WS_EX_APPWINDOW) &&
112 (GetWindow(data->hwnd, GW_OWNER) || (ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE)));
116 /***********************************************************************
117 * get_mac_rect_offset
119 * Helper for macdrv_window_to_mac_rect and macdrv_mac_to_window_rect.
121 static void get_mac_rect_offset(struct macdrv_win_data *data, DWORD style, RECT *rect)
123 DWORD ex_style, style_mask = 0, ex_style_mask = 0;
125 rect->top = rect->bottom = rect->left = rect->right = 0;
127 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
131 struct macdrv_window_features wf;
132 get_cocoa_window_features(data, style, ex_style, &wf);
134 if (wf.title_bar) style_mask |= WS_CAPTION;
137 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
138 ex_style_mask |= WS_EX_DLGMODALFRAME;
142 AdjustWindowRectEx(rect, style & style_mask, FALSE, ex_style & ex_style_mask);
144 TRACE("%p/%p style %08x ex_style %08x shaped %d -> %s\n", data->hwnd, data->cocoa_window,
145 style, ex_style, data->shaped, wine_dbgstr_rect(rect));
149 /***********************************************************************
152 static void show_window(struct macdrv_win_data *data)
154 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
156 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, NULL, NULL);
160 /***********************************************************************
163 static void hide_window(struct macdrv_win_data *data)
165 TRACE("win %p/%p\n", data->hwnd, data->cocoa_window);
167 macdrv_hide_cocoa_window(data->cocoa_window);
168 data->on_screen = FALSE;
172 /***********************************************************************
173 * macdrv_window_to_mac_rect
175 * Convert a rect from client to Mac window coordinates
177 static void macdrv_window_to_mac_rect(struct macdrv_win_data *data, DWORD style, RECT *rect)
181 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
182 if (IsRectEmpty(rect)) return;
184 get_mac_rect_offset(data, style, &rc);
186 rect->left -= rc.left;
187 rect->right -= rc.right;
189 rect->bottom -= rc.bottom;
190 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
191 if (rect->left >= rect->right) rect->right = rect->left + 1;
195 /***********************************************************************
196 * macdrv_mac_to_window_rect
198 * Opposite of macdrv_window_to_mac_rect
200 static void macdrv_mac_to_window_rect(struct macdrv_win_data *data, RECT *rect)
203 DWORD style = GetWindowLongW(data->hwnd, GWL_STYLE);
205 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return;
206 if (IsRectEmpty(rect)) return;
208 get_mac_rect_offset(data, style, &rc);
210 rect->left += rc.left;
211 rect->right += rc.right;
213 rect->bottom += rc.bottom;
214 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
215 if (rect->left >= rect->right) rect->right = rect->left + 1;
219 /***********************************************************************
220 * constrain_window_frame
222 * Alter a window frame rectangle to fit within a) Cocoa's documented
223 * limits, and b) sane sizes, like twice the desktop rect.
225 static void constrain_window_frame(CGRect* frame)
227 CGRect desktop_rect = macdrv_get_desktop_rect();
228 int max_width, max_height;
230 max_width = min(32000, 2 * CGRectGetWidth(desktop_rect));
231 max_height = min(32000, 2 * CGRectGetHeight(desktop_rect));
233 if (frame->origin.x < -16000) frame->origin.x = -16000;
234 if (frame->origin.y < -16000) frame->origin.y = -16000;
235 if (frame->origin.x > 16000) frame->origin.x = 16000;
236 if (frame->origin.y > 16000) frame->origin.y = 16000;
237 if (frame->size.width > max_width) frame->size.width = max_width;
238 if (frame->size.height > max_height) frame->size.height = max_height;
242 /***********************************************************************
245 static struct macdrv_win_data *alloc_win_data(HWND hwnd)
247 struct macdrv_win_data *data;
249 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
252 data->color_key = CLR_INVALID;
253 EnterCriticalSection(&win_data_section);
255 win_datas = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
256 CFDictionarySetValue(win_datas, hwnd, data);
262 /***********************************************************************
265 * Lock and return the data structure associated with a window.
267 static struct macdrv_win_data *get_win_data(HWND hwnd)
269 struct macdrv_win_data *data;
271 if (!hwnd) return NULL;
272 EnterCriticalSection(&win_data_section);
273 if (win_datas && (data = (struct macdrv_win_data*)CFDictionaryGetValue(win_datas, hwnd)))
275 LeaveCriticalSection(&win_data_section);
280 /***********************************************************************
283 * Release the data returned by get_win_data.
285 static void release_win_data(struct macdrv_win_data *data)
287 if (data) LeaveCriticalSection(&win_data_section);
291 /***********************************************************************
292 * macdrv_get_cocoa_window
294 * Return the Mac window associated with the full area of a window
296 static macdrv_window macdrv_get_cocoa_window(HWND hwnd)
298 struct macdrv_win_data *data = get_win_data(hwnd);
299 macdrv_window ret = data ? data->cocoa_window : NULL;
300 release_win_data(data);
305 /***********************************************************************
306 * set_cocoa_window_properties
308 * Set the window properties for a Cocoa window based on its Windows
311 static void set_cocoa_window_properties(struct macdrv_win_data *data)
313 DWORD style, ex_style;
315 macdrv_window owner_win;
316 struct macdrv_window_features wf;
317 struct macdrv_window_state state;
319 style = GetWindowLongW(data->hwnd, GWL_STYLE);
320 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
322 owner = GetWindow(data->hwnd, GW_OWNER);
323 owner_win = macdrv_get_cocoa_window(owner);
324 macdrv_set_cocoa_parent_window(data->cocoa_window, owner_win);
326 get_cocoa_window_features(data, style, ex_style, &wf);
327 macdrv_set_cocoa_window_features(data->cocoa_window, &wf);
329 get_cocoa_window_state(data, style, ex_style, &state);
330 macdrv_set_cocoa_window_state(data->cocoa_window, &state);
334 /***********************************************************************
337 * Update the window region.
339 static void sync_window_region(struct macdrv_win_data *data, HRGN win_region)
341 HRGN hrgn = win_region;
342 RGNDATA *region_data;
346 if (!data->cocoa_window) return;
347 data->shaped = FALSE;
349 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
351 if (!(hrgn = CreateRectRgn(0, 0, 0, 0))) return;
352 if (GetWindowRgn(data->hwnd, hrgn) == ERROR)
359 if (hrgn && GetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
360 MirrorRgn(data->hwnd, hrgn);
363 OffsetRgn(hrgn, data->window_rect.left - data->whole_rect.left,
364 data->window_rect.top - data->whole_rect.top);
366 region_data = get_region_data(hrgn, 0);
369 rects = (CGRect*)region_data->Buffer;
370 count = region_data->rdh.nCount;
371 /* Special case optimization. If the region entirely encloses the Cocoa
372 window, it's the same as there being no region. It's potentially
373 hard/slow to test this for arbitrary regions, so we just check for
374 very simple regions. */
375 if (count == 1 && CGRectContainsRect(rects[0], cgrect_from_rect(data->whole_rect)))
377 TRACE("optimizing for simple region that contains Cocoa content rect\n");
388 TRACE("win %p/%p win_region %p rects %p count %d\n", data->hwnd, data->cocoa_window, win_region, rects, count);
389 macdrv_set_window_shape(data->cocoa_window, rects, count);
391 HeapFree(GetProcessHeap(), 0, region_data);
392 data->shaped = (region_data != NULL);
394 if (hrgn && hrgn != win_region) DeleteObject(hrgn);
398 /***********************************************************************
401 static inline void add_bounds_rect(RECT *bounds, const RECT *rect)
403 if (rect->left >= rect->right || rect->top >= rect->bottom) return;
404 bounds->left = min(bounds->left, rect->left);
405 bounds->top = min(bounds->top, rect->top);
406 bounds->right = max(bounds->right, rect->right);
407 bounds->bottom = max(bounds->bottom, rect->bottom);
411 /***********************************************************************
412 * sync_window_opacity
414 static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE alpha,
415 BOOL per_pixel_alpha, DWORD flags)
417 CGFloat opacity = 1.0;
418 BOOL needs_flush = FALSE;
420 if (flags & LWA_ALPHA) opacity = alpha / 255.0;
422 TRACE("setting window %p/%p alpha to %g\n", data->hwnd, data->cocoa_window, opacity);
423 macdrv_set_window_alpha(data->cocoa_window, opacity);
425 if (flags & LWA_COLORKEY)
427 /* FIXME: treat PALETTEINDEX and DIBINDEX as black */
428 if ((key & (1 << 24)) || key >> 16 == 0x10ff)
434 if (data->color_key != key)
436 if (key == CLR_INVALID)
438 TRACE("clearing color-key for window %p/%p\n", data->hwnd, data->cocoa_window);
439 macdrv_clear_window_color_key(data->cocoa_window);
443 TRACE("setting color-key for window %p/%p to RGB %d,%d,%d\n", data->hwnd, data->cocoa_window,
444 GetRValue(key), GetGValue(key), GetBValue(key));
445 macdrv_set_window_color_key(data->cocoa_window, GetRValue(key), GetGValue(key), GetBValue(key));
448 data->color_key = key;
452 if (!data->per_pixel_alpha != !per_pixel_alpha)
454 macdrv_window_use_per_pixel_alpha(data->cocoa_window, per_pixel_alpha);
455 data->per_pixel_alpha = per_pixel_alpha;
459 if (needs_flush && data->surface)
464 rect = data->whole_rect;
465 OffsetRect(&rect, -data->whole_rect.left, -data->whole_rect.top);
466 data->surface->funcs->lock(data->surface);
467 bounds = data->surface->funcs->get_bounds(data->surface);
468 add_bounds_rect(bounds, &rect);
469 data->surface->funcs->unlock(data->surface);
474 /**********************************************************************
475 * create_cocoa_window
477 * Create the whole Mac window for a given window
479 static void create_cocoa_window(struct macdrv_win_data *data)
481 struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
483 struct macdrv_window_features wf;
485 DWORD style, ex_style;
491 if ((win_rgn = CreateRectRgn(0, 0, 0, 0)) &&
492 GetWindowRgn(data->hwnd, win_rgn) == ERROR)
494 DeleteObject(win_rgn);
497 data->shaped = (win_rgn != 0);
499 style = GetWindowLongW(data->hwnd, GWL_STYLE);
500 ex_style = GetWindowLongW(data->hwnd, GWL_EXSTYLE);
502 data->whole_rect = data->window_rect;
503 macdrv_window_to_mac_rect(data, style, &data->whole_rect);
505 memset(&wf, 0, sizeof(wf));
506 get_cocoa_window_features(data, style, ex_style, &wf);
508 frame = cgrect_from_rect(data->whole_rect);
509 constrain_window_frame(&frame);
511 TRACE("creating %p window %s whole %s client %s\n", data->hwnd, wine_dbgstr_rect(&data->window_rect),
512 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
514 data->cocoa_window = macdrv_create_cocoa_window(&wf, frame, thread_data->queue);
515 if (!data->cocoa_window) goto done;
517 set_cocoa_window_properties(data);
519 /* set the window text */
520 if (!InternalGetWindowText(data->hwnd, text, sizeof(text)/sizeof(WCHAR))) text[0] = 0;
521 macdrv_set_cocoa_window_title(data->cocoa_window, text, strlenW(text));
523 /* set the window region */
524 if (win_rgn) sync_window_region(data, win_rgn);
526 /* set the window opacity */
527 if (!GetLayeredWindowAttributes(data->hwnd, &key, &alpha, &layered_flags)) layered_flags = 0;
528 sync_window_opacity(data, key, alpha, FALSE, layered_flags);
531 if (win_rgn) DeleteObject(win_rgn);
535 /**********************************************************************
536 * destroy_cocoa_window
538 * Destroy the whole Mac window for a given window.
540 static void destroy_cocoa_window(struct macdrv_win_data *data)
542 if (!data->cocoa_window) return;
544 TRACE("win %p Cocoa win %p\n", data->hwnd, data->cocoa_window);
546 macdrv_destroy_cocoa_window(data->cocoa_window);
547 data->cocoa_window = 0;
548 data->on_screen = FALSE;
549 data->color_key = CLR_INVALID;
550 if (data->surface) window_surface_release(data->surface);
551 data->surface = NULL;
555 /***********************************************************************
556 * macdrv_create_win_data
558 * Create a Mac data window structure for an existing window.
560 static struct macdrv_win_data *macdrv_create_win_data(HWND hwnd, const RECT *window_rect,
561 const RECT *client_rect)
563 struct macdrv_win_data *data;
566 if (GetWindowThreadProcessId(hwnd, NULL) != GetCurrentThreadId()) return NULL;
568 if (!(parent = GetAncestor(hwnd, GA_PARENT))) /* desktop */
570 macdrv_init_thread_data();
574 /* don't create win data for HWND_MESSAGE windows */
575 if (parent != GetDesktopWindow() && !GetAncestor(parent, GA_PARENT)) return NULL;
577 if (!(data = alloc_win_data(hwnd))) return NULL;
579 data->whole_rect = data->window_rect = *window_rect;
580 data->client_rect = *client_rect;
582 if (parent == GetDesktopWindow())
584 create_cocoa_window(data);
585 TRACE("win %p/%p window %s whole %s client %s\n",
586 hwnd, data->cocoa_window, wine_dbgstr_rect(&data->window_rect),
587 wine_dbgstr_rect(&data->whole_rect), wine_dbgstr_rect(&data->client_rect));
594 /***********************************************************************
597 * Calls GetRegionData on the given region and converts the rectangle
598 * array to CGRect format. The returned buffer must be freed by
599 * caller using HeapFree(GetProcessHeap(),...).
600 * If hdc_lptodp is not 0, the rectangles are converted through LPtoDP.
602 RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp)
610 if (!hrgn || !(size = GetRegionData(hrgn, 0, NULL))) return NULL;
611 if (sizeof(CGRect) > sizeof(RECT))
613 /* add extra size for CGRect array */
614 int count = (size - sizeof(RGNDATAHEADER)) / sizeof(RECT);
615 size += count * (sizeof(CGRect) - sizeof(RECT));
617 if (!(data = HeapAlloc(GetProcessHeap(), 0, size))) return NULL;
618 if (!GetRegionData(hrgn, size, data))
620 HeapFree(GetProcessHeap(), 0, data);
624 rect = (RECT *)data->Buffer;
625 cgrect = (CGRect *)data->Buffer;
626 if (hdc_lptodp) /* map to device coordinates */
628 LPtoDP(hdc_lptodp, (POINT *)rect, data->rdh.nCount * 2);
629 for (i = 0; i < data->rdh.nCount; i++)
631 if (rect[i].right < rect[i].left)
633 INT tmp = rect[i].right;
634 rect[i].right = rect[i].left;
637 if (rect[i].bottom < rect[i].top)
639 INT tmp = rect[i].bottom;
640 rect[i].bottom = rect[i].top;
646 if (sizeof(CGRect) > sizeof(RECT))
648 /* need to start from the end */
649 for (i = data->rdh.nCount-1; i >= 0; i--)
650 cgrect[i] = cgrect_from_rect(rect[i]);
654 for (i = 0; i < data->rdh.nCount; i++)
655 cgrect[i] = cgrect_from_rect(rect[i]);
661 /***********************************************************************
662 * sync_window_position
664 * Synchronize the Mac window position with the Windows one
666 static void sync_window_position(struct macdrv_win_data *data, UINT swp_flags)
668 CGRect frame = cgrect_from_rect(data->whole_rect);
669 constrain_window_frame(&frame);
671 data->on_screen = macdrv_set_cocoa_window_frame(data->cocoa_window, &frame);
672 if (data->shaped) sync_window_region(data, (HRGN)1);
674 TRACE("win %p/%p pos %s\n", data->hwnd, data->cocoa_window,
675 wine_dbgstr_rect(&data->whole_rect));
677 if (data->on_screen && (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)))
680 macdrv_window prev_window = NULL;
681 macdrv_window next_window = NULL;
683 /* find window that this one must be after */
684 HWND prev = GetWindow(data->hwnd, GW_HWNDPREV);
685 while (prev && !((GetWindowLongW(prev, GWL_STYLE) & WS_VISIBLE) &&
686 (prev_window = macdrv_get_cocoa_window(prev))))
687 prev = GetWindow(prev, GW_HWNDPREV);
690 /* find window that this one must be before */
691 next = GetWindow(data->hwnd, GW_HWNDNEXT);
692 while (next && !((GetWindowLongW(next, GWL_STYLE) & WS_VISIBLE) &&
693 (next_window = macdrv_get_cocoa_window(next))))
694 next = GetWindow(next, GW_HWNDNEXT);
697 data->on_screen = macdrv_order_cocoa_window(data->cocoa_window, prev_window, next_window);
699 TRACE("win %p/%p below %p/%p above %p/%p\n",
700 data->hwnd, data->cocoa_window, prev, prev_window, next, next_window);
705 /***********************************************************************
708 * Move the window bits when a window is moved.
710 static void move_window_bits(HWND hwnd, macdrv_window window, const RECT *old_rect, const RECT *new_rect,
711 const RECT *old_client_rect, const RECT *new_client_rect,
712 const RECT *new_window_rect)
714 RECT src_rect = *old_rect;
715 RECT dst_rect = *new_rect;
716 HDC hdc_src, hdc_dst;
722 OffsetRect(&dst_rect, -new_window_rect->left, -new_window_rect->top);
723 parent = GetAncestor(hwnd, GA_PARENT);
724 hdc_src = GetDCEx(parent, 0, DCX_CACHE);
725 hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE | DCX_WINDOW);
729 OffsetRect(&dst_rect, -new_client_rect->left, -new_client_rect->top);
730 /* make src rect relative to the old position of the window */
731 OffsetRect(&src_rect, -old_client_rect->left, -old_client_rect->top);
732 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
733 hdc_src = hdc_dst = GetDCEx(hwnd, 0, DCX_CACHE);
736 rgn = CreateRectRgnIndirect(&dst_rect);
737 SelectClipRgn(hdc_dst, rgn);
739 ExcludeUpdateRgn(hdc_dst, hwnd);
741 TRACE("copying bits for win %p/%p %s -> %s\n", hwnd, window,
742 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect));
743 BitBlt(hdc_dst, dst_rect.left, dst_rect.top,
744 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
745 hdc_src, src_rect.left, src_rect.top, SRCCOPY);
747 ReleaseDC(hwnd, hdc_dst);
748 if (hdc_src != hdc_dst) ReleaseDC(parent, hdc_src);
752 /**********************************************************************
753 * CreateDesktopWindow (MACDRV.@)
755 BOOL CDECL macdrv_CreateDesktopWindow(HWND hwnd)
757 unsigned int width, height;
761 /* retrieve the real size of the desktop */
762 SERVER_START_REQ(get_window_rectangles)
764 req->handle = wine_server_user_handle(hwnd);
765 req->relative = COORDS_CLIENT;
766 wine_server_call(req);
767 width = reply->window.right;
768 height = reply->window.bottom;
772 if (!width && !height) /* not initialized yet */
774 CGRect rect = macdrv_get_desktop_rect();
776 SERVER_START_REQ(set_window_pos)
778 req->handle = wine_server_user_handle(hwnd);
780 req->swp_flags = SWP_NOZORDER;
781 req->window.left = CGRectGetMinX(rect);
782 req->window.top = CGRectGetMinY(rect);
783 req->window.right = CGRectGetMaxX(rect);
784 req->window.bottom = CGRectGetMaxY(rect);
785 req->client = req->window;
786 wine_server_call(req);
795 /**********************************************************************
796 * CreateWindow (MACDRV.@)
798 BOOL CDECL macdrv_CreateWindow(HWND hwnd)
804 /***********************************************************************
805 * DestroyWindow (MACDRV.@)
807 void CDECL macdrv_DestroyWindow(HWND hwnd)
809 struct macdrv_win_data *data;
813 if (!(data = get_win_data(hwnd))) return;
815 destroy_cocoa_window(data);
817 CFDictionaryRemoveValue(win_datas, hwnd);
818 release_win_data(data);
819 HeapFree(GetProcessHeap(), 0, data);
823 /***********************************************************************
824 * SetLayeredWindowAttributes (MACDRV.@)
826 * Set transparency attributes for a layered window.
828 void CDECL macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags)
830 struct macdrv_win_data *data = get_win_data(hwnd);
832 TRACE("hwnd %p key %#08x alpha %#02x flags %x\n", hwnd, key, alpha, flags);
836 data->layered = TRUE;
837 if (data->cocoa_window)
839 sync_window_opacity(data, key, alpha, FALSE, flags);
840 /* since layered attributes are now set, can now show the window */
841 if ((GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE) && !data->on_screen)
844 release_win_data(data);
847 FIXME("setting layered attributes on window %p of other process not supported\n", hwnd);
851 /*****************************************************************
852 * SetParent (MACDRV.@)
854 void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
856 struct macdrv_win_data *data;
858 TRACE("%p, %p, %p\n", hwnd, parent, old_parent);
860 if (parent == old_parent) return;
861 if (!(data = get_win_data(hwnd))) return;
863 if (parent != GetDesktopWindow()) /* a child window */
865 if (old_parent == GetDesktopWindow())
867 /* destroy the old Mac window */
868 destroy_cocoa_window(data);
871 else /* new top level window */
872 create_cocoa_window(data);
873 release_win_data(data);
877 /***********************************************************************
878 * SetWindowRgn (MACDRV.@)
880 * Assign specified region to window (for non-rectangular windows)
882 int CDECL macdrv_SetWindowRgn(HWND hwnd, HRGN hrgn, BOOL redraw)
884 struct macdrv_win_data *data;
886 TRACE("%p, %p, %d\n", hwnd, hrgn, redraw);
888 if ((data = get_win_data(hwnd)))
890 sync_window_region(data, hrgn);
891 release_win_data(data);
897 GetWindowThreadProcessId(hwnd, &procid);
898 if (procid != GetCurrentProcessId())
899 SendMessageW(hwnd, WM_MACDRV_SET_WIN_REGION, 0, 0);
906 /***********************************************************************
907 * SetWindowStyle (MACDRV.@)
909 * Update the state of the Cocoa window to reflect a style change
911 void CDECL macdrv_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style)
913 struct macdrv_win_data *data;
915 TRACE("%p, %d, %p\n", hwnd, offset, style);
917 if (hwnd == GetDesktopWindow()) return;
918 if (!(data = get_win_data(hwnd))) return;
920 if (data->cocoa_window)
922 DWORD changed = style->styleNew ^ style->styleOld;
924 set_cocoa_window_properties(data);
926 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */
928 data->layered = FALSE;
929 sync_window_opacity(data, 0, 0, FALSE, 0);
930 if (data->surface) set_surface_use_alpha(data->surface, FALSE);
934 release_win_data(data);
938 /*****************************************************************
939 * SetWindowText (MACDRV.@)
941 void CDECL macdrv_SetWindowText(HWND hwnd, LPCWSTR text)
945 TRACE("%p, %s\n", hwnd, debugstr_w(text));
947 if ((win = macdrv_get_cocoa_window(hwnd)))
948 macdrv_set_cocoa_window_title(win, text, strlenW(text));
952 /***********************************************************************
953 * UpdateLayeredWindow (MACDRV.@)
955 BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
956 const RECT *window_rect)
958 struct window_surface *surface;
959 struct macdrv_win_data *data;
960 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
962 char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
963 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
964 void *src_bits, *dst_bits;
970 if (!(data = get_win_data(hwnd))) return FALSE;
972 data->layered = TRUE;
975 OffsetRect(&rect, -window_rect->left, -window_rect->top);
977 surface = data->surface;
978 if (!surface || memcmp(&surface->rect, &rect, sizeof(RECT)))
980 data->surface = create_surface(data->cocoa_window, &rect, TRUE);
981 set_window_surface(data->cocoa_window, data->surface);
982 if (surface) window_surface_release(surface);
983 surface = data->surface;
985 else set_surface_use_alpha(surface, TRUE);
987 if (surface) window_surface_add_ref(surface);
988 release_win_data(data);
990 if (!surface) return FALSE;
993 window_surface_release(surface);
997 if (info->dwFlags & ULW_ALPHA)
999 /* Apply SourceConstantAlpha via window alpha, not blend. */
1000 alpha = info->pblend->SourceConstantAlpha;
1001 blend = *info->pblend;
1002 blend.SourceConstantAlpha = 0xff;
1007 dst_bits = surface->funcs->get_info(surface, bmi);
1009 if (!(dib = CreateDIBSection(info->hdcDst, bmi, DIB_RGB_COLORS, &src_bits, NULL, 0))) goto done;
1010 if (!(hdc = CreateCompatibleDC(0))) goto done;
1012 SelectObject(hdc, dib);
1015 IntersectRect(&rect, &rect, info->prcDirty);
1016 surface->funcs->lock(surface);
1017 memcpy(src_bits, dst_bits, bmi->bmiHeader.biSizeImage);
1018 surface->funcs->unlock(surface);
1019 PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS);
1021 if (!(ret = GdiAlphaBlend(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
1023 rect.left + (info->pptSrc ? info->pptSrc->x : 0),
1024 rect.top + (info->pptSrc ? info->pptSrc->y : 0),
1025 rect.right - rect.left, rect.bottom - rect.top,
1029 if ((data = get_win_data(hwnd)))
1031 if (surface == data->surface)
1033 surface->funcs->lock(surface);
1034 memcpy(dst_bits, src_bits, bmi->bmiHeader.biSizeImage);
1035 add_bounds_rect(surface->funcs->get_bounds(surface), &rect);
1036 surface->funcs->unlock(surface);
1037 surface->funcs->flush(surface);
1040 /* The ULW flags are a superset of the LWA flags. */
1041 sync_window_opacity(data, info->crKey, alpha, TRUE, info->dwFlags);
1043 release_win_data(data);
1047 window_surface_release(surface);
1048 if (hdc) DeleteDC(hdc);
1049 if (dib) DeleteObject(dib);
1054 /**********************************************************************
1055 * WindowMessage (MACDRV.@)
1057 LRESULT CDECL macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1059 struct macdrv_win_data *data;
1061 TRACE("%p, %u, %u, %lu\n", hwnd, msg, (unsigned)wp, lp);
1065 case WM_MACDRV_SET_WIN_REGION:
1066 if ((data = get_win_data(hwnd)))
1068 sync_window_region(data, (HRGN)1);
1069 release_win_data(data);
1074 FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp);
1079 static inline RECT get_surface_rect(const RECT *visible_rect)
1082 RECT desktop_rect = rect_from_cgrect(macdrv_get_desktop_rect());
1084 IntersectRect(&rect, visible_rect, &desktop_rect);
1085 OffsetRect(&rect, -visible_rect->left, -visible_rect->top);
1088 rect.right = max(rect.left + 128, (rect.right + 127) & ~127);
1089 rect.bottom = max(rect.top + 128, (rect.bottom + 127) & ~127);
1094 /***********************************************************************
1095 * WindowPosChanging (MACDRV.@)
1097 void CDECL macdrv_WindowPosChanging(HWND hwnd, HWND insert_after, UINT swp_flags,
1098 const RECT *window_rect, const RECT *client_rect,
1099 RECT *visible_rect, struct window_surface **surface)
1101 struct macdrv_win_data *data = get_win_data(hwnd);
1102 DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
1105 TRACE("%p after %p swp %04x window %s client %s visible %s surface %p\n", hwnd, insert_after,
1106 swp_flags, wine_dbgstr_rect(window_rect), wine_dbgstr_rect(client_rect),
1107 wine_dbgstr_rect(visible_rect), surface);
1109 if (!data && !(data = macdrv_create_win_data(hwnd, window_rect, client_rect))) return;
1111 *visible_rect = *window_rect;
1112 macdrv_window_to_mac_rect(data, style, visible_rect);
1113 TRACE("visible_rect %s -> %s\n", wine_dbgstr_rect(window_rect),
1114 wine_dbgstr_rect(visible_rect));
1116 /* create the window surface if necessary */
1117 if (!data->cocoa_window) goto done;
1118 if (swp_flags & SWP_HIDEWINDOW) goto done;
1120 if (*surface) window_surface_release(*surface);
1123 surface_rect = get_surface_rect(visible_rect);
1126 if (!memcmp(&data->surface->rect, &surface_rect, sizeof(surface_rect)))
1128 /* existing surface is good enough */
1129 window_surface_add_ref(data->surface);
1130 *surface = data->surface;
1134 else if (!(swp_flags & SWP_SHOWWINDOW) && !(style & WS_VISIBLE)) goto done;
1136 *surface = create_surface(data->cocoa_window, &surface_rect, FALSE);
1139 release_win_data(data);
1143 /***********************************************************************
1144 * WindowPosChanged (MACDRV.@)
1146 void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
1147 const RECT *window_rect, const RECT *client_rect,
1148 const RECT *visible_rect, const RECT *valid_rects,
1149 struct window_surface *surface)
1151 struct macdrv_win_data *data;
1152 DWORD new_style = GetWindowLongW(hwnd, GWL_STYLE);
1153 RECT old_window_rect, old_whole_rect, old_client_rect;
1155 if (!(data = get_win_data(hwnd))) return;
1157 old_window_rect = data->window_rect;
1158 old_whole_rect = data->whole_rect;
1159 old_client_rect = data->client_rect;
1160 data->window_rect = *window_rect;
1161 data->whole_rect = *visible_rect;
1162 data->client_rect = *client_rect;
1164 window_surface_add_ref(surface);
1165 set_window_surface(data->cocoa_window, surface);
1166 if (data->surface) window_surface_release(data->surface);
1167 data->surface = surface;
1169 TRACE("win %p/%p window %s whole %s client %s style %08x flags %08x surface %p\n",
1170 hwnd, data->cocoa_window, wine_dbgstr_rect(window_rect),
1171 wine_dbgstr_rect(visible_rect), wine_dbgstr_rect(client_rect),
1172 new_style, swp_flags, surface);
1174 if (!IsRectEmpty(&valid_rects[0]))
1176 macdrv_window window = data->cocoa_window;
1177 int x_offset = old_whole_rect.left - data->whole_rect.left;
1178 int y_offset = old_whole_rect.top - data->whole_rect.top;
1180 /* if all that happened is that the whole window moved, copy everything */
1181 if (!(swp_flags & SWP_FRAMECHANGED) &&
1182 old_whole_rect.right - data->whole_rect.right == x_offset &&
1183 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
1184 old_client_rect.left - data->client_rect.left == x_offset &&
1185 old_client_rect.right - data->client_rect.right == x_offset &&
1186 old_client_rect.top - data->client_rect.top == y_offset &&
1187 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
1188 !memcmp(&valid_rects[0], &data->client_rect, sizeof(RECT)))
1190 /* A Cocoa window's bits are moved automatically */
1191 if (!window && (x_offset != 0 || y_offset != 0))
1193 release_win_data(data);
1194 move_window_bits(hwnd, window, &old_whole_rect, visible_rect,
1195 &old_client_rect, client_rect, window_rect);
1196 if (!(data = get_win_data(hwnd))) return;
1201 release_win_data(data);
1202 move_window_bits(hwnd, window, &valid_rects[1], &valid_rects[0],
1203 &old_client_rect, client_rect, window_rect);
1204 if (!(data = get_win_data(hwnd))) return;
1208 if (!data->cocoa_window) goto done;
1210 if (data->on_screen)
1212 if ((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE))
1216 if (new_style & WS_VISIBLE)
1218 if (!data->on_screen || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
1219 set_cocoa_window_properties(data);
1221 /* layered windows are not shown until their attributes are set */
1222 if (!data->on_screen &&
1223 (data->layered || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED)))
1227 sync_window_position(data, swp_flags);
1228 set_cocoa_window_properties(data);
1231 release_win_data(data);