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