summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2011-08-17 01:13:52 -0400
committerJasper St. Pierre <jstpierre@mecheye.net>2011-08-26 11:54:24 -0400
commitaadad2377c841570b90a409c0a9ae51429cfff6c (patch)
tree8ba72ef5e764a358034fd542a34607c07dcc1a3f
parentf41c07f6a95a5a22891db45681afeb05bef669c5 (diff)
downloadgnome-session-aadad2377c841570b90a409c0a9ae51429cfff6c.tar.gz
gsm: Add a new system to get information and frob Shell Extensions
This functionality will be used to allow the user to enable and disable GNOME Shell Extensions in the fail whale dialog after a crash. https://bugzilla.gnome.org/show_bug.cgi?id=656747
-rw-r--r--configure.ac2
-rw-r--r--gnome-session/Makefile.am2
-rw-r--r--gnome-session/gsm-shell-extensions.c375
-rw-r--r--gnome-session/gsm-shell-extensions.h84
4 files changed, 463 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index b1833d54..1af6c3aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,7 @@ GLIB_REQUIRED=2.28.0
GTK3_REQUIRED=2.90.7
DBUS_GLIB_REQUIRED=0.76
UPOWER_REQUIRED=0.9.0
+JSON_GLIB_REQUIRED=0.10
dnl ====================================================================
dnl Dependency Checks
@@ -51,6 +52,7 @@ PKG_CHECK_MODULES(GNOME_SESSION,
gtk+-3.0 >= $GTK3_REQUIRED
dbus-glib-1 >= $DBUS_GLIB_REQUIRED
upower-glib >= $UPOWER_REQUIRED
+ json-glib-1.0 >= $JSON_GLIB_REQUIRED
)
PKG_CHECK_MODULES(SESSION_PROPERTIES,
diff --git a/gnome-session/Makefile.am b/gnome-session/Makefile.am
index e86c06a9..2c5a36cb 100644
--- a/gnome-session/Makefile.am
+++ b/gnome-session/Makefile.am
@@ -58,6 +58,8 @@ gnome_session_SOURCES = \
gsm-session-fill.h \
gsm-session-save.c \
gsm-session-save.h \
+ gsm-shell-extensions.c \
+ gsm-shell-extensions.h \
gsm-shell.c \
gsm-shell.h \
gsm-xsmp-server.c \
diff --git a/gnome-session/gsm-shell-extensions.c b/gnome-session/gsm-shell-extensions.c
new file mode 100644
index 00000000..60eaf2f6
--- /dev/null
+++ b/gnome-session/gsm-shell-extensions.c
@@ -0,0 +1,375 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011 Red Hat, Inc
+ *
+ * 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, 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:
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <json-glib/json-glib.h>
+
+#include "gsm-shell-extensions.h"
+
+
+struct _GsmShellExtension
+{
+ gchar *uuid;
+
+ gchar *name;
+ gchar *description;
+ gboolean enabled;
+};
+
+static void
+gsm_shell_extension_free (gpointer data)
+{
+ GsmShellExtension *extension = (GsmShellExtension *)data;
+
+ g_free (extension->uuid);
+ g_free (extension->name);
+ g_free (extension->description);
+}
+
+gchar *
+gsm_shell_extension_get_uuid (GsmShellExtension *extension)
+{
+ return extension->uuid;
+}
+
+gchar *
+gsm_shell_extension_get_name (GsmShellExtension *extension)
+{
+ return extension->name;
+}
+
+gchar *
+gsm_shell_extension_get_description (GsmShellExtension *extension)
+{
+ return extension->description;
+}
+
+gboolean
+gsm_shell_extension_get_is_enabled (GsmShellExtension *extension)
+{
+ return extension->enabled;
+}
+
+#define SHELL_SCHEMA "org.gnome.shell"
+#define ENABLED_EXTENSIONS_KEY "enabled-extensions"
+
+#define SHELL_EXTENSIONS_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_SHELL_EXTENSIONS, GsmShellExtensionsPrivate))
+
+struct _GsmShellExtensionsPrivate
+{
+ GSettings *settings;
+
+ /* uuid => GsmShellExtension */
+ GHashTable *uuid_to_extension;
+};
+
+G_DEFINE_TYPE (GsmShellExtensions, gsm_shell_extensions, G_TYPE_OBJECT);
+
+/**
+ * gsm_shell_extensions_finalize:
+ * @object: (in): A #GsmShellExtensions.
+ *
+ * Finalizer for a #GsmShellExtensions instance. Frees any resources held by
+ * the instance.
+ */
+static void
+gsm_shell_extensions_finalize (GObject *object)
+{
+ GsmShellExtensions *extensions = GSM_SHELL_EXTENSIONS (object);
+ GsmShellExtensionsPrivate *priv = extensions->priv;
+
+ if (priv->settings != NULL)
+ {
+ g_object_unref (priv->settings);
+ priv->settings = NULL;
+ }
+
+ if (priv->uuid_to_extension != NULL)
+ {
+ g_hash_table_unref (priv->uuid_to_extension);
+ priv->uuid_to_extension = NULL;
+ }
+
+ G_OBJECT_CLASS (gsm_shell_extensions_parent_class)->finalize (object);
+}
+
+/**
+ * gsm_shell_extensions_class_init:
+ * @klass: (in): A #GsmShellExtensionsClass.
+ *
+ * Initializes the #GsmShellExtensionsClass and prepares the vtable.
+ */
+static void
+gsm_shell_extensions_class_init (GsmShellExtensionsClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gsm_shell_extensions_finalize;
+ g_type_class_add_private (object_class, sizeof (GsmShellExtensionsPrivate));
+}
+
+static void
+gsm_shell_extensions_fetch_enabled (GsmShellExtensions *self)
+{
+ gchar **enabled_uuids;
+ gchar **uuids;
+
+ enabled_uuids = g_settings_get_strv (self->priv->settings, ENABLED_EXTENSIONS_KEY);
+
+ uuids = enabled_uuids;
+ while (*uuids != '\0')
+ {
+ GsmShellExtension *extension;
+ extension = g_hash_table_lookup (self->priv->uuid_to_extension, *uuids);
+ if (extension != NULL)
+ extension->enabled = TRUE;
+
+ uuids ++;
+ }
+
+ g_strfreev (enabled_uuids);
+}
+
+static void
+gsm_shell_extensions_scan_dir (GsmShellExtensions *self,
+ GFile *dir)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ JsonParser *metadata_parser;
+
+ metadata_parser = json_parser_new ();
+
+ enumerator = g_file_enumerate_children (dir,
+ "standard::*",
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+
+ if (enumerator == NULL)
+ return;
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
+ {
+ GsmShellExtension *extension = g_slice_new (GsmShellExtension);
+ gchar *metadata_filename;
+ gchar *metadata_uuid;
+ JsonObject *metadata_root;
+
+ extension->uuid = (char *) g_file_info_get_name (info);
+
+ metadata_filename = g_build_filename (g_file_get_path (dir),
+ extension->uuid,
+ "metadata.json",
+ NULL);
+
+ if (!json_parser_load_from_file (metadata_parser, metadata_filename, NULL))
+ continue;
+
+ g_free (metadata_filename);
+
+ metadata_root = json_node_get_object (json_parser_get_root (metadata_parser));
+
+ metadata_uuid = g_strdup (json_object_get_string_member (metadata_root, "uuid"));
+ if (!g_str_equal (metadata_uuid, extension->uuid))
+ {
+ g_warning ("Extension with dirname '%s' does not match metadata's UUID of '%s'. Skipping.",
+ extension->uuid,
+ metadata_uuid);
+ continue;
+ }
+
+ extension->enabled = FALSE;
+ extension->name = g_strdup (json_object_get_string_member (metadata_root, "name"));
+ extension->description = g_strdup (json_object_get_string_member (metadata_root, "description"));
+
+ g_hash_table_insert (self->priv->uuid_to_extension,
+ g_strdup (extension->uuid), extension);
+ }
+}
+
+static void
+gsm_shell_extensions_scan (GsmShellExtensions *self)
+{
+ gchar *dirname;
+ GFile *dir;
+ const gchar * const * system_data_dirs;
+
+ /* User data dir first. */
+ dirname = g_build_filename (g_get_user_data_dir (), "gnome-shell", "extensions", NULL);
+ dir = g_file_new_for_path (dirname);
+ g_free (dirname);
+
+ gsm_shell_extensions_scan_dir (self, dir);
+ g_object_unref (dir);
+
+ system_data_dirs = g_get_system_data_dirs ();
+ while ((*system_data_dirs) != '\0')
+ {
+ dirname = g_build_filename (*system_data_dirs, "gnome-shell", "extensions", NULL);
+ dir = g_file_new_for_path (dirname);
+ g_free (dirname);
+
+ gsm_shell_extensions_scan_dir (self, dir);
+ g_object_unref (dir);
+ system_data_dirs ++;
+ }
+}
+
+/**
+ * gsm_shell_extensions_init:
+ * @self: (in): A #GsmShellExtensions.
+ *
+ * Initializes the newly created #GsmShellExtensions instance.
+ */
+static void
+gsm_shell_extensions_init (GsmShellExtensions *self)
+{
+ gchar * const * schemas;
+
+ self->priv = SHELL_EXTENSIONS_PRIVATE (self);
+
+ /* Unfortunately, gsettings does not have a way to test
+ * for the existance of a schema, so hack around it. */
+ schemas = g_settings_list_schemas ();
+ while (schemas != '\0')
+ {
+ if (g_str_equal (*schemas, SHELL_SCHEMA))
+ {
+ self->priv->settings = g_settings_new (SHELL_SCHEMA);
+ break;
+ }
+
+ schemas ++;
+ }
+
+ if (self->priv->settings)
+ {
+ self->priv->uuid_to_extension = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ gsm_shell_extension_free);
+ gsm_shell_extensions_scan (self);
+ gsm_shell_extensions_fetch_enabled (self);
+ }
+}
+
+gboolean
+gsm_shell_extensions_set_enabled (GsmShellExtensions *self,
+ gchar *uuid,
+ gboolean enabled)
+{
+ gsize i, length;
+ gchar **uuids;
+ const gchar **new_uuids;
+ GsmShellExtension *extension;
+
+ if (self->priv->settings == NULL)
+ return FALSE;
+
+ extension = g_hash_table_lookup (self->priv->uuid_to_extension,
+ uuid);
+
+ if (extension == NULL)
+ return FALSE;
+
+ if (extension->enabled == enabled)
+ return TRUE;
+
+ uuids = g_settings_get_strv (self->priv->settings, ENABLED_EXTENSIONS_KEY);
+ length = g_strv_length (uuids);
+
+ if (enabled)
+ {
+ new_uuids = g_new (const gchar *, length + 2); /* New key, NULL */
+ for (i = 0; i < length; i ++)
+ new_uuids[i] = g_strdup (uuids[i]);
+
+ new_uuids[i++] = g_strdup (uuid);
+ new_uuids[i] = NULL;
+ }
+ else
+ {
+ gsize j = 0;
+ new_uuids = g_new (const gchar *, length);
+ for (i = 0; i < length; i ++)
+ {
+ if (g_str_equal (uuids[i], uuid))
+ continue;
+
+ new_uuids[j] = g_strdup (uuids[i]);
+ j ++;
+ }
+
+ new_uuids[j] = NULL;
+ }
+
+ g_strfreev (uuids);
+
+ if (g_settings_set_strv (self->priv->settings,
+ ENABLED_EXTENSIONS_KEY,
+ new_uuids))
+ {
+ extension->enabled = enabled;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+gsm_shell_extensions_foreach (GsmShellExtensions *self,
+ GsmShellExtensionFunc func,
+ gpointer user_data)
+{
+ GHashTableIter iter;
+ GsmShellExtension *extension;
+
+ if (self->priv->settings == NULL)
+ return;
+
+ g_hash_table_iter_init (&iter, self->priv->uuid_to_extension);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &extension))
+ (*func) (self, extension, user_data);
+}
+
+GsmShellExtension *
+gsm_shell_extensions_get_for_uuid (GsmShellExtensions *self,
+ gchar *uuid)
+{
+ if (self->priv->settings == NULL)
+ return NULL;
+
+ return g_hash_table_lookup (self->priv->uuid_to_extension, uuid);
+}
+
+guint
+gsm_shell_extensions_n_extensions (GsmShellExtensions *self)
+{
+ if (self->priv->settings == NULL)
+ return 0;
+
+ return g_hash_table_size (self->priv->uuid_to_extension);
+}
diff --git a/gnome-session/gsm-shell-extensions.h b/gnome-session/gsm-shell-extensions.h
new file mode 100644
index 00000000..94a8423b
--- /dev/null
+++ b/gnome-session/gsm-shell-extensions.h
@@ -0,0 +1,84 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2011 Red Hat, Inc
+ *
+ * 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, 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:
+ * Jasper St. Pierre <jstpierre@mecheye.net>
+ */
+
+#ifndef __GSM_SHELL_EXTENSIONS_H
+#define __GSM_SHELL_EXTENSIONS_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* Opaque struct to represent one shell extension. */
+typedef struct _GsmShellExtension GsmShellExtension;
+
+gchar * gsm_shell_extension_get_uuid (GsmShellExtension *extension);
+gchar * gsm_shell_extension_get_name (GsmShellExtension *extension);
+gchar * gsm_shell_extension_get_description (GsmShellExtension *extension);
+gboolean gsm_shell_extension_get_is_enabled (GsmShellExtension *extension);
+
+#define GSM_TYPE_SHELL_EXTENSIONS (gsm_shell_extensions_get_type ())
+#define GSM_SHELL_EXTENSIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_SHELL_EXTENSIONS, GsmShellExtensions))
+#define GSM_SHELL_EXTENSIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_SHELL_EXTENSIONS, GsmShellExtensionsClass))
+#define GSM_IS_SHELL_EXTENSIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_SHELL_EXTENSIONS))
+#define GSM_IS_SHELL_EXTENSIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_SHELL_EXTENSIONS))
+#define GSM_SHELL_EXTENSIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_SHELL_EXTENSIONS, GsmShellExtensionsClass))
+
+typedef struct _GsmShellExtensions GsmShellExtensions;
+typedef struct _GsmShellExtensionsClass GsmShellExtensionsClass;
+typedef struct _GsmShellExtensionsPrivate GsmShellExtensionsPrivate;
+
+typedef void (* GsmShellExtensionFunc) (GsmShellExtensions *extensions,
+ GsmShellExtension *extension,
+ gpointer user_data);
+
+struct _GsmShellExtensions
+{
+ GObject parent;
+
+ /*< private >*/
+ GsmShellExtensionsPrivate *priv;
+};
+
+struct _GsmShellExtensionsClass
+{
+ GObjectClass parent_class;
+};
+
+GType gsm_shell_extensions_get_type (void) G_GNUC_CONST;
+
+gboolean gsm_shell_extensions_set_enabled (GsmShellExtensions *self,
+ gchar *uuid,
+ gboolean value);
+
+void gsm_shell_extensions_foreach (GsmShellExtensions *self,
+ GsmShellExtensionFunc func,
+ gpointer user_data);
+
+guint gsm_shell_extensions_n_extensions (GsmShellExtensions *self);
+
+GsmShellExtension * gsm_shell_extensions_get_for_uuid (GsmShellExtensions *self,
+ gchar *uuid);
+
+G_END_DECLS
+
+#endif /* __GSM_SHELL_EXTENSIONS_H */