8
#include <glib/gi18n.h>
14
#include <libgnome/gnome-desktop-item.h>
15
#include "gnome-theme-info.h"
16
#include "gtkrc-utils.h"
19
#include <X11/Xcursor/Xcursor.h>
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"
40
/* Terminology used in this lib:
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
49
typedef struct _ThemeCallbackData
51
ThemeChangedCallback func;
56
GFileMonitor *common_theme_dir_handle;
57
GFileMonitor *gtk2_dir_handle;
58
GFileMonitor *keybinding_dir_handle;
59
GFileMonitor *metacity_dir_handle;
61
} CommonThemeDirMonitorData;
64
GFileMonitor *common_icon_theme_dir_handle;
66
} CommonIconThemeDirMonitorData;
69
GHashTable *handle_hash;
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"
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
88
static GList *callbacks = NULL;
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;
100
/* private functions */
102
safe_strcmp (const gchar *a_str,
106
return strcmp (a_str, b_str);
108
return a_str - b_str;
112
get_file_type (GFile *file)
114
GFileType file_type = G_FILE_TYPE_UNKNOWN;
115
GFileInfo *file_info;
117
file_info = g_file_query_info (file,
118
G_FILE_ATTRIBUTE_STANDARD_TYPE,
119
G_FILE_QUERY_INFO_NONE,
121
if (file_info != NULL) {
122
file_type = g_file_info_get_file_type (file_info);
123
g_object_unref (file_info);
130
add_theme_to_hash_by_name (GHashTable *hash_table,
133
GnomeThemeCommonInfo *info = data;
136
list = g_hash_table_lookup (hash_table, info->name);
138
list = g_list_append (list, info);
140
GList *list_ptr = list;
141
gboolean added = FALSE;
146
theme_priority = ((GnomeThemeCommonInfo *) list_ptr->data)->priority;
148
if (theme_priority == info->priority) {
150
list_ptr->data = info;
153
} else if (theme_priority > info->priority) {
154
list = g_list_insert_before (list, list_ptr, info);
158
list_ptr = list_ptr->next;
161
list = g_list_append (list, info);
163
g_hash_table_insert (hash_table, g_strdup (info->name), list);
167
remove_theme_from_hash_by_name (GHashTable *hash_table,
170
GnomeThemeCommonInfo *info = data;
173
list = g_hash_table_lookup (hash_table, info->name);
175
list = g_list_remove (list, info);
177
g_hash_table_remove (hash_table, info->name);
179
g_hash_table_insert (hash_table, g_strdup (info->name), list);
182
static GnomeThemeCommonInfo *
183
get_theme_from_hash_by_name (GHashTable *hash_table,
189
list = g_hash_table_lookup (hash_table, name);
191
/* -1 implies return the first one */
192
if (priority == -1) {
193
return list ? list->data : NULL;
197
GnomeThemeCommonInfo *info = (GnomeThemeCommonInfo *) list->data;
199
if (info->priority == priority)
208
theme_compare (GnomeThemeCommonInfo *a,
209
GnomeThemeCommonInfo *b)
213
g_return_val_if_fail (a->type == b->type, a->type - b->type);
216
case GNOME_THEME_TYPE_METATHEME:
217
cmp = gnome_theme_meta_info_compare (
218
(GnomeThemeMetaInfo *) a, (GnomeThemeMetaInfo *) b);
220
case GNOME_THEME_TYPE_ICON:
221
cmp = gnome_theme_icon_info_compare (
222
(GnomeThemeIconInfo *) a, (GnomeThemeIconInfo *) b);
224
case GNOME_THEME_TYPE_CURSOR:
225
cmp = gnome_theme_cursor_info_compare (
226
(GnomeThemeCursorInfo *) a, (GnomeThemeCursorInfo *) b);
229
/* not supported at this time */
230
g_assert_not_reached ();
237
theme_free (GnomeThemeCommonInfo *info)
239
switch (info->type) {
240
case GNOME_THEME_TYPE_METATHEME:
241
gnome_theme_meta_info_free ((GnomeThemeMetaInfo *) info);
243
case GNOME_THEME_TYPE_ICON:
244
gnome_theme_icon_info_free ((GnomeThemeIconInfo *) info);
246
case GNOME_THEME_TYPE_REGULAR:
247
gnome_theme_info_free ((GnomeThemeInfo *) info);
249
case GNOME_THEME_TYPE_CURSOR:
250
gnome_theme_cursor_info_free ((GnomeThemeCursorInfo *) info);
253
g_assert_not_reached ();
258
gnome_theme_info_error_quark (void)
260
return g_quark_from_static_string ("gnome-theme-info-error-quark");
264
gnome_theme_read_meta_theme (GFile *meta_theme_uri)
266
GnomeThemeMetaInfo *meta_theme_info;
267
GFile *common_theme_dir_uri;
268
GnomeDesktopItem *meta_theme_ditem;
269
gchar *meta_theme_file;
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);
277
if (meta_theme_ditem == NULL)
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);
286
str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_NAME);
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);
295
meta_theme_info->readable_name = g_strdup (str);
297
str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_COMMENT);
299
str = gnome_desktop_item_get_localestring (meta_theme_ditem, GNOME_DESKTOP_ITEM_COMMENT);
301
meta_theme_info->comment = g_strdup (str);
303
str = gnome_desktop_item_get_string (meta_theme_ditem, GNOME_DESKTOP_ITEM_ICON);
305
meta_theme_info->icon_file = g_strdup (str);
307
str = gnome_desktop_item_get_string (meta_theme_ditem, GTK_THEME_KEY);
309
gnome_theme_meta_info_free (meta_theme_info);
312
meta_theme_info->gtk_theme_name = g_strdup (str);
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);
318
scheme = g_strdup (str);
320
if (scheme != NULL) {
321
meta_theme_info->gtk_color_scheme = scheme;
322
for (; *scheme != '\0'; scheme++)
327
str = gnome_desktop_item_get_string (meta_theme_ditem, METACITY_THEME_KEY);
329
gnome_theme_meta_info_free (meta_theme_info);
332
meta_theme_info->metacity_theme_name = g_strdup (str);
334
str = gnome_desktop_item_get_string (meta_theme_ditem, ICON_THEME_KEY);
336
gnome_theme_meta_info_free (meta_theme_info);
339
meta_theme_info->icon_theme_name = g_strdup (str);
341
str = gnome_desktop_item_get_string (meta_theme_ditem, NOTIFICATION_THEME_KEY);
343
meta_theme_info->notification_theme_name = g_strdup (str);
345
str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_THEME_KEY);
347
meta_theme_info->cursor_theme_name = g_strdup (str);
349
str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_SIZE_KEY);
351
meta_theme_info->cursor_size = (int) g_ascii_strtoll (str, NULL, 10);
353
meta_theme_info->cursor_size = 18;
355
meta_theme_info->cursor_theme_name = g_strdup ("default");
356
meta_theme_info->cursor_size = 18;
359
str = gnome_desktop_item_get_string (meta_theme_ditem, APPLICATION_FONT_KEY);
361
meta_theme_info->application_font = g_strdup (str);
363
str = gnome_desktop_item_get_string (meta_theme_ditem, DOCUMENTS_FONT_KEY);
365
meta_theme_info->documents_font = g_strdup (str);
367
str = gnome_desktop_item_get_string (meta_theme_ditem, DESKTOP_FONT_KEY);
369
meta_theme_info->desktop_font = g_strdup (str);
371
str = gnome_desktop_item_get_string (meta_theme_ditem, WINDOWTITLE_FONT_KEY);
373
meta_theme_info->windowtitle_font = g_strdup (str);
375
str = gnome_desktop_item_get_string (meta_theme_ditem, MONOSPACE_FONT_KEY);
377
meta_theme_info->monospace_font = g_strdup (str);
379
str = gnome_desktop_item_get_string (meta_theme_ditem, BACKGROUND_IMAGE_KEY);
381
meta_theme_info->background_image = g_strdup (str);
383
meta_theme_info->hidden = gnome_desktop_item_get_boolean (meta_theme_ditem,
386
gnome_desktop_item_unref (meta_theme_ditem);
388
return meta_theme_info;
391
static GnomeThemeIconInfo *
392
read_icon_theme (GFile *icon_theme_uri)
394
GnomeThemeIconInfo *icon_theme_info;
395
GnomeDesktopItem *icon_theme_ditem;
396
gchar *icon_theme_file;
399
const gchar *directories;
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);
405
if (icon_theme_ditem == NULL)
408
name = gnome_desktop_item_get_localestring (icon_theme_ditem, "Icon Theme/Name");
410
name = gnome_desktop_item_get_localestring (icon_theme_ditem, GNOME_DESKTOP_ITEM_NAME);
412
gnome_desktop_item_unref (icon_theme_ditem);
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);
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);
432
gnome_desktop_item_unref (icon_theme_ditem);
434
return icon_theme_info;
439
add_default_cursor_theme ()
441
GnomeThemeCursorInfo *theme_info;
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);
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);
454
gdk_pixbuf_from_xcursor_image (XcursorImage *cursor)
457
#define BUF_SIZE sizeof(guint32) * cursor->width * cursor->height
458
guchar *buf = g_malloc0 (BUF_SIZE);
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];
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];
477
pixbuf = gdk_pixbuf_new_from_data ((const guchar *) buf,
478
GDK_COLORSPACE_RGB, TRUE, 8,
479
cursor->width, cursor->height,
481
(GdkPixbufDestroyNotify) g_free,
490
static GnomeThemeCursorInfo *
491
read_cursor_theme (GFile *cursor_theme_uri)
493
GnomeThemeCursorInfo *cursor_theme_info = NULL;
494
GFile *parent_uri, *cursors_uri;
496
const gint filter_sizes[] = { 12, 16, 24, 32, 36, 40, 48, 64 };
497
const gint num_sizes = G_N_ELEMENTS (filter_sizes);
499
parent_uri = g_file_get_parent (cursor_theme_uri);
500
cursors_uri = g_file_get_child (parent_uri, "cursors");
502
if (get_file_type (cursors_uri) == G_FILE_TYPE_DIRECTORY) {
504
XcursorImage *cursor;
505
GdkPixbuf *thumbnail = NULL;
509
name = g_file_get_basename (parent_uri);
511
sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), num_sizes);
513
for (i = 0; i < num_sizes; ++i) {
514
cursor = XcursorLibraryLoadImage ("left_ptr", name, filter_sizes[i]);
517
if (cursor->size == filter_sizes[i]) {
518
g_array_append_val (sizes, filter_sizes[i]);
520
if (thumbnail == NULL && i >= 1)
521
thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
524
XcursorImageDestroy (cursor);
528
if (sizes->len == 0) {
529
g_array_free (sizes, TRUE);
532
GnomeDesktopItem *cursor_theme_ditem;
533
gchar *cursor_theme_file;
536
cursor = XcursorLibraryLoadImage ("left_ptr", name,
537
g_array_index (sizes, gint, 0));
539
thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
540
XcursorImageDestroy (cursor);
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;
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);
554
if (cursor_theme_ditem != NULL) {
555
const gchar *readable_name;
557
readable_name = gnome_desktop_item_get_string (cursor_theme_ditem,
560
cursor_theme_info->readable_name = g_strdup (readable_name);
562
cursor_theme_info->readable_name = g_strdup (name);
564
cursor_theme_info->hidden = gnome_desktop_item_get_boolean (cursor_theme_ditem,
565
"Icon Theme/Hidden");
567
gnome_desktop_item_unref (cursor_theme_ditem);
569
cursor_theme_info->readable_name = g_strdup (name);
574
g_object_unref (cursors_uri);
575
g_object_unref (parent_uri);
577
return cursor_theme_info;
580
#else /* !HAVE_XCURSOR */
583
read_current_cursor_font (void)
587
struct dirent *file_dirent;
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)) {
595
dir = opendir (dir_name);
597
while ((file_dirent = readdir (dir)) != NULL) {
601
link_name = g_build_filename (dir_name, file_dirent->d_name, NULL);
602
if (lstat (link_name, &st)) {
607
if (S_ISLNK (st.st_mode)) {
611
length = readlink (link_name, target, 255);
614
target[length] = '\0';
615
retval = g_strdup (target);
630
read_cursor_fonts (void)
635
const gchar *builtins[][4] = {
637
"gnome/cursor-fonts/cursor-normal.pcf",
638
N_("Default Pointer"),
639
N_("Default Pointer - Current"),
640
"mouse-cursor-normal.png"
642
"gnome/cursor-fonts/cursor-white.pcf",
644
N_("White Pointer - Current"),
645
"mouse-cursor-white.png"
647
"gnome/cursor-fonts/cursor-large.pcf",
649
N_("Large Pointer - Current"),
650
"mouse-cursor-normal-large.png"
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"
659
cursor_font = read_current_cursor_font();
662
cursor_font = g_strdup (builtins[0][0]);
664
for (i = 0; i < G_N_ELEMENTS (builtins); i++) {
665
GnomeThemeCursorInfo *theme_info;
668
theme_info = gnome_theme_cursor_info_new ();
670
filename = g_build_filename (GNOMECC_DATA_DIR, "pixmaps", builtins[i][3], NULL);
671
theme_info->thumbnail = gdk_pixbuf_new_from_file (filename, NULL);
674
theme_info->path = g_build_filename (GNOMECC_DATA_DIR, builtins[i][0], NULL);
675
theme_info->name = g_strdup (theme_info->path);
677
if (!strcmp (theme_info->path, cursor_font))
678
theme_info->readable_name = g_strdup (_(builtins[i][2]));
680
theme_info->readable_name = g_strdup (_(builtins[i][1]));
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);
686
g_free (cursor_font);
688
#endif /* HAVE_XCURSOR */
691
handle_change_signal (gpointer data,
692
GnomeThemeChangeType change_type,
693
GnomeThemeElement element_type)
696
gchar *type_str = NULL;
697
gchar *change_str = NULL;
698
gchar *element_str = NULL;
700
GnomeThemeCommonInfo *theme = data;
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);
712
if (theme->type == GNOME_THEME_TYPE_METATHEME)
714
else if (theme->type == GNOME_THEME_TYPE_ICON)
716
else if (theme->type == GNOME_THEME_TYPE_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";
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";
734
if (type == GNOME_THEME_TYPE_REGULAR) {
735
g_print ("theme \"%s\" has a theme of type %s (priority %d) has been %s\n",
740
} else if (type_str != NULL) {
741
g_print ("%s theme \"%s\" (priority %d) has been %s\n",
750
/* index_uri should point to the gtkrc file that was modified */
752
update_theme_index (GFile *index_uri,
753
GnomeThemeElement key_element,
756
gboolean theme_exists;
757
GnomeThemeInfo *theme_info;
759
GFile *common_theme_dir_uri;
760
gchar *common_theme_dir;
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);
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);
771
theme_info = g_hash_table_lookup (theme_hash_by_uri, common_theme_dir);
772
if (theme_info == NULL) {
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;
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);
791
gboolean theme_used_to_exist = FALSE;
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;
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);
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);
817
if (!theme_info->has_metacity && !theme_info->has_keybinding && !theme_info->has_gtk) {
818
gnome_theme_info_free (theme_info);
822
g_free (common_theme_dir);
823
g_object_unref (parent);
824
g_object_unref (common_theme_dir_uri);
828
update_gtk2_index (GFile *gtk2_index_uri,
831
update_theme_index (gtk2_index_uri, GNOME_THEME_GTK_2, priority);
835
update_keybinding_index (GFile *keybinding_index_uri,
838
update_theme_index (keybinding_index_uri, GNOME_THEME_GTK_2_KEYBINDING, priority);
842
update_metacity_index (GFile *metacity_index_uri,
845
update_theme_index (metacity_index_uri, GNOME_THEME_METACITY, priority);
849
update_common_theme_dir_index (GFile *theme_index_uri,
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;
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;
868
hash_by_uri = meta_theme_hash_by_uri;
869
hash_by_name = meta_theme_hash_by_name;
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);
879
theme_info = (GnomeThemeCommonInfo *) gnome_theme_read_meta_theme (theme_index_uri);
886
/* cursor themes don't necessarily have an index file, so try those in any case */
888
theme_info = (GnomeThemeCommonInfo *) read_cursor_theme (theme_index_uri);
893
theme_info->priority = priority;
896
theme_exists = FALSE;
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);
904
old_theme_info = (GnomeThemeCommonInfo *) g_hash_table_lookup (hash_by_uri, common_theme_dir);
906
if (old_theme_info == NULL) {
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);
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);
923
theme_free (theme_info);
926
g_hash_table_remove (hash_by_uri, common_theme_dir);
927
remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
929
handle_change_signal (old_theme_info, GNOME_THEME_CHANGE_DELETED, 0);
930
theme_free (old_theme_info);
934
g_free (common_theme_dir);
938
update_meta_theme_index (GFile *meta_theme_index_uri,
941
update_common_theme_dir_index (meta_theme_index_uri, GNOME_THEME_TYPE_METATHEME, priority);
945
update_icon_theme_index (GFile *icon_theme_index_uri,
948
update_common_theme_dir_index (icon_theme_index_uri, GNOME_THEME_TYPE_ICON, priority);
952
update_cursor_theme_index (GFile *cursor_theme_index_uri,
956
update_common_theme_dir_index (cursor_theme_index_uri, GNOME_THEME_TYPE_CURSOR, priority);
961
gtk2_dir_changed (GFileMonitor *monitor,
964
GFileMonitorEvent event_type,
965
CommonThemeDirMonitorData *monitor_data)
967
gchar *affected_file;
969
affected_file = g_file_get_basename (file);
971
/* The only file we care about is gtkrc */
972
if (!strcmp (affected_file, "gtkrc")) {
973
update_gtk2_index (file, monitor_data->priority);
976
g_free (affected_file);
980
keybinding_dir_changed (GFileMonitor *monitor,
983
GFileMonitorEvent event_type,
984
CommonThemeDirMonitorData *monitor_data)
986
gchar *affected_file;
988
affected_file = g_file_get_basename (file);
990
/* The only file we care about is gtkrc */
991
if (!strcmp (affected_file, "gtkrc")) {
992
update_keybinding_index (file, monitor_data->priority);
995
g_free (affected_file);
999
metacity_dir_changed (GFileMonitor *monitor,
1002
GFileMonitorEvent event_type,
1003
CommonThemeDirMonitorData *monitor_data)
1005
gchar *affected_file;
1007
affected_file = g_file_get_basename (file);
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);
1014
g_free (affected_file);
1018
common_theme_dir_changed (GFileMonitor *monitor,
1021
GFileMonitorEvent event_type,
1022
CommonThemeDirMonitorData *monitor_data)
1024
gchar *affected_file;
1026
affected_file = g_file_get_basename (file);
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);
1033
g_free (affected_file);
1037
common_icon_theme_dir_changed (GFileMonitor *monitor,
1040
GFileMonitorEvent event_type,
1041
CommonIconThemeDirMonitorData *monitor_data)
1043
gchar *affected_file;
1045
affected_file = g_file_get_basename (file);
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);
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;
1057
parent = g_file_get_parent (file);
1058
index = g_file_get_child (parent, "index.theme");
1059
g_object_unref (parent);
1061
update_cursor_theme_index (index, monitor_data->priority);
1063
g_object_unref (index);
1066
g_free (affected_file);
1069
/* Add a monitor to a common_theme_dir. */
1071
add_common_theme_dir_monitor (GFile *theme_dir_uri,
1072
CommonThemeDirMonitorData *monitor_data,
1075
GFile *uri, *subdir;
1076
GFileMonitor *monitor;
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);
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)
1087
g_signal_connect (monitor, "changed",
1088
(GCallback) common_theme_dir_changed, monitor_data);
1090
monitor_data->common_theme_dir_handle = monitor;
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);
1099
g_object_unref (uri);
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);
1106
monitor_data->gtk2_dir_handle = monitor;
1107
g_object_unref (subdir);
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);
1115
g_object_unref (uri);
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);
1122
monitor_data->keybinding_dir_handle = monitor;
1123
g_object_unref (subdir);
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);
1131
g_object_unref (uri);
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);
1138
monitor_data->metacity_dir_handle = monitor;
1139
g_object_unref (subdir);
1145
add_common_icon_theme_dir_monitor (GFile *theme_dir_uri,
1146
CommonIconThemeDirMonitorData *monitor_data,
1150
GFileMonitor *monitor;
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);
1158
monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
1159
if (monitor == NULL)
1162
g_signal_connect (monitor, "changed",
1163
(GCallback) common_icon_theme_dir_changed, monitor_data);
1165
monitor_data->common_icon_theme_dir_handle = monitor;
1170
remove_common_theme_dir_monitor (CommonThemeDirMonitorData *monitor_data)
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);
1179
remove_common_icon_theme_dir_monitor (CommonIconThemeDirMonitorData *monitor_data)
1181
g_file_monitor_cancel (monitor_data->common_icon_theme_dir_handle);
1185
top_theme_dir_changed (GFileMonitor *monitor,
1188
GFileMonitorEvent event_type,
1189
CallbackTuple *tuple)
1191
GHashTable *handle_hash;
1192
CommonThemeDirMonitorData *monitor_data;
1195
handle_hash = tuple->handle_hash;
1196
priority = tuple->priority;
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);
1206
} else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
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);
1220
top_icon_theme_dir_changed (GFileMonitor *monitor,
1223
GFileMonitorEvent event_type,
1224
CallbackTuple *tuple)
1226
GHashTable *handle_hash;
1227
CommonIconThemeDirMonitorData *monitor_data;
1230
handle_hash = tuple->handle_hash;
1231
priority = tuple->priority;
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);
1241
} else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
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);
1254
/* Add a monitor to a top dir. These monitors persist for the duration of the
1258
real_add_top_theme_dir_monitor (GFile *uri,
1260
gboolean icon_theme,
1263
GFileInfo *file_info;
1264
GFileMonitor *monitor;
1265
GFileEnumerator *enumerator;
1266
CallbackTuple *tuple;
1269
if (get_file_type (uri) != G_FILE_TYPE_DIRECTORY)
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.
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;
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),
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,
1293
if (enumerator == NULL)
1296
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
1297
GFileType type = g_file_info_get_file_type (file_info);
1299
if (type == G_FILE_TYPE_DIRECTORY || type == G_FILE_TYPE_SYMBOLIC_LINK) {
1304
/* Add the directory */
1305
name = g_file_info_get_name (file_info);
1306
child = g_file_get_child (uri, name);
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;
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;
1321
g_object_unref (child);
1323
g_hash_table_insert (tuple->handle_hash, g_strdup (name), data);
1325
g_object_unref (file_info);
1327
g_file_enumerator_close (enumerator, NULL, NULL);
1333
add_top_theme_dir_monitor (GFile *uri,
1337
return real_add_top_theme_dir_monitor (uri, priority, FALSE, error);
1341
add_top_icon_theme_dir_monitor (GFile *uri,
1345
return real_add_top_theme_dir_monitor (uri, priority, TRUE, error);
1348
/* Public functions */
1350
/* GTK/Metacity/keybinding Themes */
1352
gnome_theme_info_new (void)
1354
GnomeThemeInfo *theme_info;
1356
theme_info = g_new0 (GnomeThemeInfo, 1);
1357
theme_info->type = GNOME_THEME_TYPE_REGULAR;
1363
gnome_theme_info_free (GnomeThemeInfo *theme_info)
1365
g_free (theme_info->path);
1366
g_free (theme_info->name);
1367
g_free (theme_info->readable_name);
1368
g_free (theme_info);
1372
gnome_theme_info_find (const gchar *theme_name)
1374
return (GnomeThemeInfo *)
1375
get_theme_from_hash_by_name (theme_hash_by_name, theme_name, -1);
1378
struct GnomeThemeInfoHashData
1380
gconstpointer user_data;
1385
gnome_theme_info_find_by_type_helper (gpointer key,
1387
struct GnomeThemeInfoHashData *hash_data)
1389
guint elements = GPOINTER_TO_INT (hash_data->user_data);
1392
GnomeThemeInfo *theme_info = list->data;
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);
1406
gnome_theme_info_find_by_type (guint elements)
1408
struct GnomeThemeInfoHashData data;
1409
data.user_data = GINT_TO_POINTER (elements);
1412
g_hash_table_foreach (theme_hash_by_name,
1413
(GHFunc) gnome_theme_info_find_by_type_helper,
1420
gnome_theme_info_find_all_helper (const gchar *key,
1424
/* only return visible themes */
1425
if (!((GnomeThemeCommonInfo *) list->data)->hidden)
1426
*themes = g_list_prepend (*themes, list->data);
1430
gtk_theme_info_missing_engine (const gchar *gtk_theme, gboolean nameOnly)
1432
gchar *engine = NULL;
1435
gtkrc = gtkrc_find_named (gtk_theme);
1437
GSList *engines = NULL, *l;
1440
gtkrc_get_details (gtkrc, &engines, NULL);
1443
for (l = engines; l; l = l->next) {
1444
gchar *full = g_module_build_path (GTK_ENGINE_DIR, l->data);
1446
found = g_file_test (full, G_FILE_TEST_EXISTS);
1450
engine = g_strdup (l->data);
1460
g_slist_foreach (engines, (GFunc) g_free, NULL);
1461
g_slist_free (engines);
1468
GnomeThemeIconInfo *
1469
gnome_theme_icon_info_new (void)
1471
GnomeThemeIconInfo *icon_theme_info;
1473
icon_theme_info = g_new0 (GnomeThemeIconInfo, 1);
1474
icon_theme_info->type = GNOME_THEME_TYPE_ICON;
1476
return icon_theme_info;
1480
gnome_theme_icon_info_free (GnomeThemeIconInfo *icon_theme_info)
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);
1488
GnomeThemeIconInfo *
1489
gnome_theme_icon_info_find (const gchar *icon_theme_name)
1491
g_return_val_if_fail (icon_theme_name != NULL, NULL);
1493
return (GnomeThemeIconInfo *)
1494
get_theme_from_hash_by_name (icon_theme_hash_by_name, icon_theme_name, -1);
1498
gnome_theme_icon_info_find_all (void)
1502
g_hash_table_foreach (icon_theme_hash_by_name,
1503
(GHFunc) gnome_theme_info_find_all_helper,
1510
gnome_theme_icon_info_compare (GnomeThemeIconInfo *a,
1511
GnomeThemeIconInfo *b)
1515
cmp = safe_strcmp (a->path, b->path);
1516
if (cmp != 0) return cmp;
1518
return safe_strcmp (a->name, b->name);
1522
GnomeThemeCursorInfo *
1523
gnome_theme_cursor_info_new (void)
1525
GnomeThemeCursorInfo *theme_info;
1527
theme_info = g_new0 (GnomeThemeCursorInfo, 1);
1528
theme_info->type = GNOME_THEME_TYPE_CURSOR;
1534
gnome_theme_cursor_info_free (GnomeThemeCursorInfo *cursor_theme_info)
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);
1545
GnomeThemeCursorInfo *
1546
gnome_theme_cursor_info_find (const gchar *cursor_theme_name)
1548
g_return_val_if_fail (cursor_theme_name != NULL, NULL);
1550
return (GnomeThemeCursorInfo *)
1551
get_theme_from_hash_by_name (cursor_theme_hash_by_name, cursor_theme_name, -1);
1555
gnome_theme_cursor_info_find_all (void)
1559
g_hash_table_foreach (cursor_theme_hash_by_name,
1560
(GHFunc) gnome_theme_info_find_all_helper,
1567
gnome_theme_cursor_info_compare (GnomeThemeCursorInfo *a,
1568
GnomeThemeCursorInfo *b)
1572
cmp = safe_strcmp (a->path, b->path);
1573
if (cmp != 0) return cmp;
1575
return safe_strcmp (a->name, b->name);
1579
GnomeThemeMetaInfo *
1580
gnome_theme_meta_info_new (void)
1582
GnomeThemeMetaInfo *theme_info;
1584
theme_info = g_new0 (GnomeThemeMetaInfo, 1);
1585
theme_info->type = GNOME_THEME_TYPE_METATHEME;
1591
gnome_theme_meta_info_free (GnomeThemeMetaInfo *meta_theme_info)
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);
1612
gnome_theme_meta_info_validate (const GnomeThemeMetaInfo *info, GError **error)
1614
GnomeThemeInfo *theme;
1617
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
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);
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);
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);
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."),
1655
GnomeThemeMetaInfo *
1656
gnome_theme_meta_info_find (const char *meta_theme_name)
1658
g_return_val_if_fail (meta_theme_name != NULL, NULL);
1660
return (GnomeThemeMetaInfo *)
1661
get_theme_from_hash_by_name (meta_theme_hash_by_name, meta_theme_name, -1);
1665
gnome_theme_meta_info_find_all (void)
1669
g_hash_table_foreach (meta_theme_hash_by_name,
1670
(GHFunc) gnome_theme_info_find_all_helper,
1677
gnome_theme_meta_info_compare (GnomeThemeMetaInfo *a,
1678
GnomeThemeMetaInfo *b)
1682
cmp = safe_strcmp (a->path, b->path);
1683
if (cmp != 0) return cmp;
1685
cmp = safe_strcmp (a->readable_name, b->readable_name);
1686
if (cmp != 0) return cmp;
1688
cmp = safe_strcmp (a->name, b->name);
1689
if (cmp != 0) return cmp;
1691
cmp = safe_strcmp (a->comment, b->comment);
1692
if (cmp != 0) return cmp;
1694
cmp = safe_strcmp (a->icon_file, b->icon_file);
1695
if (cmp != 0) return cmp;
1697
cmp = safe_strcmp (a->gtk_theme_name, b->gtk_theme_name);
1698
if (cmp != 0) return cmp;
1700
cmp = safe_strcmp (a->gtk_color_scheme, b->gtk_color_scheme);
1701
if (cmp != 0) return cmp;
1703
cmp = safe_strcmp (a->metacity_theme_name, b->metacity_theme_name);
1704
if (cmp != 0) return cmp;
1706
cmp = safe_strcmp (a->icon_theme_name, b->icon_theme_name);
1707
if (cmp != 0) return cmp;
1709
cmp = safe_strcmp (a->notification_theme_name, b->notification_theme_name);
1710
if (cmp != 0) return cmp;
1712
cmp = safe_strcmp (a->sound_theme_name, b->sound_theme_name);
1713
if (cmp != 0) return cmp;
1715
cmp = safe_strcmp (a->application_font, b->application_font);
1716
if (cmp != 0) return cmp;
1718
cmp = safe_strcmp (a->documents_font, b->documents_font);
1719
if (cmp != 0) return cmp;
1721
cmp = safe_strcmp (a->desktop_font, b->desktop_font);
1722
if (cmp != 0) return cmp;
1724
cmp = safe_strcmp (a->windowtitle_font, b->windowtitle_font);
1725
if (cmp != 0) return cmp;
1727
cmp = safe_strcmp (a->monospace_font, b->monospace_font);
1728
if (cmp != 0) return cmp;
1730
return safe_strcmp (a->background_image, b->background_image);
1734
gnome_theme_info_register_theme_change (ThemeChangedCallback func,
1737
ThemeCallbackData *callback_data;
1739
g_return_if_fail (func != NULL);
1741
callback_data = g_new (ThemeCallbackData, 1);
1742
callback_data->func = func;
1743
callback_data->data = data;
1745
callbacks = g_list_prepend (callbacks, callback_data);
1749
gnome_theme_color_scheme_parse (const gchar *scheme, GdkColor *colors)
1751
gchar **color_scheme_strings, **color_scheme_pair, *current_string;
1754
if (!scheme || !strcmp (scheme, ""))
1757
/* initialise the array */
1758
for (i = 0; i < NUM_SYMBOLIC_COLORS; i++)
1759
colors[i].red = colors[i].green = colors[i].blue = 0;
1761
/* The color scheme string consists of name:color pairs, separated by
1762
* newlines, so first we split the string up by new line */
1764
color_scheme_strings = g_strsplit (scheme, "\n", 0);
1766
/* loop through the name:color pairs, and save the color if we recognise the name */
1768
while ((current_string = color_scheme_strings[i++])) {
1769
color_scheme_pair = g_strsplit (current_string, ":", 0);
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]);
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]);
1793
g_strfreev (color_scheme_pair);
1796
g_strfreev (color_scheme_strings);
1802
gnome_theme_color_scheme_equal (const gchar *s1, const gchar *s2)
1804
GdkColor c1[NUM_SYMBOLIC_COLORS], c2[NUM_SYMBOLIC_COLORS];
1807
if (!gnome_theme_color_scheme_parse (s1, c1) ||
1808
!gnome_theme_color_scheme_parse (s2, c2))
1811
for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
1812
if (!gdk_color_equal (&c1[i], &c2[i]))
1822
GFile *top_theme_dir;
1823
gchar *top_theme_dir_string;
1824
static gboolean initted = FALSE;
1825
gchar **search_path;
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);
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);
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);
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);
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);
1874
g_strfreev (search_path);
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);
1887
/* make sure we have the default theme */
1888
if (!gnome_theme_cursor_info_find ("default"))
1889
add_default_cursor_theme ();
1891
/* If we don't have Xcursor, use the built-in cursor fonts instead */
1892
read_cursor_fonts ();