From abe1a40d562514cfe6b3c8dae1397d511062ddab Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sun, 2 Oct 2005 18:50:51 +0000 Subject: Use nsIDOMWindowInternal::Close to close tabs. Delay tabs destruction to 2005-10-02 Christian Persch * configure.ac: * embed/ephy-embed-shell.c: (ephy_embed_shell_dispose), (ephy_embed_shell_finalize), (ephy_embed_shell_class_init): * embed/ephy-embed.c: (ephy_embed_base_init), (ephy_embed_show_page_certificate), (ephy_embed_close): * embed/ephy-embed.h: * embed/mozilla/EphyBrowser.cpp: * embed/mozilla/EphyBrowser.h: * embed/mozilla/mozilla-embed.cpp: * src/ephy-notebook.c: (ephy_notebook_class_init), (close_button_clicked_cb): * src/ephy-notebook.h: * src/ephy-python.c: (ephy_python_init), (ephy_python_shutdown), (ephy_python_schedule_gc): * src/ephy-shell.c: (ephy_shell_class_init), (gnome_session_init), (ephy_shell_dispose), (ephy_shell_finalize): * src/ephy-tab.c: (ephy_tab_init): * src/ephy-window.c: (construct_confirm_close_dialog), (confirm_close_with_modified_forms), (embed_modal_alert_cb), (idle_tab_remove_cb), (schedule_tab_close), (embed_close_request_cb), (embed_destroy_browser_cb), (tab_added_cb), (tab_removed_cb), (tab_close_request_cb), (setup_notebook), (remove_true), (ephy_window_dispose), (cancel_handler), (ephy_window_init), (ephy_window_finalize): * src/window-commands.c: (event_with_shift), (window_cmd_view_reload), (window_cmd_file_close_window): Use nsIDOMWindowInternal::Close to close tabs. Delay tabs destruction to an idle handler, to avoid crashes when tabs are closed from signal handlers (blur, mousedown, keydown etc). Fixes bug #172878, bug #172879, bug #172882, bug #303254, bug #313425. --- src/ephy-window.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 147 insertions(+), 22 deletions(-) (limited to 'src/ephy-window.c') diff --git a/src/ephy-window.c b/src/ephy-window.c index 050a43d4d..3abcc2c7b 100644 --- a/src/ephy-window.c +++ b/src/ephy-window.c @@ -421,6 +421,7 @@ struct _EphyWindowPrivate guint help_message_cid; EphyEmbedChrome chrome; guint idle_resize_handler; + GHashTable *tabs_to_remove; EphyEmbedEvent *context_event; guint idle_worker; @@ -648,11 +649,10 @@ ephy_window_unfullscreen (EphyWindow *window) sync_chromes_visibility (window); } -static gboolean -confirm_close_with_modified_forms (EphyWindow *window) +static GtkWidget * +construct_confirm_close_dialog (EphyWindow *window) { GtkWidget *dialog; - int response; dialog = gtk_message_dialog_new (GTK_WINDOW (window), @@ -671,11 +671,21 @@ confirm_close_with_modified_forms (EphyWindow *window) gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); - /* FIXME set title */ + /* FIXME gtk_window_set_title (GTK_WINDOW (dialog), _("Close Document?")); */ gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); gtk_window_group_add_window (GTK_WINDOW (window)->group, GTK_WINDOW (dialog)); + return dialog; +} + +static gboolean +confirm_close_with_modified_forms (EphyWindow *window) +{ + GtkWidget *dialog; + int response; + + dialog = construct_confirm_close_dialog (window); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); @@ -2076,8 +2086,8 @@ update_tabs_menu_sensitivity (EphyWindow *window) } static gboolean -modal_alert_cb (EphyEmbed *embed, - EphyWindow *window) +embed_modal_alert_cb (EphyEmbed *embed, + EphyWindow *window) { EphyWindowPrivate *priv = window->priv; EphyTab *tab; @@ -2104,6 +2114,83 @@ modal_alert_cb (EphyEmbed *embed, return FALSE; } +static gboolean +idle_tab_remove_cb (EphyTab *tab) +{ + GtkWidget *toplevel; + EphyWindow *window; + EphyWindowPrivate *priv; + EphyNotebook *notebook; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tab)); + if (!EPHY_IS_WINDOW (toplevel)) return FALSE; /* FIXME should this ever occur? */ + + window = EPHY_WINDOW (toplevel); + priv = window->priv; + + if (priv->closing) return FALSE; + + g_hash_table_remove (priv->tabs_to_remove, tab); + + notebook = EPHY_NOTEBOOK (ephy_window_get_notebook (window)); + ephy_notebook_remove_tab (notebook, tab); + + /* don't run again */ + return FALSE; +} + +static void +schedule_tab_close (EphyWindow *window, + EphyEmbed *embed) +{ + EphyWindowPrivate *priv = window->priv; + EphyTab *tab; + guint id; + + LOG ("scheduling close of embed %p in window %p", embed, window); + + if (priv->closing) return; + + tab = ephy_tab_for_embed (embed); + g_return_if_fail (tab != NULL); + + if (g_hash_table_lookup (priv->tabs_to_remove, tab) != NULL) return; + + /* do this on idle, because otherwise we'll crash in certain circumstances + * (see galeon bug #116256) + */ + id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, + (GSourceFunc) idle_tab_remove_cb, + tab, NULL); + + g_hash_table_insert (priv->tabs_to_remove, tab, GUINT_TO_POINTER (id)); + + /* don't wait until idle to hide the window */ + if (g_hash_table_size (priv->tabs_to_remove) == priv->num_tabs) + { + gtk_widget_hide (GTK_WIDGET (window)); + } +} + +static gboolean +embed_close_request_cb (EphyEmbed *embed, + EphyWindow *window) +{ + LOG ("embed_close_request_cb embed %p window %p", embed, window); + + schedule_tab_close (window, embed); + + /* handled */ + return TRUE; +} + +static void +embed_destroy_browser_cb (EphyEmbed *embed, + EphyWindow *window) +{ + g_return_if_reached (); +} + static gboolean show_notebook_popup_menu (GtkNotebook *notebook, EphyWindow *window, @@ -2190,8 +2277,14 @@ tab_added_cb (EphyNotebook *notebook, embed = ephy_tab_get_embed (tab); g_return_if_fail (embed != NULL); - g_signal_connect_after (embed, "ge-modal-alert", - G_CALLBACK (modal_alert_cb), window); + g_signal_connect_object (embed, "close-request", + G_CALLBACK (embed_close_request_cb), + window, 0); + g_signal_connect_object (embed, "destroy-browser", + G_CALLBACK (embed_destroy_browser_cb), + window, 0); + g_signal_connect_object (embed, "ge-modal-alert", + G_CALLBACK (embed_modal_alert_cb), window, G_CONNECT_AFTER); /* Let the extensions attach themselves to the tab */ manager = EPHY_EXTENSION (ephy_shell_get_extensions_manager (ephy_shell)); @@ -2230,7 +2323,11 @@ tab_removed_cb (EphyNotebook *notebook, g_return_if_fail (embed != NULL); g_signal_handlers_disconnect_by_func - (embed, G_CALLBACK (modal_alert_cb), window); + (embed, G_CALLBACK (embed_modal_alert_cb), window); + g_signal_handlers_disconnect_by_func + (embed, G_CALLBACK (embed_close_request_cb), window); + g_signal_handlers_disconnect_by_func + (embed, G_CALLBACK (embed_destroy_browser_cb), window); } static void @@ -2260,24 +2357,28 @@ tabs_reordered_cb (EphyNotebook *notebook, EphyWindow *window) update_tabs_menu_sensitivity (window); } -static gboolean -tab_delete_cb (EphyNotebook *notebook, - EphyTab *tab, - EphyWindow *window) +static void +tab_close_request_cb (EphyNotebook *notebook, + EphyTab *tab, + EphyWindow *window) { - g_return_val_if_fail (EPHY_IS_TAB (tab), FALSE); + EphyWindowPrivate *priv = window->priv; + EphyEmbed *embed; if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_QUIT) && - gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook)) == 1) + gtk_notebook_get_n_pages (priv->notebook) == 1) { - return TRUE; + return; } - else if (ephy_embed_has_modified_forms (ephy_tab_get_embed (tab))) + + embed = ephy_tab_get_embed (tab); + g_return_if_fail (embed != NULL); + + if (!ephy_embed_has_modified_forms (embed) || + confirm_close_with_modified_forms (window)) { - return !confirm_close_with_modified_forms (window); + ephy_embed_close (embed); } - - return FALSE; } static GtkNotebook * @@ -2305,8 +2406,8 @@ setup_notebook (EphyWindow *window) G_CALLBACK (tab_detached_cb), NULL); g_signal_connect (G_OBJECT (notebook), "tabs_reordered", G_CALLBACK (tabs_reordered_cb), window); - g_signal_connect (G_OBJECT (notebook), "tab_delete", - G_CALLBACK (tab_delete_cb), window); + g_signal_connect (G_OBJECT (notebook), "tab_close_request", + G_CALLBACK (tab_close_request_cb), window); return notebook; } @@ -2365,6 +2466,12 @@ ephy_window_set_is_popup (EphyWindow *window, g_object_notify (G_OBJECT (window), "is-popup"); } +static gboolean +remove_true (void) +{ + return TRUE; +} + static void ephy_window_dispose (GObject *object) { @@ -2404,6 +2511,8 @@ ephy_window_dispose (GObject *object) priv->idle_resize_handler = 0; } + g_hash_table_foreach_remove (priv->tabs_to_remove, (GHRFunc) remove_true, NULL); + g_object_unref (priv->fav_menu); priv->fav_menu = NULL; @@ -2754,6 +2863,14 @@ find_toolbar_close_cb (EphyFindToolbar *toolbar, gtk_widget_hide (GTK_WIDGET (toolbar)); } +static void +cancel_handler (gpointer idptr) +{ + guint id = GPOINTER_TO_UINT (idptr); + + g_source_remove (id); +} + static void ephy_window_init (EphyWindow *window) { @@ -2769,6 +2886,9 @@ ephy_window_init (EphyWindow *window) priv = window->priv = EPHY_WINDOW_GET_PRIVATE (window); + priv->tabs_to_remove = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, cancel_handler); + window->priv->chrome = EPHY_EMBED_CHROME_ALL; ephy_gui_ensure_window_group (GTK_WINDOW (window)); @@ -2911,6 +3031,11 @@ ephy_window_constructor (GType type, static void ephy_window_finalize (GObject *object) { + EphyWindow *window = EPHY_WINDOW (object); + EphyWindowPrivate *priv = window->priv; + + g_hash_table_destroy (priv->tabs_to_remove); + G_OBJECT_CLASS (parent_class)->finalize (object); LOG ("Ephy Window finalized %p", object); -- cgit v1.2.3