# HG changeset patch # User John W. Eaton # Date 1564411384 14400 # Node ID 5f170ea12fa1cd918f933baede252705a391624b # Parent a2b1ba6c92d51286c934931ebd04991bca8ccd45 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. diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/graphics/GLCanvas.cc --- 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 (); diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/documentation-dock-widget.cc --- 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 { diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/files-dock-widget.cc --- 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 #include +#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) diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/interpreter-qobject.cc --- 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. diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/interpreter-qobject.h --- 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 +#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 m_qt_link; }; } diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/m-editor/file-editor-tab.cc --- 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"); diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/m-editor/file-editor-tab.h --- 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 diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/m-editor/file-editor.cc --- 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 (); diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/main-window.cc --- 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)); }); } - } diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/main-window.h --- 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 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 dock_widget_list (void); - + void update_default_encoding (const QString& default_encoding); base_qobject& m_octave_qobj; diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/octave-dock-widget.cc --- 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"), diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/octave-dock-widget.h --- 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 #include +#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); diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/octave-qobject.cc --- 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); diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/octave-qobject.h --- 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 #include +#include "interpreter-qobject.h" + // Defined for purposes of sending QList as part of signal. typedef QList 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; diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/qt-interpreter-events.cc --- 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"); qRegisterMetaType ("symbol_info_list"); + + qRegisterMetaType ("fcn_callback"); + qRegisterMetaType ("meth_callback"); } bool qt_interpreter_events::confirm_shutdown (void) diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/variable-editor-model.cc --- 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); }); } diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/variable-editor-model.h --- 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 #include +#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 { diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libgui/src/variable-editor.cc --- 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 diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libinterp/corefcn/event-manager.cc --- 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); } diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libinterp/corefcn/event-manager.h --- 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 #include #include #include @@ -41,6 +42,9 @@ namespace octave { + typedef std::function fcn_callback; + typedef std::function 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 - void post_event (F&& fcn, Args&&... args) + void post_event (const fcn_callback& fcn) { if (enabled ()) - gui_event_queue.add (fcn, std::forward (args)...); + gui_event_queue.add (fcn); } - template - 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)...); - } - - 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); - } }; } diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libinterp/corefcn/interpreter-private.h --- 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. diff -r a2b1ba6c92d5 -r 5f170ea12fa1 libinterp/corefcn/interpreter.cc --- 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),