Port plugin system to libpeas

Adapted from:
52fd78ddfc
This commit is contained in:
JosephMcc 2016-12-26 12:53:23 -08:00
parent 29f0acc0d6
commit b52cc3f037
11 changed files with 267 additions and 1025 deletions

View File

@ -157,6 +157,8 @@ PKG_CHECK_MODULES(XED, [
gio-2.0 >= 2.26.0 gio-2.0 >= 2.26.0
gtk+-3.0 >= 3.10.0 gtk+-3.0 >= 3.10.0
gtksourceview-3.0 >= 2.9.7 gtksourceview-3.0 >= 2.9.7
libpeas-1.0 >= 1.12.0
libpeas-gtk-1.0 >= 1.12.0
]) ])
PKG_CHECK_MODULES(X11, [x11]) PKG_CHECK_MODULES(X11, [x11])

View File

@ -6,7 +6,7 @@ pluginsdir=@libdir@/xed/plugins
Name: xed Name: xed
Description: xed Description: xed
Requires: gtksourceview-3.0 Requires: gtksourceview-3.0 libpeas-1.0 libpeas-gtk-1.0
Version: @VERSION@ Version: @VERSION@
Cflags: -I${includedir}/xed Cflags: -I${includedir}/xed
Libs: -L${libdir} Libs: -L${libdir}

View File

@ -52,11 +52,6 @@ NOINST_H_FILES = \
xed-history-entry.h \ xed-history-entry.h \
xed-io-error-message-area.h \ xed-io-error-message-area.h \
xed-language-manager.h \ xed-language-manager.h \
xed-object-module.h \
xed-plugin-info.h \
xed-plugin-info-priv.h \
xed-plugin-loader.h \
xed-plugin-manager.h \
xed-plugins-engine.h \ xed-plugins-engine.h \
xed-prefs-manager-private.h \ xed-prefs-manager-private.h \
xed-print-job.h \ xed-print-job.h \
@ -83,7 +78,6 @@ INST_H_FILES = \
xed-message.h \ xed-message.h \
xed-notebook.h \ xed-notebook.h \
xed-panel.h \ xed-panel.h \
xed-plugin.h \
xed-prefs-manager-app.h \ xed-prefs-manager-app.h \
xed-prefs-manager.h \ xed-prefs-manager.h \
xed-progress-message-area.h \ xed-progress-message-area.h \
@ -135,13 +129,8 @@ libxed_c_files = \
xed-message-bus.c \ xed-message-bus.c \
xed-message-type.c \ xed-message-type.c \
xed-message.c \ xed-message.c \
xed-object-module.c \
xed-notebook.c \ xed-notebook.c \
xed-panel.c \ xed-panel.c \
xed-plugin-info.c \
xed-plugin.c \
xed-plugin-loader.c \
xed-plugin-manager.c \
xed-plugins-engine.c \ xed-plugins-engine.c \
xed-prefs-manager-app.c \ xed-prefs-manager-app.c \
xed-prefs-manager.c \ xed-prefs-manager.c \

View File

@ -39,6 +39,7 @@
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gtksourceview/gtksource.h> #include <gtksourceview/gtksource.h>
#include <libpeas-gtk/peas-gtk-plugin-manager.h>
#include <xed/xed-prefs-manager.h> #include <xed/xed-prefs-manager.h>
@ -47,7 +48,6 @@
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-document.h" #include "xed-document.h"
#include "xed-style-scheme-manager.h" #include "xed-style-scheme-manager.h"
#include "xed-plugin-manager.h"
#include "xed-help.h" #include "xed-help.h"
#include "xed-dirs.h" #include "xed-dirs.h"
@ -1047,7 +1047,7 @@ setup_plugins_page (XedPreferencesDialog *dlg)
xed_debug (DEBUG_PREFS); xed_debug (DEBUG_PREFS);
page_content = xed_plugin_manager_new (); page_content = peas_gtk_plugin_manager_new (NULL);
g_return_if_fail (page_content != NULL); g_return_if_fail (page_content != NULL);
gtk_box_pack_start (GTK_BOX (dlg->priv->plugin_manager_place_holder), gtk_box_pack_start (GTK_BOX (dlg->priv->plugin_manager_place_holder),

View File

@ -95,17 +95,17 @@ gchar* xed_dirs_get_xed_plugins_dir(void)
return plugin_dir; return plugin_dir;
} }
gchar* xed_dirs_get_xed_plugin_loaders_dir(void) gchar* xed_dirs_get_xed_plugins_data_dir (void)
{ {
gchar* lib_dir; gchar* data_dir;
gchar* loader_dir; gchar* plugin_data_dir;
lib_dir = xed_dirs_get_xed_lib_dir(); data_dir = xed_dirs_get_xed_data_dir ();
loader_dir = g_build_filename(lib_dir, "plugin-loaders", NULL); plugin_data_dir = g_build_filename (data_dir, "plugins", NULL);
g_free(lib_dir); g_free (data_dir);
return loader_dir; return plugin_data_dir;
} }
gchar* xed_dirs_get_ui_file(const gchar* file) gchar* xed_dirs_get_ui_file(const gchar* file)

View File

@ -44,8 +44,7 @@ gchar *xed_dirs_get_xed_lib_dir (void);
gchar *xed_dirs_get_xed_plugins_dir (void); gchar *xed_dirs_get_xed_plugins_dir (void);
gchar *xed_dirs_get_xed_plugin_loaders_dir gchar *xed_dirs_get_xed_plugins_data_dir (void);
(void);
gchar *xed_dirs_get_ui_file (const gchar *file); gchar *xed_dirs_get_ui_file (const gchar *file);

View File

@ -35,827 +35,109 @@
#include <string.h> #include <string.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <girepository.h>
#include "xed-plugins-engine.h" #include "xed-plugins-engine.h"
#include "xed-plugin-info-priv.h"
#include "xed-plugin.h"
#include "xed-debug.h" #include "xed-debug.h"
#include "xed-app.h" #include "xed-app.h"
#include "xed-prefs-manager.h" #include "xed-prefs-manager.h"
#include "xed-plugin-loader.h"
#include "xed-object-module.h"
#include "xed-dirs.h" #include "xed-dirs.h"
#define XED_PLUGINS_ENGINE_BASE_KEY "/apps/xed/plugins" G_DEFINE_TYPE (XedPluginsEngine, xed_plugins_engine, PEAS_TYPE_ENGINE)
#define XED_PLUGINS_ENGINE_KEY XED_PLUGINS_ENGINE_BASE_KEY "/active-plugins"
#define PLUGIN_EXT ".xed-plugin"
#define LOADER_EXT G_MODULE_SUFFIX
typedef struct
{
XedPluginLoader *loader;
XedObjectModule *module;
} LoaderInfo;
/* Signals */
enum
{
ACTIVATE_PLUGIN,
DEACTIVATE_PLUGIN,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE(XedPluginsEngine, xed_plugins_engine, G_TYPE_OBJECT)
struct _XedPluginsEnginePrivate struct _XedPluginsEnginePrivate
{ {
GList *plugin_list; GSettings *plugin_settings;
GHashTable *loaders;
gboolean activate_from_prefs;
}; };
XedPluginsEngine *default_engine = NULL; XedPluginsEngine *default_engine = NULL;
static void xed_plugins_engine_activate_plugin_real (XedPluginsEngine *engine,
XedPluginInfo *info);
static void xed_plugins_engine_deactivate_plugin_real (XedPluginsEngine *engine,
XedPluginInfo *info);
typedef gboolean (*LoadDirCallback)(XedPluginsEngine *engine, const gchar *filename, gpointer userdata);
static gboolean
load_dir_real (XedPluginsEngine *engine,
const gchar *dir,
const gchar *suffix,
LoadDirCallback callback,
gpointer userdata)
{
GError *error = NULL;
GDir *d;
const gchar *dirent;
gboolean ret = TRUE;
g_return_val_if_fail (dir != NULL, TRUE);
xed_debug_message (DEBUG_PLUGINS, "DIR: %s", dir);
d = g_dir_open (dir, 0, &error);
if (!d)
{
g_warning ("%s", error->message);
g_error_free (error);
return TRUE;
}
while ((dirent = g_dir_read_name (d)))
{
gchar *filename;
if (!g_str_has_suffix (dirent, suffix))
continue;
filename = g_build_filename (dir, dirent, NULL);
ret = callback (engine, filename, userdata);
g_free (filename);
if (!ret)
break;
}
g_dir_close (d);
return ret;
}
static gboolean
load_plugin_info (XedPluginsEngine *engine,
const gchar *filename,
gpointer userdata)
{
XedPluginInfo *info;
info = _xed_plugin_info_new (filename);
if (info == NULL)
return TRUE;
/* If a plugin with this name has already been loaded
* drop this one (user plugins override system plugins) */
if (xed_plugins_engine_get_plugin_info (engine, xed_plugin_info_get_module_name (info)) != NULL)
{
xed_debug_message (DEBUG_PLUGINS, "Two or more plugins named '%s'. "
"Only the first will be considered.\n",
xed_plugin_info_get_module_name (info));
_xed_plugin_info_unref (info);
return TRUE;
}
engine->priv->plugin_list = g_list_prepend (engine->priv->plugin_list, info);
xed_debug_message (DEBUG_PLUGINS, "Plugin %s loaded", info->name);
return TRUE;
}
static void
load_all_plugins (XedPluginsEngine *engine)
{
gchar *plugin_dir;
const gchar *pdirs_env = NULL;
/* load user plugins */
plugin_dir = xed_dirs_get_user_plugins_dir ();
if (g_file_test (plugin_dir, G_FILE_TEST_IS_DIR))
{
load_dir_real (engine,
plugin_dir,
PLUGIN_EXT,
load_plugin_info,
NULL);
}
g_free (plugin_dir);
/* load system plugins */
pdirs_env = g_getenv ("XED_PLUGINS_PATH");
xed_debug_message (DEBUG_PLUGINS, "XED_PLUGINS_PATH=%s", pdirs_env);
if (pdirs_env != NULL)
{
gchar **pdirs;
gint i;
pdirs = g_strsplit (pdirs_env, G_SEARCHPATH_SEPARATOR_S, 0);
for (i = 0; pdirs[i] != NULL; i++)
{
if (!load_dir_real (engine,
pdirs[i],
PLUGIN_EXT,
load_plugin_info,
NULL))
{
break;
}
}
g_strfreev (pdirs);
}
else
{
plugin_dir = xed_dirs_get_xed_plugins_dir ();
load_dir_real (engine,
plugin_dir,
PLUGIN_EXT,
load_plugin_info,
NULL);
g_free (plugin_dir);
}
}
static guint
hash_lowercase (gconstpointer data)
{
gchar *lowercase;
guint ret;
lowercase = g_ascii_strdown ((const gchar *)data, -1);
ret = g_str_hash (lowercase);
g_free (lowercase);
return ret;
}
static gboolean
equal_lowercase (gconstpointer a, gconstpointer b)
{
return g_ascii_strcasecmp ((const gchar *)a, (const gchar *)b) == 0;
}
static void
loader_destroy (LoaderInfo *info)
{
if (!info)
return;
if (info->loader)
g_object_unref (info->loader);
g_free (info);
}
static void
add_loader (XedPluginsEngine *engine,
const gchar *loader_id,
XedObjectModule *module)
{
LoaderInfo *info;
info = g_new (LoaderInfo, 1);
info->loader = NULL;
info->module = module;
g_hash_table_insert (engine->priv->loaders, g_strdup (loader_id), info);
}
static void static void
xed_plugins_engine_init (XedPluginsEngine *engine) xed_plugins_engine_init (XedPluginsEngine *engine)
{ {
gchar *private_path;
GError *error = NULL;
xed_debug (DEBUG_PLUGINS); xed_debug (DEBUG_PLUGINS);
if (!g_module_supported ()) engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, XED_TYPE_PLUGINS_ENGINE, XedPluginsEnginePrivate);
engine->priv->plugin_settings = g_settings_new (XED_SCHEMA);
peas_engine_enable_loader (PEAS_ENGINE (engine), "python3");
/* This should be moved to libpeas */
if (!g_irepository_require (g_irepository_get_default (), "Peas", "1.0", 0, &error))
{ {
g_warning ("xed is not able to initialize the plugins engine."); g_warning ("Could not load Peas repository: %s", error->message);
return; g_error_free (error);
error = NULL;
} }
engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, if (!g_irepository_require (g_irepository_get_default (), "PeasGtk", "1.0", 0, &error))
XED_TYPE_PLUGINS_ENGINE, {
XedPluginsEnginePrivate); g_warning ("Could not load PeasGtk repository: %s", error->message);
g_error_free (error);
error = NULL;
}
load_all_plugins (engine); private_path = g_build_filename (LIBDIR, "girepository-1.0", NULL);
/* make sure that the first reactivation will read active plugins if (!g_irepository_require_private (g_irepository_get_default (), private_path, "Xed", "1.0", 0, &error))
from the prefs */ {
engine->priv->activate_from_prefs = TRUE; g_warning ("Could not load Xed repository: %s", error->message);
g_error_free (error);
error = NULL;
}
/* mapping from loadername -> loader object */ g_free (private_path);
engine->priv->loaders = g_hash_table_new_full (hash_lowercase,
equal_lowercase, peas_engine_add_search_path (PEAS_ENGINE (engine),
(GDestroyNotify)g_free, xed_dirs_get_user_plugins_dir (),
(GDestroyNotify)loader_destroy); xed_dirs_get_user_plugins_dir ());
peas_engine_add_search_path (PEAS_ENGINE (engine),
xed_dirs_get_xed_plugins_dir(),
xed_dirs_get_xed_plugins_data_dir());
g_settings_bind (engine->priv->plugin_settings, GPM_ACTIVE_PLUGINS,
engine, "loaded-plugins", G_SETTINGS_BIND_DEFAULT);
} }
static void static void
loader_garbage_collect (const char *id, LoaderInfo *info) xed_plugins_engine_dispose (GObject *object)
{
if (info->loader)
xed_plugin_loader_garbage_collect (info->loader);
}
void
xed_plugins_engine_garbage_collect (XedPluginsEngine *engine)
{
g_hash_table_foreach (engine->priv->loaders,
(GHFunc) loader_garbage_collect,
NULL);
}
static void
xed_plugins_engine_finalize (GObject *object)
{ {
XedPluginsEngine *engine = XED_PLUGINS_ENGINE (object); XedPluginsEngine *engine = XED_PLUGINS_ENGINE (object);
GList *item;
xed_debug (DEBUG_PLUGINS); if (engine->priv->plugin_settings != NULL)
/* Firs deactivate all plugins */
for (item = engine->priv->plugin_list; item; item = item->next)
{ {
XedPluginInfo *info = XED_PLUGIN_INFO (item->data); g_object_unref (engine->priv->plugin_settings);
engine->priv->plugin_settings = NULL;
if (xed_plugin_info_is_active (info))
xed_plugins_engine_deactivate_plugin_real (engine, info);
} }
/* unref the loaders */ G_OBJECT_CLASS (xed_plugins_engine_parent_class)->dispose (object);
g_hash_table_destroy (engine->priv->loaders);
/* and finally free the infos */
for (item = engine->priv->plugin_list; item; item = item->next)
{
XedPluginInfo *info = XED_PLUGIN_INFO (item->data);
_xed_plugin_info_unref (info);
}
g_list_free (engine->priv->plugin_list);
G_OBJECT_CLASS (xed_plugins_engine_parent_class)->finalize (object);
} }
static void static void
xed_plugins_engine_class_init (XedPluginsEngineClass *klass) xed_plugins_engine_class_init (XedPluginsEngineClass *klass)
{ {
GType the_type = G_TYPE_FROM_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = xed_plugins_engine_finalize; object_class->dispose = xed_plugins_engine_dispose;
klass->activate_plugin = xed_plugins_engine_activate_plugin_real;
klass->deactivate_plugin = xed_plugins_engine_deactivate_plugin_real;
signals[ACTIVATE_PLUGIN] =
g_signal_new ("activate-plugin",
the_type,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedPluginsEngineClass, activate_plugin),
NULL, NULL,
g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE,
1,
XED_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
signals[DEACTIVATE_PLUGIN] =
g_signal_new ("deactivate-plugin",
the_type,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (XedPluginsEngineClass, deactivate_plugin),
NULL, NULL,
g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE,
1,
XED_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
g_type_class_add_private (klass, sizeof (XedPluginsEnginePrivate)); g_type_class_add_private (klass, sizeof (XedPluginsEnginePrivate));
} }
static gboolean
load_loader (XedPluginsEngine *engine,
const gchar *filename,
gpointer data)
{
XedObjectModule *module;
gchar *base;
gchar *path;
const gchar *id;
GType type;
/* try to load in the module */
path = g_path_get_dirname (filename);
base = g_path_get_basename (filename);
/* for now they are all resident */
module = xed_object_module_new (base,
path,
"register_xed_plugin_loader",
TRUE);
g_free (base);
g_free (path);
/* make sure to load the type definition */
if (!g_type_module_use (G_TYPE_MODULE (module)))
{
g_object_unref (module);
g_warning ("Plugin loader module `%s' could not be loaded", filename);
return TRUE;
}
/* get the exported type and check the name as exported by the
* loader interface */
type = xed_object_module_get_object_type (module);
id = xed_plugin_loader_type_get_id (type);
add_loader (engine, id, module);
g_type_module_unuse (G_TYPE_MODULE (module));
return TRUE;
}
static void
ensure_loader (LoaderInfo *info)
{
if (info->loader == NULL && info->module != NULL)
{
/* create a new loader object */
XedPluginLoader *loader;
loader = (XedPluginLoader *)xed_object_module_new_object (info->module, NULL);
if (loader == NULL || !XED_IS_PLUGIN_LOADER (loader))
{
g_warning ("Loader object is not a valid XedPluginLoader instance");
if (loader != NULL && G_IS_OBJECT (loader))
g_object_unref (loader);
}
else
{
info->loader = loader;
}
}
}
static XedPluginLoader *
get_plugin_loader (XedPluginsEngine *engine, XedPluginInfo *info)
{
const gchar *loader_id;
LoaderInfo *loader_info;
loader_id = info->loader;
loader_info = (LoaderInfo *)g_hash_table_lookup (
engine->priv->loaders,
loader_id);
if (loader_info == NULL)
{
gchar *loader_dir;
loader_dir = xed_dirs_get_xed_plugin_loaders_dir ();
/* loader could not be found in the hash, try to find it by
scanning */
load_dir_real (engine,
loader_dir,
LOADER_EXT,
(LoadDirCallback)load_loader,
NULL);
g_free (loader_dir);
loader_info = (LoaderInfo *)g_hash_table_lookup (
engine->priv->loaders,
loader_id);
}
if (loader_info == NULL)
{
/* cache non-existent so we don't scan again */
add_loader (engine, loader_id, NULL);
return NULL;
}
ensure_loader (loader_info);
return loader_info->loader;
}
XedPluginsEngine * XedPluginsEngine *
xed_plugins_engine_get_default (void) xed_plugins_engine_get_default (void)
{ {
if (default_engine != NULL) if (default_engine != NULL)
{
return default_engine; return default_engine;
}
default_engine = XED_PLUGINS_ENGINE (g_object_new (XED_TYPE_PLUGINS_ENGINE, NULL)); default_engine = XED_PLUGINS_ENGINE (g_object_new (XED_TYPE_PLUGINS_ENGINE, NULL));
g_object_add_weak_pointer (G_OBJECT (default_engine), g_object_add_weak_pointer (G_OBJECT (default_engine), (gpointer) &default_engine);
(gpointer) &default_engine);
return default_engine; return default_engine;
} }
const GList *
xed_plugins_engine_get_plugin_list (XedPluginsEngine *engine)
{
xed_debug (DEBUG_PLUGINS);
return engine->priv->plugin_list;
}
static gint
compare_plugin_info_and_name (XedPluginInfo *info,
const gchar *module_name)
{
return strcmp (xed_plugin_info_get_module_name (info), module_name);
}
XedPluginInfo *
xed_plugins_engine_get_plugin_info (XedPluginsEngine *engine,
const gchar *name)
{
GList *l = g_list_find_custom (engine->priv->plugin_list,
name,
(GCompareFunc) compare_plugin_info_and_name);
return l == NULL ? NULL : (XedPluginInfo *) l->data;
}
static void
save_active_plugin_list (XedPluginsEngine *engine)
{
GSList *active_plugins = NULL;
GList *l;
for (l = engine->priv->plugin_list; l != NULL; l = l->next)
{
XedPluginInfo *info = (XedPluginInfo *) l->data;
if (xed_plugin_info_is_active (info))
{
active_plugins = g_slist_prepend (active_plugins,
(gpointer)xed_plugin_info_get_module_name (info));
}
}
xed_prefs_manager_set_active_plugins (active_plugins);
g_slist_free (active_plugins);
}
static gboolean
load_plugin (XedPluginsEngine *engine,
XedPluginInfo *info)
{
XedPluginLoader *loader;
gchar *path;
if (xed_plugin_info_is_active (info))
return TRUE;
if (!xed_plugin_info_is_available (info))
return FALSE;
loader = get_plugin_loader (engine, info);
if (loader == NULL)
{
g_warning ("Could not find loader `%s' for plugin `%s'", info->loader, info->name);
info->available = FALSE;
return FALSE;
}
path = g_path_get_dirname (info->file);
g_return_val_if_fail (path != NULL, FALSE);
info->plugin = xed_plugin_loader_load (loader, info, path);
g_free (path);
if (info->plugin == NULL)
{
g_warning ("Error loading plugin '%s'", info->name);
info->available = FALSE;
return FALSE;
}
return TRUE;
}
static void
xed_plugins_engine_activate_plugin_real (XedPluginsEngine *engine,
XedPluginInfo *info)
{
const GList *wins;
if (!load_plugin (engine, info))
return;
for (wins = xed_app_get_windows (xed_app_get_default ());
wins != NULL;
wins = wins->next)
{
xed_plugin_activate (info->plugin, XED_WINDOW (wins->data));
}
}
gboolean
xed_plugins_engine_activate_plugin (XedPluginsEngine *engine,
XedPluginInfo *info)
{
xed_debug (DEBUG_PLUGINS);
g_return_val_if_fail (info != NULL, FALSE);
if (!xed_plugin_info_is_available (info))
return FALSE;
if (xed_plugin_info_is_active (info))
return TRUE;
g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
if (xed_plugin_info_is_active (info))
save_active_plugin_list (engine);
return xed_plugin_info_is_active (info);
}
static void
call_plugin_deactivate (XedPlugin *plugin,
XedWindow *window)
{
xed_plugin_deactivate (plugin, window);
/* ensure update of ui manager, because we suspect it does something
with expected static strings in the type module (when unloaded the
strings don't exist anymore, and ui manager updates in an idle
func) */
gtk_ui_manager_ensure_update (xed_window_get_ui_manager (window));
}
static void
xed_plugins_engine_deactivate_plugin_real (XedPluginsEngine *engine,
XedPluginInfo *info)
{
const GList *wins;
XedPluginLoader *loader;
if (!xed_plugin_info_is_active (info) ||
!xed_plugin_info_is_available (info))
return;
for (wins = xed_app_get_windows (xed_app_get_default ());
wins != NULL;
wins = wins->next)
{
call_plugin_deactivate (info->plugin, XED_WINDOW (wins->data));
}
/* first unref the plugin (the loader still has one) */
g_object_unref (info->plugin);
/* find the loader and tell it to gc and unload the plugin */
loader = get_plugin_loader (engine, info);
xed_plugin_loader_garbage_collect (loader);
xed_plugin_loader_unload (loader, info);
info->plugin = NULL;
}
gboolean
xed_plugins_engine_deactivate_plugin (XedPluginsEngine *engine,
XedPluginInfo *info)
{
xed_debug (DEBUG_PLUGINS);
g_return_val_if_fail (info != NULL, FALSE);
if (!xed_plugin_info_is_active (info))
return TRUE;
g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
if (!xed_plugin_info_is_active (info))
save_active_plugin_list (engine);
return !xed_plugin_info_is_active (info);
}
void
xed_plugins_engine_activate_plugins (XedPluginsEngine *engine,
XedWindow *window)
{
GSList *active_plugins = NULL;
GList *pl;
xed_debug (DEBUG_PLUGINS);
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
g_return_if_fail (XED_IS_WINDOW (window));
/* the first time, we get the 'active' plugins from GSettings */
if (engine->priv->activate_from_prefs)
{
active_plugins = xed_prefs_manager_get_active_plugins ();
}
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
{
XedPluginInfo *info = (XedPluginInfo*)pl->data;
if (engine->priv->activate_from_prefs &&
g_slist_find_custom (active_plugins,
xed_plugin_info_get_module_name (info),
(GCompareFunc)strcmp) == NULL)
continue;
/* If plugin is not active, don't try to activate/load it */
if (!engine->priv->activate_from_prefs &&
!xed_plugin_info_is_active (info))
continue;
if (load_plugin (engine, info))
xed_plugin_activate (info->plugin,
window);
}
if (engine->priv->activate_from_prefs)
{
g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
g_slist_free (active_plugins);
engine->priv->activate_from_prefs = FALSE;
}
xed_debug_message (DEBUG_PLUGINS, "End");
/* also call update_ui after activation */
xed_plugins_engine_update_plugins_ui (engine, window);
}
void
xed_plugins_engine_deactivate_plugins (XedPluginsEngine *engine,
XedWindow *window)
{
GList *pl;
xed_debug (DEBUG_PLUGINS);
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
g_return_if_fail (XED_IS_WINDOW (window));
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
{
XedPluginInfo *info = (XedPluginInfo*)pl->data;
/* check if the plugin is actually active */
if (!xed_plugin_info_is_active (info))
continue;
/* call deactivate for the plugin for this window */
xed_plugin_deactivate (info->plugin, window);
}
xed_debug_message (DEBUG_PLUGINS, "End");
}
void
xed_plugins_engine_update_plugins_ui (XedPluginsEngine *engine,
XedWindow *window)
{
GList *pl;
xed_debug (DEBUG_PLUGINS);
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
g_return_if_fail (XED_IS_WINDOW (window));
/* call update_ui for all active plugins */
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
{
XedPluginInfo *info = (XedPluginInfo*)pl->data;
if (!xed_plugin_info_is_active (info))
continue;
xed_debug_message (DEBUG_PLUGINS, "Updating UI of %s", info->name);
xed_plugin_update_ui (info->plugin, window);
}
}
void
xed_plugins_engine_configure_plugin (XedPluginsEngine *engine,
XedPluginInfo *info,
GtkWindow *parent)
{
GtkWidget *conf_dlg;
GtkWindowGroup *wg;
xed_debug (DEBUG_PLUGINS);
g_return_if_fail (info != NULL);
conf_dlg = xed_plugin_create_configure_dialog (info->plugin);
g_return_if_fail (conf_dlg != NULL);
gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
parent);
wg = gtk_window_get_group (parent);
if (wg == NULL)
{
wg = gtk_window_group_new ();
gtk_window_group_add_window (wg, parent);
}
gtk_window_group_add_window (wg,
GTK_WINDOW (conf_dlg));
gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
gtk_widget_show (conf_dlg);
}
void
xed_plugins_engine_active_plugins_changed (XedPluginsEngine *engine)
{
gboolean to_activate;
GSList *active_plugins;
GList *pl;
xed_debug (DEBUG_PLUGINS);
active_plugins = xed_prefs_manager_get_active_plugins ();
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
{
XedPluginInfo *info = (XedPluginInfo*)pl->data;
if (!xed_plugin_info_is_available (info))
continue;
to_activate = (g_slist_find_custom (active_plugins,
xed_plugin_info_get_module_name (info),
(GCompareFunc)strcmp) != NULL);
if (!xed_plugin_info_is_active (info) && to_activate)
g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
else if (xed_plugin_info_is_active (info) && !to_activate)
g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
}
g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
g_slist_free (active_plugins);
}
void
xed_plugins_engine_rescan_plugins (XedPluginsEngine *engine)
{
xed_debug (DEBUG_PLUGINS);
load_all_plugins (engine);
}

View File

@ -32,9 +32,7 @@
#define __XED_PLUGINS_ENGINE_H__ #define __XED_PLUGINS_ENGINE_H__
#include <glib.h> #include <glib.h>
#include "xed-window.h" #include <libpeas/peas-engine.h>
#include "xed-plugin-info.h"
#include "xed-plugin.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -50,7 +48,7 @@ typedef struct _XedPluginsEnginePrivate XedPluginsEnginePrivate;
struct _XedPluginsEngine struct _XedPluginsEngine
{ {
GObject parent; PeasEngine parent;
XedPluginsEnginePrivate *priv; XedPluginsEnginePrivate *priv;
}; };
@ -58,50 +56,13 @@ typedef struct _XedPluginsEngineClass XedPluginsEngineClass;
struct _XedPluginsEngineClass struct _XedPluginsEngineClass
{ {
GObjectClass parent_class; PeasEngineClass parent_class;
void (* activate_plugin) (XedPluginsEngine *engine,
XedPluginInfo *info);
void (* deactivate_plugin) (XedPluginsEngine *engine,
XedPluginInfo *info);
}; };
GType xed_plugins_engine_get_type (void) G_GNUC_CONST; GType xed_plugins_engine_get_type (void) G_GNUC_CONST;
XedPluginsEngine *xed_plugins_engine_get_default (void); XedPluginsEngine *xed_plugins_engine_get_default (void);
void xed_plugins_engine_garbage_collect (XedPluginsEngine *engine);
const GList *xed_plugins_engine_get_plugin_list (XedPluginsEngine *engine);
XedPluginInfo *xed_plugins_engine_get_plugin_info (XedPluginsEngine *engine,
const gchar *name);
/* plugin load and unloading (overall, for all windows) */
gboolean xed_plugins_engine_activate_plugin (XedPluginsEngine *engine,
XedPluginInfo *info);
gboolean xed_plugins_engine_deactivate_plugin (XedPluginsEngine *engine,
XedPluginInfo *info);
void xed_plugins_engine_configure_plugin (XedPluginsEngine *engine,
XedPluginInfo *info,
GtkWindow *parent);
/* plugin activation/deactivation per window, private to XedWindow */
void xed_plugins_engine_activate_plugins (XedPluginsEngine *engine,
XedWindow *window);
void xed_plugins_engine_deactivate_plugins (XedPluginsEngine *engine,
XedWindow *window);
void xed_plugins_engine_update_plugins_ui (XedPluginsEngine *engine,
XedWindow *window);
/* private for GSettings notification */
void xed_plugins_engine_active_plugins_changed
(XedPluginsEngine *engine);
void xed_plugins_engine_rescan_plugins (XedPluginsEngine *engine);
G_END_DECLS G_END_DECLS
#endif /* __XED_PLUGINS_ENGINE_H__ */ #endif /* __XED_PLUGINS_ENGINE_H__ */

View File

@ -112,10 +112,6 @@ static void xed_prefs_manager_auto_save_changed (GSettings *settings,
gchar *key, gchar *key,
gpointer user_data); gpointer user_data);
static void xed_prefs_manager_active_plugins_changed (GSettings *settings,
gchar *key,
gpointer user_data);
/* GUI state is serialized to a .desktop file, not in GSettings */ /* GUI state is serialized to a .desktop file, not in GSettings */
#define XED_STATE_DEFAULT_WINDOW_STATE 0 #define XED_STATE_DEFAULT_WINDOW_STATE 0
@ -708,11 +704,6 @@ xed_prefs_manager_app_init (void)
"changed::" GPM_WRITABLE_VFS_SCHEMES, "changed::" GPM_WRITABLE_VFS_SCHEMES,
G_CALLBACK (xed_prefs_manager_auto_save_changed), G_CALLBACK (xed_prefs_manager_auto_save_changed),
NULL); NULL);
g_signal_connect (xed_prefs_manager->settings,
"changed::" GPM_ACTIVE_PLUGINS,
G_CALLBACK (xed_prefs_manager_active_plugins_changed),
NULL);
} }
return xed_prefs_manager != NULL; return xed_prefs_manager != NULL;
@ -1394,21 +1385,3 @@ xed_prefs_manager_auto_save_changed (GSettings *settings,
g_list_free (docs); g_list_free (docs);
} }
} }
static void
xed_prefs_manager_active_plugins_changed (GSettings *settings,
gchar *key,
gpointer user_data)
{
xed_debug (DEBUG_PREFS);
if (strcmp (key, GPM_ACTIVE_PLUGINS) == 0)
{
XedPluginsEngine *engine;
engine = xed_plugins_engine_get_default ();
xed_plugins_engine_active_plugins_changed (engine);
}
}

View File

@ -31,6 +31,8 @@
#ifndef __XED_WINDOW_PRIVATE_H__ #ifndef __XED_WINDOW_PRIVATE_H__
#define __XED_WINDOW_PRIVATE_H__ #define __XED_WINDOW_PRIVATE_H__
#include <libpeas/peas-extension-set.h>
#include "xed/xed-window.h" #include "xed/xed-window.h"
#include "xed-prefs-manager.h" #include "xed-prefs-manager.h"
#include "xed-message-bus.h" #include "xed-message-bus.h"
@ -53,6 +55,7 @@ struct _XedWindowPrivate
GtkWidget *language_combo; GtkWidget *language_combo;
XedMessageBus *message_bus; XedMessageBus *message_bus;
PeasExtensionSet *extensions;
/* Widgets for fullscreen mode */ /* Widgets for fullscreen mode */
GtkWidget *fullscreen_controls; GtkWidget *fullscreen_controls;

View File

@ -9,6 +9,8 @@
#include <gio/gio.h> #include <gio/gio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gtksourceview/gtksource.h> #include <gtksourceview/gtksource.h>
#include <libpeas/peas-activatable.h>
#include <libpeas/peas-extension-set.h>
#include "xed-ui.h" #include "xed-ui.h"
#include "xed-window.h" #include "xed-window.h"
@ -154,14 +156,18 @@ xed_window_dispose (GObject *object)
/* First of all, force collection so that plugins /* First of all, force collection so that plugins
* really drop some of the references. * really drop some of the references.
*/ */
xed_plugins_engine_garbage_collect (xed_plugins_engine_get_default ()); peas_engine_garbage_collect (PEAS_ENGINE (xed_plugins_engine_get_default()));
/* save the panes position and make sure to deactivate plugins /* save the panes position and make sure to deactivate plugins
* for this window, but only once */ * for this window, but only once */
if (!window->priv->dispose_has_run) if (!window->priv->dispose_has_run)
{ {
save_panes_state (window); save_panes_state (window);
xed_plugins_engine_deactivate_plugins (xed_plugins_engine_get_default (), window); /* Note that unreffing the extension will automatically remove
all extensions which in turn will deactivate the extension */
g_object_unref (window->priv->extensions);
peas_engine_garbage_collect (PEAS_ENGINE (xed_plugins_engine_get_default ()));
window->priv->dispose_has_run = TRUE; window->priv->dispose_has_run = TRUE;
} }
@ -203,9 +209,8 @@ xed_window_dispose (GObject *object)
window->priv->window_group = NULL; window->priv->window_group = NULL;
} }
/* Now that there have broken some reference loops, force collection again. /* Now that there have broken some reference loops, force collection again. */
*/ peas_engine_garbage_collect (PEAS_ENGINE (xed_plugins_engine_get_default ()));
xed_plugins_engine_garbage_collect (xed_plugins_engine_get_default ());
G_OBJECT_CLASS (xed_window_parent_class)->dispose (object); G_OBJECT_CLASS (xed_window_parent_class)->dispose (object);
} }
@ -293,7 +298,7 @@ static void
xed_window_tab_removed (XedWindow *window, xed_window_tab_removed (XedWindow *window,
XedTab *tab) XedTab *tab)
{ {
xed_plugins_engine_garbage_collect (xed_plugins_engine_get_default ()); peas_engine_garbage_collect (PEAS_ENGINE (xed_plugins_engine_get_default ()));
} }
static void static void
@ -641,7 +646,7 @@ set_sensitivity_according_to_tab (XedWindow *window,
update_next_prev_doc_sensitivity (window, tab); update_next_prev_doc_sensitivity (window, tab);
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static void static void
@ -2289,7 +2294,7 @@ sync_name (XedTab *tab,
g_free (escaped_name); g_free (escaped_name);
g_free (tip); g_free (tip);
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static XedWindow * static XedWindow *
@ -2702,7 +2707,7 @@ selection_changed (XedDocument *doc,
gtk_action_set_sensitive (action, gtk_action_set_sensitive (action,
state_normal && editable && gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER(doc))); state_normal && editable && gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER(doc)));
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static void static void
@ -2711,7 +2716,7 @@ sync_languages_menu (XedDocument *doc,
XedWindow *window) XedWindow *window)
{ {
update_languages_menu (window); update_languages_menu (window);
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static void static void
@ -2721,7 +2726,7 @@ readonly_changed (XedDocument *doc,
{ {
set_sensitivity_according_to_tab (window, window->priv->active_tab); set_sensitivity_according_to_tab (window, window->priv->active_tab);
sync_name (window->priv->active_tab, NULL, window); sync_name (window->priv->active_tab, NULL, window);
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static void static void
@ -2729,7 +2734,7 @@ editable_changed (XedView *view,
GParamSpec *arg1, GParamSpec *arg1,
XedWindow *window) XedWindow *window)
{ {
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
static void static void
@ -2871,7 +2876,7 @@ notebook_tab_removed (XedNotebook *notebook,
if (window->priv->num_tabs == 0) if (window->priv->num_tabs == 0)
{ {
xed_plugins_engine_update_plugins_ui (xed_plugins_engine_get_default (), window); peas_extension_set_call (window->priv->extensions, "update_state", window);
} }
update_window_state (window); update_window_state (window);
@ -3272,6 +3277,28 @@ add_notebook (XedWindow *window,
connect_notebook_signals (window, notebook); connect_notebook_signals (window, notebook);
} }
static void
on_extension_added (PeasExtensionSet *extensions,
PeasPluginInfo *info,
PeasExtension *exten,
XedWindow *window)
{
peas_extension_call (exten, "activate", window);
}
static void
on_extension_removed (PeasExtensionSet *extensions,
PeasPluginInfo *info,
PeasExtension *exten,
XedWindow *window)
{
peas_extension_call (exten, "deactivate", window);
/* Ensure update of the ui manager, because we suspect it does something with expected static strings in the
* type module (when unloaded the strings don't exist anymore, and the ui manager update in a idle func) */
gtk_ui_manager_ensure_update (window->priv->manager);
}
static void static void
xed_window_init (XedWindow *window) xed_window_init (XedWindow *window)
{ {
@ -3378,7 +3405,13 @@ xed_window_init (XedWindow *window)
xed_debug_message (DEBUG_WINDOW, "Update plugins ui"); xed_debug_message (DEBUG_WINDOW, "Update plugins ui");
xed_plugins_engine_activate_plugins (xed_plugins_engine_get_default (), window); window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (xed_plugins_engine_get_default ()),
PEAS_TYPE_ACTIVATABLE, "object", window, NULL);
peas_extension_set_call (window->priv->extensions, "activate");
g_signal_connect (window->priv->extensions, "extension-added", G_CALLBACK (on_extension_added), window);
g_signal_connect (window->priv->extensions, "extension-removed", G_CALLBACK (on_extension_removed), window);
/* set visibility of panes. /* set visibility of panes.
* This needs to be done after plugins activatation */ * This needs to be done after plugins activatation */