[gnome-panel] panel: Load objects from GSettings on startup



commit 52d060cce20e4c7d4deb513a8c4c074acc0efe54
Author: Vincent Untz <vuntz gnome org>
Date:   Fri Mar 25 14:24:26 2011 +0100

    panel: Load objects from GSettings on startup
    
    This is far from the end of porting the panel objects to GSettings, but
    we can now have the full default panel!
    
    The object loading code was moved to its own file.

 gnome-panel/Makefile.am           |    2 +
 gnome-panel/applet.c              |  274 +-----------------------
 gnome-panel/applet.h              |   10 -
 gnome-panel/panel-applet-frame.c  |   40 ++--
 gnome-panel/panel-applet-frame.h  |    3 +-
 gnome-panel/panel-compatibility.c |   63 ++----
 gnome-panel/panel-compatibility.h |    3 +-
 gnome-panel/panel-layout.c        |   12 +-
 gnome-panel/panel-object-loader.c |  430 +++++++++++++++++++++++++++++++++++++
 gnome-panel/panel-object-loader.h |   50 +++++
 gnome-panel/panel-profile.c       |   52 +----
 11 files changed, 545 insertions(+), 394 deletions(-)
---
diff --git a/gnome-panel/Makefile.am b/gnome-panel/Makefile.am
index bbc3706..7672946 100644
--- a/gnome-panel/Makefile.am
+++ b/gnome-panel/Makefile.am
@@ -67,6 +67,7 @@ panel_sources =			\
 	panel-ditem-editor.c	\
 	panel-layout.c		\
 	panel-modules.c		\
+	panel-object-loader.c	\
 	panel-applet-info.c
 
 panel_headers =			\
@@ -116,6 +117,7 @@ panel_headers =			\
 	panel-icon-names.h	\
 	panel-layout.h		\
 	panel-modules.h		\
+	panel-object-loader.h	\
 	panel-schemas.h		\
 	panel-applet-info.h
 
diff --git a/gnome-panel/applet.c b/gnome-panel/applet.c
index 95648d2..db08414 100644
--- a/gnome-panel/applet.c
+++ b/gnome-panel/applet.c
@@ -14,6 +14,7 @@
 #include <glib/gi18n.h>
 #include <gdk/gdkx.h>
 
+#include <libpanel-util/panel-glib.h>
 #include <libpanel-util/panel-show.h>
 
 #include "button-widget.h"
@@ -33,8 +34,7 @@
 #include "panel-globals.h"
 #include "panel-properties-dialog.h"
 #include "panel-lockdown.h"
-
-#define SMALL_ICON_SIZE 20
+#include "panel-schemas.h"
 
 static GSList *registered_applets = NULL;
 static GSList *queued_position_saves = NULL;
@@ -788,276 +788,6 @@ panel_applet_destroy (GtkWidget  *widget,
 	g_free (info);
 }
 
-typedef struct {
-	char            *id;
-	PanelObjectType  type;
-	char            *toplevel_id;
-	int              position;
-	guint            right_stick : 1;
-} PanelAppletToLoad;
-
-/* Each time those lists get both empty,
- * panel_applet_queue_initial_unhide_toplevels() should be called */
-static GSList  *panel_applets_to_load = NULL;
-static GSList  *panel_applets_loading = NULL;
-/* We have a timeout to always unhide toplevels after a delay, in case of some
- * blocking applet */
-#define         UNHIDE_TOPLEVELS_TIMEOUT_SECONDS 5
-static guint    panel_applet_unhide_toplevels_timeout = 0;
-
-static gboolean panel_applet_have_load_idle = FALSE;
-
-static void
-free_applet_to_load (PanelAppletToLoad *applet)
-{
-	g_free (applet->id);
-	applet->id = NULL;
-
-	g_free (applet->toplevel_id);
-	applet->toplevel_id = NULL;
-
-	g_free (applet);
-}
-
-gboolean
-panel_applet_on_load_queue (const char *id)
-{
-	GSList *li;
-	for (li = panel_applets_to_load; li != NULL; li = li->next) {
-		PanelAppletToLoad *applet = li->data;
-		if (strcmp (applet->id, id) == 0)
-			return TRUE;
-	}
-	for (li = panel_applets_loading; li != NULL; li = li->next) {
-		PanelAppletToLoad *applet = li->data;
-		if (strcmp (applet->id, id) == 0)
-			return TRUE;
-	}
-	return FALSE;
-}
-
-/* This doesn't do anything if the initial unhide already happened */
-static gboolean
-panel_applet_queue_initial_unhide_toplevels (gpointer user_data)
-{
-	GSList *l;
-
-	if (panel_applet_unhide_toplevels_timeout != 0) {
-		g_source_remove (panel_applet_unhide_toplevels_timeout);
-		panel_applet_unhide_toplevels_timeout = 0;
-	}
-
-	for (l = panel_toplevel_list_toplevels (); l != NULL; l = l->next)
-		panel_toplevel_queue_initial_unhide ((PanelToplevel *) l->data);
-
-	return FALSE;
-}
-
-void
-panel_applet_stop_loading (const char *id)
-{
-	PanelAppletToLoad *applet;
-	GSList *l;
-
-	for (l = panel_applets_loading; l; l = l->next) {
-		applet = l->data;
-
-		if (strcmp (applet->id, id) == 0)
-			break;
-	}
-
-	/* this can happen if we reload an applet after it crashed,
-	 * for example */
-	if (l != NULL) {
-		panel_applets_loading = g_slist_delete_link (panel_applets_loading, l);
-		free_applet_to_load (applet);
-	}
-
-	if (panel_applets_loading == NULL && panel_applets_to_load == NULL)
-		panel_applet_queue_initial_unhide_toplevels (NULL);
-}
-
-static gboolean
-panel_applet_load_idle_handler (gpointer dummy)
-{
-	PanelObjectType    applet_type;
-	PanelAppletToLoad *applet = NULL;
-	PanelToplevel     *toplevel = NULL;
-	PanelWidget       *panel_widget;
-	GSList            *l;
-
-	if (!panel_applets_to_load) {
-		panel_applet_have_load_idle = FALSE;
-		return FALSE;
-	}
-
-	for (l = panel_applets_to_load; l; l = l->next) {
-		applet = l->data;
-
-		toplevel = panel_toplevel_get_by_id (applet->toplevel_id);
-		if (toplevel)
-			break;
-	}
-
-	if (!l) {
-		/* All the remaining applets don't have a panel */
-		for (l = panel_applets_to_load; l; l = l->next)
-			free_applet_to_load (l->data);
-		g_slist_free (panel_applets_to_load);
-		panel_applets_to_load = NULL;
-		panel_applet_have_load_idle = FALSE;
-
-		if (panel_applets_loading == NULL) {
-			/* unhide any potential initially hidden toplevel */
-			panel_applet_queue_initial_unhide_toplevels (NULL);
-		}
-
-		return FALSE;
-	}
-
-	panel_applets_to_load = g_slist_delete_link (panel_applets_to_load, l);
-	panel_applets_loading = g_slist_append (panel_applets_loading, applet);
-
-	panel_widget = panel_toplevel_get_panel_widget (toplevel);
-
-	if (applet->right_stick) {
-		if (!panel_widget->packed)
-			applet->position = panel_widget->size - applet->position;
-		else
-			applet->position = -1;
-	}
-
-	/* We load applets asynchronously, so we specifically don't call
-	 * panel_applet_stop_loading() for this type. However, in case of
-	 * failure during the load, we might call panel_applet_stop_loading()
-	 * synchronously, which will make us lose the content of the applet
-	 * variable. So we save the type to be sure we always ignore the
-	 * applets. */
-	applet_type = applet->type;
-
-	switch (applet_type) {
-	case PANEL_OBJECT_APPLET:
-		panel_applet_frame_load_from_gconf (
-					panel_widget,
-					applet->position,
-					applet->id);
-		break;
-	case PANEL_OBJECT_MENU:
-		panel_menu_button_load_from_gconf (panel_widget,
-						   applet->position,
-						   TRUE,
-						   applet->id);
-		break;
-	case PANEL_OBJECT_LAUNCHER:
-		launcher_load_from_gconf (panel_widget,
-					  applet->position,
-					  applet->id);
-		break;
-	case PANEL_OBJECT_ACTION:
-		panel_action_button_load_from_gconf (
-				panel_widget,
-				applet->position,
-				TRUE,
-				applet->id);
-		break;
-	case PANEL_OBJECT_MENU_BAR:
-		panel_menu_bar_load_from_gconf (
-				panel_widget,
-				applet->position,
-				TRUE,
-				applet->id);
-		break;
-	case PANEL_OBJECT_SEPARATOR:
-		panel_separator_load_from_gconf (panel_widget,
-						 applet->position,
-						 applet->id);
-		break;
-	default:
-		g_assert_not_reached ();
-		break;
-	}
-
-	/* Only the real applets will do a late stop_loading */
-	if (applet_type != PANEL_OBJECT_APPLET)
-		panel_applet_stop_loading (applet->id);
-
-	return TRUE;
-}
-
-void
-panel_applet_queue_applet_to_load (const char      *id,
-				   PanelObjectType  type,
-				   const char      *toplevel_id,
-				   int              position,
-				   gboolean         right_stick)
-{
-	PanelAppletToLoad *applet;
-
-	if (!toplevel_id) {
-		g_warning ("No toplevel on which to load object '%s'\n", id);
-		return;
-	}
-
-	applet = g_new0 (PanelAppletToLoad, 1);
-
-	applet->id          = g_strdup (id);
-	applet->type        = type;
-	applet->toplevel_id = g_strdup (toplevel_id);
-	applet->position    = position;
-	applet->right_stick = right_stick != FALSE;
-
-	panel_applets_to_load = g_slist_prepend (panel_applets_to_load, applet);
-}
-
-static int
-panel_applet_compare (const PanelAppletToLoad *a,
-		      const PanelAppletToLoad *b)
-{
-	int c;
-
-	if ((c = strcmp (a->toplevel_id, b->toplevel_id)))
-		return c;
-	else if (a->right_stick != b->right_stick)
-		return b->right_stick ? -1 : 1;
-	else
-		return a->position - b->position;
-}
-
-void
-panel_applet_load_queued_applets (gboolean initial_load)
-{
-	if (!panel_applets_to_load) {
-		panel_applet_queue_initial_unhide_toplevels (NULL);
-		return;
-	}
-
-	if (panel_applets_to_load && panel_applet_unhide_toplevels_timeout == 0) {
-		/* Install a timeout to make sure we don't block the
-		 * unhiding because of an applet that doesn't load */
-		panel_applet_unhide_toplevels_timeout =
-			g_timeout_add_seconds (UNHIDE_TOPLEVELS_TIMEOUT_SECONDS,
-					       panel_applet_queue_initial_unhide_toplevels,
-					       NULL);
-	}
-
-	panel_applets_to_load = g_slist_sort (panel_applets_to_load,
-					      (GCompareFunc) panel_applet_compare);
-
-	if ( ! panel_applet_have_load_idle) {
-		/* on panel startup, we don't care about redraws of the
-		 * toplevels since they are hidden, so we give a higher
-		 * priority to loading of applets */
-		if (initial_load)
-			g_idle_add_full (G_PRIORITY_HIGH_IDLE,
-					 panel_applet_load_idle_handler,
-					 NULL, NULL);
-		else
-			g_idle_add (panel_applet_load_idle_handler, NULL);
-
-		panel_applet_have_load_idle = TRUE;
-	}
-}
-
 static G_CONST_RETURN char *
 panel_applet_get_toplevel_id (AppletInfo *applet)
 {
diff --git a/gnome-panel/applet.h b/gnome-panel/applet.h
index 129ebc8..dbccb25 100644
--- a/gnome-panel/applet.h
+++ b/gnome-panel/applet.h
@@ -52,7 +52,6 @@ AppletInfo *panel_applet_register    (GtkWidget       *applet,
 				      gboolean         exactpos,
 				      PanelObjectType  type,
 				      const char      *id);
-void panel_applet_stop_loading (const char *id);
 
 const char *panel_applet_get_id           (AppletInfo      *info);
 const char *panel_applet_get_id_by_widget (GtkWidget       *widget);
@@ -63,15 +62,6 @@ GSList     *panel_applet_list_applets (void);
 
 void        panel_applet_clean        (AppletInfo    *info);
 
-void panel_applet_queue_applet_to_load (const char      *id,
-					PanelObjectType  type,
-					const char      *toplevel_id,
-					int              position,
-					gboolean         right_stick);
-void panel_applet_load_queued_applets  (gboolean initial_load);
-gboolean panel_applet_on_load_queue    (const char *id);
-
-
 void            panel_applet_add_callback    (AppletInfo          *info,
 					      const gchar         *callback_name,
 					      const gchar         *stock_item,
diff --git a/gnome-panel/panel-applet-frame.c b/gnome-panel/panel-applet-frame.c
index 992b0be..a8f1c49 100644
--- a/gnome-panel/panel-applet-frame.c
+++ b/gnome-panel/panel-applet-frame.c
@@ -41,6 +41,7 @@
 #include "panel-marshal.h"
 #include "panel-background.h"
 #include "panel-lockdown.h"
+#include "panel-object-loader.h"
 #include "panel-stock-icons.h"
 #include "xstuff.h"
 #include "panel-compatibility.h"
@@ -53,7 +54,7 @@ static void panel_applet_frame_loading_failed  (const char  *iid,
 					        PanelWidget *panel,
 					        const char  *id);
 
-static void panel_applet_frame_load            (const gchar *iid,
+static void panel_applet_frame_load_helper     (const gchar *iid,
 						PanelWidget *panel,
 						int          position,
 						gboolean     exactpos,
@@ -582,7 +583,7 @@ _panel_applet_frame_activated (PanelAppletFrame           *frame,
 
 	panel_applet_frame_init_properties (frame);
 
-	panel_applet_stop_loading (frame_act->id);
+	panel_object_loader_stop_loading (frame_act->id);
 	panel_applet_frame_activating_free (frame_act);
 }
 
@@ -697,8 +698,8 @@ panel_applet_frame_reload_response (GtkWidget        *dialog,
 			panel_applet_clean (info);
 		}
 
-		panel_applet_frame_load (iid, panel,
-					 position, TRUE, id);
+		panel_applet_frame_load_helper (iid, panel,
+						position, TRUE, id);
 
 		g_free (iid);
 		g_free (id);
@@ -931,15 +932,15 @@ panel_applet_frame_loading_failed (const char  *iid,
 
 	/* Note: this call will free the memory for id, so the variable should
 	 * not get accessed afterwards. */
-	panel_applet_stop_loading (id);
+	panel_object_loader_stop_loading (id);
 }
 
 static void
-panel_applet_frame_load (const gchar *iid,
-			 PanelWidget *panel,
-			 int          position,
-			 gboolean     exactpos,
-			 const char  *id)
+panel_applet_frame_load_helper (const gchar *iid,
+				PanelWidget *panel,
+				int          position,
+				gboolean     exactpos,
+				const char  *id)
 {
 	PanelAppletFrameActivating *frame_act;
 
@@ -949,12 +950,12 @@ panel_applet_frame_load (const gchar *iid,
 
 	if (g_slist_find_custom (no_reload_applets, id,
 				 (GCompareFunc) strcmp)) {
-		panel_applet_stop_loading (id);
+		panel_object_loader_stop_loading (id);
 		return;
 	}
 
 	if (panel_lockdown_is_applet_disabled (panel_lockdown_get (), iid)) {
-		panel_applet_stop_loading (id);
+		panel_object_loader_stop_loading (id);
 		return;
 	}
 
@@ -971,23 +972,24 @@ panel_applet_frame_load (const gchar *iid,
 }
 
 void
-panel_applet_frame_load_from_gconf (PanelWidget *panel_widget,
-				    int          position,
-				    const char  *id)
+panel_applet_frame_load (GSettings   *settings,
+			 PanelWidget *panel_widget,
+			 int          position,
+			 const char  *id)
 {
 	gchar *applet_iid;
 
 	g_return_if_fail (panel_widget != NULL);
 	g_return_if_fail (id != NULL);
 
-	applet_iid = panel_compatibility_get_applet_iid (id);
+	applet_iid = panel_compatibility_get_applet_iid (settings, id);
 	if (!applet_iid) {
-		panel_applet_stop_loading (id);
+		panel_object_loader_stop_loading (id);
 		return;
 	}
 
-	panel_applet_frame_load (applet_iid, panel_widget,
-				 position, TRUE, id);
+	panel_applet_frame_load_helper (applet_iid, panel_widget,
+					position, TRUE, id);
 
 	g_free (applet_iid);
 }
diff --git a/gnome-panel/panel-applet-frame.h b/gnome-panel/panel-applet-frame.h
index 2b366a7..720d52c 100644
--- a/gnome-panel/panel-applet-frame.h
+++ b/gnome-panel/panel-applet-frame.h
@@ -83,7 +83,8 @@ void  panel_applet_frame_create             (PanelToplevel       *toplevel,
 					     int                  position,
 					     const char          *iid);
 
-void  panel_applet_frame_load_from_gconf    (PanelWidget         *panel_widget,
+void  panel_applet_frame_load               (GSettings           *settings,
+					     PanelWidget         *panel_widget,
 					     int                  position,
 					     const char          *id);
 
diff --git a/gnome-panel/panel-compatibility.c b/gnome-panel/panel-compatibility.c
index 529ba96..cd4f2ad 100644
--- a/gnome-panel/panel-compatibility.c
+++ b/gnome-panel/panel-compatibility.c
@@ -23,10 +23,13 @@
 
 #include <config.h>
 
-#include "panel-compatibility.h"
+#include <libpanel-util/panel-glib.h>
 
-#include "panel-profile.h"
 #include "panel-applets-manager.h"
+#include "panel-profile.h"
+#include "panel-schemas.h"
+
+#include "panel-compatibility.h"
 
 void
 panel_compatiblity_migrate_settings_menu_button (GConfClient *client,
@@ -49,66 +52,42 @@ panel_compatiblity_migrate_settings_menu_button (GConfClient *client,
 }
 
 gchar *
-panel_compatibility_get_applet_iid (const gchar *id)
+panel_compatibility_get_applet_iid (GSettings   *settings,
+				    const gchar *id)
 {
-	GConfClient *client = panel_gconf_get_client ();
 	PanelAppletInfo *info;
-	const char *key;
-	gchar *applet_iid;
+	gchar *object_iid;
 	gboolean needs_migration;
 	const char *iid;
 
-	/*
-	 * There are two compatibility steps here:
-	 *
-	 * 1) we need to migrate from bonobo_iid to applet_iid if there's no
-	 *    value in the applet_iid key. Always.
-	 *
-	 * 2) we need to try to migrate the iid to a new iid. We can't assume
-	 *    that the fact that the applet_iid key was used mean anything
-	 *    since the value there could well be a bonobo iid.
-	 *    The reason we really have to try to migrate first is this case:
-	 *    if an applet was added with the bonobo iid but gets ported later
-	 *    to dbus, then the reference to the bonobo iid will only be valid
-	 *    as an old reference.
-	 *    And if migration fails, we just use the iid as it is.
-	 */
-
 	needs_migration = FALSE;
 
-	key = panel_gconf_full_key (PANEL_GCONF_APPLETS, id, "applet_iid");
-	applet_iid = gconf_client_get_string (client, key, NULL);
-
-	if (!applet_iid || !applet_iid[0]) {
-		needs_migration = TRUE;
-
-		key = panel_gconf_full_key (PANEL_GCONF_APPLETS, id, "bonobo_iid");
-		applet_iid = gconf_client_get_string (client, key, NULL);
-
-		if (!applet_iid || !applet_iid[0])
-			return NULL;
+	object_iid = g_settings_get_string (settings, PANEL_OBJECT_IID_KEY);
+	if (PANEL_GLIB_STR_EMPTY (object_iid)) {
+		g_free (object_iid);
+		return NULL;
 	}
 
-	info = panel_applets_manager_get_applet_info_from_old_id (applet_iid);
+	info = panel_applets_manager_get_applet_info_from_old_id (object_iid);
 	if (!info)
-		info = panel_applets_manager_get_applet_info (applet_iid);
+		info = panel_applets_manager_get_applet_info (object_iid);
 
-	if (!info)
+	if (!info) {
+		g_free (object_iid);
 		return NULL;
+	}
 
 	iid = panel_applet_info_get_iid (info);
 
 	/* migrate if the iid in the configuration is different than the real
 	 * iid that will get used */
-	if (!g_str_equal (iid, applet_iid))
+	if (!g_str_equal (iid, object_iid))
 		needs_migration = TRUE;
 
-	g_free (applet_iid);
+	g_free (object_iid);
 
-	if (needs_migration) {
-		key = panel_gconf_full_key (PANEL_GCONF_APPLETS, id, "applet_iid");
-		gconf_client_set_string (client, key, iid, NULL);
-	}
+	if (needs_migration)
+		g_settings_set_string (settings, PANEL_OBJECT_IID_KEY, iid);
 
 	return g_strdup (iid);
 }
diff --git a/gnome-panel/panel-compatibility.h b/gnome-panel/panel-compatibility.h
index 8f3f213..f18c6a7 100644
--- a/gnome-panel/panel-compatibility.h
+++ b/gnome-panel/panel-compatibility.h
@@ -33,7 +33,8 @@ G_BEGIN_DECLS
 void panel_compatiblity_migrate_settings_menu_button (GConfClient *client,
 						      const char  *id);
 
-gchar *panel_compatibility_get_applet_iid (const gchar *id);
+gchar *panel_compatibility_get_applet_iid (GSettings   *settings,
+					   const gchar *id);
 
 G_END_DECLS
 
diff --git a/gnome-panel/panel-layout.c b/gnome-panel/panel-layout.c
index 99a8cf2..c349d03 100644
--- a/gnome-panel/panel-layout.c
+++ b/gnome-panel/panel-layout.c
@@ -37,6 +37,7 @@
 
 #include "panel.h"
 #include "panel-multiscreen.h"
+#include "panel-object-loader.h"
 #include "panel-schemas.h"
 #include "panel-toplevel.h"
 
@@ -586,10 +587,17 @@ panel_layout_load_toplevel (const char *toplevel_id)
 static void
 panel_layout_load_object (const char *object_id)
 {
+        char *path;
+
         if (PANEL_GLIB_STR_EMPTY (object_id))
                 return;
 
-        /* TODO */
+        path = g_strdup_printf ("%s%s/",
+                                PANEL_LAYOUT_OBJECT_PATH, object_id);
+
+        panel_object_loader_queue (object_id, path);
+
+        g_free (path);
 }
 
 static char *
@@ -698,5 +706,7 @@ panel_layout_load (void)
 
         panel_layout_ensure_toplevel_per_screen ();
 
+        panel_object_loader_do_load (TRUE);
+
         return TRUE;
 }
diff --git a/gnome-panel/panel-object-loader.c b/gnome-panel/panel-object-loader.c
new file mode 100644
index 0000000..c8848dc
--- /dev/null
+++ b/gnome-panel/panel-object-loader.c
@@ -0,0 +1,430 @@
+/*
+ * panel-object-loader.c: object loader
+ * vim: set et:
+ *
+ * Copyright (C) 2011 Novell, Inc.
+ *
+ * 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.
+ *
+ * Most of this code is originally from applet.c.
+ *
+ * Authors:
+ *	Vincent Untz <vuntz gnome org>
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gio/gio.h>
+
+#include <libpanel-util/panel-glib.h>
+
+#include "panel-enums.h"
+#include "panel-schemas.h"
+#include "panel-toplevel.h"
+
+/* Includes for objects we can load */
+#include "launcher.h"
+#include "panel-action-button.h"
+#include "panel-applet-frame.h"
+#include "panel-menu-bar.h"
+#include "panel-menu-button.h"
+#include "panel-separator.h"
+
+#include "panel-object-loader.h"
+
+typedef struct {
+        char      *id;
+        char      *settings_path;
+        GSettings *settings;
+        char      *toplevel_id;
+        int        position;
+        guint      right_stick : 1;
+} PanelObjectToLoad;
+
+/* Each time those lists get both empty,
+ * panel_object_loader_queue_initial_unhide_toplevels() should be called */
+static GSList  *panel_objects_to_load = NULL;
+static GSList  *panel_objects_loading = NULL;
+
+/* We have a timeout to always unhide toplevels after a delay, in case of some
+ * blocking object */
+#define         UNHIDE_TOPLEVELS_TIMEOUT_SECONDS 5
+static guint    panel_object_loader_unhide_toplevels_timeout = 0;
+
+static gboolean panel_object_loader_have_idle = FALSE;
+
+static void
+free_object_to_load (PanelObjectToLoad *object)
+{
+        g_free (object->id);
+        object->id = NULL;
+
+        g_free (object->settings_path);
+        object->settings_path = NULL;
+
+        g_object_unref (object->settings);
+        object->settings = NULL;
+
+        g_free (object->toplevel_id);
+        object->toplevel_id = NULL;
+
+        g_free (object);
+}
+
+/* This doesn't do anything if the initial unhide already happened */
+static gboolean
+panel_object_loader_queue_initial_unhide_toplevels (gpointer user_data)
+{
+        GSList *l;
+
+        if (panel_object_loader_unhide_toplevels_timeout != 0) {
+                g_source_remove (panel_object_loader_unhide_toplevels_timeout);
+                panel_object_loader_unhide_toplevels_timeout = 0;
+        }
+
+        for (l = panel_toplevel_list_toplevels (); l != NULL; l = l->next)
+                panel_toplevel_queue_initial_unhide ((PanelToplevel *) l->data);
+
+        return FALSE;
+}
+
+void
+panel_object_loader_stop_loading (const char *id)
+{
+        PanelObjectToLoad *object;
+        GSList *l;
+
+        for (l = panel_objects_loading; l; l = l->next) {
+                object = l->data;
+
+                if (g_strcmp0 (object->id, id) == 0)
+                        break;
+        }
+
+        /* this can happen if we reload an object after it crashed,
+         * for example */
+        if (l != NULL) {
+                panel_objects_loading = g_slist_delete_link (panel_objects_loading, l);
+                free_object_to_load (object);
+        }
+
+        if (panel_objects_loading == NULL && panel_objects_to_load == NULL)
+                panel_object_loader_queue_initial_unhide_toplevels (NULL);
+}
+
+static gboolean
+panel_object_loader_idle_handler (gpointer dummy)
+{
+        PanelObjectToLoad *object = NULL;
+        PanelToplevel     *toplevel = NULL;
+        PanelWidget       *panel_widget;
+        GSList            *l;
+        char              *iid = NULL;
+        PanelObjectType    object_type;
+        char              *object_type_detail = NULL;
+        gboolean           ret;
+
+        if (!panel_objects_to_load) {
+                panel_object_loader_have_idle = FALSE;
+                return FALSE;
+        }
+
+        for (l = panel_objects_to_load; l; l = l->next) {
+                object = l->data;
+
+                toplevel = panel_toplevel_get_by_id (object->toplevel_id);
+                if (toplevel)
+                        break;
+        }
+
+        if (!l) {
+                /* All the remaining objects don't have a panel */
+                for (l = panel_objects_to_load; l; l = l->next)
+                        free_object_to_load (l->data);
+                g_slist_free (panel_objects_to_load);
+                panel_objects_to_load = NULL;
+                panel_object_loader_have_idle = FALSE;
+
+                if (panel_objects_loading == NULL) {
+                        /* unhide any potential initially hidden toplevel */
+                        panel_object_loader_queue_initial_unhide_toplevels (NULL);
+                }
+
+                return FALSE;
+        }
+
+        panel_objects_to_load = g_slist_delete_link (panel_objects_to_load, l);
+        panel_objects_loading = g_slist_append (panel_objects_loading, object);
+
+        panel_widget = panel_toplevel_get_panel_widget (toplevel);
+
+        if (object->right_stick) {
+                if (!panel_widget->packed)
+                        object->position = panel_widget->size - object->position;
+                else
+                        object->position = -1;
+        }
+
+        iid = g_settings_get_string (object->settings, PANEL_OBJECT_IID_KEY);
+        ret = panel_object_iid_to_type (iid, &object_type, &object_type_detail);
+
+        if (!ret) {
+                g_printerr ("Object '%s' has an invalid iid ('%s')\n",
+                            object->id, iid);
+                panel_object_loader_stop_loading (object->id);
+                g_free (iid);
+                return TRUE;
+        }
+
+        g_free (iid);
+
+        switch (object_type) {
+        case PANEL_OBJECT_APPLET:
+                panel_applet_frame_load (
+                                object->settings,
+                                panel_widget,
+                                object->position,
+                                object->id);
+                break;
+        case PANEL_OBJECT_MENU:
+                panel_menu_button_load_from_gconf (panel_widget,
+                                object->position,
+                                TRUE,
+                                object->id);
+                break;
+        case PANEL_OBJECT_LAUNCHER:
+                launcher_load_from_gconf (panel_widget,
+                                object->position,
+                                object->id);
+                break;
+        case PANEL_OBJECT_ACTION:
+                panel_action_button_load_from_gconf (
+                                panel_widget,
+                                object->position,
+                                TRUE,
+                                object->id);
+                break;
+        case PANEL_OBJECT_MENU_BAR:
+                panel_menu_bar_load_from_gconf (
+                                panel_widget,
+                                object->position,
+                                TRUE,
+                                object->id);
+                break;
+        case PANEL_OBJECT_SEPARATOR:
+                panel_separator_load_from_gconf (panel_widget,
+                                object->position,
+                                object->id);
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+
+        /* We load applets asynchronously, so we specifically don't call
+         * panel_object_loader_stop_loading() for this type. */
+        if (object_type != PANEL_OBJECT_APPLET)
+                panel_object_loader_stop_loading (object->id);
+
+        return TRUE;
+}
+
+void
+panel_object_loader_queue (const char *id,
+                           const char *settings_path)
+{
+        PanelObjectToLoad *object;
+        GSettings         *settings;
+        char              *toplevel_id;
+
+        settings = g_settings_new_with_path (PANEL_OBJECT_SCHEMA,
+                                             settings_path);
+        toplevel_id = g_settings_get_string (settings,
+                                             PANEL_OBJECT_TOPLEVEL_ID_KEY);
+
+        if (PANEL_GLIB_STR_EMPTY (toplevel_id)) {
+                g_warning ("No toplevel on which to load object '%s'\n", id);
+                g_free (toplevel_id);
+                g_object_unref (settings);
+                return;
+        }
+
+        object = g_new0 (PanelObjectToLoad, 1);
+
+        object->id            = g_strdup (id);
+        object->settings_path = g_strdup (settings_path);
+        object->settings      = g_object_ref (settings);
+        object->toplevel_id   = toplevel_id;
+        object->position      = g_settings_get_int (settings,
+                                                    PANEL_OBJECT_POSITION_KEY);
+        object->right_stick   = g_settings_get_boolean (settings,
+                                                        PANEL_OBJECT_PACK_END_KEY);
+
+        panel_objects_to_load = g_slist_prepend (panel_objects_to_load, object);
+
+        g_object_unref (settings);
+}
+
+static int
+panel_object_compare (const PanelObjectToLoad *a,
+                      const PanelObjectToLoad *b)
+{
+        int c;
+
+        if ((c = g_strcmp0 (a->toplevel_id, b->toplevel_id)))
+                return c;
+        else if (a->right_stick != b->right_stick)
+                return b->right_stick ? -1 : 1;
+        else
+                return a->position - b->position;
+}
+
+void
+panel_object_loader_do_load (gboolean initial_load)
+{
+        if (!panel_objects_to_load) {
+                panel_object_loader_queue_initial_unhide_toplevels (NULL);
+                return;
+        }
+
+        if (panel_objects_to_load && panel_object_loader_unhide_toplevels_timeout == 0) {
+                /* Install a timeout to make sure we don't block the
+                 * unhiding because of an object that doesn't load */
+                panel_object_loader_unhide_toplevels_timeout =
+                        g_timeout_add_seconds (UNHIDE_TOPLEVELS_TIMEOUT_SECONDS,
+                                               panel_object_loader_queue_initial_unhide_toplevels,
+                                               NULL);
+        }
+
+        panel_objects_to_load = g_slist_sort (panel_objects_to_load,
+                                              (GCompareFunc) panel_object_compare);
+
+        if (!panel_object_loader_have_idle) {
+                /* on panel startup, we don't care about redraws of the
+                 * toplevels since they are hidden, so we give a higher
+                 * priority to loading of objects */
+                if (initial_load)
+                        g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+                                         panel_object_loader_idle_handler,
+                                         NULL, NULL);
+                else
+                        g_idle_add (panel_object_loader_idle_handler, NULL);
+
+                panel_object_loader_have_idle = TRUE;
+        }
+}
+
+gboolean
+panel_object_loader_is_queued (const char *id)
+{
+        GSList *li;
+        for (li = panel_objects_to_load; li != NULL; li = li->next) {
+                PanelObjectToLoad *object = li->data;
+                if (g_strcmp0 (object->id, id) == 0)
+                        return TRUE;
+        }
+        for (li = panel_objects_loading; li != NULL; li = li->next) {
+                PanelObjectToLoad *object = li->data;
+                if (g_strcmp0 (object->id, id) == 0)
+                        return TRUE;
+        }
+        return FALSE;
+}
+
+
+/*******************************\
+ * iid <=> object type mapping *
+\*******************************/
+
+static struct {
+        PanelObjectType  type;
+        const char      *id;
+        gboolean         has_detail;
+} panel_object_iid_map[] = {
+        { PANEL_OBJECT_ACTION,    "ActionButton" , TRUE  },
+        { PANEL_OBJECT_MENU_BAR,  "MenuBar"      , FALSE },
+        { PANEL_OBJECT_MENU,      "MenuButton"   , FALSE },
+        { PANEL_OBJECT_LAUNCHER,  "Launcher"     , FALSE },
+        { PANEL_OBJECT_SEPARATOR, "Separator"    , FALSE }
+};
+
+gboolean
+panel_object_iid_to_type (const char       *iid,
+                          PanelObjectType  *type,
+                          char            **detail)
+{
+	const char *instance_id;
+	char       *factory_id;
+	gboolean    is_applet;;
+        int         i;
+
+        if (detail)
+                *detail = NULL;
+
+	instance_id = g_strrstr (iid, "::");
+        if (!instance_id)
+                return FALSE;
+
+	factory_id = g_strndup (iid, strlen (iid) - strlen (instance_id));
+        is_applet = (g_strcmp0 (factory_id, "PanelInternalFactory") != 0);
+        g_free (factory_id);
+
+        if (is_applet) {
+                *type = PANEL_OBJECT_APPLET;
+                return TRUE;
+        }
+
+	instance_id += 2;
+
+        for (i = 0; i < G_N_ELEMENTS (panel_object_iid_map); i++) {
+                if (!panel_object_iid_map[i].has_detail &&
+                    g_strcmp0 (panel_object_iid_map[i].id,
+                               instance_id) == 0) {
+                        *type = panel_object_iid_map[i].type;
+                        return TRUE;
+                }
+
+                if (panel_object_iid_map[i].has_detail) {
+                        const char *d;
+
+                        if (!g_str_has_prefix (instance_id,
+                                               panel_object_iid_map[i].id))
+                                continue;
+
+                        d = instance_id + strlen (panel_object_iid_map[i].id);
+                        if (d[0] != ':')
+                                return FALSE;
+
+                        d += 1;
+                        if (d[0] == '\0')
+                                return FALSE;
+
+                        *type = panel_object_iid_map[i].type;
+                        if (detail)
+                                *detail = g_strdup (d);
+
+                        return TRUE;
+                }
+        }
+
+        /* We don't know this id; it could be provided by an applet now (for
+         * features that moved from being internal to the panel to applets, and
+         * that provide compatibility with the same id). So let's try it.  */
+        *type = PANEL_OBJECT_APPLET;
+        return TRUE;
+}
diff --git a/gnome-panel/panel-object-loader.h b/gnome-panel/panel-object-loader.h
new file mode 100644
index 0000000..d2603bd
--- /dev/null
+++ b/gnome-panel/panel-object-loader.h
@@ -0,0 +1,50 @@
+/*
+ * panel-object-loader.h: object loader
+ * vim: set et:
+ *
+ * Copyright (C) 2011 Novell, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ *	Vincent Untz <vuntz gnome org>
+ */
+
+#ifndef __PANEL_OBJECT_LOADER_H__
+#define __PANEL_OBJECT_LOADER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void     panel_object_loader_queue         (const char *id,
+                                            const char *settings_path);
+void     panel_object_loader_do_load       (gboolean initial_load);
+
+gboolean panel_object_loader_is_queued     (const char *id);
+void     panel_object_loader_stop_loading  (const char *id);
+
+/*******************************\
+ * iid <=> object type mapping *
+\*******************************/
+
+gboolean panel_object_iid_to_type (const char       *iid,
+                                   PanelObjectType  *type,
+                                   char            **detail);
+
+G_END_DECLS
+
+#endif /* __PANEL_OBJECT_LOADER_H__ */
diff --git a/gnome-panel/panel-profile.c b/gnome-panel/panel-profile.c
index 68b0752..70d860f 100644
--- a/gnome-panel/panel-profile.c
+++ b/gnome-panel/panel-profile.c
@@ -34,6 +34,7 @@
 #include "applet.h"
 #include "panel-gconf.h"
 #include "panel.h"
+#include "panel-object-loader.h"
 #include "panel-widget.h"
 #include "panel-util.h"
 #include "panel-multiscreen.h"
@@ -470,7 +471,7 @@ panel_profile_load_and_show_toplevel (GConfClient       *client,
 	}
 
 	if (!loading_queued_applets)
-		panel_applet_load_queued_applets (FALSE);
+		panel_object_loader_do_load (FALSE);
 }
 
 static void
@@ -566,49 +567,6 @@ panel_profile_load_object (GConfClient       *client,
 			   PanelGConfKeyType  type,
 			   const char        *id)
 {
-	PanelObjectType  object_type;
-	char            *object_dir;
-	const char      *key;
-	char            *type_string;
-	char            *toplevel_id;
-	int              position;
-	gboolean         right_stick;
-
-	object_dir = g_strdup_printf ("%s/%s/%s",
-				      profile_dir,
-				      type == PANEL_GCONF_OBJECTS ? "objects" : "applets",
-				      id);
-
-	gconf_client_add_dir (client, object_dir, GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
-
-	key = panel_gconf_sprintf ("%s/object_type", object_dir);
-	type_string = gconf_client_get_string (client, key, NULL);
-        
-	if (!panel_profile_map_object_type_string (type_string, &object_type)) {
-		g_free (type_string);
-		gconf_client_remove_dir (client, object_dir, NULL);
-		g_free (object_dir);
-		return;
-	}
-	
-	key = panel_gconf_sprintf ("%s/position", object_dir);
-	position = gconf_client_get_int (client, key, NULL);
-	
-	key = panel_gconf_sprintf ("%s/toplevel_id", object_dir);
-	toplevel_id = gconf_client_get_string (client, key, NULL);
-
-	key = panel_gconf_sprintf ("%s/panel_right_stick", object_dir);
-	right_stick = gconf_client_get_bool (client, key, NULL);
-
-	panel_applet_queue_applet_to_load (id,
-					   object_type,
-					   toplevel_id,
-					   position,
-					   right_stick);
-
-	g_free (toplevel_id);
-	g_free (type_string);
-	g_free (object_dir);
 }
 
 static void
@@ -853,7 +811,7 @@ panel_profile_object_id_list_update (GConfClient       *client,
 				      object_ids,
 				      (PanelProfileGetIdFunc) panel_applet_get_id,
 				      (PanelProfileLoadFunc) panel_profile_load_object,
-				      (PanelProfileOnLoadQueue) panel_applet_on_load_queue);
+				      (PanelProfileOnLoadQueue) panel_object_loader_is_queued);
 
 	panel_profile_delete_removed_ids (client,
 					  type,
@@ -865,7 +823,7 @@ panel_profile_object_id_list_update (GConfClient       *client,
 	g_slist_free (sublist);
 	g_slist_free (object_ids);
 
-	panel_applet_load_queued_applets (FALSE);
+	panel_object_loader_do_load (FALSE);
 }
 
 static void
@@ -946,6 +904,4 @@ panel_profile_load (void)
 				 PANEL_GCONF_APPLETS,
 				 panel_profile_load_object,
 				 (GConfClientNotifyFunc) panel_profile_object_id_list_notify);
-
-	panel_applet_load_queued_applets (TRUE);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]