user32: Use the stored color and mask bitmaps instead of the raw bits in GetIconInfo.
[wine] / dlls / winex11.drv / window.c
1 /*
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
7  *
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
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include <X11/Xlib.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
35 #ifdef HAVE_LIBXSHAPE
36 #include <X11/extensions/shape.h>
37 #endif /* HAVE_LIBXSHAPE */
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "wine/unicode.h"
44
45 #include "x11drv.h"
46 #include "xcomposite.h"
47 #include "wine/debug.h"
48 #include "wine/server.h"
49 #include "mwm.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
52
53 #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
65 #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
71 /* X context to associate a hwnd to an X window */
72 XContext winContext = 0;
73
74 /* X context to associate a struct x11drv_win_data to an hwnd */
75 static XContext win_data_context;
76
77 static const char whole_window_prop[] = "__wine_x11_whole_window";
78 static const char client_window_prop[]= "__wine_x11_client_window";
79 static const char icon_window_prop[]  = "__wine_x11_icon_window";
80 static const char fbconfig_id_prop[]  = "__wine_x11_fbconfig_id";
81 static const char gl_drawable_prop[]  = "__wine_x11_gl_drawable";
82 static const char pixmap_prop[]       = "__wine_x11_pixmap";
83 static const char managed_prop[]      = "__wine_x11_managed";
84
85
86 /***********************************************************************
87  * http://standards.freedesktop.org/startup-notification-spec
88  */
89 static 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
145 struct has_popup_result
146 {
147     HWND hwnd;
148     BOOL found;
149 };
150
151 static 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
160 static 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
170 /***********************************************************************
171  *              is_window_managed
172  *
173  * Check if a given window should be managed
174  */
175 static BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rect )
176 {
177     DWORD style, ex_style;
178
179     if (!managed_mode) return FALSE;
180
181     /* child windows are not managed */
182     style = GetWindowLongW( hwnd, GWL_STYLE );
183     if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) return FALSE;
184     /* activated windows are managed */
185     if (!(swp_flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) return TRUE;
186     if (hwnd == GetActiveWindow()) return TRUE;
187     /* windows with caption are managed */
188     if ((style & WS_CAPTION) == WS_CAPTION) return TRUE;
189     /* windows with thick frame are managed */
190     if (style & WS_THICKFRAME) return TRUE;
191     if (style & WS_POPUP)
192     {
193         HMONITOR hmon;
194         MONITORINFO mi;
195
196         /* popup with sysmenu == caption are managed */
197         if (style & WS_SYSMENU) return TRUE;
198         /* full-screen popup windows are managed */
199         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)
204             return TRUE;
205     }
206     /* application windows are managed */
207     ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
208     if (ex_style & WS_EX_APPWINDOW) return TRUE;
209     /* windows that own popups are managed */
210     if (has_owned_popups( hwnd )) return TRUE;
211     /* default: not managed */
212     return FALSE;
213 }
214
215
216 /***********************************************************************
217  *              X11DRV_is_window_rect_mapped
218  *
219  * Check if the X whole window should be mapped based on its rectangle
220  */
221 static BOOL is_window_rect_mapped( const RECT *rect )
222 {
223     /* don't map if rect is empty */
224     if (IsRectEmpty( rect )) return FALSE;
225
226     /* don't map if rect is off-screen */
227     if (rect->left >= virtual_screen_rect.right ||
228         rect->top >= virtual_screen_rect.bottom ||
229         rect->right <= virtual_screen_rect.left ||
230         rect->bottom <= virtual_screen_rect.top)
231         return FALSE;
232
233     return TRUE;
234 }
235
236
237 /***********************************************************************
238  *              is_window_resizable
239  *
240  * Check if window should be made resizable by the window manager
241  */
242 static inline BOOL is_window_resizable( struct x11drv_win_data *data, DWORD style )
243 {
244     if (style & WS_THICKFRAME) return TRUE;
245     /* Metacity needs the window to be resizable to make it fullscreen */
246     return (data->whole_rect.left <= 0 && data->whole_rect.right >= screen_width &&
247             data->whole_rect.top <= 0 && data->whole_rect.bottom >= screen_height);
248 }
249
250
251 /***********************************************************************
252  *              get_window_owner
253  */
254 static HWND get_window_owner( HWND hwnd )
255 {
256     RECT rect;
257     HWND owner = GetWindow( hwnd, GW_OWNER );
258     /* ignore the zero-size owners used by Delphi apps */
259     if (owner && GetWindowRect( owner, &rect ) && IsRectEmpty( &rect )) owner = 0;
260     return owner;
261 }
262
263
264 /***********************************************************************
265  *              get_mwm_decorations
266  */
267 static unsigned long get_mwm_decorations( struct x11drv_win_data *data,
268                                           DWORD style, DWORD ex_style )
269 {
270     unsigned long ret = 0;
271
272     if (!decorated_mode) return 0;
273
274     if (IsRectEmpty( &data->window_rect )) return 0;
275     if (data->shaped) return 0;
276
277     if (ex_style & WS_EX_TOOLWINDOW) return 0;
278
279     if ((style & WS_CAPTION) == WS_CAPTION)
280     {
281         ret |= MWM_DECOR_TITLE | MWM_DECOR_BORDER;
282         if (style & WS_SYSMENU) ret |= MWM_DECOR_MENU;
283         if (style & WS_MINIMIZEBOX) ret |= MWM_DECOR_MINIMIZE;
284         if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE;
285     }
286     if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER;
287     else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
288     else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER;
289     return ret;
290 }
291
292
293 /***********************************************************************
294  *              get_x11_rect_offset
295  *
296  * Helper for X11DRV_window_to_X_rect and X11DRV_X_to_window_rect.
297  */
298 static void get_x11_rect_offset( struct x11drv_win_data *data, RECT *rect )
299 {
300     DWORD style, ex_style, style_mask = 0, ex_style_mask = 0;
301     unsigned long decor;
302
303     rect->top = rect->bottom = rect->left = rect->right = 0;
304
305     style = GetWindowLongW( data->hwnd, GWL_STYLE );
306     ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
307     decor = get_mwm_decorations( data, style, ex_style );
308
309     if (decor & MWM_DECOR_TITLE) style_mask |= WS_CAPTION;
310     if (decor & MWM_DECOR_BORDER)
311     {
312         style_mask |= WS_DLGFRAME | WS_THICKFRAME;
313         ex_style_mask |= WS_EX_DLGMODALFRAME;
314     }
315
316     AdjustWindowRectEx( rect, style & style_mask, FALSE, ex_style & ex_style_mask );
317 }
318
319
320 /***********************************************************************
321  *              get_window_attributes
322  *
323  * Fill the window attributes structure for an X window.
324  */
325 static int get_window_attributes( Display *display, struct x11drv_win_data *data,
326                                   XSetWindowAttributes *attr )
327 {
328     attr->override_redirect = !data->managed;
329     attr->colormap          = X11DRV_PALETTE_PaletteXColormap;
330     attr->save_under        = ((GetClassLongW( data->hwnd, GCL_STYLE ) & CS_SAVEBITS) != 0);
331     attr->bit_gravity       = NorthWestGravity;
332     attr->win_gravity       = StaticGravity;
333     attr->backing_store     = NotUseful;
334     attr->event_mask        = (ExposureMask | PointerMotionMask |
335                                ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
336                                KeyPressMask | KeyReleaseMask | FocusChangeMask |
337                                KeymapStateMask | StructureNotifyMask);
338     if (data->managed) attr->event_mask |= PropertyChangeMask;
339
340     return (CWOverrideRedirect | CWSaveUnder | CWColormap |
341             CWEventMask | CWBitGravity | CWBackingStore);
342 }
343
344
345 /***********************************************************************
346  *              create_client_window
347  */
348 static Window create_client_window( Display *display, struct x11drv_win_data *data, XVisualInfo *vis )
349 {
350     int cx, cy, mask;
351     XSetWindowAttributes attr;
352     Window client;
353     Visual *client_visual = vis ? vis->visual : visual;
354
355     attr.bit_gravity = NorthWestGravity;
356     attr.win_gravity = NorthWestGravity;
357     attr.backing_store = NotUseful;
358     attr.event_mask = (ExposureMask | PointerMotionMask |
359                        ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
360     mask = CWEventMask | CWBitGravity | CWWinGravity | CWBackingStore;
361
362     if ((cx = data->client_rect.right - data->client_rect.left) <= 0) cx = 1;
363     else if (cx > 65535) cx = 65535;
364     if ((cy = data->client_rect.bottom - data->client_rect.top) <= 0) cy = 1;
365     else if (cy > 65535) cy = 65535;
366
367     wine_tsx11_lock();
368
369     if (vis)
370     {
371         attr.colormap = XCreateColormap( display, root_window, vis->visual,
372                                          (vis->class == PseudoColor || vis->class == GrayScale ||
373                                           vis->class == DirectColor) ? AllocAll : AllocNone );
374         mask |= CWColormap;
375     }
376
377     client = XCreateWindow( display, data->whole_window,
378                             data->client_rect.left - data->whole_rect.left,
379                             data->client_rect.top - data->whole_rect.top,
380                             cx, cy, 0, screen_depth, InputOutput,
381                             client_visual, mask, &attr );
382     if (!client)
383     {
384         wine_tsx11_unlock();
385         return 0;
386     }
387
388     if (data->client_window)
389     {
390         XDeleteContext( display, data->client_window, winContext );
391         XDestroyWindow( display, data->client_window );
392     }
393     data->client_window = client;
394     data->visualid = XVisualIDFromVisual( client_visual );
395
396     if (data->colormap) XFreeColormap( display, data->colormap );
397     data->colormap = vis ? attr.colormap : 0;
398
399     XMapWindow( display, data->client_window );
400     XSaveContext( display, data->client_window, winContext, (char *)data->hwnd );
401     wine_tsx11_unlock();
402
403     SetPropA( data->hwnd, client_window_prop, (HANDLE)data->client_window );
404     return data->client_window;
405 }
406
407
408 /***********************************************************************
409  *              sync_window_style
410  *
411  * Change the X window attributes when the window style has changed.
412  */
413 static void sync_window_style( Display *display, struct x11drv_win_data *data )
414 {
415     if (data->whole_window != root_window)
416     {
417         XSetWindowAttributes attr;
418         int mask = get_window_attributes( display, data, &attr );
419
420         wine_tsx11_lock();
421         XChangeWindowAttributes( display, data->whole_window, mask, &attr );
422         wine_tsx11_unlock();
423     }
424 }
425
426
427 /***********************************************************************
428  *              sync_window_cursor
429  */
430 static void sync_window_cursor( struct x11drv_win_data *data )
431 {
432     HCURSOR cursor;
433
434     SERVER_START_REQ( set_cursor )
435     {
436         req->flags = 0;
437         wine_server_call( req );
438         cursor = reply->prev_count >= 0 ? wine_server_ptr_handle( reply->prev_handle ) : 0;
439     }
440     SERVER_END_REQ;
441
442     set_window_cursor( data->hwnd, cursor );
443 }
444
445
446 /***********************************************************************
447  *              sync_window_region
448  *
449  * Update the X11 window region.
450  */
451 static void sync_window_region( Display *display, struct x11drv_win_data *data, HRGN win_region )
452 {
453 #ifdef HAVE_LIBXSHAPE
454     HRGN hrgn = win_region;
455
456     if (!data->whole_window) return;
457     data->shaped = FALSE;
458
459     if (hrgn == (HRGN)1)  /* hack: win_region == 1 means retrieve region from server */
460     {
461         if (!(hrgn = CreateRectRgn( 0, 0, 0, 0 ))) return;
462         if (GetWindowRgn( data->hwnd, hrgn ) == ERROR)
463         {
464             DeleteObject( hrgn );
465             hrgn = 0;
466         }
467     }
468
469     if (!hrgn)
470     {
471         wine_tsx11_lock();
472         XShapeCombineMask( display, data->whole_window, ShapeBounding, 0, 0, None, ShapeSet );
473         wine_tsx11_unlock();
474     }
475     else
476     {
477         RGNDATA *pRegionData = X11DRV_GetRegionData( hrgn, 0 );
478         if (pRegionData)
479         {
480             wine_tsx11_lock();
481             XShapeCombineRectangles( display, data->whole_window, ShapeBounding,
482                                      data->window_rect.left - data->whole_rect.left,
483                                      data->window_rect.top - data->whole_rect.top,
484                                      (XRectangle *)pRegionData->Buffer,
485                                      pRegionData->rdh.nCount, ShapeSet, YXBanded );
486             wine_tsx11_unlock();
487             HeapFree(GetProcessHeap(), 0, pRegionData);
488             data->shaped = TRUE;
489         }
490     }
491     if (hrgn && hrgn != win_region) DeleteObject( hrgn );
492 #endif  /* HAVE_LIBXSHAPE */
493 }
494
495
496 /***********************************************************************
497  *              sync_window_opacity
498  */
499 static void sync_window_opacity( Display *display, Window win,
500                                  COLORREF key, BYTE alpha, DWORD flags )
501 {
502     unsigned long opacity = 0xffffffff;
503
504     if (flags & LWA_ALPHA) opacity = (0xffffffff / 0xff) * alpha;
505
506     if (flags & LWA_COLORKEY) FIXME("LWA_COLORKEY not supported\n");
507
508     wine_tsx11_lock();
509     if (opacity == 0xffffffff)
510         XDeleteProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY) );
511     else
512         XChangeProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY),
513                          XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1 );
514     wine_tsx11_unlock();
515 }
516
517
518 /***********************************************************************
519  *              sync_window_text
520  */
521 static void sync_window_text( Display *display, Window win, const WCHAR *text )
522 {
523     UINT count;
524     char *buffer, *utf8_buffer;
525     XTextProperty prop;
526
527     /* allocate new buffer for window text */
528     count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL);
529     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count ))) return;
530     WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL);
531
532     count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
533     if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count )))
534     {
535         HeapFree( GetProcessHeap(), 0, buffer );
536         return;
537     }
538     WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
539
540     wine_tsx11_lock();
541     if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success)
542     {
543         XSetWMName( display, win, &prop );
544         XSetWMIconName( display, win, &prop );
545         XFree( prop.value );
546     }
547     /*
548       Implements a NET_WM UTF-8 title. It should be without a trailing \0,
549       according to the standard
550       ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
551     */
552     XChangeProperty( display, win, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING),
553                      8, PropModeReplace, (unsigned char *) utf8_buffer, count);
554     wine_tsx11_unlock();
555
556     HeapFree( GetProcessHeap(), 0, utf8_buffer );
557     HeapFree( GetProcessHeap(), 0, buffer );
558 }
559
560
561 /***********************************************************************
562  *              set_win_format
563  */
564 static BOOL set_win_format( HWND hwnd, XID fbconfig_id )
565 {
566     struct x11drv_win_data *data;
567     XVisualInfo *vis;
568     int w, h;
569
570     if (!(data = X11DRV_get_win_data(hwnd)) &&
571         !(data = X11DRV_create_win_data(hwnd))) return FALSE;
572
573     if (!(vis = visual_from_fbconfig_id(fbconfig_id))) return FALSE;
574
575     if (data->whole_window)
576     {
577         Display *display = thread_display();
578         Window client = data->client_window;
579
580         if (vis->visualid != data->visualid)
581         {
582             client = create_client_window( display, data, vis );
583             TRACE( "re-created client window %lx for %p fbconfig %lx\n", client, data->hwnd, fbconfig_id );
584         }
585         wine_tsx11_lock();
586         XFree(vis);
587         XFlush( display );
588         wine_tsx11_unlock();
589         if (client) goto done;
590         return FALSE;
591     }
592
593     w = data->client_rect.right - data->client_rect.left;
594     h = data->client_rect.bottom - data->client_rect.top;
595
596     if(w <= 0) w = 1;
597     if(h <= 0) h = 1;
598
599 #ifdef SONAME_LIBXCOMPOSITE
600     if(usexcomposite)
601     {
602         XSetWindowAttributes attrib;
603         static Window dummy_parent;
604
605         wine_tsx11_lock();
606         attrib.override_redirect = True;
607         if (!dummy_parent)
608         {
609             dummy_parent = XCreateWindow( gdi_display, root_window, -1, -1, 1, 1, 0, screen_depth,
610                                          InputOutput, visual, CWOverrideRedirect, &attrib );
611             XMapWindow( gdi_display, dummy_parent );
612         }
613         data->colormap = XCreateColormap(gdi_display, dummy_parent, vis->visual,
614                                          (vis->class == PseudoColor ||
615                                           vis->class == GrayScale ||
616                                           vis->class == DirectColor) ?
617                                          AllocAll : AllocNone);
618         attrib.colormap = data->colormap;
619         XInstallColormap(gdi_display, attrib.colormap);
620
621         if(data->gl_drawable) XDestroyWindow(gdi_display, data->gl_drawable);
622         data->gl_drawable = XCreateWindow(gdi_display, dummy_parent, -w, 0, w, h, 0,
623                                           vis->depth, InputOutput, vis->visual,
624                                           CWColormap | CWOverrideRedirect,
625                                           &attrib);
626         if(data->gl_drawable)
627         {
628             pXCompositeRedirectWindow(gdi_display, data->gl_drawable,
629                                       CompositeRedirectManual);
630             XMapWindow(gdi_display, data->gl_drawable);
631         }
632         XFree(vis);
633         XFlush( gdi_display );
634         wine_tsx11_unlock();
635     }
636     else
637 #endif
638     {
639         WARN("XComposite is not available, using GLXPixmap hack\n");
640
641         wine_tsx11_lock();
642
643         if(data->pixmap) XFreePixmap(gdi_display, data->pixmap);
644         data->pixmap = XCreatePixmap(gdi_display, root_window, w, h, vis->depth);
645         if(!data->pixmap)
646         {
647             XFree(vis);
648             wine_tsx11_unlock();
649             return FALSE;
650         }
651
652         if(data->gl_drawable) destroy_glxpixmap(gdi_display, data->gl_drawable);
653         data->gl_drawable = create_glxpixmap(gdi_display, vis, data->pixmap);
654         if(!data->gl_drawable)
655         {
656             XFreePixmap(gdi_display, data->pixmap);
657             data->pixmap = 0;
658         }
659         XFree(vis);
660         XFlush( gdi_display );
661         wine_tsx11_unlock();
662         if (data->pixmap) SetPropA(hwnd, pixmap_prop, (HANDLE)data->pixmap);
663     }
664
665     if (!data->gl_drawable) return FALSE;
666
667     TRACE("Created GL drawable 0x%lx, using FBConfigID 0x%lx\n",
668           data->gl_drawable, fbconfig_id);
669     SetPropA(hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
670
671 done:
672     data->fbconfig_id = fbconfig_id;
673     SetPropA(hwnd, fbconfig_id_prop, (HANDLE)data->fbconfig_id);
674     /* force DCE invalidation */
675     SetWindowPos( hwnd, 0, 0, 0, 0, 0,
676                   SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
677                   SWP_NOREDRAW | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_STATECHANGED);
678     return TRUE;
679 }
680
681 /***********************************************************************
682  *              sync_gl_drawable
683  */
684 static void sync_gl_drawable(struct x11drv_win_data *data)
685 {
686     int w = data->client_rect.right - data->client_rect.left;
687     int h = data->client_rect.bottom - data->client_rect.top;
688     XVisualInfo *vis;
689     Drawable glxp;
690     Pixmap pix;
691
692     if (w <= 0) w = 1;
693     if (h <= 0) h = 1;
694
695     TRACE("Resizing GL drawable 0x%lx to %dx%d\n", data->gl_drawable, w, h);
696 #ifdef SONAME_LIBXCOMPOSITE
697     if(usexcomposite)
698     {
699         wine_tsx11_lock();
700         XMoveResizeWindow(gdi_display, data->gl_drawable, -w, 0, w, h);
701         wine_tsx11_unlock();
702         return;
703     }
704 #endif
705
706     if (!(vis = visual_from_fbconfig_id(data->fbconfig_id))) return;
707
708     wine_tsx11_lock();
709     pix = XCreatePixmap(gdi_display, root_window, w, h, vis->depth);
710     if(!pix)
711     {
712         ERR("Failed to create pixmap for offscreen rendering\n");
713         XFree(vis);
714         wine_tsx11_unlock();
715         return;
716     }
717
718     glxp = create_glxpixmap(gdi_display, vis, pix);
719     if(!glxp)
720     {
721         ERR("Failed to create drawable for offscreen rendering\n");
722         XFreePixmap(gdi_display, pix);
723         XFree(vis);
724         wine_tsx11_unlock();
725         return;
726     }
727
728     XFree(vis);
729
730     mark_drawable_dirty(data->gl_drawable, glxp);
731
732     XFreePixmap(gdi_display, data->pixmap);
733     destroy_glxpixmap(gdi_display, data->gl_drawable);
734     TRACE( "Recreated GL drawable %lx to replace %lx\n", glxp, data->gl_drawable );
735
736     data->pixmap = pix;
737     data->gl_drawable = glxp;
738
739     XFlush( gdi_display );
740     wine_tsx11_unlock();
741
742     SetPropA(data->hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
743     SetPropA(data->hwnd, pixmap_prop, (HANDLE)data->pixmap);
744 }
745
746
747 /***********************************************************************
748  *              get_window_changes
749  *
750  * fill the window changes structure
751  */
752 static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
753 {
754     int mask = 0;
755
756     if (old->right - old->left != new->right - new->left )
757     {
758         if ((changes->width = new->right - new->left) <= 0) changes->width = 1;
759         else if (changes->width > 65535) changes->width = 65535;
760         mask |= CWWidth;
761     }
762     if (old->bottom - old->top != new->bottom - new->top)
763     {
764         if ((changes->height = new->bottom - new->top) <= 0) changes->height = 1;
765         else if (changes->height > 65535) changes->height = 65535;
766         mask |= CWHeight;
767     }
768     if (old->left != new->left)
769     {
770         changes->x = new->left;
771         mask |= CWX;
772     }
773     if (old->top != new->top)
774     {
775         changes->y = new->top;
776         mask |= CWY;
777     }
778     return mask;
779 }
780
781
782 /***********************************************************************
783  *              create_icon_window
784  */
785 static Window create_icon_window( Display *display, struct x11drv_win_data *data )
786 {
787     XSetWindowAttributes attr;
788
789     attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
790                        ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
791     attr.bit_gravity = NorthWestGravity;
792     attr.backing_store = NotUseful/*WhenMapped*/;
793     attr.colormap      = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
794
795     wine_tsx11_lock();
796     data->icon_window = XCreateWindow( display, root_window, 0, 0,
797                                        GetSystemMetrics( SM_CXICON ),
798                                        GetSystemMetrics( SM_CYICON ),
799                                        0, screen_depth,
800                                        InputOutput, visual,
801                                        CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
802     XSaveContext( display, data->icon_window, winContext, (char *)data->hwnd );
803     XFlush( display );  /* make sure the window exists before we start painting to it */
804     wine_tsx11_unlock();
805
806     TRACE( "created %lx\n", data->icon_window );
807     SetPropA( data->hwnd, icon_window_prop, (HANDLE)data->icon_window );
808     return data->icon_window;
809 }
810
811
812
813 /***********************************************************************
814  *              destroy_icon_window
815  */
816 static void destroy_icon_window( Display *display, struct x11drv_win_data *data )
817 {
818     if (!data->icon_window) return;
819     wine_tsx11_lock();
820     XDeleteContext( display, data->icon_window, winContext );
821     XDestroyWindow( display, data->icon_window );
822     data->icon_window = 0;
823     wine_tsx11_unlock();
824     RemovePropA( data->hwnd, icon_window_prop );
825 }
826
827
828 /***********************************************************************
829  *              get_bitmap_argb
830  *
831  * Return the bitmap bits in ARGB format. Helper for setting icon hints.
832  */
833 static unsigned long *get_bitmap_argb( HDC hdc, HBITMAP color, HBITMAP mask, unsigned int *size )
834 {
835     BITMAP bm;
836     BITMAPINFO *info;
837     unsigned int *ptr, *bits = NULL;
838     unsigned char *mask_bits = NULL;
839     int i, j, has_alpha = 0;
840
841     if (!GetObjectW( color, sizeof(bm), &bm )) return NULL;
842     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return NULL;
843     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
844     info->bmiHeader.biWidth = bm.bmWidth;
845     info->bmiHeader.biHeight = -bm.bmHeight;
846     info->bmiHeader.biPlanes = 1;
847     info->bmiHeader.biBitCount = 32;
848     info->bmiHeader.biCompression = BI_RGB;
849     info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
850     info->bmiHeader.biXPelsPerMeter = 0;
851     info->bmiHeader.biYPelsPerMeter = 0;
852     info->bmiHeader.biClrUsed = 0;
853     info->bmiHeader.biClrImportant = 0;
854     *size = bm.bmWidth * bm.bmHeight + 2;
855     if (!(bits = HeapAlloc( GetProcessHeap(), 0, *size * sizeof(long) ))) goto failed;
856     if (!GetDIBits( hdc, color, 0, bm.bmHeight, bits + 2, info, DIB_RGB_COLORS )) goto failed;
857
858     bits[0] = bm.bmWidth;
859     bits[1] = bm.bmHeight;
860
861     for (i = 0; i < bm.bmWidth * bm.bmHeight; i++)
862         if ((has_alpha = (bits[i + 2] & 0xff000000) != 0)) break;
863
864     if (!has_alpha)
865     {
866         unsigned int width_bytes = (bm.bmWidth + 31) / 32 * 4;
867         /* generate alpha channel from the mask */
868         info->bmiHeader.biBitCount = 1;
869         info->bmiHeader.biSizeImage = width_bytes * bm.bmHeight;
870         if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto failed;
871         if (!GetDIBits( hdc, mask, 0, bm.bmHeight, mask_bits, info, DIB_RGB_COLORS )) goto failed;
872         ptr = bits + 2;
873         for (i = 0; i < bm.bmHeight; i++)
874             for (j = 0; j < bm.bmWidth; j++, ptr++)
875                 if (!((mask_bits[i * width_bytes + j / 8] << (j % 8)) & 0x80)) *ptr |= 0xff000000;
876         HeapFree( GetProcessHeap(), 0, mask_bits );
877     }
878     HeapFree( GetProcessHeap(), 0, info );
879
880     /* convert to array of longs */
881     if (bits && sizeof(long) > sizeof(int))
882         for (i = *size - 1; i >= 0; i--) ((unsigned long *)bits)[i] = bits[i];
883
884     return (unsigned long *)bits;
885
886 failed:
887     HeapFree( GetProcessHeap(), 0, info );
888     HeapFree( GetProcessHeap(), 0, bits );
889     HeapFree( GetProcessHeap(), 0, mask_bits );
890     return NULL;
891 }
892
893
894 /***********************************************************************
895  *              set_icon_hints
896  *
897  * Set the icon wm hints
898  */
899 static void set_icon_hints( Display *display, struct x11drv_win_data *data,
900                             HICON icon_big, HICON icon_small )
901 {
902     XWMHints *hints = data->wm_hints;
903
904     if (!icon_big)
905     {
906         icon_big = (HICON)SendMessageW( data->hwnd, WM_GETICON, ICON_BIG, 0 );
907         if (!icon_big) icon_big = (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICON );
908     }
909     if (!icon_small)
910     {
911         icon_small = (HICON)SendMessageW( data->hwnd, WM_GETICON, ICON_SMALL, 0 );
912         if (!icon_small) icon_small = (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICONSM );
913     }
914
915     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
916     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
917     data->hWMIconBitmap = 0;
918     data->hWMIconMask = 0;
919
920     if (!icon_big)
921     {
922         if (!data->icon_window) create_icon_window( display, data );
923         hints->icon_window = data->icon_window;
924         hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
925     }
926     else
927     {
928         HBITMAP hbmOrig;
929         RECT rcMask;
930         BITMAP bm;
931         ICONINFO ii;
932         HDC hDC;
933         unsigned int size;
934         unsigned long *bits;
935
936         GetIconInfo(icon_big, &ii);
937
938         GetObjectW(ii.hbmMask, sizeof(bm), &bm);
939         rcMask.top    = 0;
940         rcMask.left   = 0;
941         rcMask.right  = bm.bmWidth;
942         rcMask.bottom = bm.bmHeight;
943
944         hDC = CreateCompatibleDC(0);
945         bits = get_bitmap_argb( hDC, ii.hbmColor, ii.hbmMask, &size );
946         if (GetIconInfo( icon_small, &ii ))
947         {
948             unsigned int size_small;
949             unsigned long *bits_small, *new;
950
951             if ((bits_small = get_bitmap_argb( hDC, ii.hbmColor, ii.hbmMask, &size_small )) &&
952                 (bits_small[0] != bits[0] || bits_small[1] != bits[1]))  /* size must be different */
953             {
954                 if ((new = HeapReAlloc( GetProcessHeap(), 0, bits,
955                                         (size + size_small) * sizeof(unsigned long) )))
956                 {
957                     bits = new;
958                     memcpy( bits + size, bits_small, size_small * sizeof(unsigned long) );
959                     size += size_small;
960                 }
961             }
962             HeapFree( GetProcessHeap(), 0, bits_small );
963             DeleteObject( ii.hbmColor );
964             DeleteObject( ii.hbmMask );
965         }
966         wine_tsx11_lock();
967         if (bits)
968             XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_ICON),
969                              XA_CARDINAL, 32, PropModeReplace, (unsigned char *)bits, size );
970         else
971             XDeleteProperty( display, data->whole_window, x11drv_atom(_NET_WM_ICON) );
972         wine_tsx11_unlock();
973         HeapFree( GetProcessHeap(), 0, bits );
974
975         hbmOrig = SelectObject(hDC, ii.hbmMask);
976         InvertRect(hDC, &rcMask);
977         SelectObject(hDC, ii.hbmColor);  /* force the color bitmap to x11drv mode too */
978         SelectObject(hDC, hbmOrig);
979
980         data->hWMIconBitmap = ii.hbmColor;
981         data->hWMIconMask = ii.hbmMask;
982
983         hints->icon_pixmap = X11DRV_get_pixmap(data->hWMIconBitmap);
984         hints->icon_mask = X11DRV_get_pixmap(data->hWMIconMask);
985         destroy_icon_window( display, data );
986         hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
987
988         DeleteDC(hDC);
989     }
990 }
991
992
993 /***********************************************************************
994  *              set_size_hints
995  *
996  * set the window size hints
997  */
998 static void set_size_hints( Display *display, struct x11drv_win_data *data, DWORD style )
999 {
1000     XSizeHints* size_hints;
1001
1002     if (!(size_hints = XAllocSizeHints())) return;
1003
1004     size_hints->win_gravity = StaticGravity;
1005     size_hints->flags |= PWinGravity;
1006
1007     /* don't update size hints if window is not in normal state */
1008     if (!(style & (WS_MINIMIZE | WS_MAXIMIZE)))
1009     {
1010         if (data->hwnd != GetDesktopWindow())  /* don't force position of desktop */
1011         {
1012             size_hints->x = data->whole_rect.left;
1013             size_hints->y = data->whole_rect.top;
1014             size_hints->flags |= PPosition;
1015         }
1016
1017         if (!is_window_resizable( data, style ))
1018         {
1019             size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
1020             size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
1021             size_hints->min_width = size_hints->max_width;
1022             size_hints->min_height = size_hints->max_height;
1023             size_hints->flags |= PMinSize | PMaxSize;
1024         }
1025     }
1026     XSetWMNormalHints( display, data->whole_window, size_hints );
1027     XFree( size_hints );
1028 }
1029
1030
1031 /***********************************************************************
1032  *              get_process_name
1033  *
1034  * get the name of the current process for setting class hints
1035  */
1036 static char *get_process_name(void)
1037 {
1038     static char *name;
1039
1040     if (!name)
1041     {
1042         WCHAR module[MAX_PATH];
1043         DWORD len = GetModuleFileNameW( 0, module, MAX_PATH );
1044         if (len && len < MAX_PATH)
1045         {
1046             char *ptr;
1047             WCHAR *p, *appname = module;
1048
1049             if ((p = strrchrW( appname, '/' ))) appname = p + 1;
1050             if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
1051             len = WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, NULL, 0, NULL, NULL );
1052             if ((ptr = HeapAlloc( GetProcessHeap(), 0, len )))
1053             {
1054                 WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, ptr, len, NULL, NULL );
1055                 name = ptr;
1056             }
1057         }
1058     }
1059     return name;
1060 }
1061
1062
1063 /***********************************************************************
1064  *              set_initial_wm_hints
1065  *
1066  * Set the window manager hints that don't change over the lifetime of a window.
1067  */
1068 static void set_initial_wm_hints( Display *display, struct x11drv_win_data *data )
1069 {
1070     long i;
1071     Atom protocols[3];
1072     Atom dndVersion = WINE_XDND_VERSION;
1073     XClassHint *class_hints;
1074     char *process_name = get_process_name();
1075
1076     wine_tsx11_lock();
1077
1078     /* wm protocols */
1079     i = 0;
1080     protocols[i++] = x11drv_atom(WM_DELETE_WINDOW);
1081     protocols[i++] = x11drv_atom(_NET_WM_PING);
1082     if (use_take_focus) protocols[i++] = x11drv_atom(WM_TAKE_FOCUS);
1083     XChangeProperty( display, data->whole_window, x11drv_atom(WM_PROTOCOLS),
1084                      XA_ATOM, 32, PropModeReplace, (unsigned char *)protocols, i );
1085
1086     /* class hints */
1087     if ((class_hints = XAllocClassHint()))
1088     {
1089         static char wine[] = "Wine";
1090
1091         class_hints->res_name = process_name;
1092         class_hints->res_class = wine;
1093         XSetClassHint( display, data->whole_window, class_hints );
1094         XFree( class_hints );
1095     }
1096
1097     /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */
1098     XSetWMProperties(display, data->whole_window, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1099     /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */
1100     i = getpid();
1101     XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_PID),
1102                     XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&i, 1);
1103
1104     XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
1105                      XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
1106
1107     data->wm_hints = XAllocWMHints();
1108     wine_tsx11_unlock();
1109
1110     if (data->wm_hints)
1111     {
1112         data->wm_hints->flags = 0;
1113         set_icon_hints( display, data, 0, 0 );
1114     }
1115 }
1116
1117
1118 /***********************************************************************
1119  *              get_owner_whole_window
1120  *
1121  * Retrieve an owner's window, creating it if necessary.
1122  */
1123 static Window get_owner_whole_window( HWND owner, BOOL force_managed )
1124 {
1125     struct x11drv_win_data *data;
1126
1127     if (!owner) return 0;
1128
1129     if (!(data = X11DRV_get_win_data( owner )))
1130     {
1131         if (GetWindowThreadProcessId( owner, NULL ) != GetCurrentThreadId() ||
1132             !(data = X11DRV_create_win_data( owner )))
1133             return (Window)GetPropA( owner, whole_window_prop );
1134     }
1135     else if (!data->managed && force_managed)  /* make it managed */
1136     {
1137         SetWindowPos( owner, 0, 0, 0, 0, 0,
1138                       SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE |
1139                       SWP_NOREDRAW | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_STATECHANGED );
1140     }
1141     return data->whole_window;
1142 }
1143
1144
1145 /***********************************************************************
1146  *              set_wm_hints
1147  *
1148  * Set the window manager hints for a newly-created window
1149  */
1150 static void set_wm_hints( Display *display, struct x11drv_win_data *data )
1151 {
1152     Window group_leader = data->whole_window;
1153     Window owner_win = 0;
1154     Atom window_type;
1155     MwmHints mwm_hints;
1156     DWORD style, ex_style;
1157     HWND owner;
1158
1159     if (data->hwnd == GetDesktopWindow())
1160     {
1161         /* force some styles for the desktop to get the correct decorations */
1162         style = WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
1163         ex_style = WS_EX_APPWINDOW;
1164         owner = 0;
1165     }
1166     else
1167     {
1168         style = GetWindowLongW( data->hwnd, GWL_STYLE );
1169         ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
1170         owner = get_window_owner( data->hwnd );
1171         if ((owner_win = get_owner_whole_window( owner, data->managed ))) group_leader = owner_win;
1172     }
1173
1174     wine_tsx11_lock();
1175
1176     if (owner_win) XSetTransientForHint( display, data->whole_window, owner_win );
1177
1178     /* size hints */
1179     set_size_hints( display, data, style );
1180
1181     /* set the WM_WINDOW_TYPE */
1182     if (style & WS_THICKFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
1183     else if (ex_style & WS_EX_APPWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
1184     else if (style & WS_DLGFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
1185     else if (ex_style & WS_EX_DLGMODALFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
1186     else if ((style & WS_POPUP) && owner) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
1187 #if 0  /* many window managers don't handle utility windows very well */
1188     else if (ex_style & WS_EX_TOOLWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_UTILITY);
1189 #endif
1190     else window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
1191
1192     XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_WINDOW_TYPE),
1193                     XA_ATOM, 32, PropModeReplace, (unsigned char*)&window_type, 1);
1194
1195     mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
1196     mwm_hints.decorations = get_mwm_decorations( data, style, ex_style );
1197     mwm_hints.functions = MWM_FUNC_MOVE;
1198     if (is_window_resizable( data, style )) mwm_hints.functions |= MWM_FUNC_RESIZE;
1199     if (!(style & WS_DISABLED))
1200     {
1201         if (style & WS_MINIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MINIMIZE;
1202         if (style & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
1203         if (style & WS_SYSMENU)     mwm_hints.functions |= MWM_FUNC_CLOSE;
1204     }
1205
1206     XChangeProperty( display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS),
1207                      x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace,
1208                      (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) );
1209
1210     /* wm hints */
1211     if (data->wm_hints)
1212     {
1213         data->wm_hints->flags |= InputHint | StateHint | WindowGroupHint;
1214         data->wm_hints->input = !use_take_focus && !(style & WS_DISABLED);
1215         data->wm_hints->initial_state = (style & WS_MINIMIZE) ? IconicState : NormalState;
1216         data->wm_hints->window_group = group_leader;
1217         XSetWMHints( display, data->whole_window, data->wm_hints );
1218     }
1219
1220     wine_tsx11_unlock();
1221 }
1222
1223
1224 /***********************************************************************
1225  *     update_net_wm_states
1226  */
1227 void update_net_wm_states( Display *display, struct x11drv_win_data *data )
1228 {
1229     static const unsigned int state_atoms[NB_NET_WM_STATES] =
1230     {
1231         XATOM__NET_WM_STATE_FULLSCREEN,
1232         XATOM__NET_WM_STATE_ABOVE,
1233         XATOM__NET_WM_STATE_MAXIMIZED_VERT,
1234         XATOM__NET_WM_STATE_SKIP_PAGER,
1235         XATOM__NET_WM_STATE_SKIP_TASKBAR
1236     };
1237
1238     DWORD i, style, ex_style, new_state = 0;
1239
1240     if (!data->managed) return;
1241     if (data->whole_window == root_window) return;
1242
1243     style = GetWindowLongW( data->hwnd, GWL_STYLE );
1244     if (data->whole_rect.left <= 0 && data->whole_rect.right >= screen_width &&
1245         data->whole_rect.top <= 0 && data->whole_rect.bottom >= screen_height)
1246     {
1247         if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION)
1248             new_state |= (1 << NET_WM_STATE_MAXIMIZED);
1249         else if (!(style & WS_MINIMIZE))
1250             new_state |= (1 << NET_WM_STATE_FULLSCREEN);
1251     }
1252     else if (style & WS_MAXIMIZE)
1253         new_state |= (1 << NET_WM_STATE_MAXIMIZED);
1254
1255     ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
1256     if (ex_style & WS_EX_TOPMOST)
1257         new_state |= (1 << NET_WM_STATE_ABOVE);
1258     if (ex_style & WS_EX_TOOLWINDOW)
1259         new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR) | (1 << NET_WM_STATE_SKIP_PAGER);
1260     if (!(ex_style & WS_EX_APPWINDOW) && get_window_owner( data->hwnd ))
1261         new_state |= (1 << NET_WM_STATE_SKIP_TASKBAR);
1262
1263     if (!data->mapped)  /* set the _NET_WM_STATE atom directly */
1264     {
1265         Atom atoms[NB_NET_WM_STATES+1];
1266         DWORD count;
1267
1268         for (i = count = 0; i < NB_NET_WM_STATES; i++)
1269         {
1270             if (!(new_state & (1 << i))) continue;
1271             TRACE( "setting wm state %u for unmapped window %p/%lx\n",
1272                    i, data->hwnd, data->whole_window );
1273             atoms[count++] = X11DRV_Atoms[state_atoms[i] - FIRST_XATOM];
1274             if (state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT)
1275                 atoms[count++] = x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ);
1276         }
1277         wine_tsx11_lock();
1278         XChangeProperty( display, data->whole_window, x11drv_atom(_NET_WM_STATE), XA_ATOM,
1279                          32, PropModeReplace, (unsigned char *)atoms, count );
1280         wine_tsx11_unlock();
1281     }
1282     else  /* ask the window manager to do it for us */
1283     {
1284         XEvent xev;
1285
1286         xev.xclient.type = ClientMessage;
1287         xev.xclient.window = data->whole_window;
1288         xev.xclient.message_type = x11drv_atom(_NET_WM_STATE);
1289         xev.xclient.serial = 0;
1290         xev.xclient.display = display;
1291         xev.xclient.send_event = True;
1292         xev.xclient.format = 32;
1293         xev.xclient.data.l[3] = 1;
1294
1295         for (i = 0; i < NB_NET_WM_STATES; i++)
1296         {
1297             if (!((data->net_wm_state ^ new_state) & (1 << i))) continue;  /* unchanged */
1298
1299             TRACE( "setting wm state %u for window %p/%lx to %u prev %u\n",
1300                    i, data->hwnd, data->whole_window,
1301                    (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 );
1302
1303             xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
1304             xev.xclient.data.l[1] = X11DRV_Atoms[state_atoms[i] - FIRST_XATOM];
1305             xev.xclient.data.l[2] = ((state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ?
1306                                      x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ) : 0);
1307             wine_tsx11_lock();
1308             XSendEvent( display, root_window, False,
1309                         SubstructureRedirectMask | SubstructureNotifyMask, &xev );
1310             wine_tsx11_unlock();
1311         }
1312     }
1313     data->net_wm_state = new_state;
1314 }
1315
1316
1317 /***********************************************************************
1318  *     set_xembed_flags
1319  */
1320 static void set_xembed_flags( Display *display, struct x11drv_win_data *data, unsigned long flags )
1321 {
1322     unsigned long info[2];
1323
1324     info[0] = 0; /* protocol version */
1325     info[1] = flags;
1326     wine_tsx11_lock();
1327     XChangeProperty( display, data->whole_window, x11drv_atom(_XEMBED_INFO),
1328                      x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2 );
1329     wine_tsx11_unlock();
1330 }
1331
1332
1333 /***********************************************************************
1334  *     map_window
1335  */
1336 static void map_window( Display *display, struct x11drv_win_data *data, DWORD new_style )
1337 {
1338     TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
1339
1340     remove_startup_notification( display, data->whole_window );
1341
1342     wait_for_withdrawn_state( display, data, TRUE );
1343
1344     if (!data->embedded)
1345     {
1346         update_net_wm_states( display, data );
1347         sync_window_style( display, data );
1348         wine_tsx11_lock();
1349         XMapWindow( display, data->whole_window );
1350         wine_tsx11_unlock();
1351     }
1352     else set_xembed_flags( display, data, XEMBED_MAPPED );
1353
1354     data->mapped = TRUE;
1355     data->iconic = (new_style & WS_MINIMIZE) != 0;
1356 }
1357
1358
1359 /***********************************************************************
1360  *     unmap_window
1361  */
1362 static void unmap_window( Display *display, struct x11drv_win_data *data )
1363 {
1364     TRACE( "win %p/%lx\n", data->hwnd, data->whole_window );
1365
1366     if (!data->embedded)
1367     {
1368         wait_for_withdrawn_state( display, data, FALSE );
1369         wine_tsx11_lock();
1370         if (data->managed) XWithdrawWindow( display, data->whole_window, DefaultScreen(display) );
1371         else XUnmapWindow( display, data->whole_window );
1372         wine_tsx11_unlock();
1373     }
1374     else set_xembed_flags( display, data, 0 );
1375
1376     data->mapped = FALSE;
1377     data->net_wm_state = 0;
1378 }
1379
1380
1381 /***********************************************************************
1382  *     make_window_embedded
1383  */
1384 void make_window_embedded( Display *display, struct x11drv_win_data *data )
1385 {
1386     if (data->mapped)
1387     {
1388         /* the window cannot be mapped before being embedded */
1389         unmap_window( display, data );
1390         data->embedded = TRUE;
1391         map_window( display, data, 0 );
1392     }
1393     else
1394     {
1395         data->embedded = TRUE;
1396         set_xembed_flags( display, data, 0 );
1397     }
1398 }
1399
1400
1401 /***********************************************************************
1402  *              X11DRV_window_to_X_rect
1403  *
1404  * Convert a rect from client to X window coordinates
1405  */
1406 static void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect )
1407 {
1408     RECT rc;
1409
1410     if (!data->managed) return;
1411     if (IsRectEmpty( rect )) return;
1412
1413     get_x11_rect_offset( data, &rc );
1414
1415     rect->left   -= rc.left;
1416     rect->right  -= rc.right;
1417     rect->top    -= rc.top;
1418     rect->bottom -= rc.bottom;
1419     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
1420     if (rect->left >= rect->right) rect->right = rect->left + 1;
1421 }
1422
1423
1424 /***********************************************************************
1425  *              X11DRV_X_to_window_rect
1426  *
1427  * Opposite of X11DRV_window_to_X_rect
1428  */
1429 void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect )
1430 {
1431     RECT rc;
1432
1433     if (!data->managed) return;
1434     if (IsRectEmpty( rect )) return;
1435
1436     get_x11_rect_offset( data, &rc );
1437
1438     rect->left   += rc.left;
1439     rect->right  += rc.right;
1440     rect->top    += rc.top;
1441     rect->bottom += rc.bottom;
1442     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
1443     if (rect->left >= rect->right) rect->right = rect->left + 1;
1444 }
1445
1446
1447 /***********************************************************************
1448  *              sync_window_position
1449  *
1450  * Synchronize the X window position with the Windows one
1451  */
1452 static void sync_window_position( Display *display, struct x11drv_win_data *data,
1453                                   UINT swp_flags, const RECT *old_window_rect,
1454                                   const RECT *old_whole_rect, const RECT *old_client_rect )
1455 {
1456     DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
1457     XWindowChanges changes;
1458     unsigned int mask = 0;
1459
1460     if (data->managed && data->iconic) return;
1461
1462     /* resizing a managed maximized window is not allowed */
1463     if (!(style & WS_MAXIMIZE) || !data->managed)
1464     {
1465         changes.width = data->whole_rect.right - data->whole_rect.left;
1466         changes.height = data->whole_rect.bottom - data->whole_rect.top;
1467         /* if window rect is empty force size to 1x1 */
1468         if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1;
1469         if (changes.width > 65535) changes.width = 65535;
1470         if (changes.height > 65535) changes.height = 65535;
1471         mask |= CWWidth | CWHeight;
1472     }
1473
1474     /* only the size is allowed to change for the desktop window */
1475     if (data->whole_window != root_window)
1476     {
1477         changes.x = data->whole_rect.left - virtual_screen_rect.left;
1478         changes.y = data->whole_rect.top - virtual_screen_rect.top;
1479         mask |= CWX | CWY;
1480     }
1481
1482     if (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW))
1483     {
1484         /* find window that this one must be after */
1485         HWND prev = GetWindow( data->hwnd, GW_HWNDPREV );
1486         while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE))
1487             prev = GetWindow( prev, GW_HWNDPREV );
1488         if (!prev)  /* top child */
1489         {
1490             changes.stack_mode = Above;
1491             mask |= CWStackMode;
1492         }
1493         /* should use stack_mode Below but most window managers don't get it right */
1494         /* and Above with a sibling doesn't work so well either, so we ignore it */
1495     }
1496
1497     wine_tsx11_lock();
1498     set_size_hints( display, data, style );
1499     data->configure_serial = NextRequest( display );
1500     XReconfigureWMWindow( display, data->whole_window,
1501                           DefaultScreen(display), mask, &changes );
1502 #ifdef HAVE_LIBXSHAPE
1503     if (data->shaped)
1504     {
1505         int old_x_offset = old_window_rect->left - old_whole_rect->left;
1506         int old_y_offset = old_window_rect->top - old_whole_rect->top;
1507         int new_x_offset = data->window_rect.left - data->whole_rect.left;
1508         int new_y_offset = data->window_rect.top - data->whole_rect.top;
1509         if (old_x_offset != new_x_offset || old_y_offset != new_y_offset)
1510             XShapeOffsetShape( display, data->whole_window, ShapeBounding,
1511                                new_x_offset - old_x_offset, new_y_offset - old_y_offset );
1512     }
1513 #endif
1514     wine_tsx11_unlock();
1515
1516     TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x serial=%lu\n",
1517            data->hwnd, data->whole_window, data->whole_rect.left, data->whole_rect.top,
1518            data->whole_rect.right - data->whole_rect.left,
1519            data->whole_rect.bottom - data->whole_rect.top,
1520            changes.sibling, mask, data->configure_serial );
1521 }
1522
1523
1524 /***********************************************************************
1525  *              sync_client_position
1526  *
1527  * Synchronize the X client window position with the Windows one
1528  */
1529 static void sync_client_position( Display *display, struct x11drv_win_data *data,
1530                                   UINT swp_flags, const RECT *old_client_rect,
1531                                   const RECT *old_whole_rect )
1532 {
1533     int mask;
1534     XWindowChanges changes;
1535     RECT old = *old_client_rect;
1536     RECT new = data->client_rect;
1537
1538     OffsetRect( &old, -old_whole_rect->left, -old_whole_rect->top );
1539     OffsetRect( &new, -data->whole_rect.left, -data->whole_rect.top );
1540     if (!(mask = get_window_changes( &changes, &old, &new ))) return;
1541
1542     if (data->client_window)
1543     {
1544         TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n",
1545                data->client_window, new.left, new.top,
1546                new.right - new.left, new.bottom - new.top, mask );
1547         wine_tsx11_lock();
1548         XConfigureWindow( display, data->client_window, mask, &changes );
1549         wine_tsx11_unlock();
1550     }
1551
1552     if (data->gl_drawable && (mask & (CWWidth|CWHeight))) sync_gl_drawable( data );
1553 }
1554
1555
1556 /***********************************************************************
1557  *              move_window_bits
1558  *
1559  * Move the window bits when a window is moved.
1560  */
1561 static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect, const RECT *new_rect,
1562                               const RECT *old_client_rect )
1563 {
1564     RECT src_rect = *old_rect;
1565     RECT dst_rect = *new_rect;
1566     HDC hdc_src, hdc_dst;
1567     INT code;
1568     HRGN rgn = 0;
1569     HWND parent = 0;
1570
1571     if (!data->whole_window)
1572     {
1573         OffsetRect( &dst_rect, -data->window_rect.left, -data->window_rect.top );
1574         parent = GetAncestor( data->hwnd, GA_PARENT );
1575         hdc_src = GetDCEx( parent, 0, DCX_CACHE );
1576         hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE | DCX_WINDOW );
1577     }
1578     else
1579     {
1580         OffsetRect( &dst_rect, -data->client_rect.left, -data->client_rect.top );
1581         /* make src rect relative to the old position of the window */
1582         OffsetRect( &src_rect, -old_client_rect->left, -old_client_rect->top );
1583         if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
1584         hdc_src = hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE );
1585     }
1586
1587     code = X11DRV_START_EXPOSURES;
1588     ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
1589
1590     TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
1591            data->hwnd, data->whole_window, data->client_window,
1592            wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect) );
1593     BitBlt( hdc_dst, dst_rect.left, dst_rect.top,
1594             dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
1595             hdc_src, src_rect.left, src_rect.top, SRCCOPY );
1596
1597     code = X11DRV_END_EXPOSURES;
1598     ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(rgn), (LPSTR)&rgn );
1599
1600     ReleaseDC( data->hwnd, hdc_dst );
1601     if (hdc_src != hdc_dst) ReleaseDC( parent, hdc_src );
1602
1603     if (rgn)
1604     {
1605         if (!data->whole_window)
1606         {
1607             /* map region to client rect since we are using DCX_WINDOW */
1608             OffsetRgn( rgn, data->window_rect.left - data->client_rect.left,
1609                        data->window_rect.top - data->client_rect.top );
1610             RedrawWindow( data->hwnd, NULL, rgn,
1611                           RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN );
1612         }
1613         else RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
1614         DeleteObject( rgn );
1615     }
1616 }
1617
1618
1619 /**********************************************************************
1620  *              create_whole_window
1621  *
1622  * Create the whole X window for a given window
1623  */
1624 static Window create_whole_window( Display *display, struct x11drv_win_data *data )
1625 {
1626     int cx, cy, mask;
1627     XSetWindowAttributes attr;
1628     WCHAR text[1024];
1629     COLORREF key;
1630     BYTE alpha;
1631     DWORD layered_flags;
1632     HRGN win_rgn;
1633
1634     if (!data->managed && is_window_managed( data->hwnd, SWP_NOACTIVATE, &data->window_rect ))
1635     {
1636         TRACE( "making win %p/%lx managed\n", data->hwnd, data->whole_window );
1637         data->managed = TRUE;
1638         SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
1639     }
1640
1641     if ((win_rgn = CreateRectRgn( 0, 0, 0, 0 )) &&
1642         GetWindowRgn( data->hwnd, win_rgn ) == ERROR)
1643     {
1644         DeleteObject( win_rgn );
1645         win_rgn = 0;
1646     }
1647     data->shaped = (win_rgn != 0);
1648
1649     mask = get_window_attributes( display, data, &attr );
1650
1651     data->whole_rect = data->window_rect;
1652     X11DRV_window_to_X_rect( data, &data->whole_rect );
1653     if (!(cx = data->whole_rect.right - data->whole_rect.left)) cx = 1;
1654     else if (cx > 65535) cx = 65535;
1655     if (!(cy = data->whole_rect.bottom - data->whole_rect.top)) cy = 1;
1656     else if (cy > 65535) cy = 65535;
1657
1658     wine_tsx11_lock();
1659     data->whole_window = XCreateWindow( display, root_window,
1660                                         data->whole_rect.left - virtual_screen_rect.left,
1661                                         data->whole_rect.top - virtual_screen_rect.top,
1662                                         cx, cy, 0, screen_depth, InputOutput,
1663                                         visual, mask, &attr );
1664
1665     if (data->whole_window) XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd );
1666     wine_tsx11_unlock();
1667
1668     if (!data->whole_window) goto done;
1669
1670     if (!create_client_window( display, data, NULL ))
1671     {
1672         wine_tsx11_lock();
1673         XDeleteContext( display, data->whole_window, winContext );
1674         XDestroyWindow( display, data->whole_window );
1675         data->whole_window = 0;
1676         wine_tsx11_unlock();
1677         goto done;
1678     }
1679
1680     set_initial_wm_hints( display, data );
1681     set_wm_hints( display, data );
1682
1683     SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window );
1684
1685     /* set the window text */
1686     if (!InternalGetWindowText( data->hwnd, text, sizeof(text)/sizeof(WCHAR) )) text[0] = 0;
1687     sync_window_text( display, data->whole_window, text );
1688
1689     /* set the window region */
1690     if (win_rgn) sync_window_region( display, data, win_rgn );
1691
1692     /* set the window opacity */
1693     if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0;
1694     sync_window_opacity( display, data->whole_window, key, alpha, layered_flags );
1695
1696     wine_tsx11_lock();
1697     XFlush( display );  /* make sure the window exists before we start painting to it */
1698     wine_tsx11_unlock();
1699
1700     sync_window_cursor( data );
1701 done:
1702     if (win_rgn) DeleteObject( win_rgn );
1703     return data->whole_window;
1704 }
1705
1706
1707 /**********************************************************************
1708  *              destroy_whole_window
1709  *
1710  * Destroy the whole X window for a given window.
1711  */
1712 static void destroy_whole_window( Display *display, struct x11drv_win_data *data, BOOL already_destroyed )
1713 {
1714     if (!data->whole_window) return;
1715
1716     TRACE( "win %p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window );
1717     wine_tsx11_lock();
1718     XDeleteContext( display, data->whole_window, winContext );
1719     XDeleteContext( display, data->client_window, winContext );
1720     if (!already_destroyed) XDestroyWindow( display, data->whole_window );
1721     data->whole_window = data->client_window = 0;
1722     data->wm_state = WithdrawnState;
1723     data->net_wm_state = 0;
1724     data->mapped = FALSE;
1725     if (data->xic)
1726     {
1727         XUnsetICFocus( data->xic );
1728         XDestroyIC( data->xic );
1729         data->xic = 0;
1730     }
1731     /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */
1732     XFlush( display );
1733     XFree( data->wm_hints );
1734     data->wm_hints = NULL;
1735     wine_tsx11_unlock();
1736     RemovePropA( data->hwnd, whole_window_prop );
1737     RemovePropA( data->hwnd, client_window_prop );
1738 }
1739
1740
1741 /*****************************************************************
1742  *              SetWindowText   (X11DRV.@)
1743  */
1744 void CDECL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
1745 {
1746     Window win;
1747
1748     if ((win = X11DRV_get_whole_window( hwnd )) && win != DefaultRootWindow(gdi_display))
1749     {
1750         Display *display = thread_init_display();
1751         sync_window_text( display, win, text );
1752     }
1753 }
1754
1755
1756 /***********************************************************************
1757  *              SetWindowStyle   (X11DRV.@)
1758  *
1759  * Update the X state of a window to reflect a style change
1760  */
1761 void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
1762 {
1763     struct x11drv_win_data *data;
1764     DWORD changed;
1765
1766     if (hwnd == GetDesktopWindow()) return;
1767     changed = style->styleNew ^ style->styleOld;
1768
1769     if (offset == GWL_STYLE && (changed & WS_VISIBLE) && (style->styleNew & WS_VISIBLE))
1770     {
1771         /* we don't unmap windows, that causes trouble with the window manager */
1772         if (!(data = X11DRV_get_win_data( hwnd )) &&
1773             !(data = X11DRV_create_win_data( hwnd ))) return;
1774
1775         if (data->whole_window && is_window_rect_mapped( &data->window_rect ))
1776         {
1777             Display *display = thread_display();
1778             set_wm_hints( display, data );
1779             if (!data->mapped) map_window( display, data, style->styleNew );
1780         }
1781     }
1782
1783     if (offset == GWL_STYLE && (changed & WS_DISABLED))
1784     {
1785         data = X11DRV_get_win_data( hwnd );
1786         if (data && data->whole_window)
1787             set_wm_hints( thread_display(), data );
1788     }
1789
1790     if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED))
1791     {
1792         /* changing WS_EX_LAYERED resets attributes */
1793         if ((data = X11DRV_get_win_data( hwnd )) && data->whole_window)
1794             sync_window_opacity( thread_display(), data->whole_window, 0, 0, 0 );
1795     }
1796 }
1797
1798
1799 /***********************************************************************
1800  *              DestroyWindow   (X11DRV.@)
1801  */
1802 void CDECL X11DRV_DestroyWindow( HWND hwnd )
1803 {
1804     struct x11drv_thread_data *thread_data = x11drv_thread_data();
1805     struct x11drv_win_data *data;
1806
1807     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1808
1809     if (data->pixmap)
1810     {
1811         wine_tsx11_lock();
1812         destroy_glxpixmap(gdi_display, data->gl_drawable);
1813         XFreePixmap(gdi_display, data->pixmap);
1814         wine_tsx11_unlock();
1815     }
1816     else if (data->gl_drawable)
1817     {
1818         wine_tsx11_lock();
1819         XDestroyWindow(gdi_display, data->gl_drawable);
1820         wine_tsx11_unlock();
1821     }
1822
1823     destroy_whole_window( thread_data->display, data, FALSE );
1824     destroy_icon_window( thread_data->display, data );
1825
1826     if (data->colormap)
1827     {
1828         wine_tsx11_lock();
1829         XFreeColormap( thread_data->display, data->colormap );
1830         wine_tsx11_unlock();
1831     }
1832
1833     if (thread_data->last_focus == hwnd) thread_data->last_focus = 0;
1834     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
1835     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
1836     wine_tsx11_lock();
1837     XDeleteContext( thread_data->display, (XID)hwnd, win_data_context );
1838     wine_tsx11_unlock();
1839     HeapFree( GetProcessHeap(), 0, data );
1840 }
1841
1842
1843 /***********************************************************************
1844  *              X11DRV_DestroyNotify
1845  */
1846 void X11DRV_DestroyNotify( HWND hwnd, XEvent *event )
1847 {
1848     Display *display = event->xdestroywindow.display;
1849     struct x11drv_win_data *data;
1850
1851     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1852
1853     FIXME( "window %p/%lx destroyed from the outside\n", hwnd, data->whole_window );
1854     destroy_whole_window( display, data, TRUE );
1855 }
1856
1857
1858 static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd )
1859 {
1860     struct x11drv_win_data *data;
1861
1862     if ((data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data))))
1863     {
1864         data->hwnd = hwnd;
1865         wine_tsx11_lock();
1866         if (!winContext) winContext = XUniqueContext();
1867         if (!win_data_context) win_data_context = XUniqueContext();
1868         XSaveContext( display, (XID)hwnd, win_data_context, (char *)data );
1869         wine_tsx11_unlock();
1870     }
1871     return data;
1872 }
1873
1874
1875 /* initialize the desktop window id in the desktop manager process */
1876 static struct x11drv_win_data *create_desktop_win_data( Display *display, HWND hwnd )
1877 {
1878     struct x11drv_win_data *data;
1879
1880     if (!(data = alloc_win_data( display, hwnd ))) return NULL;
1881     data->whole_window = data->client_window = root_window;
1882     data->managed = TRUE;
1883     SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
1884     SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window );
1885     SetPropA( data->hwnd, client_window_prop, (HANDLE)root_window );
1886     set_initial_wm_hints( display, data );
1887     return data;
1888 }
1889
1890 /**********************************************************************
1891  *              CreateDesktopWindow   (X11DRV.@)
1892  */
1893 BOOL CDECL X11DRV_CreateDesktopWindow( HWND hwnd )
1894 {
1895     unsigned int width, height;
1896
1897     /* retrieve the real size of the desktop */
1898     SERVER_START_REQ( get_window_rectangles )
1899     {
1900         req->handle = wine_server_user_handle( hwnd );
1901         wine_server_call( req );
1902         width  = reply->window.right - reply->window.left;
1903         height = reply->window.bottom - reply->window.top;
1904     }
1905     SERVER_END_REQ;
1906
1907     if (!width && !height)  /* not initialized yet */
1908     {
1909         SERVER_START_REQ( set_window_pos )
1910         {
1911             req->handle        = wine_server_user_handle( hwnd );
1912             req->previous      = 0;
1913             req->flags         = SWP_NOZORDER;
1914             req->window.left   = virtual_screen_rect.left;
1915             req->window.top    = virtual_screen_rect.top;
1916             req->window.right  = virtual_screen_rect.right;
1917             req->window.bottom = virtual_screen_rect.bottom;
1918             req->client        = req->window;
1919             wine_server_call( req );
1920         }
1921         SERVER_END_REQ;
1922     }
1923     else
1924     {
1925         Window win = (Window)GetPropA( hwnd, whole_window_prop );
1926         if (win && win != root_window) X11DRV_init_desktop( win, width, height );
1927     }
1928     return TRUE;
1929 }
1930
1931
1932 /**********************************************************************
1933  *              CreateWindow   (X11DRV.@)
1934  */
1935 BOOL CDECL X11DRV_CreateWindow( HWND hwnd )
1936 {
1937     if (hwnd == GetDesktopWindow() && root_window != DefaultRootWindow( gdi_display ))
1938     {
1939         Display *display = thread_init_display();
1940
1941         /* the desktop win data can't be created lazily */
1942         if (!create_desktop_win_data( display, hwnd )) return FALSE;
1943     }
1944     return TRUE;
1945 }
1946
1947
1948 /***********************************************************************
1949  *              X11DRV_get_win_data
1950  *
1951  * Return the X11 data structure associated with a window.
1952  */
1953 struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd )
1954 {
1955     struct x11drv_thread_data *thread_data = x11drv_thread_data();
1956     char *data;
1957
1958     if (!thread_data) return NULL;
1959     if (!hwnd) return NULL;
1960     if (XFindContext( thread_data->display, (XID)hwnd, win_data_context, &data )) data = NULL;
1961     return (struct x11drv_win_data *)data;
1962 }
1963
1964
1965 /***********************************************************************
1966  *              X11DRV_create_win_data
1967  *
1968  * Create an X11 data window structure for an existing window.
1969  */
1970 struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd )
1971 {
1972     Display *display;
1973     struct x11drv_win_data *data;
1974     HWND parent;
1975
1976     if (!(parent = GetAncestor( hwnd, GA_PARENT ))) return NULL;  /* desktop */
1977
1978     /* don't create win data for HWND_MESSAGE windows */
1979     if (parent != GetDesktopWindow() && !GetAncestor( parent, GA_PARENT )) return NULL;
1980
1981     display = thread_init_display();
1982     if (!(data = alloc_win_data( display, hwnd ))) return NULL;
1983
1984     GetWindowRect( hwnd, &data->window_rect );
1985     MapWindowPoints( 0, parent, (POINT *)&data->window_rect, 2 );
1986     data->whole_rect = data->window_rect;
1987     GetClientRect( hwnd, &data->client_rect );
1988     MapWindowPoints( hwnd, parent, (POINT *)&data->client_rect, 2 );
1989
1990     if (parent == GetDesktopWindow())
1991     {
1992         if (!create_whole_window( display, data ))
1993         {
1994             HeapFree( GetProcessHeap(), 0, data );
1995             return NULL;
1996         }
1997         TRACE( "win %p/%lx/%lx window %s whole %s client %s\n",
1998                hwnd, data->whole_window, data->client_window, wine_dbgstr_rect( &data->window_rect ),
1999                wine_dbgstr_rect( &data->whole_rect ), wine_dbgstr_rect( &data->client_rect ));
2000     }
2001     return data;
2002 }
2003
2004
2005 /***********************************************************************
2006  *              X11DRV_get_whole_window
2007  *
2008  * Return the X window associated with the full area of a window
2009  */
2010 Window X11DRV_get_whole_window( HWND hwnd )
2011 {
2012     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2013
2014     if (!data)
2015     {
2016         if (hwnd == GetDesktopWindow()) return root_window;
2017         return (Window)GetPropA( hwnd, whole_window_prop );
2018     }
2019     return data->whole_window;
2020 }
2021
2022
2023 /***********************************************************************
2024  *              X11DRV_get_client_window
2025  *
2026  * Return the X window associated with the client area of a window
2027  */
2028 static Window X11DRV_get_client_window( HWND hwnd )
2029 {
2030     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2031
2032     if (!data)
2033     {
2034         if (hwnd == GetDesktopWindow()) return root_window;
2035         return (Window)GetPropA( hwnd, client_window_prop );
2036     }
2037     return data->client_window;
2038 }
2039
2040
2041 /***********************************************************************
2042  *              X11DRV_get_ic
2043  *
2044  * Return the X input context associated with a window
2045  */
2046 XIC X11DRV_get_ic( HWND hwnd )
2047 {
2048     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2049     XIM xim;
2050
2051     if (!data) return 0;
2052     if (data->xic) return data->xic;
2053     if (!(xim = x11drv_thread_data()->xim)) return 0;
2054     return X11DRV_CreateIC( xim, data );
2055 }
2056
2057
2058 /***********************************************************************
2059  *              X11DRV_GetDC   (X11DRV.@)
2060  */
2061 void CDECL X11DRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect,
2062                          const RECT *top_rect, DWORD flags )
2063 {
2064     struct x11drv_escape_set_drawable escape;
2065     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2066
2067     escape.code        = X11DRV_SET_DRAWABLE;
2068     escape.mode        = IncludeInferiors;
2069     escape.fbconfig_id = 0;
2070     escape.gl_drawable = 0;
2071     escape.pixmap      = 0;
2072     escape.gl_copy     = FALSE;
2073
2074     if (top == hwnd)
2075     {
2076         escape.fbconfig_id = data ? data->fbconfig_id : (XID)GetPropA( hwnd, fbconfig_id_prop );
2077         /* GL draws to the client area even for window DCs */
2078         escape.gl_drawable = data ? data->client_window : X11DRV_get_client_window( hwnd );
2079         if (data && IsIconic( hwnd ) && data->icon_window)
2080         {
2081             escape.drawable = data->icon_window;
2082         }
2083         else if (flags & DCX_WINDOW)
2084             escape.drawable = data ? data->whole_window : X11DRV_get_whole_window( hwnd );
2085         else
2086             escape.drawable = escape.gl_drawable;
2087     }
2088     else
2089     {
2090         escape.drawable    = X11DRV_get_client_window( top );
2091         escape.fbconfig_id = data ? data->fbconfig_id : (XID)GetPropA( hwnd, fbconfig_id_prop );
2092         escape.gl_drawable = data ? data->gl_drawable : (Drawable)GetPropA( hwnd, gl_drawable_prop );
2093         escape.pixmap      = data ? data->pixmap : (Pixmap)GetPropA( hwnd, pixmap_prop );
2094         escape.gl_copy     = (escape.gl_drawable != 0);
2095         if (flags & DCX_CLIPCHILDREN) escape.mode = ClipByChildren;
2096     }
2097
2098     escape.dc_rect.left         = win_rect->left - top_rect->left;
2099     escape.dc_rect.top          = win_rect->top - top_rect->top;
2100     escape.dc_rect.right        = win_rect->right - top_rect->left;
2101     escape.dc_rect.bottom       = win_rect->bottom - top_rect->top;
2102     escape.drawable_rect.left   = top_rect->left;
2103     escape.drawable_rect.top    = top_rect->top;
2104     escape.drawable_rect.right  = top_rect->right;
2105     escape.drawable_rect.bottom = top_rect->bottom;
2106
2107     ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
2108 }
2109
2110
2111 /***********************************************************************
2112  *              X11DRV_ReleaseDC  (X11DRV.@)
2113  */
2114 void CDECL X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
2115 {
2116     struct x11drv_escape_set_drawable escape;
2117
2118     escape.code = X11DRV_SET_DRAWABLE;
2119     escape.drawable = root_window;
2120     escape.mode = IncludeInferiors;
2121     escape.drawable_rect = virtual_screen_rect;
2122     SetRect( &escape.dc_rect, 0, 0, virtual_screen_rect.right - virtual_screen_rect.left,
2123              virtual_screen_rect.bottom - virtual_screen_rect.top );
2124     OffsetRect( &escape.dc_rect, -escape.drawable_rect.left, -escape.drawable_rect.top );
2125     escape.fbconfig_id = 0;
2126     escape.gl_drawable = 0;
2127     escape.pixmap = 0;
2128     ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
2129 }
2130
2131
2132 /***********************************************************************
2133  *              SetCapture  (X11DRV.@)
2134  */
2135 void CDECL X11DRV_SetCapture( HWND hwnd, UINT flags )
2136 {
2137     struct x11drv_thread_data *thread_data = x11drv_thread_data();
2138
2139     if (!thread_data) return;
2140     if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
2141
2142     if (hwnd)
2143     {
2144         Window grab_win = X11DRV_get_client_window( GetAncestor( hwnd, GA_ROOT ) );
2145
2146         if (!grab_win) return;
2147         wine_tsx11_lock();
2148         XFlush( gdi_display );
2149         XGrabPointer( thread_data->display, grab_win, False,
2150                       PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2151                       GrabModeAsync, GrabModeAsync, None, None, CurrentTime );
2152         wine_tsx11_unlock();
2153         thread_data->grab_window = grab_win;
2154     }
2155     else  /* release capture */
2156     {
2157         wine_tsx11_lock();
2158         XFlush( gdi_display );
2159         XUngrabPointer( thread_data->display, CurrentTime );
2160         XFlush( thread_data->display );
2161         wine_tsx11_unlock();
2162         thread_data->grab_window = None;
2163     }
2164 }
2165
2166
2167 /*****************************************************************
2168  *              SetParent   (X11DRV.@)
2169  */
2170 void CDECL X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent )
2171 {
2172     Display *display = thread_display();
2173     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2174
2175     if (!data) return;
2176     if (parent == old_parent) return;
2177
2178     if (parent != GetDesktopWindow()) /* a child window */
2179     {
2180         if (old_parent == GetDesktopWindow())
2181         {
2182             /* destroy the old X windows */
2183             destroy_whole_window( display, data, FALSE );
2184             destroy_icon_window( display, data );
2185             if (data->managed)
2186             {
2187                 data->managed = FALSE;
2188                 RemovePropA( data->hwnd, managed_prop );
2189             }
2190         }
2191     }
2192     else  /* new top level window */
2193     {
2194         /* FIXME: we ignore errors since we can't really recover anyway */
2195         create_whole_window( display, data );
2196     }
2197 }
2198
2199
2200 /*****************************************************************
2201  *              SetFocus   (X11DRV.@)
2202  *
2203  * Set the X focus.
2204  */
2205 void CDECL X11DRV_SetFocus( HWND hwnd )
2206 {
2207     Display *display = thread_display();
2208     struct x11drv_win_data *data;
2209     XWindowChanges changes;
2210     DWORD timestamp;
2211
2212     if (!(hwnd = GetAncestor( hwnd, GA_ROOT ))) return;
2213     if (!(data = X11DRV_get_win_data( hwnd ))) return;
2214     if (data->managed || !data->whole_window) return;
2215
2216     if (EVENT_x11_time_to_win32_time(0))
2217         /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
2218         /* FIXME: this is not entirely correct */
2219         timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0);
2220     else
2221         timestamp = CurrentTime;
2222
2223     /* Set X focus and install colormap */
2224     wine_tsx11_lock();
2225     changes.stack_mode = Above;
2226     XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
2227     XSetInputFocus( display, data->whole_window, RevertToParent, timestamp );
2228     wine_tsx11_unlock();
2229 }
2230
2231
2232 /***********************************************************************
2233  *              WindowPosChanging   (X11DRV.@)
2234  */
2235 void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
2236                                      const RECT *window_rect, const RECT *client_rect, RECT *visible_rect )
2237 {
2238     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2239     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
2240
2241     if (!data)
2242     {
2243         /* create the win data if the window is being made visible */
2244         if (!(style & WS_VISIBLE) && !(swp_flags & SWP_SHOWWINDOW)) return;
2245         if (!(data = X11DRV_create_win_data( hwnd ))) return;
2246     }
2247
2248     /* check if we need to switch the window to managed */
2249     if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect ))
2250     {
2251         TRACE( "making win %p/%lx managed\n", hwnd, data->whole_window );
2252         if (data->mapped) unmap_window( thread_display(), data );
2253         data->managed = TRUE;
2254         SetPropA( hwnd, managed_prop, (HANDLE)1 );
2255     }
2256
2257     *visible_rect = *window_rect;
2258     X11DRV_window_to_X_rect( data, visible_rect );
2259 }
2260
2261
2262 /***********************************************************************
2263  *              WindowPosChanged   (X11DRV.@)
2264  */
2265 void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
2266                                     const RECT *rectWindow, const RECT *rectClient,
2267                                     const RECT *visible_rect, const RECT *valid_rects )
2268 {
2269     struct x11drv_thread_data *thread_data;
2270     Display *display;
2271     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2272     DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE );
2273     RECT old_window_rect, old_whole_rect, old_client_rect;
2274     int event_type;
2275
2276     if (!data) return;
2277
2278     thread_data = x11drv_thread_data();
2279     display = thread_data->display;
2280
2281     old_window_rect = data->window_rect;
2282     old_whole_rect  = data->whole_rect;
2283     old_client_rect = data->client_rect;
2284     data->window_rect = *rectWindow;
2285     data->whole_rect  = *visible_rect;
2286     data->client_rect = *rectClient;
2287
2288     TRACE( "win %p window %s client %s style %08x flags %08x\n",
2289            hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style, swp_flags );
2290
2291     if (!IsRectEmpty( &valid_rects[0] ))
2292     {
2293         int x_offset = old_whole_rect.left - data->whole_rect.left;
2294         int y_offset = old_whole_rect.top - data->whole_rect.top;
2295
2296         /* if all that happened is that the whole window moved, copy everything */
2297         if (!(swp_flags & SWP_FRAMECHANGED) &&
2298             old_whole_rect.right   - data->whole_rect.right   == x_offset &&
2299             old_whole_rect.bottom  - data->whole_rect.bottom  == y_offset &&
2300             old_client_rect.left   - data->client_rect.left   == x_offset &&
2301             old_client_rect.right  - data->client_rect.right  == x_offset &&
2302             old_client_rect.top    - data->client_rect.top    == y_offset &&
2303             old_client_rect.bottom - data->client_rect.bottom == y_offset &&
2304             !memcmp( &valid_rects[0], &data->client_rect, sizeof(RECT) ))
2305         {
2306             /* if we have an X window the bits will be moved by the X server */
2307             if (!data->whole_window)
2308                 move_window_bits( data, &old_whole_rect, &data->whole_rect, &old_client_rect );
2309         }
2310         else
2311             move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_client_rect );
2312     }
2313
2314     wine_tsx11_lock();
2315     XFlush( gdi_display );  /* make sure painting is done before we move the window */
2316     wine_tsx11_unlock();
2317
2318     sync_client_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
2319
2320     if (!data->whole_window) return;
2321
2322     /* check if we are currently processing an event relevant to this window */
2323     event_type = 0;
2324     if (thread_data->current_event && thread_data->current_event->xany.window == data->whole_window)
2325         event_type = thread_data->current_event->type;
2326
2327     if (event_type != ConfigureNotify && event_type != PropertyNotify)
2328         event_type = 0;  /* ignore other events */
2329
2330     if (data->mapped)
2331     {
2332         if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) ||
2333             (!event_type && !is_window_rect_mapped( rectWindow )))
2334             unmap_window( display, data );
2335     }
2336
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))))
2340         sync_window_position( display, data, swp_flags,
2341                               &old_window_rect, &old_whole_rect, &old_client_rect );
2342
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
2377 /***********************************************************************
2378  *           ShowWindow   (X11DRV.@)
2379  */
2380 UINT CDECL X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
2381 {
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;
2391     if (IsRectEmpty( rect )) return swp;
2392
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
2420 /**********************************************************************
2421  *              SetWindowIcon (X11DRV.@)
2422  *
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  */
2430 void CDECL X11DRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon )
2431 {
2432     Display *display = thread_display();
2433     struct x11drv_win_data *data;
2434
2435
2436     if (!(data = X11DRV_get_win_data( hwnd ))) return;
2437     if (!data->whole_window) return;
2438     if (!data->managed) return;
2439
2440     if (data->wm_hints)
2441     {
2442         if (type == ICON_BIG) set_icon_hints( display, data, icon, 0 );
2443         else set_icon_hints( display, data, 0, icon );
2444         wine_tsx11_lock();
2445         XSetWMHints( display, data->whole_window, data->wm_hints );
2446         wine_tsx11_unlock();
2447     }
2448 }
2449
2450
2451 /***********************************************************************
2452  *              SetWindowRgn  (X11DRV.@)
2453  *
2454  * Assign specified region to window (for non-rectangular windows)
2455  */
2456 int CDECL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
2457 {
2458     struct x11drv_win_data *data;
2459
2460     if ((data = X11DRV_get_win_data( hwnd )))
2461     {
2462         sync_window_region( thread_display(), data, hrgn );
2463     }
2464     else if (X11DRV_get_whole_window( hwnd ))
2465     {
2466         SendMessageW( hwnd, WM_X11DRV_SET_WIN_REGION, 0, 0 );
2467     }
2468     return TRUE;
2469 }
2470
2471
2472 /***********************************************************************
2473  *              SetLayeredWindowAttributes  (X11DRV.@)
2474  *
2475  * Set transparency attributes for a layered window.
2476  */
2477 void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
2478 {
2479     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
2480
2481     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     }
2491 }
2492
2493
2494 /**********************************************************************
2495  *           X11DRV_WindowMessage   (X11DRV.@)
2496  */
2497 LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
2498 {
2499     struct x11drv_win_data *data;
2500
2501     switch(msg)
2502     {
2503     case WM_X11DRV_ACQUIRE_SELECTION:
2504         return X11DRV_AcquireClipboard( hwnd );
2505     case WM_X11DRV_SET_WIN_FORMAT:
2506         return set_win_format( hwnd, (XID)wp );
2507     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;
2510     case WM_X11DRV_RESIZE_DESKTOP:
2511         X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) );
2512         return 0;
2513     case WM_X11DRV_SET_CURSOR:
2514         set_window_cursor( hwnd, (HCURSOR)lp );
2515         return 0;
2516     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
2523 /***********************************************************************
2524  *              is_netwm_supported
2525  */
2526 static 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  */
2559 LRESULT CDECL X11DRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam )
2560 {
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;
2629     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 */
2631     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 }