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