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