https://github.com/pop-os/cosmic-protocols/pull/28 Continues to use `xkg_config` to get list of layouts, but the group is now changed by modifying the group while leaving the config unchanged. And changes to the group are now reflected in the applet.
157 lines
4.4 KiB
Rust
157 lines
4.4 KiB
Rust
use cctk::{
|
|
cosmic_protocols::keyboard_layout::v1::client::zcosmic_keyboard_layout_v1::ZcosmicKeyboardLayoutV1,
|
|
keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState},
|
|
sctk::{
|
|
self,
|
|
registry::{ProvidesRegistryState, RegistryState},
|
|
seat::{Capability, SeatHandler, SeatState},
|
|
},
|
|
wayland_client::{
|
|
Connection, QueueHandle, delegate_noop,
|
|
globals::registry_queue_init,
|
|
protocol::{wl_keyboard, wl_seat},
|
|
},
|
|
};
|
|
use cosmic::iced;
|
|
use futures::{SinkExt, channel::mpsc, executor::block_on};
|
|
use std::{hash::Hash, thread};
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Event {
|
|
KeyboardLayout(ZcosmicKeyboardLayoutV1),
|
|
Group(usize),
|
|
}
|
|
|
|
pub fn subscription(connection: Connection) -> iced::Subscription<Event> {
|
|
#[derive(Clone)]
|
|
struct WaylandSubscription(Connection);
|
|
impl Hash for WaylandSubscription {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.0.backend().display_id().hash(state);
|
|
}
|
|
}
|
|
iced::Subscription::run_with(
|
|
WaylandSubscription(connection),
|
|
|WaylandSubscription(connection)| {
|
|
let connection = connection.clone();
|
|
iced::stream::channel(8, move |sender| async move {
|
|
thread::spawn(move || thread(connection, sender));
|
|
})
|
|
},
|
|
)
|
|
}
|
|
|
|
struct Keyboard {
|
|
seat: wl_seat::WlSeat,
|
|
keyboard_layout: ZcosmicKeyboardLayoutV1,
|
|
}
|
|
|
|
impl Drop for Keyboard {
|
|
fn drop(&mut self) {
|
|
self.keyboard_layout.destroy();
|
|
}
|
|
}
|
|
|
|
struct AppData {
|
|
seat_state: SeatState,
|
|
registry_state: RegistryState,
|
|
keyboard_layout_state: KeyboardLayoutState,
|
|
keyboard: Option<Keyboard>,
|
|
sender: mpsc::Sender<Event>,
|
|
}
|
|
|
|
impl KeyboardLayoutHandler for AppData {
|
|
fn group(
|
|
&mut self,
|
|
_conn: &Connection,
|
|
_qh: &QueueHandle<Self>,
|
|
_keyboard: &wl_keyboard::WlKeyboard,
|
|
_keyboard_layout: &ZcosmicKeyboardLayoutV1,
|
|
group: u32,
|
|
) {
|
|
let _ = block_on(self.sender.send(Event::Group(group as usize)));
|
|
}
|
|
}
|
|
|
|
impl ProvidesRegistryState for AppData {
|
|
fn registry(&mut self) -> &mut RegistryState {
|
|
&mut self.registry_state
|
|
}
|
|
|
|
sctk::registry_handlers![SeatState,];
|
|
}
|
|
|
|
impl SeatHandler for AppData {
|
|
fn seat_state(&mut self) -> &mut SeatState {
|
|
&mut self.seat_state
|
|
}
|
|
|
|
fn new_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
|
|
|
|
fn new_capability(
|
|
&mut self,
|
|
_conn: &Connection,
|
|
qh: &QueueHandle<Self>,
|
|
seat: wl_seat::WlSeat,
|
|
capability: Capability,
|
|
) {
|
|
if capability == Capability::Keyboard && self.keyboard.is_none() {
|
|
let keyboard = seat.get_keyboard(qh, ());
|
|
let keyboard_layout = self
|
|
.keyboard_layout_state
|
|
.get_keyboard_layout(&keyboard, qh);
|
|
keyboard.release();
|
|
|
|
if let Some(keyboard_layout) = keyboard_layout {
|
|
let _ = block_on(
|
|
self.sender
|
|
.send(Event::KeyboardLayout(keyboard_layout.clone())),
|
|
);
|
|
self.keyboard = Some(Keyboard {
|
|
seat,
|
|
keyboard_layout,
|
|
});
|
|
} else {
|
|
keyboard.release();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn remove_capability(
|
|
&mut self,
|
|
_conn: &Connection,
|
|
_: &QueueHandle<Self>,
|
|
seat: wl_seat::WlSeat,
|
|
_capability: Capability,
|
|
) {
|
|
self.keyboard.take_if(|x| x.seat == seat);
|
|
}
|
|
|
|
fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, seat: wl_seat::WlSeat) {
|
|
self.keyboard.take_if(|x| x.seat == seat);
|
|
}
|
|
}
|
|
|
|
fn thread(conn: Connection, sender: mpsc::Sender<Event>) {
|
|
let (globals, mut event_queue) = registry_queue_init(&conn).unwrap();
|
|
let qh = event_queue.handle();
|
|
let registry_state = RegistryState::new(&globals);
|
|
let seat_state = SeatState::new(&globals, &qh);
|
|
let keyboard_layout_state = KeyboardLayoutState::new(®istry_state, &qh);
|
|
|
|
let mut app_data = AppData {
|
|
seat_state,
|
|
registry_state,
|
|
keyboard_layout_state,
|
|
keyboard: None,
|
|
sender,
|
|
};
|
|
loop {
|
|
event_queue.blocking_dispatch(&mut app_data).unwrap();
|
|
}
|
|
}
|
|
|
|
sctk::delegate_registry!(AppData);
|
|
sctk::delegate_seat!(AppData);
|
|
cctk::delegate_keyboard_layout!(AppData);
|
|
delegate_noop!(AppData: ignore wl_keyboard::WlKeyboard);
|