2008-05-07 Jens Granseuer <jensgr@gmx.net> * gnome-theme-info.c: (gtk_theme_info_missing_engine), (gnome_theme_meta_info_validate): * gnome-theme-info.h: split out the check for the missing theme engine because we also need it for the packagekit support svn path=/trunk/; revision=8696
1895 lines
56 KiB
C
1895 lines
56 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include <glib/gi18n.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkx.h>
|
|
#include <gio/gio.h>
|
|
#include <string.h>
|
|
#include <libgnome/gnome-desktop-item.h>
|
|
#include "gnome-theme-info.h"
|
|
#include "gtkrc-utils.h"
|
|
|
|
#ifdef HAVE_XCURSOR
|
|
#include <X11/Xcursor/Xcursor.h>
|
|
#endif
|
|
|
|
#define THEME_NAME "X-GNOME-Metatheme/Name"
|
|
#define THEME_COMMENT "X-GNOME-Metatheme/Comment"
|
|
#define GTK_THEME_KEY "X-GNOME-Metatheme/GtkTheme"
|
|
#define GTK_COLOR_SCHEME_KEY "X-GNOME-Metatheme/GtkColorScheme"
|
|
#define METACITY_THEME_KEY "X-GNOME-Metatheme/MetacityTheme"
|
|
#define ICON_THEME_KEY "X-GNOME-Metatheme/IconTheme"
|
|
#define CURSOR_THEME_KEY "X-GNOME-Metatheme/CursorTheme"
|
|
#define CURSOR_SIZE_KEY "X-GNOME-Metatheme/CursorSize"
|
|
#define SOUND_THEME_KEY "X-GNOME-Metatheme/SoundTheme"
|
|
#define APPLICATION_FONT_KEY "X-GNOME-Metatheme/ApplicationFont"
|
|
#define DOCUMENTS_FONT_KEY "X-GNOME-Metatheme/DocumentsFont"
|
|
#define DESKTOP_FONT_KEY "X-GNOME-Metatheme/DesktopFont"
|
|
#define WINDOWTITLE_FONT_KEY "X-GNOME-Metatheme/WindowTitleFont"
|
|
#define MONOSPACE_FONT_KEY "X-GNOME-Metatheme/MonospaceFont"
|
|
#define BACKGROUND_IMAGE_KEY "X-GNOME-Metatheme/BackgroundImage"
|
|
|
|
/* Terminology used in this lib:
|
|
*
|
|
* /usr/share/themes, ~/.themes -- top_theme_dir
|
|
* top_theme_dir/theme_name/ -- common_theme_dir
|
|
* /usr/share/icons, ~/.icons -- top_icon_theme_dir
|
|
* top_icon_theme_dir/theme_name/ -- icon_common_theme_dir
|
|
*
|
|
*/
|
|
|
|
typedef struct _ThemeCallbackData
|
|
{
|
|
ThemeChangedCallback func;
|
|
gpointer data;
|
|
} ThemeCallbackData;
|
|
|
|
typedef struct {
|
|
GFileMonitor *common_theme_dir_handle;
|
|
GFileMonitor *gtk2_dir_handle;
|
|
GFileMonitor *keybinding_dir_handle;
|
|
GFileMonitor *metacity_dir_handle;
|
|
gint priority;
|
|
} CommonThemeDirMonitorData;
|
|
|
|
typedef struct {
|
|
GFileMonitor *common_icon_theme_dir_handle;
|
|
gint priority;
|
|
} CommonIconThemeDirMonitorData;
|
|
|
|
typedef struct {
|
|
GHashTable *handle_hash;
|
|
gint priority;
|
|
} CallbackTuple;
|
|
|
|
|
|
/* Hash tables */
|
|
|
|
/* The hashes_by_dir are indexed by an escaped uri of the common_theme_dir that
|
|
* that particular theme is part of. The data pointed to by them is a
|
|
* GnomeTheme{Meta,Icon,}Info struct. Note that the uri is of the form
|
|
* "file:///home/username/.themes/foo", and not "/home/username/.themes/foo"
|
|
*/
|
|
|
|
/* The hashes_by_name are hashed by the index of the theme. The data pointed to
|
|
* by them is a GList whose data elements are GnomeTheme{Meta,Icon,}Info
|
|
* structs. This is because a theme can be found both in the users ~/.theme as
|
|
* well as globally in $prefix. All access to them must be done via helper
|
|
* functions.
|
|
*/
|
|
static GList *callbacks = NULL;
|
|
|
|
static GHashTable *meta_theme_hash_by_uri;
|
|
static GHashTable *meta_theme_hash_by_name;
|
|
static GHashTable *icon_theme_hash_by_uri;
|
|
static GHashTable *icon_theme_hash_by_name;
|
|
static GHashTable *cursor_theme_hash_by_uri;
|
|
static GHashTable *cursor_theme_hash_by_name;
|
|
static GHashTable *theme_hash_by_uri;
|
|
static GHashTable *theme_hash_by_name;
|
|
static gboolean initting = FALSE;
|
|
|
|
/* private functions */
|
|
static gint
|
|
safe_strcmp (const gchar *a_str,
|
|
const gchar *b_str)
|
|
{
|
|
if (a_str && b_str)
|
|
return strcmp (a_str, b_str);
|
|
else
|
|
return a_str - b_str;
|
|
}
|
|
|
|
static GFileType
|
|
get_file_type (GFile *file)
|
|
{
|
|
GFileType file_type = G_FILE_TYPE_UNKNOWN;
|
|
GFileInfo *file_info;
|
|
|
|
file_info = g_file_query_info (file,
|
|
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
|
G_FILE_QUERY_INFO_NONE,
|
|
NULL, NULL);
|
|
if (file_info != NULL) {
|
|
file_type = g_file_info_get_file_type (file_info);
|
|
g_object_unref (file_info);
|
|
}
|
|
|
|
return file_type;
|
|
}
|
|
|
|
static void
|
|
add_theme_to_hash_by_name (GHashTable *hash_table,
|
|
gpointer data)
|
|
{
|
|
GnomeThemeCommonInfo *info = data;
|
|
GList *list;
|
|
|
|
list = g_hash_table_lookup (hash_table, info->name);
|
|
if (list == NULL) {
|
|
list = g_list_append (list, info);
|
|
} else {
|
|
GList *list_ptr = list;
|
|
gboolean added = FALSE;
|
|
|
|
while (list_ptr) {
|
|
gint theme_priority;
|
|
|
|
theme_priority = ((GnomeThemeCommonInfo *) list_ptr->data)->priority;
|
|
|
|
if (theme_priority == info->priority) {
|
|
/* Swap it in */
|
|
list_ptr->data = info;
|
|
added = TRUE;
|
|
break;
|
|
} else if (theme_priority > info->priority) {
|
|
list = g_list_insert_before (list, list_ptr, info);
|
|
added = TRUE;
|
|
break;
|
|
}
|
|
list_ptr = list_ptr->next;
|
|
}
|
|
if (!added)
|
|
list = g_list_append (list, info);
|
|
}
|
|
g_hash_table_insert (hash_table, g_strdup (info->name), list);
|
|
}
|
|
|
|
static void
|
|
remove_theme_from_hash_by_name (GHashTable *hash_table,
|
|
gpointer data)
|
|
{
|
|
GnomeThemeCommonInfo *info = data;
|
|
GList *list;
|
|
|
|
list = g_hash_table_lookup (hash_table, info->name);
|
|
|
|
list = g_list_remove (list, info);
|
|
if (list == NULL)
|
|
g_hash_table_remove (hash_table, info->name);
|
|
else
|
|
g_hash_table_insert (hash_table, g_strdup (info->name), list);
|
|
}
|
|
|
|
static GnomeThemeCommonInfo *
|
|
get_theme_from_hash_by_name (GHashTable *hash_table,
|
|
const gchar *name,
|
|
gint priority)
|
|
{
|
|
GList *list;
|
|
|
|
list = g_hash_table_lookup (hash_table, name);
|
|
|
|
/* -1 implies return the first one */
|
|
if (priority == -1) {
|
|
return list ? list->data : NULL;
|
|
}
|
|
|
|
while (list) {
|
|
GnomeThemeCommonInfo *info = (GnomeThemeCommonInfo *) list->data;
|
|
|
|
if (info->priority == priority)
|
|
return info;
|
|
|
|
list = list->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static gint
|
|
theme_compare (GnomeThemeCommonInfo *a,
|
|
GnomeThemeCommonInfo *b)
|
|
{
|
|
gint cmp;
|
|
|
|
g_return_val_if_fail (a->type == b->type, a->type - b->type);
|
|
|
|
switch (a->type) {
|
|
case GNOME_THEME_TYPE_METATHEME:
|
|
cmp = gnome_theme_meta_info_compare (
|
|
(GnomeThemeMetaInfo *) a, (GnomeThemeMetaInfo *) b);
|
|
break;
|
|
case GNOME_THEME_TYPE_ICON:
|
|
cmp = gnome_theme_icon_info_compare (
|
|
(GnomeThemeIconInfo *) a, (GnomeThemeIconInfo *) b);
|
|
break;
|
|
case GNOME_THEME_TYPE_CURSOR:
|
|
cmp = gnome_theme_cursor_info_compare (
|
|
(GnomeThemeCursorInfo *) a, (GnomeThemeCursorInfo *) b);
|
|
break;
|
|
default:
|
|
/* not supported at this time */
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return cmp;
|
|
}
|
|
|
|
static void
|
|
theme_free (GnomeThemeCommonInfo *info)
|
|
{
|
|
switch (info->type) {
|
|
case GNOME_THEME_TYPE_METATHEME:
|
|
gnome_theme_meta_info_free ((GnomeThemeMetaInfo *) info);
|
|
break;
|
|
case GNOME_THEME_TYPE_ICON:
|
|
gnome_theme_icon_info_free ((GnomeThemeIconInfo *) info);
|
|
break;
|
|
case GNOME_THEME_TYPE_REGULAR:
|
|
gnome_theme_info_free ((GnomeThemeInfo *) info);
|
|
break;
|
|
case GNOME_THEME_TYPE_CURSOR:
|
|
gnome_theme_cursor_info_free ((GnomeThemeCursorInfo *) info);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
GQuark
|
|
gnome_theme_info_error_quark (void)
|
|
{
|
|
return g_quark_from_static_string ("gnome-theme-info-error-quark");
|
|
}
|
|
|
|
GnomeThemeMetaInfo *
|
|
gnome_theme_read_meta_theme (GFile *meta_theme_uri)
|
|
{
|
|
GnomeThemeMetaInfo *meta_theme_info;
|
|
GFile *common_theme_dir_uri;
|
|
GnomeDesktopItem *meta_theme_ditem;
|
|
gchar *meta_theme_file;
|
|
const gchar *str;
|
|
gchar *scheme;
|
|
|
|
meta_theme_file = g_file_get_uri (meta_theme_uri);
|
|
meta_theme_ditem = gnome_desktop_item_new_from_uri (meta_theme_file, 0, NULL);
|
|
if (meta_theme_ditem == NULL) {
|
|
g_free (meta_theme_file);
|
|
return NULL;
|
|
}
|
|
|
|
common_theme_dir_uri = g_file_get_parent (meta_theme_uri);
|
|
meta_theme_info = gnome_theme_meta_info_new ();
|
|
meta_theme_info->path = meta_theme_file;
|
|
meta_theme_info->name = g_file_get_basename (common_theme_dir_uri);
|
|
g_object_unref (common_theme_dir_uri);
|
|
|
|
str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_NAME);
|
|
if (!str) {
|
|
str = gnome_desktop_item_get_localestring (meta_theme_ditem, GNOME_DESKTOP_ITEM_NAME);
|
|
if (!str) { /* shouldn't reach */
|
|
gnome_theme_meta_info_free (meta_theme_info);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
meta_theme_info->readable_name = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_localestring (meta_theme_ditem, THEME_COMMENT);
|
|
if (str == NULL)
|
|
str = gnome_desktop_item_get_localestring (meta_theme_ditem, GNOME_DESKTOP_ITEM_COMMENT);
|
|
if (str != NULL)
|
|
meta_theme_info->comment = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, GNOME_DESKTOP_ITEM_ICON);
|
|
if (str != NULL)
|
|
meta_theme_info->icon_file = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, GTK_THEME_KEY);
|
|
if (str == NULL) {
|
|
gnome_theme_meta_info_free (meta_theme_info);
|
|
return NULL;
|
|
}
|
|
meta_theme_info->gtk_theme_name = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, GTK_COLOR_SCHEME_KEY);
|
|
if (str == NULL || str[0] == '\0')
|
|
scheme = gtkrc_get_color_scheme_for_theme (meta_theme_info->gtk_theme_name);
|
|
else
|
|
scheme = g_strdup (str);
|
|
|
|
if (scheme != NULL) {
|
|
meta_theme_info->gtk_color_scheme = scheme;
|
|
for (; *scheme != '\0'; scheme++)
|
|
if (*scheme == ',')
|
|
*scheme = '\n';
|
|
}
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, METACITY_THEME_KEY);
|
|
if (str == NULL) {
|
|
gnome_theme_meta_info_free (meta_theme_info);
|
|
return NULL;
|
|
}
|
|
meta_theme_info->metacity_theme_name = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, ICON_THEME_KEY);
|
|
if (str == NULL) {
|
|
gnome_theme_meta_info_free (meta_theme_info);
|
|
return NULL;
|
|
}
|
|
meta_theme_info->icon_theme_name = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_THEME_KEY);
|
|
if (str != NULL) {
|
|
meta_theme_info->cursor_theme_name = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, CURSOR_SIZE_KEY);
|
|
if (str)
|
|
meta_theme_info->cursor_size = (int) g_ascii_strtoll (str, NULL, 10);
|
|
else
|
|
meta_theme_info->cursor_size = 18;
|
|
} else {
|
|
meta_theme_info->cursor_theme_name = g_strdup ("default");
|
|
meta_theme_info->cursor_size = 18;
|
|
}
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, APPLICATION_FONT_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->application_font = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, DOCUMENTS_FONT_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->documents_font = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, DESKTOP_FONT_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->desktop_font = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, WINDOWTITLE_FONT_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->windowtitle_font = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, MONOSPACE_FONT_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->monospace_font = g_strdup (str);
|
|
|
|
str = gnome_desktop_item_get_string (meta_theme_ditem, BACKGROUND_IMAGE_KEY);
|
|
if (str != NULL)
|
|
meta_theme_info->background_image = g_strdup (str);
|
|
|
|
gnome_desktop_item_unref (meta_theme_ditem);
|
|
|
|
return meta_theme_info;
|
|
}
|
|
|
|
static GnomeThemeIconInfo *
|
|
read_icon_theme (GFile *icon_theme_uri)
|
|
{
|
|
GnomeThemeIconInfo *icon_theme_info;
|
|
GnomeDesktopItem *icon_theme_ditem;
|
|
gchar *icon_theme_file;
|
|
const gchar *name;
|
|
const gchar *directories;
|
|
const gchar *hidden_theme_icon;
|
|
|
|
icon_theme_file = g_file_get_uri (icon_theme_uri);
|
|
icon_theme_ditem = gnome_desktop_item_new_from_uri (icon_theme_file, 0, NULL);
|
|
if (icon_theme_ditem == NULL) {
|
|
g_free (icon_theme_file);
|
|
return NULL;
|
|
}
|
|
|
|
name = gnome_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Name");
|
|
if (name == NULL) {
|
|
gnome_desktop_item_unref (icon_theme_ditem);
|
|
g_free (icon_theme_file);
|
|
return NULL;
|
|
}
|
|
|
|
/* If index.theme has no Directories entry, it is only a cursor theme */
|
|
directories = gnome_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Directories");
|
|
if (directories == NULL) {
|
|
gnome_desktop_item_unref (icon_theme_ditem);
|
|
g_free (icon_theme_file);
|
|
return NULL;
|
|
}
|
|
|
|
hidden_theme_icon = gnome_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Hidden");
|
|
if (hidden_theme_icon == NULL ||
|
|
strcmp (hidden_theme_icon, "false") == 0) {
|
|
gchar *dir_name;
|
|
icon_theme_info = gnome_theme_icon_info_new ();
|
|
icon_theme_info->readable_name = g_strdup (name);
|
|
icon_theme_info->path = icon_theme_file;
|
|
dir_name = g_path_get_dirname (icon_theme_file);
|
|
icon_theme_info->name = g_path_get_basename (dir_name);
|
|
g_free (dir_name);
|
|
} else {
|
|
icon_theme_info = NULL;
|
|
g_free (icon_theme_file);
|
|
}
|
|
|
|
gnome_desktop_item_unref (icon_theme_ditem);
|
|
|
|
return icon_theme_info;
|
|
}
|
|
|
|
#ifdef HAVE_XCURSOR
|
|
static void
|
|
add_default_cursor_theme ()
|
|
{
|
|
GnomeThemeCursorInfo *theme_info;
|
|
|
|
theme_info = gnome_theme_cursor_info_new ();
|
|
theme_info->path = g_strdup ("builtin");
|
|
theme_info->name = g_strdup ("default");
|
|
theme_info->readable_name = g_strdup (_("Default Pointer"));
|
|
theme_info->sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), 0);
|
|
|
|
g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
|
|
add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
gdk_pixbuf_from_xcursor_image (XcursorImage *cursor)
|
|
{
|
|
GdkPixbuf *pixbuf;
|
|
#define BUF_SIZE sizeof(guint32) * cursor->width * cursor->height
|
|
guchar *buf = g_malloc0 (BUF_SIZE);
|
|
guchar *it;
|
|
|
|
for (it = buf; it < (buf + BUF_SIZE); it += 4) {
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
/* on little endianess it's BGRA to RGBA */
|
|
it[0] = ((guchar *) (cursor->pixels))[it - buf + 2];
|
|
it[1] = ((guchar *) (cursor->pixels))[it - buf + 1];
|
|
it[2] = ((guchar *) (cursor->pixels))[it - buf + 0];
|
|
it[3] = ((guchar *) (cursor->pixels))[it - buf + 3];
|
|
#else
|
|
/* on big endianess it's ARGB to RGBA */
|
|
it[0] = ((guchar *) cursor->pixels)[it - buf + 1];
|
|
it[1] = ((guchar *) cursor->pixels)[it - buf + 2];
|
|
it[2] = ((guchar *) cursor->pixels)[it - buf + 3];
|
|
it[3] = ((guchar *) cursor->pixels)[it - buf + 0];
|
|
#endif
|
|
}
|
|
|
|
pixbuf = gdk_pixbuf_new_from_data ((const guchar *) buf,
|
|
GDK_COLORSPACE_RGB, TRUE, 8,
|
|
cursor->width, cursor->height,
|
|
cursor->width * 4,
|
|
(GdkPixbufDestroyNotify) g_free,
|
|
NULL);
|
|
|
|
if (!pixbuf)
|
|
g_free (buf);
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
static GnomeThemeCursorInfo *
|
|
read_cursor_theme (GFile *cursor_theme_uri)
|
|
{
|
|
GnomeThemeCursorInfo *cursor_theme_info = NULL;
|
|
GFile *parent_uri, *cursors_uri;
|
|
|
|
const gint filter_sizes[] = { 12, 16, 24, 32, 36, 40, 48, 64 };
|
|
const gint num_sizes = G_N_ELEMENTS (filter_sizes);
|
|
|
|
parent_uri = g_file_get_parent (cursor_theme_uri);
|
|
cursors_uri = g_file_get_child (parent_uri, "cursors");
|
|
|
|
if (get_file_type (cursors_uri) == G_FILE_TYPE_DIRECTORY) {
|
|
GArray *sizes;
|
|
XcursorImage *cursor;
|
|
GdkPixbuf *thumbnail = NULL;
|
|
gchar *name;
|
|
gint i;
|
|
|
|
name = g_file_get_basename (parent_uri);
|
|
|
|
sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), num_sizes);
|
|
|
|
for (i = 0; i < num_sizes; ++i) {
|
|
cursor = XcursorLibraryLoadImage ("left_ptr", name, filter_sizes[i]);
|
|
|
|
if (cursor) {
|
|
if (cursor->size == filter_sizes[i]) {
|
|
g_array_append_val (sizes, filter_sizes[i]);
|
|
|
|
if (thumbnail == NULL && i >= 1)
|
|
thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
|
|
}
|
|
|
|
XcursorImageDestroy (cursor);
|
|
}
|
|
}
|
|
|
|
if (sizes->len == 0) {
|
|
g_array_free (sizes, TRUE);
|
|
g_free (name);
|
|
} else {
|
|
GnomeDesktopItem *cursor_theme_ditem;
|
|
gchar *cursor_theme_file;
|
|
|
|
if (!thumbnail) {
|
|
cursor = XcursorLibraryLoadImage ("left_ptr", name,
|
|
g_array_index (sizes, gint, 0));
|
|
if (cursor) {
|
|
thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
|
|
XcursorImageDestroy (cursor);
|
|
}
|
|
}
|
|
|
|
cursor_theme_info = gnome_theme_cursor_info_new ();
|
|
cursor_theme_info->path = g_file_get_uri (parent_uri);
|
|
cursor_theme_info->name = name;
|
|
cursor_theme_info->sizes = sizes;
|
|
cursor_theme_info->thumbnail = thumbnail;
|
|
|
|
cursor_theme_file = g_file_get_path (cursor_theme_uri);
|
|
cursor_theme_ditem = gnome_desktop_item_new_from_file (cursor_theme_file, 0, NULL);
|
|
g_free (cursor_theme_file);
|
|
|
|
if (cursor_theme_ditem != NULL) {
|
|
const gchar *readable_name;
|
|
|
|
readable_name = gnome_desktop_item_get_string (cursor_theme_ditem,
|
|
"Icon Theme/Name");
|
|
if (readable_name)
|
|
cursor_theme_info->readable_name = g_strdup (readable_name);
|
|
else
|
|
cursor_theme_info->readable_name = g_strdup (name);
|
|
|
|
gnome_desktop_item_unref (cursor_theme_ditem);
|
|
} else {
|
|
cursor_theme_info->readable_name = g_strdup (name);
|
|
}
|
|
}
|
|
}
|
|
|
|
g_object_unref (cursors_uri);
|
|
g_object_unref (parent_uri);
|
|
|
|
return cursor_theme_info;
|
|
}
|
|
|
|
#else /* !HAVE_XCURSOR */
|
|
|
|
static gchar *
|
|
read_current_cursor_font (void)
|
|
{
|
|
DIR *dir;
|
|
gchar *dir_name;
|
|
struct dirent *file_dirent;
|
|
|
|
dir_name = g_build_filename (g_get_home_dir (), ".gnome2/share/cursor-fonts", NULL);
|
|
if (! g_file_test (dir_name, G_FILE_TEST_EXISTS)) {
|
|
g_free (dir_name);
|
|
return NULL;
|
|
}
|
|
|
|
dir = opendir (dir_name);
|
|
|
|
while ((file_dirent = readdir (dir)) != NULL) {
|
|
struct stat st;
|
|
gchar *link_name;
|
|
|
|
link_name = g_build_filename (dir_name, file_dirent->d_name, NULL);
|
|
if (lstat (link_name, &st)) {
|
|
g_free (link_name);
|
|
continue;
|
|
}
|
|
|
|
if (S_ISLNK (st.st_mode)) {
|
|
gint length;
|
|
gchar target[256];
|
|
|
|
length = readlink (link_name, target, 255);
|
|
if (length > 0) {
|
|
gchar *retval;
|
|
target[length] = '\0';
|
|
retval = g_strdup (target);
|
|
g_free (link_name);
|
|
closedir (dir);
|
|
return retval;
|
|
}
|
|
|
|
}
|
|
g_free (link_name);
|
|
}
|
|
g_free (dir_name);
|
|
closedir (dir);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
read_cursor_fonts (void)
|
|
{
|
|
gchar *cursor_font;
|
|
gint i;
|
|
|
|
const gchar *builtins[][4] = {
|
|
{
|
|
"gnome/cursor-fonts/cursor-normal.pcf",
|
|
N_("Default Pointer"),
|
|
N_("Default Pointer - Current"),
|
|
"mouse-cursor-normal.png"
|
|
}, {
|
|
"gnome/cursor-fonts/cursor-white.pcf",
|
|
N_("White Pointer"),
|
|
N_("White Pointer - Current"),
|
|
"mouse-cursor-white.png"
|
|
}, {
|
|
"gnome/cursor-fonts/cursor-large.pcf",
|
|
N_("Large Pointer"),
|
|
N_("Large Pointer - Current"),
|
|
"mouse-cursor-normal-large.png"
|
|
}, {
|
|
"gnome/cursor-fonts/cursor-large-white.pcf",
|
|
N_("Large White Pointer - Current"),
|
|
N_("Large White Pointer"),
|
|
"mouse-cursor-white-large.png"
|
|
}
|
|
};
|
|
|
|
cursor_font = read_current_cursor_font();
|
|
|
|
if (!cursor_font)
|
|
cursor_font = g_strdup (builtins[0][0]);
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (builtins); i++) {
|
|
GnomeThemeCursorInfo *theme_info;
|
|
gchar *filename;
|
|
|
|
theme_info = gnome_theme_cursor_info_new ();
|
|
|
|
filename = g_build_filename (GNOMECC_DATA_DIR, "pixmaps", builtins[i][3], NULL);
|
|
theme_info->thumbnail = gdk_pixbuf_new_from_file (filename, NULL);
|
|
g_free (filename);
|
|
|
|
theme_info->path = g_build_filename ("file://" GNOMECC_DATA_DIR, builtins[i][0], NULL);
|
|
theme_info->name = g_strdup (theme_info->path);
|
|
|
|
if (!strcmp (theme_info->path, cursor_font))
|
|
theme_info->readable_name = g_strdup (_(builtins[i][2]));
|
|
else
|
|
theme_info->readable_name = g_strdup (_(builtins[i][1]));
|
|
|
|
g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
|
|
add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
|
|
}
|
|
|
|
g_free (cursor_font);
|
|
}
|
|
#endif /* HAVE_XCURSOR */
|
|
|
|
static void
|
|
handle_change_signal (gpointer data,
|
|
GnomeThemeChangeType change_type)
|
|
{
|
|
#ifdef DEBUG
|
|
gchar *type_str = NULL;
|
|
gchar *change_str = NULL;
|
|
gchar *element_str = NULL;
|
|
#endif
|
|
GnomeThemeCommonInfo *theme = data;
|
|
GList *list;
|
|
|
|
if (initting)
|
|
return;
|
|
|
|
for (list = callbacks; list; list = list->next) {
|
|
ThemeCallbackData *callback_data = list->data;
|
|
(* callback_data->func) (theme, change_type, callback_data->data);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (theme->type == GNOME_THEME_TYPE_METATHEME)
|
|
type_str = "meta";
|
|
else if (theme->type == GNOME_THEME_TYPE_ICON)
|
|
type_str = "icon";
|
|
else if (theme->type == GNOME_THEME_TYPE_CURSOR)
|
|
type_str = "cursor";
|
|
else if (theme->type == GNOME_THEME_TYPE_REGULAR) {
|
|
GnomeThemeInfo *rtheme = (GnomeThemeInfo *) theme;
|
|
if (rtheme->has_gtk)
|
|
element_str = "gtk-2";
|
|
else if (rtheme->has_keybinding)
|
|
element_str = "keybinding";
|
|
else if (rtheme->has_metacity)
|
|
element_str = "metacity";
|
|
}
|
|
|
|
if (change_type == GNOME_THEME_CHANGE_CREATED)
|
|
change_str = "created";
|
|
else if (change_type == GNOME_THEME_CHANGE_CHANGED)
|
|
change_str = "changed";
|
|
else if (change_type == GNOME_THEME_CHANGE_DELETED)
|
|
change_str = "deleted";
|
|
|
|
if (type == GNOME_THEME_TYPE_REGULAR) {
|
|
g_print ("theme \"%s\" has a theme of type %s (priority %d) has been %s\n",
|
|
theme->name,
|
|
element_str,
|
|
theme->priority,
|
|
type_str);
|
|
} else if (type_str != NULL) {
|
|
g_print ("%s theme \"%s\" (priority %d) has been %s\n",
|
|
type_str,
|
|
theme->name,
|
|
theme->priority,
|
|
type_str);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* index_uri should point to the gtkrc file that was modified */
|
|
static void
|
|
update_theme_index (GFile *index_uri,
|
|
GnomeThemeElement key_element,
|
|
gint priority)
|
|
{
|
|
gboolean theme_exists;
|
|
GnomeThemeInfo *theme_info;
|
|
GFile *parent;
|
|
GFile *common_theme_dir_uri;
|
|
gchar *common_theme_dir;
|
|
|
|
/* First, we determine the new state of the file. We do no more
|
|
* sophisticated a test than "files exists and is a file" */
|
|
theme_exists = (get_file_type (index_uri) == G_FILE_TYPE_REGULAR);
|
|
|
|
/* Next, we see what currently exists */
|
|
parent = g_file_get_parent (index_uri);
|
|
common_theme_dir_uri = g_file_get_parent (parent);
|
|
common_theme_dir = g_file_get_uri (common_theme_dir_uri);
|
|
|
|
theme_info = g_hash_table_lookup (theme_hash_by_uri, common_theme_dir);
|
|
if (theme_info == NULL) {
|
|
if (theme_exists) {
|
|
theme_info = gnome_theme_info_new ();
|
|
theme_info->path = g_strdup (common_theme_dir);
|
|
theme_info->name = g_file_get_basename (common_theme_dir_uri);
|
|
theme_info->readable_name = g_strdup (theme_info->name);
|
|
theme_info->priority = priority;
|
|
if (key_element & GNOME_THEME_GTK_2)
|
|
theme_info->has_gtk = TRUE;
|
|
else if (key_element & GNOME_THEME_GTK_2_KEYBINDING)
|
|
theme_info->has_keybinding = TRUE;
|
|
else if (key_element & GNOME_THEME_METACITY)
|
|
theme_info->has_metacity = TRUE;
|
|
|
|
g_hash_table_insert (theme_hash_by_uri, g_strdup (common_theme_dir), theme_info);
|
|
add_theme_to_hash_by_name (theme_hash_by_name, theme_info);
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED);
|
|
}
|
|
} else {
|
|
gboolean theme_used_to_exist = FALSE;
|
|
|
|
if (key_element & GNOME_THEME_GTK_2) {
|
|
theme_used_to_exist = theme_info->has_gtk;
|
|
theme_info->has_gtk = theme_exists;
|
|
} else if (key_element & GNOME_THEME_GTK_2_KEYBINDING) {
|
|
theme_used_to_exist = theme_info->has_keybinding;
|
|
theme_info->has_keybinding = theme_exists;
|
|
} else if (key_element & GNOME_THEME_METACITY) {
|
|
theme_used_to_exist = theme_info->has_metacity;
|
|
theme_info->has_metacity = theme_exists;
|
|
}
|
|
|
|
if (!theme_info->has_metacity && !theme_info->has_keybinding && !theme_info->has_gtk) {
|
|
g_hash_table_remove (theme_hash_by_uri, common_theme_dir);
|
|
remove_theme_from_hash_by_name (theme_hash_by_name, theme_info);
|
|
}
|
|
|
|
if (theme_exists && theme_used_to_exist) {
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_CHANGED);
|
|
} else if (theme_exists && !theme_used_to_exist) {
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED);
|
|
} else if (!theme_exists && theme_used_to_exist) {
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_DELETED);
|
|
}
|
|
|
|
if (!theme_info->has_metacity && !theme_info->has_keybinding && !theme_info->has_gtk) {
|
|
gnome_theme_info_free (theme_info);
|
|
}
|
|
}
|
|
|
|
g_free (common_theme_dir);
|
|
g_object_unref (parent);
|
|
g_object_unref (common_theme_dir_uri);
|
|
}
|
|
|
|
static void
|
|
update_gtk2_index (GFile *gtk2_index_uri,
|
|
gint priority)
|
|
{
|
|
update_theme_index (gtk2_index_uri, GNOME_THEME_GTK_2, priority);
|
|
}
|
|
|
|
static void
|
|
update_keybinding_index (GFile *keybinding_index_uri,
|
|
gint priority)
|
|
{
|
|
update_theme_index (keybinding_index_uri, GNOME_THEME_GTK_2_KEYBINDING, priority);
|
|
}
|
|
|
|
static void
|
|
update_metacity_index (GFile *metacity_index_uri,
|
|
gint priority)
|
|
{
|
|
update_theme_index (metacity_index_uri, GNOME_THEME_METACITY, priority);
|
|
}
|
|
|
|
static void
|
|
update_common_theme_dir_index (GFile *theme_index_uri,
|
|
GnomeThemeType type,
|
|
gint priority)
|
|
{
|
|
gboolean theme_exists;
|
|
GnomeThemeCommonInfo *theme_info = NULL;
|
|
GnomeThemeCommonInfo *old_theme_info;
|
|
GFile *common_theme_dir_uri;
|
|
gchar *common_theme_dir;
|
|
GHashTable *hash_by_uri;
|
|
GHashTable *hash_by_name;
|
|
|
|
if (type == GNOME_THEME_TYPE_ICON) {
|
|
hash_by_uri = icon_theme_hash_by_uri;
|
|
hash_by_name = icon_theme_hash_by_name;
|
|
} else if (type == GNOME_THEME_TYPE_CURSOR) {
|
|
hash_by_uri = cursor_theme_hash_by_uri;
|
|
hash_by_name = cursor_theme_hash_by_name;
|
|
} else {
|
|
hash_by_uri = meta_theme_hash_by_uri;
|
|
hash_by_name = meta_theme_hash_by_name;
|
|
}
|
|
|
|
if (type != GNOME_THEME_TYPE_CURSOR) {
|
|
/* First, we determine the new state of the file. */
|
|
if (get_file_type (theme_index_uri) == G_FILE_TYPE_REGULAR) {
|
|
/* It's an interesting file. Let's try to load it. */
|
|
if (type == GNOME_THEME_TYPE_ICON)
|
|
theme_info = (GnomeThemeCommonInfo *) read_icon_theme (theme_index_uri);
|
|
else
|
|
theme_info = (GnomeThemeCommonInfo *) gnome_theme_read_meta_theme (theme_index_uri);
|
|
} else {
|
|
theme_info = NULL;
|
|
}
|
|
|
|
}
|
|
#ifdef HAVE_XCURSOR
|
|
/* cursor themes don't necessarily have an index file, so try those in any case */
|
|
else {
|
|
theme_info = (GnomeThemeCommonInfo *) read_cursor_theme (theme_index_uri);
|
|
}
|
|
#endif
|
|
|
|
if (theme_info) {
|
|
theme_info->priority = priority;
|
|
theme_exists = TRUE;
|
|
} else {
|
|
theme_exists = FALSE;
|
|
}
|
|
|
|
/* Next, we see what currently exists */
|
|
common_theme_dir_uri = g_file_get_parent (theme_index_uri);
|
|
common_theme_dir = g_file_get_path (common_theme_dir_uri);
|
|
g_object_unref (common_theme_dir_uri);
|
|
|
|
old_theme_info = (GnomeThemeCommonInfo *) g_hash_table_lookup (hash_by_uri, common_theme_dir);
|
|
|
|
if (old_theme_info == NULL) {
|
|
if (theme_exists) {
|
|
g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
|
|
add_theme_to_hash_by_name (hash_by_name, theme_info);
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_CREATED);
|
|
}
|
|
} else {
|
|
if (theme_exists) {
|
|
if (theme_compare (theme_info, old_theme_info) != 0) {
|
|
/* Remove old theme */
|
|
g_hash_table_remove (hash_by_uri, common_theme_dir);
|
|
remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
|
|
g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
|
|
add_theme_to_hash_by_name (hash_by_name, theme_info);
|
|
handle_change_signal (theme_info, GNOME_THEME_CHANGE_CHANGED);
|
|
theme_free (old_theme_info);
|
|
} else {
|
|
theme_free (theme_info);
|
|
}
|
|
} else {
|
|
g_hash_table_remove (hash_by_uri, common_theme_dir);
|
|
remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
|
|
|
|
handle_change_signal (old_theme_info, GNOME_THEME_CHANGE_DELETED);
|
|
theme_free (old_theme_info);
|
|
}
|
|
}
|
|
|
|
g_free (common_theme_dir);
|
|
}
|
|
|
|
static void
|
|
update_meta_theme_index (GFile *meta_theme_index_uri,
|
|
gint priority)
|
|
{
|
|
update_common_theme_dir_index (meta_theme_index_uri, GNOME_THEME_TYPE_METATHEME, priority);
|
|
}
|
|
|
|
static void
|
|
update_icon_theme_index (GFile *icon_theme_index_uri,
|
|
gint priority)
|
|
{
|
|
update_common_theme_dir_index (icon_theme_index_uri, GNOME_THEME_TYPE_ICON, priority);
|
|
}
|
|
|
|
static void
|
|
update_cursor_theme_index (GFile *cursor_theme_index_uri,
|
|
gint priority)
|
|
{
|
|
#ifdef HAVE_XCURSOR
|
|
update_common_theme_dir_index (cursor_theme_index_uri, GNOME_THEME_TYPE_CURSOR, priority);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
gtk2_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CommonThemeDirMonitorData *monitor_data)
|
|
{
|
|
gchar *affected_file;
|
|
|
|
affected_file = g_file_get_basename (file);
|
|
|
|
/* The only file we care about is gtkrc */
|
|
if (!strcmp (affected_file, "gtkrc")) {
|
|
update_gtk2_index (file, monitor_data->priority);
|
|
}
|
|
|
|
g_free (affected_file);
|
|
}
|
|
|
|
static void
|
|
keybinding_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CommonThemeDirMonitorData *monitor_data)
|
|
{
|
|
gchar *affected_file;
|
|
|
|
affected_file = g_file_get_basename (file);
|
|
|
|
/* The only file we care about is gtkrc */
|
|
if (!strcmp (affected_file, "gtkrc")) {
|
|
update_keybinding_index (file, monitor_data->priority);
|
|
}
|
|
|
|
g_free (affected_file);
|
|
}
|
|
|
|
static void
|
|
metacity_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CommonThemeDirMonitorData *monitor_data)
|
|
{
|
|
gchar *affected_file;
|
|
|
|
affected_file = g_file_get_basename (file);
|
|
|
|
/* The only file we care about is metacity-theme-1.xml */
|
|
if (!strcmp (affected_file, "metacity-theme-1.xml")) {
|
|
update_metacity_index (file, monitor_data->priority);
|
|
}
|
|
|
|
g_free (affected_file);
|
|
}
|
|
|
|
static void
|
|
common_theme_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CommonThemeDirMonitorData *monitor_data)
|
|
{
|
|
gchar *affected_file;
|
|
|
|
affected_file = g_file_get_basename (file);
|
|
|
|
/* The only file we care about is index.theme */
|
|
if (!strcmp (affected_file, "index.theme")) {
|
|
update_meta_theme_index (file, monitor_data->priority);
|
|
}
|
|
|
|
g_free (affected_file);
|
|
}
|
|
|
|
static void
|
|
common_icon_theme_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CommonIconThemeDirMonitorData *monitor_data)
|
|
{
|
|
gchar *affected_file;
|
|
|
|
affected_file = g_file_get_basename (file);
|
|
|
|
/* The only file we care about is index.theme */
|
|
if (!strcmp (affected_file, "index.theme")) {
|
|
update_icon_theme_index (file, monitor_data->priority);
|
|
update_cursor_theme_index (file, monitor_data->priority);
|
|
}
|
|
/* and the cursors subdir for cursor themes */
|
|
else if (!strcmp (affected_file, "cursors")) {
|
|
/* always call update_cursor_theme_index with the index.theme URI */
|
|
GFile *parent, *index;
|
|
|
|
parent = g_file_get_parent (file);
|
|
index = g_file_get_child (parent, "index.theme");
|
|
g_object_unref (parent);
|
|
|
|
update_cursor_theme_index (index, monitor_data->priority);
|
|
|
|
g_object_unref (index);
|
|
}
|
|
|
|
g_free (affected_file);
|
|
}
|
|
|
|
/* Add a monitor to a common_theme_dir. */
|
|
static gboolean
|
|
add_common_theme_dir_monitor (GFile *theme_dir_uri,
|
|
CommonThemeDirMonitorData *monitor_data,
|
|
GError **error)
|
|
{
|
|
GFile *uri, *subdir;
|
|
GFileMonitor *monitor;
|
|
|
|
uri = g_file_get_child (theme_dir_uri, "index.theme");
|
|
update_meta_theme_index (uri, monitor_data->priority);
|
|
g_object_unref (uri);
|
|
|
|
/* Add the handle for this directory */
|
|
monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor == NULL)
|
|
return FALSE;
|
|
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) common_theme_dir_changed, monitor_data);
|
|
|
|
monitor_data->common_theme_dir_handle = monitor;
|
|
|
|
|
|
/* gtk-2 theme subdir */
|
|
subdir = g_file_get_child (theme_dir_uri, "gtk-2.0");
|
|
uri = g_file_get_child (subdir, "gtkrc");
|
|
if (g_file_query_exists (uri, NULL)) {
|
|
update_gtk2_index (uri, monitor_data->priority);
|
|
}
|
|
g_object_unref (uri);
|
|
|
|
monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor != NULL) {
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) gtk2_dir_changed, monitor_data);
|
|
}
|
|
monitor_data->gtk2_dir_handle = monitor;
|
|
g_object_unref (subdir);
|
|
|
|
/* keybinding theme subdir */
|
|
subdir = g_file_get_child (theme_dir_uri, "gtk-2.0-key");
|
|
uri = g_file_get_child (subdir, "gtkrc");
|
|
if (g_file_query_exists (uri, NULL)) {
|
|
update_keybinding_index (uri, monitor_data->priority);
|
|
}
|
|
g_object_unref (uri);
|
|
|
|
monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor != NULL) {
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) keybinding_dir_changed, monitor_data);
|
|
}
|
|
monitor_data->keybinding_dir_handle = monitor;
|
|
g_object_unref (subdir);
|
|
|
|
/* metacity theme subdir */
|
|
subdir = g_file_get_child (theme_dir_uri, "metacity-1");
|
|
uri = g_file_get_child (subdir, "metacity-theme-1.xml");
|
|
if (g_file_query_exists (uri, NULL)) {
|
|
update_metacity_index (uri, monitor_data->priority);
|
|
}
|
|
g_object_unref (uri);
|
|
|
|
monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor != NULL) {
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) metacity_dir_changed, monitor_data);
|
|
}
|
|
monitor_data->metacity_dir_handle = monitor;
|
|
g_object_unref (subdir);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
add_common_icon_theme_dir_monitor (GFile *theme_dir_uri,
|
|
CommonIconThemeDirMonitorData *monitor_data,
|
|
GError **error)
|
|
{
|
|
GFile *index_uri;
|
|
GFileMonitor *monitor;
|
|
|
|
/* Add the handle for this directory */
|
|
index_uri = g_file_get_child (theme_dir_uri, "index.theme");
|
|
update_icon_theme_index (index_uri, monitor_data->priority);
|
|
update_cursor_theme_index (index_uri, monitor_data->priority);
|
|
g_object_unref (index_uri);
|
|
|
|
monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor == NULL)
|
|
return FALSE;
|
|
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) common_icon_theme_dir_changed, monitor_data);
|
|
|
|
monitor_data->common_icon_theme_dir_handle = monitor;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
remove_common_theme_dir_monitor (CommonThemeDirMonitorData *monitor_data)
|
|
{
|
|
g_file_monitor_cancel (monitor_data->common_theme_dir_handle);
|
|
g_file_monitor_cancel (monitor_data->gtk2_dir_handle);
|
|
g_file_monitor_cancel (monitor_data->keybinding_dir_handle);
|
|
g_file_monitor_cancel (monitor_data->metacity_dir_handle);
|
|
}
|
|
|
|
static void
|
|
remove_common_icon_theme_dir_monitor (CommonIconThemeDirMonitorData *monitor_data)
|
|
{
|
|
g_file_monitor_cancel (monitor_data->common_icon_theme_dir_handle);
|
|
}
|
|
|
|
static void
|
|
top_theme_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CallbackTuple *tuple)
|
|
{
|
|
GHashTable *handle_hash;
|
|
CommonThemeDirMonitorData *monitor_data;
|
|
gint priority;
|
|
|
|
handle_hash = tuple->handle_hash;
|
|
priority = tuple->priority;
|
|
|
|
if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
|
|
if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
|
|
monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
|
|
monitor_data->priority = priority;
|
|
add_common_theme_dir_monitor (file, monitor_data, NULL);
|
|
g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
|
|
}
|
|
|
|
} else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
|
|
gchar *name;
|
|
|
|
name = g_file_get_basename (file);
|
|
monitor_data = g_hash_table_lookup (handle_hash, name);
|
|
if (monitor_data != NULL) {
|
|
remove_common_theme_dir_monitor (monitor_data);
|
|
g_hash_table_remove (handle_hash, name);
|
|
}
|
|
g_free (name);
|
|
}
|
|
}
|
|
|
|
static void
|
|
top_icon_theme_dir_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
CallbackTuple *tuple)
|
|
{
|
|
GHashTable *handle_hash;
|
|
CommonIconThemeDirMonitorData *monitor_data;
|
|
gint priority;
|
|
|
|
handle_hash = tuple->handle_hash;
|
|
priority = tuple->priority;
|
|
|
|
if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
|
|
if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
|
|
monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
|
|
monitor_data->priority = priority;
|
|
add_common_icon_theme_dir_monitor (file, monitor_data, NULL);
|
|
g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
|
|
}
|
|
|
|
} else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
|
|
gchar *name;
|
|
|
|
name = g_file_get_basename (file);
|
|
monitor_data = g_hash_table_lookup (handle_hash, name);
|
|
if (monitor_data != NULL) {
|
|
remove_common_icon_theme_dir_monitor (monitor_data);
|
|
g_hash_table_remove (handle_hash, name);
|
|
}
|
|
g_free (name);
|
|
}
|
|
}
|
|
|
|
/* Add a monitor to a top dir. These monitors persist for the duration of the
|
|
* lib.
|
|
*/
|
|
static gboolean
|
|
real_add_top_theme_dir_monitor (GFile *uri,
|
|
gint priority,
|
|
gboolean icon_theme,
|
|
GError **error)
|
|
{
|
|
GFileInfo *file_info;
|
|
GFileMonitor *monitor;
|
|
GFileEnumerator *enumerator;
|
|
CallbackTuple *tuple;
|
|
|
|
/* Check the URI */
|
|
if (get_file_type (uri) != G_FILE_TYPE_DIRECTORY)
|
|
return FALSE;
|
|
|
|
/* handle_hash is a hash of common_theme_dir names to their monitor_data. We
|
|
* use it to remove the monitor handles when a dir is removed.
|
|
*/
|
|
tuple = g_new (CallbackTuple, 1);
|
|
tuple->handle_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
|
|
tuple->priority = priority;
|
|
|
|
/* Monitor the top directory */
|
|
monitor = g_file_monitor_directory (uri, G_FILE_MONITOR_NONE, NULL, NULL);
|
|
if (monitor != NULL) {
|
|
g_signal_connect (monitor, "changed",
|
|
(GCallback) (icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed),
|
|
tuple);
|
|
}
|
|
|
|
/* Go through the directory to add monitoring */
|
|
enumerator = g_file_enumerate_children (uri,
|
|
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
|
|
G_FILE_ATTRIBUTE_STANDARD_NAME,
|
|
G_FILE_QUERY_INFO_NONE,
|
|
NULL, NULL);
|
|
if (enumerator == NULL)
|
|
return FALSE;
|
|
|
|
while ((file_info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
|
|
GFileType type = g_file_info_get_file_type (file_info);
|
|
|
|
if (type == G_FILE_TYPE_DIRECTORY || type == G_FILE_TYPE_SYMBOLIC_LINK) {
|
|
GFile *child;
|
|
const gchar *name;
|
|
gpointer data;
|
|
|
|
/* Add the directory */
|
|
name = g_file_info_get_name (file_info);
|
|
child = g_file_get_child (uri, name);
|
|
|
|
if (icon_theme) {
|
|
CommonIconThemeDirMonitorData *monitor_data;
|
|
monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
|
|
monitor_data->priority = priority;
|
|
add_common_icon_theme_dir_monitor (child, monitor_data, error);
|
|
data = monitor_data;
|
|
} else {
|
|
CommonThemeDirMonitorData *monitor_data;
|
|
monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
|
|
monitor_data->priority = priority;
|
|
add_common_theme_dir_monitor (child, monitor_data, error);
|
|
data = monitor_data;
|
|
}
|
|
g_object_unref (child);
|
|
|
|
g_hash_table_insert (tuple->handle_hash, g_strdup (name), data);
|
|
}
|
|
g_object_unref (file_info);
|
|
}
|
|
g_file_enumerator_close (enumerator, NULL, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
add_top_theme_dir_monitor (GFile *uri,
|
|
gint priority,
|
|
GError **error)
|
|
{
|
|
return real_add_top_theme_dir_monitor (uri, priority, FALSE, error);
|
|
}
|
|
|
|
static gboolean
|
|
add_top_icon_theme_dir_monitor (GFile *uri,
|
|
gint priority,
|
|
GError **error)
|
|
{
|
|
return real_add_top_theme_dir_monitor (uri, priority, TRUE, error);
|
|
}
|
|
|
|
/* Public functions */
|
|
|
|
/* GTK/Metacity/keybinding Themes */
|
|
GnomeThemeInfo *
|
|
gnome_theme_info_new (void)
|
|
{
|
|
GnomeThemeInfo *theme_info;
|
|
|
|
theme_info = g_new0 (GnomeThemeInfo, 1);
|
|
theme_info->type = GNOME_THEME_TYPE_REGULAR;
|
|
|
|
return theme_info;
|
|
}
|
|
|
|
void
|
|
gnome_theme_info_free (GnomeThemeInfo *theme_info)
|
|
{
|
|
g_free (theme_info->path);
|
|
g_free (theme_info->name);
|
|
g_free (theme_info->readable_name);
|
|
g_free (theme_info);
|
|
}
|
|
|
|
GnomeThemeInfo *
|
|
gnome_theme_info_find (const gchar *theme_name)
|
|
{
|
|
return (GnomeThemeInfo *)
|
|
get_theme_from_hash_by_name (theme_hash_by_name, theme_name, -1);
|
|
}
|
|
|
|
struct GnomeThemeInfoHashData
|
|
{
|
|
gconstpointer user_data;
|
|
GList *list;
|
|
};
|
|
|
|
static void
|
|
gnome_theme_info_find_by_type_helper (gpointer key,
|
|
GList *list,
|
|
struct GnomeThemeInfoHashData *hash_data)
|
|
{
|
|
guint elements = GPOINTER_TO_INT (hash_data->user_data);
|
|
|
|
do {
|
|
GnomeThemeInfo *theme_info = list->data;
|
|
|
|
if ((elements & GNOME_THEME_METACITY && theme_info->has_metacity) ||
|
|
(elements & GNOME_THEME_GTK_2 && theme_info->has_gtk) ||
|
|
(elements & GNOME_THEME_GTK_2_KEYBINDING && theme_info->has_keybinding)) {
|
|
hash_data->list = g_list_prepend (hash_data->list, theme_info);
|
|
return;
|
|
}
|
|
|
|
list = list->next;
|
|
} while (list);
|
|
}
|
|
|
|
GList *
|
|
gnome_theme_info_find_by_type (guint elements)
|
|
{
|
|
struct GnomeThemeInfoHashData data;
|
|
data.user_data = GINT_TO_POINTER (elements);
|
|
data.list = NULL;
|
|
|
|
g_hash_table_foreach (theme_hash_by_name,
|
|
(GHFunc) gnome_theme_info_find_by_type_helper,
|
|
&data);
|
|
|
|
return data.list;
|
|
}
|
|
|
|
static void
|
|
gnome_theme_info_find_all_helper (const gchar *key,
|
|
GList *list,
|
|
GList **themes)
|
|
{
|
|
*themes = g_list_prepend (*themes, list->data);
|
|
}
|
|
|
|
gchar *
|
|
gtk_theme_info_missing_engine (const gchar *gtk_theme, gboolean nameOnly)
|
|
{
|
|
gchar *engine = NULL;
|
|
gchar *gtkrc;
|
|
|
|
gtkrc = gtkrc_find_named (gtk_theme);
|
|
if (gtkrc) {
|
|
GSList *engines = NULL, *l;
|
|
gboolean found;
|
|
|
|
gtkrc_get_details (gtkrc, &engines, NULL);
|
|
g_free (gtkrc);
|
|
|
|
for (l = engines; l; l = l->next) {
|
|
gchar *lib = g_strconcat ("lib", l->data, ".so", NULL);
|
|
gchar *full = g_build_filename (GTK_ENGINE_DIR, lib, NULL);
|
|
|
|
g_free (lib);
|
|
found = g_file_test (full, G_FILE_TEST_EXISTS);
|
|
|
|
if (!found) {
|
|
if (nameOnly)
|
|
engine = g_strdup (l->data);
|
|
else
|
|
engine = full;
|
|
break;
|
|
}
|
|
|
|
g_free (full);
|
|
}
|
|
|
|
g_slist_foreach (engines, (GFunc) g_free, NULL);
|
|
g_slist_free (engines);
|
|
}
|
|
|
|
return engine;
|
|
}
|
|
|
|
/* Icon themes */
|
|
GnomeThemeIconInfo *
|
|
gnome_theme_icon_info_new (void)
|
|
{
|
|
GnomeThemeIconInfo *icon_theme_info;
|
|
|
|
icon_theme_info = g_new0 (GnomeThemeIconInfo, 1);
|
|
icon_theme_info->type = GNOME_THEME_TYPE_ICON;
|
|
|
|
return icon_theme_info;
|
|
}
|
|
|
|
void
|
|
gnome_theme_icon_info_free (GnomeThemeIconInfo *icon_theme_info)
|
|
{
|
|
g_free (icon_theme_info->name);
|
|
g_free (icon_theme_info->readable_name);
|
|
g_free (icon_theme_info->path);
|
|
g_free (icon_theme_info);
|
|
}
|
|
|
|
GnomeThemeIconInfo *
|
|
gnome_theme_icon_info_find (const gchar *icon_theme_name)
|
|
{
|
|
g_return_val_if_fail (icon_theme_name != NULL, NULL);
|
|
|
|
return (GnomeThemeIconInfo *)
|
|
get_theme_from_hash_by_name (icon_theme_hash_by_name, icon_theme_name, -1);
|
|
}
|
|
|
|
GList *
|
|
gnome_theme_icon_info_find_all (void)
|
|
{
|
|
GList *list = NULL;
|
|
|
|
g_hash_table_foreach (icon_theme_hash_by_name,
|
|
(GHFunc) gnome_theme_info_find_all_helper,
|
|
&list);
|
|
|
|
return list;
|
|
}
|
|
|
|
gint
|
|
gnome_theme_icon_info_compare (GnomeThemeIconInfo *a,
|
|
GnomeThemeIconInfo *b)
|
|
{
|
|
gint cmp;
|
|
|
|
cmp = safe_strcmp (a->path, b->path);
|
|
if (cmp != 0) return cmp;
|
|
|
|
return safe_strcmp (a->name, b->name);
|
|
}
|
|
|
|
/* Cursor themes */
|
|
GnomeThemeCursorInfo *
|
|
gnome_theme_cursor_info_new (void)
|
|
{
|
|
GnomeThemeCursorInfo *theme_info;
|
|
|
|
theme_info = g_new0 (GnomeThemeCursorInfo, 1);
|
|
theme_info->type = GNOME_THEME_TYPE_CURSOR;
|
|
|
|
return theme_info;
|
|
}
|
|
|
|
void
|
|
gnome_theme_cursor_info_free (GnomeThemeCursorInfo *cursor_theme_info)
|
|
{
|
|
g_free (cursor_theme_info->name);
|
|
g_free (cursor_theme_info->readable_name);
|
|
g_free (cursor_theme_info->path);
|
|
g_array_free (cursor_theme_info->sizes, TRUE);
|
|
if (cursor_theme_info->thumbnail != NULL)
|
|
g_object_unref (cursor_theme_info->thumbnail);
|
|
g_free (cursor_theme_info);
|
|
}
|
|
|
|
GnomeThemeCursorInfo *
|
|
gnome_theme_cursor_info_find (const gchar *cursor_theme_name)
|
|
{
|
|
g_return_val_if_fail (cursor_theme_name != NULL, NULL);
|
|
|
|
return (GnomeThemeCursorInfo *)
|
|
get_theme_from_hash_by_name (cursor_theme_hash_by_name, cursor_theme_name, -1);
|
|
}
|
|
|
|
GList *
|
|
gnome_theme_cursor_info_find_all (void)
|
|
{
|
|
GList *list = NULL;
|
|
|
|
g_hash_table_foreach (cursor_theme_hash_by_name,
|
|
(GHFunc) gnome_theme_info_find_all_helper,
|
|
&list);
|
|
|
|
return list;
|
|
}
|
|
|
|
gint
|
|
gnome_theme_cursor_info_compare (GnomeThemeCursorInfo *a,
|
|
GnomeThemeCursorInfo *b)
|
|
{
|
|
gint cmp;
|
|
|
|
cmp = safe_strcmp (a->path, b->path);
|
|
if (cmp != 0) return cmp;
|
|
|
|
return safe_strcmp (a->name, b->name);
|
|
}
|
|
|
|
/* Meta themes */
|
|
GnomeThemeMetaInfo *
|
|
gnome_theme_meta_info_new (void)
|
|
{
|
|
GnomeThemeMetaInfo *theme_info;
|
|
|
|
theme_info = g_new0 (GnomeThemeMetaInfo, 1);
|
|
theme_info->type = GNOME_THEME_TYPE_METATHEME;
|
|
|
|
return theme_info;
|
|
}
|
|
|
|
void
|
|
gnome_theme_meta_info_free (GnomeThemeMetaInfo *meta_theme_info)
|
|
{
|
|
g_free (meta_theme_info->path);
|
|
g_free (meta_theme_info->readable_name);
|
|
g_free (meta_theme_info->name);
|
|
g_free (meta_theme_info->comment);
|
|
g_free (meta_theme_info->application_font);
|
|
g_free (meta_theme_info->documents_font);
|
|
g_free (meta_theme_info->desktop_font);
|
|
g_free (meta_theme_info->windowtitle_font);
|
|
g_free (meta_theme_info->monospace_font);
|
|
g_free (meta_theme_info->background_image);
|
|
g_free (meta_theme_info->gtk_theme_name);
|
|
g_free (meta_theme_info->gtk_color_scheme);
|
|
g_free (meta_theme_info->icon_theme_name);
|
|
g_free (meta_theme_info->metacity_theme_name);
|
|
g_free (meta_theme_info);
|
|
}
|
|
|
|
gboolean
|
|
gnome_theme_meta_info_validate (const GnomeThemeMetaInfo *info, GError **error)
|
|
{
|
|
GnomeThemeInfo *theme;
|
|
gchar *engine;
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
theme = gnome_theme_info_find (info->gtk_theme_name);
|
|
if (!theme || !theme->has_gtk) {
|
|
g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_GTK_THEME_NOT_AVAILABLE,
|
|
_("This theme will not look as intended because the required GTK+ theme '%s' is not installed."),
|
|
info->gtk_theme_name);
|
|
return FALSE;
|
|
}
|
|
|
|
theme = gnome_theme_info_find (info->metacity_theme_name);
|
|
if (!theme || !theme->has_metacity) {
|
|
g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_WM_THEME_NOT_AVAILABLE,
|
|
_("This theme will not look as intended because the required window manager theme '%s' is not installed."),
|
|
info->metacity_theme_name);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gnome_theme_icon_info_find (info->icon_theme_name)) {
|
|
g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_ICON_THEME_NOT_AVAILABLE,
|
|
_("This theme will not look as intended because the required icon theme '%s' is not installed."),
|
|
info->icon_theme_name);
|
|
return FALSE;
|
|
}
|
|
|
|
/* check for gtk theme engines */
|
|
engine = gtk_theme_info_missing_engine (info->gtk_theme_name, TRUE);
|
|
if (engine != NULL) {
|
|
g_set_error (error, GNOME_THEME_ERROR, GNOME_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE,
|
|
_("This theme will not look as intended because the required GTK+ theme engine '%s' is not installed."),
|
|
engine);
|
|
g_free (engine);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GnomeThemeMetaInfo *
|
|
gnome_theme_meta_info_find (const char *meta_theme_name)
|
|
{
|
|
g_return_val_if_fail (meta_theme_name != NULL, NULL);
|
|
|
|
return (GnomeThemeMetaInfo *)
|
|
get_theme_from_hash_by_name (meta_theme_hash_by_name, meta_theme_name, -1);
|
|
}
|
|
|
|
GList *
|
|
gnome_theme_meta_info_find_all (void)
|
|
{
|
|
GList *list = NULL;
|
|
|
|
g_hash_table_foreach (meta_theme_hash_by_name,
|
|
(GHFunc) gnome_theme_info_find_all_helper,
|
|
&list);
|
|
|
|
return list;
|
|
}
|
|
|
|
gint
|
|
gnome_theme_meta_info_compare (GnomeThemeMetaInfo *a,
|
|
GnomeThemeMetaInfo *b)
|
|
{
|
|
gint cmp;
|
|
|
|
cmp = safe_strcmp (a->path, b->path);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->readable_name, b->readable_name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->name, b->name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->comment, b->comment);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->icon_file, b->icon_file);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->gtk_theme_name, b->gtk_theme_name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->gtk_color_scheme, b->gtk_color_scheme);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->metacity_theme_name, b->metacity_theme_name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->icon_theme_name, b->icon_theme_name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->sound_theme_name, b->sound_theme_name);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->application_font, b->application_font);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->documents_font, b->documents_font);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->desktop_font, b->desktop_font);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->windowtitle_font, b->windowtitle_font);
|
|
if (cmp != 0) return cmp;
|
|
|
|
cmp = safe_strcmp (a->monospace_font, b->monospace_font);
|
|
if (cmp != 0) return cmp;
|
|
|
|
return safe_strcmp (a->background_image, b->background_image);
|
|
}
|
|
|
|
void
|
|
gnome_theme_info_register_theme_change (ThemeChangedCallback func,
|
|
gpointer data)
|
|
{
|
|
ThemeCallbackData *callback_data;
|
|
|
|
g_return_if_fail (func != NULL);
|
|
|
|
callback_data = g_new (ThemeCallbackData, 1);
|
|
callback_data->func = func;
|
|
callback_data->data = data;
|
|
|
|
callbacks = g_list_prepend (callbacks, callback_data);
|
|
}
|
|
|
|
gboolean
|
|
gnome_theme_color_scheme_parse (const gchar *scheme, GdkColor *colors)
|
|
{
|
|
gchar **color_scheme_strings, **color_scheme_pair, *current_string;
|
|
gint i;
|
|
|
|
if (!scheme || !strcmp (scheme, ""))
|
|
return FALSE;
|
|
|
|
/* initialise the array */
|
|
for (i = 0; i < NUM_SYMBOLIC_COLORS; i++)
|
|
colors[i].red = colors[i].green = colors[i].blue = 0;
|
|
|
|
/* The color scheme string consists of name:color pairs, separated by
|
|
* newlines, so first we split the string up by new line */
|
|
|
|
color_scheme_strings = g_strsplit (scheme, "\n", 0);
|
|
|
|
/* loop through the name:color pairs, and save the color if we recognise the name */
|
|
i = 0;
|
|
while ((current_string = color_scheme_strings[i++])) {
|
|
color_scheme_pair = g_strsplit (current_string, ":", 0);
|
|
|
|
if (color_scheme_pair[0] != NULL && color_scheme_pair[1] != NULL) {
|
|
g_strstrip (color_scheme_pair[0]);
|
|
g_strstrip (color_scheme_pair[1]);
|
|
|
|
if (!strcmp ("fg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_FG]);
|
|
else if (!strcmp ("bg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BG]);
|
|
else if (!strcmp ("text_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TEXT]);
|
|
else if (!strcmp ("base_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BASE]);
|
|
else if (!strcmp ("selected_fg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_FG]);
|
|
else if (!strcmp ("selected_bg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_BG]);
|
|
else if (!strcmp ("tooltip_fg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_FG]);
|
|
else if (!strcmp ("tooltip_bg_color", color_scheme_pair[0]))
|
|
gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_BG]);
|
|
}
|
|
|
|
g_strfreev (color_scheme_pair);
|
|
}
|
|
|
|
g_strfreev (color_scheme_strings);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gnome_theme_color_scheme_equal (const gchar *s1, const gchar *s2)
|
|
{
|
|
GdkColor c1[NUM_SYMBOLIC_COLORS], c2[NUM_SYMBOLIC_COLORS];
|
|
int i;
|
|
|
|
if (!gnome_theme_color_scheme_parse (s1, c1) ||
|
|
!gnome_theme_color_scheme_parse (s2, c2))
|
|
return FALSE;
|
|
|
|
for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
|
|
if (!gdk_color_equal (&c1[i], &c2[i]))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
gnome_theme_init ()
|
|
{
|
|
GFile *top_theme_dir;
|
|
gchar *top_theme_dir_string;
|
|
static gboolean initted = FALSE;
|
|
const gchar *gtk_data_dir;
|
|
if (initted)
|
|
return;
|
|
|
|
initting = TRUE;
|
|
|
|
meta_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
meta_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
icon_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
icon_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
cursor_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
cursor_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
/* Add all the toplevel theme dirs. */
|
|
/* $datadir/themes */
|
|
top_theme_dir_string = gtk_rc_get_theme_dir ();
|
|
top_theme_dir = g_file_new_for_path (top_theme_dir_string);
|
|
g_free (top_theme_dir_string);
|
|
add_top_theme_dir_monitor (top_theme_dir, 1, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
|
|
/* ~/.themes */
|
|
top_theme_dir_string = g_build_filename (g_get_home_dir (), ".themes", NULL);
|
|
top_theme_dir = g_file_new_for_path (top_theme_dir_string);
|
|
g_free (top_theme_dir_string);
|
|
if (!g_file_query_exists (top_theme_dir, NULL))
|
|
g_file_make_directory (top_theme_dir, NULL, NULL);
|
|
add_top_theme_dir_monitor (top_theme_dir, 0, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
|
|
/* The weird /usr/share/icons */
|
|
top_theme_dir = g_file_new_for_path ("/usr/share/icons");
|
|
add_top_icon_theme_dir_monitor (top_theme_dir, 2, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
|
|
/* $datadir/icons */
|
|
gtk_data_dir = g_getenv ("GTK_DATA_PREFIX");
|
|
if (gtk_data_dir)
|
|
top_theme_dir_string = g_build_filename (gtk_data_dir, "share", "icons", NULL);
|
|
else
|
|
top_theme_dir_string = g_build_filename (INSTALL_PREFIX, "share", "icons", NULL);
|
|
|
|
#ifdef XCURSOR_ICONDIR
|
|
/* if there's a separate xcursors dir, add that as well */
|
|
if (strcmp (XCURSOR_ICONDIR, top_theme_dir_string) &&
|
|
strcmp (XCURSOR_ICONDIR, "/usr/share/icons")) {
|
|
top_theme_dir = g_file_new_for_path (XCURSOR_ICONDIR);
|
|
if (g_file_query_exists (top_theme_dir, NULL))
|
|
add_top_icon_theme_dir_monitor (top_theme_dir, 1, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
}
|
|
#endif
|
|
|
|
top_theme_dir = g_file_new_for_path (top_theme_dir_string);
|
|
g_free (top_theme_dir_string);
|
|
add_top_icon_theme_dir_monitor (top_theme_dir, 1, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
|
|
/* ~/.icons */
|
|
top_theme_dir_string = g_build_filename (g_get_home_dir (), ".icons", NULL);
|
|
top_theme_dir = g_file_new_for_path (top_theme_dir_string);
|
|
g_free (top_theme_dir_string);
|
|
|
|
if (!g_file_query_exists (top_theme_dir, NULL))
|
|
g_file_make_directory (top_theme_dir, NULL, NULL);
|
|
add_top_icon_theme_dir_monitor (top_theme_dir, 0, NULL);
|
|
g_object_unref (top_theme_dir);
|
|
|
|
#ifdef HAVE_XCURSOR
|
|
/* make sure we have the default theme */
|
|
if (!gnome_theme_cursor_info_find ("default"))
|
|
add_default_cursor_theme ();
|
|
#else
|
|
/* If we don't have Xcursor, use the built-in cursor fonts instead */
|
|
read_cursor_fonts ();
|
|
#endif
|
|
|
|
/* done */
|
|
initted = TRUE;
|
|
initting = FALSE;
|
|
}
|