Mercurial > octave
view libgui/src/octave-qobject.cc @ 31198:863730dd0f83 stable
nextpow2: Fix for input between 0.5 and 1 (bug #62947).
* scripts/general/nextpow2.m: Switch to a naïve implementation using log2 with
a single output argument and ceil.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Wed, 24 Aug 2022 17:15:34 +0200 |
parents | 7fe4b83eb425 |
children | 36dc11ee220d |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <utility> #include <QApplication> #include <QClipboard> #include <QFile> #include <QTextCodec> #include <QThread> #include <QTimer> #include <QTranslator> // QTerminal includes #include "QTerminal.h" #include "command-widget.h" #include "community-news.h" #include "documentation-dock-widget.h" #include "files-dock-widget.h" #include "history-dock-widget.h" #include "interpreter-qobject.h" #include "main-window.h" #include "octave-qobject.h" #include "qt-application.h" #include "qt-interpreter-events.h" #include "release-notes.h" #include "resource-manager.h" #include "shortcut-manager.h" #include "terminal-dock-widget.h" #include "variable-editor.h" #include "workspace-model.h" #include "workspace-view.h" // Bug #55940 (Disable App Nap on Mac) #if defined (Q_OS_MAC) # include <objc/runtime.h> # include <objc/message.h> #endif #include "interpreter.h" #include "oct-env.h" #include "version.h" #include "ovl.h" // Bug #55940 (Disable App Nap on Mac) #if defined (Q_OS_MAC) static void disable_app_nap (void) { Class process_info_class; SEL process_info_selector; SEL begin_activity_with_options_selector; id process_info; id reason_string; id osx_latencycritical_activity; // Option codes found at https://stackoverflow.com/questions/22784886/what-can-make-nanosleep-drift-with-exactly-10-sec-on-mac-os-x-10-9/32729281#32729281 unsigned long long NSActivityUserInitiatedAllowingIdleSystemSleep = 0x00FFFFFFULL; unsigned long long NSActivityLatencyCritical = 0xFF00000000ULL; // Avoid errors on older versions of OS X process_info_class = reinterpret_cast<Class> (objc_getClass ("NSProcessInfo")); if (process_info_class == nil) return; process_info_selector = sel_getUid ("processInfo"); if (class_getClassMethod (process_info_class, process_info_selector) == nullptr) return; begin_activity_with_options_selector = sel_getUid ("beginActivityWithOptions:reason:"); if (class_getInstanceMethod (process_info_class, begin_activity_with_options_selector) == nullptr) return; process_info = reinterpret_cast<id (*) (id, SEL)> (objc_msgSend) (reinterpret_cast<id> (process_info_class), process_info_selector); if (process_info == nil) return; reason_string = reinterpret_cast<id (*) (id, SEL)> (objc_msgSend) (reinterpret_cast<id> (objc_getClass ("NSString")), sel_getUid ("alloc")); reason_string = reinterpret_cast<id (*) (id, SEL, const char *)> (objc_msgSend) (reason_string, sel_getUid ("initWithUTF8String:"), "App Nap causes pause() malfunction"); // Start an Activity that suppresses App Nap. This Activity will run for // the entire duration of the Octave process. This is intentional, // not a leak. osx_latencycritical_activity = reinterpret_cast<id (*) (id, SEL, unsigned long long, id)> (objc_msgSend) (process_info, begin_activity_with_options_selector, NSActivityUserInitiatedAllowingIdleSystemSleep | NSActivityLatencyCritical, reason_string); } #endif namespace octave { // Disable all Qt messages by default. static void message_handler (QtMsgType, const QMessageLogContext&, const QString&) { } //! Reimplement QApplication::notify. Octave's own exceptions are //! caught and rethrown in the interpreter thread. bool octave_qapplication::notify (QObject *receiver, QEvent *ev) { try { return QApplication::notify (receiver, ev); } catch (execution_exception& ee) { emit interpreter_event ([=] (void) { // INTERPRETER THREAD throw ee; }); } return false; } // We will create a QApplication object, even if START_GUI is false, // so that we can use Qt widgets for plot windows when running in // command-line mode. Note that we are creating an // octave_qapplication object but handling it as a QApplication object // because the octave_qapplication should behave identically to a // QApplication object except that it overrides the notify method so // we can handle forward Octave interpreter exceptions from the GUI // thread to the interpreter thread. base_qobject::base_qobject (qt_application& app_context, bool gui_app) : QObject (), m_app_context (app_context), m_argc (m_app_context.sys_argc ()), m_argv (m_app_context.sys_argv ()), m_qapplication (new octave_qapplication (m_argc, m_argv)), m_resource_manager (), m_shortcut_manager (*this), m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()), m_qsci_tr (new QTranslator ()), m_translators_installed (false), m_qt_interpreter_events (new qt_interpreter_events (*this)), m_interpreter_qobj (new interpreter_qobject (*this)), m_main_thread (new QThread ()), m_gui_app (gui_app), m_interpreter_ready (false), m_workspace_model (new workspace_model ()), m_documentation_widget (), m_file_browser_widget (), m_history_widget (), m_workspace_widget (), m_editor_widget (), m_variable_editor_widget (), m_main_window (nullptr) { std::string show_gui_msgs = sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES"); // Installing our handler suppresses the messages. if (show_gui_msgs.empty ()) qInstallMessageHandler (message_handler); // Set the codec for all strings (before wizard or any GUI object) #if ! defined (Q_OS_WIN32) QTextCodec::setCodecForLocale (QTextCodec::codecForName ("UTF-8")); #endif // Initialize global Qt application metadata. QCoreApplication::setApplicationName ("GNU Octave"); QCoreApplication::setApplicationVersion (OCTAVE_VERSION); // Register octave_value_list for connecting thread crossing signals. qRegisterMetaType<octave_value_list> ("octave_value_list"); // Bug #55940 (Disable App Nap on Mac) #if defined (Q_OS_MAC) // Mac App Nap feature causes pause() and sleep() to misbehave. // Disable it for the entire program run. disable_app_nap (); #endif // Force left-to-right alignment (see bug #46204) m_qapplication->setLayoutDirection (Qt::LeftToRight); // Qt docs recommend using Qt::QueuedConnection when connecting to // the QCoreApplication::exit slot. connect (m_interpreter_qobj, &interpreter_qobject::shutdown_finished, m_qapplication, &octave_qapplication::exit, Qt::QueuedConnection); connect (m_interpreter_qobj, &interpreter_qobject::ready, this, &base_qobject::interpreter_ready); connect (m_main_thread, &QThread::finished, m_main_thread, &QThread::deleteLater); // Handle any interpreter_event signal from the octave_qapplication // object here. connect (m_qapplication, QOverload<const fcn_callback&>::of (&octave_qapplication::interpreter_event), this, QOverload<const fcn_callback&>::of (&base_qobject::interpreter_event)); connect (m_qapplication, QOverload<const meth_callback&>::of (&octave_qapplication::interpreter_event), this, QOverload<const meth_callback&>::of (&base_qobject::interpreter_event)); if (m_app_context.experimental_terminal_widget ()) { connect (qt_link (), &qt_interpreter_events::start_gui_signal, this, &base_qobject::start_gui); connect (qt_link (), &qt_interpreter_events::show_terminal_window_signal, this, &base_qobject::show_terminal_window); } connect (qt_link (), &qt_interpreter_events::copy_image_to_clipboard_signal, this, &base_qobject::copy_image_to_clipboard); connect (qt_link (), &qt_interpreter_events::show_documentation_signal, this, &base_qobject::show_documentation_window); connect (qt_link (), &qt_interpreter_events::show_file_browser_signal, this, &base_qobject::show_file_browser_window); connect (qt_link (), &qt_interpreter_events::show_command_history_signal, this, &base_qobject::show_command_history_window); connect (qt_link (), &qt_interpreter_events::show_workspace_signal, this, &base_qobject::show_workspace_window); connect (qt_link (), &qt_interpreter_events::edit_variable_signal, this, &base_qobject::show_variable_editor_window); connect (qt_link (), &qt_interpreter_events::show_community_news_signal, this, &base_qobject::show_community_news); connect (qt_link (), &qt_interpreter_events::show_release_notes_signal, this, &base_qobject::show_release_notes); if (m_app_context.experimental_terminal_widget ()) { m_qapplication->setQuitOnLastWindowClosed (false); } else { if (gui_app) { m_main_window = new main_window (*this); connect (m_main_window, &main_window::show_community_news_signal, this, &base_qobject::show_community_news); connect (m_main_window, &main_window::show_release_notes_signal, this, &base_qobject::show_release_notes); if (m_interpreter_ready) m_main_window->handle_octave_ready (); else connect (m_interpreter_qobj, &interpreter_qobject::ready, m_main_window, &main_window::handle_octave_ready); connect (qt_link (), &qt_interpreter_events::focus_window_signal, m_main_window, &main_window::focus_window); m_app_context.gui_running (true); } else { // Get settings file. m_resource_manager.reload_settings (); // After settings. config_translators (); // Initilize the shortcut-manager m_shortcut_manager.init_data (); m_qapplication->setQuitOnLastWindowClosed (false); } } start_main_thread (); } base_qobject::~base_qobject (void) { // Note that we don't delete m_main_thread here. That is handled by // deleteLater slot that is called when the m_main_thread issues a // finished signal. // FIXME: Why are dock widget settings and/or the main window // configuration not saved correctly if the main window is deleted // after the dock widgets? // Calling close will cause settings to be saved. // If m_main_window exists, the widgets are closed by the main window if (! m_main_window) { if (m_terminal_widget) m_terminal_widget->close (); if (m_documentation_widget) m_documentation_widget->close (); if (m_file_browser_widget) m_file_browser_widget->close (); if (m_history_widget) m_history_widget->close (); if (m_workspace_widget) m_workspace_widget->close (); if (m_editor_widget) m_editor_widget->close (); if (m_variable_editor_widget) m_variable_editor_widget->close (); if (m_community_news) m_community_news->close (); } else { delete m_main_window; } delete m_terminal_widget; delete m_documentation_widget; delete m_file_browser_widget; delete m_history_widget; delete m_workspace_widget; delete m_editor_widget; delete m_variable_editor_widget; delete m_community_news; delete m_interpreter_qobj; delete m_qsci_tr; delete m_gui_tr; delete m_qt_tr; delete m_qapplication; delete m_workspace_model; string_vector::delete_c_str_vec (m_argv); } void base_qobject::config_translators (void) { if (m_translators_installed) return; m_resource_manager.config_translators (m_qt_tr, m_qsci_tr, m_gui_tr); m_qapplication->installTranslator (m_qt_tr); m_qapplication->installTranslator (m_gui_tr); m_qapplication->installTranslator (m_qsci_tr); m_translators_installed = true; } void base_qobject::start_main_thread (void) { // Note: if using the new experimental terminal widget, we defer // initializing and executing the interpreter until the main event // loop begins executing. // With the old terminal widget, we defer initializing and executing // the interpreter until after the main window and QApplication are // running to prevent race conditions. QTimer::singleShot (0, m_interpreter_qobj, SLOT (execute (void))); m_interpreter_qobj->moveToThread (m_main_thread); m_main_thread->start (); } int base_qobject::exec (void) { int status = m_qapplication->exec (); #if defined (Q_OS_MAC) // fprintf to stderr is needed by macOS, for poorly-understood reasons. fprintf (stderr, "\n"); #endif m_main_thread->quit (); m_main_thread->wait (); return status; } // Provided for convenience. Will be removed once we eliminate the // old terminal widget. bool base_qobject::experimental_terminal_widget (void) const { return m_app_context.experimental_terminal_widget (); } bool base_qobject::gui_running (void) const { return m_app_context.gui_running (); } QPointer<terminal_dock_widget> base_qobject::terminal_widget (main_window *mw) { if (m_terminal_widget && mw) { m_terminal_widget->set_main_window (mw); m_terminal_widget->set_adopted (true); } else if (! m_terminal_widget) { m_terminal_widget = QPointer<terminal_dock_widget> (new terminal_dock_widget (mw, *this)); if (experimental_terminal_widget ()) { command_widget *cmd_widget = m_terminal_widget->get_command_widget (); connect (cmd_widget, &command_widget::interpreter_pause, this, &base_qobject::interpreter_pause); connect (cmd_widget, &command_widget::interpreter_resume, this, &base_qobject::interpreter_resume); connect (cmd_widget, &command_widget::interpreter_stop, this, &base_qobject::interpreter_stop); connect (qt_link (), &qt_interpreter_events::interpreter_output_signal, m_terminal_widget, &terminal_dock_widget::interpreter_output); connect (qt_link (), &qt_interpreter_events::update_prompt_signal, m_terminal_widget, &terminal_dock_widget::update_prompt); connect_interpreter_events (cmd_widget); } else { QTerminal *cmd_widget = m_terminal_widget->get_qterminal (); // Connect the interrupt signal (emitted by Ctrl-C) connect (cmd_widget, &QTerminal::interrupt_signal, this, &base_qobject::interpreter_interrupt); } } return m_terminal_widget; } QPointer<documentation_dock_widget> base_qobject::documentation_widget (main_window *mw) { if (m_documentation_widget && mw) { m_documentation_widget->set_main_window (mw); m_documentation_widget->set_adopted (true); } else if (! m_documentation_widget) { m_documentation_widget = QPointer<documentation_dock_widget> (new documentation_dock_widget (mw, *this)); connect (qt_link (), &qt_interpreter_events::register_documentation_signal, m_documentation_widget, &documentation_dock_widget::registerDoc); connect (qt_link (), &qt_interpreter_events::unregister_documentation_signal, m_documentation_widget, &documentation_dock_widget::unregisterDoc); } return m_documentation_widget; } QPointer<files_dock_widget> base_qobject::file_browser_widget (main_window *mw) { if (m_file_browser_widget) { m_file_browser_widget->set_main_window (mw); m_file_browser_widget->set_adopted (true); } else if (! m_file_browser_widget) m_file_browser_widget = QPointer<files_dock_widget> (new files_dock_widget (mw, *this)); connect (qt_link (), &qt_interpreter_events::directory_changed_signal, m_file_browser_widget, &files_dock_widget::update_octave_directory); return m_file_browser_widget; } QPointer<history_dock_widget> base_qobject::history_widget (main_window *mw) { if (m_history_widget) { m_history_widget->set_main_window (mw); m_history_widget->set_adopted (true); } else if (! m_history_widget) { m_history_widget = QPointer<history_dock_widget> (new history_dock_widget (mw, *this)); connect (qt_link (), &qt_interpreter_events::set_history_signal, m_history_widget, &history_dock_widget::set_history); connect (qt_link (), &qt_interpreter_events::append_history_signal, m_history_widget, &history_dock_widget::append_history); connect (qt_link (), &qt_interpreter_events::clear_history_signal, m_history_widget, &history_dock_widget::clear_history); emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD event_manager& xevmgr = interp.get_event_manager (); xevmgr.set_history (); }); } return m_history_widget; } QPointer<workspace_view> base_qobject::workspace_widget (main_window *mw) { if (m_workspace_widget) { m_workspace_widget->set_main_window (mw); m_workspace_widget->set_adopted (true); } else if (! m_workspace_widget) { m_workspace_widget = QPointer<workspace_view> (new workspace_view (mw, *this)); m_workspace_widget->setModel (m_workspace_model); connect (m_workspace_model, &workspace_model::model_changed, m_workspace_widget, &workspace_view::handle_model_changed); connect (qt_link (), &qt_interpreter_events::set_workspace_signal, m_workspace_model, &workspace_model::set_workspace); connect (qt_link (), &qt_interpreter_events::clear_workspace_signal, m_workspace_model, &workspace_model::clear_workspace); connect (m_workspace_widget, &workspace_view::copy_variable_value_to_clipboard, [=] (const QString& var_name) { emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD octave_value val = interp.varval (var_name.toStdString ()); if (val.is_undefined ()) val = 0; std::ostringstream buf; val.print_raw (buf, true); // FIXME: is the following operation thread safe or should // it be done with a signal/slot connection? QClipboard *clipboard = QApplication::clipboard (); clipboard->setText (QString::fromStdString (buf.str ())); }); }); connect (m_workspace_widget, &workspace_view::rename_variable_signal, [=] (const QString& old_name, const QString& new_name) { emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD symbol_scope scope = interp.get_current_scope (); if (scope) { scope.rename (old_name.toStdString (), new_name.toStdString ()); tree_evaluator& tw = interp.get_evaluator (); event_manager& xevmgr = interp.get_event_manager (); xevmgr.set_workspace (true, tw.get_symbol_info ()); } // FIXME: if this action fails, do we need a way to // display that info in the GUI? }); }); connect (m_workspace_widget, &workspace_view::edit_variable_signal, [=] (const QString& var_name) { emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD std::string name = var_name.toStdString (); octave_value val = interp.varval (name); event_manager& xevmgr = interp.get_event_manager (); xevmgr.edit_variable (name, val); }); }); emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD event_manager& xevmgr = interp.get_event_manager (); xevmgr.set_workspace (); }); } return m_workspace_widget; } QPointer<file_editor_interface> base_qobject::editor_widget (main_window */*mw*/) { #if 0 if (m_editor_widget && mw) { m_editor_widget->set_main_window (mw); m_editor_widget->set_adopted (true); } else if (! m_editor_widget) m_editor_widget = new file_editor (mw, *this); #endif return m_editor_widget; } QPointer<variable_editor> base_qobject::variable_editor_widget (main_window *mw) { if (m_variable_editor_widget && mw) { m_variable_editor_widget->set_main_window (mw); m_variable_editor_widget->set_adopted (true); } else if (! m_variable_editor_widget) { m_variable_editor_widget = QPointer<variable_editor> (new variable_editor (mw, *this)); connect (m_variable_editor_widget, &variable_editor::updated, this, &base_qobject::handle_variable_editor_update); connect (m_variable_editor_widget, &variable_editor::command_signal, this, &base_qobject::execute_command); connect (qt_link (), &qt_interpreter_events::refresh_variable_editor_signal, m_variable_editor_widget, &variable_editor::refresh); connect_interpreter_events<variable_editor> (m_variable_editor_widget); } return m_variable_editor_widget; } QPointer<community_news> base_qobject::community_news_widget (int serial) { if (! m_community_news) m_community_news = QPointer<community_news> (new community_news (*this, serial)); return m_community_news; } QPointer<release_notes> base_qobject::release_notes_widget (void) { if (! m_release_notes) m_release_notes = QPointer<release_notes> (new release_notes ()); return m_release_notes; } bool base_qobject::confirm_shutdown (void) { // Currently, we forward to main_window::confirm_shutdown instead of // just displaying a dialog box here because the main_window also // knows about and is responsible for notifying the editor. return m_main_window ? m_main_window->confirm_shutdown () : true; } void base_qobject::start_gui (bool gui_app) { if (m_app_context.experimental_terminal_widget ()) { if (m_main_window) return; m_gui_app = gui_app; m_main_window = new main_window (*this); connect (qt_link (), &qt_interpreter_events::focus_window_signal, m_main_window, &main_window::focus_window); connect (qt_link (), &qt_interpreter_events::close_gui_signal, this, &base_qobject::close_gui); connect (m_main_window, &main_window::close_gui_signal, this, &base_qobject::close_gui); connect (m_main_window, &main_window::show_community_news_signal, this, &base_qobject::show_community_news); connect (m_main_window, &main_window::show_release_notes_signal, this, &base_qobject::show_release_notes); if (m_interpreter_ready) m_main_window->handle_octave_ready (); else connect (m_interpreter_qobj, &interpreter_qobject::ready, m_main_window, &main_window::handle_octave_ready); if (m_gui_app) m_qapplication->setQuitOnLastWindowClosed (true); else { // FIXME: Save current values of PS1 and PS2 so they can be // restored when we return to the command line? } m_app_context.gui_running (true); } } void base_qobject::show_terminal_window (void) { terminal_dock_widget *widget = (m_terminal_widget ? m_terminal_widget : terminal_widget ()); if (! widget->isVisible ()) { widget->show (); widget->raise (); } } void base_qobject::show_documentation_window (const QString& file) { documentation_dock_widget *widget = (m_documentation_widget ? m_documentation_widget : documentation_widget ()); widget->showDoc (file); if (! widget->isVisible ()) { widget->show (); widget->raise (); } } void base_qobject::show_file_browser_window (void) { files_dock_widget *widget = m_file_browser_widget ? m_file_browser_widget : file_browser_widget (); if (! widget->isVisible ()) { widget->show (); widget->raise (); } } void base_qobject::show_command_history_window (void) { history_dock_widget *widget = m_history_widget ? m_history_widget : history_widget (); if (! widget->isVisible ()) { widget->show (); widget->raise (); } } void base_qobject::show_workspace_window (void) { workspace_view *widget = m_workspace_widget ? m_workspace_widget : workspace_widget (); if (! widget->isVisible ()) { widget->show (); widget->raise (); } } void base_qobject::show_variable_editor_window (const QString& name, const octave_value& value) { variable_editor *widget = (m_variable_editor_widget ? m_variable_editor_widget : variable_editor_widget ()); if (! widget->isVisible ()) { widget->show (); widget->raise (); } // FIXME: Should this be done with a signal/slot connection? widget->edit_variable (name, value); } void base_qobject::handle_variable_editor_update (void) { // Called when the variable editor emits the updated signal. The size // of a variable may have changed, so we refresh the workspace in the // interpreter. That will eventually cause the workspace view in the // GUI to be updated. interpreter_event ([] (interpreter& interp) { // INTERPRETER THREAD tree_evaluator& tw = interp.get_evaluator (); event_manager& xevmgr = interp.get_event_manager (); xevmgr.set_workspace (true, tw.get_symbol_info (), false); }); } void base_qobject::show_community_news (int serial) { // Ensure widget exists. community_news_widget (serial); m_community_news->display (); } void base_qobject::show_release_notes (void) { // Ensure widget exists. release_notes_widget (); m_release_notes->display (); } void base_qobject::execute_command (const QString& command) { emit interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD // FIXME: Do we need to do anything special about errors here? // Currently the eval function will just call error() in the // interpreter event loop and throw an execution error. It will // be caught, so shouldn't crash the interpreter, but the // message may not go anywhere useful depending on how the GUI // is being used or if Octave running server mode. interp.eval (command.toStdString (), 0); }); } void base_qobject::close_gui (void) { if (m_app_context.experimental_terminal_widget ()) { if (! m_main_window) return; // FIXME: Restore previous values of PS1 and PS2 if we are // returning to the command line? interpreter_event ([=] (interpreter& interp) { // INTERPRETER THREAD application *app = interp.get_app_context (); cmdline_options opts = app->options (); if (opts.gui ()) interp.quit (0, false, false); }); m_app_context.gui_running (false); if (m_main_window) { m_main_window->deleteLater (); m_main_window = nullptr; } } } void base_qobject::interpreter_ready (void) { m_interpreter_ready = true; } void base_qobject::interpreter_event (const fcn_callback& fcn) { // The following is a direct function call across threads. It works // because 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 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::interpreter_interrupt (void) { m_interpreter_qobj->interrupt (); } // FIXME: Should we try to make the pause, stop, and resume actions // work for both the old and new terminal widget? void base_qobject::interpreter_pause (void) { if (m_app_context.experimental_terminal_widget ()) m_interpreter_qobj->pause (); } void base_qobject::interpreter_stop (void) { if (m_app_context.experimental_terminal_widget ()) m_interpreter_qobj->stop (); } void base_qobject::interpreter_resume (void) { if (m_app_context.experimental_terminal_widget ()) m_interpreter_qobj->resume (); } void base_qobject::copy_image_to_clipboard (const QString& file, bool remove_file) { QClipboard *clipboard = QApplication::clipboard (); QImage img (file); if (img.isNull ()) { // Report error? return; } clipboard->setImage (img); if (remove_file) QFile::remove (file); } }