summaryrefslogtreecommitdiff
path: root/src/core/iconcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/iconcache.c')
-rw-r--r--src/core/iconcache.c849
1 files changed, 0 insertions, 849 deletions
diff --git a/src/core/iconcache.c b/src/core/iconcache.c
deleted file mode 100644
index 7fa21840..00000000
--- a/src/core/iconcache.c
+++ /dev/null
@@ -1,849 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-/* Metacity window icons */
-
-/*
- * Copyright (C) 2002 Havoc Pennington
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include "iconcache.h"
-#include "ui.h"
-#include "errors.h"
-
-#include <X11/Xatom.h>
-
-/* The icon-reading code is also in libwnck, please sync bugfixes */
-
-static void
-get_fallback_icons (MetaScreen *screen,
- GdkPixbuf **iconp,
- int ideal_width,
- int ideal_height,
- GdkPixbuf **mini_iconp,
- int ideal_mini_width,
- int ideal_mini_height)
-{
- /* we don't scale, should be fixed if we ever un-hardcode the icon
- * size
- */
- *iconp = meta_ui_get_default_window_icon (screen->ui);
- *mini_iconp = meta_ui_get_default_mini_icon (screen->ui);
-}
-
-static gboolean
-find_largest_sizes (gulong *data,
- gulong nitems,
- int *width,
- int *height)
-{
- *width = 0;
- *height = 0;
-
- while (nitems > 0)
- {
- int w, h;
-
- if (nitems < 3)
- return FALSE; /* no space for w, h */
-
- w = data[0];
- h = data[1];
-
- if (nitems < ((gulong)(w * h) + 2))
- return FALSE; /* not enough data */
-
- *width = MAX (w, *width);
- *height = MAX (h, *height);
-
- data += (w * h) + 2;
- nitems -= (w * h) + 2;
- }
-
- return TRUE;
-}
-
-static gboolean
-find_best_size (gulong *data,
- gulong nitems,
- int ideal_width,
- int ideal_height,
- int *width,
- int *height,
- gulong **start)
-{
- int best_w;
- int best_h;
- gulong *best_start;
- int max_width, max_height;
-
- *width = 0;
- *height = 0;
- *start = NULL;
-
- if (!find_largest_sizes (data, nitems, &max_width, &max_height))
- return FALSE;
-
- if (ideal_width < 0)
- ideal_width = max_width;
- if (ideal_height < 0)
- ideal_height = max_height;
-
- 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 */
- const int ideal_size = (ideal_width + ideal_height) / 2;
- 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 (MetaDisplay *display,
- Window xwindow,
- int ideal_width,
- int ideal_height,
- int ideal_mini_width,
- int ideal_mini_height,
- int *width,
- int *height,
- guchar **pixdata,
- int *mini_width,
- int *mini_height,
- guchar **mini_pixdata)
-{
- Atom type;
- int format;
- gulong nitems;
- gulong bytes_after;
- int result, err;
- guchar *data;
- gulong *best;
- int w, h;
- gulong *best_mini;
- int mini_w, mini_h;
- gulong *data_as_long;
-
- meta_error_trap_push_with_return (display);
- type = None;
- data = NULL;
- result = XGetWindowProperty (display->xdisplay,
- xwindow,
- display->atom__NET_WM_ICON,
- 0, G_MAXLONG,
- False, XA_CARDINAL, &type, &format, &nitems,
- &bytes_after, &data);
- err = meta_error_trap_pop_with_return (display, TRUE);
-
- if (err != Success ||
- result != Success)
- return FALSE;
-
- if (type != XA_CARDINAL)
- {
- XFree (data);
- return FALSE;
- }
-
- data_as_long = (gulong *)data;
-
- if (!find_best_size (data_as_long, nitems,
- ideal_width, ideal_height,
- &w, &h, &best))
- {
- XFree (data);
- return FALSE;
- }
-
- if (!find_best_size (data_as_long, nitems,
- ideal_mini_width, ideal_mini_height,
- &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 void
-get_pixmap_geometry (MetaDisplay *display,
- Pixmap pixmap,
- int *w,
- int *h,
- int *d)
-{
- Window root_ignored;
- int x_ignored, y_ignored;
- guint width, height;
- guint border_width_ignored;
- guint depth;
-
- if (w)
- *w = 1;
- if (h)
- *h = 1;
- if (d)
- *d = 1;
-
- XGetGeometry (display->xdisplay,
- pixmap, &root_ignored, &x_ignored, &y_ignored,
- &width, &height, &border_width_ignored, &depth);
-
- if (w)
- *w = width;
- if (h)
- *h = height;
- if (d)
- *d = depth;
-}
-
-static GdkPixbuf*
-apply_mask (GdkPixbuf *pixbuf,
- GdkPixbuf *mask)
-{
- int w, h;
- int i, j;
- GdkPixbuf *with_alpha;
- guchar *src;
- guchar *dest;
- int src_stride;
- int dest_stride;
-
- w = MIN (gdk_pixbuf_get_width (mask), gdk_pixbuf_get_width (pixbuf));
- h = MIN (gdk_pixbuf_get_height (mask), gdk_pixbuf_get_height (pixbuf));
-
- with_alpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
-
- dest = gdk_pixbuf_get_pixels (with_alpha);
- src = gdk_pixbuf_get_pixels (mask);
-
- dest_stride = gdk_pixbuf_get_rowstride (with_alpha);
- src_stride = gdk_pixbuf_get_rowstride (mask);
-
- i = 0;
- while (i < h)
- {
- j = 0;
- while (j < w)
- {
- guchar *s = src + i * src_stride + j * 3;
- guchar *d = dest + i * dest_stride + j * 4;
-
- /* s[0] == s[1] == s[2], they are 255 if the bit was set, 0
- * otherwise
- */
- if (s[0] == 0)
- d[3] = 0; /* transparent */
- else
- d[3] = 255; /* opaque */
-
- ++j;
- }
-
- ++i;
- }
-
- return with_alpha;
-}
-
-static gboolean
-try_pixmap_and_mask (MetaDisplay *display,
- Pixmap src_pixmap,
- Pixmap src_mask,
- GdkPixbuf **iconp,
- int ideal_width,
- int ideal_height,
- GdkPixbuf **mini_iconp,
- int ideal_mini_width,
- int ideal_mini_height)
-{
- GdkPixbuf *unscaled = NULL;
- GdkPixbuf *mask = NULL;
- int w, h;
-
- if (src_pixmap == None)
- return FALSE;
-
- meta_error_trap_push (display);
-
- get_pixmap_geometry (display, src_pixmap, &w, &h, NULL);
-
- unscaled = meta_gdk_pixbuf_get_from_pixmap (NULL,
- src_pixmap,
- 0, 0, 0, 0,
- w, h);
-
- if (unscaled && src_mask != None)
- {
- get_pixmap_geometry (display, src_mask, &w, &h, NULL);
- mask = meta_gdk_pixbuf_get_from_pixmap (NULL,
- src_mask,
- 0, 0, 0, 0,
- w, h);
- }
-
- meta_error_trap_pop (display, FALSE);
-
- if (mask)
- {
- GdkPixbuf *masked;
-
- masked = apply_mask (unscaled, mask);
- g_object_unref (G_OBJECT (unscaled));
- unscaled = masked;
-
- g_object_unref (G_OBJECT (mask));
- mask = NULL;
- }
-
- if (unscaled)
- {
- *iconp =
- gdk_pixbuf_scale_simple (unscaled,
- ideal_width > 0 ? ideal_width :
- gdk_pixbuf_get_width (unscaled),
- ideal_height > 0 ? ideal_height :
- gdk_pixbuf_get_height (unscaled),
- GDK_INTERP_BILINEAR);
- *mini_iconp =
- gdk_pixbuf_scale_simple (unscaled,
- ideal_mini_width > 0 ? ideal_mini_width :
- gdk_pixbuf_get_width (unscaled),
- ideal_mini_height > 0 ? ideal_mini_height :
- gdk_pixbuf_get_height (unscaled),
- GDK_INTERP_BILINEAR);
-
- g_object_unref (G_OBJECT (unscaled));
-
- if (*iconp && *mini_iconp)
- return TRUE;
- else
- {
- if (*iconp)
- g_object_unref (G_OBJECT (*iconp));
- if (*mini_iconp)
- g_object_unref (G_OBJECT (*mini_iconp));
- return FALSE;
- }
- }
- else
- return FALSE;
-}
-
-static void
-get_kwm_win_icon (MetaDisplay *display,
- Window xwindow,
- Pixmap *pixmap,
- Pixmap *mask)
-{
- Atom type;
- int format;
- gulong nitems;
- gulong bytes_after;
- guchar *data;
- Pixmap *icons;
- int err, result;
-
- *pixmap = None;
- *mask = None;
-
- meta_error_trap_push_with_return (display);
- icons = NULL;
- result = XGetWindowProperty (display->xdisplay, xwindow,
- display->atom__KWM_WIN_ICON,
- 0, G_MAXLONG,
- False,
- display->atom__KWM_WIN_ICON,
- &type, &format, &nitems,
- &bytes_after, &data);
- icons = (Pixmap *)data;
-
- err = meta_error_trap_pop_with_return (display, TRUE);
- if (err != Success ||
- result != Success)
- return;
-
- if (type != display->atom__KWM_WIN_ICON)
- {
- XFree (icons);
- return;
- }
-
- *pixmap = icons[0];
- *mask = icons[1];
-
- XFree (icons);
-
- return;
-}
-
-void
-meta_icon_cache_init (MetaIconCache *icon_cache)
-{
- g_return_if_fail (icon_cache != NULL);
-
- icon_cache->origin = USING_NO_ICON;
- icon_cache->prev_pixmap = None;
- icon_cache->prev_mask = None;
-#if 0
- icon_cache->icon = NULL;
- icon_cache->mini_icon = NULL;
- icon_cache->ideal_width = -1; /* won't be a legit width */
- icon_cache->ideal_height = -1;
- icon_cache->ideal_mini_width = -1;
- icon_cache->ideal_mini_height = -1;
-#endif
- 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;
-}
-
-static void
-clear_icon_cache (MetaIconCache *icon_cache,
- gboolean dirty_all)
-{
-#if 0
- 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;
-#endif
-
- 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
-meta_icon_cache_free (MetaIconCache *icon_cache)
-{
- clear_icon_cache (icon_cache, FALSE);
-}
-
-void
-meta_icon_cache_property_changed (MetaIconCache *icon_cache,
- MetaDisplay *display,
- Atom atom)
-{
- if (atom == display->atom__NET_WM_ICON)
- icon_cache->net_wm_icon_dirty = TRUE;
- else if (atom == display->atom__KWM_WIN_ICON)
- icon_cache->kwm_win_icon_dirty = TRUE;
- else if (atom == XA_WM_HINTS)
- icon_cache->wm_hints_dirty = TRUE;
-}
-
-gboolean
-meta_icon_cache_get_icon_invalidated (MetaIconCache *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;
-}
-
-static void
-replace_cache (MetaIconCache *icon_cache,
- IconOrigin origin,
- GdkPixbuf *new_icon,
- GdkPixbuf *new_mini_icon)
-{
- clear_icon_cache (icon_cache, FALSE);
-
- icon_cache->origin = origin;
-
-#if 0
- 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;
-#endif
-}
-
-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)
- {
- 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
-meta_read_icons (MetaScreen *screen,
- Window xwindow,
- MetaIconCache *icon_cache,
- Pixmap wm_hints_pixmap,
- Pixmap wm_hints_mask,
- GdkPixbuf **iconp,
- int ideal_width,
- int ideal_height,
- GdkPixbuf **mini_iconp,
- int ideal_mini_width,
- int ideal_mini_height)
-{
- guchar *pixdata;
- int w, h;
- guchar *mini_pixdata;
- int mini_w, mini_h;
- Pixmap pixmap;
- Pixmap mask;
-
- /* Return value is whether the icon changed */
-
- g_return_val_if_fail (icon_cache != NULL, FALSE);
-
- *iconp = NULL;
- *mini_iconp = NULL;
-
-#if 0
- if (ideal_width != icon_cache->ideal_width ||
- ideal_height != icon_cache->ideal_height ||
- ideal_mini_width != icon_cache->ideal_mini_width ||
- ideal_mini_height != icon_cache->ideal_mini_height)
- clear_icon_cache (icon_cache, TRUE);
-
- icon_cache->ideal_width = ideal_width;
- icon_cache->ideal_height = ideal_height;
- icon_cache->ideal_mini_width = ideal_mini_width;
- icon_cache->ideal_mini_height = ideal_mini_height;
-#endif
-
- if (!meta_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 (screen->display, xwindow,
- ideal_width, ideal_height,
- ideal_mini_width, ideal_mini_height,
- &w, &h, &pixdata,
- &mini_w, &mini_h, &mini_pixdata))
- {
- *iconp = scaled_from_pixdata (pixdata, w, h,
- ideal_width, ideal_height);
-
- *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
- ideal_mini_width, ideal_mini_height);
-
- if (*iconp && *mini_iconp)
- {
- replace_cache (icon_cache, USING_NET_WM_ICON,
- *iconp, *mini_iconp);
-
- return TRUE;
- }
- else
- {
- if (*iconp)
- g_object_unref (G_OBJECT (*iconp));
- if (*mini_iconp)
- g_object_unref (G_OBJECT (*mini_iconp));
- }
- }
- }
-
- if (icon_cache->origin <= USING_WM_HINTS &&
- icon_cache->wm_hints_dirty)
- {
- icon_cache->wm_hints_dirty = FALSE;
-
- pixmap = wm_hints_pixmap;
- mask = wm_hints_mask;
-
- /* 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 (screen->display,
- pixmap, mask,
- iconp, ideal_width, ideal_height,
- mini_iconp, ideal_mini_width, ideal_mini_height))
- {
- 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 (screen->display, xwindow, &pixmap, &mask);
-
- if ((pixmap != icon_cache->prev_pixmap ||
- mask != icon_cache->prev_mask) &&
- pixmap != None)
- {
- if (try_pixmap_and_mask (screen->display, pixmap, mask,
- iconp, ideal_width, ideal_height,
- mini_iconp, ideal_mini_width, ideal_mini_height))
- {
- 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)
- {
- get_fallback_icons (screen,
- iconp,
- ideal_width,
- ideal_height,
- mini_iconp,
- ideal_mini_width,
- ideal_mini_height);
-
- 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;
-}