diff --git a/awesomeConfig.cmake b/awesomeConfig.cmake index 6d2e9a47..eeb263cb 100644 --- a/awesomeConfig.cmake +++ b/awesomeConfig.cmake @@ -139,6 +139,7 @@ pkg_check_modules(AWESOME_REQUIRED REQUIRED xcb-randr xcb-xtest xcb-xinerama + xcb-shape xcb-event>=0.3.4 xcb-aux>=0.3.0 xcb-atom>=0.3.0 diff --git a/common/tokenize.gperf b/common/tokenize.gperf index 8713fdd2..afe36afb 100644 --- a/common/tokenize.gperf +++ b/common/tokenize.gperf @@ -89,6 +89,8 @@ role screen selected session +shape_bounding +shape_clip Shift size_hints size_hints_honor diff --git a/swindow.c b/swindow.c index 6357bd62..21a4eb33 100644 --- a/swindow.c +++ b/swindow.c @@ -22,12 +22,67 @@ #include #include +#include #include "structs.h" #include "swindow.h" #include "draw.h" #include "common/xutil.h" +static int +have_shape(void) +{ + const xcb_query_extension_reply_t *reply; + + reply = xcb_get_extension_data(globalconf.connection, &xcb_shape_id); + if (!reply || !reply->present) + return 0; + + /* We don't need a specific version of SHAPE, no version check required */ + return 1; +} + +static void +do_update_shape(xcb_window_t win, xcb_shape_kind_t kind, image_t *image, int offset) +{ + xcb_pixmap_t shape; + + if(image) + shape = image_to_1bit_pixmap(image, win); + else + /* Reset the shape */ + shape = XCB_NONE; + + xcb_shape_mask(globalconf.connection, XCB_SHAPE_SO_SET, kind, + win, offset, offset, shape); + + if (shape != XCB_NONE) + xcb_free_pixmap(globalconf.connection, shape); +} + +/** Update the window's shape. + * \param sw The simplw window whose shape should be updated. + */ +void +simplewindow_update_shape(simple_window_t *sw) +{ + if(sw->window == XCB_NONE) + return; + + if(!have_shape()) + { + static bool warned = false; + if (!warned) + warn("The X server doesn't have the SHAPE extension; " + "can't change window's shape"); + warned = true; + return; + } + + do_update_shape(sw->window, XCB_SHAPE_SK_CLIP, sw->shape.clip, 0); + do_update_shape(sw->window, XCB_SHAPE_SK_BOUNDING, sw->shape.bounding, -sw->border.width); +} + static void simplewindow_draw_context_update(simple_window_t *sw, xcb_screen_t *s) { @@ -127,6 +182,8 @@ simplewindow_init(simple_window_t *sw, /* The default GC is just a newly created associated to the root window */ sw->gc = xcb_generate_id(globalconf.connection); xcb_create_gc(globalconf.connection, sw->gc, s->root, gc_mask, gc_values); + + simplewindow_update_shape(sw); } /** Destroy all resources of a simple window. diff --git a/swindow.h b/swindow.h index fcf8d9ed..d199aeae 100644 --- a/swindow.h +++ b/swindow.h @@ -55,6 +55,14 @@ typedef struct simple_window_t orientation_t orientation; /** Opacity */ double opacity; + /** The window's shape */ + struct + { + /** The window's content */ + image_t *clip; + /** The window's content and border */ + image_t *bounding; + } shape; } simple_window_t; void simplewindow_init(simple_window_t *s, @@ -71,6 +79,7 @@ void simplewindow_border_width_set(simple_window_t *, uint32_t); void simplewindow_border_color_set(simple_window_t *, const xcolor_t *); void simplewindow_orientation_set(simple_window_t *, orientation_t); void simplewindow_cursor_set(simple_window_t *, xcb_cursor_t); +void simplewindow_update_shape(simple_window_t *); /** Refresh the window content by copying its pixmap data to its window. * \param sw The simple window to refresh. diff --git a/wibox.c b/wibox.c index ae2ae1a3..cc9e253e 100644 --- a/wibox.c +++ b/wibox.c @@ -326,8 +326,15 @@ void wibox_refresh(void) { foreach(w, globalconf.wiboxes) + { + if((*w)->need_shape_update) + { + simplewindow_update_shape(&(*w)->sw); + (*w)->need_shape_update = false; + } if((*w)->need_update) wibox_draw(*w); + } foreach(_c, globalconf.clients) { @@ -568,6 +575,8 @@ luaA_wibox_invalidate_byitem(lua_State *L, const void *item) * \lfield opacity The opacity of the wibox, between 0 and 1. * \lfield mouse_enter A function to execute when the mouse enter the widget. * \lfield mouse_leave A function to execute when the mouse leave the widget. + * \lfield shape_clip Image describing the window's content shape. + * \lfield shape_bounding Image describing the window's border shape. */ static int luaA_wibox_index(lua_State *L) @@ -652,6 +661,12 @@ luaA_wibox_index(lua_State *L) else return 0; return 1; + case A_TK_SHAPE_BOUNDING: + image_push(L, wibox->sw.shape.bounding); + break; + case A_TK_SHAPE_CLIP: + image_push(L, wibox->sw.shape.clip); + break; default: return 0; } @@ -855,6 +870,16 @@ luaA_wibox_newindex(lua_State *L) case A_TK_MOUSE_LEAVE: luaA_registerfct(L, 3, &wibox->mouse_leave); return 0; + case A_TK_SHAPE_BOUNDING: + image_unref(L, wibox->sw.shape.bounding); + wibox->sw.shape.bounding = image_ref(L, 3); + wibox->need_shape_update = true; + break; + case A_TK_SHAPE_CLIP: + image_unref(L, wibox->sw.shape.clip); + wibox->sw.shape.clip = image_ref(L, 3); + wibox->need_shape_update = true; + break; default: switch(wibox->type) { diff --git a/wibox.h b/wibox.h index 5f548d0f..583a1937 100644 --- a/wibox.h +++ b/wibox.h @@ -59,6 +59,8 @@ struct wibox_t luaA_ref mouse_enter, mouse_leave; /** Need update */ bool need_update; + /** Need shape update */ + bool need_shape_update; /** Cursor */ char *cursor; /** Background image */