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