diff --git a/repos/gems/recipes/raw/motif_wm/layouter.config b/repos/gems/recipes/raw/motif_wm/layouter.config index 4611a48a59..1560e09e17 100644 --- a/repos/gems/recipes/raw/motif_wm/layouter.config +++ b/repos/gems/recipes/raw/motif_wm/layouter.config @@ -15,7 +15,7 @@ - + diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index 3cf51763a3..4b05218668 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -63,6 +63,8 @@ install_config { + + @@ -154,7 +156,9 @@ set fd [open [run_dir]/genode/focus w] puts $fd " 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 } diff --git a/repos/gems/src/app/window_layouter/action.h b/repos/gems/src/app/window_layouter/action.h index 45890aa426..995274b6ac 100644 --- a/repos/gems/src/app/window_layouter/action.h +++ b/repos/gems/src/app/window_layouter/action.h @@ -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; diff --git a/repos/gems/src/app/window_layouter/main.cc b/repos/gems/src/app/window_layouter/main.cc index f4a54e413a..123428445f 100644 --- a/repos/gems/src/app/window_layouter/main.cc +++ b/repos/gems/src/app/window_layouter/main.cc @@ -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 */ diff --git a/repos/gems/src/app/window_layouter/operations.h b/repos/gems/src/app/window_layouter/operations.h index 4ed9922d13..5cf7da46cc 100644 --- a/repos/gems/src/app/window_layouter/operations.h +++ b/repos/gems/src/app/window_layouter/operations.h @@ -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; diff --git a/repos/gems/src/app/window_layouter/user_state.h b/repos/gems/src/app/window_layouter/user_state.h index 255b17dca8..edb2d8cf8e 100644 --- a/repos/gems/src/app/window_layouter/user_state.h +++ b/repos/gems/src/app/window_layouter/user_state.h @@ -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"); } diff --git a/repos/gems/src/server/wm/gui.h b/repos/gems/src/server/wm/gui.h index bd9b53e46a..a289824a30 100644 --- a/repos/gems/src/server/wm/gui.h +++ b/repos/gems/src/server/wm/gui.h @@ -560,10 +560,35 @@ class Wm::Gui::Session_component : public Session_object, 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, 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, _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 >, 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_ */ diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index 41feacea3a..02cde0a789 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -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) {