[PATCH] Implement _NET_WM_ICON support for retrieving the application icon
Bernhard Walle <[email protected]>
| Newsgroups | gmane.comp.desktop.rox.devel |
|---|---|
| Message-ID | <[email protected]> |
This patch tries first to retrieve the application icon from the _NET_WM_ICON property. If that fails, it uses Motif hints as before. Some toolkits (like Java/Swing) don't set Motif hints for icons at all. See http://standards.freedesktop.org/wm-spec/1.3/ar01s05.html#id2523482 for a description of that standard. Tested with on i386-linux using ROX 2.8. Signed-off-by: Bernhard Walle <[email protected]> --- ROX-Filer/src/tasklist.c | 117 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 30 deletions(-) --- a/ROX-Filer/src/tasklist.c +++ b/ROX-Filer/src/tasklist.c @@ -25,6 +25,7 @@ #include "config.h" #include <stdlib.h> +#include <string.h> #include <gtk/gtk.h> #include <gdk/gdk.h> @@ -70,6 +71,7 @@ static GdkAtom xa_TEXT = GDK_NONE; static GdkAtom xa__NET_WM_VISIBLE_NAME = GDK_NONE; static GdkAtom xa__NET_WM_ICON_NAME = GDK_NONE; static GdkAtom xa__NET_CLIENT_LIST = GDK_NONE; +static GdkAtom xa__NET_WM_ICON = GDK_NONE; static GdkAtom xa__NET_WM_ICON_GEOMETRY = GDK_NONE; static GdkAtom xa__NET_WM_STATE = GDK_NONE; static GdkAtom xa__NET_WM_STATE_HIDDEN = GDK_NONE; @@ -138,6 +140,8 @@ void tasklist_set_active(gboolean active gdk_atom_intern("_NET_WM_VISIBLE_NAME", FALSE); xa__NET_WM_ICON_NAME = gdk_atom_intern("_NET_WM_ICON_NAME", FALSE); + xa__NET_WM_ICON = + gdk_atom_intern("_NET_WM_ICON", FALSE); xa__NET_WM_ICON_GEOMETRY = gdk_atom_intern("_NET_WM_ICON_GEOMETRY", FALSE); xa__NET_WM_STATE = gdk_atom_intern("_NET_WM_STATE", FALSE); @@ -816,6 +820,51 @@ static GdkPixbuf *apply_window_effect(Gd return new; } +static void argb_to_abgr(guint32 *p, gsize length) +{ + gint i; + + for (i = 0; i < length; i++) + p[i] = (p[i] & 0xff00ff00) | ((p[i] & 0xff) << 16) | ((p[i] >> 16) & 0xff); +} + +static GdkPixbuf *read_window_icon (Display *xdisplay, Window w) +{ + Atom type; + gint format; + gulong length, rest; + guint32 *data; + GdkPixbuf *pixbuf = NULL; + guint32 *p; + + if (XGetWindowProperty(xdisplay, w, gdk_x11_atom_to_xatom(xa__NET_WM_ICON), 0, G_MAXLONG, + FALSE, AnyPropertyType, &type, &format, &length, + &rest, (guchar **)&data) != Success || length <= 2) + return NULL; + + gint width = data[0]; + gint height = data[1]; + + p = g_malloc(width * height * sizeof(guint32)); + memcpy(p, data + 2, width * height * sizeof(guint32)); + XFree(data); + + argb_to_abgr(p, width * height); + + pixbuf = gdk_pixbuf_new_from_data((guchar *)p, GDK_COLORSPACE_RGB, TRUE, 8, width, height, + width * 4, NULL, NULL); + if (width > 24 || height > 24) + { + GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, 24, 24, GDK_INTERP_NEAREST); + g_object_unref (pixbuf); + + pixbuf = scaled; + } + + return pixbuf; +} + + /* Return a suitable icon for this window. unref the result. * Never returns NULL. */ @@ -827,49 +876,57 @@ static GdkPixbuf *get_image_for(IconWind XWMHints *hints; GdkPixbuf *retval = NULL; - /* Try the pixmap and mask in the old WMHints... */ - gdk_error_trap_push(); - hints = XGetWMHints(gdk_display, win->xwindow); - - if (hints) + retval = read_window_icon(gdk_display, win->xwindow); + if (retval) { - if (hints->flags & IconPixmapHint) - pixmap = hints->icon_pixmap; - if (hints->flags & IconMaskHint) - mask = hints->icon_mask; - - XFree(hints); - hints = NULL; + g_object_ref(retval); } - - if (pixmap != None) + else { - GdkPixbuf *mask_pb = NULL; - - retval = pixbuf_from_pixmap(pixmap); + /* Try the pixmap and mask in the old WMHints... */ + gdk_error_trap_push(); + hints = XGetWMHints(gdk_display, win->xwindow); - if (retval && mask != None) - mask_pb = pixbuf_from_pixmap(mask); + if (hints) + { + if (hints->flags & IconPixmapHint) + pixmap = hints->icon_pixmap; + if (hints->flags & IconMaskHint) + mask = hints->icon_mask; - if (mask_pb) + XFree(hints); + hints = NULL; + } + + if (pixmap != None) { - GdkPixbuf *masked; + GdkPixbuf *mask_pb = NULL; + + retval = pixbuf_from_pixmap(pixmap); - masked = apply_mask(retval, mask_pb); - g_object_unref(G_OBJECT(mask_pb)); + if (retval && mask != None) + mask_pb = pixbuf_from_pixmap(mask); - if (masked) + if (mask_pb) { - g_object_unref(G_OBJECT(retval)); - retval = masked; + GdkPixbuf *masked; + + masked = apply_mask(retval, mask_pb); + g_object_unref(G_OBJECT(mask_pb)); + + if (masked) + { + g_object_unref(G_OBJECT(retval)); + retval = masked; + } } } - } - gdk_flush(); + gdk_flush(); + + gdk_error_trap_pop(); + } - gdk_error_trap_pop(); - if (!retval) { if (!default_icon) ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/