Added the KDE 2 beta and final method of specifying systray windows.
[wine.git] / windows / x11drv / wnd.c
bloba0b1908d6610cfcbff6c3040d9da72102a3a4a29
1 /*
2 * X11 windows driver
4 * Copyright 1993, 1994, 1995, 1996 Alexandre Julliard
5 * 1993 David Metcalfe
6 * 1995, 1996 Alex Korobka
7 */
9 #include "config.h"
11 #include <X11/Xatom.h>
13 #include "ts_xlib.h"
14 #include "ts_xutil.h"
15 #include "ts_shape.h"
17 #include <stdlib.h>
18 #include <string.h>
20 #include "bitmap.h"
21 #include "debugtools.h"
22 #include "dce.h"
23 #include "gdi.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"
35 DEFAULT_DEBUG_CHANNEL(win);
37 /* Some useful macros */
38 #define HAS_DLGFRAME(style,exStyle) \
39 ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
41 /**********************************************************************/
43 extern Cursor X11DRV_MOUSE_XCursor; /* Current X cursor */
44 extern BOOL X11DRV_CreateBitmap( HBITMAP );
45 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
47 /**********************************************************************/
49 WND_DRIVER X11DRV_WND_Driver =
51 X11DRV_WND_Initialize,
52 X11DRV_WND_Finalize,
53 X11DRV_WND_CreateDesktopWindow,
54 X11DRV_WND_CreateWindow,
55 X11DRV_WND_DestroyWindow,
56 X11DRV_WND_SetParent,
57 X11DRV_WND_ForceWindowRaise,
58 X11DRV_WND_SetWindowPos,
59 X11DRV_WND_SetText,
60 X11DRV_WND_SetFocus,
61 X11DRV_WND_PreSizeMove,
62 X11DRV_WND_PostSizeMove,
63 X11DRV_WND_SurfaceCopy,
64 X11DRV_WND_SetDrawable,
65 X11DRV_WND_SetHostAttr,
66 X11DRV_WND_IsSelfClipping,
67 X11DRV_WND_SetWindowRgn
71 /* X context to associate a hwnd to an X window */
72 XContext winContext = 0;
74 Atom wmProtocols = None;
75 Atom wmDeleteWindow = None;
76 Atom dndProtocol = None;
77 Atom dndSelection = None;
78 Atom wmChangeState = None;
80 Atom kwmDockWindow = None;
81 Atom _net_kde_system_tray_window_for = None; /* KDE 2 Beta */
82 Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
84 /***********************************************************************
85 * X11DRV_WND_GetXWindow
87 * Return the X window associated to a window.
89 Window X11DRV_WND_GetXWindow(WND *wndPtr)
91 return wndPtr && wndPtr->pDriverData ?
92 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
95 /***********************************************************************
96 * X11DRV_WND_FindXWindow
98 * Return the the first X window associated to a window chain.
100 Window X11DRV_WND_FindXWindow(WND *wndPtr)
102 while (wndPtr &&
103 !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window)
104 wndPtr = wndPtr->parent;
105 return wndPtr ?
106 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
109 /***********************************************************************
110 * X11DRV_WND_RegisterWindow
112 * Associate an X window to a HWND.
114 static void X11DRV_WND_RegisterWindow(WND *wndPtr)
116 TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
118 if (!winContext) winContext = TSXUniqueContext();
119 TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr),
120 winContext, (char *) wndPtr->hwndSelf );
123 /***********************************************************************
124 * X11DRV_WND_IsZeroSizeWnd
126 * Return TRUE if the window has a height or widht less or equal to 0
128 static BOOL X11DRV_WND_IsZeroSizeWnd(WND *wndPtr)
130 if ( (wndPtr->rectWindow.left >= wndPtr->rectWindow.right) ||
131 (wndPtr->rectWindow.top >= wndPtr->rectWindow.bottom) )
132 return TRUE;
133 else
134 return FALSE;
137 /**********************************************************************
138 * X11DRV_WND_Initialize
140 void X11DRV_WND_Initialize(WND *wndPtr)
142 X11DRV_WND_DATA *pWndDriverData =
143 (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
145 wndPtr->pDriverData = (void *) pWndDriverData;
147 pWndDriverData->window = 0;
150 /**********************************************************************
151 * X11DRV_WND_Finalize
153 void X11DRV_WND_Finalize(WND *wndPtr)
155 X11DRV_WND_DATA *pWndDriverData =
156 (X11DRV_WND_DATA *) wndPtr->pDriverData;
158 if (!wndPtr->pDriverData) {
159 ERR("Trying to destroy window again. Not good.\n");
160 return;
162 if(pWndDriverData->window)
164 ERR(
165 "WND destroyed without destroying "
166 "the associated X Window (%ld)\n",
167 pWndDriverData->window
170 HeapFree(SystemHeap, 0, wndPtr->pDriverData);
171 wndPtr->pDriverData = NULL;
174 /**********************************************************************
175 * X11DRV_WND_CreateDesktopWindow
177 BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode)
179 if (wmProtocols == None)
180 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
181 if (wmDeleteWindow == None)
182 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
183 if( dndProtocol == None )
184 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
185 if( dndSelection == None )
186 dndSelection = TSXInternAtom( display, "DndSelection" , False );
187 if( wmChangeState == None )
188 wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
189 if (kwmDockWindow == None)
190 kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
191 if (_kde_net_wm_system_tray_window_for == None)
192 _kde_net_wm_system_tray_window_for = TSXInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
193 if (_net_kde_system_tray_window_for == None)
194 _net_kde_system_tray_window_for = TSXInternAtom( display, "_NET_KDE_SYSTEM_TRAY_WINDOW_FOR", False );
196 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = X11DRV_GetXRootWindow();
197 X11DRV_WND_RegisterWindow( wndPtr );
199 return TRUE;
202 /**********************************************************************
203 * X11DRV_WND_IconChanged
205 * hIcon or hIconSm has changed (or is being initialised for the
206 * first time). Complete the X11 driver-specific initialisation.
208 * This is not entirely correct, may need to create
209 * an icon window and set the pixmap as a background
211 static void X11DRV_WND_IconChanged(WND *wndPtr)
214 HICON16 hIcon = NC_IconForWindow(wndPtr);
216 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
217 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
219 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
220 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
222 if (!hIcon)
224 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap= 0;
225 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
227 else
229 HBITMAP hbmOrig;
230 RECT rcMask;
231 BITMAP bmMask;
232 ICONINFO ii;
233 HDC hDC;
235 GetIconInfo(hIcon, &ii);
237 X11DRV_CreateBitmap(ii.hbmMask);
238 X11DRV_CreateBitmap(ii.hbmColor);
240 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
241 rcMask.top = 0;
242 rcMask.left = 0;
243 rcMask.right = bmMask.bmWidth;
244 rcMask.bottom = bmMask.bmHeight;
246 hDC = CreateCompatibleDC(0);
247 hbmOrig = SelectObject(hDC, ii.hbmMask);
248 InvertRect(hDC, &rcMask);
249 SelectObject(hDC, hbmOrig);
250 DeleteDC(hDC);
252 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = ii.hbmColor;
253 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= ii.hbmMask;
255 return;
258 static void X11DRV_WND_SetIconHints(WND *wndPtr, XWMHints *hints)
260 if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap)
262 hints->icon_pixmap
263 = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap);
264 hints->flags |= IconPixmapHint;
266 else
267 hints->flags &= ~IconPixmapHint;
269 if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask)
271 hints->icon_mask
272 = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
273 hints->flags |= IconMaskHint;
275 else
276 hints->flags &= ~IconMaskHint;
279 /**********************************************************************
280 * X11DRV_WND_UpdateIconHints
282 * hIcon or hIconSm has changed (or is being initialised for the
283 * first time). Complete the X11 driver-specific initialisation
284 * and set the window hints.
286 * This is not entirely correct, may need to create
287 * an icon window and set the pixmap as a background
289 static void X11DRV_WND_UpdateIconHints(WND *wndPtr)
291 XWMHints* wm_hints;
293 X11DRV_WND_IconChanged(wndPtr);
295 wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
296 if (!wm_hints) wm_hints = TSXAllocWMHints();
297 if (wm_hints)
299 X11DRV_WND_SetIconHints(wndPtr, wm_hints);
300 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
301 TSXFree( wm_hints );
306 /**********************************************************************
307 * X11DRV_WND_CreateWindow
309 BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode)
311 /* Create the X window (only for top-level windows, and then only */
312 /* when there's no desktop window) */
314 if ((X11DRV_GetXRootWindow() == DefaultRootWindow(display))
315 && (wndPtr->parent->hwndSelf == GetDesktopWindow()))
317 Window wGroupLeader;
318 XWMHints* wm_hints;
319 XSetWindowAttributes win_attr;
321 /* Create "managed" windows only if a title bar or resizable */
322 /* frame is required. */
323 if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle)) {
324 win_attr.event_mask = ExposureMask | KeyPressMask |
325 KeyReleaseMask | PointerMotionMask |
326 ButtonPressMask | ButtonReleaseMask |
327 FocusChangeMask | StructureNotifyMask;
328 win_attr.override_redirect = FALSE;
329 wndPtr->dwExStyle |= WS_EX_MANAGED;
330 } else {
331 win_attr.event_mask = ExposureMask | KeyPressMask |
332 KeyReleaseMask | PointerMotionMask |
333 ButtonPressMask | ButtonReleaseMask |
334 FocusChangeMask;
335 win_attr.override_redirect = TRUE;
337 wndPtr->flags |= WIN_NATIVE;
339 win_attr.bit_gravity = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest;
340 win_attr.colormap = X11DRV_PALETTE_PaletteXColormap;
341 win_attr.backing_store = NotUseful;
342 win_attr.save_under = ((classPtr->style & CS_SAVEBITS) != 0);
343 win_attr.cursor = X11DRV_MOUSE_XCursor;
345 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
346 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask = 0;
347 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
349 /* Zero-size X11 window hack. X doesn't like them, and will crash */
350 /* with a BadValue unless we do something ugly like this. */
351 /* Zero size window won't be mapped */
352 if (cs->cx <= 0) cs->cx = 1;
353 if (cs->cy <= 0) cs->cy = 1;
356 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
357 TSXCreateWindow( display, X11DRV_GetXRootWindow(),
358 cs->x, cs->y, cs->cx, cs->cy,
359 0, CopyFromParent,
360 InputOutput, CopyFromParent,
361 CWEventMask | CWOverrideRedirect |
362 CWColormap | CWCursor | CWSaveUnder |
363 CWBackingStore | CWBitGravity,
364 &win_attr );
366 if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
367 return FALSE;
369 /* If we are the systray, we need to be managed to be noticed by KWM */
371 if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW)
372 X11DRV_WND_DockWindow(wndPtr);
374 if (wndPtr->dwExStyle & WS_EX_MANAGED)
376 XClassHint *class_hints = TSXAllocClassHint();
377 XSizeHints* size_hints = TSXAllocSizeHints();
379 if (class_hints)
381 class_hints->res_name = "wineManaged";
382 class_hints->res_class = "Wine";
383 TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
384 TSXFree (class_hints);
387 if (size_hints)
389 size_hints->win_gravity = StaticGravity;
390 size_hints->x = cs->x;
391 size_hints->y = cs->y;
392 size_hints->flags = PWinGravity|PPosition;
394 if (HAS_DLGFRAME(cs->style,cs->dwExStyle))
396 size_hints->min_width = size_hints->max_width = cs->cx;
397 size_hints->min_height = size_hints->max_height = cs->cy;
398 size_hints->flags |= PMinSize | PMaxSize;
401 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr),
402 size_hints, XA_WM_NORMAL_HINTS );
403 TSXFree(size_hints);
407 if (cs->hwndParent) /* Get window owner */
409 Window w;
410 WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
412 w = X11DRV_WND_FindXWindow( tmpWnd );
413 if (w != None)
415 TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
416 wGroupLeader = w;
418 WIN_ReleaseWndPtr(tmpWnd);
421 if ((wm_hints = TSXAllocWMHints()))
423 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
424 wm_hints->input = True;
426 if (wndPtr->dwExStyle & WS_EX_MANAGED)
428 X11DRV_WND_IconChanged(wndPtr);
429 X11DRV_WND_SetIconHints(wndPtr, wm_hints);
431 wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE)
432 ? IconicState : NormalState;
434 else
435 wm_hints->initial_state = NormalState;
436 wm_hints->window_group = wGroupLeader;
438 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
439 TSXFree(wm_hints);
441 X11DRV_WND_RegisterWindow( wndPtr );
443 return TRUE;
446 /***********************************************************************
447 * X11DRV_WND_DestroyWindow
449 BOOL X11DRV_WND_DestroyWindow(WND *wndPtr)
451 Window w;
452 if ((w = X11DRV_WND_GetXWindow(wndPtr)))
454 XEvent xe;
455 TSXDeleteContext( display, w, winContext );
456 TSXDestroyWindow( display, w );
457 while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
459 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
460 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
462 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
463 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
465 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
467 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
468 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
472 return TRUE;
475 /*****************************************************************
476 * X11DRV_WND_SetParent
478 WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
480 WND *pDesktop = WIN_GetDesktop();
482 if( wndPtr && pWndParent && (wndPtr != pDesktop) )
484 WND* pWndPrev = wndPtr->parent;
486 if( pWndParent != pWndPrev )
488 if ( X11DRV_WND_GetXWindow(wndPtr) )
490 /* Toplevel window needs to be reparented. Used by Tk 8.0 */
492 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
493 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
496 WIN_UnlinkWindow(wndPtr->hwndSelf);
497 wndPtr->parent = pWndParent;
499 /* Create an X counterpart for reparented top-level windows
500 * when not in the desktop mode. */
502 if( pWndParent == pDesktop )
504 if( X11DRV_GetXRootWindow() == DefaultRootWindow(display) )
506 CREATESTRUCTA cs;
507 cs.lpCreateParams = NULL;
508 cs.hInstance = 0; /* not used in following call */
509 cs.hMenu = 0; /* not used in following call */
510 cs.hwndParent = pWndParent->hwndSelf;
511 cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
512 if (!cs.cy)
513 cs.cy = 1;
514 cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
515 if (!cs.cx)
516 cs.cx = 1;
517 cs.y = wndPtr->rectWindow.top;
518 cs.x = wndPtr->rectWindow.left;
519 cs.style = wndPtr->dwStyle;
520 cs.lpszName = 0; /* not used in following call */
521 cs.lpszClass = 0; /*not used in following call */
522 cs.dwExStyle = wndPtr->dwExStyle;
523 X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
524 &cs, FALSE);
527 else /* a child window */
529 if( !( wndPtr->dwStyle & WS_CHILD ) )
531 if( wndPtr->wIDmenu != 0)
533 DestroyMenu( (HMENU) wndPtr->wIDmenu );
534 wndPtr->wIDmenu = 0;
538 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
540 WIN_ReleaseDesktop();
541 return pWndPrev;
542 } /* failure */
543 WIN_ReleaseDesktop();
544 return 0;
547 /***********************************************************************
548 * X11DRV_WND_ForceWindowRaise
550 * Raise a window on top of the X stacking order, while preserving
551 * the correct Windows Z order.
553 void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
555 XWindowChanges winChanges;
556 WND *wndPrev,*pDesktop = WIN_GetDesktop();
558 if (X11DRV_WND_IsZeroSizeWnd(wndPtr))
560 WIN_ReleaseDesktop();
561 return;
564 if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->dwExStyle & WS_EX_MANAGED) )
566 WIN_ReleaseDesktop();
567 return;
570 /* Raise all windows up to wndPtr according to their Z order.
571 * (it would be easier with sibling-related Below but it doesn't
572 * work very well with SGI mwm for instance)
574 winChanges.stack_mode = Above;
575 while (wndPtr)
577 if ( !X11DRV_WND_IsZeroSizeWnd(wndPtr) && X11DRV_WND_GetXWindow(wndPtr) )
578 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
579 CWStackMode, &winChanges );
581 wndPrev = pDesktop->child;
582 if (wndPrev == wndPtr) break;
583 while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
585 wndPtr = wndPrev;
587 WIN_ReleaseDesktop();
590 /***********************************************************************
591 * X11DRV_WND_FindDesktopXWindow [Internal]
593 * Find the actual X window which needs be restacked.
594 * Used by X11DRV_WND_SetWindowPos().
596 static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
598 if (!(wndPtr->dwExStyle & WS_EX_MANAGED))
599 return X11DRV_WND_GetXWindow(wndPtr);
600 else
602 Window window, root, parent, *children;
603 int nchildren;
604 window = X11DRV_WND_GetXWindow(wndPtr);
605 for (;;)
607 TSXQueryTree( display, window, &root, &parent,
608 &children, &nchildren );
609 TSXFree( children );
610 if (parent == root)
611 return window;
612 window = parent;
617 /***********************************************************************
618 * WINPOS_SetXWindowPos
620 * SetWindowPos() for an X window. Used by the real SetWindowPos().
622 void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos)
624 XWindowChanges winChanges;
625 int changeMask = 0;
626 BOOL isZeroSizeWnd = FALSE;
627 BOOL forceMapWindow = FALSE;
628 WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
629 if ( !winposPtr ) return;
631 /* find out if after this function we will end out with a zero-size window */
632 if (X11DRV_WND_IsZeroSizeWnd(winposPtr))
634 /* if current size is 0, and no resizing */
635 if (winpos->flags & SWP_NOSIZE)
636 isZeroSizeWnd = TRUE;
637 else if ((winpos->cx > 0) && (winpos->cy > 0))
639 /* if this function is setting a new size > 0 for the window, we
640 should map the window if WS_VISIBLE is set */
641 if ((winposPtr->dwStyle & WS_VISIBLE) && !(winpos->flags & SWP_HIDEWINDOW))
642 forceMapWindow = TRUE;
645 /* if resizing to 0 */
646 if ( !(winpos->flags & SWP_NOSIZE) && ((winpos->cx <= 0) || (winpos->cy <= 0)) )
647 isZeroSizeWnd = TRUE;
649 if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happen!!! */
651 if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
653 if(X11DRV_WND_GetXWindow(wndPtr))
654 TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
657 if(bChangePos)
659 if ( !(winpos->flags & SWP_NOSIZE))
661 winChanges.width = (winpos->cx > 0 ) ? winpos->cx : 1;
662 winChanges.height = (winpos->cy > 0 ) ? winpos->cy : 1;
663 changeMask |= CWWidth | CWHeight;
665 /* Tweak dialog window size hints */
667 if ((winposPtr->dwExStyle & WS_EX_MANAGED) &&
668 HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle))
670 XSizeHints *size_hints = TSXAllocSizeHints();
672 if (size_hints)
674 long supplied_return;
676 TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
677 &supplied_return, XA_WM_NORMAL_HINTS);
678 size_hints->min_width = size_hints->max_width = winpos->cx;
679 size_hints->min_height = size_hints->max_height = winpos->cy;
680 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
681 XA_WM_NORMAL_HINTS );
682 TSXFree(size_hints);
686 if (!(winpos->flags & SWP_NOMOVE))
688 winChanges.x = winpos->x;
689 winChanges.y = winpos->y;
690 changeMask |= CWX | CWY;
692 if (!(winpos->flags & SWP_NOZORDER) && !isZeroSizeWnd)
694 winChanges.stack_mode = Below;
695 changeMask |= CWStackMode;
697 if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
698 else if (winpos->hwndInsertAfter != HWND_BOTTOM)
700 WND* insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
701 Window stack[2];
703 /* If the window where we should do the insert is zero-sized (not mapped)
704 don't used this window since it will possibly crash the X server,
705 use the "non zero-sized" window above */
706 if (X11DRV_WND_IsZeroSizeWnd(insertPtr))
708 /* find the window on top of the zero sized window */
709 WND *pDesktop = WIN_GetDesktop();
710 WND *wndPrev = pDesktop->child;
711 WND *wndZeroSized = insertPtr;
713 while (1)
715 if (wndPrev == wndZeroSized)
716 break; /* zero-sized window is on top */
718 while (wndPrev && (wndPrev->next != wndZeroSized))
719 wndPrev = wndPrev->next;
721 /* check if the window found is not zero-sized */
722 if (X11DRV_WND_IsZeroSizeWnd(wndPrev))
724 wndZeroSized = wndPrev; /* restart the search */
725 wndPrev = pDesktop->child;
727 else
728 break; /* "above" window is found */
730 WIN_ReleaseDesktop();
732 if (wndPrev == wndZeroSized)
734 /* the zero-sized window is on top */
735 /* so set the window on top */
736 winChanges.stack_mode = Above;
738 else
740 stack[0] = X11DRV_WND_FindDesktopXWindow( wndPrev );
741 stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
743 TSXRestackWindows(display, stack, 2);
744 changeMask &= ~CWStackMode;
747 else /* Normal behavior, windows are not zero-sized */
749 stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
750 stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
752 TSXRestackWindows(display, stack, 2);
753 changeMask &= ~CWStackMode;
756 WIN_ReleaseWndPtr(insertPtr);
759 if (changeMask && X11DRV_WND_GetXWindow(winposPtr))
761 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
762 if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) )
763 X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget );
767 /* don't map the window if it's a zero size window */
768 if ( ((winpos->flags & SWP_SHOWWINDOW) && !isZeroSizeWnd) || forceMapWindow )
770 if(X11DRV_WND_GetXWindow(wndPtr))
771 TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
773 WIN_ReleaseWndPtr(winposPtr);
776 /*****************************************************************
777 * X11DRV_WND_SetText
779 void X11DRV_WND_SetText(WND *wndPtr, LPCWSTR text)
781 UINT count;
782 char *buffer;
783 static UINT text_cp = (UINT)-1;
784 Window win;
786 if (!(win = X11DRV_WND_GetXWindow(wndPtr))) return;
788 if(text_cp == (UINT)-1)
790 text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
791 TRACE("text_cp = %u\n", text_cp);
794 /* allocate new buffer for window text */
795 count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
796 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
798 ERR("Not enough memory for window text\n");
799 return;
801 WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
803 TSXStoreName( display, win, buffer );
804 TSXSetIconName( display, win, buffer );
805 HeapFree( GetProcessHeap(), 0, buffer );
808 /*****************************************************************
809 * X11DRV_WND_SetFocus
811 * Set the X focus.
812 * Explicit colormap management seems to work only with OLVWM.
814 void X11DRV_WND_SetFocus(WND *wndPtr)
816 HWND hwnd = wndPtr->hwndSelf;
817 XWindowAttributes win_attr;
818 Window win;
819 WND *w = wndPtr;
821 if (X11DRV_WND_IsZeroSizeWnd(wndPtr))
822 return;
824 /* Only mess with the X focus if there's */
825 /* no desktop window and if the window is not managed by the WM. */
826 if ((X11DRV_GetXRootWindow() != DefaultRootWindow(display))) return;
827 while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
828 w = w->parent;
829 if (!w) w = wndPtr;
830 if (w->dwExStyle & WS_EX_MANAGED) return;
832 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
834 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
835 TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
836 return;
839 /* Set X focus and install colormap */
841 if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
842 if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
843 (win_attr.map_state != IsViewable))
844 return; /* If window is not viewable, don't change anything */
846 TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
847 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
848 TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
850 EVENT_Synchronize();
853 /*****************************************************************
854 * X11DRV_WND_PreSizeMove
856 void X11DRV_WND_PreSizeMove(WND *wndPtr)
858 if (!(wndPtr->dwStyle & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
859 TSXGrabServer( display );
862 /*****************************************************************
863 * X11DRV_WND_PostSizeMove
865 void X11DRV_WND_PostSizeMove(WND *wndPtr)
867 if (!(wndPtr->dwStyle & WS_CHILD) &&
868 (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
869 TSXUngrabServer( display );
872 /*****************************************************************
873 * X11DRV_WND_SurfaceCopy
875 * Copies rect to (rect.left + dx, rect.top + dy).
877 void X11DRV_WND_SurfaceCopy(WND* wndPtr, HDC hdc, INT dx, INT dy,
878 const RECT *rect, BOOL bUpdate)
880 X11DRV_PDEVICE *physDev;
881 POINT dst, src;
882 DC *dcPtr = DC_GetDCPtr( hdc );
884 if (!dcPtr) return;
885 physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
886 dst.x = (src.x = dcPtr->DCOrgX + rect->left) + dx;
887 dst.y = (src.y = dcPtr->DCOrgY + rect->top) + dy;
889 if (bUpdate) /* handles non-Wine windows hanging over the copied area */
890 TSXSetGraphicsExposures( display, physDev->gc, True );
891 TSXSetFunction( display, physDev->gc, GXcopy );
892 TSXCopyArea( display, physDev->drawable, physDev->drawable,
893 physDev->gc, src.x, src.y,
894 rect->right - rect->left,
895 rect->bottom - rect->top,
896 dst.x, dst.y );
897 if (bUpdate)
898 TSXSetGraphicsExposures( display, physDev->gc, False );
899 GDI_ReleaseObj( hdc );
901 if (bUpdate) /* Make sure exposure events have been processed */
902 EVENT_Synchronize();
905 /***********************************************************************
906 * X11DRV_WND_SetDrawable
908 * Set the drawable, origin and dimensions for the DC associated to
909 * a given window.
911 void X11DRV_WND_SetDrawable(WND *wndPtr, HDC hdc, WORD flags, BOOL bSetClipOrigin)
913 DC *dc = DC_GetDCPtr( hdc );
914 X11DRV_PDEVICE *physDev;
915 INT dcOrgXCopy = 0, dcOrgYCopy = 0;
916 BOOL offsetClipRgn = FALSE;
918 if (!dc) return;
919 physDev = (X11DRV_PDEVICE *)dc->physDev;
920 if (!wndPtr) /* Get a DC for the whole screen */
922 dc->DCOrgX = 0;
923 dc->DCOrgY = 0;
924 physDev->drawable = X11DRV_GetXRootWindow();
925 TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
927 else
930 * This function change the coordinate system (DCOrgX,DCOrgY)
931 * values. When it moves the origin, other data like the current clipping
932 * region will not be moved to that new origin. In the case of DCs that are class
933 * or window DCs that clipping region might be a valid value from a previous use
934 * of the DC and changing the origin of the DC without moving the clip region
935 * results in a clip region that is not placed properly in the DC.
936 * This code will save the dc origin, let the SetDrawable
937 * modify the origin and reset the clipping. When the clipping is set,
938 * it is moved according to the new DC origin.
940 if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->hClipRgn > 0))
942 dcOrgXCopy = dc->DCOrgX;
943 dcOrgYCopy = dc->DCOrgY;
944 offsetClipRgn = TRUE;
947 if (flags & DCX_WINDOW)
949 dc->DCOrgX = wndPtr->rectWindow.left;
950 dc->DCOrgY = wndPtr->rectWindow.top;
952 else
954 dc->DCOrgX = wndPtr->rectClient.left;
955 dc->DCOrgY = wndPtr->rectClient.top;
957 while (!X11DRV_WND_GetXWindow(wndPtr))
959 wndPtr = wndPtr->parent;
960 dc->DCOrgX += wndPtr->rectClient.left;
961 dc->DCOrgY += wndPtr->rectClient.top;
963 dc->DCOrgX -= wndPtr->rectWindow.left;
964 dc->DCOrgY -= wndPtr->rectWindow.top;
966 /* reset the clip region, according to the new origin */
967 if ( offsetClipRgn )
969 OffsetRgn(dc->hClipRgn, dc->DCOrgX - dcOrgXCopy,dc->DCOrgY - dcOrgYCopy);
972 physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
974 #if 0
975 /* This is needed when we reuse a cached DC because
976 * SetDCState() called by ReleaseDC() screws up DC
977 * origins for child windows.
980 if( bSetClipOrigin )
981 TSXSetClipOrigin( display, physDev->gc, dc->DCOrgX, dc->DCOrgY );
982 #endif
984 GDI_ReleaseObj( hdc );
987 /***********************************************************************
988 * X11DRV_SetWMHint
990 static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
992 XWMHints* wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
993 if (!wm_hints) wm_hints = TSXAllocWMHints();
994 if (wm_hints)
996 wm_hints->flags = hint;
997 switch( hint )
999 case InputHint:
1000 wm_hints->input = val;
1001 break;
1003 case StateHint:
1004 wm_hints->initial_state = val;
1005 break;
1007 case IconPixmapHint:
1008 wm_hints->icon_pixmap = (Pixmap)val;
1009 break;
1011 case IconWindowHint:
1012 wm_hints->icon_window = (Window)val;
1013 break;
1016 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
1017 TSXFree(wm_hints);
1018 return TRUE;
1020 return FALSE;
1024 /***********************************************************************
1025 * X11DRV_WND_SetHostAttr
1027 * This function returns TRUE if the attribute is supported and the
1028 * action was successful. Otherwise it should return FALSE and Wine will try
1029 * to get by without the functionality provided by the host window system.
1031 BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value)
1033 Window w;
1035 if( (w = X11DRV_WND_GetXWindow(wnd)) )
1037 XSetWindowAttributes win_attr;
1039 switch( ha )
1041 case HAK_ICONICSTATE: /* called when a window is minimized/restored */
1043 /* don't do anything if it'a zero size window */
1044 if (X11DRV_WND_IsZeroSizeWnd(wnd))
1045 return TRUE;
1047 if( (wnd->dwExStyle & WS_EX_MANAGED) )
1049 if( value )
1051 if( wnd->dwStyle & WS_VISIBLE )
1053 XClientMessageEvent ev;
1055 /* FIXME: set proper icon */
1057 ev.type = ClientMessage;
1058 ev.display = display;
1059 ev.message_type = wmChangeState;
1060 ev.format = 32;
1061 ev.data.l[0] = IconicState;
1062 ev.window = w;
1064 if( TSXSendEvent (display,
1065 RootWindow( display, XScreenNumberOfScreen(X11DRV_GetXScreen()) ),
1066 True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev))
1068 XEvent xe;
1069 TSXFlush (display);
1070 while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) );
1072 else
1073 break;
1075 else
1076 X11DRV_SetWMHint( display, wnd, StateHint, IconicState );
1078 else
1080 if( !(wnd->flags & WS_VISIBLE) )
1081 X11DRV_SetWMHint( display, wnd, StateHint, NormalState );
1082 else
1084 XEvent xe;
1085 TSXMapWindow(display, w );
1086 while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) );
1089 return TRUE;
1091 break;
1093 case HAK_BITGRAVITY: /* called when a window is resized */
1095 if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value )
1097 win_attr.bit_gravity = value;
1098 ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value;
1099 TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr );
1101 return TRUE;
1103 case HAK_ICONS: /* called when the icons change */
1104 if ( (wnd->dwExStyle & WS_EX_MANAGED) )
1105 X11DRV_WND_UpdateIconHints(wnd);
1106 return TRUE;
1108 case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */
1110 if( (wnd->dwExStyle & WS_EX_MANAGED) )
1111 return X11DRV_SetWMHint( display, wnd, InputHint, value );
1114 return FALSE;
1117 /***********************************************************************
1118 * X11DRV_WND_IsSelfClipping
1120 BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr)
1122 return X11DRV_WND_GetXWindow(wndPtr) != None;
1125 /***********************************************************************
1126 * X11DRV_WND_DockWindow
1128 * Set the X Property of the window that tells the windowmanager we really
1129 * want to be in the systray
1131 * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is
1132 * mapped.
1134 * all others: to be added ;)
1136 void X11DRV_WND_DockWindow(WND *wndPtr)
1138 int data = 1;
1139 Window win = X11DRV_WND_GetXWindow(wndPtr);
1140 if (kwmDockWindow != None) {
1141 TSXChangeProperty(
1142 display,win,kwmDockWindow,kwmDockWindow,32,PropModeReplace,(char*)&data,1
1145 if (_kde_net_wm_system_tray_window_for != None) {
1146 TSXChangeProperty(
1147 display,
1148 win,
1149 _kde_net_wm_system_tray_window_for,
1150 XA_WINDOW,
1152 PropModeReplace,
1153 (char*)&win,
1157 if (_net_kde_system_tray_window_for != None) {
1158 TSXChangeProperty(
1159 display,
1160 win,
1161 _net_kde_system_tray_window_for,
1162 XA_WINDOW,
1164 PropModeReplace,
1165 (char*)&win,
1173 /***********************************************************************
1174 * X11DRV_WND_SetWindowRgn
1176 * Assign specified region to window (for non-rectangular windows)
1178 void X11DRV_WND_SetWindowRgn(WND *wndPtr, HRGN hrgnWnd)
1180 #ifdef HAVE_LIBXSHAPE
1181 Window win = X11DRV_WND_GetXWindow(wndPtr);
1183 if (!win) return;
1185 if (!hrgnWnd)
1187 TSXShapeCombineMask( display, win, ShapeBounding, 0, 0, None, ShapeSet );
1189 else
1191 XRectangle *aXRect;
1192 DWORD size;
1193 DWORD dwBufferSize = GetRegionData(hrgnWnd, 0, NULL);
1194 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1195 if (!pRegionData) return;
1197 GetRegionData(hrgnWnd, dwBufferSize, pRegionData);
1198 size = pRegionData->rdh.nCount;
1199 /* convert region's "Windows rectangles" to XRectangles */
1200 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1201 if (aXRect)
1203 XRectangle* pCurrRect = aXRect;
1204 RECT *pRect = (RECT*) pRegionData->Buffer;
1205 for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1207 pCurrRect->x = pRect->left;
1208 pCurrRect->y = pRect->top;
1209 pCurrRect->height = pRect->bottom - pRect->top;
1210 pCurrRect->width = pRect->right - pRect->left;
1212 TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1213 pRect - (RECT*) pRegionData->Buffer,
1214 size,
1215 pCurrRect->x,
1216 pCurrRect->y,
1217 pCurrRect->height,
1218 pCurrRect->width);
1221 /* shape = non-rectangular windows (X11/extensions) */
1222 TSXShapeCombineRectangles( display, win, ShapeBounding,
1223 0, 0, aXRect,
1224 pCurrRect - aXRect, ShapeSet, YXBanded );
1225 HeapFree(GetProcessHeap(), 0, aXRect );
1227 HeapFree(GetProcessHeap(), 0, pRegionData);
1229 #endif /* HAVE_LIBXSHAPE */