Since SetParent now hides/shows, explicitly invalidating DCs in the
[wine/testsucceed.git] / windows / x11drv / wnd.c
blobe880b1c156d758313b5e32bbcdb637f558106841
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 #ifndef X_DISPLAY_MISSING
13 #include <X11/Xatom.h>
14 #include "ts_xlib.h"
15 #include "ts_xutil.h"
17 #include <stdlib.h>
18 #include <string.h>
19 #include "color.h"
20 #include "debug.h"
21 #include "display.h"
22 #include "dce.h"
23 #include "options.h"
24 #include "message.h"
25 #include "heap.h"
26 #include "win.h"
27 #include "wintypes.h"
28 #include "class.h"
29 #include "x11drv.h"
31 /**********************************************************************/
33 extern Cursor X11DRV_MOUSE_XCursor; /* Current X cursor */
35 /**********************************************************************/
37 /* X context to associate a hwnd to an X window */
38 XContext winContext = 0;
40 Atom wmProtocols = None;
41 Atom wmDeleteWindow = None;
42 Atom dndProtocol = None;
43 Atom dndSelection = None;
45 /***********************************************************************
46 * X11DRV_WND_GetXWindow
48 * Return the X window associated to a window.
50 Window X11DRV_WND_GetXWindow(WND *wndPtr)
52 return wndPtr ?
53 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
56 /***********************************************************************
57 * X11DRV_WND_FindXWindow
59 * Return the the first X window associated to a window chain.
61 Window X11DRV_WND_FindXWindow(WND *wndPtr)
63 while (wndPtr &&
64 !((X11DRV_WND_DATA *) wndPtr->pDriverData)->window)
65 wndPtr = wndPtr->parent;
66 return wndPtr ?
67 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
70 /***********************************************************************
71 * X11DRV_WND_GetXScreen
73 * Return the X screen associated to the window.
75 Screen *X11DRV_WND_GetXScreen(WND *wndPtr)
77 while(wndPtr->parent) wndPtr = wndPtr->parent;
78 return X11DRV_DESKTOP_GetXScreen((struct tagDESKTOP *) wndPtr->wExtra);
81 /***********************************************************************
82 * X11DRV_WND_GetXRootWindow
84 * Return the X display associated to the window.
86 Window X11DRV_WND_GetXRootWindow(WND *wndPtr)
88 while(wndPtr->parent) wndPtr = wndPtr->parent;
89 return X11DRV_DESKTOP_GetXRootWindow((struct tagDESKTOP *) wndPtr->wExtra);
92 /***********************************************************************
93 * X11DRV_WND_RegisterWindow
95 * Associate an X window to a HWND.
97 static void X11DRV_WND_RegisterWindow(WND *wndPtr)
99 TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
101 if (!winContext) winContext = TSXUniqueContext();
102 TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr), winContext, (char *) wndPtr );
105 /**********************************************************************
106 * X11DRV_WND_Initialize
108 void X11DRV_WND_Initialize(WND *wndPtr)
110 X11DRV_WND_DATA *pWndDriverData =
111 (X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
113 wndPtr->pDriverData = (void *) pWndDriverData;
115 pWndDriverData->window = 0;
118 /**********************************************************************
119 * X11DRV_WND_Finalize
121 void X11DRV_WND_Finalize(WND *wndPtr)
123 X11DRV_WND_DATA *pWndDriverData =
124 (X11DRV_WND_DATA *) wndPtr->pDriverData;
126 if (!wndPtr->pDriverData) {
127 ERR(win,"Trying to destroy window again. Not good.\n");
128 return;
130 if(pWndDriverData->window)
132 ERR(win,
133 "WND destroyed without destroying "
134 "the associated X Window (%ld)\n",
135 pWndDriverData->window
138 HeapFree(SystemHeap, 0, wndPtr->pDriverData);
139 wndPtr->pDriverData = NULL;
142 /**********************************************************************
143 * X11DRV_WND_CreateDesktopWindow
145 BOOL32 X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL32 bUnicode)
147 if (wmProtocols == None)
148 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
149 if (wmDeleteWindow == None)
150 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
151 if( dndProtocol == None )
152 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
153 if( dndSelection == None )
154 dndSelection = TSXInternAtom( display, "DndSelection" , False );
156 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
157 X11DRV_WND_GetXRootWindow( wndPtr );
158 X11DRV_WND_RegisterWindow( wndPtr );
160 return TRUE;
163 /**********************************************************************
164 * X11DRV_WND_CreateWindow
166 BOOL32 X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCT32A *cs, BOOL32 bUnicode)
168 /* Create the X window (only for top-level windows, and then only */
169 /* when there's no desktop window) */
171 if (!(cs->style & WS_CHILD) &&
172 (X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
174 XSetWindowAttributes win_attr;
176 if (Options.managed && ((cs->style & (WS_DLGFRAME | WS_THICKFRAME)) ||
177 (cs->dwExStyle & WS_EX_DLGMODALFRAME)))
179 win_attr.event_mask = ExposureMask | KeyPressMask |
180 KeyReleaseMask | PointerMotionMask |
181 ButtonPressMask | ButtonReleaseMask |
182 FocusChangeMask | StructureNotifyMask;
183 win_attr.override_redirect = FALSE;
184 wndPtr->flags |= WIN_MANAGED;
186 else
188 win_attr.event_mask = ExposureMask | KeyPressMask |
189 KeyReleaseMask | PointerMotionMask |
190 ButtonPressMask | ButtonReleaseMask |
191 FocusChangeMask;
192 win_attr.override_redirect = TRUE;
194 win_attr.colormap = X11DRV_COLOR_GetColormap();
195 win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
196 win_attr.save_under = ((classPtr->style & CS_SAVEBITS) != 0);
197 win_attr.cursor = X11DRV_MOUSE_XCursor;
198 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
199 TSXCreateWindow( display,
200 X11DRV_WND_GetXRootWindow(wndPtr),
201 cs->x, cs->y, cs->cx, cs->cy,
202 0, CopyFromParent,
203 InputOutput, CopyFromParent,
204 CWEventMask | CWOverrideRedirect |
205 CWColormap | CWCursor | CWSaveUnder |
206 CWBackingStore, &win_attr );
208 if(!X11DRV_WND_GetXWindow(wndPtr))
209 return FALSE;
211 if (wndPtr->flags & WIN_MANAGED) {
212 XClassHint *class_hints = TSXAllocClassHint();
214 if (class_hints) {
215 class_hints->res_name = "wineManaged";
216 class_hints->res_class = "Wine";
217 TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
218 TSXFree (class_hints);
221 if (cs->dwExStyle & WS_EX_DLGMODALFRAME) {
222 XSizeHints* size_hints = TSXAllocSizeHints();
224 if (size_hints) {
225 size_hints->min_width = size_hints->max_width = cs->cx;
226 size_hints->min_height = size_hints->max_height = cs->cy;
227 size_hints->flags = (PSize | PMinSize | PMaxSize);
228 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), size_hints,
229 XA_WM_NORMAL_HINTS );
230 TSXFree(size_hints);
235 if (cs->hwndParent) /* Get window owner */
237 Window win = X11DRV_WND_FindXWindow( WIN_FindWndPtr( cs->hwndParent ) );
238 if (win) TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), win );
240 X11DRV_WND_RegisterWindow( wndPtr );
242 return TRUE;
245 /***********************************************************************
246 * X11DRV_WND_DestroyWindow
248 BOOL32 X11DRV_WND_DestroyWindow(WND *wndPtr)
250 if (X11DRV_WND_GetXWindow(wndPtr))
252 XEvent xe;
253 TSXDeleteContext( display, X11DRV_WND_GetXWindow(wndPtr), winContext );
254 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
255 while( TSXCheckWindowEvent(display, X11DRV_WND_GetXWindow(wndPtr), NoEventMask, &xe) );
256 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
259 return TRUE;
262 /*****************************************************************
263 * X11DRV_WND_SetParent
265 WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
267 if( wndPtr && pWndParent && (wndPtr != WIN_GetDesktop()) )
269 WND* pWndPrev = wndPtr->parent;
271 if( pWndParent != pWndPrev )
273 if ( X11DRV_WND_GetXWindow(wndPtr) )
275 /* Toplevel window needs to be reparented. Used by Tk 8.0 */
277 TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
278 ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
281 WIN_UnlinkWindow(wndPtr->hwndSelf);
282 wndPtr->parent = pWndParent;
284 /* Create an X counterpart for reparented top-level windows
285 * when not in the desktop mode. */
287 if( pWndParent == WIN_GetDesktop () )
289 wndPtr->dwStyle &= ~WS_CHILD;
290 wndPtr->wIDmenu = 0;
291 if( X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display) )
293 CREATESTRUCT32A cs;
294 cs.lpCreateParams = NULL;
295 cs.hInstance = 0; /* not used if following call */
296 cs.hMenu = 0; /* not used in following call */
297 cs.hwndParent = pWndParent->hwndSelf;
298 cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
299 cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
300 cs.y = wndPtr->rectWindow.top;
301 cs.x = wndPtr->rectWindow.left;
302 cs.style = wndPtr->dwStyle;
303 cs.lpszName = 0; /* not used in following call */
304 cs.lpszClass = 0; /*not used in following call */
305 cs.dwExStyle = wndPtr->dwExStyle;
306 X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
307 &cs, FALSE);
310 else /* a child window */
312 if( !( wndPtr->dwStyle & WS_CHILD ) )
314 wndPtr->dwStyle |= WS_CHILD;
315 if( wndPtr->wIDmenu != 0)
317 DestroyMenu32( (HMENU32) wndPtr->wIDmenu );
318 wndPtr->wIDmenu = 0;
322 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
324 return pWndPrev;
325 } /* failure */
326 return 0;
329 /***********************************************************************
330 * X11DRV_WND_ForceWindowRaise
332 * Raise a window on top of the X stacking order, while preserving
333 * the correct Windows Z order.
335 void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
337 XWindowChanges winChanges;
338 WND *wndPrev;
340 if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) )
341 return;
343 /* Raise all windows up to wndPtr according to their Z order.
344 * (it would be easier with sibling-related Below but it doesn't
345 * work very well with SGI mwm for instance)
347 winChanges.stack_mode = Above;
348 while (wndPtr)
350 if (X11DRV_WND_GetXWindow(wndPtr))
351 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
352 CWStackMode, &winChanges );
353 wndPrev = WIN_GetDesktop()->child;
354 if (wndPrev == wndPtr) break;
355 while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
356 wndPtr = wndPrev;
360 /***********************************************************************
361 * X11DRV_WND_FindDesktopXWindow [Internal]
363 * Find the actual X window which needs be restacked.
364 * Used by X11DRV_SetWindowPos().
366 static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
368 if (!(wndPtr->flags & WIN_MANAGED))
369 return X11DRV_WND_GetXWindow(wndPtr);
370 else
372 Window window, root, parent, *children;
373 int nchildren;
374 window = X11DRV_WND_GetXWindow(wndPtr);
375 for (;;)
377 TSXQueryTree( display, window, &root, &parent,
378 &children, &nchildren );
379 TSXFree( children );
380 if (parent == root)
381 return window;
382 window = parent;
387 /***********************************************************************
388 * WINPOS_SetXWindowPos
390 * SetWindowPos() for an X window. Used by the real SetWindowPos().
392 void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS32 *winpos, BOOL32 bSMC_SETXPOS)
394 XWindowChanges winChanges;
395 int changeMask = 0;
396 WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
398 if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happend!!! */
400 if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
402 if(X11DRV_WND_GetXWindow(wndPtr))
403 TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
406 if(bSMC_SETXPOS)
408 if ( !(winpos->flags & SWP_NOSIZE))
410 winChanges.width = winpos->cx;
411 winChanges.height = winpos->cy;
412 changeMask |= CWWidth | CWHeight;
414 /* Tweak dialog window size hints */
416 if ((winposPtr->flags & WIN_MANAGED) &&
417 (winposPtr->dwExStyle & WS_EX_DLGMODALFRAME))
419 XSizeHints *size_hints = TSXAllocSizeHints();
421 if (size_hints)
423 long supplied_return;
425 TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
426 &supplied_return, XA_WM_NORMAL_HINTS);
427 size_hints->min_width = size_hints->max_width = winpos->cx;
428 size_hints->min_height = size_hints->max_height = winpos->cy;
429 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
430 XA_WM_NORMAL_HINTS );
431 TSXFree(size_hints);
435 if (!(winpos->flags & SWP_NOMOVE))
437 winChanges.x = winpos->x;
438 winChanges.y = winpos->y;
439 changeMask |= CWX | CWY;
441 if (!(winpos->flags & SWP_NOZORDER))
443 winChanges.stack_mode = Below;
444 changeMask |= CWStackMode;
446 if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
447 else if (winpos->hwndInsertAfter != HWND_BOTTOM)
449 WND* insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
450 Window stack[2];
452 stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
453 stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
455 /* for stupid window managers (i.e. all of them) */
457 TSXRestackWindows(display, stack, 2);
458 changeMask &= ~CWStackMode;
461 if (changeMask)
463 TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
467 if ( winpos->flags & SWP_SHOWWINDOW )
469 if(X11DRV_WND_GetXWindow(wndPtr)) TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
473 /*****************************************************************
474 * X11DRV_WND_SetText
476 void X11DRV_WND_SetText(WND *wndPtr, LPCSTR text)
478 if (!X11DRV_WND_GetXWindow(wndPtr))
479 return;
481 TSXStoreName( display, X11DRV_WND_GetXWindow(wndPtr), text );
482 TSXSetIconName( display, X11DRV_WND_GetXWindow(wndPtr), text );
485 /*****************************************************************
486 * X11DRV_WND_SetFocus
488 * Set the X focus.
489 * Explicit colormap management seems to work only with OLVWM.
491 void X11DRV_WND_SetFocus(WND *wndPtr)
493 HWND32 hwnd = wndPtr->hwndSelf;
494 XWindowAttributes win_attr;
495 Window win;
497 /* Only mess with the X focus if there's */
498 /* no desktop window and no window manager. */
499 if ((X11DRV_WND_GetXRootWindow(wndPtr) != DefaultRootWindow(display))
500 || Options.managed) return;
502 if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
504 if (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE)
505 TSXUninstallColormap( display, X11DRV_COLOR_GetColormap() );
506 return;
509 /* Set X focus and install colormap */
511 if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
512 if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
513 (win_attr.map_state != IsViewable))
514 return; /* If window is not viewable, don't change anything */
516 TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
517 if (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE)
518 TSXInstallColormap( display, X11DRV_COLOR_GetColormap() );
520 EVENT_Synchronize();
523 /*****************************************************************
524 * X11DRV_WND_PreSizeMove
526 void X11DRV_WND_PreSizeMove(WND *wndPtr)
528 if (!(wndPtr->dwStyle & WS_CHILD) &&
529 (X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
530 TSXGrabServer( display );
533 /*****************************************************************
534 * X11DRV_WND_PostSizeMove
536 void X11DRV_WND_PostSizeMove(WND *wndPtr)
538 if (!(wndPtr->dwStyle & WS_CHILD) &&
539 (X11DRV_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
540 TSXUngrabServer( display );
544 /*****************************************************************
545 * X11DRV_WND_ScrollWindow
547 void X11DRV_WND_ScrollWindow(
548 WND *wndPtr, DC *dcPtr, INT32 dx, INT32 dy,
549 const RECT32 *clipRect, BOOL32 bUpdate)
551 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
552 POINT32 dst, src;
554 if( dx > 0 ) dst.x = (src.x = dcPtr->w.DCOrgX + clipRect->left) + dx;
555 else src.x = (dst.x = dcPtr->w.DCOrgX + clipRect->left) - dx;
557 if( dy > 0 ) dst.y = (src.y = dcPtr->w.DCOrgY + clipRect->top) + dy;
558 else src.y = (dst.y = dcPtr->w.DCOrgY + clipRect->top) - dy;
561 if ((clipRect->right - clipRect->left > abs(dx)) &&
562 (clipRect->bottom - clipRect->top > abs(dy)))
564 if (bUpdate) /* handles non-Wine windows hanging over the scrolled area */
565 TSXSetGraphicsExposures( display, physDev->gc, True );
566 TSXSetFunction( display, physDev->gc, GXcopy );
567 TSXCopyArea( display, physDev->drawable, physDev->drawable,
568 physDev->gc, src.x, src.y,
569 clipRect->right - clipRect->left - abs(dx),
570 clipRect->bottom - clipRect->top - abs(dy),
571 dst.x, dst.y );
572 if (bUpdate)
573 TSXSetGraphicsExposures( display, physDev->gc, False );
577 /***********************************************************************
578 * X11DRV_WND_SetDrawable
580 * Set the drawable, origin and dimensions for the DC associated to
581 * a given window.
583 void X11DRV_WND_SetDrawable(WND *wndPtr, DC *dc, WORD flags, BOOL32 bSetClipOrigin)
585 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
587 if (!wndPtr) /* Get a DC for the whole screen */
589 dc->w.DCOrgX = 0;
590 dc->w.DCOrgY = 0;
591 physDev->drawable = X11DRV_WND_GetXRootWindow(wndPtr);
592 TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
594 else
596 if (flags & DCX_WINDOW)
598 dc->w.DCOrgX = wndPtr->rectWindow.left;
599 dc->w.DCOrgY = wndPtr->rectWindow.top;
601 else
603 dc->w.DCOrgX = wndPtr->rectClient.left;
604 dc->w.DCOrgY = wndPtr->rectClient.top;
606 while (!X11DRV_WND_GetXWindow(wndPtr))
608 wndPtr = wndPtr->parent;
609 dc->w.DCOrgX += wndPtr->rectClient.left;
610 dc->w.DCOrgY += wndPtr->rectClient.top;
612 dc->w.DCOrgX -= wndPtr->rectWindow.left;
613 dc->w.DCOrgY -= wndPtr->rectWindow.top;
614 physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
616 #if 0
617 /* This is needed when we reuse a cached DC because
618 * SetDCState() called by ReleaseDC() screws up DC
619 * origins for child windows.
622 if( bSetClipOrigin )
623 TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY );
624 #endif
628 /***********************************************************************
629 * X11DRV_WND_IsSelfClipping
631 BOOL32 X11DRV_WND_IsSelfClipping(WND *wndPtr)
633 if( X11DRV_WND_GetXWindow(wndPtr) )
634 return TRUE; /* X itself will do the clipping */
636 return FALSE;
639 #endif /* !defined(X_DISPLAY_MISSING) */