blob: 3999054e9532ba9db572065556ba4e832a660060 [file] [log] [blame]
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001/*
2 * Window related functions
3 *
4 * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5 * Copyright 1993 David Metcalfe
6 * Copyright 1995, 1996 Alex Korobka
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000021 */
22
23#include "config.h"
24
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000025#include <stdarg.h>
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000026#include <stdlib.h>
James Liggett60a97502006-08-22 17:14:11 -070027#include <stdio.h>
Patrik Stridvallba78aac2003-08-08 21:07:23 +000028#ifdef HAVE_UNISTD_H
29# include <unistd.h>
30#endif
Dmitry Timoshkovde70d2b2001-06-19 03:32:44 +000031
Alexandre Julliard64c0e2a2003-11-21 21:48:36 +000032#include <X11/Xlib.h>
Alexandre Julliarde9119c12002-09-24 18:36:51 +000033#include <X11/Xresource.h>
34#include <X11/Xutil.h>
Alexandre Julliard395928d2008-01-23 16:30:18 +010035#ifdef HAVE_LIBXSHAPE
36#include <X11/extensions/shape.h>
37#endif /* HAVE_LIBXSHAPE */
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000038
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000039#include "windef.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000040#include "winbase.h"
41#include "wingdi.h"
42#include "winuser.h"
Ilya Konstantinov560ca322001-10-02 18:44:56 +000043#include "wine/unicode.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000044
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000045#include "x11drv.h"
Chris Robinson00633e32007-09-25 22:43:38 -070046#include "xcomposite.h"
Alexandre Julliard4d32a472005-03-25 10:38:56 +000047#include "wine/debug.h"
48#include "wine/server.h"
Ove Kaaven77e7fd72002-01-21 18:41:27 +000049#include "mwm.h"
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000050
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000051WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000052
Alexandre Julliard24dbaa02008-04-17 16:13:34 +020053#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
54#define _NET_WM_MOVERESIZE_SIZE_TOP 1
55#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
56#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
57#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
58#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
59#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
60#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
61#define _NET_WM_MOVERESIZE_MOVE 8
62#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9
63#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10
64
Alexandre Julliard855308f2008-04-23 15:32:58 +020065#define _NET_WM_STATE_REMOVE 0
66#define _NET_WM_STATE_ADD 1
67#define _NET_WM_STATE_TOGGLE 2
68
69#define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
70
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000071/* X context to associate a hwnd to an X window */
72XContext winContext = 0;
73
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +000074/* X context to associate a struct x11drv_win_data to an hwnd */
75static XContext win_data_context;
76
Alexandre Julliardaf50ad62005-07-07 17:30:57 +000077static const char whole_window_prop[] = "__wine_x11_whole_window";
Alexandre Julliard8ee07d42008-02-21 12:29:36 +010078static const char client_window_prop[]= "__wine_x11_client_window";
Alexandre Julliardaf50ad62005-07-07 17:30:57 +000079static const char icon_window_prop[] = "__wine_x11_icon_window";
Chris Robinsond9571c92007-09-15 13:02:32 -070080static const char fbconfig_id_prop[] = "__wine_x11_fbconfig_id";
Chris Robinsona8124f92007-09-25 10:20:58 -070081static const char gl_drawable_prop[] = "__wine_x11_gl_drawable";
Chris Robinson37d835b2007-09-26 08:17:13 -070082static const char pixmap_prop[] = "__wine_x11_pixmap";
Alexandre Julliardaf50ad62005-07-07 17:30:57 +000083static const char managed_prop[] = "__wine_x11_managed";
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +000084
Damjan Jovanovic3613b152009-01-06 20:59:07 +020085
86/***********************************************************************
87 * http://standards.freedesktop.org/startup-notification-spec
88 */
89static void remove_startup_notification(Display *display, Window window)
90{
91 static LONG startup_notification_removed = 0;
92 char id[1024];
93 char message[1024];
94 int i;
95 int pos;
96 XEvent xevent;
97 const char *src;
98 int srclen;
99
100 if (InterlockedCompareExchange(&startup_notification_removed, 1, 0) != 0)
101 return;
102
103 if (GetEnvironmentVariableA("DESKTOP_STARTUP_ID", id, sizeof(id)) == 0)
104 return;
105 SetEnvironmentVariableA("DESKTOP_STARTUP_ID", NULL);
106
107 pos = snprintf(message, sizeof(message), "remove: ID=");
108 message[pos++] = '"';
109 for (i = 0; id[i] && pos < sizeof(message) - 2; i++)
110 {
111 if (id[i] == '"' || id[i] == '\\')
112 message[pos++] = '\\';
113 message[pos++] = id[i];
114 }
115 message[pos++] = '"';
116 message[pos++] = '\0';
117
118 xevent.xclient.type = ClientMessage;
119 xevent.xclient.message_type = x11drv_atom(_NET_STARTUP_INFO_BEGIN);
120 xevent.xclient.display = display;
121 xevent.xclient.window = window;
122 xevent.xclient.format = 8;
123
124 src = message;
125 srclen = strlen(src) + 1;
126
127 wine_tsx11_lock();
128 while (srclen > 0)
129 {
130 int msglen = srclen;
131 if (msglen > 20)
132 msglen = 20;
133 memset(&xevent.xclient.data.b[0], 0, 20);
134 memcpy(&xevent.xclient.data.b[0], src, msglen);
135 src += msglen;
136 srclen -= msglen;
137
138 XSendEvent( display, DefaultRootWindow( display ), False, PropertyChangeMask, &xevent );
139 xevent.xclient.message_type = x11drv_atom(_NET_STARTUP_INFO);
140 }
141 wine_tsx11_unlock();
142}
143
144
Alexandre Julliard391afac2010-02-23 12:34:19 +0100145struct has_popup_result
146{
147 HWND hwnd;
148 BOOL found;
149};
150
151static BOOL CALLBACK has_popup( HWND hwnd, LPARAM lparam )
152{
153 struct has_popup_result *result = (struct has_popup_result *)lparam;
154
155 if (hwnd == result->hwnd) return FALSE; /* popups are always above owner */
156 result->found = (GetWindow( hwnd, GW_OWNER ) == result->hwnd);
157 return !result->found;
158}
159
160static BOOL has_owned_popups( HWND hwnd )
161{
162 struct has_popup_result result;
163
164 result.hwnd = hwnd;
165 result.found = FALSE;
166 EnumWindows( has_popup, (LPARAM)&result );
167 return result.found;
168}
169
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000170/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000171 * is_window_managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000172 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000173 * Check if a given window should be managed
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000174 */
Alexandre Julliard855308f2008-04-23 15:32:58 +0200175static BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rect )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000176{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000177 DWORD style, ex_style;
178
Alexandre Julliard89131822008-01-24 10:21:07 +0100179 if (!managed_mode) return FALSE;
180
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000181 /* child windows are not managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000182 style = GetWindowLongW( hwnd, GWL_STYLE );
Peter Dons Tychsend0b21ab2007-07-25 04:09:50 +0200183 if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) return FALSE;
Alexandre Julliardeffdfa72007-08-27 12:37:14 +0200184 /* activated windows are managed */
185 if (!(swp_flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) return TRUE;
186 if (hwnd == GetActiveWindow()) return TRUE;
Mike Hearn27d972f2003-12-04 21:54:13 +0000187 /* windows with caption are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000188 if ((style & WS_CAPTION) == WS_CAPTION) return TRUE;
Mike Hearn27d972f2003-12-04 21:54:13 +0000189 /* windows with thick frame are managed */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000190 if (style & WS_THICKFRAME) return TRUE;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000191 if (style & WS_POPUP)
Alex Pasadynd18c8ca2004-02-06 05:17:55 +0000192 {
Dmitry Timoshkov15c82062008-10-07 12:14:52 +0900193 HMONITOR hmon;
194 MONITORINFO mi;
195
Vitaliy Margolenabcbcc32007-02-10 10:40:50 -0700196 /* popup with sysmenu == caption are managed */
197 if (style & WS_SYSMENU) return TRUE;
198 /* full-screen popup windows are managed */
Dmitry Timoshkov15c82062008-10-07 12:14:52 +0900199 hmon = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
200 mi.cbSize = sizeof( mi );
201 GetMonitorInfoW( hmon, &mi );
202 if (window_rect->left <= mi.rcWork.left && window_rect->right >= mi.rcWork.right &&
203 window_rect->top <= mi.rcWork.top && window_rect->bottom >= mi.rcWork.bottom)
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000204 return TRUE;
Alex Pasadynd18c8ca2004-02-06 05:17:55 +0000205 }
Alexandre Julliard1f99d802008-04-25 14:26:52 +0200206 /* application windows are managed */
207 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
208 if (ex_style & WS_EX_APPWINDOW) return TRUE;
Alexandre Julliard391afac2010-02-23 12:34:19 +0100209 /* windows that own popups are managed */
210 if (has_owned_popups( hwnd )) return TRUE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000211 /* default: not managed */
212 return FALSE;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000213}
214
215
216/***********************************************************************
Alexandre Julliard2db72e92010-05-28 12:16:17 +0200217 * is_window_rect_mapped
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000218 *
219 * Check if the X whole window should be mapped based on its rectangle
220 */
Alexandre Julliard855308f2008-04-23 15:32:58 +0200221static BOOL is_window_rect_mapped( const RECT *rect )
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000222{
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000223 /* don't map if rect is off-screen */
Alexandre Julliard3c305f92006-10-23 14:37:17 +0200224 if (rect->left >= virtual_screen_rect.right ||
225 rect->top >= virtual_screen_rect.bottom ||
226 rect->right <= virtual_screen_rect.left ||
227 rect->bottom <= virtual_screen_rect.top)
228 return FALSE;
Alexandre Julliard59b7d342004-04-27 23:32:01 +0000229
230 return TRUE;
231}
232
233
234/***********************************************************************
Alexandre Julliard4d14adf2008-04-04 11:25:48 +0200235 * is_window_resizable
236 *
237 * Check if window should be made resizable by the window manager
238 */
239static inline BOOL is_window_resizable( struct x11drv_win_data *data, DWORD style )
240{
241 if (style & WS_THICKFRAME) return TRUE;
242 /* Metacity needs the window to be resizable to make it fullscreen */
243 return (data->whole_rect.left <= 0 && data->whole_rect.right >= screen_width &&
244 data->whole_rect.top <= 0 && data->whole_rect.bottom >= screen_height);
245}
246
247
248/***********************************************************************
Alexandre Julliardc4e20e72007-10-11 12:24:27 +0200249 * get_mwm_decorations
250 */
Dmitry Timoshkov15c0bcb2008-04-16 16:50:29 +0900251static unsigned long get_mwm_decorations( struct x11drv_win_data *data,
252 DWORD style, DWORD ex_style )
Alexandre Julliardc4e20e72007-10-11 12:24:27 +0200253{
254 unsigned long ret = 0;
255
Dmitry Timoshkov15c0bcb2008-04-16 16:50:29 +0900256 if (!decorated_mode) return 0;
257
258 if (IsRectEmpty( &data->window_rect )) return 0;
Alexandre Julliard2bbf00e2008-04-29 12:46:16 +0200259 if (data->shaped) return 0;
Matthew D'Asaro4217fcb2008-04-10 12:53:45 -0700260
Alexandre Julliardc4e20e72007-10-11 12:24:27 +0200261 if (ex_style & WS_EX_TOOLWINDOW) return 0;
262
263 if ((style & WS_CAPTION) == WS_CAPTION)
264 {
265 ret |= MWM_DECOR_TITLE | MWM_DECOR_BORDER;
266 if (style & WS_SYSMENU) ret |= MWM_DECOR_MENU;
267 if (style & WS_MINIMIZEBOX) ret |= MWM_DECOR_MINIMIZE;
268 if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE;
269 }
270 if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER;
271 else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
272 else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER;
Alexandre Julliardc4e20e72007-10-11 12:24:27 +0200273 return ret;
274}
275
276
277/***********************************************************************
278 * get_x11_rect_offset
279 *
280 * Helper for X11DRV_window_to_X_rect and X11DRV_X_to_window_rect.
281 */
282static void get_x11_rect_offset( struct x11drv_win_data *data, RECT *rect )
283{
284 DWORD style, ex_style, style_mask = 0, ex_style_mask = 0;
285 unsigned long decor;
286
287 rect->top = rect->bottom = rect->left = rect->right = 0;
288
289 style = GetWindowLongW( data->hwnd, GWL_STYLE );
290 ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
Dmitry Timoshkov15c0bcb2008-04-16 16:50:29 +0900291 decor = get_mwm_decorations( data, style, ex_style );
Alexandre Julliardc4e20e72007-10-11 12:24:27 +0200292
293 if (decor & MWM_DECOR_TITLE) style_mask |= WS_CAPTION;
294 if (decor & MWM_DECOR_BORDER)
295 {
296 style_mask |= WS_DLGFRAME | WS_THICKFRAME;
297 ex_style_mask |= WS_EX_DLGMODALFRAME;
298 }
299
300 AdjustWindowRectEx( rect, style & style_mask, FALSE, ex_style & ex_style_mask );
301}
302
303
304/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000305 * get_window_attributes
306 *
Alexandre Julliard883cff42001-06-12 04:02:10 +0000307 * Fill the window attributes structure for an X window.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000308 */
Alexandre Julliard6bb18e22006-03-27 15:33:43 +0200309static int get_window_attributes( Display *display, struct x11drv_win_data *data,
310 XSetWindowAttributes *attr )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000311{
Alexandre Julliardd7726c32005-02-01 18:53:59 +0000312 attr->override_redirect = !data->managed;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000313 attr->colormap = X11DRV_PALETTE_PaletteXColormap;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000314 attr->save_under = ((GetClassLongW( data->hwnd, GCL_STYLE ) & CS_SAVEBITS) != 0);
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200315 attr->bit_gravity = NorthWestGravity;
Alexandre Julliard6ba06fa2008-04-23 15:33:29 +0200316 attr->win_gravity = StaticGravity;
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200317 attr->backing_store = NotUseful;
318 attr->event_mask = (ExposureMask | PointerMotionMask |
319 ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
Vincent Povirk538cf8b2008-12-15 18:47:24 -0600320 KeyPressMask | KeyReleaseMask | FocusChangeMask |
321 KeymapStateMask | StructureNotifyMask);
322 if (data->managed) attr->event_mask |= PropertyChangeMask;
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200323
Alexandre Julliardeed9c632010-04-20 20:52:17 +0200324 return (CWOverrideRedirect | CWSaveUnder | CWColormap |
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200325 CWEventMask | CWBitGravity | CWBackingStore);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000326}
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000327
Alexandre Julliard883cff42001-06-12 04:02:10 +0000328
329/***********************************************************************
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100330 * create_client_window
331 */
332static Window create_client_window( Display *display, struct x11drv_win_data *data, XVisualInfo *vis )
333{
334 int cx, cy, mask;
335 XSetWindowAttributes attr;
336 Window client;
Alexandre Julliard30a133f2008-05-13 10:43:48 +0200337 Visual *client_visual = vis ? vis->visual : visual;
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100338
339 attr.bit_gravity = NorthWestGravity;
340 attr.win_gravity = NorthWestGravity;
341 attr.backing_store = NotUseful;
342 attr.event_mask = (ExposureMask | PointerMotionMask |
343 ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
344 mask = CWEventMask | CWBitGravity | CWWinGravity | CWBackingStore;
345
346 if ((cx = data->client_rect.right - data->client_rect.left) <= 0) cx = 1;
Alexandre Julliarda4644f12009-05-05 15:36:25 +0200347 else if (cx > 65535) cx = 65535;
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100348 if ((cy = data->client_rect.bottom - data->client_rect.top) <= 0) cy = 1;
Alexandre Julliarda4644f12009-05-05 15:36:25 +0200349 else if (cy > 65535) cy = 65535;
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100350
351 wine_tsx11_lock();
352
353 if (vis)
354 {
355 attr.colormap = XCreateColormap( display, root_window, vis->visual,
356 (vis->class == PseudoColor || vis->class == GrayScale ||
357 vis->class == DirectColor) ? AllocAll : AllocNone );
358 mask |= CWColormap;
359 }
360
361 client = XCreateWindow( display, data->whole_window,
362 data->client_rect.left - data->whole_rect.left,
363 data->client_rect.top - data->whole_rect.top,
364 cx, cy, 0, screen_depth, InputOutput,
Alexandre Julliard30a133f2008-05-13 10:43:48 +0200365 client_visual, mask, &attr );
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100366 if (!client)
367 {
368 wine_tsx11_unlock();
369 return 0;
370 }
371
372 if (data->client_window)
373 {
374 XDeleteContext( display, data->client_window, winContext );
375 XDestroyWindow( display, data->client_window );
376 }
377 data->client_window = client;
Alexandre Julliard30a133f2008-05-13 10:43:48 +0200378 data->visualid = XVisualIDFromVisual( client_visual );
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100379
380 if (data->colormap) XFreeColormap( display, data->colormap );
381 data->colormap = vis ? attr.colormap : 0;
382
383 XMapWindow( display, data->client_window );
384 XSaveContext( display, data->client_window, winContext, (char *)data->hwnd );
385 wine_tsx11_unlock();
386
387 SetPropA( data->hwnd, client_window_prop, (HANDLE)data->client_window );
388 return data->client_window;
389}
390
391
392/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +0200393 * sync_window_style
Alexandre Julliard883cff42001-06-12 04:02:10 +0000394 *
395 * Change the X window attributes when the window style has changed.
396 */
Alexandre Julliard855308f2008-04-23 15:32:58 +0200397static void sync_window_style( Display *display, struct x11drv_win_data *data )
Alexandre Julliard883cff42001-06-12 04:02:10 +0000398{
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200399 if (data->whole_window != root_window)
400 {
401 XSetWindowAttributes attr;
402 int mask = get_window_attributes( display, data, &attr );
Alexandre Julliard883cff42001-06-12 04:02:10 +0000403
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200404 wine_tsx11_lock();
Alexandre Julliard6d5f5442006-03-06 21:02:59 +0100405 XChangeWindowAttributes( display, data->whole_window, mask, &attr );
Alexandre Julliard0ce71872007-08-20 14:23:10 +0200406 wine_tsx11_unlock();
407 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000408}
409
410
411/***********************************************************************
Alexandre Julliard1afd0df2010-05-10 12:33:59 +0200412 * sync_window_cursor
413 */
414static void sync_window_cursor( struct x11drv_win_data *data )
415{
416 HCURSOR cursor;
417
418 SERVER_START_REQ( set_cursor )
419 {
420 req->flags = 0;
421 wine_server_call( req );
422 cursor = reply->prev_count >= 0 ? wine_server_ptr_handle( reply->prev_handle ) : 0;
423 }
424 SERVER_END_REQ;
425
426 set_window_cursor( data->hwnd, cursor );
427}
428
429
430/***********************************************************************
Alexandre Julliard395928d2008-01-23 16:30:18 +0100431 * sync_window_region
432 *
433 * Update the X11 window region.
434 */
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +0200435static void sync_window_region( Display *display, struct x11drv_win_data *data, HRGN win_region )
Alexandre Julliard395928d2008-01-23 16:30:18 +0100436{
437#ifdef HAVE_LIBXSHAPE
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +0200438 HRGN hrgn = win_region;
439
Alexandre Julliard395928d2008-01-23 16:30:18 +0100440 if (!data->whole_window) return;
Alexandre Julliard2bbf00e2008-04-29 12:46:16 +0200441 data->shaped = FALSE;
Alexandre Julliard395928d2008-01-23 16:30:18 +0100442
Alexandre Julliard61e50e12010-05-28 12:14:43 +0200443 if (IsRectEmpty( &data->window_rect )) /* set an empty shape */
444 {
445 static XRectangle empty_rect;
446 wine_tsx11_lock();
447 XShapeCombineRectangles( display, data->whole_window, ShapeBounding, 0, 0,
448 &empty_rect, 1, ShapeSet, YXBanded );
449 wine_tsx11_unlock();
450 return;
451 }
452
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +0200453 if (hrgn == (HRGN)1) /* hack: win_region == 1 means retrieve region from server */
454 {
455 if (!(hrgn = CreateRectRgn( 0, 0, 0, 0 ))) return;
456 if (GetWindowRgn( data->hwnd, hrgn ) == ERROR)
457 {
458 DeleteObject( hrgn );
459 hrgn = 0;
460 }
461 }
462
Alexandre Julliard395928d2008-01-23 16:30:18 +0100463 if (!hrgn)
464 {
465 wine_tsx11_lock();
466 XShapeCombineMask( display, data->whole_window, ShapeBounding, 0, 0, None, ShapeSet );
467 wine_tsx11_unlock();
468 }
469 else
470 {
471 RGNDATA *pRegionData = X11DRV_GetRegionData( hrgn, 0 );
472 if (pRegionData)
473 {
474 wine_tsx11_lock();
475 XShapeCombineRectangles( display, data->whole_window, ShapeBounding,
476 data->window_rect.left - data->whole_rect.left,
477 data->window_rect.top - data->whole_rect.top,
478 (XRectangle *)pRegionData->Buffer,
479 pRegionData->rdh.nCount, ShapeSet, YXBanded );
480 wine_tsx11_unlock();
481 HeapFree(GetProcessHeap(), 0, pRegionData);
Alexandre Julliard2bbf00e2008-04-29 12:46:16 +0200482 data->shaped = TRUE;
Alexandre Julliard395928d2008-01-23 16:30:18 +0100483 }
484 }
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +0200485 if (hrgn && hrgn != win_region) DeleteObject( hrgn );
Alexandre Julliard395928d2008-01-23 16:30:18 +0100486#endif /* HAVE_LIBXSHAPE */
487}
488
489
490/***********************************************************************
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +0200491 * sync_window_opacity
492 */
493static void sync_window_opacity( Display *display, Window win,
494 COLORREF key, BYTE alpha, DWORD flags )
495{
496 unsigned long opacity = 0xffffffff;
497
498 if (flags & LWA_ALPHA) opacity = (0xffffffff / 0xff) * alpha;
499
500 if (flags & LWA_COLORKEY) FIXME("LWA_COLORKEY not supported\n");
501
502 wine_tsx11_lock();
503 if (opacity == 0xffffffff)
504 XDeleteProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY) );
505 else
506 XChangeProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY),
507 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1 );
508 wine_tsx11_unlock();
509}
510
511
512/***********************************************************************
Alexandre Julliard3ba20252008-01-23 16:32:55 +0100513 * sync_window_text
514 */
515static void sync_window_text( Display *display, Window win, const WCHAR *text )
516{
517 UINT count;
518 char *buffer, *utf8_buffer;
519 XTextProperty prop;
520
521 /* allocate new buffer for window text */
522 count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL);
523 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count ))) return;
524 WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL);
525
526 count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
527 if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count )))
528 {
529 HeapFree( GetProcessHeap(), 0, buffer );
530 return;
531 }
532 WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
533
534 wine_tsx11_lock();
535 if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success)
536 {
537 XSetWMName( display, win, &prop );
538 XSetWMIconName( display, win, &prop );
539 XFree( prop.value );
540 }
541 /*
542 Implements a NET_WM UTF-8 title. It should be without a trailing \0,
543 according to the standard
544 ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
545 */
546 XChangeProperty( display, win, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING),
547 8, PropModeReplace, (unsigned char *) utf8_buffer, count);
548 wine_tsx11_unlock();
549
550 HeapFree( GetProcessHeap(), 0, utf8_buffer );
551 HeapFree( GetProcessHeap(), 0, buffer );
552}
553
554
555/***********************************************************************
Alexandre Julliard370368a2008-09-08 15:42:24 +0200556 * set_win_format
Chris Robinsond9571c92007-09-15 13:02:32 -0700557 */
Alexandre Julliard370368a2008-09-08 15:42:24 +0200558static BOOL set_win_format( HWND hwnd, XID fbconfig_id )
Chris Robinsond9571c92007-09-15 13:02:32 -0700559{
560 struct x11drv_win_data *data;
Chris Robinson00633e32007-09-25 22:43:38 -0700561 XVisualInfo *vis;
Chris Robinson00633e32007-09-25 22:43:38 -0700562 int w, h;
Chris Robinsond9571c92007-09-15 13:02:32 -0700563
Alexandre Julliard026974f2008-01-24 10:20:51 +0100564 if (!(data = X11DRV_get_win_data(hwnd)) &&
565 !(data = X11DRV_create_win_data(hwnd))) return FALSE;
Chris Robinsond9571c92007-09-15 13:02:32 -0700566
Alexandre Julliarded371742008-05-28 17:02:07 +0200567 if (!(vis = visual_from_fbconfig_id(fbconfig_id))) return FALSE;
Chris Robinson00633e32007-09-25 22:43:38 -0700568
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100569 if (data->whole_window)
Chris Robinson00633e32007-09-25 22:43:38 -0700570 {
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200571 Display *display = thread_display();
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100572 Window client = data->client_window;
573
Alexandre Julliard30a133f2008-05-13 10:43:48 +0200574 if (vis->visualid != data->visualid)
Chris Robinson00633e32007-09-25 22:43:38 -0700575 {
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100576 client = create_client_window( display, data, vis );
577 TRACE( "re-created client window %lx for %p fbconfig %lx\n", client, data->hwnd, fbconfig_id );
Chris Robinson00633e32007-09-25 22:43:38 -0700578 }
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100579 wine_tsx11_lock();
580 XFree(vis);
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200581 XFlush( display );
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100582 wine_tsx11_unlock();
583 if (client) goto done;
584 return FALSE;
Chris Robinson00633e32007-09-25 22:43:38 -0700585 }
586
587 w = data->client_rect.right - data->client_rect.left;
588 h = data->client_rect.bottom - data->client_rect.top;
589
590 if(w <= 0) w = 1;
591 if(h <= 0) h = 1;
592
Chris Robinson00633e32007-09-25 22:43:38 -0700593#ifdef SONAME_LIBXCOMPOSITE
594 if(usexcomposite)
595 {
596 XSetWindowAttributes attrib;
Alexandre Julliardb6059802008-05-12 19:14:11 +0200597 static Window dummy_parent;
Chris Robinson00633e32007-09-25 22:43:38 -0700598
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100599 wine_tsx11_lock();
Alexandre Julliardb6059802008-05-12 19:14:11 +0200600 attrib.override_redirect = True;
601 if (!dummy_parent)
602 {
603 dummy_parent = XCreateWindow( gdi_display, root_window, -1, -1, 1, 1, 0, screen_depth,
604 InputOutput, visual, CWOverrideRedirect, &attrib );
605 XMapWindow( gdi_display, dummy_parent );
606 }
607 data->colormap = XCreateColormap(gdi_display, dummy_parent, vis->visual,
Alexandre Julliarde9307d02008-02-21 20:23:32 +0100608 (vis->class == PseudoColor ||
609 vis->class == GrayScale ||
610 vis->class == DirectColor) ?
611 AllocAll : AllocNone);
Alexandre Julliarde9307d02008-02-21 20:23:32 +0100612 attrib.colormap = data->colormap;
Chris Robinson00633e32007-09-25 22:43:38 -0700613 XInstallColormap(gdi_display, attrib.colormap);
614
Roderick Colenbranderf0307d92008-04-22 22:15:15 +0000615 if(data->gl_drawable) XDestroyWindow(gdi_display, data->gl_drawable);
Alexandre Julliardb6059802008-05-12 19:14:11 +0200616 data->gl_drawable = XCreateWindow(gdi_display, dummy_parent, -w, 0, w, h, 0,
Chris Robinson00633e32007-09-25 22:43:38 -0700617 vis->depth, InputOutput, vis->visual,
618 CWColormap | CWOverrideRedirect,
619 &attrib);
620 if(data->gl_drawable)
621 {
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200622 pXCompositeRedirectWindow(gdi_display, data->gl_drawable,
Chris Robinson00633e32007-09-25 22:43:38 -0700623 CompositeRedirectManual);
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200624 XMapWindow(gdi_display, data->gl_drawable);
Chris Robinson00633e32007-09-25 22:43:38 -0700625 }
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100626 XFree(vis);
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200627 XFlush( gdi_display );
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100628 wine_tsx11_unlock();
Chris Robinson00633e32007-09-25 22:43:38 -0700629 }
Chris Robinson37d835b2007-09-26 08:17:13 -0700630 else
Chris Robinson00633e32007-09-25 22:43:38 -0700631#endif
Chris Robinson37d835b2007-09-26 08:17:13 -0700632 {
633 WARN("XComposite is not available, using GLXPixmap hack\n");
634
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100635 wine_tsx11_lock();
Roderick Colenbranderf0307d92008-04-22 22:15:15 +0000636
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200637 if(data->pixmap) XFreePixmap(gdi_display, data->pixmap);
638 data->pixmap = XCreatePixmap(gdi_display, root_window, w, h, vis->depth);
Chris Robinson37d835b2007-09-26 08:17:13 -0700639 if(!data->pixmap)
640 {
Chris Robinson37d835b2007-09-26 08:17:13 -0700641 XFree(vis);
642 wine_tsx11_unlock();
643 return FALSE;
644 }
645
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200646 if(data->gl_drawable) destroy_glxpixmap(gdi_display, data->gl_drawable);
647 data->gl_drawable = create_glxpixmap(gdi_display, vis, data->pixmap);
Chris Robinson37d835b2007-09-26 08:17:13 -0700648 if(!data->gl_drawable)
649 {
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200650 XFreePixmap(gdi_display, data->pixmap);
Chris Robinson37d835b2007-09-26 08:17:13 -0700651 data->pixmap = 0;
652 }
Chris Robinson00633e32007-09-25 22:43:38 -0700653 XFree(vis);
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200654 XFlush( gdi_display );
Chris Robinson00633e32007-09-25 22:43:38 -0700655 wine_tsx11_unlock();
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100656 if (data->pixmap) SetPropA(hwnd, pixmap_prop, (HANDLE)data->pixmap);
Chris Robinson00633e32007-09-25 22:43:38 -0700657 }
658
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100659 if (!data->gl_drawable) return FALSE;
Chris Robinson00633e32007-09-25 22:43:38 -0700660
661 TRACE("Created GL drawable 0x%lx, using FBConfigID 0x%lx\n",
662 data->gl_drawable, fbconfig_id);
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100663 SetPropA(hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
Chris Robinson00633e32007-09-25 22:43:38 -0700664
Alexandre Julliard42ad3452008-02-22 10:40:22 +0100665done:
Chris Robinsond9571c92007-09-15 13:02:32 -0700666 data->fbconfig_id = fbconfig_id;
667 SetPropA(hwnd, fbconfig_id_prop, (HANDLE)data->fbconfig_id);
Alexandre Julliard9727aa82008-04-21 20:32:22 +0200668 /* force DCE invalidation */
669 SetWindowPos( hwnd, 0, 0, 0, 0, 0,
670 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
Alexandre Julliardfc8c21c2008-06-18 20:10:56 +0200671 SWP_NOREDRAW | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_STATECHANGED);
Chris Robinsond9571c92007-09-15 13:02:32 -0700672 return TRUE;
673}
674
Alexandre Julliardbbfbe242008-01-23 12:28:01 +0100675/***********************************************************************
Alexandre Julliard8ee07d42008-02-21 12:29:36 +0100676 * sync_gl_drawable
Alexandre Julliardbbfbe242008-01-23 12:28:01 +0100677 */
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200678static void sync_gl_drawable(struct x11drv_win_data *data)
Chris Robinson00633e32007-09-25 22:43:38 -0700679{
680 int w = data->client_rect.right - data->client_rect.left;
681 int h = data->client_rect.bottom - data->client_rect.top;
Chris Robinson37d835b2007-09-26 08:17:13 -0700682 XVisualInfo *vis;
Chris Robinson37d835b2007-09-26 08:17:13 -0700683 Drawable glxp;
684 Pixmap pix;
Chris Robinson00633e32007-09-25 22:43:38 -0700685
Alexandre Julliardf13ef6b2008-02-22 16:30:10 +0100686 if (w <= 0) w = 1;
687 if (h <= 0) h = 1;
688
Chris Robinson00633e32007-09-25 22:43:38 -0700689 TRACE("Resizing GL drawable 0x%lx to %dx%d\n", data->gl_drawable, w, h);
690#ifdef SONAME_LIBXCOMPOSITE
691 if(usexcomposite)
692 {
693 wine_tsx11_lock();
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200694 XMoveResizeWindow(gdi_display, data->gl_drawable, -w, 0, w, h);
Chris Robinson00633e32007-09-25 22:43:38 -0700695 wine_tsx11_unlock();
696 return;
697 }
698#endif
Chris Robinson37d835b2007-09-26 08:17:13 -0700699
Alexandre Julliarded371742008-05-28 17:02:07 +0200700 if (!(vis = visual_from_fbconfig_id(data->fbconfig_id))) return;
701
Chris Robinson37d835b2007-09-26 08:17:13 -0700702 wine_tsx11_lock();
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200703 pix = XCreatePixmap(gdi_display, root_window, w, h, vis->depth);
Chris Robinson37d835b2007-09-26 08:17:13 -0700704 if(!pix)
705 {
706 ERR("Failed to create pixmap for offscreen rendering\n");
707 XFree(vis);
708 wine_tsx11_unlock();
709 return;
710 }
711
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200712 glxp = create_glxpixmap(gdi_display, vis, pix);
Chris Robinson37d835b2007-09-26 08:17:13 -0700713 if(!glxp)
714 {
715 ERR("Failed to create drawable for offscreen rendering\n");
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200716 XFreePixmap(gdi_display, pix);
Chris Robinson37d835b2007-09-26 08:17:13 -0700717 XFree(vis);
718 wine_tsx11_unlock();
719 return;
720 }
721
722 XFree(vis);
723
724 mark_drawable_dirty(data->gl_drawable, glxp);
725
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200726 XFreePixmap(gdi_display, data->pixmap);
727 destroy_glxpixmap(gdi_display, data->gl_drawable);
Alexandre Julliard9727aa82008-04-21 20:32:22 +0200728 TRACE( "Recreated GL drawable %lx to replace %lx\n", glxp, data->gl_drawable );
Chris Robinson37d835b2007-09-26 08:17:13 -0700729
730 data->pixmap = pix;
731 data->gl_drawable = glxp;
732
Alexandre Julliard6e9dea82008-05-12 19:37:54 +0200733 XFlush( gdi_display );
Chris Robinson37d835b2007-09-26 08:17:13 -0700734 wine_tsx11_unlock();
735
736 SetPropA(data->hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
737 SetPropA(data->hwnd, pixmap_prop, (HANDLE)data->pixmap);
Chris Robinson00633e32007-09-25 22:43:38 -0700738}
739
Chris Robinsond9571c92007-09-15 13:02:32 -0700740
741/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000742 * get_window_changes
743 *
744 * fill the window changes structure
745 */
746static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
747{
748 int mask = 0;
749
750 if (old->right - old->left != new->right - new->left )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000751 {
Alexandre Julliard8ee07d42008-02-21 12:29:36 +0100752 if ((changes->width = new->right - new->left) <= 0) changes->width = 1;
Alexandre Julliarda4644f12009-05-05 15:36:25 +0200753 else if (changes->width > 65535) changes->width = 65535;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000754 mask |= CWWidth;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000755 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000756 if (old->bottom - old->top != new->bottom - new->top)
757 {
Alexandre Julliard8ee07d42008-02-21 12:29:36 +0100758 if ((changes->height = new->bottom - new->top) <= 0) changes->height = 1;
Alexandre Julliarda4644f12009-05-05 15:36:25 +0200759 else if (changes->height > 65535) changes->height = 65535;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000760 mask |= CWHeight;
761 }
762 if (old->left != new->left)
763 {
764 changes->x = new->left;
765 mask |= CWX;
766 }
767 if (old->top != new->top)
768 {
769 changes->y = new->top;
770 mask |= CWY;
771 }
772 return mask;
773}
774
775
776/***********************************************************************
777 * create_icon_window
778 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000779static Window create_icon_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000780{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000781 XSetWindowAttributes attr;
782
783 attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
Alexandre Julliard9428f062002-06-14 00:08:40 +0000784 ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000785 attr.bit_gravity = NorthWestGravity;
786 attr.backing_store = NotUseful/*WhenMapped*/;
Lionel Ulmer1fc39be2001-07-12 22:27:56 +0000787 attr.colormap = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000788
Alexandre Julliard649637f2001-06-26 21:10:11 +0000789 wine_tsx11_lock();
790 data->icon_window = XCreateWindow( display, root_window, 0, 0,
791 GetSystemMetrics( SM_CXICON ),
792 GetSystemMetrics( SM_CYICON ),
793 0, screen_depth,
794 InputOutput, visual,
Lionel Ulmer1fc39be2001-07-12 22:27:56 +0000795 CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000796 XSaveContext( display, data->icon_window, winContext, (char *)data->hwnd );
Alexandre Julliard731d77f2008-04-09 20:24:27 +0200797 XFlush( display ); /* make sure the window exists before we start painting to it */
Alexandre Julliard649637f2001-06-26 21:10:11 +0000798 wine_tsx11_unlock();
799
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000800 TRACE( "created %lx\n", data->icon_window );
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000801 SetPropA( data->hwnd, icon_window_prop, (HANDLE)data->icon_window );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000802 return data->icon_window;
803}
804
805
806
807/***********************************************************************
808 * destroy_icon_window
809 */
Alexandre Julliardf777d702005-01-31 16:34:07 +0000810static void destroy_icon_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000811{
812 if (!data->icon_window) return;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000813 wine_tsx11_lock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000814 XDeleteContext( display, data->icon_window, winContext );
815 XDestroyWindow( display, data->icon_window );
816 data->icon_window = 0;
Alexandre Julliard704d0352001-07-12 02:49:31 +0000817 wine_tsx11_unlock();
Alexandre Julliardaf50ad62005-07-07 17:30:57 +0000818 RemovePropA( data->hwnd, icon_window_prop );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000819}
820
821
822/***********************************************************************
Alexandre Julliard42531202010-04-19 11:13:34 +0200823 * get_bitmap_argb
824 *
825 * Return the bitmap bits in ARGB format. Helper for setting icon hints.
826 */
827static unsigned long *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *size )
828{
829 BITMAP bm;
830 BITMAPINFO *info;
Alexandre Julliardf0644c62010-04-19 14:49:26 +0200831 unsigned int *ptr, *bits = NULL;
832 unsigned char *mask_bits = NULL;
833 int i, j, has_alpha = 0;
Alexandre Julliard42531202010-04-19 11:13:34 +0200834
835 if (!GetObjectW( color, sizeof(bm), &bm )) return NULL;
836 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return NULL;
837 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
838 info->bmiHeader.biWidth = bm.bmWidth;
839 info->bmiHeader.biHeight = -bm.bmHeight;
840 info->bmiHeader.biPlanes = 1;
841 info->bmiHeader.biBitCount = 32;
842 info->bmiHeader.biCompression = BI_RGB;
843 info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
844 info->bmiHeader.biXPelsPerMeter = 0;
845 info->bmiHeader.biYPelsPerMeter = 0;
846 info->bmiHeader.biClrUsed = 0;
847 info->bmiHeader.biClrImportant = 0;
848 *size = bm.bmWidth * bm.bmHeight + 2;
849 if (!(bits = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(long) ))) goto failed;
850 if (!GetDIBits( hdc, color, 0, bm.bmHeight, bits + 2, info, DIB_RGB_COLORS )) goto failed;
851
852 bits[0] = bm.bmWidth;
853 bits[1] = bm.bmHeight;
854
Alexandre Julliardf0644c62010-04-19 14:49:26 +0200855 for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
856 if ((has_alpha = (bits[i + 2] & 0xff000000) != 0)) break;
857
858 if (!has_alpha)
859 {
860 unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
861 /* generate alpha channel from the mask */
862 info->bmiHeader.biBitCount = 1;
863 info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
864 if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto failed;
865 if (!GetDIBits( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS )) goto failed;
866 ptr = bits + 2;
867 for (i = 0; i < bm.bmHeight; i++)
868 for (j = 0; j < bm.bmWidth; j++, ptr++)
Alexandre Julliard9ff982f2010-04-22 14:16:44 +0200869 if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
Alexandre Julliardf84f9392010-04-20 13:55:11 +0200870 HeapFree( GetProcessHeap(), 0, mask_bits );
Alexandre Julliardf0644c62010-04-19 14:49:26 +0200871 }
Alexandre Julliardf84f9392010-04-20 13:55:11 +0200872 HeapFree( GetProcessHeap(), 0, info );
Alexandre Julliardf0644c62010-04-19 14:49:26 +0200873
Alexandre Julliard42531202010-04-19 11:13:34 +0200874 /* convert to array of longs */
875 if (bits && sizeof(long) > sizeof(int))
876 for (i = *size - 1; i >= 0; i--) ((unsigned long *)bits)[i] = bits[i];
877
878 return (unsigned long *)bits;
879
880failed:
881 HeapFree( GetProcessHeap(), 0, info );
882 HeapFree( GetProcessHeap(), 0, bits );
Alexandre Julliardf0644c62010-04-19 14:49:26 +0200883 HeapFree( GetProcessHeap(), 0, mask_bits );
Alexandre Julliard42531202010-04-19 11:13:34 +0200884 return NULL;
885}
886
887
888/***********************************************************************
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000889 * set_icon_hints
890 *
891 * Set the icon wm hints
892 */
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200893static void set_icon_hints( Display *display, struct x11drv_win_data *data,
894 HICON icon_big, HICON icon_small )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000895{
Alexandre Julliardbde89572007-08-16 23:27:37 +0200896 XWMHints *hints = data->wm_hints;
897
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200898 if (!icon_big)
899 {
900 icon_big = (HICON)SendMessageW( data->hwnd, WM_GETICON, ICON_BIG, 0 );
901 if (!icon_big) icon_big = (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICON );
902 }
903 if (!icon_small)
904 {
905 icon_small = (HICON)SendMessageW( data->hwnd, WM_GETICON, ICON_SMALL, 0 );
906 if (!icon_small) icon_small = (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICONSM );
907 }
908
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000909 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
910 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliard883cff42001-06-12 04:02:10 +0000911 data->hWMIconBitmap = 0;
912 data->hWMIconMask = 0;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000913
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200914 if (!icon_big)
Alexandre Julliard883cff42001-06-12 04:02:10 +0000915 {
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000916 if (!data->icon_window) create_icon_window( display, data );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000917 hints->icon_window = data->icon_window;
918 hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000919 }
920 else
921 {
922 HBITMAP hbmOrig;
923 RECT rcMask;
Alexandre Julliardea1d71c2010-04-16 16:23:33 +0200924 BITMAP bm;
Alexandre Julliard0d84ccb2010-05-20 17:37:28 +0200925 ICONINFO ii, ii_small;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000926 HDC hDC;
Alexandre Julliard42531202010-04-19 11:13:34 +0200927 unsigned int size;
928 unsigned long *bits;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000929
Alexandre Julliard0d84ccb2010-05-20 17:37:28 +0200930 if (!GetIconInfo(icon_big, &ii)) return;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000931
Alexandre Julliardea1d71c2010-04-16 16:23:33 +0200932 GetObjectW(ii.hbmMask, sizeof(bm), &bm);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000933 rcMask.top = 0;
934 rcMask.left = 0;
Alexandre Julliardea1d71c2010-04-16 16:23:33 +0200935 rcMask.right = bm.bmWidth;
936 rcMask.bottom = bm.bmHeight;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000937
938 hDC = CreateCompatibleDC(0);
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200939 bits = get_bitmap_argb( hDC, ii.hbmColor, ii.hbmMask, &size );
Alexandre Julliard0d84ccb2010-05-20 17:37:28 +0200940 if (bits && GetIconInfo( icon_small, &ii_small ))
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200941 {
942 unsigned int size_small;
943 unsigned long *bits_small, *new;
944
Alexandre Julliard0d84ccb2010-05-20 17:37:28 +0200945 if ((bits_small = get_bitmap_argb( hDC, ii_small.hbmColor, ii_small.hbmMask, &size_small )) &&
Alexandre Julliard09dc6012010-04-22 14:47:57 +0200946 (bits_small[0] != bits[0] || bits_small[1] != bits[1])) /* size must be different */
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200947 {
948 if ((new = HeapReAlloc( GetProcessHeap(), 0, bits,
949 (size + size_small) * sizeof(unsigned long) )))
950 {
951 bits = new;
952 memcpy( bits + size, bits_small, size_small * sizeof(unsigned long) );
953 size += size_small;
954 }
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200955 }
Alexandre Julliard09dc6012010-04-22 14:47:57 +0200956 HeapFree( GetProcessHeap(), 0, bits_small );
Alexandre Julliard0d84ccb2010-05-20 17:37:28 +0200957 DeleteObject( ii_small.hbmColor );
958 DeleteObject( ii_small.hbmMask );
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200959 }
960 wine_tsx11_lock();
961 if (bits)
962 XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_ICON),
963 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)bits, size );
964 else
965 XDeleteProperty( display, data->whole_window, x11drv_atom(_NET_WM_ICON) );
966 wine_tsx11_unlock();
967 HeapFree( GetProcessHeap(), 0, bits );
968
Alexandre Julliard9ff982f2010-04-22 14:16:44 +0200969 hbmOrig = SelectObject(hDC, ii.hbmMask);
970 InvertRect(hDC, &rcMask);
971 SelectObject(hDC, ii.hbmColor); /* force the color bitmap to x11drv mode too */
972 SelectObject(hDC, hbmOrig);
973
974 data->hWMIconBitmap = ii.hbmColor;
975 data->hWMIconMask = ii.hbmMask;
976
977 hints->icon_pixmap = X11DRV_get_pixmap(data->hWMIconBitmap);
978 hints->icon_mask = X11DRV_get_pixmap(data->hWMIconMask);
979 destroy_icon_window( display, data );
980 hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
981
Alexandre Julliarda551dfe2010-04-19 17:51:44 +0200982 DeleteDC(hDC);
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000983 }
984}
985
986
987/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000988 * set_size_hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000989 *
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000990 * set the window size hints
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000991 */
Alexandre Julliardfc5ce142005-01-17 19:17:47 +0000992static void set_size_hints( Display *display, struct x11drv_win_data *data, DWORD style )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +0000993{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000994 XSizeHints* size_hints;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +0000995
Alexandre Julliardcf9d3e32008-04-04 11:28:30 +0200996 if (!(size_hints = XAllocSizeHints())) return;
Alexandre Julliardba1517f2006-03-27 22:16:04 +0200997
Alexandre Julliard6ba06fa2008-04-23 15:33:29 +0200998 size_hints->win_gravity = StaticGravity;
999 size_hints->flags |= PWinGravity;
1000
Alexandre Julliardcf9d3e32008-04-04 11:28:30 +02001001 /* don't update size hints if window is not in normal state */
1002 if (!(style & (WS_MINIMIZE | WS_MAXIMIZE)))
1003 {
Alexandre Julliardba1517f2006-03-27 22:16:04 +02001004 if (data->hwnd != GetDesktopWindow()) /* don't force position of desktop */
1005 {
Alexandre Julliardba1517f2006-03-27 22:16:04 +02001006 size_hints->x = data->whole_rect.left;
1007 size_hints->y = data->whole_rect.top;
Alexandre Julliard6ba06fa2008-04-23 15:33:29 +02001008 size_hints->flags |= PPosition;
Alexandre Julliardba1517f2006-03-27 22:16:04 +02001009 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001010
Alexandre Julliard4d14adf2008-04-04 11:25:48 +02001011 if (!is_window_resizable( data, style ))
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001012 {
Alexandre Julliard4d14adf2008-04-04 11:25:48 +02001013 size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
1014 size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
Alexandre Julliard81c4b412010-05-28 12:13:01 +02001015 if (size_hints->max_width <= 0 ||size_hints->max_height <= 0)
1016 size_hints->max_width = size_hints->max_height = 1;
Alexandre Julliard4d14adf2008-04-04 11:25:48 +02001017 size_hints->min_width = size_hints->max_width;
1018 size_hints->min_height = size_hints->max_height;
1019 size_hints->flags |= PMinSize | PMaxSize;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001020 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001021 }
Alexandre Julliardcf9d3e32008-04-04 11:28:30 +02001022 XSetWMNormalHints( display, data->whole_window, size_hints );
1023 XFree( size_hints );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001024}
1025
1026
1027/***********************************************************************
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +00001028 * get_process_name
1029 *
1030 * get the name of the current process for setting class hints
1031 */
1032static char *get_process_name(void)
1033{
1034 static char *name;
1035
1036 if (!name)
1037 {
1038 WCHAR module[MAX_PATH];
1039 DWORD len = GetModuleFileNameW( 0, module, MAX_PATH );
1040 if (len && len < MAX_PATH)
1041 {
1042 char *ptr;
1043 WCHAR *p, *appname = module;
1044
1045 if ((p = strrchrW( appname, '/' ))) appname = p + 1;
1046 if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
1047 len = WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, NULL, 0, NULL, NULL );
1048 if ((ptr = HeapAlloc( GetProcessHeap(), 0, len )))
1049 {
1050 WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, ptr, len, NULL, NULL );
1051 name = ptr;
1052 }
1053 }
1054 }
1055 return name;
1056}
1057
1058
1059/***********************************************************************
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001060 * set_initial_wm_hints
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001061 *
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001062 * Set the window manager hints that don't change over the lifetime of a window.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001063 */
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001064static void set_initial_wm_hints( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001065{
Alexandre Julliard3bfa90e2008-04-07 11:41:54 +02001066 long i;
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001067 Atom protocols[3];
Kusanagi Kouichi10789142010-02-20 17:57:07 +09001068 Atom dndVersion = WINE_XDND_VERSION;
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001069 XClassHint *class_hints;
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +00001070 char *process_name = get_process_name();
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001071
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001072 wine_tsx11_lock();
1073
1074 /* wm protocols */
1075 i = 0;
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001076 protocols[i++] = x11drv_atom(WM_DELETE_WINDOW);
1077 protocols[i++] = x11drv_atom(_NET_WM_PING);
1078 if (use_take_focus) protocols[i++] = x11drv_atom(WM_TAKE_FOCUS);
1079 XChangeProperty( display, data->whole_window, x11drv_atom(WM_PROTOCOLS),
Hans Leidekkerac147fe2005-03-22 21:17:34 +00001080 XA_ATOM, 32, PropModeReplace, (unsigned char *)protocols, i );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001081
1082 /* class hints */
1083 if ((class_hints = XAllocClassHint()))
1084 {
Andrew Talbot55e20a72006-06-26 20:56:16 +01001085 static char wine[] = "Wine";
1086
Alexandre Julliardc7dbffc2005-07-01 16:16:00 +00001087 class_hints->res_name = process_name;
Andrew Talbot55e20a72006-06-26 20:56:16 +01001088 class_hints->res_class = wine;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001089 XSetClassHint( display, data->whole_window, class_hints );
1090 XFree( class_hints );
1091 }
1092
Mike Hearn34dd4552003-05-04 02:27:20 +00001093 /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */
1094 XSetWMProperties(display, data->whole_window, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1095 /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */
1096 i = getpid();
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001097 XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_PID),
Hans Leidekkerac147fe2005-03-22 21:17:34 +00001098 XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&i, 1);
Ove Kaaven77e7fd72002-01-21 18:41:27 +00001099
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001100 XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
1101 XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
1102
Alexandre Julliarddc07b6f2008-01-22 10:17:52 +01001103 data->wm_hints = XAllocWMHints();
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001104 wine_tsx11_unlock();
Alexandre Julliard6a23bd82008-01-18 14:34:57 +01001105
1106 if (data->wm_hints)
1107 {
1108 data->wm_hints->flags = 0;
Alexandre Julliarda551dfe2010-04-19 17:51:44 +02001109 set_icon_hints( display, data, 0, 0 );
Alexandre Julliard6a23bd82008-01-18 14:34:57 +01001110 }
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001111}
1112
1113
1114/***********************************************************************
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001115 * get_owner_whole_window
1116 *
1117 * Retrieve an owner's window, creating it if necessary.
1118 */
Alexandre Julliardb6ef8a52010-03-20 20:16:42 +01001119static Window get_owner_whole_window( HWND owner, BOOL force_managed )
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001120{
1121 struct x11drv_win_data *data;
1122
1123 if (!owner) return 0;
1124
1125 if (!(data = X11DRV_get_win_data( owner )))
1126 {
Alexandre Julliard9cd1ce22010-03-01 17:06:19 +01001127 if (GetWindowThreadProcessId( owner, NULL ) != GetCurrentThreadId() ||
1128 !(data = X11DRV_create_win_data( owner )))
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001129 return (Window)GetPropA( owner, whole_window_prop );
1130 }
Alexandre Julliardb6ef8a52010-03-20 20:16:42 +01001131 else if (!data->managed && force_managed) /* make it managed */
Alexandre Julliard913cab12010-02-23 12:35:10 +01001132 {
1133 SetWindowPos( owner, 0, 0, 0, 0, 0,
1134 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
1135 SWP_NOREDRAW | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_STATECHANGED );
1136 }
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001137 return data->whole_window;
1138}
1139
1140
1141/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +02001142 * set_wm_hints
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001143 *
1144 * Set the window manager hints for a newly-created window
1145 */
Alexandre Julliard855308f2008-04-23 15:32:58 +02001146static void set_wm_hints( Display *display, struct x11drv_win_data *data )
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001147{
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001148 Window group_leader = data->whole_window;
1149 Window owner_win = 0;
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001150 Atom window_type;
1151 MwmHints mwm_hints;
Alexandre Julliard18f4fb92008-04-14 13:27:38 +02001152 DWORD style, ex_style;
1153 HWND owner;
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001154
1155 if (data->hwnd == GetDesktopWindow())
1156 {
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001157 /* force some styles for the desktop to get the correct decorations */
Alexandre Julliard18f4fb92008-04-14 13:27:38 +02001158 style = WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1159 ex_style = WS_EX_APPWINDOW;
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001160 owner = 0;
1161 }
Alexandre Julliard18f4fb92008-04-14 13:27:38 +02001162 else
1163 {
1164 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1165 ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
Alexandre Julliard61e50e12010-05-28 12:14:43 +02001166 owner = GetWindow( data->hwnd, GW_OWNER );
Alexandre Julliardb6ef8a52010-03-20 20:16:42 +01001167 if ((owner_win = get_owner_whole_window( owner, data->managed ))) group_leader = owner_win;
Alexandre Julliard18f4fb92008-04-14 13:27:38 +02001168 }
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001169
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001170 wine_tsx11_lock();
1171
Alexandre Julliard7b3a00c2010-02-23 12:33:01 +01001172 if (owner_win) XSetTransientForHint( display, data->whole_window, owner_win );
1173
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001174 /* size hints */
1175 set_size_hints( display, data, style );
1176
Nickolay V. Shmyrev1a1b9022006-10-11 19:32:22 +04001177 /* set the WM_WINDOW_TYPE */
Dmitry Timoshkov751a71a2008-04-07 13:37:44 +09001178 if (style & WS_THICKFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
Alexandre Julliard9bf9c0b2008-04-14 13:27:19 +02001179 else if (ex_style & WS_EX_APPWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
Alexandre Julliard8b84d642010-05-28 12:12:32 +02001180 else if (style & WS_MINIMIZEBOX) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
Nickolay V. Shmyrev1a1b9022006-10-11 19:32:22 +04001181 else if (style & WS_DLGFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
1182 else if (ex_style & WS_EX_DLGMODALFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
Alexandre Julliard0bbadeb2008-04-21 20:33:18 +02001183 else if ((style & WS_POPUP) && owner) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
Dmitry Timoshkov1bf824e2008-04-07 22:17:47 +09001184#if 0 /* many window managers don't handle utility windows very well */
Dmitry Timoshkov751a71a2008-04-07 13:37:44 +09001185 else if (ex_style & WS_EX_TOOLWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_UTILITY);
Dmitry Timoshkov1bf824e2008-04-07 22:17:47 +09001186#endif
Alexandre Julliard9bf9c0b2008-04-14 13:27:19 +02001187 else window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
Nickolay V. Shmyrev1a1b9022006-10-11 19:32:22 +04001188
1189 XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_WINDOW_TYPE),
1190 XA_ATOM, 32, PropModeReplace, (unsigned char*)&window_type, 1);
Mike Hearn27d972f2003-12-04 21:54:13 +00001191
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001192 mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
Dmitry Timoshkov15c0bcb2008-04-16 16:50:29 +09001193 mwm_hints.decorations = get_mwm_decorations( data, style, ex_style );
Dmitry Timoshkovac387bb2006-10-05 23:16:36 +09001194 mwm_hints.functions = MWM_FUNC_MOVE;
Alexandre Julliard4d14adf2008-04-04 11:25:48 +02001195 if (is_window_resizable( data, style )) mwm_hints.functions |= MWM_FUNC_RESIZE;
Dmitry Timoshkove35e75b2010-04-07 15:41:01 +09001196 if (!(style & WS_DISABLED))
1197 {
1198 if (style & WS_MINIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MINIMIZE;
1199 if (style & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
1200 if (style & WS_SYSMENU) mwm_hints.functions |= MWM_FUNC_CLOSE;
1201 }
Alexandre Julliardd09c3282003-11-20 04:24:18 +00001202
1203 XChangeProperty( display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS),
1204 x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace,
Hans Leidekkerac147fe2005-03-22 21:17:34 +00001205 (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001206
Alexandre Julliard704d0352001-07-12 02:49:31 +00001207 /* wm hints */
Alexandre Julliardbde89572007-08-16 23:27:37 +02001208 if (data->wm_hints)
Alexandre Julliard704d0352001-07-12 02:49:31 +00001209 {
Alexandre Julliard6a23bd82008-01-18 14:34:57 +01001210 data->wm_hints->flags |= InputHint | StateHint | WindowGroupHint;
Alexandre Julliarde3720c22009-08-13 18:18:22 +02001211 data->wm_hints->input = !use_take_focus && !(style & WS_DISABLED);
Alexandre Julliardbde89572007-08-16 23:27:37 +02001212 data->wm_hints->initial_state = (style & WS_MINIMIZE) ? IconicState : NormalState;
1213 data->wm_hints->window_group = group_leader;
Alexandre Julliardbde89572007-08-16 23:27:37 +02001214 XSetWMHints( display, data->whole_window, data->wm_hints );
Alexandre Julliard704d0352001-07-12 02:49:31 +00001215 }
Alexandre Julliard6a23bd82008-01-18 14:34:57 +01001216
1217 wine_tsx11_unlock();
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001218}
1219
1220
1221/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +02001222 * update_net_wm_states
1223 */
1224void update_net_wm_states( Display *display, struct x11drv_win_data *data )
1225{
1226 static const unsigned int state_atoms[NB_NET_WM_STATES] =
1227 {
1228 XATOM__NET_WM_STATE_FULLSCREEN,
1229 XATOM__NET_WM_STATE_ABOVE,
1230 XATOM__NET_WM_STATE_MAXIMIZED_VERT,
1231 XATOM__NET_WM_STATE_SKIP_PAGER,
1232 XATOM__NET_WM_STATE_SKIP_TASKBAR
1233 };
1234
1235 DWORD i, style, ex_style, new_state = 0;
1236
1237 if (!data->managed) return;
1238 if (data->whole_window == root_window) return;
1239
1240 style = GetWindowLongW( data->hwnd, GWL_STYLE );
1241 if (data->whole_rect.left <= 0 && data->whole_rect.right >= screen_width &&
1242 data->whole_rect.top <= 0 && data->whole_rect.bottom >= screen_height)
1243 {
1244 if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION)
1245 new_state |= (1 << NET_WM_STATE_MAXIMIZED);
1246 else if (!(style & WS_MINIMIZE))
1247 new_state |= (1 << NET_WM_STATE_FULLSCREEN);
1248 }
1249 else if (style & WS_MAXIMIZE)
1250 new_state |= (1 << NET_WM_STATE_MAXIMIZED);
1251
1252 ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
1253 if (ex_style & WS_EX_TOPMOST)
1254 new_state |= (1 << NET_WM_STATE_ABOVE);
1255 if (ex_style & WS_EX_TOOLWINDOW)
1256 new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER);
Alexandre Julliard61e50e12010-05-28 12:14:43 +02001257 if (!(ex_style & WS_EX_APPWINDOW) && GetWindow( data->hwnd, GW_OWNER ))
Alexandre Julliard855308f2008-04-23 15:32:58 +02001258 new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR);
1259
1260 if (!data->mapped) /* set the _NET_WM_STATE atom directly */
1261 {
1262 Atom atoms[NB_NET_WM_STATES+1];
1263 DWORD count;
1264
1265 for (i = count = 0; i < NB_NET_WM_STATES; i++)
1266 {
1267 if (!(new_state & (1 << i))) continue;
1268 TRACE( "setting wm state %u for unmapped window %p/%lx\n",
1269 i, data->hwnd, data->whole_window );
1270 atoms[count++] = X11DRV_Atoms[state_atoms[i] - FIRST_XATOM];
1271 if (state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT)
1272 atoms[count++] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ);
1273 }
1274 wine_tsx11_lock();
1275 XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), XA_ATOM,
1276 32, PropModeReplace, (unsigned char *)atoms, count );
1277 wine_tsx11_unlock();
1278 }
1279 else /* ask the window manager to do it for us */
1280 {
1281 XEvent xev;
1282
1283 xev.xclient.type = ClientMessage;
1284 xev.xclient.window = data->whole_window;
1285 xev.xclient.message_type = x11drv_atom(_NET_WM_STATE);
1286 xev.xclient.serial = 0;
1287 xev.xclient.display = display;
1288 xev.xclient.send_event = True;
1289 xev.xclient.format = 32;
1290 xev.xclient.data.l[3] = 1;
1291
1292 for (i = 0; i < NB_NET_WM_STATES; i++)
1293 {
1294 if (!((data->net_wm_state ^ new_state) & (1 << i))) continue; /* unchanged */
1295
1296 TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n",
1297 i, data->hwnd, data->whole_window,
1298 (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 );
1299
1300 xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1301 xev.xclient.data.l[1] = X11DRV_Atoms[state_atoms[i] - FIRST_XATOM];
1302 xev.xclient.data.l[2] = ((state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ?
1303 x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ) : 0);
1304 wine_tsx11_lock();
1305 XSendEvent( display, root_window, False,
1306 SubstructureRedirectMask | SubstructureNotifyMask, &xev );
1307 wine_tsx11_unlock();
1308 }
1309 }
1310 data->net_wm_state = new_state;
1311}
1312
1313
1314/***********************************************************************
1315 * set_xembed_flags
1316 */
1317static void set_xembed_flags( Display *display, struct x11drv_win_data *data, unsigned long flags )
1318{
1319 unsigned long info[2];
1320
1321 info[0] = 0; /* protocol version */
1322 info[1] = flags;
1323 wine_tsx11_lock();
1324 XChangeProperty( display, data->whole_window, x11drv_atom(_XEMBED_INFO),
1325 x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2 );
1326 wine_tsx11_unlock();
1327}
1328
1329
1330/***********************************************************************
1331 * map_window
1332 */
1333static void map_window( Display *display, struct x11drv_win_data *data, DWORD new_style )
1334{
1335 TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
1336
Damjan Jovanovic3613b152009-01-06 20:59:07 +02001337 remove_startup_notification( display, data->whole_window );
1338
Alexandre Julliard855308f2008-04-23 15:32:58 +02001339 wait_for_withdrawn_state( display, data, TRUE );
1340
1341 if (!data->embedded)
1342 {
1343 update_net_wm_states( display, data );
1344 sync_window_style( display, data );
1345 wine_tsx11_lock();
1346 XMapWindow( display, data->whole_window );
1347 wine_tsx11_unlock();
1348 }
1349 else set_xembed_flags( display, data, XEMBED_MAPPED );
1350
1351 data->mapped = TRUE;
1352 data->iconic = (new_style & WS_MINIMIZE) != 0;
1353}
1354
1355
1356/***********************************************************************
1357 * unmap_window
1358 */
1359static void unmap_window( Display *display, struct x11drv_win_data *data )
1360{
1361 TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
1362
1363 if (!data->embedded)
1364 {
1365 wait_for_withdrawn_state( display, data, FALSE );
1366 wine_tsx11_lock();
1367 if (data->managed) XWithdrawWindow( display, data->whole_window, DefaultScreen(display) );
1368 else XUnmapWindow( display, data->whole_window );
1369 wine_tsx11_unlock();
1370 }
1371 else set_xembed_flags( display, data, 0 );
1372
1373 data->mapped = FALSE;
1374 data->net_wm_state = 0;
1375}
1376
1377
1378/***********************************************************************
1379 * make_window_embedded
1380 */
1381void make_window_embedded( Display *display, struct x11drv_win_data *data )
1382{
1383 if (data->mapped)
1384 {
1385 /* the window cannot be mapped before being embedded */
1386 unmap_window( display, data );
1387 data->embedded = TRUE;
1388 map_window( display, data, 0 );
1389 }
1390 else
1391 {
1392 data->embedded = TRUE;
1393 set_xembed_flags( display, data, 0 );
1394 }
1395}
1396
1397
1398/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001399 * X11DRV_window_to_X_rect
1400 *
1401 * Convert a rect from client to X window coordinates
1402 */
Andrew Talbotf63ceec2009-01-29 21:40:50 +00001403static void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001404{
Alexandre Julliard8cd1f712001-07-20 18:37:37 +00001405 RECT rc;
1406
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001407 if (!data->managed) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001408 if (IsRectEmpty( rect )) return;
1409
Alexandre Julliardc4e20e72007-10-11 12:24:27 +02001410 get_x11_rect_offset( data, &rc );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001411
Alexandre Julliard8cd1f712001-07-20 18:37:37 +00001412 rect->left -= rc.left;
1413 rect->right -= rc.right;
1414 rect->top -= rc.top;
1415 rect->bottom -= rc.bottom;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001416 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
1417 if (rect->left >= rect->right) rect->right = rect->left + 1;
1418}
1419
1420
1421/***********************************************************************
1422 * X11DRV_X_to_window_rect
1423 *
1424 * Opposite of X11DRV_window_to_X_rect
1425 */
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001426void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001427{
Alexandre Julliardc4e20e72007-10-11 12:24:27 +02001428 RECT rc;
Alexandre Julliard74cd76c2007-08-29 12:02:57 +02001429
Alexandre Julliardd7726c32005-02-01 18:53:59 +00001430 if (!data->managed) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001431 if (IsRectEmpty( rect )) return;
1432
Alexandre Julliardc4e20e72007-10-11 12:24:27 +02001433 get_x11_rect_offset( data, &rc );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001434
Alexandre Julliardc4e20e72007-10-11 12:24:27 +02001435 rect->left += rc.left;
1436 rect->right += rc.right;
1437 rect->top += rc.top;
1438 rect->bottom += rc.bottom;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001439 if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
1440 if (rect->left >= rect->right) rect->right = rect->left + 1;
1441}
1442
1443
1444/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +02001445 * sync_window_position
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001446 *
Alexandre Julliardf777d702005-01-31 16:34:07 +00001447 * Synchronize the X window position with the Windows one
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001448 */
Alexandre Julliard855308f2008-04-23 15:32:58 +02001449static void sync_window_position( Display *display, struct x11drv_win_data *data,
Alexandre Julliard08b83252010-02-08 17:14:01 +01001450 UINT swp_flags, const RECT *old_window_rect,
1451 const RECT *old_whole_rect, const RECT *old_client_rect )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001452{
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001453 DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001454 XWindowChanges changes;
Alexandre Julliardbbd32aa2008-04-23 15:34:07 +02001455 unsigned int mask = 0;
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001456
1457 if (data->managed && data->iconic) return;
1458
Alexandre Julliardbbd32aa2008-04-23 15:34:07 +02001459 /* resizing a managed maximized window is not allowed */
1460 if (!(style & WS_MAXIMIZE) || !data->managed)
1461 {
Alexandre Julliard308476e2008-09-17 21:11:47 +02001462 changes.width = data->whole_rect.right - data->whole_rect.left;
1463 changes.height = data->whole_rect.bottom - data->whole_rect.top;
1464 /* if window rect is empty force size to 1x1 */
1465 if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1;
Alexandre Julliarda4644f12009-05-05 15:36:25 +02001466 if (changes.width > 65535) changes.width = 65535;
1467 if (changes.height > 65535) changes.height = 65535;
Alexandre Julliardbbd32aa2008-04-23 15:34:07 +02001468 mask |= CWWidth | CWHeight;
1469 }
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001470
1471 /* only the size is allowed to change for the desktop window */
1472 if (data->whole_window != root_window)
1473 {
1474 changes.x = data->whole_rect.left - virtual_screen_rect.left;
1475 changes.y = data->whole_rect.top - virtual_screen_rect.top;
1476 mask |= CWX | CWY;
1477 }
Alexandre Julliardf777d702005-01-31 16:34:07 +00001478
Alexandre Julliardac40efa2008-08-29 13:34:55 +02001479 if (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001480 {
Alexandre Julliardf777d702005-01-31 16:34:07 +00001481 /* find window that this one must be after */
1482 HWND prev = GetWindow( data->hwnd, GW_HWNDPREV );
1483 while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE))
1484 prev = GetWindow( prev, GW_HWNDPREV );
1485 if (!prev) /* top child */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001486 {
Alexandre Julliardf777d702005-01-31 16:34:07 +00001487 changes.stack_mode = Above;
1488 mask |= CWStackMode;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001489 }
Alexandre Julliard5787c122008-03-24 15:47:28 +01001490 /* should use stack_mode Below but most window managers don't get it right */
1491 /* and Above with a sibling doesn't work so well either, so we ignore it */
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001492 }
1493
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001494 wine_tsx11_lock();
1495 set_size_hints( display, data, style );
Alexandre Julliard00b06da2010-01-04 17:56:32 +01001496 data->configure_serial = NextRequest( display );
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001497 XReconfigureWMWindow( display, data->whole_window,
1498 DefaultScreen(display), mask, &changes );
Alexandre Julliard4c7b8ca2010-02-04 17:27:19 +01001499#ifdef HAVE_LIBXSHAPE
Alexandre Julliard61e50e12010-05-28 12:14:43 +02001500 if (IsRectEmpty( old_window_rect ) != IsRectEmpty( &data->window_rect ))
1501 sync_window_region( display, data, (HRGN)1 );
Alexandre Julliard4c7b8ca2010-02-04 17:27:19 +01001502 if (data->shaped)
1503 {
Alexandre Julliard08b83252010-02-08 17:14:01 +01001504 int old_x_offset = old_window_rect->left - old_whole_rect->left;
1505 int old_y_offset = old_window_rect->top - old_whole_rect->top;
1506 int new_x_offset = data->window_rect.left - data->whole_rect.left;
1507 int new_y_offset = data->window_rect.top - data->whole_rect.top;
1508 if (old_x_offset != new_x_offset || old_y_offset != new_y_offset)
1509 XShapeOffsetShape( display, data->whole_window, ShapeBounding,
1510 new_x_offset - old_x_offset, new_y_offset - old_y_offset );
Alexandre Julliard4c7b8ca2010-02-04 17:27:19 +01001511 }
1512#endif
Alexandre Julliardcef3bc62008-04-04 11:20:45 +02001513 wine_tsx11_unlock();
Alexandre Julliard00b06da2010-01-04 17:56:32 +01001514
1515 TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x serial=%lu\n",
1516 data->hwnd, data->whole_window, data->whole_rect.left, data->whole_rect.top,
1517 data->whole_rect.right - data->whole_rect.left,
1518 data->whole_rect.bottom - data->whole_rect.top,
1519 changes.sibling, mask, data->configure_serial );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001520}
1521
1522
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001523/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +02001524 * sync_client_position
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001525 *
1526 * Synchronize the X client window position with the Windows one
1527 */
Alexandre Julliard855308f2008-04-23 15:32:58 +02001528static void sync_client_position( Display *display, struct x11drv_win_data *data,
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001529 UINT swp_flags, const RECT *old_client_rect,
1530 const RECT *old_whole_rect )
1531{
1532 int mask;
1533 XWindowChanges changes;
1534 RECT old = *old_client_rect;
1535 RECT new = data->client_rect;
1536
1537 OffsetRect( &old, -old_whole_rect->left, -old_whole_rect->top );
1538 OffsetRect( &new, -data->whole_rect.left, -data->whole_rect.top );
1539 if (!(mask = get_window_changes( &changes, &old, &new ))) return;
1540
1541 if (data->client_window)
1542 {
1543 TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n",
1544 data->client_window, new.left, new.top,
1545 new.right - new.left, new.bottom - new.top, mask );
1546 wine_tsx11_lock();
1547 XConfigureWindow( display, data->client_window, mask, &changes );
1548 wine_tsx11_unlock();
1549 }
1550
Alexandre Julliard6e9dea82008-05-12 19:37:54 +02001551 if (data->gl_drawable && (mask & (CWWidth|CWHeight))) sync_gl_drawable( data );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001552}
1553
1554
Alexandre Julliard855308f2008-04-23 15:32:58 +02001555/***********************************************************************
1556 * move_window_bits
1557 *
1558 * Move the window bits when a window is moved.
1559 */
1560static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect, const RECT *new_rect,
1561 const RECT *old_client_rect )
1562{
1563 RECT src_rect = *old_rect;
1564 RECT dst_rect = *new_rect;
1565 HDC hdc_src, hdc_dst;
1566 INT code;
1567 HRGN rgn = 0;
1568 HWND parent = 0;
1569
1570 if (!data->whole_window)
1571 {
1572 OffsetRect( &dst_rect, -data->window_rect.left, -data->window_rect.top );
1573 parent = GetAncestor( data->hwnd, GA_PARENT );
1574 hdc_src = GetDCEx( parent, 0, DCX_CACHE );
1575 hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE | DCX_WINDOW );
1576 }
1577 else
1578 {
1579 OffsetRect( &dst_rect, -data->client_rect.left, -data->client_rect.top );
1580 /* make src rect relative to the old position of the window */
1581 OffsetRect( &src_rect, -old_client_rect->left, -old_client_rect->top );
1582 if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1583 hdc_src = hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE );
1584 }
1585
1586 code = X11DRV_START_EXPOSURES;
1587 ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
1588
1589 TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
1590 data->hwnd, data->whole_window, data->client_window,
1591 wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect) );
1592 BitBlt( hdc_dst, dst_rect.left, dst_rect.top,
1593 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1594 hdc_src, src_rect.left, src_rect.top, SRCCOPY );
1595
1596 code = X11DRV_END_EXPOSURES;
1597 ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(rgn), (LPSTR)&rgn );
1598
1599 ReleaseDC( data->hwnd, hdc_dst );
1600 if (hdc_src != hdc_dst) ReleaseDC( parent, hdc_src );
1601
1602 if (rgn)
1603 {
1604 if (!data->whole_window)
1605 {
1606 /* map region to client rect since we are using DCX_WINDOW */
1607 OffsetRgn( rgn, data->window_rect.left - data->client_rect.left,
1608 data->window_rect.top - data->client_rect.top );
1609 RedrawWindow( data->hwnd, NULL, rgn,
1610 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN );
1611 }
1612 else RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
1613 DeleteObject( rgn );
1614 }
1615}
1616
1617
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001618/**********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001619 * create_whole_window
1620 *
1621 * Create the whole X window for a given window
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001622 */
Alexandre Julliardd147e022008-01-23 21:39:32 +01001623static Window create_whole_window( Display *display, struct x11drv_win_data *data )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001624{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001625 int cx, cy, mask;
1626 XSetWindowAttributes attr;
Alexandre Julliard3ba20252008-01-23 16:32:55 +01001627 WCHAR text[1024];
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02001628 COLORREF key;
1629 BYTE alpha;
1630 DWORD layered_flags;
Alexandre Julliardaa477842010-02-01 22:35:32 +01001631 HRGN win_rgn;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001632
Alexandre Julliarde6dfbcb2008-01-25 12:07:11 +01001633 if (!data->managed && is_window_managed( data->hwnd, SWP_NOACTIVATE, &data->window_rect ))
1634 {
1635 TRACE( "making win %p/%lx managed\n", data->hwnd, data->whole_window );
1636 data->managed = TRUE;
1637 SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
1638 }
1639
Alexandre Julliardaa477842010-02-01 22:35:32 +01001640 if ((win_rgn = CreateRectRgn( 0, 0, 0, 0 )) &&
1641 GetWindowRgn( data->hwnd, win_rgn ) == ERROR)
1642 {
1643 DeleteObject( win_rgn );
1644 win_rgn = 0;
1645 }
1646 data->shaped = (win_rgn != 0);
1647
Alexandre Julliard6bb18e22006-03-27 15:33:43 +02001648 mask = get_window_attributes( display, data, &attr );
Alexandre Julliard883cff42001-06-12 04:02:10 +00001649
Alexandre Julliardac98e0c2007-08-20 22:06:33 +02001650 data->whole_rect = data->window_rect;
Alexandre Julliardedebc2b2009-06-25 12:10:44 +02001651 X11DRV_window_to_X_rect( data, &data->whole_rect );
1652 if (!(cx = data->whole_rect.right - data->whole_rect.left)) cx = 1;
1653 else if (cx > 65535) cx = 65535;
1654 if (!(cy = data->whole_rect.bottom - data->whole_rect.top)) cy = 1;
1655 else if (cy > 65535) cy = 65535;
1656
1657 wine_tsx11_lock();
Alexandre Julliarda06aeab2006-10-26 12:53:59 +02001658 data->whole_window = XCreateWindow( display, root_window,
Alexandre Julliardedebc2b2009-06-25 12:10:44 +02001659 data->whole_rect.left - virtual_screen_rect.left,
1660 data->whole_rect.top - virtual_screen_rect.top,
Alexandre Julliarda06aeab2006-10-26 12:53:59 +02001661 cx, cy, 0, screen_depth, InputOutput,
1662 visual, mask, &attr );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001663
Alexandre Julliard42ad3452008-02-22 10:40:22 +01001664 if (data->whole_window) XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd );
1665 wine_tsx11_unlock();
1666
Alexandre Julliardaa477842010-02-01 22:35:32 +01001667 if (!data->whole_window) goto done;
Alexandre Julliard42ad3452008-02-22 10:40:22 +01001668
1669 if (!create_client_window( display, data, NULL ))
Alexandre Julliard704d0352001-07-12 02:49:31 +00001670 {
Alexandre Julliard42ad3452008-02-22 10:40:22 +01001671 wine_tsx11_lock();
1672 XDeleteContext( display, data->whole_window, winContext );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001673 XDestroyWindow( display, data->whole_window );
1674 data->whole_window = 0;
1675 wine_tsx11_unlock();
Alexandre Julliardaa477842010-02-01 22:35:32 +01001676 goto done;
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001677 }
1678
Alexandre Julliard7d9739e2007-08-20 14:04:36 +02001679 set_initial_wm_hints( display, data );
Alexandre Julliard855308f2008-04-23 15:32:58 +02001680 set_wm_hints( display, data );
Alexandre Julliardf777d702005-01-31 16:34:07 +00001681
Alexandre Julliardaf50ad62005-07-07 17:30:57 +00001682 SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window );
Alexandre Julliard395928d2008-01-23 16:30:18 +01001683
Alexandre Julliard3ba20252008-01-23 16:32:55 +01001684 /* set the window text */
1685 if (!InternalGetWindowText( data->hwnd, text, sizeof(text)/sizeof(WCHAR) )) text[0] = 0;
1686 sync_window_text( display, data->whole_window, text );
1687
Alexandre Julliard395928d2008-01-23 16:30:18 +01001688 /* set the window region */
Alexandre Julliard61e50e12010-05-28 12:14:43 +02001689 if (win_rgn || IsRectEmpty( &data->window_rect )) sync_window_region( display, data, win_rgn );
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +02001690
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02001691 /* set the window opacity */
1692 if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0;
1693 sync_window_opacity( display, data->whole_window, key, alpha, layered_flags );
1694
Alexandre Julliard731d77f2008-04-09 20:24:27 +02001695 wine_tsx11_lock();
1696 XFlush( display ); /* make sure the window exists before we start painting to it */
1697 wine_tsx11_unlock();
Alexandre Julliard1afd0df2010-05-10 12:33:59 +02001698
1699 sync_window_cursor( data );
Alexandre Julliardaa477842010-02-01 22:35:32 +01001700done:
1701 if (win_rgn) DeleteObject( win_rgn );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001702 return data->whole_window;
1703}
1704
1705
1706/**********************************************************************
Alexandre Julliardf777d702005-01-31 16:34:07 +00001707 * destroy_whole_window
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001708 *
Alexandre Julliardf777d702005-01-31 16:34:07 +00001709 * Destroy the whole X window for a given window.
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001710 */
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01001711static void destroy_whole_window( Display *display, struct x11drv_win_data *data, BOOL already_destroyed )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001712{
Alexandre Julliardf777d702005-01-31 16:34:07 +00001713 if (!data->whole_window) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001714
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001715 TRACE( "win %p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window );
Alexandre Julliard883cff42001-06-12 04:02:10 +00001716 wine_tsx11_lock();
Alexandre Julliardf777d702005-01-31 16:34:07 +00001717 XDeleteContext( display, data->whole_window, winContext );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001718 XDeleteContext( display, data->client_window, winContext );
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01001719 if (!already_destroyed) XDestroyWindow( display, data->whole_window );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001720 data->whole_window = data->client_window = 0;
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01001721 data->wm_state = WithdrawnState;
1722 data->net_wm_state = 0;
1723 data->mapped = FALSE;
Alexandre Julliardf777d702005-01-31 16:34:07 +00001724 if (data->xic)
1725 {
1726 XUnsetICFocus( data->xic );
1727 XDestroyIC( data->xic );
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01001728 data->xic = 0;
Alexandre Julliardf777d702005-01-31 16:34:07 +00001729 }
Alexandre Julliard975f1b22006-05-09 17:32:40 +02001730 /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */
1731 XFlush( display );
Alexandre Julliarddc07b6f2008-01-22 10:17:52 +01001732 XFree( data->wm_hints );
1733 data->wm_hints = NULL;
Alexandre Julliard883cff42001-06-12 04:02:10 +00001734 wine_tsx11_unlock();
Alexandre Julliardaf50ad62005-07-07 17:30:57 +00001735 RemovePropA( data->hwnd, whole_window_prop );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001736 RemovePropA( data->hwnd, client_window_prop );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001737}
1738
1739
1740/*****************************************************************
1741 * SetWindowText (X11DRV.@)
1742 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01001743void CDECL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001744{
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001745 Window win;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001746
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001747 if ((win = X11DRV_get_whole_window( hwnd )) && win != DefaultRootWindow(gdi_display))
1748 {
1749 Display *display = thread_init_display();
Alexandre Julliard3ba20252008-01-23 16:32:55 +01001750 sync_window_text( display, win, text );
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001751 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001752}
1753
1754
1755/***********************************************************************
Alexandre Julliard855308f2008-04-23 15:32:58 +02001756 * SetWindowStyle (X11DRV.@)
1757 *
1758 * Update the X state of a window to reflect a style change
1759 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01001760void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
Alexandre Julliard855308f2008-04-23 15:32:58 +02001761{
Alexandre Julliard855308f2008-04-23 15:32:58 +02001762 struct x11drv_win_data *data;
Alexandre Julliard2f112132008-09-12 14:55:07 +02001763 DWORD changed;
Alexandre Julliard855308f2008-04-23 15:32:58 +02001764
1765 if (hwnd == GetDesktopWindow()) return;
Alexandre Julliard2f112132008-09-12 14:55:07 +02001766 changed = style->styleNew ^ style->styleOld;
Alexandre Julliard855308f2008-04-23 15:32:58 +02001767
Alexandre Julliard2f112132008-09-12 14:55:07 +02001768 if (offset == GWL_STYLE && (changed & WS_VISIBLE) && (style->styleNew & WS_VISIBLE))
Alexandre Julliard855308f2008-04-23 15:32:58 +02001769 {
1770 /* we don't unmap windows, that causes trouble with the window manager */
1771 if (!(data = X11DRV_get_win_data( hwnd )) &&
1772 !(data = X11DRV_create_win_data( hwnd ))) return;
1773
1774 if (data->whole_window && is_window_rect_mapped( &data->window_rect ))
1775 {
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001776 Display *display = thread_display();
Alexandre Julliard855308f2008-04-23 15:32:58 +02001777 set_wm_hints( display, data );
Alexandre Julliard2f112132008-09-12 14:55:07 +02001778 if (!data->mapped) map_window( display, data, style->styleNew );
Alexandre Julliard855308f2008-04-23 15:32:58 +02001779 }
1780 }
1781
Alexandre Julliard2f112132008-09-12 14:55:07 +02001782 if (offset == GWL_STYLE && (changed & WS_DISABLED))
Alexandre Julliard855308f2008-04-23 15:32:58 +02001783 {
1784 data = X11DRV_get_win_data( hwnd );
Dmitry Timoshkove35e75b2010-04-07 15:41:01 +09001785 if (data && data->whole_window)
1786 set_wm_hints( thread_display(), data );
Alexandre Julliard855308f2008-04-23 15:32:58 +02001787 }
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02001788
1789 if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED))
1790 {
1791 /* changing WS_EX_LAYERED resets attributes */
1792 if ((data = X11DRV_get_win_data( hwnd )) && data->whole_window)
1793 sync_window_opacity( thread_display(), data->whole_window, 0, 0, 0 );
1794 }
Alexandre Julliard855308f2008-04-23 15:32:58 +02001795}
1796
1797
1798/***********************************************************************
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001799 * DestroyWindow (X11DRV.@)
1800 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01001801void CDECL X11DRV_DestroyWindow( HWND hwnd )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001802{
Alexandre Julliard9428f062002-06-14 00:08:40 +00001803 struct x11drv_thread_data *thread_data = x11drv_thread_data();
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001804 struct x11drv_win_data *data;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001805
Alexandre Julliard2997fc52005-07-18 13:20:18 +00001806 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001807
Chris Robinson37d835b2007-09-26 08:17:13 -07001808 if (data->pixmap)
1809 {
Chris Robinson37d835b2007-09-26 08:17:13 -07001810 wine_tsx11_lock();
Alexandre Julliard6e9dea82008-05-12 19:37:54 +02001811 destroy_glxpixmap(gdi_display, data->gl_drawable);
1812 XFreePixmap(gdi_display, data->pixmap);
Chris Robinson37d835b2007-09-26 08:17:13 -07001813 wine_tsx11_unlock();
1814 }
1815 else if (data->gl_drawable)
Chris Robinson00633e32007-09-25 22:43:38 -07001816 {
1817 wine_tsx11_lock();
Alexandre Julliard6e9dea82008-05-12 19:37:54 +02001818 XDestroyWindow(gdi_display, data->gl_drawable);
Chris Robinson00633e32007-09-25 22:43:38 -07001819 wine_tsx11_unlock();
1820 }
1821
Alexandre Julliard06a14072008-06-26 15:08:08 +02001822 destroy_whole_window( thread_data->display, data, FALSE );
1823 destroy_icon_window( thread_data->display, data );
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001824
Alexandre Julliarde9307d02008-02-21 20:23:32 +01001825 if (data->colormap)
1826 {
1827 wine_tsx11_lock();
Alexandre Julliard06a14072008-06-26 15:08:08 +02001828 XFreeColormap( thread_data->display, data->colormap );
Alexandre Julliarde9307d02008-02-21 20:23:32 +01001829 wine_tsx11_unlock();
1830 }
1831
Alexandre Julliardf777d702005-01-31 16:34:07 +00001832 if (thread_data->last_focus == hwnd) thread_data->last_focus = 0;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001833 if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
1834 if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001835 wine_tsx11_lock();
Alexandre Julliard06a14072008-06-26 15:08:08 +02001836 XDeleteContext( thread_data->display, (XID)hwnd, win_data_context );
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001837 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001838 HeapFree( GetProcessHeap(), 0, data );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00001839}
1840
1841
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01001842/***********************************************************************
1843 * X11DRV_DestroyNotify
1844 */
1845void X11DRV_DestroyNotify( HWND hwnd, XEvent *event )
1846{
1847 Display *display = event->xdestroywindow.display;
1848 struct x11drv_win_data *data;
1849
1850 if (!(data = X11DRV_get_win_data( hwnd ))) return;
1851
1852 FIXME( "window %p/%lx destroyed from the outside\n", hwnd, data->whole_window );
1853 destroy_whole_window( display, data, TRUE );
1854}
1855
1856
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001857static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd )
1858{
1859 struct x11drv_win_data *data;
1860
Alexandre Julliard30d84fc2008-01-22 10:15:38 +01001861 if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001862 {
Alexandre Julliard30d84fc2008-01-22 10:15:38 +01001863 data->hwnd = hwnd;
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001864 wine_tsx11_lock();
1865 if (!winContext) winContext = XUniqueContext();
1866 if (!win_data_context) win_data_context = XUniqueContext();
1867 XSaveContext( display, (XID)hwnd, win_data_context, (char *)data );
1868 wine_tsx11_unlock();
1869 }
1870 return data;
1871}
1872
1873
Alexandre Julliardc19af912008-01-17 19:53:59 +01001874/* initialize the desktop window id in the desktop manager process */
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001875static struct x11drv_win_data *create_desktop_win_data( Display *display, HWND hwnd )
Alexandre Julliarddb6608a2006-03-27 22:43:03 +02001876{
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001877 struct x11drv_win_data *data;
Alexandre Julliarddb6608a2006-03-27 22:43:03 +02001878
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001879 if (!(data = alloc_win_data( display, hwnd ))) return NULL;
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001880 data->whole_window = data->client_window = root_window;
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001881 data->managed = TRUE;
1882 SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
1883 SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window );
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001884 SetPropA( data->hwnd, client_window_prop, (HANDLE)root_window );
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001885 set_initial_wm_hints( display, data );
1886 return data;
Alexandre Julliarddb6608a2006-03-27 22:43:03 +02001887}
1888
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001889/**********************************************************************
1890 * CreateDesktopWindow (X11DRV.@)
1891 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01001892BOOL CDECL X11DRV_CreateDesktopWindow( HWND hwnd )
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001893{
Alexandre Julliardc19af912008-01-17 19:53:59 +01001894 unsigned int width, height;
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001895
Alexandre Julliardc19af912008-01-17 19:53:59 +01001896 /* retrieve the real size of the desktop */
1897 SERVER_START_REQ( get_window_rectangles )
1898 {
Alexandre Julliard7fdadbb2008-12-08 16:58:20 +01001899 req->handle = wine_server_user_handle( hwnd );
Alexandre Julliardc19af912008-01-17 19:53:59 +01001900 wine_server_call( req );
1901 width = reply->window.right - reply->window.left;
1902 height = reply->window.bottom - reply->window.top;
1903 }
1904 SERVER_END_REQ;
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001905
Alexandre Julliardc19af912008-01-17 19:53:59 +01001906 if (!width && !height) /* not initialized yet */
1907 {
1908 SERVER_START_REQ( set_window_pos )
1909 {
Alexandre Julliard7fdadbb2008-12-08 16:58:20 +01001910 req->handle = wine_server_user_handle( hwnd );
Alexandre Julliardc19af912008-01-17 19:53:59 +01001911 req->previous = 0;
1912 req->flags = SWP_NOZORDER;
1913 req->window.left = virtual_screen_rect.left;
1914 req->window.top = virtual_screen_rect.top;
1915 req->window.right = virtual_screen_rect.right;
1916 req->window.bottom = virtual_screen_rect.bottom;
1917 req->client = req->window;
1918 wine_server_call( req );
1919 }
1920 SERVER_END_REQ;
1921 }
1922 else
1923 {
1924 Window win = (Window)GetPropA( hwnd, whole_window_prop );
1925 if (win && win != root_window) X11DRV_init_desktop( win, width, height );
1926 }
Alexandre Julliarde419cb82005-07-07 20:33:29 +00001927 return TRUE;
1928}
1929
1930
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001931/**********************************************************************
1932 * CreateWindow (X11DRV.@)
1933 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01001934BOOL CDECL X11DRV_CreateWindow( HWND hwnd )
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001935{
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001936 if (hwnd == GetDesktopWindow() && root_window != DefaultRootWindow( gdi_display ))
Alexandre Julliardb6cc7f92008-01-24 10:20:11 +01001937 {
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001938 Display *display = thread_init_display();
1939
Alexandre Julliard026974f2008-01-24 10:20:51 +01001940 /* the desktop win data can't be created lazily */
1941 if (!create_desktop_win_data( display, hwnd )) return FALSE;
Alexandre Julliarddb6608a2006-03-27 22:43:03 +02001942 }
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001943 return TRUE;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00001944}
1945
1946
1947/***********************************************************************
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001948 * X11DRV_get_win_data
1949 *
1950 * Return the X11 data structure associated with a window.
1951 */
1952struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd )
1953{
Alexandre Julliard06a14072008-06-26 15:08:08 +02001954 struct x11drv_thread_data *thread_data = x11drv_thread_data();
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001955 char *data;
Alexandre Julliarde5515552005-02-09 14:01:40 +00001956
Alexandre Julliard06a14072008-06-26 15:08:08 +02001957 if (!thread_data) return NULL;
1958 if (!hwnd) return NULL;
1959 if (XFindContext( thread_data->display, (XID)hwnd, win_data_context, &data )) data = NULL;
Alexandre Julliardd56ccaa2005-01-28 17:25:50 +00001960 return (struct x11drv_win_data *)data;
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00001961}
1962
1963
1964/***********************************************************************
Alexandre Julliard026974f2008-01-24 10:20:51 +01001965 * X11DRV_create_win_data
1966 *
1967 * Create an X11 data window structure for an existing window.
1968 */
1969struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd )
1970{
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001971 Display *display;
Alexandre Julliard026974f2008-01-24 10:20:51 +01001972 struct x11drv_win_data *data;
1973 HWND parent;
1974
1975 if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL; /* desktop */
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001976
Alexandre Julliard93a02e72008-06-26 16:49:09 +02001977 /* don't create win data for HWND_MESSAGE windows */
1978 if (parent != GetDesktopWindow() && !GetAncestor( parent, GA_PARENT )) return NULL;
1979
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02001980 display = thread_init_display();
Alexandre Julliard026974f2008-01-24 10:20:51 +01001981 if (!(data = alloc_win_data( display, hwnd ))) return NULL;
1982
1983 GetWindowRect( hwnd, &data->window_rect );
1984 MapWindowPoints( 0, parent, (POINT *)&data->window_rect, 2 );
1985 data->whole_rect = data->window_rect;
1986 GetClientRect( hwnd, &data->client_rect );
1987 MapWindowPoints( hwnd, parent, (POINT *)&data->client_rect, 2 );
1988
1989 if (parent == GetDesktopWindow())
1990 {
1991 if (!create_whole_window( display, data ))
1992 {
1993 HeapFree( GetProcessHeap(), 0, data );
1994 return NULL;
1995 }
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01001996 TRACE( "win %p/%lx/%lx window %s whole %s client %s\n",
1997 hwnd, data->whole_window, data->client_window, wine_dbgstr_rect( &data->window_rect ),
Alexandre Julliard026974f2008-01-24 10:20:51 +01001998 wine_dbgstr_rect( &data->whole_rect ), wine_dbgstr_rect( &data->client_rect ));
1999 }
Alexandre Julliard026974f2008-01-24 10:20:51 +01002000 return data;
2001}
2002
2003
2004/***********************************************************************
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00002005 * X11DRV_get_whole_window
2006 *
2007 * Return the X window associated with the full area of a window
2008 */
2009Window X11DRV_get_whole_window( HWND hwnd )
2010{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002011 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliard8fd26b92001-10-15 17:56:45 +00002012
Alexandre Julliardc19af912008-01-17 19:53:59 +01002013 if (!data)
2014 {
2015 if (hwnd == GetDesktopWindow()) return root_window;
2016 return (Window)GetPropA( hwnd, whole_window_prop );
2017 }
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002018 return data->whole_window;
Alexandre Julliarddc4fe772001-06-04 21:55:17 +00002019}
2020
2021
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00002022/***********************************************************************
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01002023 * X11DRV_get_client_window
2024 *
2025 * Return the X window associated with the client area of a window
2026 */
Andrew Talbotf63ceec2009-01-29 21:40:50 +00002027static Window X11DRV_get_client_window( HWND hwnd )
Alexandre Julliard8ee07d42008-02-21 12:29:36 +01002028{
2029 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2030
2031 if (!data)
2032 {
2033 if (hwnd == GetDesktopWindow()) return root_window;
2034 return (Window)GetPropA( hwnd, client_window_prop );
2035 }
2036 return data->client_window;
2037}
2038
2039
2040/***********************************************************************
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00002041 * X11DRV_get_ic
2042 *
2043 * Return the X input context associated with a window
2044 */
2045XIC X11DRV_get_ic( HWND hwnd )
2046{
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002047 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Kusanagi Kouichi185157c2008-04-04 20:44:36 +09002048 XIM xim;
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00002049
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002050 if (!data) return 0;
Kusanagi Kouichi185157c2008-04-04 20:44:36 +09002051 if (data->xic) return data->xic;
2052 if (!(xim = x11drv_thread_data()->xim)) return 0;
2053 return X11DRV_CreateIC( xim, data );
Alexandre Julliard8b6a2192003-01-23 01:28:12 +00002054}
2055
2056
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002057/***********************************************************************
2058 * X11DRV_GetDC (X11DRV.@)
2059 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002060void CDECL X11DRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect,
2061 const RECT *top_rect, DWORD flags )
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002062{
2063 struct x11drv_escape_set_drawable escape;
2064 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2065
2066 escape.code = X11DRV_SET_DRAWABLE;
2067 escape.mode = IncludeInferiors;
2068 escape.fbconfig_id = 0;
2069 escape.gl_drawable = 0;
2070 escape.pixmap = 0;
Alexandre Julliard2d9b3812008-05-28 17:52:06 +02002071 escape.gl_copy = FALSE;
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002072
Henri Verbeet3255b212010-04-11 21:47:49 +02002073 if (top == hwnd)
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002074 {
Alexandre Julliard2d9b3812008-05-28 17:52:06 +02002075 escape.fbconfig_id = data ? data->fbconfig_id : (XID)GetPropA( hwnd, fbconfig_id_prop );
2076 /* GL draws to the client area even for window DCs */
2077 escape.gl_drawable = data ? data->client_window : X11DRV_get_client_window( hwnd );
Henri Verbeet3255b212010-04-11 21:47:49 +02002078 if (data && IsIconic( hwnd ) && data->icon_window)
2079 {
2080 escape.drawable = data->icon_window;
2081 }
2082 else if (flags & DCX_WINDOW)
Alexandre Julliard2d9b3812008-05-28 17:52:06 +02002083 escape.drawable = data ? data->whole_window : X11DRV_get_whole_window( hwnd );
2084 else
2085 escape.drawable = escape.gl_drawable;
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002086 }
2087 else
2088 {
2089 escape.drawable = X11DRV_get_client_window( top );
2090 escape.fbconfig_id = data ? data->fbconfig_id : (XID)GetPropA( hwnd, fbconfig_id_prop );
2091 escape.gl_drawable = data ? data->gl_drawable : (Drawable)GetPropA( hwnd, gl_drawable_prop );
2092 escape.pixmap = data ? data->pixmap : (Pixmap)GetPropA( hwnd, pixmap_prop );
Alexandre Julliard2d9b3812008-05-28 17:52:06 +02002093 escape.gl_copy = (escape.gl_drawable != 0);
Alexandre Julliardaf369102008-03-18 12:42:25 +01002094 if (flags & DCX_CLIPCHILDREN) escape.mode = ClipByChildren;
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002095 }
2096
2097 escape.dc_rect.left = win_rect->left - top_rect->left;
2098 escape.dc_rect.top = win_rect->top - top_rect->top;
2099 escape.dc_rect.right = win_rect->right - top_rect->left;
2100 escape.dc_rect.bottom = win_rect->bottom - top_rect->top;
2101 escape.drawable_rect.left = top_rect->left;
2102 escape.drawable_rect.top = top_rect->top;
2103 escape.drawable_rect.right = top_rect->right;
2104 escape.drawable_rect.bottom = top_rect->bottom;
2105
2106 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
2107}
2108
2109
2110/***********************************************************************
2111 * X11DRV_ReleaseDC (X11DRV.@)
2112 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002113void CDECL X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002114{
2115 struct x11drv_escape_set_drawable escape;
2116
2117 escape.code = X11DRV_SET_DRAWABLE;
2118 escape.drawable = root_window;
2119 escape.mode = IncludeInferiors;
2120 escape.drawable_rect = virtual_screen_rect;
2121 SetRect( &escape.dc_rect, 0, 0, virtual_screen_rect.right - virtual_screen_rect.left,
2122 virtual_screen_rect.bottom - virtual_screen_rect.top );
Alexandre Julliardbcf88b52010-02-16 12:37:42 +01002123 OffsetRect( &escape.dc_rect, -escape.drawable_rect.left, -escape.drawable_rect.top );
Alexandre Julliard1642fbc2008-02-25 15:59:19 +01002124 escape.fbconfig_id = 0;
2125 escape.gl_drawable = 0;
2126 escape.pixmap = 0;
2127 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
2128}
2129
2130
Alexandre Julliarddc26f272008-03-12 15:01:24 +01002131/***********************************************************************
2132 * SetCapture (X11DRV.@)
2133 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002134void CDECL X11DRV_SetCapture( HWND hwnd, UINT flags )
Alexandre Julliarddc26f272008-03-12 15:01:24 +01002135{
2136 struct x11drv_thread_data *thread_data = x11drv_thread_data();
2137
Alexandre Julliard06a14072008-06-26 15:08:08 +02002138 if (!thread_data) return;
Alexandre Julliard78de7e32008-03-24 17:59:40 +01002139 if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
Alexandre Julliarddc26f272008-03-12 15:01:24 +01002140
2141 if (hwnd)
2142 {
2143 Window grab_win = X11DRV_get_client_window( GetAncestor( hwnd, GA_ROOT ) );
2144
2145 if (!grab_win) return;
2146 wine_tsx11_lock();
2147 XFlush( gdi_display );
2148 XGrabPointer( thread_data->display, grab_win, False,
2149 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
Alexandre Julliard78de7e32008-03-24 17:59:40 +01002150 GrabModeAsync, GrabModeAsync, None, None, CurrentTime );
Alexandre Julliarddc26f272008-03-12 15:01:24 +01002151 wine_tsx11_unlock();
2152 thread_data->grab_window = grab_win;
2153 }
2154 else /* release capture */
2155 {
2156 wine_tsx11_lock();
2157 XFlush( gdi_display );
2158 XUngrabPointer( thread_data->display, CurrentTime );
Alexandre Julliard95cf00f2009-01-26 15:12:55 +01002159 XFlush( thread_data->display );
Alexandre Julliarddc26f272008-03-12 15:01:24 +01002160 wine_tsx11_unlock();
2161 thread_data->grab_window = None;
2162 }
2163}
2164
2165
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002166/*****************************************************************
2167 * SetParent (X11DRV.@)
2168 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002169void CDECL X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002170{
Alexandre Julliard43230042001-05-16 19:52:29 +00002171 Display *display = thread_display();
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002172 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002173
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002174 if (!data) return;
2175 if (parent == old_parent) return;
Alexandre Julliardfb0ff052001-10-16 21:58:58 +00002176
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002177 if (parent != GetDesktopWindow()) /* a child window */
Alexandre Julliard4d32a472005-03-25 10:38:56 +00002178 {
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002179 if (old_parent == GetDesktopWindow())
Alexandre Julliard4d32a472005-03-25 10:38:56 +00002180 {
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002181 /* destroy the old X windows */
Alexandre Julliard3b6f95c2008-03-05 16:51:09 +01002182 destroy_whole_window( display, data, FALSE );
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002183 destroy_icon_window( display, data );
2184 if (data->managed)
Alexandre Julliardf777d702005-01-31 16:34:07 +00002185 {
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002186 data->managed = FALSE;
2187 RemovePropA( data->hwnd, managed_prop );
Alexandre Julliardf777d702005-01-31 16:34:07 +00002188 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002189 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002190 }
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002191 else /* new top level window */
2192 {
2193 /* FIXME: we ignore errors since we can't really recover anyway */
Alexandre Julliardd147e022008-01-23 21:39:32 +01002194 create_whole_window( display, data );
Pierre d'Herbemont221b0442006-12-10 23:21:28 +01002195 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002196}
2197
2198
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002199/*****************************************************************
2200 * SetFocus (X11DRV.@)
2201 *
2202 * Set the X focus.
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002203 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002204void CDECL X11DRV_SetFocus( HWND hwnd )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002205{
Alexandre Julliard43230042001-05-16 19:52:29 +00002206 Display *display = thread_display();
Alexandre Julliardd7726c32005-02-01 18:53:59 +00002207 struct x11drv_win_data *data;
Alexandre Julliard125793d2008-02-18 17:22:51 +01002208 XWindowChanges changes;
Vincent Povirke4a50e12010-03-17 12:29:23 -05002209 DWORD timestamp;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002210
Alexandre Julliard9d53a1a2008-06-26 16:21:32 +02002211 if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
Alexandre Julliardd7726c32005-02-01 18:53:59 +00002212 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Todd Mokros88ac4b92005-08-22 09:14:21 +00002213 if (data->managed || !data->whole_window) return;
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00002214
Vincent Povirke4a50e12010-03-17 12:29:23 -05002215 if (EVENT_x11_time_to_win32_time(0))
2216 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
2217 /* FIXME: this is not entirely correct */
2218 timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
2219 else
2220 timestamp = CurrentTime;
2221
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00002222 /* Set X focus and install colormap */
2223 wine_tsx11_lock();
Alexandre Julliard125793d2008-02-18 17:22:51 +01002224 changes.stack_mode = Above;
2225 XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
Vincent Povirke4a50e12010-03-17 12:29:23 -05002226 XSetInputFocus( display, data->whole_window, RevertToParent, timestamp );
Alexandre Julliard0801ffc2001-08-24 00:26:59 +00002227 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002228}
2229
2230
Alexandre Julliard855308f2008-04-23 15:32:58 +02002231/***********************************************************************
Alexandre Julliard89a3bd02008-07-02 15:40:10 +02002232 * WindowPosChanging (X11DRV.@)
Alexandre Julliard855308f2008-04-23 15:32:58 +02002233 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002234void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
2235 const RECT *window_rect, const RECT *client_rect, RECT *visible_rect )
Alexandre Julliard89a3bd02008-07-02 15:40:10 +02002236{
2237 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2238 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
2239
2240 if (!data)
2241 {
2242 /* create the win data if the window is being made visible */
2243 if (!(style & WS_VISIBLE) && !(swp_flags & SWP_SHOWWINDOW)) return;
2244 if (!(data = X11DRV_create_win_data( hwnd ))) return;
2245 }
2246
2247 /* check if we need to switch the window to managed */
2248 if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect ))
2249 {
2250 TRACE( "making win %p/%lx managed\n", hwnd, data->whole_window );
2251 if (data->mapped) unmap_window( thread_display(), data );
2252 data->managed = TRUE;
2253 SetPropA( hwnd, managed_prop, (HANDLE)1 );
2254 }
2255
2256 *visible_rect = *window_rect;
2257 X11DRV_window_to_X_rect( data, visible_rect );
2258}
2259
2260
2261/***********************************************************************
2262 * WindowPosChanged (X11DRV.@)
2263 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002264void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
2265 const RECT *rectWindow, const RECT *rectClient,
2266 const RECT *visible_rect, const RECT *valid_rects )
Alexandre Julliard855308f2008-04-23 15:32:58 +02002267{
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02002268 struct x11drv_thread_data *thread_data;
2269 Display *display;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002270 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2271 DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard08b83252010-02-08 17:14:01 +01002272 RECT old_window_rect, old_whole_rect, old_client_rect;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002273 int event_type;
2274
Alexandre Julliard89a3bd02008-07-02 15:40:10 +02002275 if (!data) return;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002276
Alexandre Julliarde7044cb2008-06-26 16:47:42 +02002277 thread_data = x11drv_thread_data();
2278 display = thread_data->display;
2279
Alexandre Julliard08b83252010-02-08 17:14:01 +01002280 old_window_rect = data->window_rect;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002281 old_whole_rect = data->whole_rect;
2282 old_client_rect = data->client_rect;
2283 data->window_rect = *rectWindow;
Alexandre Julliard89a3bd02008-07-02 15:40:10 +02002284 data->whole_rect = *visible_rect;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002285 data->client_rect = *rectClient;
Alexandre Julliard855308f2008-04-23 15:32:58 +02002286
2287 TRACE( "win %p window %s client %s style %08x flags %08x\n",
2288 hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style, swp_flags );
2289
2290 if (!IsRectEmpty( &valid_rects[0] ))
2291 {
2292 int x_offset = old_whole_rect.left - data->whole_rect.left;
2293 int y_offset = old_whole_rect.top - data->whole_rect.top;
2294
2295 /* if all that happened is that the whole window moved, copy everything */
2296 if (!(swp_flags & SWP_FRAMECHANGED) &&
2297 old_whole_rect.right - data->whole_rect.right == x_offset &&
2298 old_whole_rect.bottom - data->whole_rect.bottom == y_offset &&
2299 old_client_rect.left - data->client_rect.left == x_offset &&
2300 old_client_rect.right - data->client_rect.right == x_offset &&
2301 old_client_rect.top - data->client_rect.top == y_offset &&
2302 old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2303 !memcmp( &valid_rects[0], &data->client_rect, sizeof(RECT) ))
2304 {
2305 /* if we have an X window the bits will be moved by the X server */
2306 if (!data->whole_window)
2307 move_window_bits( data, &old_whole_rect, &data->whole_rect, &old_client_rect );
2308 }
2309 else
2310 move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_client_rect );
2311 }
2312
2313 wine_tsx11_lock();
2314 XFlush( gdi_display ); /* make sure painting is done before we move the window */
2315 wine_tsx11_unlock();
2316
2317 sync_client_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
2318
2319 if (!data->whole_window) return;
2320
2321 /* check if we are currently processing an event relevant to this window */
2322 event_type = 0;
2323 if (thread_data->current_event && thread_data->current_event->xany.window == data->whole_window)
2324 event_type = thread_data->current_event->type;
2325
2326 if (event_type != ConfigureNotify && event_type != PropertyNotify)
2327 event_type = 0; /* ignore other events */
2328
Alexandre Julliard6b9517a2008-05-01 17:45:17 +02002329 if (data->mapped)
2330 {
2331 if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) ||
Alexandre Julliard2db72e92010-05-28 12:16:17 +02002332 (event_type != ConfigureNotify &&
2333 !is_window_rect_mapped( rectWindow ) && is_window_rect_mapped( &old_window_rect )))
Alexandre Julliard6b9517a2008-05-01 17:45:17 +02002334 unmap_window( display, data );
2335 }
Alexandre Julliard855308f2008-04-23 15:32:58 +02002336
2337 /* don't change position if we are about to minimize or maximize a managed window */
2338 if (!event_type &&
2339 !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE))))
Alexandre Julliard08b83252010-02-08 17:14:01 +01002340 sync_window_position( display, data, swp_flags,
2341 &old_window_rect, &old_whole_rect, &old_client_rect );
Alexandre Julliard855308f2008-04-23 15:32:58 +02002342
2343 if ((new_style & WS_VISIBLE) &&
2344 ((new_style & WS_MINIMIZE) || is_window_rect_mapped( rectWindow )))
2345 {
2346 if (!data->mapped || (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)))
2347 set_wm_hints( display, data );
2348
2349 if (!data->mapped)
2350 {
2351 map_window( display, data, new_style );
2352 }
2353 else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE)))
2354 {
2355 data->iconic = (new_style & WS_MINIMIZE) != 0;
2356 TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic );
2357 wine_tsx11_lock();
2358 if (data->iconic)
2359 XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
2360 else if (is_window_rect_mapped( rectWindow ))
2361 XMapWindow( display, data->whole_window );
2362 wine_tsx11_unlock();
2363 update_net_wm_states( display, data );
2364 }
2365 else if (!event_type)
2366 {
2367 update_net_wm_states( display, data );
2368 }
2369 }
2370
2371 wine_tsx11_lock();
2372 XFlush( display ); /* make sure changes are done before we start painting again */
2373 wine_tsx11_unlock();
2374}
2375
2376
Alexandre Julliard31b40612008-07-31 11:40:49 +02002377/***********************************************************************
2378 * ShowWindow (X11DRV.@)
2379 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002380UINT CDECL X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
Alexandre Julliard31b40612008-07-31 11:40:49 +02002381{
2382 int x, y;
2383 unsigned int width, height, border, depth;
2384 Window root, top;
2385 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
2386 struct x11drv_thread_data *thread_data = x11drv_thread_data();
2387 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2388
2389 if (!data || !data->whole_window || !data->managed || !data->mapped || data->iconic) return swp;
2390 if (style & WS_MINIMIZE) return swp;
Alexandre Julliard3cb23d32008-09-17 21:13:11 +02002391 if (IsRectEmpty( rect )) return swp;
Alexandre Julliard31b40612008-07-31 11:40:49 +02002392
2393 /* only fetch the new rectangle if the ShowWindow was a result of a window manager event */
2394
2395 if (!thread_data->current_event || thread_data->current_event->xany.window != data->whole_window)
2396 return swp;
2397
2398 if (thread_data->current_event->type != ConfigureNotify &&
2399 thread_data->current_event->type != PropertyNotify)
2400 return swp;
2401
2402 TRACE( "win %p/%lx cmd %d at %s flags %08x\n",
2403 hwnd, data->whole_window, cmd, wine_dbgstr_rect(rect), swp );
2404
2405 wine_tsx11_lock();
2406 XGetGeometry( thread_data->display, data->whole_window,
2407 &root, &x, &y, &width, &height, &border, &depth );
2408 XTranslateCoordinates( thread_data->display, data->whole_window, root, 0, 0, &x, &y, &top );
2409 wine_tsx11_unlock();
2410 rect->left = x;
2411 rect->top = y;
2412 rect->right = x + width;
2413 rect->bottom = y + height;
2414 OffsetRect( rect, virtual_screen_rect.left, virtual_screen_rect.top );
2415 X11DRV_X_to_window_rect( data, rect );
2416 return swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE);
2417}
2418
2419
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002420/**********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00002421 * SetWindowIcon (X11DRV.@)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002422 *
2423 * hIcon or hIconSm has changed (or is being initialised for the
2424 * first time). Complete the X11 driver-specific initialisation
2425 * and set the window hints.
2426 *
2427 * This is not entirely correct, may need to create
2428 * an icon window and set the pixmap as a background
2429 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002430void CDECL X11DRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon )
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002431{
Alexandre Julliard43230042001-05-16 19:52:29 +00002432 Display *display = thread_display();
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002433 struct x11drv_win_data *data;
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002434
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002435
Alexandre Julliardfc5ce142005-01-17 19:17:47 +00002436 if (!(data = X11DRV_get_win_data( hwnd ))) return;
Alexandre Julliardf777d702005-01-31 16:34:07 +00002437 if (!data->whole_window) return;
Alexandre Julliardd7726c32005-02-01 18:53:59 +00002438 if (!data->managed) return;
Alexandre Julliard8fd26b92001-10-15 17:56:45 +00002439
Alexandre Julliardbde89572007-08-16 23:27:37 +02002440 if (data->wm_hints)
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002441 {
Alexandre Julliarda551dfe2010-04-19 17:51:44 +02002442 if (type == ICON_BIG) set_icon_hints( display, data, icon, 0 );
2443 else set_icon_hints( display, data, 0, icon );
Alexandre Julliarde9119c12002-09-24 18:36:51 +00002444 wine_tsx11_lock();
Alexandre Julliardbde89572007-08-16 23:27:37 +02002445 XSetWMHints( display, data->whole_window, data->wm_hints );
Alexandre Julliarde9119c12002-09-24 18:36:51 +00002446 wine_tsx11_unlock();
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002447 }
Alexandre Julliard9ae0fe52001-04-24 23:28:52 +00002448}
Alexandre Julliard395928d2008-01-23 16:30:18 +01002449
2450
2451/***********************************************************************
2452 * SetWindowRgn (X11DRV.@)
2453 *
2454 * Assign specified region to window (for non-rectangular windows)
2455 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002456int CDECL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
Alexandre Julliard395928d2008-01-23 16:30:18 +01002457{
2458 struct x11drv_win_data *data;
2459
2460 if ((data = X11DRV_get_win_data( hwnd )))
2461 {
2462 sync_window_region( thread_display(), data, hrgn );
Alexandre Julliard395928d2008-01-23 16:30:18 +01002463 }
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +02002464 else if (X11DRV_get_whole_window( hwnd ))
Alexandre Julliard395928d2008-01-23 16:30:18 +01002465 {
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +02002466 SendMessageW( hwnd, WM_X11DRV_SET_WIN_REGION, 0, 0 );
Alexandre Julliard395928d2008-01-23 16:30:18 +01002467 }
Alexandre Julliard395928d2008-01-23 16:30:18 +01002468 return TRUE;
2469}
Alexandre Julliard24dbaa02008-04-17 16:13:34 +02002470
2471
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02002472/***********************************************************************
2473 * SetLayeredWindowAttributes (X11DRV.@)
2474 *
2475 * Set transparency attributes for a layered window.
2476 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002477void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02002478{
Alexandre Julliardfb84ba52008-09-22 12:52:53 +02002479 struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02002480
Alexandre Julliardfb84ba52008-09-22 12:52:53 +02002481 if (data)
2482 {
2483 if (data->whole_window)
2484 sync_window_opacity( thread_display(), data->whole_window, key, alpha, flags );
2485 }
2486 else
2487 {
2488 Window win = X11DRV_get_whole_window( hwnd );
2489 if (win) sync_window_opacity( gdi_display, win, key, alpha, flags );
2490 }
Alexandre Julliardbe3c3a52008-09-12 15:54:02 +02002491}
2492
2493
Alexandre Julliard370368a2008-09-08 15:42:24 +02002494/**********************************************************************
2495 * X11DRV_WindowMessage (X11DRV.@)
2496 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002497LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
Alexandre Julliard370368a2008-09-08 15:42:24 +02002498{
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +02002499 struct x11drv_win_data *data;
2500
Alexandre Julliard370368a2008-09-08 15:42:24 +02002501 switch(msg)
2502 {
2503 case WM_X11DRV_ACQUIRE_SELECTION:
2504 return X11DRV_AcquireClipboard( hwnd );
Alexandre Julliard370368a2008-09-08 15:42:24 +02002505 case WM_X11DRV_SET_WIN_FORMAT:
2506 return set_win_format( hwnd, (XID)wp );
Alexandre Julliard9d45cfd2008-09-08 15:51:08 +02002507 case WM_X11DRV_SET_WIN_REGION:
2508 if ((data = X11DRV_get_win_data( hwnd ))) sync_window_region( thread_display(), data, (HRGN)1 );
2509 return 0;
Alexandre Julliard370368a2008-09-08 15:42:24 +02002510 case WM_X11DRV_RESIZE_DESKTOP:
2511 X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) );
2512 return 0;
Alexandre Julliard65515532010-04-28 19:23:05 -05002513 case WM_X11DRV_SET_CURSOR:
2514 set_window_cursor( hwnd, (HCURSOR)lp );
2515 return 0;
Alexandre Julliard370368a2008-09-08 15:42:24 +02002516 default:
2517 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
2518 return 0;
2519 }
2520}
2521
2522
Alexandre Julliard24dbaa02008-04-17 16:13:34 +02002523/***********************************************************************
2524 * is_netwm_supported
2525 */
2526static BOOL is_netwm_supported( Display *display, Atom atom )
2527{
2528 static Atom *net_supported;
2529 static int net_supported_count = -1;
2530 int i;
2531
2532 wine_tsx11_lock();
2533 if (net_supported_count == -1)
2534 {
2535 Atom type;
2536 int format;
2537 unsigned long count, remaining;
2538
2539 if (!XGetWindowProperty( display, DefaultRootWindow(display), x11drv_atom(_NET_SUPPORTED), 0,
2540 ~0UL, False, XA_ATOM, &type, &format, &count,
2541 &remaining, (unsigned char **)&net_supported ))
2542 net_supported_count = get_property_size( format, count ) / sizeof(Atom);
2543 else
2544 net_supported_count = 0;
2545 }
2546 wine_tsx11_unlock();
2547
2548 for (i = 0; i < net_supported_count; i++)
2549 if (net_supported[i] == atom) return TRUE;
2550 return FALSE;
2551}
2552
2553
2554/***********************************************************************
2555 * SysCommand (X11DRV.@)
2556 *
2557 * Perform WM_SYSCOMMAND handling.
2558 */
Maarten Lankhorst0a645952008-12-16 15:32:08 +01002559LRESULT CDECL X11DRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam )
Alexandre Julliard24dbaa02008-04-17 16:13:34 +02002560{
2561 WPARAM hittest = wparam & 0x0f;
2562 DWORD dwPoint;
2563 int x, y, dir;
2564 XEvent xev;
2565 Display *display = thread_display();
2566 struct x11drv_win_data *data;
2567
2568 if (!(data = X11DRV_get_win_data( hwnd ))) return -1;
2569 if (!data->whole_window || !data->managed || !data->mapped) return -1;
2570
2571 switch (wparam & 0xfff0)
2572 {
2573 case SC_MOVE:
2574 if (!hittest) dir = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
2575 else dir = _NET_WM_MOVERESIZE_MOVE;
2576 break;
2577 case SC_SIZE:
2578 /* windows without WS_THICKFRAME are not resizable through the window manager */
2579 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_THICKFRAME)) return -1;
2580
2581 switch (hittest)
2582 {
2583 case WMSZ_LEFT: dir = _NET_WM_MOVERESIZE_SIZE_LEFT; break;
2584 case WMSZ_RIGHT: dir = _NET_WM_MOVERESIZE_SIZE_RIGHT; break;
2585 case WMSZ_TOP: dir = _NET_WM_MOVERESIZE_SIZE_TOP; break;
2586 case WMSZ_TOPLEFT: dir = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; break;
2587 case WMSZ_TOPRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; break;
2588 case WMSZ_BOTTOM: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOM; break;
2589 case WMSZ_BOTTOMLEFT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; break;
2590 case WMSZ_BOTTOMRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; break;
2591 default: dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD; break;
2592 }
2593 break;
2594
2595 case SC_KEYMENU:
2596 /* prevent a simple ALT press+release from activating the system menu,
2597 * as that can get confusing on managed windows */
2598 if ((WCHAR)lparam) return -1; /* got an explicit char */
2599 if (GetMenu( hwnd )) return -1; /* window has a real menu */
2600 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return -1; /* no system menu */
2601 TRACE( "ignoring SC_KEYMENU wp %lx lp %lx\n", wparam, lparam );
2602 return 0;
2603
2604 default:
2605 return -1;
2606 }
2607
2608 if (IsZoomed(hwnd)) return -1;
2609
2610 if (!is_netwm_supported( display, x11drv_atom(_NET_WM_MOVERESIZE) ))
2611 {
2612 TRACE( "_NET_WM_MOVERESIZE not supported\n" );
2613 return -1;
2614 }
2615
2616 dwPoint = GetMessagePos();
2617 x = (short)LOWORD(dwPoint);
2618 y = (short)HIWORD(dwPoint);
2619
2620 TRACE("hwnd %p, x %d, y %d, dir %d\n", hwnd, x, y, dir);
2621
2622 xev.xclient.type = ClientMessage;
2623 xev.xclient.window = X11DRV_get_whole_window(hwnd);
2624 xev.xclient.message_type = x11drv_atom(_NET_WM_MOVERESIZE);
2625 xev.xclient.serial = 0;
2626 xev.xclient.display = display;
2627 xev.xclient.send_event = True;
2628 xev.xclient.format = 32;
Alexandre Julliard9fab7b42008-09-12 11:03:26 +02002629 xev.xclient.data.l[0] = x - virtual_screen_rect.left; /* x coord */
2630 xev.xclient.data.l[1] = y - virtual_screen_rect.top; /* y coord */
Alexandre Julliard24dbaa02008-04-17 16:13:34 +02002631 xev.xclient.data.l[2] = dir; /* direction */
2632 xev.xclient.data.l[3] = 1; /* button */
2633 xev.xclient.data.l[4] = 0; /* unused */
2634
2635 /* need to ungrab the pointer that may have been automatically grabbed
2636 * with a ButtonPress event */
2637 wine_tsx11_lock();
2638 XUngrabPointer( display, CurrentTime );
2639 XSendEvent(display, root_window, False, SubstructureNotifyMask, &xev);
2640 wine_tsx11_unlock();
2641 return 0;
2642}