[gnome-panel] libpanel-applet-private: add GpModule
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-panel] libpanel-applet-private: add GpModule
- Date: Thu, 27 Oct 2016 20:23:42 +0000 (UTC)
commit 187d919b9cb514d87cd8247c185a8320adb798ea
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Thu Oct 27 23:19:56 2016 +0300
libpanel-applet-private: add GpModule
gnome-panel/libpanel-applet-private/Makefile.am | 2 +
.../libpanel-applet-private/gp-module-private.h | 61 +++
gnome-panel/libpanel-applet-private/gp-module.c | 445 ++++++++++++++++++++
3 files changed, 508 insertions(+), 0 deletions(-)
---
diff --git a/gnome-panel/libpanel-applet-private/Makefile.am b/gnome-panel/libpanel-applet-private/Makefile.am
index 198d0cf..0fdca48 100644
--- a/gnome-panel/libpanel-applet-private/Makefile.am
+++ b/gnome-panel/libpanel-applet-private/Makefile.am
@@ -23,6 +23,8 @@ libpanel_applet_private_la_SOURCES = \
gp-applet-frame.h \
gp-applet-manager.c \
gp-applet-manager.h \
+ gp-module.c \
+ gp-module-private.h \
panel-applets-manager-dbus.c \
panel-applets-manager-dbus.h \
panel-applet-container.c \
diff --git a/gnome-panel/libpanel-applet-private/gp-module-private.h
b/gnome-panel/libpanel-applet-private/gp-module-private.h
new file mode 100644
index 0000000..c6ede2c
--- /dev/null
+++ b/gnome-panel/libpanel-applet-private/gp-module-private.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GP_MODULE_PRIVATE_H
+#define GP_MODULE_PRIVATE_H
+
+#include "libgnome-panel/gp-applet.h"
+#include "libgnome-panel/gp-module.h"
+
+G_BEGIN_DECLS
+
+#define GP_TYPE_MODULE gp_module_get_type ()
+G_DECLARE_FINAL_TYPE (GpModule, gp_module, GP, MODULE, GObject)
+
+typedef enum
+{
+ GP_MODULE_ERROR_APPLET_DOES_NOT_EXIST,
+ GP_MODULE_ERROR_MISSING_APPLET_INFO,
+ GP_MODULE_ERROR_MISSING_APPLET_TYPE,
+} GpModuleError;
+
+#define GP_MODULE_ERROR gp_module_error_quark ()
+GQuark gp_module_error_quark (void);
+
+GpModule *gp_module_new_from_path (const gchar *path);
+
+GpModule *gp_module_new_from_vtable (const GpModuleVTable *vtable);
+
+const gchar *gp_module_get_id (GpModule *module);
+
+const gchar * const *gp_module_get_applets (GpModule *module);
+
+GpAppletInfo *gp_module_get_applet_info (GpModule *module,
+ const gchar *applet,
+ GError **error);
+
+GpApplet *gp_module_applet_new (GpModule *module,
+ const gchar *applet,
+ const gchar *settings_path,
+ gboolean locked_down,
+ GtkOrientation orientation,
+ GtkPositionType position,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/gnome-panel/libpanel-applet-private/gp-module.c b/gnome-panel/libpanel-applet-private/gp-module.c
new file mode 100644
index 0000000..619fea5
--- /dev/null
+++ b/gnome-panel/libpanel-applet-private/gp-module.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2016 Alberts Muktupāvels
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
+#include "gp-module-private.h"
+#include "libgnome-panel/gp-applet-info-private.h"
+#include "libgnome-panel/gp-module-info-private.h"
+
+typedef guint32 (* GetAbiVersionFunc) (void);
+typedef void (* GetVTableFunc) (GpModuleVTable *vtable);
+
+struct _GpModule
+{
+ GObject parent;
+
+ gboolean builtin;
+
+ gchar *path;
+ GModule *library;
+
+ GpModuleVTable vtable;
+
+ GpModuleInfo *info;
+ GHashTable *applets;
+};
+
+G_DEFINE_TYPE (GpModule, gp_module, G_TYPE_OBJECT)
+
+static gboolean
+match_backend (GpAppletInfo *info)
+{
+ GdkDisplay *display;
+ gchar **backends;
+ gboolean match;
+ guint i;
+
+ if (info->backends == NULL)
+ return TRUE;
+
+ display = gdk_display_get_default ();
+ backends = g_strsplit (info->backends, ",", -1);
+ match = FALSE;
+
+ for (i = 0; backends[i] != NULL; i++)
+ {
+ if (g_strcmp0 (backends[i], "*") == 0)
+ {
+ match = TRUE;
+ break;
+ }
+
+#ifdef GDK_WINDOWING_WAYLAND
+ if (g_strcmp0 (backends[i], "wayland") == 0 &&
+ GDK_IS_WAYLAND_DISPLAY (display))
+ {
+ match = TRUE;
+ break;
+ }
+#endif
+
+#ifdef GDK_WINDOWING_X11
+ if (g_strcmp0 (backends[i], "x11") == 0 && GDK_IS_X11_DISPLAY (display))
+ {
+ match = TRUE;
+ break;
+ }
+#endif
+ }
+
+ g_strfreev (backends);
+
+ return match;
+}
+
+static const gchar *
+get_current_backend (void)
+{
+#ifdef GDK_WINDOWING_WAYLAND
+ if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()))
+ return "wayland";
+#endif
+
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
+ return "x11";
+#endif
+
+ return "unknown";
+}
+
+static gboolean
+is_valid_applet (GpModule *module,
+ const gchar *applet,
+ GError **error)
+{
+ guint i;
+
+ for (i = 0; module->info->applets[i] != NULL; i++)
+ {
+ if (g_strcmp0 (module->info->applets[i], applet) == 0)
+ return TRUE;
+ }
+
+ g_set_error (error, GP_MODULE_ERROR, GP_MODULE_ERROR_APPLET_DOES_NOT_EXIST,
+ "Module '%s' does not have applet '%s'",
+ module->info->id, applet);
+
+ return FALSE;
+}
+
+static GpAppletInfo *
+get_applet_info (GpModule *module,
+ const gchar *applet,
+ GError **error)
+{
+ GpAppletInfo *info;
+
+ info = g_hash_table_lookup (module->applets, applet);
+
+ if (info != NULL)
+ return info;
+
+ info = module->vtable.get_applet_info (applet);
+
+ if (info == NULL)
+ {
+ g_set_error (error, GP_MODULE_ERROR, GP_MODULE_ERROR_MISSING_APPLET_INFO,
+ "Module '%s' did not return required info about applet '%s'",
+ module->info->id, applet);
+
+ return NULL;
+ }
+
+ g_hash_table_insert (module->applets, g_strdup (applet), info);
+
+ return info;
+}
+
+static void
+applet_info_free (gpointer data)
+{
+ GpAppletInfo *info;
+
+ info = (GpAppletInfo *) data;
+
+ gp_applet_info_free (info);
+}
+
+static gboolean
+load_module_info (GpModule *module)
+{
+ GpModuleInfo *info;
+
+ module->info = info = module->vtable.get_module_info ();
+
+ if (info == NULL)
+ {
+ g_warning ("Failed to get 'GpModuleInfo' from module '%s'", module->path);
+ return FALSE;
+ }
+
+ if (info->id == NULL || *info->id == '\0')
+ {
+ g_warning ("Module '%s' does not have valid id", module->path);
+ return FALSE;
+ }
+
+ if (info->applets == NULL || info->applets[0] == NULL)
+ {
+ g_warning ("Module '%s' does not have valid applets", module->path);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gp_module_finalize (GObject *object)
+{
+ GpModule *module;
+
+ module = GP_MODULE (object);
+
+ g_clear_pointer (&module->path, g_free);
+
+ if (module->library != NULL)
+ {
+ g_module_close (module->library);
+ module->library = NULL;
+ }
+
+ g_clear_pointer (&module->info, gp_module_info_free);
+ g_clear_pointer (&module->info, g_hash_table_destroy);
+
+ G_OBJECT_CLASS (gp_module_parent_class)->finalize (object);
+}
+
+static void
+gp_module_class_init (GpModuleClass *module_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (module_class);
+
+ object_class->finalize = gp_module_finalize;
+}
+
+static void
+gp_module_init (GpModule *module)
+{
+ module->applets = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, applet_info_free);
+}
+
+GQuark
+gp_module_error_quark (void)
+{
+ return g_quark_from_static_string ("gp-module-error-quark");
+}
+
+GpModule *
+gp_module_new_from_path (const gchar *path)
+{
+ GpModule *module;
+ GModuleFlags flags;
+ const gchar *symbol;
+ GetAbiVersionFunc abi_version_func;
+ GetVTableFunc vtable_func;
+
+ g_return_val_if_fail (path != NULL && *path != '\0', NULL);
+
+ module = g_object_new (GP_TYPE_MODULE, NULL);
+ module->builtin = FALSE;
+
+ flags = G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL;
+
+ module->path = g_strdup (path);
+ module->library = g_module_open (path, flags);
+
+ if (module->library == NULL)
+ {
+ g_warning ("Failed to load module '%s': %s", path, g_module_error ());
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ symbol = "gp_module_get_abi_version";
+ if (!g_module_symbol (module->library, symbol, (gpointer) &abi_version_func))
+ {
+ g_warning ("Failed to get '%s' for module '%s': %s",
+ symbol, path, g_module_error ());
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ if (abi_version_func == NULL)
+ {
+ g_warning ("Invalid '%s' in module '%s'", symbol, path);
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ if (abi_version_func () != GP_MODULE_ABI_VERSION)
+ {
+ g_warning ("Module '%s' ABI version does not match", path);
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ symbol = "gp_module_get_vtable";
+ if (!g_module_symbol (module->library, symbol, (gpointer) &vtable_func))
+ {
+ g_warning ("Failed to get '%s' for module '%s': %s",
+ symbol, path, g_module_error ());
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ if (vtable_func == NULL)
+ {
+ g_warning ("Invalid '%s' in module '%s'", symbol, path);
+
+ g_object_unref (module);
+ return NULL;
+ }
+
+ vtable_func (&module->vtable);
+
+ if (!load_module_info (module))
+ {
+ g_object_unref (module);
+ return NULL;
+ }
+
+ return module;
+}
+
+GpModule *
+gp_module_new_from_vtable (const GpModuleVTable *vtable)
+{
+ GpModule *module;
+
+ module = g_object_new (GP_TYPE_MODULE, NULL);
+ module->builtin = TRUE;
+
+ module->vtable = *vtable;
+
+ if (!load_module_info (module))
+ {
+ g_object_unref (module);
+ return NULL;
+ }
+
+ return module;
+}
+
+const gchar *
+gp_module_get_id (GpModule *module)
+{
+ return module->info->id;
+}
+
+const gchar * const *
+gp_module_get_applets (GpModule *module)
+{
+ return (const gchar * const *) module->info->applets;
+}
+
+/**
+ * gp_module_applet_new:
+ * @module: a #GpModule
+ * @applet: the applet id
+ * @error: return location for a #GError, or %NULL
+ *
+ * Returns the #GpAppletInfo for @applet in @module if exists, %NULL
+ * otherwise.
+ *
+ * Returns: (transfer none): the #GpAppletInfo, or %NULL.
+ */
+GpAppletInfo *
+gp_module_get_applet_info (GpModule *module,
+ const gchar *applet,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (!is_valid_applet (module, applet, error))
+ return NULL;
+
+ return get_applet_info (module, applet, error);
+}
+
+/**
+ * gp_module_applet_new:
+ * @module: a #GpModule
+ * @applet: the applet id
+ * @settings_path: the #GSettings path to the per-instance settings
+ * @locked_down: whether applet is on locked down panel
+ * @orientation: the orientation of the panel
+ * @position: the position of the panel
+ * @error: return location for a #GError, or %NULL
+ *
+ * Returns a newly allocated applet.
+ *
+ * Returns: (transfer full): a newly created #GpApplet, or %NULL.
+ */
+GpApplet *
+gp_module_applet_new (GpModule *module,
+ const gchar *applet,
+ const gchar *settings_path,
+ gboolean locked_down,
+ GtkOrientation orientation,
+ GtkPositionType position,
+ GError **error)
+{
+ GpAppletInfo *info;
+ GType type;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (!is_valid_applet (module, applet, error))
+ return NULL;
+
+ info = get_applet_info (module, applet, error);
+ if (info == NULL)
+ return NULL;
+
+ if (!match_backend (info))
+ {
+ g_set_error (error, GP_MODULE_ERROR, GP_MODULE_ERROR_MISSING_APPLET_INFO,
+ "Module '%s' did not return required info about applet '%s'",
+ module->info->id, applet);
+
+ return NULL;
+ }
+
+ type = module->vtable.get_applet_type (applet);
+ if (type == G_TYPE_NONE)
+ {
+ g_set_error (error, GP_MODULE_ERROR, GP_MODULE_ERROR_MISSING_APPLET_TYPE,
+ "Applet '%s' from module '%s' does not work with current backend '%s'",
+ applet, module->info->id, get_current_backend ());
+
+ return NULL;
+ }
+
+ return g_object_new (type,
+ "id", applet,
+ "settings-path", settings_path,
+ "translation-domain", module->info->domain,
+ "locked-down", locked_down,
+ "orientation", orientation,
+ "position", position,
+ NULL);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]