# HG changeset patch
# User Daniel J Sebald <daniel.sebald@ieee.org>
# Date 1411164787 18000
# Node ID bfedf9d2c44ac8dff8d5cd03de577cdb12275e9a
# Parent  90dd85369c2e8b2db2b040854ec979bd7367c578
New background command queue for GUI to send commands and receive data.

* file-editor-tab.cc (file_editor_tab::file_editor_tab):
Added file_editor pointer to constructor. Connect background command signal
to file_editor equivalent signal.
(file_editor_tab::add_breakpoint_callback): Removed.
(file_editor_tab::remove_breakpoint_callback): Removed.
(file_editor_tab::remove_all_breakpoints_callback): Removed.
(file_editor_tab::request_add_breakpoint): Remove post_event, queue
'dbstop ()' command.
(file_editor_tab::request_remove_breakpoint): Remove post_event, queue
'dbclear ()' command.
(file_editor_tab::remove_all_breakpoints): Use bp_info second argument of 1.
Remove post_event, queue 'dbclear ()' command.
(file_editor_tab::add_all_breakpoints): Added. Get octave_value for 'file' and
'line', convert 'line' to array for 'file' name match, and call
do_breakpoint_marker() for each entry in line number array.
(file_editor_tab::load_file): Emit 'dbstatus()' command to background queue.

* file-editor-tab.h:
(file_editor_tab::file_editor_tab): Add parent input argument.
(file_editor_tab::add_all_breakpoints): Added. Declaration.
(file_editor_tab::queue_background_octave_command): Added. New signal.
(file_editor_tab::add_breakpoint_callback): Removed.
(file_editor_tab::remove_breakpoint_callback): Removed.
(file_editor_tab::remove_all_breakpoints_callback): Removed.


* file-editor.cc (file_editor::request_new_file,
file_editor::request_open_file): Add 'this' to calls to new file_editor_tab().
(file_editor::add_file_editor_tab): Connect have_octave_command_result()
file_editor signal to add_all_breakpoints() file_editor_tab slot.

* file-editor.h (file_editor::queue_background_octave_command,
file_editor::have_octave_command_result): Added. New signals.

* main-window.cc (main_window::main_window): Remove initialization of
_cmd_queue, _cmd_processing, _cmd_queue_mutex, _dbg_queue, _dbg_processing,
and _dbg_queue_mutex.
(main_window::~main_window): Remove deleting _cmd_queue.
(main_window::handle_save_workspace_request): Remove post_event, queue
'save ()' command.
(main_window::handle_load_workspace_request): Remove post_event, queue
'load ()' command.
(main_window::handle_clear_workspace_request): Remove post_event, queue
'clear ()' command.
(main_window::handle_rename_variable_request): Remove post_event, queue
assignment (=) command followed by 'clear()' command.
(main_window::handle_clear_command_window_request): Remove post_event, queue
'clc ()' command.
(main_window::handle_clear_history_request): Remove post_event, queue
'history ('-c')' command.
(main_window::execute_command_in_terminal): Emit queue_octave_command() rather
than call member function queue_command().
(main_window::run_file_in_terminal): Remove post_event, move code from
run_file_callback() and queue_command() to here utilizing
queue_octave_command() signal.
(main_window::run_file_callback): Removed.
(main_window::queue_command): Moved to octave-qt-link.cc.
(main_window::handle_new_figure_request): Remove post_event, queue 'figure ()'
command.
(main_window::browse_for_directory): Add comment about modal dialogs.
(main_window::set_current_working_directory): Remove post_event, queue
'cd ()' command.
(main_window::debug_continue, main_window::debug_step_into,
main_window::debug_step_out): Remove queue_debug() call, queue 'dbcont ()'
command.
(main_window::debug_quit): Remove queue_debug() call, queue 'dbquit ()'
command.
(main_window::closeEvent): Remove post_event, queue 'exit ()' command.
(main_window::construct_octave_qt_link): Connect queue_octave_command() and
queue_background_octave_command() signals to corresponding octave_qt_link slots.
Connect editor_window queue_background_octave_command signals to corresponding
octave_qt_link slots. Connect _octave_qt_link have_octave_command_result()
signal to editor_window have_octave_command_result() slot.
(main_window::save_workspace_callback, main_window::load_workspace_callback,
main_window::clear_workspace_callback, main_window::rename_variable_callback,
main_window::clear_command_window_callback, main_window::clear_history_callback,
main_window::execute_command_callback, main_window::new_figure_callback,
main_window::change_directory_callback, main_window::queue_debug,
main_window::execute_debug_callback, main_window::exit_callback): Removed.

* main-window.h (main_window : public QMainWindow): Remove QQueue.h and
QSemaphore.h from list of includes. Remove all member functions
listed above for main-window.cc. Declare queue_octave_command() and
queue_octave_background_command() signals. Removed _cmd_queue, _cmd_processing,
_cmd_queue_mutex, _dbg_queue, _dbg_processing, and _dbg_queue declarations.

* octave-qt-link.cc: Add parse.h, cmd-edit.h and oct-mutex.h to list of
included files.
(octave_qt_link::octave_qt_link): Initialize _cmd_processing object. Register
meta type octave_value_list, connect transmit_octave_command_result() to
receive_octave_command_result(), connect finished_with_command_result() to
handle_finished_with_command_result().
(octave_qt_link::do_process_events): Added. Virtual override. Lock (foreground)
event queue, execute event, unlock event queue. Lock background queue mutex,
get background command, unlock background mutex, evaluate command with
eval_string (), redraw, lock mutex, signal across thread, wait, unlock mutex.
(octave_qt_link::handle_queue_background_octave_command): Added. Lock
background queue mutex, place command info in queue, unlock mutex.
(octave_qt_link::receive_octave_command_result): Added. Emit signal to GUI
object connections, signal finished with data.
(octave_qt_link::handle_finished_with_command_result): Added. Try locking mutex.
If fail after 5 seconds, indicate connection lost. If success, unlock mutex
and wake Octave worker thread.
(octave_qt_link::execute_command_callback): Moved here from main-window.cc.
(octave_qt_link::handle_queue_octave_command: Moved here from main-window.cc
where it was named queue_command().

* octave-qt-link.h: Add QStringList.h, QMutex.h, QWaitCondition.h, QSemaphore.h,
and "oct-obj.h" header list.
(octave_qt_link : public QObject, public octave_link): Add command status
enumeration. Add command_info structure. Add QList to hold command_info. New
do_process_events () member. Add background_queue_mutex, events_process_mutex,
and events_process_waitcondition Qt members. Add _cmd_queue, _cmd_process, and
_cmd_queue_mutex member objects.  Declare execute_command_callback(). New
signals and slots declarations as described for octave-qt-link.cc above.

* octave-link.h (octave_link): Change do_process_events to virtual.

diff --git a/libgui/src/m-editor/file-editor-tab.cc b/libgui/src/m-editor/file-editor-tab.cc
--- a/libgui/src/m-editor/file-editor-tab.cc
+++ b/libgui/src/m-editor/file-editor-tab.cc
@@ -57,6 +57,7 @@
 
 #include "debug.h"
 #include "octave-qt-link.h"
+#include "ov-struct.h"
 #include "version.h"
 #include "utils.h"
 #include "defaults.h"
@@ -64,7 +65,8 @@
 
 // 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)
+file_editor_tab::file_editor_tab (file_editor *p, const QString directory_arg)
+ : QWidget (p)
 {
   QString directory = directory_arg;
   _lexer_apis = 0;
@@ -169,6 +171,22 @@
   QSettings *settings = resource_manager::get_settings ();
   if (settings)
     notice_settings (settings);
+
+  // For issuing debugger-related commands to the Octave core.
+  connect (this,
+           SIGNAL (queue_background_octave_command (const QString&,
+                                                    const int)),
+           p,
+           SIGNAL (queue_background_octave_command (const QString&,
+                                                    const int)));
+  connect (this,
+           SIGNAL (queue_background_octave_command (const QString&,
+                                                    const int,
+                                                    const QObject*)),
+           p,
+           SIGNAL (queue_background_octave_command (const QString&,
+                                                    const int,
+                                                    const QObject*)));
 }
 
 file_editor_tab::~file_editor_tab (void)
@@ -756,33 +774,6 @@
   _edit_area->markerDeleteAll (bookmark);
 }
 
-void
-file_editor_tab::add_breakpoint_callback (const bp_info& info)
-{
-  bp_table::intmap line_info;
-  line_info[0] = info.line;
-
-  if (octave_qt_link::file_in_path (info.file, info.dir))
-    bp_table::add_breakpoint (info.function_name, line_info);
-}
-
-void
-file_editor_tab::remove_breakpoint_callback (const bp_info& info)
-{
-  bp_table::intmap line_info;
-  line_info[0] = info.line;
-
-  if (octave_qt_link::file_in_path (info.file, info.dir))
-    bp_table::remove_breakpoint (info.function_name, line_info);
-}
-
-void
-file_editor_tab::remove_all_breakpoints_callback (const bp_info& info)
-{
-  if (octave_qt_link::file_in_path (info.file, info.dir))
-    bp_table::remove_all_breakpoints_in_file (info.function_name, true);
-}
-
 file_editor_tab::bp_info::bp_info (const QString& fname, int l)
   : line (l), file (fname.toStdString ())
 {
@@ -818,8 +809,12 @@
 {
   bp_info info (_file_name, line+1);
 
-  octave_link::post_event
-    (this, &file_editor_tab::add_breakpoint_callback, info);
+  QString command;
+  command = "dbstop (\"" + QString(info.function_name.c_str()) + "\", ";
+  command += QString ().setNum (info.line) + ");";
+
+  // There is only one output argument for dbstop.
+  emit queue_background_octave_command (command, 1);
 }
 
 void
@@ -827,8 +822,12 @@
 {
   bp_info info (_file_name, line+1);
 
-  octave_link::post_event
-    (this, &file_editor_tab::remove_breakpoint_callback, info);
+  QString command;
+  command = "dbclear (\"" + QString(info.function_name.c_str()) + "\", ";
+  command += QString ().setNum (line + 1) + ");";
+
+  // There are no output arguments for dbclear.
+  emit queue_background_octave_command (command, 0);
 }
 
 void
@@ -886,10 +885,40 @@
   if (ID != this)
     return;
 
-  bp_info info (_file_name);
+  bp_info info (_file_name, 0+1);
 
-  octave_link::post_event
-    (this, &file_editor_tab::remove_all_breakpoints_callback, info);
+  QString command;
+  command = "dbclear (\"" + QString(info.function_name.c_str()) + "\");";
+
+  // There are no output arguments for dbclear.
+  emit queue_background_octave_command (command, 0);
+}
+
+void
+file_editor_tab::add_all_breakpoints (const QObject *ID, const QString& command,
+                                      const int status,
+                                      const octave_value_list& output)
+{
+  // Only act if the command originated from this tab.
+  if (ID != this)
+    return;
+
+  if (command.contains ("dbstatus") && status == octave_qt_link::CommandOK)
+    {
+      octave_value file = output (0).map_value ().contents ("file");
+      octave_value line = output (0).map_value ().contents ("line");
+      string_vector svfile = file.all_strings ();
+      for (octave_idx_type i = 0; i < svfile.length (); i++)
+        {
+          if (same_file (svfile[i], _file_name.toStdString ()))
+            {
+              octave_value_list linelst = line.list_value ();
+              NDArray linenr = linelst (i).array_value ();
+              for (octave_idx_type j = 0; j < linenr.length (); j++)
+                do_breakpoint_marker (true, this, linenr (j));
+            }
+        }
+    }
 }
 
 void
@@ -1309,6 +1338,9 @@
   update_window_title (false); // window title (no modification)
   _edit_area->setModified (false); // loaded file is not modified yet
 
+  // Inquire from Octave core any breakpoints that are set.
+  emit queue_background_octave_command ("dbstatus ();", 1, this);
+
   return QString ();
 }
 
diff --git a/libgui/src/m-editor/file-editor-tab.h b/libgui/src/m-editor/file-editor-tab.h
--- a/libgui/src/m-editor/file-editor-tab.h
+++ b/libgui/src/m-editor/file-editor-tab.h
@@ -44,7 +44,7 @@
 
 public:
 
-  file_editor_tab (const QString& directory = "");
+  file_editor_tab (file_editor *p, QString directory = "");
 
   ~file_editor_tab (void);
 
@@ -88,6 +88,8 @@
   void next_breakpoint (const QWidget *ID);
   void previous_breakpoint (const QWidget *ID);
   void remove_all_breakpoints (const QWidget *ID);
+  void add_all_breakpoints (const QObject *ID, const QString& command,
+                            const int status, const octave_value_list& output);
 
   void scintilla_command (const QWidget *, unsigned int);
 
@@ -136,6 +138,11 @@
   void execute_command_in_terminal_signal (const QString&);
   void set_global_edit_shortcuts_signal (bool);
   void create_context_menu_tab_signal (QMenu *);
+  void queue_background_octave_command (const QString& command,
+                                        const int nargout,
+                                        const QObject* ID);
+  void queue_background_octave_command (const QString& command,
+                                        const int nargout);
 
 protected:
 
@@ -203,9 +210,6 @@
   QString comment_string (const QString&);
   void do_indent_selected_text (bool indent);
 
-  void add_breakpoint_callback (const bp_info& info);
-  void remove_breakpoint_callback (const bp_info& info);
-  void remove_all_breakpoints_callback (const bp_info& info);
   void center_current_line ();
 
   void add_octave_apis (octave_value_list key_ovl);
diff --git a/libgui/src/m-editor/file-editor.cc b/libgui/src/m-editor/file-editor.cc
--- a/libgui/src/m-editor/file-editor.cc
+++ b/libgui/src/m-editor/file-editor.cc
@@ -148,7 +148,7 @@
   // editor tab has yet to be created and there is no object to
   // pass a signal to.  Hence, functionality is here.
 
-  file_editor_tab *fileEditorTab = new file_editor_tab (ced);
+  file_editor_tab *fileEditorTab = new file_editor_tab (this, ced);
   if (fileEditorTab)
     {
       add_file_editor_tab (fileEditorTab, "");  // new tab with empty title
@@ -356,7 +356,7 @@
         }
       else
         {
-          file_editor_tab *fileEditorTab = new file_editor_tab ();
+          file_editor_tab *fileEditorTab = new file_editor_tab (this);
           if (fileEditorTab)
             {
               QString result = fileEditorTab->load_file (openFileName);
@@ -1587,6 +1587,22 @@
                                                      int)),
            f, SLOT (do_breakpoint_marker (bool, const QWidget*, int)));
 
+  // The following connection can be done sometime after constructing the
+  // file_editor_tab, which loads a file and queues a background dbstatus
+  // command, so long as there is not a return to the GUI thread core in
+  // between.  That being the case, even if that dbstatus command has
+  // completed by now, the following signal will not be emitted until the GUI
+  // thread gets around to handling the recieved command result, which
+  // happens after this function returns.  Note that the file management
+  // construction steps could be cleaned up a little.
+  connect (this,
+           SIGNAL (have_octave_command_result (const QObject *, const QString&,
+                                               const int,
+                                               const octave_value_list&)),
+           f,
+           SLOT (add_all_breakpoints (const QObject *, const QString&,
+                                      const int, const octave_value_list&)));
+
   _tab_widget->setCurrentWidget (f);
 
   check_actions ();
diff --git a/libgui/src/m-editor/file-editor.h b/libgui/src/m-editor/file-editor.h
--- a/libgui/src/m-editor/file-editor.h
+++ b/libgui/src/m-editor/file-editor.h
@@ -114,6 +114,11 @@
   void execute_command_in_terminal_signal (const QString&);
   void file_loaded_signal ();
 
+  void queue_background_octave_command (const QString& command, const int nargout, const QObject* ID);
+  void queue_background_octave_command (const QString& command, const int nargout);
+  void have_octave_command_result (const QObject *, const QString&,
+                                   const int, const octave_value_list&);
+
 public slots:
   void focus (void);
 
diff --git a/libgui/src/main-window.cc b/libgui/src/main-window.cc
--- a/libgui/src/main-window.cc
+++ b/libgui/src/main-window.cc
@@ -90,12 +90,6 @@
     community_news_window (0),
     _octave_qt_link (0),
     _clipboard (QApplication::clipboard ()),
-    _cmd_queue (new QStringList ()),  // no command pending
-    _cmd_processing (1),
-    _cmd_queue_mutex (),
-    _dbg_queue (new QStringList ()),  // no debug pending
-    _dbg_processing (1),
-    _dbg_queue_mutex (),
     _prevent_readline_conflicts (true)
 {
   QSettings *settings = resource_manager::get_settings ();
@@ -155,7 +149,6 @@
       community_news_window = 0;
     }
   delete _octave_qt_link;
-  delete _cmd_queue;
 }
 
 bool
@@ -191,13 +184,18 @@
 void
 main_window::handle_save_workspace_request (void)
 {
+  // FIXME: Freezing the GUI waiting for user input should be avoided.
   QString file =
     QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), ".", 0, 0,
                                   QFileDialog::DontUseNativeDialog);
 
   if (! file.isEmpty ())
-    octave_link::post_event (this, &main_window::save_workspace_callback,
-                             file.toStdString ());
+    {
+      QString command = "save ('" + file + "');";
+
+      // There are no output arguments for save.
+      emit queue_background_octave_command (command, 0);
+    }
 }
 
 void
@@ -205,19 +203,25 @@
 {
   QString file = file_arg;
 
+  // FIXME: Freezing the GUI waiting for user input should be avoided.
   if (file.isEmpty ())
     file = QFileDialog::getOpenFileName (this, tr ("Load Workspace"), ".", 0, 0,
                                          QFileDialog::DontUseNativeDialog);
 
   if (! file.isEmpty ())
-    octave_link::post_event (this, &main_window::load_workspace_callback,
-                             file.toStdString ());
+    {
+      QString command = "load ('" + file + "');";
+
+      // Loading whole workspace, no output arguments are needed.
+      emit queue_background_octave_command (command, 0);
+    }
 }
 
 void
 main_window::handle_clear_workspace_request (void)
 {
-  octave_link::post_event (this, &main_window::clear_workspace_callback);
+  // There are no output arguments for clear.
+  emit queue_background_octave_command ("clear ();", 0);
 }
 
 void
@@ -227,8 +231,18 @@
 {
   name_pair names (old_name.toStdString (), new_name.toStdString ());
 
-  octave_link::post_event (this, &main_window::rename_variable_callback,
-                           names);
+  // If it is desired to check that the first command passed before
+  // issuing the second command, a slot will be needed that implements
+  // a simple state machine.
+
+  QString command = new_name + " = " + old_name + ";";
+
+  // No output arguments are needed.  The way this could fail is that
+  // the old name doesn't exist.
+  emit queue_background_octave_command (command, 0);
+
+  // There are no output arguments for clear.
+  emit queue_background_octave_command ("clear ('" + old_name + "');", 0);
 }
 
 void
@@ -240,13 +254,15 @@
 void
 main_window::handle_clear_command_window_request (void)
 {
-  octave_link::post_event (this, &main_window::clear_command_window_callback);
+  // There are no output arguments for clc.
+  emit queue_background_octave_command ("clc ();", 0);
 }
 
 void
 main_window::handle_clear_history_request (void)
 {
-  octave_link::post_event (this, &main_window::clear_history_callback);
+  // Just clearing all history, so no output arguments are needed.
+  emit queue_background_octave_command ("history ('-c');", 0);
 }
 
 bool
@@ -259,7 +275,7 @@
 void
 main_window::execute_command_in_terminal (const QString& command)
 {
-  queue_command (command);
+  emit queue_octave_command (command);
   if (focus_console_after_command ())
     focus_command_window ();
 }
@@ -290,37 +306,20 @@
       return;
     }
 
-  octave_link::post_event (this, &main_window::run_file_callback, info);
-  if (focus_console_after_command ())
-    focus_command_window ();
-}
-
-void
-main_window::run_file_callback (const QFileInfo& info)
-{
   QString dir = info.absolutePath ();
-  QString function_name = info.fileName ();
-  function_name.chop (info.suffix ().length () + 1);
   if (octave_qt_link::file_in_path (info.absoluteFilePath ().toStdString (),
                                     dir.toStdString ()))
-    queue_command (function_name);
-}
-
-void
-main_window::queue_command (QString command)
-{
-  _cmd_queue_mutex.lock ();
-  _cmd_queue->append (command);   // queue command
-  _cmd_queue_mutex.unlock ();
-
-  if (_cmd_processing.tryAcquire ())  // if callback not processing, post event
-    octave_link::post_event (this, &main_window::execute_command_callback);
+    {
+      emit queue_octave_command (function_name);
+      if (focus_console_after_command ())
+        focus_command_window ();
+    }
 }
 
 void
 main_window::handle_new_figure_request (void)
 {
-  octave_link::post_event (this, &main_window::new_figure_callback);
+  emit queue_background_octave_command ("figure ();", 0);
 }
 
 void
@@ -748,6 +747,7 @@
 void
 main_window::browse_for_directory (void)
 {
+  // FIXME: Freezing the GUI waiting for user input should be avoided.
   QString dir
     = QFileDialog::getExistingDirectory (this, tr ("Browse directories"), 0,
                                          QFileDialog::ShowDirsOnly |
@@ -771,8 +771,13 @@
   QFileInfo fileInfo (xdir);
 
   if (fileInfo.exists () && fileInfo.isDir ())
-    octave_link::post_event (this, &main_window::change_directory_callback,
-                             xdir.toStdString ());
+    {
+      QString command = "cd ('" + xdir + "');";
+
+      // For now, no output arguments are needed and there is no need to
+      // check for success because the file search dialog is fairly robust.
+      emit queue_background_octave_command (command, 0);
+    }
 }
 
 void
@@ -835,31 +840,46 @@
 void
 main_window::debug_continue (void)
 {
-  queue_debug ("cont");
+  // There are no output arguments for dbcont.
+  emit queue_background_octave_command ("dbcont ();", 0);
+  // Force debug result to appear.
+  emit queue_octave_command ("");
 }
 
 void
 main_window::debug_step_into (void)
 {
-  queue_debug ("in");
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ('in');", 0);
+  // Force debug result to appear.
+  emit queue_octave_command ("");
 }
 
 void
 main_window::debug_step_over (void)
 {
-  queue_debug ("step");
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ();\n", 0);
+  // Force debug result to appear.
+  emit queue_octave_command ("");
 }
 
 void
 main_window::debug_step_out (void)
 {
-  queue_debug ("out");
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ('out');", 0);
+  // Force debug result to appear.
+  emit queue_octave_command ("");
 }
 
 void
 main_window::debug_quit (void)
 {
-  queue_debug ("quit");
+  // There are no output arguments for dbquit.
+  emit queue_background_octave_command ("dbquit ();", 0);
+  // Force debug result to appear.
+  emit queue_octave_command ("");
 }
 
 void
@@ -914,7 +934,8 @@
 {
   e->ignore ();
   if (confirm_exit_octave())
-    octave_link::post_event (this, &main_window::exit_callback);
+    // There are no output arguments for exit.
+    emit queue_background_octave_command ("exit ();", 0);
 }
 
 void
@@ -1339,7 +1360,6 @@
 #endif
 
   focus_command_window ();  // make sure that the command window has focus
-
 }
 
 
@@ -1421,6 +1441,41 @@
            SIGNAL (show_doc_signal (const QString &)),
            this, SLOT (handle_show_doc (const QString &)));
 
+  connect (this,
+           SIGNAL (queue_octave_command (const QString&)),
+           _octave_qt_link,
+           SLOT (handle_queue_octave_command (const QString&)));
+
+  connect (this,
+           SIGNAL (queue_background_octave_command (const QString&, const int)),
+           _octave_qt_link,
+           SLOT (handle_queue_background_octave_command (const QString&,
+                                                         const int)));
+
+  connect (editor_window,
+           SIGNAL (queue_background_octave_command (const QString&, const int)),
+           _octave_qt_link,
+           SLOT (handle_queue_background_octave_command (const QString&,
+                                                         const int)));
+
+  connect (editor_window,
+           SIGNAL (queue_background_octave_command (const QString&,
+                                                    const int,
+                                                    const QObject*)),
+           _octave_qt_link,
+           SLOT (handle_queue_background_octave_command (const QString&,
+                                                         const int,
+                                                         const QObject*)));
+
+  connect (_octave_qt_link,
+           SIGNAL (have_octave_command_result (const QObject *, const QString&,
+                                               const int,
+                                               const octave_value_list&)),
+           editor_window,
+           SIGNAL (have_octave_command_result (const QObject *, const QString&,
+                                               const int,
+                                               const octave_value_list&)));
+
   connect (_workspace_model,
            SIGNAL (rename_variable (const QString&, const QString&)),
            this,
@@ -2050,38 +2105,6 @@
 }
 
 void
-main_window::save_workspace_callback (const std::string& file)
-{
-  Fsave (ovl (file));
-}
-
-void
-main_window::load_workspace_callback (const std::string& file)
-{
-  Fload (ovl (file));
-
-  octave_link::set_workspace (true, symbol_table::workspace_info ());
-}
-
-void
-main_window::clear_workspace_callback (void)
-{
-  Fclear ();
-}
-
-void
-main_window::rename_variable_callback (const main_window::name_pair& names)
-{
-  /* bool status = */ symbol_table::rename (names.first, names.second);
-
-  // if (status)
-  octave_link::set_workspace (true, symbol_table::workspace_info ());
-
-  //  else
-  //    ; // we need an octave_link action that runs a GUI error option.
-}
-
-void
 main_window::command_window_undo_callback (void)
 {
   command_editor::undo ();
@@ -2089,125 +2112,12 @@
 }
 
 void
-main_window::clear_command_window_callback (void)
-{
-  Fclc ();
-  command_editor::interrupt (true);
-}
-
-void
 main_window::resize_command_window_callback (void)
 {
   command_editor::resize_terminal ();
 }
 
 void
-main_window::clear_history_callback (void)
-{
-  Fhistory (ovl ("-c"));
-}
-
-void
-main_window::execute_command_callback ()
-{
-  bool repost = false;          // flag for reposting event for this callback
-
-  if (!_cmd_queue->isEmpty ())  // list can not be empty here, just to make sure
-    {
-      std::string pending_input = command_editor::get_current_line ();
-      command_editor::set_initial_input (pending_input);
-
-      _cmd_queue_mutex.lock (); // critical path
-      std::string command = _cmd_queue->takeFirst ().toStdString ();
-      if (_cmd_queue->isEmpty ())
-        _cmd_processing.release ();  // cmd queue empty, processing will stop
-      else
-        repost = true;          // not empty, repost at end
-      _cmd_queue_mutex.unlock ();
-
-      command_editor::replace_line (command);
-
-      command_editor::redisplay ();
-      // We are executing inside the command editor event loop.  Force
-      // the current line to be returned for processing.
-      command_editor::accept_line ();
-    }
-
-  if (repost)  // queue not empty, so repost event for further processing
-    octave_link::post_event (this, &main_window::execute_command_callback);
-
-}
-
-void
-main_window::new_figure_callback (void)
-{
-  Fbuiltin (ovl ("figure"));
-  Fdrawnow ();
-}
-
-void
-main_window::change_directory_callback (const std::string& directory)
-{
-  Fcd (ovl (directory));
-}
-
-// The next callbacks are invoked by GUI buttons.  Those buttons
-// should only be active when we are doing debugging, which means that
-// Octave is waiting for input in get_debug_input.  Calling
-// command_editor::interrupt will force readline to return even if it
-// has not read any input, and then get_debug_input will return,
-// allowing the evaluator to continue and execute the next statement.
-
-void
-main_window::queue_debug (QString debug_cmd)
-{
-  _dbg_queue_mutex.lock ();
-  _dbg_queue->append (debug_cmd);   // queue command
-  _dbg_queue_mutex.unlock ();
-
-  if (_dbg_processing.tryAcquire ())  // if callback not processing, post event
-    octave_link::post_event (this, &main_window::execute_debug_callback);
-}
-
-void
-main_window::execute_debug_callback ()
-{
-  bool repost = false;          // flag for reposting event for this callback
-
-  if (!_dbg_queue->isEmpty ())  // list can not be empty here, just to make sure
-    {
-      _dbg_queue_mutex.lock (); // critical path
-      QString debug = _dbg_queue->takeFirst ();
-      if (_dbg_queue->isEmpty ())
-        _dbg_processing.release ();  // cmd queue empty, processing will stop
-      else
-        repost = true;          // not empty, repost at end
-      _dbg_queue_mutex.unlock ();
-
-      if (debug == "step")
-        Fdbstep ();
-      else if (debug == "cont")
-        Fdbcont ();
-      else if (debug == "quit")
-        Fdbquit ();
-      else
-        Fdbstep (ovl (debug.toStdString ()));
-
-      command_editor::interrupt (true);
-    }
-
-  if (repost)  // queue not empty, so repost event for further processing
-    octave_link::post_event (this, &main_window::execute_debug_callback);
-
-}
-
-void
-main_window::exit_callback (void)
-{
-  Fquit ();
-}
-
-void
 main_window::find_files (const QString &start_dir)
 {
 
diff --git a/libgui/src/main-window.h b/libgui/src/main-window.h
--- a/libgui/src/main-window.h
+++ b/libgui/src/main-window.h
@@ -31,12 +31,10 @@
 #include <QMdiArea>
 #include <QStatusBar>
 #include <QToolBar>
-#include <QQueue>
 #include <QMdiSubWindow>
 #include <QCloseEvent>
 #include <QToolButton>
 #include <QComboBox>
-#include <QSemaphore>
 
 // Editor includes
 #include "file-editor-interface.h"
@@ -82,6 +80,8 @@
   void settings_changed (const QSettings *);
   void new_file_signal (const QString&);
   void open_file_signal (const QString&);
+  void queue_octave_command (const QString&);
+  void queue_background_octave_command (const QString&, const int);
 
   void show_doc_signal (const QString&);
 
@@ -240,38 +240,12 @@
 
   void establish_octave_link (void);
 
-  void save_workspace_callback (const std::string& file);
-
-  void load_workspace_callback (const std::string& file);
-
-  void rename_variable_callback (const name_pair& names);
-
   void command_window_undo_callback (void);
 
-  void clear_command_window_callback (void);
-
   void resize_command_window_callback (void);
 
-  void clear_workspace_callback (void);
-
-  void clear_history_callback (void);
-
-  void execute_command_callback ();
-  void run_file_callback (const QFileInfo& info);
   bool focus_console_after_command ();
 
-  void new_figure_callback (void);
-
-  void change_directory_callback (const std::string& directory);
-
-  void exit_callback (void);
-
-  void queue_command (QString command);
-
-  void queue_debug (QString command);
-
-  void execute_debug_callback ();
-
   void configure_shortcuts ();
 
   bool confirm_exit_octave ();
@@ -387,16 +361,6 @@
   // Flag for closing whole application.
   bool _closing;
 
-  // semaphore to synchronize execution signals and related callback
-  QStringList *_cmd_queue;
-  QSemaphore   _cmd_processing;
-  QMutex       _cmd_queue_mutex;
-
-  // semaphore to synchronize debug signals and related callbacks
-  QStringList *_dbg_queue;
-  QSemaphore   _dbg_processing;
-  QMutex       _dbg_queue_mutex;
-
   bool _prevent_readline_conflicts;
 };
 
diff --git a/libgui/src/octave-qt-link.cc b/libgui/src/octave-qt-link.cc
--- a/libgui/src/octave-qt-link.cc
+++ b/libgui/src/octave-qt-link.cc
@@ -38,14 +38,17 @@
 #include "load-path.h"
 #include "oct-env.h"
 #include "utils.h"
+#include "parse.h"
+#include "cmd-edit.h"
 
+#include "oct-mutex.h"
 #include "octave-qt-link.h"
 
 #include "resource-manager.h"
 
 octave_qt_link::octave_qt_link (QWidget *p)
   : octave_link (), main_thread (new QThread ()),
-    command_interpreter (new octave_interpreter ())
+    command_interpreter (new octave_interpreter ()), _cmd_processing (1)
 {
   connect (this, SIGNAL (execute_interpreter_signal (void)),
            command_interpreter, SLOT (execute (void)));
@@ -56,6 +59,31 @@
   command_interpreter->moveToThread (main_thread);
 
   main_thread->start ();
+
+  // Register octave_value_list so that command results may be signaled
+  // to objects in the GUI thread.
+  qRegisterMetaType<octave_value_list> ("octave_value_list");
+
+  // This is a cross-thread connection when this object exists in the
+  // GUI thread and transmit_octave_command_result is emitted from the
+  // worker (Octave core) thread.
+  connect (this,
+           SIGNAL (transmit_octave_command_result (const QObject *,
+                                                   const QString&,
+                                                   const int,
+                                                   const octave_value_list&)),
+           this,
+           SLOT (receive_octave_command_result (const QObject *,
+                                                const QString&,
+                                                const int,
+                                                const octave_value_list&)));
+
+  // This is a cross-thread confirmation that the GUI thread is finished
+  // with the data resulting from a background Octave command.
+  connect (this,
+           SIGNAL (finished_with_command_result (void)),
+           this,
+           SLOT (handle_finished_with_command_result (void)));
 }
 
 octave_qt_link::~octave_qt_link (void) { }
@@ -474,6 +502,156 @@
   emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
 }
 
+void
+octave_qt_link::do_process_events (void)
+{
+  // This processes commands in the foreground similar to the overridden
+  // code in octave_link::do_process_events.
+  event_queue_mutex->lock ();
+  gui_event_queue.run ();
+  event_queue_mutex->unlock ();
+
+  // This processes commands in the background and returns results.
+  while (! background_octave_command_queue.isEmpty ())
+    {
+      background_queue_mutex.lock ();
+      command_info ci = background_octave_command_queue.takeFirst ();
+      background_queue_mutex.unlock ();
+
+      // Evaluate this string without producing any output or advancing the
+      // line number shown at the terminal command line prompt.
+      octave_value_list retval;
+      int parse_status;
+      retval = eval_string (ci.command.toStdString (), false,
+                            parse_status, ci.nargout);
+      Fdrawnow ();
+
+      int command_status;
+      if (parse_status)
+        command_status = ParseFail;
+      else if (error_state)
+        command_status = ProcessFail;
+      else
+        command_status = CommandOK;
+
+      // This lock is to ensure that this Octave worker thread becomes
+      // unlocked by the QWaitCondition a few lines further down before
+      // the GUI thread attempts to wake the process.  Otherwise, there
+      // is the risk of this thread being awaken before going to sleep.
+      events_process_mutex.lock ();
+
+      emit transmit_octave_command_result (ci.senderid, ci.command,
+                                           command_status, retval);
+
+      events_process_waitcondition.wait (&events_process_mutex);
+      events_process_mutex.unlock ();
+    }
+}
+
+void
+octave_qt_link::handle_queue_background_octave_command (const QString& command,
+                                                        const int nargout,
+                                                        const QObject* ID)
+{
+  background_queue_mutex.lock ();
+  command_info cominf = {ID, command, nargout};
+  background_octave_command_queue.append (cominf);
+  background_queue_mutex.unlock ();
+}
+
+void
+octave_qt_link::receive_octave_command_result (const QObject *ID,
+                                               const QString& command,
+                                               const int status,
+                                               const octave_value_list& output)
+{
+  // Passing octave_value_list through a thread is thread safe.  Passing an
+  // octave_value through a thread is not because octave_value uses a
+  // reference count which could be mangled in the queued signal/slot copy and
+  // delete mechanism.  (When a signal is emitted from one thread to an object
+  // in another thread, queued signals result, not direct signals.  That means
+  // a copy-construct is done in one thread, while the destruct is done in
+  // another thread.)  No type of operation on the octave_value of the output
+  // list should be done in this routine.  However, because the worker thread
+  // is asleep, operations on octave_value types and its member derivatives
+  // is fine in DIRECT connections to the following signal because then
+  // the reference count increment and decrement are in the same thread and
+  // happen before the worker thread is awaken.  (Direct connections are those
+  // for which the signal and slot object are in the same thread.)
+
+  emit have_octave_command_result (ID, command, status, output);
+
+  emit finished_with_command_result ();
+}
+
+void
+octave_qt_link::handle_finished_with_command_result (void)
+{
+  // Wake up Octave worker process so that it continues but make sure the
+  // process is asleep first just in case there is some rare condition in
+  // which the GUI thread reaches this point before the Octave worker thread
+  // goes into a sleep state.
+  if (! events_process_mutex.tryLock (5000))
+    {
+      // Create a NonModal message about error.
+      QMessageBox* msgBox = new QMessageBox (
+              QMessageBox::Critical, tr ("Octave Qt Link"),
+              "Connection Timeout: Lost link to worker process.",
+              QMessageBox::Ok, 0);
+      msgBox->setWindowModality (Qt::NonModal);
+      msgBox->setAttribute (Qt::WA_DeleteOnClose);
+      msgBox->show ();
+    }
+  else
+    {
+      events_process_mutex.unlock ();
+      events_process_waitcondition.wakeAll ();
+    }
+}
+
+// FIXME: Callback can likely be avoided if handle_queue_octave_command is
+// placed in the worker thread.  See background queue setup.
+void
+octave_qt_link::execute_command_callback ()
+{
+  bool repost = false;          // flag for reposting event for this callback
+
+  if (!_cmd_queue.isEmpty ())  // list can not be empty here, just to make sure
+    {
+      std::string pending_input = command_editor::get_current_line ();
+      command_editor::set_initial_input (pending_input);
+
+      _cmd_queue_mutex.lock (); // critical path
+      std::string command = _cmd_queue.takeFirst ().toStdString ();
+      if (_cmd_queue.isEmpty ())
+        _cmd_processing.release ();  // cmd queue empty, processing will stop
+      else
+        repost = true;          // not empty, repost at end
+      _cmd_queue_mutex.unlock ();
+
+      command_editor::replace_line (command);
+
+      command_editor::redisplay ();
+      // We are executing inside the command editor event loop.  Force
+      // the current line to be returned for processing.
+      command_editor::accept_line ();
+    }
+
+  if (repost)  // queue not empty, so repost event for further processing
+    octave_link::post_event (this, &octave_qt_link::execute_command_callback);
+
+}
+
+void
+octave_qt_link::handle_queue_octave_command (const QString& command)
+{
+  _cmd_queue_mutex.lock ();
+  _cmd_queue.append (command);   // queue command
+  _cmd_queue_mutex.unlock ();
+
+  if (_cmd_processing.tryAcquire ())  // if callback not processing, post event
+    octave_link::post_event (this, &octave_qt_link::execute_command_callback);
+}
 
 bool
 octave_qt_link::file_in_path (const std::string& file, const std::string& dir)
diff --git a/libgui/src/octave-qt-link.h b/libgui/src/octave-qt-link.h
--- a/libgui/src/octave-qt-link.h
+++ b/libgui/src/octave-qt-link.h
@@ -29,13 +29,19 @@
 #include <string>
 
 #include <QList>
+#include <QStringList>
 #include <QObject>
 #include <QString>
 #include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QSemaphore>
 
 #include "octave-link.h"
 #include "octave-interpreter.h"
 
+#include "oct-obj.h"
+
 // Defined for purposes of sending QList<int> as part of signal.
 typedef QList<int> QIntList;
 
@@ -53,6 +59,13 @@
 
 public:
 
+  enum
+    {
+      CommandOK = 0,
+      ParseFail,
+      ProcessFail
+    };
+
   octave_qt_link (QWidget *p);
 
   ~octave_qt_link (void);
@@ -146,6 +159,30 @@
 
   octave_interpreter *command_interpreter;
 
+  // GUI events issue background Octave commands which are stored in a queue.
+  struct command_info
+    {
+      const QObject *senderid;
+      const QString command;
+      const int nargout;
+    };
+  QList<command_info> background_octave_command_queue;
+
+  // Background Octave command queue mutex access control.
+  void do_process_events (void);
+  QMutex background_queue_mutex;
+  QMutex events_process_mutex;
+  QWaitCondition events_process_waitcondition;
+
+  // GUE events issue foreground Octave commands which are stored in a queue.
+  QStringList _cmd_queue;
+  QSemaphore  _cmd_processing;
+
+  // Foreground Octave command queue mutex access control.
+  QMutex      _cmd_queue_mutex;
+
+  void execute_command_callback (void);
+
 signals:
 
   void execute_interpreter_signal (void);
@@ -185,9 +222,35 @@
 
   void show_doc_signal (const QString &file);
 
+  // Emit this signal from within the Octave worker thread.  There should
+  // be only one slot connected to this signal, receive_octave_command_result.
+  void transmit_octave_command_result (const QObject *, const QString&,
+                                       const int, const octave_value_list&);
+
+  // Emit this signal from within the GUI thread.  Many QObject slots may
+  // connect to this signal, but the programming rule is that none of them
+  // should modify any contents of the output octave_value.  ONLY retrieve
+  // results.
+  void have_octave_command_result (const QObject *, const QString&,
+                                   const int, const octave_value_list&);
+
+  void finished_with_command_result (void);
+
 public slots:
 
   void terminal_interrupt (void);
+
+  void handle_queue_octave_command (const QString& command);
+  void handle_queue_background_octave_command (const QString& command, const int nargout, const QObject* ID);
+  void handle_queue_background_octave_command (const QString& command, const int nargout)
+    {
+      handle_queue_background_octave_command (command, nargout, sender ());
+    };
+  void receive_octave_command_result (const QObject *ID,
+                                      const QString& command,
+                                      const int status,
+                                      const octave_value_list& output);
+  void handle_finished_with_command_result (void);
 };
 
 #endif
diff --git a/libinterp/corefcn/octave-link.h b/libinterp/corefcn/octave-link.h
--- a/libinterp/corefcn/octave-link.h
+++ b/libinterp/corefcn/octave-link.h
@@ -356,7 +356,7 @@
   bool link_enabled;
 
   void do_generate_events (void);
-  void do_process_events (void);
+  virtual void do_process_events (void);
   void do_discard_events (void);
 
   template <class T>
exporting patch:
<fdopen>
