changeset 19748:21015ca26566

Restructure shutdown flow and behavior for improved robustness * file-editor-interface.h (file_editor_interface::check_closing): Remove closing_state argument from input. * file-editor-tab.cc (file_editor_tab::_cancelled): New static variable for managing chain of file closes. (file_editor_tab::file_editor_tab): Discard _app_closing and _modal_dialog initializations. (file_editor_tab::closeEvent): Upon accepting the close event, als request tab removal. (file_editor_tab::check_modified_file): New simple routine checking for modified file if there hasn't been cancellation yet. (file_editor_tab::run_file): Remove use of _modal_dialog. (file_editor_tab::show_dialog): Add modal input setting. Remove use of _app_closing and _modal_dialog. (file_editor_tab::check_file_modified): Remove situational message for just one. If modified, call show_dialog with modal true, return QMessageBox::Cancel if anything cancelled, otherwise the user decision. (file_editor_tab::handle_file_modified_answer): Do not remove file editor tab in any case. If user cancelled, set _cancelled true. (file_editor_tab::save_file): Add "false" (non-modal) to show_dialog() call. (file_editor_tab::save_file_as): Add "false" (non-modal) to show_dialog() call. (file_editor_tab::conditional_close): Remove input argument and use of variable _app_closing. * file-editor-tab.h (file_editor_tab::conditional_close): Remove input argument. (file_editor_tab::reset_cancel): New member function declaration for managing cancellation of tab chain saves. (file_editor_tab::was_cancel): New member function for indicating any cancellation when saving modified files. (file_editor_tab::check_modified_file): New slot declaration for checking and saving file modifications. (file_editor_tab::show_dialog): Add modal option input argument. (file_editor_tab::_app_closing, file_editor_tab::_modal_dialog): Remove. (file_editor_tab::_cancelled): Add. * file-editor.cc (file_editor::file_editor): Remove _check_closing_done initialization. (file_editor::~file_editor): Remove use of _check_closing_done and check_closing(). (file_editor::check_closing): Clear cancellation history and check all files for modifications, without closing. Close all tabs and delete associated widgets if no cancellation. Remove use of _check_closing_done. (file_editor::request_close_file): Remove argument from conditional_close() function call. (file_editor::request_close_all_files): Ditto. (file_editor::request_close_other_files): Ditto. (file_editor::handle_tab_close_request): Ditto. (file_editor::handle_tab_remove_request): Add comment about deleting sender. (file_editor::add_file_editor_tab): Connect fetab_check_modified_file signal to check_modified_file slot. * file-editor.h (file_editor::fetab_check_modified_file): New signal. (file_editor::check_closing): Remove input argument. (file_editor::_check_closing_done): Remove. * main-window.cc (main_window::confirm_shutdown_octave): Rename of member function main_window::confirm_exit_octave(). Change return type to void. Set octave/qt link confirmation result then awake worker process. (main_window::exit_app): Rename of member function main_window::exit(). (main_window::closeEvent): Rather than post callback event, queue "exit" in the command buffer. (main_window::construct_octave_qt_link): Connect confirm_shutdown_signal to confirm_shutdown_octave slot. Connect exit_app_signal to exit_app slot. (main_window::exit_callback): Remove. (main_window::confirm_exit_octave): Renamed as confirm_shutdown_octave(). * main-window.h (main_window::confirm_shutdown_octave): Rename of slot confirm_exit_octave(). (main_window::exit): Renamed exit_app(). (main_window::exit_callback): Removed declaration. (main_window::confirm_exit_octave): Renamed confirm_shutdown_octave(). * octave-qt-link.cc (octave_qt_link::do_confirm_shutdown): New virtual function definition for initiating GUI shutdown and confirm exit. Worker process goes into sleep mode after issuing cross-thread signal. Return confirmation result. (octave_qt_link::do_exit): Change exit_signal to exit_app_signal. octave-qt-link.h (octave_qt_link::do_confirm_shutdown): New virtual function declaration for qt GUI. (octave_qt_link::mutex): Added. A QMutex for communicating with Qt GUI. (octave_qt_link::waitcondition): Added. For process wait. (octave_qt_link::shutdown_confirmation): Added. Store confirmation result. (octave_qt_link::_shutdown_confirm_result): Added. Confirmation result. (octave_qt_link::exit_signal): Signal renamed exit_app_signal. (octave_qt_link::confirm_shutdown_signal): Added. (octave_qt_link::exit_app_signal): Renamed of exit_signal. octave-link.h (octave_link::confirm_shutdown): Added. Access virtual function do_confirm_shutdown. (octave_link::do_confirm_shutdown): Added. Virtual function for GUI link. toplev.cc (clean_up_and_exit): Change 'retval' to 'status', as header file uses argument name 'status'. (quit): First initiate GUI shutdown via octave_link::confirm_shutdown() and if not confirmed, immediately return thereby avoiding exit sequence.
author Daniel J Sebald <daniel.sebald@ieee.org>
date Sat, 14 Feb 2015 11:27:10 -0600
parents 1a6fa5a523e4
children 788d1b951eb3
files libgui/src/m-editor/file-editor-interface.h libgui/src/m-editor/file-editor-tab.cc libgui/src/m-editor/file-editor-tab.h libgui/src/m-editor/file-editor.cc libgui/src/m-editor/file-editor.h libgui/src/main-window.cc libgui/src/main-window.h libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libinterp/corefcn/octave-link.h libinterp/corefcn/toplev.cc
diffstat 11 files changed, 160 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/m-editor/file-editor-interface.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/m-editor/file-editor-interface.h	Sat Feb 14 11:27:10 2015 -0600
@@ -60,7 +60,7 @@
 
   virtual void handle_edit_file_request (const QString& file) = 0;
 
-  virtual bool check_closing (int closing_state) = 0;
+  virtual bool check_closing (void) = 0;
 
   virtual void empty_script (bool, bool) = 0;
 
--- a/libgui/src/m-editor/file-editor-tab.cc	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/m-editor/file-editor-tab.cc	Sat Feb 14 11:27:10 2015 -0600
@@ -63,15 +63,15 @@
 #include "defaults.h"
 #include <oct-map.h>
 
+bool file_editor_tab::_cancelled = false;
+
 // Make parent null for the file editor tab so that warning
 // WindowModal messages don't affect grandparents.
 file_editor_tab::file_editor_tab (const QString& directory_arg)
 {
   QString directory = directory_arg;
   _lexer_apis = 0;
-  _app_closing = 0;   // app is not closing
   _is_octave_file = true;
-  _modal_dialog = false;
 
   // Make sure there is a slash at the end of the directory name
   // for identification when saved later.
@@ -193,7 +193,10 @@
   if (check_file_modified () == QMessageBox::Cancel)
     e->ignore ();
   else
-    e->accept ();
+    {
+      e->accept ();
+      emit tab_remove_request ();
+    }
 }
 
 void
@@ -628,6 +631,16 @@
 }
 
 void
+file_editor_tab::check_modified_file (void)
+{
+  if (_cancelled)
+    return;
+
+  if (check_file_modified () == QMessageBox::Cancel)
+    _cancelled = true;
+}
+
+void
 file_editor_tab::save_file (const QWidget *ID)
 {
   if (ID != this)
@@ -635,8 +648,8 @@
 
   save_file (_file_name);
 }
+
 void
-
 file_editor_tab::save_file (const QWidget *ID, const QString& fileName,
                             bool remove_on_success)
 {
@@ -678,11 +691,7 @@
     return;
 
   if (_edit_area->isModified () | ! valid_file_name ())
-    {
-      _modal_dialog = true;    // force modal dialog if the file is a new one
-      save_file (_file_name);  // save file dialog
-      _modal_dialog = false;   // back to non-modal dialogs
-    }
+    save_file (_file_name);  // save file dialog
 
   QFileInfo info (_file_name);
   emit run_file_signal (info);
@@ -1208,13 +1217,12 @@
                              _is_octave_file);
 }
 
-// show_dialog: shows a modal or non modal dialog depeding on the closing
-//              of the app and the flag _modal_dialog
+// show_dialog: shows a modal or non modal dialog depending on input arg
 void
-file_editor_tab::show_dialog (QDialog *dlg)
+file_editor_tab::show_dialog (QDialog *dlg, bool modal)
 {
   dlg->setAttribute (Qt::WA_DeleteOnClose);
-  if (_app_closing | _modal_dialog)
+  if (modal)
     dlg->exec ();
   else
     {
@@ -1231,32 +1239,19 @@
     {
       activateWindow ();
       raise ();
+      setFocus ();
       // File is modified but not saved, ask user what to do.  The file
       // editor tab can't be made parent because it may be deleted depending
       // upon the response.  Instead, change the _edit_area to read only.
       QMessageBox::StandardButtons buttons = QMessageBox::Save |
-                                             QMessageBox::Discard;
-      QString available_actions;
-
-      switch (_app_closing)
-        {
-          case -1:  // octave is exiting and so does the gui
-            available_actions =
-              tr ("Do you want to save or discard the changes?");
-            break;
+                                             QMessageBox::Discard |
+                                             QMessageBox::Cancel;
 
-          case 1:   // gui is exiting
-            available_actions =
-              tr ("Do you want to cancel exiting octave, save or discard the changes?");
-            buttons = buttons | QMessageBox::Cancel;
-            break;
-
-          case 0:   // tab is closing
-            available_actions =
-              tr ("Do you want to cancel closing, save or discard the changes?");
-            buttons = buttons | QMessageBox::Cancel;
-            break;
-        }
+      // For now, just a warning message about closing a tab that has been
+      // modified seems sufficient.  Exit-condition-specific messages could
+      // be achieved by making 'available_actions' a function input string.
+      QString available_actions =
+          tr ("Do you want to cancel closing, save or discard the changes?");
 
       QString file;
       if (valid_file_name ())
@@ -1266,9 +1261,9 @@
 
       QMessageBox* msgBox
         = new QMessageBox (QMessageBox::Warning, tr ("Octave Editor"),
-                           tr ("The file\n"
-                               "%1\n"
-                               "is about to be closed but has been modified.\n"
+                           tr ("The file\n\n"
+                               "  %1\n\n"
+                               "is about to be closed but has been modified.  "
                                "%2").
                            arg (file). arg (available_actions),
                            buttons, qobject_cast<QWidget *> (parent ()));
@@ -1278,14 +1273,17 @@
       connect (msgBox, SIGNAL (finished (int)),
                this, SLOT (handle_file_modified_answer (int)));
 
-      show_dialog (msgBox);
+      show_dialog (msgBox, true);
 
-      return QMessageBox::Cancel;
+      if (_cancelled)
+        return QMessageBox::Cancel;
+      else
+        return decision;
     }
   else
     {
-      // Nothing was modified, just remove from editor.
-      emit tab_remove_request ();
+      // Nothing was modified.  Leave tab present in case user
+      // decides to cancel some point further along.
     }
 
   return decision;
@@ -1296,18 +1294,18 @@
 {
   if (decision == QMessageBox::Save)
     {
-      // Save file, then remove from editor.
-      save_file (_file_name, true);
+      // Save file, but do not remove from editor.
+      save_file (_file_name, false);
     }
   else if (decision == QMessageBox::Discard)
     {
-      // User doesn't want to save, just remove from editor.
-      emit tab_remove_request ();
+      // User doesn't want to save, leave tab and remove subsequently.
     }
   else
     {
       // User canceled, allow editing again.
       _edit_area->setReadOnly (false);
+      _cancelled = true;
     }
 }
 
@@ -1497,7 +1495,7 @@
                            tr ("Could not open file %1 for write:\n%2.").
                            arg (file_to_save).arg (file.errorString ()),
                            QMessageBox::Ok, 0);
-      show_dialog (msgBox);
+      show_dialog (msgBox, false);
 
       return;
     }
@@ -1646,7 +1644,7 @@
                this, SLOT (handle_save_file_as_answer (const QString&)));
     }
 
-  show_dialog (fileDialog);
+  show_dialog (fileDialog, false);
 }
 
 void
@@ -1934,9 +1932,8 @@
 // When emitting a signal, only the return value from the last slot
 // goes back to the sender
 bool
-file_editor_tab::conditional_close (int app_closing)
+file_editor_tab::conditional_close (void)
 {
-  _app_closing = app_closing;
   return close ();
 }
 
--- a/libgui/src/m-editor/file-editor-tab.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/m-editor/file-editor-tab.h	Sat Feb 14 11:27:10 2015 -0600
@@ -52,8 +52,10 @@
   octave_qscintilla *qsci_edit_area () { return _edit_area; }
 
   // Will initiate close if associated with the identifier tag.
-  bool conditional_close (int app_closing = 0);  // default 0: close tab only
+  bool conditional_close (void);
 
+  static void reset_cancel (void) {_cancelled = false;}
+  static bool was_cancelled (void) {return _cancelled;}
 
 public slots:
 
@@ -74,6 +76,7 @@
   void set_focus (const QWidget *ID);
   void context_help (const QWidget *ID, bool);
   void context_edit (const QWidget *ID);
+  void check_modified_file (void);
   void save_file (const QWidget *ID);
   void save_file (const QWidget *ID, const QString& fileName,
                   bool remove_on_success);
@@ -199,7 +202,7 @@
   void request_add_breakpoint (int line);
   void request_remove_breakpoint (int line);
 
-  void show_dialog (QDialog *dlg);
+  void show_dialog (QDialog *dlg, bool modal);
   int check_file_modified ();
   void do_comment_selected_text (bool comment);
   QString comment_string (const QString&);
@@ -230,9 +233,7 @@
 
   bool _long_title;
   bool _copy_available;
-  int _app_closing;     // -1: octave exits, 1: exit request in gui, 0: no exit
   bool _is_octave_file;
-  bool _modal_dialog;
   bool _always_reload_changed_files;
 
   QFileSystemWatcher _file_system_watcher;
@@ -243,6 +244,8 @@
 
   QsciAPIs *_lexer_apis;
   QString _prep_apis_file;
+
+  static bool _cancelled;
 };
 
 #endif
--- a/libgui/src/m-editor/file-editor.cc	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/m-editor/file-editor.cc	Sat Feb 14 11:27:10 2015 -0600
@@ -54,8 +54,6 @@
   // files will change ced accordingly.
   ced = QDir::currentPath ();
 
-  _check_closing_done = false;  // init flag for closing process
-
   construct ();
 
   setVisible (false);
@@ -65,22 +63,12 @@
 
 file_editor::~file_editor (void)
 {
-  // Close open tabs, if existing. In this case app closing must be
-  // initiated by octave since check_closing was already done if the gui
-  // initiated the closing. All tabs will be definetly closed and the
-  // user can not cancel exiting (close state -1)
-  // We have to prevent that on case of gui-closing this check is done
-  // a second time resulting in an empty file list (tabs closed) for the
-  // the next start, that is what _check_closing_done is for
-  if (! _check_closing_done)
-    check_closing (-1);
-
   if (_mru_file_menu)
     delete _mru_file_menu;
 }
 
 bool
-file_editor::check_closing (int closing_state)
+file_editor::check_closing (void)
 {
   // Save open files for restoring in next session; this only is possible
   QSettings *settings = resource_manager::get_settings ();
@@ -102,31 +90,29 @@
   settings->setValue ("editor/savedSessionTabs", fetFileNames);
   settings->sync ();
 
-  // Close all tabs. If exit is requested by the gui (octave still running)
-  // check whether closing a tab is successful or whether user wnats to cancel
-  // exiting the program. Return false in the latter case.
-  file_editor_tab *editor_tab;
+  // Save all tabs with confirmation.
+  file_editor_tab::reset_cancel ();
+  emit fetab_check_modified_file ();
 
-  for (int index = _tab_widget->count ()-1; index >= 0; index--)
+  // Close all tabs if there was no cancellation.
+  if (file_editor_tab::was_cancelled ())
+    return false;
+
+  for (int i = 0; i < _tab_widget->count (); i++)
     {
-      editor_tab = static_cast <file_editor_tab *> (_tab_widget->widget (index));
-      if ((! editor_tab->conditional_close (closing_state)) && closing_state == 1)
-        return false;
+      delete _tab_widget->widget (i);
+      _tab_widget->removeTab (i);
     }
 
-  // Here, we really want to exit and all tabs are closed
-  _check_closing_done = true;  // check is already done, prevent a second check
-                               // which would store an empty file list
   return true;
 }
 
-
 void
 file_editor::focus (void)
 {
   octave_dock_widget::focus ();
 
-// set focus to current tab
+  // set focus to current tab
   QWidget *fileEditorTab = _tab_widget->currentWidget ();
   if (fileEditorTab)
     emit fetab_set_focus (fileEditorTab);
@@ -423,7 +409,7 @@
                     }
                   else
                     {
-                      // File does not exist, should it be crated?
+                      // File does not exist, should it be created?
                       bool create_file = true;
                       QMessageBox *msgBox;
                       QSettings *settings = resource_manager::get_settings ();
@@ -952,7 +938,7 @@
 {
   file_editor_tab *editor_tab =
       static_cast <file_editor_tab *> (_tab_widget->currentWidget ());
-  editor_tab->conditional_close (0);  // 0: app is not closing, only tab
+  editor_tab->conditional_close ();
 }
 
 void
@@ -964,7 +950,7 @@
   for (int index = _tab_widget->count ()-1; index >= 0; index--)
     {
       editor_tab = static_cast <file_editor_tab *> (_tab_widget->widget (index));
-      editor_tab->conditional_close (0);  // 0: app is not closing, only tab
+      editor_tab->conditional_close ();
     }
 }
 
@@ -981,7 +967,7 @@
         {
           editor_tab =
               static_cast <file_editor_tab *> (_tab_widget->widget (index));
-          editor_tab->conditional_close (0);  // 0: app is not closing, only tab
+          editor_tab->conditional_close ();
         }
     }
 }
@@ -992,7 +978,7 @@
 {
   file_editor_tab *editor_tab =
        static_cast <file_editor_tab *> (_tab_widget->widget (index));
-  editor_tab->conditional_close (0);  // 0: app is not closing, only tab
+  editor_tab->conditional_close ();
 }
 
 void
@@ -1006,6 +992,8 @@
           if (_tab_widget->widget (i) == fileEditorTab)
             {
               _tab_widget->removeTab (i);
+              // Deleting sender is dodgy, but works because the signal
+              // is the last item in the sender's routines.
               delete fileEditorTab;
               break;
             }
@@ -1664,6 +1652,9 @@
                                           bool)),
            f, SLOT (save_file (const QWidget*, const QString&, bool)));
 
+  connect (this, SIGNAL (fetab_check_modified_file (void)),
+           f, SLOT (check_modified_file (void)));
+
   // Signals from the file_editor trivial operations
   connect (this, SIGNAL (fetab_zoom_in (const QWidget*)),
            f, SLOT (zoom_in (const QWidget*)));
--- a/libgui/src/m-editor/file-editor.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/m-editor/file-editor.h	Sat Feb 14 11:27:10 2015 -0600
@@ -76,6 +76,7 @@
   // No fetab_new, functionality in editor
   void fetab_context_help (const QWidget* ID, bool);
   void fetab_context_edit (const QWidget* ID);
+  void fetab_check_modified_file (void);
   void fetab_save_file (const QWidget* ID);
   void fetab_save_file_as (const QWidget* ID);
   void fetab_print_file (const QWidget* ID);
@@ -117,7 +118,7 @@
 
   void focus (void);
   void enable_menu_shortcuts (bool);
-  bool check_closing (int closing_state);
+  bool check_closing (void);
 
   void request_new_file (const QString& commands);
   void request_new_script (const QString& commands);
@@ -351,8 +352,6 @@
   QMenu *_mru_file_menu;
   QAction *_mru_file_actions[MaxMRUFiles];
   QStringList _mru_files;
-
-  bool _check_closing_done;
 };
 
 #endif // FILEEDITORMDISUBWINDOW_H
--- a/libgui/src/main-window.cc	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/main-window.cc	Sat Feb 14 11:27:10 2015 -0600
@@ -777,6 +777,33 @@
   resource_manager::update_network_settings ();
 }
 
+void
+main_window::confirm_shutdown_octave (void)
+{
+  bool closenow = true;
+
+  QSettings *settings = resource_manager::get_settings ();
+
+  if (settings->value ("prompt_to_exit", false).toBool ())
+    {
+      int ans = QMessageBox::question (this, tr ("Octave"),
+         tr ("Are you sure you want to exit Octave?"),
+          QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
+
+      if (ans !=  QMessageBox::Ok)
+        closenow = false;
+    }
+
+#ifdef HAVE_QSCINTILLA
+  if (closenow)
+    closenow = editor_window->check_closing ();
+#endif
+
+  _octave_qt_link->shutdown_confirmation (closenow);
+
+  // Awake the worker thread so that it continues shutting down (or not).
+  _octave_qt_link->waitcondition.wakeAll ();
+}
 
 void
 main_window::prepare_to_exit (void)
@@ -785,7 +812,7 @@
 }
 
 void
-main_window::exit (int status)
+main_window::exit_app (int status)
 {
   qApp->exit (status);
 }
@@ -985,8 +1012,7 @@
 main_window::closeEvent (QCloseEvent *e)
 {
   e->ignore ();
-  if (confirm_exit_octave())
-    octave_link::post_event (this, &main_window::exit_callback);
+  queue_command ("exit");
 }
 
 void
@@ -1435,8 +1461,11 @@
 {
   _octave_qt_link = new octave_qt_link (this);
 
-  connect (_octave_qt_link, SIGNAL (exit_signal (int)),
-           this, SLOT (exit (int)));
+  connect (_octave_qt_link, SIGNAL (confirm_shutdown_signal ()),
+           this, SLOT (confirm_shutdown_octave ()));
+
+  connect (_octave_qt_link, SIGNAL (exit_app_signal (int)),
+           this, SLOT (exit_app (int)));
 
   connect (_octave_qt_link,
            SIGNAL (set_workspace_signal
@@ -2138,12 +2167,6 @@
 }
 
 void
-main_window::exit_callback (void)
-{
-  Fquit ();
-}
-
-void
 main_window::find_files (const QString &start_dir)
 {
 
@@ -2358,29 +2381,3 @@
   _clipboard->clear (QClipboard::Clipboard);
 }
 
-bool
-main_window::confirm_exit_octave ()
-{
-  bool closenow = true;
-
-  QSettings *settings = resource_manager::get_settings ();
-
-  if (settings->value ("prompt_to_exit", false).toBool ())
-    {
-      int ans = QMessageBox::question (this, tr ("Octave"),
-         tr ("Are you sure you want to exit Octave?"),
-          QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
-
-      if (ans !=  QMessageBox::Ok)
-        return false;
-
-    }
-
-#ifdef HAVE_QSCINTILLA
-  closenow = editor_window->check_closing (1);  // 1: exit request from gui
-#endif
-
-  return closenow;
-}
-
-
--- a/libgui/src/main-window.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/main-window.h	Sat Feb 14 11:27:10 2015 -0600
@@ -132,8 +132,9 @@
                                                          = QString ());
   void show_about_octave (void);
   void notice_settings (const QSettings *settings);
+  void confirm_shutdown_octave (void);
   void prepare_to_exit (void);
-  void exit (int status);
+  void exit_app (int status);
   void reset_windows (void);
 
   void change_directory (const QString& dir);
@@ -275,8 +276,6 @@
 
   void change_directory_callback (const std::string& directory);
 
-  void exit_callback (void);
-
   void queue_command (QString command);
 
   void queue_debug (QString command);
@@ -285,8 +284,6 @@
 
   void configure_shortcuts ();
 
-  bool confirm_exit_octave ();
-
   workspace_model *_workspace_model;
 
   QHash<QMenu*, QStringList> _hash_menu_text;
--- a/libgui/src/octave-qt-link.cc	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/octave-qt-link.cc	Sat Feb 14 11:27:10 2015 -0600
@@ -67,10 +67,24 @@
 }
 
 bool
+octave_qt_link::do_confirm_shutdown (void)
+{
+  emit confirm_shutdown_signal ();
+
+  // Wait while the GUI shuts down.
+  waitcondition.wait (&mutex);
+
+  // The GUI has sent a signal and the process has been awakened.
+  return _shutdown_confirm_result;
+}
+
+bool
 octave_qt_link::do_exit (int status)
 {
-  emit exit_signal (status);
+  emit exit_app_signal (status);
 
+  // Could wait for a while and then timeout, but for now just
+  // assume the GUI application exit will be without problems.
   return true;
 }
 
--- a/libgui/src/octave-qt-link.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libgui/src/octave-qt-link.h	Sat Feb 14 11:27:10 2015 -0600
@@ -32,6 +32,8 @@
 #include <QObject>
 #include <QString>
 #include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
 
 #include "octave-link.h"
 #include "octave-interpreter.h"
@@ -59,6 +61,7 @@
 
   void execute_interpreter (void);
 
+  bool do_confirm_shutdown (void);
   bool do_exit (int status);
 
   bool do_edit_file (const std::string& file);
@@ -130,9 +133,13 @@
 
   void do_show_doc (const std::string& file);
 
+  QMutex mutex;
+  QWaitCondition waitcondition;
+  void shutdown_confirmation (bool sd) {_shutdown_confirm_result = sd;}
+
 private:
 
-  // No copying!
+  bool _shutdown_confirm_result;
 
   octave_qt_link (const octave_qt_link&);
 
@@ -150,8 +157,6 @@
 
   void execute_interpreter_signal (void);
 
-  void exit_signal (int status);
-
   void edit_file_signal (const QString& file);
 
   void change_directory_signal (const QString& dir);
@@ -185,6 +190,9 @@
 
   void show_doc_signal (const QString &file);
 
+  void confirm_shutdown_signal (void);
+  void exit_app_signal (int status);
+
 public slots:
 
   void terminal_interrupt (void);
--- a/libinterp/corefcn/octave-link.h	Sat Feb 14 09:32:57 2015 -0800
+++ b/libinterp/corefcn/octave-link.h	Sat Feb 14 11:27:10 2015 -0600
@@ -79,6 +79,16 @@
       instance->do_discard_events ();
   }
 
+  static bool confirm_shutdown (void)
+  {
+    bool retval = true;
+
+    if (instance_ok ())
+      retval = instance->do_confirm_shutdown ();
+
+    return retval;
+  }
+
   static bool exit (int status)
   {
     bool retval = false;
@@ -380,6 +390,7 @@
   void do_entered_readline_hook (void) { }
   void do_finished_readline_hook (void) { }
 
+  virtual bool do_confirm_shutdown (void) = 0;
   virtual bool do_exit (int status) = 0;
 
   virtual bool do_edit_file (const std::string& file) = 0;
--- a/libinterp/corefcn/toplev.cc	Sat Feb 14 09:32:57 2015 -0800
+++ b/libinterp/corefcn/toplev.cc	Sat Feb 14 11:27:10 2015 -0600
@@ -757,11 +757,11 @@
 }
 
 void
-clean_up_and_exit (int retval, bool safe_to_return)
+clean_up_and_exit (int status, bool safe_to_return)
 {
   do_octave_atexit ();
 
-  if (octave_link::exit (retval))
+  if (octave_link::exit (status))
     {
       if (safe_to_return)
         return;
@@ -782,7 +782,7 @@
   else
     {
       if (octave_exit)
-        (*octave_exit) (retval);
+        (*octave_exit) (status);
     }
 }
 
@@ -806,6 +806,12 @@
 {
   octave_value_list retval;
 
+  // Confirm OK to shutdown.  Note: A dynamic function installation similar
+  // to overriding polymorphism for which the GUI can install its own "quit"
+  // yet call this base "quit" could be nice.  No link would be needed here.
+  if (! octave_link::confirm_shutdown ())
+    return retval;
+
   if (! quit_allowed)
     error ("quit: not supported in embedded mode");
   else