Add cosmic-keyboard-layout-unstable-v1 protocol
https://github.com/pop-os/cosmic-protocols/pull/28 Allows clients like `cosmic-applet-input-sources` to show which layout group is active and update it. Currently this is implemented by update the `xkb_config` to change the layout order.
This commit is contained in:
parent
031fdc389a
commit
29320bdab5
7 changed files with 215 additions and 11 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
|
@ -788,7 +788,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-client-toolkit"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#160b086abe03cd34a8a375d7fbe47b24308d1f38"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#0d0b0b573fe4836ede4c237dadd365033cd28296"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"cosmic-protocols",
|
||||
|
|
@ -918,7 +918,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cosmic-protocols"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#160b086abe03cd34a8a375d7fbe47b24308d1f38"
|
||||
source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#0d0b0b573fe4836ede4c237dadd365033cd28296"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"wayland-backend",
|
||||
|
|
@ -1204,7 +1204,7 @@ dependencies = [
|
|||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1518,7 +1518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2688,7 +2688,7 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde_core",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2811,7 +2811,7 @@ version = "1.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "770919970f7d2f74fea948900d35e2ef64f44129e8ae4015f59de1f0aca7c2a5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3421,7 +3421,7 @@ version = "0.50.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4502,7 +4502,7 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5094,7 +5094,7 @@ dependencies = [
|
|||
"getrandom 0.4.1",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6113,7 +6113,7 @@ version = "0.1.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ use std::{
|
|||
time::{Duration, Instant},
|
||||
};
|
||||
use tracing::{error, info, warn};
|
||||
use wayland::protocols::overlap_notify::OverlapNotifyState;
|
||||
use wayland::protocols::{
|
||||
keyboard_layout::KeyboardLayoutState, overlap_notify::OverlapNotifyState,
|
||||
};
|
||||
|
||||
use crate::wayland::handlers::compositor::client_compositor_state;
|
||||
|
||||
|
|
@ -331,5 +333,6 @@ fn refresh(state: &mut State) {
|
|||
state::Common::refresh_focus(state);
|
||||
OverlapNotifyState::refresh(state);
|
||||
state.common.update_x11_stacking_order();
|
||||
KeyboardLayoutState::refresh(state);
|
||||
state.last_refresh = LastRefresh::At(Instant::now());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
corner_radius::CornerRadiusState,
|
||||
drm::WlDrmState,
|
||||
image_capture_source::CosmicImageCaptureSourceState,
|
||||
keyboard_layout::KeyboardLayoutState,
|
||||
output_configuration::OutputConfigurationState,
|
||||
output_power::OutputPowerState,
|
||||
overlap_notify::OverlapNotifyState,
|
||||
|
|
@ -279,6 +280,7 @@ pub struct Common {
|
|||
pub overlap_notify_state: OverlapNotifyState,
|
||||
pub a11y_state: A11yState,
|
||||
pub dbus_state: DBusState,
|
||||
pub keyboard_layout_state: KeyboardLayoutState,
|
||||
|
||||
// shell-related wayland state
|
||||
pub xdg_shell_state: XdgShellState,
|
||||
|
|
@ -682,6 +684,7 @@ impl State {
|
|||
AlphaModifierState::new::<Self>(dh);
|
||||
SinglePixelBufferState::new::<Self>(dh);
|
||||
FixesState::new::<Self>(dh);
|
||||
let keyboard_layout_state = KeyboardLayoutState::new::<State, _>(&dh, client_not_sandboxed);
|
||||
|
||||
let idle_notifier_state = IdleNotifierState::<Self>::new(dh, handle.clone());
|
||||
let idle_inhibit_manager_state = IdleInhibitManagerState::new::<State>(dh);
|
||||
|
|
@ -792,6 +795,7 @@ impl State {
|
|||
xwayland_shell_state,
|
||||
pointer_focus_state: None,
|
||||
dbus_state,
|
||||
keyboard_layout_state,
|
||||
|
||||
#[cfg(feature = "logind")]
|
||||
inhibit_lid_fd: None,
|
||||
|
|
|
|||
10
src/wayland/handlers/keyboard_layout.rs
Normal file
10
src/wayland/handlers/keyboard_layout.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::state::State;
|
||||
use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState};
|
||||
|
||||
impl KeyboardLayoutHandler for State {
|
||||
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState {
|
||||
&mut self.common.keyboard_layout_state
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ pub mod idle_notify;
|
|||
pub mod image_capture_source;
|
||||
pub mod image_copy_capture;
|
||||
pub mod input_method;
|
||||
pub mod keyboard_layout;
|
||||
pub mod keyboard_shortcuts_inhibit;
|
||||
pub mod layer_shell;
|
||||
pub mod output;
|
||||
|
|
|
|||
185
src/wayland/protocols/keyboard_layout.rs
Normal file
185
src/wayland/protocols/keyboard_layout.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use cosmic_protocols::keyboard_layout::v1::server::{
|
||||
zcosmic_keyboard_layout_manager_v1::{self, ZcosmicKeyboardLayoutManagerV1},
|
||||
zcosmic_keyboard_layout_v1::{self, ZcosmicKeyboardLayoutV1},
|
||||
};
|
||||
use smithay::{
|
||||
input::{
|
||||
SeatHandler,
|
||||
keyboard::{KeyboardHandle, Layout},
|
||||
},
|
||||
reexports::wayland_server::{
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
|
||||
},
|
||||
wayland::{Dispatch2, GlobalDispatch2},
|
||||
};
|
||||
use std::mem;
|
||||
use wayland_backend::server::{ClientId, GlobalId};
|
||||
|
||||
pub trait KeyboardLayoutHandler {
|
||||
fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KeyboardLayoutState {
|
||||
pub global: GlobalId,
|
||||
keyboard_layouts: Vec<(ZcosmicKeyboardLayoutV1, Option<Layout>)>,
|
||||
}
|
||||
|
||||
impl KeyboardLayoutState {
|
||||
pub fn new<D, F>(dh: &DisplayHandle, client_filter: F) -> Self
|
||||
where
|
||||
D: GlobalDispatch<ZcosmicKeyboardLayoutManagerV1, LayoutGlobalData> + 'static,
|
||||
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
||||
{
|
||||
let global = dh.create_global::<D, ZcosmicKeyboardLayoutManagerV1, _>(
|
||||
1,
|
||||
LayoutGlobalData {
|
||||
filter: Box::new(client_filter),
|
||||
},
|
||||
);
|
||||
KeyboardLayoutState {
|
||||
global,
|
||||
keyboard_layouts: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh<D>(state: &mut D)
|
||||
where
|
||||
D: SeatHandler + KeyboardLayoutHandler + 'static,
|
||||
{
|
||||
let mut keyboard_layouts = mem::take(&mut state.keyboard_layout_state().keyboard_layouts);
|
||||
for (keyboard_layout, last_layout) in &mut keyboard_layouts {
|
||||
if let Some(data) = keyboard_layout.data::<LayoutUserData<D>>() {
|
||||
if let Some(handle) = &data.handle {
|
||||
let active_layout = handle.with_xkb_state(state, |context| {
|
||||
context.xkb().lock().unwrap().active_layout()
|
||||
});
|
||||
if *last_layout != Some(active_layout) {
|
||||
keyboard_layout.group(active_layout.0);
|
||||
*last_layout = Some(active_layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
state.keyboard_layout_state().keyboard_layouts = keyboard_layouts;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LayoutGlobalData {
|
||||
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
||||
}
|
||||
|
||||
struct LayoutManagerData;
|
||||
|
||||
impl<D> GlobalDispatch2<ZcosmicKeyboardLayoutManagerV1, D> for LayoutGlobalData
|
||||
where
|
||||
D: Dispatch<ZcosmicKeyboardLayoutManagerV1, LayoutManagerData> + 'static,
|
||||
{
|
||||
fn bind(
|
||||
&self,
|
||||
_state: &mut D,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: New<ZcosmicKeyboardLayoutManagerV1>,
|
||||
data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
data_init.init(resource, LayoutManagerData);
|
||||
}
|
||||
|
||||
fn can_view(&self, client: &Client) -> bool {
|
||||
(self.filter)(client)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Dispatch2<ZcosmicKeyboardLayoutManagerV1, D> for LayoutManagerData
|
||||
where
|
||||
D: Dispatch<ZcosmicKeyboardLayoutV1, LayoutUserData<D>>,
|
||||
D: 'static,
|
||||
D: SeatHandler,
|
||||
D: KeyboardLayoutHandler,
|
||||
{
|
||||
fn request(
|
||||
&self,
|
||||
state: &mut D,
|
||||
_client: &Client,
|
||||
_resource: &ZcosmicKeyboardLayoutManagerV1,
|
||||
request: zcosmic_keyboard_layout_manager_v1::Request,
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
match request {
|
||||
zcosmic_keyboard_layout_manager_v1::Request::GetKeyboardLayout {
|
||||
keyboard_layout,
|
||||
keyboard,
|
||||
} => {
|
||||
let handle = KeyboardHandle::<D>::from_resource(&keyboard);
|
||||
let active_layout = handle.as_ref().map(|handle| {
|
||||
handle.with_xkb_state(state, |context| {
|
||||
context.xkb().lock().unwrap().active_layout()
|
||||
})
|
||||
});
|
||||
let keyboard_layout = data_init.init(keyboard_layout, LayoutUserData { handle });
|
||||
if let Some(layout) = active_layout {
|
||||
keyboard_layout.group(layout.0);
|
||||
}
|
||||
state
|
||||
.keyboard_layout_state()
|
||||
.keyboard_layouts
|
||||
.push((keyboard_layout, active_layout));
|
||||
}
|
||||
zcosmic_keyboard_layout_manager_v1::Request::Destroy => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct LayoutUserData<D: SeatHandler> {
|
||||
handle: Option<KeyboardHandle<D>>,
|
||||
}
|
||||
|
||||
impl<D> Dispatch2<ZcosmicKeyboardLayoutV1, D> for LayoutUserData<D>
|
||||
where
|
||||
D: 'static,
|
||||
D: SeatHandler,
|
||||
D: KeyboardLayoutHandler,
|
||||
{
|
||||
fn request(
|
||||
&self,
|
||||
state: &mut D,
|
||||
_client: &Client,
|
||||
_resource: &ZcosmicKeyboardLayoutV1,
|
||||
request: zcosmic_keyboard_layout_v1::Request,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, D>,
|
||||
) {
|
||||
match request {
|
||||
zcosmic_keyboard_layout_v1::Request::SetGroup { group } => {
|
||||
if let Some(handle) = self.handle.as_ref() {
|
||||
handle.with_xkb_state(state, |mut context| {
|
||||
context.set_layout(Layout(group));
|
||||
});
|
||||
}
|
||||
}
|
||||
zcosmic_keyboard_layout_v1::Request::Destroy => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn destroyed(
|
||||
&self,
|
||||
state: &mut D,
|
||||
_client: ClientId,
|
||||
keyboard_layout: &ZcosmicKeyboardLayoutV1,
|
||||
) {
|
||||
let keyboard_layouts = &mut state.keyboard_layout_state().keyboard_layouts;
|
||||
if let Some(idx) = keyboard_layouts
|
||||
.iter()
|
||||
.position(|(x, _)| x == keyboard_layout)
|
||||
{
|
||||
keyboard_layouts.remove(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ pub mod a11y;
|
|||
pub mod corner_radius;
|
||||
pub mod drm;
|
||||
pub mod image_capture_source;
|
||||
pub mod keyboard_layout;
|
||||
pub mod output_configuration;
|
||||
pub mod output_power;
|
||||
pub mod overlap_notify;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue