Check if the window is managed before trying to give it focus.
[wine] / windows / x11drv / wnd.c
1 /*
2  * X11 windows driver
3  *
4  * Copyright 1993, 1994, 1995, 1996 Alexandre Julliard
5  *                             1993 David Metcalfe
6  *                       1995, 1996 Alex Korobka
7  */
8
9 #include "config.h"
10
11 #ifndef X_DISPLAY_MISSING
12
13 #include <X11/Xatom.h>
14 #include "ts_xlib.h"
15 #include "ts_xutil.h"
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include "bitmap.h"
20 #include "color.h"
21 #include "debugtools.h"
22 #include "display.h"
23 #include "dce.h"
24 #include "options.h"
25 #include "message.h"
26 #include "heap.h"
27 #include "win.h"
28 #include "windef.h"
29 #include "class.h"
30 #include "x11drv.h"
31 #include "wine/winuser16.h"
32
33 DEFAULT_DEBUG_CHANNEL(win)
34
35   /* Some useful macros */
36 #define HAS_DLGFRAME(style,exStyle) \
37 ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
38
39 /**********************************************************************/
40
41 extern Cursor X11DRV_MOUSE_XCursor;  /* Current X cursor */
42 extern BOOL   X11DRV_CreateBitmap( HBITMAP );
43 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
44
45 /**********************************************************************/
46
47 /* X context to associate a hwnd to an X window */
48 XContext winContext = 0;
49
50 Atom wmProtocols = None;
51 Atom wmDeleteWindow = None;
52 Atom dndProtocol = None;
53 Atom dndSelection = None;
54 Atom wmChangeState = None;
55
56 /***********************************************************************
57  *              X11DRV_WND_GetXWindow
58  *
59  * Return the X window associated to a window.
60  */
61 Window X11DRV_WND_GetXWindow(WND *wndPtr)
62 {
63     return wndPtr && wndPtr->pDriverData ? 
64       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
65 }
66
67 /***********************************************************************
68  *              X11DRV_WND_FindXWindow
69  *
70  * Return the the first X window associated to a window chain.
71  */
72 Window X11DRV_WND_FindXWindow(WND *wndPtr)
73 {
74     while (wndPtr && 
75            !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window) 
76       wndPtr = wndPtr->parent;
77     return wndPtr ?
78       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
79 }
80
81 /***********************************************************************
82  *              X11DRV_WND_GetXScreen
83  *
84  * Return the X screen associated to the window.
85  */
86 Screen *X11DRV_WND_GetXScreen(WND *wndPtr)
87 {
88   while(wndPtr->parent) wndPtr = wndPtr->parent;
89   return X11DRV_DESKTOP_GetXScreen((struct tagDESKTOP *) wndPtr->wExtra);
90 }
91
92 /***********************************************************************
93  *              X11DRV_WND_GetXRootWindow
94  *
95  * Return the X display associated to the window.
96  */
97 Window X11DRV_WND_GetXRootWindow(WND *wndPtr)
98 {
99   while(wndPtr->parent) wndPtr = wndPtr->parent;
100   return X11DRV_DESKTOP_GetXRootWindow((struct tagDESKTOP *) wndPtr->wExtra);
101 }
102
103 /***********************************************************************
104  *              X11DRV_WND_RegisterWindow
105  *
106  * Associate an X window to a HWND.
107  */
108 static void X11DRV_WND_RegisterWindow(WND *wndPtr)
109 {
110   TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
111   
112   if (!winContext) winContext = TSXUniqueContext();
113   TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr), 
114                   winContext, (char *) wndPtr->hwndSelf );
115 }
116
117 /**********************************************************************
118  *              X11DRV_WND_Initialize
119  */
120 void X11DRV_WND_Initialize(WND *wndPtr)
121 {
122   X11DRV_WND_DATA *pWndDriverData = 
123     (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
124
125   wndPtr->pDriverData = (void *) pWndDriverData;
126
127   pWndDriverData->window = 0;
128 }
129
130 /**********************************************************************
131  *              X11DRV_WND_Finalize
132  */
133 void X11DRV_WND_Finalize(WND *wndPtr)
134 {
135   X11DRV_WND_DATA *pWndDriverData =
136     (X11DRV_WND_DATA *) wndPtr->pDriverData;
137
138   if (!wndPtr->pDriverData) {
139      ERR("Trying to destroy window again. Not good.\n");
140      return;
141   }
142   if(pWndDriverData->window)
143     {
144       ERR(
145           "WND destroyed without destroying "
146           "the associated X Window (%ld)\n", 
147           pWndDriverData->window
148       );
149     }
150   HeapFree(SystemHeap, 0, wndPtr->pDriverData);
151   wndPtr->pDriverData = NULL;
152 }
153
154 /**********************************************************************
155  *              X11DRV_WND_CreateDesktopWindow
156  */
157 BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode)
158 {
159     if (wmProtocols == None)
160         wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
161     if (wmDeleteWindow == None)
162         wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
163     if( dndProtocol == None )
164         dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
165     if( dndSelection == None )
166         dndSelection = TSXInternAtom( display, "DndSelection" , False );
167     if( wmChangeState == None )
168         wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
169
170     ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = 
171       X11DRV_WND_GetXRootWindow( wndPtr );
172     X11DRV_WND_RegisterWindow( wndPtr );
173
174     return TRUE;
175 }
176
177
178 /**********************************************************************
179  *              X11DRV_WND_CreateWindow
180  */
181 BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode)
182 {
183   /* Create the X window (only for top-level windows, and then only */
184   /* when there's no desktop window) */
185   
186   if (!(cs->style & WS_CHILD) && 
187       (X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
188   {
189       Window    wGroupLeader;
190       XWMHints* wm_hints;
191       XSetWindowAttributes win_attr;
192       
193       /* Create "managed" windows only if a title bar or resizable */
194       /* frame is required. */
195         if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle))
196         {
197           win_attr.event_mask = ExposureMask | KeyPressMask |
198             KeyReleaseMask | PointerMotionMask |
199             ButtonPressMask | ButtonReleaseMask |
200             FocusChangeMask | StructureNotifyMask;
201           win_attr.override_redirect = FALSE;
202           wndPtr->flags |= WIN_MANAGED;
203         }
204       else
205         {
206           win_attr.event_mask = ExposureMask | KeyPressMask |
207             KeyReleaseMask | PointerMotionMask |
208             ButtonPressMask | ButtonReleaseMask |
209             FocusChangeMask;
210           win_attr.override_redirect = TRUE;
211         }
212       wndPtr->flags |= WIN_NATIVE;
213
214       win_attr.bit_gravity   = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest;
215       win_attr.colormap      = X11DRV_PALETTE_PaletteXColormap;
216       win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
217       win_attr.save_under    = ((classPtr->style & CS_SAVEBITS) != 0);
218       win_attr.cursor        = X11DRV_MOUSE_XCursor;
219
220       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
221       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
222       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = 
223         TSXCreateWindow( display, 
224                          X11DRV_WND_GetXRootWindow(wndPtr), 
225                          cs->x, cs->y, cs->cx, cs->cy, 
226                          0, CopyFromParent, 
227                          InputOutput, CopyFromParent,
228                          CWEventMask | CWOverrideRedirect |
229                          CWColormap | CWCursor | CWSaveUnder |
230                          CWBackingStore | CWBitGravity, 
231                          &win_attr );
232       
233       if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
234         return FALSE;
235
236       if (wndPtr->flags & WIN_MANAGED) 
237       {
238           XClassHint *class_hints = TSXAllocClassHint();
239           XSizeHints* size_hints = TSXAllocSizeHints();
240           
241           if (class_hints) 
242           {
243               class_hints->res_name = "wineManaged";
244               class_hints->res_class = "Wine";
245               TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
246               TSXFree (class_hints);
247           }
248
249           if (size_hints) 
250           {
251               size_hints->win_gravity = StaticGravity;
252               size_hints->flags = PWinGravity;
253
254               if (HAS_DLGFRAME(cs->style,cs->dwExStyle))
255               {
256                   size_hints->min_width = size_hints->max_width = cs->cx;
257                   size_hints->min_height = size_hints->max_height = cs->cy;
258                   size_hints->flags |= PMinSize | PMaxSize;
259               }
260
261               TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), 
262                                  size_hints, XA_WM_NORMAL_HINTS );
263               TSXFree(size_hints);
264           }
265       }
266       
267       if (cs->hwndParent)  /* Get window owner */
268       {
269           Window w;
270           WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
271
272           w = X11DRV_WND_FindXWindow( tmpWnd );
273           if (w != None)
274           {
275               TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
276               wGroupLeader = w;
277           }
278           WIN_ReleaseWndPtr(tmpWnd);
279       }
280
281       wm_hints = TSXAllocWMHints();
282       {
283           wm_hints->flags = InputHint | StateHint | WindowGroupHint;
284           wm_hints->input = True;
285
286           if( wndPtr->flags & WIN_MANAGED )
287           {
288               if( wndPtr->class->hIcon )
289               { 
290                   CURSORICONINFO *ptr;
291
292                   if( (ptr = (CURSORICONINFO *)GlobalLock16( wndPtr->class->hIcon )) )
293                   {
294                       /* This is not entirely correct, may need to create
295                        * an icon window and set the pixmap as a background */
296
297                       HBITMAP hBitmap = CreateBitmap( ptr->nWidth, ptr->nHeight, 
298                           ptr->bPlanes, ptr->bBitsPerPixel, (char *)(ptr + 1) +
299                           ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
300
301                       if( hBitmap )
302                       {
303                         ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = hBitmap;
304                           X11DRV_CreateBitmap( hBitmap );
305                           wm_hints->flags |= IconPixmapHint;
306                           wm_hints->icon_pixmap = X11DRV_BITMAP_Pixmap( hBitmap );
307                       }
308                    }
309               }
310               wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE) 
311                                         ? IconicState : NormalState;
312           }
313           else
314               wm_hints->initial_state = NormalState;
315           wm_hints->window_group = wGroupLeader;
316
317           TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
318           TSXFree(wm_hints);
319       }
320       X11DRV_WND_RegisterWindow( wndPtr );
321   }
322   return TRUE;
323 }
324
325 /***********************************************************************
326  *              X11DRV_WND_DestroyWindow
327  */
328 BOOL X11DRV_WND_DestroyWindow(WND *wndPtr)
329 {
330    Window w;
331    if ((w = X11DRV_WND_GetXWindow(wndPtr)))
332    {
333        XEvent xe;
334        TSXDeleteContext( display, w, winContext );
335        TSXDestroyWindow( display, w );
336        while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
337
338        ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
339        if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
340        {
341            DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
342            ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
343        }
344    }
345
346    return TRUE;
347 }
348
349 /*****************************************************************
350  *              X11DRV_WND_SetParent
351  */
352 WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
353 {
354     WND *pDesktop = WIN_GetDesktop();
355     
356     if( wndPtr && pWndParent && (wndPtr != pDesktop) )
357     {
358         WND* pWndPrev = wndPtr->parent;
359
360         if( pWndParent != pWndPrev )
361         {
362             if ( X11DRV_WND_GetXWindow(wndPtr) )
363             {
364                 /* Toplevel window needs to be reparented.  Used by Tk 8.0 */
365
366                 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
367                 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
368             }
369
370             WIN_UnlinkWindow(wndPtr->hwndSelf);
371             wndPtr->parent = pWndParent;
372
373             /* Create an X counterpart for reparented top-level windows
374              * when not in the desktop mode. */
375
376             if( pWndParent == pDesktop )
377             {
378                 wndPtr->dwStyle &= ~WS_CHILD;
379                 wndPtr->wIDmenu = 0;
380                 if( X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display) )
381                 {
382                     CREATESTRUCTA cs;
383                     cs.lpCreateParams = NULL;
384                     cs.hInstance = 0; /* not used if following call */
385                     cs.hMenu = 0; /* not used in following call */
386                     cs.hwndParent = pWndParent->hwndSelf;
387                     cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
388                     if (!cs.cy)
389                       cs.cy = 1;
390                     cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
391                     if (!cs.cx)
392                       cs.cx = 1;
393                     cs.y = wndPtr->rectWindow.top;
394                     cs.x = wndPtr->rectWindow.left;
395                     cs.style = wndPtr->dwStyle;
396                     cs.lpszName = 0; /* not used in following call */
397                     cs.lpszClass = 0; /*not used in following call */
398                     cs.dwExStyle = wndPtr->dwExStyle;
399                     X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
400                                             &cs, FALSE);
401                 }
402             }
403             else /* a child window */
404             {
405                 if( !( wndPtr->dwStyle & WS_CHILD ) )
406                 {
407                     wndPtr->dwStyle |= WS_CHILD;
408                     if( wndPtr->wIDmenu != 0)
409                     {
410                         DestroyMenu( (HMENU) wndPtr->wIDmenu );
411                         wndPtr->wIDmenu = 0;
412                     }
413                 }
414             }
415             WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
416         }
417         WIN_ReleaseDesktop();
418         return pWndPrev;
419     } /* failure */
420     WIN_ReleaseDesktop();
421     return 0;
422 }
423
424 /***********************************************************************
425  *              X11DRV_WND_ForceWindowRaise
426  *
427  * Raise a window on top of the X stacking order, while preserving 
428  * the correct Windows Z order.
429  */
430 void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
431 {
432   XWindowChanges winChanges;
433   WND *wndPrev,*pDesktop = WIN_GetDesktop();
434   
435   if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) )
436   {
437       WIN_ReleaseDesktop();
438     return;
439   }
440   
441   /* Raise all windows up to wndPtr according to their Z order.
442    * (it would be easier with sibling-related Below but it doesn't
443    * work very well with SGI mwm for instance)
444    */
445   winChanges.stack_mode = Above;
446   while (wndPtr)
447     {
448       if (X11DRV_WND_GetXWindow(wndPtr)) 
449         TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
450                                 CWStackMode, &winChanges );
451       wndPrev = pDesktop->child;
452       if (wndPrev == wndPtr) break;
453       while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
454       wndPtr = wndPrev;
455     }
456   WIN_ReleaseDesktop();
457 }
458
459 /***********************************************************************
460  *              X11DRV_WND_FindDesktopXWindow   [Internal]
461  *
462  * Find the actual X window which needs be restacked.
463  * Used by X11DRV_SetWindowPos().
464  */
465 static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
466 {
467   if (!(wndPtr->flags & WIN_MANAGED))
468     return X11DRV_WND_GetXWindow(wndPtr);
469   else
470     {
471       Window window, root, parent, *children;
472       int nchildren;
473       window = X11DRV_WND_GetXWindow(wndPtr);
474       for (;;)
475         {
476           TSXQueryTree( display, window, &root, &parent,
477                         &children, &nchildren );
478           TSXFree( children );
479           if (parent == root)
480             return window;
481           window = parent;
482         }
483     }
484 }
485
486 /***********************************************************************
487  *           WINPOS_SetXWindowPos
488  *
489  * SetWindowPos() for an X window. Used by the real SetWindowPos().
490  */
491 void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos)
492 {
493     XWindowChanges winChanges;
494     int changeMask = 0;
495     WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
496     if ( !winposPtr ) return;
497
498     if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happend!!! */
499   
500     if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
501     {
502       if(X11DRV_WND_GetXWindow(wndPtr)) 
503         TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
504     }
505
506     if(bChangePos)
507     {
508         if ( !(winpos->flags & SWP_NOSIZE))
509         {
510           winChanges.width     = (winpos->cx > 0 ) ? winpos->cx : 1;
511           winChanges.height    = (winpos->cy > 0 ) ? winpos->cy : 1;
512           changeMask |= CWWidth | CWHeight;
513           
514           /* Tweak dialog window size hints */
515           
516           if ((winposPtr->flags & WIN_MANAGED) &&
517                HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle))
518             {
519               XSizeHints *size_hints = TSXAllocSizeHints();
520               
521               if (size_hints)
522                 {
523                   long supplied_return;
524                   
525                   TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
526                                      &supplied_return, XA_WM_NORMAL_HINTS);
527                   size_hints->min_width = size_hints->max_width = winpos->cx;
528                   size_hints->min_height = size_hints->max_height = winpos->cy;
529                   TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
530                                      XA_WM_NORMAL_HINTS );
531                   TSXFree(size_hints);
532                 }
533             }
534         }
535         if (!(winpos->flags & SWP_NOMOVE))
536         {
537           winChanges.x = winpos->x;
538           winChanges.y = winpos->y;
539           changeMask |= CWX | CWY;
540         }
541         if (!(winpos->flags & SWP_NOZORDER))
542         {
543           winChanges.stack_mode = Below;
544           changeMask |= CWStackMode;
545           
546           if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
547           else if (winpos->hwndInsertAfter != HWND_BOTTOM)
548             {
549               WND*   insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
550               Window stack[2];
551               
552               stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
553               stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
554               
555               /* for stupid window managers (i.e. all of them) */
556               
557               TSXRestackWindows(display, stack, 2); 
558               changeMask &= ~CWStackMode;
559               
560               WIN_ReleaseWndPtr(insertPtr);
561             }
562         }
563         if (changeMask && X11DRV_WND_GetXWindow(winposPtr))
564         {
565             TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
566             if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) )
567                 X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget );
568         }
569     }
570
571     if ( winpos->flags & SWP_SHOWWINDOW )
572     {
573         if(X11DRV_WND_GetXWindow(wndPtr)) 
574            TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
575     }
576     WIN_ReleaseWndPtr(winposPtr);
577 }
578
579 /*****************************************************************
580  *              X11DRV_WND_SetText
581  */
582 void X11DRV_WND_SetText(WND *wndPtr, LPCSTR text)
583 {   
584   if (!X11DRV_WND_GetXWindow(wndPtr))
585     return;
586
587   TSXStoreName( display, X11DRV_WND_GetXWindow(wndPtr), text );
588   TSXSetIconName( display, X11DRV_WND_GetXWindow(wndPtr), text );
589 }
590
591 /*****************************************************************
592  *              X11DRV_WND_SetFocus
593  *
594  * Set the X focus.
595  * Explicit colormap management seems to work only with OLVWM.
596  */
597 void X11DRV_WND_SetFocus(WND *wndPtr)
598 {
599   HWND hwnd =  wndPtr->hwndSelf;
600   XWindowAttributes win_attr;
601   Window win;
602   
603   /* Only mess with the X focus if there's */
604   /* no desktop window and if the window is not managed by the WM. */
605   if ((X11DRV_WND_GetXRootWindow(wndPtr) != DefaultRootWindow(display))
606       || (wndPtr->flags & WIN_MANAGED)) return;
607   
608   if (!hwnd)    /* If setting the focus to 0, uninstall the colormap */
609     {
610       if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
611         TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
612       return;
613     }
614   
615   /* Set X focus and install colormap */
616   
617   if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
618   if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
619       (win_attr.map_state != IsViewable))
620     return;  /* If window is not viewable, don't change anything */
621   
622   TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
623   if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
624     TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
625   
626   EVENT_Synchronize();
627 }
628
629 /*****************************************************************
630  *              X11DRV_WND_PreSizeMove
631  */
632 void X11DRV_WND_PreSizeMove(WND *wndPtr)
633 {
634   if (!(wndPtr->dwStyle & WS_CHILD) && 
635       (X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
636     TSXGrabServer( display );
637 }
638
639 /*****************************************************************
640  *               X11DRV_WND_PostSizeMove
641  */
642 void X11DRV_WND_PostSizeMove(WND *wndPtr)
643 {
644   if (!(wndPtr->dwStyle & WS_CHILD) && 
645       (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
646     TSXUngrabServer( display );
647 }
648
649 /*****************************************************************
650  *               X11DRV_WND_SurfaceCopy
651  *
652  * Copies rect to (rect.left + dx, rect.top + dy). 
653  */
654 void X11DRV_WND_SurfaceCopy(WND* wndPtr, DC *dcPtr, INT dx, INT dy, 
655                             const RECT *rect, BOOL bUpdate)
656 {
657     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
658     POINT dst, src;
659   
660     dst.x = (src.x = dcPtr->w.DCOrgX + rect->left) + dx;
661     dst.y = (src.y = dcPtr->w.DCOrgY + rect->top) + dy;
662   
663     if (bUpdate) /* handles non-Wine windows hanging over the copied area */
664         TSXSetGraphicsExposures( display, physDev->gc, True );
665     TSXSetFunction( display, physDev->gc, GXcopy );
666     TSXCopyArea( display, physDev->drawable, physDev->drawable,
667                  physDev->gc, src.x, src.y,
668                  rect->right - rect->left,
669                  rect->bottom - rect->top,
670                  dst.x, dst.y );
671     if (bUpdate)
672         TSXSetGraphicsExposures( display, physDev->gc, False );
673
674     if (bUpdate) /* Make sure exposure events have been processed */
675         EVENT_Synchronize();
676 }
677
678 /***********************************************************************
679  *              X11DRV_WND_SetDrawable
680  *
681  * Set the drawable, origin and dimensions for the DC associated to
682  * a given window.
683  */
684 void X11DRV_WND_SetDrawable(WND *wndPtr, DC *dc, WORD flags, BOOL bSetClipOrigin)
685 {
686     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
687     INT dcOrgXCopy, dcOrgYCopy;
688     BOOL offsetClipRgn = FALSE;
689
690     if (!wndPtr)  /* Get a DC for the whole screen */
691     {
692         dc->w.DCOrgX = 0;
693         dc->w.DCOrgY = 0;
694         physDev->drawable = X11DRV_WND_GetXRootWindow(wndPtr);
695         TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
696     }
697     else
698     {
699         /*
700          * This function change the coordinate system (DCOrgX,DCOrgY)
701          * values. When it moves the origin, other data like the current clipping
702          * region will not be moved to that new origin. In the case of DCs that are class
703          * or window DCs that clipping region might be a valid value from a previous use
704          * of the DC and changing the origin of the DC without moving the clip region
705          * results in a clip region that is not placed properly in the DC.
706          * This code will save the dc origin, let the SetDrawable
707          * modify the origin and reset the clipping. When the clipping is set,
708          * it is moved according to the new DC origin.
709          */
710          if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->w.hClipRgn > 0))
711          {
712              dcOrgXCopy = dc->w.DCOrgX;
713              dcOrgYCopy = dc->w.DCOrgY;
714              offsetClipRgn = TRUE;
715          }
716
717         if (flags & DCX_WINDOW)
718         {
719             dc->w.DCOrgX  = wndPtr->rectWindow.left;
720             dc->w.DCOrgY  = wndPtr->rectWindow.top;
721         }
722         else
723         {
724             dc->w.DCOrgX  = wndPtr->rectClient.left;
725             dc->w.DCOrgY  = wndPtr->rectClient.top;
726         }
727         while (!X11DRV_WND_GetXWindow(wndPtr))
728         {
729             wndPtr = wndPtr->parent;
730             dc->w.DCOrgX += wndPtr->rectClient.left;
731             dc->w.DCOrgY += wndPtr->rectClient.top;
732         }
733         dc->w.DCOrgX -= wndPtr->rectWindow.left;
734         dc->w.DCOrgY -= wndPtr->rectWindow.top;
735
736         /* reset the clip region, according to the new origin */
737         if ( offsetClipRgn )
738         {
739              OffsetRgn(dc->w.hClipRgn, dc->w.DCOrgX - dcOrgXCopy,dc->w.DCOrgY - dcOrgYCopy);
740         }
741         
742         physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
743
744 #if 0
745         /* This is needed when we reuse a cached DC because
746          * SetDCState() called by ReleaseDC() screws up DC
747          * origins for child windows.
748          */
749
750         if( bSetClipOrigin )
751             TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY );
752 #endif
753     }
754 }
755
756 /***********************************************************************
757  *              X11DRV_SetWMHint
758  */
759 static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
760 {
761     XWMHints* wm_hints = TSXAllocWMHints();
762     {
763         wm_hints->flags = hint;
764         switch( hint )
765         {
766             case InputHint:
767                  wm_hints->input = val;
768                  break;
769
770             case StateHint:
771                  wm_hints->initial_state = val;
772                  break;
773
774             case IconPixmapHint:
775                  wm_hints->icon_pixmap = (Pixmap)val;
776                  break;
777
778             case IconWindowHint:
779                  wm_hints->icon_window = (Window)val;
780                  break;
781         }
782
783         TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
784         TSXFree(wm_hints);
785         return TRUE;
786     }
787     return FALSE;
788 }
789
790
791 /***********************************************************************
792  *              X11DRV_WND_SetHostAttr
793  *
794  * This function returns TRUE if the attribute is supported and the
795  * action was successful. Otherwise it should return FALSE and Wine will try 
796  * to get by without the functionality provided by the host window system.
797  */
798 BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value)
799 {
800     Window w;
801
802     if( (w = X11DRV_WND_GetXWindow(wnd)) )
803     {
804         XSetWindowAttributes win_attr;
805
806         switch( ha )
807         {
808         case HAK_ICONICSTATE: /* called when a window is minimized/restored */
809
810                     if( (wnd->flags & WIN_MANAGED) )
811                     {
812                         if( value )
813                         {
814                             if( wnd->dwStyle & WS_VISIBLE )
815                             {
816                                 XClientMessageEvent ev;
817
818                                 /* FIXME: set proper icon */
819
820                                 ev.type = ClientMessage;
821                                 ev.display = display;
822                                 ev.message_type = wmChangeState;
823                                 ev.format = 32;
824                                 ev.data.l[0] = IconicState;
825                                 ev.window = w;
826
827                                 if( TSXSendEvent (display,
828                 RootWindow( display, XScreenNumberOfScreen(X11DRV_WND_GetXScreen(wnd)) ), 
829                 True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev))
830                                 {
831                                     XEvent xe;
832                                     TSXFlush (display);
833                                     while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) );
834                                 }
835                                 else 
836                                     break;
837                             }
838                             else
839                                 X11DRV_SetWMHint( display, wnd, StateHint, IconicState );
840                         }
841                         else
842                         {
843                             if( !(wnd->flags & WS_VISIBLE) )
844                                 X11DRV_SetWMHint( display, wnd, StateHint, NormalState );
845                             else
846                             {
847                                 XEvent xe;
848                                 TSXMapWindow(display, w );
849                                 while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) );
850                             }
851                         }
852                         return TRUE;
853                     }
854                     break;
855
856         case HAK_BITGRAVITY: /* called when a window is resized */
857
858                     if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value )
859                     {
860                         win_attr.bit_gravity = value;
861                         ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value;
862                         TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr );
863                     }
864                    return TRUE;
865
866         case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */
867
868                 if( (wnd->flags & WIN_MANAGED) )
869                     return X11DRV_SetWMHint( display, wnd, InputHint, value );
870         }
871     }
872     return FALSE;
873 }
874
875 /***********************************************************************
876  *              X11DRV_WND_IsSelfClipping
877  */
878 BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr)
879 {
880   return X11DRV_WND_GetXWindow(wndPtr) != None;
881 }
882
883 #endif /* !defined(X_DISPLAY_MISSING) */