Finish C-side support for window shapes (FS#1051)
A drawin's and a client's bounding and clip shape can now be queried and is returned as a cairo surface. Also, a client window's shape (e.g. xeyes setting its own shape) can be queried via c.shape_client_bounding and c.shape_client_clip. All of these properties now emit signals when changed. (This also silently fixes a bug in luaA_drawin_set_shape_bounding() which forgot to include the drawin's border in its size calculation) Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
5cd8c7e540
commit
56c5797905
10
awesome.c
10
awesome.c
|
@ -460,9 +460,13 @@ main(int argc, char **argv)
|
||||||
xcb_prefetch_maximum_request_length(globalconf.connection);
|
xcb_prefetch_maximum_request_length(globalconf.connection);
|
||||||
|
|
||||||
/* check for xtest extension */
|
/* check for xtest extension */
|
||||||
const xcb_query_extension_reply_t *xtest_query;
|
const xcb_query_extension_reply_t *query;
|
||||||
xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id);
|
query = xcb_get_extension_data(globalconf.connection, &xcb_test_id);
|
||||||
globalconf.have_xtest = xtest_query->present;
|
globalconf.have_xtest = query->present;
|
||||||
|
|
||||||
|
/* check for shape extension */
|
||||||
|
query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
|
||||||
|
globalconf.have_shape = query->present;
|
||||||
|
|
||||||
/* Allocate the key symbols */
|
/* Allocate the key symbols */
|
||||||
globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection);
|
globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection);
|
||||||
|
|
30
event.c
30
event.c
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
#include <xcb/shape.h>
|
||||||
#include <xcb/xcb_atom.h>
|
#include <xcb/xcb_atom.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_event.h>
|
#include <xcb/xcb_event.h>
|
||||||
|
@ -686,6 +687,24 @@ event_handle_randr_screen_change_notify(xcb_randr_screen_change_notify_event_t *
|
||||||
awesome_restart();
|
awesome_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The shape notify event handler.
|
||||||
|
* \param ev The event.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
event_handle_shape_notify(xcb_shape_notify_event_t *ev)
|
||||||
|
{
|
||||||
|
client_t *c = client_getbywin(ev->affected_window);
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
luaA_object_push(globalconf.L, c);
|
||||||
|
if (ev->shape_kind == XCB_SHAPE_SK_BOUNDING)
|
||||||
|
luaA_object_emit_signal(globalconf.L, -1, "property::shape_client_bounding", 0);
|
||||||
|
if (ev->shape_kind == XCB_SHAPE_SK_CLIP)
|
||||||
|
luaA_object_emit_signal(globalconf.L, -1, "property::shape_client_clip", 0);
|
||||||
|
lua_pop(globalconf.L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The client message event handler.
|
/** The client message event handler.
|
||||||
* \param ev The event.
|
* \param ev The event.
|
||||||
*/
|
*/
|
||||||
|
@ -829,6 +848,7 @@ void event_handle(xcb_generic_event_t *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t randr_screen_change_notify = 0;
|
static uint8_t randr_screen_change_notify = 0;
|
||||||
|
static uint8_t shape_notify = 0;
|
||||||
|
|
||||||
if(randr_screen_change_notify == 0)
|
if(randr_screen_change_notify == 0)
|
||||||
{
|
{
|
||||||
|
@ -838,9 +858,19 @@ void event_handle(xcb_generic_event_t *event)
|
||||||
if(randr_query->present)
|
if(randr_query->present)
|
||||||
randr_screen_change_notify = randr_query->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
|
randr_screen_change_notify = randr_query->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
|
||||||
}
|
}
|
||||||
|
if(shape_notify == 0)
|
||||||
|
{
|
||||||
|
/* check for shape extension */
|
||||||
|
const xcb_query_extension_reply_t *shape_query;
|
||||||
|
shape_query = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
|
||||||
|
if(shape_query->present)
|
||||||
|
shape_notify = shape_query->first_event + XCB_SHAPE_NOTIFY;
|
||||||
|
}
|
||||||
|
|
||||||
if (response_type == randr_screen_change_notify)
|
if (response_type == randr_screen_change_notify)
|
||||||
event_handle_randr_screen_change_notify((void *) event);
|
event_handle_randr_screen_change_notify((void *) event);
|
||||||
|
if (response_type == shape_notify)
|
||||||
|
event_handle_shape_notify((void *) event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -83,6 +83,8 @@ typedef struct
|
||||||
uint16_t numlockmask, shiftlockmask, capslockmask, modeswitchmask;
|
uint16_t numlockmask, shiftlockmask, capslockmask, modeswitchmask;
|
||||||
/** Check for XTest extension */
|
/** Check for XTest extension */
|
||||||
bool have_xtest;
|
bool have_xtest;
|
||||||
|
/** Check for SHAPE extension */
|
||||||
|
bool have_shape;
|
||||||
/** Clients list */
|
/** Clients list */
|
||||||
client_array_t clients;
|
client_array_t clients;
|
||||||
/** Embedded windows */
|
/** Embedded windows */
|
||||||
|
|
|
@ -41,8 +41,10 @@ module("client")
|
||||||
-- @field sticky Set the client sticky, i.e. available on all tags.
|
-- @field sticky Set the client sticky, i.e. available on all tags.
|
||||||
-- @field modal Indicate if the client is modal.
|
-- @field modal Indicate if the client is modal.
|
||||||
-- @field focusable True if the client can receive the input focus.
|
-- @field focusable True if the client can receive the input focus.
|
||||||
-- @field shape_bounding The client's bounding shape as a (native) cairo surface.
|
-- @field shape_bounding The client's bounding shape as set by awesome as a (native) cairo surface.
|
||||||
-- @field shape_clip The client's clip shape as a (native) cairo surface.
|
-- @field shape_clip The client's clip shape as set by awesome as a (native) cairo surface.
|
||||||
|
-- @field shape_client_bounding The client's bounding shape as set by the program as a (native) cairo surface.
|
||||||
|
-- @field shape_client_clip The client's clip shape as set by the program as a (native) cairo surface.
|
||||||
-- @class table
|
-- @class table
|
||||||
-- @name client
|
-- @name client
|
||||||
|
|
||||||
|
|
|
@ -440,6 +440,8 @@ client_manage(xcb_window_t w, xcb_get_geometry_reply_t *wgeom, bool startup)
|
||||||
|
|
||||||
/* Make sure the window is automatically mapped if awesome exits or dies. */
|
/* Make sure the window is automatically mapped if awesome exits or dies. */
|
||||||
xcb_change_save_set(globalconf.connection, XCB_SET_MODE_INSERT, w);
|
xcb_change_save_set(globalconf.connection, XCB_SET_MODE_INSERT, w);
|
||||||
|
if (globalconf.have_shape)
|
||||||
|
xcb_shape_select_input(globalconf.connection, w, 1);
|
||||||
|
|
||||||
client_t *c = client_new(globalconf.L);
|
client_t *c = client_new(globalconf.L);
|
||||||
xcb_screen_t *s = globalconf.screen;
|
xcb_screen_t *s = globalconf.screen;
|
||||||
|
@ -1198,6 +1200,8 @@ client_unmanage(client_t *c, bool window_valid)
|
||||||
/* Remove this window from the save set since this shouldn't be made visible
|
/* Remove this window from the save set since this shouldn't be made visible
|
||||||
* after a restart anymore. */
|
* after a restart anymore. */
|
||||||
xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, c->window);
|
xcb_change_save_set(globalconf.connection, XCB_SET_MODE_DELETE, c->window);
|
||||||
|
if (globalconf.have_shape)
|
||||||
|
xcb_shape_select_input(globalconf.connection, c->window, 0);
|
||||||
|
|
||||||
/* Do this last to avoid races with clients. According to ICCCM, clients
|
/* Do this last to avoid races with clients. According to ICCCM, clients
|
||||||
* arent allowed to re-use the window until after this. */
|
* arent allowed to re-use the window until after this. */
|
||||||
|
@ -1972,7 +1976,39 @@ luaA_client_get_size_hints(lua_State *L, client_t *c)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the client's bounding shape.
|
/** Get the client's child window bounding 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_client_shape_bounding(lua_State *L, client_t *c)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(c->window, XCB_SHAPE_SK_BOUNDING);
|
||||||
|
if (!surf)
|
||||||
|
return 0;
|
||||||
|
/* lua has to make sure to free the ref or we have a leak */
|
||||||
|
lua_pushlightuserdata(L, surf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the client's frame window bounding 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_bounding(lua_State *L, client_t *c)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(c->frame_window, XCB_SHAPE_SK_BOUNDING);
|
||||||
|
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 bounding shape.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \param client The client object.
|
* \param client The client object.
|
||||||
* \return The number of elements pushed on stack.
|
* \return The number of elements pushed on stack.
|
||||||
|
@ -1987,10 +2023,43 @@ luaA_client_set_shape_bounding(lua_State *L, client_t *c)
|
||||||
c->geometry.width + (c->border_width * 2),
|
c->geometry.width + (c->border_width * 2),
|
||||||
c->geometry.height + (c->border_width * 2),
|
c->geometry.height + (c->border_width * 2),
|
||||||
XCB_SHAPE_SK_BOUNDING, surf, -c->border_width);
|
XCB_SHAPE_SK_BOUNDING, surf, -c->border_width);
|
||||||
|
luaA_object_emit_signal(L, -3, "property::shape_bounding", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the client's clip shape.
|
/** Get the client's child window clip 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_client_shape_clip(lua_State *L, client_t *c)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(c->window, XCB_SHAPE_SK_CLIP);
|
||||||
|
if (!surf)
|
||||||
|
return 0;
|
||||||
|
/* lua has to make sure to free the ref or we have a leak */
|
||||||
|
lua_pushlightuserdata(L, surf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the client's frame window clip 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_clip(lua_State *L, client_t *c)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(c->frame_window, XCB_SHAPE_SK_CLIP);
|
||||||
|
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 clip shape.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \param client The client object.
|
* \param client The client object.
|
||||||
* \return The number of elements pushed on stack.
|
* \return The number of elements pushed on stack.
|
||||||
|
@ -2003,6 +2072,7 @@ luaA_client_set_shape_clip(lua_State *L, client_t *c)
|
||||||
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
||||||
xwindow_set_shape(c->frame_window, c->geometry.width, c->geometry.height,
|
xwindow_set_shape(c->frame_window, c->geometry.width, c->geometry.height,
|
||||||
XCB_SHAPE_SK_CLIP, surf, 0);
|
XCB_SHAPE_SK_CLIP, surf, 0);
|
||||||
|
luaA_object_emit_signal(L, -3, "property::shape_clip", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2226,12 +2296,20 @@ client_class_setup(lua_State *L)
|
||||||
NULL);
|
NULL);
|
||||||
luaA_class_add_property(&client_class, "shape_bounding",
|
luaA_class_add_property(&client_class, "shape_bounding",
|
||||||
(lua_class_propfunc_t) luaA_client_set_shape_bounding,
|
(lua_class_propfunc_t) luaA_client_set_shape_bounding,
|
||||||
NULL,
|
(lua_class_propfunc_t) luaA_client_get_shape_bounding,
|
||||||
(lua_class_propfunc_t) luaA_client_set_shape_bounding);
|
(lua_class_propfunc_t) luaA_client_set_shape_bounding);
|
||||||
luaA_class_add_property(&client_class, "shape_clip",
|
luaA_class_add_property(&client_class, "shape_clip",
|
||||||
(lua_class_propfunc_t) luaA_client_set_shape_clip,
|
(lua_class_propfunc_t) luaA_client_set_shape_clip,
|
||||||
NULL,
|
(lua_class_propfunc_t) luaA_client_get_shape_clip,
|
||||||
(lua_class_propfunc_t) luaA_client_set_shape_clip);
|
(lua_class_propfunc_t) luaA_client_set_shape_clip);
|
||||||
|
luaA_class_add_property(&client_class, "client_shape_bounding",
|
||||||
|
NULL,
|
||||||
|
(lua_class_propfunc_t) luaA_client_get_client_shape_bounding,
|
||||||
|
NULL);
|
||||||
|
luaA_class_add_property(&client_class, "client_shape_clip",
|
||||||
|
NULL,
|
||||||
|
(lua_class_propfunc_t) luaA_client_get_client_shape_clip,
|
||||||
|
NULL);
|
||||||
|
|
||||||
signal_add(&client_class.signals, "focus");
|
signal_add(&client_class.signals, "focus");
|
||||||
signal_add(&client_class.signals, "list");
|
signal_add(&client_class.signals, "list");
|
||||||
|
@ -2263,6 +2341,10 @@ client_class_setup(lua_State *L)
|
||||||
signal_add(&client_class.signals, "property::pid");
|
signal_add(&client_class.signals, "property::pid");
|
||||||
signal_add(&client_class.signals, "property::role");
|
signal_add(&client_class.signals, "property::role");
|
||||||
signal_add(&client_class.signals, "property::screen");
|
signal_add(&client_class.signals, "property::screen");
|
||||||
|
signal_add(&client_class.signals, "property::shape_bounding");
|
||||||
|
signal_add(&client_class.signals, "property::shape_client_bounding");
|
||||||
|
signal_add(&client_class.signals, "property::shape_client_clip");
|
||||||
|
signal_add(&client_class.signals, "property::shape_clip");
|
||||||
signal_add(&client_class.signals, "property::size_hints_honor");
|
signal_add(&client_class.signals, "property::size_hints_honor");
|
||||||
signal_add(&client_class.signals, "property::skip_taskbar");
|
signal_add(&client_class.signals, "property::skip_taskbar");
|
||||||
signal_add(&client_class.signals, "property::sticky");
|
signal_add(&client_class.signals, "property::sticky");
|
||||||
|
|
|
@ -536,6 +536,22 @@ luaA_drawin_get_drawable(lua_State *L, drawin_t *drawin)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the drawin's bounding 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_bounding(lua_State *L, drawin_t *drawin)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_BOUNDING);
|
||||||
|
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 bounding shape.
|
/** Set the drawin's bounding shape.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \param drawin The drawin object.
|
* \param drawin The drawin object.
|
||||||
|
@ -547,11 +563,30 @@ luaA_drawin_set_shape_bounding(lua_State *L, drawin_t *drawin)
|
||||||
cairo_surface_t *surf = NULL;
|
cairo_surface_t *surf = NULL;
|
||||||
if(!lua_isnil(L, -1))
|
if(!lua_isnil(L, -1))
|
||||||
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
||||||
xwindow_set_shape(drawin->window, drawin->geometry.width, drawin->geometry.height,
|
xwindow_set_shape(drawin->window,
|
||||||
|
drawin->geometry.width + 2*drawin->border_width,
|
||||||
|
drawin->geometry.height + 2*drawin->border_width,
|
||||||
XCB_SHAPE_SK_BOUNDING, surf, -drawin->border_width);
|
XCB_SHAPE_SK_BOUNDING, surf, -drawin->border_width);
|
||||||
|
luaA_object_emit_signal(L, -3, "property::shape_bounding", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the drawin's clip 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_clip(lua_State *L, drawin_t *drawin)
|
||||||
|
{
|
||||||
|
cairo_surface_t *surf = xwindow_get_shape(drawin->window, XCB_SHAPE_SK_CLIP);
|
||||||
|
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 clip shape.
|
/** Set the drawin's clip shape.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \param drawin The drawin object.
|
* \param drawin The drawin object.
|
||||||
|
@ -565,6 +600,7 @@ luaA_drawin_set_shape_clip(lua_State *L, drawin_t *drawin)
|
||||||
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
surf = (cairo_surface_t *)lua_touserdata(L, -1);
|
||||||
xwindow_set_shape(drawin->window, drawin->geometry.width, drawin->geometry.height,
|
xwindow_set_shape(drawin->window, drawin->geometry.width, drawin->geometry.height,
|
||||||
XCB_SHAPE_SK_CLIP, surf, 0);
|
XCB_SHAPE_SK_CLIP, surf, 0);
|
||||||
|
luaA_object_emit_signal(L, -3, "property::shape_clip", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,13 +666,15 @@ drawin_class_setup(lua_State *L)
|
||||||
(lua_class_propfunc_t) luaA_window_set_type);
|
(lua_class_propfunc_t) luaA_window_set_type);
|
||||||
luaA_class_add_property(&drawin_class, "shape_bounding",
|
luaA_class_add_property(&drawin_class, "shape_bounding",
|
||||||
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding,
|
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding,
|
||||||
NULL,
|
(lua_class_propfunc_t) luaA_drawin_get_shape_bounding,
|
||||||
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding);
|
(lua_class_propfunc_t) luaA_drawin_set_shape_bounding);
|
||||||
luaA_class_add_property(&drawin_class, "shape_clip",
|
luaA_class_add_property(&drawin_class, "shape_clip",
|
||||||
(lua_class_propfunc_t) luaA_drawin_set_shape_clip,
|
(lua_class_propfunc_t) luaA_drawin_set_shape_clip,
|
||||||
NULL,
|
(lua_class_propfunc_t) luaA_drawin_get_shape_clip,
|
||||||
(lua_class_propfunc_t) luaA_drawin_set_shape_clip);
|
(lua_class_propfunc_t) luaA_drawin_set_shape_clip);
|
||||||
|
|
||||||
|
signal_add(&client_class.signals, "property::shape_bounding");
|
||||||
|
signal_add(&client_class.signals, "property::shape_clip");
|
||||||
signal_add(&drawin_class.signals, "property::border_width");
|
signal_add(&drawin_class.signals, "property::border_width");
|
||||||
signal_add(&drawin_class.signals, "property::cursor");
|
signal_add(&drawin_class.signals, "property::cursor");
|
||||||
signal_add(&drawin_class.signals, "property::height");
|
signal_add(&drawin_class.signals, "property::height");
|
||||||
|
|
67
xwindow.c
67
xwindow.c
|
@ -258,6 +258,70 @@ xwindow_set_border_color(xcb_window_t w, color_t *color)
|
||||||
xcb_change_window_attributes(globalconf.connection, w, XCB_CW_BORDER_PIXEL, &color->pixel);
|
xcb_change_window_attributes(globalconf.connection, w, XCB_CW_BORDER_PIXEL, &color->pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get one of a window's shapes as a cairo surface */
|
||||||
|
cairo_surface_t *
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t x, y;
|
||||||
|
uint16_t width, height;
|
||||||
|
bool shaped;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shaped)
|
||||||
|
{
|
||||||
|
free(extents);
|
||||||
|
free(rects_reply);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A1, width, height);
|
||||||
|
cairo_t *cr = cairo_create(surface);
|
||||||
|
int num_rects = xcb_shape_get_rectangles_rectangles_length(rects_reply);
|
||||||
|
xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(rects_reply);
|
||||||
|
|
||||||
|
cairo_surface_set_device_offset(surface, -x, -y);
|
||||||
|
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_rects; i++)
|
||||||
|
cairo_rectangle(cr, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||||
|
cairo_fill(cr);
|
||||||
|
|
||||||
|
cairo_destroy(cr);
|
||||||
|
free(extents);
|
||||||
|
free(rects_reply);
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
/** Turn a cairo surface into a pixmap with depth 1 */
|
/** Turn a cairo surface into a pixmap with depth 1 */
|
||||||
static xcb_pixmap_t
|
static xcb_pixmap_t
|
||||||
xwindow_shape_pixmap(int width, int height, cairo_surface_t *surf)
|
xwindow_shape_pixmap(int width, int height, cairo_surface_t *surf)
|
||||||
|
@ -286,6 +350,9 @@ xwindow_shape_pixmap(int width, int height, cairo_surface_t *surf)
|
||||||
void
|
void
|
||||||
xwindow_set_shape(xcb_window_t win, int width, int height, enum xcb_shape_sk_t kind, cairo_surface_t *surf, int offset)
|
xwindow_set_shape(xcb_window_t win, int width, int height, enum xcb_shape_sk_t kind, cairo_surface_t *surf, int offset)
|
||||||
{
|
{
|
||||||
|
if (!globalconf.have_shape)
|
||||||
|
return;
|
||||||
|
|
||||||
xcb_pixmap_t pixmap = XCB_NONE;
|
xcb_pixmap_t pixmap = XCB_NONE;
|
||||||
if (surf)
|
if (surf)
|
||||||
pixmap = xwindow_shape_pixmap(width, height, surf);
|
pixmap = xwindow_shape_pixmap(width, height, surf);
|
||||||
|
|
|
@ -40,6 +40,7 @@ void xwindow_grabkeys(xcb_window_t, key_array_t *);
|
||||||
void xwindow_takefocus(xcb_window_t);
|
void xwindow_takefocus(xcb_window_t);
|
||||||
void xwindow_set_cursor(xcb_window_t, xcb_cursor_t);
|
void xwindow_set_cursor(xcb_window_t, xcb_cursor_t);
|
||||||
void xwindow_set_border_color(xcb_window_t, color_t *);
|
void xwindow_set_border_color(xcb_window_t, color_t *);
|
||||||
|
cairo_surface_t *xwindow_get_shape(xcb_window_t, enum xcb_shape_sk_t);
|
||||||
void xwindow_set_shape(xcb_window_t, int, int, enum xcb_shape_sk_t, cairo_surface_t *, int);
|
void xwindow_set_shape(xcb_window_t, int, int, enum xcb_shape_sk_t, cairo_surface_t *, int);
|
||||||
void xwindow_translate_for_gravity(xcb_gravity_t, int16_t, int16_t, int16_t, int16_t, int16_t *, int16_t *);
|
void xwindow_translate_for_gravity(xcb_gravity_t, int16_t, int16_t, int16_t, int16_t, int16_t *, int16_t *);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue