[PATCH 3/4] 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 all the icons in _NET_WM_ICON via
iterators instead of just the first one.

Thanks to Arnaud Fontaine for his help with the API.

Signed-off-by: Uli Schlachter <psychon at znc.in>
---
 ewmh/ewmh.c.m4     |   81 +++++++++++++++++++++++++++++++++++++++++++++++----
 ewmh/xcb_ewmh.h.m4 |   20 ++++++++++++-
 2 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/ewmh/ewmh.c.m4 b/ewmh/ewmh.c.m4
index 490727e..2ba0f3e 100644
--- a/ewmh/ewmh.c.m4
+++ b/ewmh/ewmh.c.m4
@@ -1146,21 +1146,39 @@ xcb_ewmh_get_wm_icon_from_reply(xcb_ewmh_get_wm_icon_reply_t *wm_icon,
 {
   if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32)
     return 0;
+  unsigned int num_icons = 0;
   uint32_t r_value_len = xcb_get_property_value_length(r);
   uint32_t *r_value = (uint32_t *) xcb_get_property_value(r);
   if(r_value_len <= (sizeof(uint32_t) * 2) || !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));
+
+  /* Find the number of icons in the reply. */
+  while (r_value_len > (sizeof(uint32_t) * 2))
+  {
+    /* 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)
+      break;
+
+    num_icons++;
+
+    /* Find 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);
+    r_value = &r_value[expected_len + 2];
+  }
+
+  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;
 }
@@ -1185,6 +1203,55 @@ xcb_ewmh_get_wm_icon_reply_wipe(xcb_ewmh_get_wm_icon_reply_t *wm_icon)
   free(wm_icon->_reply);
 }
 
+xcb_ewmh_wm_icon_iterator_t
+xcb_ewmh_get_wm_icon_iterator(const xcb_ewmh_get_wm_icon_reply_t *wm_icon)
+{
+  xcb_ewmh_wm_icon_iterator_t ret;
+
+  ret.width = 0;
+  ret.height = 0;
+  ret.data = NULL;
+  ret.rem = wm_icon->_num_icons;
+  ret.index = 0;
+
+  if (ret.rem > 0)
+  {
+    uint32_t *r_value = (uint32_t *) xcb_get_property_value(wm_icon->_reply);
+    ret.width = r_value[0];
+    ret.height = r_value[1];
+    ret.data = &r_value[2];
+  }
+
+  return ret;
+}
+
+unsigned int xcb_ewmh_get_wm_icon_length(const xcb_ewmh_get_wm_icon_reply_t *wm_icon)
+{
+  return wm_icon->_num_icons;
+}
+
+void xcb_ewmh_get_wm_icon_next(xcb_ewmh_wm_icon_iterator_t *iterator)
+{
+  if (iterator->rem <= 1)
+  {
+    iterator->index += iterator->rem;
+    iterator->rem = 0;
+    iterator->width = 0;
+    iterator->height = 0;
+    iterator->data = NULL;
+    return;
+  }
+
+  uint64_t icon_len = iterator->width * (uint64_t) iterator->height;
+  uint32_t *data = iterator->data + icon_len;
+
+  iterator->rem--;
+  iterator->index++;
+  iterator->width = data[0];
+  iterator->height = data[1];
+  iterator->data = &data[2];
+}
+
 /**
  * _NET_WM_PID
  */
diff --git a/ewmh/xcb_ewmh.h.m4 b/ewmh/xcb_ewmh.h.m4
index c1d8f09..d30ecec 100644
--- a/ewmh/xcb_ewmh.h.m4
+++ b/ewmh/xcb_ewmh.h.m4
@@ -295,7 +295,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 +304,18 @@ typedef struct {
   uint32_t height;
   /** Rows, left to right and top to bottom of the CARDINAL ARGB */
   uint32_t *data;
+  /** Number of icons remaining */
+  unsigned int rem;
+  /** Index of the current icon in the array of icons */
+  unsigned int index;
+} xcb_ewmh_wm_icon_iterator_t;
+
+/**
+ * @brief Hold reply of _NET_WM_ICON GetProperty
+ */
+typedef struct {
+  /** Number of icons */
+  unsigned int _num_icons;
   /** The actual GetProperty reply */
   xcb_get_property_reply_t *_reply;
 } xcb_ewmh_get_wm_icon_reply_t;
@@ -2023,6 +2035,12 @@ uint8_t xcb_ewmh_get_wm_icon_reply(xcb_ewmh_connection_t *ewmh,
                                    xcb_ewmh_get_wm_icon_reply_t *wm_icon,
                                    xcb_generic_error_t **e);
 
+xcb_ewmh_wm_icon_iterator_t xcb_ewmh_get_wm_icon_iterator(const xcb_ewmh_get_wm_icon_reply_t *wm_icon);
+
+unsigned int xcb_ewmh_get_wm_icon_length(const xcb_ewmh_get_wm_icon_reply_t *wm_icon);
+
+void xcb_ewmh_get_wm_icon_next(xcb_ewmh_wm_icon_iterator_t *iterator);
+
 void xcb_ewmh_get_wm_icon_reply_wipe(xcb_ewmh_get_wm_icon_reply_t *wm_icon);
 
 xcb_void_cookie_t xcb_ewmh_set_wm_pid(xcb_ewmh_connection_t *ewmh,
-- 
1.7.4.1


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



More information about the Xcb mailing list