/*********************************************************************** * fapplication.cpp - Manages the application events * * * * This file is part of the Final Cut widget toolkit * * * * Copyright 2013-2020 Markus Gans * * * * The Final Cut is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * The Final Cut 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 Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program. If not, see * * . * ***********************************************************************/ #include #include #include #include "final/fapplication.h" #include "final/fevent.h" #include "final/flog.h" #include "final/flogger.h" #include "final/fmenu.h" #include "final/fmenubar.h" #include "final/fmessagebox.h" #include "final/fmouse.h" #include "final/fstartoptions.h" #include "final/fstatusbar.h" #include "final/ftermdata.h" #include "final/ftermios.h" #include "final/fwidgetcolors.h" #include "final/fwindow.h" namespace finalcut { // Global application object static FApplication* app_object{nullptr}; // Flag to exit the local event loop static bool app_exit_loop{false}; // Static attributes FWidget* FWidget::main_widget {nullptr}; // main application widget FWidget* FWidget::active_window {nullptr}; // the active window FWidget* FWidget::focus_widget {nullptr}; // has keyboard input focus FWidget* FWidget::clicked_widget {nullptr}; // is focused by click FWidget* FWidget::open_menu {nullptr}; // currently open menu FWidget* FWidget::move_size_widget {nullptr}; // move/size by keyboard FWidget* FApplication::keyboard_widget {nullptr}; // has the keyboard focus FKeyboard* FApplication::keyboard {nullptr}; // keyboard access FMouseControl* FApplication::mouse {nullptr}; // mouse control int FApplication::loop_level {0}; // event loop level int FApplication::quit_code {EXIT_SUCCESS}; bool FApplication::quit_now {false}; //---------------------------------------------------------------------- // class FApplication //---------------------------------------------------------------------- // constructors and destructor //---------------------------------------------------------------------- FApplication::FApplication (const int& _argc, char* _argv[]) : FWidget{processParameters(_argc, _argv)} , app_argc{_argc} , app_argv{_argv} { if ( quit_now ) return; if ( app_object ) { auto ftermdata = FTerm::getFTermData(); ftermdata->setExitMessage("FApplication: There should be " "only one application object"); FApplication::exit(EXIT_FAILURE); return; } // First define the application object app_object = this; if ( ! (_argc && _argv) ) { static char empty_str[1] = ""; app_argc = 0; app_argv = reinterpret_cast(&empty_str); } init(); } //---------------------------------------------------------------------- FApplication::~FApplication() // destructor { app_object = nullptr; if ( eventInQueue() ) event_queue.clear(); destroyLog(); } // public methods of FApplication //---------------------------------------------------------------------- FApplication* FApplication::getApplicationObject() { return app_object; } //---------------------------------------------------------------------- FApplication::FLogPtr& FApplication::getLog() { // Global logger object static FLogPtr* logger = new FLogPtr(); if ( logger && logger->get() == nullptr ) *logger = std::make_shared(); return *logger; } //---------------------------------------------------------------------- void FApplication::setLog (const FLogPtr& logger) { getLog() = logger; } //---------------------------------------------------------------------- bool FApplication::isQuit() { return ( app_object ) ? quit_now : true; } //---------------------------------------------------------------------- int FApplication::exec() // run { if ( quit_now ) { quit_now = false; return quit_code; } quit_code = EXIT_SUCCESS; enterLoop(); return quit_code; } //---------------------------------------------------------------------- int FApplication::enterLoop() // event loop { loop_level++; quit_now = false; const bool old_app_exit_loop = app_exit_loop; app_exit_loop = false; while ( ! (quit_now || app_exit_loop) ) processNextEvent(); app_exit_loop = old_app_exit_loop; loop_level--; return 0; } //---------------------------------------------------------------------- void FApplication::exitLoop() { app_exit_loop = true; } //---------------------------------------------------------------------- void FApplication::exit (int retcode) { quit_now = true; quit_code = retcode; } //---------------------------------------------------------------------- void FApplication::quit() { FApplication::exit(0); } //---------------------------------------------------------------------- bool FApplication::sendEvent (FObject* receiver, FEvent* event ) { if ( quit_now || app_exit_loop || ! (bool(receiver) && bool(event)) ) return false; if ( ! isEventProcessable (receiver, event) ) return false; // Sends the event event directly to receiver bool ret = receiver->event(event); event->send = true; return ret; } //---------------------------------------------------------------------- void FApplication::queueEvent (FObject* receiver, FEvent* event) { if ( ! (bool(receiver) && bool(event)) ) return; // queue this event event->queued = true; event_queue.emplace_back (receiver, event); } //---------------------------------------------------------------------- void FApplication::sendQueuedEvents() { while ( eventInQueue() ) { const EventPair& event_pair = event_queue.front(); event_pair.second->queued = false; sendEvent(event_pair.first, event_pair.second); event_queue.pop_front(); } } //---------------------------------------------------------------------- bool FApplication::eventInQueue() { if ( app_object ) return ( ! event_queue.empty() ); else return false; } //---------------------------------------------------------------------- bool FApplication::removeQueuedEvent (const FObject* receiver) { if ( ! eventInQueue() ) return false; if ( ! receiver ) return false; bool retval{false}; auto iter = event_queue.begin(); while ( iter != event_queue.end() ) { if ( iter->first == receiver ) { iter = event_queue.erase(iter); retval = true; } else ++iter; } return retval; } //---------------------------------------------------------------------- void FApplication::initTerminal() { if ( ! isQuit() ) FWidget::initTerminal(); } //---------------------------------------------------------------------- void FApplication::setDefaultTheme() { if ( FTerm::getMaxColor() < 16 ) // for 8 color mode { if ( getStartOptions().color_change ) FTerm::setColorPaletteTheme(); setColorTheme(); } else { if ( getStartOptions().color_change ) FTerm::setColorPaletteTheme(); setColorTheme(); } } //---------------------------------------------------------------------- void FApplication::setDarkTheme() { if ( getStartOptions().color_change ) FTerm::setColorPaletteTheme(); if ( FTerm::getMaxColor() < 16 ) // for 8 color mode setColorTheme(); else setColorTheme(); } //---------------------------------------------------------------------- void FApplication::closeConfirmationDialog (FWidget* w, FCloseEvent* ev) { app_object->unsetMoveSizeMode(); const int ret = FMessageBox::info ( w, "Quit" , "Do you really want\n" "to quit the program ?" , FMessageBox::Yes , FMessageBox::No ); if ( ret == FMessageBox::Yes ) ev->accept(); else { ev->ignore(); // Status bar restore after closing the FMessageBox if ( getStatusBar() ) getStatusBar()->drawMessage(); } } // protected methods of FApplication //---------------------------------------------------------------------- void FApplication::processExternalUserEvent() { // This method can be overloaded and replaced by own code } // private methods of FApplication //---------------------------------------------------------------------- void FApplication::init() { // Initialize keyboard keyboard = FTerm::getFKeyboard(); // Set the keyboard keypress timeout if ( keyboard ) { auto cmd1 = std::bind(&FApplication::keyPressed, this); auto cmd2 = std::bind(&FApplication::keyReleased, this); auto cmd3 = std::bind(&FApplication::escapeKeyPressed, this); FKeyboardCommand key_cmd1 (cmd1); FKeyboardCommand key_cmd2 (cmd2); FKeyboardCommand key_cmd3 (cmd3); keyboard->setPressCommand (key_cmd1); keyboard->setReleaseCommand (key_cmd2); keyboard->setEscPressedCommand (key_cmd3); keyboard->setKeypressTimeout (key_timeout); } // Initialize mouse control mouse = FTerm::getFMouseControl(); // Set stdin number for a gpm-mouse if ( mouse ) mouse->setStdinNo (FTermios::getStdIn()); // Set the default double click interval if ( mouse ) mouse->setDblclickInterval (dblclick_interval); // Initialize logging if ( ! getStartOptions().logfile_stream.is_open() ) getLog()->setLineEnding(FLog::CRLF); } //---------------------------------------------------------------------- void FApplication::setTerminalEncoding (const FString& enc_str) { const FString& enc = enc_str.toLower(); if ( enc.includes("utf8") ) getStartOptions().encoding = fc::UTF8; else if ( enc.includes("vt100") ) getStartOptions().encoding = fc::VT100; else if ( enc.includes("pc") ) getStartOptions().encoding = fc::PC; else if ( enc.includes("ascii") ) getStartOptions().encoding = fc::ASCII; else if ( enc.includes("help") ) showParameterUsage(); else { auto ftermdata = FTerm::getFTermData(); ftermdata->setExitMessage ( "Unknown encoding \"" + enc_str + "\"\n(Valid encodings are utf8, " + "vt100, pc and ascii)" ); exit(EXIT_FAILURE); } } //---------------------------------------------------------------------- void FApplication::setLogFile (const FString& filename) { auto& log_stream = getStartOptions().logfile_stream; log_stream.open(filename, std::ofstream::out); if ( log_stream.is_open() ) { // Get the global logger object FLog& log = *FApplication::getLog(); log.setOutputStream(log_stream); log.enableTimestamp(); log.setLineEnding (finalcut::FLog::LF); } else { auto ftermdata = FTerm::getFTermData(); ftermdata->setExitMessage ( "Could not open log file \"" + filename + "\"" ); exit(EXIT_FAILURE); } } //---------------------------------------------------------------------- void FApplication::cmd_options (const int& argc, char* argv[]) { // Interpret the command line options while ( true ) { static struct option long_options[] = { {"encoding", required_argument, nullptr, 0 }, {"log-file", required_argument, nullptr, 0 }, {"no-mouse", no_argument, nullptr, 0 }, {"no-optimized-cursor", no_argument, nullptr, 0 }, {"no-terminal-detection", no_argument, nullptr, 0 }, {"no-terminal-data-request", no_argument, nullptr, 0 }, {"no-color-change", no_argument, nullptr, 0 }, {"no-sgr-optimizer", no_argument, nullptr, 0 }, {"vgafont", no_argument, nullptr, 0 }, {"newfont", no_argument, nullptr, 0 }, {"dark-theme", no_argument, nullptr, 0 }, #if defined(__FreeBSD__) || defined(__DragonFly__) {"no-esc-for-alt-meta", no_argument, nullptr, 0 }, {"no-cursorstyle-change", no_argument, nullptr, 0 }, #elif defined(__NetBSD__) || defined(__OpenBSD__) {"no-esc-for-alt-meta", no_argument, nullptr, 0 }, #endif {nullptr, 0, nullptr, 0 } }; opterr = 0; int idx{0}; const int c = getopt_long (argc, argv, "", long_options, &idx); if ( c == -1 ) break; if ( c == 0 ) { if ( std::strcmp(long_options[idx].name, "encoding") == 0 ) setTerminalEncoding(FString(optarg)); if ( std::strcmp(long_options[idx].name, "log-file") == 0 ) setLogFile(FString(optarg)); if ( std::strcmp(long_options[idx].name, "no-mouse") == 0 ) getStartOptions().mouse_support = false; if ( std::strcmp(long_options[idx].name, "no-optimized-cursor") == 0 ) getStartOptions().cursor_optimisation = false; if ( std::strcmp(long_options[idx].name, "no-terminal-detection") == 0 ) getStartOptions().terminal_detection = false; if ( std::strcmp(long_options[idx].name, "no-terminal-data-request") == 0 ) getStartOptions().terminal_data_request = false; if ( std::strcmp(long_options[idx].name, "no-color-change") == 0 ) getStartOptions().color_change = false; if ( std::strcmp(long_options[idx].name, "no-sgr-optimizer") == 0 ) getStartOptions().sgr_optimizer = false; if ( std::strcmp(long_options[idx].name, "vgafont") == 0 ) getStartOptions().vgafont = true; if ( std::strcmp(long_options[idx].name, "newfont") == 0 ) getStartOptions().newfont = true; if ( std::strcmp(long_options[idx].name, "dark-theme") == 0 ) getStartOptions().dark_theme = true; #if defined(__FreeBSD__) || defined(__DragonFly__) if ( std::strcmp(long_options[idx].name, "no-esc-for-alt-meta") == 0 ) getStartOptions().meta_sends_escape = false; if ( std::strcmp(long_options[idx].name, "no-cursorstyle-change") == 0 ) getStartOptions().change_cursorstyle = false; #elif defined(__NetBSD__) || defined(__OpenBSD__) if ( std::strcmp(long_options[idx].name, "no-esc-for-alt-meta") == 0 ) getStartOptions().meta_sends_escape = false; #endif } } } //---------------------------------------------------------------------- inline FStartOptions& FApplication::getStartOptions() { return FStartOptions::getFStartOptions(); } //---------------------------------------------------------------------- void FApplication::showParameterUsage() { std::cout \ << "Generic options:\n" << " -h, --help " << " Display this help and exit\n" << "\n" << "The Final Cut options:\n" << " --encoding= " << " Sets the character encoding mode\n" << " " << " {utf8, vt100, pc, ascii}\n" << " --log-file= " << " Writes log output to FILE\n" << " --no-mouse " << " Disable mouse support\n" << " --no-optimized-cursor " << " Disable cursor optimization\n" << " --no-terminal-detection " << " Disable terminal detection\n" << " --no-terminal-data-request" << " Do not determine terminal font and title\n" << " --no-color-change " << " Do not redefine the color palette\n" << " --no-sgr-optimizer " << " Do not optimize SGR sequences\n" << " --vgafont " << " Set the standard vga 8x16 font\n" << " --newfont " << " Enables the graphical font\n" << " --dark-theme " << " Enables the dark theme\n" #if defined(__FreeBSD__) || defined(__DragonFly__) << "\n" << "FreeBSD console options:\n" << " --no-esc-for-alt-meta " << " Do not send a ESC prefix for the alt/meta key\n" << " --no-cursorstyle-change " << " Do not change the current cursor style\n" #elif defined(__NetBSD__) || defined(__OpenBSD__) << "\n" << "NetBSD/OpenBSD console options:\n" << " --no-esc-for-alt-meta " << " Do not send a ESC prefix for the alt/meta key\n" #endif << std::endl; // newline character + flushes the output stream } //---------------------------------------------------------------------- inline void FApplication::destroyLog() { const FLogPtr* logger = &(getLog()); delete logger; } //---------------------------------------------------------------------- inline void FApplication::findKeyboardWidget() { // Find the widget that has the keyboard focus FWidget* widget{nullptr}; auto focus = getFocusWidget(); auto move_size = getMoveSizeWidget(); if ( focus ) { if ( move_size ) widget = move_size; else widget = focus; } else { widget = getMainWidget(); if ( widget && widget->numOfChildren() >= 1 ) widget->focusFirstChild(); } keyboard_widget = widget; } //---------------------------------------------------------------------- inline bool FApplication::isKeyPressed() const { if ( mouse && mouse->isGpmMouseEnabled() ) return mouse->getGpmKeyPressed(keyboard->unprocessedInput()); return keyboard->isKeyPressed(); } //---------------------------------------------------------------------- void FApplication::keyPressed() { performKeyboardAction(); } //---------------------------------------------------------------------- void FApplication::keyReleased() { sendKeyUpEvent (keyboard_widget); } //---------------------------------------------------------------------- void FApplication::escapeKeyPressed() { sendEscapeKeyPressEvent(); } //---------------------------------------------------------------------- inline void FApplication::performKeyboardAction() { switch ( keyboard->getKey() ) { case fc::Fckey_l: // Ctrl-L (redraw the screen) redraw(); break; case fc::Fkey_mouse: if ( mouse ) { FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); mouse->setRawData (FMouse::x11, buffer); keyboard->unprocessedInput() = mouse->isInputDataPending(); processMouseEvent(); } break; case fc::Fkey_extended_mouse: if ( mouse ) { FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); mouse->setRawData (FMouse::sgr, buffer); keyboard->unprocessedInput() = mouse->isInputDataPending(); processMouseEvent(); } break; case fc::Fkey_urxvt_mouse: if ( mouse ) { FKeyboard::keybuffer& buffer = keyboard->getKeyBuffer(); mouse->setRawData (FMouse::urxvt, buffer); keyboard->unprocessedInput() = mouse->isInputDataPending(); processMouseEvent(); } break; default: const bool acceptKeyDown = sendKeyDownEvent (keyboard_widget); const bool acceptKeyPress = sendKeyPressEvent (keyboard_widget); if ( ! (acceptKeyDown || acceptKeyPress) ) sendKeyboardAccelerator(); break; } } //---------------------------------------------------------------------- inline void FApplication::sendEscapeKeyPressEvent() { // Send an escape key press event FKeyEvent k_press_ev (fc::KeyPress_Event, fc::Fkey_escape); sendEvent (keyboard_widget, &k_press_ev); } //---------------------------------------------------------------------- inline bool FApplication::sendKeyDownEvent (FWidget* widget) { // Send key down event FKeyEvent k_down_ev (fc::KeyDown_Event, keyboard->getKey()); sendEvent (widget, &k_down_ev); return k_down_ev.isAccepted(); } //---------------------------------------------------------------------- inline bool FApplication::sendKeyPressEvent (FWidget* widget) { // Send key press event FKeyEvent k_press_ev (fc::KeyPress_Event, keyboard->getKey()); sendEvent (widget, &k_press_ev); return k_press_ev.isAccepted(); } //---------------------------------------------------------------------- inline bool FApplication::sendKeyUpEvent (FWidget* widget) { // Send key up event FKeyEvent k_up_ev (fc::KeyUp_Event, keyboard->getKey()); sendEvent (widget, &k_up_ev); return k_up_ev.isAccepted(); } //---------------------------------------------------------------------- inline void FApplication::sendKeyboardAccelerator() { if ( FWidget::getOpenMenu() ) return; // Switch to a specific dialog with Meta + 1..9 bool accpt = processDialogSwitchAccelerator(); // Windows keyboard accelerator if ( ! accpt ) { auto window = static_cast(getActiveWindow()); if ( window ) accpt = processAccelerator (window); } // Global keyboard accelerator if ( ! accpt ) { auto root_widget = static_cast(getRootWidget()); if ( root_widget ) processAccelerator (root_widget); } } //---------------------------------------------------------------------- void FApplication::processKeyboardEvent() { if ( quit_now || app_exit_loop ) return; findKeyboardWidget(); flush(); keyboard->escapeKeyHandling(); // special case: Esc key keyboard->clearKeyBufferOnTimeout(); if ( isKeyPressed() ) keyboard->fetchKeyCode(); } //---------------------------------------------------------------------- bool FApplication::processDialogSwitchAccelerator() { if ( keyboard->getKey() >= fc::Fmkey_1 && keyboard->getKey() <= fc::Fmkey_9 ) { const FKey key = keyboard->getKey(); const std::size_t n = key - fc::Fmkey_0; const std::size_t s = getDialogList()->size(); if ( s > 0 && s >= n ) { // unset the move/size mode auto move_size = getMoveSizeWidget(); if ( move_size ) { auto w = move_size; setMoveSizeWidget(nullptr); w->redraw(); } FAccelEvent a_ev (fc::Accelerator_Event, getFocusWidget()); sendEvent (getDialogList()->at(n - 1), &a_ev); return true; } } return false; } //---------------------------------------------------------------------- bool FApplication::processAccelerator (const FWidget* const& widget) { bool accpt{false}; if ( widget && ! widget->getAcceleratorList().empty() ) { auto iter = widget->getAcceleratorList().begin(); const auto& last = widget->getAcceleratorList().end(); while ( iter != last && ! quit_now && ! app_exit_loop ) { if ( iter->key == keyboard->getKey() ) { // unset the move/size mode auto move_size = getMoveSizeWidget(); if ( move_size ) { auto w = move_size; setMoveSizeWidget(nullptr); w->redraw(); } FAccelEvent a_ev (fc::Accelerator_Event, getFocusWidget()); sendEvent (iter->object, &a_ev); accpt = a_ev.isAccepted(); break; } ++iter; } } return accpt; } //---------------------------------------------------------------------- bool FApplication::getMouseEvent() { bool mouse_event_occurred{false}; if ( mouse && mouse->hasData() ) { struct timeval* time_keypressed = keyboard->getKeyPressedTime(); mouse->processEvent (time_keypressed); keyboard->unprocessedInput() = mouse->isInputDataPending(); mouse_event_occurred = mouse->hasEvent(); } return mouse_event_occurred; } //---------------------------------------------------------------------- FWidget*& FApplication::determineClickedWidget() { FWidget*& clicked = FWidget::getClickedWidget(); if ( clicked || ! mouse ) return clicked; if ( ! mouse->isLeftButtonPressed() && ! mouse->isLeftButtonDoubleClick() && ! mouse->isRightButtonPressed() && ! mouse->isMiddleButtonPressed() && ! mouse->isWheelUp() && ! mouse->isWheelDown() ) return clicked; auto mouse_position = mouse->getPos(); // Determine the window object on the current click position auto window = FWindow::getWindowWidgetAt (mouse_position); if ( window ) { // Determine the widget at the current click position auto child = window->childWidgetAt (mouse_position); clicked = ( child != nullptr ) ? child : window; setClickedWidget (clicked); } return clicked; } //---------------------------------------------------------------------- void FApplication::unsetMoveSizeMode() { // Unset the move/size mode auto move_size = getMoveSizeWidget(); if ( move_size ) { auto w = move_size; setMoveSizeWidget(nullptr); w->redraw(); } } //---------------------------------------------------------------------- void FApplication::closeDropDown() { // Close the open menu if ( ! mouse || mouse->isMoved() ) return; auto mouse_position = mouse->getPos(); finalcut::closeDropDown (this, mouse_position); } //---------------------------------------------------------------------- void FApplication::unselectMenubarItems() { // Unselect the menu bar items const auto& openmenu = FWidget::getOpenMenu(); auto menu_bar = FWidget::getMenuBar(); if ( openmenu || (mouse && mouse->isMoved()) ) return; if ( ! (menu_bar && menu_bar->hasSelectedItem() && mouse) ) return; const auto& mouse_position = mouse->getPos(); if ( ! menu_bar->getTermGeometry().contains(mouse_position) ) { if ( FWidget::getStatusBar() ) FWidget::getStatusBar()->clearMessage(); menu_bar->resetMenu(); menu_bar->redraw(); // No widget was been clicked if ( ! FWidget::getClickedWidget() ) FWindow::switchToPrevWindow(this); if ( FWidget::getStatusBar() ) FWidget::getStatusBar()->drawMessage(); updateTerminal(); flush(); } } //---------------------------------------------------------------------- void FApplication::sendMouseEvent() { auto clicked = FWidget::getClickedWidget(); if ( ! (clicked && mouse) ) return; const auto& mouse_position = mouse->getPos(); int key_state{0}; if ( mouse->isShiftKeyPressed() ) key_state |= fc::ShiftButton; if ( mouse->isControlKeyPressed() ) key_state |= fc::ControlButton; if ( mouse->isMetaKeyPressed() ) key_state |= fc::MetaButton; const auto& widgetMousePos = clicked->termToWidgetPos(mouse_position); if ( mouse->isMoved() ) { sendMouseMoveEvent (widgetMousePos, mouse_position, key_state); } else { sendMouseLeftClickEvent (widgetMousePos, mouse_position, key_state); sendMouseRightClickEvent (widgetMousePos, mouse_position, key_state); sendMouseMiddleClickEvent (widgetMousePos, mouse_position, key_state); } sendWheelEvent (widgetMousePos, mouse_position); mouse->clearEvent(); } //---------------------------------------------------------------------- void FApplication::sendMouseMoveEvent ( const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) { if ( ! mouse ) return; auto clicked = FWidget::getClickedWidget(); if ( mouse->isLeftButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); sendEvent (clicked, &m_down_ev); } if ( mouse->isRightButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); sendEvent (clicked, &m_down_ev); } if ( mouse->isMiddleButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseMove_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); sendEvent (clicked, &m_down_ev); } } //---------------------------------------------------------------------- void FApplication::sendMouseLeftClickEvent ( const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) { if ( ! mouse ) return; auto clicked = FWidget::getClickedWidget(); if ( mouse->isLeftButtonDoubleClick() ) { FMouseEvent m_dblclick_ev ( fc::MouseDoubleClick_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); sendEvent (clicked, &m_dblclick_ev); } else if ( mouse->isLeftButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); sendEvent (clicked, &m_down_ev); } else if ( mouse->isLeftButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::LeftButton | key_state ); auto released_widget = clicked; if ( ! mouse->isRightButtonPressed() && ! mouse->isMiddleButtonPressed() ) setClickedWidget(nullptr); sendEvent (released_widget, &m_up_ev); } } //---------------------------------------------------------------------- void FApplication::sendMouseRightClickEvent ( const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) { if ( ! mouse ) return; auto clicked = FWidget::getClickedWidget(); if ( mouse->isRightButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); sendEvent (clicked, &m_down_ev); } else if ( mouse->isRightButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::RightButton | key_state ); auto released_widget = clicked; if ( ! mouse->isLeftButtonPressed() && ! mouse->isMiddleButtonPressed() ) setClickedWidget(nullptr); sendEvent (released_widget, &m_up_ev); } } //---------------------------------------------------------------------- void FApplication::sendMouseMiddleClickEvent ( const FPoint& widgetMousePos , const FPoint& mouse_position , int key_state ) { if ( ! mouse ) return; auto clicked = FWidget::getClickedWidget(); if ( mouse->isMiddleButtonPressed() ) { FMouseEvent m_down_ev ( fc::MouseDown_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); sendEvent (clicked, &m_down_ev); // gnome-terminal sends no released on middle click if ( FTerm::isGnomeTerminal() ) setClickedWidget(nullptr); } else if ( mouse->isMiddleButtonReleased() ) { FMouseEvent m_up_ev ( fc::MouseUp_Event , widgetMousePos , mouse_position , fc::MiddleButton | key_state ); auto released_widget = clicked; if ( ! mouse->isLeftButtonPressed() && ! mouse->isRightButtonPressed() ) { setClickedWidget(nullptr); } sendEvent (released_widget, &m_up_ev); } } //---------------------------------------------------------------------- void FApplication::sendWheelEvent ( const FPoint& widgetMousePos , const FPoint& mouse_position ) { if ( ! mouse ) return; auto clicked = FWidget::getClickedWidget(); if ( mouse->isWheelUp() ) { FWheelEvent wheel_ev ( fc::MouseWheel_Event , widgetMousePos , mouse_position , fc::WheelUp ); auto scroll_over_widget = clicked; setClickedWidget(nullptr); sendEvent(scroll_over_widget, &wheel_ev); } if ( mouse->isWheelDown() ) { FWheelEvent wheel_ev ( fc::MouseWheel_Event , widgetMousePos , mouse_position , fc::WheelDown ); auto scroll_over_widget = clicked; setClickedWidget(nullptr); sendEvent (scroll_over_widget, &wheel_ev); } } //---------------------------------------------------------------------- FWidget* FApplication::processParameters (const int& argc, char* argv[]) { if ( argc > 0 && argv[1] && ( std::strcmp(argv[1], "--help") == 0 || std::strcmp(argv[1], "-h") == 0 ) ) { showParameterUsage(); FApplication::exit(EXIT_SUCCESS); } cmd_options (argc, argv); return nullptr; } //---------------------------------------------------------------------- void FApplication::processMouseEvent() { if ( ! getMouseEvent() ) return; determineClickedWidget(); unsetMoveSizeMode(); closeDropDown(); unselectMenubarItems(); sendMouseEvent(); if ( mouse ) mouse->drawGpmPointer(); } //---------------------------------------------------------------------- void FApplication::processResizeEvent() { if ( ! FTerm::hasChangedTermSize() ) return; if ( mouse ) { mouse->setMaxWidth (uInt16(getDesktopWidth())); mouse->setMaxHeight (uInt16(getDesktopHeight())); } FResizeEvent r_ev(fc::Resize_Event); sendEvent(app_object, &r_ev); if ( r_ev.isAccepted() ) FTerm::changeTermSizeFinished(); } //---------------------------------------------------------------------- void FApplication::processCloseWidget() { setTerminalUpdates (FVTerm::stop_terminal_updates); if ( getWidgetCloseList() && ! getWidgetCloseList()->empty() ) { auto iter = getWidgetCloseList()->begin(); while ( iter != getWidgetCloseList()->end() && *iter ) { delete *iter; ++iter; } getWidgetCloseList()->clear(); } setTerminalUpdates (FVTerm::start_terminal_updates); } //---------------------------------------------------------------------- void FApplication::processLogger() { // Synchronizing the stream buffer with the logging output auto logger = getLog(); if ( ! logger->str().empty() ) logger->pubsync(); logger->flush(); } //---------------------------------------------------------------------- bool FApplication::processNextEvent() { uInt num_events{0}; processKeyboardEvent(); processMouseEvent(); processResizeEvent(); processTerminalUpdate(); processCloseWidget(); processLogger(); processExternalUserEvent(); sendQueuedEvents(); num_events += processTimerEvent(); return ( num_events > 0 ); } //---------------------------------------------------------------------- void FApplication::performTimerAction (FObject* receiver, FEvent* event) { sendEvent (receiver, event); } //---------------------------------------------------------------------- bool FApplication::isEventProcessable ( const FObject* receiver , const FEvent* event ) { if ( ! receiver->isWidget() ) // No restrictions for non-widgets return true; const auto widget = static_cast(receiver); if ( getModalDialogCounter() > 0 ) { const FWidget* window; if ( widget->isWindowWidget() ) window = widget; else window = FWindow::getWindowWidget(widget); // block events for widgets in non modal windows if ( window && ! window->getFlags().modal && ! window->isMenuWidget() ) { switch ( uInt(event->getType()) ) { case fc::KeyPress_Event: case fc::KeyUp_Event: case fc::KeyDown_Event: case fc::MouseDown_Event: case fc::MouseUp_Event: case fc::MouseDoubleClick_Event: case fc::MouseWheel_Event: case fc::MouseMove_Event: case fc::FocusIn_Event: case fc::FocusOut_Event: case fc::ChildFocusIn_Event: case fc::ChildFocusOut_Event: case fc::Accelerator_Event: return false; default: break; } } } // Throw away mouse events for disabled widgets if ( event->getType() >= fc::MouseDown_Event && event->getType() <= fc::MouseMove_Event && ! widget->isEnabled() ) return false; return true; } } // namespace finalcut