aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog34
-rw-r--r--configure.ac4
-rw-r--r--embed/ephy-embed-shell.c32
-rw-r--r--embed/ephy-embed.c30
-rw-r--r--embed/ephy-embed.h4
-rw-r--r--embed/mozilla/EphyBrowser.cpp61
-rw-r--r--embed/mozilla/EphyBrowser.h10
-rw-r--r--embed/mozilla/mozilla-embed.cpp9
-rw-r--r--src/ephy-notebook.c26
-rw-r--r--src/ephy-notebook.h2
-rw-r--r--src/ephy-python.c6
-rw-r--r--src/ephy-shell.c73
-rw-r--r--src/ephy-tab.c23
-rw-r--r--src/ephy-window.c169
-rw-r--r--src/window-commands.c63
15 files changed, 393 insertions, 153 deletions
diff --git a/ChangeLog b/ChangeLog
index e8f7088fc..f93ed2b2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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