From 2fddbd302426f7d6cd11e2b5fe5ef0d670bd0f68 Mon Sep 17 00:00:00 2001 From: David Reveman Date: Wed, 19 Nov 2008 17:33:38 -0500 Subject: [PATCH] Have DMX DnD support handle shaped windows properly. --- configure.ac | 2 +- hw/dmx/dmx.h | 2 + hw/dmx/dmxdnd.c | 262 +++++++++++++++++++++++++++++++++++++----- hw/dmx/dmxextension.c | 19 +++ 4 files changed, 255 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac index e06750622..56b1d99a2 100644 --- a/configure.ac +++ b/configure.ac @@ -1568,7 +1568,7 @@ AM_CONDITIONAL(INTEGRATED_XPBPROXY, [test "x$INTEGRATED_XPBPROXY" = xyes]) dnl DMX DDX -PKG_CHECK_MODULES([DMXMODULES], [xmuu xext x11 xrender xfixes xfont xi >= 1.1.99.1 dmxproto xau xcomposite xrandr xv x11-xcb xcb-randr xcb-xinput xcb-aux >= 0.2.1 xcb-image $XDMCP_MODULES], [have_dmx=yes], [have_dmx=no]) +PKG_CHECK_MODULES([DMXMODULES], [xmuu xext x11 xrender xfixes xfont xi >= 1.1.99.1 dmxproto xau xcomposite xrandr xv x11-xcb xcb-randr xcb-xinput xcb-aux >= 0.2.1 xcb-image xcb-shape $XDMCP_MODULES], [have_dmx=yes], [have_dmx=no]) if test "x$DMX" = xauto; then DMX="$have_dmx" case $host_os in diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h index 321355438..0833adbf2 100644 --- a/hw/dmx/dmx.h +++ b/hw/dmx/dmx.h @@ -189,6 +189,8 @@ typedef struct _DMXScreenInfo { Pixel beBlackPixel; /**< Default black pixel for BE */ Pixel beWhitePixel; /**< Default white pixel for BE */ + int beShapeEventBase; + #ifdef RANDR Bool beRandr; /**< Use RANDR support on BE server */ Bool beRandrPending; diff --git a/hw/dmx/dmxdnd.c b/hw/dmx/dmxdnd.c index 6218b661c..0841db639 100644 --- a/hw/dmx/dmxdnd.c +++ b/hw/dmx/dmxdnd.c @@ -45,13 +45,16 @@ #endif #include +#include struct _DMXDnDChild { - Window target; - Window wid; - BoxRec box; - int map_state; - int version; + Window target; + Window wid; + BoxRec box; + RegionPtr boundingShape; + RegionPtr inputShape; + int map_state; + int version; }; void @@ -138,7 +141,27 @@ dmxBEDnDUpdateTarget (ScreenPtr pScreen) dmxScreen->dndChildren[n].box.y1 <= dmxScreen->dndY && dmxScreen->dndChildren[n].box.x2 > dmxScreen->dndX && dmxScreen->dndChildren[n].box.y2 > dmxScreen->dndY) - break; + { + BoxRec box; + + if ((!dmxScreen->dndChildren[n].boundingShape || + POINT_IN_REGION (pScreen, + dmxScreen->dndChildren[n].boundingShape, + dmxScreen->dndX - + dmxScreen->dndChildren[n].box.x1, + dmxScreen->dndY - + dmxScreen->dndChildren[n].box.y1, + &box)) && + (!dmxScreen->dndChildren[n].inputShape || + POINT_IN_REGION (pScreen, + dmxScreen->dndChildren[n].inputShape, + dmxScreen->dndX - + dmxScreen->dndChildren[n].box.x1, + dmxScreen->dndY - + dmxScreen->dndChildren[n].box.y1, + &box))) + break; + } } if (n >= 0 && dmxScreen->dndChildren[n].version >= 3) @@ -353,6 +376,103 @@ dmxDnDGeometryReply (ScreenPtr pScreen, } } +typedef struct dmx_xcb_shape_get_rectangles_reply_t { + uint8_t response_type; + uint8_t ordering; + uint16_t sequence; + uint32_t length; + uint32_t rectangles_len; + uint32_t pad1; + uint32_t pad2; + uint32_t pad3; + uint32_t pad4; + uint32_t pad5; +} dmx_xcb_shape_get_rectangles_reply_t; + +static void +dmxDnDBoundingShapeReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + RegionPtr pRegion; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + dmx_xcb_shape_get_rectangles_reply_t *xshape = + (dmx_xcb_shape_get_rectangles_reply_t *) reply; + + pRegion = RECTS_TO_REGION (pScreen, + xshape->rectangles_len, + (xRectangle *) (xshape + 1), + xshape->ordering); + + if (dmxScreen->dndChildren[n].boundingShape) + REGION_DESTROY (pScreen, dmxScreen->dndChildren[n].boundingShape); + + dmxScreen->dndChildren[n].boundingShape = pRegion; + } +} + +static void +dmxDnDInputShapeReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int n = (int) data; + RegionPtr pRegion; + + if (!dmxScreen->dndChildren || n >= dmxScreen->dndNChildren) + return; + + if (reply) + { + dmx_xcb_shape_get_rectangles_reply_t *xshape = + (dmx_xcb_shape_get_rectangles_reply_t *) reply; + + pRegion = RECTS_TO_REGION (pScreen, + xshape->rectangles_len, + (xRectangle *) (xshape + 1), + xshape->ordering); + + if (dmxScreen->dndChildren[n].inputShape) + REGION_DESTROY (pScreen, dmxScreen->dndChildren[n].inputShape); + + dmxScreen->dndChildren[n].inputShape = pRegion; + } +} + +static void +dmxDnDBoundingShapeUpdateReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + dmxDnDBoundingShapeReply (pScreen, sequence, reply, error, data); + dmxBEDnDUpdateTarget (pScreen); +} + +static void +dmxDnDInputShapeUpdateReply (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply, + xcb_generic_error_t *error, + void *data) +{ + dmxDnDInputShapeReply (pScreen, sequence, reply, error, data); + dmxBEDnDUpdateTarget (pScreen); +} + static void dmxDnDWindowAttributesReply (ScreenPtr pScreen, unsigned int sequence, @@ -415,15 +535,18 @@ dmxDnDQueryTreeReply (ScreenPtr pScreen, { xcb_get_property_cookie_t prop; xcb_get_geometry_cookie_t geometry; + xcb_shape_get_rectangles_cookie_t shape; xcb_get_window_attributes_cookie_t attr; - children[n].box.x1 = 0; - children[n].box.y1 = 0; - children[n].box.x2 = 0; - children[n].box.y2 = 0; - children[n].version = 0; - children[n].target = c[n]; - children[n].wid = c[n]; + children[n].box.x1 = 0; + children[n].box.y1 = 0; + children[n].box.x2 = 0; + children[n].box.y2 = 0; + children[n].boundingShape = NULL; + children[n].inputShape = NULL; + children[n].version = 0; + children[n].target = c[n]; + children[n].wid = c[n]; prop = xcb_get_property (dmxScreen->connection, xFalse, @@ -457,6 +580,22 @@ dmxDnDQueryTreeReply (ScreenPtr pScreen, geometry.sequence, (void *) n); + xcb_shape_select_input (dmxScreen->connection, c[n], 1); + + shape = xcb_shape_get_rectangles (dmxScreen->connection, c[n], + ShapeBounding); + dmxAddRequest (&dmxScreen->request, + dmxDnDBoundingShapeReply, + shape.sequence, + (void *) n); + + shape = xcb_shape_get_rectangles (dmxScreen->connection, c[n], + ShapeInput); + dmxAddRequest (&dmxScreen->request, + dmxDnDInputShapeReply, + shape.sequence, + (void *) n); + attr = xcb_get_window_attributes (dmxScreen->connection, c[n]); dmxAddRequest (&dmxScreen->request, dmxDnDWindowAttributesReply, @@ -504,6 +643,37 @@ dmxBEDnDUpdatePosition (ScreenPtr pScreen, dmxBEDnDUpdateTarget (screenInfo.screens[i]); } +static void +dmxDnDFreeChildren (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->dndChildren) + { + int i; + + for (i = 0; i < dmxScreen->dndNChildren; i++) + { + if (dmxScreen->dndChildren[i].boundingShape) + REGION_DESTROY (pScreen, + dmxScreen->dndChildren[i].boundingShape); + + if (dmxScreen->dndChildren[i].inputShape) + REGION_DESTROY (pScreen, + dmxScreen->dndChildren[i].inputShape); + + xcb_shape_select_input (dmxScreen->connection, + dmxScreen->dndChildren[i].target, + 0); + } + + xfree (dmxScreen->dndChildren); + + dmxScreen->dndChildren = NULL; + dmxScreen->dndNChildren = 0; + } +} + static void dmxBEDnDHideProxyWindow (ScreenPtr pScreen) { @@ -523,13 +693,7 @@ dmxBEDnDHideProxyWindow (ScreenPtr pScreen) DefaultRootWindow (dmxScreen->beDisplay), dmxScreen->scrnEventMask); - if (dmxScreen->dndChildren) - { - xfree (dmxScreen->dndChildren); - - dmxScreen->dndChildren = NULL; - dmxScreen->dndNChildren = 0; - } + dmxDnDFreeChildren (pScreen); dmxScreen->dndSource = None; dmxScreen->queryTree.sequence = 0; @@ -1284,8 +1448,9 @@ dmxScreenEventCheckDnD (ScreenPtr pScreen, { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; xcb_map_notify_event_t *xmap = (xcb_map_notify_event_t *) event; + int reltype, type = event->response_type & 0x7f; - switch (event->response_type & ~0x80) { + switch (type) { case XCB_MAP_NOTIFY: if (xmap->window == dmxScreen->rootWin) return FALSE; @@ -1295,14 +1460,8 @@ dmxScreenEventCheckDnD (ScreenPtr pScreen, case XCB_CONFIGURE_NOTIFY: if (xmap->event != DefaultRootWindow (dmxScreen->beDisplay)) return FALSE; - - if (dmxScreen->dndChildren) - { - xfree (dmxScreen->dndChildren); - dmxScreen->dndChildren = NULL; - dmxScreen->dndNChildren = 0; - } + dmxDnDFreeChildren (pScreen); dmxScreen->queryTree.sequence = 0; @@ -1364,7 +1523,52 @@ dmxScreenEventCheckDnD (ScreenPtr pScreen, } } break; default: - return FALSE; + reltype = type - dmxScreen->beShapeEventBase; + + switch (reltype) { + case XCB_SHAPE_NOTIFY: { + xcb_shape_notify_event_t *xshape = + (xcb_shape_notify_event_t *) event; + int i; + + for (i = 0; i < dmxScreen->dndNChildren; i++) + if (dmxScreen->dndChildren[i].target == xshape->affected_window) + break; + + if (i < dmxScreen->dndNChildren) + { + xcb_shape_get_rectangles_cookie_t shape; + + switch (xshape->shape_kind) { + case ShapeBounding: + shape = xcb_shape_get_rectangles (dmxScreen->connection, + xshape->affected_window, + ShapeBounding); + dmxAddRequest (&dmxScreen->request, + dmxDnDBoundingShapeUpdateReply, + shape.sequence, + (void *) i); + + case ShapeInput: + shape = xcb_shape_get_rectangles (dmxScreen->connection, + xshape->affected_window, + ShapeInput); + dmxAddRequest (&dmxScreen->request, + dmxDnDInputShapeUpdateReply, + shape.sequence, + (void *) i); + default: + break; + } + } + else + { + return FALSE; + } + } break; + default: + return FALSE; + } } return TRUE; diff --git a/hw/dmx/dmxextension.c b/hw/dmx/dmxextension.c index 6aa3321f6..3764bf31f 100644 --- a/hw/dmx/dmxextension.c +++ b/hw/dmx/dmxextension.c @@ -1433,6 +1433,8 @@ dmxAttachScreen (int idx, ScreenPtr pScreen; DMXScreenInfo *dmxScreen; DMXScreenInfo oldDMXScreen; + Bool beShape = FALSE; + int errorBase; /* Return failure if dynamic addition/removal of screens is disabled */ if (!dmxAddRemoveScreens) { @@ -1493,6 +1495,23 @@ dmxAttachScreen (int idx, return 1; } + XLIB_PROLOGUE (dmxScreens); + beShape = XShapeQueryExtension (dmxScreen->beDisplay, + &dmxScreen->beShapeEventBase, + &errorBase); + XLIB_EPILOGUE (dmxScreen); + + if (!beShape) + { + dmxLogErrorSet (dmxWarning, errorSet, error, errorName, + "SHAPE extension missing"); + dmxCloseDisplay (dmxScreen); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + if (!dmxScreen->scrnWin) dmxScreen->scrnWin = DefaultRootWindow (dmxScreen->beDisplay);