Merge pull request #1475 from psychon/input-shape-support
Input shape support
This commit is contained in:
commit
cbd22eea50
10
awesome.c
10
awesome.c
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -288,6 +288,7 @@ end
|
|||
-- @tparam wibox.widget arg.widget The widget that the wibox displays.
|
||||
-- @param arg.shape_bounding The wibox’s bounding shape as a (native) cairo surface.
|
||||
-- @param arg.shape_clip The wibox’s clip shape as a (native) cairo surface.
|
||||
-- @param arg.shape_input The wibox’s 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.
|
||||
|
|
|
@ -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 wibox’s bounding shape as a (native) cairo surface.
|
||||
-- @param args.shape_clip The wibox’s clip shape as a (native) cairo surface.
|
||||
-- @param args.shape_input The wibox’s 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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
91
xwindow.c
91
xwindow.c
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue