~ubuntu-branches/ubuntu/vivid/marco/vivid

« back to all changes in this revision

Viewing changes to src/core/iconcache.c

  • Committer: Package Import Robot
  • Author(s): Mike Gabriel
  • Date: 2014-01-21 19:52:39 UTC
  • Revision ID: package-import@ubuntu.com-20140121195239-c4k1v8umdw1u4n29
Tags: upstream-1.6.2
ImportĀ upstreamĀ versionĀ 1.6.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/* Marco window icons */
 
4
 
 
5
/*
 
6
 * Copyright (C) 2002 Havoc Pennington
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2 of the
 
11
 * License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
21
 * 02110-1301, USA.
 
22
 */
 
23
 
 
24
#include <config.h>
 
25
#include "iconcache.h"
 
26
#include "ui.h"
 
27
#include "errors.h"
 
28
 
 
29
#include <X11/Xatom.h>
 
30
 
 
31
/* The icon-reading code is also in libwnck, please sync bugfixes */
 
32
 
 
33
static void
 
34
get_fallback_icons (MetaScreen     *screen,
 
35
                    GdkPixbuf     **iconp,
 
36
                    int             ideal_width,
 
37
                    int             ideal_height,
 
38
                    GdkPixbuf     **mini_iconp,
 
39
                    int             ideal_mini_width,
 
40
                    int             ideal_mini_height)
 
41
{
 
42
  /* we don't scale, should be fixed if we ever un-hardcode the icon
 
43
   * size
 
44
   */
 
45
  *iconp = meta_ui_get_default_window_icon (screen->ui);
 
46
  *mini_iconp = meta_ui_get_default_mini_icon (screen->ui);
 
47
}
 
48
 
 
49
static gboolean
 
50
find_largest_sizes (gulong *data,
 
51
                    gulong  nitems,
 
52
                    int    *width,
 
53
                    int    *height)
 
54
{
 
55
  *width = 0;
 
56
  *height = 0;
 
57
 
 
58
  while (nitems > 0)
 
59
    {
 
60
      int w, h;
 
61
 
 
62
      if (nitems < 3)
 
63
        return FALSE; /* no space for w, h */
 
64
 
 
65
      w = data[0];
 
66
      h = data[1];
 
67
 
 
68
      if (nitems < ((gulong)(w * h) + 2))
 
69
        return FALSE; /* not enough data */
 
70
 
 
71
      *width = MAX (w, *width);
 
72
      *height = MAX (h, *height);
 
73
 
 
74
      data += (w * h) + 2;
 
75
      nitems -= (w * h) + 2;
 
76
    }
 
77
 
 
78
  return TRUE;
 
79
}
 
80
 
 
81
static gboolean
 
82
find_best_size (gulong  *data,
 
83
                gulong   nitems,
 
84
                int      ideal_width,
 
85
                int      ideal_height,
 
86
                int     *width,
 
87
                int     *height,
 
88
                gulong **start)
 
89
{
 
90
  int best_w;
 
91
  int best_h;
 
92
  gulong *best_start;
 
93
  int max_width, max_height;
 
94
 
 
95
  *width = 0;
 
96
  *height = 0;
 
97
  *start = NULL;
 
98
 
 
99
  if (!find_largest_sizes (data, nitems, &max_width, &max_height))
 
100
    return FALSE;
 
101
 
 
102
  if (ideal_width < 0)
 
103
    ideal_width = max_width;
 
104
  if (ideal_height < 0)
 
105
    ideal_height = max_height;
 
106
 
 
107
  best_w = 0;
 
108
  best_h = 0;
 
109
  best_start = NULL;
 
110
 
 
111
  while (nitems > 0)
 
112
    {
 
113
      int w, h;
 
114
      gboolean replace;
 
115
 
 
116
      replace = FALSE;
 
117
 
 
118
      if (nitems < 3)
 
119
        return FALSE; /* no space for w, h */
 
120
 
 
121
      w = data[0];
 
122
      h = data[1];
 
123
 
 
124
      if (nitems < ((gulong)(w * h) + 2))
 
125
        break; /* not enough data */
 
126
 
 
127
      if (best_start == NULL)
 
128
        {
 
129
          replace = TRUE;
 
130
        }
 
131
      else
 
132
        {
 
133
          /* work with averages */
 
134
          const int ideal_size = (ideal_width + ideal_height) / 2;
 
135
          int best_size = (best_w + best_h) / 2;
 
136
          int this_size = (w + h) / 2;
 
137
 
 
138
          /* larger than desired is always better than smaller */
 
139
          if (best_size < ideal_size &&
 
140
              this_size >= ideal_size)
 
141
            replace = TRUE;
 
142
          /* if we have too small, pick anything bigger */
 
143
          else if (best_size < ideal_size &&
 
144
                   this_size > best_size)
 
145
            replace = TRUE;
 
146
          /* if we have too large, pick anything smaller
 
147
           * but still >= the ideal
 
148
           */
 
149
          else if (best_size > ideal_size &&
 
150
                   this_size >= ideal_size &&
 
151
                   this_size < best_size)
 
152
            replace = TRUE;
 
153
        }
 
154
 
 
155
      if (replace)
 
156
        {
 
157
          best_start = data + 2;
 
158
          best_w = w;
 
159
          best_h = h;
 
160
        }
 
161
 
 
162
      data += (w * h) + 2;
 
163
      nitems -= (w * h) + 2;
 
164
    }
 
165
 
 
166
  if (best_start)
 
167
    {
 
168
      *start = best_start;
 
169
      *width = best_w;
 
170
      *height = best_h;
 
171
      return TRUE;
 
172
    }
 
173
  else
 
174
    return FALSE;
 
175
}
 
176
 
 
177
static void
 
178
argbdata_to_pixdata (gulong *argb_data, int len, guchar **pixdata)
 
179
{
 
180
  guchar *p;
 
181
  int i;
 
182
 
 
183
  *pixdata = g_new (guchar, len * 4);
 
184
  p = *pixdata;
 
185
 
 
186
  /* One could speed this up a lot. */
 
187
  i = 0;
 
188
  while (i < len)
 
189
    {
 
190
      guint argb;
 
191
      guint rgba;
 
192
 
 
193
      argb = argb_data[i];
 
194
      rgba = (argb << 8) | (argb >> 24);
 
195
 
 
196
      *p = rgba >> 24;
 
197
      ++p;
 
198
      *p = (rgba >> 16) & 0xff;
 
199
      ++p;
 
200
      *p = (rgba >> 8) & 0xff;
 
201
      ++p;
 
202
      *p = rgba & 0xff;
 
203
      ++p;
 
204
 
 
205
      ++i;
 
206
    }
 
207
}
 
208
 
 
209
static gboolean
 
210
read_rgb_icon (MetaDisplay   *display,
 
211
               Window         xwindow,
 
212
               int            ideal_width,
 
213
               int            ideal_height,
 
214
               int            ideal_mini_width,
 
215
               int            ideal_mini_height,
 
216
               int           *width,
 
217
               int           *height,
 
218
               guchar       **pixdata,
 
219
               int           *mini_width,
 
220
               int           *mini_height,
 
221
               guchar       **mini_pixdata)
 
222
{
 
223
  Atom type;
 
224
  int format;
 
225
  gulong nitems;
 
226
  gulong bytes_after;
 
227
  int result, err;
 
228
  guchar *data;
 
229
  gulong *best;
 
230
  int w, h;
 
231
  gulong *best_mini;
 
232
  int mini_w, mini_h;
 
233
  gulong *data_as_long;
 
234
 
 
235
  meta_error_trap_push_with_return (display);
 
236
  type = None;
 
237
  data = NULL;
 
238
  result = XGetWindowProperty (display->xdisplay,
 
239
                               xwindow,
 
240
                               display->atom__NET_WM_ICON,
 
241
                               0, G_MAXLONG,
 
242
                               False, XA_CARDINAL, &type, &format, &nitems,
 
243
                               &bytes_after, &data);
 
244
  err = meta_error_trap_pop_with_return (display, TRUE);
 
245
 
 
246
  if (err != Success ||
 
247
      result != Success)
 
248
    return FALSE;
 
249
 
 
250
  if (type != XA_CARDINAL)
 
251
    {
 
252
      XFree (data);
 
253
      return FALSE;
 
254
    }
 
255
 
 
256
  data_as_long = (gulong *)data;
 
257
 
 
258
  if (!find_best_size (data_as_long, nitems,
 
259
                       ideal_width, ideal_height,
 
260
                       &w, &h, &best))
 
261
    {
 
262
      XFree (data);
 
263
      return FALSE;
 
264
    }
 
265
 
 
266
  if (!find_best_size (data_as_long, nitems,
 
267
                       ideal_mini_width, ideal_mini_height,
 
268
                       &mini_w, &mini_h, &best_mini))
 
269
    {
 
270
      XFree (data);
 
271
      return FALSE;
 
272
    }
 
273
 
 
274
  *width = w;
 
275
  *height = h;
 
276
 
 
277
  *mini_width = mini_w;
 
278
  *mini_height = mini_h;
 
279
 
 
280
  argbdata_to_pixdata (best, w * h, pixdata);
 
281
  argbdata_to_pixdata (best_mini, mini_w * mini_h, mini_pixdata);
 
282
 
 
283
  XFree (data);
 
284
 
 
285
  return TRUE;
 
286
}
 
287
 
 
288
static void
 
289
free_pixels (guchar *pixels, gpointer data)
 
290
{
 
291
  g_free (pixels);
 
292
}
 
293
 
 
294
static void
 
295
get_pixmap_geometry (MetaDisplay *display,
 
296
                     Pixmap       pixmap,
 
297
                     int         *w,
 
298
                     int         *h,
 
299
                     int         *d)
 
300
{
 
301
  Window root_ignored;
 
302
  int x_ignored, y_ignored;
 
303
  guint width, height;
 
304
  guint border_width_ignored;
 
305
  guint depth;
 
306
 
 
307
  if (w)
 
308
    *w = 1;
 
309
  if (h)
 
310
    *h = 1;
 
311
  if (d)
 
312
    *d = 1;
 
313
 
 
314
  XGetGeometry (display->xdisplay,
 
315
                pixmap, &root_ignored, &x_ignored, &y_ignored,
 
316
                &width, &height, &border_width_ignored, &depth);
 
317
 
 
318
  if (w)
 
319
    *w = width;
 
320
  if (h)
 
321
    *h = height;
 
322
  if (d)
 
323
    *d = depth;
 
324
}
 
325
 
 
326
static GdkPixbuf*
 
327
apply_mask (GdkPixbuf *pixbuf,
 
328
            GdkPixbuf *mask)
 
329
{
 
330
  int w, h;
 
331
  int i, j;
 
332
  GdkPixbuf *with_alpha;
 
333
  guchar *src;
 
334
  guchar *dest;
 
335
  int src_stride;
 
336
  int dest_stride;
 
337
 
 
338
  w = MIN (gdk_pixbuf_get_width (mask), gdk_pixbuf_get_width (pixbuf));
 
339
  h = MIN (gdk_pixbuf_get_height (mask), gdk_pixbuf_get_height (pixbuf));
 
340
 
 
341
  with_alpha = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
 
342
 
 
343
  dest = gdk_pixbuf_get_pixels (with_alpha);
 
344
  src = gdk_pixbuf_get_pixels (mask);
 
345
 
 
346
  dest_stride = gdk_pixbuf_get_rowstride (with_alpha);
 
347
  src_stride = gdk_pixbuf_get_rowstride (mask);
 
348
 
 
349
  i = 0;
 
350
  while (i < h)
 
351
    {
 
352
      j = 0;
 
353
      while (j < w)
 
354
        {
 
355
          guchar *s = src + i * src_stride + j * 3;
 
356
          guchar *d = dest + i * dest_stride + j * 4;
 
357
 
 
358
          /* s[0] == s[1] == s[2], they are 255 if the bit was set, 0
 
359
           * otherwise
 
360
           */
 
361
          if (s[0] == 0)
 
362
            d[3] = 0;   /* transparent */
 
363
          else
 
364
            d[3] = 255; /* opaque */
 
365
 
 
366
          ++j;
 
367
        }
 
368
 
 
369
      ++i;
 
370
    }
 
371
 
 
372
  return with_alpha;
 
373
}
 
374
 
 
375
static gboolean
 
376
try_pixmap_and_mask (MetaDisplay *display,
 
377
                     Pixmap       src_pixmap,
 
378
                     Pixmap       src_mask,
 
379
                     GdkPixbuf  **iconp,
 
380
                     int          ideal_width,
 
381
                     int          ideal_height,
 
382
                     GdkPixbuf  **mini_iconp,
 
383
                     int          ideal_mini_width,
 
384
                     int          ideal_mini_height)
 
385
{
 
386
  GdkPixbuf *unscaled = NULL;
 
387
  GdkPixbuf *mask = NULL;
 
388
  int w, h;
 
389
 
 
390
  if (src_pixmap == None)
 
391
    return FALSE;
 
392
 
 
393
  meta_error_trap_push (display);
 
394
 
 
395
  get_pixmap_geometry (display, src_pixmap, &w, &h, NULL);
 
396
 
 
397
  unscaled = meta_gdk_pixbuf_get_from_pixmap (NULL,
 
398
                                              src_pixmap,
 
399
                                              0, 0, 0, 0,
 
400
                                              w, h);
 
401
 
 
402
  if (unscaled && src_mask != None)
 
403
    {
 
404
      get_pixmap_geometry (display, src_mask, &w, &h, NULL);
 
405
      mask = meta_gdk_pixbuf_get_from_pixmap (NULL,
 
406
                                              src_mask,
 
407
                                              0, 0, 0, 0,
 
408
                                              w, h);
 
409
    }
 
410
 
 
411
  meta_error_trap_pop (display, FALSE);
 
412
 
 
413
  if (mask)
 
414
    {
 
415
      GdkPixbuf *masked;
 
416
 
 
417
      masked = apply_mask (unscaled, mask);
 
418
      g_object_unref (G_OBJECT (unscaled));
 
419
      unscaled = masked;
 
420
 
 
421
      g_object_unref (G_OBJECT (mask));
 
422
      mask = NULL;
 
423
    }
 
424
 
 
425
  if (unscaled)
 
426
    {
 
427
      *iconp =
 
428
        gdk_pixbuf_scale_simple (unscaled,
 
429
                                 ideal_width > 0 ? ideal_width :
 
430
                                 gdk_pixbuf_get_width (unscaled),
 
431
                                 ideal_height > 0 ? ideal_height :
 
432
                                 gdk_pixbuf_get_height (unscaled),
 
433
                                 GDK_INTERP_BILINEAR);
 
434
      *mini_iconp =
 
435
        gdk_pixbuf_scale_simple (unscaled,
 
436
                                 ideal_mini_width > 0 ? ideal_mini_width :
 
437
                                 gdk_pixbuf_get_width (unscaled),
 
438
                                 ideal_mini_height > 0 ? ideal_mini_height :
 
439
                                 gdk_pixbuf_get_height (unscaled),
 
440
                                 GDK_INTERP_BILINEAR);
 
441
 
 
442
      g_object_unref (G_OBJECT (unscaled));
 
443
      
 
444
      if (*iconp && *mini_iconp)
 
445
        return TRUE;
 
446
      else
 
447
        {
 
448
          if (*iconp)
 
449
            g_object_unref (G_OBJECT (*iconp));
 
450
          if (*mini_iconp)
 
451
            g_object_unref (G_OBJECT (*mini_iconp));
 
452
          return FALSE;
 
453
        }
 
454
    }
 
455
  else
 
456
    return FALSE;
 
457
}
 
458
 
 
459
static void
 
460
get_kwm_win_icon (MetaDisplay *display,
 
461
                  Window       xwindow,
 
462
                  Pixmap      *pixmap,
 
463
                  Pixmap      *mask)
 
464
{
 
465
  Atom type;
 
466
  int format;
 
467
  gulong nitems;
 
468
  gulong bytes_after;
 
469
  guchar *data;
 
470
  Pixmap *icons;
 
471
  int err, result;
 
472
 
 
473
  *pixmap = None;
 
474
  *mask = None;
 
475
 
 
476
  meta_error_trap_push_with_return (display);
 
477
  icons = NULL;
 
478
  result = XGetWindowProperty (display->xdisplay, xwindow,
 
479
                               display->atom__KWM_WIN_ICON,
 
480
                               0, G_MAXLONG,
 
481
                               False,
 
482
                               display->atom__KWM_WIN_ICON,
 
483
                               &type, &format, &nitems,
 
484
                               &bytes_after, &data);
 
485
  icons = (Pixmap *)data;
 
486
 
 
487
  err = meta_error_trap_pop_with_return (display, TRUE);
 
488
  if (err != Success ||
 
489
      result != Success)
 
490
    return;
 
491
 
 
492
  if (type != display->atom__KWM_WIN_ICON)
 
493
    {
 
494
      XFree (icons);
 
495
      return;
 
496
    }
 
497
 
 
498
  *pixmap = icons[0];
 
499
  *mask = icons[1];
 
500
 
 
501
  XFree (icons);
 
502
 
 
503
  return;
 
504
}
 
505
 
 
506
void
 
507
meta_icon_cache_init (MetaIconCache *icon_cache)
 
508
{
 
509
  g_return_if_fail (icon_cache != NULL);
 
510
 
 
511
  icon_cache->origin = USING_NO_ICON;
 
512
  icon_cache->prev_pixmap = None;
 
513
  icon_cache->prev_mask = None;
 
514
#if 0
 
515
  icon_cache->icon = NULL;
 
516
  icon_cache->mini_icon = NULL;
 
517
  icon_cache->ideal_width = -1; /* won't be a legit width */
 
518
  icon_cache->ideal_height = -1;
 
519
  icon_cache->ideal_mini_width = -1;
 
520
  icon_cache->ideal_mini_height = -1;
 
521
#endif
 
522
  icon_cache->want_fallback = TRUE;
 
523
  icon_cache->wm_hints_dirty = TRUE;
 
524
  icon_cache->kwm_win_icon_dirty = TRUE;
 
525
  icon_cache->net_wm_icon_dirty = TRUE;
 
526
}
 
527
 
 
528
static void
 
529
clear_icon_cache (MetaIconCache *icon_cache,
 
530
                  gboolean       dirty_all)
 
531
{
 
532
#if 0
 
533
  if (icon_cache->icon)
 
534
    g_object_unref (G_OBJECT (icon_cache->icon));
 
535
  icon_cache->icon = NULL;
 
536
 
 
537
  if (icon_cache->mini_icon)
 
538
    g_object_unref (G_OBJECT (icon_cache->mini_icon));
 
539
  icon_cache->mini_icon = NULL;
 
540
#endif
 
541
  
 
542
  icon_cache->origin = USING_NO_ICON;
 
543
 
 
544
  if (dirty_all)
 
545
    {
 
546
      icon_cache->wm_hints_dirty = TRUE;
 
547
      icon_cache->kwm_win_icon_dirty = TRUE;
 
548
      icon_cache->net_wm_icon_dirty = TRUE;
 
549
    }
 
550
}
 
551
 
 
552
void
 
553
meta_icon_cache_free (MetaIconCache *icon_cache)
 
554
{
 
555
  clear_icon_cache (icon_cache, FALSE);
 
556
}
 
557
 
 
558
void
 
559
meta_icon_cache_property_changed (MetaIconCache *icon_cache,
 
560
                                  MetaDisplay   *display,
 
561
                                  Atom           atom)
 
562
{
 
563
  if (atom == display->atom__NET_WM_ICON)
 
564
    icon_cache->net_wm_icon_dirty = TRUE;
 
565
  else if (atom == display->atom__KWM_WIN_ICON)
 
566
    icon_cache->kwm_win_icon_dirty = TRUE;
 
567
  else if (atom == XA_WM_HINTS)
 
568
    icon_cache->wm_hints_dirty = TRUE;
 
569
}
 
570
 
 
571
gboolean
 
572
meta_icon_cache_get_icon_invalidated (MetaIconCache *icon_cache)
 
573
{
 
574
  if (icon_cache->origin <= USING_KWM_WIN_ICON &&
 
575
      icon_cache->kwm_win_icon_dirty)
 
576
    return TRUE;
 
577
  else if (icon_cache->origin <= USING_WM_HINTS &&
 
578
           icon_cache->wm_hints_dirty)
 
579
    return TRUE;
 
580
  else if (icon_cache->origin <= USING_NET_WM_ICON &&
 
581
           icon_cache->net_wm_icon_dirty)
 
582
    return TRUE;
 
583
  else if (icon_cache->origin < USING_FALLBACK_ICON &&
 
584
           icon_cache->want_fallback)
 
585
    return TRUE;
 
586
  else if (icon_cache->origin == USING_NO_ICON)
 
587
    return TRUE;
 
588
  else if (icon_cache->origin == USING_FALLBACK_ICON &&
 
589
           !icon_cache->want_fallback)
 
590
    return TRUE;
 
591
  else
 
592
    return FALSE;
 
593
}
 
594
 
 
595
static void
 
596
replace_cache (MetaIconCache *icon_cache,
 
597
               IconOrigin     origin,
 
598
               GdkPixbuf     *new_icon,
 
599
               GdkPixbuf     *new_mini_icon)
 
600
{
 
601
  clear_icon_cache (icon_cache, FALSE);
 
602
 
 
603
  icon_cache->origin = origin;
 
604
 
 
605
#if 0
 
606
  if (new_icon)
 
607
    g_object_ref (G_OBJECT (new_icon));
 
608
 
 
609
  icon_cache->icon = new_icon;
 
610
 
 
611
  if (new_mini_icon)
 
612
    g_object_ref (G_OBJECT (new_mini_icon));
 
613
 
 
614
  icon_cache->mini_icon = new_mini_icon;
 
615
#endif
 
616
}
 
617
 
 
618
static GdkPixbuf*
 
619
scaled_from_pixdata (guchar *pixdata,
 
620
                     int     w,
 
621
                     int     h,
 
622
                     int     new_w,
 
623
                     int     new_h)
 
624
{
 
625
  GdkPixbuf *src;
 
626
  GdkPixbuf *dest;
 
627
  
 
628
  src = gdk_pixbuf_new_from_data (pixdata,
 
629
                                  GDK_COLORSPACE_RGB,
 
630
                                  TRUE,
 
631
                                  8,
 
632
                                  w, h, w * 4,
 
633
                                  free_pixels, 
 
634
                                  NULL);
 
635
 
 
636
  if (src == NULL)
 
637
    return NULL;
 
638
 
 
639
  if (w != h)
 
640
    {
 
641
      GdkPixbuf *tmp;
 
642
      int size;
 
643
 
 
644
      size = MAX (w, h);
 
645
      
 
646
      tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size, size);
 
647
 
 
648
      if (tmp)
 
649
        {
 
650
          gdk_pixbuf_fill (tmp, 0);
 
651
          gdk_pixbuf_copy_area (src, 0, 0, w, h,
 
652
                                tmp,
 
653
                                (size - w) / 2, (size - h) / 2);
 
654
          
 
655
          g_object_unref (src);
 
656
          src = tmp;
 
657
        }
 
658
    }
 
659
  
 
660
  if (w != new_w || h != new_h)
 
661
    {
 
662
      dest = gdk_pixbuf_scale_simple (src, new_w, new_h, GDK_INTERP_BILINEAR);
 
663
      
 
664
      g_object_unref (G_OBJECT (src));
 
665
    }
 
666
  else
 
667
    {
 
668
      dest = src;
 
669
    }
 
670
 
 
671
  return dest;
 
672
}
 
673
 
 
674
gboolean
 
675
meta_read_icons (MetaScreen     *screen,
 
676
                 Window          xwindow,
 
677
                 MetaIconCache  *icon_cache,
 
678
                 Pixmap          wm_hints_pixmap,
 
679
                 Pixmap          wm_hints_mask,
 
680
                 GdkPixbuf     **iconp,
 
681
                 int             ideal_width,
 
682
                 int             ideal_height,
 
683
                 GdkPixbuf     **mini_iconp,
 
684
                 int             ideal_mini_width,
 
685
                 int             ideal_mini_height)
 
686
{
 
687
  guchar *pixdata;
 
688
  int w, h;
 
689
  guchar *mini_pixdata;
 
690
  int mini_w, mini_h;
 
691
  Pixmap pixmap;
 
692
  Pixmap mask;
 
693
 
 
694
  /* Return value is whether the icon changed */
 
695
 
 
696
  g_return_val_if_fail (icon_cache != NULL, FALSE);
 
697
 
 
698
  *iconp = NULL;
 
699
  *mini_iconp = NULL;
 
700
 
 
701
#if 0
 
702
  if (ideal_width != icon_cache->ideal_width ||
 
703
      ideal_height != icon_cache->ideal_height ||
 
704
      ideal_mini_width != icon_cache->ideal_mini_width ||
 
705
      ideal_mini_height != icon_cache->ideal_mini_height)
 
706
    clear_icon_cache (icon_cache, TRUE);
 
707
 
 
708
  icon_cache->ideal_width = ideal_width;
 
709
  icon_cache->ideal_height = ideal_height;
 
710
  icon_cache->ideal_mini_width = ideal_mini_width;
 
711
  icon_cache->ideal_mini_height = ideal_mini_height;
 
712
#endif
 
713
  
 
714
  if (!meta_icon_cache_get_icon_invalidated (icon_cache))
 
715
    return FALSE; /* we have no new info to use */
 
716
 
 
717
  pixdata = NULL;
 
718
 
 
719
  /* Our algorithm here assumes that we can't have for example origin
 
720
   * < USING_NET_WM_ICON and icon_cache->net_wm_icon_dirty == FALSE
 
721
   * unless we have tried to read NET_WM_ICON.
 
722
   *
 
723
   * Put another way, if an icon origin is not dirty, then we have
 
724
   * tried to read it at the current size. If it is dirty, then
 
725
   * we haven't done that since the last change.
 
726
   */
 
727
 
 
728
  if (icon_cache->origin <= USING_NET_WM_ICON &&
 
729
      icon_cache->net_wm_icon_dirty)
 
730
 
 
731
    {
 
732
      icon_cache->net_wm_icon_dirty = FALSE;
 
733
 
 
734
      if (read_rgb_icon (screen->display, xwindow,
 
735
                         ideal_width, ideal_height,
 
736
                         ideal_mini_width, ideal_mini_height,
 
737
                         &w, &h, &pixdata,
 
738
                         &mini_w, &mini_h, &mini_pixdata))
 
739
        {
 
740
          *iconp = scaled_from_pixdata (pixdata, w, h,
 
741
                                        ideal_width, ideal_height);
 
742
 
 
743
          *mini_iconp = scaled_from_pixdata (mini_pixdata, mini_w, mini_h,
 
744
                                             ideal_mini_width, ideal_mini_height);
 
745
 
 
746
          if (*iconp && *mini_iconp)
 
747
            {
 
748
              replace_cache (icon_cache, USING_NET_WM_ICON,
 
749
                             *iconp, *mini_iconp);
 
750
              
 
751
              return TRUE;
 
752
            }
 
753
          else
 
754
            {
 
755
              if (*iconp)
 
756
                g_object_unref (G_OBJECT (*iconp));
 
757
              if (*mini_iconp)
 
758
                g_object_unref (G_OBJECT (*mini_iconp));
 
759
            }
 
760
        }
 
761
    }
 
762
 
 
763
  if (icon_cache->origin <= USING_WM_HINTS &&
 
764
      icon_cache->wm_hints_dirty)
 
765
    {
 
766
      icon_cache->wm_hints_dirty = FALSE;
 
767
 
 
768
      pixmap = wm_hints_pixmap;
 
769
      mask = wm_hints_mask;
 
770
 
 
771
      /* We won't update if pixmap is unchanged;
 
772
       * avoids a get_from_drawable() on every geometry
 
773
       * hints change
 
774
       */
 
775
      if ((pixmap != icon_cache->prev_pixmap ||
 
776
           mask != icon_cache->prev_mask) &&
 
777
          pixmap != None)
 
778
        {
 
779
          if (try_pixmap_and_mask (screen->display,
 
780
                                   pixmap, mask,
 
781
                                   iconp, ideal_width, ideal_height,
 
782
                                   mini_iconp, ideal_mini_width, ideal_mini_height))
 
783
            {
 
784
              icon_cache->prev_pixmap = pixmap;
 
785
              icon_cache->prev_mask = mask;
 
786
 
 
787
              replace_cache (icon_cache, USING_WM_HINTS,
 
788
                             *iconp, *mini_iconp);
 
789
 
 
790
              return TRUE;
 
791
            }
 
792
        }
 
793
    }
 
794
 
 
795
  if (icon_cache->origin <= USING_KWM_WIN_ICON &&
 
796
      icon_cache->kwm_win_icon_dirty)
 
797
    {
 
798
      icon_cache->kwm_win_icon_dirty = FALSE;
 
799
 
 
800
      get_kwm_win_icon (screen->display, xwindow, &pixmap, &mask);
 
801
 
 
802
      if ((pixmap != icon_cache->prev_pixmap ||
 
803
           mask != icon_cache->prev_mask) &&
 
804
          pixmap != None)
 
805
        {
 
806
          if (try_pixmap_and_mask (screen->display, pixmap, mask,
 
807
                                   iconp, ideal_width, ideal_height,
 
808
                                   mini_iconp, ideal_mini_width, ideal_mini_height))
 
809
            {
 
810
              icon_cache->prev_pixmap = pixmap;
 
811
              icon_cache->prev_mask = mask;
 
812
 
 
813
              replace_cache (icon_cache, USING_KWM_WIN_ICON,
 
814
                             *iconp, *mini_iconp);
 
815
 
 
816
              return TRUE;
 
817
            }
 
818
        }
 
819
    }
 
820
 
 
821
  if (icon_cache->want_fallback &&
 
822
      icon_cache->origin < USING_FALLBACK_ICON)
 
823
    {
 
824
      get_fallback_icons (screen,
 
825
                          iconp,
 
826
                          ideal_width,
 
827
                          ideal_height,
 
828
                          mini_iconp,
 
829
                          ideal_mini_width,
 
830
                          ideal_mini_height);
 
831
 
 
832
      replace_cache (icon_cache, USING_FALLBACK_ICON,
 
833
                     *iconp, *mini_iconp);
 
834
      
 
835
      return TRUE;
 
836
    }
 
837
 
 
838
  if (!icon_cache->want_fallback &&
 
839
      icon_cache->origin == USING_FALLBACK_ICON)
 
840
    {
 
841
      /* Get rid of current icon */
 
842
      clear_icon_cache (icon_cache, FALSE);
 
843
 
 
844
      return TRUE;
 
845
    }
 
846
 
 
847
  /* found nothing new */
 
848
  return FALSE;
 
849
}