2
* Copyright (C) 2008-2009 Nick Schermer <nick@xfce.org>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License along
15
* with this program; if not, write to the Free Software Foundation, Inc.,
16
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
#include <glib/gstdio.h>
26
#include <libxfce4util/libxfce4util.h>
28
#include <common/panel-private.h>
29
#include <libxfce4panel/libxfce4panel.h>
30
#include <libxfce4panel/xfce-panel-plugin-provider.h>
32
#include <panel/panel-module.h>
33
#include <panel/panel-module-factory.h>
34
#include <panel/panel-plugin-external-wrapper.h>
35
#include <panel/panel-plugin-external-46.h>
37
#define PANEL_PLUGINS_LIB_DIR (LIBDIR G_DIR_SEPARATOR_S "panel" G_DIR_SEPARATOR_S "plugins")
38
#define PANEL_PLUGINS_LIB_DIR_OLD (LIBDIR G_DIR_SEPARATOR_S "panel-plugins")
41
typedef enum _PanelModuleRunMode PanelModuleRunMode;
42
typedef enum _PanelModuleUnique PanelModuleUnique;
46
static void panel_module_dispose (GObject *object);
47
static void panel_module_finalize (GObject *object);
48
static gboolean panel_module_load (GTypeModule *type_module);
49
static void panel_module_unload (GTypeModule *type_module);
50
static void panel_module_plugin_destroyed (gpointer user_data,
51
GObject *where_the_plugin_was);
55
struct _PanelModuleClass
57
GTypeModuleClass __parent__;
60
enum _PanelModuleRunMode
63
INTERNAL, /* plugin library will be loaded in the panel */
64
WRAPPER, /* external library with comunication through PanelPluginExternal */
65
EXTERNAL_46 /* external executable with comunication through PanelPluginExternal46 */
68
enum _PanelModuleUnique
77
GTypeModule __parent__;
80
PanelModuleRunMode mode;
82
/* filename to the library or executable
83
* for an old 4.6 plugin */
86
/* plugin information from the desktop file */
93
PanelModuleUnique unique_mode;
95
/* module location (null for 4.6 plugins) */
98
/* for non-gobject plugin */
99
PluginConstructFunc construct_func;
101
/* for gobject plugins */
107
static GQuark module_quark = 0;
111
G_DEFINE_TYPE (PanelModule, panel_module, G_TYPE_TYPE_MODULE)
116
panel_module_class_init (PanelModuleClass *klass)
118
GObjectClass *gobject_class;
119
GTypeModuleClass *gtype_module_class;
121
gobject_class = G_OBJECT_CLASS (klass);
122
gobject_class->dispose = panel_module_dispose;
123
gobject_class->finalize = panel_module_finalize;
125
gtype_module_class = G_TYPE_MODULE_CLASS (klass);
126
gtype_module_class->load = panel_module_load;
127
gtype_module_class->unload = panel_module_unload;
129
module_quark = g_quark_from_static_string ("panel-module");
135
panel_module_init (PanelModule *module)
137
module->mode = UNKNOWN;
138
module->filename = NULL;
139
module->display_name = NULL;
140
module->comment = NULL;
141
module->icon_name = NULL;
142
module->use_count = 0;
143
module->unique_mode = UNIQUE_FALSE;
144
module->library = NULL;
145
module->construct_func = NULL;
146
module->plugin_type = G_TYPE_NONE;
152
panel_module_dispose (GObject *object)
154
/* Do nothing to avoid problems with dispose in GTypeModule when
155
* types are registered.
157
* For us this is not a problem since the modules are released when
158
* everything is destroyed. So we really want that last unref before
159
* closing the application. */
165
panel_module_finalize (GObject *object)
167
PanelModule *module = PANEL_MODULE (object);
169
g_free (module->filename);
170
g_free (module->display_name);
171
g_free (module->comment);
172
g_free (module->icon_name);
174
(*G_OBJECT_CLASS (panel_module_parent_class)->finalize) (object);
180
panel_module_load (GTypeModule *type_module)
182
PanelModule *module = PANEL_MODULE (type_module);
183
PluginInitFunc init_func;
184
gboolean make_resident = TRUE;
187
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
188
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), FALSE);
189
panel_return_val_if_fail (module->mode == INTERNAL, FALSE);
190
panel_return_val_if_fail (module->library == NULL, FALSE);
191
panel_return_val_if_fail (module->plugin_type == G_TYPE_NONE, FALSE);
192
panel_return_val_if_fail (module->construct_func == NULL, FALSE);
194
/* open the module */
195
module->library = g_module_open (module->filename, G_MODULE_BIND_LOCAL);
196
if (G_UNLIKELY (module->library == NULL))
198
g_critical ("Failed to load module \"%s\": %s.",
204
/* check if there is a preinit function */
205
if (g_module_symbol (module->library, "xfce_panel_module_preinit", &foo))
207
/* large message, but technically never shown to normal users */
208
g_warning ("The plugin \"%s\" is marked as internal in the desktop file, "
209
"but the developer has defined an pre-init function, which is "
210
"not supported for internal plugins. " PACKAGE_NAME " will force "
211
"the plugin to run external.", module->filename);
213
panel_module_unload (type_module);
215
/* from now on, run this plugin in a wrapper */
216
module->mode = WRAPPER;
221
/* try to link the contruct function */
222
if (g_module_symbol (module->library, "xfce_panel_module_init", (gpointer) &init_func))
224
/* initialize the plugin */
225
module->plugin_type = init_func (type_module, &make_resident);
227
/* whether to make this plugin resident or not */
229
g_module_make_resident (module->library);
231
else if (!g_module_symbol (module->library, "xfce_panel_module_construct",
232
(gpointer) &module->construct_func))
234
g_critical ("Module \"%s\" lacks a plugin register function.",
237
panel_module_unload (type_module);
248
panel_module_unload (GTypeModule *type_module)
250
PanelModule *module = PANEL_MODULE (type_module);
252
panel_return_if_fail (PANEL_IS_MODULE (module));
253
panel_return_if_fail (G_IS_TYPE_MODULE (module));
254
panel_return_if_fail (module->mode == INTERNAL);
255
panel_return_if_fail (module->library != NULL);
256
panel_return_if_fail (module->plugin_type != G_TYPE_NONE
257
|| module->construct_func != NULL);
259
g_module_close (module->library);
261
/* reset plugin state */
262
module->library = NULL;
263
module->construct_func = NULL;
264
module->plugin_type = G_TYPE_NONE;
270
panel_module_plugin_destroyed (gpointer user_data,
271
GObject *where_the_plugin_was)
273
PanelModule *module = PANEL_MODULE (user_data);
275
panel_return_if_fail (PANEL_IS_MODULE (module));
276
panel_return_if_fail (G_IS_TYPE_MODULE (module));
277
panel_return_if_fail (module->use_count > 0);
279
/* decrease counter */
282
/* unuse the library if the plugin runs internal */
283
if (module->mode == INTERNAL)
284
g_type_module_unuse (G_TYPE_MODULE (module));
286
/* emit signal unique signal in the factory */
287
if (module->unique_mode != UNIQUE_FALSE)
288
panel_module_factory_emit_unique_changed (module);
294
panel_module_new_from_desktop_file (const gchar *filename,
296
gboolean force_external)
298
PanelModule *module = NULL;
300
const gchar *module_name;
302
const gchar *module_exec;
303
const gchar *module_unique;
306
panel_return_val_if_fail (!exo_str_is_empty (filename), NULL);
307
panel_return_val_if_fail (!exo_str_is_empty (name), NULL);
309
rc = xfce_rc_simple_open (filename, TRUE);
310
if (G_UNLIKELY (rc == NULL))
312
g_critical ("Plugin %s: Unable to read from desktop file \"%s\"",
317
if (!xfce_rc_has_group (rc, "Xfce Panel"))
319
g_critical ("Plugin %s: Desktop file \"%s\" has no "
320
"\"Xfce Panel\" group", name, filename);
325
xfce_rc_set_group (rc, "Xfce Panel");
327
/* read module location from the desktop file */
328
module_name = xfce_rc_read_entry_untranslated (rc, "X-XFCE-Module", NULL);
329
if (G_LIKELY (module_name != NULL))
332
if (xfce_rc_has_entry (rc, "X-XFCE-Module-Path"))
334
/* show a messsage if the old module path key still exists */
335
g_message ("Plugin %s: The \"X-XFCE-Module-Path\" key is "
336
"ignored in \"%s\", the panel will look for the "
337
"module in %s. See bug #5455 why this decision was made",
338
name, filename, PANEL_PLUGINS_LIB_DIR);
342
path = g_module_build_path (PANEL_PLUGINS_LIB_DIR, module_name);
343
found = g_file_test (path, G_FILE_TEST_EXISTS);
347
/* deprecated location for module plugin directories */
349
path = g_module_build_path (PANEL_PLUGINS_LIB_DIR_OLD, module_name);
350
found = g_file_test (path, G_FILE_TEST_EXISTS);
353
if (G_LIKELY (found))
355
/* create new module */
356
module = g_object_new (PANEL_TYPE_MODULE, NULL);
357
module->filename = path;
359
/* run mode of the module, by default everything runs in
360
* the wrapper, unless defined otherwise */
361
if (force_external || !xfce_rc_read_bool_entry (rc, "X-XFCE-Internal", FALSE))
362
module->mode = WRAPPER;
364
module->mode = INTERNAL;
368
g_critical ("Plugin %s: There was no module found at \"%s\"",
375
/* yeah, we support ancient shizzle too... */
376
module_exec = xfce_rc_read_entry_untranslated (rc, "X-XFCE-Exec", NULL);
377
if (module_exec != NULL
378
&& g_path_is_absolute (module_exec)
379
&& g_file_test (module_exec, G_FILE_TEST_EXISTS))
381
module = g_object_new (PANEL_TYPE_MODULE, NULL);
382
module->filename = g_strdup (module_exec);
383
module->mode = EXTERNAL_46;
387
g_critical ("Plugin %s: There was no executable found at \"%s\"",
392
if (G_LIKELY (module != NULL))
394
g_type_module_set_name (G_TYPE_MODULE (module), name);
395
panel_assert (module->mode != UNKNOWN);
397
/* read the remaining information */
398
module->display_name = g_strdup (xfce_rc_read_entry (rc, "Name", name));
399
module->comment = g_strdup (xfce_rc_read_entry (rc, "Comment", NULL));
400
module->icon_name = g_strdup (xfce_rc_read_entry_untranslated (rc, "Icon", NULL));
402
module_unique = xfce_rc_read_entry (rc, "X-XFCE-Unique", NULL);
403
if (G_LIKELY (module_unique == NULL))
404
module->unique_mode = UNIQUE_FALSE;
405
else if (strcasecmp (module_unique, "screen") == 0)
406
module->unique_mode = UNIQUE_SCREEN;
407
else if (strcasecmp (module_unique, "true") == 0)
408
module->unique_mode = UNIQUE_TRUE;
410
module->unique_mode = UNIQUE_FALSE;
421
panel_module_new_plugin (PanelModule *module,
426
GtkWidget *plugin = NULL;
428
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
429
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
430
panel_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
431
panel_return_val_if_fail (unique_id != -1, NULL);
432
panel_return_val_if_fail (module->mode != UNKNOWN, NULL);
434
/* return null if the module is not usable (unique and already used) */
435
if (G_UNLIKELY (!panel_module_is_usable (module, screen)))
438
switch (module->mode)
441
if (g_type_module_use (G_TYPE_MODULE (module)))
443
if (module->plugin_type != G_TYPE_NONE)
445
/* plugin is build as an object, to use its gtype */
446
plugin = g_object_new (module->plugin_type,
447
"name", panel_module_get_name (module),
448
"unique-id", unique_id,
449
"display-name", module->display_name,
450
"comment", module->comment,
451
"arguments", arguments,
454
else if (module->construct_func != NULL)
456
/* create plugin using the 'old style' construct function */
457
plugin = (*module->construct_func) (panel_module_get_name (module),
459
module->display_name,
465
if (G_LIKELY (plugin != NULL))
468
g_type_module_unuse (G_TYPE_MODULE (module));
471
/* fall-through (make wrapper plugin), probably a plugin with
472
* preinit_func which is not supported for internal plugins */
475
plugin = panel_plugin_external_wrapper_new (module, unique_id, arguments);
479
plugin = panel_plugin_external_46_new (module, unique_id, arguments);
483
panel_assert_not_reached ();
487
if (G_LIKELY (plugin != NULL))
492
/* handle module use count and unloading */
493
g_object_weak_ref (G_OBJECT (plugin),
494
panel_module_plugin_destroyed, module);
496
/* add link to the module */
497
g_object_set_qdata (G_OBJECT (plugin), module_quark, module);
506
panel_module_get_name (PanelModule *module)
508
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
509
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
511
return G_TYPE_MODULE (module)->name;
517
panel_module_get_filename (PanelModule *module)
519
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
520
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
522
return module->filename;
528
panel_module_get_display_name (PanelModule *module)
530
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
531
panel_return_val_if_fail (G_IS_TYPE_MODULE (module), NULL);
532
panel_return_val_if_fail (module->display_name == NULL
533
|| g_utf8_validate (module->display_name, -1, NULL), NULL);
535
return module->display_name;
541
panel_module_get_comment (PanelModule *module)
543
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
544
panel_return_val_if_fail (module->comment == NULL
545
|| g_utf8_validate (module->comment, -1, NULL), NULL);
547
return module->comment;
553
panel_module_get_icon_name (PanelModule *module)
555
panel_return_val_if_fail (PANEL_IS_MODULE (module), NULL);
556
panel_return_val_if_fail (module->icon_name == NULL
557
|| g_utf8_validate (module->icon_name, -1, NULL), NULL);
559
return module->icon_name;
565
panel_module_get_from_plugin_provider (XfcePanelPluginProvider *provider)
567
panel_return_val_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider), NULL);
569
/* return the panel module */
570
return g_object_get_qdata (G_OBJECT (provider), module_quark);
576
panel_module_is_valid (PanelModule *module)
578
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
580
return g_file_test (module->filename, G_FILE_TEST_EXISTS);
586
panel_module_is_unique (PanelModule *module)
588
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
590
return module->unique_mode != UNIQUE_FALSE;
596
panel_module_is_usable (PanelModule *module,
599
PanelModuleFactory *factory;
600
GSList *plugins, *li;
601
gboolean usable = TRUE;
603
panel_return_val_if_fail (PANEL_IS_MODULE (module), FALSE);
604
panel_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
606
if (module->use_count > 0
607
&& module->unique_mode == UNIQUE_TRUE)
610
if (module->use_count > 0
611
&& module->unique_mode == UNIQUE_SCREEN)
613
factory = panel_module_factory_get ();
614
plugins = panel_module_factory_get_plugins (factory, panel_module_get_name (module));
616
/* search existing plugins if one of them runs on this screen */
617
for (li = plugins; usable && li != NULL; li = li->next)
618
if (screen == gtk_widget_get_screen (GTK_WIDGET (li->data)))
621
g_slist_free (plugins);
622
g_object_unref (G_OBJECT (factory));