Index: gedit-session.c =================================================================== RCS file: /cvs/gnome/gedit/gedit/gedit-session.c,v retrieving revision 1.9.8.10 diff -u -p -r1.9.8.10 gedit-session.c --- gedit-session.c 4 Dec 2005 14:20:33 -0000 1.9.8.10 +++ gedit-session.c 4 Dec 2005 15:14:29 -0000 @@ -3,7 +3,7 @@ * This file is part of gedit * * Copyright (C) 2002 Ximian, Inc. - * Copyright (C) 2005 Paolo Maggi + * Copyright (C) 2005 - Paolo Maggi * * Author: Federico Mena-Quintero * @@ -28,9 +28,10 @@ * list of people on the gedit Team. * See the ChangeLog files for a list of changes. * - * $Id: gedit-session.c,v 1.9.8.10 2005/12/04 14:20:33 paolo Exp $ + * $Id: gedit-session.c,v 1.9.8.8 2005/11/27 09:11:21 paolo Exp $ */ + #ifdef HAVE_CONFIG_H #include #endif @@ -51,6 +52,8 @@ #include "gedit-metadata-manager.h" #include "gedit-window.h" #include "gedit-app.h" +#include "gedit-commands.h" +#include "dialogs/gedit-close-confirmation-dialog.h" /* The master client we use for SM */ static GnomeClient *master_client = NULL; @@ -58,6 +61,12 @@ static GnomeClient *master_client = NULL /* argv[0] from main(); used as the command to restart the program */ static const char *program_argv0 = NULL; +/* FIXME: get rid of these two globals... + * Can there be more than an interaction request at once? + */ +static gint interaction_key; +static GSList *window_dirty_list; + static gchar * get_session_dir () { @@ -77,7 +86,7 @@ get_session_file_path (GnomeClient *clie const gchar *prefix; gchar *session_dir; gchar *session_file; - gchar *session_path; + gchar *session_path; prefix = gnome_client_get_config_prefix (client); gedit_debug_message (DEBUG_SESSION, "Prefix: %s", prefix); @@ -218,12 +227,17 @@ save_window_session (xmlTextWriterPtr w } static void -save_session (const gchar *fname) +save_session () { int ret; + gchar *fname; xmlTextWriterPtr writer; const GList *windows; + /* nitpick: we are using the master client instead of the one + * passed to the interaction_func... we have just a client anyway */ + fname = get_session_file_path (master_client); + gedit_debug_message (DEBUG_SESSION, "Session file: %s", fname); if (!ensure_session_dir ()) @@ -274,33 +288,263 @@ out: if (ret < 0) unlink (fname); + + g_free (fname); } -static void -interaction_function (GnomeClient *client, - gint key, - GnomeDialogType dialog_type, - gpointer shutdown) +static void +finish_interaction (gboolean cancel_shutdown) { - gchar *fname; + /* save session file even if shutdown was cancelled */ + save_session (); + + gnome_interaction_key_return (interaction_key, + cancel_shutdown); + + interaction_key = 0; +} + +/* move to gedit-window.c ? We would use it also in commands-file.c... + * we also call this multiple time per window, so we may want to either + * cache the result or keep it always uptodate... list is short though, + * so it's not a real performance problem. + */ +static GList * +window_get_unsaved_documents (GeditWindow *window) +{ + GList *unsaved_docs = NULL; + GList *docs; + GList *l; + + docs = gedit_window_get_documents (window); + + for (l = docs; l != NULL; l = l->next) + { + GeditTab *tab; + GeditDocument *doc; + + doc = GEDIT_DOCUMENT (l->data); + tab = gedit_tab_get_from_document (doc); + + if (!_gedit_tab_can_close (tab)) + unsaved_docs = g_list_prepend (unsaved_docs, doc); + } + + g_list_free (docs); + + return g_list_reverse (unsaved_docs); +} + +static void +window_handled (GeditWindow *window) +{ + window_dirty_list = g_slist_remove (window_dirty_list, window); + + /* whee... we made it! */ + if (window_dirty_list == NULL) + finish_interaction (FALSE); +} + +static void +window_state_change (GeditWindow *window, + GParamSpec *pspec, + gpointer data) +{ + /* FIXME: should we also check the window state? */ + + /* FIXME: we may still have unsaved docs if we unselected + * them in the confirmation dialog */ + if (window_get_unsaved_documents (window) == NULL) + { + g_signal_handlers_disconnect_by_func (window, window_state_change, data); + window_handled (window); + } +} + +static void +close_discarded_and_save_the_rest (const GList *docs_to_save, + GeditWindow *window) +{ + GList *tabs; + GList *l; + GList *tabs_to_close = NULL; + + tabs = gtk_container_get_children ( + GTK_CONTAINER (_gedit_window_get_notebook (window))); + + for (l = tabs; l != NULL; l = l->next) + { + GeditTab *t; + GeditDocument *doc; + + t = GEDIT_TAB (l->data); + + doc = gedit_tab_get_document (t); + + if (!g_list_find (docs_to_save, doc)) + g_list_prepend (tabs_to_close, t); + } + + gedit_window_close_tabs (window, tabs_to_close); + g_list_free (tabs_to_close); + + _gedit_cmd_file_save_documents_list (window, docs_to_save); +} + +static void +close_confirmation_dialog_response_handler (GeditCloseConfirmationDialog *dlg, + gint response_id, + GeditWindow *window) +{ + const GList *unsaved_documents; + const GList *selected_documents; + GSList *l; + + gedit_debug (DEBUG_COMMANDS); + + unsaved_documents = gedit_close_confirmation_dialog_get_unsaved_documents (dlg); + + switch (response_id) + { + case GTK_RESPONSE_YES: + /* save selected docs */ + + g_signal_connect (window, + "notify::state", + G_CALLBACK (window_state_change), + NULL); + + selected_documents = gedit_close_confirmation_dialog_get_selected_documents (dlg); + + close_discarded_and_save_the_rest (selected_documents, window); + + // FIXME: also need to lock the window to prevent further changes.. + + break; + + case GTK_RESPONSE_NO: + /* dont save */ + window_handled (window); + break; + + default: + /* disconnect window_state_changed where needed */ + for (l = window_dirty_list; l != NULL; l = l->next) + g_signal_handlers_disconnect_by_func (window, + window_state_change, NULL); + g_slist_free (window_dirty_list); + window_dirty_list = NULL; + + /* cancel shutdown */ + finish_interaction (TRUE); + + break; + } + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +static void +session_close_all (GeditWindow *window) +{ + GSList *unsaved_docs; + GtkWidget *dlg; gedit_debug (DEBUG_SESSION); -#if 0 - /* Save all unsaved files */ - if (GPOINTER_TO_INT (shutdown)) - gedit_file_save_all (); -#endif - /* Save session data */ - fname = get_session_file_path (client); + unsaved_docs = window_get_unsaved_documents (window); - save_session (fname); + g_return_if_fail (unsaved_docs != NULL); - g_free (fname); + if (unsaved_docs->next == NULL) + { + /* There is only one unsaved document */ + GeditTab *tab; + GeditDocument *doc; - gnome_interaction_key_return (key, FALSE); + doc = GEDIT_DOCUMENT (unsaved_docs->data); - gedit_debug_message (DEBUG_SESSION, "END"); + tab = gedit_tab_get_from_document (doc); + g_return_if_fail (tab != NULL); + + gedit_window_set_active_tab (window, tab); + + dlg = gedit_close_confirmation_dialog_new_single ( + GTK_WINDOW (window), + doc); + } + else + { + dlg = gedit_close_confirmation_dialog_new (GTK_WINDOW (window), + unsaved_docs); + } + + g_slist_free (unsaved_docs); + + g_signal_connect (dlg, + "response", + G_CALLBACK (close_confirmation_dialog_response_handler), + window); + + gtk_widget_show (dlg); +} + +static void +save_all_docs_and_save_session () +{ + GeditApp *app; + const GList *l; + + app = gedit_app_get_default (); + + g_assert (window_dirty_list == NULL); + + for (l = gedit_app_get_windows (app); l != NULL; l = l->next) + { + if (window_get_unsaved_documents (GEDIT_WINDOW (l->data)) != NULL) + { + window_dirty_list = g_slist_prepend (window_dirty_list, l->data); + } + } + + /* no modified docs, go on and save session */ + if (window_dirty_list == NULL) + { + finish_interaction (FALSE); + + return; + } + + for (l = window_dirty_list; l != NULL; l = l->next) + { + // maybe run the dialog in sequence when one is closed instead? + + session_close_all (GEDIT_WINDOW (l->data)); + } +} + +static void +interaction_function (GnomeClient *client, + gint key, + GnomeDialogType dialog_type, + gpointer shutdown) +{ + gedit_debug (DEBUG_SESSION); + + g_assert (interaction_key == 0); + interaction_key = key; + + /* If we are shutting down, give the user the chance to save + * first, otherwise just ignore untitled documents documents. + */ + if (GPOINTER_TO_INT (shutdown)) + { + save_all_docs_and_save_session (); + } + else + { + finish_interaction (FALSE); + } } /* save_yourself handler for the master client */ @@ -321,20 +565,20 @@ client_save_yourself_cb (GnomeClient GNOME_DIALOG_NORMAL, interaction_function, GINT_TO_POINTER (shutdown)); - + /* Tell the session manager how to discard this save */ argv[2] = get_session_file_path (client); gnome_client_set_discard_command (client, 3, argv); g_free (argv[2]); - + /* Tell the session manager how to clone or restart this instance */ argv[0] = (char *) program_argv0; - argv[1] = NULL; /* "--debug-session"; */ + argv[1] = NULL; - gnome_client_set_clone_command (client, 1 /*2*/, argv); - gnome_client_set_restart_command (client, 1 /*2*/, argv); + gnome_client_set_clone_command (client, 1, argv); + gnome_client_set_restart_command (client, 1, argv); gedit_debug_message (DEBUG_SESSION, "END");