diff options
author | Christian Persch <chpe@cvs.gnome.org> | 2006-02-02 21:31:32 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2006-02-02 21:31:32 +0800 |
commit | 4d8b2c6114da0d8b629215a2ca690411d1d71949 (patch) | |
tree | 64ed27dc4ebd81a958dea41f97e92e2926ad56b3 /src/ephy-session.c | |
parent | cbecc0e54beb04ea9b2094058331237f5362ff48 (diff) | |
download | gsoc2013-epiphany-4d8b2c6114da0d8b629215a2ca690411d1d71949.tar.gz gsoc2013-epiphany-4d8b2c6114da0d8b629215a2ca690411d1d71949.tar.zst gsoc2013-epiphany-4d8b2c6114da0d8b629215a2ca690411d1d71949.zip |
Queue commands received from the main and remote instances, and process
2006-02-02 Christian Persch <chpe@cvs.gnome.org>
* src/ephy-session.c: (save_yourself_cb), (die_cb),
(session_command_free), (session_command_find),
(resume_dialog_response_cb), (resume_dialog_weak_ref_cb),
(session_command_autoresume),
(session_command_open_bookmarks_editor),
(session_command_open_uris), (session_command_dispatch),
(session_command_queue_next), (session_command_queue_clear),
(ephy_session_init), (ephy_session_dispose),
(ephy_session_finalize), (ephy_session_close), (ephy_session_load),
(ephy_session_get_active_window), (ephy_session_queue_command):
* src/ephy-session.h:
* src/ephy-main.c: (unref_proxy_reply_cb), (open_urls),
(call_dbus_proxy), (queue_commands), (main):
Queue commands received from the main and remote instances,
and process them after autoresume has completed. Bug #328286.
* data/epiphany-service.xml:
* lib/ephy-file-helpers.c: (ephy_file_helpers_init):
* lib/ephy-file-helpers.h:
* src/ephy-activation.c: (session_queue_command),
(ephy_activation_load_uri_list), (ephy_activation_load_session),
(ephy_activation_open_bookmarks_editor):
* src/ephy-activation.h:
* src/ephy-dbus.c:
* src/ephy-dbus.h:
* src/epiphany.defs:
Diffstat (limited to 'src/ephy-session.c')
-rw-r--r-- | src/ephy-session.c | 622 |
1 files changed, 518 insertions, 104 deletions
diff --git a/src/ephy-session.c b/src/ephy-session.c index ffa81bbe6..d9a9a59a0 100644 --- a/src/ephy-session.c +++ b/src/ephy-session.c @@ -36,9 +36,7 @@ #include "ephy-debug.h" #include <glib/gi18n.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> +#include <gtk/gtkmain.h> #include <gtk/gtkimage.h> #include <gtk/gtklabel.h> #include <gtk/gtkstock.h> @@ -46,11 +44,27 @@ #include <gtk/gtkvbox.h> #include <gtk/gtkdialog.h> #include <gtk/gtkmessagedialog.h> + +#include <libgnomeui/gnome-client.h> + #include <libgnomevfs/gnome-vfs-ops.h> #include <libgnomevfs/gnome-vfs-utils.h> + #include <libxml/tree.h> #include <libxml/xmlwriter.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +typedef struct +{ + EphySessionCommand command; + char *arg; + char **args; + guint32 user_time; +} SessionCommand; + #define EPHY_SESSION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SESSION, EphySessionPrivate)) struct _EphySessionPrivate @@ -58,6 +72,10 @@ struct _EphySessionPrivate GList *windows; GList *tool_windows; GtkWidget *resume_dialog; + + GQueue *queue; + guint queue_idle_id; + guint dont_save : 1; guint quit_while_resuming : 1; }; @@ -69,6 +87,7 @@ struct _EphySessionPrivate static void ephy_session_class_init (EphySessionClass *klass); static void ephy_session_iface_init (EphyExtensionIface *iface); static void ephy_session_init (EphySession *session); +static void session_command_queue_next (EphySession *session); enum { @@ -117,6 +136,57 @@ ephy_session_get_type (void) return type; } +/* Gnome session client */ + +static gboolean +save_yourself_cb (GnomeClient *client, + gint phase, + GnomeSaveStyle save_style, + gboolean shutdown, + GnomeInteractStyle interact_style, + gboolean fast, + EphySession *session) +{ + char *argv[] = { NULL, "--load-session", NULL }; + char *discard_argv[] = { "rm", "-f", NULL }; + char *tmp, *save_to; + + LOG ("save_yourself_cb"); + + tmp = g_build_filename (ephy_dot_dir (), + "session_gnome-XXXXXX", + NULL); + save_to = ephy_file_tmp_filename (tmp, "xml"); + g_free (tmp); + + argv[0] = g_get_prgname (); + argv[2] = save_to; + gnome_client_set_restart_command + (client, 3, argv); + + discard_argv[2] = save_to; + gnome_client_set_discard_command (client, 3, + discard_argv); + + ephy_session_save (session, save_to); + + g_free (save_to); + + return TRUE; +} + +static void +die_cb (GnomeClient* client, + EphySession *session) + +{ + LOG ("die_cb"); + + ephy_session_close (session); +} + +/* Helper functions */ + static char * get_session_filename (const char *filename) { @@ -207,6 +277,334 @@ window_focus_in_event_cb (EphyWindow *window, return FALSE; } +/* Queue worker */ + +static void +session_command_free (SessionCommand *cmd) +{ + g_assert (cmd != NULL); + + g_free (cmd->arg); + if (cmd->args) + { + g_strfreev (cmd->args); + } + + g_free (cmd); + + g_object_unref (ephy_shell_get_default ()); +} + +static int +session_command_find (const SessionCommand *cmd, + gpointer cmdptr) +{ + EphySessionCommand command = GPOINTER_TO_INT (cmdptr); + + return command != cmd->command; +} + +static void +resume_dialog_response_cb (GtkWidget *dialog, + int response, + EphySession *session) +{ + guint32 user_time; + + LOG ("resume_dialog_response_cb response:%d", response); + + gtk_widget_hide (dialog); + + user_time = gtk_get_current_event_time (); + + if (response == GTK_RESPONSE_ACCEPT) + { + ephy_session_queue_command (session, + EPHY_SESSION_CMD_LOAD_SESSION, + SESSION_CRASHED, NULL, + user_time, TRUE); + } + + ephy_session_queue_command (session, + EPHY_SESSION_CMD_MAYBE_OPEN_WINDOW, + NULL, NULL, user_time, FALSE); + + gtk_widget_destroy (dialog); +} + +static void +resume_dialog_weak_ref_cb (EphySession *session, + GObject *zombie) +{ + EphySessionPrivate *priv = session->priv; + + LOG ("resume_dialog_weak_ref_cb"); + + priv->resume_dialog = NULL; + + gtk_window_set_auto_startup_notification (TRUE); + + session_command_queue_next (session); + + g_object_unref (ephy_shell_get_default ()); +} + +static void +session_command_autoresume (EphySession *session, + guint32 user_time) +{ + EphySessionPrivate *priv = session->priv; + GtkWidget *dialog; + char *saved_session; + gboolean crashed_session; + + LOG ("ephy_session_autoresume"); + + saved_session = get_session_filename (SESSION_CRASHED); + crashed_session = g_file_test (saved_session, G_FILE_TEST_EXISTS); + g_free (saved_session); + + if (crashed_session == FALSE || + priv->windows != NULL || + priv->tool_windows != NULL) + { + /* FIXME can this happen? */ + if (priv->resume_dialog != NULL) + { + gtk_widget_hide (priv->resume_dialog); + gtk_widget_destroy (priv->resume_dialog); + } + + ephy_session_queue_command (session, + EPHY_SESSION_CMD_MAYBE_OPEN_WINDOW, + NULL, NULL, user_time, FALSE); + + return; + } + + if (priv->resume_dialog) + { + gtk_window_present_with_time (GTK_WINDOW (priv->resume_dialog), + user_time); + + return; + } + + /* Ref the shell while we show the dialogue. The unref + * happens in the weak ref notification when the dialogue + * is destroyed. + */ + g_object_ref (ephy_shell_get_default ()); + + dialog = gtk_message_dialog_new + (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + _("Recover previous browser windows and tabs?")); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + _("Epiphany appears to have exited unexpectedly the last time " + "it was run. You can recover the opened windows and tabs.")); + + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Don't Recover"), GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (GTK_DIALOG (dialog), + _("_Recover"), GTK_RESPONSE_ACCEPT); + + gtk_window_set_title (GTK_WINDOW (dialog), _("Crash Recovery")); + gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + + g_signal_connect (dialog, "response", + G_CALLBACK (resume_dialog_response_cb), session); + g_object_weak_ref (G_OBJECT (dialog), + (GWeakNotify) resume_dialog_weak_ref_cb, + session); + + /* FIXME ? */ + gtk_window_set_auto_startup_notification (FALSE); + + priv->resume_dialog = dialog; + + gtk_window_present_with_time (GTK_WINDOW (dialog), user_time); +} + +static void +session_command_open_bookmarks_editor (EphySession *session, + guint32 user_time) +{ + GtkWidget *editor; + + editor = ephy_shell_get_bookmarks_editor (ephy_shell_get_default ()); + + gtk_window_present_with_time (GTK_WINDOW (editor), user_time); +} + +static void +session_command_open_uris (EphySession *session, + char **uris, + const char *options, + guint32 user_time) +{ + EphyShell *shell; + EphyWindow *window; + EphyTab *tab; + EphyNewTabFlags flags = 0; + guint i; + + shell = ephy_shell_get_default (); + + g_object_ref (shell); + + window = ephy_session_get_active_window (session); + + if (options != NULL && strstr (options, "new-window") != NULL) + { + window = NULL; + flags |= EPHY_NEW_TAB_IN_NEW_WINDOW; + } + else if (options != NULL && strstr (options, "new-tab") != NULL) + { + flags |= EPHY_NEW_TAB_IN_EXISTING_WINDOW | + EPHY_NEW_TAB_JUMP; + } + + for (i = 0; uris[i] != NULL; ++i) + { + const char *url = uris[i]; + EphyNewTabFlags page_flags; + + if (url[0] == '\0') + { + page_flags = EPHY_NEW_TAB_HOME_PAGE; + } + else + { + page_flags = EPHY_NEW_TAB_OPEN_PAGE; + } + + tab = ephy_shell_new_tab_full (shell, window, + NULL /* parent tab */, + url, + flags | page_flags, + EPHY_EMBED_CHROME_ALL, + FALSE /* is popup? */, + user_time); + + window = EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tab))); + } + + g_object_unref (shell); +} + +static gboolean +session_command_dispatch (EphySession *session) +{ + EphySessionPrivate *priv = session->priv; + SessionCommand *cmd; + gboolean run_again = TRUE; + + cmd = g_queue_pop_head (priv->queue); + g_assert (cmd != NULL); + + LOG ("dispatching queue cmd:%d", cmd->command); + + switch (cmd->command) + { + case EPHY_SESSION_CMD_RESUME_SESSION: + session_command_autoresume (session, cmd->user_time); + break; + case EPHY_SESSION_CMD_LOAD_SESSION: + ephy_session_load (session, cmd->arg, cmd->user_time); + break; + case EPHY_SESSION_CMD_OPEN_BOOKMARKS_EDITOR: + session_command_open_bookmarks_editor (session, cmd->user_time); + break; + case EPHY_SESSION_CMD_OPEN_URIS: + session_command_open_uris (session, cmd->args, cmd->arg, cmd->user_time); + break; + case EPHY_SESSION_CMD_MAYBE_OPEN_WINDOW: + /* FIXME: maybe just check for normal windows? */ + if (priv->windows == NULL && + priv->tool_windows == NULL) + { + ephy_shell_new_tab_full (ephy_shell_get_default (), + NULL /* window */, NULL /* tab */, + NULL /* URL */, + EPHY_NEW_TAB_IN_NEW_WINDOW | + EPHY_NEW_TAB_HOME_PAGE, + EPHY_EMBED_CHROME_ALL, + FALSE /* is popup? */, + cmd->user_time); + } + break; + default: + g_assert_not_reached (); + break; + } + + /* Look if there's anything else to dispatch */ + if (g_queue_is_empty (priv->queue) || + priv->resume_dialog != NULL) + { + priv->queue_idle_id = 0; + run_again = FALSE; + } + + /* This unrefs the shell! */ + session_command_free (cmd); + + return run_again; +} + +static void +session_command_queue_next (EphySession *session) +{ + EphySessionPrivate *priv = session->priv; + + LOG ("queue_next"); + + if (!g_queue_is_empty (priv->queue) && + priv->resume_dialog == NULL && + priv->queue_idle_id == 0) + { + priv->queue_idle_id = + g_idle_add ((GSourceFunc) session_command_dispatch, + session); + } +} + +static void +session_command_queue_clear (EphySession *session) +{ + EphySessionPrivate *priv = session->priv; + + if (priv->resume_dialog != NULL) + { + gtk_widget_destroy (priv->resume_dialog); + /* destroying the resume dialogue will set this to NULL */ + g_assert (priv->resume_dialog == NULL); + } + + if (priv->queue_idle_id != 0) + { + g_source_remove (priv->queue_idle_id); + priv->queue_idle_id = 0; + } + + if (priv->queue != NULL) + { + g_queue_foreach (priv->queue, (GFunc) session_command_free, NULL); + g_queue_free (priv->queue); + priv->queue = NULL; + } +} + +/* EphyExtensionIface implementation */ + static void impl_attach_window (EphyExtension *extension, EphyWindow *window) @@ -263,19 +661,33 @@ impl_detach_window (EphyExtension *extension, */ } +/* Class implementation */ + static void ephy_session_init (EphySession *session) { - session->priv = EPHY_SESSION_GET_PRIVATE (session); + EphySessionPrivate *priv; + GnomeClient *client; LOG ("EphySession initialising"); + + priv = session->priv = EPHY_SESSION_GET_PRIVATE (session); + + priv->queue = g_queue_new (); + + client = gnome_master_client (); + g_signal_connect (client, "save-yourself", + G_CALLBACK (save_yourself_cb), session); + g_signal_connect (client, "die", + G_CALLBACK (die_cb), session); } static void ephy_session_dispose (GObject *object) { - EphySession *session = EPHY_SESSION(object); + EphySession *session = EPHY_SESSION (object); EphySessionPrivate *priv = session->priv; + GnomeClient *client; LOG ("EphySession disposing"); @@ -287,6 +699,14 @@ ephy_session_dispose (GObject *object) session_delete (session, SESSION_CRASHED); } + session_command_queue_clear (session); + + client = gnome_master_client (); + g_signal_handlers_disconnect_by_func + (client, G_CALLBACK (save_yourself_cb), session); + g_signal_handlers_disconnect_by_func + (client, G_CALLBACK (die_cb), session); + parent_class->dispose (object); } @@ -301,7 +721,7 @@ ephy_session_finalize (GObject *object) g_list_free (session->priv->windows); g_list_free (session->priv->tool_windows); - G_OBJECT_CLASS (parent_class)->finalize (object); + parent_class->finalize (object); } static void @@ -363,100 +783,7 @@ ephy_session_class_init (EphySessionClass *class) g_type_class_add_private (object_class, sizeof (EphySessionPrivate)); } -static gboolean -offer_to_resume (EphySession *session, - guint32 user_time) -{ - GtkWidget *dialog; - int response; - - dialog = gtk_message_dialog_new - (NULL, - GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - _("Recover previous browser windows and tabs?")); - - gtk_message_dialog_format_secondary_text - (GTK_MESSAGE_DIALOG (dialog), - _("Epiphany appears to have exited unexpectedly the last time " - "it was run. You can recover the opened windows and tabs.")); - - gtk_dialog_add_button (GTK_DIALOG (dialog), - _("_Don't Recover"), GTK_RESPONSE_CANCEL); - gtk_dialog_add_button (GTK_DIALOG (dialog), - _("_Recover"), GTK_RESPONSE_ACCEPT); - - gtk_window_set_title (GTK_WINDOW (dialog), _("Crash Recovery")); - gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); - gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - - session->priv->resume_dialog = dialog; - - ephy_gui_window_update_user_time (session->priv->resume_dialog, - user_time); - - gtk_window_set_auto_startup_notification (FALSE); - response = gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_window_set_auto_startup_notification (TRUE); - - gtk_widget_destroy (dialog); - - session->priv->resume_dialog = NULL; - - return (response == GTK_RESPONSE_ACCEPT); -} - -/** - * ephy_session_autoresume: - * @session: a #EphySession - * @user_time: a timestamp, or 0 - * - * Resume a crashed session when necessary (interactive) - * - * Return value: TRUE if handled; windows have actually - * been opened or the dialog from a previous instance - * has been re-presented to the user. - **/ -gboolean -ephy_session_autoresume (EphySession *session, - guint32 user_time) -{ - EphySessionPrivate *priv = session->priv; - char *saved_session; - gboolean retval = FALSE; - - LOG ("ephy_session_autoresume"); - - if (priv->windows != NULL || priv->tool_windows != NULL) return FALSE; - - if (priv->resume_dialog) - { - ephy_gui_window_update_user_time (priv->resume_dialog, - user_time); - ephy_gui_window_present (GTK_WINDOW (priv->resume_dialog), - user_time); - return TRUE; - } - - saved_session = get_session_filename (SESSION_CRASHED); - - if (g_file_test (saved_session, G_FILE_TEST_EXISTS) - && offer_to_resume (session, user_time)) - { - priv->dont_save = TRUE; - retval = ephy_session_load (session, saved_session, - 0 /* since we've shown the dialogue */); - priv->dont_save = FALSE; - ephy_session_save (session, SESSION_CRASHED); - } - - g_free (saved_session); - - /* ensure we don't open a blank window when quitting while resuming */ - return retval || priv->quit_while_resuming; -} +/* Implementation */ static void close_dialog (GtkWidget *widget) @@ -480,12 +807,15 @@ ephy_session_close (EphySession *session) /* we have to ref the shell or else we may get finalised between * destroying the windows and destroying the tool windows */ - g_object_ref (ephy_shell); + g_object_ref (ephy_shell_get_default ()); priv->dont_save = TRUE; /* need to set this up here while the dialogue hasn't been killed yet */ priv->quit_while_resuming = priv->resume_dialog != NULL; + /* Clear command queue */ + session_command_queue_clear (session); + ephy_embed_shell_prepare_close (embed_shell); /* there may still be windows open, like dialogues posed from @@ -513,7 +843,11 @@ ephy_session_close (EphySession *session) g_list_free (windows); session->priv->dont_save = FALSE; - g_object_unref (ephy_shell); + + /* Clear command queue */ + session_command_queue_clear (session); + + g_object_unref (ephy_shell_get_default ()); } static int @@ -861,7 +1195,7 @@ restore_geometry (GtkWindow *window, * ephy_session_load: * @session: a #EphySession * @filename: the path of the source file - * @user_time: a timestamp, or 0 + * @user_time: a user_time, or 0 * * Load a session from disk, restoring the windows and their state * @@ -872,6 +1206,7 @@ ephy_session_load (EphySession *session, const char *filename, guint32 user_time) { + EphySessionPrivate *priv = session->priv; xmlDocPtr doc; xmlNodePtr child; EphyWindow *window; @@ -890,6 +1225,10 @@ ephy_session_load (EphySession *session, return FALSE; } + g_object_ref (ephy_shell_get_default ()); + + priv->dont_save = TRUE; + child = xmlDocGetRootElement (doc); /* skip the session node */ @@ -946,7 +1285,13 @@ ephy_session_load (EphySession *session, xmlFreeDoc (doc); - return (session->priv->windows != NULL || session->priv->tool_windows != NULL); + priv->dont_save = FALSE; + + ephy_session_save (session, SESSION_CRASHED); + + g_object_unref (ephy_shell_get_default ()); + + return (priv->windows != NULL || priv->tool_windows != NULL); } /** @@ -1034,3 +1379,72 @@ ephy_session_get_active_window (EphySession *session) return window; } + +/** + * ephy_session_queue_command: + * @session: a #EphySession + **/ +void +ephy_session_queue_command (EphySession *session, + EphySessionCommand command, + const char *arg, + char **args, + guint32 user_time, + gboolean priority) +{ + EphySessionPrivate *priv; + GList *element; + SessionCommand *cmd; + + LOG ("queue_command command:%d", command); + + g_return_if_fail (EPHY_IS_SESSION (session)); + g_return_if_fail (command != EPHY_SESSION_CMD_OPEN_URIS || args != NULL); + + priv = session->priv; + + /* First look if the same command is already queued */ + if (command > EPHY_SESSION_CMD_RESUME_SESSION && + command < EPHY_SESSION_CMD_OPEN_URIS) + { + element = g_queue_find_custom (priv->queue, + GINT_TO_POINTER (command), + (GCompareFunc) session_command_find); + if (element != NULL) + { + cmd = (SessionCommand *) element->data; + + if ((command == EPHY_SESSION_CMD_LOAD_SESSION && + strcmp (cmd->arg, arg) == 0) || + command == EPHY_SESSION_CMD_OPEN_BOOKMARKS_EDITOR || + command == EPHY_SESSION_CMD_RESUME_SESSION) + { + cmd->user_time = user_time; + g_queue_remove (priv->queue, cmd); + g_queue_push_tail (priv->queue, cmd); + + return; + } + } + } + + /* FIXME: use g_slice_new */ + cmd = g_new0 (SessionCommand, 1); + cmd->command = command; + cmd->arg = arg ? g_strdup (arg) : NULL; + cmd->args = args ? g_strdupv (args) : NULL; + cmd->user_time = user_time; + /* This ref is released in session_command_free */ + g_object_ref (ephy_shell_get_default ()); + + if (priority) + { + g_queue_push_head (priv->queue, cmd); + } + else + { + g_queue_push_tail (priv->queue, cmd); + } + + session_command_queue_next (session); +} |