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
This commit is contained in:
Norman Feske 2024-09-19 18:00:38 +02:00 committed by Christian Helmuth
parent 58d20c7751
commit e69ade5299
4 changed files with 104 additions and 84 deletions

View File

@ -178,15 +178,15 @@
</dir>
<dir name="dev"> <log/> </dir>
</vfs>
<policy label="log" decoration="yes" motion="20"/>
<policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="20"/>
<policy label="log" decoration="yes" motion="40"/>
<policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="40"/>
<policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="40"/>
<policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="60"/>
<policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="40"/>
<policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="60"/>
<policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="60"/>
<policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="40"/>
<policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="40"/>
<policy label_prefix="logo" decoration="no"/>
<default-policy/>
</config>

View File

@ -17,6 +17,7 @@
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <gui_session/connection.h>
#include <timer_session/connection.h>
#include <os/pixel_rgb888.h>
#include <os/reporter.h>
@ -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<Main> _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;
}

View File

@ -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:

View File

@ -17,6 +17,7 @@
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
#include <timer_session/connection.h>
/* decorator includes */
#include <decorator/window_stack.h>
@ -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<Main> _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;
}