2
* panel-object-loader.c: object loader
5
* Copyright (C) 2011 Novell, Inc.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License as
9
* published by the Free Software Foundation; either version 2 of the
10
* License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22
* Most of this code is originally from applet.c.
25
* Vincent Untz <vuntz@gnome.org>
34
#include <libpanel-util/panel-glib.h>
36
#include "panel-enums.h"
37
#include "panel-schemas.h"
38
#include "panel-toplevel.h"
40
/* Includes for objects we can load */
42
#include "panel-action-button.h"
43
#include "panel-applet-frame.h"
44
#include "panel-menu-bar.h"
45
#include "panel-menu-button.h"
46
#include "panel-separator.h"
47
#include "panel-user-menu.h"
49
#include "panel-object-loader.h"
56
PanelObjectPackType pack_type;
60
/* Each time those lists get both empty,
61
* panel_object_loader_queue_initial_unhide_toplevels() should be called */
62
static GSList *panel_objects_to_load = NULL;
63
static GSList *panel_objects_loading = NULL;
65
/* We have a timeout to always unhide toplevels after a delay, in case of some
67
#define UNHIDE_TOPLEVELS_TIMEOUT_SECONDS 5
68
static guint panel_object_loader_unhide_toplevels_timeout = 0;
70
static gboolean panel_object_loader_have_idle = FALSE;
73
free_object_to_load (PanelObjectToLoad *object)
78
g_free (object->settings_path);
79
object->settings_path = NULL;
81
g_object_unref (object->settings);
82
object->settings = NULL;
84
g_free (object->toplevel_id);
85
object->toplevel_id = NULL;
90
/* This doesn't do anything if the initial unhide already happened */
92
panel_object_loader_queue_initial_unhide_toplevels (gpointer user_data)
96
if (panel_object_loader_unhide_toplevels_timeout != 0) {
97
g_source_remove (panel_object_loader_unhide_toplevels_timeout);
98
panel_object_loader_unhide_toplevels_timeout = 0;
101
for (l = panel_toplevel_list_toplevels (); l != NULL; l = l->next)
102
panel_toplevel_queue_initial_unhide ((PanelToplevel *) l->data);
108
panel_object_loader_stop_loading (const char *id)
110
PanelObjectToLoad *object;
113
for (l = panel_objects_loading; l; l = l->next) {
115
if (g_strcmp0 (object->id, id) == 0)
119
panel_objects_loading = g_slist_delete_link (panel_objects_loading, l);
120
free_object_to_load (object);
123
for (l = panel_objects_to_load; l; l = l->next) {
125
if (g_strcmp0 (object->id, id) == 0)
129
panel_objects_to_load = g_slist_delete_link (panel_objects_to_load, l);
130
free_object_to_load (object);
133
if (panel_objects_loading == NULL && panel_objects_to_load == NULL)
134
panel_object_loader_queue_initial_unhide_toplevels (NULL);
138
panel_object_loader_idle_handler (gpointer dummy)
140
PanelObjectToLoad *object = NULL;
141
PanelToplevel *toplevel = NULL;
142
PanelWidget *panel_widget;
145
PanelObjectType object_type;
146
char *object_type_detail = NULL;
149
if (!panel_objects_to_load) {
150
panel_object_loader_have_idle = FALSE;
154
for (l = panel_objects_to_load; l; l = l->next) {
157
toplevel = panel_toplevel_get_by_id (object->toplevel_id);
163
/* All the remaining objects don't have a panel */
164
for (l = panel_objects_to_load; l; l = l->next)
165
free_object_to_load (l->data);
166
g_slist_free (panel_objects_to_load);
167
panel_objects_to_load = NULL;
168
panel_object_loader_have_idle = FALSE;
170
if (panel_objects_loading == NULL) {
171
/* unhide any potential initially hidden toplevel */
172
panel_object_loader_queue_initial_unhide_toplevels (NULL);
178
panel_objects_to_load = g_slist_delete_link (panel_objects_to_load, l);
179
panel_objects_loading = g_slist_append (panel_objects_loading, object);
181
panel_widget = panel_toplevel_get_panel_widget (toplevel);
183
iid = g_settings_get_string (object->settings, PANEL_OBJECT_IID_KEY);
184
ret = panel_object_iid_to_type (iid, &object_type, &object_type_detail);
187
g_printerr ("Object '%s' has an invalid iid ('%s')\n",
189
panel_object_loader_stop_loading (object->id);
196
switch (object_type) {
197
case PANEL_OBJECT_APPLET:
198
panel_applet_frame_load (panel_widget,
202
case PANEL_OBJECT_MENU:
203
panel_menu_button_load (panel_widget,
207
case PANEL_OBJECT_LAUNCHER:
208
launcher_load (panel_widget,
212
case PANEL_OBJECT_ACTION:
213
panel_action_button_load (panel_widget,
218
case PANEL_OBJECT_MENU_BAR:
219
panel_menu_bar_load (panel_widget,
223
case PANEL_OBJECT_SEPARATOR:
224
panel_separator_load (panel_widget,
228
case PANEL_OBJECT_USER_MENU:
229
panel_user_menu_load (panel_widget,
234
g_assert_not_reached ();
238
/* We load applets asynchronously, so we specifically don't call
239
* panel_object_loader_stop_loading() for this type. */
240
if (object_type != PANEL_OBJECT_APPLET)
241
panel_object_loader_stop_loading (object->id);
247
panel_object_loader_queue (const char *id,
248
const char *settings_path)
250
PanelObjectToLoad *object;
254
if (panel_object_loader_is_queued (id))
257
settings = g_settings_new_with_path (PANEL_OBJECT_SCHEMA,
259
toplevel_id = g_settings_get_string (settings,
260
PANEL_OBJECT_TOPLEVEL_ID_KEY);
262
if (PANEL_GLIB_STR_EMPTY (toplevel_id)) {
263
g_warning ("No toplevel on which to load object '%s'\n", id);
264
g_free (toplevel_id);
265
g_object_unref (settings);
269
object = g_new0 (PanelObjectToLoad, 1);
271
object->id = g_strdup (id);
272
object->settings_path = g_strdup (settings_path);
273
object->settings = g_object_ref (settings);
274
object->toplevel_id = toplevel_id;
275
object->pack_type = g_settings_get_enum (settings,
276
PANEL_OBJECT_PACK_TYPE_KEY);
277
object->pack_index = g_settings_get_int (settings,
278
PANEL_OBJECT_PACK_INDEX_KEY);
280
panel_objects_to_load = g_slist_prepend (panel_objects_to_load, object);
282
g_object_unref (settings);
286
panel_object_compare (const PanelObjectToLoad *a,
287
const PanelObjectToLoad *b)
291
if ((c = g_strcmp0 (a->toplevel_id, b->toplevel_id)))
293
else if (a->pack_type != b->pack_type)
294
return a->pack_type - b->pack_type; /* start < center < end */
296
/* note: for packed-end, we explicitly want to start loading
297
* from the right/bottom instead of left/top to avoid moving
298
* applets that are on the inside; so the maths are good even
300
return a->pack_index - b->pack_index;
304
panel_object_loader_do_load (gboolean initial_load)
306
if (!panel_objects_to_load) {
307
panel_object_loader_queue_initial_unhide_toplevels (NULL);
311
if (panel_objects_to_load && panel_object_loader_unhide_toplevels_timeout == 0) {
312
/* Install a timeout to make sure we don't block the
313
* unhiding because of an object that doesn't load */
314
panel_object_loader_unhide_toplevels_timeout =
315
g_timeout_add_seconds (UNHIDE_TOPLEVELS_TIMEOUT_SECONDS,
316
panel_object_loader_queue_initial_unhide_toplevels,
320
panel_objects_to_load = g_slist_sort (panel_objects_to_load,
321
(GCompareFunc) panel_object_compare);
323
if (!panel_object_loader_have_idle) {
324
/* on panel startup, we don't care about redraws of the
325
* toplevels since they are hidden, so we give a higher
326
* priority to loading of objects */
328
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
329
panel_object_loader_idle_handler,
332
g_idle_add (panel_object_loader_idle_handler, NULL);
334
panel_object_loader_have_idle = TRUE;
339
panel_object_loader_is_queued (const char *id)
342
for (li = panel_objects_to_load; li != NULL; li = li->next) {
343
PanelObjectToLoad *object = li->data;
344
if (g_strcmp0 (object->id, id) == 0)
347
for (li = panel_objects_loading; li != NULL; li = li->next) {
348
PanelObjectToLoad *object = li->data;
349
if (g_strcmp0 (object->id, id) == 0)
356
/*******************************\
357
* iid <=> object type mapping *
358
\*******************************/
360
#define PANEL_INTERNAL_FACTORY "PanelInternalFactory"
363
PanelObjectType type;
366
} panel_object_iid_map[] = {
367
{ PANEL_OBJECT_ACTION, "ActionButton" , TRUE },
368
{ PANEL_OBJECT_MENU_BAR, "MenuBar" , FALSE },
369
{ PANEL_OBJECT_MENU, "MenuButton" , FALSE },
370
{ PANEL_OBJECT_LAUNCHER, "Launcher" , FALSE },
371
{ PANEL_OBJECT_SEPARATOR, "Separator" , FALSE },
372
{ PANEL_OBJECT_USER_MENU, "UserMenu" , FALSE }
376
panel_object_type_to_iid (PanelObjectType type,
381
if (type == PANEL_OBJECT_APPLET)
382
return g_strdup (detail);
384
for (i = 0; i < G_N_ELEMENTS (panel_object_iid_map); i++) {
385
if (panel_object_iid_map[i].type != type)
388
if (panel_object_iid_map[i].has_detail &&
389
PANEL_GLIB_STR_EMPTY (detail))
392
if (panel_object_iid_map[i].has_detail)
393
return g_strdup_printf ("%s::%s:%s",
394
PANEL_INTERNAL_FACTORY,
395
panel_object_iid_map[i].id,
398
return g_strdup_printf ("%s::%s",
399
PANEL_INTERNAL_FACTORY,
400
panel_object_iid_map[i].id);
407
panel_object_iid_to_type (const char *iid,
408
PanelObjectType *type,
411
const char *instance_id;
419
instance_id = g_strrstr (iid, "::");
423
factory_id = g_strndup (iid, strlen (iid) - strlen (instance_id));
424
is_applet = (g_strcmp0 (factory_id, PANEL_INTERNAL_FACTORY) != 0);
428
*type = PANEL_OBJECT_APPLET;
434
for (i = 0; i < G_N_ELEMENTS (panel_object_iid_map); i++) {
435
if (!panel_object_iid_map[i].has_detail &&
436
g_strcmp0 (panel_object_iid_map[i].id,
438
*type = panel_object_iid_map[i].type;
442
if (panel_object_iid_map[i].has_detail) {
445
if (!g_str_has_prefix (instance_id,
446
panel_object_iid_map[i].id))
449
d = instance_id + strlen (panel_object_iid_map[i].id);
457
*type = panel_object_iid_map[i].type;
459
*detail = g_strdup (d);
465
/* We don't know this id; it could be provided by an applet now (for
466
* features that moved from being internal to the panel to applets, and
467
* that provide compatibility with the same id). So let's try it. */
468
*type = PANEL_OBJECT_APPLET;