xwindow: Add support for input shape from SHAPE 1.1

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2017-01-26 10:43:49 +01:00
parent 2d736bf3b5
commit 64e05c236f
3 changed files with 71 additions and 32 deletions

View File

@ -661,6 +661,16 @@ main(int argc, char **argv)
/* check for shape extension */ /* check for shape extension */
query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id); query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
globalconf.have_shape = query && query->present; globalconf.have_shape = query && query->present;
if (globalconf.have_shape)
{
xcb_shape_query_version_reply_t *reply =
xcb_shape_query_version_reply(globalconf.connection,
xcb_shape_query_version_unchecked(globalconf.connection),
NULL);
globalconf.have_input_shape = reply && (reply->major_version > 1 ||
(reply->major_version == 1 && reply->minor_version >= 1));
p_delete(&reply);
}
event_init(); event_init();

View File

@ -106,6 +106,8 @@ typedef struct
bool have_xtest; bool have_xtest;
/** Check for SHAPE extension */ /** Check for SHAPE extension */
bool have_shape; bool have_shape;
/** Check for SHAPE extension with input shape support */
bool have_input_shape;
/** Check for XKB extension */ /** Check for XKB extension */
bool have_xkb; bool have_xkb;
uint8_t event_base_shape; uint8_t event_base_shape;

View File

@ -265,44 +265,70 @@ xwindow_get_shape(xcb_window_t win, enum xcb_shape_sk_t kind)
{ {
if (!globalconf.have_shape) if (!globalconf.have_shape)
return NULL; return NULL;
if (kind == XCB_SHAPE_SK_INPUT && !globalconf.have_input_shape)
xcb_shape_query_extents_cookie_t ecookie = xcb_shape_query_extents(globalconf.connection, win); return NULL;
xcb_shape_get_rectangles_cookie_t rcookie = xcb_shape_get_rectangles(globalconf.connection, win, kind);
xcb_shape_query_extents_reply_t *extents = xcb_shape_query_extents_reply(globalconf.connection, ecookie, NULL);
xcb_shape_get_rectangles_reply_t *rects_reply = xcb_shape_get_rectangles_reply(globalconf.connection, rcookie, NULL);
if (!extents || !rects_reply)
{
free(extents);
free(rects_reply);
/* Create a cairo surface in an error state */
return cairo_image_surface_create(CAIRO_FORMAT_INVALID, -1, -1);
}
int16_t x, y; int16_t x, y;
uint16_t width, height; uint16_t width, height;
bool shaped; xcb_shape_get_rectangles_cookie_t rcookie = xcb_shape_get_rectangles(globalconf.connection, win, kind);
if (kind == XCB_SHAPE_SK_BOUNDING) if (kind == XCB_SHAPE_SK_INPUT)
{ {
x = extents->bounding_shape_extents_x; /* We cannot query the size/existence of an input shape... */
y = extents->bounding_shape_extents_y; xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(globalconf.connection,
width = extents->bounding_shape_extents_width; xcb_get_geometry(globalconf.connection, win), NULL);
height = extents->bounding_shape_extents_height; if (!geom)
shaped = extents->bounding_shaped; {
} else { xcb_discard_reply(globalconf.connection, rcookie.sequence);
assert(kind == XCB_SHAPE_SK_CLIP); /* Create a cairo surface in an error state */
x = extents->clip_shape_extents_x; return cairo_image_surface_create(CAIRO_FORMAT_INVALID, -1, -1);
y = extents->clip_shape_extents_y; }
width = extents->clip_shape_extents_width; x = 0;
height = extents->clip_shape_extents_height; y = 0;
shaped = extents->clip_shaped; width = geom->width;
height = geom->height;
}
else
{
xcb_shape_query_extents_cookie_t ecookie = xcb_shape_query_extents(globalconf.connection, win);
xcb_shape_query_extents_reply_t *extents = xcb_shape_query_extents_reply(globalconf.connection, ecookie, NULL);
bool shaped;
if (!extents)
{
xcb_discard_reply(globalconf.connection, rcookie.sequence);
/* Create a cairo surface in an error state */
return cairo_image_surface_create(CAIRO_FORMAT_INVALID, -1, -1);
}
if (kind == XCB_SHAPE_SK_BOUNDING)
{
x = extents->bounding_shape_extents_x;
y = extents->bounding_shape_extents_y;
width = extents->bounding_shape_extents_width;
height = extents->bounding_shape_extents_height;
shaped = extents->bounding_shaped;
} else {
assert(kind == XCB_SHAPE_SK_CLIP);
x = extents->clip_shape_extents_x;
y = extents->clip_shape_extents_y;
width = extents->clip_shape_extents_width;
height = extents->clip_shape_extents_height;
shaped = extents->clip_shaped;
}
p_delete(&extents);
if (!shaped)
{
xcb_discard_reply(globalconf.connection, rcookie.sequence);
return NULL;
}
} }
if (!shaped) xcb_shape_get_rectangles_reply_t *rects_reply = xcb_shape_get_rectangles_reply(globalconf.connection, rcookie, NULL);
if (!rects_reply)
{ {
free(extents); /* Create a cairo surface in an error state */
free(rects_reply); return cairo_image_surface_create(CAIRO_FORMAT_INVALID, -1, -1);
return NULL;
} }
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height);
@ -318,7 +344,6 @@ xwindow_get_shape(xcb_window_t win, enum xcb_shape_sk_t kind)
cairo_fill(cr); cairo_fill(cr);
cairo_destroy(cr); cairo_destroy(cr);
free(extents);
free(rects_reply); free(rects_reply);
return surface; return surface;
} }
@ -356,6 +381,8 @@ xwindow_set_shape(xcb_window_t win, int width, int height, enum xcb_shape_sk_t k
{ {
if (!globalconf.have_shape) if (!globalconf.have_shape)
return; return;
if (kind == XCB_SHAPE_SK_INPUT && !globalconf.have_input_shape)
return;
xcb_pixmap_t pixmap = XCB_NONE; xcb_pixmap_t pixmap = XCB_NONE;
if (surf) if (surf)