Browse Source

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>
Uli Schlachter 5 years ago
parent
commit
30b313f77a
4 changed files with 104 additions and 5 deletions
  1. 21
    4
      draw.c
  2. 65
    0
      objects/client.c
  3. 4
    1
      objects/client.h
  4. 14
    0
      property.c

+ 21
- 4
draw.c View File

@@ -188,6 +188,18 @@ draw_surface_from_pixbuf(GdkPixbuf *buf)
188 188
     return surface;
189 189
 }
190 190
 
191
+static void
192
+get_surface_size(cairo_surface_t *surface, int *width, int *height)
193
+{
194
+    double x1, y1, x2, y2;
195
+    cairo_t *cr = cairo_create(surface);
196
+
197
+    cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
198
+    cairo_destroy(cr);
199
+    *width = x2 - x1;
200
+    *height = y2 - y1;
201
+}
202
+
191 203
 /** Duplicate the specified image surface.
192 204
  * \param surface The surface to copy
193 205
  * \return A pointer to a new cairo image surface.
@@ -195,10 +207,15 @@ draw_surface_from_pixbuf(GdkPixbuf *buf)
195 207
 cairo_surface_t *
196 208
 draw_dup_image_surface(cairo_surface_t *surface)
197 209
 {
198
-    cairo_surface_t *res = cairo_image_surface_create(
199
-            cairo_image_surface_get_format(surface),
200
-            cairo_image_surface_get_width(surface),
201
-            cairo_image_surface_get_height(surface));
210
+    cairo_surface_t *res;
211
+    int width, height;
212
+
213
+    get_surface_size(surface, &width, &height);
214
+#if CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR > 12
215
+    res = cairo_surface_create_similar_image(surface, CAIRO_FORMAT_ARGB32, width, height);
216
+#else
217
+    res = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
218
+#endif
202 219
 
203 220
     cairo_t *cr = cairo_create(res);
204 221
     cairo_set_source_surface(cr, surface, 0, 0);

+ 65
- 0
objects/client.c View File

@@ -1308,6 +1308,71 @@ client_set_icon(client_t *c, cairo_surface_t *s)
1308 1308
     lua_pop(L, 1);
1309 1309
 }
1310 1310
 
1311
+/** Set a client icon.
1312
+ * \param c The client to change.
1313
+ * \param icon A bitmap containing the icon.
1314
+ * \param mask A mask for the bitmap (optional)
1315
+ */
1316
+void
1317
+client_set_icon_from_pixmaps(client_t *c, xcb_pixmap_t icon, xcb_pixmap_t mask)
1318
+{
1319
+    xcb_get_geometry_cookie_t geom_icon_c, geom_mask_c;
1320
+    xcb_get_geometry_reply_t *geom_icon_r, *geom_mask_r = NULL;
1321
+    cairo_surface_t *s_icon, *result;
1322
+
1323
+    geom_icon_c = xcb_get_geometry_unchecked(globalconf.connection, icon);
1324
+    if (mask)
1325
+        geom_mask_c = xcb_get_geometry_unchecked(globalconf.connection, mask);
1326
+    geom_icon_r = xcb_get_geometry_reply(globalconf.connection, geom_icon_c, NULL);
1327
+    if (mask)
1328
+        geom_mask_r = xcb_get_geometry_reply(globalconf.connection, geom_mask_c, NULL);
1329
+
1330
+    if (!geom_icon_r || (mask && !geom_mask_r))
1331
+        goto out;
1332
+    if ((geom_icon_r->depth != 1 && geom_icon_r->depth != globalconf.screen->root_depth)
1333
+            || (geom_mask_r && geom_mask_r->depth != 1))
1334
+    {
1335
+        warn("Got pixmaps with depth (%d, %d) while processing icon, but only depth 1 and %d are allowed",
1336
+                geom_icon_r->depth, geom_mask_r ? geom_mask_r->depth : 0, globalconf.screen->root_depth);
1337
+        goto out;
1338
+    }
1339
+
1340
+    if (geom_icon_r->depth == 1)
1341
+        s_icon = cairo_xcb_surface_create_for_bitmap(globalconf.connection,
1342
+                globalconf.screen, icon, geom_icon_r->width, geom_icon_r->height);
1343
+    else
1344
+        s_icon = cairo_xcb_surface_create(globalconf.connection, icon, globalconf.default_visual,
1345
+                geom_icon_r->width, geom_icon_r->height);
1346
+    result = s_icon;
1347
+
1348
+    if (mask)
1349
+    {
1350
+        cairo_surface_t *s_mask;
1351
+        cairo_t *cr;
1352
+
1353
+        result = cairo_surface_create_similar(s_icon, CAIRO_CONTENT_COLOR_ALPHA, geom_icon_r->width, geom_icon_r->height);
1354
+        s_mask = cairo_xcb_surface_create_for_bitmap(globalconf.connection,
1355
+                globalconf.screen, mask, geom_icon_r->width, geom_icon_r->height);
1356
+        cr = cairo_create(result);
1357
+
1358
+        cairo_set_source_surface(cr, s_icon, 0, 0);
1359
+        cairo_mask_surface(cr, s_mask, 0, 0);
1360
+        cairo_surface_destroy(s_mask);
1361
+        cairo_destroy(cr);
1362
+    }
1363
+
1364
+    client_set_icon(c, result);
1365
+
1366
+    cairo_surface_destroy(result);
1367
+    if (result != s_icon)
1368
+        cairo_surface_destroy(s_icon);
1369
+
1370
+out:
1371
+    p_delete(&geom_icon_r);
1372
+    p_delete(&geom_mask_r);
1373
+}
1374
+
1375
+
1311 1376
 /** Kill a client.
1312 1377
  * \param L The Lua VM state.
1313 1378
  *

+ 4
- 1
objects/client.h View File

@@ -101,6 +101,8 @@ struct client_t
101 101
     key_array_t keys;
102 102
     /** Icon */
103 103
     cairo_surface_t *icon;
104
+    /** True if we ever got an icon from _NET_WM_ICON */
105
+    bool have_ewmh_icon;
104 106
     /** Size hints */
105 107
     xcb_size_hints_t size_hints;
106 108
     /** The visualtype that c->window uses */
@@ -164,7 +166,8 @@ void client_set_transient_for(lua_State *L, int, client_t *);
164 166
 void client_set_name(lua_State *L, int, char *);
165 167
 void client_set_alt_name(lua_State *L, int, char *);
166 168
 void client_set_group_window(lua_State *, int, xcb_window_t);
167
-void client_set_icon(client_t *c, cairo_surface_t *s);
169
+void client_set_icon(client_t *, cairo_surface_t *);
170
+void client_set_icon_from_pixmaps(client_t *, xcb_pixmap_t, xcb_pixmap_t);
168 171
 void client_set_skip_taskbar(lua_State *, int, bool);
169 172
 void client_focus(client_t *);
170 173
 void client_focus_update(client_t *);

+ 14
- 0
property.c View File

@@ -206,6 +206,19 @@ property_update_wm_hints(client_t *c, xcb_get_property_cookie_t cookie)
206 206
     if(wmh.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP)
207 207
         client_set_group_window(L, -1, wmh.window_group);
208 208
 
209
+    if(!c->have_ewmh_icon)
210
+    {
211
+        if(wmh.flags & XCB_ICCCM_WM_HINT_ICON_PIXMAP)
212
+        {
213
+            if(wmh.flags & XCB_ICCCM_WM_HINT_ICON_MASK)
214
+                client_set_icon_from_pixmaps(c, wmh.icon_pixmap, wmh.icon_mask);
215
+            else
216
+                client_set_icon_from_pixmaps(c, wmh.icon_pixmap, XCB_NONE);
217
+        }
218
+        else
219
+            client_set_icon(c, NULL);
220
+    }
221
+
209 222
     lua_pop(L, 1);
210 223
 }
211 224
 
@@ -263,6 +276,7 @@ property_update_net_wm_icon(client_t *c, xcb_get_property_cookie_t cookie)
263 276
     if(!surface)
264 277
         return;
265 278
 
279
+    c->have_ewmh_icon = true;
266 280
     client_set_icon(c, surface);
267 281
     cairo_surface_destroy(surface);
268 282
 }

Loading…
Cancel
Save