diff options
author | Christian Persch <chpe@cvs.gnome.org> | 2005-10-03 02:50:51 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2005-10-03 02:50:51 +0800 |
commit | abe1a40d562514cfe6b3c8dae1397d511062ddab (patch) | |
tree | 08fb5018af362336c9b92f0e1d83d25c2bd3b2b8 | |
parent | 8a92076ee578e5c6aa8bb0a39fcdbe8741ce2e52 (diff) | |
download | gsoc2013-epiphany-abe1a40d562514cfe6b3c8dae1397d511062ddab.tar.gz gsoc2013-epiphany-abe1a40d562514cfe6b3c8dae1397d511062ddab.tar.zst gsoc2013-epiphany-abe1a40d562514cfe6b3c8dae1397d511062ddab.zip |
Use nsIDOMWindowInternal::Close to close tabs. Delay tabs destruction to
2005-10-02 Christian Persch <chpe@cvs.gnome.org>
* 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.
-rw-r--r-- | ChangeLog | 34 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | embed/ephy-embed-shell.c | 32 | ||||
-rw-r--r-- | embed/ephy-embed.c | 30 | ||||
-rw-r--r-- | embed/ephy-embed.h | 4 | ||||
-rw-r--r-- | embed/mozilla/EphyBrowser.cpp | 61 | ||||
-rw-r--r-- | embed/mozilla/EphyBrowser.h | 10 | ||||
-rw-r--r-- | embed/mozilla/mozilla-embed.cpp | 9 | ||||
-rw-r--r-- | src/ephy-notebook.c | 26 | ||||
-rw-r--r-- | src/ephy-notebook.h | 2 | ||||
-rw-r--r-- | src/ephy-python.c | 6 | ||||
-rw-r--r-- | src/ephy-shell.c | 73 | ||||
-rw-r--r-- | src/ephy-tab.c | 23 | ||||
-rw-r--r-- | src/ephy-window.c | 169 | ||||
-rw-r--r-- | src/window-commands.c | 63 |
15 files changed, 393 insertions, 153 deletions
@@ -1,5 +1,39 @@ 2005-10-02 Christian Persch <chpe@cvs.gnome.org> + * 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. + +2005-10-02 Christian Persch <chpe@cvs.gnome.org> + * embed/print-dialog.c: (ephy_print_do_print_idle_cb): Remove unused variable. diff --git a/configure.ac b/configure.ac index 9a2180854..fac05ca45 100644 --- a/configure.ac +++ b/configure.ac @@ -210,8 +210,8 @@ AC_MSG_RESULT([$gecko]) case "$gecko" in mozilla) min_version=1.7.9 flavour=mozilla ;; seamonkey) min_version=1.0 flavour=mozilla ;; -*firefox) min_version=1.0 flavour=toolkit ;; -*thunderbird) min_version=1.0 flavour=toolkit ;; +*firefox) min_version=1.0.5 flavour=toolkit ;; +*thunderbird) min_version=1.0.5 flavour=toolkit ;; esac MOZILLA=$gecko diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c index 43e7fb692..fb7a7d216 100644 --- a/embed/ephy-embed-shell.c +++ b/embed/ephy-embed-shell.c @@ -87,40 +87,49 @@ ephy_embed_shell_get_type (void) } static void -ephy_embed_shell_finalize (GObject *object) +ephy_embed_shell_dispose (GObject *object) { EphyEmbedShell *shell = EPHY_EMBED_SHELL (object); - LOG ("Unref history"); - if (shell->priv->global_history) - { - g_object_unref (shell->priv->global_history); - } - - LOG ("Unref downloader"); if (shell->priv->downloader_view) { + LOG ("Unref downloader"); g_object_remove_weak_pointer (G_OBJECT(shell->priv->downloader_view), (gpointer *) &shell->priv->downloader_view); g_object_unref (shell->priv->downloader_view); } - LOG ("Unref favicon cache"); if (shell->priv->favicon_cache) { + LOG ("Unref favicon cache"); g_object_unref (G_OBJECT (shell->priv->favicon_cache)); } - LOG ("Unref encodings"); if (shell->priv->encodings) + LOG ("Unref encodings"); { + LOG ("Unref encodings"); g_object_unref (G_OBJECT (shell->priv->encodings)); } - LOG ("Unref embed single"); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +ephy_embed_shell_finalize (GObject *object) +{ + EphyEmbedShell *shell = EPHY_EMBED_SHELL (object); + + if (shell->priv->global_history) + { + LOG ("Unref history"); + g_object_unref (shell->priv->global_history); + } + if (shell->priv->embed_single) { + LOG ("Unref embed single"); g_object_unref (G_OBJECT (shell->priv->embed_single)); } @@ -235,6 +244,7 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass) parent_class = (GObjectClass *) g_type_class_peek_parent (klass); + object_class->dispose = ephy_embed_shell_dispose; object_class->finalize = ephy_embed_shell_finalize; klass->get_embed_single = impl_get_embed_single; diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c index 60e82be0a..b1128a835 100644 --- a/embed/ephy-embed.c +++ b/embed/ephy-embed.c @@ -368,6 +368,23 @@ ephy_embed_base_init (gpointer g_class) 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); +/** + * EphyEmbed::close-request + * @embed: + * + * The ::close signal is emitted when the embed request closing. + * Return %TRUE to prevent closing. You HAVE to process removal of the embed + * as soon as possible after that. + **/ + g_signal_new ("close-request", + EPHY_TYPE_EMBED, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyEmbedIface, close_request), + g_signal_accumulator_true_handled, NULL, + ephy_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, + 0); + initialized = TRUE; } } @@ -732,6 +749,19 @@ ephy_embed_show_page_certificate (EphyEmbed *embed) } /** + * ephy_embed_close: + * @embed: an #EphyEmbed + * + * Closes the @embed + **/ +void +ephy_embed_close (EphyEmbed *embed) +{ + EphyEmbedIface *iface = EPHY_EMBED_GET_IFACE (embed); + iface->close (embed); +} + +/** * ephy_embed_set_encoding: * @embed: an #EphyEmbed * @encoding: the desired encoding diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h index eaac67801..96e4ee77f 100644 --- a/embed/ephy-embed.h +++ b/embed/ephy-embed.h @@ -149,6 +149,7 @@ struct _EphyEmbedIface EphyEmbed *new_embed); gboolean (* search_key_press) (EphyEmbed *embed, GdkEventKey *event); + gboolean (* close_request) (EphyEmbed *embed); /* Methods */ void (* load_url) (EphyEmbed *embed, @@ -197,6 +198,7 @@ struct _EphyEmbedIface EphyEmbedPrintPreviewNavType type, int page); gboolean (* has_modified_forms) (EphyEmbed *embed); + void (* close) (EphyEmbed *embed); }; GType ephy_embed_net_state_get_type (void); @@ -290,6 +292,8 @@ void ephy_embed_print_preview_navigate (EphyEmbed *embed, int page); /* Misc. utility */ +void ephy_embed_close (EphyEmbed *embed); + gboolean ephy_embed_has_modified_forms (EphyEmbed *embed); G_END_DECLS diff --git a/embed/mozilla/EphyBrowser.cpp b/embed/mozilla/EphyBrowser.cpp index 3812b87d1..77b7e2c5c 100644 --- a/embed/mozilla/EphyBrowser.cpp +++ b/embed/mozilla/EphyBrowser.cpp @@ -90,6 +90,7 @@ /* will never be frozen */ #include "nsIDocShell.h" #include "nsIMarkupDocumentViewer.h" +#include <nsIDOMWindowInternal.h> #ifdef HAVE_MOZILLA_PSM /* not sure about this one: */ #include <nsITransportSecurityInfo.h> @@ -108,6 +109,7 @@ const static PRUnichar kDOMMouseScroll[] = { 'D', 'O', 'M', 'M', 'o', 'u', 's', const static PRUnichar kDOMPopupBlocked[] = { 'D', 'O', 'M', 'P', 'o', 'p', 'u', 'p', 'B', 'l', 'o', 'c', 'k', 'e', 'd', '\0' }; const static PRUnichar kDOMWillOpenModalDialog[] = { 'D', 'O', 'M', 'W', 'i', 'l', 'l', 'O', 'p', 'e', 'n', 'M', 'o', 'd', 'a', 'l', 'D', 'i', 'a', 'l', 'o', 'g', '\0' }; const static PRUnichar kDOMModalDialogClosed[] = { 'D', 'O', 'M', 'M', 'o', 'd', 'a', 'l', 'D', 'i', 'a', 'l', 'o', 'g', 'C', 'l', 'o', 's', 'e', 'd', '\0' }; +const static PRUnichar kDOMWindowClose[] = { 'D', 'O', 'M', 'W', 'i', 'n', 'd', 'o', 'w', 'C', 'l', 'o', 's', 'e', '\0' }; const static PRUnichar kHrefAttr[] = { 'h', 'r', 'e', 'f', '\0' }; const static PRUnichar kTypeAttr[] = { 't', 'y', 'p', 'e', '\0' }; const static PRUnichar kTitleAttr[] = { 't', 'i', 't', 'l', 'e', '\0' }; @@ -273,11 +275,39 @@ EphyDOMLinkEventListener::HandleEvent (nsIDOMEvent* aDOMEvent) } NS_IMETHODIMP -EphyDOMContentLoadedEventListener::HandleEvent (nsIDOMEvent* aDOMEvent) +EphyMiscDOMEventsListener::HandleEvent (nsIDOMEvent* aDOMEvent) { - LOG ("DOMContentLoaded event fired up"); + /* make sure the event is trusted */ + nsCOMPtr<nsIDOMNSEvent> nsEvent (do_QueryInterface (aDOMEvent)); + NS_ENSURE_TRUE (nsEvent, NS_ERROR_FAILURE); + PRBool isTrusted = PR_FALSE; + nsEvent->GetIsTrusted (&isTrusted); + if (!isTrusted) return NS_OK; - g_signal_emit_by_name (mOwner->mEmbed, "dom_content_loaded", (gpointer)aDOMEvent); + nsresult rv; + nsEmbedString type; + rv = aDOMEvent->GetType (type); + NS_ENSURE_SUCCESS (rv, rv); + + nsEmbedCString cType; + NS_UTF16ToCString (type, NS_CSTRING_ENCODING_UTF8, cType); + + if (g_ascii_strcasecmp (cType.get(), "DOMContentLoaded") == 0) + { + g_signal_emit_by_name (mOwner->mEmbed, "dom_content_loaded", + (gpointer)aDOMEvent); + } + else if (g_ascii_strcasecmp (cType.get(), "DOMWindowClose") == 0) + { + gboolean prevent = FALSE; + + g_signal_emit_by_name (mOwner->mEmbed, "close-request", &prevent); + + if (prevent) + { + aDOMEvent->PreventDefault (); + } + } return NS_OK; } @@ -484,7 +514,7 @@ EphyContextMenuListener::HandleEvent (nsIDOMEvent* aDOMEvent) EphyBrowser::EphyBrowser () : mDOMLinkEventListener(nsnull) -, mDOMContentLoadedEventListener(nsnull) +, mMiscDOMEventsListener(nsnull) , mDOMScrollEventListener(nsnull) , mPopupBlockEventListener(nsnull) , mModalAlertListener(nsnull) @@ -524,8 +554,8 @@ nsresult EphyBrowser::Init (GtkMozEmbed *mozembed) mDOMLinkEventListener = new EphyDOMLinkEventListener(this); if (!mDOMLinkEventListener) return NS_ERROR_OUT_OF_MEMORY; - mDOMContentLoadedEventListener = new EphyDOMContentLoadedEventListener(this); - if (!mDOMContentLoadedEventListener) return NS_ERROR_OUT_OF_MEMORY; + mMiscDOMEventsListener = new EphyMiscDOMEventsListener(this); + if (!mMiscDOMEventsListener) return NS_ERROR_OUT_OF_MEMORY; mDOMScrollEventListener = new EphyDOMScrollEventListener(this); if (!mDOMScrollEventListener) return NS_ERROR_OUT_OF_MEMORY; @@ -630,7 +660,9 @@ EphyBrowser::AttachListeners(void) rv = target->AddEventListener(nsEmbedString(kDOMLinkAdded), mDOMLinkEventListener, PR_FALSE, PR_FALSE); rv |= target->AddEventListener(nsEmbedString(kDOMContentLoaded), - mDOMContentLoadedEventListener, PR_FALSE, PR_FALSE); + mMiscDOMEventsListener, PR_FALSE, PR_FALSE); + rv |= target->AddEventListener(nsEmbedString(kDOMWindowClose), + mMiscDOMEventsListener, PR_FALSE, PR_FALSE); rv |= target->AddEventListener(nsEmbedString(kDOMMouseScroll), mDOMScrollEventListener, PR_TRUE /* capture */, PR_FALSE); rv |= target->AddEventListener(nsEmbedString(kDOMPopupBlocked), @@ -641,7 +673,7 @@ EphyBrowser::AttachListeners(void) mModalAlertListener, PR_TRUE, PR_FALSE); rv |= target->AddEventListener(nsEmbedString(kContextMenu), mContextMenuListener, PR_TRUE /* capture */, PR_FALSE); - NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS (rv, rv); return NS_OK; } @@ -655,7 +687,9 @@ EphyBrowser::DetachListeners(void) rv = mEventTarget->RemoveEventListener(nsEmbedString(kDOMLinkAdded), mDOMLinkEventListener, PR_FALSE); rv |= mEventTarget->RemoveEventListener(nsEmbedString(kDOMContentLoaded), - mDOMContentLoadedEventListener, PR_FALSE); + mMiscDOMEventsListener, PR_FALSE); + rv |= mEventTarget->RemoveEventListener(nsEmbedString(kDOMWindowClose), + mMiscDOMEventsListener, PR_FALSE); rv |= mEventTarget->RemoveEventListener(nsEmbedString(kDOMMouseScroll), mDOMScrollEventListener, PR_TRUE); /* capture */ rv |= mEventTarget->RemoveEventListener(nsEmbedString(kDOMPopupBlocked), @@ -1298,6 +1332,15 @@ EphyBrowser::GetDocumentType () return type; } +nsresult +EphyBrowser::Close () +{ + nsCOMPtr<nsIDOMWindowInternal> domWin (do_QueryInterface (mDOMWindow)); + NS_ENSURE_TRUE (domWin, NS_ERROR_FAILURE); + + return domWin->Close(); +} + #ifndef HAVE_GECKO_1_8 nsresult EphyBrowser::FocusActivate () diff --git a/embed/mozilla/EphyBrowser.h b/embed/mozilla/EphyBrowser.h index 3b4fb2284..2020cf4f1 100644 --- a/embed/mozilla/EphyBrowser.h +++ b/embed/mozilla/EphyBrowser.h @@ -93,12 +93,12 @@ public: EphyModalAlertEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; }; -class EphyDOMContentLoadedEventListener : public EphyEventListener +class EphyMiscDOMEventsListener : public EphyEventListener { public: NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); - EphyDOMContentLoadedEventListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; + EphyMiscDOMEventsListener(EphyBrowser *aOwner) : EphyEventListener(aOwner) { }; }; class EphyDOMScrollEventListener : public EphyEventListener @@ -129,7 +129,7 @@ class EphyBrowser { friend class EphyEventListener; friend class EphyDOMLinkEventListener; -friend class EphyDOMContentLoadedEventListener; +friend class EphyMiscDOMEventsListener; friend class EphyDOMScrollEventListener; friend class EphyPopupBlockEventListener; friend class EphyModalAlertEventListener; @@ -177,6 +177,8 @@ public: nsresult GetSecurityInfo (PRUint32 *aState, nsACString &aDescription); nsresult ShowCertificate (); + nsresult Close (); + EphyEmbedDocumentType GetDocumentType (); #ifndef HAVE_GECKO_1_8 @@ -193,7 +195,7 @@ private: nsCOMPtr<nsIDOMEventTarget> mEventTarget; nsCOMPtr<nsIDOMWindow> mDOMWindow; EphyDOMLinkEventListener *mDOMLinkEventListener; - EphyDOMContentLoadedEventListener *mDOMContentLoadedEventListener; + EphyMiscDOMEventsListener *mMiscDOMEventsListener; EphyDOMScrollEventListener *mDOMScrollEventListener; EphyPopupBlockEventListener *mPopupBlockEventListener; EphyModalAlertEventListener *mModalAlertListener; diff --git a/embed/mozilla/mozilla-embed.cpp b/embed/mozilla/mozilla-embed.cpp index b0e9ed5ff..5116f12e3 100644 --- a/embed/mozilla/mozilla-embed.cpp +++ b/embed/mozilla/mozilla-embed.cpp @@ -223,6 +223,14 @@ child_focus_out_event_cb (GtkWidget *child, #endif /* !HAVE_GECKO_1_8 */ static void +impl_close (EphyEmbed *embed) +{ + MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; + + mpriv->browser->Close (); +} + +static void mozilla_embed_realize (GtkWidget *widget) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (widget)->priv; @@ -1163,6 +1171,7 @@ ephy_embed_iface_init (EphyEmbedIface *iface) iface->shistory_go_nth = impl_shistory_go_nth; iface->get_security_level = impl_get_security_level; iface->show_page_certificate = impl_show_page_certificate; + iface->close = impl_close; iface->set_encoding = impl_set_encoding; iface->get_encoding = impl_get_encoding; iface->has_automatic_encoding = impl_has_automatic_encoding; diff --git a/src/ephy-notebook.c b/src/ephy-notebook.c index fd4d41208..63e4a92c1 100644 --- a/src/ephy-notebook.c +++ b/src/ephy-notebook.c @@ -113,7 +113,7 @@ enum TAB_REMOVED, TABS_REORDERED, TAB_DETACHED, - TAB_DELETE, + TAB_CLOSE_REQUEST, LAST_SIGNAL }; @@ -260,14 +260,14 @@ ephy_notebook_class_init (EphyNotebookClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - signals[TAB_DELETE] = - g_signal_new ("tab_delete", + signals[TAB_CLOSE_REQUEST] = + g_signal_new ("tab-close-request", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EphyNotebookClass, tab_delete), - g_signal_accumulator_true_handled, NULL, - ephy_marshal_BOOLEAN__OBJECT, - G_TYPE_BOOLEAN, + G_STRUCT_OFFSET (EphyNotebookClass, tab_close_req), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, EPHY_TYPE_TAB); @@ -1023,16 +1023,10 @@ sync_label (EphyTab *tab, GParamSpec *pspec, GtkWidget *proxy) static void close_button_clicked_cb (GtkWidget *widget, GtkWidget *tab) { - EphyNotebook *notebook; - gboolean inhibited = FALSE; - - notebook = EPHY_NOTEBOOK (gtk_widget_get_parent (tab)); - g_signal_emit (G_OBJECT (notebook), signals[TAB_DELETE], 0, tab, &inhibited); + GtkWidget *notebook; - if (inhibited == FALSE) - { - ephy_notebook_remove_tab (notebook, EPHY_TAB (tab)); - } + notebook = gtk_widget_get_parent (tab); + g_signal_emit (notebook, signals[TAB_CLOSE_REQUEST], 0, tab); } static void diff --git a/src/ephy-notebook.h b/src/ephy-notebook.h index 04ae54fcd..6ad66d870 100644 --- a/src/ephy-notebook.h +++ b/src/ephy-notebook.h @@ -61,7 +61,7 @@ struct _EphyNotebookClass void (* tab_detached) (EphyNotebook *notebook, EphyTab *tab); void (* tabs_reordered) (EphyNotebook *notebook); - gboolean (* tab_delete) (EphyNotebook *notebook, + void (* tab_close_req) (EphyNotebook *notebook, EphyTab *tab); }; diff --git a/src/ephy-python.c b/src/ephy-python.c index 01c255879..12da0d69f 100644 --- a/src/ephy-python.c +++ b/src/ephy-python.c @@ -38,6 +38,7 @@ extern PyMethodDef pyepiphany_functions[]; static guint idle_gc_handler = 0; static guint idle_shutdown_handler = 0; +static gboolean python_initialised = FALSE; void ephy_python_init (void) @@ -46,6 +47,7 @@ ephy_python_init (void) PyObject *m, *d; Py_Initialize(); + python_initialised = TRUE; argv[0] = g_get_prgname (); PySys_SetArgv (1, argv); @@ -74,6 +76,8 @@ idle_shutdown (void) void ephy_python_shutdown (void) { + if (!python_initialised) return; + g_return_if_fail (idle_shutdown_handler == 0); LOG ("EphyPython shutdown with %s GC scheduled", @@ -123,7 +127,7 @@ ephy_python_schedule_gc (void) { /* LOG ("Scheduling a GC with %s GC already scheduled", idle_gc_handler != 0 ? "a" : "no"); */ - if (idle_gc_handler == 0) + if (python_initialised && idle_gc_handler == 0) { idle_gc_handler = g_idle_add ((GSourceFunc) idle_gc, NULL); } diff --git a/src/ephy-shell.c b/src/ephy-shell.c index 0fba9847f..ac48e82b3 100644 --- a/src/ephy-shell.c +++ b/src/ephy-shell.c @@ -91,6 +91,7 @@ EphyShell *ephy_shell = NULL; static void ephy_shell_class_init (EphyShellClass *klass); static void ephy_shell_init (EphyShell *shell); +static void ephy_shell_dispose (GObject *object); static void ephy_shell_finalize (GObject *object); static GObject *impl_get_embed_single (EphyEmbedShell *embed_shell); @@ -145,6 +146,7 @@ ephy_shell_class_init (EphyShellClass *klass) parent_class = g_type_class_peek_parent (klass); + object_class->dispose = ephy_shell_dispose; object_class->finalize = ephy_shell_finalize; embed_shell_class->get_embed_single = impl_get_embed_single; @@ -414,14 +416,13 @@ gnome_session_init (EphyShell *shell) client = gnome_master_client (); - g_signal_connect (G_OBJECT (client), - "save_yourself", - G_CALLBACK (save_yourself_cb), - shell); - g_signal_connect (G_OBJECT (client), - "die", - G_CALLBACK (die_cb), - shell); + g_signal_connect_object (client, "save_yourself", + G_CALLBACK (save_yourself_cb), shell, 0); + /* don't use connect_object here, since that will ref the shell + * while dispatching the callbacks! + */ + g_signal_connect (client, "die", + G_CALLBACK (die_cb), shell); } gboolean @@ -525,101 +526,107 @@ done: } static void -ephy_shell_finalize (GObject *object) +ephy_shell_dispose (GObject *object) { EphyShell *shell = EPHY_SHELL (object); - g_assert (ephy_shell == NULL); + LOG ("EphyShell disposing"); + + if (shell->priv->automation_factory) + { + LOG ("Deregistering bonobo server"); + bonobo_activation_unregister_active_server + (AUTOMATION_FACTORY_IID, BONOBO_OBJREF (shell->priv->automation_factory)); + + bonobo_object_unref (shell->priv->automation_factory); + } - /* this will unload the extensions */ - LOG ("Unref extension manager"); if (shell->priv->extensions_manager) { + LOG ("Unref extension manager"); + /* this will unload the extensions */ g_object_unref (shell->priv->extensions_manager); } #ifdef ENABLE_DBUS - LOG ("Shutting down DBUS service"); if (shell->priv->dbus_service) { + LOG ("Shutting down DBUS service"); g_object_unref (shell->priv->dbus_service); } #endif - LOG ("Unref session manager"); if (shell->priv->session) { + LOG ("Unref session manager"); g_object_unref (shell->priv->session); } - LOG ("Unref lockdown controller"); if (shell->priv->lockdown) { + LOG ("Unref lockdown controller"); g_object_unref (shell->priv->lockdown); } - LOG ("Unref toolbars model"); if (shell->priv->toolbars_model) { + LOG ("Unref toolbars model"); g_object_unref (shell->priv->toolbars_model); } - LOG ("Unref fullscreen toolbars model"); if (shell->priv->fs_toolbars_model) { + LOG ("Unref fullscreen toolbars model"); g_object_unref (shell->priv->fs_toolbars_model); } - LOG ("Unref Bookmarks Editor"); if (shell->priv->bme) { + LOG ("Unref Bookmarks Editor"); gtk_widget_destroy (GTK_WIDGET (shell->priv->bme)); } - LOG ("Unref History Window"); if (shell->priv->history_window) { + LOG ("Unref History Window"); gtk_widget_destroy (GTK_WIDGET (shell->priv->history_window)); } - LOG ("Unref PDM Dialog"); if (shell->priv->pdm_dialog) { + LOG ("Unref PDM Dialog"); g_object_unref (shell->priv->pdm_dialog); } - LOG ("Unref prefs dialog"); if (shell->priv->prefs_dialog) { + LOG ("Unref prefs dialog"); g_object_unref (shell->priv->prefs_dialog); } - LOG ("Unref print setup dialog"); if (shell->priv->print_setup_dialog) { + LOG ("Unref print setup dialog"); g_object_unref (shell->priv->print_setup_dialog); } - LOG ("Unref bookmarks"); if (shell->priv->bookmarks) { + LOG ("Unref bookmarks"); g_object_unref (shell->priv->bookmarks); } - G_OBJECT_CLASS (parent_class)->finalize (object); - - if (shell->priv->automation_factory) - { - bonobo_activation_unregister_active_server - (AUTOMATION_FACTORY_IID, BONOBO_OBJREF (shell->priv->automation_factory)); + G_OBJECT_CLASS (parent_class)->dispose (object); +} - bonobo_object_unref (shell->priv->automation_factory); - } +static void +ephy_shell_finalize (GObject *object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); - LOG ("Ephy shell finalized"); + LOG ("Ephy shell finalised"); } - /** * ephy_shell_get_default: * diff --git a/src/ephy-tab.c b/src/ephy-tab.c index d07152a53..f19b6fd22 100644 --- a/src/ephy-tab.c +++ b/src/ephy-tab.c @@ -1795,26 +1795,6 @@ ephy_tab_visibility_cb (EphyEmbed *embed, gboolean visibility, g_object_notify (G_OBJECT (tab), "visibility"); } -static void -ephy_tab_destroy_brsr_cb (EphyEmbed *embed, EphyTab *tab) -{ - EphyWindow *window; - GtkWidget *notebook; - - g_return_if_fail (EPHY_IS_TAB (tab)); - - LOG ("ephy_tab_destroy_browser_cb tab %p parent %p", - tab, ((GtkWidget *) tab)->parent); - - window = ephy_tab_get_window (tab); - g_return_if_fail (window != NULL); - - /* Do not use ephy_window_remove_tab because it will - check for unsubmitted forms */ - notebook = ephy_window_get_notebook (window); - ephy_notebook_remove_tab (EPHY_NOTEBOOK (notebook), tab); -} - static gboolean open_link_in_new_tab (EphyTab *tab, const char *link_address) @@ -2045,9 +2025,6 @@ ephy_tab_init (EphyTab *tab) g_signal_connect_object (embed, "visibility", G_CALLBACK (ephy_tab_visibility_cb), tab, 0); - g_signal_connect_object (embed, "destroy_browser", - G_CALLBACK (ephy_tab_destroy_brsr_cb), - tab, 0); g_signal_connect_object (embed, "ge_dom_mouse_click", G_CALLBACK (ephy_tab_dom_mouse_click_cb), tab, 0); 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; @@ -2105,6 +2115,83 @@ modal_alert_cb (EphyEmbed *embed, } 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, GdkEventButton *event) @@ -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; @@ -2755,6 +2864,14 @@ find_toolbar_close_cb (EphyFindToolbar *toolbar, } static void +cancel_handler (gpointer idptr) +{ + guint id = GPOINTER_TO_UINT (idptr); + + g_source_remove (id); +} + +static void ephy_window_init (EphyWindow *window) { EphyWindowPrivate *priv; @@ -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); diff --git a/src/window-commands.c b/src/window-commands.c index 6e119d327..79659dba9 100644 --- a/src/window-commands.c +++ b/src/window-commands.c @@ -165,6 +165,33 @@ window_cmd_go_forward (GtkAction *action, ephy_embed_go_forward (embed); } +static gboolean +event_with_shift (void) +{ + GdkEvent *event; + GdkEventType type = 0; + guint state = 0; + + event = gtk_get_current_event (); + if (event) + { + type = event->type; + + if (type == GDK_BUTTON_RELEASE) + { + state = event->button.state; + } + else if (type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE) + { + state = event->key.state; + } + + gdk_event_free (event); + } + + return (state & GDK_SHIFT_MASK) != 0; +} + void window_cmd_go_location (GtkAction *action, EphyWindow *window) @@ -191,39 +218,13 @@ window_cmd_view_reload (GtkAction *action, EphyWindow *window) { EphyEmbed *embed; - GdkEvent *event; - GdkEventType type; - guint state = 0; - gboolean force = FALSE; embed = ephy_window_get_active_embed (window); g_return_if_fail (embed != NULL); - event = gtk_get_current_event (); - if (event) - { - type = event->type; - - if (type == GDK_BUTTON_RELEASE) - { - state = event->button.state; - } - else if (type == GDK_KEY_RELEASE) - { - state = event->key.state; - } - - gdk_event_free (event); - } - - if (state & GDK_SHIFT_MASK) - { - force = TRUE; - } - gtk_widget_grab_focus (GTK_WIDGET (embed)); - ephy_embed_reload (embed, force); + ephy_embed_reload (embed, event_with_shift ()); } void @@ -387,7 +388,7 @@ void window_cmd_file_close_window (GtkAction *action, EphyWindow *window) { - EphyTab *tab; + EphyEmbed *embed; if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_QUIT) && gtk_notebook_get_n_pages (GTK_NOTEBOOK (ephy_window_get_notebook (window))) == 1) @@ -395,10 +396,10 @@ window_cmd_file_close_window (GtkAction *action, return; } - tab = ephy_window_get_active_tab (window); - g_return_if_fail (tab != NULL); + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); - ephy_window_remove_tab (window, tab); + ephy_embed_close (embed); } void |