winex11: Add generic mechanism for managing WM_STATE properties.
[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
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "wine/unicode.h"
41
42 #include "x11drv.h"
43 #include "xcomposite.h"
44 #include "wine/debug.h"
45 #include "wine/server.h"
46 #include "win.h"
47 #include "mwm.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
50
51 /* X context to associate a hwnd to an X window */
52 XContext winContext = 0;
53
54 /* X context to associate a struct x11drv_win_data to an hwnd */
55 static XContext win_data_context;
56
57 static const char whole_window_prop[] = "__wine_x11_whole_window";
58 static const char icon_window_prop[]  = "__wine_x11_icon_window";
59 static const char fbconfig_id_prop[]  = "__wine_x11_fbconfig_id";
60 static const char gl_drawable_prop[]  = "__wine_x11_gl_drawable";
61 static const char pixmap_prop[]       = "__wine_x11_pixmap";
62 static const char managed_prop[]      = "__wine_x11_managed";
63 static const char visual_id_prop[]    = "__wine_x11_visual_id";
64
65 /* for XDG systray icons */
66 #define SYSTEM_TRAY_REQUEST_DOCK    0
67
68 extern int usexcomposite;
69
70 /***********************************************************************
71  *              is_window_managed
72  *
73  * Check if a given window should be managed
74  */
75 BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rect )
76 {
77     DWORD style, ex_style;
78
79     /* tray window is always managed */
80     ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
81     if (ex_style & WS_EX_TRAYWINDOW) return TRUE;
82     /* child windows are not managed */
83     style = GetWindowLongW( hwnd, GWL_STYLE );
84     if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) return FALSE;
85     /* activated windows are managed */
86     if (!(swp_flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) return TRUE;
87     if (hwnd == GetActiveWindow()) return TRUE;
88     /* windows with caption are managed */
89     if ((style & WS_CAPTION) == WS_CAPTION) return TRUE;
90     /* tool windows are not managed  */
91     if (ex_style & WS_EX_TOOLWINDOW) return FALSE;
92     /* windows with thick frame are managed */
93     if (style & WS_THICKFRAME) return TRUE;
94     /* application windows are managed */
95     if (ex_style & WS_EX_APPWINDOW) return TRUE;
96     if (style & WS_POPUP)
97     {
98         /* popup with sysmenu == caption are managed */
99         if (style & WS_SYSMENU) return TRUE;
100         /* full-screen popup windows are managed */
101         if ((window_rect->right - window_rect->left) == screen_width &&
102             (window_rect->bottom - window_rect->top) == screen_height)
103             return TRUE;
104     }
105     /* default: not managed */
106     return FALSE;
107 }
108
109
110 /***********************************************************************
111  *              X11DRV_is_window_rect_mapped
112  *
113  * Check if the X whole window should be mapped based on its rectangle
114  */
115 BOOL X11DRV_is_window_rect_mapped( const RECT *rect )
116 {
117     /* don't map if rect is empty */
118     if (IsRectEmpty( rect )) return FALSE;
119
120     /* don't map if rect is off-screen */
121     if (rect->left >= virtual_screen_rect.right ||
122         rect->top >= virtual_screen_rect.bottom ||
123         rect->right <= virtual_screen_rect.left ||
124         rect->bottom <= virtual_screen_rect.top)
125         return FALSE;
126
127     return TRUE;
128 }
129
130
131 /***********************************************************************
132  *              get_window_attributes
133  *
134  * Fill the window attributes structure for an X window.
135  */
136 static int get_window_attributes( Display *display, struct x11drv_win_data *data,
137                                   XSetWindowAttributes *attr )
138 {
139     attr->override_redirect = !data->managed;
140     attr->colormap          = X11DRV_PALETTE_PaletteXColormap;
141     attr->save_under        = ((GetClassLongW( data->hwnd, GCL_STYLE ) & CS_SAVEBITS) != 0);
142     attr->cursor            = x11drv_thread_data()->cursor;
143     attr->bit_gravity       = NorthWestGravity;
144     attr->backing_store     = NotUseful;
145     attr->event_mask        = (ExposureMask | PointerMotionMask |
146                                ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
147                                KeyPressMask | KeyReleaseMask | FocusChangeMask | KeymapStateMask);
148     if (data->managed) attr->event_mask |= StructureNotifyMask;
149
150     return (CWOverrideRedirect | CWSaveUnder | CWColormap | CWCursor |
151             CWEventMask | CWBitGravity | CWBackingStore);
152 }
153
154
155 /***********************************************************************
156  *              X11DRV_sync_window_style
157  *
158  * Change the X window attributes when the window style has changed.
159  */
160 void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data )
161 {
162     if (data->whole_window != root_window)
163     {
164         XSetWindowAttributes attr;
165         int mask = get_window_attributes( display, data, &attr );
166
167         wine_tsx11_lock();
168         XChangeWindowAttributes( display, data->whole_window, mask, &attr );
169         wine_tsx11_unlock();
170     }
171 }
172
173
174 /***********************************************************************
175  *              X11DRV_set_win_format
176  */
177 BOOL X11DRV_set_win_format( HWND hwnd, XID fbconfig_id )
178 {
179     Display *display = thread_display();
180     struct x11drv_win_data *data;
181     XVisualInfo *vis;
182     Drawable parent;
183     HWND next_hwnd;
184     int w, h;
185
186     if (!(data = X11DRV_get_win_data(hwnd))) return FALSE;
187
188     wine_tsx11_lock();
189
190     vis = visual_from_fbconfig_id(fbconfig_id);
191     if(!vis) return FALSE;
192
193     if(data->whole_window && vis->visualid == XVisualIDFromVisual(visual))
194     {
195         TRACE("Whole window available and visual match, rendering onscreen\n");
196         goto done;
197     }
198
199     wine_tsx11_unlock();
200
201     parent = data->whole_window;
202     next_hwnd = hwnd;
203     while(!parent)
204     {
205         next_hwnd = GetAncestor(next_hwnd, GA_PARENT);
206         if(!next_hwnd)
207         {
208             ERR("Could not find parent HWND with a drawable!\n");
209             return FALSE;
210         }
211         parent = X11DRV_get_whole_window(next_hwnd);
212     }
213
214     w = data->client_rect.right - data->client_rect.left;
215     h = data->client_rect.bottom - data->client_rect.top;
216
217     if(w <= 0) w = 1;
218     if(h <= 0) h = 1;
219
220     wine_tsx11_lock();
221 #ifdef SONAME_LIBXCOMPOSITE
222     if(usexcomposite)
223     {
224         XSetWindowAttributes attrib;
225
226         attrib.override_redirect = True;
227         attrib.colormap = XCreateColormap(display, parent, vis->visual,
228                                           (vis->class == PseudoColor ||
229                                            vis->class == GrayScale ||
230                                            vis->class == DirectColor) ?
231                                           AllocAll : AllocNone);
232         XInstallColormap(gdi_display, attrib.colormap);
233
234         data->gl_drawable = XCreateWindow(display, parent, -w, 0, w, h, 0,
235                                           vis->depth, InputOutput, vis->visual,
236                                           CWColormap | CWOverrideRedirect,
237                                           &attrib);
238         if(data->gl_drawable)
239         {
240             pXCompositeRedirectWindow(display, data->gl_drawable,
241                                       CompositeRedirectManual);
242             XMapWindow(display, data->gl_drawable);
243         }
244     }
245     else
246 #endif
247     {
248         WARN("XComposite is not available, using GLXPixmap hack\n");
249
250         data->pixmap = XCreatePixmap(display, parent, w, h, vis->depth);
251         if(!data->pixmap)
252         {
253             ERR("Failed to create pixmap for offscreen rendering\n");
254             XFree(vis);
255             wine_tsx11_unlock();
256             return FALSE;
257         }
258
259         data->gl_drawable = create_glxpixmap(display, vis, data->pixmap);
260         if(!data->gl_drawable)
261         {
262             XFreePixmap(display, data->pixmap);
263             data->pixmap = 0;
264         }
265     }
266
267     if(!data->gl_drawable)
268     {
269         ERR("Failed to create drawable for offscreen rendering\n");
270         XFree(vis);
271         wine_tsx11_unlock();
272         return FALSE;
273     }
274
275 done:
276     XFree(vis);
277
278     XFlush(display);
279     wine_tsx11_unlock();
280
281     TRACE("Created GL drawable 0x%lx, using FBConfigID 0x%lx\n",
282           data->gl_drawable, fbconfig_id);
283
284     data->fbconfig_id = fbconfig_id;
285     SetPropA(hwnd, fbconfig_id_prop, (HANDLE)data->fbconfig_id);
286     SetPropA(hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
287     SetPropA(hwnd, pixmap_prop, (HANDLE)data->pixmap);
288     invalidate_dce( hwnd, &data->window_rect );
289     return TRUE;
290 }
291
292 static void update_gl_drawable(Display *display, struct x11drv_win_data *data, const RECT *old_client_rect)
293 {
294     int w = data->client_rect.right - data->client_rect.left;
295     int h = data->client_rect.bottom - data->client_rect.top;
296     XVisualInfo *vis;
297     Drawable parent;
298     HWND next_hwnd;
299     Drawable glxp;
300     Pixmap pix;
301
302     if((w == old_client_rect->right - old_client_rect->left &&
303         h == old_client_rect->bottom - old_client_rect->top) ||
304        w <= 0 || h <= 0)
305     {
306         TRACE("No resize needed\n");
307         return;
308     }
309
310     TRACE("Resizing GL drawable 0x%lx to %dx%d\n", data->gl_drawable, w, h);
311 #ifdef SONAME_LIBXCOMPOSITE
312     if(usexcomposite)
313     {
314         wine_tsx11_lock();
315         XMoveResizeWindow(display, data->gl_drawable, -w, 0, w, h);
316         wine_tsx11_unlock();
317         return;
318     }
319 #endif
320
321     parent = data->whole_window;
322     next_hwnd = data->hwnd;
323     while(!parent)
324     {
325         next_hwnd = GetAncestor(next_hwnd, GA_PARENT);
326         if(!next_hwnd)
327         {
328             ERR("Could not find parent HWND with a drawable!\n");
329             return;
330         }
331         parent = X11DRV_get_whole_window(next_hwnd);
332     }
333
334     wine_tsx11_lock();
335
336     vis = visual_from_fbconfig_id(data->fbconfig_id);
337     if(!vis) return;
338
339     pix = XCreatePixmap(display, parent, w, h, vis->depth);
340     if(!pix)
341     {
342         ERR("Failed to create pixmap for offscreen rendering\n");
343         XFree(vis);
344         wine_tsx11_unlock();
345         return;
346     }
347
348     glxp = create_glxpixmap(display, vis, pix);
349     if(!glxp)
350     {
351         ERR("Failed to create drawable for offscreen rendering\n");
352         XFreePixmap(display, pix);
353         XFree(vis);
354         wine_tsx11_unlock();
355         return;
356     }
357
358     XFree(vis);
359
360     mark_drawable_dirty(data->gl_drawable, glxp);
361
362     XFreePixmap(display, data->pixmap);
363     destroy_glxpixmap(display, data->gl_drawable);
364
365     data->pixmap = pix;
366     data->gl_drawable = glxp;
367
368     XFlush(display);
369     wine_tsx11_unlock();
370
371     SetPropA(data->hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
372     SetPropA(data->hwnd, pixmap_prop, (HANDLE)data->pixmap);
373     invalidate_dce( data->hwnd, &data->window_rect );
374 }
375
376
377 /***********************************************************************
378  *              get_window_changes
379  *
380  * fill the window changes structure
381  */
382 static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
383 {
384     int mask = 0;
385
386     if (old->right - old->left != new->right - new->left )
387     {
388         if (!(changes->width = new->right - new->left)) changes->width = 1;
389         mask |= CWWidth;
390     }
391     if (old->bottom - old->top != new->bottom - new->top)
392     {
393         if (!(changes->height = new->bottom - new->top)) changes->height = 1;
394         mask |= CWHeight;
395     }
396     if (old->left != new->left)
397     {
398         changes->x = new->left;
399         mask |= CWX;
400     }
401     if (old->top != new->top)
402     {
403         changes->y = new->top;
404         mask |= CWY;
405     }
406     return mask;
407 }
408
409
410 /***********************************************************************
411  *              create_icon_window
412  */
413 static Window create_icon_window( Display *display, struct x11drv_win_data *data )
414 {
415     XSetWindowAttributes attr;
416
417     attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
418                        ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
419     attr.bit_gravity = NorthWestGravity;
420     attr.backing_store = NotUseful/*WhenMapped*/;
421     attr.colormap      = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
422
423     wine_tsx11_lock();
424     data->icon_window = XCreateWindow( display, root_window, 0, 0,
425                                        GetSystemMetrics( SM_CXICON ),
426                                        GetSystemMetrics( SM_CYICON ),
427                                        0, screen_depth,
428                                        InputOutput, visual,
429                                        CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
430     XSaveContext( display, data->icon_window, winContext, (char *)data->hwnd );
431     wine_tsx11_unlock();
432
433     TRACE( "created %lx\n", data->icon_window );
434     SetPropA( data->hwnd, icon_window_prop, (HANDLE)data->icon_window );
435     return data->icon_window;
436 }
437
438
439
440 /***********************************************************************
441  *              destroy_icon_window
442  */
443 static void destroy_icon_window( Display *display, struct x11drv_win_data *data )
444 {
445     if (!data->icon_window) return;
446     if (x11drv_thread_data()->cursor_window == data->icon_window)
447         x11drv_thread_data()->cursor_window = None;
448     wine_tsx11_lock();
449     XDeleteContext( display, data->icon_window, winContext );
450     XDestroyWindow( display, data->icon_window );
451     data->icon_window = 0;
452     wine_tsx11_unlock();
453     RemovePropA( data->hwnd, icon_window_prop );
454 }
455
456
457 /***********************************************************************
458  *              set_icon_hints
459  *
460  * Set the icon wm hints
461  */
462 static void set_icon_hints( Display *display, struct x11drv_win_data *data, HICON hIcon )
463 {
464     XWMHints *hints = data->wm_hints;
465
466     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
467     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
468     data->hWMIconBitmap = 0;
469     data->hWMIconMask = 0;
470
471     if (!data->managed)
472     {
473         destroy_icon_window( display, data );
474         hints->flags &= ~(IconPixmapHint | IconMaskHint | IconWindowHint);
475     }
476     else if (!hIcon)
477     {
478         if (!data->icon_window) create_icon_window( display, data );
479         hints->icon_window = data->icon_window;
480         hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
481     }
482     else
483     {
484         HBITMAP hbmOrig;
485         RECT rcMask;
486         BITMAP bmMask;
487         ICONINFO ii;
488         HDC hDC;
489
490         GetIconInfo(hIcon, &ii);
491
492         GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
493         rcMask.top    = 0;
494         rcMask.left   = 0;
495         rcMask.right  = bmMask.bmWidth;
496         rcMask.bottom = bmMask.bmHeight;
497
498         hDC = CreateCompatibleDC(0);
499         hbmOrig = SelectObject(hDC, ii.hbmMask);
500         InvertRect(hDC, &rcMask);
501         SelectObject(hDC, ii.hbmColor);  /* force the color bitmap to x11drv mode too */
502         SelectObject(hDC, hbmOrig);
503         DeleteDC(hDC);
504
505         data->hWMIconBitmap = ii.hbmColor;
506         data->hWMIconMask = ii.hbmMask;
507
508         hints->icon_pixmap = X11DRV_get_pixmap(data->hWMIconBitmap);
509         hints->icon_mask = X11DRV_get_pixmap(data->hWMIconMask);
510         destroy_icon_window( display, data );
511         hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
512     }
513 }
514
515 /***********************************************************************
516  *              systray_dock_window
517  *
518  * Docks the given X window with the NETWM system tray.
519  */
520 static void systray_dock_window( Display *display, struct x11drv_win_data *data )
521 {
522     static Atom systray_atom;
523     Window systray_window;
524
525     wine_tsx11_lock();
526     if (!systray_atom)
527     {
528         if (DefaultScreen( display ) == 0)
529             systray_atom = x11drv_atom(_NET_SYSTEM_TRAY_S0);
530         else
531         {
532             char systray_buffer[29]; /* strlen(_NET_SYSTEM_TRAY_S4294967295)+1 */
533             sprintf( systray_buffer, "_NET_SYSTEM_TRAY_S%u", DefaultScreen( display ) );
534             systray_atom = XInternAtom( display, systray_buffer, False );
535         }
536     }
537     systray_window = XGetSelectionOwner( display, systray_atom );
538     wine_tsx11_unlock();
539
540     TRACE("Docking tray icon %p\n", data->hwnd);
541
542     if (systray_window != None)
543     {
544         XEvent ev;
545         unsigned long info[2];
546                 
547         /* Put the window offscreen so it isn't mapped. The window _cannot_ be 
548          * mapped if we intend to dock with an XEMBED tray. If the window is 
549          * mapped when we dock, it may become visible as a child of the root 
550          * window after it docks, which isn't the proper behavior. 
551          *
552          * For more information on this problem, see
553          * http://standards.freedesktop.org/xembed-spec/latest/ar01s04.html */
554         
555         SetWindowPos( data->hwnd, NULL, virtual_screen_rect.right + 1, virtual_screen_rect.bottom + 1,
556                       0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE );
557
558         /* set XEMBED protocol data on the window */
559         info[0] = 0; /* protocol version */
560         info[1] = 1; /* mapped = true */
561         
562         wine_tsx11_lock();
563         XChangeProperty( display, data->whole_window,
564                          x11drv_atom(_XEMBED_INFO),
565                          x11drv_atom(_XEMBED_INFO), 32, PropModeReplace,
566                          (unsigned char*)info, 2 );
567         wine_tsx11_unlock();
568     
569         /* send the docking request message */
570         ZeroMemory( &ev, sizeof(ev) ); 
571         ev.xclient.type = ClientMessage;
572         ev.xclient.window = systray_window;
573         ev.xclient.message_type = x11drv_atom( _NET_SYSTEM_TRAY_OPCODE );
574         ev.xclient.format = 32;
575         ev.xclient.data.l[0] = CurrentTime;
576         ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
577         ev.xclient.data.l[2] = data->whole_window;
578         ev.xclient.data.l[3] = 0;
579         ev.xclient.data.l[4] = 0;
580         
581         wine_tsx11_lock();
582         XSendEvent( display, systray_window, False, NoEventMask, &ev );
583         wine_tsx11_unlock();
584
585     }
586     else
587     {
588         int val = 1;
589
590         /* fall back to he KDE hints if the WM doesn't support XEMBED'ed
591          * systrays */
592         
593         wine_tsx11_lock();
594         XChangeProperty( display, data->whole_window, 
595                          x11drv_atom(KWM_DOCKWINDOW),
596                          x11drv_atom(KWM_DOCKWINDOW), 32, PropModeReplace,
597                          (unsigned char*)&val, 1 );
598         XChangeProperty( display, data->whole_window,
599                          x11drv_atom(_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR),
600                          XA_WINDOW, 32, PropModeReplace,
601                          (unsigned char*)&data->whole_window, 1 );
602        wine_tsx11_unlock();
603     }
604 }
605
606
607 /***********************************************************************
608  *              set_size_hints
609  *
610  * set the window size hints
611  */
612 static void set_size_hints( Display *display, struct x11drv_win_data *data, DWORD style )
613 {
614     XSizeHints* size_hints;
615
616     if ((size_hints = XAllocSizeHints()))
617     {
618         size_hints->flags = 0;
619
620         if (data->hwnd != GetDesktopWindow())  /* don't force position of desktop */
621         {
622             size_hints->win_gravity = StaticGravity;
623             size_hints->x = data->whole_rect.left;
624             size_hints->y = data->whole_rect.top;
625             size_hints->flags |= PWinGravity | PPosition;
626         }
627
628         if ( !(style & WS_THICKFRAME) )
629         {
630             size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
631             size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
632             size_hints->min_width = size_hints->max_width;
633             size_hints->min_height = size_hints->max_height;
634             size_hints->flags |= PMinSize | PMaxSize;
635         }
636         XSetWMNormalHints( display, data->whole_window, size_hints );
637         XFree( size_hints );
638     }
639 }
640
641
642 /***********************************************************************
643  *              get_process_name
644  *
645  * get the name of the current process for setting class hints
646  */
647 static char *get_process_name(void)
648 {
649     static char *name;
650
651     if (!name)
652     {
653         WCHAR module[MAX_PATH];
654         DWORD len = GetModuleFileNameW( 0, module, MAX_PATH );
655         if (len && len < MAX_PATH)
656         {
657             char *ptr;
658             WCHAR *p, *appname = module;
659
660             if ((p = strrchrW( appname, '/' ))) appname = p + 1;
661             if ((p = strrchrW( appname, '\\' ))) appname = p + 1;
662             len = WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, NULL, 0, NULL, NULL );
663             if ((ptr = HeapAlloc( GetProcessHeap(), 0, len )))
664             {
665                 WideCharToMultiByte( CP_UNIXCP, 0, appname, -1, ptr, len, NULL, NULL );
666                 name = ptr;
667             }
668         }
669     }
670     return name;
671 }
672
673
674 /***********************************************************************
675  *              set_initial_wm_hints
676  *
677  * Set the window manager hints that don't change over the lifetime of a window.
678  */
679 static void set_initial_wm_hints( Display *display, struct x11drv_win_data *data )
680 {
681     int i;
682     Atom protocols[3];
683     Atom dndVersion = 4;
684     XClassHint *class_hints;
685     char *process_name = get_process_name();
686
687     wine_tsx11_lock();
688
689     /* wm protocols */
690     i = 0;
691     protocols[i++] = x11drv_atom(WM_DELETE_WINDOW);
692     protocols[i++] = x11drv_atom(_NET_WM_PING);
693     if (use_take_focus) protocols[i++] = x11drv_atom(WM_TAKE_FOCUS);
694     XChangeProperty( display, data->whole_window, x11drv_atom(WM_PROTOCOLS),
695                      XA_ATOM, 32, PropModeReplace, (unsigned char *)protocols, i );
696
697     /* class hints */
698     if ((class_hints = XAllocClassHint()))
699     {
700         static char wine[] = "Wine";
701
702         class_hints->res_name = process_name;
703         class_hints->res_class = wine;
704         XSetClassHint( display, data->whole_window, class_hints );
705         XFree( class_hints );
706     }
707
708     /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */
709     XSetWMProperties(display, data->whole_window, NULL, NULL, NULL, 0, NULL, NULL, NULL);
710     /* set the pid. together, these properties are needed so the window manager can kill us if we freeze */
711     i = getpid();
712     XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_PID),
713                     XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&i, 1);
714
715     XChangeProperty( display, data->whole_window, x11drv_atom(XdndAware),
716                      XA_ATOM, 32, PropModeReplace, (unsigned char*)&dndVersion, 1 );
717
718     wine_tsx11_unlock();
719 }
720
721
722 /***********************************************************************
723  *              X11DRV_set_wm_hints
724  *
725  * Set the window manager hints for a newly-created window
726  */
727 void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data )
728 {
729     Window group_leader;
730     Atom window_type;
731     MwmHints mwm_hints;
732     DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
733     DWORD ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
734     HWND owner = GetWindow( data->hwnd, GW_OWNER );
735
736     if (data->hwnd == GetDesktopWindow())
737     {
738         if (data->whole_window == DefaultRootWindow(display)) return;
739         /* force some styles for the desktop to get the correct decorations */
740         style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
741         owner = 0;
742     }
743
744     /* transient for hint */
745     if (owner)
746     {
747         Window owner_win = X11DRV_get_whole_window( owner );
748         wine_tsx11_lock();
749         XSetTransientForHint( display, data->whole_window, owner_win );
750         wine_tsx11_unlock();
751         group_leader = owner_win;
752     }
753     else group_leader = data->whole_window;
754
755     wine_tsx11_lock();
756
757     /* size hints */
758     set_size_hints( display, data, style );
759
760     /* set the WM_WINDOW_TYPE */
761     window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
762     if (ex_style & WS_EX_TOOLWINDOW) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_UTILITY);
763     else if (style & WS_THICKFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_NORMAL);
764     else if (style & WS_DLGFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
765     else if (ex_style & WS_EX_DLGMODALFRAME) window_type = x11drv_atom(_NET_WM_WINDOW_TYPE_DIALOG);
766
767     XChangeProperty(display, data->whole_window, x11drv_atom(_NET_WM_WINDOW_TYPE),
768                     XA_ATOM, 32, PropModeReplace, (unsigned char*)&window_type, 1);
769
770     mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
771     mwm_hints.functions = MWM_FUNC_MOVE;
772     if (style & WS_THICKFRAME)  mwm_hints.functions |= MWM_FUNC_RESIZE;
773     if (style & WS_MINIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MINIMIZE;
774     if (style & WS_MAXIMIZEBOX) mwm_hints.functions |= MWM_FUNC_MAXIMIZE;
775     if (style & WS_SYSMENU)     mwm_hints.functions |= MWM_FUNC_CLOSE;
776     mwm_hints.decorations = 0;
777     if (!(ex_style & WS_EX_TOOLWINDOW))
778     {
779         if ((style & WS_CAPTION) == WS_CAPTION)
780         {
781             mwm_hints.decorations |= MWM_DECOR_TITLE;
782             if (style & WS_SYSMENU) mwm_hints.decorations |= MWM_DECOR_MENU;
783             if (style & WS_MINIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MINIMIZE;
784             if (style & WS_MAXIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MAXIMIZE;
785         }
786         if (ex_style & WS_EX_DLGMODALFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
787         else if (style & WS_THICKFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
788         else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) mwm_hints.decorations |= MWM_DECOR_BORDER;
789         else if (style & WS_BORDER) mwm_hints.decorations |= MWM_DECOR_BORDER;
790         else if (!(style & (WS_CHILD|WS_POPUP))) mwm_hints.decorations |= MWM_DECOR_BORDER;
791     }
792
793     XChangeProperty( display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS),
794                      x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace,
795                      (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) );
796
797     wine_tsx11_unlock();
798
799     /* wm hints */
800     if (data->wm_hints)
801     {
802         data->wm_hints->flags = InputHint | StateHint | WindowGroupHint;
803         data->wm_hints->input = !(style & WS_DISABLED);
804         data->wm_hints->initial_state = (style & WS_MINIMIZE) ? IconicState : NormalState;
805         data->wm_hints->window_group = group_leader;
806         set_icon_hints( display, data, (HICON)GetClassLongPtrW( data->hwnd, GCLP_HICON ) );
807
808         wine_tsx11_lock();
809         XSetWMHints( display, data->whole_window, data->wm_hints );
810         wine_tsx11_unlock();
811     }
812 }
813
814
815 /***********************************************************************
816  *              X11DRV_set_iconic_state
817  *
818  * Set the X11 iconic state according to the window style.
819  */
820 void X11DRV_set_iconic_state( HWND hwnd )
821 {
822     Display *display = thread_display();
823     struct x11drv_win_data *data;
824     RECT rect;
825     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
826     BOOL iconic = (style & WS_MINIMIZE) != 0;
827
828     if (!(data = X11DRV_get_win_data( hwnd ))) return;
829     if (!data->whole_window || data->whole_window == DefaultRootWindow(display)) return;
830
831     GetWindowRect( hwnd, &rect );
832
833     wine_tsx11_lock();
834
835     if (data->wm_hints)
836     {
837         data->wm_hints->flags |= StateHint | IconPositionHint;
838         data->wm_hints->initial_state = iconic ? IconicState : NormalState;
839         data->wm_hints->icon_x = rect.left - virtual_screen_rect.left;
840         data->wm_hints->icon_y = rect.top - virtual_screen_rect.top;
841         XSetWMHints( display, data->whole_window, data->wm_hints );
842     }
843
844     if (style & WS_VISIBLE)
845     {
846         if (iconic)
847             XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
848         else
849             if (X11DRV_is_window_rect_mapped( &rect ))
850                 XMapWindow( display, data->whole_window );
851     }
852
853     wine_tsx11_unlock();
854 }
855
856
857 /***********************************************************************
858  *              X11DRV_window_to_X_rect
859  *
860  * Convert a rect from client to X window coordinates
861  */
862 void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect )
863 {
864     RECT rc;
865     DWORD ex_style;
866
867     if (!data->managed) return;
868     if (IsRectEmpty( rect )) return;
869     ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
870     if (ex_style & WS_EX_TOOLWINDOW) return;
871
872     rc.top = rc.bottom = rc.left = rc.right = 0;
873
874     AdjustWindowRectEx( &rc, GetWindowLongW( data->hwnd, GWL_STYLE ) & ~(WS_HSCROLL|WS_VSCROLL),
875                         FALSE, ex_style );
876
877     rect->left   -= rc.left;
878     rect->right  -= rc.right;
879     rect->top    -= rc.top;
880     rect->bottom -= rc.bottom;
881     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
882     if (rect->left >= rect->right) rect->right = rect->left + 1;
883 }
884
885
886 /***********************************************************************
887  *              X11DRV_X_to_window_rect
888  *
889  * Opposite of X11DRV_window_to_X_rect
890  */
891 void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect )
892 {
893     DWORD ex_style;
894
895     if (!data->managed) return;
896     if (IsRectEmpty( rect )) return;
897     ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE );
898     if (ex_style & WS_EX_TOOLWINDOW) return;
899
900     AdjustWindowRectEx( rect, GetWindowLongW( data->hwnd, GWL_STYLE ) & ~(WS_HSCROLL|WS_VSCROLL),
901                         FALSE, ex_style );
902
903     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
904     if (rect->left >= rect->right) rect->right = rect->left + 1;
905 }
906
907
908 /***********************************************************************
909  *              X11DRV_sync_window_position
910  *
911  * Synchronize the X window position with the Windows one
912  */
913 void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data,
914                                   UINT swp_flags, const RECT *new_client_rect,
915                                   const RECT *new_whole_rect )
916 {
917     XWindowChanges changes;
918     int mask;
919     RECT old_whole_rect;
920     RECT old_client_rect;
921
922     old_whole_rect = data->whole_rect;
923     data->whole_rect = *new_whole_rect;
924
925     old_client_rect = data->client_rect;
926     data->client_rect = *new_client_rect;
927     OffsetRect( &data->client_rect, -data->whole_rect.left, -data->whole_rect.top );
928
929     if (data->gl_drawable)
930         update_gl_drawable(display, data, &old_client_rect);
931
932     if (!data->whole_window || data->lock_changes) return;
933
934     mask = get_window_changes( &changes, &old_whole_rect, &data->whole_rect );
935
936     if (!(swp_flags & SWP_NOZORDER))
937     {
938         /* find window that this one must be after */
939         HWND prev = GetWindow( data->hwnd, GW_HWNDPREV );
940         while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE))
941             prev = GetWindow( prev, GW_HWNDPREV );
942         if (!prev)  /* top child */
943         {
944             changes.stack_mode = Above;
945             mask |= CWStackMode;
946         }
947         else
948         {
949             /* should use stack_mode Below but most window managers don't get it right */
950             /* so move it above the next one in Z order */
951             HWND next = GetWindow( data->hwnd, GW_HWNDNEXT );
952             while (next && !(GetWindowLongW( next, GWL_STYLE ) & WS_VISIBLE))
953                 next = GetWindow( next, GW_HWNDNEXT );
954             if (next)
955             {
956                 changes.stack_mode = Above;
957                 changes.sibling = X11DRV_get_whole_window(next);
958                 mask |= CWStackMode | CWSibling;
959             }
960         }
961     }
962
963     if (mask)
964     {
965         DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE );
966
967         TRACE( "setting win %lx pos %d,%d,%dx%d after %lx changes=%x\n",
968                data->whole_window, data->whole_rect.left, data->whole_rect.top,
969                data->whole_rect.right - data->whole_rect.left,
970                data->whole_rect.bottom - data->whole_rect.top, changes.sibling, mask );
971
972         wine_tsx11_lock();
973         if (mask & (CWWidth|CWHeight)) set_size_hints( display, data, style );
974         if (mask & CWX) changes.x -= virtual_screen_rect.left;
975         if (mask & CWY) changes.y -= virtual_screen_rect.top;
976         XReconfigureWMWindow( display, data->whole_window,
977                               DefaultScreen(display), mask, &changes );
978         wine_tsx11_unlock();
979     }
980 }
981
982
983 /**********************************************************************
984  *              create_whole_window
985  *
986  * Create the whole X window for a given window
987  */
988 static Window create_whole_window( Display *display, struct x11drv_win_data *data, DWORD style )
989 {
990     int cx, cy, mask;
991     XSetWindowAttributes attr;
992     XIM xim;
993
994     if (!(cx = data->window_rect.right - data->window_rect.left)) cx = 1;
995     if (!(cy = data->window_rect.bottom - data->window_rect.top)) cy = 1;
996
997     mask = get_window_attributes( display, data, &attr );
998
999     wine_tsx11_lock();
1000
1001     data->whole_rect = data->window_rect;
1002     data->whole_window = XCreateWindow( display, root_window,
1003                                         data->window_rect.left - virtual_screen_rect.left,
1004                                         data->window_rect.top - virtual_screen_rect.top,
1005                                         cx, cy, 0, screen_depth, InputOutput,
1006                                         visual, mask, &attr );
1007
1008     if (!data->whole_window)
1009     {
1010         wine_tsx11_unlock();
1011         return 0;
1012     }
1013     XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd );
1014
1015     /* non-maximized child must be at bottom of Z order */
1016     if ((style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
1017     {
1018         XWindowChanges changes;
1019         changes.stack_mode = Below;
1020         XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
1021     }
1022     wine_tsx11_unlock();
1023
1024     xim = x11drv_thread_data()->xim;
1025     if (xim) data->xic = X11DRV_CreateIC( xim, display, data->whole_window );
1026
1027     set_initial_wm_hints( display, data );
1028     X11DRV_set_wm_hints( display, data );
1029
1030     SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window );
1031     return data->whole_window;
1032 }
1033
1034
1035 /**********************************************************************
1036  *              destroy_whole_window
1037  *
1038  * Destroy the whole X window for a given window.
1039  */
1040 static void destroy_whole_window( Display *display, struct x11drv_win_data *data )
1041 {
1042     struct x11drv_thread_data *thread_data = x11drv_thread_data();
1043
1044     if (!data->whole_window) return;
1045
1046     TRACE( "win %p xwin %lx\n", data->hwnd, data->whole_window );
1047     if (thread_data->cursor_window == data->whole_window) thread_data->cursor_window = None;
1048     wine_tsx11_lock();
1049     XDeleteContext( display, data->whole_window, winContext );
1050     if (data->whole_window != DefaultRootWindow(display))
1051         XDestroyWindow( display, data->whole_window );
1052     data->whole_window = 0;
1053     if (data->xic)
1054     {
1055         XUnsetICFocus( data->xic );
1056         XDestroyIC( data->xic );
1057     }
1058     /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */
1059     XFlush( display );
1060     wine_tsx11_unlock();
1061     RemovePropA( data->hwnd, whole_window_prop );
1062 }
1063
1064
1065 /*****************************************************************
1066  *              SetWindowText   (X11DRV.@)
1067  */
1068 void X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
1069 {
1070     Display *display = thread_display();
1071     UINT count;
1072     char *buffer;
1073     char *utf8_buffer;
1074     Window win;
1075     XTextProperty prop;
1076
1077     if ((win = X11DRV_get_whole_window( hwnd )) && win != DefaultRootWindow(display))
1078     {
1079         /* allocate new buffer for window text */
1080         count = WideCharToMultiByte(CP_UNIXCP, 0, text, -1, NULL, 0, NULL, NULL);
1081         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count )))
1082         {
1083             ERR("Not enough memory for window text\n");
1084             return;
1085         }
1086         WideCharToMultiByte(CP_UNIXCP, 0, text, -1, buffer, count, NULL, NULL);
1087
1088         count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
1089         if (!(utf8_buffer = HeapAlloc( GetProcessHeap(), 0, count )))
1090         {
1091             ERR("Not enough memory for window text in UTF-8\n");
1092             HeapFree( GetProcessHeap(), 0, buffer );
1093             return;
1094         }
1095         WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
1096
1097         wine_tsx11_lock();
1098         if (XmbTextListToTextProperty( display, &buffer, 1, XStdICCTextStyle, &prop ) == Success)
1099         {
1100             XSetWMName( display, win, &prop );
1101             XSetWMIconName( display, win, &prop );
1102             XFree( prop.value );
1103         }
1104         /*
1105         Implements a NET_WM UTF-8 title. It should be without a trailing \0,
1106         according to the standard
1107         ( http://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text ).
1108         */
1109         XChangeProperty( display, win, x11drv_atom(_NET_WM_NAME), x11drv_atom(UTF8_STRING),
1110                          8, PropModeReplace, (unsigned char *) utf8_buffer, count);
1111         wine_tsx11_unlock();
1112
1113         HeapFree( GetProcessHeap(), 0, utf8_buffer );
1114         HeapFree( GetProcessHeap(), 0, buffer );
1115     }
1116 }
1117
1118
1119 /***********************************************************************
1120  *              DestroyWindow   (X11DRV.@)
1121  */
1122 void X11DRV_DestroyWindow( HWND hwnd )
1123 {
1124     struct x11drv_thread_data *thread_data = x11drv_thread_data();
1125     Display *display = thread_data->display;
1126     struct x11drv_win_data *data;
1127
1128     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1129
1130     if (data->pixmap)
1131     {
1132         destroy_glxpixmap(display, data->gl_drawable);
1133         wine_tsx11_lock();
1134         XFreePixmap(display, data->pixmap);
1135         wine_tsx11_unlock();
1136     }
1137     else if (data->gl_drawable)
1138     {
1139         wine_tsx11_lock();
1140         XDestroyWindow(display, data->gl_drawable);
1141         wine_tsx11_unlock();
1142     }
1143
1144     free_window_dce( data );
1145     destroy_whole_window( display, data );
1146     destroy_icon_window( display, data );
1147
1148     if (thread_data->last_focus == hwnd) thread_data->last_focus = 0;
1149     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
1150     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
1151     wine_tsx11_lock();
1152     XDeleteContext( display, (XID)hwnd, win_data_context );
1153     XFree( data->wm_hints );
1154     wine_tsx11_unlock();
1155     HeapFree( GetProcessHeap(), 0, data );
1156 }
1157
1158
1159 static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd )
1160 {
1161     struct x11drv_win_data *data;
1162
1163     if ((data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data))))
1164     {
1165         data->hwnd          = hwnd;
1166         data->whole_window  = 0;
1167         data->icon_window   = 0;
1168         data->fbconfig_id   = 0;
1169         data->gl_drawable   = 0;
1170         data->pixmap        = 0;
1171         data->xic           = 0;
1172         data->managed       = FALSE;
1173         data->wm_state      = 0;
1174         data->dce           = NULL;
1175         data->lock_changes  = 0;
1176         data->hWMIconBitmap = 0;
1177         data->hWMIconMask   = 0;
1178
1179         wine_tsx11_lock();
1180         if (!winContext) winContext = XUniqueContext();
1181         if (!win_data_context) win_data_context = XUniqueContext();
1182         XSaveContext( display, (XID)hwnd, win_data_context, (char *)data );
1183         data->wm_hints = XAllocWMHints();
1184         wine_tsx11_unlock();
1185     }
1186     return data;
1187 }
1188
1189
1190 /* fill in the desktop X window id in the x11drv_win_data structure */
1191 static void get_desktop_xwin( Display *display, struct x11drv_win_data *data )
1192 {
1193     Window win = (Window)GetPropA( data->hwnd, whole_window_prop );
1194
1195     if (win)
1196     {
1197         unsigned int width, height;
1198
1199         /* retrieve the real size of the desktop */
1200         SERVER_START_REQ( get_window_rectangles )
1201         {
1202             req->handle = data->hwnd;
1203             wine_server_call( req );
1204             width  = reply->window.right - reply->window.left;
1205             height = reply->window.bottom - reply->window.top;
1206         }
1207         SERVER_END_REQ;
1208         data->whole_window = win;
1209         if (win != root_window) X11DRV_init_desktop( win, width, height );
1210     }
1211     else
1212     {
1213         VisualID visualid;
1214
1215         wine_tsx11_lock();
1216         visualid = XVisualIDFromVisual(visual);
1217         wine_tsx11_unlock();
1218         SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window );
1219         SetPropA( data->hwnd, visual_id_prop, (HANDLE)visualid );
1220         data->whole_window = root_window;
1221         X11DRV_SetWindowPos( data->hwnd, 0, &virtual_screen_rect, &virtual_screen_rect,
1222                              SWP_NOZORDER | SWP_NOACTIVATE, NULL );
1223         if (root_window != DefaultRootWindow( display ))
1224         {
1225             data->managed = TRUE;
1226             SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
1227             set_initial_wm_hints( display, data );
1228         }
1229     }
1230 }
1231
1232 /**********************************************************************
1233  *              CreateDesktopWindow   (X11DRV.@)
1234  */
1235 BOOL X11DRV_CreateDesktopWindow( HWND hwnd )
1236 {
1237     Display *display = thread_display();
1238     struct x11drv_win_data *data;
1239
1240     if (!(data = alloc_win_data( display, hwnd ))) return FALSE;
1241
1242     get_desktop_xwin( display, data );
1243
1244     return TRUE;
1245 }
1246
1247
1248 /**********************************************************************
1249  *              CreateWindow   (X11DRV.@)
1250  */
1251 BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
1252 {
1253     Display *display = thread_display();
1254     WND *wndPtr;
1255     struct x11drv_win_data *data;
1256     HWND insert_after;
1257     RECT rect;
1258     DWORD style;
1259     CBT_CREATEWNDA cbtc;
1260     CREATESTRUCTA cbcs;
1261     BOOL ret = FALSE;
1262
1263     if (!(data = alloc_win_data( display, hwnd ))) return FALSE;
1264
1265     if (cs->cx > 65535)
1266     {
1267         ERR( "invalid window width %d\n", cs->cx );
1268         cs->cx = 65535;
1269     }
1270     if (cs->cy > 65535)
1271     {
1272         ERR( "invalid window height %d\n", cs->cy );
1273         cs->cy = 65535;
1274     }
1275     if (cs->cx < 0)
1276     {
1277         ERR( "invalid window width %d\n", cs->cx );
1278         cs->cx = 0;
1279     }
1280     if (cs->cy < 0)
1281     {
1282         ERR( "invalid window height %d\n", cs->cy );
1283         cs->cy = 0;
1284     }
1285
1286     /* initialize the dimensions before sending WM_GETMINMAXINFO */
1287     SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1288     X11DRV_SetWindowPos( hwnd, 0, &rect, &rect, SWP_NOZORDER | SWP_NOACTIVATE, NULL );
1289
1290     /* create an X window if it's a top level window */
1291     if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1292     {
1293         if (!create_whole_window( display, data, cs->style )) goto failed;
1294     }
1295     else if (hwnd == GetDesktopWindow())
1296     {
1297         get_desktop_xwin( display, data );
1298     }
1299
1300     /* get class or window DC if needed */
1301     alloc_window_dce( data );
1302
1303     /* Call the WH_CBT hook */
1304
1305     /* the window style passed to the hook must be the real window style,
1306      * rather than just the window style that the caller to CreateWindowEx
1307      * passed in, so we have to copy the original CREATESTRUCT and get the
1308      * the real style. */
1309     cbcs = *cs;
1310     cbcs.style = GetWindowLongW(hwnd, GWL_STYLE);
1311
1312     cbtc.lpcs = &cbcs;
1313     cbtc.hwndInsertAfter = HWND_TOP;
1314     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode ))
1315     {
1316         TRACE("CBT-hook returned !0\n");
1317         goto failed;
1318     }
1319
1320     /* Send the WM_GETMINMAXINFO message and fix the size if needed */
1321     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1322     {
1323         POINT maxSize, maxPos, minTrack, maxTrack;
1324
1325         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1326         if (maxTrack.x < cs->cx) cs->cx = maxTrack.x;
1327         if (maxTrack.y < cs->cy) cs->cy = maxTrack.y;
1328         if (cs->cx < 0) cs->cx = 0;
1329         if (cs->cy < 0) cs->cy = 0;
1330
1331         SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
1332         if (!X11DRV_SetWindowPos( hwnd, 0, &rect, &rect, SWP_NOZORDER | SWP_NOACTIVATE, NULL ))
1333             return FALSE;
1334     }
1335
1336     /* send WM_NCCREATE */
1337     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cs->cx, cs->cy );
1338     if (unicode)
1339         ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1340     else
1341         ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1342     if (!ret)
1343     {
1344         WARN("aborted by WM_xxCREATE!\n");
1345         return FALSE;
1346     }
1347
1348     /* make sure the window is still valid */
1349     if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
1350     if (data->whole_window) X11DRV_sync_window_style( display, data );
1351
1352     /* send WM_NCCALCSIZE */
1353     rect = data->window_rect;
1354     SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect );
1355
1356     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1357
1358     /* yes, even if the CBT hook was called with HWND_TOP */
1359     insert_after = (wndPtr->dwStyle & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1360
1361     X11DRV_SetWindowPos( hwnd, insert_after, &wndPtr->rectWindow, &rect, SWP_NOACTIVATE, NULL );
1362
1363     TRACE( "win %p window %d,%d,%d,%d client %d,%d,%d,%d whole %d,%d,%d,%d X client %d,%d,%d,%d xwin %x\n",
1364            hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,
1365            wndPtr->rectWindow.right, wndPtr->rectWindow.bottom,
1366            wndPtr->rectClient.left, wndPtr->rectClient.top,
1367            wndPtr->rectClient.right, wndPtr->rectClient.bottom,
1368            data->whole_rect.left, data->whole_rect.top,
1369            data->whole_rect.right, data->whole_rect.bottom,
1370            data->client_rect.left, data->client_rect.top,
1371            data->client_rect.right, data->client_rect.bottom,
1372            (unsigned int)data->whole_window );
1373
1374     WIN_ReleasePtr( wndPtr );
1375
1376     if (unicode)
1377         ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1378     else
1379         ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
1380
1381     if (!ret) return FALSE;
1382
1383     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1384
1385     /* Send the size messages */
1386
1387     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return FALSE;
1388     if (!(wndPtr->flags & WIN_NEED_SIZE))
1389     {
1390         RECT rect = wndPtr->rectClient;
1391         WIN_ReleasePtr( wndPtr );
1392         /* send it anyway */
1393         if (((rect.right-rect.left) <0) ||((rect.bottom-rect.top)<0))
1394             WARN("sending bogus WM_SIZE message 0x%08x\n",
1395                  MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1396         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1397                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1398         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1399     }
1400     else WIN_ReleasePtr( wndPtr );
1401
1402     /* Show the window, maximizing or minimizing if needed */
1403
1404     style = GetWindowLongW( hwnd, GWL_STYLE );
1405     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1406     {
1407         extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/
1408
1409         RECT newPos;
1410         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1411         WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1412         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1413
1414         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1415         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1416
1417         SetWindowPos( hwnd, 0, newPos.left, newPos.top,
1418                       newPos.right, newPos.bottom, swFlag );
1419     }
1420
1421     /* Dock system tray windows. */
1422     /* Dock after the window is created so we don't have problems calling
1423      * SetWindowPos. */
1424     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TRAYWINDOW)
1425         systray_dock_window( display, data );
1426
1427     return TRUE;
1428
1429  failed:
1430     X11DRV_DestroyWindow( hwnd );
1431     return FALSE;
1432 }
1433
1434
1435 /***********************************************************************
1436  *              X11DRV_get_win_data
1437  *
1438  * Return the X11 data structure associated with a window.
1439  */
1440 struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd )
1441 {
1442     char *data;
1443
1444     if (!hwnd || XFindContext( thread_display(), (XID)hwnd, win_data_context, &data )) data = NULL;
1445     return (struct x11drv_win_data *)data;
1446 }
1447
1448
1449 /***********************************************************************
1450  *              X11DRV_get_whole_window
1451  *
1452  * Return the X window associated with the full area of a window
1453  */
1454 Window X11DRV_get_whole_window( HWND hwnd )
1455 {
1456     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1457
1458     if (!data) return (Window)GetPropA( hwnd, whole_window_prop );
1459     return data->whole_window;
1460 }
1461
1462
1463 /***********************************************************************
1464  *              X11DRV_get_fbconfig_id
1465  *
1466  * Return the GLXFBConfig ID of the drawable used by the window for
1467  * OpenGL rendering. This is 0 for windows without a pixel format set.
1468  */
1469 XID X11DRV_get_fbconfig_id( HWND hwnd )
1470 {
1471     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1472
1473     if (!data) return (XID)GetPropA( hwnd, fbconfig_id_prop );
1474     return data->fbconfig_id;
1475 }
1476
1477 /***********************************************************************
1478  *              X11DRV_get_gl_drawable
1479  *
1480  * Return the GL drawable for this window.
1481  */
1482 Drawable X11DRV_get_gl_drawable( HWND hwnd )
1483 {
1484     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1485
1486     if (!data) return (Drawable)GetPropA( hwnd, gl_drawable_prop );
1487     return data->gl_drawable;
1488 }
1489
1490 /***********************************************************************
1491  *              X11DRV_get_gl_pixmap
1492  *
1493  * Return the Pixmap associated with the GL drawable (if any) for this window.
1494  */
1495 Pixmap X11DRV_get_gl_pixmap( HWND hwnd )
1496 {
1497     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1498
1499     if (!data) return (Pixmap)GetPropA( hwnd, pixmap_prop );
1500     return data->pixmap;
1501 }
1502
1503
1504 /***********************************************************************
1505  *              X11DRV_get_ic
1506  *
1507  * Return the X input context associated with a window
1508  */
1509 XIC X11DRV_get_ic( HWND hwnd )
1510 {
1511     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1512
1513     if (!data) return 0;
1514     return data->xic;
1515 }
1516
1517
1518 /*****************************************************************
1519  *              SetParent   (X11DRV.@)
1520  */
1521 void X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent )
1522 {
1523     Display *display = thread_display();
1524     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
1525
1526     if (!data) return;
1527     if (parent == old_parent) return;
1528
1529     if (parent != GetDesktopWindow()) /* a child window */
1530     {
1531         if (old_parent == GetDesktopWindow())
1532         {
1533             /* destroy the old X windows */
1534             destroy_whole_window( display, data );
1535             destroy_icon_window( display, data );
1536             if (data->managed)
1537             {
1538                 data->managed = FALSE;
1539                 RemovePropA( data->hwnd, managed_prop );
1540             }
1541         }
1542     }
1543     else  /* new top level window */
1544     {
1545         /* FIXME: we ignore errors since we can't really recover anyway */
1546         create_whole_window( display, data, GetWindowLongW( hwnd, GWL_STYLE ) );
1547     }
1548 }
1549
1550
1551 /*****************************************************************
1552  *              SetFocus   (X11DRV.@)
1553  *
1554  * Set the X focus.
1555  * Explicit colormap management seems to work only with OLVWM.
1556  */
1557 void X11DRV_SetFocus( HWND hwnd )
1558 {
1559     Display *display = thread_display();
1560     struct x11drv_win_data *data;
1561     XWindowAttributes win_attr;
1562
1563     /* Only mess with the X focus if there's */
1564     /* no desktop window and if the window is not managed by the WM. */
1565     if (root_window != DefaultRootWindow(display)) return;
1566
1567     if (!hwnd)  /* If setting the focus to 0, uninstall the colormap */
1568     {
1569         wine_tsx11_lock();
1570         if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1571             XUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1572         wine_tsx11_unlock();
1573         return;
1574     }
1575
1576     hwnd = GetAncestor( hwnd, GA_ROOT );
1577
1578     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1579     if (data->managed || !data->whole_window) return;
1580
1581     /* Set X focus and install colormap */
1582     wine_tsx11_lock();
1583     if (XGetWindowAttributes( display, data->whole_window, &win_attr ) &&
1584         (win_attr.map_state == IsViewable))
1585     {
1586         /* If window is not viewable, don't change anything */
1587
1588         /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1589         /* FIXME: this is not entirely correct */
1590         XSetInputFocus( display, data->whole_window, RevertToParent,
1591                         /* CurrentTime */
1592                         GetMessageTime() - EVENT_x11_time_to_win32_time(0));
1593         if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1594             XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1595     }
1596     wine_tsx11_unlock();
1597 }
1598
1599
1600 /**********************************************************************
1601  *              SetWindowIcon (X11DRV.@)
1602  *
1603  * hIcon or hIconSm has changed (or is being initialised for the
1604  * first time). Complete the X11 driver-specific initialisation
1605  * and set the window hints.
1606  *
1607  * This is not entirely correct, may need to create
1608  * an icon window and set the pixmap as a background
1609  */
1610 void X11DRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon )
1611 {
1612     Display *display = thread_display();
1613     struct x11drv_win_data *data;
1614
1615     if (type != ICON_BIG) return;  /* nothing to do here */
1616
1617     if (!(data = X11DRV_get_win_data( hwnd ))) return;
1618     if (!data->whole_window) return;
1619     if (!data->managed) return;
1620
1621     if (data->wm_hints)
1622     {
1623         set_icon_hints( display, data, icon );
1624         wine_tsx11_lock();
1625         XSetWMHints( display, data->whole_window, data->wm_hints );
1626         wine_tsx11_unlock();
1627     }
1628 }