- implementation of SetWindowsRgn and GetWindowRgn
[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 #include <X11/Xatom.h>
12
13 #include "ts_xlib.h"
14 #include "ts_xutil.h"
15 #include "ts_shape.h"
16
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "bitmap.h"
21 #include "color.h"
22 #include "debugtools.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 "wingdi.h"
32 #include "winnls.h"
33 #include "wine/winuser16.h"
34
35 DEFAULT_DEBUG_CHANNEL(win);
36
37   /* Some useful macros */
38 #define HAS_DLGFRAME(style,exStyle) \
39 ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
40
41 /**********************************************************************/
42
43 extern Cursor X11DRV_MOUSE_XCursor;  /* Current X cursor */
44 extern BOOL   X11DRV_CreateBitmap( HBITMAP );
45 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
46
47 /**********************************************************************/
48
49 /* X context to associate a hwnd to an X window */
50 XContext winContext = 0;
51
52 Atom wmProtocols = None;
53 Atom wmDeleteWindow = None;
54 Atom dndProtocol = None;
55 Atom dndSelection = None;
56 Atom wmChangeState = None;
57
58 Atom kwmDockWindow = None;
59
60 /***********************************************************************
61  *              X11DRV_WND_GetXWindow
62  *
63  * Return the X window associated to a window.
64  */
65 Window X11DRV_WND_GetXWindow(WND *wndPtr)
66 {
67     return wndPtr && wndPtr->pDriverData ? 
68       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
69 }
70
71 /***********************************************************************
72  *              X11DRV_WND_FindXWindow
73  *
74  * Return the the first X window associated to a window chain.
75  */
76 Window X11DRV_WND_FindXWindow(WND *wndPtr)
77 {
78     while (wndPtr && 
79            !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window) 
80       wndPtr = wndPtr->parent;
81     return wndPtr ?
82       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
83 }
84
85 /***********************************************************************
86  *              X11DRV_WND_RegisterWindow
87  *
88  * Associate an X window to a HWND.
89  */
90 static void X11DRV_WND_RegisterWindow(WND *wndPtr)
91 {
92   TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
93   
94   if (!winContext) winContext = TSXUniqueContext();
95   TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr), 
96                   winContext, (char *) wndPtr->hwndSelf );
97 }
98
99 /**********************************************************************
100  *              X11DRV_WND_Initialize
101  */
102 void X11DRV_WND_Initialize(WND *wndPtr)
103 {
104   X11DRV_WND_DATA *pWndDriverData = 
105     (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
106
107   wndPtr->pDriverData = (void *) pWndDriverData;
108
109   pWndDriverData->window = 0;
110 }
111
112 /**********************************************************************
113  *              X11DRV_WND_Finalize
114  */
115 void X11DRV_WND_Finalize(WND *wndPtr)
116 {
117   X11DRV_WND_DATA *pWndDriverData =
118     (X11DRV_WND_DATA *) wndPtr->pDriverData;
119
120   if (!wndPtr->pDriverData) {
121      ERR("Trying to destroy window again. Not good.\n");
122      return;
123   }
124   if(pWndDriverData->window)
125     {
126       ERR(
127           "WND destroyed without destroying "
128           "the associated X Window (%ld)\n", 
129           pWndDriverData->window
130       );
131     }
132   HeapFree(SystemHeap, 0, wndPtr->pDriverData);
133   wndPtr->pDriverData = NULL;
134 }
135
136 /**********************************************************************
137  *              X11DRV_WND_CreateDesktopWindow
138  */
139 BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode)
140 {
141     if (wmProtocols == None)
142         wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
143     if (wmDeleteWindow == None)
144         wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
145     if( dndProtocol == None )
146         dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
147     if( dndSelection == None )
148         dndSelection = TSXInternAtom( display, "DndSelection" , False );
149     if( wmChangeState == None )
150         wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
151     if (kwmDockWindow == None)
152         kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
153
154     ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = X11DRV_GetXRootWindow();
155     X11DRV_WND_RegisterWindow( wndPtr );
156
157     return TRUE;
158 }
159
160 /**********************************************************************
161  *              X11DRV_WND_IconChanged
162  *
163  * hIcon or hIconSm has changed (or is being initialised for the
164  * first time). Complete the X11 driver-specific initialisation.
165  *
166  * This is not entirely correct, may need to create
167  * an icon window and set the pixmap as a background
168  */
169 static void X11DRV_WND_IconChanged(WND *wndPtr)
170 {
171
172     HICON16 hIcon = NC_IconForWindow(wndPtr); 
173
174     if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
175         DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
176
177     if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
178         DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
179
180     if (!hIcon)
181     {
182         ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap= 0;
183         ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
184     }
185     else
186     {
187         HBITMAP hbmOrig;
188         RECT rcMask;
189         BITMAP bmMask;
190         ICONINFO ii;
191         HDC hDC;
192
193         GetIconInfo(hIcon, &ii);
194
195         X11DRV_CreateBitmap(ii.hbmMask);
196         X11DRV_CreateBitmap(ii.hbmColor);
197
198         GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
199         rcMask.top    = 0;
200         rcMask.left   = 0;
201         rcMask.right  = bmMask.bmWidth;
202         rcMask.bottom = bmMask.bmHeight;
203
204         hDC = CreateCompatibleDC(0);
205         hbmOrig = SelectObject(hDC, ii.hbmMask);
206         InvertRect(hDC, &rcMask);
207         SelectObject(hDC, hbmOrig);
208         DeleteDC(hDC);
209
210         ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = ii.hbmColor;
211         ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= ii.hbmMask;
212     }
213     return;
214 }
215
216 static void X11DRV_WND_SetIconHints(WND *wndPtr, XWMHints *hints)
217 {
218     if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap)
219     {
220         hints->icon_pixmap
221             = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap);
222         hints->flags |= IconPixmapHint;
223     }
224     else
225         hints->flags &= ~IconPixmapHint;
226
227     if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask)
228     {
229         hints->icon_mask
230             = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
231         hints->flags |= IconMaskHint;
232     }
233     else
234         hints->flags &= ~IconMaskHint;
235 }
236
237 /**********************************************************************
238  *              X11DRV_WND_UpdateIconHints
239  *
240  * hIcon or hIconSm has changed (or is being initialised for the
241  * first time). Complete the X11 driver-specific initialisation
242  * and set the window hints.
243  *
244  * This is not entirely correct, may need to create
245  * an icon window and set the pixmap as a background
246  */
247 static void X11DRV_WND_UpdateIconHints(WND *wndPtr)
248 {
249     XWMHints* wm_hints;
250
251     X11DRV_WND_IconChanged(wndPtr);
252
253     wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
254     if (!wm_hints) wm_hints = TSXAllocWMHints();
255     if (wm_hints)
256     {
257         X11DRV_WND_SetIconHints(wndPtr, wm_hints);
258         TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
259         TSXFree( wm_hints );
260     }
261 }
262
263
264 /**********************************************************************
265  *              X11DRV_WND_CreateWindow
266  */
267 BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode)
268 {
269   /* Create the X window (only for top-level windows, and then only */
270   /* when there's no desktop window) */
271   
272   if ((X11DRV_GetXRootWindow() == DefaultRootWindow(display))
273       && (wndPtr->parent->hwndSelf == GetDesktopWindow()))
274   {
275       Window    wGroupLeader;
276       XWMHints* wm_hints;
277       XSetWindowAttributes win_attr;
278       
279       /* Create "managed" windows only if a title bar or resizable */
280       /* frame is required. */
281         if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle)) {
282           win_attr.event_mask = ExposureMask | KeyPressMask |
283             KeyReleaseMask | PointerMotionMask |
284             ButtonPressMask | ButtonReleaseMask |
285             FocusChangeMask | StructureNotifyMask;
286           win_attr.override_redirect = FALSE;
287           wndPtr->flags |= WIN_MANAGED;
288         } else {
289           win_attr.event_mask = ExposureMask | KeyPressMask |
290             KeyReleaseMask | PointerMotionMask |
291             ButtonPressMask | ButtonReleaseMask |
292             FocusChangeMask;
293           win_attr.override_redirect = TRUE;
294         }
295       wndPtr->flags |= WIN_NATIVE;
296
297       win_attr.bit_gravity   = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest;
298       win_attr.colormap      = X11DRV_PALETTE_PaletteXColormap;
299       win_attr.backing_store = NotUseful;
300       win_attr.save_under    = ((classPtr->style & CS_SAVEBITS) != 0);
301       win_attr.cursor        = X11DRV_MOUSE_XCursor;
302
303       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
304       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask = 0;
305       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
306
307       /* Zero-size X11 window hack.  X doesn't like them, and will crash */
308       /* with a BadValue unless we do something ugly like this. */
309       /* FIXME:  there must be a better way.  */
310         if (cs->cx <= 0) cs->cx = 1;
311         if (cs->cy <= 0) cs->cy = 1;
312       /* EMXIF */
313
314       ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = 
315         TSXCreateWindow( display, X11DRV_GetXRootWindow(), 
316                          cs->x, cs->y, cs->cx, cs->cy, 
317                          0, CopyFromParent, 
318                          InputOutput, CopyFromParent,
319                          CWEventMask | CWOverrideRedirect |
320                          CWColormap | CWCursor | CWSaveUnder |
321                          CWBackingStore | CWBitGravity, 
322                          &win_attr );
323       
324       if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
325         return FALSE;
326
327       /* If we are the systray, we need to be managed to be noticed by KWM */
328
329       if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW)
330         X11DRV_WND_DockWindow(wndPtr);
331
332       if (wndPtr->flags & WIN_MANAGED) 
333       {
334           XClassHint *class_hints = TSXAllocClassHint();
335           XSizeHints* size_hints = TSXAllocSizeHints();
336           
337           if (class_hints) 
338           {
339               class_hints->res_name = "wineManaged";
340               class_hints->res_class = "Wine";
341               TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
342               TSXFree (class_hints);
343           }
344
345           if (size_hints) 
346           {
347               size_hints->win_gravity = StaticGravity;
348               size_hints->flags = PWinGravity;
349
350               if (HAS_DLGFRAME(cs->style,cs->dwExStyle))
351               {
352                   size_hints->min_width = size_hints->max_width = cs->cx;
353                   size_hints->min_height = size_hints->max_height = cs->cy;
354                   size_hints->flags |= PMinSize | PMaxSize;
355               }
356
357               TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), 
358                                  size_hints, XA_WM_NORMAL_HINTS );
359               TSXFree(size_hints);
360           }
361       }
362       
363       if (cs->hwndParent)  /* Get window owner */
364       {
365           Window w;
366           WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
367
368           w = X11DRV_WND_FindXWindow( tmpWnd );
369           if (w != None)
370           {
371               TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
372               wGroupLeader = w;
373           }
374           WIN_ReleaseWndPtr(tmpWnd);
375       }
376
377       if ((wm_hints = TSXAllocWMHints()))
378       {
379           wm_hints->flags = InputHint | StateHint | WindowGroupHint;
380           wm_hints->input = True;
381
382           if( wndPtr->flags & WIN_MANAGED )
383           {
384               X11DRV_WND_IconChanged(wndPtr);
385               X11DRV_WND_SetIconHints(wndPtr, wm_hints);
386
387               wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE) 
388                                         ? IconicState : NormalState;
389           }
390           else
391               wm_hints->initial_state = NormalState;
392           wm_hints->window_group = wGroupLeader;
393
394           TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
395           TSXFree(wm_hints);
396       }
397       X11DRV_WND_RegisterWindow( wndPtr );
398   }
399   return TRUE;
400 }
401
402 /***********************************************************************
403  *              X11DRV_WND_DestroyWindow
404  */
405 BOOL X11DRV_WND_DestroyWindow(WND *wndPtr)
406 {
407    Window w;
408    if ((w = X11DRV_WND_GetXWindow(wndPtr)))
409    {
410        XEvent xe;
411        TSXDeleteContext( display, w, winContext );
412        TSXDestroyWindow( display, w );
413        while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
414
415        ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
416        if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
417        {
418            DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
419            ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
420        }
421        if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
422        {
423            DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
424            ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
425        }
426    }
427
428    return TRUE;
429 }
430
431 /*****************************************************************
432  *              X11DRV_WND_SetParent
433  */
434 WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
435 {
436     WND *pDesktop = WIN_GetDesktop();
437     
438     if( wndPtr && pWndParent && (wndPtr != pDesktop) )
439     {
440         WND* pWndPrev = wndPtr->parent;
441
442         if( pWndParent != pWndPrev )
443         {
444             if ( X11DRV_WND_GetXWindow(wndPtr) )
445             {
446                 /* Toplevel window needs to be reparented.  Used by Tk 8.0 */
447
448                 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
449                 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
450             }
451
452             WIN_UnlinkWindow(wndPtr->hwndSelf);
453             wndPtr->parent = pWndParent;
454
455             /* Create an X counterpart for reparented top-level windows
456              * when not in the desktop mode. */
457
458             if( pWndParent == pDesktop )
459             {
460                 if( X11DRV_GetXRootWindow() == DefaultRootWindow(display) )
461                 {
462                     CREATESTRUCTA cs;
463                     cs.lpCreateParams = NULL;
464                     cs.hInstance = 0; /* not used in following call */
465                     cs.hMenu = 0; /* not used in following call */
466                     cs.hwndParent = pWndParent->hwndSelf;
467                     cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
468                     if (!cs.cy)
469                       cs.cy = 1;
470                     cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
471                     if (!cs.cx)
472                       cs.cx = 1;
473                     cs.y = wndPtr->rectWindow.top;
474                     cs.x = wndPtr->rectWindow.left;
475                     cs.style = wndPtr->dwStyle;
476                     cs.lpszName = 0; /* not used in following call */
477                     cs.lpszClass = 0; /*not used in following call */
478                     cs.dwExStyle = wndPtr->dwExStyle;
479                     X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
480                                             &cs, FALSE);
481                 }
482             }
483             else /* a child window */
484             {
485                 if( !( wndPtr->dwStyle & WS_CHILD ) )
486                 {
487                     if( wndPtr->wIDmenu != 0)
488                     {
489                         DestroyMenu( (HMENU) wndPtr->wIDmenu );
490                         wndPtr->wIDmenu = 0;
491                     }
492                 }
493             }
494             WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
495         }
496         WIN_ReleaseDesktop();
497         return pWndPrev;
498     } /* failure */
499     WIN_ReleaseDesktop();
500     return 0;
501 }
502
503 /***********************************************************************
504  *              X11DRV_WND_ForceWindowRaise
505  *
506  * Raise a window on top of the X stacking order, while preserving 
507  * the correct Windows Z order.
508  */
509 void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
510 {
511   XWindowChanges winChanges;
512   WND *wndPrev,*pDesktop = WIN_GetDesktop();
513   
514   if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) )
515   {
516       WIN_ReleaseDesktop();
517     return;
518   }
519   
520   /* Raise all windows up to wndPtr according to their Z order.
521    * (it would be easier with sibling-related Below but it doesn't
522    * work very well with SGI mwm for instance)
523    */
524   winChanges.stack_mode = Above;
525   while (wndPtr)
526     {
527       if (X11DRV_WND_GetXWindow(wndPtr)) 
528         TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
529                                 CWStackMode, &winChanges );
530       wndPrev = pDesktop->child;
531       if (wndPrev == wndPtr) break;
532       while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
533       wndPtr = wndPrev;
534     }
535   WIN_ReleaseDesktop();
536 }
537
538 /***********************************************************************
539  *              X11DRV_WND_FindDesktopXWindow   [Internal]
540  *
541  * Find the actual X window which needs be restacked.
542  * Used by X11DRV_WND_SetWindowPos().
543  */
544 static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
545 {
546   if (!(wndPtr->flags & WIN_MANAGED))
547     return X11DRV_WND_GetXWindow(wndPtr);
548   else
549     {
550       Window window, root, parent, *children;
551       int nchildren;
552       window = X11DRV_WND_GetXWindow(wndPtr);
553       for (;;)
554         {
555           TSXQueryTree( display, window, &root, &parent,
556                         &children, &nchildren );
557           TSXFree( children );
558           if (parent == root)
559             return window;
560           window = parent;
561         }
562     }
563 }
564
565 /***********************************************************************
566  *           WINPOS_SetXWindowPos
567  *
568  * SetWindowPos() for an X window. Used by the real SetWindowPos().
569  */
570 void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos)
571 {
572     XWindowChanges winChanges;
573     int changeMask = 0;
574     WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
575     if ( !winposPtr ) return;
576
577     if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happen!!! */
578   
579     if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
580     {
581       if(X11DRV_WND_GetXWindow(wndPtr)) 
582         TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
583     }
584
585     if(bChangePos)
586     {
587         if ( !(winpos->flags & SWP_NOSIZE))
588         {
589           winChanges.width     = (winpos->cx > 0 ) ? winpos->cx : 1;
590           winChanges.height    = (winpos->cy > 0 ) ? winpos->cy : 1;
591           changeMask |= CWWidth | CWHeight;
592           
593           /* Tweak dialog window size hints */
594           
595           if ((winposPtr->flags & WIN_MANAGED) &&
596                HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle))
597             {
598               XSizeHints *size_hints = TSXAllocSizeHints();
599               
600               if (size_hints)
601                 {
602                   long supplied_return;
603                   
604                   TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
605                                      &supplied_return, XA_WM_NORMAL_HINTS);
606                   size_hints->min_width = size_hints->max_width = winpos->cx;
607                   size_hints->min_height = size_hints->max_height = winpos->cy;
608                   TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
609                                      XA_WM_NORMAL_HINTS );
610                   TSXFree(size_hints);
611                 }
612             }
613         }
614         if (!(winpos->flags & SWP_NOMOVE))
615         {
616           winChanges.x = winpos->x;
617           winChanges.y = winpos->y;
618           changeMask |= CWX | CWY;
619         }
620         if (!(winpos->flags & SWP_NOZORDER))
621         {
622           winChanges.stack_mode = Below;
623           changeMask |= CWStackMode;
624           
625           if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
626           else if (winpos->hwndInsertAfter != HWND_BOTTOM)
627             {
628               WND*   insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
629               Window stack[2];
630               
631               stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
632               stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
633               
634               /* for stupid window managers (i.e. all of them) */
635               
636               TSXRestackWindows(display, stack, 2); 
637               changeMask &= ~CWStackMode;
638               
639               WIN_ReleaseWndPtr(insertPtr);
640             }
641         }
642         if (changeMask && X11DRV_WND_GetXWindow(winposPtr))
643         {
644             TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
645             if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) )
646                 X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget );
647         }
648     }
649
650     if ( winpos->flags & SWP_SHOWWINDOW )
651     {
652         if(X11DRV_WND_GetXWindow(wndPtr)) 
653            TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
654     }
655     WIN_ReleaseWndPtr(winposPtr);
656 }
657
658 /*****************************************************************
659  *              X11DRV_WND_SetText
660  */
661 void X11DRV_WND_SetText(WND *wndPtr, LPCWSTR text)
662 {   
663     UINT count;
664     char *buffer;
665     static UINT text_cp = (UINT)-1;
666     Window win;
667
668     if (!(win = X11DRV_WND_GetXWindow(wndPtr))) return;
669
670     if(text_cp == (UINT)-1)
671     {
672         text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
673         TRACE("text_cp = %u\n", text_cp);
674     }
675
676     /* allocate new buffer for window text */
677     count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
678     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
679     {
680         ERR("Not enough memory for window text\n");
681         return;
682     }
683     WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
684
685     TSXStoreName( display, win, buffer );
686     TSXSetIconName( display, win, buffer );
687     HeapFree( GetProcessHeap(), 0, buffer );
688 }
689
690 /*****************************************************************
691  *              X11DRV_WND_SetFocus
692  *
693  * Set the X focus.
694  * Explicit colormap management seems to work only with OLVWM.
695  */
696 void X11DRV_WND_SetFocus(WND *wndPtr)
697 {
698   HWND hwnd =  wndPtr->hwndSelf;
699   XWindowAttributes win_attr;
700   Window win;
701   WND *w = wndPtr;
702   
703   /* Only mess with the X focus if there's */
704   /* no desktop window and if the window is not managed by the WM. */
705   if ((X11DRV_GetXRootWindow() != DefaultRootWindow(display))) return;
706   while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
707       w = w->parent;
708   if (!w) w = wndPtr;
709   if (w->flags & WIN_MANAGED) return;
710
711   if (!hwnd)    /* If setting the focus to 0, uninstall the colormap */
712     {
713       if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
714         TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
715       return;
716     }
717   
718   /* Set X focus and install colormap */
719   
720   if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
721   if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
722       (win_attr.map_state != IsViewable))
723     return;  /* If window is not viewable, don't change anything */
724   
725   TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
726   if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
727     TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
728   
729   EVENT_Synchronize();
730 }
731
732 /*****************************************************************
733  *              X11DRV_WND_PreSizeMove
734  */
735 void X11DRV_WND_PreSizeMove(WND *wndPtr)
736 {
737   if (!(wndPtr->dwStyle & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
738     TSXGrabServer( display );
739 }
740
741 /*****************************************************************
742  *               X11DRV_WND_PostSizeMove
743  */
744 void X11DRV_WND_PostSizeMove(WND *wndPtr)
745 {
746   if (!(wndPtr->dwStyle & WS_CHILD) && 
747       (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
748     TSXUngrabServer( display );
749 }
750
751 /*****************************************************************
752  *               X11DRV_WND_SurfaceCopy
753  *
754  * Copies rect to (rect.left + dx, rect.top + dy). 
755  */
756 void X11DRV_WND_SurfaceCopy(WND* wndPtr, DC *dcPtr, INT dx, INT dy, 
757                             const RECT *rect, BOOL bUpdate)
758 {
759     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
760     POINT dst, src;
761   
762     dst.x = (src.x = dcPtr->w.DCOrgX + rect->left) + dx;
763     dst.y = (src.y = dcPtr->w.DCOrgY + rect->top) + dy;
764   
765     if (bUpdate) /* handles non-Wine windows hanging over the copied area */
766         TSXSetGraphicsExposures( display, physDev->gc, True );
767     TSXSetFunction( display, physDev->gc, GXcopy );
768     TSXCopyArea( display, physDev->drawable, physDev->drawable,
769                  physDev->gc, src.x, src.y,
770                  rect->right - rect->left,
771                  rect->bottom - rect->top,
772                  dst.x, dst.y );
773     if (bUpdate)
774         TSXSetGraphicsExposures( display, physDev->gc, False );
775
776     if (bUpdate) /* Make sure exposure events have been processed */
777         EVENT_Synchronize();
778 }
779
780 /***********************************************************************
781  *              X11DRV_WND_SetDrawable
782  *
783  * Set the drawable, origin and dimensions for the DC associated to
784  * a given window.
785  */
786 void X11DRV_WND_SetDrawable(WND *wndPtr, DC *dc, WORD flags, BOOL bSetClipOrigin)
787 {
788     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
789     INT dcOrgXCopy = 0, dcOrgYCopy = 0;
790     BOOL offsetClipRgn = FALSE;
791
792     if (!wndPtr)  /* Get a DC for the whole screen */
793     {
794         dc->w.DCOrgX = 0;
795         dc->w.DCOrgY = 0;
796         physDev->drawable = X11DRV_GetXRootWindow();
797         TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
798     }
799     else
800     {
801         /*
802          * This function change the coordinate system (DCOrgX,DCOrgY)
803          * values. When it moves the origin, other data like the current clipping
804          * region will not be moved to that new origin. In the case of DCs that are class
805          * or window DCs that clipping region might be a valid value from a previous use
806          * of the DC and changing the origin of the DC without moving the clip region
807          * results in a clip region that is not placed properly in the DC.
808          * This code will save the dc origin, let the SetDrawable
809          * modify the origin and reset the clipping. When the clipping is set,
810          * it is moved according to the new DC origin.
811          */
812          if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->w.hClipRgn > 0))
813          {
814              dcOrgXCopy = dc->w.DCOrgX;
815              dcOrgYCopy = dc->w.DCOrgY;
816              offsetClipRgn = TRUE;
817          }
818
819         if (flags & DCX_WINDOW)
820         {
821             dc->w.DCOrgX  = wndPtr->rectWindow.left;
822             dc->w.DCOrgY  = wndPtr->rectWindow.top;
823         }
824         else
825         {
826             dc->w.DCOrgX  = wndPtr->rectClient.left;
827             dc->w.DCOrgY  = wndPtr->rectClient.top;
828         }
829         while (!X11DRV_WND_GetXWindow(wndPtr))
830         {
831             wndPtr = wndPtr->parent;
832             dc->w.DCOrgX += wndPtr->rectClient.left;
833             dc->w.DCOrgY += wndPtr->rectClient.top;
834         }
835         dc->w.DCOrgX -= wndPtr->rectWindow.left;
836         dc->w.DCOrgY -= wndPtr->rectWindow.top;
837
838         /* reset the clip region, according to the new origin */
839         if ( offsetClipRgn )
840         {
841              OffsetRgn(dc->w.hClipRgn, dc->w.DCOrgX - dcOrgXCopy,dc->w.DCOrgY - dcOrgYCopy);
842         }
843         
844         physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
845
846 #if 0
847         /* This is needed when we reuse a cached DC because
848          * SetDCState() called by ReleaseDC() screws up DC
849          * origins for child windows.
850          */
851
852         if( bSetClipOrigin )
853             TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY );
854 #endif
855     }
856 }
857
858 /***********************************************************************
859  *              X11DRV_SetWMHint
860  */
861 static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
862 {
863     XWMHints* wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
864     if (!wm_hints) wm_hints = TSXAllocWMHints();
865     if (wm_hints)
866     {
867         wm_hints->flags = hint;
868         switch( hint )
869         {
870             case InputHint:
871                  wm_hints->input = val;
872                  break;
873
874             case StateHint:
875                  wm_hints->initial_state = val;
876                  break;
877
878             case IconPixmapHint:
879                  wm_hints->icon_pixmap = (Pixmap)val;
880                  break;
881
882             case IconWindowHint:
883                  wm_hints->icon_window = (Window)val;
884                  break;
885         }
886
887         TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
888         TSXFree(wm_hints);
889         return TRUE;
890     }
891     return FALSE;
892 }
893
894
895 /***********************************************************************
896  *              X11DRV_WND_SetHostAttr
897  *
898  * This function returns TRUE if the attribute is supported and the
899  * action was successful. Otherwise it should return FALSE and Wine will try 
900  * to get by without the functionality provided by the host window system.
901  */
902 BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value)
903 {
904     Window w;
905
906     if( (w = X11DRV_WND_GetXWindow(wnd)) )
907     {
908         XSetWindowAttributes win_attr;
909
910         switch( ha )
911         {
912         case HAK_ICONICSTATE: /* called when a window is minimized/restored */
913
914                     if( (wnd->flags & WIN_MANAGED) )
915                     {
916                         if( value )
917                         {
918                             if( wnd->dwStyle & WS_VISIBLE )
919                             {
920                                 XClientMessageEvent ev;
921
922                                 /* FIXME: set proper icon */
923
924                                 ev.type = ClientMessage;
925                                 ev.display = display;
926                                 ev.message_type = wmChangeState;
927                                 ev.format = 32;
928                                 ev.data.l[0] = IconicState;
929                                 ev.window = w;
930
931                                 if( TSXSendEvent (display,
932                 RootWindow( display, XScreenNumberOfScreen(X11DRV_GetXScreen()) ), 
933                 True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev))
934                                 {
935                                     XEvent xe;
936                                     TSXFlush (display);
937                                     while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) );
938                                 }
939                                 else 
940                                     break;
941                             }
942                             else
943                                 X11DRV_SetWMHint( display, wnd, StateHint, IconicState );
944                         }
945                         else
946                         {
947                             if( !(wnd->flags & WS_VISIBLE) )
948                                 X11DRV_SetWMHint( display, wnd, StateHint, NormalState );
949                             else
950                             {
951                                 XEvent xe;
952                                 TSXMapWindow(display, w );
953                                 while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) );
954                             }
955                         }
956                         return TRUE;
957                     }
958                     break;
959
960         case HAK_BITGRAVITY: /* called when a window is resized */
961
962                     if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value )
963                     {
964                         win_attr.bit_gravity = value;
965                         ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value;
966                         TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr );
967                     }
968                    return TRUE;
969
970         case HAK_ICONS: /* called when the icons change */
971             if ( (wnd->flags & WIN_MANAGED) )
972                 X11DRV_WND_UpdateIconHints(wnd);
973             return TRUE;
974
975         case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */
976
977                 if( (wnd->flags & WIN_MANAGED) )
978                     return X11DRV_SetWMHint( display, wnd, InputHint, value );
979         }
980     }
981     return FALSE;
982 }
983
984 /***********************************************************************
985  *              X11DRV_WND_IsSelfClipping
986  */
987 BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr)
988 {
989   return X11DRV_WND_GetXWindow(wndPtr) != None;
990 }
991
992 /***********************************************************************
993  *              X11DRV_WND_DockWindow
994  *
995  * Set the X Property of the window that tells the windowmanager we really
996  * want to be in the systray
997  *
998  * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is 
999  *      mapped.
1000  *
1001  * all others: to be added ;)
1002  */
1003 void X11DRV_WND_DockWindow(WND *wndPtr)
1004
1005   int data = 1;
1006   Window win = X11DRV_WND_GetXWindow(wndPtr);
1007   if (kwmDockWindow == None) 
1008           return; /* no KDE running */
1009   TSXChangeProperty(
1010     display,win,kwmDockWindow,kwmDockWindow,32,PropModeReplace,(char*)&data,1
1011   );
1012 }
1013
1014
1015 /***********************************************************************
1016  *              X11DRV_WND_SetWindowRgn
1017  *
1018  * Assign specified region to window (for non-rectangular windows)
1019  */
1020 void X11DRV_WND_SetWindowRgn(WND *wndPtr, HRGN hrgnWnd)
1021 {
1022 #ifdef HAVE_LIBXSHAPE
1023     Window win = X11DRV_WND_GetXWindow(wndPtr);
1024
1025     if (!win) return;
1026
1027     if (!hrgnWnd)
1028     {
1029         TSXShapeCombineMask( display, win, ShapeBounding, 0, 0, None, ShapeSet );
1030     }
1031     else
1032     {
1033         XRectangle *aXRect;
1034         DWORD size;
1035         DWORD dwBufferSize = GetRegionData(hrgnWnd, 0, NULL);
1036         PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1037         if (!pRegionData) return;
1038
1039         GetRegionData(hrgnWnd, dwBufferSize, pRegionData);
1040         size = pRegionData->rdh.nCount;
1041         /* convert region's "Windows rectangles" to XRectangles */
1042         aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1043         if (aXRect)
1044         {
1045             XRectangle* pCurrRect = aXRect;
1046             RECT *pRect = (RECT*) pRegionData->Buffer;
1047             for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1048             {
1049                 pCurrRect->x      = pRect->left;
1050                 pCurrRect->y      = pRect->top;
1051                 pCurrRect->height = pRect->bottom - pRect->top;
1052                 pCurrRect->width  = pRect->right  - pRect->left;
1053
1054                 TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1055                       pRect - (RECT*) pRegionData->Buffer,
1056                       size,
1057                       pCurrRect->x,
1058                       pCurrRect->y,
1059                       pCurrRect->height,
1060                       pCurrRect->width);
1061             }
1062
1063             /* shape = non-rectangular windows (X11/extensions) */
1064             TSXShapeCombineRectangles( display, win, ShapeBounding, 
1065                                        0, 0, aXRect,
1066                                        pCurrRect - aXRect, ShapeSet, YXBanded );
1067             HeapFree(GetProcessHeap(), 0, aXRect );
1068         }
1069         HeapFree(GetProcessHeap(), 0, pRegionData);
1070     }
1071 #endif  /* HAVE_LIBXSHAPE */
1072 }