changeset 27260:5ac60319575b

separate octave_link event queue from events and actions * octave-link.h, octave-link.cc (octave_link_events): New class containing the virtual functions from octave_link that are intended to be overridden. The octave_link class now manages the queue of events and provides static wrappers to call these event functions (or skip calling them if the link is disabled). (octave_link::event_queue_mutex, octave_link::gui_event_queue, octave_link::debugging, octave_link::link_enabled): Now static. Change all uses to match. (octave_link::instance): Now pointer to octave_link_events object. * octave-qt-link.h, octave-qt-link.cc (octave_qt_link_events): Rename from octave_qt_link and derive from octave_link_events instead of octave_link. Change all uses. * interpreter-qobject.h, interpreter-qobject.cc (interpreter_qobject::m_qt_link): Now pointer to octave_qt_link_events. Change all uses to match.
author John W. Eaton <jwe@octave.org>
date Thu, 18 Jul 2019 01:15:21 -0400
parents a42821748671
children dccdc3b001a2
files libgui/src/interpreter-qobject.cc libgui/src/interpreter-qobject.h libgui/src/m-editor/file-editor-tab.cc libgui/src/main-window.cc libgui/src/octave-qt-link.cc libgui/src/octave-qt-link.h libinterp/corefcn/octave-link.cc libinterp/corefcn/octave-link.h
diffstat 8 files changed, 374 insertions(+), 330 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/interpreter-qobject.cc	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/interpreter-qobject.cc	Thu Jul 18 01:15:21 2019 -0400
@@ -37,7 +37,7 @@
 {
   interpreter_qobject::interpreter_qobject (base_qobject *oct_qobj)
     : QObject (), m_octave_qobject (oct_qobj),
-      m_qt_link (new octave_qt_link ())
+      m_qt_link (new octave_qt_link_events ())
   {
     octave_link::connect_link (m_qt_link);
 
--- a/libgui/src/interpreter-qobject.h	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/interpreter-qobject.h	Thu Jul 18 01:15:21 2019 -0400
@@ -29,7 +29,7 @@
 namespace octave
 {
   class base_qobject;
-  class octave_qt_link;
+  class octave_qt_link_events;
 
   class interpreter_qobject : public QObject
   {
@@ -41,7 +41,7 @@
 
     ~interpreter_qobject (void) = default;
 
-    octave_qt_link * qt_link (void) { return m_qt_link; }
+    octave_qt_link_events * qt_link (void) { return m_qt_link; }
 
     void confirm_shutdown (bool closenow);
 
@@ -60,7 +60,7 @@
 
     base_qobject *m_octave_qobject;
 
-    octave_qt_link *m_qt_link;
+    octave_qt_link_events *m_qt_link;
   };
 }
 
--- a/libgui/src/m-editor/file-editor-tab.cc	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/m-editor/file-editor-tab.cc	Thu Jul 18 01:15:21 2019 -0400
@@ -1113,7 +1113,7 @@
          bp_table::intmap line_info;
          line_info[0] = info.line;
 
-         if (octave_qt_link::file_in_path (info.file, info.dir))
+         if (octave_qt_link_events::file_in_path (info.file, info.dir))
            {
              bp_table& bptab = __get_bp_table__ ("file_editor_tab::handle_request_remove_breakpoint");
 
@@ -1193,7 +1193,7 @@
     octave_link::post_event
       ([info] (void)
        {
-         if (octave_qt_link::file_in_path (info.file, info.dir))
+         if (octave_qt_link_events::file_in_path (info.file, info.dir))
            {
              bp_table& bptab = __get_bp_table__ ("file_editor_tab::remove_all_breakpoints");
 
@@ -1325,7 +1325,7 @@
          bp_table::intmap line_info;
          line_info[0] = info.line;
 
-         if (octave_qt_link::file_in_path (info.file, info.dir))
+         if (octave_qt_link_events::file_in_path (info.file, info.dir))
            {
              bp_table& bptab = __get_bp_table__ ("file_editor_tab::add_breakpoint_event");
 
--- a/libgui/src/main-window.cc	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/main-window.cc	Thu Jul 18 01:15:21 2019 -0400
@@ -514,7 +514,7 @@
   {
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
-    octave_qt_link *qt_link = interp_qobj->qt_link ();
+    octave_qt_link_events *qt_link = interp_qobj->qt_link ();
 
     // Wait for worker to suspend
     qt_link->lock ();
@@ -1046,7 +1046,7 @@
 
              std::string path = info.absolutePath ().toStdString ();
 
-             if (octave_qt_link::file_in_path (file_path, path))
+             if (octave_qt_link_events::file_in_path (file_path, path))
                command_editor::replace_line (function_name.toStdString ());
            }
          else
@@ -1882,7 +1882,7 @@
 
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
-    octave_qt_link *qt_link = interp_qobj->qt_link ();
+    octave_qt_link_events *qt_link = interp_qobj->qt_link ();
 
     connect (qt_link,
              SIGNAL (edit_variable_signal (const QString&,
@@ -2069,7 +2069,7 @@
   {
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
-    octave_qt_link *qt_link = interp_qobj->qt_link ();
+    octave_qt_link_events *qt_link = interp_qobj->qt_link ();
 
     connect (qt_link,
              SIGNAL (set_workspace_signal (bool, bool, const symbol_info_list&)),
@@ -2674,7 +2674,7 @@
 
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
-    octave_qt_link *qt_link = interp_qobj->qt_link ();
+    octave_qt_link_events *qt_link = interp_qobj->qt_link ();
 
     // Wait for worker to suspend
     qt_link->lock ();
--- a/libgui/src/octave-qt-link.cc	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/octave-qt-link.cc	Thu Jul 18 01:15:21 2019 -0400
@@ -54,14 +54,14 @@
 
 namespace octave
 {
-  octave_qt_link::octave_qt_link (void)
-    : octave_link (), m_shutdown_confirm_result (false)
+  octave_qt_link_events::octave_qt_link_events (void)
+    : octave_link_events (), m_shutdown_confirm_result (false)
   {
     qRegisterMetaType<octave_value> ("octave_value");
     qRegisterMetaType<symbol_info_list> ("symbol_info_list");
   }
 
-  bool octave_qt_link::do_confirm_shutdown (void)
+  bool octave_qt_link_events::do_confirm_shutdown (void)
   {
     // Lock the mutex before emitting signal.
     lock ();
@@ -78,21 +78,21 @@
     return m_shutdown_confirm_result;
   }
 
-  bool octave_qt_link::do_copy_image_to_clipboard (const std::string& file)
+  bool octave_qt_link_events::do_copy_image_to_clipboard (const std::string& file)
   {
     emit copy_image_to_clipboard_signal (QString::fromStdString (file), true);
 
     return true;
   }
 
-  bool octave_qt_link::do_edit_file (const std::string& file)
+  bool octave_qt_link_events::do_edit_file (const std::string& file)
   {
     emit edit_file_signal (QString::fromStdString (file));
 
     return true;
   }
 
-  bool octave_qt_link::do_prompt_new_edit_file (const std::string& file)
+  bool octave_qt_link_events::do_prompt_new_edit_file (const std::string& file)
   {
     QSettings *settings = resource_manager::get_settings ();
 
@@ -126,7 +126,7 @@
     return (answer == tr ("Create"));
   }
 
-  uint8NDArray octave_qt_link::do_get_named_icon (const std::string& icon_name)
+  uint8NDArray octave_qt_link_events::do_get_named_icon (const std::string& icon_name)
   {
     uint8NDArray retval;
     QIcon icon = resource_manager::icon (QString::fromStdString (icon_name));
@@ -152,7 +152,7 @@
     return retval;
   }
 
-  std::string octave_qt_link::do_question_dialog (const std::string& msg,
+  std::string octave_qt_link_events::do_question_dialog (const std::string& msg,
                                                   const std::string& title,
                                                   const std::string& btn1,
                                                   const std::string& btn2,
@@ -237,7 +237,7 @@
   }
 
   std::pair<std::list<int>, int>
-  octave_qt_link::do_list_dialog (const std::list<std::string>& list,
+  octave_qt_link_events::do_list_dialog (const std::list<std::string>& list,
                                   const std::string& mode,
                                   int width, int height,
                                   const std::list<int>& initial,
@@ -272,7 +272,7 @@
   }
 
   std::list<std::string>
-  octave_qt_link::do_input_dialog (const std::list<std::string>& prompt,
+  octave_qt_link_events::do_input_dialog (const std::list<std::string>& prompt,
                                    const std::string& title,
                                    const std::list<float>& nr,
                                    const std::list<float>& nc,
@@ -305,7 +305,7 @@
   }
 
   std::list<std::string>
-  octave_qt_link::do_file_dialog (const filter_list& filter,
+  octave_qt_link_events::do_file_dialog (const filter_list& filter,
                                   const std::string& title,
                                   const std::string& filename,
                                   const std::string& dirname,
@@ -347,7 +347,7 @@
   // This uses a QMessageBox unlike other functions in this file,
   // because uiwidget_creator.waitcondition.wait hangs when called from
   // file_editor_tab::handle_context_menu_break_condition().  (FIXME: why hang?)
-  int octave_qt_link::do_debug_cd_or_addpath_error (const std::string& file,
+  int octave_qt_link_events::do_debug_cd_or_addpath_error (const std::string& file,
                                                     const std::string& dir,
                                                     bool addpath_option)
   {
@@ -400,12 +400,12 @@
     return retval;
   }
 
-  void octave_qt_link::do_change_directory (const std::string& dir)
+  void octave_qt_link_events::do_change_directory (const std::string& dir)
   {
     emit change_directory_signal (QString::fromStdString (dir));
   }
 
-  void octave_qt_link::do_file_remove (const std::string& old_name,
+  void octave_qt_link_events::do_file_remove (const std::string& old_name,
                                        const std::string& new_name)
   {
     // Lock the mutex before signaling
@@ -420,18 +420,18 @@
     unlock ();
   }
 
-  void octave_qt_link::do_file_renamed (bool load_new)
+  void octave_qt_link_events::do_file_renamed (bool load_new)
   {
     emit file_renamed_signal (load_new);
   }
 
-  void octave_qt_link::do_execute_command_in_terminal
+  void octave_qt_link_events::do_execute_command_in_terminal
     (const std::string& command)
   {
     emit execute_command_in_terminal_signal (QString::fromStdString (command));
   }
 
-  void octave_qt_link::do_set_workspace (bool top_level, bool debug,
+  void octave_qt_link_events::do_set_workspace (bool top_level, bool debug,
                                          const symbol_info_list& syminfo,
                                          bool update_variable_editor)
   {
@@ -444,12 +444,12 @@
       emit refresh_variable_editor_signal ();
   }
 
-  void octave_qt_link::do_clear_workspace (void)
+  void octave_qt_link_events::do_clear_workspace (void)
   {
     emit clear_workspace_signal ();
   }
 
-  void octave_qt_link::do_set_history (const string_vector& hist)
+  void octave_qt_link_events::do_set_history (const string_vector& hist)
   {
     QStringList qt_hist;
 
@@ -459,27 +459,27 @@
     emit set_history_signal (qt_hist);
   }
 
-  void octave_qt_link::do_append_history (const std::string& hist_entry)
+  void octave_qt_link_events::do_append_history (const std::string& hist_entry)
   {
     emit append_history_signal (QString::fromStdString (hist_entry));
   }
 
-  void octave_qt_link::do_clear_history (void)
+  void octave_qt_link_events::do_clear_history (void)
   {
     emit clear_history_signal ();
   }
 
-  void octave_qt_link::do_pre_input_event (void)
+  void octave_qt_link_events::do_pre_input_event (void)
   { }
 
-  void octave_qt_link::do_post_input_event (void)
+  void octave_qt_link_events::do_post_input_event (void)
   { }
 
-  void octave_qt_link::do_enter_debugger_event (const std::string& file,
+  void octave_qt_link_events::do_enter_debugger_event (const std::string& file,
                                                 int line)
   {
     interpreter& interp = __get_interpreter__ (
-                                  "octave_qt_link::do_enter_debugger_event");
+                                  "octave_qt_link_events::do_enter_debugger_event");
     octave_value_list fct = F__which__ (interp, ovl (file),0);
     octave_map map = fct(0).map_value ();
 
@@ -492,20 +492,20 @@
     emit enter_debugger_signal ();
   }
 
-  void octave_qt_link::do_execute_in_debugger_event (const std::string& file,
+  void octave_qt_link_events::do_execute_in_debugger_event (const std::string& file,
                                                      int line)
   {
     do_delete_debugger_pointer (file, line);
   }
 
-  void octave_qt_link::do_exit_debugger_event (void)
+  void octave_qt_link_events::do_exit_debugger_event (void)
   {
     emit exit_debugger_signal ();
   }
 
   // Display (if @insert true) or remove the appropriate symbol for a breakpoint
   // in @file at @line with condition @cond.
-  void octave_qt_link::do_update_breakpoint (bool insert,
+  void octave_qt_link_events::do_update_breakpoint (bool insert,
                                              const std::string& file,
                                              int line,
                                              const std::string& cond)
@@ -514,7 +514,52 @@
                                           line, QString::fromStdString (cond));
   }
 
-  bool octave_qt_link::file_in_path (const std::string& file,
+  void octave_qt_link_events::do_show_preferences (void)
+  {
+    emit show_preferences_signal ();
+  }
+
+  std::string octave_qt_link_events::do_gui_preference (const std::string& key,
+                                                 const std::string& value)
+  {
+    QString pref_value;
+
+    // Lock the mutex before signaling
+    lock ();
+
+    // Emit the signal for changing or getting a preference
+    emit gui_preference_signal (QString::fromStdString (key),
+                                QString::fromStdString (value), &pref_value);
+
+    // Wait for the GUI and unlock when resumed
+    wait ();
+    unlock ();
+
+    return pref_value.toStdString ();
+  }
+
+  void octave_qt_link_events::do_show_doc (const std::string& file)
+  {
+    emit show_doc_signal (QString::fromStdString (file));
+  }
+
+  void octave_qt_link_events::do_register_doc (const std::string& file)
+  {
+    emit register_doc_signal (QString::fromStdString (file));
+  }
+
+  void octave_qt_link_events::do_unregister_doc (const std::string& file)
+  {
+    emit unregister_doc_signal (QString::fromStdString (file));
+  }
+
+  void octave_qt_link_events::do_edit_variable (const std::string& expr,
+                                         const octave_value& val)
+  {
+    emit edit_variable_signal (QString::fromStdString (expr), val);
+  }
+
+  bool octave_qt_link_events::file_in_path (const std::string& file,
                                      const std::string& dir)
   {
 
@@ -527,7 +572,7 @@
       ok = true;
     else
       {
-        load_path& lp = __get_load_path__ ("octave_qt_link::file_in_path");
+        load_path& lp = __get_load_path__ ("octave_qt_link_events::file_in_path");
 
         bool dir_in_load_path = lp.contains_canonical (dir);
 
@@ -563,7 +608,7 @@
 
     if (! ok)
       {
-        int action = debug_cd_or_addpath_error (file, dir, addpath_option);
+        int action = octave_link::debug_cd_or_addpath_error (file, dir, addpath_option);
         switch (action)
           {
           case 1:
@@ -573,7 +618,7 @@
 
           case 2:
             {
-              load_path& lp = __get_load_path__ ("octave_qt_link::file_in_path");
+              load_path& lp = __get_load_path__ ("octave_qt_link_events::file_in_path");
 
               lp.prepend (dir);
               ok = true;
@@ -588,59 +633,14 @@
     return ok;
   }
 
-  void octave_qt_link::do_show_preferences (void)
-  {
-    emit show_preferences_signal ();
-  }
-
-  std::string octave_qt_link::do_gui_preference (const std::string& key,
-                                                 const std::string& value)
-  {
-    QString pref_value;
-
-    // Lock the mutex before signaling
-    lock ();
-
-    // Emit the signal for changing or getting a preference
-    emit gui_preference_signal (QString::fromStdString (key),
-                                QString::fromStdString (value), &pref_value);
-
-    // Wait for the GUI and unlock when resumed
-    wait ();
-    unlock ();
-
-    return pref_value.toStdString ();
-  }
-
-  void octave_qt_link::do_show_doc (const std::string& file)
-  {
-    emit show_doc_signal (QString::fromStdString (file));
-  }
-
-  void octave_qt_link::do_register_doc (const std::string& file)
-  {
-    emit register_doc_signal (QString::fromStdString (file));
-  }
-
-  void octave_qt_link::do_unregister_doc (const std::string& file)
-  {
-    emit unregister_doc_signal (QString::fromStdString (file));
-  }
-
-  void octave_qt_link::do_edit_variable (const std::string& expr,
-                                         const octave_value& val)
-  {
-    emit edit_variable_signal (QString::fromStdString (expr), val);
-  }
-
-  void octave_qt_link::do_insert_debugger_pointer (const std::string& file,
-                                                   int line)
+  void octave_qt_link_events::do_insert_debugger_pointer (const std::string& file,
+                                                          int line)
   {
     emit insert_debugger_pointer_signal (QString::fromStdString (file), line);
   }
 
-  void octave_qt_link::do_delete_debugger_pointer (const std::string& file,
-                                                   int line)
+  void octave_qt_link_events::do_delete_debugger_pointer (const std::string& file,
+                                                          int line)
   {
     emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
   }
--- a/libgui/src/octave-qt-link.h	Thu Jul 18 00:08:07 2019 -0400
+++ b/libgui/src/octave-qt-link.h	Thu Jul 18 01:15:21 2019 -0400
@@ -50,27 +50,28 @@
   //! buffering access operations to octave and executing them in the
   //! readline event hook, which lives in the octave thread.
 
-  class octave_qt_link : public QObject, public octave_link
+  class octave_qt_link_events : public QObject, public octave_link_events
   {
     Q_OBJECT
 
   public:
 
-    octave_qt_link (void);
+    octave_qt_link_events (void);
 
     // No copying!
 
-    octave_qt_link (const octave_qt_link&) = delete;
+    octave_qt_link_events (const octave_qt_link_events&) = delete;
 
-    octave_qt_link& operator = (const octave_qt_link&) = delete;
+    octave_qt_link_events& operator = (const octave_qt_link_events&) = delete;
 
-    ~octave_qt_link (void) = default;
+    ~octave_qt_link_events (void) = default;
 
     bool do_confirm_shutdown (void);
 
     bool do_copy_image_to_clipboard (const std::string& file);
 
     bool do_edit_file (const std::string& file);
+
     bool do_prompt_new_edit_file (const std::string& file);
 
     std::string
@@ -122,46 +123,58 @@
     void do_clear_workspace (void);
 
     void do_set_history (const string_vector& hist);
+
     void do_append_history (const std::string& hist_entry);
+
     void do_clear_history (void);
 
     void do_pre_input_event (void);
+
     void do_post_input_event (void);
 
     void do_enter_debugger_event (const std::string& file, int line);
+
     void do_execute_in_debugger_event (const std::string& file, int line);
+
     void do_exit_debugger_event (void);
 
     void do_update_breakpoint (bool insert, const std::string& file, int line,
                                const std::string& cond);
 
-    static bool file_in_path (const std::string& file, const std::string& dir);
-
     void do_show_preferences (void);
 
     std::string do_gui_preference (const std::string& key,
                                    const std::string& value);
     void do_show_doc (const std::string& file);
+
     void do_register_doc (const std::string& file);
+
     void do_unregister_doc (const std::string& file);
 
     void do_edit_variable (const std::string& name, const octave_value& val);
 
     void shutdown_confirmation (bool sd) { m_shutdown_confirm_result = sd; }
 
+    static bool file_in_path (const std::string& file, const std::string& dir);
+
     void lock (void) { m_mutex.lock (); }
+
     void wait (void) { m_waitcondition.wait (&m_mutex); }
+
     void unlock (void) { m_mutex.unlock (); }
+
     void wake_all (void) { m_waitcondition.wakeAll (); }
 
   private:
 
     void do_insert_debugger_pointer (const std::string& file, int line);
+
     void do_delete_debugger_pointer (const std::string& file, int line);
 
     bool m_shutdown_confirm_result;
 
     QMutex m_mutex;
+
     QWaitCondition m_waitcondition;
 
   signals:
@@ -173,6 +186,7 @@
     void change_directory_signal (const QString& dir);
 
     void file_remove_signal (const QString& old_name, const QString& new_name);
+
     void file_renamed_signal (bool load_new);
 
     void execute_command_in_terminal_signal (const QString& command);
@@ -183,16 +197,20 @@
     void clear_workspace_signal (void);
 
     void set_history_signal (const QStringList& hist);
+
     void append_history_signal (const QString& hist_entry);
+
     void clear_history_signal (void);
 
     void enter_debugger_signal (void);
+
     void exit_debugger_signal (void);
 
     void update_breakpoint_marker_signal (bool insert, const QString& file,
                                           int line, const QString& cond);
 
     void insert_debugger_pointer_signal (const QString&, int);
+
     void delete_debugger_pointer_signal (const QString&, int);
 
     void show_preferences_signal (void);
--- a/libinterp/corefcn/octave-link.cc	Thu Jul 18 00:08:07 2019 -0400
+++ b/libinterp/corefcn/octave-link.cc	Thu Jul 18 01:15:21 2019 -0400
@@ -46,20 +46,85 @@
   return 0;
 }
 
-octave_link *octave_link::instance = nullptr;
+octave_link_events *octave_link::instance = nullptr;
+
+octave::mutex *octave_link::event_queue_mutex = new octave::mutex ();
+
+octave::event_queue octave_link::gui_event_queue;
+
+bool octave_link::debugging = false;
+
+bool octave_link::link_enabled = true;
 
 octave_link::octave_link (void)
-  : event_queue_mutex (new octave::mutex ()), gui_event_queue (),
-    debugging (false), link_enabled (true)
-{
-  octave::command_editor::add_event_hook (octave_readline_hook);
-}
+{ }
 
 octave_link::~octave_link (void)
 {
   delete event_queue_mutex;
 }
 
+// OBJ should be an object of a class that is derived from the base
+// class octave_link, or 0 to disconnect the link.  It is the
+// responsibility of the caller to delete obj.
+
+void
+octave_link::connect_link (octave_link_events *obj)
+{
+  if (obj && instance)
+    error ("octave_link is already linked!");
+
+  instance = obj;
+
+  octave::command_editor::add_event_hook (octave_readline_hook);
+}
+
+octave_link_events *
+octave_link::disconnect_link (bool delete_instance)
+{
+  if (delete_instance)
+    {
+      delete instance;
+      instance = nullptr;
+      return nullptr;
+    }
+  else
+    {
+      octave_link_events *retval = instance;
+      instance = nullptr;
+      return retval;
+    }
+}
+
+void
+octave_link::process_events (bool disable_flag)
+{
+  if (enabled ())
+    {
+      if (disable_flag)
+        disable ();
+
+      event_queue_mutex->lock ();
+
+      gui_event_queue.run ();
+
+      event_queue_mutex->unlock ();
+    }
+}
+
+void
+octave_link::discard_events (void)
+{
+  if (enabled ())
+    {
+      event_queue_mutex->lock ();
+
+      gui_event_queue.discard ();
+
+      event_queue_mutex->unlock ();
+    }
+}
+
 void
 octave_link::set_workspace (void)
 {
@@ -68,45 +133,11 @@
       octave::tree_evaluator& tw
         = octave::__get_evaluator__ ("octave_link::set_workspace");
 
-      instance->do_set_workspace (tw.at_top_level (),
-                                  instance->debugging,
+      instance->do_set_workspace (tw.at_top_level (), debugging,
                                   tw.get_symbol_info (), true);
     }
 }
 
-// OBJ should be an object of a class that is derived from the base
-// class octave_link, or 0 to disconnect the link.  It is the
-// responsibility of the caller to delete obj.
-
-void
-octave_link::connect_link (octave_link *obj)
-{
-  if (obj && instance)
-    error ("octave_link is already linked!");
-
-  instance = obj;
-}
-
-void
-octave_link::do_process_events (void)
-{
-  event_queue_mutex->lock ();
-
-  gui_event_queue.run ();
-
-  event_queue_mutex->unlock ();
-}
-
-void
-octave_link::do_discard_events (void)
-{
-  event_queue_mutex->lock ();
-
-  gui_event_queue.discard ();
-
-  event_queue_mutex->unlock ();
-}
-
 DEFUN (__octave_link_enabled__, , ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} __octave_link_enabled__ ()
--- a/libinterp/corefcn/octave-link.h	Thu Jul 18 00:08:07 2019 -0400
+++ b/libinterp/corefcn/octave-link.h	Thu Jul 18 01:15:21 2019 -0400
@@ -43,6 +43,152 @@
   class symbol_info_list;
 }
 
+class
+octave_link_events
+{
+public:
+
+  octave_link_events (void) = default;
+
+  octave_link_events (const octave_link_events&) = default;
+
+  octave_link_events& operator = (const octave_link_events&) = default;
+
+  virtual ~octave_link_events (void) = default;
+
+  virtual bool do_confirm_shutdown (void) { return false; }
+
+  virtual bool do_copy_image_to_clipboard (const std::string& /*file*/)
+  {
+    return false;
+  }
+
+  virtual bool do_edit_file (const std::string& /*file*/) { return false; }
+
+  virtual bool do_prompt_new_edit_file (const std::string& /*file*/)
+  {
+    return false;
+  }
+
+  virtual std::string
+  do_question_dialog (const std::string& /*msg*/,
+                      const std::string& /*title*/,
+                      const std::string& /*btn1*/,
+                      const std::string& /*btn2*/,
+                      const std::string& /*btn3*/,
+                      const std::string& /*btndef*/)
+  {
+    return "";
+  }
+
+  virtual std::pair<std::list<int>, int>
+  do_list_dialog (const std::list<std::string>& /*list*/,
+                  const std::string& /*mode*/,
+                  int /*width*/, int /*height*/,
+                  const std::list<int>& /*initial_value*/,
+                  const std::string& /*name*/,
+                  const std::list<std::string>& /*prompt*/,
+                  const std::string& /*ok_string*/,
+                  const std::string& /*cancel_string*/)
+  {
+    return std::pair<std::list<int>, int> ();
+  }
+
+  virtual std::list<std::string>
+  do_input_dialog (const std::list<std::string>& /*prompt*/,
+                   const std::string& /*title*/,
+                   const std::list<float>& /*nr*/,
+                   const std::list<float>& /*nc*/,
+                   const std::list<std::string>& /*defaults*/)
+  {
+    return std::list<std::string> ();
+  }
+
+  typedef std::list<std::pair<std::string, std::string>> filter_list;
+
+  virtual std::list<std::string>
+  do_file_dialog (const filter_list& /*filter*/,
+                  const std::string& /*title*/,
+                  const std::string& /*filename*/,
+                  const std::string& /*dirname*/,
+                  const std::string& /*multimode*/)
+  {
+    return std::list<std::string> ();
+  }
+
+  virtual int
+  do_debug_cd_or_addpath_error (const std::string& /*file*/,
+                                const std::string& /*dir*/,
+                                bool /*addpath_option*/)
+  {
+    return -1;
+  }
+
+  virtual void do_change_directory (const std::string& /*dir*/) { }
+
+  virtual void do_file_remove (const std::string& /*old_name*/,
+                               const std::string& /*new_name*/)
+  { }
+
+  virtual void do_file_renamed (bool) { }
+
+  virtual void
+  do_execute_command_in_terminal (const std::string& /*command*/) { }
+
+  virtual uint8NDArray do_get_named_icon (const std::string& /*icon_name*/)
+  {
+    return uint8NDArray ();
+  }
+
+  virtual void do_set_workspace (bool /*top_level*/, bool /*debug*/,
+                                 const octave::symbol_info_list& /*syminfo*/,
+                                 bool /*update_variable_editor*/)
+  { }
+
+  virtual void do_clear_workspace (void) { }
+
+  virtual void do_set_history (const string_vector& /*hist*/) { }
+
+  virtual void do_append_history (const std::string& /*hist_entry*/) { }
+
+  virtual void do_clear_history (void) { }
+
+  virtual void do_pre_input_event (void) { }
+
+  virtual void do_post_input_event (void) { }
+
+  virtual void
+  do_enter_debugger_event (const std::string& /*file*/, int /*line*/) { }
+
+  virtual void
+  do_execute_in_debugger_event (const std::string& /*file*/, int /*line*/) { }
+
+  virtual void do_exit_debugger_event (void) { }
+
+  virtual void do_update_breakpoint (bool /*insert*/,
+                                     const std::string& /*file*/,
+                                     int /*line*/, const std::string& /*cond*/)
+  { }
+
+  virtual void do_show_preferences (void) { }
+
+  virtual std::string do_gui_preference (const std::string& /*key*/,
+                                         const std::string& /*value*/)
+  {
+    return "";
+  }
+
+  virtual void do_show_doc (const std::string& /*file*/) { }
+
+  virtual void do_register_doc (const std::string& /*file*/) { }
+
+  virtual void do_unregister_doc (const std::string& /*file*/) { }
+
+  virtual void do_edit_variable (const std::string& /*name*/,
+                                 const octave_value& /*val*/)
+  { }
+};
+
 //! Provides threadsafe access to octave.
 //! @author Jacob Dawid
 //!
@@ -68,25 +214,35 @@
 
   virtual ~octave_link (void);
 
+  static void connect_link (octave_link_events *obj);
+
+  static octave_link_events * disconnect_link (bool delete_instance = true);
+
+  static bool enable (void)
+  {
+    bool retval = link_enabled;
+    link_enabled = true;
+    return retval;
+  }
+
+  static bool disable (void)
+  {
+    bool retval = link_enabled;
+    link_enabled = false;
+    return retval;
+  }
+
+  static bool enabled (void)
+  {
+    return link_enabled;
+  }
+
   // If disable is TRUE, then no additional events will be processed
   // other than exit.
 
-  static void process_events (bool disable = false)
-  {
-    if (enabled ())
-      {
-        if (disable)
-          instance->do_disable ();
+  static void process_events (bool disable_arg = false);
 
-        instance->do_process_events ();
-      }
-  }
-
-  static void discard_events (void)
-  {
-    if (enabled ())
-      instance->do_discard_events ();
-  }
+  static void discard_events (void);
 
   static bool confirm_shutdown (void)
   {
@@ -103,7 +259,7 @@
   post_event (F&& fcn, Args&&... args)
   {
     if (enabled ())
-      instance->do_post_event (fcn, std::forward<Args> (args)...);
+      gui_event_queue.add (fcn, std::forward<Args> (args)...);
   }
 
   template <typename T, typename... Params, typename... Args>
@@ -111,14 +267,14 @@
   post_event (T *obj, void (T::*method) (Params...), Args&&... args)
   {
     if (enabled ())
-      instance->do_post_event (obj, method, std::forward<Args> (args)...);
+      gui_event_queue.add_method (obj, method, std::forward<Args> (args)...);
   }
 
   static void
   post_exception (const std::exception_ptr &p)
   {
     if (enabled ())
-      instance->do_post_exception (p);
+      post_event (&octave_link::rethrow_exception_callback, p);
   }
 
   static bool
@@ -240,7 +396,7 @@
                              bool update_variable_editor = true)
   {
     if (enabled ())
-      instance->do_set_workspace (top_level, instance->debugging, syminfo,
+      instance->do_set_workspace (top_level, debugging, syminfo,
                                   update_variable_editor);
   }
 
@@ -284,7 +440,7 @@
   {
     if (enabled ())
       {
-        instance->debugging = true;
+        debugging = true;
 
         instance->do_enter_debugger_event (file, line);
       }
@@ -298,9 +454,9 @@
 
   static void exit_debugger_event (void)
   {
-    if (enabled () && instance->debugging)
+    if (enabled () && debugging)
       {
-        instance->debugging = false;
+        debugging = false;
 
         instance->do_exit_debugger_event ();
       }
@@ -314,53 +470,6 @@
       instance->do_update_breakpoint (insert, file, line, cond);
   }
 
-  static void connect_link (octave_link *);
-
-  static octave_link * disconnect_link (bool delete_instance = true)
-  {
-    if (delete_instance)
-      {
-        delete instance;
-        instance = nullptr;
-        return nullptr;
-      }
-    else
-      {
-        octave_link *retval = instance;
-        instance = nullptr;
-        return retval;
-      }
-  }
-
-  static bool enable (void)
-  {
-    return instance_ok () ? instance->do_enable () : false;
-  }
-
-  static bool disable (void)
-  {
-    return instance_ok () ? instance->do_disable () : false;
-  }
-
-  bool do_enable (void)
-  {
-    bool retval = link_enabled;
-    link_enabled = true;
-    return retval;
-  }
-
-  bool do_disable (void)
-  {
-    bool retval = link_enabled;
-    link_enabled = false;
-    return retval;
-  }
-
-  static bool enabled (void)
-  {
-    return instance_ok () ? instance->link_enabled : false;
-  }
-
   static bool
   show_preferences ()
   {
@@ -436,139 +545,25 @@
 
 private:
 
-  static octave_link *instance;
+  static octave_link_events *instance;
 
   static bool instance_ok (void) { return instance != nullptr; }
 
 protected:
 
   // Semaphore to lock access to the event queue.
-  octave::mutex *event_queue_mutex;
+  static octave::mutex *event_queue_mutex;
 
   // Event Queue.
-  octave::event_queue gui_event_queue;
-
-  bool debugging;
-  bool link_enabled;
-
-  void do_process_events (void);
-  void do_discard_events (void);
+  static octave::event_queue gui_event_queue;
 
-  template <typename F, typename... Args>
-  void do_post_event (F&& fcn, Args&&... args)
-  {
-    gui_event_queue.add (fcn, std::forward<Args> (args)...);
-  }
+  static bool debugging;
+  static bool link_enabled;
 
-  template <typename T, typename... Params, typename... Args>
-  void do_post_event (T *obj, void (T::*method) (Params...), Args&&... args)
-  {
-    gui_event_queue.add_method (obj, method, std::forward<Args> (args)...);
-  }
-
-  void
-  rethrow_exception_callback (const std::exception_ptr &p)
+  static void rethrow_exception_callback (const std::exception_ptr &p)
   {
     std::rethrow_exception (p);
   }
-
-  void
-  do_post_exception (const std::exception_ptr &p)
-  {
-    do_post_event (this, &octave_link::rethrow_exception_callback, p);
-  }
-
-  void do_entered_readline_hook (void) { }
-  void do_finished_readline_hook (void) { }
-
-  virtual bool do_confirm_shutdown (void) = 0;
-
-  virtual bool do_copy_image_to_clipboard (const std::string& file) = 0;
-
-  virtual bool do_edit_file (const std::string& file) = 0;
-  virtual bool do_prompt_new_edit_file (const std::string& file) = 0;
-  virtual std::string
-  do_question_dialog (const std::string& msg, const std::string& title,
-                      const std::string& btn1, const std::string& btn2,
-                      const std::string& btn3, const std::string& btndef) = 0;
-
-  virtual std::pair<std::list<int>, int>
-  do_list_dialog (const std::list<std::string>& list,
-                  const std::string& mode,
-                  int width, int height,
-                  const std::list<int>& initial_value,
-                  const std::string& name,
-                  const std::list<std::string>& prompt,
-                  const std::string& ok_string,
-                  const std::string& cancel_string) = 0;
-
-  virtual std::list<std::string>
-  do_input_dialog (const std::list<std::string>& prompt,
-                   const std::string& title,
-                   const std::list<float>& nr,
-                   const std::list<float>& nc,
-                   const std::list<std::string>& defaults) = 0;
-
-  virtual std::list<std::string>
-  do_file_dialog (const filter_list& filter, const std::string& title,
-                  const std::string& filename, const std::string& dirname,
-                  const std::string& multimode) = 0;
-
-  virtual int
-  do_debug_cd_or_addpath_error (const std::string& file,
-                                const std::string& dir,
-                                bool addpath_option) = 0;
-
-  virtual void do_change_directory (const std::string& dir) = 0;
-
-  virtual void do_file_remove (const std::string& old_name,
-                               const std::string& new_name) = 0;
-  virtual void do_file_renamed (bool) = 0;
-
-  virtual void do_execute_command_in_terminal (const std::string& command) = 0;
-
-  virtual uint8NDArray
-  do_get_named_icon (const std::string& icon_name) = 0;
-
-  virtual void
-  do_set_workspace (bool top_level, bool debug,
-                    const octave::symbol_info_list& syminfo,
-                    bool update_variable_editor) = 0;
-
-  virtual void do_clear_workspace (void) = 0;
-
-  virtual void do_set_history (const string_vector& hist) = 0;
-  virtual void do_append_history (const std::string& hist_entry) = 0;
-  virtual void do_clear_history (void) = 0;
-
-  virtual void do_pre_input_event (void) = 0;
-  virtual void do_post_input_event (void) = 0;
-
-  virtual void
-  do_enter_debugger_event (const std::string& file, int line) = 0;
-
-  virtual void
-  do_execute_in_debugger_event (const std::string& file, int line) = 0;
-
-  virtual void do_exit_debugger_event (void) = 0;
-
-  virtual void do_update_breakpoint (bool insert,
-                                     const std::string& file, int line,
-                                     const std::string& cond) = 0;
-
-  virtual void do_show_preferences (void) = 0;
-
-  virtual std::string do_gui_preference (const std::string& key,
-                                         const std::string& value) = 0;
-
-  virtual void do_show_doc (const std::string& file) = 0;
-
-  virtual void do_register_doc (const std::string& file) = 0;
-
-  virtual void do_unregister_doc (const std::string& file) = 0;
-
-  virtual void
-  do_edit_variable (const std::string& name, const octave_value& val) = 0;
 };
 
 #endif