wm/layouter: Raise window on click

This commit is contained in:
Norman Feske 2015-05-30 16:18:23 +02:00 committed by Christian Helmuth
parent b4ebefd616
commit 69da1fa1ed
3 changed files with 143 additions and 18 deletions

View File

@ -267,12 +267,14 @@ struct Floating_window_layouter::Main
List<Window> windows; List<Window> windows;
unsigned hovered_window_id = 0;
unsigned focused_window_id = 0; unsigned focused_window_id = 0;
unsigned key_cnt = 0; unsigned key_cnt = 0;
Window::Element hovered_element = Window::Element::UNDEFINED; 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) 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()) { 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); bool const is_focused = w->has_id(focused_window_id);
Window::Element const highlight = Window::Element const highlight =
is_focused ? hovered_element : Window::Element::UNDEFINED; is_hovered ? hovered_element : Window::Element::UNDEFINED;
w->serialize(xml, is_focused, highlight); 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); window.initiate_drag_operation(hovered_element);
drag_init_done = true;
/* bring focused window to front */ /* bring focused window to front */
if (&window != windows.first()) { if (&window != windows.first()) {
windows.remove(&window); 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 * 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. * 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; dragged_window_id = id;
hovered_window_id = id;
focused_window_id = id; focused_window_id = id;
Window *window = lookup_window_by_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; hovered_element = hovered;
generate_window_layout_model(); generate_window_layout_model();
generate_focus_model();
} }
} catch (...) { } catch (...) {
/* reset focused window if pointer does not hover over any window */ /* reset focused window if pointer does not hover over any window */
if (!drag_state) { if (!drag_state) {
hovered_element = Window::Element::UNDEFINED; hovered_element = Window::Element::UNDEFINED;
hovered_window_id = 0;
generate_window_layout_model(); generate_window_layout_model();
generate_focus_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_window_layout_model = false;
bool need_regenerate_resize_request_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()) { while (input.is_pending()) {
@ -587,19 +593,25 @@ void Floating_window_layouter::Main::handle_input(unsigned)
&& e.keycode() == Input::BTN_LEFT) { && e.keycode() == Input::BTN_LEFT) {
drag_state = true; drag_state = true;
dragged_window_id = focused_window_id; drag_init_done = false;
dragged_window_id = hovered_window_id;
pointer_clicked = pointer_curr; pointer_clicked = pointer_curr;
pointer_last = pointer_clicked; 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. * event, we can initiate the drag operation immediately.
* Otherwise, we the initiation is deferred to the next * Otherwise, we the initiation is deferred to the next
* update of the hover model. * update of the hover model.
*/ */
if (focused_window) { if (hovered_window) {
initiate_window_drag(*focused_window); initiate_window_drag(*hovered_window);
need_regenerate_window_layout_model = true; need_regenerate_window_layout_model = true;
if (focused_window_id != hovered_window_id) {
focused_window_id = hovered_window_id;
generate_focus_model();
}
} }
} }

View File

@ -85,10 +85,61 @@ struct Wm::Main
Input::Session_component window_layouter_input; 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 }; Window_registry window_registry { *env()->heap(), window_list_reporter };
Nitpicker::Root nitpicker_root { ep, window_registry, 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 { Decorator_nitpicker_service decorator_nitpicker_service {
ep, *env()->heap(), env()->ram_session_cap(), pointer_reporter, ep, *env()->heap(), env()->ram_session_cap(), pointer_reporter,

View File

@ -52,6 +52,7 @@ namespace Wm { namespace Nitpicker {
using namespace ::Nitpicker; using namespace ::Nitpicker;
class Click_handler;
class View_handle_ctx; class View_handle_ctx;
class View; class View;
class Top_level_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(); }; struct Nitpicker::View { GENODE_RPC_INTERFACE(); };
@ -423,6 +440,7 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object<Session>,
List<Child_view> _child_views; List<Child_view> _child_views;
Input::Session_component _input_session; Input::Session_component _input_session;
Input::Session_capability _input_session_cap; Input::Session_capability _input_session_cap;
Click_handler &_click_handler;
Signal_context_capability _mode_sigh; Signal_context_capability _mode_sigh;
Area _requested_size; Area _requested_size;
@ -495,6 +513,22 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object<Session>,
return Input::Event(); 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) void _input_handler(unsigned)
{ {
Point const input_origin = _input_origin(); Point const input_origin = _input_origin();
@ -508,8 +542,29 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object<Session>,
/* we trust nitpicker to return a valid number of events */ /* we trust nitpicker to return a valid number of events */
for (size_t i = 0; i < num_events; i++) for (size_t i = 0; i < num_events; i++) {
_input_session.submit(_translate_event(events[i], input_origin));
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<Session>,
Entrypoint &ep, Entrypoint &ep,
Allocator &session_alloc, Allocator &session_alloc,
Session_label const &session_label, Session_label const &session_label,
bool const direct) bool const direct,
Click_handler &click_handler)
: :
_session_label(session_label), _session_label(session_label),
_ram(ram), _ram(ram),
@ -664,6 +720,7 @@ class Wm::Nitpicker::Session_component : public Genode::Rpc_object<Session>,
_top_level_view_alloc(&session_alloc), _top_level_view_alloc(&session_alloc),
_child_view_alloc(&session_alloc), _child_view_alloc(&session_alloc),
_input_session_cap(_ep.manage(_input_session)), _input_session_cap(_ep.manage(_input_session)),
_click_handler(click_handler),
_view_handle_registry(session_alloc) _view_handle_registry(session_alloc)
{ {
_nitpicker_input.sigh(_input_dispatcher); _nitpicker_input.sigh(_input_dispatcher);
@ -879,6 +936,8 @@ class Wm::Nitpicker::Root : public Genode::Root_component<Session_component>,
Window_registry &_window_registry; Window_registry &_window_registry;
Click_handler &_click_handler;
List<Session_component> _sessions; List<Session_component> _sessions;
protected: protected:
@ -900,7 +959,8 @@ class Wm::Nitpicker::Root : public Genode::Root_component<Session_component>,
Session_component *session = new (md_alloc()) Session_component *session = new (md_alloc())
Session_component(_ram, _window_registry, Session_component(_ram, _window_registry,
_ep, *md_alloc(), session_label, direct); _ep, *md_alloc(), session_label, direct,
_click_handler);
_sessions.insert(session); _sessions.insert(session);
@ -925,10 +985,12 @@ class Wm::Nitpicker::Root : public Genode::Root_component<Session_component>,
*/ */
Root(Entrypoint &ep, Root(Entrypoint &ep,
Window_registry &window_registry, Allocator &md_alloc, Window_registry &window_registry, Allocator &md_alloc,
Ram_session_capability ram) Ram_session_capability ram,
Click_handler &click_handler)
: :
Root_component<Session_component>(&ep.rpc_ep(), &md_alloc), Root_component<Session_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)); Genode::env()->parent()->announce(_ep.manage(*this));
} }