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;
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();
}
}
}

View File

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

View File

@ -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<Session>,
List<Child_view> _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<Session>,
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<Session>,
/* 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<Session>,
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<Session>,
_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<Session_component>,
Window_registry &_window_registry;
Click_handler &_click_handler;
List<Session_component> _sessions;
protected:
@ -900,7 +959,8 @@ class Wm::Nitpicker::Root : public Genode::Root_component<Session_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<Session_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<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));
}