changeset 27302:5f170ea12fa1

use Qt signals to pass interpreter callbacks to octave-qobject * interpreter-qobject.h, interpreter-qobject.cc (interpreter_qobject::m_interpreter): New data member. (interpreter_qobject::execute): Cache pointer to interpreter after it is created. Set it to nullptr before exiting to disable interpreter events. (interpreter_qobject::interpreter_event): New functions. * octave-qobject.h, octave-qobject.cc (octave_qapplication::interpreter_event): New signals. (base_qobject::interpreter_event): New slots. Forward action to m_interpreter object interpreter_event functions. (base_qobject::base_qobject): Connect interpreter_event signals for octave_qapplication to the base_qobject::interpreter_event slots. (octave_qapplication::notify): Emit interpreter_event signal instead of using event_manager::post_exception. * qt-interpreter-events.cc: Declare and register octave::fcn_callback and octave::meth_callback as Qt meta types. * event-manager.h, event-manager.cc (event_manager::m_interpreter): New data member. Update constructor, change all uses. (octave::fcn_callback, octave::meth_callback): New typedefs. (event_manager::post_event): Limit allowable callback function signatures. For meth_callback functions, arrange for a reference to the interpreter object to be passed as the first argument. (event_manager::post_exception): Delete. (event_manager::rethrow_exception_callback): Delete. * GLCanvas.cc (GLCanvas::do_print): Use event_manager::post_event instead of event_manager::post_exception. * file-editor-tab.h (file_eitor_tab::interpreter_event): New signals. * file-editor.cc (file_editor::add_file_editor_tab): Forward interpreter_event signal from newly constructed file_editor_tab object to the interpreter_event signal of the file_editor object. * main-window.h, main-window.cc (main_window::construct): Connect the interpreter_event signal from the main_window object to the parent octave_qobject object. (main_window::interpreter_event): New signals. * octave-dock-widget.h, octave-dock-widget.cc (octave_dock_widget::octave_dock_widget) Forward the interpreter_event signal from the octave_dock_widget object to the interpreter_event signal for parent main_window object. (octave_dock_widget::interpreter_event): New signals. * variable-editor-model.h, variable-editor-model.cc (variable_editor_model::init_from_oct, variable_editor_model::retrieve_variable): Accept reference to interpreter object as an argument. Change all uses. (variable_editor_model::interpreter_event): New signals. * variable-editor.cc (variable_editor::edit_variable): Forward interpreter_event signal from newly constructed variable_editor_model to interpreter_event signal fro variable_editor object. * files-dock-widget.cc, file-editor-tab.cc, main-window.cc, variable-editor-model.cc: In all functions that need to perform interpreter actions, emit an interpreter_event signal instead of accessing the interprter event_manager and calling post_interpreter_event directly.
author John W. Eaton <jwe@octave.org>
date Mon, 29 Jul 2019 10:43:04 -0400
parents a2b1ba6c92d5
children 07b330708e3c
files libgui/graphics/GLCanvas.cc libgui/src/documentation-dock-widget.cc libgui/src/files-dock-widget.cc libgui/src/interpreter-qobject.cc libgui/src/interpreter-qobject.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/main-window.cc libgui/src/main-window.h libgui/src/octave-dock-widget.cc libgui/src/octave-dock-widget.h libgui/src/octave-qobject.cc libgui/src/octave-qobject.h libgui/src/qt-interpreter-events.cc libgui/src/variable-editor-model.cc libgui/src/variable-editor-model.h libgui/src/variable-editor.cc libinterp/corefcn/event-manager.cc libinterp/corefcn/event-manager.h libinterp/corefcn/interpreter-private.h libinterp/corefcn/interpreter.cc
diffstat 22 files changed, 280 insertions(+), 260 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/graphics/GLCanvas.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/graphics/GLCanvas.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -177,7 +177,11 @@
             octave::event_manager& evmgr
               = octave::__get_event_manager__ ("GLCanvas::do_print");
 
-            evmgr.post_exception (std::current_exception ());
+            evmgr.post_event
+              ([] (void)
+               {
+                 std::rethrow_exception (std::current_exception ());
+               });
           }
 
         end_rendering ();
--- a/libgui/src/documentation-dock-widget.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/documentation-dock-widget.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -27,7 +27,6 @@
 #include "documentation-dock-widget.h"
 
 #include "help.h"
-#include "interpreter-private.h"
 
 namespace octave
 {
--- a/libgui/src/files-dock-widget.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/files-dock-widget.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -45,12 +45,12 @@
 #include <QDesktopServices>
 #include <QFileDialog>
 
+#include "qt-interpreter-events.h"
+
+#include "builtin-defun-decls.h"
+#include "interpreter.h"
 #include "load-save.h"
 #include "oct-env.h"
-#include "interpreter-private.h"
-#include "interpreter.h"
-#include "qt-interpreter-events.h"
-#include "builtin-defun-decls.h"
 
 namespace octave
 {
@@ -818,17 +818,11 @@
 
     if (infos.length () > 0)
       {
-        event_manager& evmgr
-          = __get_event_manager__ ("files_dock_widget::contextmenu_add_to_path");
-
-        evmgr.post_event
-          ([dir_list, rm, subdirs] (void)
+        emit interpreter_event
+          ([dir_list, rm, subdirs] (interpreter& interp)
           {
             // INTERPRETER THREAD
 
-            interpreter& interp
-              = __get_interpreter__ ("files_dock_widget::contextmenu_add_to_path");
-
             octave_value_list paths = ovl ();
 
             if (subdirs)
--- a/libgui/src/interpreter-qobject.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/interpreter-qobject.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -36,7 +36,7 @@
 namespace octave
 {
   interpreter_qobject::interpreter_qobject (base_qobject *oct_qobj)
-    : QObject (), m_octave_qobject (oct_qobj),
+    : QObject (), m_octave_qobject (oct_qobj), m_interpreter (nullptr),
       m_qt_link (new qt_interpreter_events ())
   { }
 
@@ -82,6 +82,8 @@
             // The interpreter should be completely ready at this point so let
             // the GUI know.
 
+            m_interpreter = &interp;
+
             emit octave_ready_signal ();
 
             // Start executing commands in the command window.
@@ -94,6 +96,10 @@
         exit_status = ex.exit_status ();
       }
 
+    // Disable events from being passed from the GUI to the interpreter.
+
+    m_interpreter = nullptr;
+
     // Whether or not initialization succeeds we need to clean up the
     // interpreter once we are done with it.
 
@@ -102,6 +108,26 @@
     emit octave_finished_signal (exit_status);
   }
 
+  void interpreter_qobject::interpreter_event (const fcn_callback& fcn)
+  {
+    if (! m_interpreter)
+      return;
+
+    event_manager& evmgr = m_interpreter->get_event_manager ();
+
+    evmgr.post_event (fcn);
+  }
+
+  void interpreter_qobject::interpreter_event (const meth_callback& meth)
+  {
+    if (! m_interpreter)
+      return;
+
+    event_manager& evmgr = m_interpreter->get_event_manager ();
+
+    evmgr.post_event (meth);
+  }
+
   void interpreter_qobject::confirm_shutdown (bool closenow)
   {
     // Wait for link thread to go to sleep state.
--- a/libgui/src/interpreter-qobject.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/interpreter-qobject.h	Mon Jul 29 10:43:04 2019 -0400
@@ -28,10 +28,13 @@
 
 #include <QObject>
 
+#include "qt-interpreter-events.h"
+
 namespace octave
 {
+  class interpreter;
+
   class base_qobject;
-  class qt_interpreter_events;
 
   class interpreter_qobject : public QObject
   {
@@ -47,13 +50,36 @@
 
     void confirm_shutdown (bool closenow);
 
+    void interpreter_event (const fcn_callback& fcn);
+
+    void interpreter_event (const meth_callback& meth);
+
   signals:
 
     void octave_ready_signal (void);
+
     void octave_finished_signal (int);
 
   public slots:
 
+    // Programming Note: With the current design of the interpreter,
+    // additional signals will not be noticed because the execute
+    // function starts the Octave interpreter and it doesn't return
+    // until the interpreter exits.  So the Qt event loop running in the
+    // thread where the interpreter_qobject object lives never has a
+    // chance to see another signal.  Changing the design of the
+    // terminal widget as proposed and discussed here:
+    //
+    //   https://lists.gnu.org/archive/html/octave-maintainers/2019-05/msg00115.html
+    //   https://lists.gnu.org/archive/html/octave-maintainers/2019-06/msg00009.html
+    //
+    // coulld solve that problem.  Briefly, instead of having the Octave
+    // interpreter block and wait for keyboard input, the terminal
+    // widget would be in charge of accepting keyboard events and use
+    // readline in callback mode.  Then the terminal widget and the
+    // interpreter will not block except when executing code.  Then we
+    // could have the interpreter qobject directly accept signals.
+
     //! Initialize and execute the octave interpreter.
 
     void execute (void);
@@ -62,6 +88,8 @@
 
     base_qobject *m_octave_qobject;
 
+    interpreter *m_interpreter;
+
     std::shared_ptr<qt_interpreter_events> m_qt_link;
   };
 }
--- a/libgui/src/m-editor/file-editor-tab.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/m-editor/file-editor-tab.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -1104,18 +1104,17 @@
   {
     bp_info info (_file_name, line);
 
-    event_manager& evmgr
-      = __get_event_manager__ ("file_editor_tab::handle_request_remove_breakpoint");
-
-    evmgr.post_event
-      ([info] (void)
+    emit interpreter_event
+      ([info] (interpreter& interp)
        {
          bp_table::intmap line_info;
          line_info[0] = info.line;
 
          if (qt_interpreter_events::file_in_path (info.file, info.dir))
            {
-             bp_table& bptab = __get_bp_table__ ("file_editor_tab::handle_request_remove_breakpoint");
+             tree_evaluator& tw = interp.get_evaluator ();
+
+             bp_table& bptab = tw.get_bp_table ();
 
              bptab.remove_breakpoint (info.function_name, line_info);
            }
@@ -1190,15 +1189,14 @@
 
     bp_info info (_file_name);
 
-    event_manager& evmgr
-      = __get_event_manager__ ("file_editor_tab::remove_all_breakpoints");
-
-    evmgr.post_event
-      ([info] (void)
+    emit interpreter_event
+      ([info] (interpreter& interp)
        {
          if (qt_interpreter_events::file_in_path (info.file, info.dir))
            {
-             bp_table& bptab = __get_bp_table__ ("file_editor_tab::remove_all_breakpoints");
+             tree_evaluator& tw = interp.get_evaluator ();
+
+             bp_table& bptab = tw.get_bp_table ();
 
              bptab.remove_all_breakpoints_in_file (info.function_name, true);
            }
@@ -1322,18 +1320,17 @@
 
   void file_editor_tab::add_breakpoint_event (const bp_info& info)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("file_editor_tab::add_breakpoint_event");
-
-    evmgr.post_event
-      ([this, info] (void)
+    emit interpreter_event
+      ([this, info] (interpreter& interp)
        {
          bp_table::intmap line_info;
          line_info[0] = info.line;
 
          if (qt_interpreter_events::file_in_path (info.file, info.dir))
            {
-             bp_table& bptab = __get_bp_table__ ("file_editor_tab::add_breakpoint_event");
+             tree_evaluator& tw = interp.get_evaluator ();
+
+             bp_table& bptab = tw.get_bp_table ();
 
              bp_table::intmap bpmap
                = bptab.add_breakpoint (info.function_name, "", line_info, info.condition);
@@ -2053,17 +2050,11 @@
 
     // Create and queue the command object.
 
-    event_manager& evmgr
-      = __get_event_manager__ ("file_editor_tab::update_breakpoints");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([this] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("file_editor_tab::update_breakpoints");
-
          octave_value_list argout = Fdbstatus (interp, ovl (), 1);
 
          connect (this, SIGNAL (update_breakpoints_signal (const octave_value_list&)),
@@ -2119,8 +2110,10 @@
   bool file_editor_tab::exit_debug_and_clear (const QString& full_name_q,
                                               const QString& base_name_q)
   {
-    symbol_table& symtab
-      = __get_symbol_table__ ("file_editor_tab::exit_debug_and_clear");
+    interpreter& interp
+      = __get_interpreter__ ("file_editor_tab::exit_debug_and_clear");
+
+    symbol_table& symtab = interp.get_symbol_table ();
 
     std::string base_name = base_name_q.toStdString ();
     octave_value sym;
@@ -2149,8 +2142,9 @@
     bool retval = true;
 
     octave_idx_type curr_frame = -1;
-    tree_evaluator& tw
-      = __get_evaluator__ ("file_editor_tab::exit_debug_and_clear");
+
+    tree_evaluator& tw = interp.get_evaluator ();
+
     octave_map stk = tw.backtrace (curr_frame, false);
 
     Cell names = stk.contents ("name");
--- a/libgui/src/m-editor/file-editor-tab.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/m-editor/file-editor-tab.h	Mon Jul 29 10:43:04 2019 -0400
@@ -36,10 +36,12 @@
 
 #include "find-dialog.h"
 #include "octave-qscintilla.h"
-#include "builtin-defun-decls.h"
+// Only needed for typedef of "QIntList", which may be typedefed
+// elsewhere.  Could use common location.
+#include "marker.h"
+#include "qt-interpreter-events.h"
 
-#include "marker.h" /* Only needed for typedef of "QIntList", which may be
-                       typedefed elsewhere.  Could use common location. */
+#include "builtin-defun-decls.h"
 
 class octave_value_list;
 
@@ -187,6 +189,9 @@
 
     void debug_quit_signal (void);
 
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
     // FIXME: The following is similar to "process_octave_code"
     // signal.  However, currently that signal is connected to
     // something that simply focuses a window and not actually
--- a/libgui/src/m-editor/file-editor.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/m-editor/file-editor.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -2420,6 +2420,15 @@
              f, SLOT (do_breakpoint_marker (bool, const QWidget*, int,
                                             const QString&)));
 
+    // Any interpreter_event signal from a file_editor_tab_widget is
+    // handled the same as for the parent main_window object.
+
+    connect (f, SIGNAL (interpreter_event (const fcn_callback&)),
+             this, SIGNAL (interpreter_event (const fcn_callback&)));
+
+    connect (f, SIGNAL (interpreter_event (const meth_callback&)),
+             this, SIGNAL (interpreter_event (const meth_callback&)));
+
     m_tab_widget->setCurrentWidget (f);
 
     check_actions ();
--- a/libgui/src/main-window.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/main-window.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -341,17 +341,11 @@
 
     if (! file.isEmpty ())
       {
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::handle_save_workspace_request");
-
-        evmgr.post_event
-          ([file] (void)
+        emit interpreter_event
+          ([file] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
-             interpreter& interp
-               = __get_interpreter__ ("main_window::handle_save_workspace_request");
-
              Fsave (interp, ovl (file.toStdString ()));
            });
       }
@@ -373,17 +367,11 @@
 
     if (! file.isEmpty ())
       {
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::handle_load_workspace_request");
-
-        evmgr.post_event
-          ([file] (void)
+        emit interpreter_event
+          ([file] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
-             interpreter& interp
-               = __get_interpreter__ ("main_window::handle_load_workspace_request");
-
              Fload (interp, ovl (file.toStdString ()));
 
              tree_evaluator& tw = interp.get_evaluator ();
@@ -401,17 +389,11 @@
       {
         std::string file = file_arg.toStdString ();
 
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::handle_open_any_request");
-
-        evmgr.post_event
-          ([file] (void)
+        emit interpreter_event
+          ([file] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
-             interpreter& interp
-               = __get_interpreter__ ("main_window::handle_open_any_request");
-
              feval ("open", ovl (file));
 
              // Update the workspace since open.m may have loaded new
@@ -427,27 +409,18 @@
 
   void main_window::handle_clear_workspace_request (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_clear_workspace_request");
-
-    evmgr.post_event
-      ([] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::handle_clear_workspace_request");
-
          Fclear (interp);
        });
   }
 
   void main_window::handle_clear_command_window_request (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_clear_command_window_request");
-
-    evmgr.post_event
+    emit interpreter_event
       ([] (void)
        {
          // INTERPRETER THREAD
@@ -459,16 +432,12 @@
 
   void main_window::handle_clear_history_request (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_clear_history_request");
-
-    evmgr.post_event
-      ([] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         history_system& history_sys
-           = __get_history_system__ ("main_window::clear_history_request");
+         history_system& history_sys = interp.get_history_system ();
 
          history_sys.do_history (ovl ("-c"));
        });
@@ -478,10 +447,7 @@
   {
     if (command_window_has_focus ())
       {
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::handle_undo_request");
-
-        evmgr.post_event
+        emit interpreter_event
           ([] (void)
            {
              // INTERPRETER THREAD
@@ -501,17 +467,11 @@
     std::string old_name = old_name_arg.toStdString ();
     std::string new_name = new_name_arg.toStdString ();
 
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_rename_variable_request");
-
-    evmgr.post_event
-      ([old_name, new_name] (void)
+    emit interpreter_event
+      ([old_name, new_name] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::rename_variable_request");
-
          symbol_scope scope = interp.get_current_scope ();
 
          if (scope)
@@ -998,10 +958,7 @@
 
     if (fileInfo.exists () && fileInfo.isDir ())
       {
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::set_current_working_directory");
-
-        evmgr.post_event
+        emit interpreter_event
           ([xdir] (void)
            {
              // INTERPRETER THREAD
@@ -1036,10 +993,7 @@
 
   void main_window::execute_command_in_terminal (const QString& command)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::execute_command_in_terminal");
-
-    evmgr.post_event
+    emit interpreter_event
       ([command] (void)
        {
          // INTERPRETER THREAD
@@ -1058,11 +1012,8 @@
 
   void main_window::run_file_in_terminal (const QFileInfo& info)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::run_file_in_terminal");
-
-    evmgr.post_event
-      ([info] (void)
+    emit interpreter_event
+      ([info] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1084,9 +1035,6 @@
            }
          else
            {
-             interpreter& interp
-               = __get_interpreter__ ("main_window::run_file_in_terminal");
-
              // No valid identifier: use equivalent of Fsource (), no
              // debug possible.
 
@@ -1107,17 +1055,11 @@
 
   void main_window::handle_new_figure_request (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_new_figure_request");
-
-    evmgr.post_event
-      ([] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::new_figure_request");
-
          Fbuiltin (interp, ovl ("figure"));
          Fdrawnow ();
        });
@@ -1155,17 +1097,11 @@
 
   void main_window::debug_continue (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::debug_continue");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([this] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::debug_continue");
-
          F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
          Fdbcont (interp);
 
@@ -1175,17 +1111,11 @@
 
   void main_window::debug_step_into (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::debug_step_into");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([this] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::debug_step_into");
-
          F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
          Fdbstep (interp, ovl ("in"));
 
@@ -1199,18 +1129,11 @@
       {
         // We are in debug mode, just call dbstep.
 
-        event_manager& evmgr
-          = __get_event_manager__ ("main_window::debug_step_over");
-
-        evmgr.post_event
-          ([this] (void)
+        emit interpreter_event
+          ([this] (interpreter& interp)
            {
-             // INTERPRETER THREAD
-
-             interpreter& interp
-               = __get_interpreter__ ("main_window::debug_step_over");
-
-             F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
+             F__db_next_breakpoint_quiet__ (interp,
+                                            ovl (m_suppress_dbg_location));
              Fdbstep (interp);
 
              command_editor::interrupt (true);
@@ -1225,16 +1148,11 @@
 
   void main_window::debug_step_out (void)
   {
-    event_manager& evmgr = __get_event_manager__ ("main_window::debug_step_out");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([this] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::debug_step_out");
-
          F__db_next_breakpoint_quiet__ (interp, ovl (m_suppress_dbg_location));
          Fdbstep (interp, ovl ("out"));
 
@@ -1244,16 +1162,11 @@
 
   void main_window::debug_quit (void)
   {
-    event_manager& evmgr = __get_event_manager__ ("main_window::debug_quit");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::debug_quit");
-
          Fdbquit (interp);
 
          command_editor::interrupt (true);
@@ -1807,9 +1720,7 @@
 
   void main_window::set_screen_size (int ht, int wd)
   {
-    event_manager& evmgr = __get_event_manager__ ("main_window::set_screen_size");
-
-    evmgr.post_event
+    emit interpreter_event
       ([ht, wd] (void)
        {
          // INTERPRETER THREAD
@@ -1895,17 +1806,11 @@
     // interpreter.  That will eventually cause the workspace view in the
     // GUI to be updated.
 
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::handle_variable_editor_update");
-
-    evmgr.post_event
-      ([] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::handle_variable_editor_update");
-
          tree_evaluator& tw = interp.get_evaluator ();
 
          event_manager& xevmgr = interp.get_event_manager ();
@@ -1918,15 +1823,11 @@
   {
     e->ignore ();
 
-    event_manager& evmgr = __get_event_manager__ ("main_window::closeEvent");
-
-    evmgr.post_event
-      ([] (void)
+    emit interpreter_event
+      ([] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp = __get_interpreter__ ("main_window::closeEvent");
-
          Fquit (interp);
        });
   }
@@ -2130,6 +2031,12 @@
              SIGNAL (file_remove_signal (const QString&, const QString&)),
              this, SLOT (file_remove_proxy (const QString&, const QString&)));
 
+    connect (this, SIGNAL (interpreter_event (const fcn_callback&)),
+             &m_octave_qobj, SLOT (interpreter_event (const fcn_callback&)));
+
+    connect (this, SIGNAL (interpreter_event (const meth_callback&)),
+             &m_octave_qobj, SLOT (interpreter_event (const meth_callback&)));
+
     configure_shortcuts ();
   }
 
@@ -2879,20 +2786,12 @@
     if (m_default_encoding.startsWith ("SYSTEM", Qt::CaseInsensitive))
       mfile_encoding = "SYSTEM";
 
-    event_manager& evmgr
-      = __get_event_manager__ ("main_window::notice_settings");
-
-    evmgr.post_event
-      ([this, mfile_encoding] (void)
+    emit interpreter_event
+      ([mfile_encoding] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         interpreter& interp
-           = __get_interpreter__ ("main_window::notice_settings");
-
-         F__mfile_encoding__ (interp,
-                              ovl (mfile_encoding));
+         F__mfile_encoding__ (interp, ovl (mfile_encoding));
        });
   }
-
 }
--- a/libgui/src/main-window.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/main-window.h	Mon Jul 29 10:43:04 2019 -0400
@@ -51,6 +51,7 @@
 #include "find-files-dialog.h"
 #include "set-path-dialog.h"
 #include "history-dock-widget.h"
+#include "interpreter-qobject.h"
 #include "octave-dock-widget.h"
 #include "qt-interpreter-events.h"
 #include "resource-manager.h"
@@ -63,7 +64,8 @@
 
 namespace octave
 {
-  class base_qobject;
+  class interpreter;
+
   class settings_dialog;
 
   //! Represents the main window.
@@ -113,6 +115,9 @@
 
     void add_actions_signal (QList <QAction *> action_list);
 
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
   public slots:
 
     void focus_changed (QWidget *w_old, QWidget *w_new);
@@ -282,7 +287,7 @@
     void configure_shortcuts (void);
 
     QList<octave_dock_widget *> dock_widget_list (void);
-    
+
     void update_default_encoding (const QString& default_encoding);
 
     base_qobject& m_octave_qobj;
--- a/libgui/src/octave-dock-widget.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/octave-dock-widget.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -211,6 +211,15 @@
     connect (m_close_action, SIGNAL (triggered (bool)),
              this, SLOT (change_visibility (bool)));
 
+    // Any interpreter_event signal from an octave_dock_widget object is
+    // handled the same as for the parent main_window object.
+
+    connect (this, SIGNAL (interpreter_event (const fcn_callback&)),
+             p, SIGNAL (interpreter_event (const fcn_callback&)));
+
+    connect (this, SIGNAL (interpreter_event (const meth_callback&)),
+             p, SIGNAL (interpreter_event (const meth_callback&)));
+
     m_close_action->setToolTip (tr ("Hide widget"));
 
     setStyleSheet (qdockwidget_css (QString (":/actions/icons/widget-close.png"),
--- a/libgui/src/octave-dock-widget.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/octave-dock-widget.h	Mon Jul 29 10:43:04 2019 -0400
@@ -30,6 +30,8 @@
 #include <QToolButton>
 #include <QMouseEvent>
 
+#include "qt-interpreter-events.h"
+
 namespace octave
 {
 
@@ -98,6 +100,9 @@
 
     void queue_make_widget (void);
 
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
   protected:
 
     virtual void closeEvent (QCloseEvent *e);
--- a/libgui/src/octave-qobject.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/octave-qobject.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -42,7 +42,6 @@
 #include "qt-application.h"
 #include "resource-manager.h"
 
-#include "interpreter-private.h"
 #include "ovl.h"
 #include "oct-env.h"
 #include "version.h"
@@ -70,9 +69,11 @@
       }
     catch (execution_exception&)
       {
-        event_manager& evmgr = __get_event_manager__ ("octave_qapplication::notify");
-
-        evmgr.post_exception (std::current_exception ());
+        emit interpreter_event
+          ([] (void)
+           {
+             std::rethrow_exception (std::current_exception ());
+           });
       }
 
    return false;
@@ -142,6 +143,15 @@
 
     connect (m_main_thread, SIGNAL (finished (void)),
              m_main_thread, SLOT (deleteLater (void)));
+
+    // Handle any interpreter_event signal from the octave_qapplication
+    // object here.
+
+    connect (m_qapplication, SIGNAL (interpreter_event (const fcn_callback&)),
+             this, SLOT (interpreter_event (const fcn_callback&)));
+
+    connect (m_qapplication, SIGNAL (interpreter_event (const meth_callback&)),
+             this, SLOT (interpreter_event (const meth_callback&)));
   }
 
   base_qobject::~base_qobject (void)
@@ -194,6 +204,30 @@
     qApp->exit (exit_status);
   }
 
+  void base_qobject::interpreter_event (const fcn_callback& fcn)
+  {
+    // The following is a direct function call across threads.  It works
+    // because the it is accessing a thread-safe queue of events that
+    // are later executed by the Octave interpreter in the other thread.
+
+    // See also the comments in interpreter-qobject.h about
+    // interpreter_qobject slots.
+
+    m_interpreter_qobj->interpreter_event (fcn);
+  }
+
+  void base_qobject::interpreter_event (const meth_callback& meth)
+  {
+    // The following is a direct function call across threads.  It works
+    // because the it is accessing a thread-safe queue of events that
+    // are later executed by the Octave interpreter in the other thread.
+
+    // See also the comments in interpreter-qobject.h about
+    // interpreter_qobject slots.
+
+    m_interpreter_qobj->interpreter_event (meth);
+  }
+
   void base_qobject::confirm_shutdown_octave (void)
   {
     m_interpreter_qobj->confirm_shutdown (true);
--- a/libgui/src/octave-qobject.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/octave-qobject.h	Mon Jul 29 10:43:04 2019 -0400
@@ -30,6 +30,8 @@
 #include <QString>
 #include <QStringList>
 
+#include "interpreter-qobject.h"
+
 // Defined for purposes of sending QList<int> as part of signal.
 typedef QList<int> QIntList;
 
@@ -38,7 +40,6 @@
 
 namespace octave
 {
-  class interpreter_qobject;
   class main_window;
   class qt_application;
 
@@ -51,6 +52,8 @@
 
   class octave_qapplication : public QApplication
   {
+    Q_OBJECT
+
   public:
 
     octave_qapplication (int& argc, char **argv)
@@ -60,6 +63,11 @@
     virtual bool notify (QObject *receiver, QEvent *e) override;
 
     ~octave_qapplication (void) { };
+
+  signals:
+
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
   };
 
   //! Base class for Octave interfaces that use Qt.  There are two
@@ -127,6 +135,10 @@
                                    const QString& dirname,
                                    const QString& multimode);
 
+    void interpreter_event (const fcn_callback& fcn);
+
+    void interpreter_event (const meth_callback& meth);
+
   protected:
 
     qt_application& m_app_context;
@@ -137,7 +149,7 @@
     int m_argc;
     char **m_argv;
 
-    QApplication *m_qapplication;
+    octave_qapplication *m_qapplication;
 
     QTranslator *m_qt_tr;
     QTranslator *m_gui_tr;
--- a/libgui/src/qt-interpreter-events.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/qt-interpreter-events.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -51,6 +51,8 @@
 
 Q_DECLARE_METATYPE (octave_value)
 Q_DECLARE_METATYPE (octave::symbol_info_list)
+Q_DECLARE_METATYPE (octave::fcn_callback)
+Q_DECLARE_METATYPE (octave::meth_callback)
 
 namespace octave
 {
@@ -59,6 +61,9 @@
   {
     qRegisterMetaType<octave_value> ("octave_value");
     qRegisterMetaType<symbol_info_list> ("symbol_info_list");
+
+    qRegisterMetaType<fcn_callback> ("fcn_callback");
+    qRegisterMetaType<meth_callback> ("meth_callback");
   }
 
   bool qt_interpreter_events::confirm_shutdown (void)
--- a/libgui/src/variable-editor-model.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/variable-editor-model.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -39,7 +39,6 @@
 #include "variable-editor-model.h"
 
 #include "interpreter.h"
-#include "interpreter-private.h"
 #include "ov.h"
 #include "parse.h"
 #include "pr-flt-fmt.h"
@@ -1012,22 +1011,17 @@
 
     std::string expr = os.str ();
 
-    event_manager& evmgr = __get_event_manager__ ("variable_editor_model::setData");
-
-    evmgr.post_event
-      ([this, nm, expr, idx] (void)
+    emit interpreter_event
+      ([this, nm, expr, idx] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
          try
            {
-             interpreter& interp
-               = __get_interpreter__ ("variable_editor_model::setData");
-
              int parse_status = 0;
              interp.eval_string (expr, true, parse_status);
 
-             octave_value val = retrieve_variable (nm);
+             octave_value val = retrieve_variable (interp, nm);
 
              emit update_data_signal (val);
            }
@@ -1140,7 +1134,7 @@
   }
 
   void
-  variable_editor_model::init_from_oct (void)
+  variable_editor_model::init_from_oct (interpreter& interp)
   {
     // INTERPRETER THREAD
 
@@ -1148,7 +1142,7 @@
 
     try
       {
-        octave_value val = retrieve_variable (nm);
+        octave_value val = retrieve_variable (interp, nm);
 
         emit update_data_signal (val);
       }
@@ -1166,23 +1160,17 @@
   {
     std::string expr = expr_arg.toStdString ();
 
-    event_manager& evmgr
-      = __get_event_manager__ ("variable_editor_model::eval_expr_event");
-
-    evmgr.post_event
-      ([this, expr] (void)
+    emit interpreter_event
+      ([this, expr] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
          try
            {
-             interpreter& interp
-               = __get_interpreter__ ("variable_editor_model::eval_expr_event");
-
              int parse_status = 0;
              interp.eval_string (expr, true, parse_status);
 
-             init_from_oct ();
+             init_from_oct (interp);
            }
          catch  (execution_exception&)
            {
@@ -1200,7 +1188,8 @@
   // try-catch block that catches execution exceptions.
 
   octave_value
-  variable_editor_model::retrieve_variable (const std::string& x)
+  variable_editor_model::retrieve_variable (interpreter& interp,
+                                            const std::string& x)
   {
     // INTERPRETER THREAD
 
@@ -1213,9 +1202,6 @@
 
     if (symbol_exist (name, "var") > 0)
       {
-        interpreter& interp
-          = __get_interpreter__ ("variable_editor_model::retrieve_variable");
-
         int parse_status = 0;
         return interp.eval_string (x, true, parse_status);
       }
@@ -1240,15 +1226,12 @@
   void
   variable_editor_model::update_data_cache (void)
   {
-    event_manager& evmgr
-      = __get_event_manager__ ("variable_editor_model::update_data_cache");
-
-    evmgr.post_event
-      ([this] (void)
+    emit interpreter_event
+      ([this] (interpreter& interp)
        {
          // INTERPRETER_THREAD
 
-         init_from_oct ();
+         init_from_oct (interp);
        });
   }
 
--- a/libgui/src/variable-editor-model.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/variable-editor-model.h	Mon Jul 29 10:43:04 2019 -0400
@@ -29,11 +29,15 @@
 #include <QMap>
 #include <QString>
 
+#include "qt-interpreter-events.h"
+
 #include "ov.h"
 #include "pr-flt-fmt.h"
 
 namespace octave
 {
+  class interpreter;
+
   class base_ve_model
   {
   public:
@@ -281,6 +285,9 @@
 
     void edit_variable_signal (const QString& name, const octave_value& val);
 
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
   public slots:
 
     void update_data (const octave_value& val);
@@ -299,11 +306,11 @@
 
     base_ve_model *rep;
 
-    void init_from_oct (void);
+    void init_from_oct (interpreter& interp);
 
     void eval_expr_event (const QString& expr);
 
-    octave_value retrieve_variable (const std::string& name);
+    octave_value retrieve_variable (interpreter&, const std::string& name);
 
     bool is_valid (void) const
     {
--- a/libgui/src/variable-editor.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libgui/src/variable-editor.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -1257,6 +1257,15 @@
     connect (edit_view, SIGNAL (doubleClicked (const QModelIndex&)),
              model, SLOT (double_click (const QModelIndex&)));
 
+    // Any interpreter_event signal from a variable_editor_model object is
+    // handled the same as for the parent variable_editor object.
+
+    connect (model, SIGNAL (interpreter_event (const fcn_callback&)),
+             this, SIGNAL (interpreter_event (const fcn_callback&)));
+
+    connect (model, SIGNAL (interpreter_event (const meth_callback&)),
+             this, SIGNAL (interpreter_event (const meth_callback&)));
+
     // Must supply a title for a QLabel to be created.  Calling set_title()
     // more than once will add more QLabels.  Could change octave_dock_widget
     // to always supply a QLabl (initially empty) and then simply update its
--- a/libinterp/corefcn/event-manager.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libinterp/corefcn/event-manager.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -49,9 +49,10 @@
     return 0;
   }
 
-  event_manager::event_manager (void)
-    : instance (nullptr), event_queue_mutex (new mutex ()),
-      gui_event_queue (), debugging (false), link_enabled (false)
+  event_manager::event_manager (interpreter& interp)
+    : m_interpreter (interp), instance (nullptr),
+      event_queue_mutex (new mutex ()), gui_event_queue (),
+      debugging (false), link_enabled (false)
   {
     command_editor::add_event_hook (readline_event_hook);
   }
--- a/libinterp/corefcn/event-manager.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libinterp/corefcn/event-manager.h	Mon Jul 29 10:43:04 2019 -0400
@@ -27,6 +27,7 @@
 
 #include "octave-config.h"
 
+#include <functional>
 #include <list>
 #include <memory>
 #include <string>
@@ -41,6 +42,9 @@
 
 namespace octave
 {
+  typedef std::function<void (void)> fcn_callback;
+  typedef std::function<void (octave::interpreter&)> meth_callback;
+
   class symbol_info_list;
 
   // The methods in this class provide a way to pass signals to the GUI
@@ -219,7 +223,7 @@
   {
   public:
 
-    event_manager (void);
+    event_manager (interpreter& interp);
 
     // No copying!
 
@@ -262,24 +266,16 @@
     // The queued functions are executed when the interpreter is
     // otherwise idle.
 
-    template <typename F, typename... Args>
-    void post_event (F&& fcn, Args&&... args)
+    void post_event (const fcn_callback& fcn)
     {
       if (enabled ())
-        gui_event_queue.add (fcn, std::forward<Args> (args)...);
+        gui_event_queue.add (fcn);
     }
 
-    template <typename T, typename... Params, typename... Args>
-    void post_event (T *obj, void (T::*method) (Params...), Args&&... args)
+    void post_event (const meth_callback& meth)
     {
       if (enabled ())
-        gui_event_queue.add_method (obj, method, std::forward<Args> (args)...);
-    }
-
-    void post_exception (const std::exception_ptr& p)
-    {
-      if (enabled ())
-        post_event (this, &event_manager::rethrow_exception_callback, p);
+        gui_event_queue.add (std::bind (meth, std::ref (m_interpreter)));
     }
 
     // The following functions correspond to the virtual fuunctions in
@@ -549,6 +545,8 @@
 
   private:
 
+    interpreter& m_interpreter;
+
     // Using a shared_ptr to manage the link_events object ensures that it
     // will be valid until it is no longer needed.
 
@@ -564,11 +562,6 @@
 
     bool debugging;
     bool link_enabled;
-
-    void rethrow_exception_callback (const std::exception_ptr& p)
-    {
-      std::rethrow_exception (p);
-    }
   };
 }
 
--- a/libinterp/corefcn/interpreter-private.h	Sun Jul 28 17:24:42 2019 -0400
+++ b/libinterp/corefcn/interpreter-private.h	Mon Jul 29 10:43:04 2019 -0400
@@ -90,7 +90,6 @@
 
   extern gtk_manager& __get_gtk_manager__ (const std::string& who);
 
-
   // Functions that could be methods in the interpreter class but maybe
   // shouldn't be exposed as part of the public interface.
 
--- a/libinterp/corefcn/interpreter.cc	Sun Jul 28 17:24:42 2019 -0400
+++ b/libinterp/corefcn/interpreter.cc	Mon Jul 29 10:43:04 2019 -0400
@@ -381,7 +381,7 @@
       m_url_handle_manager (),
       m_cdef_manager (*this),
       m_gtk_manager (),
-      m_event_manager (),
+      m_event_manager (*this),
       m_interactive (false),
       m_read_site_files (true),
       m_read_init_files (m_app_context != nullptr),