wine-wine/windows/x11drv/wnd.c

911 lines
27 KiB
C

/*
* X11 windows driver
*
* Copyright 1993, 1994, 1995, 1996 Alexandre Julliard
* 1993 David Metcalfe
* 1995, 1996 Alex Korobka
*/
#include "config.h"
#ifndef X_DISPLAY_MISSING
#include <X11/Xatom.h>
#include "ts_xlib.h"
#include "ts_xutil.h"
#include <stdlib.h>
#include <string.h>
#include "bitmap.h"
#include "color.h"
#include "debugtools.h"
#include "display.h"
#include "dce.h"
#include "options.h"
#include "message.h"
#include "heap.h"
#include "win.h"
#include "windef.h"
#include "class.h"
#include "x11drv.h"
#include "wine/winuser16.h"
DEFAULT_DEBUG_CHANNEL(win)
/* Some useful macros */
#define HAS_DLGFRAME(style,exStyle) \
((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
/**********************************************************************/
extern Cursor X11DRV_MOUSE_XCursor; /* Current X cursor */
extern BOOL X11DRV_CreateBitmap( HBITMAP );
extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
/**********************************************************************/
/* X context to associate a hwnd to an X window */
XContext winContext = 0;
Atom wmProtocols = None;
Atom wmDeleteWindow = None;
Atom dndProtocol = None;
Atom dndSelection = None;
Atom wmChangeState = None;
Atom kwmDockWindow = None;
/***********************************************************************
* X11DRV_WND_GetXWindow
*
* Return the X window associated to a window.
*/
Window X11DRV_WND_GetXWindow(WND *wndPtr)
{
return wndPtr && wndPtr->pDriverData ?
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
}
/***********************************************************************
* X11DRV_WND_FindXWindow
*
* Return the the first X window associated to a window chain.
*/
Window X11DRV_WND_FindXWindow(WND *wndPtr)
{
while (wndPtr &&
!((X11DRV_WND_DATA *) wndPtr->pDriverData)->window)
wndPtr = wndPtr->parent;
return wndPtr ?
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window : 0;
}
/***********************************************************************
* X11DRV_WND_GetXScreen
*
* Return the X screen associated to the window.
*/
Screen *X11DRV_WND_GetXScreen(WND *wndPtr)
{
while(wndPtr->parent) wndPtr = wndPtr->parent;
return X11DRV_DESKTOP_GetXScreen((struct tagDESKTOP *) wndPtr->wExtra);
}
/***********************************************************************
* X11DRV_WND_GetXRootWindow
*
* Return the X display associated to the window.
*/
Window X11DRV_WND_GetXRootWindow(WND *wndPtr)
{
while(wndPtr->parent) wndPtr = wndPtr->parent;
return X11DRV_DESKTOP_GetXRootWindow((struct tagDESKTOP *) wndPtr->wExtra);
}
/***********************************************************************
* X11DRV_WND_RegisterWindow
*
* Associate an X window to a HWND.
*/
static void X11DRV_WND_RegisterWindow(WND *wndPtr)
{
TSXSetWMProtocols( display, X11DRV_WND_GetXWindow(wndPtr), &wmDeleteWindow, 1 );
if (!winContext) winContext = TSXUniqueContext();
TSXSaveContext( display, X11DRV_WND_GetXWindow(wndPtr),
winContext, (char *) wndPtr->hwndSelf );
}
/**********************************************************************
* X11DRV_WND_Initialize
*/
void X11DRV_WND_Initialize(WND *wndPtr)
{
X11DRV_WND_DATA *pWndDriverData =
(X11DRV_WND_DATA *) HeapAlloc(SystemHeap, 0, sizeof(X11DRV_WND_DATA));
wndPtr->pDriverData = (void *) pWndDriverData;
pWndDriverData->window = 0;
}
/**********************************************************************
* X11DRV_WND_Finalize
*/
void X11DRV_WND_Finalize(WND *wndPtr)
{
X11DRV_WND_DATA *pWndDriverData =
(X11DRV_WND_DATA *) wndPtr->pDriverData;
if (!wndPtr->pDriverData) {
ERR("Trying to destroy window again. Not good.\n");
return;
}
if(pWndDriverData->window)
{
ERR(
"WND destroyed without destroying "
"the associated X Window (%ld)\n",
pWndDriverData->window
);
}
HeapFree(SystemHeap, 0, wndPtr->pDriverData);
wndPtr->pDriverData = NULL;
}
/**********************************************************************
* X11DRV_WND_CreateDesktopWindow
*/
BOOL X11DRV_WND_CreateDesktopWindow(WND *wndPtr, CLASS *classPtr, BOOL bUnicode)
{
if (wmProtocols == None)
wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
if (wmDeleteWindow == None)
wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
if( dndProtocol == None )
dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
if( dndSelection == None )
dndSelection = TSXInternAtom( display, "DndSelection" , False );
if( wmChangeState == None )
wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
if (kwmDockWindow == None)
kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
X11DRV_WND_GetXRootWindow( wndPtr );
X11DRV_WND_RegisterWindow( wndPtr );
return TRUE;
}
/**********************************************************************
* X11DRV_WND_CreateWindow
*/
BOOL X11DRV_WND_CreateWindow(WND *wndPtr, CLASS *classPtr, CREATESTRUCTA *cs, BOOL bUnicode)
{
/* Create the X window (only for top-level windows, and then only */
/* when there's no desktop window) */
if (!(cs->style & WS_CHILD) &&
(X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
{
Window wGroupLeader;
XWMHints* wm_hints;
XSetWindowAttributes win_attr;
/* Create "managed" windows only if a title bar or resizable */
/* frame is required. */
if (WIN_WindowNeedsWMBorder(cs->style, cs->dwExStyle)) {
win_attr.event_mask = ExposureMask | KeyPressMask |
KeyReleaseMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask |
FocusChangeMask | StructureNotifyMask;
win_attr.override_redirect = FALSE;
wndPtr->flags |= WIN_MANAGED;
} else {
win_attr.event_mask = ExposureMask | KeyPressMask |
KeyReleaseMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask |
FocusChangeMask;
win_attr.override_redirect = TRUE;
}
wndPtr->flags |= WIN_NATIVE;
win_attr.bit_gravity = (classPtr->style & (CS_VREDRAW | CS_HREDRAW)) ? BGForget : BGNorthWest;
win_attr.colormap = X11DRV_PALETTE_PaletteXColormap;
win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
win_attr.save_under = ((classPtr->style & CS_SAVEBITS) != 0);
win_attr.cursor = X11DRV_MOUSE_XCursor;
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
TSXCreateWindow( display,
X11DRV_WND_GetXRootWindow(wndPtr),
cs->x, cs->y, cs->cx, cs->cy,
0, CopyFromParent,
InputOutput, CopyFromParent,
CWEventMask | CWOverrideRedirect |
CWColormap | CWCursor | CWSaveUnder |
CWBackingStore | CWBitGravity,
&win_attr );
if(!(wGroupLeader = X11DRV_WND_GetXWindow(wndPtr)))
return FALSE;
/* If we are the systray, we need to be managed to be noticed by KWM */
if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW)
X11DRV_WND_DockWindow(wndPtr);
if (wndPtr->flags & WIN_MANAGED)
{
XClassHint *class_hints = TSXAllocClassHint();
XSizeHints* size_hints = TSXAllocSizeHints();
if (class_hints)
{
class_hints->res_name = "wineManaged";
class_hints->res_class = "Wine";
TSXSetClassHint( display, ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window, class_hints );
TSXFree (class_hints);
}
if (size_hints)
{
size_hints->win_gravity = StaticGravity;
size_hints->flags = PWinGravity;
if (HAS_DLGFRAME(cs->style,cs->dwExStyle))
{
size_hints->min_width = size_hints->max_width = cs->cx;
size_hints->min_height = size_hints->max_height = cs->cy;
size_hints->flags |= PMinSize | PMaxSize;
}
TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr),
size_hints, XA_WM_NORMAL_HINTS );
TSXFree(size_hints);
}
}
if (cs->hwndParent) /* Get window owner */
{
Window w;
WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
w = X11DRV_WND_FindXWindow( tmpWnd );
if (w != None)
{
TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
wGroupLeader = w;
}
WIN_ReleaseWndPtr(tmpWnd);
}
wm_hints = TSXAllocWMHints();
{
wm_hints->flags = InputHint | StateHint | WindowGroupHint;
wm_hints->input = True;
if( wndPtr->flags & WIN_MANAGED )
{
if( wndPtr->class->hIcon )
{
CURSORICONINFO *ptr;
if( (ptr = (CURSORICONINFO *)GlobalLock16( wndPtr->class->hIcon )) )
{
/* This is not entirely correct, may need to create
* an icon window and set the pixmap as a background */
HBITMAP hBitmap = CreateBitmap( ptr->nWidth, ptr->nHeight,
ptr->bPlanes, ptr->bBitsPerPixel, (char *)(ptr + 1) +
ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
if( hBitmap )
{
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = hBitmap;
X11DRV_CreateBitmap( hBitmap );
wm_hints->flags |= IconPixmapHint;
wm_hints->icon_pixmap = X11DRV_BITMAP_Pixmap( hBitmap );
}
}
}
wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE)
? IconicState : NormalState;
}
else
wm_hints->initial_state = NormalState;
wm_hints->window_group = wGroupLeader;
TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
TSXFree(wm_hints);
}
X11DRV_WND_RegisterWindow( wndPtr );
}
return TRUE;
}
/***********************************************************************
* X11DRV_WND_DestroyWindow
*/
BOOL X11DRV_WND_DestroyWindow(WND *wndPtr)
{
Window w;
if ((w = X11DRV_WND_GetXWindow(wndPtr)))
{
XEvent xe;
TSXDeleteContext( display, w, winContext );
TSXDestroyWindow( display, w );
while( TSXCheckWindowEvent(display, w, NoEventMask, &xe) );
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
{
DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = 0;
}
}
return TRUE;
}
/*****************************************************************
* X11DRV_WND_SetParent
*/
WND *X11DRV_WND_SetParent(WND *wndPtr, WND *pWndParent)
{
WND *pDesktop = WIN_GetDesktop();
if( wndPtr && pWndParent && (wndPtr != pDesktop) )
{
WND* pWndPrev = wndPtr->parent;
if( pWndParent != pWndPrev )
{
if ( X11DRV_WND_GetXWindow(wndPtr) )
{
/* Toplevel window needs to be reparented. Used by Tk 8.0 */
TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
}
WIN_UnlinkWindow(wndPtr->hwndSelf);
wndPtr->parent = pWndParent;
/* Create an X counterpart for reparented top-level windows
* when not in the desktop mode. */
if( pWndParent == pDesktop )
{
wndPtr->dwStyle &= ~WS_CHILD;
wndPtr->wIDmenu = 0;
if( X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display) )
{
CREATESTRUCTA cs;
cs.lpCreateParams = NULL;
cs.hInstance = 0; /* not used in following call */
cs.hMenu = 0; /* not used in following call */
cs.hwndParent = pWndParent->hwndSelf;
cs.cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
if (!cs.cy)
cs.cy = 1;
cs.cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
if (!cs.cx)
cs.cx = 1;
cs.y = wndPtr->rectWindow.top;
cs.x = wndPtr->rectWindow.left;
cs.style = wndPtr->dwStyle;
cs.lpszName = 0; /* not used in following call */
cs.lpszClass = 0; /*not used in following call */
cs.dwExStyle = wndPtr->dwExStyle;
X11DRV_WND_CreateWindow(wndPtr, wndPtr->class,
&cs, FALSE);
}
}
else /* a child window */
{
if( !( wndPtr->dwStyle & WS_CHILD ) )
{
wndPtr->dwStyle |= WS_CHILD;
if( wndPtr->wIDmenu != 0)
{
DestroyMenu( (HMENU) wndPtr->wIDmenu );
wndPtr->wIDmenu = 0;
}
}
}
WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
}
WIN_ReleaseDesktop();
return pWndPrev;
} /* failure */
WIN_ReleaseDesktop();
return 0;
}
/***********************************************************************
* X11DRV_WND_ForceWindowRaise
*
* Raise a window on top of the X stacking order, while preserving
* the correct Windows Z order.
*/
void X11DRV_WND_ForceWindowRaise(WND *wndPtr)
{
XWindowChanges winChanges;
WND *wndPrev,*pDesktop = WIN_GetDesktop();
if( !wndPtr || !X11DRV_WND_GetXWindow(wndPtr) || (wndPtr->flags & WIN_MANAGED) )
{
WIN_ReleaseDesktop();
return;
}
/* Raise all windows up to wndPtr according to their Z order.
* (it would be easier with sibling-related Below but it doesn't
* work very well with SGI mwm for instance)
*/
winChanges.stack_mode = Above;
while (wndPtr)
{
if (X11DRV_WND_GetXWindow(wndPtr))
TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(wndPtr), 0,
CWStackMode, &winChanges );
wndPrev = pDesktop->child;
if (wndPrev == wndPtr) break;
while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
wndPtr = wndPrev;
}
WIN_ReleaseDesktop();
}
/***********************************************************************
* X11DRV_WND_FindDesktopXWindow [Internal]
*
* Find the actual X window which needs be restacked.
* Used by X11DRV_SetWindowPos().
*/
static Window X11DRV_WND_FindDesktopXWindow( WND *wndPtr )
{
if (!(wndPtr->flags & WIN_MANAGED))
return X11DRV_WND_GetXWindow(wndPtr);
else
{
Window window, root, parent, *children;
int nchildren;
window = X11DRV_WND_GetXWindow(wndPtr);
for (;;)
{
TSXQueryTree( display, window, &root, &parent,
&children, &nchildren );
TSXFree( children );
if (parent == root)
return window;
window = parent;
}
}
}
/***********************************************************************
* WINPOS_SetXWindowPos
*
* SetWindowPos() for an X window. Used by the real SetWindowPos().
*/
void X11DRV_WND_SetWindowPos(WND *wndPtr, const WINDOWPOS *winpos, BOOL bChangePos)
{
XWindowChanges winChanges;
int changeMask = 0;
WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
if ( !winposPtr ) return;
if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happend!!! */
if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
{
if(X11DRV_WND_GetXWindow(wndPtr))
TSXUnmapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
}
if(bChangePos)
{
if ( !(winpos->flags & SWP_NOSIZE))
{
winChanges.width = (winpos->cx > 0 ) ? winpos->cx : 1;
winChanges.height = (winpos->cy > 0 ) ? winpos->cy : 1;
changeMask |= CWWidth | CWHeight;
/* Tweak dialog window size hints */
if ((winposPtr->flags & WIN_MANAGED) &&
HAS_DLGFRAME(winposPtr->dwStyle,winposPtr->dwExStyle))
{
XSizeHints *size_hints = TSXAllocSizeHints();
if (size_hints)
{
long supplied_return;
TSXGetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
&supplied_return, XA_WM_NORMAL_HINTS);
size_hints->min_width = size_hints->max_width = winpos->cx;
size_hints->min_height = size_hints->max_height = winpos->cy;
TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(winposPtr), size_hints,
XA_WM_NORMAL_HINTS );
TSXFree(size_hints);
}
}
}
if (!(winpos->flags & SWP_NOMOVE))
{
winChanges.x = winpos->x;
winChanges.y = winpos->y;
changeMask |= CWX | CWY;
}
if (!(winpos->flags & SWP_NOZORDER))
{
winChanges.stack_mode = Below;
changeMask |= CWStackMode;
if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
else if (winpos->hwndInsertAfter != HWND_BOTTOM)
{
WND* insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
Window stack[2];
stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
/* for stupid window managers (i.e. all of them) */
TSXRestackWindows(display, stack, 2);
changeMask &= ~CWStackMode;
WIN_ReleaseWndPtr(insertPtr);
}
}
if (changeMask && X11DRV_WND_GetXWindow(winposPtr))
{
TSXReconfigureWMWindow( display, X11DRV_WND_GetXWindow(winposPtr), 0, changeMask, &winChanges );
if( winposPtr->class->style & (CS_VREDRAW | CS_HREDRAW) )
X11DRV_WND_SetHostAttr( winposPtr, HAK_BITGRAVITY, BGForget );
}
}
if ( winpos->flags & SWP_SHOWWINDOW )
{
if(X11DRV_WND_GetXWindow(wndPtr))
TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
}
WIN_ReleaseWndPtr(winposPtr);
}
/*****************************************************************
* X11DRV_WND_SetText
*/
void X11DRV_WND_SetText(WND *wndPtr, LPCSTR text)
{
if (!X11DRV_WND_GetXWindow(wndPtr))
return;
TSXStoreName( display, X11DRV_WND_GetXWindow(wndPtr), text );
TSXSetIconName( display, X11DRV_WND_GetXWindow(wndPtr), text );
}
/*****************************************************************
* X11DRV_WND_SetFocus
*
* Set the X focus.
* Explicit colormap management seems to work only with OLVWM.
*/
void X11DRV_WND_SetFocus(WND *wndPtr)
{
HWND hwnd = wndPtr->hwndSelf;
XWindowAttributes win_attr;
Window win;
/* Only mess with the X focus if there's */
/* no desktop window and if the window is not managed by the WM. */
if ((X11DRV_WND_GetXRootWindow(wndPtr) != DefaultRootWindow(display))
|| (wndPtr->flags & WIN_MANAGED)) return;
if (!hwnd) /* If setting the focus to 0, uninstall the colormap */
{
if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
return;
}
/* Set X focus and install colormap */
if (!(win = X11DRV_WND_FindXWindow(wndPtr))) return;
if (!TSXGetWindowAttributes( display, win, &win_attr ) ||
(win_attr.map_state != IsViewable))
return; /* If window is not viewable, don't change anything */
TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
EVENT_Synchronize();
}
/*****************************************************************
* X11DRV_WND_PreSizeMove
*/
void X11DRV_WND_PreSizeMove(WND *wndPtr)
{
if (!(wndPtr->dwStyle & WS_CHILD) &&
(X11DRV_WND_GetXRootWindow(wndPtr) == DefaultRootWindow(display)))
TSXGrabServer( display );
}
/*****************************************************************
* X11DRV_WND_PostSizeMove
*/
void X11DRV_WND_PostSizeMove(WND *wndPtr)
{
if (!(wndPtr->dwStyle & WS_CHILD) &&
(X11DRV_GetXRootWindow() == DefaultRootWindow(display)))
TSXUngrabServer( display );
}
/*****************************************************************
* X11DRV_WND_SurfaceCopy
*
* Copies rect to (rect.left + dx, rect.top + dy).
*/
void X11DRV_WND_SurfaceCopy(WND* wndPtr, DC *dcPtr, INT dx, INT dy,
const RECT *rect, BOOL bUpdate)
{
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
POINT dst, src;
dst.x = (src.x = dcPtr->w.DCOrgX + rect->left) + dx;
dst.y = (src.y = dcPtr->w.DCOrgY + rect->top) + dy;
if (bUpdate) /* handles non-Wine windows hanging over the copied area */
TSXSetGraphicsExposures( display, physDev->gc, True );
TSXSetFunction( display, physDev->gc, GXcopy );
TSXCopyArea( display, physDev->drawable, physDev->drawable,
physDev->gc, src.x, src.y,
rect->right - rect->left,
rect->bottom - rect->top,
dst.x, dst.y );
if (bUpdate)
TSXSetGraphicsExposures( display, physDev->gc, False );
if (bUpdate) /* Make sure exposure events have been processed */
EVENT_Synchronize();
}
/***********************************************************************
* X11DRV_WND_SetDrawable
*
* Set the drawable, origin and dimensions for the DC associated to
* a given window.
*/
void X11DRV_WND_SetDrawable(WND *wndPtr, DC *dc, WORD flags, BOOL bSetClipOrigin)
{
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
INT dcOrgXCopy = 0, dcOrgYCopy = 0;
BOOL offsetClipRgn = FALSE;
if (!wndPtr) /* Get a DC for the whole screen */
{
dc->w.DCOrgX = 0;
dc->w.DCOrgY = 0;
physDev->drawable = X11DRV_WND_GetXRootWindow(wndPtr);
TSXSetSubwindowMode( display, physDev->gc, IncludeInferiors );
}
else
{
/*
* This function change the coordinate system (DCOrgX,DCOrgY)
* values. When it moves the origin, other data like the current clipping
* region will not be moved to that new origin. In the case of DCs that are class
* or window DCs that clipping region might be a valid value from a previous use
* of the DC and changing the origin of the DC without moving the clip region
* results in a clip region that is not placed properly in the DC.
* This code will save the dc origin, let the SetDrawable
* modify the origin and reset the clipping. When the clipping is set,
* it is moved according to the new DC origin.
*/
if ( (wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)) && (dc->w.hClipRgn > 0))
{
dcOrgXCopy = dc->w.DCOrgX;
dcOrgYCopy = dc->w.DCOrgY;
offsetClipRgn = TRUE;
}
if (flags & DCX_WINDOW)
{
dc->w.DCOrgX = wndPtr->rectWindow.left;
dc->w.DCOrgY = wndPtr->rectWindow.top;
}
else
{
dc->w.DCOrgX = wndPtr->rectClient.left;
dc->w.DCOrgY = wndPtr->rectClient.top;
}
while (!X11DRV_WND_GetXWindow(wndPtr))
{
wndPtr = wndPtr->parent;
dc->w.DCOrgX += wndPtr->rectClient.left;
dc->w.DCOrgY += wndPtr->rectClient.top;
}
dc->w.DCOrgX -= wndPtr->rectWindow.left;
dc->w.DCOrgY -= wndPtr->rectWindow.top;
/* reset the clip region, according to the new origin */
if ( offsetClipRgn )
{
OffsetRgn(dc->w.hClipRgn, dc->w.DCOrgX - dcOrgXCopy,dc->w.DCOrgY - dcOrgYCopy);
}
physDev->drawable = X11DRV_WND_GetXWindow(wndPtr);
#if 0
/* This is needed when we reuse a cached DC because
* SetDCState() called by ReleaseDC() screws up DC
* origins for child windows.
*/
if( bSetClipOrigin )
TSXSetClipOrigin( display, physDev->gc, dc->w.DCOrgX, dc->w.DCOrgY );
#endif
}
}
/***********************************************************************
* X11DRV_SetWMHint
*/
static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
{
XWMHints* wm_hints = TSXAllocWMHints();
{
wm_hints->flags = hint;
switch( hint )
{
case InputHint:
wm_hints->input = val;
break;
case StateHint:
wm_hints->initial_state = val;
break;
case IconPixmapHint:
wm_hints->icon_pixmap = (Pixmap)val;
break;
case IconWindowHint:
wm_hints->icon_window = (Window)val;
break;
}
TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
TSXFree(wm_hints);
return TRUE;
}
return FALSE;
}
/***********************************************************************
* X11DRV_WND_SetHostAttr
*
* This function returns TRUE if the attribute is supported and the
* action was successful. Otherwise it should return FALSE and Wine will try
* to get by without the functionality provided by the host window system.
*/
BOOL X11DRV_WND_SetHostAttr(WND* wnd, INT ha, INT value)
{
Window w;
if( (w = X11DRV_WND_GetXWindow(wnd)) )
{
XSetWindowAttributes win_attr;
switch( ha )
{
case HAK_ICONICSTATE: /* called when a window is minimized/restored */
if( (wnd->flags & WIN_MANAGED) )
{
if( value )
{
if( wnd->dwStyle & WS_VISIBLE )
{
XClientMessageEvent ev;
/* FIXME: set proper icon */
ev.type = ClientMessage;
ev.display = display;
ev.message_type = wmChangeState;
ev.format = 32;
ev.data.l[0] = IconicState;
ev.window = w;
if( TSXSendEvent (display,
RootWindow( display, XScreenNumberOfScreen(X11DRV_WND_GetXScreen(wnd)) ),
True, (SubstructureRedirectMask | SubstructureNotifyMask), (XEvent*)&ev))
{
XEvent xe;
TSXFlush (display);
while( !TSXCheckTypedWindowEvent( display, w, UnmapNotify, &xe) );
}
else
break;
}
else
X11DRV_SetWMHint( display, wnd, StateHint, IconicState );
}
else
{
if( !(wnd->flags & WS_VISIBLE) )
X11DRV_SetWMHint( display, wnd, StateHint, NormalState );
else
{
XEvent xe;
TSXMapWindow(display, w );
while( !TSXCheckTypedWindowEvent( display, w, MapNotify, &xe) );
}
}
return TRUE;
}
break;
case HAK_BITGRAVITY: /* called when a window is resized */
if( ((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity != value )
{
win_attr.bit_gravity = value;
((X11DRV_WND_DATA *) wnd->pDriverData)->bit_gravity = value;
TSXChangeWindowAttributes( display, w, CWBitGravity, &win_attr );
}
return TRUE;
case HAK_ACCEPTFOCUS: /* called when a window is disabled/enabled */
if( (wnd->flags & WIN_MANAGED) )
return X11DRV_SetWMHint( display, wnd, InputHint, value );
}
}
return FALSE;
}
/***********************************************************************
* X11DRV_WND_IsSelfClipping
*/
BOOL X11DRV_WND_IsSelfClipping(WND *wndPtr)
{
return X11DRV_WND_GetXWindow(wndPtr) != None;
}
/***********************************************************************
* X11DRV_WND_DockWindow
*
* Set the X Property of the window that tells the windowmanager we really
* want to be in the systray
*
* KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is
* mapped.
*
* all others: to be added ;)
*/
void X11DRV_WND_DockWindow(WND *wndPtr)
{
int data = 1;
Window win = X11DRV_WND_GetXWindow(wndPtr);
if (kwmDockWindow == None)
return; /* no KDE running */
TSXChangeProperty(
display,win,kwmDockWindow,kwmDockWindow,32,PropModeReplace,(char*)&data,1
);
}
#endif /* !defined(X_DISPLAY_MISSING) */