diff --git a/Cargo.lock b/Cargo.lock index 4fe8c5d2..ee28ae54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6659,6 +6659,7 @@ dependencies = [ "log", "serde", "serde_json", + "slotmap", "smallvec", "smol", ] @@ -7237,6 +7238,7 @@ dependencies = [ "serde", "serde_json", "serde_json5", + "slotmap", "smol", "strum", "walkdir", diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml index a39eeb4e..76f73626 100644 --- a/wayvr-ipc/Cargo.toml +++ b/wayvr-ipc/Cargo.toml @@ -15,6 +15,7 @@ bytes.workspace = true interprocess.workspace = true log.workspace = true serde.workspace = true +slotmap.workspace = true smallvec.workspace = true # client-only deps diff --git a/wayvr-ipc/src/client.rs b/wayvr-ipc/src/client.rs index 9625130e..947ac456 100644 --- a/wayvr-ipc/src/client.rs +++ b/wayvr-ipc/src/client.rs @@ -1,6 +1,8 @@ use bytes::BufMut; use interprocess::local_socket::{self, ToNsName}; use serde::Serialize; +use slotmap::DenseSlotMap; +use slotmap::new_key_type; use smallvec::SmallVec; use smol::io::AsyncReadExt; use smol::io::AsyncWriteExt; @@ -9,7 +11,6 @@ use std::os::unix::net::UnixStream as StdUnixStream; use std::sync::{Arc, Weak}; use crate::{ - gen_id, ipc::{self, Serial}, packet_client::{self, HandsfreeParams, PacketClient}, packet_server::{self, PacketServer}, @@ -22,12 +23,9 @@ pub struct QueuedPacket { packet: Option, } -gen_id!( - QueuedPacketVec, - QueuedPacket, - QueuedPacketCell, - QueuedPacketHandle -); +new_key_type! { + pub struct QueuedPacketHandle; +} #[derive(Debug, Serialize, Clone)] pub struct AuthInfo { @@ -41,7 +39,7 @@ pub struct WayVRClient { sender: SenderMutex, cancel_tx: async_channel::Sender<()>, exiting: bool, - queued_packets: QueuedPacketVec, + queued_packets: DenseSlotMap, pub auth: Option, pub on_signal: Option, } @@ -156,7 +154,7 @@ impl WayVRClient { sender: sender.clone(), cancel_tx, exiting: false, - queued_packets: QueuedPacketVec::new(), + queued_packets: Default::default(), auth: None, on_signal: None, })); @@ -263,12 +261,7 @@ impl WayVRClient { // queue packet to read if it contains a serial response if let Some(serial) = packet.serial() { - for qpacket in &mut client.queued_packets.vec { - let Some(qpacket) = qpacket else { - continue; - }; - - let qpacket = &mut qpacket.obj; + for (_, qpacket) in &mut client.queued_packets { if qpacket.serial != *serial { continue; //skip } @@ -306,7 +299,7 @@ impl WayVRClient { // Send packet to the server let queued_packet_handle = { let mut client = client_mtx.lock().await; - let handle = client.queued_packets.add(QueuedPacket { + let handle = client.queued_packets.insert(QueuedPacket { notifier: notifier.clone(), packet: None, // will be filled after notify serial, @@ -329,7 +322,7 @@ impl WayVRClient { let cell = client .queued_packets - .get_mut(&queued_packet_handle) + .get_mut(queued_packet_handle) .ok_or(anyhow::anyhow!( "missing packet cell, this shouldn't happen" ))?; @@ -338,7 +331,7 @@ impl WayVRClient { anyhow::bail!("packet is None, this shouldn't happen"); }; - client.queued_packets.remove(&queued_packet_handle); + client.queued_packets.remove(queued_packet_handle); Ok(packet) } diff --git a/wayvr-ipc/src/packet_server.rs b/wayvr-ipc/src/packet_server.rs index 12ed8fe7..bdbfecd5 100644 --- a/wayvr-ipc/src/packet_server.rs +++ b/wayvr-ipc/src/packet_server.rs @@ -21,14 +21,12 @@ pub struct Disconnect { #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] pub struct WvrProcessHandle { - pub idx: u32, - pub generation: u64, + pub user: u64, } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] pub struct WvrWindowHandle { - pub idx: u32, - pub generation: u64, + pub user: u64, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/wayvr-ipc/src/util/handle.rs b/wayvr-ipc/src/util/handle.rs deleted file mode 100644 index e9e51305..00000000 --- a/wayvr-ipc/src/util/handle.rs +++ /dev/null @@ -1,171 +0,0 @@ -#[macro_export] -macro_rules! gen_id { - ( - $container_name:ident, - $instance_name:ident, - $cell_name:ident, - $handle_name:ident) => { - //ThingCell - pub struct $cell_name { - pub obj: $instance_name, - pub generation: u64, - } - - //ThingVec - pub struct $container_name { - // Vec> - pub vec: Vec>, - - cur_generation: u64, - } - - //ThingHandle - #[derive(Default, Clone, Copy, PartialEq, Hash, Eq)] - pub struct $handle_name { - idx: u32, - generation: u64, - } - - #[allow(dead_code)] - impl $handle_name { - pub fn reset(&mut self) { - self.generation = 0; - } - - pub fn is_set(&self) -> bool { - self.generation > 0 - } - - pub fn id(&self) -> u32 { - self.idx - } - - pub fn new(idx: u32, generation: u64) -> Self { - Self { idx, generation } - } - } - - //ThingVec - #[allow(dead_code)] - impl $container_name { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - vec: Vec::new(), - cur_generation: 0, - } - } - - pub fn iter(&self, callback: &dyn Fn($handle_name, &$instance_name)) { - for (idx, opt_cell) in self.vec.iter().enumerate() { - if let Some(cell) = opt_cell { - let handle = $container_name::get_handle(&cell, idx); - callback(handle, &cell.obj); - } - } - } - - pub fn iter_mut(&mut self, callback: &mut dyn FnMut($handle_name, &mut $instance_name)) { - for (idx, opt_cell) in self.vec.iter_mut().enumerate() { - if let Some(cell) = opt_cell { - let handle = $container_name::get_handle(&cell, idx); - callback(handle, &mut cell.obj); - } - } - } - - pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name { - $handle_name { - idx: idx as u32, - generation: cell.generation, - } - } - - fn find_unused_idx(&mut self) -> Option { - for (num, obj) in self.vec.iter().enumerate() { - if obj.is_none() { - return Some(num as u32); - } - } - None - } - - pub fn add(&mut self, obj: $instance_name) -> $handle_name { - self.cur_generation += 1; - let generation = self.cur_generation; - - let unused_idx = self.find_unused_idx(); - - let idx = if let Some(idx) = unused_idx { - idx - } else { - self.vec.len() as u32 - }; - - let handle = $handle_name { idx, generation }; - - let cell = $cell_name { obj, generation }; - - if let Some(idx) = unused_idx { - self.vec[idx as usize] = Some(cell); - } else { - self.vec.push(Some(cell)) - } - - handle - } - - pub fn remove(&mut self, handle: &$handle_name) { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return; - } - - // Remove only if the generation matches - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - self.vec[handle.idx as usize] = None; - } - } - } - - pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&cell.obj); - } - } - - None - } - - pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &mut self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&mut cell.obj); - } - } - - None - } - } - }; -} - -/* Example usage: -gen_id!(ThingVec, ThingInstance, ThingCell, ThingHandle); - -struct ThingInstance {} - -impl ThingInstance {} - */ diff --git a/wayvr-ipc/src/util/mod.rs b/wayvr-ipc/src/util/mod.rs index cf2f06fe..68a42c0b 100644 --- a/wayvr-ipc/src/util/mod.rs +++ b/wayvr-ipc/src/util/mod.rs @@ -1,4 +1,2 @@ -pub mod handle; - #[cfg(feature = "client")] pub mod notifier; diff --git a/wayvr/Cargo.toml b/wayvr/Cargo.toml index 64b5a22b..8f608ce4 100644 --- a/wayvr/Cargo.toml +++ b/wayvr/Cargo.toml @@ -36,7 +36,7 @@ idmap-derive.workspace = true input = { version = "0.9.1", default-features = false, - features = ["libinput_1_19", "udev"], + features = ["libinput_1_19", "udev"] } interprocess.workspace = true libc.workspace = true diff --git a/wayvr/src/backend/wayvr/client.rs b/wayvr/src/backend/wayvr/client.rs index 95dfc97a..2bf7d32f 100644 --- a/wayvr/src/backend/wayvr/client.rs +++ b/wayvr/src/backend/wayvr/client.rs @@ -8,6 +8,7 @@ use std::{ use anyhow::Context; use glam::{DVec2, Vec2}; +use slotmap::DenseSlotMap; use smithay::{ backend::input::{Axis, AxisSource, ButtonState, Keycode}, input::{ @@ -146,7 +147,7 @@ impl WayVRCompositor { fn accept_connection( &mut self, stream: UnixStream, - processes: &mut process::ProcessVec, + processes: &mut DenseSlotMap, ) -> anyhow::Result<()> { let client = self .display @@ -154,13 +155,13 @@ impl WayVRCompositor { .insert_client(stream, Arc::new(comp::ClientState::default())) .unwrap(); - let creds = client.get_credentials(&self.display.handle())?; + let credentials = client.get_credentials(&self.display.handle())?; - let process_env = get_wayvr_env_from_pid(creds.pid)?; + let process_env = get_wayvr_env_from_pid(credentials.pid)?; // Find suitable auth key from the process list - for p in processes.vec.iter().flatten() { - if let process::Process::Managed(process) = &p.obj + for (_, process) in processes { + if let process::Process::Managed(process) = &process && let Some(auth_key) = &process_env.display_auth { // Find process with matching auth key @@ -168,7 +169,7 @@ impl WayVRCompositor { // Add client self.add_client(WayVRClient { client, - pid: creds.pid as u32, + pid: credentials.pid as u32, }); return Ok(()); } @@ -179,7 +180,7 @@ impl WayVRCompositor { // Treat external processes exclusively (spawned by the user or external program) log::warn!( "External process ID {} connected to this Wayland server", - creds.pid + credentials.pid ); self.state @@ -187,13 +188,16 @@ impl WayVRCompositor { .send(WayVRTask::NewExternalProcess(ExternalProcessRequest { env: process_env, client, - pid: creds.pid as u32, + pid: credentials.pid as u32, })); Ok(()) } - fn accept_connections(&mut self, processes: &mut process::ProcessVec) -> anyhow::Result<()> { + fn accept_connections( + &mut self, + processes: &mut DenseSlotMap, + ) -> anyhow::Result<()> { if let Some(stream) = self.listener.accept()? && let Err(e) = self.accept_connection(stream, processes) { @@ -203,7 +207,10 @@ impl WayVRCompositor { Ok(()) } - pub fn tick_wayland(&mut self, processes: &mut process::ProcessVec) -> anyhow::Result<()> { + pub fn tick_wayland( + &mut self, + processes: &mut DenseSlotMap, + ) -> anyhow::Result<()> { if let Err(e) = self.accept_connections(processes) { log::error!("accept_connections failed: {e}"); } diff --git a/wayvr/src/backend/wayvr/handle.rs b/wayvr/src/backend/wayvr/handle.rs deleted file mode 100644 index b419dc3c..00000000 --- a/wayvr/src/backend/wayvr/handle.rs +++ /dev/null @@ -1,177 +0,0 @@ -#[macro_export] -macro_rules! gen_id { - ( - $container_name:ident, - $instance_name:ident, - $cell_name:ident, - $handle_name:ident) => { - //ThingCell - #[derive(Debug)] - pub struct $cell_name { - pub obj: $instance_name, - pub generation: u64, - } - - //ThingVec - #[derive(Debug)] - pub struct $container_name { - // Vec> - pub vec: Vec>, - - cur_generation: u64, - } - - //ThingHandle - #[derive(Default, Debug, Clone, Copy, PartialEq, Hash, Eq)] - pub struct $handle_name { - idx: u32, - generation: u64, - } - - #[allow(dead_code)] - impl $handle_name { - pub const fn reset(&mut self) { - self.generation = 0; - } - - pub const fn is_set(&self) -> bool { - self.generation > 0 - } - - pub const fn id(&self) -> u32 { - self.idx - } - - pub const fn new(idx: u32, generation: u64) -> Self { - Self { idx, generation } - } - } - - //ThingVec - impl $container_name { - pub const fn new() -> Self { - Self { - vec: Vec::new(), - cur_generation: 0, - } - } - - pub fn iter(&self) -> impl Iterator { - self.vec.iter().enumerate().filter_map(|(idx, opt_cell)| { - opt_cell.as_ref().map(|cell| { - let handle = $container_name::get_handle(&cell, idx); - (handle, &cell.obj) - }) - }) - } - - #[allow(dead_code)] - pub fn iter_mut( - &mut self, - ) -> impl Iterator { - self.vec - .iter_mut() - .enumerate() - .filter_map(|(idx, opt_cell)| { - opt_cell.as_mut().map(|cell| { - let handle = $container_name::get_handle(&cell, idx); - (handle, &mut cell.obj) - }) - }) - } - - pub const fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name { - $handle_name { - idx: idx as u32, - generation: cell.generation, - } - } - - fn find_unused_idx(&mut self) -> Option { - for (num, obj) in self.vec.iter().enumerate() { - if obj.is_none() { - return Some(num as u32); - } - } - None - } - - pub fn add(&mut self, obj: $instance_name) -> $handle_name { - self.cur_generation += 1; - let generation = self.cur_generation; - - let unused_idx = self.find_unused_idx(); - - let idx = if let Some(idx) = unused_idx { - idx - } else { - self.vec.len() as u32 - }; - - let handle = $handle_name { idx, generation }; - - let cell = $cell_name { obj, generation }; - - if let Some(idx) = unused_idx { - self.vec[idx as usize] = Some(cell); - } else { - self.vec.push(Some(cell)) - } - - handle - } - - pub fn remove(&mut self, handle: &$handle_name) { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return; - } - - // Remove only if the generation matches - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - self.vec[handle.idx as usize] = None; - } - } - } - - pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&cell.obj); - } - } - - None - } - - pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &mut self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&mut cell.obj); - } - } - - None - } - } - }; -} - -/* Example usage: -gen_id!(ThingVec, ThingInstance, ThingCell, ThingHandle); - -struct ThingInstance {} - -impl ThingInstance {} - */ diff --git a/wayvr/src/backend/wayvr/mod.rs b/wayvr/src/backend/wayvr/mod.rs index e41df3c8..d30550ea 100644 --- a/wayvr/src/backend/wayvr/mod.rs +++ b/wayvr/src/backend/wayvr/mod.rs @@ -1,6 +1,5 @@ pub mod client; mod comp; -mod handle; pub mod hit_test; mod image_importer; mod input_capture; @@ -11,8 +10,7 @@ pub mod window; use anyhow::Context; use comp::Application; use glam::{DVec2, Vec2}; -use process::ProcessVec; -use slotmap::SecondaryMap; +use slotmap::{DenseSlotMap, SecondaryMap}; use smallvec::SmallVec; use smithay::{ desktop::PopupManager, @@ -136,7 +134,7 @@ pub enum WayVRTask { pub struct WvrServerState { pub manager: client::WayVRCompositor, pub wm: window::WindowManager, - pub processes: process::ProcessVec, + pub processes: DenseSlotMap, pub tasks: SyncEventQueue, ticks: u64, cur_modifiers: u8, @@ -298,7 +296,7 @@ impl WvrServerState { Ok(Self { manager: client::WayVRCompositor::new(state, display, seat_keyboard, seat_pointer)?, - processes: ProcessVec::new(), + processes: Default::default(), wm: window::WindowManager::new(), ticks: 0, tasks, @@ -341,7 +339,7 @@ impl WvrServerState { } for p_handle in &to_remove { - wvr_server.processes.remove(p_handle); + wvr_server.processes.remove(*p_handle); wvr_server.process_removed(&mut app.tasks, *p_handle); } @@ -399,7 +397,7 @@ impl WvrServerState { // Size, icon & fallback title comes from process let (fallback_size, pos, fallback_title, icon, is_cage) = - match wvr_server.processes.get(&process_handle) { + match wvr_server.processes.get(process_handle) { Some(Process::Managed(p)) => { let size: Size = Size::new(p.resolution[0] as _, p.resolution[1] as _); @@ -529,7 +527,7 @@ impl WvrServerState { let process_handle = wvr_server .wm .windows - .get(&window_handle) + .get(window_handle) .map(|window| window.process); if let Some(oid) = wvr_server.window_to_overlay.remove(&window_handle) { @@ -601,7 +599,7 @@ impl WvrServerState { } } WayVRTask::ProcessTerminationRequest(process_handle, signal) => { - if let Some(process) = wvr_server.processes.get_mut(&process_handle) { + if let Some(process) = wvr_server.processes.get_mut(process_handle) { process.kill(signal); } @@ -625,7 +623,7 @@ impl WvrServerState { } } WayVRTask::CloseWindowRequest(window_handle) => { - if let Some(w) = wvr_server.wm.windows.get(&window_handle) { + if let Some(w) = wvr_server.wm.windows.get(window_handle) { log::info!("Sending window close to {window_handle:?}"); w.toplevel.send_close(); } else { @@ -684,7 +682,7 @@ impl WvrServerState { self.overlay_to_window.insert(oid, window); self.window_to_overlay.insert(window, oid); - if let Some(process_handle) = self.wm.windows.get(&window).map(|window| window.process) { + if let Some(process_handle) = self.wm.windows.get(window).map(|window| window.process) { let overlays = self.process_overlays.entry(process_handle).or_default(); overlays.retain(|other| *other != oid); overlays.push(oid); @@ -719,7 +717,7 @@ impl WvrServerState { } for hnd in &to_remove { - self.wm.windows.remove(hnd); + self.wm.windows.remove(*hnd); } self.process_overlays.remove(&process); @@ -740,7 +738,7 @@ impl WvrServerState { WvrHitTarget::Toplevel { .. } => self .wm .windows - .get(&hover_window) + .get(hover_window) .map(|w| { let surface = w.toplevel.wl_surface().clone(); PointerFocusTarget::Surface { @@ -966,7 +964,7 @@ impl WvrServerState { break 'mouse_update; }; - let Some(window) = self.wm.windows.get(&hover.hover_window) else { + let Some(window) = self.wm.windows.get(hover.hover_window) else { break 'mouse_update; }; let toplevel = window.toplevel.wl_surface().clone(); @@ -1045,7 +1043,7 @@ impl WvrServerState { let surface = self .wm .windows - .get(&hover_window) + .get(hover_window) .map(|x| x.toplevel.wl_surface().clone()); ( @@ -1057,7 +1055,7 @@ impl WvrServerState { let surface = self .wm .windows - .get(&hover_window) + .get(hover_window) .map(|x| x.toplevel.wl_surface().clone()); (None, pressed.then_some(surface).flatten()) } @@ -1207,7 +1205,7 @@ impl WvrServerState { pub fn add_external_process(&mut self, pid: u32) -> process::ProcessHandle { self.processes - .add(process::Process::External(process::ExternalProcess { pid })) + .insert(process::Process::External(process::ExternalProcess { pid })) } #[allow(clippy::too_many_arguments)] @@ -1243,7 +1241,7 @@ impl WvrServerState { let handle = self .processes - .add(process::Process::Managed(process::WayVRProcess { + .insert(process::Process::Managed(process::WayVRProcess { auth_key, child, exec_path: String::from(exec_path), diff --git a/wayvr/src/backend/wayvr/process.rs b/wayvr/src/backend/wayvr/process.rs index 811fc026..3841a679 100644 --- a/wayvr/src/backend/wayvr/process.rs +++ b/wayvr/src/backend/wayvr/process.rs @@ -1,9 +1,8 @@ use std::{collections::HashMap, io::Read, sync::Arc}; +use slotmap::{DenseSlotMap, new_key_type}; use wayvr_ipc::{packet_client, packet_server}; -use crate::gen_id; - #[derive(Debug)] #[allow(dead_code)] pub struct WayVRProcess { @@ -176,24 +175,26 @@ impl ExternalProcess { } } -gen_id!(ProcessVec, Process, ProcessCell, ProcessHandle); +new_key_type! { + pub struct ProcessHandle; +} -pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option { +pub fn find_by_pid( + processes: &DenseSlotMap, + pid: u32, +) -> Option { log::debug!("Finding process with PID {pid}"); - for (idx, cell) in processes.vec.iter().enumerate() { - let Some(cell) = cell else { - continue; - }; - match &cell.obj { + for (handle, process) in processes { + match &process { Process::Managed(wayvr_process) => { if wayvr_process.child.id() == pid { - return Some(ProcessVec::get_handle(cell, idx)); + return Some(handle); } } Process::External(external_process) => { if external_process.pid == pid { - return Some(ProcessVec::get_handle(cell, idx)); + return Some(handle); } } } @@ -202,14 +203,11 @@ pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option { log::debug!("Finding by PID failed, trying WAYVR_DISPLAY_AUTH..."); if let Ok(Some(value)) = get_process_env_value(pid as i32, "WAYVR_DISPLAY_AUTH") { - for (idx, cell) in processes.vec.iter().enumerate() { - let Some(cell) = cell else { - continue; - }; - if let Process::Managed(wayvr_process) = &cell.obj + for (handle, process) in processes { + if let Process::Managed(wayvr_process) = &process && wayvr_process.auth_key == value { - return Some(ProcessVec::get_handle(cell, idx)); + return Some(handle); } } } @@ -219,17 +217,13 @@ pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option { } impl ProcessHandle { - pub const fn from_packet(handle: packet_server::WvrProcessHandle) -> Self { - Self { - generation: handle.generation, - idx: handle.idx, - } + pub fn from_packet(handle: packet_server::WvrProcessHandle) -> Self { + Self::from(slotmap::KeyData::from_ffi(handle.user)) } - pub const fn as_packet(&self) -> packet_server::WvrProcessHandle { + pub fn as_packet(&self) -> packet_server::WvrProcessHandle { packet_server::WvrProcessHandle { - idx: self.idx, - generation: self.generation, + user: self.0.as_ffi(), } } } diff --git a/wayvr/src/backend/wayvr/window.rs b/wayvr/src/backend/wayvr/window.rs index 47899987..9a65c3fb 100644 --- a/wayvr/src/backend/wayvr/window.rs +++ b/wayvr/src/backend/wayvr/window.rs @@ -1,11 +1,12 @@ use std::rc::Rc; use glam::DVec2; +use slotmap::{DenseSlotMap, new_key_type}; use smithay::utils::{Logical, Size}; use smithay::wayland::shell::xdg::ToplevelSurface; use wayvr_ipc::packet_server; -use crate::{backend::wayvr::process, gen_id}; +use crate::backend::wayvr::process; #[derive(Debug)] pub struct Window { @@ -113,27 +114,24 @@ pub struct MouseState { #[derive(Debug)] pub struct WindowManager { - pub windows: WindowVec, + pub windows: DenseSlotMap, pub mouse: Option, pub keyboard_focus: Option, } impl WindowManager { - pub const fn new() -> Self { + pub fn new() -> Self { Self { - windows: WindowVec::new(), + windows: Default::default(), mouse: None, keyboard_focus: None, } } pub fn find_window_handle(&self, toplevel: &ToplevelSurface) -> Option { - for (idx, cell) in self.windows.vec.iter().enumerate() { - if let Some(cell) = cell { - let window = &cell.obj; - if *window.toplevel == *toplevel { - return Some(WindowVec::get_handle(cell, idx)); - } + for (handle, window) in &self.windows { + if *window.toplevel == *toplevel { + return Some(handle); } } None @@ -151,28 +149,26 @@ impl WindowManager { ) -> WindowHandle { let mut window = Window::new(toplevel, process, bounds, min_size, max_size); window.remember_committed_size(Size::new(size_x as i32, size_y as i32)); - self.windows.add(window) + self.windows.insert(window) } pub fn remove_window(&mut self, window_handle: WindowHandle) { - self.windows.remove(&window_handle); + self.windows.remove(window_handle); } } -gen_id!(WindowVec, Window, WindowCell, WindowHandle); +new_key_type! { + pub struct WindowHandle; +} impl WindowHandle { - pub const fn from_packet(handle: packet_server::WvrWindowHandle) -> Self { - Self { - generation: handle.generation, - idx: handle.idx, - } + pub fn from_packet(handle: packet_server::WvrWindowHandle) -> Self { + Self::from(slotmap::KeyData::from_ffi(handle.user)) } - pub const fn as_packet(&self) -> packet_server::WvrWindowHandle { + pub fn as_packet(&self) -> packet_server::WvrWindowHandle { packet_server::WvrWindowHandle { - idx: self.idx, - generation: self.generation, + user: self.0.as_ffi(), } } } diff --git a/wayvr/src/ipc/ipc_server.rs b/wayvr/src/ipc/ipc_server.rs index d949ffe0..0320effb 100644 --- a/wayvr/src/ipc/ipc_server.rs +++ b/wayvr/src/ipc/ipc_server.rs @@ -227,7 +227,7 @@ impl Connection { .wvr_server .wm .windows - .get_mut(&wayvr::window::WindowHandle::from_packet(handle)) + .get_mut(wayvr::window::WindowHandle::from_packet(handle)) { window.visible = visible; } @@ -272,19 +272,8 @@ impl Connection { let list: Vec = params .wvr_server .processes - .vec .iter() - .enumerate() - .filter_map(|(idx, opt_cell)| { - let Some(cell) = opt_cell else { - return None; - }; - let process = &cell.obj; - Some(process.to_packet(wayvr::process::ProcessHandle::new( - idx as u32, - cell.generation, - ))) - }) + .map(|(handle, process)| process.to_packet(handle)) .collect(); send_packet( @@ -306,7 +295,7 @@ impl Connection { use crate::backend::wayvr::process::KillSignal; let native_handle = &wayvr::process::ProcessHandle::from_packet(process_handle); - let process = params.wvr_server.processes.get_mut(native_handle); + let process = params.wvr_server.processes.get_mut(*native_handle); let Some(process) = process else { return; @@ -325,7 +314,7 @@ impl Connection { let process = params .wvr_server .processes - .get(native_handle) + .get(*native_handle) .map(|process| process.to_packet(*native_handle)); send_packet( diff --git a/wayvr/src/overlays/dashboard.rs b/wayvr/src/overlays/dashboard.rs index e3824542..fe972925 100644 --- a/wayvr/src/overlays/dashboard.rs +++ b/wayvr/src/overlays/dashboard.rs @@ -427,7 +427,7 @@ impl DashInterface for DashInterfaceLive { let handle = ProcessHandle::from_packet(handle); wvr_server .processes - .get(&handle) + .get(handle) .map(|x| x.to_packet(handle)) } diff --git a/wayvr/src/overlays/wayvr.rs b/wayvr/src/overlays/wayvr.rs index 90f5ad25..69bd52e1 100644 --- a/wayvr/src/overlays/wayvr.rs +++ b/wayvr/src/overlays/wayvr.rs @@ -97,7 +97,7 @@ pub fn create_wl_window_overlay( let resizable = app .wvr_server .as_mut() - .and_then(|wvr| wvr.wm.windows.get(&window)) + .and_then(|wvr| wvr.wm.windows.get(window)) .map(|w| w.resizable()) .unwrap_or(false); @@ -284,7 +284,7 @@ impl WvrWindowBackend { self.resizable = app .wvr_server .as_mut() - .and_then(|wvr| wvr.wm.windows.get(&self.window)) + .and_then(|wvr| wvr.wm.windows.get(self.window)) .map(|w| w.resizable()) .unwrap_or(false); @@ -475,7 +475,7 @@ impl WvrWindowBackend { let committed = Size::new(inner_extent[0].max(1) as i32, inner_extent[1].max(1) as i32); - let Some(window) = wvr_server.wm.windows.get_mut(&self.window) else { + let Some(window) = wvr_server.wm.windows.get_mut(self.window) else { return Ok(()); }; @@ -516,7 +516,7 @@ impl OverlayBackend for WvrWindowBackend { let Some(toplevel) = app .wvr_server .as_ref() - .and_then(|sv| sv.wm.windows.get(&self.window)) + .and_then(|sv| sv.wm.windows.get(self.window)) .map(|win| win.toplevel.clone()) else { log::debug!( @@ -742,7 +742,7 @@ impl OverlayBackend for WvrWindowBackend { } } - if let Some(window) = wvr_server.wm.windows.get(&self.window) { + if let Some(window) = wvr_server.wm.windows.get(self.window) { let surface_id = window.toplevel.wl_surface().id(); state.send_frame_callbacks_for_surface_id(&surface_id); } @@ -774,7 +774,7 @@ impl OverlayBackend for WvrWindowBackend { } OverlayEventData::WvrCommand(WvrCommand::ReloadTitle) => { let wvr_server = app.wvr_server.as_mut().unwrap(); //never None - if let Some(window) = wvr_server.wm.windows.get(&self.window) { + if let Some(window) = wvr_server.wm.windows.get(self.window) { let title = with_states(window.toplevel.wl_surface(), |states| { states .data_map @@ -795,14 +795,14 @@ impl OverlayBackend for WvrWindowBackend { } OverlayEventData::WvrCommand(WvrCommand::KillProcess(signal)) => { let wvr_server = app.wvr_server.as_mut().unwrap(); - let Some(p) = wvr_server.wm.windows.get(&self.window) else { + let Some(p) = wvr_server.wm.windows.get(self.window) else { return Ok(()); }; wvr_server.terminate_process(p.process, signal); } OverlayEventData::ResizeRequest(new_size) => { let wvr_server = app.wvr_server.as_mut().unwrap(); - let Some(win) = wvr_server.wm.windows.get_mut(&self.window) else { + let Some(win) = wvr_server.wm.windows.get_mut(self.window) else { log::warn!("Could not process resize request: window not found"); return Ok(()); }; diff --git a/wlx-common/Cargo.toml b/wlx-common/Cargo.toml index 920cf779..ca92bea3 100644 --- a/wlx-common/Cargo.toml +++ b/wlx-common/Cargo.toml @@ -19,6 +19,7 @@ log.workspace = true serde = { workspace = true, features = ["rc"] } serde_json.workspace = true serde_json5.workspace = true +slotmap.workspace = true smol.workspace = true strum.workspace = true xdg.workspace = true diff --git a/wlx-common/src/dash_interface_emulated.rs b/wlx-common/src/dash_interface_emulated.rs index fa839538..9a4ff1a0 100644 --- a/wlx-common/src/dash_interface_emulated.rs +++ b/wlx-common/src/dash_interface_emulated.rs @@ -1,3 +1,4 @@ +use slotmap::{DenseSlotMap, new_key_type}; use wayvr_ipc::{ packet_client::WvrProcessLaunchParams, packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle}, @@ -7,25 +8,19 @@ use crate::{ config::GeneralConfig, dash_interface::{self, ConfigChangeKind, DashInterface, DashPlayspaceTask}, desktop_finder::DesktopFinder, - gen_id, }; +new_key_type! { + pub struct EmuProcessHandle; +} + #[derive(Debug)] pub struct EmuProcess { name: String, } -impl EmuProcess { - fn to(&self, handle: EmuProcessHandle) -> WvrProcess { - WvrProcess { - handle: WvrProcessHandle { - generation: handle.generation, - idx: handle.idx, - }, - name: self.name.clone(), - userdata: Default::default(), - } - } +new_key_type! { + pub struct EmuWindowHandle; } #[derive(Debug)] @@ -34,6 +29,18 @@ pub struct EmuWindow { process_handle: EmuProcessHandle, } +impl EmuProcess { + fn to(&self, handle: EmuProcessHandle) -> WvrProcess { + WvrProcess { + handle: WvrProcessHandle { + user: handle.0.as_ffi(), + }, + name: self.name.clone(), + userdata: Default::default(), + } + } +} + impl EmuWindow { fn to(&self, handle: EmuWindowHandle) -> WvrWindow { WvrWindow { @@ -41,24 +48,18 @@ impl EmuWindow { size_y: 720, /* stub */ visible: true, handle: WvrWindowHandle { - generation: handle.generation, - idx: handle.idx, + user: handle.0.as_ffi(), }, process_handle: WvrProcessHandle { - generation: self.process_handle.generation, - idx: self.process_handle.idx, + user: self.process_handle.0.as_ffi(), }, } } } -gen_id!(EmuWindowVec, EmuWindow, EmuWindowCell, EmuWindowHandle); - -gen_id!(EmuProcessVec, EmuProcess, EmuProcessCell, EmuProcessHandle); - pub struct DashInterfaceEmulated { - processes: EmuProcessVec, - windows: EmuWindowVec, + windows: DenseSlotMap, + processes: DenseSlotMap, desktop_finder: DesktopFinder, general_config: GeneralConfig, monado_clients: Vec, @@ -69,13 +70,13 @@ pub struct DashInterfaceEmulated { impl DashInterfaceEmulated { pub fn new() -> Self { - let mut processes = EmuProcessVec::new(); - let process_handle = processes.add(EmuProcess { + let mut processes = DenseSlotMap::::default(); + let process_handle = processes.insert(EmuProcess { name: String::from("My app"), }); - let mut windows = EmuWindowVec::new(); - windows.add(EmuWindow { + let mut windows = DenseSlotMap::::default(); + windows.insert(EmuWindow { process_handle, visible: true, }); @@ -144,16 +145,15 @@ impl DashInterface<()> for DashInterfaceEmulated { } fn window_request_close(&mut self, _: &mut (), handle: WvrWindowHandle) -> anyhow::Result<()> { - self.windows.remove(&EmuWindowHandle { - generation: handle.generation, - idx: handle.idx, - }); + self + .windows + .remove(EmuWindowHandle::from(slotmap::KeyData::from_ffi(handle.user))); Ok(()) } fn process_get(&mut self, _: &mut (), handle: WvrProcessHandle) -> Option { - let emu_handle = EmuProcessHandle::new(handle.idx, handle.generation); - self.processes.get(&emu_handle).map(|process| process.to(emu_handle)) + let emu_handle = EmuProcessHandle::from(slotmap::KeyData::from_ffi(handle.user)); + self.processes.get(emu_handle).map(|process| process.to(emu_handle)) } fn process_launch( @@ -162,17 +162,14 @@ impl DashInterface<()> for DashInterfaceEmulated { _: bool, params: WvrProcessLaunchParams, ) -> anyhow::Result { - let res = self.processes.add(EmuProcess { name: params.name }); + let res = self.processes.insert(EmuProcess { name: params.name }); - self.windows.add(EmuWindow { + self.windows.insert(EmuWindow { process_handle: res, visible: true, }); - Ok(WvrProcessHandle { - generation: res.generation, - idx: res.idx, - }) + Ok(WvrProcessHandle { user: res.0.as_ffi() }) } fn process_list(&mut self, _: &mut ()) -> anyhow::Result> { @@ -189,26 +186,26 @@ impl DashInterface<()> for DashInterfaceEmulated { let mut to_remove = None; for (wh, w) in self.windows.iter() { - if w.process_handle == EmuProcessHandle::new(handle.idx, handle.generation) { + if w.process_handle == EmuProcessHandle::from(slotmap::KeyData::from_ffi(handle.user)) { to_remove = Some(wh); } } if let Some(wh) = to_remove { - self.windows.remove(&wh); + self.windows.remove(wh); } self .processes - .remove(&EmuProcessHandle::new(handle.idx, handle.generation)); + .remove(EmuProcessHandle::from(slotmap::KeyData::from_ffi(handle.user))); Ok(()) } fn window_set_visible(&mut self, _: &mut (), handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()> { - match self.windows.get_mut(&EmuWindowHandle { - generation: handle.generation, - idx: handle.idx, - }) { + match self + .windows + .get_mut(EmuWindowHandle::from(slotmap::KeyData::from_ffi(handle.user))) + { Some(w) => { w.visible = visible; Ok(()) diff --git a/wlx-common/src/handle.rs b/wlx-common/src/handle.rs deleted file mode 100644 index d300d052..00000000 --- a/wlx-common/src/handle.rs +++ /dev/null @@ -1,172 +0,0 @@ -#[macro_export] -macro_rules! gen_id { - ( - $container_name:ident, - $instance_name:ident, - $cell_name:ident, - $handle_name:ident) => { - //ThingCell - #[derive(Debug)] - pub struct $cell_name { - pub obj: $instance_name, - pub generation: u64, - } - - //ThingVec - #[derive(Debug)] - pub struct $container_name { - // Vec> - pub vec: Vec>, - - cur_generation: u64, - } - - //ThingHandle - #[derive(Default, Debug, Clone, Copy, PartialEq, Hash, Eq)] - pub struct $handle_name { - idx: u32, - generation: u64, - } - - #[allow(dead_code)] - impl $handle_name { - pub const fn reset(&mut self) { - self.generation = 0; - } - - pub const fn is_set(&self) -> bool { - self.generation > 0 - } - - pub const fn id(&self) -> u32 { - self.idx - } - - pub const fn new(idx: u32, generation: u64) -> Self { - Self { idx, generation } - } - } - - //ThingVec - impl $container_name { - #[allow(clippy::new_without_default)] - pub const fn new() -> Self { - Self { - vec: Vec::new(), - cur_generation: 0, - } - } - - pub fn iter(&self) -> impl Iterator { - self.vec.iter().enumerate().filter_map(|(idx, opt_cell)| { - opt_cell.as_ref().map(|cell| { - let handle = $container_name::get_handle(&cell, idx); - (handle, &cell.obj) - }) - }) - } - - pub fn iter_mut(&mut self) -> impl Iterator { - self.vec.iter_mut().enumerate().filter_map(|(idx, opt_cell)| { - opt_cell.as_mut().map(|cell| { - let handle = $container_name::get_handle(&cell, idx); - (handle, &mut cell.obj) - }) - }) - } - - pub const fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name { - $handle_name { - idx: idx as u32, - generation: cell.generation, - } - } - - fn find_unused_idx(&mut self) -> Option { - for (num, obj) in self.vec.iter().enumerate() { - if obj.is_none() { - return Some(num as u32); - } - } - None - } - - pub fn add(&mut self, obj: $instance_name) -> $handle_name { - self.cur_generation += 1; - let generation = self.cur_generation; - - let unused_idx = self.find_unused_idx(); - - let idx = if let Some(idx) = unused_idx { - idx - } else { - self.vec.len() as u32 - }; - - let handle = $handle_name { idx, generation }; - - let cell = $cell_name { obj, generation }; - - if let Some(idx) = unused_idx { - self.vec[idx as usize] = Some(cell); - } else { - self.vec.push(Some(cell)) - } - - handle - } - - pub fn remove(&mut self, handle: &$handle_name) { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return; - } - - // Remove only if the generation matches - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - self.vec[handle.idx as usize] = None; - } - } - } - - pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&cell.obj); - } - } - - None - } - - pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> { - // Out of bounds, ignore - if handle.idx as usize >= self.vec.len() { - return None; - } - - if let Some(cell) = &mut self.vec[handle.idx as usize] { - if cell.generation == handle.generation { - return Some(&mut cell.obj); - } - } - - None - } - } - }; -} - -/* Example usage: -gen_id!(ThingVec, ThingInstance, ThingCell, ThingHandle); - -struct ThingInstance {} - -impl ThingInstance {} - */ diff --git a/wlx-common/src/lib.rs b/wlx-common/src/lib.rs index f9ca1a51..59be4476 100644 --- a/wlx-common/src/lib.rs +++ b/wlx-common/src/lib.rs @@ -9,7 +9,6 @@ pub mod dash_interface; pub mod dash_interface_emulated; pub mod data_dir; pub mod desktop_finder; -mod handle; pub mod locale; pub mod openxr_actions; pub mod openxr_bindings_schema;