2002-02-09 23:03:52 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2002-10-27 03:03:32 +00:00
|
|
|
#include <config.h>
|
2002-02-09 23:03:52 +00:00
|
|
|
#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,
|
2004-04-19 14:53:14 +00:00
|
|
|
gulong nitems,
|
2002-02-09 23:03:52 +00:00
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
*width = 0;
|
|
|
|
*height = 0;
|
|
|
|
|
|
|
|
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 < ((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,
|
2004-04-19 14:53:14 +00:00
|
|
|
gulong nitems,
|
2002-02-09 23:03:52 +00:00
|
|
|
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 < ((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;
|
|
|
|
gulong *data;
|
|
|
|
gulong *best;
|
|
|
|
int w, h;
|
|
|
|
gulong *best_mini;
|
|
|
|
int mini_w, mini_h;
|
|
|
|
|
2002-10-21 21:44:35 +00:00
|
|
|
meta_error_trap_push_with_return (display);
|
2002-02-09 23:03:52 +00:00
|
|
|
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, ((guchar **)&data));
|
|
|
|
|
2002-10-21 21:44:35 +00:00
|
|
|
err = meta_error_trap_pop_with_return (display, TRUE);
|
2002-02-09 23:03:52 +00:00
|
|
|
|
|
|
|
if (err != Success ||
|
|
|
|
result != Success)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (type != XA_CARDINAL)
|
|
|
|
{
|
|
|
|
XFree (data);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!find_best_size (data, nitems,
|
|
|
|
ideal_width, ideal_height,
|
|
|
|
&w, &h, &best))
|
|
|
|
{
|
|
|
|
XFree (data);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!find_best_size (data, 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);
|
|
|
|
}
|
|
|
|
|
2002-10-21 21:44:35 +00:00
|
|
|
meta_error_trap_pop (display, FALSE);
|
2002-02-09 23:03:52 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
Pixmap *icons;
|
|
|
|
int err, result;
|
|
|
|
|
|
|
|
*pixmap = None;
|
|
|
|
*mask = None;
|
|
|
|
|
2002-10-21 21:44:35 +00:00
|
|
|
meta_error_trap_push_with_return (display);
|
2002-02-09 23:03:52 +00:00
|
|
|
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, (guchar **)&icons);
|
|
|
|
|
2002-10-21 21:44:35 +00:00
|
|
|
err = meta_error_trap_pop_with_return (display, TRUE);
|
2002-02-09 23:03:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2003-11-24 19:09:25 +00:00
|
|
|
icon_cache->prev_mask = None;
|
2002-02-09 23:03:52 +00:00
|
|
|
#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;
|
|
|
|
|
2002-04-21 20:17:44 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-09 23:03:52 +00:00
|
|
|
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;
|
|
|
|
}
|