~kroq-gar78/ubuntu/precise/gnome-control-center/fix-885947

« back to all changes in this revision

Viewing changes to capplets/common/gnome-theme-info.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mto: (206.1.1 oneiric-proposed)
  • mto: This revision was merged to the branch mainline in revision 165.
  • Revision ID: james.westby@ubuntu.com-20110517104727-ky274kr7t5a1nk9r
Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ifdef HAVE_CONFIG_H
2
 
#include <config.h>
3
 
#endif
4
 
 
5
 
#include <sys/types.h>
6
 
#include <sys/stat.h>
7
 
#include <dirent.h>
8
 
#include <glib/gi18n.h>
9
 
#include <gmodule.h>
10
 
#include <gtk/gtk.h>
11
 
#include <gdk/gdkx.h>
12
 
#include <gio/gio.h>
13
 
#include <string.h>
14
 
#include <libgnome/gnome-desktop-item.h>
15
 
#include "gnome-theme-info.h"
16
 
#include "gtkrc-utils.h"
17
 
 
18
 
#ifdef HAVE_XCURSOR
19
 
#include <X11/Xcursor/Xcursor.h>
20
 
#endif
21
 
 
22
 
#define THEME_NAME "X-GNOME-Metatheme/Name"
23
 
#define THEME_COMMENT "X-GNOME-Metatheme/Comment"
24
 
#define GTK_THEME_KEY "X-GNOME-Metatheme/GtkTheme"
25
 
#define GTK_COLOR_SCHEME_KEY "X-GNOME-Metatheme/GtkColorScheme"
26
 
#define METACITY_THEME_KEY "X-GNOME-Metatheme/MetacityTheme"
27
 
#define ICON_THEME_KEY "X-GNOME-Metatheme/IconTheme"
28
 
#define CURSOR_THEME_KEY "X-GNOME-Metatheme/CursorTheme"
29
 
#define NOTIFICATION_THEME_KEY "X-GNOME-Metatheme/NotificationTheme"
30
 
#define CURSOR_SIZE_KEY "X-GNOME-Metatheme/CursorSize"
31
 
#define SOUND_THEME_KEY "X-GNOME-Metatheme/SoundTheme"
32
 
#define APPLICATION_FONT_KEY "X-GNOME-Metatheme/ApplicationFont"
33
 
#define DOCUMENTS_FONT_KEY "X-GNOME-Metatheme/DocumentsFont"
34
 
#define DESKTOP_FONT_KEY "X-GNOME-Metatheme/DesktopFont"
35
 
#define WINDOWTITLE_FONT_KEY "X-GNOME-Metatheme/WindowTitleFont"
36
 
#define MONOSPACE_FONT_KEY "X-GNOME-Metatheme/MonospaceFont"
37
 
#define BACKGROUND_IMAGE_KEY "X-GNOME-Metatheme/BackgroundImage"
38
 
#define HIDDEN_KEY "X-GNOME-Metatheme/Hidden"
39
 
 
40
 
/* Terminology used in this lib:
41
 
 *
42
 
 * /usr/share/themes, ~/.themes   -- top_theme_dir
43
 
 * top_theme_dir/theme_name/      -- common_theme_dir
44
 
 * /usr/share/icons, ~/.icons     -- top_icon_theme_dir
45
 
 * top_icon_theme_dir/theme_name/ -- icon_common_theme_dir
46
 
 *
47
 
 */
48
 
 
49
 
typedef struct _ThemeCallbackData
50
 
{
51
 
  ThemeChangedCallback func;
52
 
  gpointer data;
53
 
} ThemeCallbackData;
54
 
 
55
 
typedef struct {
56
 
  GFileMonitor *common_theme_dir_handle;
57
 
  GFileMonitor *gtk2_dir_handle;
58
 
  GFileMonitor *keybinding_dir_handle;
59
 
  GFileMonitor *metacity_dir_handle;
60
 
  gint priority;
61
 
} CommonThemeDirMonitorData;
62
 
 
63
 
typedef struct {
64
 
  GFileMonitor *common_icon_theme_dir_handle;
65
 
  gint priority;
66
 
} CommonIconThemeDirMonitorData;
67
 
 
68
 
typedef struct {
69
 
  GHashTable *handle_hash;
70
 
  gint priority;
71
 
} CallbackTuple;
72
 
 
73
 
 
74
 
/* Hash tables */
75
 
 
76
 
/* The hashes_by_dir are indexed by an escaped uri of the common_theme_dir that
77
 
 * that particular theme is part of.  The data pointed to by them is a
78
 
 * GnomeTheme{Meta,Icon,}Info struct.  Note that the uri is of the form
79
 
 * "file:///home/username/.themes/foo", and not "/home/username/.themes/foo"
80
 
 */
81
 
 
82
 
/* The hashes_by_name are hashed by the index of the theme.  The data pointed to
83
 
 * by them is a GList whose data elements are GnomeTheme{Meta,Icon,}Info
84
 
 * structs.  This is because a theme can be found both in the users ~/.theme as
85
 
 * well as globally in $prefix.  All access to them must be done via helper
86
 
 * functions.
87
 
 */
88
 
static GList *callbacks = NULL;
89
 
 
90
 
static GHashTable *meta_theme_hash_by_uri;
91
 
static GHashTable *meta_theme_hash_by_name;
92
 
static GHashTable *icon_theme_hash_by_uri;
93
 
static GHashTable *icon_theme_hash_by_name;
94
 
static GHashTable *cursor_theme_hash_by_uri;
95
 
static GHashTable *cursor_theme_hash_by_name;
96
 
static GHashTable *theme_hash_by_uri;
97
 
static GHashTable *theme_hash_by_name;
98
 
static gboolean initting = FALSE;
99
 
 
100
 
/* private functions */
101
 
static gint
102
 
safe_strcmp (const gchar *a_str,
103
 
             const gchar *b_str)
104
 
{
105
 
  if (a_str && b_str)
106
 
    return strcmp (a_str, b_str);
107
 
  else
108
 
    return a_str - b_str;
109
 
}
110
 
 
111
 
static GFileType
112
 
get_file_type (GFile *file)
113
 
{
114
 
  GFileType file_type = G_FILE_TYPE_UNKNOWN;
115
 
  GFileInfo *file_info;
116
 
 
117
 
  file_info = g_file_query_info (file,
118
 
                                 G_FILE_ATTRIBUTE_STANDARD_TYPE,
119
 
                                 G_FILE_QUERY_INFO_NONE,
120
 
                                 NULL, NULL);
121
 
  if (file_info != NULL) {
122
 
    file_type = g_file_info_get_file_type (file_info);
123
 
    g_object_unref (file_info);
124
 
  }
125
 
 
126
 
  return file_type;
127
 
}
128
 
 
129
 
static void
130
 
add_theme_to_hash_by_name (GHashTable *hash_table,
131
 
                           gpointer    data)
132
 
{
133
 
  GnomeThemeCommonInfo *info = data;
134
 
  GList *list;
135
 
 
136
 
  list = g_hash_table_lookup (hash_table, info->name);
137
 
  if (list == NULL) {
138
 
    list = g_list_append (list, info);
139
 
  } else {
140
 
    GList *list_ptr = list;
141
 
    gboolean added = FALSE;
142
 
 
143
 
    while (list_ptr) {
144
 
      gint theme_priority;
145
 
 
146
 
      theme_priority = ((GnomeThemeCommonInfo *) list_ptr->data)->priority;
147
 
 
148
 
      if (theme_priority == info->priority) {
149
 
        /* Swap it in */
150
 
        list_ptr->data = info;
151
 
        added = TRUE;
152
 
        break;
153
 
      } else if (theme_priority > info->priority) {
154
 
        list = g_list_insert_before (list, list_ptr, info);
155
 
        added = TRUE;
156
 
        break;
157
 
      }
158
 
      list_ptr = list_ptr->next;
159
 
    }
160
 
    if (!added)
161
 
      list = g_list_append (list, info);
162
 
  }
163
 
  g_hash_table_insert (hash_table, g_strdup (info->name), list);
164
 
}
165
 
 
166
 
static void
167
 
remove_theme_from_hash_by_name (GHashTable *hash_table,
168
 
                                gpointer    data)
169
 
{
170
 
  GnomeThemeCommonInfo *info = data;
171
 
  GList *list;
172
 
 
173
 
  list = g_hash_table_lookup (hash_table, info->name);
174
 
 
175
 
  list = g_list_remove (list, info);
176
 
  if (list == NULL)
177
 
    g_hash_table_remove (hash_table, info->name);
178
 
  else
179
 
    g_hash_table_insert (hash_table, g_strdup (info->name), list);
180
 
}
181
 
 
182
 
static GnomeThemeCommonInfo *
183
 
get_theme_from_hash_by_name (GHashTable  *hash_table,
184
 
                             const gchar *name,
185
 
                             gint         priority)
186
 
{
187
 
  GList *list;
188
 
 
189
 
  list = g_hash_table_lookup (hash_table, name);
190
 
 
191
 
  /* -1 implies return the first one */
192
 
  if (priority == -1) {
193
 
    return list ? list->data : NULL;
194
 
  }
195
 
 
196
 
  while (list) {
197
 
    GnomeThemeCommonInfo *info = (GnomeThemeCommonInfo *) list->data;
198
 
 
199
 
    if (info->priority == priority)
200
 
      return info;
201
 
 
202
 
    list = list->next;
203
 
  }
204
 
  return NULL;
205
 
}
206
 
 
207
 
static gint
208
 
theme_compare (GnomeThemeCommonInfo *a,
209
 
               GnomeThemeCommonInfo *b)
210
 
{
211
 
  gint cmp;
212
 
 
213
 
  g_return_val_if_fail (a->type == b->type, a->type - b->type);
214
 
 
215
 
  switch (a->type) {
216
 
  case GNOME_THEME_TYPE_METATHEME:
217
 
    cmp = gnome_theme_meta_info_compare (
218
 
                    (GnomeThemeMetaInfo *) a, (GnomeThemeMetaInfo *) b);
219
 
    break;
220
 
  case GNOME_THEME_TYPE_ICON:
221
 
    cmp = gnome_theme_icon_info_compare (
222
 
                    (GnomeThemeIconInfo *) a, (GnomeThemeIconInfo *) b);
223
 
    break;
224
 
  case GNOME_THEME_TYPE_CURSOR:
225
 
    cmp = gnome_theme_cursor_info_compare (
226
 
                    (GnomeThemeCursorInfo *) a, (GnomeThemeCursorInfo *) b);
227
 
    break;
228
 
  default:
229
 
    /* not supported at this time */
230
 
    g_assert_not_reached ();
231
 
  }
232
 
 
233
 
  return cmp;
234
 
}
235
 
 
236
 
static void
237
 
theme_free (GnomeThemeCommonInfo *info)
238
 
{
239
 
  switch (info->type) {
240
 
  case GNOME_THEME_TYPE_METATHEME:
241
 
    gnome_theme_meta_info_free ((GnomeThemeMetaInfo *) info);
242
 
    break;
243
 
  case GNOME_THEME_TYPE_ICON:
244
 
    gnome_theme_icon_info_free ((GnomeThemeIconInfo *) info);
245
 
    break;
246
 
  case GNOME_THEME_TYPE_REGULAR:
247
 
    gnome_theme_info_free ((GnomeThemeInfo *) info);
248
 
    break;
249
 
  case GNOME_THEME_TYPE_CURSOR:
250
 
    gnome_theme_cursor_info_free ((GnomeThemeCursorInfo *) info);
251
 
    break;
252
 
  default:
253
 
    g_assert_not_reached ();
254
 
  }
255
 
}
256
 
 
257
 
GQuark
258
 
gnome_theme_info_error_quark (void)
259
 
{
260
 
  return g_quark_from_static_string ("gnome-theme-info-error-quark");
261
 
}
262
 
 
263
 
GnomeThemeMetaInfo *
264
 
gnome_theme_read_meta_theme (GFile *meta_theme_uri)
265
 
{
266
 
  GnomeThemeMetaInfo *meta_theme_info;
267
 
  GFile *common_theme_dir_uri;
268
 
  GnomeDesktopItem *meta_theme_ditem;
269
 
  gchar *meta_theme_file;
270
 
  const gchar *str;
271
 
  gchar *scheme;
272
 
 
273
 
  meta_theme_file = g_file_get_uri (meta_theme_uri);
274
 
  meta_theme_ditem = gnome_desktop_item_new_from_uri (meta_theme_file, 0, NULL);
275
 
  g_free (meta_theme_file);
276
 
 
277
 
  if (meta_theme_ditem == NULL)
278
 
    return NULL;
279
 
 
280
 
  common_theme_dir_uri = g_file_get_parent (meta_theme_uri);
281
 
  meta_theme_info = gnome_theme_meta_info_new ();
282
 
  meta_theme_info->path = g_file_get_path (meta_theme_uri);
283
 
  meta_theme_info->name = g_file_get_basename (common_theme_dir_uri);
284
 
  g_object_unref (common_theme_dir_uri);
285
 
 
286
 
  str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_NAME);
287
 
  if (!str) {
288
 
    str = gnome_desktop_item_get_localestring (meta_theme_ditem, GNOME_DESKTOP_ITEM_NAME);
289
 
    if (!str) { /* shouldn't reach */
290
 
      gnome_theme_meta_info_free (meta_theme_info);
291
 
      return NULL;
292
 
    }
293
 
  }
294
 
 
295
 
  meta_theme_info->readable_name = g_strdup (str);
296
 
 
297
 
  str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_COMMENT);
298
 
  if (str == NULL)
299
 
    str = gnome_desktop_item_get_localestring (meta_theme_ditem, GNOME_DESKTOP_ITEM_COMMENT);
300
 
  if (str != NULL)
301
 
    meta_theme_info->comment = g_strdup (str);
302
 
 
303
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, GNOME_DESKTOP_ITEM_ICON);
304
 
  if (str != NULL)
305
 
    meta_theme_info->icon_file = g_strdup (str);
306
 
 
307
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, GTK_THEME_KEY);
308
 
  if (str == NULL) {
309
 
    gnome_theme_meta_info_free (meta_theme_info);
310
 
    return NULL;
311
 
  }
312
 
  meta_theme_info->gtk_theme_name = g_strdup (str);
313
 
 
314
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, GTK_COLOR_SCHEME_KEY);
315
 
  if (str == NULL || str[0] == '\0')
316
 
    scheme = gtkrc_get_color_scheme_for_theme (meta_theme_info->gtk_theme_name);
317
 
  else
318
 
    scheme = g_strdup (str);
319
 
 
320
 
  if (scheme != NULL) {
321
 
    meta_theme_info->gtk_color_scheme = scheme;
322
 
    for (; *scheme != '\0'; scheme++)
323
 
      if (*scheme == ',')
324
 
        *scheme = '\n';
325
 
  }
326
 
 
327
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, METACITY_THEME_KEY);
328
 
  if (str == NULL) {
329
 
    gnome_theme_meta_info_free (meta_theme_info);
330
 
    return NULL;
331
 
  }
332
 
  meta_theme_info->metacity_theme_name = g_strdup (str);
333
 
 
334
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, ICON_THEME_KEY);
335
 
  if (str == NULL) {
336
 
    gnome_theme_meta_info_free (meta_theme_info);
337
 
    return NULL;
338
 
  }
339
 
  meta_theme_info->icon_theme_name = g_strdup (str);
340
 
 
341
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, NOTIFICATION_THEME_KEY);
342
 
  if (str != NULL)
343
 
    meta_theme_info->notification_theme_name = g_strdup (str);
344
 
 
345
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_THEME_KEY);
346
 
  if (str != NULL) {
347
 
    meta_theme_info->cursor_theme_name = g_strdup (str);
348
 
 
349
 
    str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_SIZE_KEY);
350
 
    if (str)
351
 
      meta_theme_info->cursor_size = (int) g_ascii_strtoll (str, NULL, 10);
352
 
    else
353
 
      meta_theme_info->cursor_size = 18;
354
 
  } else {
355
 
    meta_theme_info->cursor_theme_name = g_strdup ("default");
356
 
    meta_theme_info->cursor_size = 18;
357
 
  }
358
 
 
359
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, APPLICATION_FONT_KEY);
360
 
  if (str != NULL)
361
 
    meta_theme_info->application_font = g_strdup (str);
362
 
 
363
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, DOCUMENTS_FONT_KEY);
364
 
  if (str != NULL)
365
 
    meta_theme_info->documents_font = g_strdup (str);
366
 
 
367
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, DESKTOP_FONT_KEY);
368
 
  if (str != NULL)
369
 
    meta_theme_info->desktop_font = g_strdup (str);
370
 
 
371
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, WINDOWTITLE_FONT_KEY);
372
 
  if (str != NULL)
373
 
    meta_theme_info->windowtitle_font = g_strdup (str);
374
 
 
375
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, MONOSPACE_FONT_KEY);
376
 
  if (str != NULL)
377
 
    meta_theme_info->monospace_font = g_strdup (str);
378
 
 
379
 
  str = gnome_desktop_item_get_string (meta_theme_ditem, BACKGROUND_IMAGE_KEY);
380
 
  if (str != NULL)
381
 
    meta_theme_info->background_image = g_strdup (str);
382
 
 
383
 
  meta_theme_info->hidden = gnome_desktop_item_get_boolean (meta_theme_ditem,
384
 
                                                            HIDDEN_KEY);
385
 
 
386
 
  gnome_desktop_item_unref (meta_theme_ditem);
387
 
 
388
 
  return meta_theme_info;
389
 
}
390
 
 
391
 
static GnomeThemeIconInfo *
392
 
read_icon_theme (GFile *icon_theme_uri)
393
 
{
394
 
  GnomeThemeIconInfo *icon_theme_info;
395
 
  GnomeDesktopItem *icon_theme_ditem;
396
 
  gchar *icon_theme_file;
397
 
  gchar *dir_name;
398
 
  const gchar *name;
399
 
  const gchar *directories;
400
 
 
401
 
  icon_theme_file = g_file_get_uri (icon_theme_uri);
402
 
  icon_theme_ditem = gnome_desktop_item_new_from_uri (icon_theme_file, 0, NULL);
403
 
  g_free (icon_theme_file);
404
 
 
405
 
  if (icon_theme_ditem == NULL)
406
 
    return NULL;
407
 
 
408
 
  name = gnome_desktop_item_get_localestring (icon_theme_ditem, "Icon Theme/Name");
409
 
  if (!name) {
410
 
    name = gnome_desktop_item_get_localestring (icon_theme_ditem, GNOME_DESKTOP_ITEM_NAME);
411
 
    if (!name) {
412
 
      gnome_desktop_item_unref (icon_theme_ditem);
413
 
      return NULL;
414
 
    }
415
 
  }
416
 
 
417
 
  /* If index.theme has no Directories entry, it is only a cursor theme */
418
 
  directories = gnome_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Directories");
419
 
  if (directories == NULL) {
420
 
    gnome_desktop_item_unref (icon_theme_ditem);
421
 
    return NULL;
422
 
  }
423
 
 
424
 
  icon_theme_info = gnome_theme_icon_info_new ();
425
 
  icon_theme_info->readable_name = g_strdup (name);
426
 
  icon_theme_info->path = g_file_get_path (icon_theme_uri);
427
 
  icon_theme_info->hidden = gnome_desktop_item_get_boolean (icon_theme_ditem, "Icon Theme/Hidden");
428
 
  dir_name = g_path_get_dirname (icon_theme_info->path);
429
 
  icon_theme_info->name = g_path_get_basename (dir_name);
430
 
  g_free (dir_name);
431
 
 
432
 
  gnome_desktop_item_unref (icon_theme_ditem);
433
 
 
434
 
  return icon_theme_info;
435
 
}
436
 
 
437
 
#ifdef HAVE_XCURSOR
438
 
static void
439
 
add_default_cursor_theme ()
440
 
{
441
 
  GnomeThemeCursorInfo *theme_info;
442
 
 
443
 
  theme_info = gnome_theme_cursor_info_new ();
444
 
  theme_info->path = g_strdup ("builtin");
445
 
  theme_info->name = g_strdup ("default");
446
 
  theme_info->readable_name = g_strdup (_("Default Pointer"));
447
 
  theme_info->sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), 0);
448
 
 
449
 
  g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
450
 
  add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
451
 
}
452
 
 
453
 
static GdkPixbuf *
454
 
gdk_pixbuf_from_xcursor_image (XcursorImage *cursor)
455
 
{
456
 
  GdkPixbuf *pixbuf;
457
 
#define BUF_SIZE sizeof(guint32) * cursor->width * cursor->height
458
 
  guchar *buf = g_malloc0 (BUF_SIZE);
459
 
  guchar *it;
460
 
 
461
 
  for (it = buf; it < (buf + BUF_SIZE); it += 4) {
462
 
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
463
 
    /* on little endianess it's BGRA to RGBA */
464
 
    it[0] = ((guchar *) (cursor->pixels))[it - buf + 2];
465
 
    it[1] = ((guchar *) (cursor->pixels))[it - buf + 1];
466
 
    it[2] = ((guchar *) (cursor->pixels))[it - buf + 0];
467
 
    it[3] = ((guchar *) (cursor->pixels))[it - buf + 3];
468
 
#else
469
 
    /* on big endianess it's ARGB to RGBA */
470
 
    it[0] = ((guchar *) cursor->pixels)[it - buf + 1];
471
 
    it[1] = ((guchar *) cursor->pixels)[it - buf + 2];
472
 
    it[2] = ((guchar *) cursor->pixels)[it - buf + 3];
473
 
    it[3] = ((guchar *) cursor->pixels)[it - buf + 0];
474
 
#endif
475
 
  }
476
 
 
477
 
  pixbuf = gdk_pixbuf_new_from_data ((const guchar *) buf,
478
 
                        GDK_COLORSPACE_RGB, TRUE, 8,
479
 
                        cursor->width, cursor->height,
480
 
                        cursor->width * 4,
481
 
                        (GdkPixbufDestroyNotify) g_free,
482
 
                        NULL);
483
 
 
484
 
  if (!pixbuf)
485
 
    g_free (buf);
486
 
 
487
 
  return pixbuf;
488
 
}
489
 
 
490
 
static GnomeThemeCursorInfo *
491
 
read_cursor_theme (GFile *cursor_theme_uri)
492
 
{
493
 
  GnomeThemeCursorInfo *cursor_theme_info = NULL;
494
 
  GFile *parent_uri, *cursors_uri;
495
 
 
496
 
  const gint filter_sizes[] = { 12, 16, 24, 32, 36, 40, 48, 64 };
497
 
  const gint num_sizes = G_N_ELEMENTS (filter_sizes);
498
 
 
499
 
  parent_uri = g_file_get_parent (cursor_theme_uri);
500
 
  cursors_uri = g_file_get_child (parent_uri, "cursors");
501
 
 
502
 
  if (get_file_type (cursors_uri) == G_FILE_TYPE_DIRECTORY) {
503
 
    GArray *sizes;
504
 
    XcursorImage *cursor;
505
 
    GdkPixbuf *thumbnail = NULL;
506
 
    gchar *name;
507
 
    gint i;
508
 
 
509
 
    name = g_file_get_basename (parent_uri);
510
 
 
511
 
    sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), num_sizes);
512
 
 
513
 
    for (i = 0; i < num_sizes; ++i) {
514
 
      cursor = XcursorLibraryLoadImage ("left_ptr", name, filter_sizes[i]);
515
 
 
516
 
      if (cursor) {
517
 
        if (cursor->size == filter_sizes[i]) {
518
 
          g_array_append_val (sizes, filter_sizes[i]);
519
 
 
520
 
          if (thumbnail == NULL && i >= 1)
521
 
            thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
522
 
        }
523
 
 
524
 
        XcursorImageDestroy (cursor);
525
 
      }
526
 
    }
527
 
 
528
 
    if (sizes->len == 0) {
529
 
      g_array_free (sizes, TRUE);
530
 
      g_free (name);
531
 
    } else {
532
 
      GnomeDesktopItem *cursor_theme_ditem;
533
 
      gchar *cursor_theme_file;
534
 
 
535
 
      if (!thumbnail) {
536
 
        cursor = XcursorLibraryLoadImage ("left_ptr", name,
537
 
                                          g_array_index (sizes, gint, 0));
538
 
        if (cursor) {
539
 
          thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
540
 
          XcursorImageDestroy (cursor);
541
 
        }
542
 
      }
543
 
 
544
 
      cursor_theme_info = gnome_theme_cursor_info_new ();
545
 
      cursor_theme_info->path = g_file_get_path (parent_uri);
546
 
      cursor_theme_info->name = name;
547
 
      cursor_theme_info->sizes = sizes;
548
 
      cursor_theme_info->thumbnail = thumbnail;
549
 
 
550
 
      cursor_theme_file = g_file_get_path (cursor_theme_uri);
551
 
      cursor_theme_ditem = gnome_desktop_item_new_from_file (cursor_theme_file, 0, NULL);
552
 
      g_free (cursor_theme_file);
553
 
 
554
 
      if (cursor_theme_ditem != NULL) {
555
 
        const gchar *readable_name;
556
 
 
557
 
        readable_name = gnome_desktop_item_get_string (cursor_theme_ditem,
558
 
                                                       "Icon Theme/Name");
559
 
        if (readable_name)
560
 
          cursor_theme_info->readable_name = g_strdup (readable_name);
561
 
        else
562
 
          cursor_theme_info->readable_name = g_strdup (name);
563
 
 
564
 
        cursor_theme_info->hidden = gnome_desktop_item_get_boolean (cursor_theme_ditem,
565
 
                                                                    "Icon Theme/Hidden");
566
 
 
567
 
        gnome_desktop_item_unref (cursor_theme_ditem);
568
 
      } else {
569
 
        cursor_theme_info->readable_name = g_strdup (name);
570
 
      }
571
 
    }
572
 
  }
573
 
 
574
 
  g_object_unref (cursors_uri);
575
 
  g_object_unref (parent_uri);
576
 
 
577
 
  return cursor_theme_info;
578
 
}
579
 
 
580
 
#else /* !HAVE_XCURSOR */
581
 
 
582
 
static gchar *
583
 
read_current_cursor_font (void)
584
 
{
585
 
  DIR *dir;
586
 
  gchar *dir_name;
587
 
  struct dirent *file_dirent;
588
 
 
589
 
  dir_name = g_build_filename (g_get_home_dir (), ".gnome2/share/cursor-fonts", NULL);
590
 
  if (! g_file_test (dir_name, G_FILE_TEST_EXISTS)) {
591
 
    g_free (dir_name);
592
 
    return NULL;
593
 
  }
594
 
 
595
 
  dir = opendir (dir_name);
596
 
 
597
 
  while ((file_dirent = readdir (dir)) != NULL) {
598
 
    struct stat st;
599
 
    gchar *link_name;
600
 
 
601
 
    link_name = g_build_filename (dir_name, file_dirent->d_name, NULL);
602
 
    if (lstat (link_name, &st)) {
603
 
      g_free (link_name);
604
 
      continue;
605
 
    }
606
 
 
607
 
    if (S_ISLNK (st.st_mode)) {
608
 
      gint length;
609
 
      gchar target[256];
610
 
 
611
 
      length = readlink (link_name, target, 255);
612
 
      if (length > 0) {
613
 
        gchar *retval;
614
 
        target[length] = '\0';
615
 
        retval = g_strdup (target);
616
 
        g_free (link_name);
617
 
        closedir (dir);
618
 
        return retval;
619
 
      }
620
 
 
621
 
    }
622
 
    g_free (link_name);
623
 
  }
624
 
  g_free (dir_name);
625
 
  closedir (dir);
626
 
  return NULL;
627
 
}
628
 
 
629
 
static void
630
 
read_cursor_fonts (void)
631
 
{
632
 
  gchar *cursor_font;
633
 
  gint i;
634
 
 
635
 
  const gchar *builtins[][4] = {
636
 
    {
637
 
      "gnome/cursor-fonts/cursor-normal.pcf",
638
 
      N_("Default Pointer"),
639
 
      N_("Default Pointer - Current"),
640
 
      "mouse-cursor-normal.png"
641
 
    }, {
642
 
      "gnome/cursor-fonts/cursor-white.pcf",
643
 
      N_("White Pointer"),
644
 
      N_("White Pointer - Current"),
645
 
      "mouse-cursor-white.png"
646
 
    }, {
647
 
      "gnome/cursor-fonts/cursor-large.pcf",
648
 
      N_("Large Pointer"),
649
 
      N_("Large Pointer - Current"),
650
 
      "mouse-cursor-normal-large.png"
651
 
    }, {
652
 
      "gnome/cursor-fonts/cursor-large-white.pcf",
653
 
      N_("Large White Pointer - Current"),
654
 
      N_("Large White Pointer"),
655
 
      "mouse-cursor-white-large.png"
656
 
    }
657
 
  };
658
 
 
659
 
  cursor_font = read_current_cursor_font();
660
 
 
661
 
  if (!cursor_font)
662
 
    cursor_font = g_strdup (builtins[0][0]);
663
 
 
664
 
  for (i = 0; i < G_N_ELEMENTS (builtins); i++) {
665
 
    GnomeThemeCursorInfo *theme_info;
666
 
    gchar *filename;
667
 
 
668
 
    theme_info = gnome_theme_cursor_info_new ();
669
 
 
670
 
    filename = g_build_filename (GNOMECC_DATA_DIR, "pixmaps", builtins[i][3], NULL);
671
 
    theme_info->thumbnail = gdk_pixbuf_new_from_file (filename, NULL);
672
 
    g_free (filename);
673
 
 
674
 
    theme_info->path = g_build_filename (GNOMECC_DATA_DIR, builtins[i][0], NULL);
675
 
    theme_info->name = g_strdup (theme_info->path);
676
 
 
677
 
    if (!strcmp (theme_info->path, cursor_font))
678
 
      theme_info->readable_name = g_strdup (_(builtins[i][2]));
679
 
    else
680
 
      theme_info->readable_name = g_strdup (_(builtins[i][1]));
681
 
 
682
 
    g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
683
 
    add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
684
 
  }
685
 
 
686
 
  g_free (cursor_font);
687
 
}
688
 
#endif /* HAVE_XCURSOR */
689
 
 
690
 
static void
691
 
handle_change_signal (gpointer             data,
692
 
                      GnomeThemeChangeType change_type,
693
 
                      GnomeThemeElement    element_type)
694
 
{
695
 
#ifdef DEBUG
696
 
  gchar *type_str = NULL;
697
 
  gchar *change_str = NULL;
698
 
  gchar *element_str = NULL;
699
 
#endif
700
 
  GnomeThemeCommonInfo *theme = data;
701
 
  GList *list;
702
 
 
703
 
  if (initting)
704
 
    return;
705
 
 
706
 
  for (list = callbacks; list; list = list->next) {
707
 
    ThemeCallbackData *callback_data = list->data;
708
 
    (* callback_data->func) (theme, change_type, element_type, callback_data->data);
709
 
  }
710
 
 
711
 
#ifdef DEBUG
712
 
  if (theme->type == GNOME_THEME_TYPE_METATHEME)
713
 
    type_str = "meta";
714
 
  else if (theme->type == GNOME_THEME_TYPE_ICON)
715
 
    type_str = "icon";
716
 
  else if (theme->type == GNOME_THEME_TYPE_CURSOR)
717
 
    type_str = "cursor";
718
 
  else if (theme->type == GNOME_THEME_TYPE_REGULAR) {
719
 
    if (element_type & GNOME_THEME_GTK_2)
720
 
      element_str = "gtk-2";
721
 
    else if (element_type & GNOME_THEME_GTK_2_KEYBINDING)
722
 
      element_str = "keybinding";
723
 
    else if (element_type & GNOME_THEME_METACITY)
724
 
      element_str = "metacity";
725
 
  }
726
 
 
727
 
  if (change_type == GNOME_THEME_CHANGE_CREATED)
728
 
    change_str = "created";
729
 
  else if (change_type == GNOME_THEME_CHANGE_CHANGED)
730
 
    change_str = "changed";
731
 
  else if (change_type == GNOME_THEME_CHANGE_DELETED)
732
 
    change_str = "deleted";
733
 
 
734
 
  if (type == GNOME_THEME_TYPE_REGULAR) {
735
 
    g_print ("theme \"%s\" has a theme of type %s (priority %d) has been %s\n",
736
 
             theme->name,
737
 
             element_str,
738
 
             theme->priority,
739
 
             type_str);
740
 
  } else if (type_str != NULL) {
741
 
    g_print ("%s theme \"%s\" (priority %d) has been %s\n",
742
 
             type_str,
743
 
             theme->name,
744
 
             theme->priority,
745
 
             type_str);
746
 
    }
747
 
#endif
748
 
}
749
 
 
750
 
/* index_uri should point to the gtkrc file that was modified */
751
 
static void
752
 
update_theme_index (GFile            *index_uri,
753
 
                    GnomeThemeElement key_element,
754
 
                    gint              priority)
755
 
{
756
 
  gboolean theme_exists;
757
 
  GnomeThemeInfo *theme_info;
758
 
  GFile *parent;
759
 
  GFile *common_theme_dir_uri;
760
 
  gchar *common_theme_dir;
761
 
 
762
 
  /* First, we determine the new state of the file.  We do no more
763
 
   * sophisticated a test than "files exists and is a file" */
764
 
  theme_exists = (get_file_type (index_uri) == G_FILE_TYPE_REGULAR);
765
 
 
766
 
  /* Next, we see what currently exists */
767
 
  parent = g_file_get_parent (index_uri);
768
 
  common_theme_dir_uri = g_file_get_parent (parent);
769
 
  common_theme_dir = g_file_get_path (common_theme_dir_uri);
770
 
 
771
 
  theme_info = g_hash_table_lookup (theme_hash_by_uri, common_theme_dir);
772
 
  if (theme_info == NULL) {
773
 
    if (theme_exists) {
774
 
      theme_info = gnome_theme_info_new ();
775
 
      theme_info->path = g_strdup (common_theme_dir);
776
 
      theme_info->name = g_file_get_basename (common_theme_dir_uri);
777
 
      theme_info->readable_name = g_strdup (theme_info->name);
778
 
      theme_info->priority = priority;
779
 
      if (key_element & GNOME_THEME_GTK_2)
780
 
        theme_info->has_gtk = TRUE;
781
 
      else if (key_element & GNOME_THEME_GTK_2_KEYBINDING)
782
 
        theme_info->has_keybinding = TRUE;
783
 
      else if (key_element & GNOME_THEME_METACITY)
784
 
        theme_info->has_metacity = TRUE;
785
 
 
786
 
      g_hash_table_insert (theme_hash_by_uri, g_strdup (common_theme_dir), theme_info);
787
 
      add_theme_to_hash_by_name (theme_hash_by_name, theme_info);
788
 
      handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED, key_element);
789
 
    }
790
 
  } else {
791
 
    gboolean theme_used_to_exist = FALSE;
792
 
 
793
 
    if (key_element & GNOME_THEME_GTK_2) {
794
 
      theme_used_to_exist = theme_info->has_gtk;
795
 
      theme_info->has_gtk = theme_exists;
796
 
    } else if (key_element & GNOME_THEME_GTK_2_KEYBINDING) {
797
 
      theme_used_to_exist = theme_info->has_keybinding;
798
 
      theme_info->has_keybinding = theme_exists;
799
 
    } else if (key_element & GNOME_THEME_METACITY) {
800
 
      theme_used_to_exist = theme_info->has_metacity;
801
 
      theme_info->has_metacity = theme_exists;
802
 
    }
803
 
 
804
 
    if (!theme_info->has_metacity && !theme_info->has_keybinding && !theme_info->has_gtk) {
805
 
      g_hash_table_remove (theme_hash_by_uri, common_theme_dir);
806
 
      remove_theme_from_hash_by_name (theme_hash_by_name, theme_info);
807
 
    }
808
 
 
809
 
    if (theme_exists && theme_used_to_exist) {
810
 
      handle_change_signal (theme_info, GNOME_THEME_CHANGE_CHANGED, key_element);
811
 
    } else if (theme_exists && !theme_used_to_exist) {
812
 
      handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED, key_element);
813
 
    } else if (!theme_exists && theme_used_to_exist) {
814
 
      handle_change_signal (theme_info, GNOME_THEME_CHANGE_DELETED, key_element);
815
 
    }
816
 
 
817
 
    if (!theme_info->has_metacity && !theme_info->has_keybinding && !theme_info->has_gtk) {
818
 
      gnome_theme_info_free (theme_info);
819
 
    }
820
 
  }
821
 
 
822
 
  g_free (common_theme_dir);
823
 
  g_object_unref (parent);
824
 
  g_object_unref (common_theme_dir_uri);
825
 
}
826
 
 
827
 
static void
828
 
update_gtk2_index (GFile *gtk2_index_uri,
829
 
                   gint   priority)
830
 
{
831
 
  update_theme_index (gtk2_index_uri, GNOME_THEME_GTK_2, priority);
832
 
}
833
 
 
834
 
static void
835
 
update_keybinding_index (GFile *keybinding_index_uri,
836
 
                         gint   priority)
837
 
{
838
 
  update_theme_index (keybinding_index_uri, GNOME_THEME_GTK_2_KEYBINDING, priority);
839
 
}
840
 
 
841
 
static void
842
 
update_metacity_index (GFile *metacity_index_uri,
843
 
                       gint   priority)
844
 
{
845
 
  update_theme_index (metacity_index_uri, GNOME_THEME_METACITY, priority);
846
 
}
847
 
 
848
 
static void
849
 
update_common_theme_dir_index (GFile         *theme_index_uri,
850
 
                               GnomeThemeType type,
851
 
                               gint           priority)
852
 
{
853
 
  gboolean theme_exists;
854
 
  GnomeThemeCommonInfo *theme_info = NULL;
855
 
  GnomeThemeCommonInfo *old_theme_info;
856
 
  GFile *common_theme_dir_uri;
857
 
  gchar *common_theme_dir;
858
 
  GHashTable *hash_by_uri;
859
 
  GHashTable *hash_by_name;
860
 
 
861
 
  if (type == GNOME_THEME_TYPE_ICON) {
862
 
    hash_by_uri = icon_theme_hash_by_uri;
863
 
    hash_by_name = icon_theme_hash_by_name;
864
 
  } else if (type == GNOME_THEME_TYPE_CURSOR) {
865
 
    hash_by_uri = cursor_theme_hash_by_uri;
866
 
    hash_by_name = cursor_theme_hash_by_name;
867
 
  } else {
868
 
    hash_by_uri = meta_theme_hash_by_uri;
869
 
    hash_by_name = meta_theme_hash_by_name;
870
 
  }
871
 
 
872
 
  if (type != GNOME_THEME_TYPE_CURSOR) {
873
 
    /* First, we determine the new state of the file. */
874
 
    if (get_file_type (theme_index_uri) == G_FILE_TYPE_REGULAR) {
875
 
      /* It's an interesting file. Let's try to load it. */
876
 
      if (type == GNOME_THEME_TYPE_ICON)
877
 
        theme_info = (GnomeThemeCommonInfo *) read_icon_theme (theme_index_uri);
878
 
      else
879
 
        theme_info = (GnomeThemeCommonInfo *) gnome_theme_read_meta_theme (theme_index_uri);
880
 
    } else {
881
 
      theme_info = NULL;
882
 
    }
883
 
 
884
 
  }
885
 
#ifdef HAVE_XCURSOR
886
 
  /* cursor themes don't necessarily have an index file, so try those in any case */
887
 
  else {
888
 
    theme_info = (GnomeThemeCommonInfo *) read_cursor_theme (theme_index_uri);
889
 
  }
890
 
#endif
891
 
 
892
 
  if (theme_info) {
893
 
    theme_info->priority = priority;
894
 
    theme_exists = TRUE;
895
 
  } else {
896
 
    theme_exists = FALSE;
897
 
  }
898
 
 
899
 
  /* Next, we see what currently exists */
900
 
  common_theme_dir_uri = g_file_get_parent (theme_index_uri);
901
 
  common_theme_dir = g_file_get_path (common_theme_dir_uri);
902
 
  g_object_unref (common_theme_dir_uri);
903
 
 
904
 
  old_theme_info = (GnomeThemeCommonInfo *) g_hash_table_lookup (hash_by_uri, common_theme_dir);
905
 
 
906
 
  if (old_theme_info == NULL) {
907
 
    if (theme_exists) {
908
 
      g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
909
 
      add_theme_to_hash_by_name (hash_by_name, theme_info);
910
 
      handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED, 0);
911
 
    }
912
 
  } else {
913
 
    if (theme_exists) {
914
 
      if (theme_compare (theme_info, old_theme_info) != 0) {
915
 
        /* Remove old theme */
916
 
        g_hash_table_remove (hash_by_uri, common_theme_dir);
917
 
        remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
918
 
        g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
919
 
        add_theme_to_hash_by_name (hash_by_name, theme_info);
920
 
        handle_change_signal (theme_info, GNOME_THEME_CHANGE_CHANGED, 0);
921
 
        theme_free (old_theme_info);
922
 
      } else {
923
 
        theme_free (theme_info);
924
 
      }
925
 
    } else {
926
 
      g_hash_table_remove (hash_by_uri, common_theme_dir);
927
 
      remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
928
 
 
929
 
      handle_change_signal (old_theme_info, GNOME_THEME_CHANGE_DELETED, 0);
930
 
      theme_free (old_theme_info);
931
 
    }
932
 
  }
933
 
 
934
 
  g_free (common_theme_dir);
935
 
}
936
 
 
937
 
static void
938
 
update_meta_theme_index (GFile *meta_theme_index_uri,
939
 
                         gint   priority)
940
 
{
941
 
  update_common_theme_dir_index (meta_theme_index_uri, GNOME_THEME_TYPE_METATHEME, priority);
942
 
}
943
 
 
944
 
static void
945
 
update_icon_theme_index (GFile *icon_theme_index_uri,
946
 
                         gint   priority)
947
 
{
948
 
  update_common_theme_dir_index (icon_theme_index_uri, GNOME_THEME_TYPE_ICON, priority);
949
 
}
950
 
 
951
 
static void
952
 
update_cursor_theme_index (GFile *cursor_theme_index_uri,
953
 
                           gint   priority)
954
 
{
955
 
#ifdef HAVE_XCURSOR
956
 
  update_common_theme_dir_index (cursor_theme_index_uri, GNOME_THEME_TYPE_CURSOR, priority);
957
 
#endif
958
 
}
959
 
 
960
 
static void
961
 
gtk2_dir_changed (GFileMonitor              *monitor,
962
 
                  GFile                     *file,
963
 
                  GFile                     *other_file,
964
 
                  GFileMonitorEvent          event_type,
965
 
                  CommonThemeDirMonitorData *monitor_data)
966
 
{
967
 
  gchar *affected_file;
968
 
 
969
 
  affected_file = g_file_get_basename (file);
970
 
 
971
 
  /* The only file we care about is gtkrc */
972
 
  if (!strcmp (affected_file, "gtkrc")) {
973
 
    update_gtk2_index (file, monitor_data->priority);
974
 
  }
975
 
 
976
 
  g_free (affected_file);
977
 
}
978
 
 
979
 
static void
980
 
keybinding_dir_changed (GFileMonitor              *monitor,
981
 
                        GFile                     *file,
982
 
                        GFile                     *other_file,
983
 
                        GFileMonitorEvent          event_type,
984
 
                        CommonThemeDirMonitorData *monitor_data)
985
 
{
986
 
  gchar *affected_file;
987
 
 
988
 
  affected_file = g_file_get_basename (file);
989
 
 
990
 
  /* The only file we care about is gtkrc */
991
 
  if (!strcmp (affected_file, "gtkrc")) {
992
 
    update_keybinding_index (file, monitor_data->priority);
993
 
  }
994
 
 
995
 
  g_free (affected_file);
996
 
}
997
 
 
998
 
static void
999
 
metacity_dir_changed (GFileMonitor              *monitor,
1000
 
                      GFile                     *file,
1001
 
                      GFile                     *other_file,
1002
 
                      GFileMonitorEvent          event_type,
1003
 
                      CommonThemeDirMonitorData *monitor_data)
1004
 
{
1005
 
  gchar *affected_file;
1006
 
 
1007
 
  affected_file = g_file_get_basename (file);
1008
 
 
1009
 
  /* The only file we care about is metacity-theme-1.xml */
1010
 
  if (!strcmp (affected_file, "metacity-theme-1.xml")) {
1011
 
    update_metacity_index (file, monitor_data->priority);
1012
 
  }
1013
 
 
1014
 
  g_free (affected_file);
1015
 
}
1016
 
 
1017
 
static void
1018
 
common_theme_dir_changed (GFileMonitor              *monitor,
1019
 
                          GFile                     *file,
1020
 
                          GFile                     *other_file,
1021
 
                          GFileMonitorEvent          event_type,
1022
 
                          CommonThemeDirMonitorData *monitor_data)
1023
 
{
1024
 
  gchar *affected_file;
1025
 
 
1026
 
  affected_file = g_file_get_basename (file);
1027
 
 
1028
 
  /* The only file we care about is index.theme */
1029
 
  if (!strcmp (affected_file, "index.theme")) {
1030
 
    update_meta_theme_index (file, monitor_data->priority);
1031
 
  }
1032
 
 
1033
 
  g_free (affected_file);
1034
 
}
1035
 
 
1036
 
static void
1037
 
common_icon_theme_dir_changed (GFileMonitor                  *monitor,
1038
 
                               GFile                         *file,
1039
 
                               GFile                         *other_file,
1040
 
                               GFileMonitorEvent              event_type,
1041
 
                               CommonIconThemeDirMonitorData *monitor_data)
1042
 
{
1043
 
  gchar *affected_file;
1044
 
 
1045
 
  affected_file = g_file_get_basename (file);
1046
 
 
1047
 
  /* The only file we care about is index.theme */
1048
 
  if (!strcmp (affected_file, "index.theme")) {
1049
 
    update_icon_theme_index (file, monitor_data->priority);
1050
 
    update_cursor_theme_index (file, monitor_data->priority);
1051
 
  }
1052
 
  /* and the cursors subdir for cursor themes */
1053
 
  else if (!strcmp (affected_file, "cursors")) {
1054
 
    /* always call update_cursor_theme_index with the index.theme URI */
1055
 
    GFile *parent, *index;
1056
 
 
1057
 
    parent = g_file_get_parent (file);
1058
 
    index = g_file_get_child (parent, "index.theme");
1059
 
    g_object_unref (parent);
1060
 
 
1061
 
    update_cursor_theme_index (index, monitor_data->priority);
1062
 
 
1063
 
    g_object_unref (index);
1064
 
  }
1065
 
 
1066
 
  g_free (affected_file);
1067
 
}
1068
 
 
1069
 
/* Add a monitor to a common_theme_dir. */
1070
 
static gboolean
1071
 
add_common_theme_dir_monitor (GFile                      *theme_dir_uri,
1072
 
                              CommonThemeDirMonitorData  *monitor_data,
1073
 
                              GError                    **error)
1074
 
{
1075
 
  GFile *uri, *subdir;
1076
 
  GFileMonitor *monitor;
1077
 
 
1078
 
  uri = g_file_get_child (theme_dir_uri, "index.theme");
1079
 
  update_meta_theme_index (uri, monitor_data->priority);
1080
 
  g_object_unref (uri);
1081
 
 
1082
 
  /* Add the handle for this directory */
1083
 
  monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
1084
 
  if (monitor == NULL)
1085
 
    return FALSE;
1086
 
 
1087
 
  g_signal_connect (monitor, "changed",
1088
 
                    (GCallback) common_theme_dir_changed, monitor_data);
1089
 
 
1090
 
  monitor_data->common_theme_dir_handle = monitor;
1091
 
 
1092
 
 
1093
 
  /* gtk-2 theme subdir */
1094
 
  subdir = g_file_get_child (theme_dir_uri, "gtk-2.0");
1095
 
  uri = g_file_get_child (subdir, "gtkrc");
1096
 
  if (g_file_query_exists (uri, NULL)) {
1097
 
    update_gtk2_index (uri, monitor_data->priority);
1098
 
  }
1099
 
  g_object_unref (uri);
1100
 
 
1101
 
  monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
1102
 
  if (monitor != NULL) {
1103
 
    g_signal_connect (monitor, "changed",
1104
 
                      (GCallback) gtk2_dir_changed, monitor_data);
1105
 
  }
1106
 
  monitor_data->gtk2_dir_handle = monitor;
1107
 
  g_object_unref (subdir);
1108
 
 
1109
 
  /* keybinding theme subdir */
1110
 
  subdir = g_file_get_child (theme_dir_uri, "gtk-2.0-key");
1111
 
  uri = g_file_get_child (subdir, "gtkrc");
1112
 
  if (g_file_query_exists (uri, NULL)) {
1113
 
    update_keybinding_index (uri, monitor_data->priority);
1114
 
  }
1115
 
  g_object_unref (uri);
1116
 
 
1117
 
  monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
1118
 
  if (monitor != NULL) {
1119
 
    g_signal_connect (monitor, "changed",
1120
 
                      (GCallback) keybinding_dir_changed, monitor_data);
1121
 
  }
1122
 
  monitor_data->keybinding_dir_handle = monitor;
1123
 
  g_object_unref (subdir);
1124
 
 
1125
 
  /* metacity theme subdir */
1126
 
  subdir = g_file_get_child (theme_dir_uri, "metacity-1");
1127
 
  uri = g_file_get_child (subdir, "metacity-theme-1.xml");
1128
 
  if (g_file_query_exists (uri, NULL)) {
1129
 
    update_metacity_index (uri, monitor_data->priority);
1130
 
  }
1131
 
  g_object_unref (uri);
1132
 
 
1133
 
  monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
1134
 
  if (monitor != NULL) {
1135
 
    g_signal_connect (monitor, "changed",
1136
 
                      (GCallback) metacity_dir_changed, monitor_data);
1137
 
  }
1138
 
  monitor_data->metacity_dir_handle = monitor;
1139
 
  g_object_unref (subdir);
1140
 
 
1141
 
  return TRUE;
1142
 
}
1143
 
 
1144
 
static gboolean
1145
 
add_common_icon_theme_dir_monitor (GFile                          *theme_dir_uri,
1146
 
                                   CommonIconThemeDirMonitorData  *monitor_data,
1147
 
                                   GError                        **error)
1148
 
{
1149
 
  GFile *index_uri;
1150
 
  GFileMonitor *monitor;
1151
 
 
1152
 
  /* Add the handle for this directory */
1153
 
  index_uri = g_file_get_child (theme_dir_uri, "index.theme");
1154
 
  update_icon_theme_index (index_uri, monitor_data->priority);
1155
 
  update_cursor_theme_index (index_uri, monitor_data->priority);
1156
 
  g_object_unref (index_uri);
1157
 
 
1158
 
  monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
1159
 
  if (monitor == NULL)
1160
 
    return FALSE;
1161
 
 
1162
 
  g_signal_connect (monitor, "changed",
1163
 
                    (GCallback) common_icon_theme_dir_changed, monitor_data);
1164
 
 
1165
 
  monitor_data->common_icon_theme_dir_handle = monitor;
1166
 
  return TRUE;
1167
 
}
1168
 
 
1169
 
static void
1170
 
remove_common_theme_dir_monitor (CommonThemeDirMonitorData *monitor_data)
1171
 
{
1172
 
  g_file_monitor_cancel (monitor_data->common_theme_dir_handle);
1173
 
  g_file_monitor_cancel (monitor_data->gtk2_dir_handle);
1174
 
  g_file_monitor_cancel (monitor_data->keybinding_dir_handle);
1175
 
  g_file_monitor_cancel (monitor_data->metacity_dir_handle);
1176
 
}
1177
 
 
1178
 
static void
1179
 
remove_common_icon_theme_dir_monitor (CommonIconThemeDirMonitorData *monitor_data)
1180
 
{
1181
 
  g_file_monitor_cancel (monitor_data->common_icon_theme_dir_handle);
1182
 
}
1183
 
 
1184
 
static void
1185
 
top_theme_dir_changed (GFileMonitor     *monitor,
1186
 
                       GFile            *file,
1187
 
                       GFile            *other_file,
1188
 
                       GFileMonitorEvent event_type,
1189
 
                       CallbackTuple    *tuple)
1190
 
{
1191
 
  GHashTable *handle_hash;
1192
 
  CommonThemeDirMonitorData *monitor_data;
1193
 
  gint priority;
1194
 
 
1195
 
  handle_hash = tuple->handle_hash;
1196
 
  priority = tuple->priority;
1197
 
 
1198
 
  if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
1199
 
    if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
1200
 
      monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
1201
 
      monitor_data->priority = priority;
1202
 
      add_common_theme_dir_monitor (file, monitor_data, NULL);
1203
 
      g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
1204
 
    }
1205
 
 
1206
 
  } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
1207
 
    gchar *name;
1208
 
 
1209
 
    name = g_file_get_basename (file);
1210
 
    monitor_data = g_hash_table_lookup (handle_hash, name);
1211
 
    if (monitor_data != NULL) {
1212
 
      remove_common_theme_dir_monitor (monitor_data);
1213
 
      g_hash_table_remove (handle_hash, name);
1214
 
    }
1215
 
    g_free (name);
1216
 
  }
1217
 
}
1218
 
 
1219
 
static void
1220
 
top_icon_theme_dir_changed (GFileMonitor     *monitor,
1221
 
                            GFile            *file,
1222
 
                            GFile            *other_file,
1223
 
                            GFileMonitorEvent event_type,
1224
 
                            CallbackTuple    *tuple)
1225
 
{
1226
 
  GHashTable *handle_hash;
1227
 
  CommonIconThemeDirMonitorData *monitor_data;
1228
 
  gint priority;
1229
 
 
1230
 
  handle_hash = tuple->handle_hash;
1231
 
  priority = tuple->priority;
1232
 
 
1233
 
  if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
1234
 
    if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
1235
 
      monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
1236
 
      monitor_data->priority = priority;
1237
 
      add_common_icon_theme_dir_monitor (file, monitor_data, NULL);
1238
 
      g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
1239
 
    }
1240
 
 
1241
 
  } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
1242
 
    gchar *name;
1243
 
 
1244
 
    name = g_file_get_basename (file);
1245
 
    monitor_data = g_hash_table_lookup (handle_hash, name);
1246
 
    if (monitor_data != NULL) {
1247
 
      remove_common_icon_theme_dir_monitor (monitor_data);
1248
 
      g_hash_table_remove (handle_hash, name);
1249
 
    }
1250
 
    g_free (name);
1251
 
  }
1252
 
}
1253
 
 
1254
 
/* Add a monitor to a top dir.  These monitors persist for the duration of the
1255
 
 * lib.
1256
 
 */
1257
 
static gboolean
1258
 
real_add_top_theme_dir_monitor (GFile    *uri,
1259
 
                                gint      priority,
1260
 
                                gboolean  icon_theme,
1261
 
                                GError  **error)
1262
 
{
1263
 
  GFileInfo *file_info;
1264
 
  GFileMonitor *monitor;
1265
 
  GFileEnumerator *enumerator;
1266
 
  CallbackTuple *tuple;
1267
 
 
1268
 
  /* Check the URI */
1269
 
  if (get_file_type (uri) != G_FILE_TYPE_DIRECTORY)
1270
 
    return FALSE;
1271
 
 
1272
 
  /* handle_hash is a hash of common_theme_dir names to their monitor_data.  We
1273
 
   * use it to remove the monitor handles when a dir is removed.
1274
 
   */
1275
 
  tuple = g_new (CallbackTuple, 1);
1276
 
  tuple->handle_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
1277
 
  tuple->priority = priority;
1278
 
 
1279
 
  /* Monitor the top directory */
1280
 
  monitor = g_file_monitor_directory (uri, G_FILE_MONITOR_NONE, NULL, NULL);
1281
 
  if (monitor != NULL) {
1282
 
    g_signal_connect (monitor, "changed",
1283
 
                      (GCallback) (icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed),
1284
 
                      tuple);
1285
 
  }
1286
 
 
1287
 
  /* Go through the directory to add monitoring */
1288
 
  enumerator = g_file_enumerate_children (uri,
1289
 
                                          G_FILE_ATTRIBUTE_STANDARD_TYPE ","
1290
 
                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
1291
 
                                          G_FILE_QUERY_INFO_NONE,
1292
 
                                          NULL, NULL);
1293
 
  if (enumerator == NULL)
1294
 
    return FALSE;
1295
 
 
1296
 
  while ((file_info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
1297
 
    GFileType type = g_file_info_get_file_type (file_info);
1298
 
 
1299
 
    if (type == G_FILE_TYPE_DIRECTORY || type == G_FILE_TYPE_SYMBOLIC_LINK) {
1300
 
      GFile *child;
1301
 
      const gchar *name;
1302
 
      gpointer data;
1303
 
 
1304
 
      /* Add the directory */
1305
 
      name = g_file_info_get_name (file_info);
1306
 
      child = g_file_get_child (uri, name);
1307
 
 
1308
 
      if (icon_theme) {
1309
 
        CommonIconThemeDirMonitorData *monitor_data;
1310
 
        monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
1311
 
        monitor_data->priority = priority;
1312
 
        add_common_icon_theme_dir_monitor (child, monitor_data, error);
1313
 
        data = monitor_data;
1314
 
      } else {
1315
 
        CommonThemeDirMonitorData *monitor_data;
1316
 
        monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
1317
 
        monitor_data->priority = priority;
1318
 
        add_common_theme_dir_monitor (child, monitor_data, error);
1319
 
        data = monitor_data;
1320
 
      }
1321
 
      g_object_unref (child);
1322
 
 
1323
 
      g_hash_table_insert (tuple->handle_hash, g_strdup (name), data);
1324
 
    }
1325
 
    g_object_unref (file_info);
1326
 
  }
1327
 
  g_file_enumerator_close (enumerator, NULL, NULL);
1328
 
 
1329
 
  return TRUE;
1330
 
}
1331
 
 
1332
 
static gboolean
1333
 
add_top_theme_dir_monitor (GFile   *uri,
1334
 
                           gint     priority,
1335
 
                           GError **error)
1336
 
{
1337
 
  return real_add_top_theme_dir_monitor (uri, priority, FALSE, error);
1338
 
}
1339
 
 
1340
 
static gboolean
1341
 
add_top_icon_theme_dir_monitor (GFile   *uri,
1342
 
                                gint     priority,
1343
 
                                GError **error)
1344
 
{
1345
 
  return real_add_top_theme_dir_monitor (uri, priority, TRUE, error);
1346
 
}
1347
 
 
1348
 
/* Public functions */
1349
 
 
1350
 
/* GTK/Metacity/keybinding Themes */
1351
 
GnomeThemeInfo *
1352
 
gnome_theme_info_new (void)
1353
 
{
1354
 
  GnomeThemeInfo *theme_info;
1355
 
 
1356
 
  theme_info = g_new0 (GnomeThemeInfo, 1);
1357
 
  theme_info->type = GNOME_THEME_TYPE_REGULAR;
1358
 
 
1359
 
  return theme_info;
1360
 
}
1361
 
 
1362
 
void
1363
 
gnome_theme_info_free (GnomeThemeInfo *theme_info)
1364
 
{
1365
 
  g_free (theme_info->path);
1366
 
  g_free (theme_info->name);
1367
 
  g_free (theme_info->readable_name);
1368
 
  g_free (theme_info);
1369
 
}
1370
 
 
1371
 
GnomeThemeInfo *
1372
 
gnome_theme_info_find (const gchar *theme_name)
1373
 
{
1374
 
  return (GnomeThemeInfo *)
1375
 
         get_theme_from_hash_by_name (theme_hash_by_name, theme_name, -1);
1376
 
}
1377
 
 
1378
 
struct GnomeThemeInfoHashData
1379
 
{
1380
 
  gconstpointer user_data;
1381
 
  GList *list;
1382
 
};
1383
 
 
1384
 
static void
1385
 
gnome_theme_info_find_by_type_helper (gpointer key,
1386
 
                                      GList *list,
1387
 
                                      struct GnomeThemeInfoHashData *hash_data)
1388
 
{
1389
 
  guint elements = GPOINTER_TO_INT (hash_data->user_data);
1390
 
 
1391
 
  do {
1392
 
    GnomeThemeInfo *theme_info = list->data;
1393
 
 
1394
 
    if ((elements & GNOME_THEME_METACITY && theme_info->has_metacity) ||
1395
 
        (elements & GNOME_THEME_GTK_2 && theme_info->has_gtk) ||
1396
 
        (elements & GNOME_THEME_GTK_2_KEYBINDING && theme_info->has_keybinding)) {
1397
 
      hash_data->list = g_list_prepend (hash_data->list, theme_info);
1398
 
      return;
1399
 
    }
1400
 
 
1401
 
    list = list->next;
1402
 
  } while (list);
1403
 
}
1404
 
 
1405
 
GList *
1406
 
gnome_theme_info_find_by_type (guint elements)
1407
 
{
1408
 
  struct GnomeThemeInfoHashData data;
1409
 
  data.user_data = GINT_TO_POINTER (elements);
1410
 
  data.list = NULL;
1411
 
 
1412
 
  g_hash_table_foreach (theme_hash_by_name,
1413
 
                        (GHFunc) gnome_theme_info_find_by_type_helper,
1414
 
                        &data);
1415
 
 
1416
 
  return data.list;
1417
 
}
1418
 
 
1419
 
static void
1420
 
gnome_theme_info_find_all_helper (const gchar *key,
1421
 
                                  GList *list,
1422
 
                                  GList **themes)
1423
 
{
1424
 
  /* only return visible themes */
1425
 
  if (!((GnomeThemeCommonInfo *) list->data)->hidden)
1426
 
    *themes = g_list_prepend (*themes, list->data);
1427
 
}
1428
 
 
1429
 
gchar *
1430
 
gtk_theme_info_missing_engine (const gchar *gtk_theme, gboolean nameOnly)
1431
 
{
1432
 
  gchar *engine = NULL;
1433
 
  gchar *gtkrc;
1434
 
 
1435
 
  gtkrc = gtkrc_find_named (gtk_theme);
1436
 
  if (gtkrc) {
1437
 
    GSList *engines = NULL, *l;
1438
 
    gboolean found;
1439
 
 
1440
 
    gtkrc_get_details (gtkrc, &engines, NULL);
1441
 
    g_free (gtkrc);
1442
 
 
1443
 
    for (l = engines; l; l = l->next) {
1444
 
      gchar *full = g_module_build_path (GTK_ENGINE_DIR, l->data);
1445
 
 
1446
 
      found = g_file_test (full, G_FILE_TEST_EXISTS);
1447
 
 
1448
 
      if (!found) {
1449
 
        if (nameOnly) {
1450
 
          engine = g_strdup (l->data);
1451
 
          g_free (full);
1452
 
        } else
1453
 
          engine = full;
1454
 
        break;
1455
 
      }
1456
 
 
1457
 
      g_free (full);
1458
 
    }
1459
 
 
1460
 
    g_slist_foreach (engines, (GFunc) g_free, NULL);
1461
 
    g_slist_free (engines);
1462
 
  }
1463
 
 
1464
 
  return engine;
1465
 
}
1466
 
 
1467
 
/* Icon themes */
1468
 
GnomeThemeIconInfo *
1469
 
gnome_theme_icon_info_new (void)
1470
 
{
1471
 
  GnomeThemeIconInfo *icon_theme_info;
1472
 
 
1473
 
  icon_theme_info = g_new0 (GnomeThemeIconInfo, 1);
1474
 
  icon_theme_info->type = GNOME_THEME_TYPE_ICON;
1475
 
 
1476
 
  return icon_theme_info;
1477
 
}
1478
 
 
1479
 
void
1480
 
gnome_theme_icon_info_free (GnomeThemeIconInfo *icon_theme_info)
1481
 
{
1482
 
  g_free (icon_theme_info->name);
1483
 
  g_free (icon_theme_info->readable_name);
1484
 
  g_free (icon_theme_info->path);
1485
 
  g_free (icon_theme_info);
1486
 
}
1487
 
 
1488
 
GnomeThemeIconInfo *
1489
 
gnome_theme_icon_info_find (const gchar *icon_theme_name)
1490
 
{
1491
 
  g_return_val_if_fail (icon_theme_name != NULL, NULL);
1492
 
 
1493
 
  return (GnomeThemeIconInfo *)
1494
 
         get_theme_from_hash_by_name (icon_theme_hash_by_name, icon_theme_name, -1);
1495
 
}
1496
 
 
1497
 
GList *
1498
 
gnome_theme_icon_info_find_all (void)
1499
 
{
1500
 
  GList *list = NULL;
1501
 
 
1502
 
  g_hash_table_foreach (icon_theme_hash_by_name,
1503
 
                        (GHFunc) gnome_theme_info_find_all_helper,
1504
 
                        &list);
1505
 
 
1506
 
  return list;
1507
 
}
1508
 
 
1509
 
gint
1510
 
gnome_theme_icon_info_compare (GnomeThemeIconInfo *a,
1511
 
                               GnomeThemeIconInfo *b)
1512
 
{
1513
 
  gint cmp;
1514
 
 
1515
 
  cmp = safe_strcmp (a->path, b->path);
1516
 
  if (cmp != 0) return cmp;
1517
 
 
1518
 
  return safe_strcmp (a->name, b->name);
1519
 
}
1520
 
 
1521
 
/* Cursor themes */
1522
 
GnomeThemeCursorInfo *
1523
 
gnome_theme_cursor_info_new (void)
1524
 
{
1525
 
  GnomeThemeCursorInfo *theme_info;
1526
 
 
1527
 
  theme_info = g_new0 (GnomeThemeCursorInfo, 1);
1528
 
  theme_info->type = GNOME_THEME_TYPE_CURSOR;
1529
 
 
1530
 
  return theme_info;
1531
 
}
1532
 
 
1533
 
void
1534
 
gnome_theme_cursor_info_free (GnomeThemeCursorInfo *cursor_theme_info)
1535
 
{
1536
 
  g_free (cursor_theme_info->name);
1537
 
  g_free (cursor_theme_info->readable_name);
1538
 
  g_free (cursor_theme_info->path);
1539
 
  g_array_free (cursor_theme_info->sizes, TRUE);
1540
 
  if (cursor_theme_info->thumbnail != NULL)
1541
 
    g_object_unref (cursor_theme_info->thumbnail);
1542
 
  g_free (cursor_theme_info);
1543
 
}
1544
 
 
1545
 
GnomeThemeCursorInfo *
1546
 
gnome_theme_cursor_info_find (const gchar *cursor_theme_name)
1547
 
{
1548
 
  g_return_val_if_fail (cursor_theme_name != NULL, NULL);
1549
 
 
1550
 
  return (GnomeThemeCursorInfo *)
1551
 
         get_theme_from_hash_by_name (cursor_theme_hash_by_name, cursor_theme_name, -1);
1552
 
}
1553
 
 
1554
 
GList *
1555
 
gnome_theme_cursor_info_find_all (void)
1556
 
{
1557
 
  GList *list = NULL;
1558
 
 
1559
 
  g_hash_table_foreach (cursor_theme_hash_by_name,
1560
 
                        (GHFunc) gnome_theme_info_find_all_helper,
1561
 
                        &list);
1562
 
 
1563
 
  return list;
1564
 
}
1565
 
 
1566
 
gint
1567
 
gnome_theme_cursor_info_compare (GnomeThemeCursorInfo *a,
1568
 
                                 GnomeThemeCursorInfo *b)
1569
 
{
1570
 
  gint cmp;
1571
 
 
1572
 
  cmp = safe_strcmp (a->path, b->path);
1573
 
  if (cmp != 0) return cmp;
1574
 
 
1575
 
  return safe_strcmp (a->name, b->name);
1576
 
}
1577
 
 
1578
 
/* Meta themes */
1579
 
GnomeThemeMetaInfo *
1580
 
gnome_theme_meta_info_new (void)
1581
 
{
1582
 
  GnomeThemeMetaInfo *theme_info;
1583
 
 
1584
 
  theme_info = g_new0 (GnomeThemeMetaInfo, 1);
1585
 
  theme_info->type = GNOME_THEME_TYPE_METATHEME;
1586
 
 
1587
 
  return theme_info;
1588
 
}
1589
 
 
1590
 
void
1591
 
gnome_theme_meta_info_free (GnomeThemeMetaInfo *meta_theme_info)
1592
 
{
1593
 
  g_free (meta_theme_info->path);
1594
 
  g_free (meta_theme_info->readable_name);
1595
 
  g_free (meta_theme_info->name);
1596
 
  g_free (meta_theme_info->comment);
1597
 
  g_free (meta_theme_info->application_font);
1598
 
  g_free (meta_theme_info->documents_font);
1599
 
  g_free (meta_theme_info->desktop_font);
1600
 
  g_free (meta_theme_info->windowtitle_font);
1601
 
  g_free (meta_theme_info->monospace_font);
1602
 
  g_free (meta_theme_info->background_image);
1603
 
  g_free (meta_theme_info->gtk_theme_name);
1604
 
  g_free (meta_theme_info->gtk_color_scheme);
1605
 
  g_free (meta_theme_info->icon_theme_name);
1606
 
  g_free (meta_theme_info->metacity_theme_name);
1607
 
  g_free (meta_theme_info->notification_theme_name);
1608
 
  g_free (meta_theme_info);
1609
 
}
1610
 
 
1611
 
gboolean
1612
 
gnome_theme_meta_info_validate (const GnomeThemeMetaInfo *info, GError **error)
1613
 
{
1614
 
  GnomeThemeInfo *theme;
1615
 
  gchar *engine;
1616
 
 
1617
 
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1618
 
 
1619
 
  theme = gnome_theme_info_find (info->gtk_theme_name);
1620
 
  if (!theme || !theme->has_gtk) {
1621
 
    g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_GTK_THEME_NOT_AVAILABLE,
1622
 
                 _("This theme will not look as intended because the required GTK+ theme '%s' is not installed."),
1623
 
                 info->gtk_theme_name);
1624
 
    return FALSE;
1625
 
  }
1626
 
 
1627
 
  theme = gnome_theme_info_find (info->metacity_theme_name);
1628
 
  if (!theme || !theme->has_metacity) {
1629
 
    g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_WM_THEME_NOT_AVAILABLE,
1630
 
                 _("This theme will not look as intended because the required window manager theme '%s' is not installed."),
1631
 
                 info->metacity_theme_name);
1632
 
    return FALSE;
1633
 
  }
1634
 
 
1635
 
  if (!gnome_theme_icon_info_find (info->icon_theme_name)) {
1636
 
    g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_ICON_THEME_NOT_AVAILABLE,
1637
 
                 _("This theme will not look as intended because the required icon theme '%s' is not installed."),
1638
 
                 info->icon_theme_name);
1639
 
    return FALSE;
1640
 
  }
1641
 
 
1642
 
  /* check for gtk theme engines */
1643
 
  engine = gtk_theme_info_missing_engine (info->gtk_theme_name, TRUE);
1644
 
  if (engine != NULL) {
1645
 
    g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE,
1646
 
                 _("This theme will not look as intended because the required GTK+ theme engine '%s' is not installed."),
1647
 
                 engine);
1648
 
    g_free (engine);
1649
 
    return FALSE;
1650
 
  }
1651
 
 
1652
 
  return TRUE;
1653
 
}
1654
 
 
1655
 
GnomeThemeMetaInfo *
1656
 
gnome_theme_meta_info_find (const char *meta_theme_name)
1657
 
{
1658
 
  g_return_val_if_fail (meta_theme_name != NULL, NULL);
1659
 
 
1660
 
  return (GnomeThemeMetaInfo *)
1661
 
         get_theme_from_hash_by_name (meta_theme_hash_by_name, meta_theme_name, -1);
1662
 
}
1663
 
 
1664
 
GList *
1665
 
gnome_theme_meta_info_find_all (void)
1666
 
{
1667
 
  GList *list = NULL;
1668
 
 
1669
 
  g_hash_table_foreach (meta_theme_hash_by_name,
1670
 
                        (GHFunc) gnome_theme_info_find_all_helper,
1671
 
                        &list);
1672
 
 
1673
 
  return list;
1674
 
}
1675
 
 
1676
 
gint
1677
 
gnome_theme_meta_info_compare (GnomeThemeMetaInfo *a,
1678
 
                               GnomeThemeMetaInfo *b)
1679
 
{
1680
 
  gint cmp;
1681
 
 
1682
 
  cmp = safe_strcmp (a->path, b->path);
1683
 
  if (cmp != 0) return cmp;
1684
 
 
1685
 
  cmp = safe_strcmp (a->readable_name, b->readable_name);
1686
 
  if (cmp != 0) return cmp;
1687
 
 
1688
 
  cmp = safe_strcmp (a->name, b->name);
1689
 
  if (cmp != 0) return cmp;
1690
 
 
1691
 
  cmp = safe_strcmp (a->comment, b->comment);
1692
 
  if (cmp != 0) return cmp;
1693
 
 
1694
 
  cmp = safe_strcmp (a->icon_file, b->icon_file);
1695
 
  if (cmp != 0) return cmp;
1696
 
 
1697
 
  cmp = safe_strcmp (a->gtk_theme_name, b->gtk_theme_name);
1698
 
  if (cmp != 0) return cmp;
1699
 
 
1700
 
  cmp = safe_strcmp (a->gtk_color_scheme, b->gtk_color_scheme);
1701
 
  if (cmp != 0) return cmp;
1702
 
 
1703
 
  cmp = safe_strcmp (a->metacity_theme_name, b->metacity_theme_name);
1704
 
  if (cmp != 0) return cmp;
1705
 
 
1706
 
  cmp = safe_strcmp (a->icon_theme_name, b->icon_theme_name);
1707
 
  if (cmp != 0) return cmp;
1708
 
 
1709
 
  cmp = safe_strcmp (a->notification_theme_name, b->notification_theme_name);
1710
 
  if (cmp != 0) return cmp;
1711
 
 
1712
 
  cmp = safe_strcmp (a->sound_theme_name, b->sound_theme_name);
1713
 
  if (cmp != 0) return cmp;
1714
 
 
1715
 
  cmp = safe_strcmp (a->application_font, b->application_font);
1716
 
  if (cmp != 0) return cmp;
1717
 
 
1718
 
  cmp = safe_strcmp (a->documents_font, b->documents_font);
1719
 
  if (cmp != 0) return cmp;
1720
 
 
1721
 
  cmp = safe_strcmp (a->desktop_font, b->desktop_font);
1722
 
  if (cmp != 0) return cmp;
1723
 
 
1724
 
  cmp = safe_strcmp (a->windowtitle_font, b->windowtitle_font);
1725
 
  if (cmp != 0) return cmp;
1726
 
 
1727
 
  cmp = safe_strcmp (a->monospace_font, b->monospace_font);
1728
 
  if (cmp != 0) return cmp;
1729
 
 
1730
 
  return safe_strcmp (a->background_image, b->background_image);
1731
 
}
1732
 
 
1733
 
void
1734
 
gnome_theme_info_register_theme_change (ThemeChangedCallback func,
1735
 
                                        gpointer data)
1736
 
{
1737
 
  ThemeCallbackData *callback_data;
1738
 
 
1739
 
  g_return_if_fail (func != NULL);
1740
 
 
1741
 
  callback_data = g_new (ThemeCallbackData, 1);
1742
 
  callback_data->func = func;
1743
 
  callback_data->data = data;
1744
 
 
1745
 
  callbacks = g_list_prepend (callbacks, callback_data);
1746
 
}
1747
 
 
1748
 
gboolean
1749
 
gnome_theme_color_scheme_parse (const gchar *scheme, GdkColor *colors)
1750
 
{
1751
 
  gchar **color_scheme_strings, **color_scheme_pair, *current_string;
1752
 
  gint i;
1753
 
 
1754
 
  if (!scheme || !strcmp (scheme, ""))
1755
 
    return FALSE;
1756
 
 
1757
 
  /* initialise the array */
1758
 
  for (i = 0; i < NUM_SYMBOLIC_COLORS; i++)
1759
 
    colors[i].red = colors[i].green = colors[i].blue = 0;
1760
 
 
1761
 
  /* The color scheme string consists of name:color pairs, separated by
1762
 
   * newlines, so first we split the string up by new line */
1763
 
 
1764
 
  color_scheme_strings = g_strsplit (scheme, "\n", 0);
1765
 
 
1766
 
  /* loop through the name:color pairs, and save the color if we recognise the name */
1767
 
  i = 0;
1768
 
  while ((current_string = color_scheme_strings[i++])) {
1769
 
    color_scheme_pair = g_strsplit (current_string, ":", 0);
1770
 
 
1771
 
    if (color_scheme_pair[0] != NULL && color_scheme_pair[1] != NULL) {
1772
 
      g_strstrip (color_scheme_pair[0]);
1773
 
      g_strstrip (color_scheme_pair[1]);
1774
 
 
1775
 
      if (!strcmp ("fg_color", color_scheme_pair[0]))
1776
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_FG]);
1777
 
      else if (!strcmp ("bg_color", color_scheme_pair[0]))
1778
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BG]);
1779
 
      else if (!strcmp ("text_color", color_scheme_pair[0]))
1780
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TEXT]);
1781
 
      else if (!strcmp ("base_color", color_scheme_pair[0]))
1782
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BASE]);
1783
 
      else if (!strcmp ("selected_fg_color", color_scheme_pair[0]))
1784
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_FG]);
1785
 
      else if (!strcmp ("selected_bg_color", color_scheme_pair[0]))
1786
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_BG]);
1787
 
      else if (!strcmp ("tooltip_fg_color", color_scheme_pair[0]))
1788
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_FG]);
1789
 
      else if (!strcmp ("tooltip_bg_color", color_scheme_pair[0]))
1790
 
        gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_BG]);
1791
 
    }
1792
 
 
1793
 
    g_strfreev (color_scheme_pair);
1794
 
  }
1795
 
 
1796
 
  g_strfreev (color_scheme_strings);
1797
 
 
1798
 
  return TRUE;
1799
 
}
1800
 
 
1801
 
gboolean
1802
 
gnome_theme_color_scheme_equal (const gchar *s1, const gchar *s2)
1803
 
{
1804
 
  GdkColor c1[NUM_SYMBOLIC_COLORS], c2[NUM_SYMBOLIC_COLORS];
1805
 
  int i;
1806
 
 
1807
 
  if (!gnome_theme_color_scheme_parse (s1, c1) ||
1808
 
      !gnome_theme_color_scheme_parse (s2, c2))
1809
 
    return FALSE;
1810
 
 
1811
 
  for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
1812
 
    if (!gdk_color_equal (&c1[i], &c2[i]))
1813
 
      return FALSE;
1814
 
  }
1815
 
 
1816
 
  return TRUE;
1817
 
}
1818
 
 
1819
 
void
1820
 
gnome_theme_init ()
1821
 
{
1822
 
  GFile *top_theme_dir;
1823
 
  gchar *top_theme_dir_string;
1824
 
  static gboolean initted = FALSE;
1825
 
  gchar **search_path;
1826
 
  gint i, n;
1827
 
 
1828
 
  if (initted)
1829
 
    return;
1830
 
 
1831
 
  initting = TRUE;
1832
 
 
1833
 
  meta_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1834
 
  meta_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1835
 
  icon_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1836
 
  icon_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1837
 
  cursor_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1838
 
  cursor_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1839
 
  theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1840
 
  theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1841
 
 
1842
 
  /* Add all the toplevel theme dirs. */
1843
 
  /* $datadir/themes */
1844
 
  top_theme_dir_string = gtk_rc_get_theme_dir ();
1845
 
  top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1846
 
  g_free (top_theme_dir_string);
1847
 
  add_top_theme_dir_monitor (top_theme_dir, 1, NULL);
1848
 
  g_object_unref (top_theme_dir);
1849
 
 
1850
 
  /* ~/.themes */
1851
 
  top_theme_dir_string  = g_build_filename (g_get_home_dir (), ".themes", NULL);
1852
 
  top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1853
 
  g_free (top_theme_dir_string);
1854
 
  if (!g_file_query_exists (top_theme_dir, NULL))
1855
 
    g_file_make_directory (top_theme_dir, NULL, NULL);
1856
 
  add_top_theme_dir_monitor (top_theme_dir, 0, NULL);
1857
 
  g_object_unref (top_theme_dir);
1858
 
 
1859
 
  /* ~/.icons */
1860
 
  top_theme_dir_string = g_build_filename (g_get_home_dir (), ".icons", NULL);
1861
 
  top_theme_dir = g_file_new_for_path (top_theme_dir_string);
1862
 
  g_free (top_theme_dir_string);
1863
 
  if (!g_file_query_exists (top_theme_dir, NULL))
1864
 
    g_file_make_directory (top_theme_dir, NULL, NULL);
1865
 
  g_object_unref (top_theme_dir);
1866
 
 
1867
 
  /* icon theme search path */
1868
 
  gtk_icon_theme_get_search_path (gtk_icon_theme_get_default (), &search_path, &n);
1869
 
  for (i = 0; i < n; ++i) {
1870
 
    top_theme_dir = g_file_new_for_path (search_path[i]);
1871
 
    add_top_icon_theme_dir_monitor (top_theme_dir, i, NULL);
1872
 
    g_object_unref (top_theme_dir);
1873
 
  }
1874
 
  g_strfreev (search_path);
1875
 
 
1876
 
#ifdef XCURSOR_ICONDIR
1877
 
  /* if there's a separate xcursors dir, add that as well */
1878
 
  if (strcmp (XCURSOR_ICONDIR, top_theme_dir_string) &&
1879
 
      strcmp (XCURSOR_ICONDIR, "/usr/share/icons")) {
1880
 
    top_theme_dir = g_file_new_for_path (XCURSOR_ICONDIR);
1881
 
    add_top_icon_theme_dir_monitor (top_theme_dir, 1, NULL);
1882
 
    g_object_unref (top_theme_dir);
1883
 
  }
1884
 
#endif
1885
 
 
1886
 
#ifdef HAVE_XCURSOR
1887
 
  /* make sure we have the default theme */
1888
 
  if (!gnome_theme_cursor_info_find ("default"))
1889
 
    add_default_cursor_theme ();
1890
 
#else
1891
 
  /* If we don't have Xcursor, use the built-in cursor fonts instead */
1892
 
  read_cursor_fonts ();
1893
 
#endif
1894
 
 
1895
 
  /* done */
1896
 
  initted = TRUE;
1897
 
  initting = FALSE;
1898
 
}