2
/* vim: set sw=2 et: */
5
* Copyright (C) 2001 Havoc Pennington
6
* Copyright (C) 2005-2007 Vincent Untz
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Library General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Library General Public License for more details.
18
* You should have received a copy of the GNU Library General Public
19
* License along with this library; if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
29
#include <X11/Xatom.h>
37
typedef struct _WnckIconCache WnckIconCache;
40
_wnck_error_trap_push (void)
42
gdk_error_trap_push ();
46
_wnck_error_trap_pop (void)
48
XSync (gdk_display, False);
49
return gdk_error_trap_pop ();
53
latin1_to_utf8 (const char *latin1)
58
str = g_string_new (NULL);
63
g_string_append_unichar (str, (gunichar) *p);
67
return g_string_free (str, FALSE);
71
_wnck_get_wmclass (Window xwindow,
78
_wnck_error_trap_push ();
83
XGetClassHint (gdk_display, xwindow,
86
_wnck_error_trap_pop ();
99
*res_name = latin1_to_utf8 (ch.res_name);
107
*res_class = latin1_to_utf8 (ch.res_class);
109
XFree (ch.res_class);
115
_wnck_get_client_name (Window xwindow, char **client_name)
117
XTextProperty text_prop;
120
_wnck_error_trap_push ();
122
status = XGetWMClientMachine(gdk_display, xwindow, &text_prop);
124
_wnck_error_trap_pop ();
131
XFree (text_prop.value);
137
*client_name = latin1_to_utf8 (text_prop.value);
138
XFree (text_prop.value);
143
* WNCK_GET_ICON_AT_SIZE
145
static GHashTable *atom_hash = NULL;
146
static GHashTable *reverse_atom_hash = NULL;
149
_wnck_atom_get (const char *atom_name)
153
g_return_val_if_fail (atom_name != NULL, None);
157
atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
158
reverse_atom_hash = g_hash_table_new (NULL, NULL);
161
retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name));
164
retval = XInternAtom (gdk_display, atom_name, FALSE);
170
name_copy = g_strdup (atom_name);
172
g_hash_table_insert (atom_hash, name_copy, GUINT_TO_POINTER (retval));
173
g_hash_table_insert (reverse_atom_hash,
174
GUINT_TO_POINTER (retval), name_copy);
181
/* The icon-reading code is copied
182
* from metacity, please sync bugfixes
185
find_largest_sizes (gulong * data, gulong nitems, int *width, int *height)
198
return FALSE; /* no space for w, h */
203
if (nitems < ((w * h) + 2))
204
return FALSE; /* not enough data */
206
*width = MAX (w, *width);
207
*height = MAX (h, *height);
210
nitems -= (w * h) + 2;
217
find_best_size (gulong * data,
220
int ideal_height, int *width, int *height, gulong ** start)
225
int max_width, max_height;
231
if (!find_largest_sizes (data, nitems, &max_width, &max_height))
235
ideal_width = max_width;
236
if (ideal_height < 0)
237
ideal_height = max_height;
251
return FALSE; /* no space for w, h */
256
if (nitems < ((w * h) + 2))
257
break; /* not enough data */
259
if (best_start == NULL)
265
/* work with averages */
266
const int ideal_size = (ideal_width + ideal_height) / 2;
267
int best_size = (best_w + best_h) / 2;
268
int this_size = (w + h) / 2;
270
/* larger than desired is always better than smaller */
271
if (best_size < ideal_size && this_size >= ideal_size)
273
/* if we have too small, pick anything bigger */
274
else if (best_size < ideal_size && this_size > best_size)
276
/* if we have too large, pick anything smaller
277
* but still >= the ideal
279
else if (best_size > ideal_size &&
280
this_size >= ideal_size && this_size < best_size)
286
best_start = data + 2;
292
nitems -= (w * h) + 2;
307
argbdata_to_pixdata (gulong * argb_data, int len, guchar ** pixdata)
312
*pixdata = g_new (guchar, len * 4);
315
/* One could speed this up a lot. */
323
rgba = (argb << 8) | (argb >> 24);
327
*p = (rgba >> 16) & 0xff;
329
*p = (rgba >> 8) & 0xff;
339
read_rgb_icon (Window xwindow,
342
int ideal_mini_width,
343
int ideal_mini_height,
347
int *mini_width, int *mini_height, guchar ** mini_pixdata)
360
_wnck_error_trap_push ();
363
result = XGetWindowProperty (gdk_display,
365
_wnck_atom_get ("_NET_WM_ICON"),
367
False, XA_CARDINAL, &type, &format, &nitems,
368
&bytes_after, (void *) &data);
370
err = _wnck_error_trap_pop ();
372
if (err != Success || result != Success)
375
if (type != XA_CARDINAL)
381
if (!find_best_size (data, nitems,
382
ideal_width, ideal_height, &w, &h, &best))
388
if (!find_best_size (data, nitems,
389
ideal_mini_width, ideal_mini_height,
390
&mini_w, &mini_h, &best_mini))
399
*mini_width = mini_w;
400
*mini_height = mini_h;
402
argbdata_to_pixdata (best, w * h, pixdata);
403
argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
411
free_pixels (guchar * pixels, gpointer data)
417
get_pixmap_geometry (Pixmap pixmap, int *w, int *h, int *d)
420
int x_ignored, y_ignored;
422
guint border_width_ignored;
432
XGetGeometry (gdk_display,
433
pixmap, &root_ignored, &x_ignored, &y_ignored,
434
&width, &height, &border_width_ignored, &depth);
445
apply_mask (GdkPixbuf * pixbuf, GdkPixbuf * mask)
449
GdkPixbuf *with_alpha;
455
w = MIN (gdk_pixbuf_get_width (mask), gdk_pixbuf_get_width (pixbuf));
456
h = MIN (gdk_pixbuf_get_height (mask), gdk_pixbuf_get_height (pixbuf));
458
with_alpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
460
dest = gdk_pixbuf_get_pixels (with_alpha);
461
src = gdk_pixbuf_get_pixels (mask);
463
dest_stride = gdk_pixbuf_get_rowstride (with_alpha);
464
src_stride = gdk_pixbuf_get_rowstride (mask);
472
guchar *s = src + i * src_stride + j * 3;
473
guchar *d = dest + i * dest_stride + j * 4;
475
/* s[0] == s[1] == s[2], they are 255 if the bit was set, 0
479
d[3] = 0; /* transparent */
481
d[3] = 255; /* opaque */
492
get_cmap (GdkPixmap * pixmap)
496
cmap = gdk_drawable_get_colormap (pixmap);
498
g_object_ref (G_OBJECT (cmap));
502
if (gdk_drawable_get_depth (pixmap) == 1)
509
/* Try system cmap */
510
GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (pixmap));
511
cmap = gdk_screen_get_system_colormap (screen);
512
g_object_ref (G_OBJECT (cmap));
516
/* Be sure we aren't going to blow up due to visual mismatch */
518
(gdk_colormap_get_visual (cmap)->depth !=
519
gdk_drawable_get_depth (pixmap)))
526
_wnck_gdk_pixbuf_get_from_pixmap (GdkPixbuf * dest,
531
int dest_y, int width, int height)
533
GdkDrawable *drawable;
540
drawable = gdk_xid_table_lookup (xpixmap);
543
g_object_ref (G_OBJECT (drawable));
545
drawable = gdk_pixmap_foreign_new (xpixmap);
549
cmap = get_cmap (drawable);
551
/* GDK is supposed to do this but doesn't in GTK 2.0.2,
555
gdk_drawable_get_size (drawable, &width, NULL);
557
gdk_drawable_get_size (drawable, NULL, &height);
559
retval = gdk_pixbuf_get_from_drawable (dest,
563
dest_x, dest_y, width, height);
567
g_object_unref (G_OBJECT (cmap));
569
g_object_unref (G_OBJECT (drawable));
575
try_pixmap_and_mask (Pixmap src_pixmap,
580
GdkPixbuf ** mini_iconp,
581
int ideal_mini_width, int ideal_mini_height)
583
GdkPixbuf *unscaled = NULL;
584
GdkPixbuf *mask = NULL;
587
if (src_pixmap == None)
590
_wnck_error_trap_push ();
592
get_pixmap_geometry (src_pixmap, &w, &h, NULL);
594
unscaled = _wnck_gdk_pixbuf_get_from_pixmap (NULL,
595
src_pixmap, 0, 0, 0, 0, w, h);
597
if (unscaled && src_mask != None)
599
get_pixmap_geometry (src_mask, &w, &h, NULL);
600
mask = _wnck_gdk_pixbuf_get_from_pixmap (NULL,
601
src_mask, 0, 0, 0, 0, w, h);
604
_wnck_error_trap_pop ();
610
masked = apply_mask (unscaled, mask);
611
g_object_unref (G_OBJECT (unscaled));
614
g_object_unref (G_OBJECT (mask));
621
gdk_pixbuf_scale_simple (unscaled,
622
ideal_width > 0 ? ideal_width :
623
gdk_pixbuf_get_width (unscaled),
624
ideal_height > 0 ? ideal_height :
625
gdk_pixbuf_get_height (unscaled),
626
GDK_INTERP_BILINEAR);
628
gdk_pixbuf_scale_simple (unscaled,
629
ideal_mini_width > 0 ? ideal_mini_width :
630
gdk_pixbuf_get_width (unscaled),
631
ideal_mini_height > 0 ? ideal_mini_height :
632
gdk_pixbuf_get_height (unscaled),
633
GDK_INTERP_BILINEAR);
635
g_object_unref (G_OBJECT (unscaled));
643
get_kwm_win_icon (Window xwindow, Pixmap * pixmap, Pixmap * mask)
655
_wnck_error_trap_push ();
657
result = XGetWindowProperty (gdk_display, xwindow,
658
_wnck_atom_get ("KWM_WIN_ICON"),
661
_wnck_atom_get ("KWM_WIN_ICON"),
662
&type, &format, &nitems,
663
&bytes_after, (void *) &icons);
665
err = _wnck_error_trap_pop ();
666
if (err != Success || result != Success)
669
if (type != _wnck_atom_get ("KWM_WIN_ICON"))
685
/* These MUST be in ascending order of preference;
686
* i.e. if we get _NET_WM_ICON and already have
687
* WM_HINTS, we prefer _NET_WM_ICON
696
struct _WnckIconCache
702
GdkPixbuf *mini_icon;
705
int ideal_mini_width;
706
int ideal_mini_height;
707
guint want_fallback:1;
708
/* TRUE if these props have changed */
709
guint wm_hints_dirty:1;
710
guint kwm_win_icon_dirty:1;
711
guint net_wm_icon_dirty:1;
716
scaled_from_pixdata (guchar * pixdata, int w, int h, int new_w, int new_h)
721
src = gdk_pixbuf_new_from_data (pixdata,
723
TRUE, 8, w, h, w * 4, free_pixels, NULL);
735
tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
739
gdk_pixbuf_fill (tmp, 0);
740
gdk_pixbuf_copy_area (src, 0, 0, w, h,
741
tmp, (size - w) / 2, (size - h) / 2);
744
g_object_unref (src);
749
if (w != new_w || h != new_h)
751
dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
753
g_object_unref (G_OBJECT (src));
764
_wnck_read_icons_ (Window xwindow,
765
GtkWidget * icon_cache,
769
GdkPixbuf ** mini_iconp,
770
int ideal_mini_width, int ideal_mini_height)
774
guchar *mini_pixdata;
783
if (read_rgb_icon (xwindow,
784
ideal_width, ideal_height,
785
ideal_mini_width, ideal_mini_height,
786
&w, &h, &pixdata, &mini_w, &mini_h, &mini_pixdata))
788
*iconp = scaled_from_pixdata (pixdata, w, h, ideal_width, ideal_height);
790
*mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
791
ideal_mini_width, ideal_mini_height);
797
_wnck_error_trap_push ();
798
hints = XGetWMHints (gdk_display, xwindow);
799
_wnck_error_trap_pop ();
804
if (hints->flags & IconPixmapHint)
805
pixmap = hints->icon_pixmap;
806
if (hints->flags & IconMaskHint)
807
mask = hints->icon_mask;
814
if (try_pixmap_and_mask (pixmap, mask,
815
iconp, ideal_width, ideal_height,
816
mini_iconp, ideal_mini_width, ideal_mini_height))
821
get_kwm_win_icon (xwindow, &pixmap, &mask);
823
if (try_pixmap_and_mask (pixmap, mask,
824
iconp, ideal_width, ideal_height,
825
mini_iconp, ideal_mini_width, ideal_mini_height))
834
_wnck_get_icon_at_size (WnckWindow *window,
838
GdkPixbuf *icon, *icon_scaled, *mini_icon;
845
res = _wnck_read_icons_ (wnck_window_get_xid (window),
853
g_object_unref (mini_icon);
859
icon = wnck_window_get_icon (window);
860
icon_scaled = gdk_pixbuf_scale_simple (icon, width, height,
861
GDK_INTERP_BILINEAR);
867
* XUTILS_GET_NAMED_ICON
869
* Probably shouldn't be in here, but I'm not feeling like creating another
870
* source header and file for one function. Sue me. Well don't actually.
874
strip_extension (const char *file)
878
stripped = g_strdup (file);
880
p = strrchr (stripped, '.');
882
(!strcmp (p, ".png") ||
883
!strcmp (p, ".svg") ||
884
!strcmp (p, ".xpm")))
890
/* Gets the pixbuf from a desktop file's icon name. Based on the same function
891
* from matchbox-desktop
894
get_icon (const gchar *name, guint size)
896
static GtkIconTheme *theme = NULL;
897
GdkPixbuf *pixbuf = NULL;
898
GError *error = NULL;
899
gchar *stripped = NULL;
904
theme = gtk_icon_theme_get_default ();
908
pixbuf = gtk_icon_theme_load_icon (theme, "application-x-executable",
913
if (g_path_is_absolute (name))
915
if (g_file_test (name, G_FILE_TEST_EXISTS))
917
pixbuf = gdk_pixbuf_new_from_file_at_scale (name, size, size,
921
/*g_warning ("Error loading icon: %s\n", error->message);*/
922
g_error_free (error);
929
stripped = strip_extension (name);
931
pixbuf = gtk_icon_theme_load_icon (theme,
934
GTK_ICON_LOOKUP_FORCE_SVG, &error);
937
/*g_warning ("Error loading icon: %s\n", error->message);*/
938
g_error_free (error);
942
/* Always try and send back something */
944
pixbuf = gtk_icon_theme_load_icon (theme, "stock_folder",
947
width = gdk_pixbuf_get_width (pixbuf);
948
height = gdk_pixbuf_get_height (pixbuf);
950
if (width != size || height != size)
952
GdkPixbuf *temp = pixbuf;
953
pixbuf = gdk_pixbuf_scale_simple (temp,
957
g_object_unref (temp);
966
xutils_get_named_icon (const gchar *icon_name,
970
return get_icon (icon_name, width);