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