window layouter: fix glitch after window resize

This patch improves the transition from an interactive window geometry
change (dragging a window element) to the point where the resulting
new layout rules come into effect. During this short time, no resize
request must be issued because such a resize request would be based on
stale rules.

Fixes 
This commit is contained in:
Norman Feske 2019-03-14 14:15:58 +01:00 committed by Christian Helmuth
parent baf46db287
commit d75c5f6722
2 changed files with 48 additions and 3 deletions
repos/gems
recipes/src/window_layouter
src/app/window_layouter

@ -4,3 +4,4 @@ input_session
report_session
nitpicker_session
framebuffer_session
timer_session

@ -23,6 +23,7 @@
#include <input_session/client.h>
#include <input/event.h>
#include <input/keycodes.h>
#include <timer_session/connection.h>
/* local includes */
#include <window_list.h>
@ -45,6 +46,13 @@ struct Window_layouter::Main : Operations,
Signal_handler<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
Timer::Connection _drop_timer { _env };
bool _defer_layout_change = false;
Signal_handler<Main> _drop_timer_handler {
_env.ep(), *this, &Main::_handle_drop_timer };
Heap _heap { _env.ram(), _env.rm() };
Area _screen_size { };
@ -126,7 +134,24 @@ struct Window_layouter::Main : Operations,
/**
* Layout_rules::Change_handler interface
*/
void layout_rules_changed() override { _update_window_layout(); }
void layout_rules_changed() override
{
/*
* When re-importing rules generated by the drop operation, issue an
* updated resize request immediately instead of waiting for the
* '_drop_timer_handler'. Clear '_defer_layout_change' before calling
* '_update_window_layout' because '_gen_window_layout' evaluates
* this flag.
*/
bool const issue_resize_request = _defer_layout_change;
_defer_layout_change = false;
_update_window_layout();
if (issue_resize_request)
_gen_resize_request();
}
/**
* Window_list::Change_handler interface
@ -216,6 +241,12 @@ struct Window_layouter::Main : Operations,
_gen_resize_request();
}
void _handle_drop_timer()
{
/* discharge '_defer_layout_change' */
layout_rules_changed();
}
void finalize_drag(Window_id id, Window::Element, Point, Point) override
{
/*
@ -229,10 +260,15 @@ struct Window_layouter::Main : Operations,
_window_list.with_window(id, [&] (Window &window) {
window.finalize_drag_operation(); });
_gen_resize_request();
/*
* Mask the generation of resize requests until the updated rules are
* imported the next time. Discharge the masking after a timeout for
* the case where rules fixed and not fed back to the layouter.
*/
_defer_layout_change = true;
_drop_timer.trigger_once(250*1000);
}
/**
* Install handler for responding to hover changes
*/
@ -340,6 +376,8 @@ struct Window_layouter::Main : Operations,
_nitpicker.mode_sigh(_mode_change_handler);
_handle_mode_change();
_drop_timer.sigh(_drop_timer_handler);
_hover.sigh(_hover_handler);
_decorator_margins_rom.sigh(_decorator_margins_handler);
_input.sigh(_input_handler);
@ -360,6 +398,9 @@ struct Window_layouter::Main : Operations,
void Window_layouter::Main::_gen_window_layout()
{
if (_defer_layout_change)
return;
/* update hover and focus state of each window */
_window_list.for_each_window([&] (Window &window) {
@ -377,6 +418,9 @@ void Window_layouter::Main::_gen_window_layout()
void Window_layouter::Main::_gen_resize_request()
{
if (_defer_layout_change)
return;
bool resize_needed = false;
_window_list.for_each_window([&] (Window const &window) {
if (window.resize_request_needed())