diff --git a/ChangeLog b/ChangeLog index e5bfbfd5..51cb29a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-08-15 Markus Gans + * The call of the function setNonBlockingRead() resulted in + a high CPU load in idle mode. + Thanks to Pavel Stehule for reporting this problem. + 2020-08-11 Markus Gans * New callback backend was implemented. Callback functions with any number of arguments are now possible. diff --git a/src/fapplication.cpp b/src/fapplication.cpp index 1cd5382c..24b61449 100644 --- a/src/fapplication.cpp +++ b/src/fapplication.cpp @@ -20,9 +20,11 @@ * . * ***********************************************************************/ +#include #include #include #include +#include #include "final/fapplication.h" #include "final/fevent.h" @@ -61,7 +63,8 @@ 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}; - +uInt64 FApplication::next_event_wait{50000}; // preset to 50 ms +struct timeval FApplication::time_last_event{}; //---------------------------------------------------------------------- // class FApplication @@ -330,6 +333,7 @@ void FApplication::closeConfirmationDialog (FWidget* w, FCloseEvent* ev) void FApplication::processExternalUserEvent() { // This method can be overloaded and replaced by own code + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } @@ -337,6 +341,10 @@ void FApplication::processExternalUserEvent() //---------------------------------------------------------------------- void FApplication::init() { + // Initialize the last event time + time_last_event.tv_sec = 0; + time_last_event.tv_usec = 0; + // Initialize keyboard keyboard = FTerm::getFKeyboard(); @@ -1207,21 +1215,19 @@ void FApplication::processResizeEvent() const //---------------------------------------------------------------------- void FApplication::processCloseWidget() { + if ( ! getWidgetCloseList() || getWidgetCloseList()->empty() ) + return; + setTerminalUpdates (FVTerm::stop_terminal_updates); + auto iter = getWidgetCloseList()->begin(); - if ( getWidgetCloseList() && ! getWidgetCloseList()->empty() ) + while ( iter != getWidgetCloseList()->end() && *iter ) { - auto iter = getWidgetCloseList()->begin(); - - while ( iter != getWidgetCloseList()->end() && *iter ) - { - delete *iter; - ++iter; - } - - getWidgetCloseList()->clear(); + delete *iter; + ++iter; } + getWidgetCloseList()->clear(); setTerminalUpdates (FVTerm::start_terminal_updates); } @@ -1243,12 +1249,18 @@ bool FApplication::processNextEvent() { uInt num_events{0}; - processKeyboardEvent(); - processMouseEvent(); - processResizeEvent(); - processTerminalUpdate(); - processCloseWidget(); - processLogger(); + if ( isNextEventTimeout() ) + { + FObject::getCurrentTime (&time_last_event); + processKeyboardEvent(); + processMouseEvent(); + processResizeEvent(); + processTerminalUpdate(); + processCloseWidget(); + processLogger(); + updateTerminal(); + } + processExternalUserEvent(); sendQueuedEvents(); @@ -1318,4 +1330,10 @@ bool FApplication::isEventProcessable ( const FObject* receiver return true; } +//---------------------------------------------------------------------- +bool FApplication::isNextEventTimeout() +{ + return FObject::isTimeout (&time_last_event, next_event_wait); +} + } // namespace finalcut diff --git a/src/fkeyboard.cpp b/src/fkeyboard.cpp index 84fb8687..049f9907 100644 --- a/src/fkeyboard.cpp +++ b/src/fkeyboard.cpp @@ -44,7 +44,9 @@ namespace finalcut // static class attributes uInt64 FKeyboard::read_blocking_time{100000}; // preset to 100 ms uInt64 FKeyboard::key_timeout{100000}; // preset to 100 ms +uInt64 FKeyboard::interval_timeout{75000}; // preset to 75 ms struct timeval FKeyboard::time_keypressed{}; +struct timeval FKeyboard::time_last_request{}; #if defined(__linux__) FTermLinux* FKeyboard::linux{nullptr}; @@ -62,6 +64,8 @@ FKeyboard::FKeyboard() // Initialize keyboard values time_keypressed.tv_sec = 0; time_keypressed.tv_usec = 0; + time_last_request.tv_sec = 0; + time_last_request.tv_usec = 0; // Get the stdin file status flags stdin_status_flags = fcntl(FTermios::getStdIn(), F_GETFL); @@ -117,6 +121,9 @@ bool& FKeyboard::unprocessedInput() //---------------------------------------------------------------------- bool FKeyboard::isKeyPressed() const { + if ( ! isIntervalTimeout() ) + return false; + fd_set ifds{}; struct timeval tv{}; const int stdin_no = FTermios::getStdIn(); @@ -125,6 +132,7 @@ bool FKeyboard::isKeyPressed() const FD_SET(stdin_no, &ifds); tv.tv_sec = 0; tv.tv_usec = suseconds_t(read_blocking_time); // preset to 100 ms + FObject::getCurrentTime (&time_last_request); const int result = select (stdin_no + 1, &ifds, nullptr, nullptr, &tv); if ( result > 0 && FD_ISSET(stdin_no, &ifds) ) @@ -351,11 +359,17 @@ bool FKeyboard::setNonBlockingInput (bool enable) } //---------------------------------------------------------------------- -bool FKeyboard::isKeypressTimeout() +inline bool FKeyboard::isKeypressTimeout() { return FObject::isTimeout (&time_keypressed, key_timeout); } +//---------------------------------------------------------------------- +inline bool FKeyboard::isIntervalTimeout() +{ + return FObject::isTimeout (&time_last_request, interval_timeout); +} + //---------------------------------------------------------------------- FKey FKeyboard::UTF8decode (const char utf8[]) const { diff --git a/src/fmessagebox.cpp b/src/fmessagebox.cpp index f46498f2..1e720423 100644 --- a/src/fmessagebox.cpp +++ b/src/fmessagebox.cpp @@ -278,7 +278,7 @@ inline void FMessageBox::deallocation() //---------------------------------------------------------------------- inline void FMessageBox::initCallbacks() { - if ( button_digit[0] != 0 ) + if ( button[0] && button_digit[0] != 0 ) { button[0]->addCallback ( @@ -288,7 +288,7 @@ inline void FMessageBox::initCallbacks() ); } - if ( button_digit[1] != 0 ) + if ( button[1] && button_digit[1] != 0 ) { button[1]->addCallback ( @@ -298,7 +298,7 @@ inline void FMessageBox::initCallbacks() ); } - if ( button_digit[2] != 0 ) + if ( button[2] && button_digit[2] != 0 ) { button[2]->addCallback ( diff --git a/src/fspinbox.cpp b/src/fspinbox.cpp index 8ce5e3e6..38d74290 100644 --- a/src/fspinbox.cpp +++ b/src/fspinbox.cpp @@ -429,7 +429,7 @@ void FSpinBox::forceFocus() } //---------------------------------------------------------------------- -void FSpinBox::cb_inputFieldActivate() +void FSpinBox::cb_inputFieldActivate() const { processActivate(); } diff --git a/src/fstring.cpp b/src/fstring.cpp index fff47f25..b2b3f819 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -380,19 +380,7 @@ const FString& FString::operator () () const //---------------------------------------------------------------------- std::size_t FString::getUTF8length() const { - if ( ! string ) - return 0; - - std::size_t len{0}; - const char* s = c_str(); - - while ( *s ) - { - len += std::size_t((*s & 0xc0) != 0x80); - s++; - } - - return len; + return length; } //---------------------------------------------------------------------- diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 41255d54..99f40a7c 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -56,11 +56,13 @@ bool FVTerm::force_terminal_update{false}; bool FVTerm::no_terminal_updates{false}; bool FVTerm::cursor_hideable{false}; int FVTerm::skipped_terminal_update{}; +uInt64 FVTerm::term_size_check_timeout{500000}; // 500 ms uInt FVTerm::erase_char_length{}; uInt FVTerm::repeat_char_length{}; uInt FVTerm::clr_bol_length{}; uInt FVTerm::clr_eol_length{}; uInt FVTerm::cursor_address_length{}; +struct timeval FVTerm::last_term_size_check{}; std::queue* FVTerm::output_buffer{nullptr}; FPoint* FVTerm::term_pos{nullptr}; FSystem* FVTerm::fsystem{nullptr}; @@ -1968,6 +1970,10 @@ void FVTerm::init() createArea (term_geometry, shadow_size, vdesktop); vdesktop->visible = true; active_area = vdesktop; + + // Initialize the last terminal size check time + last_term_size_check.tv_sec = 0; + last_term_size_check.tv_usec = 0; } //---------------------------------------------------------------------- @@ -2899,6 +2905,11 @@ bool FVTerm::isInsideTerminal (const FPoint& pos) const //---------------------------------------------------------------------- inline bool FVTerm::isTermSizeChanged() const { + if ( ! isTermSizeCheckTimeout() ) + return false; + + FObject::getCurrentTime (&last_term_size_check); + const auto& data = FTerm::getFTermData(); if ( ! data ) @@ -2915,6 +2926,12 @@ inline bool FVTerm::isTermSizeChanged() const return false; } +//---------------------------------------------------------------------- +inline bool FVTerm::isTermSizeCheckTimeout() +{ + return FObject::isTimeout (&last_term_size_check, term_size_check_timeout); +} + //---------------------------------------------------------------------- inline void FVTerm::markAsPrinted (uInt pos, uInt line) { diff --git a/src/include/final/fapplication.h b/src/include/final/fapplication.h index fc7c0b76..f6706974 100644 --- a/src/include/final/fapplication.h +++ b/src/include/final/fapplication.h @@ -198,6 +198,7 @@ class FApplication : public FWidget bool processNextEvent(); void performTimerAction (FObject*, FEvent*) override; static bool isEventProcessable (const FObject*, const FEvent*); + static bool isNextEventTimeout(); // Data members int app_argc{}; @@ -205,6 +206,8 @@ class FApplication : public FWidget uInt64 key_timeout{100000}; // 100 ms uInt64 dblclick_interval{500000}; // 500 ms FEventQueue event_queue{}; + static uInt64 next_event_wait; + static timeval time_last_event; static int quit_code; static bool quit_now; static int loop_level; diff --git a/src/include/final/fcallback.h b/src/include/final/fcallback.h index 1afa8339..0eb5d9f9 100644 --- a/src/include/final/fcallback.h +++ b/src/include/final/fcallback.h @@ -55,13 +55,20 @@ struct FCallbackData FCallbackData() { } - FCallbackData (const FString& s, FWidget* i, void* m, const FCall& c) + template + FCallbackData (const FString& s, FWidget* i, FuncPtr m, const FCall& c) : cb_signal(s) , cb_instance(i) , cb_function_ptr(m) , cb_function(c) { } + FCallbackData (const FCallbackData&) = default; + FCallbackData (FCallbackData&&) = default; + + FCallbackData& operator = (const FCallbackData&) = default; + FCallbackData& operator = (FCallbackData&&) = default; + // Data members FString cb_signal{}; FWidget* cb_instance{}; @@ -77,6 +84,53 @@ struct FCallbackData class FCallback { public: + // Using-declaration + template + using ObjectPointer = + typename std::enable_if< ! std::is_member_function_pointer::value + && ! std::is_function::type>::value + && ! std::is_function::value + && std::is_pointer::value + && std::is_object::value + && ! std::is_class::value + , std::nullptr_t >; + template + using ClassObject = + typename std::enable_if< ! std::is_member_function_pointer::value + && ! std::is_function::type>::value + && ! std::is_function::value + && ! std::is_pointer::value + && std::is_object::value + && std::is_class::value + , std::nullptr_t >; + template + using MemberFunctionPointer = + typename std::enable_if< std::is_member_function_pointer::value + && ! std::is_function::type>::value + && ! std::is_function::value + && ! std::is_pointer::value + && std::is_object::value + && ! std::is_class::value + , std::nullptr_t >; + template + using FunctionPointer = + typename std::enable_if< ! std::is_member_function_pointer::value + && std::is_function::type>::value + && ! std::is_function::value + && std::is_pointer::value + && std::is_object::value + && ! std::is_class::value + , std::nullptr_t >; + template + using FunctionReference = + typename std::enable_if< ! std::is_member_function_pointer::value + && std::is_function::type>::value + && std::is_function::value + && ! std::is_pointer::value + && ! std::is_object::value + && ! std::is_class::value + , std::nullptr_t >; + // Constructors FCallback(); @@ -103,19 +157,8 @@ class FCallback // Methods template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - && std::is_member_function_pointer::value - && ! std::is_function::type>::value - && ! std::is_function::value - && ! std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr + , typename ObjectPointer::type = nullptr + , typename MemberFunctionPointer::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Object&& cb_instance @@ -125,29 +168,17 @@ class FCallback // Add a member function pointer as callback Object instance = cb_instance; - auto member = reinterpret_cast(std::addressof(cb_member)); auto fn = std::bind ( std::forward(cb_member) , std::forward(cb_instance) , std::forward(args)... ); - FCallbackData obj{ cb_signal, instance, member, fn }; + FCallbackData obj{ cb_signal, instance, nullptr, fn }; callback_objects.push_back(obj); } template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - && ! std::is_member_function_pointer::value - && ! std::is_function::type>::value - && ! std::is_function::value - && ! std::is_pointer::value - && std::is_object::value - && std::is_class::value - , std::nullptr_t >::type = nullptr + , typename ObjectPointer::type = nullptr + , typename ClassObject::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Object&& cb_instance @@ -162,13 +193,7 @@ class FCallback } template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && ! std::is_pointer::value - && std::is_object::value - && std::is_class::value - , std::nullptr_t >::type = nullptr + , typename ClassObject::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function&& cb_function @@ -183,13 +208,7 @@ class FCallback } template::value - && std::is_function::type>::value - && std::is_function::value - && ! std::is_pointer::value - && ! std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr + , typename FunctionReference::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function& cb_function @@ -204,14 +223,8 @@ class FCallback } template::value - && std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr - , typename... Args> + , typename FunctionPointer::type = nullptr + , typename... Args> void addCallback ( const FString& cb_signal , Function&& cb_function , Args&&... args) @@ -226,13 +239,7 @@ class FCallback } template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && ! std::is_pointer::value - && std::is_object::value - && std::is_class::value - , std::nullptr_t >::type = nullptr + , typename ClassObject::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function& cb_function @@ -246,13 +253,7 @@ class FCallback } template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr > + , typename ObjectPointer::type = nullptr> void delCallback (Object&& cb_instance) { // Deletes entries with the given instance from the callback list @@ -290,13 +291,7 @@ class FCallback } template::value - && ! std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr > + , typename ObjectPointer::type = nullptr> void delCallback (const FString& cb_signal, Object&& cb_instance) { // Deletes entries with the given signal and instance @@ -318,13 +313,7 @@ class FCallback } template::value - && std::is_function::type>::value - && ! std::is_function::value - && std::is_pointer::value - && std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr > + , typename FunctionPointer::type = nullptr> void delCallback (FunctionPtr&& cb_func_ptr) { // Deletes entries with the given function pointer @@ -346,13 +335,7 @@ class FCallback } template::value - && std::is_function::type>::value - && std::is_function::value - && ! std::is_pointer::value - && ! std::is_object::value - && ! std::is_class::value - , std::nullptr_t >::type = nullptr > + , typename FunctionReference::type = nullptr> void delCallback (Function& cb_function) { // Deletes entries with the given function from the callback list diff --git a/src/include/final/fkeyboard.h b/src/include/final/fkeyboard.h index 3a6b3b58..6f090aa7 100644 --- a/src/include/final/fkeyboard.h +++ b/src/include/final/fkeyboard.h @@ -148,6 +148,7 @@ class FKeyboard final // Inquiry static bool isKeypressTimeout(); + static bool isIntervalTimeout(); // Methods FKey UTF8decode (const char[]) const; @@ -171,8 +172,10 @@ class FKeyboard final #endif static timeval time_keypressed; + static timeval time_last_request; static uInt64 read_blocking_time; static uInt64 key_timeout; + static uInt64 interval_timeout; fc::FKeyMap* key_map{nullptr}; FKey key{0}; uChar read_character{}; diff --git a/src/include/final/fspinbox.h b/src/include/final/fspinbox.h index ba979458..08ffffd7 100644 --- a/src/include/final/fspinbox.h +++ b/src/include/final/fspinbox.h @@ -140,7 +140,7 @@ class FSpinBox : public FWidget void forceFocus(); // Callback methods - void cb_inputFieldActivate(); + void cb_inputFieldActivate() const; void cb_inputFieldChange (const FLineEdit&); // Data members diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index 21a34177..a7c2da6d 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -408,6 +408,7 @@ class FVTerm bool updateTerminalCursor() const; bool isInsideTerminal (const FPoint&) const; bool isTermSizeChanged() const; + static bool isTermSizeCheckTimeout(); static void markAsPrinted (uInt, uInt); static void markAsPrinted (uInt, uInt, uInt); static void newFontChanges (FChar*&); @@ -437,10 +438,12 @@ class FVTerm static FChar i_ch; // inherit background character static FPoint* term_pos; // terminal cursor position static FKeyboard* keyboard; + static timeval last_term_size_check; static bool terminal_update_complete; static bool terminal_update_pending; static bool force_terminal_update; static bool no_terminal_updates; + static uInt64 term_size_check_timeout; static int skipped_terminal_update; static uInt erase_char_length; static uInt repeat_char_length;