[PATCH 2/3] Return more icons from _NET_WM_ICON

Uli Schlachter psychon at znc.in
Fri Mar 11 02:24:27 PST 2011


EWMH says that _NET_WM_ICON is an array of icon. That means that it can contain
more than one icon. This way, apps can provide icons of different sizes. Common
sizes seem to be 16x16, 32x32 and 48x48.

This commit makes it possible to access up to EWMH_WM_ICON_MAX of the icons in
_NET_WM_ICON. The value for EWMH_WM_ICON_MAX is 8, because a common number of
icons seems to be 3 and I added some security margin to this. :-)

If a _NET_WM_ICON property contains more than EWMH_WM_ICON_MAX icons, the excess
icons are silently ignored.

Signed-off-by: Uli Schlachter <psychon at znc.in>
---
 ewmh/ewmh.c.m4     |   53 ++++++++++++++++++++++++++++++++++++++++++++-------
 ewmh/xcb_ewmh.h.m4 |   18 ++++++++++++++++-
 2 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/ewmh/ewmh.c.m4 b/ewmh/ewmh.c.m4
index 176ba19..4a609b6 100644
--- a/ewmh/ewmh.c.m4
+++ b/ewmh/ewmh.c.m4
@@ -1140,11 +1140,43 @@ xcb_ewmh_set_wm_icon(xcb_ewmh_connection_t *ewmh,
 
 DO_GET_PROPERTY(wm_icon, _NET_WM_ICON, XCB_ATOM_CARDINAL, UINT_MAX)
 
+static uint32_t *
+xcb_ewmh_get_wm_icon_from_reply_next(xcb_ewmh_get_wm_icon_reply_t *wm_icon,
+                                     uint32_t *r_value,
+                                     uint32_t *r_value_len,
+                                     uint8_t idx)
+{
+  if (*r_value_len <= (sizeof(uint32_t) * 2))
+    return NULL;
+  /* Check that the property is as long as it should be, handling
+     integer overflow. "-2" to handle the width and height fields. */
+  const uint64_t expected_len = r_value[0] * (uint64_t) r_value[1];
+  if(!r_value[0] || !r_value[1] || expected_len > *r_value_len / 4 - 2)
+    return NULL;
+
+  /* We can only handle up to EWMH_WM_ICON_MAX icons */
+  if (idx >= EWMH_WM_ICON_MAX)
+    return NULL;
+
+  wm_icon->icons[idx].width = r_value[0];
+  wm_icon->icons[idx].height = r_value[1];
+  wm_icon->icons[idx].data = r_value + 2;
+
+  /* Return pointer to next icon in the reply. This cannot overflow,
+   * because above we made sure that:
+   *          expected_len      <= *r_value_len/4 - 2
+   * <=> 4 * (expected_len + 2) <= *r_value_len
+   */
+  *r_value_len -= 4 * (2 + expected_len);
+  return &r_value[expected_len + 2];
+}
+
 uint8_t
 xcb_ewmh_get_wm_icon_from_reply(xcb_ewmh_get_wm_icon_reply_t *wm_icon,
                                 xcb_get_property_reply_t *r)
 {
-  const uint32_t r_value_len = xcb_get_property_value_length(r);
+  uint8_t num_icons = 0;
+  uint32_t r_value_len = xcb_get_property_value_length(r);
   if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 ||
      r_value_len <= (sizeof(uint32_t) * 2))
     return 0;
@@ -1153,16 +1185,21 @@ xcb_ewmh_get_wm_icon_from_reply(xcb_ewmh_get_wm_icon_reply_t *wm_icon,
   if(!r_value)
     return 0;
 
-  /* Check that the property is as long as it should be, handling
-     integer overflow. "-2" to handle the width and height fields. */
-  const uint64_t expected_len = r_value[0] * (uint64_t) r_value[1];
-  if(!r_value[0] || !r_value[1] || expected_len > r_value_len / 4 - 2)
+  memset(wm_icon, 0, sizeof(xcb_ewmh_get_wm_icon_reply_t));
+
+  /* Parse all icons the icons in the reply.
+   * xcb_ewmh_get_wm_icon_from_reply_next makes sure we stop at the end. */
+  r_value = xcb_ewmh_get_wm_icon_from_reply_next(wm_icon, r_value, &r_value_len, num_icons);
+  while (r_value) {
+    num_icons++;
+    r_value = xcb_ewmh_get_wm_icon_from_reply_next(wm_icon, r_value, &r_value_len, num_icons);
+  }
+
+  if (num_icons == 0)
     return 0;
 
   wm_icon->_reply = r;
-  wm_icon->width = r_value[0];
-  wm_icon->height = r_value[1];
-  wm_icon->data = r_value + 2;
+  wm_icon->num_icons = num_icons;
 
   return 1;
 }
diff --git a/ewmh/xcb_ewmh.h.m4 b/ewmh/xcb_ewmh.h.m4
index c1d8f09..d35f4d4 100644
--- a/ewmh/xcb_ewmh.h.m4
+++ b/ewmh/xcb_ewmh.h.m4
@@ -54,6 +54,12 @@ extern "C" {
 #endif
 
 /**
+ * @brief Maximum number of icons in _NET_WM_ICON property that we support.
+ * This number is an arbitrary pick.
+ */
+#define EWMH_WM_ICON_MAX 8
+
+/**
  * @brief Hold EWMH information specific to a screen
  */
 typedef struct {
@@ -295,7 +301,7 @@ typedef struct {
 } xcb_ewmh_wm_strut_partial_t;
 
 /**
- * @brief Hold reply of _NET_WM_ICON GetProperty
+ * @brief Hold a single icon from reply of _NET_WM_ICON GetProperty
  */
 typedef struct {
   /** Icon width */
@@ -304,6 +310,16 @@ typedef struct {
   uint32_t height;
   /** Rows, left to right and top to bottom of the CARDINAL ARGB */
   uint32_t *data;
+} xcb_ewmh_wm_icon_t;
+
+/**
+ * @brief Hold reply of _NET_WM_ICON GetProperty
+ */
+typedef struct {
+  /** Icons */
+  xcb_ewmh_wm_icon_t icons[EWMH_WM_ICON_MAX];
+  /** Number of icons in 'icons' */
+  uint8_t num_icons;
   /** The actual GetProperty reply */
   xcb_get_property_reply_t *_reply;
 } xcb_ewmh_get_wm_icon_reply_t;
-- 
1.7.2.3


--------------090907060109020503090309
Content-Type: text/x-diff;
 name="0003-A-small-test-app-for-ewmh_get_wm_icon_.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="0003-A-small-test-app-for-ewmh_get_wm_icon_.patch"



More information about the Xcb mailing list