From b76a1c9eedba6918e083293d18483e6cdfdbe7e6 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 29 Jul 2024 13:56:42 -0700 Subject: [PATCH] WIP Add `cosmic-keymap-unstable-v1` protocol --- Cargo.lock | 2 +- Cargo.toml | 3 +- src/state.rs | 2 + src/wayland/handlers/keymap.rs | 5 ++ src/wayland/handlers/mod.rs | 1 + src/wayland/protocols/keymap.rs | 100 ++++++++++++++++++++++++++++++++ src/wayland/protocols/mod.rs | 1 + 7 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 src/wayland/handlers/keymap.rs create mode 100644 src/wayland/protocols/keymap.rs diff --git a/Cargo.lock b/Cargo.lock index aebb3e94..246e38df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -899,7 +899,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?branch=main#ec1616b90fa6b4568709cfe2c0627b1e8cc887e0" +source = "git+https://github.com/pop-os/cosmic-protocols?branch=keymap#17fb2f85904355abc7c7eecdd3f12763de7e39ca" dependencies = [ "bitflags 2.6.0", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index 6aa22761..ed29f123 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ bytemuck = "1.12" calloop = {version = "0.14.1", features = ["executor"]} cosmic-comp-config = {path = "cosmic-comp-config"} cosmic-config = {git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"]} -cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"]} +# cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"]} +cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", branch = "keymap", default-features = false, features = ["server"]} cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" } edid-rs = {version = "0.1"} egui = {version = "0.29.0", optional = true} diff --git a/src/state.rs b/src/state.rs index 747754c0..2eab2327 100644 --- a/src/state.rs +++ b/src/state.rs @@ -15,6 +15,7 @@ use crate::{ atspi::AtspiState, drm::WlDrmState, image_source::ImageSourceState, + keymap::KeymapState, output_configuration::OutputConfigurationState, output_power::OutputPowerState, screencopy::ScreencopyState, @@ -522,6 +523,7 @@ impl State { VirtualKeyboardManagerState::new::(&dh, client_is_privileged); AlphaModifierState::new::(&dh); SinglePixelBufferState::new::(&dh); + KeymapState::new::(&dh, client_is_privileged); let idle_notifier_state = IdleNotifierState::::new(&dh, handle.clone()); let idle_inhibit_manager_state = IdleInhibitManagerState::new::(&dh); diff --git a/src/wayland/handlers/keymap.rs b/src/wayland/handlers/keymap.rs new file mode 100644 index 00000000..9b4a50c3 --- /dev/null +++ b/src/wayland/handlers/keymap.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +use crate::{state::State, wayland::protocols::keymap::delegate_keymap}; + +delegate_keymap!(State); diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 52414103..1a288abc 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -17,6 +17,7 @@ pub mod idle_notify; pub mod image_source; pub mod input_method; pub mod keyboard_shortcuts_inhibit; +pub mod keymap; pub mod layer_shell; pub mod output; pub mod output_configuration; diff --git a/src/wayland/protocols/keymap.rs b/src/wayland/protocols/keymap.rs new file mode 100644 index 00000000..e96fd132 --- /dev/null +++ b/src/wayland/protocols/keymap.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use cosmic_protocols::keymap::v1::server::zcosmic_keymap_manager_v1::{ + self, ZcosmicKeymapManagerV1, +}; +use smithay::{ + input::{ + keyboard::{KeyboardHandle, Layout}, + SeatHandler, + }, + reexports::wayland_server::{Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New}, +}; +use wayland_backend::server::GlobalId; + +pub struct KeymapState { + pub global: GlobalId, +} + +impl KeymapState { + pub fn new(dh: &DisplayHandle, client_filter: F) -> Self + where + D: GlobalDispatch + 'static, + F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static, + { + let global = dh.create_global::( + 1, + KeymapGlobalData { + filter: Box::new(client_filter), + }, + ); + KeymapState { global } + } +} + +pub struct KeymapGlobalData { + filter: Box Fn(&'a Client) -> bool + Send + Sync>, +} + +impl GlobalDispatch for KeymapState +where + D: GlobalDispatch + + Dispatch + + 'static, +{ + fn bind( + _state: &mut D, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + _global_data: &KeymapGlobalData, + data_init: &mut DataInit<'_, D>, + ) { + data_init.init(resource, ()); + } + + fn can_view(client: Client, global_data: &KeymapGlobalData) -> bool { + (global_data.filter)(&client) + } +} + +impl Dispatch for KeymapState +where + D: Dispatch + 'static, + D: SeatHandler, +{ + fn request( + state: &mut D, + _client: &Client, + _resource: &ZcosmicKeymapManagerV1, + request: zcosmic_keymap_manager_v1::Request, + _data: &(), + _dhandle: &DisplayHandle, + _data_init: &mut DataInit<'_, D>, + ) { + match request { + zcosmic_keymap_manager_v1::Request::SetGroup { keyboard, group } => { + if let Some(handle) = KeyboardHandle::::from_resource(&keyboard) { + handle.with_xkb_state(state, |mut context| { + context.set_layout(Layout(group)); + // TODO is `modifiers` sent? + }); + } + } + zcosmic_keymap_manager_v1::Request::Destroy => {} + _ => unreachable!(), + } + } +} + +macro_rules! delegate_keymap { + ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { + smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + cosmic_protocols::keymap::v1::server::zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1: $crate::wayland::protocols::keymap::KeymapGlobalData + ] => $crate::wayland::protocols::keymap::KeymapState); + smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + cosmic_protocols::keymap::v1::server::zcosmic_keymap_manager_v1::ZcosmicKeymapManagerV1: () + ] => $crate::wayland::protocols::keymap::KeymapState); + }; +} +pub(crate) use delegate_keymap; diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index 3fe5285d..5e6923f7 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -3,6 +3,7 @@ pub mod atspi; pub mod drm; pub mod image_source; +pub mod keymap; pub mod output_configuration; pub mod output_power; pub mod overlap_notify;