~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to lib/appUtil/appUtilX11.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-15 21:21:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080815212140-05fhxj8wroosysmj
Tags: 2008.08.08-109361-1ubuntu1
* Merge from Debian unstable (LP: #258393), remaining Ubuntu change:
  - add ubuntu_toolchain_FTBFS.dpatch patch, fix FTBFS
* Update ubuntu_toolchain_FTBFS.dpatch patch for the new version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2008 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License as published
 
6
 * by the Free Software Foundation version 2.1 and no later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
 
11
 * License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * appUtilX11.c --
 
21
 *
 
22
 *    Utility functions to retrieve application icons.
 
23
 */
 
24
 
 
25
#define _GNU_SOURCE 1
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <unistd.h>
 
29
 
 
30
#include "vmware.h"
 
31
#include "str.h"
 
32
#include "posix.h"
 
33
#include "debug.h"
 
34
 
 
35
#ifndef GTK2
 
36
#error "Gtk 2.0 is required"
 
37
#endif
 
38
 
 
39
#include <glib.h>
 
40
#include <gtk/gtk.h>
 
41
#include <gdk/gdkx.h>
 
42
#include <X11/Xlib.h>
 
43
#include <X11/Xatom.h>
 
44
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
 
45
 
 
46
/*
 
47
 *-----------------------------------------------------------------------------
 
48
 *
 
49
 * AppUtilIconThemeReallyHasIcon --
 
50
 *
 
51
 *      Utility function to detect whether an icon is really available. This is necessary
 
52
 *      because sometimes gtk_icon_theme_has_icon() lies to us...
 
53
 *
 
54
 * Results:
 
55
 *      TRUE if the icon theme really has a usable icon, FALSE otherwise.
 
56
 *
 
57
 * Side effects:
 
58
 *      None.
 
59
 *
 
60
 *-----------------------------------------------------------------------------
 
61
 */
 
62
 
 
63
static Bool
 
64
AppUtilIconThemeReallyHasIcon(GtkIconTheme *iconTheme, // IN
 
65
                              const char *iconName)    // IN
 
66
{
 
67
   gint *iconSizes;
 
68
   Bool retval;
 
69
 
 
70
   if (!gtk_icon_theme_has_icon(iconTheme, iconName)) {
 
71
      return FALSE;
 
72
   }
 
73
 
 
74
   iconSizes = gtk_icon_theme_get_icon_sizes(iconTheme, iconName);
 
75
   retval = iconSizes && iconSizes[0];
 
76
   g_free(iconSizes);
 
77
 
 
78
   return retval;
 
79
}
 
80
 
 
81
 
 
82
/*
 
83
 *-----------------------------------------------------------------------------
 
84
 *
 
85
 * AppUtilCollectNamedIcons --
 
86
 *
 
87
 *      Tries to find icons with a particular name (which may be a full filesystem path,
 
88
 *      a filename with extension, or just an abstract app name).
 
89
 *
 
90
 * Results:
 
91
 *      None.
 
92
 *
 
93
 * Side effects:
 
94
 *      May add icons into 'pixbufs'
 
95
 *
 
96
 *-----------------------------------------------------------------------------
 
97
 */
 
98
 
 
99
static void
 
100
AppUtilCollectNamedIcons(GPtrArray *pixbufs,   // IN/OUT
 
101
                         const char *iconName) // IN
 
102
{
 
103
   char *myIconName;
 
104
   /*
 
105
    * Use the GtkIconTheme to track down any available icons for this app.
 
106
    */
 
107
   GtkIconTheme *iconTheme = NULL;
 
108
   char *ctmp2;
 
109
   Bool foundIt; // Did we find this icon in the GtkIconTheme?
 
110
   static const char *extraIconPaths[] = {
 
111
      "/usr/share/pixmaps",
 
112
      "/usr/local/share/pixmaps",
 
113
      "/usr/local/share/icons",
 
114
      "/opt/kde3/share/icons",
 
115
      "/opt/kde3/share/pixmaps",
 
116
      "/opt/kde4/share/icons",
 
117
      "/opt/kde4/share/pixmaps",
 
118
      "/opt/gnome/share/icons",
 
119
      "/opt/gnome/share/pixmaps"
 
120
   };
 
121
   int iconNameLen;
 
122
 
 
123
   ASSERT(iconName);
 
124
 
 
125
   iconNameLen = strlen(iconName) + 1;
 
126
   myIconName = g_alloca(iconNameLen); // We need to modify the name sometimes
 
127
   Str_Strcpy(myIconName, iconName, iconNameLen);
 
128
 
 
129
   ctmp2 = strrchr(myIconName, '.');
 
130
   if (*myIconName != '/' && ctmp2 && strlen(ctmp2) <= 5) {
 
131
      /*
 
132
       * If it's a plain filename that we could possibly feed into GtkIconTheme as an
 
133
       * icon ID, trim the file extension to turn it into an icon ID string and make
 
134
       * GtkIconTheme happy.
 
135
       */
 
136
      *ctmp2 = '\0';
 
137
   }
 
138
 
 
139
   iconTheme = gtk_icon_theme_get_default();
 
140
   g_object_ref(G_OBJECT(iconTheme));
 
141
   foundIt = AppUtilIconThemeReallyHasIcon(iconTheme, myIconName);
 
142
   if (!foundIt) {
 
143
      /*
 
144
       * Try looking through some auxiliary icon themes.
 
145
       */
 
146
      int i;
 
147
      static const char *extraThemes[] = {
 
148
         /*
 
149
          * Some other icon themes to try.
 
150
          */
 
151
         "hicolor",
 
152
         "Bluecurve",
 
153
         "HighContrast-SVG",
 
154
         "HighContrastLargePrint",
 
155
         NULL
 
156
      };
 
157
      g_object_unref(G_OBJECT(iconTheme));
 
158
      iconTheme = gtk_icon_theme_new();
 
159
      for (i = 0; i < ARRAYSIZE(extraIconPaths); i++) {
 
160
         if (extraIconPaths[i]) {
 
161
            if (g_file_test(extraIconPaths[i], G_FILE_TEST_EXISTS)) {
 
162
               gtk_icon_theme_append_search_path(iconTheme, extraIconPaths[i]);
 
163
            } else {
 
164
               extraIconPaths[i] = NULL;
 
165
            }
 
166
         }
 
167
      }
 
168
 
 
169
      for (i = 0; extraThemes[i]; i++) {
 
170
         gtk_icon_theme_set_custom_theme(iconTheme, extraThemes[i]);
 
171
         foundIt = AppUtilIconThemeReallyHasIcon(iconTheme, myIconName);
 
172
         if (foundIt) {
 
173
            break;
 
174
         }
 
175
      }
 
176
   }
 
177
 
 
178
   if (!foundIt) {
 
179
      /*
 
180
       * Try looking for it as a non-GtkIconTheme managed file, to deal with older
 
181
       * systems.
 
182
       */
 
183
      if (iconName[0] != '/') {
 
184
         char *ctmp2;
 
185
         char *ctmpext;
 
186
         int i;
 
187
 
 
188
         myIconName = NULL;
 
189
         ctmpext = strrchr(iconName, '.');
 
190
         ctmp2 = g_alloca(PATH_MAX);
 
191
         for (i = 0; !myIconName && i < ARRAYSIZE(extraIconPaths); i++) {
 
192
            if (!extraIconPaths[i]) {
 
193
               continue;
 
194
            }
 
195
 
 
196
            if (ctmpext) {
 
197
               g_snprintf(ctmp2, PATH_MAX, "%s/%s", extraIconPaths[i], iconName);
 
198
               if (g_file_test(ctmp2, G_FILE_TEST_EXISTS)) {
 
199
                  myIconName = ctmp2;
 
200
               }
 
201
            } else {
 
202
               static const char *iconExtensions[] = {
 
203
                  ".png",
 
204
                  ".xpm",
 
205
                  ".gif",
 
206
                  ".svg",
 
207
               };
 
208
               int j;
 
209
 
 
210
               for (j = 0; j < ARRAYSIZE(iconExtensions); j++) {
 
211
                  g_snprintf(ctmp2, PATH_MAX, "%s/%s%s",
 
212
                             extraIconPaths[i],
 
213
                             iconName, iconExtensions[j]);
 
214
                  if (g_file_test(ctmp2, G_FILE_TEST_EXISTS)) {
 
215
                     myIconName = ctmp2;
 
216
                     break;
 
217
                  }
 
218
               }
 
219
            }
 
220
         }
 
221
      } else {
 
222
         Str_Strcpy(myIconName, iconName, iconNameLen);
 
223
      }
 
224
   }
 
225
 
 
226
   if (foundIt) {
 
227
      /*
 
228
       * If we know this icon can be loaded via GtkIconTheme, do so.
 
229
       */
 
230
      gint *iconSizes;
 
231
      int i;
 
232
      Bool needToUseScalable;
 
233
 
 
234
      iconSizes = gtk_icon_theme_get_icon_sizes(iconTheme, myIconName);
 
235
 
 
236
      ASSERT(iconSizes);
 
237
      needToUseScalable = (iconSizes[0] == -1 && iconSizes[1] == 0);
 
238
 
 
239
      /*
 
240
       * Before we try to actually dump the icons out to the host, count how many we
 
241
       * actually can load.
 
242
       */
 
243
      for (i = 0; iconSizes[i]; i++) {
 
244
         GdkPixbuf *pixbuf;
 
245
         GtkIconInfo *iconInfo;
 
246
         gint thisSize;
 
247
 
 
248
         thisSize = iconSizes[i];
 
249
         if (thisSize == -1 && !needToUseScalable) {
 
250
            continue; // Skip scalable icons if we have prerendered versions
 
251
         }
 
252
 
 
253
         if (thisSize == -1) {
 
254
            thisSize = 64; // Render SVG icons to 64x64
 
255
         }
 
256
 
 
257
         iconInfo = gtk_icon_theme_lookup_icon(iconTheme, myIconName, thisSize, 0);
 
258
 
 
259
         if (!iconInfo) {
 
260
            Debug("Couldn't find %s icon for size %d\n", myIconName, thisSize);
 
261
            continue;
 
262
         }
 
263
 
 
264
         pixbuf = gtk_icon_info_load_icon(iconInfo, NULL);
 
265
 
 
266
         if (!pixbuf) {
 
267
            pixbuf = gtk_icon_info_get_builtin_pixbuf(iconInfo);
 
268
         }
 
269
 
 
270
         if (pixbuf) {
 
271
            g_ptr_array_add(pixbufs, pixbuf);
 
272
         } else {
 
273
            Debug("WARNING: Not even a built-in pixbuf for icon %s\n", myIconName);
 
274
         }
 
275
 
 
276
         gtk_icon_info_free(iconInfo);
 
277
      }
 
278
 
 
279
      g_free(iconSizes);
 
280
 
 
281
   } else if (myIconName && myIconName[0] == '/') {
 
282
      GdkPixbuf *pixbuf;
 
283
      pixbuf = gdk_pixbuf_new_from_file(myIconName, NULL);
 
284
      if (pixbuf) {
 
285
         g_ptr_array_add(pixbufs, pixbuf);
 
286
      }
 
287
   }
 
288
 
 
289
   if (iconTheme) {
 
290
      g_object_unref(G_OBJECT(iconTheme));
 
291
   }
 
292
}
 
293
 
 
294
 
 
295
/*
 
296
 *-----------------------------------------------------------------------------
 
297
 *
 
298
 * AppUtilComparePixbufSizes --
 
299
 *
 
300
 *      Compares two GdkPixbufs to sort them by image dimensions
 
301
 *
 
302
 * Results:
 
303
 *      -1 if A is larger than B, 0 if equal, 1 if A is smaller than B
 
304
 *
 
305
 * Side effects:
 
306
 *      None.
 
307
 *
 
308
 *-----------------------------------------------------------------------------
 
309
 */
 
310
 
 
311
static gint
 
312
AppUtilComparePixbufSizes(gconstpointer a, // IN
 
313
                          gconstpointer b) // IN
 
314
{
 
315
   GdkPixbuf *pba;
 
316
   GdkPixbuf *pbb;
 
317
   int asize;
 
318
   int bsize;
 
319
 
 
320
   if (a && !b) {
 
321
      return -1;
 
322
   } else if (!a && b) {
 
323
      return 1;
 
324
   } else if (!a && !b) {
 
325
      return 0;
 
326
   }
 
327
 
 
328
   pba = GDK_PIXBUF(*(gconstpointer *)a);
 
329
   asize = gdk_pixbuf_get_width(pba) * gdk_pixbuf_get_height(pba);
 
330
 
 
331
   pbb = GDK_PIXBUF(*(gconstpointer *)b);
 
332
   bsize = gdk_pixbuf_get_width(pbb) * gdk_pixbuf_get_height(pbb);
 
333
 
 
334
   if (asize > bsize) {
 
335
      return -1;
 
336
   } else if (asize < bsize) {
 
337
      return 1;
 
338
   }
 
339
 
 
340
   return 0;
 
341
}
 
342
 
 
343
 
 
344
/*
 
345
 *-----------------------------------------------------------------------------
 
346
 *
 
347
 * AppUtil_CollectIconArray --
 
348
 *
 
349
 *      Given a variety of information about an application (its icon name, X window ID,
 
350
 *      etc.), return an array of GdkPixbufs that represent the icons for that
 
351
 *      application.
 
352
 *
 
353
 * Results:
 
354
 *      GPtrArray of GdkPixbufs, or NULL on failure. The returned array may have zero
 
355
 *      elements. The array will be sorted by icon size, largest to smallest.
 
356
 *
 
357
 * Side effects:
 
358
 *      Caller becomes owner of the array and pixbufs that are allocated during this
 
359
 *      function.
 
360
 *
 
361
 *-----------------------------------------------------------------------------
 
362
 */
 
363
 
 
364
GPtrArray *
 
365
AppUtil_CollectIconArray(const char *iconName,        // IN
 
366
                         unsigned long windowID)      // IN
 
367
{
 
368
   GPtrArray *pixbufs;
 
369
 
 
370
   ASSERT(iconName != NULL || windowID != None);
 
371
 
 
372
   pixbufs = g_ptr_array_new();
 
373
 
 
374
   if (iconName) {
 
375
      AppUtilCollectNamedIcons(pixbufs, iconName);
 
376
   }
 
377
 
 
378
   if (!pixbufs->len && windowID != None) {
 
379
      /*
 
380
       * Try loading the icon from the X Window's _NET_WM_ICON/WM_HINTS property.
 
381
       */
 
382
      Display *dpy;
 
383
      XWMHints *wmh;
 
384
      Atom actualType = None;
 
385
      int actualFormat;
 
386
      unsigned long nitems = 0;
 
387
      unsigned long bytesLeft;
 
388
      XID *value;
 
389
      XTextProperty wmIconName;
 
390
 
 
391
      dpy = gdk_x11_get_default_xdisplay();
 
392
      XGetWindowProperty(dpy, windowID, XInternAtom(dpy, "_NET_WM_ICON", FALSE),
 
393
                         0, LONG_MAX, False, XA_CARDINAL,
 
394
                         &actualType, &actualFormat, &nitems,
 
395
                         &bytesLeft, (unsigned char **)&value);
 
396
 
 
397
      if (nitems) {
 
398
         /*
 
399
          * _NET_WM_ICON: Transform ARGB data into pixbufs...
 
400
          */
 
401
         int i;
 
402
 
 
403
         for (i = 0; i < nitems; ) {
 
404
            GdkPixbuf *pixbuf;
 
405
            int width;
 
406
            int height;
 
407
            int x;
 
408
            int y;
 
409
            int rowstride;
 
410
            guchar *pixels;
 
411
 
 
412
            ASSERT((nitems - i) >= 2);
 
413
            width = value[i];
 
414
            height = value[i + 1];
 
415
            i += 2;
 
416
            pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
 
417
            if (pixbuf) {
 
418
               pixels = gdk_pixbuf_get_pixels(pixbuf);
 
419
               rowstride = gdk_pixbuf_get_rowstride(pixbuf);
 
420
 
 
421
               for (y = 0; y < height; y++) {
 
422
                  for (x = 0; x < width && i < nitems; x++, i++) {
 
423
                     guchar *pixel = &pixels[y * rowstride + x * 4];
 
424
                     XID currentValue = value[i];
 
425
 
 
426
                     /*
 
427
                      * Input data: BGRA data (high byte is A, low byte is B -
 
428
                      * freedesktop calls this ARGB, but that's not correct).
 
429
                      *
 
430
                      * Output data: RGBA data.
 
431
                      */
 
432
                     *pixel = (currentValue >> 16) & 0xFF;
 
433
                     *(pixel + 1) = (currentValue >> 8) & 0xFF;
 
434
                     *(pixel + 2) = currentValue & 0xFF;
 
435
                     *(pixel + 3) = (currentValue >> 24) & 0xFF;
 
436
                  }
 
437
               }
 
438
 
 
439
               g_ptr_array_add(pixbufs, pixbuf);
 
440
            } else {
 
441
               Debug("gdk_pixbuf_new failed when decoding _NET_WM_ICON\n");
 
442
               break;
 
443
            }
 
444
         }
 
445
         XFree(value);
 
446
      }
 
447
      nitems = 0;
 
448
      if (!pixbufs->len &&
 
449
          XGetWindowProperty(dpy, windowID, XInternAtom(dpy, "_NET_WM_ICON_NAME", FALSE),
 
450
                             0, LONG_MAX, False, XInternAtom(dpy, "UTF8_STRING", FALSE),
 
451
                             &actualType, &actualFormat, &nitems,
 
452
                             &bytesLeft, (unsigned char **)&value) == Success
 
453
          && nitems) {
 
454
         /*
 
455
          * _NET_WM_ICON_NAME
 
456
          */
 
457
         AppUtilCollectNamedIcons(pixbufs, (char *)value);
 
458
         XFree(value);
 
459
      }
 
460
 
 
461
      if (!pixbufs->len && XGetWMIconName(dpy, windowID, &wmIconName)) {
 
462
         /*
 
463
          * WM_ICON_NAME
 
464
          */
 
465
         AppUtilCollectNamedIcons(pixbufs, wmIconName.value);
 
466
         XFree(wmIconName.value);
 
467
      }
 
468
 
 
469
      if (!pixbufs->len && (wmh = XGetWMHints(dpy, windowID))) {
 
470
         /*
 
471
          * WM_HINTS
 
472
          */
 
473
         if (wmh->flags & IconPixmapHint) {
 
474
            Window dummyWin;
 
475
            int x;
 
476
            int y;
 
477
            unsigned int width;
 
478
            unsigned int height;
 
479
            unsigned int border;
 
480
            unsigned int depth;
 
481
            GdkPixbuf *pixbuf = NULL;
 
482
 
 
483
            if (XGetGeometry(dpy, wmh->icon_pixmap, &dummyWin,
 
484
                             &x, &y, &width, &height, &border, &depth)) {
 
485
 
 
486
               pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
 
487
 
 
488
               if (!gdk_pixbuf_xlib_get_from_drawable (pixbuf, wmh->icon_pixmap,
 
489
                                                       DefaultColormap(dpy, 0),
 
490
                                                       DefaultVisual(dpy, 0),
 
491
                                                       0, 0, 0, 0, width, height)) {
 
492
                  g_object_unref(G_OBJECT(pixbuf));
 
493
                  pixbuf = NULL;
 
494
               }
 
495
 
 
496
               if (pixbuf && (wmh->flags & IconMaskHint)) {
 
497
                  /*
 
498
                   * Apply the X bitmap mask.
 
499
                   */
 
500
                  GdkPixbuf *pixbuf_mask;
 
501
 
 
502
                  pixbuf_mask =
 
503
                     gdk_pixbuf_xlib_get_from_drawable(pixbuf,
 
504
                                                       wmh->icon_mask,
 
505
                                                       DefaultColormap(dpy, 0),
 
506
                                                       DefaultVisual(dpy, 0),
 
507
                                                       0, 0, 0, 0,
 
508
                                                       width, height);
 
509
                  if (pixbuf_mask) {
 
510
                     int x;
 
511
                     int y;
 
512
                     int rowstride;
 
513
                     int rowstride_mask;
 
514
                     guchar *pixels;
 
515
                     guchar *pixels_mask;
 
516
                     int depth_mask;
 
517
                     int n_channels_mask;
 
518
 
 
519
                     pixels = gdk_pixbuf_get_pixels(pixbuf);
 
520
                     pixels_mask = gdk_pixbuf_get_pixels(pixbuf_mask);
 
521
                     rowstride = gdk_pixbuf_get_rowstride(pixbuf);
 
522
                     rowstride_mask = gdk_pixbuf_get_rowstride(pixbuf_mask);
 
523
                     depth_mask = gdk_pixbuf_get_bits_per_sample(pixbuf_mask);
 
524
                     ASSERT(gdk_pixbuf_get_bits_per_sample(pixbuf) == 8);
 
525
                     n_channels_mask = gdk_pixbuf_get_n_channels(pixbuf_mask);
 
526
 
 
527
                     for (y = 0; y < height; y++) {
 
528
                        guchar *thisrow_mask = pixels_mask + y * rowstride_mask;
 
529
                        guchar *thisrow = pixels + y * rowstride;
 
530
                        for (x = 0; x < width; x++) {
 
531
                           guchar newAlpha = 0xFF;
 
532
                           switch(depth_mask) {
 
533
                           case 1:
 
534
                              newAlpha = thisrow_mask[x * n_channels_mask / 8];
 
535
                              newAlpha >>= (x % 8);
 
536
                              newAlpha = newAlpha ? 0xFF : 0;
 
537
                              break;
 
538
                           case 8:
 
539
                              /*
 
540
                               * For some reason, gdk-pixbuf-xlib turns a monochrome
 
541
                               * bitmap into 0/1 values in the blue channel of an RGBA
 
542
                               * pixmap.
 
543
                               */
 
544
                              newAlpha = (thisrow_mask[x * n_channels_mask + 2])
 
545
                                 ? 0xFF : 0;
 
546
                              break;
 
547
                           default:
 
548
                              NOT_REACHED();
 
549
                              break;
 
550
                           }
 
551
 
 
552
                           thisrow[x * 4 + 3] = newAlpha;
 
553
                        }
 
554
                     }
 
555
                  }
 
556
               }
 
557
 
 
558
               if (pixbuf) {
 
559
                  g_ptr_array_add(pixbufs, pixbuf);
 
560
               }
 
561
            }
 
562
         }
 
563
 
 
564
         XFree(wmh);
 
565
      }
 
566
 
 
567
      if (!pixbufs->len) {
 
568
         /*
 
569
          * Last resort - try using the WM_CLASS as an icon name
 
570
          */
 
571
 
 
572
         XClassHint hints;
 
573
 
 
574
         if (XGetClassHint(dpy, windowID, &hints)) {
 
575
            if (hints.res_name) {
 
576
               AppUtilCollectNamedIcons(pixbufs, hints.res_name);
 
577
            }
 
578
 
 
579
            XFree(hints.res_name);
 
580
            XFree(hints.res_class);
 
581
         }
 
582
      }
 
583
   }
 
584
 
 
585
   /*
 
586
    * In order to make it easy for AppUtil users to pick the icon they want, we sort them
 
587
    * largest-to-smallest.
 
588
    */
 
589
   g_ptr_array_sort(pixbufs, AppUtilComparePixbufSizes);
 
590
 
 
591
   if (!pixbufs->len) {
 
592
      Debug("WARNING: No icons found for %s / %#lx\n", iconName, windowID);
 
593
   }
 
594
 
 
595
   return pixbufs;
 
596
}
 
597
 
 
598
 
 
599
/*
 
600
 *-----------------------------------------------------------------------------
 
601
 *
 
602
 * AppUtil_FreeIconArray --
 
603
 *
 
604
 *      Frees the result of AppUtil_CollectIconArray
 
605
 *
 
606
 * Results:
 
607
 *      None.
 
608
 *
 
609
 * Side effects:
 
610
 *      Array and its contents are destroyed
 
611
 *
 
612
 *-----------------------------------------------------------------------------
 
613
 */
 
614
 
 
615
void
 
616
AppUtil_FreeIconArray(GPtrArray *pixbufs) // IN
 
617
{
 
618
   int i;
 
619
 
 
620
   if (!pixbufs) {
 
621
      return;
 
622
   }
 
623
 
 
624
   for (i = 0; i < pixbufs->len; i++) {
 
625
      g_object_unref(G_OBJECT(g_ptr_array_index(pixbufs, i)));
 
626
   }
 
627
 
 
628
   g_ptr_array_free(pixbufs, TRUE);
 
629
}
 
630
/*
 
631
 *-----------------------------------------------------------------------------
 
632
 *
 
633
 * AppUtil_AppIsSkippable --
 
634
 *
 
635
 *      Can an executable be ignored for the purposes of determining the path to run an
 
636
 *      app with? Usually true for interpreters and the like, for which the script path
 
637
 *      should be used instead.
 
638
 *
 
639
 * Results:
 
640
 *      TRUE if the app should be ignored, FALSE otherwise.
 
641
 *
 
642
 * Side effects:
 
643
 *      None.
 
644
 *
 
645
 *-----------------------------------------------------------------------------
 
646
 */
 
647
 
 
648
Bool
 
649
AppUtil_AppIsSkippable(const char *appName)
 
650
{
 
651
   static const char *skipAppsList[] = {
 
652
      "python",
 
653
      "python2.5",
 
654
      "python2.4",
 
655
      "python2.3",
 
656
      "python2.2",
 
657
      "perl",
 
658
      "getproxy"
 
659
   };
 
660
   char cbuf[PATH_MAX];
 
661
   int i;
 
662
   char *ctmp;
 
663
 
 
664
   Str_Strcpy(cbuf, appName, sizeof cbuf);
 
665
   ctmp = basename(cbuf);
 
666
 
 
667
   for (i = 0; i < ARRAYSIZE(skipAppsList); i++) {
 
668
      if (!strcmp(ctmp, skipAppsList[i])) {
 
669
         return TRUE;
 
670
      }
 
671
   }
 
672
 
 
673
   return FALSE;
 
674
}
 
675
 
 
676
 
 
677
/*
 
678
 *-----------------------------------------------------------------------------
 
679
 *
 
680
 * AppUtil_CanonicalizeAppName --
 
681
 *
 
682
 *      Turns the app name (or path) into a full path for the executable.
 
683
 *
 
684
 * Results:
 
685
 *      Path, or NULL if not available
 
686
 *
 
687
 * Side effects:
 
688
 *      Allocated memory is returned 
 
689
 *
 
690
 *-----------------------------------------------------------------------------
 
691
 */
 
692
 
 
693
char *
 
694
AppUtil_CanonicalizeAppName(const char *appName, // IN
 
695
                            const char *cwd)     // IN
 
696
{
 
697
   char *ctmp;
 
698
   ASSERT(appName);
 
699
 
 
700
   if (appName[0] == '/') {
 
701
      return g_strdup(appName);
 
702
   }
 
703
 
 
704
   ctmp = g_find_program_in_path(appName);
 
705
   if (ctmp) {
 
706
      return ctmp;
 
707
   }
 
708
 
 
709
   if (cwd) {
 
710
      char cbuf[PATH_MAX];
 
711
 
 
712
      getcwd(cbuf, sizeof cbuf);
 
713
      chdir(cwd);
 
714
      ctmp = Posix_RealPath(appName);
 
715
      chdir(cbuf);
 
716
 
 
717
      return ctmp;
 
718
   }
 
719
 
 
720
   return NULL;
 
721
}
 
722
 
 
723
 
 
724
/*
 
725
 *-----------------------------------------------------------------------------
 
726
 *
 
727
 * AppUtil_Init --
 
728
 *
 
729
 *      Initializes the AppUtil library for subsequent use.
 
730
 *
 
731
 * Results:
 
732
 *      None.
 
733
 *
 
734
 * Side effects:
 
735
 *      Internal state is initialized. Currently this is just gdk-pixbuf-xlib.
 
736
 *
 
737
 *-----------------------------------------------------------------------------
 
738
 */
 
739
 
 
740
void
 
741
AppUtil_Init(void)
 
742
{
 
743
   gdk_pixbuf_xlib_init(gdk_x11_get_default_xdisplay(), 0);
 
744
}