You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
13 KiB
469 lines
13 KiB
/* $Id$ */
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <gmodule.h>
|
|
#include <exo/exo.h>
|
|
#include <glib/gstdio.h>
|
|
#include <libxfce4util/libxfce4util.h>
|
|
#include <libxfce4panel/libxfce4panel.h>
|
|
#include <libxfce4panel/xfce-panel-plugin-provider.h>
|
|
|
|
#include <panel/panel-private.h>
|
|
#include <panel/panel-module.h>
|
|
#include <panel/panel-module-factory.h>
|
|
#include <panel/panel-plugin-external.h>
|
|
|
|
|
|
|
|
static void panel_module_class_init (PanelModuleClass *klass);
|
|
static void panel_module_init (PanelModule *plugin);
|
|
static void panel_module_dispose (GObject *object);
|
|
static void panel_module_finalize (GObject *object);
|
|
static gboolean panel_module_load (GTypeModule *type_module);
|
|
static void panel_module_unload (GTypeModule *type_module);
|
|
static void panel_module_item_finalized (gpointer user_data,
|
|
GObject *item);
|
|
|
|
|
|
|
|
struct _PanelModuleClass
|
|
{
|
|
GTypeModuleClass __parent__;
|
|
};
|
|
|
|
|
|
|
|
struct _PanelModule
|
|
{
|
|
GTypeModule __parent__;
|
|
|
|
/* to plugin library */
|
|
GModule *library;
|
|
|
|
/* plugin init function */
|
|
PluginConstructFunc construct_func;
|
|
|
|
/* whether to run the plugin in the wrapper */
|
|
guint run_in_wrapper : 1;
|
|
|
|
/* the library location */
|
|
gchar *filename;
|
|
|
|
/* plugin information from the desktop file */
|
|
gchar *name;
|
|
gchar *comment;
|
|
gchar *icon_name;
|
|
|
|
/* whether this plugin is unique (only 1 running instance) */
|
|
guint is_unique : 1;
|
|
|
|
/* use count */
|
|
guint use_count;
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (PanelModule, panel_module, G_TYPE_TYPE_MODULE);
|
|
|
|
|
|
|
|
static void
|
|
panel_module_class_init (PanelModuleClass *klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GTypeModuleClass *gtype_module_class;
|
|
|
|
gobject_class = G_OBJECT_CLASS (klass);
|
|
gobject_class->dispose = panel_module_dispose;
|
|
gobject_class->finalize = panel_module_finalize;
|
|
|
|
gtype_module_class = G_TYPE_MODULE_CLASS (klass);
|
|
gtype_module_class->load = panel_module_load;
|
|
gtype_module_class->unload = panel_module_unload;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_module_init (PanelModule *module)
|
|
{
|
|
/* initialize */
|
|
module->library = NULL;
|
|
module->construct_func = NULL;
|
|
module->filename = NULL;
|
|
module->run_in_wrapper = TRUE;
|
|
module->name = NULL;
|
|
module->comment = NULL;
|
|
module->icon_name = NULL;
|
|
module->is_unique = FALSE;
|
|
module->use_count = 0;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_module_dispose (GObject *object)
|
|
{
|
|
/* Do nothing to avoid problems with dispose in GTypeModule when
|
|
* types are registered.
|
|
*
|
|
* For us this is not a problem since the modules are released when
|
|
* everything is destroyed. So we really want that last unref before
|
|
* closing the application. */
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_module_finalize (GObject *object)
|
|
{
|
|
PanelModule *module = PANEL_MODULE (object);
|
|
|
|
/* cleanup */
|
|
g_free (module->filename);
|
|
g_free (module->name);
|
|
g_free (module->comment);
|
|
g_free (module->icon_name);
|
|
|
|
(*G_OBJECT_CLASS (panel_module_parent_class)->finalize) (object);
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
panel_module_load (GTypeModule *type_module)
|
|
{
|
|
PanelModule *module = PANEL_MODULE (type_module);
|
|
PluginRegisterTypesFunc register_func;
|
|
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
|
|
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), FALSE);
|
|
|
|
/* load the module */
|
|
module->library = g_module_open (module->filename, G_MODULE_BIND_LOCAL);
|
|
if (G_UNLIKELY (module->library == NULL))
|
|
{
|
|
g_critical ("Failed to load plugin '%s': %s", panel_module_get_name (module), g_module_error ());
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* link the required construct function */
|
|
if (!g_module_symbol (module->library, "xfce_panel_plugin_construct", (gpointer) &module->construct_func))
|
|
{
|
|
g_critical ("Plugin '%s' lacks required symbol: %s", panel_module_get_name (module), g_module_error ());
|
|
|
|
/* unload */
|
|
panel_module_unload (type_module);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* run the type register function if available */
|
|
if (g_module_symbol (module->library, "xfce_panel_plugin_register_types", (gpointer) ®ister_func))
|
|
(*register_func) (type_module);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_module_unload (GTypeModule *type_module)
|
|
{
|
|
PanelModule *module = PANEL_MODULE (type_module);
|
|
|
|
panel_return_if_fail (PANEL_IS_MODULE (module));
|
|
panel_return_if_fail (G_IS_TYPE_MODULE (module));
|
|
|
|
/* unload the library */
|
|
g_module_close (module->library);
|
|
|
|
/* reset plugin state */
|
|
module->library = NULL;
|
|
module->construct_func = NULL;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
panel_module_item_finalized (gpointer user_data,
|
|
GObject *item)
|
|
{
|
|
PanelModule *module = PANEL_MODULE (user_data);
|
|
|
|
panel_return_if_fail (PANEL_IS_MODULE (module));
|
|
panel_return_if_fail (G_IS_TYPE_MODULE (module));
|
|
panel_return_if_fail (module->use_count > 0);
|
|
panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (item));
|
|
|
|
/* decrease counter */
|
|
module->use_count--;
|
|
|
|
/* unuse the library if the plugin runs internal */
|
|
/* TODO this needs to be fixed */
|
|
//if (!xfce_panel_plugin_provider_is_external (XFCE_PANEL_PLUGIN_PROVIDER (item)))
|
|
// g_type_module_unuse (G_TYPE_MODULE (module));
|
|
|
|
/* emit signal unique signal in the factory */
|
|
if (module->is_unique)
|
|
panel_module_factory_emit_unique_changed (module);
|
|
}
|
|
|
|
|
|
|
|
PanelModule *
|
|
panel_module_new_from_desktop_file (const gchar *filename,
|
|
const gchar *name)
|
|
{
|
|
PanelModule *module = NULL;
|
|
XfceRc *rc;
|
|
const gchar *module_name;
|
|
const gchar *directory;
|
|
const gchar *value;
|
|
gchar *path;
|
|
|
|
panel_return_val_if_fail (filename != NULL && *filename != '\0', NULL);
|
|
|
|
/* open the desktop file */
|
|
rc = xfce_rc_simple_open (filename, TRUE);
|
|
if (G_LIKELY (rc != NULL && xfce_rc_has_group (rc, "Xfce Panel")))
|
|
{
|
|
/* set the xfce panel group */
|
|
xfce_rc_set_group (rc, "Xfce Panel");
|
|
|
|
/* read library location from the desktop file */
|
|
module_name = xfce_rc_read_entry (rc, "X-XFCE-Module", NULL);
|
|
directory = xfce_rc_read_entry (rc, "X-XFCE-Module-Path", NULL);
|
|
|
|
if (G_LIKELY (module_name != NULL && directory != NULL))
|
|
{
|
|
/* build the module path */
|
|
path = g_module_build_path (directory, module_name);
|
|
|
|
/* test if the library exists */
|
|
if (G_LIKELY (g_file_test (path, G_FILE_TEST_EXISTS)))
|
|
{
|
|
/* create new module */
|
|
module = g_object_new (PANEL_TYPE_MODULE, NULL);
|
|
|
|
/* set library location */
|
|
module->filename = path;
|
|
}
|
|
else
|
|
{
|
|
/* cleanup */
|
|
g_free (path);
|
|
}
|
|
}
|
|
|
|
/* read the remaining information */
|
|
if (G_LIKELY (module != NULL))
|
|
{
|
|
/* set the module name */
|
|
g_type_module_set_name (G_TYPE_MODULE (module), name);
|
|
|
|
/* read the plugin name */
|
|
value = xfce_rc_read_entry (rc, "Name", NULL);
|
|
module->name = g_strdup (value);
|
|
|
|
/* read the plugin comment */
|
|
value = xfce_rc_read_entry (rc, "Comment", NULL);
|
|
module->comment = g_strdup (value);
|
|
|
|
/* read the plugin icon */
|
|
value = xfce_rc_read_entry (rc, "Icon", NULL);
|
|
module->icon_name = g_strdup (value);
|
|
|
|
/* whether the plugin is unique */
|
|
module->is_unique = xfce_rc_read_bool_entry (rc, "X-XFCE-Unique", FALSE);
|
|
|
|
/* whether to run the plugin external */
|
|
module->run_in_wrapper = xfce_rc_read_bool_entry (rc, "X-XFCE-External", TRUE);
|
|
}
|
|
else if (xfce_rc_has_entry (rc, "X-XFCE-Exec"))
|
|
{
|
|
/* old external plugin, not usable anymore */
|
|
//g_message ("The plugin from desktop file \"%s\" should be ported to an internal plugin", filename);
|
|
}
|
|
else
|
|
{
|
|
/* print warning */
|
|
g_warning ("Failed to create a plugin from desktop file \"%s\"", filename);
|
|
}
|
|
|
|
/* close rc file */
|
|
xfce_rc_close (rc);
|
|
}
|
|
|
|
return module;
|
|
}
|
|
|
|
|
|
|
|
XfcePanelPluginProvider *
|
|
panel_module_create_plugin (PanelModule *module,
|
|
GdkScreen *screen,
|
|
const gchar *name,
|
|
const gchar *id,
|
|
gchar **arguments,
|
|
UseWrapper use_wrapper)
|
|
{
|
|
XfcePanelPluginProvider *plugin = NULL;
|
|
gboolean external;
|
|
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
|
|
panel_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
|
|
panel_return_val_if_fail (name != NULL && *name != '\0', NULL);
|
|
panel_return_val_if_fail (id != NULL && *id != '\0', NULL);
|
|
panel_return_val_if_fail (exo_str_is_equal (name, G_TYPE_MODULE (module)->name), NULL);
|
|
|
|
/* return null if the module is not usable (unique and already used) */
|
|
if (G_UNLIKELY (panel_module_is_usable (module) == FALSE))
|
|
return NULL;
|
|
|
|
/* whether we're going to start the module external */
|
|
external = !!(use_wrapper == FORCE_EXTERNAL || (use_wrapper == FROM_DESKTOP_FILE && module->run_in_wrapper));
|
|
|
|
if (external)
|
|
{
|
|
/* create external plugin */
|
|
plugin = panel_plugin_external_new (module, name, id, arguments);
|
|
}
|
|
else
|
|
{
|
|
/* increase the module use count */
|
|
g_type_module_use (G_TYPE_MODULE (module));
|
|
|
|
if (G_LIKELY (module->library))
|
|
{
|
|
/* debug check */
|
|
panel_return_val_if_fail (module->construct_func != NULL, NULL);
|
|
|
|
/* create a new panel plugin */
|
|
plugin = (*module->construct_func) (name, id, module->name, arguments, screen);
|
|
}
|
|
else
|
|
{
|
|
/* this should never happen */
|
|
panel_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
if (G_LIKELY (plugin))
|
|
{
|
|
/* increase count */
|
|
module->use_count++;
|
|
|
|
/* handle module use count and unloading */
|
|
g_object_weak_ref (G_OBJECT (plugin), panel_module_item_finalized, module);
|
|
|
|
/* emit unique-changed if the plugin is unique */
|
|
if (module->is_unique)
|
|
panel_module_factory_emit_unique_changed (module);
|
|
}
|
|
else if (external == FALSE)
|
|
{
|
|
/* decrease the use count since loading failed somehow */
|
|
g_type_module_unuse (G_TYPE_MODULE (module));
|
|
}
|
|
|
|
return plugin;
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
panel_module_get_internal_name (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
|
|
|
|
return G_TYPE_MODULE (module)->name;
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
panel_module_get_library_filename (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
|
|
|
|
return module->filename;
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
panel_module_get_name (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
|
|
panel_return_val_if_fail (module->name == NULL || g_utf8_validate (module->name, -1, NULL), NULL);
|
|
panel_return_val_if_fail (module->name != NULL || g_utf8_validate (G_TYPE_MODULE (module)->name, -1, NULL), NULL);
|
|
|
|
return module->name ? module->name : G_TYPE_MODULE (module)->name;
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
panel_module_get_comment (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (module->comment == NULL || g_utf8_validate (module->comment, -1, NULL), NULL);
|
|
|
|
return module->comment;
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
panel_module_get_icon_name (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
|
|
panel_return_val_if_fail (module->icon_name == NULL || g_utf8_validate (module->icon_name, -1, NULL), NULL);
|
|
|
|
return module->icon_name;
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
panel_module_is_valid (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
|
|
|
|
return g_file_test (module->filename, G_FILE_TEST_EXISTS);
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
panel_module_is_usable (PanelModule *module)
|
|
{
|
|
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
|
|
|
|
/* whether the module is usable */
|
|
return module->is_unique ? module->use_count == 0 : TRUE;
|
|
}
|
|
|