refactor(wayland): use smithay seats
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -299,9 +299,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
version = "0.12.2"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aadd183e815348c0649051b1c43418643208f8ed13c8a84da7215b4e1cf42714"
|
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.0",
|
||||||
"log",
|
"log",
|
||||||
@@ -591,7 +591,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.0",
|
"libloading 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2025,7 +2025,7 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/smithay/smithay.git#91e61f13501f21d66803efac947bfafed43080c5"
|
source = "git+https://github.com/smithay/smithay.git#8287457195cf6a495331f65f5e0119f931ff7e79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.0",
|
||||||
@@ -2627,9 +2627,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.31.0"
|
version = "0.31.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c"
|
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.0",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ pub struct PanelItemInitData {
|
|||||||
|
|
||||||
pub trait Backend: Send + Sync + 'static {
|
pub trait Backend: Send + Sync + 'static {
|
||||||
fn start_data(&self) -> Result<PanelItemInitData>;
|
fn start_data(&self) -> Result<PanelItemInitData>;
|
||||||
|
fn surface_alive(&self, surface: &SurfaceID) -> bool;
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
|
||||||
|
|
||||||
@@ -542,6 +543,9 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
|||||||
fn start_data(&self) -> Result<PanelItemInitData> {
|
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||||
self.backend.start_data()
|
self.backend.start_data()
|
||||||
}
|
}
|
||||||
|
fn surface_alive(&self, surface: &SurfaceID) -> bool {
|
||||||
|
self.backend.surface_alive(surface)
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||||
self.backend.apply_surface_material(surface, model_part)
|
self.backend.apply_surface_material(surface, model_part)
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ pub mod xwayland_rootless;
|
|||||||
use self::xwayland_rootless::XWaylandState;
|
use self::xwayland_rootless::XWaylandState;
|
||||||
|
|
||||||
use self::{state::WaylandState, surface::CORE_SURFACES};
|
use self::{state::WaylandState, surface::CORE_SURFACES};
|
||||||
use crate::wayland::seat::SeatData;
|
|
||||||
use crate::{core::task, wayland::state::ClientState};
|
use crate::{core::task, wayland::state::ClientState};
|
||||||
use color_eyre::eyre::{ensure, Result};
|
use color_eyre::eyre::{ensure, Result};
|
||||||
use global_counter::primitive::exact::CounterU32;
|
use global_counter::primitive::exact::CounterU32;
|
||||||
@@ -179,10 +178,9 @@ impl Wayland {
|
|||||||
id: OnceCell::new(),
|
id: OnceCell::new(),
|
||||||
compositor_state: Default::default(),
|
compositor_state: Default::default(),
|
||||||
display: Arc::downgrade(&display),
|
display: Arc::downgrade(&display),
|
||||||
seat: SeatData::new(&dh1)
|
seat: state.lock().seat.clone(),
|
||||||
});
|
});
|
||||||
let client = dh2.insert_client(stream.into_std()?, client_state.clone())?;
|
let _client = dh2.insert_client(stream.into_std()?, client_state.clone())?;
|
||||||
let _ = client_state.seat.client.set(client.id());
|
|
||||||
}
|
}
|
||||||
e = dispatch_poll_listener.readable() => { // Dispatch
|
e = dispatch_poll_listener.readable() => { // Dispatch
|
||||||
let mut guard = e?;
|
let mut guard = e?;
|
||||||
|
|||||||
@@ -1,471 +1,82 @@
|
|||||||
use super::{
|
use super::{state::WaylandState, surface::CoreSurface};
|
||||||
state::{ClientState, WaylandState},
|
|
||||||
surface::CoreSurface,
|
|
||||||
SERIAL_COUNTER,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::task,
|
core::task,
|
||||||
nodes::items::panel::{Backend, Geometry, PanelItem},
|
nodes::{
|
||||||
};
|
data::KEYMAPS,
|
||||||
use color_eyre::eyre::{bail, eyre, Result};
|
items::panel::{Backend, Geometry, PanelItem},
|
||||||
use mint::Vector2;
|
|
||||||
use nanoid::nanoid;
|
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use rand::{seq::IteratorRandom, thread_rng};
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
|
||||||
use smithay::{
|
|
||||||
input::keyboard::{KeymapFile, ModifiersState},
|
|
||||||
reexports::wayland_server::{
|
|
||||||
backend::{ClientId, GlobalId, ObjectId},
|
|
||||||
protocol::{
|
|
||||||
wl_keyboard::{self, KeyState, WlKeyboard},
|
|
||||||
wl_pointer::{self, Axis, ButtonState, WlPointer},
|
|
||||||
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
|
|
||||||
wl_surface::WlSurface,
|
|
||||||
wl_touch::{self, WlTouch},
|
|
||||||
},
|
|
||||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak as WlWeak,
|
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
use mint::Vector2;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use smithay::{
|
||||||
|
backend::input::{AxisRelativeDirection, ButtonState, KeyState},
|
||||||
|
delegate_seat,
|
||||||
|
input::{
|
||||||
|
keyboard::{FilterResult, LedState},
|
||||||
|
pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent},
|
||||||
|
touch::{self, DownEvent, UpEvent},
|
||||||
|
Seat, SeatHandler,
|
||||||
|
},
|
||||||
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak as WlWeak},
|
||||||
|
utils::SERIAL_COUNTER,
|
||||||
wayland::compositor,
|
wayland::compositor,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::sync::{Arc, Weak};
|
||||||
collections::VecDeque,
|
|
||||||
sync::Arc,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
use tracing::{debug, warn};
|
|
||||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keycode, Keymap};
|
impl SeatHandler for WaylandState {
|
||||||
|
type PointerFocus = WlSurface;
|
||||||
|
type KeyboardFocus = WlSurface;
|
||||||
|
type TouchFocus = WlSurface;
|
||||||
|
|
||||||
|
fn seat_state(&mut self) -> &mut smithay::input::SeatState<Self> {
|
||||||
|
&mut self.seat_state
|
||||||
|
}
|
||||||
|
fn focus_changed(&mut self, _seat: &Seat<Self>, _focused: Option<&Self::KeyboardFocus>) {}
|
||||||
|
fn cursor_image(&mut self, _seat: &Seat<Self>, image: CursorImageStatus) {
|
||||||
|
self.seat.cursor_info_tx.send_modify(|c| match image {
|
||||||
|
CursorImageStatus::Hidden => c.surface = None,
|
||||||
|
CursorImageStatus::Surface(surface) => {
|
||||||
|
CoreSurface::add_to(self.display_handle.clone(), &surface, || (), |_| ());
|
||||||
|
compositor::with_states(&surface, |data| {
|
||||||
|
if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() {
|
||||||
|
core_surface.set_material_offset(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
c.surface = Some(surface.downgrade())
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn led_state_changed(&mut self, _seat: &Seat<Self>, _led_state: LedState) {}
|
||||||
|
}
|
||||||
|
delegate_seat!(WaylandState);
|
||||||
|
|
||||||
pub fn handle_cursor<B: Backend>(
|
pub fn handle_cursor<B: Backend>(
|
||||||
panel_item: &Arc<PanelItem<B>>,
|
panel_item: &Arc<PanelItem<B>>,
|
||||||
mut cursor: watch::Receiver<Option<CursorInfo>>,
|
mut cursor: watch::Receiver<CursorInfo>,
|
||||||
) {
|
) {
|
||||||
let panel_item_weak = Arc::downgrade(panel_item);
|
let panel_item_weak = Arc::downgrade(panel_item);
|
||||||
let _ = task::new(|| "cursor handler", async move {
|
let _ = task::new(|| "cursor handler", async move {
|
||||||
while cursor.changed().await.is_ok() {
|
while cursor.changed().await.is_ok() {
|
||||||
let Some(panel_item) = panel_item_weak.upgrade() else {continue};
|
let Some(panel_item) = panel_item_weak.upgrade() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let cursor_info = cursor.borrow();
|
let cursor_info = cursor.borrow();
|
||||||
panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data));
|
panel_item.set_cursor(cursor_info.cursor_data());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KeyboardInfo {
|
|
||||||
keymap_string: String,
|
|
||||||
keymap: KeymapFile,
|
|
||||||
state: xkb::State,
|
|
||||||
mods: ModifiersState,
|
|
||||||
keys: FxHashSet<u32>,
|
|
||||||
}
|
|
||||||
impl KeyboardInfo {
|
|
||||||
pub fn new(keymap_string: String, keymap: &Keymap) -> Self {
|
|
||||||
KeyboardInfo {
|
|
||||||
keymap_string,
|
|
||||||
state: xkb::State::new(keymap),
|
|
||||||
keymap: KeymapFile::new(keymap),
|
|
||||||
mods: ModifiersState::default(),
|
|
||||||
keys: FxHashSet::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn process(&mut self, key: u32, pressed: bool, keyboard: &WlKeyboard) -> Result<usize> {
|
|
||||||
let xkb_key_state = if pressed {
|
|
||||||
xkb::KeyDirection::Down
|
|
||||||
} else {
|
|
||||||
xkb::KeyDirection::Up
|
|
||||||
};
|
|
||||||
let state_components = self.state.update_key(Keycode::new(key + 8), xkb_key_state);
|
|
||||||
if state_components != 0 {
|
|
||||||
self.mods.update_with(&self.state);
|
|
||||||
keyboard.modifiers(
|
|
||||||
0,
|
|
||||||
self.mods.serialized.depressed,
|
|
||||||
self.mods.serialized.latched,
|
|
||||||
self.mods.serialized.locked,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// if pressed {
|
|
||||||
// println!("Key {key} is being pressed with {state_components} modifiers");
|
|
||||||
// } else {
|
|
||||||
// println!("Key {key} is being released with {state_components} modifiers");
|
|
||||||
// }
|
|
||||||
|
|
||||||
let wl_key_state = if pressed {
|
|
||||||
KeyState::Pressed
|
|
||||||
} else {
|
|
||||||
KeyState::Released
|
|
||||||
};
|
|
||||||
keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state);
|
|
||||||
match wl_key_state {
|
|
||||||
KeyState::Pressed => {
|
|
||||||
self.keys.insert(key);
|
|
||||||
}
|
|
||||||
KeyState::Released => {
|
|
||||||
self.keys.remove(&key);
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
Ok(self.keys.len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe impl Send for KeyboardInfo {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum PointerEvent {
|
|
||||||
Motion(Vector2<f32>),
|
|
||||||
Button {
|
|
||||||
button: u32,
|
|
||||||
state: u32,
|
|
||||||
},
|
|
||||||
Scroll {
|
|
||||||
axis_continuous: Option<Vector2<f32>>,
|
|
||||||
axis_discrete: Option<Vector2<f32>>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum KeyboardEvent {
|
|
||||||
Keymap,
|
|
||||||
Key { key: u32, state: bool },
|
|
||||||
}
|
|
||||||
|
|
||||||
const POINTER_EVENT_TIMEOUT: Duration = Duration::from_millis(50);
|
|
||||||
struct SurfaceInfo {
|
|
||||||
wl_surface: WlWeak<WlSurface>,
|
|
||||||
cursor_sender: watch::Sender<Option<CursorInfo>>,
|
|
||||||
pointer_queue: VecDeque<PointerEvent>,
|
|
||||||
pointer_latest_event: Instant,
|
|
||||||
keyboard_queue: VecDeque<KeyboardEvent>,
|
|
||||||
keyboard_info: Option<KeyboardInfo>,
|
|
||||||
}
|
|
||||||
impl SurfaceInfo {
|
|
||||||
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
|
|
||||||
SurfaceInfo {
|
|
||||||
wl_surface: wl_surface.downgrade(),
|
|
||||||
cursor_sender,
|
|
||||||
pointer_queue: VecDeque::new(),
|
|
||||||
pointer_latest_event: Instant::now(),
|
|
||||||
keyboard_queue: VecDeque::new(),
|
|
||||||
keyboard_info: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn flush(&self) {
|
|
||||||
if let Some(client) = self.wl_surface.upgrade().ok().and_then(|s| s.client()) {
|
|
||||||
if let Some(client_data) = client.get_data::<ClientState>() {
|
|
||||||
client_data.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool {
|
|
||||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
|
||||||
let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; };
|
|
||||||
let Some(focus_size) = core_surface.size() else { return false; };
|
|
||||||
|
|
||||||
if !self.pointer_queue.is_empty() {
|
|
||||||
self.pointer_latest_event = Instant::now();
|
|
||||||
}
|
|
||||||
while let Some(event) = self.pointer_queue.pop_front() {
|
|
||||||
match (locked, event) {
|
|
||||||
(false, PointerEvent::Motion(pos)) => {
|
|
||||||
pointer.enter(
|
|
||||||
SERIAL_COUNTER.inc(),
|
|
||||||
&focus,
|
|
||||||
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
|
||||||
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
|
||||||
);
|
|
||||||
locked = true;
|
|
||||||
}
|
|
||||||
(true, PointerEvent::Motion(pos)) => {
|
|
||||||
pointer.motion(
|
|
||||||
0,
|
|
||||||
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
|
||||||
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
|
||||||
);
|
|
||||||
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(true, PointerEvent::Button { button, state }) => {
|
|
||||||
pointer.button(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
button,
|
|
||||||
match state {
|
|
||||||
0 => ButtonState::Released,
|
|
||||||
1 => ButtonState::Pressed,
|
|
||||||
_ => continue,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(
|
|
||||||
true,
|
|
||||||
PointerEvent::Scroll {
|
|
||||||
axis_continuous,
|
|
||||||
axis_discrete,
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
if let Some(axis_continuous) = axis_continuous {
|
|
||||||
pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64);
|
|
||||||
pointer.axis(0, Axis::VerticalScroll, -axis_continuous.y as f64);
|
|
||||||
}
|
|
||||||
if pointer.version() >= wl_pointer::EVT_AXIS_DISCRETE_SINCE {
|
|
||||||
if let Some(axis_discrete) = axis_discrete {
|
|
||||||
pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32);
|
|
||||||
pointer.axis_discrete(Axis::VerticalScroll, -axis_discrete.y as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE
|
|
||||||
&& axis_discrete.is_none()
|
|
||||||
&& axis_continuous.is_none()
|
|
||||||
{
|
|
||||||
pointer.axis_stop(0, Axis::HorizontalScroll);
|
|
||||||
pointer.axis_stop(0, Axis::VerticalScroll);
|
|
||||||
}
|
|
||||||
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(locked, event) => {
|
|
||||||
warn!(locked, ?event, "Invalid pointer event!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.pointer_latest_event.elapsed() > POINTER_EVENT_TIMEOUT {
|
|
||||||
pointer.leave(SERIAL_COUNTER.inc(), &focus);
|
|
||||||
locked = false;
|
|
||||||
}
|
|
||||||
self.flush();
|
|
||||||
|
|
||||||
locked
|
|
||||||
}
|
|
||||||
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool {
|
|
||||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
|
||||||
let Some(info) = self.keyboard_info.as_mut() else { return true; };
|
|
||||||
|
|
||||||
if !locked {
|
|
||||||
keyboard.enter(0, &focus, vec![]);
|
|
||||||
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
|
||||||
keyboard.repeat_info(0, 0);
|
|
||||||
}
|
|
||||||
locked = info.keymap.send(keyboard).is_ok();
|
|
||||||
}
|
|
||||||
while let Some(event) = self.keyboard_queue.pop_front() {
|
|
||||||
debug!(locked, ?event, "Process keyboard event");
|
|
||||||
match (locked, event) {
|
|
||||||
(true, KeyboardEvent::Keymap) => {
|
|
||||||
let _ = info.keymap.send(keyboard);
|
|
||||||
}
|
|
||||||
(true, KeyboardEvent::Key { key, state }) => {
|
|
||||||
if let Ok(key_count) = info.process(key, state, keyboard) {
|
|
||||||
if key_count == 0 {
|
|
||||||
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(locked, event) => {
|
|
||||||
warn!(locked, ?event, "Invalid keyboard event!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.flush();
|
|
||||||
locked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SeatData {
|
|
||||||
pub client: OnceCell<ClientId>,
|
|
||||||
global_id: OnceCell<GlobalId>,
|
|
||||||
surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>,
|
|
||||||
pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>,
|
|
||||||
keyboard: OnceCell<(WlKeyboard, Mutex<ObjectId>)>,
|
|
||||||
touch: OnceCell<WlTouch>,
|
|
||||||
touches: Mutex<FxHashMap<ObjectId, u32>>,
|
|
||||||
}
|
|
||||||
impl SeatData {
|
|
||||||
pub fn new(dh: &DisplayHandle) -> Arc<Self> {
|
|
||||||
let seat_data = Arc::new(SeatData {
|
|
||||||
client: OnceCell::new(),
|
|
||||||
global_id: OnceCell::new(),
|
|
||||||
surfaces: Mutex::new(FxHashMap::default()),
|
|
||||||
pointer: OnceCell::new(),
|
|
||||||
keyboard: OnceCell::new(),
|
|
||||||
touch: OnceCell::new(),
|
|
||||||
touches: Mutex::new(FxHashMap::default()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let _ = seat_data
|
|
||||||
.global_id
|
|
||||||
.set(dh.create_global::<WaylandState, _, _>(7, seat_data.clone()));
|
|
||||||
|
|
||||||
seat_data
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_keymap(&self, keymap_str: String, surfaces: Vec<WlSurface>) -> Result<()> {
|
|
||||||
let context = xkb::Context::new(0);
|
|
||||||
let keymap =
|
|
||||||
Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
|
||||||
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
|
||||||
let mut panels = self.surfaces.lock();
|
|
||||||
let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")};
|
|
||||||
for surface in surfaces {
|
|
||||||
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
|
|
||||||
if let Some(keyboard_info) = &mut surface_info.keyboard_info {
|
|
||||||
if &keyboard_info.keymap_string == &keymap_str {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
surface_info
|
|
||||||
.keyboard_info
|
|
||||||
.replace(KeyboardInfo::new(keymap_str.clone(), &keymap));
|
|
||||||
|
|
||||||
if *focus.lock() == surface.id() {
|
|
||||||
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
|
|
||||||
let mut surfaces = self.surfaces.lock();
|
|
||||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
|
||||||
surface_info.pointer_queue.push_back(event);
|
|
||||||
drop(surfaces);
|
|
||||||
self.handle_pointer_events();
|
|
||||||
}
|
|
||||||
pub fn keyboard_event(&self, surface: &WlSurface, event: KeyboardEvent) {
|
|
||||||
let mut surfaces = self.surfaces.lock();
|
|
||||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
|
||||||
surface_info.keyboard_queue.push_back(event);
|
|
||||||
drop(surfaces);
|
|
||||||
self.handle_keyboard_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_pointer_events(&self) {
|
|
||||||
let mut surfaces = self.surfaces.lock();
|
|
||||||
let Some((pointer, pointer_focus)) = self.pointer.get() else {return};
|
|
||||||
let mut pointer_focus = pointer_focus.lock();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let locked = !pointer_focus.is_null();
|
|
||||||
// Pick a pointer to focus on if there is none
|
|
||||||
if pointer_focus.is_null() {
|
|
||||||
*pointer_focus = surfaces
|
|
||||||
.iter()
|
|
||||||
.filter(|(_k, v)| !v.pointer_queue.is_empty())
|
|
||||||
.map(|(k, _v)| k)
|
|
||||||
.choose(&mut thread_rng())
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(ObjectId::null());
|
|
||||||
}
|
|
||||||
if pointer_focus.is_null() {
|
|
||||||
// If there's still none, guess we're done with pointer events for the time being
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let Some(surface_info) = surfaces.get_mut(&pointer_focus) else {break};
|
|
||||||
if surface_info.handle_pointer_events(pointer, locked) {
|
|
||||||
// We haven't gotten to a point where we can switch the focus
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
*pointer_focus = ObjectId::null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn handle_keyboard_events(&self) {
|
|
||||||
let mut surfaces = self.surfaces.lock();
|
|
||||||
let Some((keyboard, keyboard_focus)) = self.keyboard.get() else {return};
|
|
||||||
let mut keyboard_focus = keyboard_focus.lock();
|
|
||||||
loop {
|
|
||||||
let locked = !keyboard_focus.is_null();
|
|
||||||
// Pick a keyboard to focus on if there is none
|
|
||||||
if keyboard_focus.is_null() {
|
|
||||||
*keyboard_focus = surfaces
|
|
||||||
.iter()
|
|
||||||
.filter(|(_k, v)| v.keyboard_info.is_some())
|
|
||||||
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
|
||||||
.map(|(k, _v)| k)
|
|
||||||
.choose(&mut thread_rng())
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(ObjectId::null());
|
|
||||||
}
|
|
||||||
// If there's still none, guess we're done with keyboard events for the time being
|
|
||||||
let Some(surface_info) = surfaces.get_mut(&keyboard_focus) else {break};
|
|
||||||
if surface_info.handle_keyboard_events(keyboard, locked) {
|
|
||||||
// We haven't gotten to a point where we can switch the focus
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
*keyboard_focus = ObjectId::null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver<Option<CursorInfo>> {
|
|
||||||
let (tx, rx) = watch::channel(None);
|
|
||||||
self.surfaces
|
|
||||||
.lock()
|
|
||||||
.insert(surface.id(), SurfaceInfo::new(surface, tx));
|
|
||||||
|
|
||||||
rx
|
|
||||||
}
|
|
||||||
pub fn drop_surface(&self, surface: &WlSurface) {
|
|
||||||
self.surfaces.lock().remove(&surface.id());
|
|
||||||
if let Some((_, pointer_focus)) = self.pointer.get() {
|
|
||||||
let mut pointer_focus = pointer_focus.lock();
|
|
||||||
if *pointer_focus == surface.id() {
|
|
||||||
*pointer_focus = ObjectId::null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some((_, keyboard_focus)) = self.keyboard.get() {
|
|
||||||
let mut keyboard_focus = keyboard_focus.lock();
|
|
||||||
if *keyboard_focus == surface.id() {
|
|
||||||
*keyboard_focus = ObjectId::null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.touches.lock().remove(&surface.id());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn touch_down(&self, surface: &WlSurface, id: u32, position: Vector2<f32>) {
|
|
||||||
let Some(touch) = self.touch.get() else {return};
|
|
||||||
touch.down(
|
|
||||||
SERIAL_COUNTER.inc(),
|
|
||||||
0,
|
|
||||||
surface,
|
|
||||||
id as i32,
|
|
||||||
position.x as f64,
|
|
||||||
position.y as f64,
|
|
||||||
);
|
|
||||||
self.touches.lock().insert(surface.id(), id);
|
|
||||||
}
|
|
||||||
pub fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
|
||||||
let Some(touch) = self.touch.get() else {return};
|
|
||||||
touch.motion(0, id as i32, position.x as f64, position.y as f64);
|
|
||||||
}
|
|
||||||
pub fn touch_up(&self, id: u32) {
|
|
||||||
let Some(touch) = self.touch.get() else {return};
|
|
||||||
touch.up(SERIAL_COUNTER.inc(), 0, id as i32);
|
|
||||||
let mut touches = self.touches.lock();
|
|
||||||
touches.retain(|_, tid| *tid != id);
|
|
||||||
}
|
|
||||||
pub fn reset_touches(&self) {
|
|
||||||
let Some(touch) = self.touch.get() else {return};
|
|
||||||
for (_, touch_id) in self.touches.lock().drain() {
|
|
||||||
touch.up(SERIAL_COUNTER.inc(), 0, touch_id as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CursorInfo {
|
pub struct CursorInfo {
|
||||||
pub surface: WlWeak<WlSurface>,
|
pub surface: Option<WlWeak<WlSurface>>,
|
||||||
pub hotspot_x: i32,
|
pub hotspot_x: i32,
|
||||||
pub hotspot_y: i32,
|
pub hotspot_y: i32,
|
||||||
}
|
}
|
||||||
impl CursorInfo {
|
impl CursorInfo {
|
||||||
pub fn cursor_data(&self) -> Option<Geometry> {
|
pub fn cursor_data(&self) -> Option<Geometry> {
|
||||||
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
|
let cursor_size =
|
||||||
|
CoreSurface::from_wl_surface(&self.surface.as_ref()?.upgrade().ok()?)?.size()?;
|
||||||
Some(Geometry {
|
Some(Geometry {
|
||||||
origin: [self.hotspot_x, self.hotspot_y].into(),
|
origin: [self.hotspot_x, self.hotspot_y].into(),
|
||||||
size: cursor_size,
|
size: cursor_size,
|
||||||
@@ -473,134 +84,194 @@ impl CursorInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalDispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
pub struct SeatWrapper {
|
||||||
fn bind(
|
wayland_state: Weak<Mutex<WaylandState>>,
|
||||||
_state: &mut WaylandState,
|
cursor_info_tx: watch::Sender<CursorInfo>,
|
||||||
_handle: &DisplayHandle,
|
pub cursor_info_rx: watch::Receiver<CursorInfo>,
|
||||||
_client: &Client,
|
seat: Seat<WaylandState>,
|
||||||
resource: New<WlSeat>,
|
touches: Mutex<FxHashMap<u32, WlWeak<WlSurface>>>,
|
||||||
data: &Arc<SeatData>,
|
|
||||||
data_init: &mut DataInit<'_, WaylandState>,
|
|
||||||
) {
|
|
||||||
let resource = data_init.init(resource, data.clone());
|
|
||||||
|
|
||||||
if resource.version() >= EVT_NAME_SINCE {
|
|
||||||
resource.name(nanoid!());
|
|
||||||
}
|
|
||||||
|
|
||||||
resource.capabilities(Capability::Pointer | Capability::Keyboard | Capability::Touch);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_view(client: Client, data: &Arc<SeatData>) -> bool {
|
|
||||||
let Some(seat_client) = data.client.get().cloned() else {return false};
|
|
||||||
client.id() == seat_client
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl SeatWrapper {
|
||||||
impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
pub fn new(wayland_state: Weak<Mutex<WaylandState>>, seat: Seat<WaylandState>) -> Self {
|
||||||
fn request(
|
let (cursor_info_tx, cursor_info_rx) = watch::channel(CursorInfo {
|
||||||
_state: &mut WaylandState,
|
surface: None,
|
||||||
_client: &Client,
|
hotspot_x: 0,
|
||||||
_resource: &WlSeat,
|
hotspot_y: 0,
|
||||||
request: wl_seat::Request,
|
});
|
||||||
data: &Arc<SeatData>,
|
SeatWrapper {
|
||||||
_dh: &DisplayHandle,
|
wayland_state,
|
||||||
data_init: &mut DataInit<'_, WaylandState>,
|
cursor_info_tx,
|
||||||
|
cursor_info_rx,
|
||||||
|
seat,
|
||||||
|
touches: Mutex::new(FxHashMap::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn pointer_motion(&self, surface: WlSurface, position: Vector2<f32>) {
|
||||||
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(pointer) = self.seat.get_pointer() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
pointer.motion(
|
||||||
|
&mut state.lock(),
|
||||||
|
Some((surface, (0, 0).into())),
|
||||||
|
&MotionEvent {
|
||||||
|
location: (position.x as f64, position.y as f64).into(),
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn pointer_button(&self, button: u32, pressed: bool) {
|
||||||
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(pointer) = self.seat.get_pointer() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
pointer.button(
|
||||||
|
&mut state.lock(),
|
||||||
|
&ButtonEvent {
|
||||||
|
button,
|
||||||
|
state: if pressed {
|
||||||
|
ButtonState::Pressed
|
||||||
|
} else {
|
||||||
|
ButtonState::Released
|
||||||
|
},
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn pointer_scroll(
|
||||||
|
&self,
|
||||||
|
scroll_distance: Option<Vector2<f32>>,
|
||||||
|
scroll_steps: Option<Vector2<f32>>,
|
||||||
) {
|
) {
|
||||||
match request {
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
wl_seat::Request::GetPointer { id } => {
|
return;
|
||||||
let pointer = data_init.init(id, data.clone());
|
};
|
||||||
let _ = data.pointer.set((pointer, Mutex::new(ObjectId::null())));
|
let mut state = state.lock();
|
||||||
}
|
let Some(pointer) = self.seat.get_pointer() else {
|
||||||
wl_seat::Request::GetKeyboard { id } => {
|
return;
|
||||||
let keyboard = data_init.init(id, data.clone());
|
};
|
||||||
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
pointer.axis(
|
||||||
keyboard.repeat_info(0, 0);
|
&mut state,
|
||||||
}
|
AxisFrame {
|
||||||
let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null())));
|
source: None,
|
||||||
}
|
relative_direction: (
|
||||||
wl_seat::Request::GetTouch { id } => {
|
AxisRelativeDirection::Identical,
|
||||||
let _ = data.touch.set(data_init.init(id, data.clone()));
|
AxisRelativeDirection::Identical,
|
||||||
}
|
),
|
||||||
wl_seat::Request::Release => (),
|
time: 0,
|
||||||
_ => unreachable!(),
|
axis: scroll_distance
|
||||||
}
|
.map(|d| (d.x as f64, d.y as f64))
|
||||||
}
|
.unwrap_or((0.0, 0.0)),
|
||||||
}
|
v120: scroll_steps.map(|d| ((d.x * 120.0) as i32, (d.y * 120.0) as i32)),
|
||||||
|
stop: (false, false),
|
||||||
impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
},
|
||||||
fn request(
|
)
|
||||||
_state: &mut WaylandState,
|
}
|
||||||
_client: &Client,
|
|
||||||
_resource: &WlPointer,
|
pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: &str, keys: Vec<i32>) {
|
||||||
request: wl_pointer::Request,
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
seat_data: &Arc<SeatData>,
|
return;
|
||||||
dh: &DisplayHandle,
|
};
|
||||||
_data_init: &mut DataInit<'_, WaylandState>,
|
let Some(keyboard) = self.seat.get_keyboard() else {
|
||||||
) {
|
return;
|
||||||
match request {
|
};
|
||||||
wl_pointer::Request::SetCursor {
|
let keymaps = KEYMAPS.lock();
|
||||||
serial: _,
|
let Some(keymap) = keymaps.get(keymap_id).cloned() else {
|
||||||
surface,
|
return;
|
||||||
hotspot_x,
|
};
|
||||||
hotspot_y,
|
|
||||||
} => {
|
keyboard.set_focus(
|
||||||
if let Some(surface) = surface.as_ref() {
|
&mut state.lock(),
|
||||||
CoreSurface::add_to(dh.clone(), surface, || (), |_| ());
|
Some(surface),
|
||||||
compositor::with_states(surface, |data| {
|
SERIAL_COUNTER.next_serial(),
|
||||||
if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() {
|
);
|
||||||
core_surface.set_material_offset(1);
|
if keyboard
|
||||||
}
|
.set_keymap_from_string(&mut state.lock(), keymap)
|
||||||
})
|
.is_err()
|
||||||
}
|
{
|
||||||
|
return;
|
||||||
let Some((_, focus)) = seat_data.pointer.get() else {return};
|
}
|
||||||
let focus = focus.lock();
|
for key in keys {
|
||||||
let surfaces = seat_data.surfaces.lock();
|
keyboard.input(
|
||||||
let Some(surface_info) = surfaces.get(&focus) else {return};
|
&mut state.lock(),
|
||||||
let cursor_info = surface.map(|surface| CursorInfo {
|
key.abs() as u32,
|
||||||
surface: surface.downgrade(),
|
if key > 0 {
|
||||||
hotspot_x,
|
KeyState::Pressed
|
||||||
hotspot_y,
|
} else {
|
||||||
});
|
KeyState::Released
|
||||||
let _ = surface_info.cursor_sender.send_replace(cursor_info);
|
},
|
||||||
}
|
SERIAL_COUNTER.next_serial(),
|
||||||
wl_pointer::Request::Release => (),
|
0,
|
||||||
_ => unreachable!(),
|
|_, _, _| FilterResult::Forward::<()>,
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<WlKeyboard, Arc<SeatData>, WaylandState> for WaylandState {
|
pub fn touch_down(&self, surface: WlSurface, id: u32, position: Vector2<f32>) {
|
||||||
fn request(
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
_state: &mut WaylandState,
|
return;
|
||||||
_client: &Client,
|
};
|
||||||
_resource: &WlKeyboard,
|
let Some(touch) = self.seat.get_touch() else {
|
||||||
request: <WlKeyboard as Resource>::Request,
|
return;
|
||||||
_data: &Arc<SeatData>,
|
};
|
||||||
_dh: &DisplayHandle,
|
touch.down(
|
||||||
_data_init: &mut DataInit<'_, WaylandState>,
|
&mut state.lock(),
|
||||||
) {
|
Some((surface, (0, 0).into())),
|
||||||
match request {
|
&DownEvent {
|
||||||
wl_keyboard::Request::Release => (),
|
slot: Some(id).into(),
|
||||||
_ => unreachable!(),
|
location: (position.x as f64, position.y as f64).into(),
|
||||||
}
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
}
|
time: 0,
|
||||||
}
|
},
|
||||||
|
);
|
||||||
impl Dispatch<WlTouch, Arc<SeatData>, WaylandState> for WaylandState {
|
touch.frame(&mut state.lock());
|
||||||
fn request(
|
}
|
||||||
_state: &mut WaylandState,
|
pub fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
||||||
_client: &Client,
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
_resource: &WlTouch,
|
return;
|
||||||
request: <WlTouch as Resource>::Request,
|
};
|
||||||
_data: &Arc<SeatData>,
|
let Some(surface) = self.touches.lock().get(&id).and_then(|c| c.upgrade().ok()) else {
|
||||||
_dh: &DisplayHandle,
|
return;
|
||||||
_data_init: &mut DataInit<'_, WaylandState>,
|
};
|
||||||
) {
|
let Some(touch) = self.seat.get_touch() else {
|
||||||
match request {
|
return;
|
||||||
wl_touch::Request::Release => (),
|
};
|
||||||
_ => unreachable!(),
|
touch.motion(
|
||||||
|
&mut state.lock(),
|
||||||
|
Some((surface, (0, 0).into())),
|
||||||
|
&touch::MotionEvent {
|
||||||
|
slot: Some(id).into(),
|
||||||
|
location: (position.x as f64, position.y as f64).into(),
|
||||||
|
time: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
touch.frame(&mut state.lock());
|
||||||
|
}
|
||||||
|
pub fn touch_up(&self, id: u32) {
|
||||||
|
let Some(state) = self.wayland_state.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(touch) = self.seat.get_touch() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
touch.up(
|
||||||
|
&mut state.lock(),
|
||||||
|
&UpEvent {
|
||||||
|
slot: Some(id).into(),
|
||||||
|
serial: SERIAL_COUNTER.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn reset_touches(&self) {
|
||||||
|
for id in self.touches.lock().keys() {
|
||||||
|
self.touch_up(*id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
606
src/wayland/seat_old.rs
Normal file
606
src/wayland/seat_old.rs
Normal file
@@ -0,0 +1,606 @@
|
|||||||
|
use super::{
|
||||||
|
state::{ClientState, WaylandState},
|
||||||
|
surface::CoreSurface,
|
||||||
|
SERIAL_COUNTER,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
core::task,
|
||||||
|
nodes::items::panel::{Backend, Geometry, PanelItem},
|
||||||
|
};
|
||||||
|
use color_eyre::eyre::{bail, eyre, Result};
|
||||||
|
use mint::Vector2;
|
||||||
|
use nanoid::nanoid;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use rand::{seq::IteratorRandom, thread_rng};
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
use smithay::{
|
||||||
|
input::keyboard::{KeymapFile, ModifiersState},
|
||||||
|
reexports::wayland_server::{
|
||||||
|
backend::{ClientId, GlobalId, ObjectId},
|
||||||
|
protocol::{
|
||||||
|
wl_keyboard::{self, KeyState, WlKeyboard},
|
||||||
|
wl_pointer::{self, Axis, ButtonState, WlPointer},
|
||||||
|
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
|
||||||
|
wl_surface::WlSurface,
|
||||||
|
wl_touch::{self, WlTouch},
|
||||||
|
},
|
||||||
|
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak as WlWeak,
|
||||||
|
},
|
||||||
|
wayland::compositor,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
sync::Arc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
use tokio::sync::watch;
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keycode, Keymap};
|
||||||
|
|
||||||
|
pub fn handle_cursor<B: Backend>(
|
||||||
|
panel_item: &Arc<PanelItem<B>>,
|
||||||
|
mut cursor: watch::Receiver<Option<CursorInfo>>,
|
||||||
|
) {
|
||||||
|
let panel_item_weak = Arc::downgrade(panel_item);
|
||||||
|
let _ = task::new(|| "cursor handler", async move {
|
||||||
|
while cursor.changed().await.is_ok() {
|
||||||
|
let Some(panel_item) = panel_item_weak.upgrade() else {continue};
|
||||||
|
let cursor_info = cursor.borrow();
|
||||||
|
panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KeyboardInfo {
|
||||||
|
keymap_string: String,
|
||||||
|
keymap: KeymapFile,
|
||||||
|
state: xkb::State,
|
||||||
|
mods: ModifiersState,
|
||||||
|
keys: FxHashSet<u32>,
|
||||||
|
}
|
||||||
|
impl KeyboardInfo {
|
||||||
|
pub fn new(keymap_string: String, keymap: &Keymap) -> Self {
|
||||||
|
KeyboardInfo {
|
||||||
|
keymap_string,
|
||||||
|
state: xkb::State::new(keymap),
|
||||||
|
keymap: KeymapFile::new(keymap),
|
||||||
|
mods: ModifiersState::default(),
|
||||||
|
keys: FxHashSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn process(&mut self, key: u32, pressed: bool, keyboard: &WlKeyboard) -> Result<usize> {
|
||||||
|
let xkb_key_state = if pressed {
|
||||||
|
xkb::KeyDirection::Down
|
||||||
|
} else {
|
||||||
|
xkb::KeyDirection::Up
|
||||||
|
};
|
||||||
|
let state_components = self.state.update_key(Keycode::new(key + 8), xkb_key_state);
|
||||||
|
if state_components != 0 {
|
||||||
|
self.mods.update_with(&self.state);
|
||||||
|
keyboard.modifiers(
|
||||||
|
0,
|
||||||
|
self.mods.serialized.depressed,
|
||||||
|
self.mods.serialized.latched,
|
||||||
|
self.mods.serialized.locked,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// if pressed {
|
||||||
|
// println!("Key {key} is being pressed with {state_components} modifiers");
|
||||||
|
// } else {
|
||||||
|
// println!("Key {key} is being released with {state_components} modifiers");
|
||||||
|
// }
|
||||||
|
|
||||||
|
let wl_key_state = if pressed {
|
||||||
|
KeyState::Pressed
|
||||||
|
} else {
|
||||||
|
KeyState::Released
|
||||||
|
};
|
||||||
|
keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state);
|
||||||
|
match wl_key_state {
|
||||||
|
KeyState::Pressed => {
|
||||||
|
self.keys.insert(key);
|
||||||
|
}
|
||||||
|
KeyState::Released => {
|
||||||
|
self.keys.remove(&key);
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
Ok(self.keys.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl Send for KeyboardInfo {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum PointerEvent {
|
||||||
|
Motion(Vector2<f32>),
|
||||||
|
Button {
|
||||||
|
button: u32,
|
||||||
|
state: u32,
|
||||||
|
},
|
||||||
|
Scroll {
|
||||||
|
axis_continuous: Option<Vector2<f32>>,
|
||||||
|
axis_discrete: Option<Vector2<f32>>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum KeyboardEvent {
|
||||||
|
Keymap,
|
||||||
|
Key { key: u32, state: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
const POINTER_EVENT_TIMEOUT: Duration = Duration::from_millis(50);
|
||||||
|
struct SurfaceInfo {
|
||||||
|
wl_surface: WlWeak<WlSurface>,
|
||||||
|
cursor_sender: watch::Sender<Option<CursorInfo>>,
|
||||||
|
pointer_queue: VecDeque<PointerEvent>,
|
||||||
|
pointer_latest_event: Instant,
|
||||||
|
keyboard_queue: VecDeque<KeyboardEvent>,
|
||||||
|
keyboard_info: Option<KeyboardInfo>,
|
||||||
|
}
|
||||||
|
impl SurfaceInfo {
|
||||||
|
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
|
||||||
|
SurfaceInfo {
|
||||||
|
wl_surface: wl_surface.downgrade(),
|
||||||
|
cursor_sender,
|
||||||
|
pointer_queue: VecDeque::new(),
|
||||||
|
pointer_latest_event: Instant::now(),
|
||||||
|
keyboard_queue: VecDeque::new(),
|
||||||
|
keyboard_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn flush(&self) {
|
||||||
|
if let Some(client) = self.wl_surface.upgrade().ok().and_then(|s| s.client()) {
|
||||||
|
if let Some(client_data) = client.get_data::<ClientState>() {
|
||||||
|
client_data.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool {
|
||||||
|
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||||
|
let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; };
|
||||||
|
let Some(focus_size) = core_surface.size() else { return false; };
|
||||||
|
|
||||||
|
if !self.pointer_queue.is_empty() {
|
||||||
|
self.pointer_latest_event = Instant::now();
|
||||||
|
}
|
||||||
|
while let Some(event) = self.pointer_queue.pop_front() {
|
||||||
|
match (locked, event) {
|
||||||
|
(false, PointerEvent::Motion(pos)) => {
|
||||||
|
pointer.enter(
|
||||||
|
SERIAL_COUNTER.inc(),
|
||||||
|
&focus,
|
||||||
|
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
||||||
|
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
||||||
|
);
|
||||||
|
locked = true;
|
||||||
|
}
|
||||||
|
(true, PointerEvent::Motion(pos)) => {
|
||||||
|
pointer.motion(
|
||||||
|
0,
|
||||||
|
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
||||||
|
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
||||||
|
);
|
||||||
|
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true, PointerEvent::Button { button, state }) => {
|
||||||
|
pointer.button(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
button,
|
||||||
|
match state {
|
||||||
|
0 => ButtonState::Released,
|
||||||
|
1 => ButtonState::Pressed,
|
||||||
|
_ => continue,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
true,
|
||||||
|
PointerEvent::Scroll {
|
||||||
|
axis_continuous,
|
||||||
|
axis_discrete,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
if let Some(axis_continuous) = axis_continuous {
|
||||||
|
pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64);
|
||||||
|
pointer.axis(0, Axis::VerticalScroll, -axis_continuous.y as f64);
|
||||||
|
}
|
||||||
|
if pointer.version() >= wl_pointer::EVT_AXIS_DISCRETE_SINCE {
|
||||||
|
if let Some(axis_discrete) = axis_discrete {
|
||||||
|
pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32);
|
||||||
|
pointer.axis_discrete(Axis::VerticalScroll, -axis_discrete.y as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE
|
||||||
|
&& axis_discrete.is_none()
|
||||||
|
&& axis_continuous.is_none()
|
||||||
|
{
|
||||||
|
pointer.axis_stop(0, Axis::HorizontalScroll);
|
||||||
|
pointer.axis_stop(0, Axis::VerticalScroll);
|
||||||
|
}
|
||||||
|
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
||||||
|
pointer.frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(locked, event) => {
|
||||||
|
warn!(locked, ?event, "Invalid pointer event!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.pointer_latest_event.elapsed() > POINTER_EVENT_TIMEOUT {
|
||||||
|
pointer.leave(SERIAL_COUNTER.inc(), &focus);
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
self.flush();
|
||||||
|
|
||||||
|
locked
|
||||||
|
}
|
||||||
|
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool {
|
||||||
|
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||||
|
let Some(info) = self.keyboard_info.as_mut() else { return true; };
|
||||||
|
|
||||||
|
if !locked {
|
||||||
|
keyboard.enter(0, &focus, vec![]);
|
||||||
|
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
||||||
|
keyboard.repeat_info(0, 0);
|
||||||
|
}
|
||||||
|
locked = info.keymap.send(keyboard).is_ok();
|
||||||
|
}
|
||||||
|
while let Some(event) = self.keyboard_queue.pop_front() {
|
||||||
|
debug!(locked, ?event, "Process keyboard event");
|
||||||
|
match (locked, event) {
|
||||||
|
(true, KeyboardEvent::Keymap) => {
|
||||||
|
let _ = info.keymap.send(keyboard);
|
||||||
|
}
|
||||||
|
(true, KeyboardEvent::Key { key, state }) => {
|
||||||
|
if let Ok(key_count) = info.process(key, state, keyboard) {
|
||||||
|
if key_count == 0 {
|
||||||
|
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(locked, event) => {
|
||||||
|
warn!(locked, ?event, "Invalid keyboard event!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.flush();
|
||||||
|
locked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SeatData {
|
||||||
|
pub client: OnceCell<ClientId>,
|
||||||
|
global_id: OnceCell<GlobalId>,
|
||||||
|
surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>,
|
||||||
|
pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>,
|
||||||
|
keyboard: OnceCell<(WlKeyboard, Mutex<ObjectId>)>,
|
||||||
|
touch: OnceCell<WlTouch>,
|
||||||
|
touches: Mutex<FxHashMap<ObjectId, u32>>,
|
||||||
|
}
|
||||||
|
impl SeatData {
|
||||||
|
pub fn new(dh: &DisplayHandle) -> Arc<Self> {
|
||||||
|
let seat_data = Arc::new(SeatData {
|
||||||
|
client: OnceCell::new(),
|
||||||
|
global_id: OnceCell::new(),
|
||||||
|
surfaces: Mutex::new(FxHashMap::default()),
|
||||||
|
pointer: OnceCell::new(),
|
||||||
|
keyboard: OnceCell::new(),
|
||||||
|
touch: OnceCell::new(),
|
||||||
|
touches: Mutex::new(FxHashMap::default()),
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = seat_data
|
||||||
|
.global_id
|
||||||
|
.set(dh.create_global::<WaylandState, _, _>(7, seat_data.clone()));
|
||||||
|
|
||||||
|
seat_data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_keymap(&self, keymap_str: String, surfaces: Vec<WlSurface>) -> Result<()> {
|
||||||
|
let context = xkb::Context::new(0);
|
||||||
|
let keymap =
|
||||||
|
Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
||||||
|
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
||||||
|
let mut panels = self.surfaces.lock();
|
||||||
|
let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")};
|
||||||
|
for surface in surfaces {
|
||||||
|
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
|
||||||
|
if let Some(keyboard_info) = &mut surface_info.keyboard_info {
|
||||||
|
if &keyboard_info.keymap_string == &keymap_str {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
surface_info
|
||||||
|
.keyboard_info
|
||||||
|
.replace(KeyboardInfo::new(keymap_str.clone(), &keymap));
|
||||||
|
|
||||||
|
if *focus.lock() == surface.id() {
|
||||||
|
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
|
||||||
|
let mut surfaces = self.surfaces.lock();
|
||||||
|
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||||
|
surface_info.pointer_queue.push_back(event);
|
||||||
|
drop(surfaces);
|
||||||
|
self.handle_pointer_events();
|
||||||
|
}
|
||||||
|
pub fn keyboard_event(&self, surface: &WlSurface, event: KeyboardEvent) {
|
||||||
|
let mut surfaces = self.surfaces.lock();
|
||||||
|
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||||
|
surface_info.keyboard_queue.push_back(event);
|
||||||
|
drop(surfaces);
|
||||||
|
self.handle_keyboard_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_pointer_events(&self) {
|
||||||
|
let mut surfaces = self.surfaces.lock();
|
||||||
|
let Some((pointer, pointer_focus)) = self.pointer.get() else {return};
|
||||||
|
let mut pointer_focus = pointer_focus.lock();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let locked = !pointer_focus.is_null();
|
||||||
|
// Pick a pointer to focus on if there is none
|
||||||
|
if pointer_focus.is_null() {
|
||||||
|
*pointer_focus = surfaces
|
||||||
|
.iter()
|
||||||
|
.filter(|(_k, v)| !v.pointer_queue.is_empty())
|
||||||
|
.map(|(k, _v)| k)
|
||||||
|
.choose(&mut thread_rng())
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(ObjectId::null());
|
||||||
|
}
|
||||||
|
if pointer_focus.is_null() {
|
||||||
|
// If there's still none, guess we're done with pointer events for the time being
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let Some(surface_info) = surfaces.get_mut(&pointer_focus) else {break};
|
||||||
|
if surface_info.handle_pointer_events(pointer, locked) {
|
||||||
|
// We haven't gotten to a point where we can switch the focus
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*pointer_focus = ObjectId::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn handle_keyboard_events(&self) {
|
||||||
|
let mut surfaces = self.surfaces.lock();
|
||||||
|
let Some((keyboard, keyboard_focus)) = self.keyboard.get() else {return};
|
||||||
|
let mut keyboard_focus = keyboard_focus.lock();
|
||||||
|
loop {
|
||||||
|
let locked = !keyboard_focus.is_null();
|
||||||
|
// Pick a keyboard to focus on if there is none
|
||||||
|
if keyboard_focus.is_null() {
|
||||||
|
*keyboard_focus = surfaces
|
||||||
|
.iter()
|
||||||
|
.filter(|(_k, v)| v.keyboard_info.is_some())
|
||||||
|
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
||||||
|
.map(|(k, _v)| k)
|
||||||
|
.choose(&mut thread_rng())
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(ObjectId::null());
|
||||||
|
}
|
||||||
|
// If there's still none, guess we're done with keyboard events for the time being
|
||||||
|
let Some(surface_info) = surfaces.get_mut(&keyboard_focus) else {break};
|
||||||
|
if surface_info.handle_keyboard_events(keyboard, locked) {
|
||||||
|
// We haven't gotten to a point where we can switch the focus
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
*keyboard_focus = ObjectId::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver<Option<CursorInfo>> {
|
||||||
|
let (tx, rx) = watch::channel(None);
|
||||||
|
self.surfaces
|
||||||
|
.lock()
|
||||||
|
.insert(surface.id(), SurfaceInfo::new(surface, tx));
|
||||||
|
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
pub fn drop_surface(&self, surface: &WlSurface) {
|
||||||
|
self.surfaces.lock().remove(&surface.id());
|
||||||
|
if let Some((_, pointer_focus)) = self.pointer.get() {
|
||||||
|
let mut pointer_focus = pointer_focus.lock();
|
||||||
|
if *pointer_focus == surface.id() {
|
||||||
|
*pointer_focus = ObjectId::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((_, keyboard_focus)) = self.keyboard.get() {
|
||||||
|
let mut keyboard_focus = keyboard_focus.lock();
|
||||||
|
if *keyboard_focus == surface.id() {
|
||||||
|
*keyboard_focus = ObjectId::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.touches.lock().remove(&surface.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn touch_down(&self, surface: &WlSurface, id: u32, position: Vector2<f32>) {
|
||||||
|
let Some(touch) = self.touch.get() else {return};
|
||||||
|
touch.down(
|
||||||
|
SERIAL_COUNTER.inc(),
|
||||||
|
0,
|
||||||
|
surface,
|
||||||
|
id as i32,
|
||||||
|
position.x as f64,
|
||||||
|
position.y as f64,
|
||||||
|
);
|
||||||
|
self.touches.lock().insert(surface.id(), id);
|
||||||
|
}
|
||||||
|
pub fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
||||||
|
let Some(touch) = self.touch.get() else {return};
|
||||||
|
touch.motion(0, id as i32, position.x as f64, position.y as f64);
|
||||||
|
}
|
||||||
|
pub fn touch_up(&self, id: u32) {
|
||||||
|
let Some(touch) = self.touch.get() else {return};
|
||||||
|
touch.up(SERIAL_COUNTER.inc(), 0, id as i32);
|
||||||
|
let mut touches = self.touches.lock();
|
||||||
|
touches.retain(|_, tid| *tid != id);
|
||||||
|
}
|
||||||
|
pub fn reset_touches(&self) {
|
||||||
|
let Some(touch) = self.touch.get() else {return};
|
||||||
|
for (_, touch_id) in self.touches.lock().drain() {
|
||||||
|
touch.up(SERIAL_COUNTER.inc(), 0, touch_id as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CursorInfo {
|
||||||
|
pub surface: WlWeak<WlSurface>,
|
||||||
|
pub hotspot_x: i32,
|
||||||
|
pub hotspot_y: i32,
|
||||||
|
}
|
||||||
|
impl CursorInfo {
|
||||||
|
pub fn cursor_data(&self) -> Option<Geometry> {
|
||||||
|
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
|
||||||
|
Some(Geometry {
|
||||||
|
origin: [self.hotspot_x, self.hotspot_y].into(),
|
||||||
|
size: cursor_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalDispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||||
|
fn bind(
|
||||||
|
_state: &mut WaylandState,
|
||||||
|
_handle: &DisplayHandle,
|
||||||
|
_client: &Client,
|
||||||
|
resource: New<WlSeat>,
|
||||||
|
data: &Arc<SeatData>,
|
||||||
|
data_init: &mut DataInit<'_, WaylandState>,
|
||||||
|
) {
|
||||||
|
let resource = data_init.init(resource, data.clone());
|
||||||
|
|
||||||
|
if resource.version() >= EVT_NAME_SINCE {
|
||||||
|
resource.name(nanoid!());
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.capabilities(Capability::Pointer | Capability::Keyboard | Capability::Touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_view(client: Client, data: &Arc<SeatData>) -> bool {
|
||||||
|
let Some(seat_client) = data.client.get().cloned() else {return false};
|
||||||
|
client.id() == seat_client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||||
|
fn request(
|
||||||
|
_state: &mut WaylandState,
|
||||||
|
_client: &Client,
|
||||||
|
_resource: &WlSeat,
|
||||||
|
request: wl_seat::Request,
|
||||||
|
data: &Arc<SeatData>,
|
||||||
|
_dh: &DisplayHandle,
|
||||||
|
data_init: &mut DataInit<'_, WaylandState>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
wl_seat::Request::GetPointer { id } => {
|
||||||
|
let pointer = data_init.init(id, data.clone());
|
||||||
|
let _ = data.pointer.set((pointer, Mutex::new(ObjectId::null())));
|
||||||
|
}
|
||||||
|
wl_seat::Request::GetKeyboard { id } => {
|
||||||
|
let keyboard = data_init.init(id, data.clone());
|
||||||
|
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
||||||
|
keyboard.repeat_info(0, 0);
|
||||||
|
}
|
||||||
|
let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null())));
|
||||||
|
}
|
||||||
|
wl_seat::Request::GetTouch { id } => {
|
||||||
|
let _ = data.touch.set(data_init.init(id, data.clone()));
|
||||||
|
}
|
||||||
|
wl_seat::Request::Release => (),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
||||||
|
fn request(
|
||||||
|
_state: &mut WaylandState,
|
||||||
|
_client: &Client,
|
||||||
|
_resource: &WlPointer,
|
||||||
|
request: wl_pointer::Request,
|
||||||
|
seat_data: &Arc<SeatData>,
|
||||||
|
dh: &DisplayHandle,
|
||||||
|
_data_init: &mut DataInit<'_, WaylandState>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
wl_pointer::Request::SetCursor {
|
||||||
|
serial: _,
|
||||||
|
surface,
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y,
|
||||||
|
} => {
|
||||||
|
if let Some(surface) = surface.as_ref() {
|
||||||
|
CoreSurface::add_to(dh.clone(), surface, || (), |_| ());
|
||||||
|
compositor::with_states(surface, |data| {
|
||||||
|
if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() {
|
||||||
|
core_surface.set_material_offset(1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some((_, focus)) = seat_data.pointer.get() else {return};
|
||||||
|
let focus = focus.lock();
|
||||||
|
let surfaces = seat_data.surfaces.lock();
|
||||||
|
let Some(surface_info) = surfaces.get(&focus) else {return};
|
||||||
|
let cursor_info = surface.map(|surface| CursorInfo {
|
||||||
|
surface: surface.downgrade(),
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y,
|
||||||
|
});
|
||||||
|
let _ = surface_info.cursor_sender.send_replace(cursor_info);
|
||||||
|
}
|
||||||
|
wl_pointer::Request::Release => (),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WlKeyboard, Arc<SeatData>, WaylandState> for WaylandState {
|
||||||
|
fn request(
|
||||||
|
_state: &mut WaylandState,
|
||||||
|
_client: &Client,
|
||||||
|
_resource: &WlKeyboard,
|
||||||
|
request: <WlKeyboard as Resource>::Request,
|
||||||
|
_data: &Arc<SeatData>,
|
||||||
|
_dh: &DisplayHandle,
|
||||||
|
_data_init: &mut DataInit<'_, WaylandState>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
wl_keyboard::Request::Release => (),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WlTouch, Arc<SeatData>, WaylandState> for WaylandState {
|
||||||
|
fn request(
|
||||||
|
_state: &mut WaylandState,
|
||||||
|
_client: &Client,
|
||||||
|
_resource: &WlTouch,
|
||||||
|
request: <WlTouch as Resource>::Request,
|
||||||
|
_data: &Arc<SeatData>,
|
||||||
|
_dh: &DisplayHandle,
|
||||||
|
_data_init: &mut DataInit<'_, WaylandState>,
|
||||||
|
) {
|
||||||
|
match request {
|
||||||
|
wl_touch::Request::Release => (),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::DisplayWrapper;
|
use super::{seat::SeatWrapper, DisplayWrapper};
|
||||||
use crate::wayland::{drm::wl_drm::WlDrm, seat::SeatData};
|
use crate::wayland::drm::wl_drm::WlDrm;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
@@ -9,6 +9,7 @@ use smithay::{
|
|||||||
renderer::gles::GlesRenderer,
|
renderer::gles::GlesRenderer,
|
||||||
},
|
},
|
||||||
delegate_dmabuf, delegate_output, delegate_shm,
|
delegate_dmabuf, delegate_output, delegate_shm,
|
||||||
|
input::{keyboard::XkbConfig, SeatState},
|
||||||
output::{Mode, Output, Scale, Subpixel},
|
output::{Mode, Output, Scale, Subpixel},
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::{
|
wayland_protocols::xdg::{
|
||||||
@@ -45,7 +46,7 @@ pub struct ClientState {
|
|||||||
pub id: OnceCell<ClientId>,
|
pub id: OnceCell<ClientId>,
|
||||||
pub compositor_state: CompositorClientState,
|
pub compositor_state: CompositorClientState,
|
||||||
pub display: Weak<DisplayWrapper>,
|
pub display: Weak<DisplayWrapper>,
|
||||||
pub seat: Arc<SeatData>,
|
pub seat: Arc<SeatWrapper>,
|
||||||
}
|
}
|
||||||
impl ClientState {
|
impl ClientState {
|
||||||
pub fn flush(&self) {
|
pub fn flush(&self) {
|
||||||
@@ -80,6 +81,8 @@ pub struct WaylandState {
|
|||||||
dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||||
pub drm_formats: Vec<Fourcc>,
|
pub drm_formats: Vec<Fourcc>,
|
||||||
pub dmabuf_tx: UnboundedSender<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
|
pub dmabuf_tx: UnboundedSender<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
|
||||||
|
pub seat_state: SeatState<Self>,
|
||||||
|
pub seat: Arc<SeatWrapper>,
|
||||||
pub output: Output,
|
pub output: Output,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +136,12 @@ impl WaylandState {
|
|||||||
(dmabuf_state, dmabuf_global, None)
|
(dmabuf_state, dmabuf_global, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut seat_state = SeatState::new();
|
||||||
|
let mut seat = seat_state.new_wl_seat(&display_handle, "seat0");
|
||||||
|
seat.add_pointer();
|
||||||
|
seat.add_keyboard(XkbConfig::default(), 200, 25).unwrap();
|
||||||
|
seat.add_touch();
|
||||||
|
|
||||||
let output = Output::new(
|
let output = Output::new(
|
||||||
"1x".to_owned(),
|
"1x".to_owned(),
|
||||||
smithay::output::PhysicalProperties {
|
smithay::output::PhysicalProperties {
|
||||||
@@ -173,6 +182,8 @@ impl WaylandState {
|
|||||||
drm_formats,
|
drm_formats,
|
||||||
dmabuf_state,
|
dmabuf_state,
|
||||||
dmabuf_tx,
|
dmabuf_tx,
|
||||||
|
seat_state,
|
||||||
|
seat: Arc::new(SeatWrapper::new(weak.clone(), seat)),
|
||||||
output,
|
output,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
use super::{popup::PopupData, surface::XdgSurfaceData, ToplevelData};
|
use super::{popup::PopupData, surface::XdgSurfaceData, ToplevelData};
|
||||||
use crate::{
|
use crate::{
|
||||||
nodes::{
|
nodes::{
|
||||||
data::KEYMAPS,
|
|
||||||
drawable::model::ModelPart,
|
drawable::model::ModelPart,
|
||||||
items::panel::{Backend, ChildInfo, PanelItem, PanelItemInitData, SurfaceID},
|
items::panel::{Backend, ChildInfo, PanelItem, PanelItemInitData, SurfaceID},
|
||||||
},
|
},
|
||||||
wayland::{
|
wayland::{seat::SeatWrapper, state::ClientState, surface::CoreSurface, utils, SERIAL_COUNTER},
|
||||||
seat::{CursorInfo, KeyboardEvent, PointerEvent, SeatData},
|
|
||||||
state::ClientState,
|
|
||||||
surface::CoreSurface,
|
|
||||||
utils, SERIAL_COUNTER,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use mint::Vector2;
|
use mint::Vector2;
|
||||||
@@ -18,10 +12,9 @@ use parking_lot::Mutex;
|
|||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use smithay::reexports::{
|
use smithay::reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
||||||
wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak},
|
wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak as WlWeak},
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::watch;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
pub struct XdgToplevelState {
|
pub struct XdgToplevelState {
|
||||||
@@ -30,22 +23,18 @@ pub struct XdgToplevelState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct XdgBackend {
|
pub struct XdgBackend {
|
||||||
toplevel: Weak<XdgToplevel>,
|
toplevel: WlWeak<XdgToplevel>,
|
||||||
toplevel_wl_surface: Weak<WlSurface>,
|
toplevel_wl_surface: WlWeak<WlSurface>,
|
||||||
pub toplevel_state: Mutex<XdgToplevelState>,
|
pub toplevel_state: Mutex<XdgToplevelState>,
|
||||||
popups: Mutex<FxHashMap<String, Weak<WlSurface>>>,
|
popups: Mutex<FxHashMap<String, WlWeak<WlSurface>>>,
|
||||||
pub cursor: watch::Receiver<Option<CursorInfo>>,
|
pub seat: Arc<SeatWrapper>,
|
||||||
pub seat: Arc<SeatData>,
|
|
||||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
|
||||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
|
||||||
}
|
}
|
||||||
impl XdgBackend {
|
impl XdgBackend {
|
||||||
pub fn create(
|
pub fn create(
|
||||||
toplevel_wl_surface: WlSurface,
|
toplevel_wl_surface: WlSurface,
|
||||||
toplevel: XdgToplevel,
|
toplevel: XdgToplevel,
|
||||||
seat: Arc<SeatData>,
|
seat: Arc<SeatWrapper>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cursor = seat.new_surface(&toplevel_wl_surface);
|
|
||||||
XdgBackend {
|
XdgBackend {
|
||||||
toplevel: toplevel.downgrade(),
|
toplevel: toplevel.downgrade(),
|
||||||
toplevel_wl_surface: toplevel_wl_surface.downgrade(),
|
toplevel_wl_surface: toplevel_wl_surface.downgrade(),
|
||||||
@@ -54,15 +43,19 @@ impl XdgBackend {
|
|||||||
activated: false,
|
activated: false,
|
||||||
}),
|
}),
|
||||||
popups: Mutex::new(FxHashMap::default()),
|
popups: Mutex::new(FxHashMap::default()),
|
||||||
cursor,
|
|
||||||
seat,
|
seat,
|
||||||
pointer_grab: Mutex::new(None),
|
|
||||||
keyboard_grab: Mutex::new(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||||
match id {
|
match id {
|
||||||
SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(),
|
SurfaceID::Cursor => self
|
||||||
|
.seat
|
||||||
|
.cursor_info_rx
|
||||||
|
.borrow()
|
||||||
|
.surface
|
||||||
|
.clone()?
|
||||||
|
.upgrade()
|
||||||
|
.ok(),
|
||||||
SurfaceID::Toplevel => self.toplevel_wl_surface(),
|
SurfaceID::Toplevel => self.toplevel_wl_surface(),
|
||||||
SurfaceID::Child(popup) => {
|
SurfaceID::Child(popup) => {
|
||||||
let popups = self.popups.lock();
|
let popups = self.popups.lock();
|
||||||
@@ -146,13 +139,6 @@ impl XdgBackend {
|
|||||||
}
|
}
|
||||||
pub fn drop_popup(&self, panel_item: &PanelItem<XdgBackend>, uid: &str) {
|
pub fn drop_popup(&self, panel_item: &PanelItem<XdgBackend>, uid: &str) {
|
||||||
panel_item.drop_child(uid);
|
panel_item.drop_child(uid);
|
||||||
let Some(popup) = self.popups.lock().remove(uid) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(wl_surface) = popup.upgrade().ok() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.seat.drop_surface(&wl_surface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn child_data(&self) -> FxHashMap<String, ChildInfo> {
|
fn child_data(&self) -> FxHashMap<String, ChildInfo> {
|
||||||
@@ -193,17 +179,21 @@ impl Backend for XdgBackend {
|
|||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| eyre!("Could not get toplevel"))?;
|
.ok_or_else(|| eyre!("Could not get toplevel"))?;
|
||||||
|
|
||||||
let pointer_grab = self.pointer_grab.lock().clone();
|
|
||||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
|
||||||
|
|
||||||
Ok(PanelItemInitData {
|
Ok(PanelItemInitData {
|
||||||
cursor: self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
cursor: (*self.seat.cursor_info_rx.borrow()).cursor_data(),
|
||||||
toplevel: toplevel_data.into(),
|
toplevel: toplevel_data.into(),
|
||||||
children: self.child_data(),
|
children: self.child_data(),
|
||||||
pointer_grab,
|
pointer_grab: None,
|
||||||
keyboard_grab,
|
keyboard_grab: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
fn surface_alive(&self, surface: &SurfaceID) -> bool {
|
||||||
|
match surface {
|
||||||
|
SurfaceID::Cursor => true,
|
||||||
|
SurfaceID::Toplevel => true,
|
||||||
|
SurfaceID::Child(c) => self.popups.lock().contains_key(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||||
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {
|
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {
|
||||||
@@ -237,66 +227,32 @@ impl Backend for XdgBackend {
|
|||||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.seat
|
self.seat.pointer_motion(surface, position)
|
||||||
.pointer_event(&surface, PointerEvent::Motion(position));
|
|
||||||
}
|
}
|
||||||
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool) {
|
fn pointer_button(&self, _surface: &SurfaceID, button: u32, pressed: bool) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
self.seat.pointer_button(button, pressed)
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.seat.pointer_event(
|
|
||||||
&surface,
|
|
||||||
PointerEvent::Button {
|
|
||||||
button,
|
|
||||||
state: if pressed { 1 } else { 0 },
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn pointer_scroll(
|
fn pointer_scroll(
|
||||||
&self,
|
&self,
|
||||||
surface: &SurfaceID,
|
_surface: &SurfaceID,
|
||||||
scroll_distance: Option<Vector2<f32>>,
|
scroll_distance: Option<Vector2<f32>>,
|
||||||
scroll_steps: Option<Vector2<f32>>,
|
scroll_steps: Option<Vector2<f32>>,
|
||||||
) {
|
) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
self.seat.pointer_scroll(scroll_distance, scroll_steps)
|
||||||
return;
|
|
||||||
};
|
|
||||||
self.seat.pointer_event(
|
|
||||||
&surface,
|
|
||||||
PointerEvent::Scroll {
|
|
||||||
axis_continuous: scroll_distance,
|
|
||||||
axis_discrete: scroll_steps,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
|
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let keymaps = KEYMAPS.lock();
|
self.seat.keyboard_keys(surface, keymap_id, keys)
|
||||||
let Some(keymap) = keymaps.get(keymap_id).cloned() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for key in keys {
|
|
||||||
self.seat.keyboard_event(
|
|
||||||
&surface,
|
|
||||||
KeyboardEvent::Key {
|
|
||||||
key: key.abs() as u32,
|
|
||||||
state: key > 0,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
|
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.seat.touch_down(&surface, id, position)
|
self.seat.touch_down(surface, id, position)
|
||||||
}
|
}
|
||||||
fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
||||||
self.seat.touch_move(id, position)
|
self.seat.touch_move(id, position)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use parking_lot::Mutex;
|
|||||||
use smithay::reexports::{
|
use smithay::reexports::{
|
||||||
wayland_protocols::xdg::shell::server::{
|
wayland_protocols::xdg::shell::server::{
|
||||||
xdg_surface::{self, XdgSurface},
|
xdg_surface::{self, XdgSurface},
|
||||||
xdg_toplevel::{XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
xdg_toplevel::{WmCapabilities, XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
||||||
},
|
},
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource,
|
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource,
|
||||||
@@ -58,7 +58,13 @@ impl Dispatch<XdgSurface, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
|||||||
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
||||||
|
|
||||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||||
toplevel.wm_capabilities(vec![3]);
|
toplevel.wm_capabilities(
|
||||||
|
vec![WmCapabilities::Maximize, WmCapabilities::Fullscreen]
|
||||||
|
.into_iter()
|
||||||
|
.map(u32::from)
|
||||||
|
.flat_map(u32::to_ne_bytes)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
toplevel.configure(
|
toplevel.configure(
|
||||||
0,
|
0,
|
||||||
@@ -69,7 +75,7 @@ impl Dispatch<XdgSurface, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
|||||||
.flat_map(u32::to_ne_bytes)
|
.flat_map(u32::to_ne_bytes)
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![1].into_iter().flat_map(u32::to_ne_bytes).collect()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
@@ -100,7 +106,10 @@ impl Dispatch<XdgSurface, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
|||||||
);
|
);
|
||||||
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
||||||
utils::insert_data_raw(&wl_surface, node);
|
utils::insert_data_raw(&wl_surface, node);
|
||||||
handle_cursor(&panel_item, panel_item.backend.cursor.clone());
|
handle_cursor(
|
||||||
|
&panel_item,
|
||||||
|
panel_item.backend.seat.cursor_info_rx.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -172,10 +181,7 @@ impl Dispatch<XdgSurface, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
|||||||
&panel_item,
|
&panel_item,
|
||||||
positioner,
|
positioner,
|
||||||
);
|
);
|
||||||
handle_cursor(
|
handle_cursor(&panel_item, panel_item.backend.seat.cursor_info_rx.clone());
|
||||||
&panel_item,
|
|
||||||
panel_item.backend.seat.new_surface(&wl_surface),
|
|
||||||
);
|
|
||||||
let xdg_popup = data_init.init(id, wl_surface.downgrade());
|
let xdg_popup = data_init.init(id, wl_surface.downgrade());
|
||||||
utils::insert_data(&wl_surface, SurfaceID::Child(uid));
|
utils::insert_data(&wl_surface, SurfaceID::Child(uid));
|
||||||
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl Drop for ToplevelData {
|
|||||||
|
|
||||||
impl Dispatch<XdgToplevel, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
impl Dispatch<XdgToplevel, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
||||||
fn request(
|
fn request(
|
||||||
_state: &mut WaylandState,
|
state: &mut WaylandState,
|
||||||
_client: &Client,
|
_client: &Client,
|
||||||
xdg_toplevel: &XdgToplevel,
|
xdg_toplevel: &XdgToplevel,
|
||||||
request: xdg_toplevel::Request,
|
request: xdg_toplevel::Request,
|
||||||
@@ -230,7 +230,6 @@ impl Dispatch<XdgToplevel, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
|||||||
error!("Couldn't get the panel item");
|
error!("Couldn't get the panel item");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
panel_item.backend.seat.drop_surface(&wl_surface);
|
|
||||||
panel_item.drop_toplevel();
|
panel_item.drop_toplevel();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
Reference in New Issue
Block a user