source: trunk/third/gnome-core/applets/tasklist/tasklist_icon.c @ 17152

Revision 17152, 10.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17151, which included commits to RCS files with non-trunk default branches.
Line 
1#include <X11/Xlib.h>
2#include <X11/Xutil.h>
3#include <gdk-pixbuf/gdk-pixbuf.h>
4#include <gdk/gdkx.h>
5#include <gnome.h>
6#include <gwmh.h>
7#include "tasklist_applet.h"
8
9static gboolean tasklist_icon_check_mini (TasklistTask *task);
10static gboolean tasklist_icon_check_x (TasklistTask *task);
11static void tasklist_icon_set_minimized (TasklistTask *task);
12
13#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
14
15/* Shamelessly stolen from gwmh.c by Tim Janik */
16
17Pixmap
18tasklist_icon_get_pixmap (TasklistTask *task)
19{
20        XWMHints *wmhints;
21        Pixmap pixmap;
22
23        if (task == NULL)
24                return 0;
25       
26        gdk_error_trap_push ();
27        wmhints = XGetWMHints (GDK_DISPLAY (), task->gwmh_task->xwin);
28        gdk_flush ();
29        if (gdk_error_trap_pop ())
30                return 0;
31
32        if (!wmhints)
33                return 0;
34       
35        if (!(wmhints->flags & IconPixmapHint)) {
36                XFree (wmhints);
37                return 0;
38        }
39
40        pixmap = wmhints->icon_pixmap;
41
42        XFree (wmhints);
43
44        return pixmap;
45}
46
47static gpointer
48get_typed_property_data (Display *xdisplay,
49                         Window   xwindow,
50                         Atom     property,
51                         Atom     requested_type,
52                         gint    *size_p,
53                         guint    expected_format)
54{
55        static const guint prop_buffer_lengh = 1024 * 1024;
56        unsigned char *prop_data = NULL;
57        Atom type_returned = 0;
58        unsigned long nitems_return = 0, bytes_after_return = 0;
59        int format_returned = 0;
60        gpointer data = NULL;
61        gboolean abort = FALSE;
62       
63        g_return_val_if_fail (size_p != NULL, NULL);
64        *size_p = 0;
65       
66        gdk_error_trap_push ();
67       
68        abort = XGetWindowProperty (xdisplay,
69                                    xwindow,
70                                    property,
71                                    0, prop_buffer_lengh,
72                                    False,
73                                    requested_type,
74                                    &type_returned, &format_returned,
75                                    &nitems_return,
76                                    &bytes_after_return,
77                                    &prop_data) != Success;
78        if (gdk_error_trap_pop () ||
79            type_returned == None)
80                abort++;
81        if (!abort &&
82            requested_type != AnyPropertyType &&
83            requested_type != type_returned) {
84                g_warning (G_GNUC_PRETTY_FUNCTION "(): Property has wrong type, probably on crack");
85                abort++;
86        }
87        if (!abort && bytes_after_return) {
88                        g_warning (G_GNUC_PRETTY_FUNCTION "(): Eeek, property has more than %u bytes, stored on harddisk?",
89                                   prop_buffer_lengh);
90                        abort++;
91        }
92        if (!abort && expected_format && expected_format != format_returned) {
93                g_warning (G_GNUC_PRETTY_FUNCTION "(): Expected format (%u) unmatched (%d), programmer was drunk?",
94                           expected_format, format_returned);
95                abort++;
96        }
97        if (!abort && prop_data && nitems_return && format_returned) {
98                switch (format_returned) {
99                case 32:
100                        *size_p = nitems_return * 4;
101                        if (sizeof (gulong) == 8) {
102                                guint32 i, *mem = g_malloc0 (*size_p + 1);
103                                gulong *prop_longs = (gulong*) prop_data;
104                               
105                                for (i = 0; i < *size_p / 4; i++)
106                                        mem[i] = prop_longs[i];
107                                data = mem;
108                        }
109                        break;
110                case 16:
111                        *size_p = nitems_return * 2;
112                        break;
113                case 8:
114                        *size_p = nitems_return;
115                        break;
116                default:
117                        g_warning ("Unknown property data format with %d bits (extraterrestrial?)",
118                                   format_returned);
119                        break;
120                }
121                if (!data && *size_p) {
122                        guint8 *mem = g_malloc (*size_p + 1);
123                       
124                        memcpy (mem, prop_data, *size_p);
125                        mem[*size_p] = 0;
126                        data = mem;
127                }
128        }
129
130        if (prop_data)
131                XFree (prop_data);
132       
133        return data;
134}
135
136static gboolean
137tasklist_icon_check_mini (TasklistTask *task)
138{
139        GdkGC *gc;
140        int x, y;
141        guint b, width, height, depth;
142        guint32 *atomdata;
143        Window root;
144        GdkImage *image;
145        GdkPixmap *pixmap;
146        GdkBitmap *mask;
147        GdkPixbuf *pixbuf, *pixbuf2;
148        gint size;
149        static gulong KWM_WIN_ICON = 0;
150        Display *xdisplay;
151        guchar *data;
152       
153        if (!KWM_WIN_ICON) {
154                KWM_WIN_ICON = gdk_atom_intern ("KWM_WIN_ICON", FALSE);
155        }
156
157        xdisplay = GDK_WINDOW_XDISPLAY (task->gwmh_task->gdkwindow);
158       
159        atomdata = get_typed_property_data (xdisplay,
160                                            task->gwmh_task->xwin,
161                                            KWM_WIN_ICON,
162                                            KWM_WIN_ICON,
163                                            &size,
164                                            32);
165        if (!atomdata)
166                return FALSE;
167       
168        if (!atomdata[0]) {
169                g_free (atomdata);
170                return FALSE;
171        }
172
173        gdk_error_trap_push ();
174
175        /* Get icon size and depth */
176        XGetGeometry (xdisplay, (Drawable)atomdata[0], &root, &x, &y,
177                      &width, &height, &b, &depth);
178
179        /* Create a new GdkPixmap and copy the mini icon pixmap to it */
180        pixmap = gdk_pixmap_new (NULL, width, height, depth);
181        gc = gdk_gc_new (pixmap);
182        XCopyArea (GDK_WINDOW_XDISPLAY (pixmap), atomdata[0], GDK_WINDOW_XWINDOW (pixmap),
183                   GDK_GC_XGC (gc), 0, 0, width, height, 0, 0);
184        gdk_gc_destroy (gc);
185       
186        pixbuf = gdk_pixbuf_get_from_drawable (NULL,
187                                               pixmap,
188                                               gtk_widget_get_colormap (task->tasklist->area),
189                                               0, 0,
190                                               0, 0,
191                                               width, height);
192        gdk_pixmap_unref (pixmap);
193       
194        if (size > 1 && atomdata[1]) {
195                mask = gdk_pixmap_new (NULL, width, height, depth);
196                gc = gdk_gc_new (mask);
197                gdk_gc_set_background (gc, &task->tasklist->area->style->black);
198                gdk_gc_set_foreground (gc, &task->tasklist->area->style->white);
199                XCopyPlane (GDK_DISPLAY (), atomdata[1], GDK_WINDOW_XWINDOW (mask),
200                            GDK_GC_XGC (gc), 0, 0, width, height, 0, 0, 1);
201                gdk_gc_unref (gc);
202               
203                image = gdk_image_get (mask, 0, 0, width, height);
204                g_return_val_if_fail (image != NULL, FALSE);
205       
206                pixbuf2 = pixbuf;
207                pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
208                gdk_pixbuf_unref(pixbuf2);
209               
210                data = gdk_pixbuf_get_pixels (pixbuf);
211                for (y = 0; y < gdk_pixbuf_get_height (pixbuf); y++)
212                        for (x = 0; x < gdk_pixbuf_get_width (pixbuf); x++)
213                        {
214                                data += 3;
215                                *data++ = gdk_image_get_pixel (image, x, y) == 0 ? 0 : 255;
216                        }
217                gdk_pixmap_unref (mask);
218                gdk_image_destroy(image);       
219        }
220
221        gdk_flush ();
222        gdk_error_trap_pop ();
223
224        g_free (atomdata);
225       
226        task->icon->normal = pixbuf;
227       
228        return TRUE;
229}
230
231static gboolean
232tasklist_icon_check_x (TasklistTask *task)
233{
234        XWMHints * wmhints;
235        GdkPixmap *pixmap, *mask;
236        GdkPixbuf *pixbuf, *scaled;
237        GdkImage *image;
238        GdkGC *gc;
239        Window root;
240        int x, y;
241        unsigned int width, height;
242        unsigned int border_width;
243        unsigned int depth;
244        guchar *data;
245
246        gdk_error_trap_push ();
247       
248        wmhints = XGetWMHints (GDK_DISPLAY (), task->gwmh_task->xwin);
249
250        if (!wmhints) {
251                gdk_flush ();
252                gdk_error_trap_pop ();
253                return FALSE;
254        }
255       
256        if (!(wmhints->flags & IconPixmapHint)) {
257                XFree (wmhints);
258                gdk_flush ();
259                gdk_error_trap_pop ();
260                return FALSE;
261        }
262
263        XGetGeometry (GDK_DISPLAY (), wmhints->icon_pixmap, &root,
264                      &x, &y, &width, &height,
265                      &border_width, &depth);
266       
267        if (width > 65535 || height > 65535) {
268                XFree (wmhints);
269                gdk_flush ();
270                gdk_error_trap_pop ();
271                return FALSE;
272        }
273       
274        pixmap = gdk_pixmap_new (task->tasklist->area->window, width, height, -1);     
275        gc = gdk_gc_new (pixmap);
276
277        if (depth == 1) {
278                gdk_gc_set_background (gc, &task->tasklist->area->style->white);
279                gdk_gc_set_foreground (gc, &task->tasklist->area->style->black);
280                XCopyPlane (GDK_DISPLAY (), wmhints->icon_pixmap, GDK_WINDOW_XWINDOW (pixmap),
281                           GDK_GC_XGC (gc), 0, 0, width, height, 0, 0, 1);
282        }
283        else {
284                XCopyArea (GDK_DISPLAY (), wmhints->icon_pixmap, GDK_WINDOW_XWINDOW (pixmap),
285                           GDK_GC_XGC (gc), 0, 0, width, height, 0, 0);
286        }
287        pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, gtk_widget_get_colormap (task->tasklist->area),
288                                               0, 0,
289                                               0, 0, width, height);
290        gdk_gc_destroy (gc);
291
292        if (depth == 1) {
293                scaled = pixbuf;
294                pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
295                gdk_pixbuf_unref(scaled);
296        }
297       
298        if (wmhints->flags & IconMaskHint) {
299               mask = gdk_pixmap_new (NULL, width, height, depth);
300               gc = gdk_gc_new (mask);
301               gdk_gc_set_background (gc, &task->tasklist->area->style->black);
302               gdk_gc_set_foreground (gc, &task->tasklist->area->style->white);
303               XCopyPlane (GDK_DISPLAY (), wmhints->icon_mask, GDK_WINDOW_XWINDOW (mask),
304                           GDK_GC_XGC (gc), 0, 0, width, height, 0, 0, 1);
305               gdk_gc_unref (gc);
306
307               image = gdk_image_get (mask, 0, 0, width, height);
308               g_return_val_if_fail (image != NULL, FALSE);
309               
310               scaled = pixbuf;
311               pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
312               gdk_pixbuf_unref (scaled);
313
314               data = gdk_pixbuf_get_pixels (pixbuf);
315               for (y = 0; y < gdk_pixbuf_get_height (pixbuf); y++)
316                 for (x = 0; x < gdk_pixbuf_get_width (pixbuf); x++)
317                   {
318                     data += 3;
319                     *data++ = gdk_image_get_pixel (image, x, y) == 0 ? 0 : 255;
320                   }
321
322               gdk_pixmap_unref (mask);
323               gdk_image_destroy (image);
324        }
325
326        scaled = gdk_pixbuf_scale_simple (pixbuf,
327                                          20, 20,
328                                          GDK_INTERP_BILINEAR);
329        gdk_pixbuf_unref (pixbuf);
330        gdk_pixmap_unref (pixmap);
331       
332        task->icon->normal = scaled;
333
334        XFree (wmhints);
335
336        gdk_flush ();
337        gdk_error_trap_pop ();
338
339        return TRUE;
340
341}
342
343void
344tasklist_icon_set (TasklistTask *task)
345{
346        if (task == NULL)
347                return;
348       
349        task->icon = g_new0 (TasklistIcon, 1);
350
351        task->icon->normal    = task->tasklist->unknown_icon->normal;
352        task->icon->minimized = task->tasklist->unknown_icon->minimized;
353
354        if (!tasklist_icon_check_x (task))
355                tasklist_icon_check_mini (task);
356               
357
358        tasklist_icon_set_minimized (task);
359}
360
361static void
362tasklist_icon_set_minimized (TasklistTask *task)
363{
364        if (task->icon->minimized &&
365            task->icon->minimized != task->tasklist->unknown_icon->minimized)
366                gdk_pixbuf_unref (task->icon->minimized);
367
368        task->icon->minimized = tasklist_icon_create_minimized_icon (task->tasklist, task->icon->normal);
369}
370
371void
372tasklist_icon_destroy (TasklistTask *task)
373{
374        if (task == NULL)
375                return;
376       
377        if (task->icon->normal != task->tasklist->unknown_icon->normal) {
378                gdk_pixbuf_unref (task->icon->normal);
379                task->icon->normal = NULL;
380        }
381       
382        if (task->icon->minimized != task->tasklist->unknown_icon->minimized) {
383                gdk_pixbuf_unref (task->icon->minimized);
384                task->icon->minimized = NULL;
385        }
386
387        g_free (task->icon);
388        task->icon = NULL;
389}
390
391/* Stolen from gnome-pixmap.c */
392GdkPixbuf *
393tasklist_icon_create_minimized_icon (Tasklist *tasklist, GdkPixbuf *pixbuf)
394{
395        GdkPixbuf *target;
396        gint i, j;
397        gint width, height, has_alpha, rowstride;
398        guchar *target_pixels;
399        guchar *original_pixels;
400        guchar *dest_pixel, *src_pixel;
401        gint32 red, green, blue;
402        GdkColor color;
403       
404        color = tasklist->area->style->bg[GTK_STATE_NORMAL];
405        red = color.red / 255;
406        blue = color.blue / 255;
407        green = color.green / 255;
408       
409        has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
410        width = gdk_pixbuf_get_width (pixbuf);
411        height = gdk_pixbuf_get_height (pixbuf);
412        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
413
414        target = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
415                                 has_alpha,
416                                 gdk_pixbuf_get_bits_per_sample (pixbuf),
417                                 width, height);
418
419        target_pixels = gdk_pixbuf_get_pixels (target);
420        original_pixels = gdk_pixbuf_get_pixels (pixbuf);
421
422        for (i = 0; i < height; i++) {
423                for (j = 0; j < width; j++) {
424                                src_pixel = original_pixels + i*rowstride + j*(has_alpha?4:3);
425                                dest_pixel = target_pixels + i*rowstride + j*(has_alpha?4:3);
426
427                                dest_pixel[0] = ((src_pixel[0] - red) >> 1) + red;
428                                dest_pixel[1] = ((src_pixel[1] - green) >> 1) + green;
429                                dest_pixel[2] = ((src_pixel[2] - blue) >> 1) + blue;
430                               
431                                if (has_alpha)
432                                        dest_pixel[3] = src_pixel[3];
433
434                }
435        }
436       
437        return target;
438}
Note: See TracBrowser for help on using the repository browser.