If window was not resized and not moved, repaint only itself excluding
[wine.git] / windows / x11drv / wnd.c
blobfecf53c07d0efbf1027d890803baee75932bcf37
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 "dc.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;
82 /***********************************************************************
83 * X11DRV_WND_GetXWindow
85 * Return the X window associated to a window.
87 Window X11DRV_WND_GetXWindow(WND *wndPtr)
89 return wndPtr && wndPtr->pDriverData ?
90 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
93 /***********************************************************************
94 * X11DRV_WND_FindXWindow
96 * Return the the first X window associated to a window chain.
98 Window X11DRV_WND_FindXWindow(WND *wndPtr)
100 while (wndPtr &&
101 !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window)
102 wndPtr = wndPtr->parent;
103 return wndPtr ?
104 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
107 /***********************************************************************
108 * X11DRV_WND_RegisterWindow
110 * Associate an X window to a HWND.
112 static void X11DRV_WND_RegisterWindow(WND *wndPtr)
114 TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
116 if (!winContext) winContext = TSXUniqueContext();
117 TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr),
118 winContext, (char *) wndPtr->hwndSelf );
121 /***********************************************************************
122 * X11DRV_WND_IsZeroSizeWnd
124 * Return TRUE if the window has a height or widht less or equal to 0
126 static BOOL X11DRV_WND_IsZeroSizeWnd(WND *wndPtr)
128 if ( (wndPtr->rectWindow.left >= wndPtr->rectWindow.right) ||
129 (wndPtr->rectWindow.top >= wndPtr->rectWindow.bottom) )
130 return TRUE;
131 else
132 return FALSE;
135 /**********************************************************************
136 * X11DRV_WND_Initialize
138 void X11DRV_WND_Initialize(WND *wndPtr)
140 X11DRV_WND_DATA *pWndDriverData =
141 (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
143 wndPtr->pDriverData = (void *) pWndDriverData;
145 pWndDriverData->window = 0;
148 /**********************************************************************
149 * X11DRV_WND_Finalize
151 void X11DRV_WND_Finalize(WND *wndPtr)
153 X11DRV_WND_DATA *pWndDriverData =
154 (X11DRV_WND_DATA *) wndPtr->pDriverData;
156 if (!wndPtr->pDriverData) {
157 ERR("Trying to destroy window again. Not good.\n");
158 return;
160 if(pWndDriverData->window)
162 ERR(
163 "WND destroyed without destroying "
164 "the associated X Window (%ld)\n",
165 pWndDriverData->window
168 HeapFree(SystemHeap, 0, wndPtr->pDriverData);
169 wndPtr->pDriverData = NULL;
172 /**********************************************************************
173 * X11DRV_WND_CreateDesktopWindow
175 BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode)
177 if (wmProtocols == None)
178 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
179 if (wmDeleteWindow == None)
180 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
181 if( dndProtocol == None )
182 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
183 if( dndSelection == None )
184 dndSelection = TSXInternAtom( display, "DndSelection" , False );
185 if( wmChangeState == None )
186 wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
187 if (kwmDockWindow == None)
188 kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
190 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = X11DRV_GetXRootWindow();
191 X11DRV_WND_RegisterWindow( wndPtr );
193 return TRUE;
196 /**********************************************************************
197 * X11DRV_WND_IconChanged
199 * hIcon or hIconSm has changed (or is being initialised for the
200 * first time). Complete the X11 driver-specific initialisation.
202 * This is not entirely correct, may need to create
203 * an icon window and set the pixmap as a background
205 static void X11DRV_WND_IconChanged(WND *wndPtr)
208 HICON16 hIcon = NC_IconForWindow(wndPtr);
210 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
211 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
213 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
214 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
216 if (!hIcon)
218 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap= 0;
219 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
221 else
223 HBITMAP hbmOrig;
224 RECT rcMask;
225 BITMAP bmMask;
226 ICONINFO ii;
227 HDC hDC;
229 GetIconInfo(hIcon, &ii);
231 X11DRV_CreateBitmap(ii.hbmMask);
232 X11DRV_CreateBitmap(ii.hbmColor);
234 GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
235 rcMask.top = 0;
236 rcMask.left = 0;
237 rcMask.right = bmMask.bmWidth;
238 rcMask.bottom = bmMask.bmHeight;
240 hDC = CreateCompatibleDC(0);
241 hbmOrig = SelectObject(hDC, ii.hbmMask);
242 InvertRect(hDC, &rcMask);
243 SelectObject(hDC, hbmOrig);
244 DeleteDC(hDC);
246 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = ii.hbmColor;
247 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= ii.hbmMask;
249 return;
252 static void X11DRV_WND_SetIconHints(WND *wndPtr, XWMHints *hints)
254 if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap)
256 hints->icon_pixmap
257 = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap);
258 hints->flags |= IconPixmapHint;
260 else
261 hints->flags &= ~IconPixmapHint;
263 if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask)
265 hints->icon_mask
266 = X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
267 hints->flags |= IconMaskHint;
269 else
270 hints->flags &= ~IconMaskHint;
273 /**********************************************************************
274 * X11DRV_WND_UpdateIconHints
276 * hIcon or hIconSm has changed (or is being initialised for the
277 * first time). Complete the X11 driver-specific initialisation
278 * and set the window hints.
280 * This is not entirely correct, may need to create
281 * an icon window and set the pixmap as a background
283 static void X11DRV_WND_UpdateIconHints(WND *wndPtr)
285 XWMHints* wm_hints;
287 X11DRV_WND_IconChanged(wndPtr);
289 wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
290 if (!wm_hints) wm_hints = TSXAllocWMHints();
291 if (wm_hints)
293 X11DRV_WND_SetIconHints(wndPtr, wm_hints);
294 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
295 TSXFree( wm_hints );
300 /**********************************************************************
301 * X11DRV_WND_CreateWindow
303 BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode)
305 /* Create the X window (only for top-level windows, and then only */
306 /* when there's no desktop window) */
308 if ((X11DRV_GetXRootWindow() == DefaultRootWindow(display))
309 && (wndPtr->parent->hwndSelf == GetDesktopWindow()))
311 Window wGroupLeader;
312 XWMHints* wm_hints;
313 XSetWindowAttributes win_attr;
315 /* Create "managed" windows only if a title bar or resizable */
316 /* frame is required. */
317 if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle)) {
318 win_attr.event_mask = ExposureMask | KeyPressMask |
319 KeyReleaseMask | PointerMotionMask |
320 ButtonPressMask | ButtonReleaseMask |
321 FocusChangeMask | StructureNotifyMask;
322 win_attr.override_redirect = FALSE;
323 wndPtr->flags |= WIN_MANAGED;
324 } else {
325 win_attr.event_mask = ExposureMask | KeyPressMask |
326 KeyReleaseMask | PointerMotionMask |
327 ButtonPressMask | ButtonReleaseMask |
328 FocusChangeMask;
329 win_attr.override_redirect = TRUE;
331 wndPtr->flags |= WIN_NATIVE;
333 win_attr.bit_gravity = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest;
334 win_attr.colormap = X11DRV_PALETTE_PaletteXColormap;
335 win_attr.backing_store = NotUseful;
336 win_attr.save_under = ((classPtr->style & CS_SAVEBITS) != 0);
337 win_attr.cursor = X11DRV_MOUSE_XCursor;
339 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
340 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask = 0;
341 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
343 /* Zero-size X11 window hack. X doesn't like them, and will crash */
344 /* with a BadValue unless we do something ugly like this. */
345 /* Zero size window won't be mapped */
346 if (cs->cx <= 0) cs->cx = 1;
347 if (cs->cy <= 0) cs->cy = 1;
350 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
351 TSXCreateWindow( display, X11DRV_GetXRootWindow(),
352 cs->x, cs->y, cs->cx, cs->cy,
353 0, CopyFromParent,
354 InputOutput, CopyFromParent,
355 CWEventMask | CWOverrideRedirect |
356 CWColormap | CWCursor | CWSaveUnder |
357 CWBackingStore | CWBitGravity,
358 &win_attr );
360 if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
361 return FALSE;
363 /* If we are the systray, we need to be managed to be noticed by KWM */
365 if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW)
366 X11DRV_WND_DockWindow(wndPtr);
368 if (wndPtr->flags & WIN_MANAGED)
370 XClassHint *class_hints = TSXAllocClassHint();
371 XSizeHints* size_hints = TSXAllocSizeHints();
373 if (class_hints)
375 class_hints->res_name = "wineManaged";
376 class_hints->res_class = "Wine";
377 TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
378 TSXFree (class_hints);
381 if (size_hints)
383 size_hints->win_gravity = StaticGravity;
384 size_hints->x = cs->x;
385 size_hints->y = cs->y;
386 size_hints->flags = PWinGravity|PPosition;
388 if (HAS_DLGFRAME(cs->style,cs->dwExStyle))
390 size_hints->min_width = size_hints->max_width = cs->cx;
391 size_hints->min_height = size_hints->max_height = cs->cy;
392 size_hints->flags |= PMinSize | PMaxSize;
395 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr),
396 size_hints, XA_WM_NORMAL_HINTS );
397 TSXFree(size_hints);
401 if (cs->hwndParent) /* Get window owner */
403 Window w;
404 WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
406 w = X11DRV_WND_FindXWindow( tmpWnd );
407 if (w != None)
409 TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
410 wGroupLeader = w;
412 WIN_ReleaseWndPtr(tmpWnd);
415 if ((wm_hints = TSXAllocWMHints()))
417 wm_hints->flags = InputHint | StateHint | WindowGroupHint;
418 wm_hints->input = True;
420 if( wndPtr->flags & WIN_MANAGED )
422 X11DRV_WND_IconChanged(wndPtr);
423 X11DRV_WND_SetIconHints(wndPtr, wm_hints);
425 wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE)
426 ? IconicState : NormalState;
428 else
429 wm_hints->initial_state = NormalState;
430 wm_hints->window_group = wGroupLeader;
432 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
433 TSXFree(wm_hints);
435 X11DRV_WND_RegisterWindow( wndPtr );
437 return TRUE;
440 /***********************************************************************
441 * X11DRV_WND_DestroyWindow
443 BOOL X11DRV_WND_DestroyWindow(WND *wndPtr)
445 Window w;
446 if ((w = X11DRV_WND_GetXWindow(wndPtr)))
448 XEvent xe;
449 TSXDeleteContext( display, w, winContext );
450 TSXDestroyWindow( display, w );
451 while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
453 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
454 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
456 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
457 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
459 if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
461 DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
462 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
466 return TRUE;
469 /*****************************************************************
470 * X11DRV_WND_SetParent
472 WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
474 WND *pDesktop = WIN_GetDesktop();
476 if( wndPtr && pWndParent && (wndPtr != pDesktop) )
478 WND* pWndPrev = wndPtr->parent;
480 if( pWndParent != pWndPrev )
482 if ( X11DRV_WND_GetXWindow(wndPtr) )
484 /* Toplevel window needs to be reparented. Used by Tk 8.0 */
486 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
487 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
490 WIN_UnlinkWindow(wndPtr->hwndSelf);
491 wndPtr->parent = pWndParent;
493 /* Create an X counterpart for reparented top-level windows
494 * when not in the desktop mode. */
496 if( pWndParent == pDesktop )
498 if( X11DRV_GetXRootWindow() == DefaultRootWindow(display) )
500 CREATESTRUCTA cs;
501 cs.lpCreateParams = NULL;
502 cs.hInstance = 0; /* not used in following call */
503 cs.hMenu = 0; /* not used in following call */
504 cs.hwndParent = pWndParent->hwndSelf;
505 cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
506 if (!cs.cy)
507 cs.cy = 1;
508 cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
509 if (!cs.cx)
510 cs.cx = 1;
511 cs.y = wndPtr->rectWindow.top;
512 cs.x = wndPtr->rectWindow.left;
513 cs.style = wndPtr->dwStyle;
514 cs.lpszName = 0; /* not used in following call */
515 cs.lpszClass = 0; /*not used in following call */
516 cs.dwExStyle = wndPtr->dwExStyle;
517 X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
518 &cs, FALSE);
521 else /* a child window */
523 if( !( wndPtr->dwStyle & WS_CHILD ) )
525 if( wndPtr->wIDmenu != 0)
527 DestroyMenu( (HMENU) wndPtr->wIDmenu );
528 wndPtr->wIDmenu = 0;
532 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
534 WIN_ReleaseDesktop();
535 return pWndPrev;
536 } /* failure */
537 WIN_ReleaseDesktop();
538 return 0;
541 /***********************************************************************
542 * X11DRV_WND_ForceWindowRaise
544 * Raise a window on top of the X stacking order, while preserving
545 * the correct Windows Z order.
547 void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
549 XWindowChanges winChanges;
550 WND *wndPrev,*pDesktop = WIN_GetDesktop();
552 if (X11DRV_WND_IsZeroSizeWnd(wndPtr))
554 WIN_ReleaseDesktop();
555 return;
558 if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) )
560 WIN_ReleaseDesktop();
561 return;
564 /* Raise all windows up to wndPtr according to their Z order.
565 * (it would be easier with sibling-related Below but it doesn't
566 * work very well with SGI mwm for instance)
568 winChanges.stack_mode = Above;
569 while (wndPtr)
571 if ( !X11DRV_WND_IsZeroSizeWnd(wndPtr) && X11DRV_WND_GetXWindow(wndPtr) )
572 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
573 CWStackMode, &winChanges );
575 wndPrev = pDesktop->child;
576 if (wndPrev == wndPtr) break;
577 while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
579 wndPtr = wndPrev;
581 WIN_ReleaseDesktop();
584 /***********************************************************************
585 * X11DRV_WND_FindDesktopXWindow [Internal]
587 * Find the actual X window which needs be restacked.
588 * Used by X11DRV_WND_SetWindowPos().
590 static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
592 if (!(wndPtr->flags & WIN_MANAGED))
593 return X11DRV_WND_GetXWindow(wndPtr);
594 else
596 Window window, root, parent, *children;
597 int nchildren;
598 window = X11DRV_WND_GetXWindow(wndPtr);
599 for (;;)
601 TSXQueryTree( display, window, &root, &parent,
602 &children, &nchildren );
603 TSXFree( children );
604 if (parent == root)
605 return window;
606 window = parent;
611 /***********************************************************************
612 * WINPOS_SetXWindowPos
614 * SetWindowPos() for an X window. Used by the real SetWindowPos().
616 void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos)
618 XWindowChanges winChanges;
619 int changeMask = 0;
620 BOOL isZeroSizeWnd = FALSE;
621 BOOL forceMapWindow = FALSE;
622 WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
623 if ( !winposPtr ) return;
625 /* find out if after this function we will end out with a zero-size window */
626 if (X11DRV_WND_IsZeroSizeWnd(winposPtr))
628 /* if current size is 0, and no resizing */
629 if (winpos->flags & SWP_NOSIZE)
630 isZeroSizeWnd = TRUE;
631 else if ((winpos->cx > 0) && (winpos->cy > 0))
633 /* if this function is setting a new size > 0 for the window, we
634 should map the window if WS_VISIBLE is set */
635 if ((winposPtr->dwStyle & WS_VISIBLE) && !(winpos->flags & SWP_HIDEWINDOW))
636 forceMapWindow = TRUE;
639 /* if resizing to 0 */
640 if ( !(winpos->flags & SWP_NOSIZE) && ((winpos->cx <= 0) || (winpos->cy <= 0)) )
641 isZeroSizeWnd = TRUE;
643 if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happen!!! */
645 if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
647 if(X11DRV_WND_GetXWindow(wndPtr))
648 TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
651 if(bChangePos)
653 if ( !(winpos->flags & SWP_NOSIZE))
655 winChanges.width = (winpos->cx > 0 ) ? winpos->cx : 1;
656 winChanges.height = (winpos->cy > 0 ) ? winpos->cy : 1;
657 changeMask |= CWWidth | CWHeight;
659 /* Tweak dialog window size hints */
661 if ((winposPtr->flags & WIN_MANAGED) &&
662 HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle))
664 XSizeHints *size_hints = TSXAllocSizeHints();
666 if (size_hints)
668 long supplied_return;
670 TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
671 &supplied_return, XA_WM_NORMAL_HINTS);
672 size_hints->min_width = size_hints->max_width = winpos->cx;
673 size_hints->min_height = size_hints->max_height = winpos->cy;
674 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
675 XA_WM_NORMAL_HINTS );
676 TSXFree(size_hints);
680 if (!(winpos->flags & SWP_NOMOVE))
682 winChanges.x = winpos->x;
683 winChanges.y = winpos->y;
684 changeMask |= CWX | CWY;
686 if (!(winpos->flags & SWP_NOZORDER) && !isZeroSizeWnd)
688 winChanges.stack_mode = Below;
689 changeMask |= CWStackMode;
691 if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
692 else if (winpos->hwndInsertAfter != HWND_BOTTOM)
694 WND* insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
695 Window stack[2];
697 /* If the window where we should do the insert is zero-sized (not mapped)
698 don't used this window since it will possibly crash the X server,
699 use the "non zero-sized" window above */
700 if (X11DRV_WND_IsZeroSizeWnd(insertPtr))
702 /* find the window on top of the zero sized window */
703 WND *pDesktop = WIN_GetDesktop();
704 WND *wndPrev = pDesktop->child;
705 WND *wndZeroSized = insertPtr;
707 while (1)
709 if (wndPrev == wndZeroSized)
710 break; /* zero-sized window is on top */
712 while (wndPrev && (wndPrev->next != wndZeroSized))
713 wndPrev = wndPrev->next;
715 /* check if the window found is not zero-sized */
716 if (X11DRV_WND_IsZeroSizeWnd(wndPrev))
718 wndZeroSized = wndPrev; /* restart the search */
719 wndPrev = pDesktop->child;
721 else
722 break; /* "above" window is found */
724 WIN_ReleaseDesktop();
726 if (wndPrev == wndZeroSized)
728 /* the zero-sized window is on top */
729 /* so set the window on top */
730 winChanges.stack_mode = Above;
732 else
734 stack[0] = X11DRV_WND_FindDesktopXWindow( wndPrev );
735 stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
737 TSXRestackWindows(display, stack, 2);
738 changeMask &= ~CWStackMode;
741 else /* Normal behavior, windows are not zero-sized */
743 stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
744 stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
746 TSXRestackWindows(display, stack, 2);
747 changeMask &= ~CWStackMode;
750 WIN_ReleaseWndPtr(insertPtr);
753 if (changeMask && X11DRV_WND_GetXWindow(winposPtr))
755 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
756 if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) )
757 X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget );
761 /* don't map the window if it's a zero size window */
762 if ( ((winpos->flags & SWP_SHOWWINDOW) && !isZeroSizeWnd) || forceMapWindow )
764 if(X11DRV_WND_GetXWindow(wndPtr))
765 TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
767 WIN_ReleaseWndPtr(winposPtr);
770 /*****************************************************************
771 * X11DRV_WND_SetText
773 void X11DRV_WND_SetText(WND *wndPtr, LPCWSTR text)
775 UINT count;
776 char *buffer;
777 static UINT text_cp = (UINT)-1;
778 Window win;
780 if (!(win = X11DRV_WND_GetXWindow(wndPtr))) return;
782 if(text_cp == (UINT)-1)
784 text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
785 TRACE("text_cp = %u\n", text_cp);
788 /* allocate new buffer for window text */
789 count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
790 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
792 ERR("Not enough memory for window text\n");
793 return;
795 WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
797 TSXStoreName( display, win, buffer );
798 TSXSetIconName( display, win, buffer );
799 HeapFree( GetProcessHeap(), 0, buffer );
802 /*****************************************************************
803 * X11DRV_WND_SetFocus
805 * Set the X focus.
806 * Explicit colormap management seems to work only with OLVWM.
808 void X11DRV_WND_SetFocus(WND *wndPtr)
810 HWND hwnd = wndPtr->hwndSelf;
811 XWindowAttributes win_attr;
812 Window win;
813 WND *w = wndPtr;
815 if (X11DRV_WND_IsZeroSizeWnd(wndPtr))
816 return;
818 /* Only mess with the X focus if there's */
819 /* no desktop window and if the window is not managed by the WM. */
820 if ((X11DRV_GetXRootWindow() != DefaultRootWindow(display))) return;
821 while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
822 w = w->parent;
823 if (!w) w = wndPtr;
824 if (w->flags & WIN_MANAGED) return;
826 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
828 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
829 TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
830 return;
833 /* Set X focus and install colormap */
835 if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
836 if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
837 (win_attr.map_state != IsViewable))
838 return; /* If window is not viewable, don't change anything */
840 TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
841 if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
842 TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
844 EVENT_Synchronize();
847 /*****************************************************************
848 * X11DRV_WND_PreSizeMove
850 void X11DRV_WND_PreSizeMove(WND *wndPtr)
852 if (!(wndPtr->dwStyle & WS_CHILD) && (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
853 TSXGrabServer( display );
856 /*****************************************************************
857 * X11DRV_WND_PostSizeMove
859 void X11DRV_WND_PostSizeMove(WND *wndPtr)
861 if (!(wndPtr->dwStyle & WS_CHILD) &&
862 (X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
863 TSXUngrabServer( display );
866 /*****************************************************************
867 * X11DRV_WND_SurfaceCopy
869 * Copies rect to (rect.left + dx, rect.top + dy).
871 void X11DRV_WND_SurfaceCopy(WND* wndPtr, HDC hdc, INT dx, INT dy,
872 const RECT *rect, BOOL bUpdate)
874 X11DRV_PDEVICE *physDev;
875 POINT dst, src;
876 DC *dcPtr = DC_GetDCPtr( hdc );
878 if (!dcPtr) return;
879 physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
880 dst.x = (src.x = dcPtr->w.DCOrgX + rect->left) + dx;
881 dst.y = (src.y = dcPtr->w.DCOrgY + rect->top) + dy;
883 if (bUpdate) /* handles non-Wine windows hanging over the copied area */
884 TSXSetGraphicsExposures( display, physDev->gc, True );
885 TSXSetFunction( display, physDev->gc, GXcopy );
886 TSXCopyArea( display, physDev->drawable, physDev->drawable,
887 physDev->gc, src.x, src.y,
888 rect->right - rect->left,
889 rect->bottom - rect->top,
890 dst.x, dst.y );
891 if (bUpdate)
892 TSXSetGraphicsExposures( display, physDev->gc, False );
893 GDI_ReleaseObj( hdc );
895 if (bUpdate) /* Make sure exposure events have been processed */
896 EVENT_Synchronize();
899 /***********************************************************************
900 * X11DRV_WND_SetDrawable
902 * Set the drawable, origin and dimensions for the DC associated to
903 * a given window.
905 void X11DRV_WND_SetDrawable(WND *wndPtr, HDC hdc, WORD flags, BOOL bSetClipOrigin)
907 DC *dc = DC_GetDCPtr( hdc );
908 X11DRV_PDEVICE *physDev;
909 INT dcOrgXCopy = 0, dcOrgYCopy = 0;
910 BOOL offsetClipRgn = FALSE;
912 if (!dc) return;
913 physDev = (X11DRV_PDEVICE *)dc->physDev;
914 if (!wndPtr) /* Get a DC for the whole screen */
916 dc->w.DCOrgX = 0;
917 dc->w.DCOrgY = 0;
918 physDev->drawable = X11DRV_GetXRootWindow();
919 TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
921 else
924 * This function change the coordinate system (DCOrgX,DCOrgY)
925 * values. When it moves the origin, other data like the current clipping
926 * region will not be moved to that new origin. In the case of DCs that are class
927 * or window DCs that clipping region might be a valid value from a previous use
928 * of the DC and changing the origin of the DC without moving the clip region
929 * results in a clip region that is not placed properly in the DC.
930 * This code will save the dc origin, let the SetDrawable
931 * modify the origin and reset the clipping. When the clipping is set,
932 * it is moved according to the new DC origin.
934 if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->w.hClipRgn > 0))
936 dcOrgXCopy = dc->w.DCOrgX;
937 dcOrgYCopy = dc->w.DCOrgY;
938 offsetClipRgn = TRUE;
941 if (flags & DCX_WINDOW)
943 dc->w.DCOrgX = wndPtr->rectWindow.left;
944 dc->w.DCOrgY = wndPtr->rectWindow.top;
946 else
948 dc->w.DCOrgX = wndPtr->rectClient.left;
949 dc->w.DCOrgY = wndPtr->rectClient.top;
951 while (!X11DRV_WND_GetXWindow(wndPtr))
953 wndPtr = wndPtr->parent;
954 dc->w.DCOrgX += wndPtr->rectClient.left;
955 dc->w.DCOrgY += wndPtr->rectClient.top;
957 dc->w.DCOrgX -= wndPtr->rectWindow.left;
958 dc->w.DCOrgY -= wndPtr->rectWindow.top;
960 /* reset the clip region, according to the new origin */
961 if ( offsetClipRgn )
963 OffsetRgn(dc->w.hClipRgn, dc->w.DCOrgX - dcOrgXCopy,dc->w.DCOrgY - dcOrgYCopy);
966 physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
968 #if 0
969 /* This is needed when we reuse a cached DC because
970 * SetDCState() called by ReleaseDC() screws up DC
971 * origins for child windows.
974 if( bSetClipOrigin )
975 TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY );
976 #endif
978 GDI_ReleaseObj( hdc );
981 /***********************************************************************
982 * X11DRV_SetWMHint
984 static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
986 XWMHints* wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
987 if (!wm_hints) wm_hints = TSXAllocWMHints();
988 if (wm_hints)
990 wm_hints->flags = hint;
991 switch( hint )
993 case InputHint:
994 wm_hints->input = val;
995 break;
997 case StateHint:
998 wm_hints->initial_state = val;
999 break;
1001 case IconPixmapHint:
1002 wm_hints->icon_pixmap = (Pixmap)val;
1003 break;
1005 case IconWindowHint:
1006 wm_hints->icon_window = (Window)val;
1007 break;
1010 TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
1011 TSXFree(wm_hints);
1012 return TRUE;
1014 return FALSE;
1018 /***********************************************************************
1019 * X11DRV_WND_SetHostAttr
1021 * This function returns TRUE if the attribute is supported and the
1022 * action was successful. Otherwise it should return FALSE and Wine will try
1023 * to get by without the functionality provided by the host window system.
1025 BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value)
1027 Window w;
1029 if( (w = X11DRV_WND_GetXWindow(wnd)) )
1031 XSetWindowAttributes win_attr;
1033 switch( ha )
1035 case HAK_ICONICSTATE: /* called when a window is minimized/restored */
1037 /* don't do anything if it'a zero size window */
1038 if (X11DRV_WND_IsZeroSizeWnd(wnd))
1039 return TRUE;
1041 if( (wnd->flags & WIN_MANAGED) )
1043 if( value )
1045 if( wnd->dwStyle & WS_VISIBLE )
1047 XClientMessageEvent ev;
1049 /* FIXME: set proper icon */
1051 ev.type = ClientMessage;
1052 ev.display = display;
1053 ev.message_type = wmChangeState;
1054 ev.format = 32;
1055 ev.data.l[0] = IconicState;
1056 ev.window = w;
1058 if( TSXSendEvent (display,
1059 RootWindow( display, XScreenNumberOfScreen(X11DRV_GetXScreen()) ),
1060 True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev))
1062 XEvent xe;
1063 TSXFlush (display);
1064 while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) );
1066 else
1067 break;
1069 else
1070 X11DRV_SetWMHint( display, wnd, StateHint, IconicState );
1072 else
1074 if( !(wnd->flags & WS_VISIBLE) )
1075 X11DRV_SetWMHint( display, wnd, StateHint, NormalState );
1076 else
1078 XEvent xe;
1079 TSXMapWindow(display, w );
1080 while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) );
1083 return TRUE;
1085 break;
1087 case HAK_BITGRAVITY: /* called when a window is resized */
1089 if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value )
1091 win_attr.bit_gravity = value;
1092 ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value;
1093 TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr );
1095 return TRUE;
1097 case HAK_ICONS: /* called when the icons change */
1098 if ( (wnd->flags & WIN_MANAGED) )
1099 X11DRV_WND_UpdateIconHints(wnd);
1100 return TRUE;
1102 case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */
1104 if( (wnd->flags & WIN_MANAGED) )
1105 return X11DRV_SetWMHint( display, wnd, InputHint, value );
1108 return FALSE;
1111 /***********************************************************************
1112 * X11DRV_WND_IsSelfClipping
1114 BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr)
1116 return X11DRV_WND_GetXWindow(wndPtr) != None;
1119 /***********************************************************************
1120 * X11DRV_WND_DockWindow
1122 * Set the X Property of the window that tells the windowmanager we really
1123 * want to be in the systray
1125 * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is
1126 * mapped.
1128 * all others: to be added ;)
1130 void X11DRV_WND_DockWindow(WND *wndPtr)
1132 int data = 1;
1133 Window win = X11DRV_WND_GetXWindow(wndPtr);
1134 if (kwmDockWindow == None)
1135 return; /* no KDE running */
1136 TSXChangeProperty(
1137 display,win,kwmDockWindow,kwmDockWindow,32,PropModeReplace,(char*)&data,1
1142 /***********************************************************************
1143 * X11DRV_WND_SetWindowRgn
1145 * Assign specified region to window (for non-rectangular windows)
1147 void X11DRV_WND_SetWindowRgn(WND *wndPtr, HRGN hrgnWnd)
1149 #ifdef HAVE_LIBXSHAPE
1150 Window win = X11DRV_WND_GetXWindow(wndPtr);
1152 if (!win) return;
1154 if (!hrgnWnd)
1156 TSXShapeCombineMask( display, win, ShapeBounding, 0, 0, None, ShapeSet );
1158 else
1160 XRectangle *aXRect;
1161 DWORD size;
1162 DWORD dwBufferSize = GetRegionData(hrgnWnd, 0, NULL);
1163 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1164 if (!pRegionData) return;
1166 GetRegionData(hrgnWnd, dwBufferSize, pRegionData);
1167 size = pRegionData->rdh.nCount;
1168 /* convert region's "Windows rectangles" to XRectangles */
1169 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1170 if (aXRect)
1172 XRectangle* pCurrRect = aXRect;
1173 RECT *pRect = (RECT*) pRegionData->Buffer;
1174 for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1176 pCurrRect->x = pRect->left;
1177 pCurrRect->y = pRect->top;
1178 pCurrRect->height = pRect->bottom - pRect->top;
1179 pCurrRect->width = pRect->right - pRect->left;
1181 TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1182 pRect - (RECT*) pRegionData->Buffer,
1183 size,
1184 pCurrRect->x,
1185 pCurrRect->y,
1186 pCurrRect->height,
1187 pCurrRect->width);
1190 /* shape = non-rectangular windows (X11/extensions) */
1191 TSXShapeCombineRectangles( display, win, ShapeBounding,
1192 0, 0, aXRect,
1193 pCurrRect - aXRect, ShapeSet, YXBanded );
1194 HeapFree(GetProcessHeap(), 0, aXRect );
1196 HeapFree(GetProcessHeap(), 0, pRegionData);
1198 #endif /* HAVE_LIBXSHAPE */