[PATCH v5 weston] xwm: Choose icon closest to target size

Derek Foreman derekf at osg.samsung.com
Tue Mar 27 17:43:36 UTC 2018


Xwayland clients can offer multiple icon sizes in no particular order.
Previously xwm was selecting the first one unconditionally. This patch
selects the icon that matches the size closest to the target size. The
target size is hard coded to 16 since there is only one theme and the
data used to create the theme is hard coded.

Co-authored-by: Scott Moreau <oreaus at gmail.com>

---

Changed in v2:

- Fix typo setting width to height

Changed in v3:

- Move checks for malformed input into data handling function

Changed in v4:

- #define XWM_ICON_SIZE in this patch and do not #undef it
- Start with first icon found before choosing icon\
- Check for NULL data in get_icon_size_from_data()

Changed in v5:
- remove allocations, process in a single pass
- rebase on top of memory leak fix

 xwayland/window-manager.c | 51 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 44 insertions(+), 7 deletions(-)

diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
index dad117fa..5209ac66 100644
--- a/xwayland/window-manager.c
+++ b/xwayland/window-manager.c
@@ -127,6 +127,8 @@ struct motif_wm_hints {
 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
 #define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
 
+#define XWM_ICON_SIZE 16 /* width and height of frame icon */
+
 struct weston_output_weak_ref {
 	struct weston_output *output;
 	struct wl_listener destroy_listener;
@@ -1352,6 +1354,44 @@ weston_wm_window_schedule_repaint(struct weston_wm_window *window)
 				       weston_wm_window_do_repaint, window);
 }
 
+static uint32_t *
+get_icon_size_from_data(int target_width, int target_height,
+			uint32_t *width, uint32_t *height,
+			uint32_t length, uint32_t *data)
+{
+	uint32_t *d = data, *ret = NULL, w, h;
+	int a1, a2, a3;
+
+	if (!data)
+		return NULL;
+
+	/* Choose closest match by comparing icon dimension areas */
+	a1 = target_width * target_height;
+
+	*width = *height = 0;
+
+	while (d - data < length / 4) {
+		w = *d++;
+		h = *d++;
+
+		/* Some checks against malformed input. */
+		if (w == 0 || h == 0 || length < 2 + w * h)
+			return ret;
+
+		a2 = w * h;
+		a3 = *width * *height;
+		if (!a3 || abs(a2 - a1) < abs(a3 - a1)) {
+			*width = w;
+			*height = h;
+			ret = d;
+		}
+
+		d += a2;
+	}
+
+	return ret;
+}
+
 static void
 handle_icon_surface_destroy(void *data)
 {
@@ -1367,9 +1407,6 @@ weston_wm_handle_icon(struct weston_wm *wm, struct weston_wm_window *window)
 	uint32_t *data, width, height;
 	cairo_surface_t *new_surface;
 
-	/* TODO: icons don’t have any specified order, we should pick the
-	 * closest one to the target dimension instead of the first one. */
-
 	cookie = xcb_get_property(wm->conn, 0, window->id,
 	                          wm->atom.net_wm_icon, XCB_ATOM_ANY, 0,
 	                          UINT32_MAX);
@@ -1383,11 +1420,11 @@ weston_wm_handle_icon(struct weston_wm *wm, struct weston_wm_window *window)
 	}
 
 	data = xcb_get_property_value(reply);
-	width = *data++;
-	height = *data++;
 
-	/* Some checks against malformed input. */
-	if (width == 0 || height == 0 || length < 2 + width * height) {
+	data = get_icon_size_from_data(XWM_ICON_SIZE, XWM_ICON_SIZE,
+					&width, &height, length, data);
+
+	if (!data) {
 		free(reply);
 		return;
 	}
-- 
2.14.3



More information about the wayland-devel mailing list