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