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