summaryrefslogtreecommitdiff
path: root/src/gs-theme-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gs-theme-manager.c')
-rw-r--r--src/gs-theme-manager.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/gs-theme-manager.c b/src/gs-theme-manager.c
new file mode 100644
index 0000000..32b086f
--- /dev/null
+++ b/src/gs-theme-manager.c
@@ -0,0 +1,453 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: William Jon McCann <[email protected]>
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <glib-object.h>
+#include <matemenu-tree.h>
+
+#include "gs-theme-manager.h"
+#include "gs-debug.h"
+
+static void gs_theme_manager_class_init (GSThemeManagerClass *klass);
+static void gs_theme_manager_init (GSThemeManager *theme_manager);
+static void gs_theme_manager_finalize (GObject *object);
+
+#define GS_THEME_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_THEME_MANAGER, GSThemeManagerPrivate))
+
+struct _GSThemeInfo
+{
+ char *name;
+ char *exec;
+ char *file_id;
+ guint refcount;
+};
+
+struct GSThemeManagerPrivate
+{
+ MateMenuTree *menu_tree;
+};
+
+G_DEFINE_TYPE (GSThemeManager, gs_theme_manager, G_TYPE_OBJECT)
+
+static gpointer theme_manager_object = NULL;
+
+static const char *known_engine_locations [] =
+{
+ SAVERDIR,
+#ifdef XSCREENSAVER_HACK_DIR
+ XSCREENSAVER_HACK_DIR,
+#endif
+ LIBEXECDIR "/xscreensaver",
+ "/usr/libexec/xscreensaver",
+ "/usr/lib/xscreensaver",
+ NULL
+};
+
+/* Returns the full path to the queried command */
+static char *
+find_command (const char *command)
+{
+ int i;
+
+ if (g_path_is_absolute (command))
+ {
+ char *dirname;
+
+ dirname = g_path_get_dirname (command);
+ for (i = 0; known_engine_locations [i]; i++)
+ {
+ if (strcmp (dirname, known_engine_locations [i]) == 0)
+ {
+ if (g_file_test (command, G_FILE_TEST_IS_EXECUTABLE)
+ && ! g_file_test (command, G_FILE_TEST_IS_DIR))
+ {
+ g_free (dirname);
+ return g_strdup (command);
+ }
+ }
+ }
+ g_free (dirname);
+ }
+ else
+ {
+ for (i = 0; known_engine_locations [i]; i++)
+ {
+ char *path;
+
+ path = g_build_filename (known_engine_locations [i], command, NULL);
+
+ if (g_file_test (path, G_FILE_TEST_IS_EXECUTABLE)
+ && ! g_file_test (path, G_FILE_TEST_IS_DIR))
+ {
+ return path;
+ }
+
+ g_free (path);
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+check_command (const char *command)
+{
+ char *path;
+ char **argv;
+
+ g_return_val_if_fail (command != NULL, FALSE);
+
+ g_shell_parse_argv (command, NULL, &argv, NULL);
+ path = find_command (argv [0]);
+ g_strfreev (argv);
+
+ if (path != NULL)
+ {
+ g_free (path);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+add_known_engine_locations_to_path (void)
+{
+ static gboolean already_added;
+ int i;
+ GString *str;
+
+ /* We only want to add the items to the path once */
+ if (already_added)
+ {
+ return;
+ }
+
+ already_added = TRUE;
+
+ /* TODO: set a default PATH ? */
+
+ str = g_string_new (g_getenv ("PATH"));
+ for (i = 0; known_engine_locations [i]; i++)
+ {
+ /* TODO: check that permissions are safe */
+ if (g_file_test (known_engine_locations [i], G_FILE_TEST_IS_DIR))
+ {
+ g_string_append_printf (str, ":%s", known_engine_locations [i]);
+ }
+ }
+
+ g_setenv ("PATH", str->str, TRUE);
+ g_string_free (str, TRUE);
+}
+
+GSThemeInfo *
+gs_theme_info_ref (GSThemeInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+ g_return_val_if_fail (info->refcount > 0, NULL);
+
+ info->refcount++;
+
+ return info;
+}
+
+void
+gs_theme_info_unref (GSThemeInfo *info)
+{
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (info->refcount > 0);
+
+ if (--info->refcount == 0)
+ {
+ g_free (info->name);
+ g_free (info->exec);
+ g_free (info->file_id);
+
+ g_free (info);
+ }
+}
+
+const char *
+gs_theme_info_get_id (GSThemeInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->file_id;
+}
+
+const char *
+gs_theme_info_get_name (GSThemeInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->name;
+}
+
+const char *
+gs_theme_info_get_exec (GSThemeInfo *info)
+{
+ const char *exec;
+
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (check_command (info->exec))
+ {
+ exec = info->exec;
+ }
+ else
+ {
+ exec = NULL;
+ }
+
+ return exec;
+}
+
+static GSThemeInfo *
+gs_theme_info_new_from_matemenu_tree_entry (MateMenuTreeEntry *entry)
+{
+ GSThemeInfo *info;
+ const char *str;
+ char *pos;
+
+ info = g_new0 (GSThemeInfo, 1);
+
+ info->refcount = 1;
+ info->name = g_strdup (matemenu_tree_entry_get_name (entry));
+ info->exec = g_strdup (matemenu_tree_entry_get_exec (entry));
+
+ /* remove the .desktop suffix */
+ str = matemenu_tree_entry_get_desktop_file_id (entry);
+ pos = g_strrstr (str, ".desktop");
+ if (pos)
+ {
+ info->file_id = g_strndup (str, pos - str);
+ }
+ else
+ {
+ info->file_id = g_strdup (str);
+ }
+
+ return info;
+}
+
+static GSThemeInfo *
+find_info_for_id (MateMenuTree *tree,
+ const char *id)
+{
+ GSThemeInfo *info;
+ MateMenuTreeDirectory *root;
+ GSList *items;
+ GSList *l;
+
+ root = matemenu_tree_get_root_directory (tree);
+ if (root == NULL)
+ {
+ return NULL;
+ }
+
+ items = matemenu_tree_directory_get_contents (root);
+
+ info = NULL;
+
+ for (l = items; l; l = l->next)
+ {
+ if (info == NULL
+ && matemenu_tree_item_get_type (l->data) == MATEMENU_TREE_ITEM_ENTRY)
+ {
+ MateMenuTreeEntry *entry = l->data;
+ const char *file_id;
+
+ file_id = matemenu_tree_entry_get_desktop_file_id (entry);
+ if (file_id && id && strcmp (file_id, id) == 0)
+ {
+ info = gs_theme_info_new_from_matemenu_tree_entry (entry);
+ }
+ }
+
+ matemenu_tree_item_unref (l->data);
+ }
+
+ g_slist_free (items);
+ matemenu_tree_item_unref (root);
+
+ return info;
+}
+
+GSThemeInfo *
+gs_theme_manager_lookup_theme_info (GSThemeManager *theme_manager,
+ const char *name)
+{
+ GSThemeInfo *info;
+ char *id;
+
+ g_return_val_if_fail (GS_IS_THEME_MANAGER (theme_manager), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ id = g_strdup_printf ("%s.desktop", name);
+ info = find_info_for_id (theme_manager->priv->menu_tree, id);
+ g_free (id);
+
+ return info;
+}
+
+static void
+theme_prepend_entry (GSList **parent_list,
+ MateMenuTreeEntry *entry,
+ const char *filename)
+{
+ GSThemeInfo *info;
+
+ info = gs_theme_info_new_from_matemenu_tree_entry (entry);
+
+ *parent_list = g_slist_prepend (*parent_list, info);
+}
+
+static void
+make_theme_list (GSList **parent_list,
+ MateMenuTreeDirectory *directory,
+ const char *filename)
+{
+ GSList *items;
+ GSList *l;
+
+ items = matemenu_tree_directory_get_contents (directory);
+
+ for (l = items; l; l = l->next)
+ {
+ switch (matemenu_tree_item_get_type (l->data))
+ {
+
+ case MATEMENU_TREE_ITEM_ENTRY:
+ theme_prepend_entry (parent_list, l->data, filename);
+ break;
+
+ case MATEMENU_TREE_ITEM_ALIAS:
+ case MATEMENU_TREE_ITEM_DIRECTORY:
+ default:
+ break;
+ }
+
+ matemenu_tree_item_unref (l->data);
+ }
+
+ g_slist_free (items);
+
+ *parent_list = g_slist_reverse (*parent_list);
+}
+
+GSList *
+gs_theme_manager_get_info_list (GSThemeManager *theme_manager)
+{
+ GSList *l = NULL;
+ MateMenuTreeDirectory *root;
+
+ g_return_val_if_fail (GS_IS_THEME_MANAGER (theme_manager), NULL);
+
+ root = matemenu_tree_get_root_directory (theme_manager->priv->menu_tree);
+
+ if (root != NULL)
+ {
+ make_theme_list (&l, root, "mate-screensavers.menu");
+ matemenu_tree_item_unref (root);
+ }
+
+ return l;
+}
+
+static void
+gs_theme_manager_class_init (GSThemeManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gs_theme_manager_finalize;
+
+ g_type_class_add_private (klass, sizeof (GSThemeManagerPrivate));
+}
+
+static MateMenuTree *
+get_themes_tree (void)
+{
+ MateMenuTree *themes_tree = NULL;
+
+ /* we only need to add the locations to the path once
+ and since this is only run once we'll do it here */
+ add_known_engine_locations_to_path ();
+
+ themes_tree = matemenu_tree_lookup ("mate-screensavers.menu", MATEMENU_TREE_FLAGS_NONE);
+
+ return themes_tree;
+}
+
+static void
+gs_theme_manager_init (GSThemeManager *theme_manager)
+{
+ theme_manager->priv = GS_THEME_MANAGER_GET_PRIVATE (theme_manager);
+
+ theme_manager->priv->menu_tree = get_themes_tree ();
+}
+
+static void
+gs_theme_manager_finalize (GObject *object)
+{
+ GSThemeManager *theme_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GS_IS_THEME_MANAGER (object));
+
+ theme_manager = GS_THEME_MANAGER (object);
+
+ g_return_if_fail (theme_manager->priv != NULL);
+
+ if (theme_manager->priv->menu_tree != NULL)
+ {
+ matemenu_tree_unref (theme_manager->priv->menu_tree);
+ }
+
+ G_OBJECT_CLASS (gs_theme_manager_parent_class)->finalize (object);
+}
+
+GSThemeManager *
+gs_theme_manager_new (void)
+{
+ if (theme_manager_object)
+ {
+ g_object_ref (theme_manager_object);
+ }
+ else
+ {
+ theme_manager_object = g_object_new (GS_TYPE_THEME_MANAGER, NULL);
+ g_object_add_weak_pointer (theme_manager_object,
+ (gpointer *) &theme_manager_object);
+ }
+
+ return GS_THEME_MANAGER (theme_manager_object);
+}