From e69ade529909ac752fd9bad2221e82786769ed93 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 19 Sep 2024 18:00:38 +0200 Subject: [PATCH] decorator: use timer for animation timing This patch changes the precision of the configuration's motion attribute to a multiple of 10 ms (centi-seconds). The previous version used steps of 20 ms. Hence, one needs to adjust existing configurations by doubling the motion attribute values of the themed decorator. Issue #5347 --- repos/gems/sculpt/leitzentrale/default | 18 ++-- repos/gems/src/app/decorator/main.cc | 91 ++++++++++--------- repos/gems/src/app/decorator/window_element.h | 4 +- repos/gems/src/app/themed_decorator/main.cc | 75 ++++++++------- 4 files changed, 104 insertions(+), 84 deletions(-) diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index 13c7801756..b4919bc8f6 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -178,15 +178,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/repos/gems/src/app/decorator/main.cc b/repos/gems/src/app/decorator/main.cc index 43c284bf8e..a696b4cc38 100644 --- a/repos/gems/src/app/decorator/main.cc +++ b/repos/gems/src/app/decorator/main.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,18 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Gui::Connection _gui { _env }; struct Canvas @@ -104,33 +117,31 @@ struct Decorator::Main : Window_factory_base Animator _animator { }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; - - /** - * Install handler for responding to GUI sync events - */ - void _handle_gui_sync(); - - void _trigger_sync_handling() - { - _gui.framebuffer.sync_sigh(_gui_sync_handler); - } + Ticks _previous_sync { }; Signal_handler
_gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; + void _handle_gui_sync(); + + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() + { + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + if (idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } + } + Heap _heap { _env.ram(), _env.rm() }; Attached_rom_dataspace _config { _env, "config" }; @@ -267,16 +278,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -300,31 +310,30 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI - * sync signal occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; + if (model_updated || windows_animated) { - Dirty_rect dirty = _window_stack.draw(_canvas->canvas); + Dirty_rect dirty = _window_stack.draw(_canvas->canvas); - _window_stack.update_gui_views(); + _window_stack.update_gui_views(); - _gui.execute(); + _gui.execute(); - dirty.flush([&] (Rect const &r) { - _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + dirty.flush([&] (Rect const &r) { + _gui.framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); }); + } /* * Disable sync handling when becoming idle */ - if (!_animator.active()) + if (!_animator.active()) { _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + + _previous_sync = now; } diff --git a/repos/gems/src/app/decorator/window_element.h b/repos/gems/src/app/decorator/window_element.h index 6865fb5f17..d51cf99b71 100644 --- a/repos/gems/src/app/decorator/window_element.h +++ b/repos/gems/src/app/decorator/window_element.h @@ -99,10 +99,10 @@ class Decorator::Window_element : public Animator::Item /* medium fade-in when gaining the focus or hover highlight */ if ((!_state.focused && state.focused) || (!_state.highlighted && state.highlighted)) - return 15; + return 30; /* slow fade-out when leaving focus or hover highlight */ - return 20; + return 40; } public: diff --git a/repos/gems/src/app/themed_decorator/main.cc b/repos/gems/src/app/themed_decorator/main.cc index 5361aa819f..5bcbe84687 100644 --- a/repos/gems/src/app/themed_decorator/main.cc +++ b/repos/gems/src/app/themed_decorator/main.cc @@ -17,6 +17,7 @@ #include #include #include +#include /* decorator includes */ #include @@ -36,6 +37,18 @@ struct Decorator::Main : Window_factory_base { Env &_env; + Timer::Connection _timer { _env }; + + /* + * Time base for animations, which are computed in steps of 10 ms + */ + struct Ticks { uint64_t cs; /* centi-seconds (10 ms) */ }; + + Ticks _now() + { + return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 }; + } + Window_stack _window_stack = { *this }; /** @@ -77,19 +90,7 @@ struct Decorator::Main : Window_factory_base Reporter _decorator_margins_reporter = { _env, "decorator_margins" }; - /** - * Process the update every 'frame_period' GUI sync signals. The - * 'frame_cnt' holds the counter of the GUI sync signals. - * - * A lower 'frame_period' value makes the decorations more responsive - * but it also puts more load on the system. - * - * If the GUI sync signal fires every 10 milliseconds, a - * 'frame_period' of 2 results in an update rate of 1000/20 = 50 frames per - * second. - */ - unsigned _frame_cnt = 0; - unsigned _frame_period = 2; + Ticks _previous_sync { }; /** * Install handler for responding to GUI sync events @@ -99,9 +100,22 @@ struct Decorator::Main : Window_factory_base Signal_handler
_gui_sync_handler = { _env.ep(), *this, &Main::_handle_gui_sync }; - void _trigger_sync_handling() + bool _gui_sync_enabled = false; + + void _trigger_gui_sync() { - _gui.framebuffer.sync_sigh(_gui_sync_handler); + Ticks const now = _now(); + bool const idle = now.cs - _previous_sync.cs > 3; + + if (!_gui_sync_enabled) { + _gui.framebuffer.sync_sigh(_gui_sync_handler); + _gui_sync_enabled = true; + } + + if (idle) { + _previous_sync = now; + _gui_sync_handler.local_submit(); + } } Attached_rom_dataspace _config { _env, "config" }; @@ -141,7 +155,7 @@ struct Decorator::Main : Window_factory_base Genode::log("pointer information unavailable"); } - _trigger_sync_handling(); + _trigger_gui_sync(); _hover_reporter.enabled(true); @@ -252,16 +266,15 @@ void Decorator::Main::_handle_window_layout_update() _window_layout_update_needed = true; - _trigger_sync_handling(); + _trigger_gui_sync(); } void Decorator::Main::_handle_gui_sync() { - if (_frame_cnt++ < _frame_period) - return; + Ticks const now = _now(); - _frame_cnt = 0; + Ticks const passed_ticks { now.cs - _previous_sync.cs }; bool model_updated = false; @@ -286,25 +299,23 @@ void Decorator::Main::_handle_gui_sync() bool const windows_animated = _window_stack.schedule_animated_windows(); - /* - * To make the perceived animation speed independent from the setting of - * 'frame_period', we update the animation as often as the GUI sync signal - * occurs. - */ - for (unsigned i = 0; i < _frame_period; i++) + for (unsigned i = 0; i < passed_ticks.cs; i++) _animator.animate(); - if (!model_updated && !windows_animated) - return; - - _window_stack.update_gui_views(); - _gui.execute(); + if (model_updated || windows_animated) { + _window_stack.update_gui_views(); + _gui.execute(); + } /* * Disable sync handling when becoming idle */ - if (!_animator.active()) + if (!_animator.active()) { _gui.framebuffer.sync_sigh(Signal_context_capability()); + _gui_sync_enabled = false; + } + + _previous_sync = now; }