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"/>
|
||||
</rules>
|
||||
|
||||
<press key="KEY_SCREEN">
|
||||
<press key="KEY_SCREEN" action="release_grab">
|
||||
<press key="KEY_TAB" action="next_window">
|
||||
<release key="KEY_TAB">
|
||||
<release key="KEY_SCREEN" action="raise_window"/>
|
||||
|
@ -63,6 +63,8 @@ install_config {
|
||||
|
||||
<policy label_prefix="pointer" domain="pointer"/>
|
||||
<default-policy domain="default"/>
|
||||
|
||||
<global-key name="KEY_SCREEN" label="wm -> wm -> decorator" />
|
||||
</config>
|
||||
</start>
|
||||
|
||||
@ -154,7 +156,9 @@ set fd [open [run_dir]/genode/focus w]
|
||||
puts $fd "<focus label=\"wm -> focus\"/>"
|
||||
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 }
|
||||
|
||||
|
@ -49,6 +49,7 @@ class Window_layouter::Action
|
||||
PREV_TAB,
|
||||
TOOGLE_OVERLAY,
|
||||
SCREEN,
|
||||
RELEASE_GRAB,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -64,6 +65,7 @@ class Window_layouter::Action
|
||||
if (string == "raise_window") return RAISE_WINDOW;
|
||||
if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN;
|
||||
if (string == "screen") return SCREEN;
|
||||
if (string == "release_grab") return RELEASE_GRAB;
|
||||
|
||||
Genode::warning("cannot convert \"", string, "\" to action type");
|
||||
return NONE;
|
||||
|
@ -196,6 +196,12 @@ struct Window_layouter::Main : Operations,
|
||||
_gen_focus();
|
||||
}
|
||||
|
||||
void release_grab() override
|
||||
{
|
||||
/* wm revokes exclusive input on each focus update */
|
||||
_gen_focus();
|
||||
}
|
||||
|
||||
void toggle_fullscreen(Window_id id) override
|
||||
{
|
||||
/* 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 toggle_fullscreen(Window_id) = 0;
|
||||
virtual void focus(Window_id) = 0;
|
||||
virtual void release_grab() = 0;
|
||||
virtual void to_front(Window_id) = 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;
|
||||
|
@ -332,6 +332,10 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e,
|
||||
_operations.screen(action.target_name());
|
||||
return;
|
||||
|
||||
case Action::RELEASE_GRAB:
|
||||
_operations.release_grab();
|
||||
return;
|
||||
|
||||
default:
|
||||
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 {
|
||||
_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
|
||||
*/
|
||||
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;
|
||||
|
||||
@ -734,6 +759,31 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
|
||||
if (propagate_to_pointer_state)
|
||||
_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 */
|
||||
_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();
|
||||
}
|
||||
|
||||
void revoke_exclusive_input()
|
||||
{
|
||||
if (_exclusive_input_granted) {
|
||||
_gui_input.exclusive(false);
|
||||
_exclusive_input_granted = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** 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())
|
||||
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_ */
|
||||
|
@ -77,6 +77,7 @@ struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action
|
||||
|
||||
void _handle_focus_update()
|
||||
{
|
||||
_gui_root.revoke_exclusive_input();
|
||||
_focus_rom.update();
|
||||
_focus_rom.xml().with_optional_sub_node("window", [&] (Xml_node const &window) {
|
||||
_with_win_id_from_xml(window, [&] (Window_registry::Id id) {
|
||||
|
Loading…
Reference in New Issue
Block a user