[epiphany] Refactor EphyShell lifetime tracking



commit 46845bbcf412994f0bb3e949178c6f72f676f70b
Author: Xan Lopez <xan gnome org>
Date:   Fri Oct 23 02:51:17 2009 +0300

    Refactor EphyShell lifetime tracking
    
    Stop having each EphyWindow ref the shell, and instead have the shell
    track all the newly created EphyWindows. When the last one is gone,
    quit the GTK+ mainloop. This is simpler and avoids potential reference
    cycles (see bug #573551).
    
    Bug #599348

 embed/downloader-view.c  |   17 +----------------
 embed/ephy-embed-shell.c |   40 ++++++++++++++++++++++++++++++++++++++++
 embed/ephy-embed-shell.h |    4 ++++
 src/ephy-main.c          |   23 +++++++++--------------
 src/ephy-window.c        |   12 +-----------
 5 files changed, 55 insertions(+), 41 deletions(-)
---
diff --git a/embed/downloader-view.c b/embed/downloader-view.c
index da28caf..a2f6558 100644
--- a/embed/downloader-view.c
+++ b/embed/downloader-view.c
@@ -74,7 +74,6 @@ struct _DownloaderViewPrivate
 	NotifyNotification *notification;
 #endif
 
-	guint idle_unref : 1;
 	guint source_id;
 	guint notification_timeout;
 };
@@ -222,8 +221,6 @@ prepare_close_cb (EphyEmbedShell *shell,
 	/* hide window already */
 	gtk_widget_hide (priv->window);
 
-	priv->idle_unref = FALSE;
-
 	/* cancel pending downloads */
 	g_hash_table_foreach_remove (priv->downloads_hash,
 				     (GHRFunc) remove_download, view);
@@ -237,14 +234,12 @@ prepare_close_cb (EphyEmbedShell *shell,
 static void
 downloader_view_init (DownloaderView *dv)
 {
-	g_object_ref (embed_shell);
-
+	_ephy_embed_shell_track_object (embed_shell, G_OBJECT (dv));
 	dv->priv = EPHY_DOWNLOADER_VIEW_GET_PRIVATE (dv);
 
 	dv->priv->downloads_hash = g_hash_table_new_full
 		(g_direct_hash, g_direct_equal, NULL,
 		 (GDestroyNotify)gtk_tree_row_reference_free);
-	dv->priv->idle_unref = TRUE;
 
 	downloader_view_build_ui (dv);
 
@@ -259,7 +254,6 @@ downloader_view_finalize (GObject *object)
 {
 	DownloaderView *dv = EPHY_DOWNLOADER_VIEW (object);
 	DownloaderViewPrivate *priv = dv->priv;
-	gboolean idle_unref = dv->priv->idle_unref;
 
 	if (priv->status_icon != NULL)
 	{
@@ -286,15 +280,6 @@ downloader_view_finalize (GObject *object)
 	g_hash_table_destroy (dv->priv->downloads_hash);
 
 	G_OBJECT_CLASS (downloader_view_parent_class)->finalize (object);
-
-	if (idle_unref)
-	{
-		ephy_object_idle_unref (embed_shell);
-	}
-	else
-	{
-		g_object_unref (embed_shell);
-	}
 }
 
 DownloaderView *
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 85eb7fa..17f4b98 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -57,12 +57,14 @@ struct _EphyEmbedShellPrivate
 	EphyAdBlockManager *adblock_manager;
 	GtkPageSetup *page_setup;
 	GtkPrintSettings *print_settings;
+	guint object_count;
 	guint single_initialised : 1;
 };
 
 enum
 {
 	PREPARE_CLOSE,
+	QUIT,
 	LAST_SIGNAL
 };
 
@@ -315,6 +317,25 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
 			      NULL, NULL,
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE, 0);
+
+/**
+ * EphyEmbedShell::quit:
+ * @shell: an #EphyEmbedShell
+ * 
+ * The ::quit is emitted when all windows (browser windows, popups,
+ * download windows, etc) are closed and the @shell is ready to be
+ * closed.
+ *
+ * Since: 2.30
+ **/
+	signals[QUIT] =
+		g_signal_new ("quit",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
 	
 	g_type_class_add_private (object_class, sizeof (EphyEmbedShellPrivate));
 }
@@ -490,3 +511,22 @@ ephy_embed_shell_get_print_settings (EphyEmbedShell *shell)
 
 	return priv->print_settings;
 }
+
+
+static void
+object_notify_cb (EphyEmbedShell *shell, GObject *object)
+{
+	shell->priv->object_count--;
+	if (shell->priv->object_count == 0)
+		g_signal_emit (shell, signals[QUIT], 0);
+}
+
+void
+_ephy_embed_shell_track_object (EphyEmbedShell *shell, GObject *object)
+{
+	g_return_if_fail (EPHY_IS_EMBED_SHELL (shell));
+	g_return_if_fail (G_IS_OBJECT (object));
+
+	g_object_weak_ref (object, (GWeakNotify)object_notify_cb, shell);
+	shell->priv->object_count++;
+}
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index 9772293..ef10c2a 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -91,6 +91,10 @@ void		   ephy_embed_shell_set_print_settings	(EphyEmbedShell *shell,
 		
 GtkPrintSettings  *ephy_embed_shell_get_print_settings	(EphyEmbedShell *shell);
 
+/* Private API */
+void	       _ephy_embed_shell_track_object		(EphyEmbedShell *shell,
+							 GObject        *object);
+
 G_END_DECLS
 
 #endif /* !EPHY_EMBED_SHELL_H */
diff --git a/src/ephy-main.c b/src/ephy-main.c
index 5daca6f..493eb91 100644
--- a/src/ephy-main.c
+++ b/src/ephy-main.c
@@ -238,16 +238,6 @@ handle_email (GtkAboutDialog *about,
 }
 
 static void
-shell_weak_notify (gpointer data,
-                   GObject *zombie)
-{
-	if (gtk_main_level ())
-	{
-		gtk_main_quit ();
-	}
-}
-
-static void
 unref_proxy_reply_cb (DBusGProxy *proxy,
 		      GError *error,
 		      gpointer user_data)
@@ -468,6 +458,12 @@ save_accels (void)
         g_free (filename);
 }
 
+static void
+shell_quit_cb (EphyShell *shell, gpointer data)
+{
+	gtk_main_quit ();
+}
+
 int
 main (int argc,
       char *argv[])
@@ -767,13 +763,10 @@ main (int argc,
 
 	/* Now create the shell */
 	_ephy_shell_create_instance ();
+	g_signal_connect (ephy_shell, "quit", G_CALLBACK (shell_quit_cb), NULL);
 
 	queue_commands (user_time);
 
-	/* We'll release the initial reference on idle */
-	g_object_weak_ref (G_OBJECT (ephy_shell), shell_weak_notify, NULL);
-	ephy_object_idle_unref (ephy_shell);
-
 #ifdef HAVE_LIBNOTIFY	
 	/* Init notifications for the download manager */
 	notify_init (PACKAGE);
@@ -782,6 +775,8 @@ main (int argc,
 	gtk_main ();
 
 	/* Shutdown */
+	g_object_unref (ephy_shell);
+
 #ifdef HAVE_LIBNOTIFY	
 	if (notify_is_initted ())
 		notify_uninit ();
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 3f53fa3..df0c7df 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -458,7 +458,6 @@ struct _EphyWindowPrivate
 	guint is_popup : 1;
 	guint present_on_insert : 1;
 	guint key_theme_is_emacs : 1;
-	guint shell_unref : 1;
 };
 
 enum
@@ -3315,15 +3314,6 @@ ephy_window_dispose (GObject *object)
 	destroy_fullscreen_popup (window);
 
 	G_OBJECT_CLASS (ephy_window_parent_class)->dispose (object);
-
-	/* We need to unref the shell after chaining up to the parent
-	 * class, since our children widgets might need the shell to
-	 * be around for some cleanup operations */
-	if (window->priv->shell_unref == FALSE)
-	{
-		g_object_unref (ephy_shell);
-		window->priv->shell_unref = TRUE;
-	}
 }
 
 static void
@@ -3642,7 +3632,7 @@ ephy_window_init (EphyWindow *window)
 {
 	LOG ("EphyWindow initialising %p", window);
 
-	g_object_ref (ephy_shell);
+	_ephy_embed_shell_track_object (EPHY_EMBED_SHELL (ephy_shell), G_OBJECT (window));
 
 	window->priv = EPHY_WINDOW_GET_PRIVATE (window);
 }



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