1664 lines
43 KiB
Diff
1664 lines
43 KiB
Diff
From bd8ab37c271c065c0bcd09362222ca37f05aedf7 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Alberts=20Muktup=C4=81vels?= <alberts.muktupavels@gmail.com>
|
|
Date: Tue, 11 May 2021 21:00:01 +0300
|
|
Subject: [PATCH 1/6] xutils: move WnckIconCache to its own file
|
|
|
|
---
|
|
libwnck/application.c | 1 +
|
|
libwnck/meson.build | 2 +
|
|
libwnck/window.c | 1 +
|
|
libwnck/wnck-icon-cache-private.h | 51 ++
|
|
libwnck/wnck-icon-cache.c | 756 ++++++++++++++++++++++++++++++
|
|
libwnck/xutils.c | 729 +---------------------------
|
|
libwnck/xutils.h | 22 +-
|
|
7 files changed, 815 insertions(+), 747 deletions(-)
|
|
create mode 100644 libwnck/wnck-icon-cache-private.h
|
|
create mode 100644 libwnck/wnck-icon-cache.c
|
|
|
|
diff --git a/libwnck/application.c b/libwnck/application.c
|
|
index 9a03342..8d78209 100644
|
|
--- a/libwnck/application.c
|
|
+++ b/libwnck/application.c
|
|
@@ -25,6 +25,7 @@
|
|
#include <glib/gi18n-lib.h>
|
|
#include "application.h"
|
|
#include "private.h"
|
|
+#include "wnck-icon-cache-private.h"
|
|
|
|
/**
|
|
* SECTION:application
|
|
diff --git a/libwnck/meson.build b/libwnck/meson.build
|
|
index eef9de5..aa60e83 100644
|
|
--- a/libwnck/meson.build
|
|
+++ b/libwnck/meson.build
|
|
@@ -59,6 +59,8 @@ sources = [
|
|
'window.c',
|
|
'wnck-handle-private.h',
|
|
'wnck-handle.c',
|
|
+ 'wnck-icon-cache-private.h',
|
|
+ 'wnck-icon-cache.c',
|
|
'wnck-image-menu-item-private.h',
|
|
'wnck-image-menu-item.c',
|
|
'workspace.c',
|
|
diff --git a/libwnck/window.c b/libwnck/window.c
|
|
index 66a4386..25c56a5 100644
|
|
--- a/libwnck/window.c
|
|
+++ b/libwnck/window.c
|
|
@@ -33,6 +33,7 @@
|
|
#include "xutils.h"
|
|
#include "private.h"
|
|
#include "wnck-enum-types.h"
|
|
+#include "wnck-icon-cache-private.h"
|
|
|
|
/**
|
|
* SECTION:window
|
|
diff --git a/libwnck/wnck-icon-cache-private.h b/libwnck/wnck-icon-cache-private.h
|
|
new file mode 100644
|
|
index 0000000..6a3d5ec
|
|
--- /dev/null
|
|
+++ b/libwnck/wnck-icon-cache-private.h
|
|
@@ -0,0 +1,51 @@
|
|
+/*
|
|
+ * Copyright (C) 2001 Havoc Pennington
|
|
+ * Copyright (C) 2005-2007 Vincent Untz
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Library General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Library General Public
|
|
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#ifndef WNCK_ICON_CACHE_PRIVATE_H
|
|
+#define WNCK_ICON_CACHE_PRIVATE_H
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+#include <X11/Xatom.h>
|
|
+
|
|
+#include <gdk/gdk.h>
|
|
+#include <libwnck/screen.h>
|
|
+
|
|
+G_BEGIN_DECLS
|
|
+
|
|
+typedef struct _WnckIconCache WnckIconCache;
|
|
+
|
|
+WnckIconCache *_wnck_icon_cache_new (void);
|
|
+void _wnck_icon_cache_free (WnckIconCache *icon_cache);
|
|
+void _wnck_icon_cache_property_changed (WnckIconCache *icon_cache,
|
|
+ Atom atom);
|
|
+gboolean _wnck_icon_cache_get_icon_invalidated (WnckIconCache *icon_cache);
|
|
+void _wnck_icon_cache_set_want_fallback (WnckIconCache *icon_cache,
|
|
+ gboolean setting);
|
|
+gboolean _wnck_icon_cache_get_is_fallback (WnckIconCache *icon_cache);
|
|
+
|
|
+gboolean _wnck_read_icons (WnckScreen *screen,
|
|
+ Window xwindow,
|
|
+ WnckIconCache *icon_cache,
|
|
+ GdkPixbuf **iconp,
|
|
+ int ideal_size,
|
|
+ GdkPixbuf **mini_iconp,
|
|
+ int ideal_mini_size);
|
|
+
|
|
+G_END_DECLS
|
|
+
|
|
+#endif
|
|
diff --git a/libwnck/wnck-icon-cache.c b/libwnck/wnck-icon-cache.c
|
|
new file mode 100644
|
|
index 0000000..1749585
|
|
--- /dev/null
|
|
+++ b/libwnck/wnck-icon-cache.c
|
|
@@ -0,0 +1,756 @@
|
|
+/*
|
|
+ * Copyright (C) 2001 Havoc Pennington
|
|
+ * Copyright (C) 2005-2007 Vincent Untz
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Library General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Library General Public
|
|
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+#include "wnck-icon-cache-private.h"
|
|
+
|
|
+#include <cairo-xlib.h>
|
|
+#if HAVE_CAIRO_XLIB_XRENDER
|
|
+#include <cairo-xlib-xrender.h>
|
|
+#endif
|
|
+
|
|
+#include "private.h"
|
|
+#include "xutils.h"
|
|
+
|
|
+typedef enum
|
|
+{
|
|
+ /* These MUST be in ascending order of preference;
|
|
+ * i.e. if we get _NET_WM_ICON and already have
|
|
+ * WM_HINTS, we prefer _NET_WM_ICON
|
|
+ */
|
|
+ USING_NO_ICON,
|
|
+ USING_FALLBACK_ICON,
|
|
+ USING_KWM_WIN_ICON,
|
|
+ USING_WM_HINTS,
|
|
+ USING_NET_WM_ICON
|
|
+} IconOrigin;
|
|
+
|
|
+struct _WnckIconCache
|
|
+{
|
|
+ IconOrigin origin;
|
|
+ Pixmap prev_pixmap;
|
|
+ Pixmap prev_mask;
|
|
+ GdkPixbuf *icon;
|
|
+ GdkPixbuf *mini_icon;
|
|
+ int ideal_size;
|
|
+ int ideal_mini_size;
|
|
+ guint want_fallback : 1;
|
|
+ /* TRUE if these props have changed */
|
|
+ guint wm_hints_dirty : 1;
|
|
+ guint kwm_win_icon_dirty : 1;
|
|
+ guint net_wm_icon_dirty : 1;
|
|
+};
|
|
+
|
|
+static gboolean
|
|
+find_best_size (gulong *data,
|
|
+ gulong nitems,
|
|
+ int ideal_size,
|
|
+ int *width,
|
|
+ int *height,
|
|
+ gulong **start)
|
|
+{
|
|
+ int best_w;
|
|
+ int best_h;
|
|
+ gulong *best_start;
|
|
+
|
|
+ *width = 0;
|
|
+ *height = 0;
|
|
+ *start = NULL;
|
|
+
|
|
+ best_w = 0;
|
|
+ best_h = 0;
|
|
+ best_start = NULL;
|
|
+
|
|
+ while (nitems > 0)
|
|
+ {
|
|
+ int w, h;
|
|
+ gboolean replace;
|
|
+
|
|
+ replace = FALSE;
|
|
+
|
|
+ if (nitems < 3)
|
|
+ return FALSE; /* no space for w, h */
|
|
+
|
|
+ w = data[0];
|
|
+ h = data[1];
|
|
+
|
|
+ if (nitems < ((gulong) (w * h) + 2))
|
|
+ break; /* not enough data */
|
|
+
|
|
+ if (best_start == NULL)
|
|
+ {
|
|
+ replace = TRUE;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* work with averages */
|
|
+ int best_size = (best_w + best_h) / 2;
|
|
+ int this_size = (w + h) / 2;
|
|
+
|
|
+ /* larger than desired is always better than smaller */
|
|
+ if (best_size < ideal_size &&
|
|
+ this_size >= ideal_size)
|
|
+ replace = TRUE;
|
|
+ /* if we have too small, pick anything bigger */
|
|
+ else if (best_size < ideal_size &&
|
|
+ this_size > best_size)
|
|
+ replace = TRUE;
|
|
+ /* if we have too large, pick anything smaller
|
|
+ * but still >= the ideal
|
|
+ */
|
|
+ else if (best_size > ideal_size &&
|
|
+ this_size >= ideal_size &&
|
|
+ this_size < best_size)
|
|
+ replace = TRUE;
|
|
+ }
|
|
+
|
|
+ if (replace)
|
|
+ {
|
|
+ best_start = data + 2;
|
|
+ best_w = w;
|
|
+ best_h = h;
|
|
+ }
|
|
+
|
|
+ data += (w * h) + 2;
|
|
+ nitems -= (w * h) + 2;
|
|
+ }
|
|
+
|
|
+ if (best_start)
|
|
+ {
|
|
+ *start = best_start;
|
|
+ *width = best_w;
|
|
+ *height = best_h;
|
|
+ return TRUE;
|
|
+ }
|
|
+ else
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+static void
|
|
+argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
|
|
+{
|
|
+ guchar *p;
|
|
+ int i;
|
|
+
|
|
+ *pixdata = g_new (guchar, len * 4);
|
|
+ p = *pixdata;
|
|
+
|
|
+ /* One could speed this up a lot. */
|
|
+ i = 0;
|
|
+ while (i < len)
|
|
+ {
|
|
+ guint argb;
|
|
+ guint rgba;
|
|
+
|
|
+ argb = argb_data[i];
|
|
+ rgba = (argb << 8) | (argb >> 24);
|
|
+
|
|
+ *p = rgba >> 24;
|
|
+ ++p;
|
|
+ *p = (rgba >> 16) & 0xff;
|
|
+ ++p;
|
|
+ *p = (rgba >> 8) & 0xff;
|
|
+ ++p;
|
|
+ *p = rgba & 0xff;
|
|
+ ++p;
|
|
+
|
|
+ ++i;
|
|
+ }
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+read_rgb_icon (Screen *screen,
|
|
+ Window xwindow,
|
|
+ int ideal_size,
|
|
+ int ideal_mini_size,
|
|
+ int *width,
|
|
+ int *height,
|
|
+ guchar **pixdata,
|
|
+ int *mini_width,
|
|
+ int *mini_height,
|
|
+ guchar **mini_pixdata)
|
|
+{
|
|
+ Display *display;
|
|
+ Atom type;
|
|
+ int format;
|
|
+ gulong nitems;
|
|
+ gulong bytes_after;
|
|
+ int result, err;
|
|
+ gulong *data;
|
|
+ gulong *best;
|
|
+ int w, h;
|
|
+ gulong *best_mini;
|
|
+ int mini_w, mini_h;
|
|
+
|
|
+ display = DisplayOfScreen (screen);
|
|
+
|
|
+ _wnck_error_trap_push (display);
|
|
+ type = None;
|
|
+ data = NULL;
|
|
+ result = XGetWindowProperty (display,
|
|
+ xwindow,
|
|
+ _wnck_atom_get ("_NET_WM_ICON"),
|
|
+ 0, G_MAXLONG,
|
|
+ False, XA_CARDINAL, &type, &format, &nitems,
|
|
+ &bytes_after, (void*)&data);
|
|
+
|
|
+ err = _wnck_error_trap_pop (display);
|
|
+
|
|
+ if (err != Success ||
|
|
+ result != Success)
|
|
+ return FALSE;
|
|
+
|
|
+ if (type != XA_CARDINAL)
|
|
+ {
|
|
+ XFree (data);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (!find_best_size (data, nitems, ideal_size, &w, &h, &best))
|
|
+ {
|
|
+ XFree (data);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ if (!find_best_size (data, nitems,
|
|
+ ideal_mini_size,
|
|
+ &mini_w, &mini_h, &best_mini))
|
|
+ {
|
|
+ XFree (data);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ *width = w;
|
|
+ *height = h;
|
|
+
|
|
+ *mini_width = mini_w;
|
|
+ *mini_height = mini_h;
|
|
+
|
|
+ argbdata_to_pixdata (best, w * h, pixdata);
|
|
+ argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
|
|
+
|
|
+ XFree (data);
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+try_pixmap_and_mask (Screen *screen,
|
|
+ Pixmap src_pixmap,
|
|
+ Pixmap src_mask,
|
|
+ GdkPixbuf **iconp,
|
|
+ int ideal_size,
|
|
+ GdkPixbuf **mini_iconp,
|
|
+ int ideal_mini_size)
|
|
+{
|
|
+ cairo_surface_t *surface, *mask_surface, *image;
|
|
+ GdkDisplay *gdk_display;
|
|
+ GdkPixbuf *unscaled;
|
|
+ int width, height;
|
|
+ cairo_t *cr;
|
|
+
|
|
+ if (src_pixmap == None)
|
|
+ return FALSE;
|
|
+
|
|
+ surface = _wnck_cairo_surface_get_from_pixmap (screen, src_pixmap);
|
|
+
|
|
+ if (surface && src_mask != None)
|
|
+ mask_surface = _wnck_cairo_surface_get_from_pixmap (screen, src_mask);
|
|
+ else
|
|
+ mask_surface = NULL;
|
|
+
|
|
+ if (surface == NULL)
|
|
+ return FALSE;
|
|
+
|
|
+ gdk_display = gdk_x11_lookup_xdisplay (XDisplayOfScreen (screen));
|
|
+ g_assert (gdk_display != NULL);
|
|
+
|
|
+ gdk_x11_display_error_trap_push (gdk_display);
|
|
+
|
|
+ width = cairo_xlib_surface_get_width (surface);
|
|
+ height = cairo_xlib_surface_get_height (surface);
|
|
+
|
|
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
+ width, height);
|
|
+ cr = cairo_create (image);
|
|
+
|
|
+ /* Need special code for alpha-only surfaces. We only get those
|
|
+ * for bitmaps. And in that case, it's a differentiation between
|
|
+ * foreground (white) and background (black).
|
|
+ */
|
|
+ if (cairo_surface_get_content (surface) & CAIRO_CONTENT_ALPHA)
|
|
+ {
|
|
+ cairo_push_group (cr);
|
|
+
|
|
+ /* black background */
|
|
+ cairo_set_source_rgb (cr, 0, 0, 0);
|
|
+ cairo_paint (cr);
|
|
+ /* mask with white foreground */
|
|
+ cairo_set_source_rgb (cr, 1, 1, 1);
|
|
+ cairo_mask_surface (cr, surface, 0, 0);
|
|
+
|
|
+ cairo_pop_group_to_source (cr);
|
|
+ }
|
|
+ else
|
|
+ cairo_set_source_surface (cr, surface, 0, 0);
|
|
+
|
|
+ if (mask_surface)
|
|
+ {
|
|
+ cairo_mask_surface (cr, mask_surface, 0, 0);
|
|
+ cairo_surface_destroy (mask_surface);
|
|
+ }
|
|
+ else
|
|
+ cairo_paint (cr);
|
|
+
|
|
+ cairo_surface_destroy (surface);
|
|
+ cairo_destroy (cr);
|
|
+
|
|
+ if (gdk_x11_display_error_trap_pop (gdk_display) != Success)
|
|
+ {
|
|
+ cairo_surface_destroy (image);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ unscaled = gdk_pixbuf_get_from_surface (image,
|
|
+ 0, 0,
|
|
+ width, height);
|
|
+
|
|
+ cairo_surface_destroy (image);
|
|
+
|
|
+ if (unscaled)
|
|
+ {
|
|
+ *iconp =
|
|
+ gdk_pixbuf_scale_simple (unscaled,
|
|
+ ideal_size,
|
|
+ ideal_size,
|
|
+ GDK_INTERP_BILINEAR);
|
|
+ *mini_iconp =
|
|
+ gdk_pixbuf_scale_simple (unscaled,
|
|
+ ideal_mini_size,
|
|
+ ideal_mini_size,
|
|
+ GDK_INTERP_BILINEAR);
|
|
+
|
|
+ g_object_unref (G_OBJECT (unscaled));
|
|
+ return TRUE;
|
|
+ }
|
|
+ else
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+static void
|
|
+get_kwm_win_icon (Screen *screen,
|
|
+ Window xwindow,
|
|
+ Pixmap *pixmap,
|
|
+ Pixmap *mask)
|
|
+{
|
|
+ Display *display;
|
|
+ Atom type;
|
|
+ int format;
|
|
+ gulong nitems;
|
|
+ gulong bytes_after;
|
|
+ Pixmap *icons;
|
|
+ int err, result;
|
|
+
|
|
+ display = DisplayOfScreen (screen);
|
|
+
|
|
+ *pixmap = None;
|
|
+ *mask = None;
|
|
+
|
|
+ _wnck_error_trap_push (display);
|
|
+ icons = NULL;
|
|
+ result = XGetWindowProperty (display, xwindow,
|
|
+ _wnck_atom_get ("KWM_WIN_ICON"),
|
|
+ 0, G_MAXLONG,
|
|
+ False,
|
|
+ _wnck_atom_get ("KWM_WIN_ICON"),
|
|
+ &type, &format, &nitems,
|
|
+ &bytes_after, (void*)&icons);
|
|
+
|
|
+ err = _wnck_error_trap_pop (display);
|
|
+ if (err != Success ||
|
|
+ result != Success)
|
|
+ return;
|
|
+
|
|
+ if (type != _wnck_atom_get ("KWM_WIN_ICON"))
|
|
+ {
|
|
+ XFree (icons);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ *pixmap = icons[0];
|
|
+ *mask = icons[1];
|
|
+
|
|
+ XFree (icons);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void
|
|
+clear_icon_cache (WnckIconCache *icon_cache,
|
|
+ gboolean dirty_all)
|
|
+{
|
|
+ if (icon_cache->icon)
|
|
+ g_object_unref (G_OBJECT (icon_cache->icon));
|
|
+ icon_cache->icon = NULL;
|
|
+
|
|
+ if (icon_cache->mini_icon)
|
|
+ g_object_unref (G_OBJECT (icon_cache->mini_icon));
|
|
+ icon_cache->mini_icon = NULL;
|
|
+
|
|
+ icon_cache->origin = USING_NO_ICON;
|
|
+
|
|
+ if (dirty_all)
|
|
+ {
|
|
+ icon_cache->wm_hints_dirty = TRUE;
|
|
+ icon_cache->kwm_win_icon_dirty = TRUE;
|
|
+ icon_cache->net_wm_icon_dirty = TRUE;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+replace_cache (WnckIconCache *icon_cache,
|
|
+ IconOrigin origin,
|
|
+ GdkPixbuf *new_icon,
|
|
+ GdkPixbuf *new_mini_icon)
|
|
+{
|
|
+ clear_icon_cache (icon_cache, FALSE);
|
|
+
|
|
+ icon_cache->origin = origin;
|
|
+
|
|
+ if (new_icon)
|
|
+ g_object_ref (G_OBJECT (new_icon));
|
|
+
|
|
+ icon_cache->icon = new_icon;
|
|
+
|
|
+ if (new_mini_icon)
|
|
+ g_object_ref (G_OBJECT (new_mini_icon));
|
|
+
|
|
+ icon_cache->mini_icon = new_mini_icon;
|
|
+}
|
|
+
|
|
+static void
|
|
+free_pixels (guchar *pixels,
|
|
+ gpointer data)
|
|
+{
|
|
+ g_free (pixels);
|
|
+}
|
|
+
|
|
+static GdkPixbuf*
|
|
+scaled_from_pixdata (guchar *pixdata,
|
|
+ int w,
|
|
+ int h,
|
|
+ int new_w,
|
|
+ int new_h)
|
|
+{
|
|
+ GdkPixbuf *src;
|
|
+ GdkPixbuf *dest;
|
|
+
|
|
+ src = gdk_pixbuf_new_from_data (pixdata,
|
|
+ GDK_COLORSPACE_RGB,
|
|
+ TRUE,
|
|
+ 8,
|
|
+ w, h, w * 4,
|
|
+ free_pixels,
|
|
+ NULL);
|
|
+
|
|
+ if (src == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ if (w != h)
|
|
+ {
|
|
+ GdkPixbuf *tmp;
|
|
+ int size;
|
|
+
|
|
+ size = MAX (w, h);
|
|
+
|
|
+ tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
|
|
+
|
|
+ if (tmp != NULL)
|
|
+ {
|
|
+ gdk_pixbuf_fill (tmp, 0);
|
|
+ gdk_pixbuf_copy_area (src, 0, 0, w, h,
|
|
+ tmp,
|
|
+ (size - w) / 2, (size - h) / 2);
|
|
+
|
|
+ g_object_unref (src);
|
|
+ src = tmp;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (w != new_w || h != new_h)
|
|
+ {
|
|
+ dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
|
|
+
|
|
+ g_object_unref (G_OBJECT (src));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ dest = src;
|
|
+ }
|
|
+
|
|
+ return dest;
|
|
+}
|
|
+
|
|
+WnckIconCache*
|
|
+_wnck_icon_cache_new (void)
|
|
+{
|
|
+ WnckIconCache *icon_cache;
|
|
+
|
|
+ icon_cache = g_slice_new0 (WnckIconCache);
|
|
+
|
|
+ icon_cache->origin = USING_NO_ICON;
|
|
+ icon_cache->prev_pixmap = None;
|
|
+ icon_cache->icon = NULL;
|
|
+ icon_cache->mini_icon = NULL;
|
|
+ icon_cache->ideal_size = -1; /* won't be a legit size */
|
|
+ icon_cache->ideal_mini_size = -1;
|
|
+ icon_cache->want_fallback = TRUE;
|
|
+ icon_cache->wm_hints_dirty = TRUE;
|
|
+ icon_cache->kwm_win_icon_dirty = TRUE;
|
|
+ icon_cache->net_wm_icon_dirty = TRUE;
|
|
+
|
|
+ return icon_cache;
|
|
+}
|
|
+
|
|
+void
|
|
+_wnck_icon_cache_free (WnckIconCache *icon_cache)
|
|
+{
|
|
+ clear_icon_cache (icon_cache, FALSE);
|
|
+
|
|
+ g_slice_free (WnckIconCache, icon_cache);
|
|
+}
|
|
+
|
|
+void
|
|
+_wnck_icon_cache_property_changed (WnckIconCache *icon_cache,
|
|
+ Atom atom)
|
|
+{
|
|
+ if (atom == _wnck_atom_get ("_NET_WM_ICON"))
|
|
+ icon_cache->net_wm_icon_dirty = TRUE;
|
|
+ else if (atom == _wnck_atom_get ("KWM_WIN_ICON"))
|
|
+ icon_cache->kwm_win_icon_dirty = TRUE;
|
|
+ else if (atom == _wnck_atom_get ("WM_HINTS"))
|
|
+ icon_cache->wm_hints_dirty = TRUE;
|
|
+}
|
|
+
|
|
+gboolean
|
|
+_wnck_icon_cache_get_icon_invalidated (WnckIconCache *icon_cache)
|
|
+{
|
|
+ if (icon_cache->origin <= USING_KWM_WIN_ICON &&
|
|
+ icon_cache->kwm_win_icon_dirty)
|
|
+ return TRUE;
|
|
+ else if (icon_cache->origin <= USING_WM_HINTS &&
|
|
+ icon_cache->wm_hints_dirty)
|
|
+ return TRUE;
|
|
+ else if (icon_cache->origin <= USING_NET_WM_ICON &&
|
|
+ icon_cache->net_wm_icon_dirty)
|
|
+ return TRUE;
|
|
+ else if (icon_cache->origin < USING_FALLBACK_ICON &&
|
|
+ icon_cache->want_fallback)
|
|
+ return TRUE;
|
|
+ else if (icon_cache->origin == USING_NO_ICON)
|
|
+ return TRUE;
|
|
+ else if (icon_cache->origin == USING_FALLBACK_ICON &&
|
|
+ !icon_cache->want_fallback)
|
|
+ return TRUE;
|
|
+ else
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+void
|
|
+_wnck_icon_cache_set_want_fallback (WnckIconCache *icon_cache,
|
|
+ gboolean setting)
|
|
+{
|
|
+ icon_cache->want_fallback = setting;
|
|
+}
|
|
+
|
|
+gboolean
|
|
+_wnck_icon_cache_get_is_fallback (WnckIconCache *icon_cache)
|
|
+{
|
|
+ return icon_cache->origin == USING_FALLBACK_ICON;
|
|
+}
|
|
+
|
|
+gboolean
|
|
+_wnck_read_icons (WnckScreen *screen,
|
|
+ Window xwindow,
|
|
+ WnckIconCache *icon_cache,
|
|
+ GdkPixbuf **iconp,
|
|
+ int ideal_size,
|
|
+ GdkPixbuf **mini_iconp,
|
|
+ int ideal_mini_size)
|
|
+{
|
|
+ Screen *xscreen;
|
|
+ Display *display;
|
|
+ guchar *pixdata;
|
|
+ int w, h;
|
|
+ guchar *mini_pixdata;
|
|
+ int mini_w, mini_h;
|
|
+ Pixmap pixmap;
|
|
+ Pixmap mask;
|
|
+ XWMHints *hints;
|
|
+
|
|
+ /* Return value is whether the icon changed */
|
|
+
|
|
+ g_return_val_if_fail (icon_cache != NULL, FALSE);
|
|
+
|
|
+ xscreen = _wnck_screen_get_xscreen (screen);
|
|
+ display = DisplayOfScreen (xscreen);
|
|
+
|
|
+ *iconp = NULL;
|
|
+ *mini_iconp = NULL;
|
|
+
|
|
+ if (ideal_size != icon_cache->ideal_size ||
|
|
+ ideal_mini_size != icon_cache->ideal_mini_size)
|
|
+ clear_icon_cache (icon_cache, TRUE);
|
|
+
|
|
+ icon_cache->ideal_size = ideal_size;
|
|
+ icon_cache->ideal_mini_size = ideal_mini_size;
|
|
+
|
|
+ if (!_wnck_icon_cache_get_icon_invalidated (icon_cache))
|
|
+ return FALSE; /* we have no new info to use */
|
|
+
|
|
+ pixdata = NULL;
|
|
+
|
|
+ /* Our algorithm here assumes that we can't have for example origin
|
|
+ * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE
|
|
+ * unless we have tried to read NET_WM_ICON.
|
|
+ *
|
|
+ * Put another way, if an icon origin is not dirty, then we have
|
|
+ * tried to read it at the current size. If it is dirty, then
|
|
+ * we haven't done that since the last change.
|
|
+ */
|
|
+
|
|
+ if (icon_cache->origin <= USING_NET_WM_ICON &&
|
|
+ icon_cache->net_wm_icon_dirty)
|
|
+
|
|
+ {
|
|
+ icon_cache->net_wm_icon_dirty = FALSE;
|
|
+
|
|
+ if (read_rgb_icon (xscreen, xwindow,
|
|
+ ideal_size,
|
|
+ ideal_mini_size,
|
|
+ &w, &h, &pixdata,
|
|
+ &mini_w, &mini_h, &mini_pixdata))
|
|
+ {
|
|
+ *iconp = scaled_from_pixdata (pixdata, w, h, ideal_size, ideal_size);
|
|
+
|
|
+ *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
|
|
+ ideal_mini_size, ideal_mini_size);
|
|
+
|
|
+ replace_cache (icon_cache, USING_NET_WM_ICON,
|
|
+ *iconp, *mini_iconp);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (icon_cache->origin <= USING_WM_HINTS &&
|
|
+ icon_cache->wm_hints_dirty)
|
|
+ {
|
|
+ icon_cache->wm_hints_dirty = FALSE;
|
|
+
|
|
+ _wnck_error_trap_push (display);
|
|
+ hints = XGetWMHints (display, xwindow);
|
|
+ _wnck_error_trap_pop (display);
|
|
+ pixmap = None;
|
|
+ mask = None;
|
|
+ if (hints)
|
|
+ {
|
|
+ if (hints->flags & IconPixmapHint)
|
|
+ pixmap = hints->icon_pixmap;
|
|
+ if (hints->flags & IconMaskHint)
|
|
+ mask = hints->icon_mask;
|
|
+
|
|
+ XFree (hints);
|
|
+ hints = NULL;
|
|
+ }
|
|
+
|
|
+ /* We won't update if pixmap is unchanged;
|
|
+ * avoids a get_from_drawable() on every geometry
|
|
+ * hints change
|
|
+ */
|
|
+ if ((pixmap != icon_cache->prev_pixmap ||
|
|
+ mask != icon_cache->prev_mask) &&
|
|
+ pixmap != None)
|
|
+ {
|
|
+ if (try_pixmap_and_mask (xscreen, pixmap, mask,
|
|
+ iconp, ideal_size,
|
|
+ mini_iconp, ideal_mini_size))
|
|
+ {
|
|
+ icon_cache->prev_pixmap = pixmap;
|
|
+ icon_cache->prev_mask = mask;
|
|
+
|
|
+ replace_cache (icon_cache, USING_WM_HINTS,
|
|
+ *iconp, *mini_iconp);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (icon_cache->origin <= USING_KWM_WIN_ICON &&
|
|
+ icon_cache->kwm_win_icon_dirty)
|
|
+ {
|
|
+ icon_cache->kwm_win_icon_dirty = FALSE;
|
|
+
|
|
+ get_kwm_win_icon (xscreen, xwindow, &pixmap, &mask);
|
|
+
|
|
+ if ((pixmap != icon_cache->prev_pixmap ||
|
|
+ mask != icon_cache->prev_mask) &&
|
|
+ pixmap != None)
|
|
+ {
|
|
+ if (try_pixmap_and_mask (xscreen, pixmap, mask,
|
|
+ iconp, ideal_size,
|
|
+ mini_iconp, ideal_mini_size))
|
|
+ {
|
|
+ icon_cache->prev_pixmap = pixmap;
|
|
+ icon_cache->prev_mask = mask;
|
|
+
|
|
+ replace_cache (icon_cache, USING_KWM_WIN_ICON,
|
|
+ *iconp, *mini_iconp);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (icon_cache->want_fallback &&
|
|
+ icon_cache->origin < USING_FALLBACK_ICON)
|
|
+ {
|
|
+ _wnck_get_fallback_icons (iconp,
|
|
+ ideal_size,
|
|
+ mini_iconp,
|
|
+ ideal_mini_size);
|
|
+
|
|
+ replace_cache (icon_cache, USING_FALLBACK_ICON,
|
|
+ *iconp, *mini_iconp);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ if (!icon_cache->want_fallback &&
|
|
+ icon_cache->origin == USING_FALLBACK_ICON)
|
|
+ {
|
|
+ /* Get rid of current icon */
|
|
+ clear_icon_cache (icon_cache, FALSE);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ /* found nothing new */
|
|
+ return FALSE;
|
|
+}
|
|
diff --git a/libwnck/xutils.c b/libwnck/xutils.c
|
|
index 8c14234..58873dc 100644
|
|
--- a/libwnck/xutils.c
|
|
+++ b/libwnck/xutils.c
|
|
@@ -1451,206 +1451,7 @@ _wnck_select_input (Screen *screen,
|
|
return old_mask;
|
|
}
|
|
|
|
-static gboolean
|
|
-find_best_size (gulong *data,
|
|
- gulong nitems,
|
|
- int ideal_size,
|
|
- int *width,
|
|
- int *height,
|
|
- gulong **start)
|
|
-{
|
|
- int best_w;
|
|
- int best_h;
|
|
- gulong *best_start;
|
|
-
|
|
- *width = 0;
|
|
- *height = 0;
|
|
- *start = NULL;
|
|
-
|
|
- best_w = 0;
|
|
- best_h = 0;
|
|
- best_start = NULL;
|
|
-
|
|
- while (nitems > 0)
|
|
- {
|
|
- int w, h;
|
|
- gboolean replace;
|
|
-
|
|
- replace = FALSE;
|
|
-
|
|
- if (nitems < 3)
|
|
- return FALSE; /* no space for w, h */
|
|
-
|
|
- w = data[0];
|
|
- h = data[1];
|
|
-
|
|
- if (nitems < ((gulong) (w * h) + 2))
|
|
- break; /* not enough data */
|
|
-
|
|
- if (best_start == NULL)
|
|
- {
|
|
- replace = TRUE;
|
|
- }
|
|
- else
|
|
- {
|
|
- /* work with averages */
|
|
- int best_size = (best_w + best_h) / 2;
|
|
- int this_size = (w + h) / 2;
|
|
-
|
|
- /* larger than desired is always better than smaller */
|
|
- if (best_size < ideal_size &&
|
|
- this_size >= ideal_size)
|
|
- replace = TRUE;
|
|
- /* if we have too small, pick anything bigger */
|
|
- else if (best_size < ideal_size &&
|
|
- this_size > best_size)
|
|
- replace = TRUE;
|
|
- /* if we have too large, pick anything smaller
|
|
- * but still >= the ideal
|
|
- */
|
|
- else if (best_size > ideal_size &&
|
|
- this_size >= ideal_size &&
|
|
- this_size < best_size)
|
|
- replace = TRUE;
|
|
- }
|
|
-
|
|
- if (replace)
|
|
- {
|
|
- best_start = data + 2;
|
|
- best_w = w;
|
|
- best_h = h;
|
|
- }
|
|
-
|
|
- data += (w * h) + 2;
|
|
- nitems -= (w * h) + 2;
|
|
- }
|
|
-
|
|
- if (best_start)
|
|
- {
|
|
- *start = best_start;
|
|
- *width = best_w;
|
|
- *height = best_h;
|
|
- return TRUE;
|
|
- }
|
|
- else
|
|
- return FALSE;
|
|
-}
|
|
-
|
|
-static void
|
|
-argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
|
|
-{
|
|
- guchar *p;
|
|
- int i;
|
|
-
|
|
- *pixdata = g_new (guchar, len * 4);
|
|
- p = *pixdata;
|
|
-
|
|
- /* One could speed this up a lot. */
|
|
- i = 0;
|
|
- while (i < len)
|
|
- {
|
|
- guint argb;
|
|
- guint rgba;
|
|
-
|
|
- argb = argb_data[i];
|
|
- rgba = (argb << 8) | (argb >> 24);
|
|
-
|
|
- *p = rgba >> 24;
|
|
- ++p;
|
|
- *p = (rgba >> 16) & 0xff;
|
|
- ++p;
|
|
- *p = (rgba >> 8) & 0xff;
|
|
- ++p;
|
|
- *p = rgba & 0xff;
|
|
- ++p;
|
|
-
|
|
- ++i;
|
|
- }
|
|
-}
|
|
-
|
|
-static gboolean
|
|
-read_rgb_icon (Screen *screen,
|
|
- Window xwindow,
|
|
- int ideal_size,
|
|
- int ideal_mini_size,
|
|
- int *width,
|
|
- int *height,
|
|
- guchar **pixdata,
|
|
- int *mini_width,
|
|
- int *mini_height,
|
|
- guchar **mini_pixdata)
|
|
-{
|
|
- Display *display;
|
|
- Atom type;
|
|
- int format;
|
|
- gulong nitems;
|
|
- gulong bytes_after;
|
|
- int result, err;
|
|
- gulong *data;
|
|
- gulong *best;
|
|
- int w, h;
|
|
- gulong *best_mini;
|
|
- int mini_w, mini_h;
|
|
-
|
|
- display = DisplayOfScreen (screen);
|
|
-
|
|
- _wnck_error_trap_push (display);
|
|
- type = None;
|
|
- data = NULL;
|
|
- result = XGetWindowProperty (display,
|
|
- xwindow,
|
|
- _wnck_atom_get ("_NET_WM_ICON"),
|
|
- 0, G_MAXLONG,
|
|
- False, XA_CARDINAL, &type, &format, &nitems,
|
|
- &bytes_after, (void*)&data);
|
|
-
|
|
- err = _wnck_error_trap_pop (display);
|
|
-
|
|
- if (err != Success ||
|
|
- result != Success)
|
|
- return FALSE;
|
|
-
|
|
- if (type != XA_CARDINAL)
|
|
- {
|
|
- XFree (data);
|
|
- return FALSE;
|
|
- }
|
|
-
|
|
- if (!find_best_size (data, nitems, ideal_size, &w, &h, &best))
|
|
- {
|
|
- XFree (data);
|
|
- return FALSE;
|
|
- }
|
|
-
|
|
- if (!find_best_size (data, nitems,
|
|
- ideal_mini_size,
|
|
- &mini_w, &mini_h, &best_mini))
|
|
- {
|
|
- XFree (data);
|
|
- return FALSE;
|
|
- }
|
|
-
|
|
- *width = w;
|
|
- *height = h;
|
|
-
|
|
- *mini_width = mini_w;
|
|
- *mini_height = mini_h;
|
|
-
|
|
- argbdata_to_pixdata (best, w * h, pixdata);
|
|
- argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
|
|
-
|
|
- XFree (data);
|
|
-
|
|
- return TRUE;
|
|
-}
|
|
-
|
|
-static void
|
|
-free_pixels (guchar *pixels, gpointer data)
|
|
-{
|
|
- g_free (pixels);
|
|
-}
|
|
-
|
|
-static cairo_surface_t *
|
|
+cairo_surface_t *
|
|
_wnck_cairo_surface_get_from_pixmap (Screen *screen,
|
|
Pixmap xpixmap)
|
|
{
|
|
@@ -1741,534 +1542,6 @@ _wnck_gdk_pixbuf_get_from_pixmap (Screen *screen,
|
|
return retval;
|
|
}
|
|
|
|
-static gboolean
|
|
-try_pixmap_and_mask (Screen *screen,
|
|
- Pixmap src_pixmap,
|
|
- Pixmap src_mask,
|
|
- GdkPixbuf **iconp,
|
|
- int ideal_size,
|
|
- GdkPixbuf **mini_iconp,
|
|
- int ideal_mini_size)
|
|
-{
|
|
- cairo_surface_t *surface, *mask_surface, *image;
|
|
- GdkDisplay *gdk_display;
|
|
- GdkPixbuf *unscaled;
|
|
- int width, height;
|
|
- cairo_t *cr;
|
|
-
|
|
- if (src_pixmap == None)
|
|
- return FALSE;
|
|
-
|
|
- surface = _wnck_cairo_surface_get_from_pixmap (screen, src_pixmap);
|
|
-
|
|
- if (surface && src_mask != None)
|
|
- mask_surface = _wnck_cairo_surface_get_from_pixmap (screen, src_mask);
|
|
- else
|
|
- mask_surface = NULL;
|
|
-
|
|
- if (surface == NULL)
|
|
- return FALSE;
|
|
-
|
|
- gdk_display = gdk_x11_lookup_xdisplay (XDisplayOfScreen (screen));
|
|
- g_assert (gdk_display != NULL);
|
|
-
|
|
- gdk_x11_display_error_trap_push (gdk_display);
|
|
-
|
|
- width = cairo_xlib_surface_get_width (surface);
|
|
- height = cairo_xlib_surface_get_height (surface);
|
|
-
|
|
- image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
- width, height);
|
|
- cr = cairo_create (image);
|
|
-
|
|
- /* Need special code for alpha-only surfaces. We only get those
|
|
- * for bitmaps. And in that case, it's a differentiation between
|
|
- * foreground (white) and background (black).
|
|
- */
|
|
- if (cairo_surface_get_content (surface) & CAIRO_CONTENT_ALPHA)
|
|
- {
|
|
- cairo_push_group (cr);
|
|
-
|
|
- /* black background */
|
|
- cairo_set_source_rgb (cr, 0, 0, 0);
|
|
- cairo_paint (cr);
|
|
- /* mask with white foreground */
|
|
- cairo_set_source_rgb (cr, 1, 1, 1);
|
|
- cairo_mask_surface (cr, surface, 0, 0);
|
|
-
|
|
- cairo_pop_group_to_source (cr);
|
|
- }
|
|
- else
|
|
- cairo_set_source_surface (cr, surface, 0, 0);
|
|
-
|
|
- if (mask_surface)
|
|
- {
|
|
- cairo_mask_surface (cr, mask_surface, 0, 0);
|
|
- cairo_surface_destroy (mask_surface);
|
|
- }
|
|
- else
|
|
- cairo_paint (cr);
|
|
-
|
|
- cairo_surface_destroy (surface);
|
|
- cairo_destroy (cr);
|
|
-
|
|
- if (gdk_x11_display_error_trap_pop (gdk_display) != Success)
|
|
- {
|
|
- cairo_surface_destroy (image);
|
|
- return FALSE;
|
|
- }
|
|
-
|
|
- unscaled = gdk_pixbuf_get_from_surface (image,
|
|
- 0, 0,
|
|
- width, height);
|
|
-
|
|
- cairo_surface_destroy (image);
|
|
-
|
|
- if (unscaled)
|
|
- {
|
|
- *iconp =
|
|
- gdk_pixbuf_scale_simple (unscaled,
|
|
- ideal_size,
|
|
- ideal_size,
|
|
- GDK_INTERP_BILINEAR);
|
|
- *mini_iconp =
|
|
- gdk_pixbuf_scale_simple (unscaled,
|
|
- ideal_mini_size,
|
|
- ideal_mini_size,
|
|
- GDK_INTERP_BILINEAR);
|
|
-
|
|
- g_object_unref (G_OBJECT (unscaled));
|
|
- return TRUE;
|
|
- }
|
|
- else
|
|
- return FALSE;
|
|
-}
|
|
-
|
|
-static void
|
|
-get_kwm_win_icon (Screen *screen,
|
|
- Window xwindow,
|
|
- Pixmap *pixmap,
|
|
- Pixmap *mask)
|
|
-{
|
|
- Display *display;
|
|
- Atom type;
|
|
- int format;
|
|
- gulong nitems;
|
|
- gulong bytes_after;
|
|
- Pixmap *icons;
|
|
- int err, result;
|
|
-
|
|
- display = DisplayOfScreen (screen);
|
|
-
|
|
- *pixmap = None;
|
|
- *mask = None;
|
|
-
|
|
- _wnck_error_trap_push (display);
|
|
- icons = NULL;
|
|
- result = XGetWindowProperty (display, xwindow,
|
|
- _wnck_atom_get ("KWM_WIN_ICON"),
|
|
- 0, G_MAXLONG,
|
|
- False,
|
|
- _wnck_atom_get ("KWM_WIN_ICON"),
|
|
- &type, &format, &nitems,
|
|
- &bytes_after, (void*)&icons);
|
|
-
|
|
- err = _wnck_error_trap_pop (display);
|
|
- if (err != Success ||
|
|
- result != Success)
|
|
- return;
|
|
-
|
|
- if (type != _wnck_atom_get ("KWM_WIN_ICON"))
|
|
- {
|
|
- XFree (icons);
|
|
- return;
|
|
- }
|
|
-
|
|
- *pixmap = icons[0];
|
|
- *mask = icons[1];
|
|
-
|
|
- XFree (icons);
|
|
-
|
|
- return;
|
|
-}
|
|
-
|
|
-typedef enum
|
|
-{
|
|
- /* These MUST be in ascending order of preference;
|
|
- * i.e. if we get _NET_WM_ICON and already have
|
|
- * WM_HINTS, we prefer _NET_WM_ICON
|
|
- */
|
|
- USING_NO_ICON,
|
|
- USING_FALLBACK_ICON,
|
|
- USING_KWM_WIN_ICON,
|
|
- USING_WM_HINTS,
|
|
- USING_NET_WM_ICON
|
|
-} IconOrigin;
|
|
-
|
|
-struct _WnckIconCache
|
|
-{
|
|
- IconOrigin origin;
|
|
- Pixmap prev_pixmap;
|
|
- Pixmap prev_mask;
|
|
- GdkPixbuf *icon;
|
|
- GdkPixbuf *mini_icon;
|
|
- int ideal_size;
|
|
- int ideal_mini_size;
|
|
- guint want_fallback : 1;
|
|
- /* TRUE if these props have changed */
|
|
- guint wm_hints_dirty : 1;
|
|
- guint kwm_win_icon_dirty : 1;
|
|
- guint net_wm_icon_dirty : 1;
|
|
-};
|
|
-
|
|
-WnckIconCache*
|
|
-_wnck_icon_cache_new (void)
|
|
-{
|
|
- WnckIconCache *icon_cache;
|
|
-
|
|
- icon_cache = g_slice_new0 (WnckIconCache);
|
|
-
|
|
- icon_cache->origin = USING_NO_ICON;
|
|
- icon_cache->prev_pixmap = None;
|
|
- icon_cache->icon = NULL;
|
|
- icon_cache->mini_icon = NULL;
|
|
- icon_cache->ideal_size = -1; /* won't be a legit size */
|
|
- icon_cache->ideal_mini_size = -1;
|
|
- icon_cache->want_fallback = TRUE;
|
|
- icon_cache->wm_hints_dirty = TRUE;
|
|
- icon_cache->kwm_win_icon_dirty = TRUE;
|
|
- icon_cache->net_wm_icon_dirty = TRUE;
|
|
-
|
|
- return icon_cache;
|
|
-}
|
|
-
|
|
-static void
|
|
-clear_icon_cache (WnckIconCache *icon_cache,
|
|
- gboolean dirty_all)
|
|
-{
|
|
- if (icon_cache->icon)
|
|
- g_object_unref (G_OBJECT (icon_cache->icon));
|
|
- icon_cache->icon = NULL;
|
|
-
|
|
- if (icon_cache->mini_icon)
|
|
- g_object_unref (G_OBJECT (icon_cache->mini_icon));
|
|
- icon_cache->mini_icon = NULL;
|
|
-
|
|
- icon_cache->origin = USING_NO_ICON;
|
|
-
|
|
- if (dirty_all)
|
|
- {
|
|
- icon_cache->wm_hints_dirty = TRUE;
|
|
- icon_cache->kwm_win_icon_dirty = TRUE;
|
|
- icon_cache->net_wm_icon_dirty = TRUE;
|
|
- }
|
|
-}
|
|
-
|
|
-void
|
|
-_wnck_icon_cache_free (WnckIconCache *icon_cache)
|
|
-{
|
|
- clear_icon_cache (icon_cache, FALSE);
|
|
-
|
|
- g_slice_free (WnckIconCache, icon_cache);
|
|
-}
|
|
-
|
|
-void
|
|
-_wnck_icon_cache_property_changed (WnckIconCache *icon_cache,
|
|
- Atom atom)
|
|
-{
|
|
- if (atom == _wnck_atom_get ("_NET_WM_ICON"))
|
|
- icon_cache->net_wm_icon_dirty = TRUE;
|
|
- else if (atom == _wnck_atom_get ("KWM_WIN_ICON"))
|
|
- icon_cache->kwm_win_icon_dirty = TRUE;
|
|
- else if (atom == _wnck_atom_get ("WM_HINTS"))
|
|
- icon_cache->wm_hints_dirty = TRUE;
|
|
-}
|
|
-
|
|
-gboolean
|
|
-_wnck_icon_cache_get_icon_invalidated (WnckIconCache *icon_cache)
|
|
-{
|
|
- if (icon_cache->origin <= USING_KWM_WIN_ICON &&
|
|
- icon_cache->kwm_win_icon_dirty)
|
|
- return TRUE;
|
|
- else if (icon_cache->origin <= USING_WM_HINTS &&
|
|
- icon_cache->wm_hints_dirty)
|
|
- return TRUE;
|
|
- else if (icon_cache->origin <= USING_NET_WM_ICON &&
|
|
- icon_cache->net_wm_icon_dirty)
|
|
- return TRUE;
|
|
- else if (icon_cache->origin < USING_FALLBACK_ICON &&
|
|
- icon_cache->want_fallback)
|
|
- return TRUE;
|
|
- else if (icon_cache->origin == USING_NO_ICON)
|
|
- return TRUE;
|
|
- else if (icon_cache->origin == USING_FALLBACK_ICON &&
|
|
- !icon_cache->want_fallback)
|
|
- return TRUE;
|
|
- else
|
|
- return FALSE;
|
|
-}
|
|
-
|
|
-void
|
|
-_wnck_icon_cache_set_want_fallback (WnckIconCache *icon_cache,
|
|
- gboolean setting)
|
|
-{
|
|
- icon_cache->want_fallback = setting;
|
|
-}
|
|
-
|
|
-gboolean
|
|
-_wnck_icon_cache_get_is_fallback (WnckIconCache *icon_cache)
|
|
-{
|
|
- return icon_cache->origin == USING_FALLBACK_ICON;
|
|
-}
|
|
-
|
|
-static void
|
|
-replace_cache (WnckIconCache *icon_cache,
|
|
- IconOrigin origin,
|
|
- GdkPixbuf *new_icon,
|
|
- GdkPixbuf *new_mini_icon)
|
|
-{
|
|
- clear_icon_cache (icon_cache, FALSE);
|
|
-
|
|
- icon_cache->origin = origin;
|
|
-
|
|
- if (new_icon)
|
|
- g_object_ref (G_OBJECT (new_icon));
|
|
-
|
|
- icon_cache->icon = new_icon;
|
|
-
|
|
- if (new_mini_icon)
|
|
- g_object_ref (G_OBJECT (new_mini_icon));
|
|
-
|
|
- icon_cache->mini_icon = new_mini_icon;
|
|
-}
|
|
-
|
|
-static GdkPixbuf*
|
|
-scaled_from_pixdata (guchar *pixdata,
|
|
- int w,
|
|
- int h,
|
|
- int new_w,
|
|
- int new_h)
|
|
-{
|
|
- GdkPixbuf *src;
|
|
- GdkPixbuf *dest;
|
|
-
|
|
- src = gdk_pixbuf_new_from_data (pixdata,
|
|
- GDK_COLORSPACE_RGB,
|
|
- TRUE,
|
|
- 8,
|
|
- w, h, w * 4,
|
|
- free_pixels,
|
|
- NULL);
|
|
-
|
|
- if (src == NULL)
|
|
- return NULL;
|
|
-
|
|
- if (w != h)
|
|
- {
|
|
- GdkPixbuf *tmp;
|
|
- int size;
|
|
-
|
|
- size = MAX (w, h);
|
|
-
|
|
- tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
|
|
-
|
|
- if (tmp != NULL)
|
|
- {
|
|
- gdk_pixbuf_fill (tmp, 0);
|
|
- gdk_pixbuf_copy_area (src, 0, 0, w, h,
|
|
- tmp,
|
|
- (size - w) / 2, (size - h) / 2);
|
|
-
|
|
- g_object_unref (src);
|
|
- src = tmp;
|
|
- }
|
|
- }
|
|
-
|
|
- if (w != new_w || h != new_h)
|
|
- {
|
|
- dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
|
|
-
|
|
- g_object_unref (G_OBJECT (src));
|
|
- }
|
|
- else
|
|
- {
|
|
- dest = src;
|
|
- }
|
|
-
|
|
- return dest;
|
|
-}
|
|
-
|
|
-gboolean
|
|
-_wnck_read_icons (WnckScreen *screen,
|
|
- Window xwindow,
|
|
- WnckIconCache *icon_cache,
|
|
- GdkPixbuf **iconp,
|
|
- int ideal_size,
|
|
- GdkPixbuf **mini_iconp,
|
|
- int ideal_mini_size)
|
|
-{
|
|
- Screen *xscreen;
|
|
- Display *display;
|
|
- guchar *pixdata;
|
|
- int w, h;
|
|
- guchar *mini_pixdata;
|
|
- int mini_w, mini_h;
|
|
- Pixmap pixmap;
|
|
- Pixmap mask;
|
|
- XWMHints *hints;
|
|
-
|
|
- /* Return value is whether the icon changed */
|
|
-
|
|
- g_return_val_if_fail (icon_cache != NULL, FALSE);
|
|
-
|
|
- xscreen = _wnck_screen_get_xscreen (screen);
|
|
- display = DisplayOfScreen (xscreen);
|
|
-
|
|
- *iconp = NULL;
|
|
- *mini_iconp = NULL;
|
|
-
|
|
- if (ideal_size != icon_cache->ideal_size ||
|
|
- ideal_mini_size != icon_cache->ideal_mini_size)
|
|
- clear_icon_cache (icon_cache, TRUE);
|
|
-
|
|
- icon_cache->ideal_size = ideal_size;
|
|
- icon_cache->ideal_mini_size = ideal_mini_size;
|
|
-
|
|
- if (!_wnck_icon_cache_get_icon_invalidated (icon_cache))
|
|
- return FALSE; /* we have no new info to use */
|
|
-
|
|
- pixdata = NULL;
|
|
-
|
|
- /* Our algorithm here assumes that we can't have for example origin
|
|
- * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE
|
|
- * unless we have tried to read NET_WM_ICON.
|
|
- *
|
|
- * Put another way, if an icon origin is not dirty, then we have
|
|
- * tried to read it at the current size. If it is dirty, then
|
|
- * we haven't done that since the last change.
|
|
- */
|
|
-
|
|
- if (icon_cache->origin <= USING_NET_WM_ICON &&
|
|
- icon_cache->net_wm_icon_dirty)
|
|
-
|
|
- {
|
|
- icon_cache->net_wm_icon_dirty = FALSE;
|
|
-
|
|
- if (read_rgb_icon (xscreen, xwindow,
|
|
- ideal_size,
|
|
- ideal_mini_size,
|
|
- &w, &h, &pixdata,
|
|
- &mini_w, &mini_h, &mini_pixdata))
|
|
- {
|
|
- *iconp = scaled_from_pixdata (pixdata, w, h, ideal_size, ideal_size);
|
|
-
|
|
- *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
|
|
- ideal_mini_size, ideal_mini_size);
|
|
-
|
|
- replace_cache (icon_cache, USING_NET_WM_ICON,
|
|
- *iconp, *mini_iconp);
|
|
-
|
|
- return TRUE;
|
|
- }
|
|
- }
|
|
-
|
|
- if (icon_cache->origin <= USING_WM_HINTS &&
|
|
- icon_cache->wm_hints_dirty)
|
|
- {
|
|
- icon_cache->wm_hints_dirty = FALSE;
|
|
-
|
|
- _wnck_error_trap_push (display);
|
|
- hints = XGetWMHints (display, xwindow);
|
|
- _wnck_error_trap_pop (display);
|
|
- pixmap = None;
|
|
- mask = None;
|
|
- if (hints)
|
|
- {
|
|
- if (hints->flags & IconPixmapHint)
|
|
- pixmap = hints->icon_pixmap;
|
|
- if (hints->flags & IconMaskHint)
|
|
- mask = hints->icon_mask;
|
|
-
|
|
- XFree (hints);
|
|
- hints = NULL;
|
|
- }
|
|
-
|
|
- /* We won't update if pixmap is unchanged;
|
|
- * avoids a get_from_drawable() on every geometry
|
|
- * hints change
|
|
- */
|
|
- if ((pixmap != icon_cache->prev_pixmap ||
|
|
- mask != icon_cache->prev_mask) &&
|
|
- pixmap != None)
|
|
- {
|
|
- if (try_pixmap_and_mask (xscreen, pixmap, mask,
|
|
- iconp, ideal_size,
|
|
- mini_iconp, ideal_mini_size))
|
|
- {
|
|
- icon_cache->prev_pixmap = pixmap;
|
|
- icon_cache->prev_mask = mask;
|
|
-
|
|
- replace_cache (icon_cache, USING_WM_HINTS,
|
|
- *iconp, *mini_iconp);
|
|
-
|
|
- return TRUE;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- if (icon_cache->origin <= USING_KWM_WIN_ICON &&
|
|
- icon_cache->kwm_win_icon_dirty)
|
|
- {
|
|
- icon_cache->kwm_win_icon_dirty = FALSE;
|
|
-
|
|
- get_kwm_win_icon (xscreen, xwindow, &pixmap, &mask);
|
|
-
|
|
- if ((pixmap != icon_cache->prev_pixmap ||
|
|
- mask != icon_cache->prev_mask) &&
|
|
- pixmap != None)
|
|
- {
|
|
- if (try_pixmap_and_mask (xscreen, pixmap, mask,
|
|
- iconp, ideal_size,
|
|
- mini_iconp, ideal_mini_size))
|
|
- {
|
|
- icon_cache->prev_pixmap = pixmap;
|
|
- icon_cache->prev_mask = mask;
|
|
-
|
|
- replace_cache (icon_cache, USING_KWM_WIN_ICON,
|
|
- *iconp, *mini_iconp);
|
|
-
|
|
- return TRUE;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- if (icon_cache->want_fallback &&
|
|
- icon_cache->origin < USING_FALLBACK_ICON)
|
|
- {
|
|
- _wnck_get_fallback_icons (iconp,
|
|
- ideal_size,
|
|
- mini_iconp,
|
|
- ideal_mini_size);
|
|
-
|
|
- replace_cache (icon_cache, USING_FALLBACK_ICON,
|
|
- *iconp, *mini_iconp);
|
|
-
|
|
- return TRUE;
|
|
- }
|
|
-
|
|
- if (!icon_cache->want_fallback &&
|
|
- icon_cache->origin == USING_FALLBACK_ICON)
|
|
- {
|
|
- /* Get rid of current icon */
|
|
- clear_icon_cache (icon_cache, FALSE);
|
|
-
|
|
- return TRUE;
|
|
- }
|
|
-
|
|
- /* found nothing new */
|
|
- return FALSE;
|
|
-}
|
|
-
|
|
static GdkPixbuf*
|
|
default_icon_at_size (int size)
|
|
{
|
|
diff --git a/libwnck/xutils.h b/libwnck/xutils.h
|
|
index e5ef85d..2af255d 100644
|
|
--- a/libwnck/xutils.h
|
|
+++ b/libwnck/xutils.h
|
|
@@ -159,25 +159,6 @@ void _wnck_keyboard_size (WnckScreen *screen,
|
|
void _wnck_toggle_showing_desktop (Screen *screen,
|
|
gboolean show);
|
|
|
|
-typedef struct _WnckIconCache WnckIconCache;
|
|
-
|
|
-WnckIconCache *_wnck_icon_cache_new (void);
|
|
-void _wnck_icon_cache_free (WnckIconCache *icon_cache);
|
|
-void _wnck_icon_cache_property_changed (WnckIconCache *icon_cache,
|
|
- Atom atom);
|
|
-gboolean _wnck_icon_cache_get_icon_invalidated (WnckIconCache *icon_cache);
|
|
-void _wnck_icon_cache_set_want_fallback (WnckIconCache *icon_cache,
|
|
- gboolean setting);
|
|
-gboolean _wnck_icon_cache_get_is_fallback (WnckIconCache *icon_cache);
|
|
-
|
|
-gboolean _wnck_read_icons (WnckScreen *screen,
|
|
- Window xwindow,
|
|
- WnckIconCache *icon_cache,
|
|
- GdkPixbuf **iconp,
|
|
- int ideal_size,
|
|
- GdkPixbuf **mini_iconp,
|
|
- int ideal_mini_size);
|
|
-
|
|
void _wnck_get_fallback_icons (GdkPixbuf **iconp,
|
|
int ideal_size,
|
|
GdkPixbuf **mini_iconp,
|
|
@@ -213,6 +194,9 @@ void _wnck_set_desktop_layout (Screen *xscreen,
|
|
int rows,
|
|
int columns);
|
|
|
|
+cairo_surface_t *_wnck_cairo_surface_get_from_pixmap (Screen *screen,
|
|
+ Pixmap xpixmap);
|
|
+
|
|
GdkPixbuf* _wnck_gdk_pixbuf_get_from_pixmap (Screen *screen,
|
|
Pixmap xpixmap);
|
|
|
|
--
|
|
2.31.1
|
|
|