Removed some unnecessary includes.
[wine] / dlls / x11drv / window.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5  * Copyright 1993 David Metcalfe
6  * Copyright 1995, 1996 Alex Korobka
7  */
8
9 #include "config.h"
10
11 #include <stdlib.h>
12
13 #include "ts_xlib.h"
14 #include "ts_xutil.h"
15
16 #include "winbase.h"
17 #include "wingdi.h"
18 #include "winreg.h"
19 #include "winuser.h"
20
21 #include "debugtools.h"
22 #include "x11drv.h"
23 #include "win.h"
24 #include "dce.h"
25 #include "options.h"
26
27 DEFAULT_DEBUG_CHANNEL(x11drv);
28
29 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
30
31 #define HAS_DLGFRAME(style,exStyle) \
32     (((exStyle) & WS_EX_DLGMODALFRAME) || \
33      (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
34
35 /* X context to associate a hwnd to an X window */
36 XContext winContext = 0;
37
38 Atom wmProtocols = None;
39 Atom wmDeleteWindow = None;
40 Atom wmTakeFocus = None;
41 Atom dndProtocol = None;
42 Atom dndSelection = None;
43 Atom wmChangeState = None;
44 Atom kwmDockWindow = None;
45 Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
46
47
48 /***********************************************************************
49  *              is_window_managed
50  *
51  * Check if a given window should be managed
52  */
53 inline static BOOL is_window_managed( WND *win )
54 {
55     if (!Options.managed) return FALSE;
56
57     /* tray window is always managed */
58     if (win->dwExStyle & WS_EX_TRAYWINDOW) return TRUE;
59     /* child windows are not managed */
60     if (win->dwStyle & WS_CHILD) return FALSE;
61     /* tool windows are not managed */
62     if (win->dwExStyle & WS_EX_TOOLWINDOW) return FALSE;
63     /* windows with caption or thick frame are managed */
64     if ((win->dwStyle & WS_CAPTION) == WS_CAPTION) return TRUE;
65     if (win->dwStyle & WS_THICKFRAME) return TRUE;
66     /* default: not managed */
67     return FALSE;
68 }
69
70
71 /***********************************************************************
72  *              is_window_top_level
73  *
74  * Check if a given window is a top level X11 window
75  */
76 inline static BOOL is_window_top_level( WND *win )
77 {
78     return (root_window == DefaultRootWindow(gdi_display) &&
79             win->parent->hwndSelf == GetDesktopWindow());
80 }
81
82
83 /***********************************************************************
84  *              is_client_window_mapped
85  *
86  * Check if the X client window should be mapped
87  */
88 inline static BOOL is_client_window_mapped( WND *win )
89 {
90     struct x11drv_win_data *data = win->pDriverData;
91     return !(win->dwStyle & WS_MINIMIZE) && !IsRectEmpty( &data->client_rect );
92 }
93
94
95 /***********************************************************************
96  *              get_window_attributes
97  *
98  * Fill the window attributes structure for an X window.
99  * Returned cursor must be freed by caller.
100  */
101 static int get_window_attributes( Display *display, WND *win, XSetWindowAttributes *attr )
102 {
103     BOOL is_top_level = is_window_top_level( win );
104     BOOL managed = is_top_level && is_window_managed( win );
105
106     if (managed) win->dwExStyle |= WS_EX_MANAGED;
107     else win->dwExStyle &= ~WS_EX_MANAGED;
108
109     attr->override_redirect = !managed;
110     attr->colormap          = X11DRV_PALETTE_PaletteXColormap;
111     attr->save_under        = ((win->clsStyle & CS_SAVEBITS) != 0);
112     attr->cursor            = None;
113     attr->event_mask        = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
114                                ButtonPressMask | ButtonReleaseMask);
115     if (is_window_top_level( win ))
116     {
117         attr->event_mask |= StructureNotifyMask | FocusChangeMask;
118         attr->cursor = X11DRV_GetCursor( display, GlobalLock16(GetCursor()) );
119     }
120     return (CWOverrideRedirect | CWSaveUnder | CWEventMask | CWColormap | CWCursor);
121 }
122
123
124 /***********************************************************************
125  *              sync_window_style
126  *
127  * Change the X window attributes when the window style has changed.
128  */
129 static void sync_window_style( Display *display, WND *win )
130 {
131     XSetWindowAttributes attr;
132     int mask;
133
134     wine_tsx11_lock();
135     mask = get_window_attributes( display, win, &attr );
136     XChangeWindowAttributes( display, get_whole_window(win), mask, &attr );
137     if (attr.cursor) XFreeCursor( display, attr.cursor );
138     wine_tsx11_unlock();
139 }
140
141
142 /***********************************************************************
143  *              get_window_changes
144  *
145  * fill the window changes structure
146  */
147 static int get_window_changes( XWindowChanges *changes, const RECT *old, const RECT *new )
148 {
149     int mask = 0;
150
151     if (old->right - old->left != new->right - new->left )
152     {
153         if (!(changes->width = new->right - new->left)) changes->width = 1;
154         mask |= CWWidth;
155     }
156     if (old->bottom - old->top != new->bottom - new->top)
157     {
158         if (!(changes->height = new->bottom - new->top)) changes->height = 1;
159         mask |= CWHeight;
160     }
161     if (old->left != new->left)
162     {
163         changes->x = new->left;
164         mask |= CWX;
165     }
166     if (old->top != new->top)
167     {
168         changes->y = new->top;
169         mask |= CWY;
170     }
171     return mask;
172 }
173
174
175 /***********************************************************************
176  *              create_icon_window
177  */
178 static Window create_icon_window( Display *display, WND *win )
179 {
180     struct x11drv_win_data *data = win->pDriverData;
181     XSetWindowAttributes attr;
182
183     attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
184                        ButtonPressMask | ButtonReleaseMask);
185     attr.bit_gravity = NorthWestGravity;
186     attr.backing_store = NotUseful/*WhenMapped*/;
187     attr.colormap      = X11DRV_PALETTE_PaletteXColormap; /* Needed due to our visual */
188
189     wine_tsx11_lock();
190     data->icon_window = XCreateWindow( display, root_window, 0, 0,
191                                        GetSystemMetrics( SM_CXICON ),
192                                        GetSystemMetrics( SM_CYICON ),
193                                        0, screen_depth,
194                                        InputOutput, visual,
195                                        CWEventMask | CWBitGravity | CWBackingStore | CWColormap, &attr );
196     XSaveContext( display, data->icon_window, winContext, (char *)win->hwndSelf );
197     wine_tsx11_unlock();
198
199     TRACE( "created %lx\n", data->icon_window );
200     SetPropA( win->hwndSelf, "__wine_x11_icon_window", (HANDLE)data->icon_window );
201     return data->icon_window;
202 }
203
204
205
206 /***********************************************************************
207  *              destroy_icon_window
208  */
209 inline static void destroy_icon_window( Display *display, WND *win )
210 {
211     struct x11drv_win_data *data = win->pDriverData;
212
213     if (!data->icon_window) return;
214     wine_tsx11_lock();
215     XDeleteContext( display, data->icon_window, winContext );
216     XDestroyWindow( display, data->icon_window );
217     data->icon_window = 0;
218     wine_tsx11_unlock();
219     RemovePropA( win->hwndSelf, "__wine_x11_icon_window" );
220 }
221
222
223 /***********************************************************************
224  *              set_icon_hints
225  *
226  * Set the icon wm hints
227  */
228 static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints )
229 {
230     X11DRV_WND_DATA *data = wndPtr->pDriverData;
231     HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON );
232
233     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
234     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
235     data->hWMIconBitmap = 0;
236     data->hWMIconMask = 0;
237
238     if (!(wndPtr->dwExStyle & WS_EX_MANAGED))
239     {
240         destroy_icon_window( display, wndPtr );
241         hints->flags &= ~(IconPixmapHint | IconMaskHint | IconWindowHint);
242     }
243     else if (!hIcon)
244     {
245         if (!data->icon_window) create_icon_window( display, wndPtr );
246         hints->icon_window = data->icon_window;
247         hints->flags = (hints->flags & ~(IconPixmapHint | IconMaskHint)) | IconWindowHint;
248     }
249     else
250     {
251         HBITMAP hbmOrig;
252         RECT rcMask;
253         BITMAP bmMask;
254         ICONINFO ii;
255         HDC hDC;
256
257         GetIconInfo(hIcon, &ii);
258
259         X11DRV_CreateBitmap(ii.hbmMask);
260         X11DRV_CreateBitmap(ii.hbmColor);
261
262         GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
263         rcMask.top    = 0;
264         rcMask.left   = 0;
265         rcMask.right  = bmMask.bmWidth;
266         rcMask.bottom = bmMask.bmHeight;
267
268         hDC = CreateCompatibleDC(0);
269         hbmOrig = SelectObject(hDC, ii.hbmMask);
270         InvertRect(hDC, &rcMask);
271         SelectObject(hDC, hbmOrig);
272         DeleteDC(hDC);
273
274         data->hWMIconBitmap = ii.hbmColor;
275         data->hWMIconMask = ii.hbmMask;
276
277         hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap);
278         hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask);
279         destroy_icon_window( display, wndPtr );
280         hints->flags = (hints->flags & ~IconWindowHint) | IconPixmapHint | IconMaskHint;
281     }
282 }
283
284
285 /***********************************************************************
286  *              set_size_hints
287  *
288  * set the window size hints
289  */
290 static void set_size_hints( Display *display, WND *win )
291 {
292     XSizeHints* size_hints;
293     struct x11drv_win_data *data = win->pDriverData;
294
295     if ((size_hints = XAllocSizeHints()))
296     {
297         size_hints->win_gravity = StaticGravity;
298         size_hints->x = data->whole_rect.left;
299         size_hints->y = data->whole_rect.top;
300         size_hints->flags = PWinGravity | PPosition;
301
302         if (HAS_DLGFRAME( win->dwStyle, win->dwExStyle ))
303         {
304             size_hints->max_width = data->whole_rect.right - data->whole_rect.left;
305             size_hints->max_height = data->whole_rect.bottom - data->whole_rect.top;
306             size_hints->min_width = size_hints->max_width;
307             size_hints->min_height = size_hints->max_height;
308             size_hints->flags |= PMinSize | PMaxSize;
309         }
310         XSetWMNormalHints( display, data->whole_window, size_hints );
311         XFree( size_hints );
312     }
313 }
314
315
316 /***********************************************************************
317  *              set_wm_hints
318  *
319  * Set the window manager hints for a newly-created window
320  */
321 static void set_wm_hints( Display *display, WND *win )
322 {
323     struct x11drv_win_data *data = win->pDriverData;
324     Window group_leader;
325     XClassHint *class_hints;
326     XWMHints* wm_hints;
327     Atom protocols[2];
328     int i;
329
330     wine_tsx11_lock();
331
332     /* wm protocols */
333     i = 0;
334     protocols[i++] = wmDeleteWindow;
335     if (wmTakeFocus) protocols[i++] = wmTakeFocus;
336     XSetWMProtocols( display, data->whole_window, protocols, i );
337
338     /* class hints */
339     if ((class_hints = XAllocClassHint()))
340     {
341         class_hints->res_name = "wine";
342         class_hints->res_class = "Wine";
343         XSetClassHint( display, data->whole_window, class_hints );
344         XFree( class_hints );
345     }
346
347     /* transient for hint */
348     if (win->owner)
349     {
350         struct x11drv_win_data *owner_data = win->owner->pDriverData;
351         XSetTransientForHint( display, data->whole_window, owner_data->whole_window );
352         group_leader = owner_data->whole_window;
353     }
354     else group_leader = data->whole_window;
355
356     /* size hints */
357     set_size_hints( display, win );
358
359     /* systray properties (KDE only for now) */
360     if (win->dwExStyle & WS_EX_TRAYWINDOW)
361     {
362         int val = 1;
363         if (kwmDockWindow != None)
364             TSXChangeProperty( display, data->whole_window, kwmDockWindow, kwmDockWindow,
365                                32, PropModeReplace, (char*)&val, 1 );
366         if (_kde_net_wm_system_tray_window_for != None)
367             TSXChangeProperty( display, data->whole_window, _kde_net_wm_system_tray_window_for,
368                                XA_WINDOW, 32, PropModeReplace, (char*)&data->whole_window, 1 );
369     }
370
371     wine_tsx11_unlock();
372
373     /* wm hints */
374     if ((wm_hints = TSXAllocWMHints()))
375     {
376         wm_hints->flags = InputHint | StateHint | WindowGroupHint;
377         /* use globally active model if take focus is supported,
378          * passive model otherwise (cf. ICCCM) */
379         wm_hints->input = !wmTakeFocus;
380
381         set_icon_hints( display, win, wm_hints );
382
383         wm_hints->initial_state = (win->dwStyle & WS_MINIMIZE) ? IconicState : NormalState;
384         wm_hints->window_group = group_leader;
385
386         wine_tsx11_lock();
387         XSetWMHints( display, data->whole_window, wm_hints );
388         XFree(wm_hints);
389         wine_tsx11_unlock();
390     }
391 }
392
393
394 /***********************************************************************
395  *              X11DRV_set_iconic_state
396  *
397  * Set the X11 iconic state according to the window style.
398  */
399 void X11DRV_set_iconic_state( WND *win )
400 {
401     Display *display = thread_display();
402     struct x11drv_win_data *data = win->pDriverData;
403     XWMHints* wm_hints;
404     BOOL iconic = IsIconic( win->hwndSelf );
405
406     wine_tsx11_lock();
407
408     if (iconic) XUnmapWindow( display, data->client_window );
409     else if (is_client_window_mapped( win )) XMapWindow( display, data->client_window );
410
411     if (!(wm_hints = XGetWMHints( display, data->whole_window ))) wm_hints = XAllocWMHints();
412     wm_hints->flags |= StateHint | IconPositionHint;
413     wm_hints->initial_state = iconic ? IconicState : NormalState;
414     wm_hints->icon_x = win->rectWindow.left;
415     wm_hints->icon_y = win->rectWindow.top;
416     XSetWMHints( display, data->whole_window, wm_hints );
417
418     if (win->dwStyle & WS_VISIBLE)
419     {
420         if (iconic)
421             XIconifyWindow( display, data->whole_window, DefaultScreen(display) );
422         else
423             if (!IsRectEmpty( &win->rectWindow )) XMapWindow( display, data->whole_window );
424     }
425
426     XFree(wm_hints);
427     wine_tsx11_unlock();
428 }
429
430
431 /***********************************************************************
432  *              X11DRV_window_to_X_rect
433  *
434  * Convert a rect from client to X window coordinates
435  */
436 void X11DRV_window_to_X_rect( WND *win, RECT *rect )
437 {
438     RECT rc;
439
440     if (!(win->dwExStyle & WS_EX_MANAGED)) return;
441     if (IsRectEmpty( rect )) return;
442
443     rc.top = rc.bottom = rc.left = rc.right = 0;
444
445     AdjustWindowRectEx( &rc, win->dwStyle & ~(WS_HSCROLL|WS_VSCROLL), FALSE, win->dwExStyle );
446
447     rect->left   -= rc.left;
448     rect->right  -= rc.right;
449     rect->top    -= rc.top;
450     rect->bottom -= rc.bottom;
451     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
452     if (rect->left >= rect->right) rect->right = rect->left + 1;
453 }
454
455
456 /***********************************************************************
457  *              X11DRV_X_to_window_rect
458  *
459  * Opposite of X11DRV_window_to_X_rect
460  */
461 void X11DRV_X_to_window_rect( WND *win, RECT *rect )
462 {
463     if (!(win->dwExStyle & WS_EX_MANAGED)) return;
464     if (IsRectEmpty( rect )) return;
465
466     AdjustWindowRectEx( rect, win->dwStyle & ~(WS_HSCROLL|WS_VSCROLL), FALSE, win->dwExStyle );
467
468     if (rect->top >= rect->bottom) rect->bottom = rect->top + 1;
469     if (rect->left >= rect->right) rect->right = rect->left + 1;
470 }
471
472
473 /***********************************************************************
474  *              X11DRV_sync_whole_window_position
475  *
476  * Synchronize the X whole window position with the Windows one
477  */
478 int X11DRV_sync_whole_window_position( Display *display, WND *win, int zorder )
479 {
480     XWindowChanges changes;
481     int mask;
482     struct x11drv_win_data *data = win->pDriverData;
483     RECT whole_rect = win->rectWindow;
484
485     X11DRV_window_to_X_rect( win, &whole_rect );
486     mask = get_window_changes( &changes, &data->whole_rect, &whole_rect );
487
488     if (zorder)
489     {
490         /* find window that this one must be after */
491         WND *prev = win->parent->child;
492         if (prev == win)  /* top child */
493         {
494             changes.stack_mode = Above;
495             mask |= CWStackMode;
496         }
497         else
498         {
499             while (prev && prev->next != win) prev = prev->next;
500             if (prev)
501             {
502                 changes.stack_mode = Below;
503                 changes.sibling = get_whole_window(prev);
504                 mask |= CWStackMode | CWSibling;
505             }
506             else ERR( "previous window not found for %x, list corrupted?\n", win->hwndSelf );
507         }
508     }
509
510     data->whole_rect = whole_rect;
511
512     if (mask)
513     {
514         TRACE( "setting win %lx pos %d,%d,%dx%d after %lx changes=%x\n",
515                data->whole_window, whole_rect.left, whole_rect.top,
516                whole_rect.right - whole_rect.left, whole_rect.bottom - whole_rect.top,
517                changes.sibling, mask );
518         wine_tsx11_lock();
519         XSync( gdi_display, False );  /* flush graphics operations before moving the window */
520         if (is_window_top_level( win ))
521         {
522             if (mask & (CWWidth|CWHeight)) set_size_hints( display, win );
523             XReconfigureWMWindow( display, data->whole_window,
524                                   DefaultScreen(display), mask, &changes );
525         }
526         else XConfigureWindow( display, data->whole_window, mask, &changes );
527         wine_tsx11_unlock();
528     }
529     return mask;
530 }
531
532
533 /***********************************************************************
534  *              X11DRV_sync_client_window_position
535  *
536  * Synchronize the X client window position with the Windows one
537  */
538 int X11DRV_sync_client_window_position( Display *display, WND *win )
539 {
540     XWindowChanges changes;
541     int mask;
542     struct x11drv_win_data *data = win->pDriverData;
543     RECT client_rect = win->rectClient;
544
545     OffsetRect( &client_rect, -data->whole_rect.left, -data->whole_rect.top );
546
547     if ((mask = get_window_changes( &changes, &data->client_rect, &client_rect )))
548     {
549         BOOL was_mapped = is_client_window_mapped( win );
550
551         TRACE( "setting win %lx pos %d,%d,%dx%d (was %d,%d,%dx%d) after %lx changes=%x\n",
552                data->client_window, client_rect.left, client_rect.top,
553                client_rect.right - client_rect.left, client_rect.bottom - client_rect.top,
554                data->client_rect.left, data->client_rect.top,
555                data->client_rect.right - data->client_rect.left,
556                data->client_rect.bottom - data->client_rect.top,
557                changes.sibling, mask );
558         data->client_rect = client_rect;
559         wine_tsx11_lock();
560         XSync( gdi_display, False );  /* flush graphics operations before moving the window */
561         if (was_mapped && !is_client_window_mapped( win ))
562             XUnmapWindow( display, data->client_window );
563         XConfigureWindow( display, data->client_window, mask, &changes );
564         if (!was_mapped && is_client_window_mapped( win ))
565             XMapWindow( display, data->client_window );
566         wine_tsx11_unlock();
567     }
568     return mask;
569 }
570
571
572 /***********************************************************************
573  *              X11DRV_register_window
574  *
575  * Associate an X window to a HWND.
576  */
577 void X11DRV_register_window( Display *display, HWND hwnd, struct x11drv_win_data *data )
578 {
579     wine_tsx11_lock();
580     XSaveContext( display, data->whole_window, winContext, (char *)hwnd );
581     XSaveContext( display, data->client_window, winContext, (char *)hwnd );
582     wine_tsx11_unlock();
583 }
584
585
586 /**********************************************************************
587  *              create_desktop
588  */
589 static void create_desktop( Display *display, WND *wndPtr )
590 {
591     X11DRV_WND_DATA *data = wndPtr->pDriverData;
592
593     wine_tsx11_lock();
594     winContext     = XUniqueContext();
595     wmProtocols    = XInternAtom( display, "WM_PROTOCOLS", False );
596     wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", False );
597 /*    wmTakeFocus    = XInternAtom( display, "WM_TAKE_FOCUS", False );*/
598     wmTakeFocus = 0;  /* not yet */
599     dndProtocol = XInternAtom( display, "DndProtocol" , False );
600     dndSelection = XInternAtom( display, "DndSelection" , False );
601     wmChangeState = XInternAtom (display, "WM_CHANGE_STATE", False);
602     kwmDockWindow = XInternAtom( display, "KWM_DOCKWINDOW", False );
603     _kde_net_wm_system_tray_window_for = XInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
604     wine_tsx11_unlock();
605
606     data->whole_window = data->client_window = root_window;
607
608     SetPropA( wndPtr->hwndSelf, "__wine_x11_whole_window", (HANDLE)root_window );
609     SetPropA( wndPtr->hwndSelf, "__wine_x11_client_window", (HANDLE)root_window );
610     SetPropA( wndPtr->hwndSelf, "__wine_x11_visual_id", (HANDLE)XVisualIDFromVisual(visual) );
611
612     if (root_window != DefaultRootWindow(display)) X11DRV_create_desktop_thread();
613 }
614
615
616 /**********************************************************************
617  *              create_whole_window
618  *
619  * Create the whole X window for a given window
620  */
621 static Window create_whole_window( Display *display, WND *win )
622 {
623     struct x11drv_win_data *data = win->pDriverData;
624     int cx, cy, mask;
625     XSetWindowAttributes attr;
626     Window parent;
627     RECT rect;
628     BOOL is_top_level = is_window_top_level( win );
629
630     rect = win->rectWindow;
631     X11DRV_window_to_X_rect( win, &rect );
632
633     if (!(cx = rect.right - rect.left)) cx = 1;
634     if (!(cy = rect.bottom - rect.top)) cy = 1;
635
636     parent = get_client_window( win->parent );
637
638     wine_tsx11_lock();
639
640     mask = get_window_attributes( display, win, &attr );
641
642     /* set the attributes that don't change over the lifetime of the window */
643     attr.bit_gravity       = ForgetGravity;
644     attr.win_gravity       = NorthWestGravity;
645     attr.backing_store     = NotUseful/*WhenMapped*/;
646     mask |= CWBitGravity | CWWinGravity | CWBackingStore;
647
648     data->whole_rect = rect;
649     data->whole_window = XCreateWindow( display, parent, rect.left, rect.top, cx, cy,
650                                         0, screen_depth, InputOutput, visual,
651                                         mask, &attr );
652     if (attr.cursor) XFreeCursor( display, attr.cursor );
653
654     if (!data->whole_window)
655     {
656         wine_tsx11_unlock();
657         return 0;
658     }
659
660     /* non-maximized child must be at bottom of Z order */
661     if ((win->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
662     {
663         XWindowChanges changes;
664         changes.stack_mode = Below;
665         XConfigureWindow( display, data->whole_window, CWStackMode, &changes );
666     }
667
668     wine_tsx11_unlock();
669
670     if (is_top_level) set_wm_hints( display, win );
671
672     return data->whole_window;
673 }
674
675
676 /**********************************************************************
677  *              create_client_window
678  *
679  * Create the client window for a given window
680  */
681 static Window create_client_window( Display *display, WND *win )
682 {
683     struct x11drv_win_data *data = win->pDriverData;
684     RECT rect = data->whole_rect;
685     XSetWindowAttributes attr;
686
687     OffsetRect( &rect, -data->whole_rect.left, -data->whole_rect.top );
688     data->client_rect = rect;
689
690     attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
691                        ButtonPressMask | ButtonReleaseMask);
692     attr.bit_gravity = (win->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ?
693                        ForgetGravity : NorthWestGravity;
694     attr.backing_store = NotUseful/*WhenMapped*/;
695
696     wine_tsx11_lock();
697     data->client_window = XCreateWindow( display, data->whole_window, 0, 0,
698                                          max( rect.right - rect.left, 1 ),
699                                          max( rect.bottom - rect.top, 1 ),
700                                          0, screen_depth,
701                                          InputOutput, visual,
702                                          CWEventMask | CWBitGravity | CWBackingStore, &attr );
703     if (data->client_window && is_client_window_mapped( win ))
704         XMapWindow( display, data->client_window );
705     wine_tsx11_unlock();
706     return data->client_window;
707 }
708
709
710 /*****************************************************************
711  *              SetWindowText   (X11DRV.@)
712  */
713 BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
714 {
715     Display *display = thread_display();
716     UINT count;
717     char *buffer;
718     static UINT text_cp = (UINT)-1;
719     Window win;
720     WND *wndPtr = WIN_FindWndPtr( hwnd );
721
722     if (!wndPtr) return FALSE;
723     if ((win = get_whole_window(wndPtr)))
724     {
725         if (text_cp == (UINT)-1)
726         {
727             HKEY hkey;
728             /* default value */
729             text_cp = CP_ACP;
730             if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
731             {
732                 char buffer[20];
733                 DWORD type, count = sizeof(buffer);
734                 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buffer, &count))
735                     text_cp = atoi(buffer);
736                 RegCloseKey(hkey);
737             }
738             TRACE("text_cp = %u\n", text_cp);
739         }
740
741         /* allocate new buffer for window text */
742         count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
743         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
744         {
745             ERR("Not enough memory for window text\n");
746             WIN_ReleaseWndPtr( wndPtr );
747             return FALSE;
748         }
749         WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
750
751         wine_tsx11_lock();
752         XStoreName( display, win, buffer );
753         XSetIconName( display, win, buffer );
754         wine_tsx11_unlock();
755
756         HeapFree( GetProcessHeap(), 0, buffer );
757     }
758     WIN_ReleaseWndPtr( wndPtr );
759     return TRUE;
760 }
761
762
763 /***********************************************************************
764  *              DestroyWindow   (X11DRV.@)
765  */
766 BOOL X11DRV_DestroyWindow( HWND hwnd )
767 {
768     Display *display = thread_display();
769     WND *wndPtr = WIN_FindWndPtr( hwnd );
770     X11DRV_WND_DATA *data = wndPtr->pDriverData;
771
772     if (!data) goto done;
773
774     if (data->whole_window)
775     {
776         TRACE( "win %x xwin %lx/%lx\n", hwnd, data->whole_window, data->client_window );
777         wine_tsx11_lock();
778         XSync( gdi_display, False );  /* flush any reference to this drawable in GDI queue */
779         XDeleteContext( display, data->whole_window, winContext );
780         XDeleteContext( display, data->client_window, winContext );
781         XDestroyWindow( display, data->whole_window );  /* this destroys client too */
782         destroy_icon_window( display, wndPtr );
783         wine_tsx11_unlock();
784     }
785
786     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
787     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
788     HeapFree( GetProcessHeap(), 0, data );
789     wndPtr->pDriverData = NULL;
790  done:
791     WIN_ReleaseWndPtr( wndPtr );
792     return TRUE;
793 }
794
795
796 /**********************************************************************
797  *              CreateWindow   (X11DRV.@)
798  */
799 BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
800 {
801     Display *display = thread_display();
802     WND *wndPtr;
803     struct x11drv_win_data *data;
804     RECT rect;
805     BOOL ret = FALSE;
806
807     if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data)))) return FALSE;
808     data->whole_window  = 0;
809     data->client_window = 0;
810     data->icon_window   = 0;
811     data->hWMIconBitmap = 0;
812     data->hWMIconMask   = 0;
813
814     wndPtr = WIN_FindWndPtr( hwnd );
815     wndPtr->pDriverData = data;
816
817     if (!wndPtr->parent)
818     {
819         SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
820         create_desktop( display, wndPtr );
821         WIN_ReleaseWndPtr( wndPtr );
822         return TRUE;
823     }
824
825     if (!create_whole_window( display, wndPtr )) goto failed;
826     if (!create_client_window( display, wndPtr )) goto failed;
827     TSXSync( display, False );
828
829     WIN_ReleaseWndPtr( wndPtr );
830
831     SetPropA( hwnd, "__wine_x11_whole_window", (HANDLE)data->whole_window );
832     SetPropA( hwnd, "__wine_x11_client_window", (HANDLE)data->client_window );
833
834     /* send WM_NCCREATE */
835     TRACE( "hwnd %x cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cs->cx, cs->cy );
836     if (unicode)
837         ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
838     else
839         ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
840     if (!ret)
841     {
842         X11DRV_DestroyWindow( hwnd );
843         return FALSE;
844     }
845
846     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
847
848     sync_window_style( display, wndPtr );
849
850     /* send WM_NCCALCSIZE */
851     rect = wndPtr->rectWindow;
852     SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect );
853     if (rect.left > rect.right || rect.top > rect.bottom) rect = wndPtr->rectWindow;
854     wndPtr->rectClient = rect;
855     X11DRV_sync_client_window_position( display, wndPtr );
856     X11DRV_register_window( display, hwnd, data );
857
858     TRACE( "win %x window %d,%d,%d,%d client %d,%d,%d,%d whole %d,%d,%d,%d X client %d,%d,%d,%d xwin %x/%x\n",
859            hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,
860            wndPtr->rectWindow.right, wndPtr->rectWindow.bottom,
861            wndPtr->rectClient.left, wndPtr->rectClient.top,
862            wndPtr->rectClient.right, wndPtr->rectClient.bottom,
863            data->whole_rect.left, data->whole_rect.top,
864            data->whole_rect.right, data->whole_rect.bottom,
865            data->client_rect.left, data->client_rect.top,
866            data->client_rect.right, data->client_rect.bottom,
867            (unsigned int)data->whole_window, (unsigned int)data->client_window );
868
869     if ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
870         WIN_LinkWindow( hwnd, HWND_BOTTOM );
871     else
872         WIN_LinkWindow( hwnd, HWND_TOP );
873
874     WIN_ReleaseWndPtr( wndPtr );
875
876     if (unicode)
877         ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
878     else
879         ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
880
881     if (!ret)
882     {
883         WIN_UnlinkWindow( hwnd );
884         X11DRV_DestroyWindow( hwnd );
885         return FALSE;
886     }
887
888     /* Send the size messages */
889
890     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
891     if (!(wndPtr->flags & WIN_NEED_SIZE))
892     {
893         /* send it anyway */
894         if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
895             ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
896             WARN("sending bogus WM_SIZE message 0x%08lx\n",
897                  MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
898                           wndPtr->rectClient.bottom-wndPtr->rectClient.top));
899         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
900                       MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
901                                wndPtr->rectClient.bottom-wndPtr->rectClient.top));
902         SendMessageW( hwnd, WM_MOVE, 0,
903                       MAKELONG( wndPtr->rectClient.left, wndPtr->rectClient.top ) );
904     }
905
906     /* Show the window, maximizing or minimizing if needed */
907
908     if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
909     {
910         extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/
911
912         RECT newPos;
913         UINT swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
914         wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
915         WINPOS_MinMaximize( hwnd, swFlag, &newPos );
916         swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow())
917             ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
918             : SWP_NOZORDER | SWP_FRAMECHANGED;
919         SetWindowPos( hwnd, 0, newPos.left, newPos.top,
920                       newPos.right, newPos.bottom, swFlag );
921     }
922
923     WIN_ReleaseWndPtr( wndPtr );
924     return TRUE;
925
926
927  failed:
928     X11DRV_DestroyWindow( wndPtr->hwndSelf );
929     WIN_ReleaseWndPtr( wndPtr );
930     return FALSE;
931 }
932
933
934 /***********************************************************************
935  *              X11DRV_get_client_window
936  *
937  * Return the X window associated with the client area of a window
938  */
939 Window X11DRV_get_client_window( HWND hwnd )
940 {
941     Window ret = 0;
942     WND *win = WIN_FindWndPtr( hwnd );
943     if (win)
944     {
945         struct x11drv_win_data *data = win->pDriverData;
946         ret = data->client_window;
947         WIN_ReleaseWndPtr( win );
948     }
949     return ret;
950 }
951
952
953 /***********************************************************************
954  *              X11DRV_get_whole_window
955  *
956  * Return the X window associated with the full area of a window
957  */
958 Window X11DRV_get_whole_window( HWND hwnd )
959 {
960     Window ret = 0;
961     WND *win = WIN_FindWndPtr( hwnd );
962     if (win)
963     {
964         struct x11drv_win_data *data = win->pDriverData;
965         ret = data->whole_window;
966         WIN_ReleaseWndPtr( win );
967     }
968     return ret;
969 }
970
971
972 /***********************************************************************
973  *              X11DRV_get_top_window
974  *
975  * Return the X window associated with the top-level parent of a window
976  */
977 Window X11DRV_get_top_window( HWND hwnd )
978 {
979     Window ret = 0;
980     WND *win = WIN_FindWndPtr( hwnd );
981     while (win && win->parent->hwndSelf != GetDesktopWindow())
982         WIN_UpdateWndPtr( &win, win->parent );
983     if (win)
984     {
985         struct x11drv_win_data *data = win->pDriverData;
986         ret = data->whole_window;
987         WIN_ReleaseWndPtr( win );
988     }
989     return ret;
990 }
991
992
993 /*****************************************************************
994  *              SetParent   (X11DRV.@)
995  */
996 HWND X11DRV_SetParent( HWND hwnd, HWND parent )
997 {
998     Display *display = thread_display();
999     WND *wndPtr;
1000     WND *pWndParent;
1001     DWORD dwStyle;
1002     HWND retvalue;
1003
1004     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
1005
1006     dwStyle = wndPtr->dwStyle;
1007
1008     if (!parent) parent = GetDesktopWindow();
1009
1010     if (!(pWndParent = WIN_FindWndPtr(parent)))
1011     {
1012         WIN_ReleaseWndPtr( wndPtr );
1013         return 0;
1014     }
1015
1016     /* Windows hides the window first, then shows it again
1017      * including the WM_SHOWWINDOW messages and all */
1018     if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
1019
1020     retvalue = wndPtr->parent->hwndSelf;  /* old parent */
1021     if (pWndParent != wndPtr->parent)
1022     {
1023         struct x11drv_win_data *data = wndPtr->pDriverData;
1024
1025         WIN_UnlinkWindow(wndPtr->hwndSelf);
1026         wndPtr->parent = pWndParent;
1027         WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
1028
1029         if (parent != GetDesktopWindow()) /* a child window */
1030         {
1031             if (!(wndPtr->dwStyle & WS_CHILD) && wndPtr->wIDmenu)
1032             {
1033                 DestroyMenu( (HMENU)wndPtr->wIDmenu );
1034                 wndPtr->wIDmenu = 0;
1035             }
1036         }
1037
1038         if (is_window_top_level( wndPtr )) set_wm_hints( display, wndPtr );
1039         wine_tsx11_lock();
1040         sync_window_style( display, wndPtr );
1041         XReparentWindow( display, data->whole_window, get_client_window(pWndParent),
1042                          data->whole_rect.left, data->whole_rect.top );
1043         wine_tsx11_unlock();
1044     }
1045     WIN_ReleaseWndPtr( pWndParent );
1046     WIN_ReleaseWndPtr( wndPtr );
1047
1048     /* SetParent additionally needs to make hwnd the topmost window
1049        in the x-order and send the expected WM_WINDOWPOSCHANGING and
1050        WM_WINDOWPOSCHANGED notification messages. 
1051     */
1052     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
1053                   SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
1054                   ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
1055     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1056      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
1057
1058     return retvalue;
1059 }
1060
1061
1062 /*******************************************************************
1063  *              EnableWindow   (X11DRV.@)
1064  */
1065 BOOL X11DRV_EnableWindow( HWND hwnd, BOOL enable )
1066 {
1067     Display *display = thread_display();
1068     XWMHints *wm_hints;
1069     WND *wndPtr;
1070     BOOL retvalue;
1071
1072     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1073
1074     retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1075
1076     if (enable && (wndPtr->dwStyle & WS_DISABLED))
1077     {
1078         /* Enable window */
1079         wndPtr->dwStyle &= ~WS_DISABLED;
1080
1081         if (wndPtr->dwExStyle & WS_EX_MANAGED)
1082         {
1083             wine_tsx11_lock();
1084             if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
1085                 wm_hints = XAllocWMHints();
1086             if (wm_hints)
1087             {
1088                 wm_hints->flags |= InputHint;
1089                 wm_hints->input = TRUE;
1090                 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
1091                 XFree(wm_hints);
1092             }
1093             wine_tsx11_unlock();
1094         }
1095
1096         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1097     }
1098     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1099     {
1100         SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0 );
1101
1102         /* Disable window */
1103         wndPtr->dwStyle |= WS_DISABLED;
1104
1105         if (wndPtr->dwExStyle & WS_EX_MANAGED)
1106         {
1107             wine_tsx11_lock();
1108             if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
1109                 wm_hints = XAllocWMHints();
1110             if (wm_hints)
1111             {
1112                 wm_hints->flags |= InputHint;
1113                 wm_hints->input = FALSE;
1114                 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
1115                 XFree(wm_hints);
1116             }
1117             wine_tsx11_unlock();
1118         }
1119
1120         if (hwnd == GetFocus())
1121             SetFocus( 0 );  /* A disabled window can't have the focus */
1122
1123         if (hwnd == GetCapture())
1124             ReleaseCapture();  /* A disabled window can't capture the mouse */
1125
1126         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1127     }
1128     WIN_ReleaseWndPtr(wndPtr);
1129     return retvalue;
1130 }
1131
1132
1133 /*****************************************************************
1134  *              SetFocus   (X11DRV.@)
1135  *
1136  * Set the X focus.
1137  * Explicit colormap management seems to work only with OLVWM.
1138  */
1139 void X11DRV_SetFocus( HWND hwnd )
1140 {
1141     Display *display = thread_display();
1142     XWindowAttributes win_attr;
1143     Window win;
1144     WND *wndPtr = WIN_FindWndPtr( hwnd );
1145     WND *w = wndPtr;
1146
1147     if (!wndPtr) return;
1148
1149     /* Only mess with the X focus if there's */
1150     /* no desktop window and if the window is not managed by the WM. */
1151     if (root_window != DefaultRootWindow(display)) goto done;
1152
1153     while (w && !get_whole_window(w)) w = w->parent;
1154     if (!w) goto done;
1155     if (w->dwExStyle & WS_EX_MANAGED) goto done;
1156
1157     if (!hwnd)  /* If setting the focus to 0, uninstall the colormap */
1158     {
1159         if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1160             TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1161     }
1162     else if ((win = get_whole_window(w)))
1163     {
1164         /* Set X focus and install colormap */
1165         wine_tsx11_lock();
1166         if (XGetWindowAttributes( display, win, &win_attr ) &&
1167             (win_attr.map_state == IsViewable))
1168         {
1169             /* If window is not viewable, don't change anything */
1170
1171             /* we must not use CurrentTime (ICCCM), so try to use last message time instead */
1172             /* FIXME: this is not entirely correct */
1173             XSetInputFocus( display, win, RevertToParent,
1174                             /*CurrentTime*/ GetMessageTime() + X11DRV_server_startticks );
1175             if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
1176                 XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
1177         }
1178         wine_tsx11_unlock();
1179     }
1180
1181  done:
1182     WIN_ReleaseWndPtr( wndPtr );
1183 }
1184
1185
1186 /**********************************************************************
1187  *              SetWindowIcon (X11DRV.@)
1188  *
1189  * hIcon or hIconSm has changed (or is being initialised for the
1190  * first time). Complete the X11 driver-specific initialisation
1191  * and set the window hints.
1192  *
1193  * This is not entirely correct, may need to create
1194  * an icon window and set the pixmap as a background
1195  */
1196 HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small )
1197 {
1198     Display *display = thread_display();
1199     WND *wndPtr = WIN_FindWndPtr( hwnd );
1200     int index = small ? GCL_HICONSM : GCL_HICON;
1201     HICON old;
1202
1203     if (!wndPtr) return 0;
1204
1205     old = GetClassLongW( hwnd, index );
1206     SetClassLongW( hwnd, index, icon );
1207
1208     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE |
1209                   SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1210
1211     if (wndPtr->dwExStyle & WS_EX_MANAGED)
1212     {
1213         Window win = get_whole_window(wndPtr);
1214         XWMHints* wm_hints = TSXGetWMHints( display, win );
1215
1216         if (!wm_hints) wm_hints = TSXAllocWMHints();
1217         if (wm_hints)
1218         {
1219             set_icon_hints( display, wndPtr, wm_hints );
1220             TSXSetWMHints( display, win, wm_hints );
1221             TSXFree( wm_hints );
1222         }
1223     }
1224
1225     WIN_ReleaseWndPtr( wndPtr );
1226     return old;
1227 }