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