Implement icon_pixmap and icon_mask from WM_HINTS (FS#1297)
Fun fact: ICCCM specifies that icon_pixmap must have depth 1. Xterm uses a pixmap with depth 24. Yay... As such, I don't have any test for the depth == 1 case and will just assume that it does the right thing. If it doesn't, I bet no one will notice anyway. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
b9ea9255e9
commit
30b313f77a
25
draw.c
25
draw.c
|
@ -188,6 +188,18 @@ draw_surface_from_pixbuf(GdkPixbuf *buf)
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_surface_size(cairo_surface_t *surface, int *width, int *height)
|
||||||
|
{
|
||||||
|
double x1, y1, x2, y2;
|
||||||
|
cairo_t *cr = cairo_create(surface);
|
||||||
|
|
||||||
|
cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
*width = x2 - x1;
|
||||||
|
*height = y2 - y1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Duplicate the specified image surface.
|
/** Duplicate the specified image surface.
|
||||||
* \param surface The surface to copy
|
* \param surface The surface to copy
|
||||||
* \return A pointer to a new cairo image surface.
|
* \return A pointer to a new cairo image surface.
|
||||||
|
@ -195,10 +207,15 @@ draw_surface_from_pixbuf(GdkPixbuf *buf)
|
||||||
cairo_surface_t *
|
cairo_surface_t *
|
||||||
draw_dup_image_surface(cairo_surface_t *surface)
|
draw_dup_image_surface(cairo_surface_t *surface)
|
||||||
{
|
{
|
||||||
cairo_surface_t *res = cairo_image_surface_create(
|
cairo_surface_t *res;
|
||||||
cairo_image_surface_get_format(surface),
|
int width, height;
|
||||||
cairo_image_surface_get_width(surface),
|
|
||||||
cairo_image_surface_get_height(surface));
|
get_surface_size(surface, &width, &height);
|
||||||
|
#if CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR > 12
|
||||||
|
res = cairo_surface_create_similar_image(surface, CAIRO_FORMAT_ARGB32, width, height);
|
||||||
|
#else
|
||||||
|
res = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
cairo_t *cr = cairo_create(res);
|
cairo_t *cr = cairo_create(res);
|
||||||
cairo_set_source_surface(cr, surface, 0, 0);
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
|
|
@ -1308,6 +1308,71 @@ client_set_icon(client_t *c, cairo_surface_t *s)
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set a client icon.
|
||||||
|
* \param c The client to change.
|
||||||
|
* \param icon A bitmap containing the icon.
|
||||||
|
* \param mask A mask for the bitmap (optional)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
client_set_icon_from_pixmaps(client_t *c, xcb_pixmap_t icon, xcb_pixmap_t mask)
|
||||||
|
{
|
||||||
|
xcb_get_geometry_cookie_t geom_icon_c, geom_mask_c;
|
||||||
|
xcb_get_geometry_reply_t *geom_icon_r, *geom_mask_r = NULL;
|
||||||
|
cairo_surface_t *s_icon, *result;
|
||||||
|
|
||||||
|
geom_icon_c = xcb_get_geometry_unchecked(globalconf.connection, icon);
|
||||||
|
if (mask)
|
||||||
|
geom_mask_c = xcb_get_geometry_unchecked(globalconf.connection, mask);
|
||||||
|
geom_icon_r = xcb_get_geometry_reply(globalconf.connection, geom_icon_c, NULL);
|
||||||
|
if (mask)
|
||||||
|
geom_mask_r = xcb_get_geometry_reply(globalconf.connection, geom_mask_c, NULL);
|
||||||
|
|
||||||
|
if (!geom_icon_r || (mask && !geom_mask_r))
|
||||||
|
goto out;
|
||||||
|
if ((geom_icon_r->depth != 1 && geom_icon_r->depth != globalconf.screen->root_depth)
|
||||||
|
|| (geom_mask_r && geom_mask_r->depth != 1))
|
||||||
|
{
|
||||||
|
warn("Got pixmaps with depth (%d, %d) while processing icon, but only depth 1 and %d are allowed",
|
||||||
|
geom_icon_r->depth, geom_mask_r ? geom_mask_r->depth : 0, globalconf.screen->root_depth);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geom_icon_r->depth == 1)
|
||||||
|
s_icon = cairo_xcb_surface_create_for_bitmap(globalconf.connection,
|
||||||
|
globalconf.screen, icon, geom_icon_r->width, geom_icon_r->height);
|
||||||
|
else
|
||||||
|
s_icon = cairo_xcb_surface_create(globalconf.connection, icon, globalconf.default_visual,
|
||||||
|
geom_icon_r->width, geom_icon_r->height);
|
||||||
|
result = s_icon;
|
||||||
|
|
||||||
|
if (mask)
|
||||||
|
{
|
||||||
|
cairo_surface_t *s_mask;
|
||||||
|
cairo_t *cr;
|
||||||
|
|
||||||
|
result = cairo_surface_create_similar(s_icon, CAIRO_CONTENT_COLOR_ALPHA, geom_icon_r->width, geom_icon_r->height);
|
||||||
|
s_mask = cairo_xcb_surface_create_for_bitmap(globalconf.connection,
|
||||||
|
globalconf.screen, mask, geom_icon_r->width, geom_icon_r->height);
|
||||||
|
cr = cairo_create(result);
|
||||||
|
|
||||||
|
cairo_set_source_surface(cr, s_icon, 0, 0);
|
||||||
|
cairo_mask_surface(cr, s_mask, 0, 0);
|
||||||
|
cairo_surface_destroy(s_mask);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
client_set_icon(c, result);
|
||||||
|
|
||||||
|
cairo_surface_destroy(result);
|
||||||
|
if (result != s_icon)
|
||||||
|
cairo_surface_destroy(s_icon);
|
||||||
|
|
||||||
|
out:
|
||||||
|
p_delete(&geom_icon_r);
|
||||||
|
p_delete(&geom_mask_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Kill a client.
|
/** Kill a client.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
*
|
*
|
||||||
|
|
|
@ -101,6 +101,8 @@ struct client_t
|
||||||
key_array_t keys;
|
key_array_t keys;
|
||||||
/** Icon */
|
/** Icon */
|
||||||
cairo_surface_t *icon;
|
cairo_surface_t *icon;
|
||||||
|
/** True if we ever got an icon from _NET_WM_ICON */
|
||||||
|
bool have_ewmh_icon;
|
||||||
/** Size hints */
|
/** Size hints */
|
||||||
xcb_size_hints_t size_hints;
|
xcb_size_hints_t size_hints;
|
||||||
/** The visualtype that c->window uses */
|
/** The visualtype that c->window uses */
|
||||||
|
@ -164,7 +166,8 @@ void client_set_transient_for(lua_State *L, int, client_t *);
|
||||||
void client_set_name(lua_State *L, int, char *);
|
void client_set_name(lua_State *L, int, char *);
|
||||||
void client_set_alt_name(lua_State *L, int, char *);
|
void client_set_alt_name(lua_State *L, int, char *);
|
||||||
void client_set_group_window(lua_State *, int, xcb_window_t);
|
void client_set_group_window(lua_State *, int, xcb_window_t);
|
||||||
void client_set_icon(client_t *c, cairo_surface_t *s);
|
void client_set_icon(client_t *, cairo_surface_t *);
|
||||||
|
void client_set_icon_from_pixmaps(client_t *, xcb_pixmap_t, xcb_pixmap_t);
|
||||||
void client_set_skip_taskbar(lua_State *, int, bool);
|
void client_set_skip_taskbar(lua_State *, int, bool);
|
||||||
void client_focus(client_t *);
|
void client_focus(client_t *);
|
||||||
void client_focus_update(client_t *);
|
void client_focus_update(client_t *);
|
||||||
|
|
14
property.c
14
property.c
|
@ -206,6 +206,19 @@ property_update_wm_hints(client_t *c, xcb_get_property_cookie_t cookie)
|
||||||
if(wmh.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP)
|
if(wmh.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP)
|
||||||
client_set_group_window(L, -1, wmh.window_group);
|
client_set_group_window(L, -1, wmh.window_group);
|
||||||
|
|
||||||
|
if(!c->have_ewmh_icon)
|
||||||
|
{
|
||||||
|
if(wmh.flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP)
|
||||||
|
{
|
||||||
|
if(wmh.flags & XCB_ICCCM_WM_HINT_ICON_MASK)
|
||||||
|
client_set_icon_from_pixmaps(c, wmh.icon_pixmap, wmh.icon_mask);
|
||||||
|
else
|
||||||
|
client_set_icon_from_pixmaps(c, wmh.icon_pixmap, XCB_NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
client_set_icon(c, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +276,7 @@ property_update_net_wm_icon(client_t *c, xcb_get_property_cookie_t cookie)
|
||||||
if(!surface)
|
if(!surface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
c->have_ewmh_icon = true;
|
||||||
client_set_icon(c, surface);
|
client_set_icon(c, surface);
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue