mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-23 04:25:21 +00:00
window layouter: reduce snap-back artifact
When resizing windows of clients that respond very slowly to resize requests, the window's size sometimes snapped back to its original size immediately after finishing the drag operation. The problem was caused by the interplay of the layout rules (obtained via the 'rules' ROM, generated by the 'rules' report) and the temporary interactive state that occurs during drag operations. The rules are updated only at the time of releasing the button to keep the overhead while dragging the window low. However, when releasing the mouse, the (now outdated) rules kicked back into effect, triggering resize requests for the window to its old size. The patch solves this problem by decoupling the dragged state of a window from the physical release of the button. The button release triggers a transition from a DRAGGING to a SETTLING state and programs a timer. In the SETTLING state, the windows behave as in DRAGGING state, giving the interactive geometry precedence over the rules-dictated geometry. During this state, further responses of window-resize requests may come in and are handled like dragging was still in progress. After a timeout, however, the current window layout is conserved as a new rules report and the state goes back to IDLE. For clients that takes a very long time (in particular, VirtualBox when resizing the desktop, which takes sometimes multiple seconds), the snap-back artifact can still occur, but the effect is reduced.
This commit is contained in:
parent
48a361107f
commit
7e7eff0eb7
@ -48,7 +48,9 @@ struct Window_layouter::Main : Operations,
|
||||
|
||||
Timer::Connection _drop_timer { _env };
|
||||
|
||||
bool _defer_layout_change = false;
|
||||
enum class Drag_state { IDLE, DRAGGING, SETTLING };
|
||||
|
||||
Drag_state _drag_state { Drag_state::IDLE };
|
||||
|
||||
Signal_handler<Main> _drop_timer_handler {
|
||||
_env.ep(), *this, &Main::_handle_drop_timer };
|
||||
@ -138,21 +140,9 @@ struct Window_layouter::Main : Operations,
|
||||
*/
|
||||
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();
|
||||
_gen_resize_request();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,6 +210,11 @@ struct Window_layouter::Main : Operations,
|
||||
|
||||
void drag(Window_id id, Window::Element element, Point clicked, Point curr) override
|
||||
{
|
||||
if (_drag_state == Drag_state::SETTLING)
|
||||
return;
|
||||
|
||||
_drag_state = Drag_state::DRAGGING;
|
||||
|
||||
to_front(id);
|
||||
|
||||
bool window_layout_changed = false;
|
||||
@ -245,11 +240,15 @@ struct Window_layouter::Main : Operations,
|
||||
|
||||
void _handle_drop_timer()
|
||||
{
|
||||
/* discharge '_defer_layout_change' */
|
||||
layout_rules_changed();
|
||||
_drag_state = Drag_state::IDLE;
|
||||
|
||||
_gen_rules();
|
||||
|
||||
_window_list.for_each_window([&] (Window &window) {
|
||||
window.finalize_drag_operation(); });
|
||||
}
|
||||
|
||||
void finalize_drag(Window_id id, Window::Element, Point, Point) override
|
||||
void finalize_drag(Window_id, Window::Element, Point, Point) override
|
||||
{
|
||||
/*
|
||||
* Update window layout because highlighting may have changed after the
|
||||
@ -257,17 +256,9 @@ struct Window_layouter::Main : Operations,
|
||||
* dragging of a resize handle, the resize handle is no longer hovered.
|
||||
*/
|
||||
_gen_window_layout();
|
||||
_gen_rules();
|
||||
|
||||
_window_list.with_window(id, [&] (Window &window) {
|
||||
window.finalize_drag_operation(); });
|
||||
_drag_state = Drag_state::SETTLING;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -400,9 +391,6 @@ 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) {
|
||||
|
||||
@ -420,9 +408,6 @@ void Window_layouter::Main::_gen_window_layout()
|
||||
|
||||
void Window_layouter::Main::_gen_resize_request()
|
||||
{
|
||||
if (_defer_layout_change)
|
||||
return;
|
||||
|
||||
bool resize_needed = false;
|
||||
_assign_list.for_each([&] (Assign const &assign) {
|
||||
assign.for_each_member([&] (Assign::Member const &member) {
|
||||
|
@ -466,12 +466,13 @@ class Window_layouter::Window : public List_model<Window>::Element
|
||||
|
||||
void finalize_drag_operation()
|
||||
{
|
||||
_dragged = false;
|
||||
_drag_left_border = false;
|
||||
_drag_right_border = false;
|
||||
_drag_top_border = false;
|
||||
_drag_bottom_border = false;
|
||||
_dragged_size = effective_inner_geometry().area();
|
||||
_geometry = effective_inner_geometry();
|
||||
_dragged_size = _geometry.area();
|
||||
_dragged = false;
|
||||
}
|
||||
|
||||
void to_front_cnt(unsigned to_front_cnt) { _to_front_cnt = to_front_cnt; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user