From 69da1fa1edf2fc398fd920fbeee8ab6d26a2965a Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sat, 30 May 2015 16:18:23 +0200 Subject: [PATCH] wm/layouter: Raise window on click --- .../src/app/floating_window_layouter/main.cc | 34 ++++++--- repos/gems/src/server/wm/main.cc | 53 ++++++++++++- repos/gems/src/server/wm/nitpicker.h | 74 +++++++++++++++++-- 3 files changed, 143 insertions(+), 18 deletions(-) diff --git a/repos/gems/src/app/floating_window_layouter/main.cc b/repos/gems/src/app/floating_window_layouter/main.cc index 81bb0cf9d2..94b3bf8d7a 100644 --- a/repos/gems/src/app/floating_window_layouter/main.cc +++ b/repos/gems/src/app/floating_window_layouter/main.cc @@ -267,12 +267,14 @@ struct Floating_window_layouter::Main List windows; + unsigned hovered_window_id = 0; unsigned focused_window_id = 0; unsigned key_cnt = 0; Window::Element hovered_element = Window::Element::UNDEFINED; - bool drag_state = false; + bool drag_state = false; + bool drag_init_done = true; Window *lookup_window_by_id(unsigned id) { @@ -400,10 +402,11 @@ void Floating_window_layouter::Main::generate_window_layout_model() { for (Window *w = windows.first(); w; w = w->next()) { + bool const is_hovered = w->has_id(hovered_window_id); bool const is_focused = w->has_id(focused_window_id); Window::Element const highlight = - is_focused ? hovered_element : Window::Element::UNDEFINED; + is_hovered ? hovered_element : Window::Element::UNDEFINED; w->serialize(xml, is_focused, highlight); } @@ -476,6 +479,8 @@ void Floating_window_layouter::Main::initiate_window_drag(Window &window) { window.initiate_drag_operation(hovered_element); + drag_init_done = true; + /* bring focused window to front */ if (&window != windows.first()) { windows.remove(&window); @@ -526,9 +531,10 @@ void Floating_window_layouter::Main::handle_hover_update(unsigned) * when the model is updated and we are still in dragged state, we can * finally initiate the window-drag operation for the now-known window. */ - if (id && drag_state && dragged_window_id == 0) + if (id && !drag_init_done && dragged_window_id == 0) { dragged_window_id = id; + hovered_window_id = id; focused_window_id = id; Window *window = lookup_window_by_id(id); @@ -539,18 +545,18 @@ void Floating_window_layouter::Main::handle_hover_update(unsigned) } } - if (!drag_state && (id != focused_window_id || hovered != hovered_element)) { + if (!drag_state && (id != hovered_window_id || hovered != hovered_element)) { - focused_window_id = id; + hovered_window_id = id; hovered_element = hovered; generate_window_layout_model(); - generate_focus_model(); } } catch (...) { /* reset focused window if pointer does not hover over any window */ if (!drag_state) { hovered_element = Window::Element::UNDEFINED; + hovered_window_id = 0; generate_window_layout_model(); generate_focus_model(); } @@ -563,7 +569,7 @@ void Floating_window_layouter::Main::handle_input(unsigned) bool need_regenerate_window_layout_model = false; bool need_regenerate_resize_request_model = false; - Window *focused_window = lookup_window_by_id(focused_window_id); + Window *hovered_window = lookup_window_by_id(hovered_window_id); while (input.is_pending()) { @@ -587,19 +593,25 @@ void Floating_window_layouter::Main::handle_input(unsigned) && e.keycode() == Input::BTN_LEFT) { drag_state = true; - dragged_window_id = focused_window_id; + drag_init_done = false; + dragged_window_id = hovered_window_id; pointer_clicked = pointer_curr; pointer_last = pointer_clicked; /* - * If the focused window is known at the time of the press + * If the hovered window is known at the time of the press * event, we can initiate the drag operation immediately. * Otherwise, we the initiation is deferred to the next * update of the hover model. */ - if (focused_window) { - initiate_window_drag(*focused_window); + if (hovered_window) { + initiate_window_drag(*hovered_window); need_regenerate_window_layout_model = true; + + if (focused_window_id != hovered_window_id) { + focused_window_id = hovered_window_id; + generate_focus_model(); + } } } diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index eca3d987d1..2401921917 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -85,10 +85,61 @@ struct Wm::Main Input::Session_component window_layouter_input; + /* handler that forwards clicks into unfocused windows to the layouter */ + struct Click_handler : Nitpicker::Click_handler + { + Input::Session_component &window_layouter_input; + Local_reporter &pointer_reporter; + + void _submit_button_event(Input::Event::Type type, Nitpicker::Point pos) + { + window_layouter_input.submit(Input::Event(type, Input::BTN_LEFT, + pos.x(), pos.y(), 0, 0)); + } + + void handle_enter(Nitpicker::Point pos) override + { + Local_reporter::Xml_generator xml(pointer_reporter, [&] () + { + xml.attribute("xpos", pos.x()); + xml.attribute("ypos", pos.y()); + }); + } + + void handle_click(Nitpicker::Point pos) override + { + /* + * Propagate clicked-at position to decorator such that it can + * update its hover model. + */ + Local_reporter::Xml_generator xml(pointer_reporter, [&] () + { + xml.attribute("xpos", pos.x()); + xml.attribute("ypos", pos.y()); + }); + + /* + * Supply artificial mouse click to the decorator's input session + * (which is routed to the layouter). + */ + _submit_button_event(Input::Event::PRESS, pos); + _submit_button_event(Input::Event::RELEASE, pos); + } + + Click_handler(Input::Session_component &window_layouter_input, + Local_reporter &pointer_reporter) + : + window_layouter_input(window_layouter_input), + pointer_reporter(pointer_reporter) + { } + + } click_handler { window_layouter_input, pointer_reporter }; + Window_registry window_registry { *env()->heap(), window_list_reporter }; Nitpicker::Root nitpicker_root { ep, window_registry, - *env()->heap(), env()->ram_session_cap() }; + *env()->heap(), env()->ram_session_cap(), + click_handler }; Decorator_nitpicker_service decorator_nitpicker_service { ep, *env()->heap(), env()->ram_session_cap(), pointer_reporter, diff --git a/repos/gems/src/server/wm/nitpicker.h b/repos/gems/src/server/wm/nitpicker.h index 926eee18dc..db3e2d59f3 100644 --- a/repos/gems/src/server/wm/nitpicker.h +++ b/repos/gems/src/server/wm/nitpicker.h @@ -52,6 +52,7 @@ namespace Wm { namespace Nitpicker { using namespace ::Nitpicker; + class Click_handler; class View_handle_ctx; class View; class Top_level_view; @@ -66,6 +67,22 @@ namespace Wm { namespace Nitpicker { } } +/** + * Interface used for propagating clicks into unfocused windows to the layouter + * + * The click handler is invoked only for those click events that are of + * interest to the layouter. In particular, a click into an unfocused window + * may trigger the layouter to raise the window and change the focus. However, + * clicks into an already focused window should be of no interest to the + * layouter. So we hide them from the layouter. + */ +struct Wm::Nitpicker::Click_handler +{ + virtual void handle_click(Point pos) = 0; + virtual void handle_enter(Point pos) = 0; +}; + + struct Nitpicker::View { GENODE_RPC_INTERFACE(); }; @@ -423,6 +440,7 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object, List _child_views; Input::Session_component _input_session; Input::Session_capability _input_session_cap; + Click_handler &_click_handler; Signal_context_capability _mode_sigh; Area _requested_size; @@ -495,6 +513,22 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object, return Input::Event(); } + bool _is_click_into_unfocused_view(Input::Event const ev) + { + /* + * XXX check if unfocused + * + * Right now, we report more butten events to the layouter + * than the layouter really needs. + */ + if (ev.type() == Input::Event::PRESS && ev.keycode() == Input::BTN_LEFT) + return true; + + return false; + } + + bool _first_motion = true; + void _input_handler(unsigned) { Point const input_origin = _input_origin(); @@ -508,8 +542,29 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object, /* we trust nitpicker to return a valid number of events */ - for (size_t i = 0; i < num_events; i++) - _input_session.submit(_translate_event(events[i], input_origin)); + for (size_t i = 0; i < num_events; i++) { + + Input::Event const ev = events[i]; + + /* propagate layout-affecting events to the layouter */ + if (_is_click_into_unfocused_view(ev)) + _click_handler.handle_click(Point(ev.ax(), ev.ay())); + + /* + * Reset pointer model for the decorator once the pointer + * enters the application area of a window. + */ + if (ev.type() == Input::Event::MOTION && _first_motion) { + _click_handler.handle_enter(Point(ev.ax(), ev.ay())); + _first_motion = false; + } + + if (ev.type() == Input::Event::LEAVE) + _first_motion = true; + + /* submit event to the client */ + _input_session.submit(_translate_event(ev, input_origin)); + } } } @@ -654,7 +709,8 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object, Entrypoint &ep, Allocator &session_alloc, Session_label const &session_label, - bool const direct) + bool const direct, + Click_handler &click_handler) : _session_label(session_label), _ram(ram), @@ -664,6 +720,7 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object, _top_level_view_alloc(&session_alloc), _child_view_alloc(&session_alloc), _input_session_cap(_ep.manage(_input_session)), + _click_handler(click_handler), _view_handle_registry(session_alloc) { _nitpicker_input.sigh(_input_dispatcher); @@ -879,6 +936,8 @@ class Wm::Nitpicker::Root : public Genode::Root_component, Window_registry &_window_registry; + Click_handler &_click_handler; + List _sessions; protected: @@ -900,7 +959,8 @@ class Wm::Nitpicker::Root : public Genode::Root_component, Session_component *session = new (md_alloc()) Session_component(_ram, _window_registry, - _ep, *md_alloc(), session_label, direct); + _ep, *md_alloc(), session_label, direct, + _click_handler); _sessions.insert(session); @@ -925,10 +985,12 @@ class Wm::Nitpicker::Root : public Genode::Root_component, */ Root(Entrypoint &ep, Window_registry &window_registry, Allocator &md_alloc, - Ram_session_capability ram) + Ram_session_capability ram, + Click_handler &click_handler) : Root_component(&ep.rpc_ep(), &md_alloc), - _ep(ep), _ram(ram), _window_registry(window_registry) + _ep(ep), _ram(ram), _window_registry(window_registry), + _click_handler(click_handler) { Genode::env()->parent()->announce(_ep.manage(*this)); }