mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
wm/layouter: pointer grabbing/ungrabbing
This patch implements the following policy for applications requesting exclusive input (relative motion): The pointer is grabbed as soon as the user clicks inside the application window. It is forcibly ungrabbed on any window-focus change or when tapping the KEY_SCREEN. An application can always enable (transient) exclusive input during a key sequence, e.g., when dragging the mouse while holding the mouse button. Transient exclusive input is revoked when releasing the last button/key. Fixes #5355
This commit is contained in:
parent
92227df624
commit
ca47280ce9
@ -15,7 +15,7 @@
|
|||||||
<assign label_prefix="" target="screen_1" xpos="any" ypos="any"/>
|
<assign label_prefix="" target="screen_1" xpos="any" ypos="any"/>
|
||||||
</rules>
|
</rules>
|
||||||
|
|
||||||
<press key="KEY_SCREEN">
|
<press key="KEY_SCREEN" action="release_grab">
|
||||||
<press key="KEY_TAB" action="next_window">
|
<press key="KEY_TAB" action="next_window">
|
||||||
<release key="KEY_TAB">
|
<release key="KEY_TAB">
|
||||||
<release key="KEY_SCREEN" action="raise_window"/>
|
<release key="KEY_SCREEN" action="raise_window"/>
|
||||||
|
@ -63,6 +63,8 @@ install_config {
|
|||||||
|
|
||||||
<policy label_prefix="pointer" domain="pointer"/>
|
<policy label_prefix="pointer" domain="pointer"/>
|
||||||
<default-policy domain="default"/>
|
<default-policy domain="default"/>
|
||||||
|
|
||||||
|
<global-key name="KEY_SCREEN" label="wm -> wm -> decorator" />
|
||||||
</config>
|
</config>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
@ -154,7 +156,9 @@ set fd [open [run_dir]/genode/focus w]
|
|||||||
puts $fd "<focus label=\"wm -> focus\"/>"
|
puts $fd "<focus label=\"wm -> focus\"/>"
|
||||||
close $fd
|
close $fd
|
||||||
|
|
||||||
copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/
|
copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/wm.config [run_dir]/genode/
|
||||||
|
copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/layouter.config [run_dir]/genode/
|
||||||
|
copy_file [genode_dir]/repos/gems/recipes/raw/motif_wm/decorator_init.config [run_dir]/genode/
|
||||||
|
|
||||||
build { app/window_layouter app/decorator server/nitpicker server/wm test/nitpicker }
|
build { app/window_layouter app/decorator server/nitpicker server/wm test/nitpicker }
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ class Window_layouter::Action
|
|||||||
PREV_TAB,
|
PREV_TAB,
|
||||||
TOOGLE_OVERLAY,
|
TOOGLE_OVERLAY,
|
||||||
SCREEN,
|
SCREEN,
|
||||||
|
RELEASE_GRAB,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -64,6 +65,7 @@ class Window_layouter::Action
|
|||||||
if (string == "raise_window") return RAISE_WINDOW;
|
if (string == "raise_window") return RAISE_WINDOW;
|
||||||
if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN;
|
if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN;
|
||||||
if (string == "screen") return SCREEN;
|
if (string == "screen") return SCREEN;
|
||||||
|
if (string == "release_grab") return RELEASE_GRAB;
|
||||||
|
|
||||||
Genode::warning("cannot convert \"", string, "\" to action type");
|
Genode::warning("cannot convert \"", string, "\" to action type");
|
||||||
return NONE;
|
return NONE;
|
||||||
|
@ -196,6 +196,12 @@ struct Window_layouter::Main : Operations,
|
|||||||
_gen_focus();
|
_gen_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release_grab() override
|
||||||
|
{
|
||||||
|
/* wm revokes exclusive input on each focus update */
|
||||||
|
_gen_focus();
|
||||||
|
}
|
||||||
|
|
||||||
void toggle_fullscreen(Window_id id) override
|
void toggle_fullscreen(Window_id id) override
|
||||||
{
|
{
|
||||||
/* make sure that the specified window is the front-most one */
|
/* make sure that the specified window is the front-most one */
|
||||||
|
@ -28,6 +28,7 @@ struct Window_layouter::Operations : Interface
|
|||||||
virtual void close(Window_id) = 0;
|
virtual void close(Window_id) = 0;
|
||||||
virtual void toggle_fullscreen(Window_id) = 0;
|
virtual void toggle_fullscreen(Window_id) = 0;
|
||||||
virtual void focus(Window_id) = 0;
|
virtual void focus(Window_id) = 0;
|
||||||
|
virtual void release_grab() = 0;
|
||||||
virtual void to_front(Window_id) = 0;
|
virtual void to_front(Window_id) = 0;
|
||||||
virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0;
|
virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0;
|
||||||
virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0;
|
virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0;
|
||||||
|
@ -332,6 +332,10 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e,
|
|||||||
_operations.screen(action.target_name());
|
_operations.screen(action.target_name());
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case Action::RELEASE_GRAB:
|
||||||
|
_operations.release_grab();
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
warning("action ", (int)action.type(), " unhanded");
|
warning("action ", (int)action.type(), " unhanded");
|
||||||
}
|
}
|
||||||
|
@ -560,10 +560,35 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
|
|||||||
Input::Session_component _input_session {
|
Input::Session_component _input_session {
|
||||||
_env.ep(), _ram, _env.rm(), *this };
|
_env.ep(), _ram, _env.rm(), *this };
|
||||||
|
|
||||||
|
bool _exclusive_input_requested = false,
|
||||||
|
_exclusive_input_granted = false;
|
||||||
|
|
||||||
|
/* used for hiding the click-to-grab event from the client */
|
||||||
|
bool _consume_one_btn_left_release = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input::Session_component::Action interface
|
* Input::Session_component::Action interface
|
||||||
*/
|
*/
|
||||||
void exclusive_input_requested(bool) override { }
|
void exclusive_input_requested(bool const requested) override
|
||||||
|
{
|
||||||
|
if (requested == _exclusive_input_requested)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow immediate changes when
|
||||||
|
*
|
||||||
|
* 1. Exclusive input is already granted by the user having clicked
|
||||||
|
* into the window, or
|
||||||
|
* 2. The client yields the exclusivity, or
|
||||||
|
* 3. Transient exclusive input is requested while a button is held.
|
||||||
|
* In this case, exclusive input will be revoked as soon as the
|
||||||
|
* last button/key is released.
|
||||||
|
*/
|
||||||
|
if (_exclusive_input_granted || _key_cnt || !requested)
|
||||||
|
_gui_input.exclusive(requested);
|
||||||
|
|
||||||
|
_exclusive_input_requested = requested;
|
||||||
|
}
|
||||||
|
|
||||||
Click_handler &_click_handler;
|
Click_handler &_click_handler;
|
||||||
|
|
||||||
@ -734,6 +759,31 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
|
|||||||
if (propagate_to_pointer_state)
|
if (propagate_to_pointer_state)
|
||||||
_pointer_state.apply_event(ev);
|
_pointer_state.apply_event(ev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle pointer grabbing/ungrabbing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* revoke transient exclusive input (while clicked) */
|
||||||
|
if (ev.release() && _key_cnt == 0)
|
||||||
|
if (_exclusive_input_requested && !_exclusive_input_granted)
|
||||||
|
_gui_input.exclusive(false);
|
||||||
|
|
||||||
|
/* grant exclusive input when clicking into window */
|
||||||
|
if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
|
||||||
|
if (_exclusive_input_requested && !_exclusive_input_granted) {
|
||||||
|
_gui_input.exclusive(true);
|
||||||
|
_exclusive_input_granted = true;
|
||||||
|
_consume_one_btn_left_release = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.key_release(Input::BTN_LEFT)) {
|
||||||
|
if (_consume_one_btn_left_release) {
|
||||||
|
_consume_one_btn_left_release = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* submit event to the client */
|
/* submit event to the client */
|
||||||
_input_session.submit(_translate_event(ev, input_origin));
|
_input_session.submit(_translate_event(ev, input_origin));
|
||||||
}
|
}
|
||||||
@ -1014,6 +1064,14 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
|
|||||||
_info_rom->trigger_update();
|
_info_rom->trigger_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void revoke_exclusive_input()
|
||||||
|
{
|
||||||
|
if (_exclusive_input_granted) {
|
||||||
|
_gui_input.exclusive(false);
|
||||||
|
_exclusive_input_granted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** GUI session interface **
|
** GUI session interface **
|
||||||
@ -1650,6 +1708,12 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
|
|||||||
for (Session_component *s = _sessions.first(); s; s = s->next())
|
for (Session_component *s = _sessions.first(); s; s = s->next())
|
||||||
s->propagate_mode_change();
|
s->propagate_mode_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void revoke_exclusive_input()
|
||||||
|
{
|
||||||
|
for (Session_component *s = _sessions.first(); s; s = s->next())
|
||||||
|
s->revoke_exclusive_input();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _GUI_H_ */
|
#endif /* _GUI_H_ */
|
||||||
|
@ -77,6 +77,7 @@ struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action
|
|||||||
|
|
||||||
void _handle_focus_update()
|
void _handle_focus_update()
|
||||||
{
|
{
|
||||||
|
_gui_root.revoke_exclusive_input();
|
||||||
_focus_rom.update();
|
_focus_rom.update();
|
||||||
_focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) {
|
_focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) {
|
||||||
_with_win_id_from_xml(window, [&] (Window_registry::Id id) {
|
_with_win_id_from_xml(window, [&] (Window_registry::Id id) {
|
||||||
|
Loading…
Reference in New Issue
Block a user