Merge pull request #1475 from psychon/input-shape-support

Input shape support
This commit is contained in:
Emmanuel Lepage Vallée 2017-02-03 12:25:56 -05:00 committed by GitHub
commit cbd22eea50
8 changed files with 182 additions and 32 deletions

View File

@ -691,6 +691,16 @@ main(int argc, char **argv)
/* check for shape extension */
query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
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();

View File

@ -161,6 +161,15 @@
-- @property shape_clip
-- @param surface._native
--- The wibox's input shape as a (native) cairo surface.
--
-- **Signal:**
--
-- * *property::shape_input*
--
-- @property shape_input
-- @param surface._native
--- Get or set mouse buttons bindings to a wibox.
--
-- @param buttons_table A table of buttons objects, or nothing.

View File

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

View File

@ -288,6 +288,7 @@ end
-- @tparam wibox.widget arg.widget The widget that the wibox displays.
-- @param arg.shape_bounding The wiboxs bounding shape as a (native) cairo surface.
-- @param arg.shape_clip The wiboxs clip shape as a (native) cairo surface.
-- @param arg.shape_input The wiboxs input shape as a (native) cairo surface.
-- @tparam color arg.bg The background of the wibox.
-- @tparam surface arg.bgimage The background image of the drawable.
-- @tparam color arg.fg The foreground (text) of the wibox.

View File

@ -32,6 +32,7 @@ wibox.hierarchy = require("wibox.hierarchy")
local force_forward = {
shape_bounding = true,
shape_clip = true,
shape_input = true,
}
--@DOC_wibox_COMMON@
@ -178,6 +179,7 @@ local function setup_signals(_wibox)
clone_signal("property::geometry")
clone_signal("property::shape_bounding")
clone_signal("property::shape_clip")
clone_signal("property::shape_input")
obj = _wibox._drawable
clone_signal("button::press")
@ -205,6 +207,7 @@ end
-- @tparam wibox.widget args.widget The widget that the wibox displays.
-- @param args.shape_bounding The wiboxs bounding shape as a (native) cairo surface.
-- @param args.shape_clip The wiboxs clip shape as a (native) cairo surface.
-- @param args.shape_input The wiboxs input shape as a (native) cairo surface.
-- @tparam color args.bg The background of the wibox.
-- @tparam surface args.bgimage The background image of the drawable.
-- @tparam color args.fg The foreground (text) of the wibox.

View File

@ -669,6 +669,17 @@
* @param surface
*/
/**
* The client's input shape as set by awesome as a (native) cairo surface.
*
* **Signal:**
*
* * *property::shape\_input*
*
* @property shape_input
* @param surface
*/
/**
* The client's bounding shape as set by the program as a (native) cairo surface.
*
@ -3289,6 +3300,41 @@ luaA_client_set_shape_clip(lua_State *L, client_t *c)
return 0;
}
/** Get the client's frame window input shape.
* \param L The Lua VM state.
* \param client The client object.
* \return The number of elements pushed on stack.
*/
static int
luaA_client_get_shape_input(lua_State *L, client_t *c)
{
cairo_surface_t *surf = xwindow_get_shape(c->frame_window, XCB_SHAPE_SK_INPUT);
if (!surf)
return 0;
/* lua has to make sure to free the ref or we have a leak */
lua_pushlightuserdata(L, surf);
return 1;
}
/** Set the client's frame window input shape.
* \param L The Lua VM state.
* \param client The client object.
* \return The number of elements pushed on stack.
*/
static int
luaA_client_set_shape_input(lua_State *L, client_t *c)
{
cairo_surface_t *surf = NULL;
if(!lua_isnil(L, -1))
surf = (cairo_surface_t *)lua_touserdata(L, -1);
xwindow_set_shape(c->frame_window,
c->geometry.width + (c->border_width * 2),
c->geometry.height + (c->border_width * 2),
XCB_SHAPE_SK_INPUT, surf, -c->border_width);
luaA_object_emit_signal(L, -3, "property::shape_input", 0);
return 0;
}
/** Get or set keys bindings for a client.
*
* @param keys_table An array of key bindings objects, or nothing.
@ -3536,6 +3582,10 @@ client_class_setup(lua_State *L)
(lua_class_propfunc_t) luaA_client_set_shape_clip,
(lua_class_propfunc_t) luaA_client_get_shape_clip,
(lua_class_propfunc_t) luaA_client_set_shape_clip);
luaA_class_add_property(&client_class, "shape_input",
(lua_class_propfunc_t) luaA_client_set_shape_input,
(lua_class_propfunc_t) luaA_client_get_shape_input,
(lua_class_propfunc_t) luaA_client_set_shape_input);
luaA_class_add_property(&client_class, "startup_id",
NULL,
(lua_class_propfunc_t) luaA_client_get_startup_id,

View File

@ -63,6 +63,7 @@
* @field window The X window id.
* @field shape_bounding The drawin's bounding shape as a (native) cairo surface.
* @field shape_clip The drawin's clip shape as a (native) cairo surface.
* @field shape_input The drawin's input shape as a (native) cairo surface.
* @table drawin
*/
@ -78,6 +79,10 @@
* @signal property::shape_clip
*/
/**
* @signal property::shape_input
*/
/**
* @signal property::border_width
*/
@ -690,6 +695,45 @@ luaA_drawin_set_shape_clip(lua_State *L, drawin_t *drawin)
return 0;
}
/** Get the drawin's input shape.
* \param L The Lua VM state.
* \param drawin The drawin object.
* \return The number of elements pushed on stack.
*/
static int
luaA_drawin_get_shape_input(lua_State *L, drawin_t *drawin)
{
cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_INPUT);
if (!surf)
return 0;
/* lua has to make sure to free the ref or we have a leak */
lua_pushlightuserdata(L, surf);
return 1;
}
/** Set the drawin's input shape.
* \param L The Lua VM state.
* \param drawin The drawin object.
* \return The number of elements pushed on stack.
*/
static int
luaA_drawin_set_shape_input(lua_State *L, drawin_t *drawin)
{
cairo_surface_t *surf = NULL;
if(!lua_isnil(L, -1))
surf = (cairo_surface_t *)lua_touserdata(L, -1);
/* The drawin might have been resized to a larger size. Apply that. */
drawin_apply_moveresize(drawin);
xwindow_set_shape(drawin->window,
drawin->geometry.width + 2*drawin->border_width,
drawin->geometry.height + 2*drawin->border_width,
XCB_SHAPE_SK_INPUT, surf, -drawin->border_width);
luaA_object_emit_signal(L, -3, "property::shape_input", 0);
return 0;
}
void
drawin_class_setup(lua_State *L)
{
@ -758,6 +802,10 @@ drawin_class_setup(lua_State *L)
(lua_class_propfunc_t) luaA_drawin_set_shape_clip,
(lua_class_propfunc_t) luaA_drawin_get_shape_clip,
(lua_class_propfunc_t) luaA_drawin_set_shape_clip);
luaA_class_add_property(&drawin_class, "shape_input",
(lua_class_propfunc_t) luaA_drawin_set_shape_input,
(lua_class_propfunc_t) luaA_drawin_get_shape_input,
(lua_class_propfunc_t) luaA_drawin_set_shape_input);
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -265,44 +265,70 @@ xwindow_get_shape(xcb_window_t win, enum xcb_shape_sk_t kind)
{
if (!globalconf.have_shape)
return NULL;
xcb_shape_query_extents_cookie_t ecookie = xcb_shape_query_extents(globalconf.connection, win);
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);
}
if (kind == XCB_SHAPE_SK_INPUT && !globalconf.have_input_shape)
return NULL;
int16_t x, y;
uint16_t width, height;
bool shaped;
if (kind == XCB_SHAPE_SK_BOUNDING)
xcb_shape_get_rectangles_cookie_t rcookie = xcb_shape_get_rectangles(globalconf.connection, win, kind);
if (kind == XCB_SHAPE_SK_INPUT)
{
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;
/* We cannot query the size/existence of an input shape... */
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(globalconf.connection,
xcb_get_geometry(globalconf.connection, win), NULL);
if (!geom)
{
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);
}
x = 0;
y = 0;
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);
free(rects_reply);
return NULL;
/* Create a cairo surface in an error state */
return cairo_image_surface_create(CAIRO_FORMAT_INVALID, -1, -1);
}
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_destroy(cr);
free(extents);
free(rects_reply);
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)
return;
if (kind == XCB_SHAPE_SK_INPUT && !globalconf.have_input_shape)
return;
xcb_pixmap_t pixmap = XCB_NONE;
if (surf)