533 lines
14 KiB
C
533 lines
14 KiB
C
/*
|
|
|
|
Copyright 1993 by Davor Matic
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software
|
|
and its documentation for any purpose is hereby granted without fee,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation. Davor Matic makes no representations about
|
|
the suitability of this software for any purpose. It is provided "as
|
|
is" without express or implied warranty.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_XNEST_CONFIG_H
|
|
#include <xnest-config.h>
|
|
#endif
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "gcstruct.h"
|
|
#include "window.h"
|
|
#include "windowstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "colormapst.h"
|
|
#include "scrnintstr.h"
|
|
#include "region.h"
|
|
|
|
#include "mi.h"
|
|
|
|
#include "Xnest.h"
|
|
|
|
#include "Display.h"
|
|
#include "Screen.h"
|
|
#include "XNGC.h"
|
|
#include "Drawable.h"
|
|
#include "Color.h"
|
|
#include "Visual.h"
|
|
#include "Events.h"
|
|
#include "Args.h"
|
|
|
|
DevPrivateKey xnestWindowPrivateKey = &xnestWindowPrivateKey;
|
|
|
|
static int
|
|
xnestFindWindowMatch(WindowPtr pWin, pointer ptr)
|
|
{
|
|
xnestWindowMatch *wm = (xnestWindowMatch *)ptr;
|
|
if (wm->window == xnestWindow(pWin)) {
|
|
wm->pWin = pWin;
|
|
return WT_STOPWALKING;
|
|
}
|
|
else
|
|
return WT_WALKCHILDREN;
|
|
}
|
|
|
|
WindowPtr
|
|
xnestWindowPtr(Window window)
|
|
{
|
|
xnestWindowMatch wm;
|
|
int i;
|
|
|
|
wm.pWin = NullWindow;
|
|
wm.window = window;
|
|
|
|
for (i = 0; i < xnestNumScreens; i++) {
|
|
WalkTree(screenInfo.screens[i], xnestFindWindowMatch, (pointer) &wm);
|
|
if (wm.pWin) break;
|
|
}
|
|
|
|
return wm.pWin;
|
|
}
|
|
|
|
Bool
|
|
xnestCreateWindow(WindowPtr pWin)
|
|
{
|
|
unsigned long mask;
|
|
XSetWindowAttributes attributes;
|
|
Visual *visual;
|
|
ColormapPtr pCmap;
|
|
|
|
if (pWin->drawable.class == InputOnly) {
|
|
mask = 0L;
|
|
visual = CopyFromParent;
|
|
}
|
|
else {
|
|
mask = CWEventMask | CWBackingStore;
|
|
attributes.event_mask = ExposureMask;
|
|
attributes.backing_store = NotUseful;
|
|
|
|
if (pWin->parent) {
|
|
if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent)) {
|
|
visual = xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
|
|
mask |= CWColormap;
|
|
if (pWin->optional->colormap) {
|
|
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
|
|
attributes.colormap = xnestColormap(pCmap);
|
|
}
|
|
else
|
|
attributes.colormap = xnestDefaultVisualColormap(visual);
|
|
}
|
|
else
|
|
visual = CopyFromParent;
|
|
}
|
|
else { /* root windows have their own colormaps at creation time */
|
|
visual = xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
|
|
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
|
|
mask |= CWColormap;
|
|
attributes.colormap = xnestColormap(pCmap);
|
|
}
|
|
}
|
|
|
|
xnestWindowPriv(pWin)->window = XCreateWindow(xnestDisplay,
|
|
xnestWindowParent(pWin),
|
|
pWin->origin.x -
|
|
wBorderWidth(pWin),
|
|
pWin->origin.y -
|
|
wBorderWidth(pWin),
|
|
pWin->drawable.width,
|
|
pWin->drawable.height,
|
|
pWin->borderWidth,
|
|
pWin->drawable.depth,
|
|
pWin->drawable.class,
|
|
visual,
|
|
mask, &attributes);
|
|
xnestWindowPriv(pWin)->parent = xnestWindowParent(pWin);
|
|
xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
|
|
xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
|
|
xnestWindowPriv(pWin)->width = pWin->drawable.width;
|
|
xnestWindowPriv(pWin)->height = pWin->drawable.height;
|
|
xnestWindowPriv(pWin)->border_width = pWin->borderWidth;
|
|
xnestWindowPriv(pWin)->sibling_above = None;
|
|
if (pWin->nextSib)
|
|
xnestWindowPriv(pWin->nextSib)->sibling_above = xnestWindow(pWin);
|
|
#ifdef SHAPE
|
|
xnestWindowPriv(pWin)->bounding_shape =
|
|
REGION_CREATE(pWin->drawable.pScreen, NULL, 1);
|
|
xnestWindowPriv(pWin)->clip_shape =
|
|
REGION_CREATE(pWin->drawable.pScreen, NULL, 1);
|
|
#endif /* SHAPE */
|
|
|
|
if (!pWin->parent) /* only the root window will have the right colormap */
|
|
xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
|
|
|
|
return True;
|
|
}
|
|
|
|
Bool
|
|
xnestDestroyWindow(WindowPtr pWin)
|
|
{
|
|
if (pWin->nextSib)
|
|
xnestWindowPriv(pWin->nextSib)->sibling_above =
|
|
xnestWindowPriv(pWin)->sibling_above;
|
|
#ifdef SHAPE
|
|
REGION_DESTROY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->bounding_shape);
|
|
REGION_DESTROY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->clip_shape);
|
|
#endif
|
|
XDestroyWindow(xnestDisplay, xnestWindow(pWin));
|
|
xnestWindowPriv(pWin)->window = None;
|
|
|
|
if (pWin->optional && pWin->optional->colormap && pWin->parent)
|
|
xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
|
|
|
|
return True;
|
|
}
|
|
|
|
Bool
|
|
xnestPositionWindow(WindowPtr pWin, int x, int y)
|
|
{
|
|
xnestConfigureWindow(pWin,
|
|
CWParent |
|
|
CWX | CWY |
|
|
CWWidth | CWHeight |
|
|
CWBorderWidth);
|
|
|
|
return True;
|
|
}
|
|
|
|
void
|
|
xnestConfigureWindow(WindowPtr pWin, unsigned int mask)
|
|
{
|
|
unsigned int valuemask;
|
|
XWindowChanges values;
|
|
|
|
if (mask & CWParent &&
|
|
xnestWindowPriv(pWin)->parent != xnestWindowParent(pWin)) {
|
|
XReparentWindow(xnestDisplay, xnestWindow(pWin),
|
|
xnestWindowParent(pWin),
|
|
pWin->origin.x - wBorderWidth(pWin),
|
|
pWin->origin.y - wBorderWidth(pWin));
|
|
xnestWindowPriv(pWin)->parent = xnestWindowParent(pWin);
|
|
xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
|
|
xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
|
|
xnestWindowPriv(pWin)->sibling_above = None;
|
|
if (pWin->nextSib)
|
|
xnestWindowPriv(pWin->nextSib)->sibling_above = xnestWindow(pWin);
|
|
}
|
|
|
|
valuemask = 0;
|
|
|
|
if (mask & CWX &&
|
|
xnestWindowPriv(pWin)->x != pWin->origin.x - wBorderWidth(pWin)) {
|
|
valuemask |= CWX;
|
|
values.x =
|
|
xnestWindowPriv(pWin)->x =
|
|
pWin->origin.x - wBorderWidth(pWin);
|
|
}
|
|
|
|
if (mask & CWY &&
|
|
xnestWindowPriv(pWin)->y != pWin->origin.y - wBorderWidth(pWin)) {
|
|
valuemask |= CWY;
|
|
values.y =
|
|
xnestWindowPriv(pWin)->y =
|
|
pWin->origin.y - wBorderWidth(pWin);
|
|
}
|
|
|
|
if (mask & CWWidth &&
|
|
xnestWindowPriv(pWin)->width != pWin->drawable.width) {
|
|
valuemask |= CWWidth;
|
|
values.width =
|
|
xnestWindowPriv(pWin)->width =
|
|
pWin->drawable.width;
|
|
}
|
|
|
|
if (mask & CWHeight &&
|
|
xnestWindowPriv(pWin)->height != pWin->drawable.height) {
|
|
valuemask |= CWHeight;
|
|
values.height =
|
|
xnestWindowPriv(pWin)->height =
|
|
pWin->drawable.height;
|
|
}
|
|
|
|
if (mask & CWBorderWidth &&
|
|
xnestWindowPriv(pWin)->border_width != pWin->borderWidth) {
|
|
valuemask |= CWBorderWidth;
|
|
values.border_width =
|
|
xnestWindowPriv(pWin)->border_width =
|
|
pWin->borderWidth;
|
|
}
|
|
|
|
if (valuemask)
|
|
XConfigureWindow(xnestDisplay, xnestWindow(pWin), valuemask, &values);
|
|
|
|
if (mask & CWStackingOrder &&
|
|
xnestWindowPriv(pWin)->sibling_above != xnestWindowSiblingAbove(pWin)) {
|
|
WindowPtr pSib;
|
|
|
|
/* find the top sibling */
|
|
for (pSib = pWin; pSib->prevSib != NullWindow; pSib = pSib->prevSib);
|
|
|
|
/* the top sibling */
|
|
valuemask = CWStackMode;
|
|
values.stack_mode = Above;
|
|
XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask, &values);
|
|
xnestWindowPriv(pSib)->sibling_above = None;
|
|
|
|
/* the rest of siblings */
|
|
for (pSib = pSib->nextSib; pSib != NullWindow; pSib = pSib->nextSib) {
|
|
valuemask = CWSibling | CWStackMode;
|
|
values.sibling = xnestWindowSiblingAbove(pSib);
|
|
values.stack_mode = Below;
|
|
XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask, &values);
|
|
xnestWindowPriv(pSib)->sibling_above = xnestWindowSiblingAbove(pSib);
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool
|
|
xnestChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
|
|
{
|
|
XSetWindowAttributes attributes;
|
|
|
|
if (mask & CWBackPixmap)
|
|
switch (pWin->backgroundState) {
|
|
case None:
|
|
attributes.background_pixmap = None;
|
|
break;
|
|
|
|
case ParentRelative:
|
|
attributes.background_pixmap = ParentRelative;
|
|
break;
|
|
|
|
case BackgroundPixmap:
|
|
attributes.background_pixmap = xnestPixmap(pWin->background.pixmap);
|
|
break;
|
|
|
|
case BackgroundPixel:
|
|
mask &= ~CWBackPixmap;
|
|
break;
|
|
}
|
|
|
|
if (mask & CWBackPixel) {
|
|
if (pWin->backgroundState == BackgroundPixel)
|
|
attributes.background_pixel = xnestPixel(pWin->background.pixel);
|
|
else
|
|
mask &= ~CWBackPixel;
|
|
}
|
|
|
|
if (mask & CWBorderPixmap) {
|
|
if (pWin->borderIsPixel)
|
|
mask &= ~CWBorderPixmap;
|
|
else
|
|
attributes.border_pixmap = xnestPixmap(pWin->border.pixmap);
|
|
}
|
|
|
|
if (mask & CWBorderPixel) {
|
|
if (pWin->borderIsPixel)
|
|
attributes.border_pixel = xnestPixel(pWin->border.pixel);
|
|
else
|
|
mask &= ~CWBorderPixel;
|
|
}
|
|
|
|
if (mask & CWBitGravity)
|
|
attributes.bit_gravity = pWin->bitGravity;
|
|
|
|
if (mask & CWWinGravity) /* dix does this for us */
|
|
mask &= ~CWWinGravity;
|
|
|
|
if (mask & CWBackingStore) /* this is really not useful */
|
|
mask &= ~CWBackingStore;
|
|
|
|
if (mask & CWBackingPlanes) /* this is really not useful */
|
|
mask &= ~CWBackingPlanes;
|
|
|
|
if (mask & CWBackingPixel) /* this is really not useful */
|
|
mask &= ~CWBackingPixel;
|
|
|
|
if (mask & CWOverrideRedirect)
|
|
attributes.override_redirect = pWin->overrideRedirect;
|
|
|
|
if (mask & CWSaveUnder) /* this is really not useful */
|
|
mask &= ~CWSaveUnder;
|
|
|
|
if (mask & CWEventMask) /* events are handled elsewhere */
|
|
mask &= ~CWEventMask;
|
|
|
|
if (mask & CWDontPropagate) /* events are handled elsewhere */
|
|
mask &= ~CWDontPropagate;
|
|
|
|
if (mask & CWColormap) {
|
|
ColormapPtr pCmap;
|
|
|
|
pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP);
|
|
|
|
attributes.colormap = xnestColormap(pCmap);
|
|
|
|
xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
|
|
}
|
|
|
|
if (mask & CWCursor) /* this is handeled in cursor code */
|
|
mask &= ~CWCursor;
|
|
|
|
if (mask)
|
|
XChangeWindowAttributes(xnestDisplay, xnestWindow(pWin),
|
|
mask, &attributes);
|
|
|
|
return True;
|
|
}
|
|
|
|
Bool
|
|
xnestRealizeWindow(WindowPtr pWin)
|
|
{
|
|
xnestConfigureWindow(pWin, CWStackingOrder);
|
|
#ifdef SHAPE
|
|
xnestShapeWindow(pWin);
|
|
#endif /* SHAPE */
|
|
XMapWindow(xnestDisplay, xnestWindow(pWin));
|
|
|
|
return True;
|
|
}
|
|
|
|
Bool
|
|
xnestUnrealizeWindow(WindowPtr pWin)
|
|
{
|
|
XUnmapWindow(xnestDisplay, xnestWindow(pWin));
|
|
|
|
return True;
|
|
}
|
|
|
|
void
|
|
xnestCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
|
|
{
|
|
}
|
|
|
|
void
|
|
xnestClipNotify(WindowPtr pWin, int dx, int dy)
|
|
{
|
|
xnestConfigureWindow(pWin, CWStackingOrder);
|
|
#ifdef SHAPE
|
|
xnestShapeWindow(pWin);
|
|
#endif /* SHAPE */
|
|
}
|
|
|
|
static Bool
|
|
xnestWindowExposurePredicate(Display *display, XEvent *event, XPointer ptr)
|
|
{
|
|
return (event->type == Expose && event->xexpose.window == *(Window *)ptr);
|
|
}
|
|
|
|
void
|
|
xnestWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed)
|
|
{
|
|
XEvent event;
|
|
Window window;
|
|
BoxRec Box;
|
|
|
|
XSync(xnestDisplay, False);
|
|
|
|
window = xnestWindow(pWin);
|
|
|
|
while (XCheckIfEvent(xnestDisplay, &event,
|
|
xnestWindowExposurePredicate, (char *)&window)) {
|
|
|
|
Box.x1 = pWin->drawable.x + wBorderWidth(pWin) + event.xexpose.x;
|
|
Box.y1 = pWin->drawable.y + wBorderWidth(pWin) + event.xexpose.y;
|
|
Box.x2 = Box.x1 + event.xexpose.width;
|
|
Box.y2 = Box.y1 + event.xexpose.height;
|
|
|
|
event.xexpose.type = ProcessedExpose;
|
|
|
|
if (RECT_IN_REGION(pWin->drawable.pScreen, pRgn, &Box) != rgnIN)
|
|
XPutBackEvent(xnestDisplay, &event);
|
|
}
|
|
|
|
miWindowExposures(pWin, pRgn, other_exposed);
|
|
}
|
|
|
|
#ifdef SHAPE
|
|
void
|
|
xnestSetShape(WindowPtr pWin)
|
|
{
|
|
xnestShapeWindow(pWin);
|
|
miSetShape(pWin);
|
|
}
|
|
|
|
static Bool
|
|
xnestRegionEqual(RegionPtr pReg1, RegionPtr pReg2)
|
|
{
|
|
BoxPtr pBox1, pBox2;
|
|
unsigned int n1, n2;
|
|
|
|
if (pReg1 == pReg2) return True;
|
|
|
|
if (pReg1 == NullRegion || pReg2 == NullRegion) return False;
|
|
|
|
pBox1 = REGION_RECTS(pReg1);
|
|
n1 = REGION_NUM_RECTS(pReg1);
|
|
|
|
pBox2 = REGION_RECTS(pReg2);
|
|
n2 = REGION_NUM_RECTS(pReg2);
|
|
|
|
if (n1 != n2) return False;
|
|
|
|
if (pBox1 == pBox2) return True;
|
|
|
|
if (memcmp(pBox1, pBox2, n1 * sizeof(BoxRec))) return False;
|
|
|
|
return True;
|
|
}
|
|
|
|
void
|
|
xnestShapeWindow(WindowPtr pWin)
|
|
{
|
|
Region reg;
|
|
BoxPtr pBox;
|
|
XRectangle rect;
|
|
int i;
|
|
|
|
if (!xnestRegionEqual(xnestWindowPriv(pWin)->bounding_shape,
|
|
wBoundingShape(pWin))) {
|
|
|
|
if (wBoundingShape(pWin)) {
|
|
REGION_COPY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->bounding_shape, wBoundingShape(pWin));
|
|
|
|
reg = XCreateRegion();
|
|
pBox = REGION_RECTS(xnestWindowPriv(pWin)->bounding_shape);
|
|
for (i = 0;
|
|
i < REGION_NUM_RECTS(xnestWindowPriv(pWin)->bounding_shape);
|
|
i++) {
|
|
rect.x = pBox[i].x1;
|
|
rect.y = pBox[i].y1;
|
|
rect.width = pBox[i].x2 - pBox[i].x1;
|
|
rect.height = pBox[i].y2 - pBox[i].y1;
|
|
XUnionRectWithRegion(&rect, reg, reg);
|
|
}
|
|
XShapeCombineRegion(xnestDisplay, xnestWindow(pWin),
|
|
ShapeBounding, 0, 0, reg, ShapeSet);
|
|
XDestroyRegion(reg);
|
|
}
|
|
else {
|
|
REGION_EMPTY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->bounding_shape);
|
|
|
|
XShapeCombineMask(xnestDisplay, xnestWindow(pWin),
|
|
ShapeBounding, 0, 0, None, ShapeSet);
|
|
}
|
|
}
|
|
|
|
if (!xnestRegionEqual(xnestWindowPriv(pWin)->clip_shape,
|
|
wClipShape(pWin))) {
|
|
|
|
if (wClipShape(pWin)) {
|
|
REGION_COPY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->clip_shape, wClipShape(pWin));
|
|
|
|
reg = XCreateRegion();
|
|
pBox = REGION_RECTS(xnestWindowPriv(pWin)->clip_shape);
|
|
for (i = 0;
|
|
i < REGION_NUM_RECTS(xnestWindowPriv(pWin)->clip_shape);
|
|
i++) {
|
|
rect.x = pBox[i].x1;
|
|
rect.y = pBox[i].y1;
|
|
rect.width = pBox[i].x2 - pBox[i].x1;
|
|
rect.height = pBox[i].y2 - pBox[i].y1;
|
|
XUnionRectWithRegion(&rect, reg, reg);
|
|
}
|
|
XShapeCombineRegion(xnestDisplay, xnestWindow(pWin),
|
|
ShapeClip, 0, 0, reg, ShapeSet);
|
|
XDestroyRegion(reg);
|
|
}
|
|
else {
|
|
REGION_EMPTY(pWin->drawable.pScreen,
|
|
xnestWindowPriv(pWin)->clip_shape);
|
|
|
|
XShapeCombineMask(xnestDisplay, xnestWindow(pWin),
|
|
ShapeClip, 0, 0, None, ShapeSet);
|
|
}
|
|
}
|
|
}
|
|
#endif /* SHAPE */
|