events: add support for switch events#4948
Conversation
There was a problem hiding this comment.
Pull request overview
Adds first-class handling of libinput “switch” events (e.g. tablet-mode toggles) to Mir, so these events can be converted into Mir input events and surfaced through the public toolkit API instead of being intercepted only by downstream consumers (e.g. QtMir).
Changes:
- Introduces
MirSwitchEventplus new toolkit enums/accessors for switch action/state. - Extends the input event builder + event factory code to construct switch events and exports the new symbols.
- Adds libinput evdev handling for
LIBINPUT_EVENT_SWITCH_TOGGLEand threads the new input-event type through a few server components’ input-type switches.
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit-tests/input/evdev/test_libinput_device.cpp | Extends the test event-builder mock for switch events (but no new switch tests yet). |
| src/server/shell/decoration/input.cpp | Ignores switch input events in decoration input handling. |
| src/server/shell/abstract_shell.cpp | Explicitly returns false for switch input events. |
| src/server/input/idle_poking_dispatcher.cpp | Ensures switch events don’t poke the idle timer. |
| src/server/input/default_event_builder.h | Adds switch_event() to DefaultEventBuilder. |
| src/server/input/default_event_builder.cpp | Implements DefaultEventBuilder::switch_event(). |
| src/server/frontend_xwayland/xwayland_surface_observer.cpp | Treats switch events as non-move/resize events. |
| src/platforms/evdev/libinput_device.h | Declares switch-event conversion method. |
| src/platforms/evdev/libinput_device.cpp | Handles LIBINPUT_EVENT_SWITCH_TOGGLE and converts tablet-mode toggles. |
| src/common/symbols.map | Exports new switch event C API + factory symbol. |
| src/common/input/input_event.cpp | Adds switch input-type string + toolkit accessors for switch events. |
| src/common/events/switch_event.cpp | Implements the new MirSwitchEvent type. |
| src/common/events/input_event.cpp | Adds to_switch() casting helpers. |
| src/common/events/event_private.h | Pulls in the new switch event definition for internal event plumbing. |
| src/common/events/event_builders.cpp | Adds make_switch_event() factory. |
| src/common/events/CMakeLists.txt | Builds the new switch_event.cpp. |
| include/platform/mir/input/event_builder.h | Adds EventBuilder::switch_event() API. |
| include/core/mir_toolkit/events/enums.h | Adds mir_input_event_type_switch and switch action/state enums. |
| include/common/mir/events/switch_event.h | Adds internal C++ MirSwitchEvent header. |
| include/common/mir/events/input_event.h | Adds to_switch() declarations. |
| include/common/mir/events/event_builders.h | Declares make_switch_event() factory. |
| include/common/mir_toolkit/events/input/switch_event.h | Adds toolkit header for switch event accessors. |
| include/common/mir_toolkit/events/input/input_event.h | Exposes mir_input_event_get_switch_event() in the toolkit API. |
| mir::EventUPtr mie::LibInputDevice::convert_switch_event(libinput_event_switch* switch_event) | ||
| { | ||
| auto const libinput_switch_type = libinput_event_switch_get_switch(switch_event); | ||
| auto const libinput_switch_state = libinput_event_switch_get_switch_state(switch_event); | ||
|
|
||
| switch (libinput_switch_type) | ||
| { | ||
| case LIBINPUT_SWITCH_TABLET_MODE: | ||
| return builder->switch_event( | ||
| mir_switch_action_tablet_mode, | ||
| libinput_switch_state == LIBINPUT_SWITCH_STATE_ON ? mir_switch_state_on : mir_switch_state_off); | ||
| default: | ||
| return {nullptr, [](auto){}}; | ||
| } |
| std::optional<Timestamp> timestamp, | ||
| std::vector<mir::events::TouchContact> const& contacts) = 0; | ||
|
|
||
| virtual EventUPtr switch_event( |
| mir::EventUPtr mev::make_switch_event( | ||
| MirInputDeviceId device_id, | ||
| MirSwitchAction action, | ||
| MirSwitchState state) | ||
| { | ||
| auto e = new_event<MirSwitchEvent>(device_id); | ||
| e->set_action(action); | ||
| e->set_state(state); | ||
|
|
||
| return make_uptr_event(e); | ||
| } |
| if(ev->input_type() != mir_input_event_type_switch) | ||
| { | ||
| mir::fatal_error_abort("expected switch input event but event was of type ", | ||
| input_event_type_to_c_str(ev->input_type())); | ||
| } |
| #ifndef MIR_COMMON_SWITCH_EVENT_H_ | ||
| #define MIR_COMMON_SWITCH_EVENT_H_ | ||
|
|
||
| #include <mir/events/input_event.h> | ||
|
|
| #ifndef MIR_TOOLKIT_SWITCH_EVENT_H_ | ||
| #define MIR_TOOLKIT_SWITCH_EVENT_H_ | ||
|
|
||
| #include <mir_toolkit/events/input/input_event.h> | ||
|
|
| #include <mir/events/input_event.h> | ||
| #include <mir/events/switch_event.h> | ||
|
|
| BOOST_THROW_EXCEPTION(std::logic_error("deprecated event builder method called")); | ||
| } | ||
|
|
||
| MOCK_METHOD(mir::EventUPtr, switch_event, (MirSwitchAction, MirSwitchState), ()); |
| MirSwitchAction action, | ||
| MirSwitchState state); |
AlanGriffiths
left a comment
There was a problem hiding this comment.
The approach looks sensible.
Copilot has identified a bunch of housekeeping (missing license headers, builder parameters etc). These need addressing. (Technically, copyright doesn't need to be assigned to Canonical as long as the CLA is in place.)
This does involve ABI breakages, so we also need to bump .sonames etc. (but the Mir team can deal with that separately.)
There are, however, parallel APIs in libmiral (include/miral/miral/toolkit_event.h) and, potentially, libmiroil (include/miroil/miroil/input_device.h) that need to reflect these changes.
| mir_input_event_type_touch = 1, | ||
| mir_input_event_type_pointer = 2, | ||
| mir_input_event_type_keyboard_resync = 3, | ||
| mir_input_event_type_switch = 4, |
There was a problem hiding this comment.
FLAGGING FOR ATTENTION: Extending this switch is an ABI break: downstream code needs to be recompiled. (That's not blocking this PR, but we need to do deal with it before a release.)
| std::optional<Timestamp> timestamp, | ||
| std::vector<mir::events::TouchContact> const& contacts) = 0; | ||
|
|
||
| virtual EventUPtr switch_event( |
There was a problem hiding this comment.
FLAGGING FOR ATTENTION: Adding a virtual function to this interface is an ABI break: downstream code needs to be recompiled and implement this function. (That's not blocking this PR, but we need to do deal with it before a release.)
Note also: as we're breaking ABI, there's a bunch of [[deprecated]] functions we can get rid of.
* currently these events are not handled by Mir itself. QtMir is the only user, with an event filter to steal these switch events. Signed-off-by: Muhammad <thevancedgamer@mentallysanemainliners.org>
Signed-off-by: Muhammad <thevancedgamer@mentallysanemainliners.org>
What's new?
Adds support for processing switch events from libinput
Checklist