Update Smithay (virtual keyboard, layer-shell geometry, GPU profiling)

Also includes the necessary code to handle the virtual keyboard
compositor-side. Similar to the virtual pointer, we have an InputDevice
impl that allows reusing the logic from process_input_event().

Co-authored-by: wxt <3264117476@qq.com>
This commit is contained in:
Ivan Molodetskikh
2026-01-17 20:32:05 +03:00
parent 3ccb06f564
commit 74d14be01f
7 changed files with 179 additions and 8 deletions
+1 -2
View File
@@ -68,7 +68,7 @@ use smithay::{
delegate_pointer_gestures, delegate_presentation, delegate_primary_selection,
delegate_relative_pointer, delegate_seat, delegate_security_context, delegate_session_lock,
delegate_single_pixel_buffer, delegate_tablet_manager, delegate_text_input_manager,
delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation,
delegate_viewporter, delegate_xdg_activation,
};
pub use crate::handlers::xdg_shell::KdeDecorationsModeState;
@@ -279,7 +279,6 @@ impl KeyboardShortcutsInhibitHandler for State {
delegate_input_method_manager!(State);
delegate_keyboard_shortcuts_inhibit!(State);
delegate_virtual_keyboard_manager!(State);
impl SelectionHandler for State {
type SelectionUserData = Arc<[u8]>;
+7
View File
@@ -4,6 +4,7 @@ use smithay::backend::winit::WinitVirtualDevice;
use smithay::output::Output;
use crate::niri::State;
use crate::protocols::virtual_keyboard::VirtualKeyboard;
use crate::protocols::virtual_pointer::VirtualPointer;
pub trait NiriInputBackend: input::InputBackend<Device = Self::NiriDevice> {
@@ -44,6 +45,12 @@ impl NiriInputDevice for WinitVirtualDevice {
}
}
impl NiriInputDevice for VirtualKeyboard {
fn output(&self, _: &State) -> Option<Output> {
None
}
}
impl NiriInputDevice for VirtualPointer {
fn output(&self, _: &State) -> Option<Output> {
self.output().cloned()
+29 -3
View File
@@ -7,7 +7,7 @@ use std::time::Duration;
use calloop::timer::{TimeoutAction, Timer};
use input::event::gesture::GestureEventCoordinates as _;
use niri_config::{
Action, Bind, Binds, Config, Key, ModKey, Modifiers, MruDirection, SwitchBinds, Trigger,
Action, Bind, Binds, Config, Key, ModKey, Modifiers, MruDirection, SwitchBinds, Trigger, Xkb,
};
use niri_ipc::LayoutSwitchTarget;
use smithay::backend::input::{
@@ -48,6 +48,7 @@ use crate::dbus::freedesktop_a11y::KbMonBlock;
use crate::layout::scrolling::ScrollDirection;
use crate::layout::{ActivateWindow, LayoutElement as _};
use crate::niri::{CastTarget, PointerVisibility, State};
use crate::protocols::virtual_keyboard::VirtualKeyboard;
use crate::ui::mru::{WindowMru, WindowMruUi};
use crate::ui::screenshot_ui::ScreenshotUi;
use crate::utils::spawning::{spawn, spawn_sh};
@@ -360,11 +361,36 @@ impl State {
.is_some_and(KeyboardShortcutsInhibitor::is_active)
}
fn on_keyboard<I: InputBackend>(
fn on_keyboard<I: InputBackend + 'static>(
&mut self,
event: I::KeyboardKeyEvent,
consumed_by_a11y: &mut bool,
) {
) where
I::Device: 'static,
{
// Reset the keymap when handling a physical keyboard after a virtual one.
if self.niri.reset_keymap {
let device = event.device();
let is_virtual_keyboard = (&device as &dyn Any)
.downcast_ref::<VirtualKeyboard>()
.is_some();
if !is_virtual_keyboard {
self.niri.reset_keymap = false;
let config = self.niri.config.borrow();
let xkb_config = config.input.keyboard.xkb.clone();
std::mem::drop(config);
if xkb_config != Xkb::default() {
self.set_xkb_config(xkb_config.to_xkb_config());
} else {
// Use locale1 settings if xkb config is unset.
let xkb = self.niri.xkb_from_locale1.clone().unwrap_or_default();
self.set_xkb_config(xkb.to_xkb_config());
}
}
}
let mod_key = self.backend.mod_key(&self.niri.config.borrow());
let serial = SERIAL_COUNTER.next_serial();
+7 -1
View File
@@ -331,6 +331,11 @@ pub struct Niri {
/// Most recent XKB settings from org.freedesktop.locale1.
pub xkb_from_locale1: Option<Xkb>,
/// Whether to reset the keymap on the next physical keyboard event.
///
/// Set to true when handling virtual keyboard events which override the keymap.
pub reset_keymap: bool,
pub cursor_manager: CursorManager,
pub cursor_texture_cache: CursorTextureCache,
pub cursor_shape_manager_state: CursorShapeManagerState,
@@ -1385,7 +1390,7 @@ impl State {
}
}
fn set_xkb_config(&mut self, xkb: XkbConfig) {
pub fn set_xkb_config(&mut self, xkb: XkbConfig) {
let keyboard = self.niri.seat.get_keyboard().unwrap();
let num_lock = keyboard.modifier_state().num_lock;
if let Err(err) = keyboard.set_xkb_config(self, xkb) {
@@ -2505,6 +2510,7 @@ impl Niri {
is_fdo_idle_inhibited: Arc::new(AtomicBool::new(false)),
keyboard_shortcuts_inhibiting_surfaces: HashMap::new(),
xkb_from_locale1: None,
reset_keymap: false,
cursor_manager,
cursor_texture_cache: Default::default(),
cursor_shape_manager_state,
+1
View File
@@ -4,6 +4,7 @@ pub mod gamma_control;
pub mod mutter_x11_interop;
pub mod output_management;
pub mod screencopy;
pub mod virtual_keyboard;
pub mod virtual_pointer;
pub mod raw;
+132
View File
@@ -0,0 +1,132 @@
use smithay::backend::input::{
Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, Keycode,
UnusedEvent,
};
use smithay::delegate_virtual_keyboard_manager;
use smithay::input::keyboard::xkb::ModMask;
use smithay::input::keyboard::KeyboardHandle;
use smithay::wayland::virtual_keyboard::VirtualKeyboardHandler;
use crate::niri::State;
pub struct VirtualKeyboardInputBackend;
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct VirtualKeyboard;
impl Device for VirtualKeyboard {
fn id(&self) -> String {
String::from("virtual keyboard")
}
fn name(&self) -> String {
String::from("virtual keyboard")
}
fn has_capability(&self, capability: DeviceCapability) -> bool {
matches!(capability, DeviceCapability::Keyboard)
}
fn usb_id(&self) -> Option<(u32, u32)> {
None
}
fn syspath(&self) -> Option<std::path::PathBuf> {
None
}
}
pub struct VirtualKeyboardKeyEvent {
pub keycode: Keycode,
pub state: KeyState,
pub time: u32,
}
impl Event<VirtualKeyboardInputBackend> for VirtualKeyboardKeyEvent {
fn time(&self) -> u64 {
self.time as u64 * 1000 // millis to micros
}
fn device(&self) -> VirtualKeyboard {
VirtualKeyboard
}
}
impl KeyboardKeyEvent<VirtualKeyboardInputBackend> for VirtualKeyboardKeyEvent {
fn key_code(&self) -> Keycode {
self.keycode
}
fn state(&self) -> KeyState {
self.state
}
fn count(&self) -> u32 {
0 // Not used by niri
}
}
impl InputBackend for VirtualKeyboardInputBackend {
type Device = VirtualKeyboard;
type KeyboardKeyEvent = VirtualKeyboardKeyEvent;
type PointerAxisEvent = UnusedEvent;
type PointerButtonEvent = UnusedEvent;
type PointerMotionEvent = UnusedEvent;
type PointerMotionAbsoluteEvent = UnusedEvent;
type GestureSwipeBeginEvent = UnusedEvent;
type GestureSwipeUpdateEvent = UnusedEvent;
type GestureSwipeEndEvent = UnusedEvent;
type GesturePinchBeginEvent = UnusedEvent;
type GesturePinchUpdateEvent = UnusedEvent;
type GesturePinchEndEvent = UnusedEvent;
type GestureHoldBeginEvent = UnusedEvent;
type GestureHoldEndEvent = UnusedEvent;
type TouchDownEvent = UnusedEvent;
type TouchUpEvent = UnusedEvent;
type TouchMotionEvent = UnusedEvent;
type TouchCancelEvent = UnusedEvent;
type TouchFrameEvent = UnusedEvent;
type TabletToolAxisEvent = UnusedEvent;
type TabletToolProximityEvent = UnusedEvent;
type TabletToolTipEvent = UnusedEvent;
type TabletToolButtonEvent = UnusedEvent;
type SwitchToggleEvent = UnusedEvent;
type SpecialEvent = UnusedEvent;
}
impl VirtualKeyboardHandler for State {
fn on_keyboard_event(
&mut self,
keycode: Keycode,
state: KeyState,
time: u32,
_keyboard: KeyboardHandle<Self>,
) {
// The virtual keyboard impl in Smithay changes the keymap, so we'll need to reset it on
// the next real keyboard event.
self.niri.reset_keymap = true;
let event = VirtualKeyboardKeyEvent {
keycode,
state,
time,
};
self.process_input_event(InputEvent::<VirtualKeyboardInputBackend>::Keyboard { event });
}
// We handle modifiers when the key event is sent.
fn on_keyboard_modifiers(
&mut self,
_depressed_mods: ModMask,
_latched_mods: ModMask,
_locked_mods: ModMask,
_keyboard: KeyboardHandle<Self>,
) {
}
}
delegate_virtual_keyboard_manager!(State);