1200 lines
36 KiB
C
1200 lines
36 KiB
C
/*
|
|
* X11 windows driver
|
|
*
|
|
* Copyright 1993, 1994, 1995, 1996 Alexandre Julliard
|
|
* 1993 David Metcalfe
|
|
* 1995, 1996 Alex Korobka
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include "ts_xlib.h"
|
|
#include "ts_xutil.h"
|
|
#include "ts_shape.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "bitmap.h"
|
|
#include "debugtools.h"
|
|
#include "dce.h"
|
|
#include "dc.h"
|
|
#include "options.h"
|
|
#include "message.h"
|
|
#include "heap.h"
|
|
#include "win.h"
|
|
#include "windef.h"
|
|
#include "class.h"
|
|
#include "x11drv.h"
|
|
#include "wingdi.h"
|
|
#include "winnls.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 );
|
|
|
|
/**********************************************************************/
|
|
|
|
WND_DRIVER X11DRV_WND_Driver =
|
|
{
|
|
X11DRV_WND_Initialize,
|
|
X11DRV_WND_Finalize,
|
|
X11DRV_WND_CreateDesktopWindow,
|
|
X11DRV_WND_CreateWindow,
|
|
X11DRV_WND_DestroyWindow,
|
|
X11DRV_WND_SetParent,
|
|
X11DRV_WND_ForceWindowRaise,
|
|
X11DRV_WND_SetWindowPos,
|
|
X11DRV_WND_SetText,
|
|
X11DRV_WND_SetFocus,
|
|
X11DRV_WND_PreSizeMove,
|
|
X11DRV_WND_PostSizeMove,
|
|
X11DRV_WND_SurfaceCopy,
|
|
X11DRV_WND_SetDrawable,
|
|
X11DRV_WND_SetHostAttr,
|
|
X11DRV_WND_IsSelfClipping,
|
|
X11DRV_WND_SetWindowRgn
|
|
};
|
|
|
|
|
|
/* 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_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_IsZeroSizeWnd
|
|
*
|
|
* Return TRUE if the window has a height or widht less or equal to 0
|
|
*/
|
|
static BOOL X11DRV_WND_IsZeroSizeWnd(WND *wndPtr)
|
|
{
|
|
if ( (wndPtr->rectWindow.left >= wndPtr->rectWindow.right) ||
|
|
(wndPtr->rectWindow.top >= wndPtr->rectWindow.bottom) )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* 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_GetXRootWindow();
|
|
X11DRV_WND_RegisterWindow( wndPtr );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* X11DRV_WND_IconChanged
|
|
*
|
|
* hIcon or hIconSm has changed (or is being initialised for the
|
|
* first time). Complete the X11 driver-specific initialisation.
|
|
*
|
|
* This is not entirely correct, may need to create
|
|
* an icon window and set the pixmap as a background
|
|
*/
|
|
static void X11DRV_WND_IconChanged(WND *wndPtr)
|
|
{
|
|
|
|
HICON16 hIcon = NC_IconForWindow(wndPtr);
|
|
|
|
if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap )
|
|
DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap );
|
|
|
|
if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
|
|
DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
|
|
|
|
if (!hIcon)
|
|
{
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap= 0;
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 0;
|
|
}
|
|
else
|
|
{
|
|
HBITMAP hbmOrig;
|
|
RECT rcMask;
|
|
BITMAP bmMask;
|
|
ICONINFO ii;
|
|
HDC hDC;
|
|
|
|
GetIconInfo(hIcon, &ii);
|
|
|
|
X11DRV_CreateBitmap(ii.hbmMask);
|
|
X11DRV_CreateBitmap(ii.hbmColor);
|
|
|
|
GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
|
|
rcMask.top = 0;
|
|
rcMask.left = 0;
|
|
rcMask.right = bmMask.bmWidth;
|
|
rcMask.bottom = bmMask.bmHeight;
|
|
|
|
hDC = CreateCompatibleDC(0);
|
|
hbmOrig = SelectObject(hDC, ii.hbmMask);
|
|
InvertRect(hDC, &rcMask);
|
|
SelectObject(hDC, hbmOrig);
|
|
DeleteDC(hDC);
|
|
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap = ii.hbmColor;
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= ii.hbmMask;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void X11DRV_WND_SetIconHints(WND *wndPtr, XWMHints *hints)
|
|
{
|
|
if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap)
|
|
{
|
|
hints->icon_pixmap
|
|
= X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconBitmap);
|
|
hints->flags |= IconPixmapHint;
|
|
}
|
|
else
|
|
hints->flags &= ~IconPixmapHint;
|
|
|
|
if (((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask)
|
|
{
|
|
hints->icon_mask
|
|
= X11DRV_BITMAP_Pixmap(((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
|
|
hints->flags |= IconMaskHint;
|
|
}
|
|
else
|
|
hints->flags &= ~IconMaskHint;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* X11DRV_WND_UpdateIconHints
|
|
*
|
|
* hIcon or hIconSm has changed (or is being initialised for the
|
|
* first time). Complete the X11 driver-specific initialisation
|
|
* and set the window hints.
|
|
*
|
|
* This is not entirely correct, may need to create
|
|
* an icon window and set the pixmap as a background
|
|
*/
|
|
static void X11DRV_WND_UpdateIconHints(WND *wndPtr)
|
|
{
|
|
XWMHints* wm_hints;
|
|
|
|
X11DRV_WND_IconChanged(wndPtr);
|
|
|
|
wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
|
|
if (!wm_hints) wm_hints = TSXAllocWMHints();
|
|
if (wm_hints)
|
|
{
|
|
X11DRV_WND_SetIconHints(wndPtr, wm_hints);
|
|
TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
|
|
TSXFree( wm_hints );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* 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 ((X11DRV_GetXRootWindow() == DefaultRootWindow(display))
|
|
&& (wndPtr->parent->hwndSelf == GetDesktopWindow()))
|
|
{
|
|
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 = 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)->hWMIconMask = 0;
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->bit_gravity = win_attr.bit_gravity;
|
|
|
|
/* Zero-size X11 window hack. X doesn't like them, and will crash */
|
|
/* with a BadValue unless we do something ugly like this. */
|
|
/* Zero size window won't be mapped */
|
|
if (cs->cx <= 0) cs->cx = 1;
|
|
if (cs->cy <= 0) cs->cy = 1;
|
|
|
|
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->window =
|
|
TSXCreateWindow( display, X11DRV_GetXRootWindow(),
|
|
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->x = cs->x;
|
|
size_hints->y = cs->y;
|
|
size_hints->flags = PWinGravity|PPosition;
|
|
|
|
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);
|
|
}
|
|
|
|
if ((wm_hints = TSXAllocWMHints()))
|
|
{
|
|
wm_hints->flags = InputHint | StateHint | WindowGroupHint;
|
|
wm_hints->input = True;
|
|
|
|
if( wndPtr->flags & WIN_MANAGED )
|
|
{
|
|
X11DRV_WND_IconChanged(wndPtr);
|
|
X11DRV_WND_SetIconHints(wndPtr, wm_hints);
|
|
|
|
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;
|
|
}
|
|
if( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask )
|
|
{
|
|
DeleteObject( ((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask);
|
|
((X11DRV_WND_DATA *) wndPtr->pDriverData)->hWMIconMask= 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 )
|
|
{
|
|
if( X11DRV_GetXRootWindow() == 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 ) )
|
|
{
|
|
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 (X11DRV_WND_IsZeroSizeWnd(wndPtr))
|
|
{
|
|
WIN_ReleaseDesktop();
|
|
return;
|
|
}
|
|
|
|
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_IsZeroSizeWnd(wndPtr) && 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_WND_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;
|
|
BOOL isZeroSizeWnd = FALSE;
|
|
BOOL forceMapWindow = FALSE;
|
|
WND *winposPtr = WIN_FindWndPtr( winpos->hwnd );
|
|
if ( !winposPtr ) return;
|
|
|
|
/* find out if after this function we will end out with a zero-size window */
|
|
if (X11DRV_WND_IsZeroSizeWnd(winposPtr))
|
|
{
|
|
/* if current size is 0, and no resizing */
|
|
if (winpos->flags & SWP_NOSIZE)
|
|
isZeroSizeWnd = TRUE;
|
|
else if ((winpos->cx > 0) && (winpos->cy > 0))
|
|
{
|
|
/* if this function is setting a new size > 0 for the window, we
|
|
should map the window if WS_VISIBLE is set */
|
|
if ((winposPtr->dwStyle & WS_VISIBLE) && !(winpos->flags & SWP_HIDEWINDOW))
|
|
forceMapWindow = TRUE;
|
|
}
|
|
}
|
|
/* if resizing to 0 */
|
|
if ( !(winpos->flags & SWP_NOSIZE) && ((winpos->cx <= 0) || (winpos->cy <= 0)) )
|
|
isZeroSizeWnd = TRUE;
|
|
|
|
if(!wndPtr->hwndSelf) wndPtr = NULL; /* FIXME: WND destroyed, shouldn't happen!!! */
|
|
|
|
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) && !isZeroSizeWnd)
|
|
{
|
|
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];
|
|
|
|
/* If the window where we should do the insert is zero-sized (not mapped)
|
|
don't used this window since it will possibly crash the X server,
|
|
use the "non zero-sized" window above */
|
|
if (X11DRV_WND_IsZeroSizeWnd(insertPtr))
|
|
{
|
|
/* find the window on top of the zero sized window */
|
|
WND *pDesktop = WIN_GetDesktop();
|
|
WND *wndPrev = pDesktop->child;
|
|
WND *wndZeroSized = insertPtr;
|
|
|
|
while (1)
|
|
{
|
|
if (wndPrev == wndZeroSized)
|
|
break; /* zero-sized window is on top */
|
|
|
|
while (wndPrev && (wndPrev->next != wndZeroSized))
|
|
wndPrev = wndPrev->next;
|
|
|
|
/* check if the window found is not zero-sized */
|
|
if (X11DRV_WND_IsZeroSizeWnd(wndPrev))
|
|
{
|
|
wndZeroSized = wndPrev; /* restart the search */
|
|
wndPrev = pDesktop->child;
|
|
}
|
|
else
|
|
break; /* "above" window is found */
|
|
}
|
|
WIN_ReleaseDesktop();
|
|
|
|
if (wndPrev == wndZeroSized)
|
|
{
|
|
/* the zero-sized window is on top */
|
|
/* so set the window on top */
|
|
winChanges.stack_mode = Above;
|
|
}
|
|
else
|
|
{
|
|
stack[0] = X11DRV_WND_FindDesktopXWindow( wndPrev );
|
|
stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
|
|
|
|
TSXRestackWindows(display, stack, 2);
|
|
changeMask &= ~CWStackMode;
|
|
}
|
|
}
|
|
else /* Normal behavior, windows are not zero-sized */
|
|
{
|
|
stack[0] = X11DRV_WND_FindDesktopXWindow( insertPtr );
|
|
stack[1] = X11DRV_WND_FindDesktopXWindow( winposPtr );
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
/* don't map the window if it's a zero size window */
|
|
if ( ((winpos->flags & SWP_SHOWWINDOW) && !isZeroSizeWnd) || forceMapWindow )
|
|
{
|
|
if(X11DRV_WND_GetXWindow(wndPtr))
|
|
TSXMapWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
|
|
}
|
|
WIN_ReleaseWndPtr(winposPtr);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* X11DRV_WND_SetText
|
|
*/
|
|
void X11DRV_WND_SetText(WND *wndPtr, LPCWSTR text)
|
|
{
|
|
UINT count;
|
|
char *buffer;
|
|
static UINT text_cp = (UINT)-1;
|
|
Window win;
|
|
|
|
if (!(win = X11DRV_WND_GetXWindow(wndPtr))) return;
|
|
|
|
if(text_cp == (UINT)-1)
|
|
{
|
|
text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
|
|
TRACE("text_cp = %u\n", text_cp);
|
|
}
|
|
|
|
/* allocate new buffer for window text */
|
|
count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
|
|
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
|
|
{
|
|
ERR("Not enough memory for window text\n");
|
|
return;
|
|
}
|
|
WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
|
|
|
|
TSXStoreName( display, win, buffer );
|
|
TSXSetIconName( display, win, buffer );
|
|
HeapFree( GetProcessHeap(), 0, buffer );
|
|
}
|
|
|
|
/*****************************************************************
|
|
* 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;
|
|
WND *w = wndPtr;
|
|
|
|
if (X11DRV_WND_IsZeroSizeWnd(wndPtr))
|
|
return;
|
|
|
|
/* Only mess with the X focus if there's */
|
|
/* no desktop window and if the window is not managed by the WM. */
|
|
if ((X11DRV_GetXRootWindow() != DefaultRootWindow(display))) return;
|
|
while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
|
|
w = w->parent;
|
|
if (!w) w = wndPtr;
|
|
if (w->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_GetXRootWindow() == 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, HDC hdc, INT dx, INT dy,
|
|
const RECT *rect, BOOL bUpdate)
|
|
{
|
|
X11DRV_PDEVICE *physDev;
|
|
POINT dst, src;
|
|
DC *dcPtr = DC_GetDCPtr( hdc );
|
|
|
|
if (!dcPtr) return;
|
|
physDev = (X11DRV_PDEVICE *)dcPtr->physDev;
|
|
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();
|
|
GDI_HEAP_UNLOCK( hdc );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* X11DRV_WND_SetDrawable
|
|
*
|
|
* Set the drawable, origin and dimensions for the DC associated to
|
|
* a given window.
|
|
*/
|
|
void X11DRV_WND_SetDrawable(WND *wndPtr, HDC hdc, WORD flags, BOOL bSetClipOrigin)
|
|
{
|
|
DC *dc = DC_GetDCPtr( hdc );
|
|
X11DRV_PDEVICE *physDev;
|
|
INT dcOrgXCopy = 0, dcOrgYCopy = 0;
|
|
BOOL offsetClipRgn = FALSE;
|
|
|
|
if (!dc) return;
|
|
physDev = (X11DRV_PDEVICE *)dc->physDev;
|
|
if (!wndPtr) /* Get a DC for the whole screen */
|
|
{
|
|
dc->w.DCOrgX = 0;
|
|
dc->w.DCOrgY = 0;
|
|
physDev->drawable = X11DRV_GetXRootWindow();
|
|
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
|
|
}
|
|
GDI_HEAP_UNLOCK( hdc );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* X11DRV_SetWMHint
|
|
*/
|
|
static BOOL X11DRV_SetWMHint(Display* display, WND* wndPtr, int hint, int val)
|
|
{
|
|
XWMHints* wm_hints = TSXGetWMHints( display, X11DRV_WND_GetXWindow(wndPtr) );
|
|
if (!wm_hints) wm_hints = TSXAllocWMHints();
|
|
if (wm_hints)
|
|
{
|
|
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 */
|
|
|
|
/* don't do anything if it'a zero size window */
|
|
if (X11DRV_WND_IsZeroSizeWnd(wnd))
|
|
return TRUE;
|
|
|
|
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_GetXScreen()) ),
|
|
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_ICONS: /* called when the icons change */
|
|
if ( (wnd->flags & WIN_MANAGED) )
|
|
X11DRV_WND_UpdateIconHints(wnd);
|
|
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
|
|
);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* X11DRV_WND_SetWindowRgn
|
|
*
|
|
* Assign specified region to window (for non-rectangular windows)
|
|
*/
|
|
void X11DRV_WND_SetWindowRgn(WND *wndPtr, HRGN hrgnWnd)
|
|
{
|
|
#ifdef HAVE_LIBXSHAPE
|
|
Window win = X11DRV_WND_GetXWindow(wndPtr);
|
|
|
|
if (!win) return;
|
|
|
|
if (!hrgnWnd)
|
|
{
|
|
TSXShapeCombineMask( display, win, ShapeBounding, 0, 0, None, ShapeSet );
|
|
}
|
|
else
|
|
{
|
|
XRectangle *aXRect;
|
|
DWORD size;
|
|
DWORD dwBufferSize = GetRegionData(hrgnWnd, 0, NULL);
|
|
PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
|
|
if (!pRegionData) return;
|
|
|
|
GetRegionData(hrgnWnd, dwBufferSize, pRegionData);
|
|
size = pRegionData->rdh.nCount;
|
|
/* convert region's "Windows rectangles" to XRectangles */
|
|
aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
|
|
if (aXRect)
|
|
{
|
|
XRectangle* pCurrRect = aXRect;
|
|
RECT *pRect = (RECT*) pRegionData->Buffer;
|
|
for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
|
|
{
|
|
pCurrRect->x = pRect->left;
|
|
pCurrRect->y = pRect->top;
|
|
pCurrRect->height = pRect->bottom - pRect->top;
|
|
pCurrRect->width = pRect->right - pRect->left;
|
|
|
|
TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
|
|
pRect - (RECT*) pRegionData->Buffer,
|
|
size,
|
|
pCurrRect->x,
|
|
pCurrRect->y,
|
|
pCurrRect->height,
|
|
pCurrRect->width);
|
|
}
|
|
|
|
/* shape = non-rectangular windows (X11/extensions) */
|
|
TSXShapeCombineRectangles( display, win, ShapeBounding,
|
|
0, 0, aXRect,
|
|
pCurrRect - aXRect, ShapeSet, YXBanded );
|
|
HeapFree(GetProcessHeap(), 0, aXRect );
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, pRegionData);
|
|
}
|
|
#endif /* HAVE_LIBXSHAPE */
|
|
}
|