# HG changeset patch
# User Daniel J Sebald <daniel.sebald@ieee.org>
# Date 1366261994 18000
# Node ID 58dd034ecb472051b9fbaef48e5f8e6e7526f8ef
# Parent  e192525236ad2d32978fe1ed9cf5b44a712ee682
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::run_file_callback,
file_editor_tab::add_breakpoint_callback,
file_editor_tab::remove_breakpoint_callback,
file_editor_tab::remove_all_breakpoints_callback): Remove.
(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): Remove post_event, queue command
'dbclear ()' command.
(file_editor_tab::add_all_breakpoints): New. Gets octave_value for 'file' and
'line', converts 'line' to array for 'file' name match, and calls
do_breakpoint_marker for each entry in line number array.
(file_editor_tab::load_file): Issue 'dbstatus()' command to background queue.

* file-editor-tab.h: Add <config.h> and "oct-obj.h" headers.
(file_editor_tab::run_file_callback,
file_editor_tab::add_breakpoint_callback,
file_editor_tab::remove_breakpoint_callback,
file_editor_tab::remove_all_breakpoints_callback): Remove.
(file_editor_tab::add_all_breakpoints): New.

* file-editor.cc (file_editor::request_new_file,
file_editor::request_open_file): Add 'this' to list of file_editor_tab
arguments.
(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): New signals.

* main-window.cc (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::browse_for_directory): Remove post_event, queue 'cd ()' command.
(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 post_event, queue 'dbcont ()' command.
(main_window::debug_quit): Remove post_event, queue 'dbquit ()' command.
(main_window::closeEvent): Remove post_event, queue 'exit ()' command.
(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::change_directory_callback,
main_window::debug_continue_callback, main_window::debug_continue_callback,
main_window::debug_step_into_callback, main_window::debug_step_over_callback,
main_window::debug_step_out_callback, main_window::debug_quit_callback,
main_window::exit_callback): Remove.
(main_window::construct_octave_qt_link): Connect signal
queue_background_octave_command to slot handle_queue_octave_command for main
window and _octave_qt_link and file editor window and _octave_qt_link. Connect
_octave_qt_link have_octave_command_result signal to file editor equivalent.

* main_window.h (main_window : public QMainWindow): Remove all member functions
listed above for main_window.cc.  Add queue_background_octave_command member.

* octave-qt-link.cc (octave_qt_link::octave_qt_link): 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): New. Virtual override. Lock mutex, get
command, unlock mutex, evaluate command with eval_string (), lock mutex,
signal across thread, wait, unlock mutex.
(octave_qt_link::handle_queue_octave_command): New. Lock mutex, place command
info in queue, unlock mutex.
(octave_qt_link::receive_octave_command_result): New. Emit signal to GUI
object connections, signal finished with data.
(octave_qt_link::handle_finished_with_command_result): New. Try locking mutex.
If fail after 5 seconds, indicate connection lost.  If success, unlock mutex
and wake Octave worker thread.

* octave-qt-link.h: Add <config.h> and "oct-obj.h" headers.
(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. New signals and slots as described
for octave-qt-link.cc above.

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

diff -r e192525236ad -r 58dd034ecb47 libgui/src/m-editor/file-editor-tab.cc
--- a/libgui/src/m-editor/file-editor-tab.cc	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/m-editor/file-editor-tab.cc	Thu Apr 18 00:13:14 2013 -0500
@@ -47,14 +47,20 @@
 
 #include "file-editor-tab.h"
 #include "file-editor.h"
+#if USE_CALLBACKS
 #include "octave-link.h"
+#else
+#include "octave-qt-link.h"
+#include "ov-struct.h"
+#endif
 
 #include "debug.h"
 #include "oct-env.h"
 
 // Make parent null for the file editor tab so that warning
 // WindowModal messages don't affect grandparents.
-file_editor_tab::file_editor_tab (QString directory)
+file_editor_tab::file_editor_tab (file_editor *p, QString directory)
+ : QWidget (p)
 {
   // Make sure there is a slash at the end of the directory name
   // for identification when saved later.
@@ -121,6 +127,14 @@
   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)));
 }
 
 file_editor_tab::~file_editor_tab ()
@@ -350,12 +364,13 @@
   delete printer;
 }
 
-
+#if USE_CALLBACKS
 void
 file_editor_tab::run_file_callback (void)
 {
   // Maybe someday we will do something here?
 }
+#endif
 
 void
 file_editor_tab::run_file (const QWidget* ID)
@@ -374,10 +389,12 @@
   function_name.chop (file_info.suffix ().length () + 1);
   emit process_octave_code (QString ("cd \'%1\'\n%2\n")
                     .arg(path).arg (function_name));
- 
+
+#if USE_CALLBACKS 
   // TODO: Sending a run event crashes for long scripts. Find out why.
   // octave_link::post_event
   //   (this, &file_editor_tab::run_file_callback, _file_name.toStdString ()));
+#endif
 }
 
 void
@@ -431,6 +448,7 @@
   _edit_area->markerDeleteAll (bookmark);
 }
 
+#if USE_CALLBACKS
 void
 file_editor_tab::add_breakpoint_callback (const bp_info& info)
 {
@@ -468,6 +486,7 @@
   if (intmap.size() > 0)
     _edit_area->markerDeleteAll (breakpoint);
 }
+#endif
 
 void
 file_editor_tab::request_add_breakpoint (int line)
@@ -479,10 +498,19 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
+#if USE_CALLBACKS
   bp_info info (path, function_name, line);
 
   octave_link::post_event
     (this, &file_editor_tab::add_breakpoint_callback, info);
+#else
+  QString command;
+  command = "dbstop (\"" + function_name + "\", ";
+  command += QString ().setNum (line) + ");";
+
+  // There is only one output argument for dbstop.
+  emit queue_background_octave_command (command, 1);
+#endif
 }
 
 void
@@ -495,10 +523,19 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
+#if USE_CALLBACKS
   bp_info info (path, function_name, line);
 
   octave_link::post_event
     (this, &file_editor_tab::remove_breakpoint_callback, info);
+#else
+  QString command;
+  command = "dbclear (\"" + function_name + "\", ";
+  command += QString ().setNum (line + 1) + ");";
+
+  // There are no output arguments for dbclear.
+  emit queue_background_octave_command (command, 0);
+#endif
 }
 
 void
@@ -556,12 +593,56 @@
   // We have to cut off the suffix, because octave appends it.
   function_name.chop (file_info.suffix ().length () + 1);
 
+#if USE_CALLBACKS
   bp_info info (path, function_name, 0);
 
   octave_link::post_event
     (this, &file_editor_tab::remove_all_breakpoints_callback, info);
+#else
+  QString command;
+  command = "dbclear (\"" + function_name + "\");";
+
+  // There are no output arguments for dbclear.
+  emit queue_background_octave_command (command, 0);
+#endif
 }
 
+#if !USE_CALLBACKS
+void
+file_editor_tab::add_all_breakpoints (const QObject *ID, const QString& command,
+                                      const int status,
+                                      const octave_value_list& output)
+{
+
+  // FIXME:  Would like to use ID to avoid running code if possible.
+  // However, because of the SIGNAL/SIGNAL connection the sender that
+  // is stored in the queue is not the sender of the original signal.
+  // Either signal directly to the octave_qt_link, or place the original
+  // sender as an argument variable to queue_background_octave_command.
+  //
+  // Really don't need the ID in this case because dbstatus contains
+  // file information.
+//  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 (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) - 1);
+            }
+        }
+    }
+}
+#endif
+
 void
 file_editor_tab::comment_selected_text (const QWidget* ID)
 {
@@ -774,7 +855,7 @@
 }
 
 QString
-file_editor_tab::load_file(const QString& fileName)
+file_editor_tab::load_file (const QString& fileName)
 {
   QFile file (fileName);
   if (!file.open (QFile::ReadOnly))
@@ -791,6 +872,12 @@
   update_window_title (false); // window title (no modification)
   _edit_area->setModified (false); // loaded file is not modified yet
 
+#if USE_CALLBACKS
+#else
+  // Inquire from Octave core any breakpoints that are set.
+  emit queue_background_octave_command ("dbstatus ();", 1);
+#endif
+
   return QString ();
 }
 
diff -r e192525236ad -r 58dd034ecb47 libgui/src/m-editor/file-editor-tab.h
--- a/libgui/src/m-editor/file-editor-tab.h	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/m-editor/file-editor-tab.h	Thu Apr 18 00:13:14 2013 -0500
@@ -30,13 +30,19 @@
 #include <QSettings>
 
 #include "find-dialog.h"
+//#include "octave-qt-link.h"
+// FIXME -- we should not be including config.h in header files.
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "oct-obj.h"
 
 class file_editor;
 class file_editor_tab : public QWidget
 {
   Q_OBJECT
   public:
-  file_editor_tab (QString directory = "");
+  file_editor_tab (file_editor *p, QString directory = "");
   ~file_editor_tab ();
 
 public slots:
@@ -73,6 +79,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 comment_selected_text (const QWidget* ID);
   void uncomment_selected_text (const QWidget* ID);
@@ -99,6 +107,9 @@
   void mru_add_file (const QString& file_name);
   void editor_check_conflict_save (const QString& saveFileName, bool remove_on_success);
   void process_octave_code (const QString& command);
+#if !USE_CALLBACKS
+  void queue_background_octave_command (const QString& command, const int nargout);
+#endif
 
 protected:
   void closeEvent (QCloseEvent *event);
@@ -142,10 +153,12 @@
   int check_file_modified ();
   void do_comment_selected_text (bool comment);
 
+#if USE_CALLBACKS
   void run_file_callback (void);
   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);
+#endif
   void center_current_line ();
 
   QsciScintilla *       _edit_area;
diff -r e192525236ad -r 58dd034ecb47 libgui/src/m-editor/file-editor.cc
--- a/libgui/src/m-editor/file-editor.cc	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/m-editor/file-editor.cc	Thu Apr 18 00:13:14 2013 -0500
@@ -138,7 +138,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
@@ -217,7 +217,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);
@@ -989,6 +989,19 @@
   connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget *, int)),
            f, SLOT (do_breakpoint_marker (bool, const QWidget *, int)));
 
+  // This can be done after constructing the file_editor_tab, which does a
+  // load file and queues a background dbstatus command.  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.  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);
 }
 
diff -r e192525236ad -r 58dd034ecb47 libgui/src/m-editor/file-editor.h
--- a/libgui/src/m-editor/file-editor.h	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/m-editor/file-editor.h	Thu Apr 18 00:13:14 2013 -0500
@@ -98,6 +98,11 @@
   void fetab_delete_debugger_pointer (const QWidget* ID, int line = -1);
   void fetab_do_breakpoint_marker (bool insert, const QWidget* ID, int line = -1);
   void fetab_set_focus (const QWidget* ID);
+#if !USE_CALLBACKS
+  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&);
+#endif
 
 public slots:
   void focus (void);
diff -r e192525236ad -r 58dd034ecb47 libgui/src/main-window.cc
--- a/libgui/src/main-window.cc	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/main-window.cc	Thu Apr 18 00:13:14 2013 -0500
@@ -131,12 +131,23 @@
 void
 main_window::handle_save_workspace_request (void)
 {
+  // FIXME: Freezing the GUI waiting for user input should be avoided.
   QString selectedFile =
     QFileDialog::getSaveFileName (this, tr ("Save Workspace As"),
                                   resource_manager::get_home_path ());
+
   if (!selectedFile.isEmpty ())
+#if USE_CALLBACKS
     octave_link::post_event (this, &main_window::save_workspace_callback,
                              selectedFile.toStdString ());
+#else
+    {
+      QString command = "save ('" + selectedFile + "');";
+
+      // There are no output arguments for save.
+      emit queue_background_octave_command (command, 0);
+    }
+#endif
 }
 
 void
@@ -144,18 +155,33 @@
 {
   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"),
                                          resource_manager::get_home_path ());
   if (! file.isEmpty ())
+#if USE_CALLBACKS
     octave_link::post_event (this, &main_window::load_workspace_callback,
                              file.toStdString ());
+#else
+    {
+      QString command = "load ('" + file + "');";
+
+      // Loading whole workspace, no output arguments are needed.
+      emit queue_background_octave_command (command, 0);
+    }
+#endif
 }
 
 void
 main_window::handle_clear_workspace_request (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::clear_workspace_callback);
+#else
+  // There are no output arguments for clear.
+  emit queue_background_octave_command ("clear ();", 0);
+#endif
 }
 
 void
@@ -165,20 +191,43 @@
 {
   name_pair names (old_name.toStdString (), new_name.toStdString ());
 
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::rename_variable_callback,
                            names);
+#else
+  // 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 + ";";
+  // There are no output arguments for clear.
+  emit queue_background_octave_command (command, 0);
+  // There are no output arguments for clear.
+  emit queue_background_octave_command ("clear ('" + old_name + "');", 0);
+#endif
 }
 
 void
 main_window::handle_clear_command_window_request (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::clear_command_window_callback);
+#else
+  // There are no output arguments for clc.
+  emit queue_background_octave_command ("clc ();", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
 main_window::handle_clear_history_request (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::clear_history_callback);
+#else
+  // Just clearing all history, so no output arguments are needed.
+  emit queue_background_octave_command ("history ('-c');", 0);
+#endif
 }
 
 void
@@ -326,13 +375,24 @@
 void
 main_window::browse_for_directory (void)
 {
+  // FIXME: Freezing the GUI waiting for user input should be avoided.
   QString dir =
     QFileDialog::getExistingDirectory (this, tr ("Set working directory"));
 
   if (! dir.isEmpty ())
+#if USE_CALLBACKS
     octave_link::post_event (this,
                              &main_window::change_directory_callback,
                              dir.toStdString ());
+#else
+    {
+      QString command = "cd ('" + dir + "');";
+
+      // 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);
+    }
+#endif
 }
 
 void
@@ -345,8 +405,18 @@
   QFileInfo fileInfo (xdir);
 
   if (fileInfo.exists () && fileInfo.isDir ())
+#if USE_CALLBACKS
     octave_link::post_event (this, &main_window::change_directory_callback,
                              xdir.toStdString ());
+#else
+    {
+      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);
+    }
+#endif
 }
 
 void
@@ -411,31 +481,61 @@
 void
 main_window::debug_continue (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::debug_continue_callback);
+#else
+  // There are no output arguments for dbcont.
+  emit queue_background_octave_command ("dbcont ();", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
 main_window::debug_step_into (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::debug_step_into_callback);
+#else
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ('in');", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
 main_window::debug_step_over (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::debug_step_over_callback);
+#else
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ();", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
 main_window::debug_step_out (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::debug_step_out_callback);
+#else
+  // There are no output arguments for dbstep.
+  emit queue_background_octave_command ("dbstep ('out');", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
 main_window::debug_quit (void)
 {
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::debug_quit_callback);
+#else
+  // There are no output arguments for dbquit.
+  emit queue_background_octave_command ("dbquit ();", 0);
+  command_editor::interrupt (true);
+#endif
 }
 
 void
@@ -450,7 +550,12 @@
 main_window::closeEvent (QCloseEvent *e)
 {
   e->ignore ();
+#if USE_CALLBACKS
   octave_link::post_event (this, &main_window::exit_callback);
+#else
+  // There are no output arguments for exit.
+  emit queue_background_octave_command ("exit ();", 0);
+#endif
 }
 
 void
@@ -782,6 +887,27 @@
            editor_window,
            SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
 
+#if !USE_CALLBACKS
+  connect (this,
+           SIGNAL (queue_background_octave_command (const QString&, const int)),
+           _octave_qt_link,
+           SLOT (handle_queue_octave_command (const QString&, const int)));
+
+  connect (editor_window,
+           SIGNAL (queue_background_octave_command (const QString&, const int)),
+           _octave_qt_link,
+           SLOT (handle_queue_octave_command (const QString&, const int)));
+
+  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&)));
+#endif
+
   connect (_workspace_model,
            SIGNAL (rename_variable (const QString&, const QString&)),
            this,
@@ -1306,6 +1432,7 @@
            this, SLOT (change_directory_up ()));
 }
 
+#if USE_CALLBACKS
 void
 main_window::save_workspace_callback (const std::string& file)
 {
@@ -1410,6 +1537,7 @@
 {
   Fquit ();
 }
+#endif
 
 void
 main_window::find_files(const QString &start_dir)
diff -r e192525236ad -r 58dd034ecb47 libgui/src/main-window.h
--- a/libgui/src/main-window.h	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/main-window.h	Thu Apr 18 00:13:14 2013 -0500
@@ -79,6 +79,9 @@
   void relay_command_signal (const QString&);
   void new_file_signal (const QString&);
   void open_file_signal (const QString&);
+#if !USE_CALLBACKS
+  void queue_background_octave_command (const QString&, const int);
+#endif
 
 public slots:
   void report_status_message (const QString& statusMessage);
@@ -175,6 +178,7 @@
 
   void establish_octave_link (void);
 
+#if USE_CALLBACKS
   void save_workspace_callback (const std::string& file);
 
   void load_workspace_callback (const std::string& file);
@@ -200,6 +204,7 @@
   void debug_quit_callback (void);
 
   void exit_callback (void);
+#endif
 
   // Data models.
   workspace_model *_workspace_model;
diff -r e192525236ad -r 58dd034ecb47 libgui/src/octave-qt-link.cc
--- a/libgui/src/octave-qt-link.cc	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/octave-qt-link.cc	Thu Apr 18 00:13:14 2013 -0500
@@ -29,6 +29,7 @@
 #include <QStringList>
 
 #include "str-vec.h"
+#include "parse.h"
 
 #include "dialog.h"
 #include "workspace-element.h"
@@ -37,7 +38,34 @@
 
 octave_qt_link::octave_qt_link (octave_main_thread *mt)
   : octave_link (), main_thread (mt)
-{ }
+{
+#if !USE_CALLBACKS
+  // 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 is 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)));
+#endif
+}
 
 octave_qt_link::~octave_qt_link (void) { }
 
@@ -261,3 +289,113 @@
 {
   emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
 }
+
+void
+octave_qt_link::do_process_events (void)
+{
+#if USE_CALLBACKS
+  octave_link::do_process_events ();
+#else
+  while (! background_octave_command_queue.isEmpty ())
+    {
+      background_queue_mutex.lock ();
+      command_info ci = background_octave_command_queue.takeFirst ();
+      background_queue_mutex.unlock ();
+fprintf(stderr,"Your wish is my command:  %s\n",ci.command.toStdString().c_str());
+      // 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);
+
+      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 ();
+
+fprintf (stderr, "Here's right before transmitting signal.\n");
+      emit transmit_octave_command_result (ci.senderid, ci.command,
+                                           command_status, retval);
+fprintf (stderr, "Here's right after transmitting signal.\n");
+
+      events_process_waitcondition.wait (&events_process_mutex);
+      events_process_mutex.unlock ();
+    }
+#endif
+}
+
+#if !USE_CALLBACKS
+void
+octave_qt_link::handle_queue_octave_command (const QString& command,
+                                             const int nargout)
+{
+  background_queue_mutex.lock ();
+  command_info cominf = {sender (), 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.)
+
+fprintf(stderr,"GUI?  Here's the result for:  %s\n",command.toStdString().c_str());
+  emit have_octave_command_result (ID, command, status, output);
+
+fprintf(stderr,"OK, All done.\n");
+  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 to a sleep state.
+  if (! events_process_mutex.tryLock (5000))
+    {
+fprintf(stderr, "Failed Unlock.\n");
+      // 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
+    {
+fprintf(stderr, "Now waking worker thread.\n");
+      events_process_mutex.unlock ();
+      events_process_waitcondition.wakeAll ();
+    }
+}
+#endif
diff -r e192525236ad -r 58dd034ecb47 libgui/src/octave-qt-link.h
--- a/libgui/src/octave-qt-link.h	Tue Apr 16 21:34:39 2013 +0200
+++ b/libgui/src/octave-qt-link.h	Thu Apr 18 00:13:14 2013 -0500
@@ -31,9 +31,16 @@
 #include <QList>
 #include <QObject>
 #include <QString>
+#include <QMutex>
+#include <QWaitCondition>
 
 #include "octave-link.h"
 #include "octave-main-thread.h"
+// FIXME -- we should not be including config.h in header files.
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "oct-obj.h"
 
 // \class OctaveLink
 // \brief Provides threadsafe access to octave.
@@ -49,6 +56,16 @@
 
 public:
 
+#define USE_CALLBACKS 0
+#if !USE_CALLBACKS
+  enum
+    {
+      CommandOK = 0,
+      ParseFail,
+      ProcessFail
+    };
+#endif
+
   octave_qt_link (octave_main_thread *mt);
 
   ~octave_qt_link (void);
@@ -113,6 +130,23 @@
   // Thread running octave_main.
   octave_main_thread *main_thread;
 
+#if !USE_CALLBACKS
+  // 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;
+
+  // Process GUI events in the background Octave command queue.
+  void do_process_events (void);
+  QMutex background_queue_mutex;
+  QMutex events_process_mutex;
+  QWaitCondition events_process_waitcondition;
+#endif
+
 signals:
 
   void exit_signal (int status);
@@ -142,6 +176,28 @@
 
   void insert_debugger_pointer_signal (const QString&, int);
   void delete_debugger_pointer_signal (const QString&, int);
+
+#if !USE_CALLBACKS
+  // 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 handle_queue_octave_command (const QString& command, const int nargout);
+  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
 };
 
 #endif
diff -r e192525236ad -r 58dd034ecb47 libinterp/interpfcn/octave-link.h
--- a/libinterp/interpfcn/octave-link.h	Tue Apr 16 21:34:39 2013 +0200
+++ b/libinterp/interpfcn/octave-link.h	Thu Apr 18 00:13:14 2013 -0500
@@ -285,7 +285,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>
