get rid of handle.rs in favor of DenseSlotMap

This commit is contained in:
Aleksander 2026-07-25 21:26:34 +02:00 committed by galister
parent e40b953e5a
commit c92e27dcf9
19 changed files with 142 additions and 689 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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<PacketServer>,
}
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<QueuedPacketHandle, QueuedPacket>,
pub auth: Option<AuthInfo>,
pub on_signal: Option<SignalFunc>,
}
@ -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)
}

View File

@ -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)]

View File

@ -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<Option<ThingCell>>
pub vec: Vec<Option<$cell_name>>,
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<u32> {
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 {}
*/

View File

@ -1,4 +1,2 @@
pub mod handle;
#[cfg(feature = "client")]
pub mod notifier;

View File

@ -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

View File

@ -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<process::ProcessHandle, process::Process>,
) -> 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<process::ProcessHandle, process::Process>,
) -> 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<process::ProcessHandle, process::Process>,
) -> anyhow::Result<()> {
if let Err(e) = self.accept_connections(processes) {
log::error!("accept_connections failed: {e}");
}

View File

@ -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<Option<ThingCell>>
pub vec: Vec<Option<$cell_name>>,
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<Item = ($handle_name, &$instance_name)> {
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<Item = ($handle_name, &mut $instance_name)> {
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<u32> {
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 {}
*/

View File

@ -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<process::ProcessHandle, process::Process>,
pub tasks: SyncEventQueue<WayVRTask>,
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<i32, Logical> =
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),

View File

@ -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<ProcessHandle> {
pub fn find_by_pid(
processes: &DenseSlotMap<ProcessHandle, Process>,
pid: u32,
) -> Option<ProcessHandle> {
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<ProcessHandle> {
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<ProcessHandle> {
}
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(),
}
}
}

View File

@ -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<WindowHandle, Window>,
pub mouse: Option<MouseState>,
pub keyboard_focus: Option<WindowHandle>,
}
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<WindowHandle> {
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(),
}
}
}

View File

@ -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<packet_server::WvrProcess> = 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(

View File

@ -427,7 +427,7 @@ impl DashInterface<AppState> for DashInterfaceLive {
let handle = ProcessHandle::from_packet(handle);
wvr_server
.processes
.get(&handle)
.get(handle)
.map(|x| x.to_packet(handle))
}

View File

@ -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(());
};

View File

@ -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

View File

@ -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<EmuWindowHandle, EmuWindow>,
processes: DenseSlotMap<EmuProcessHandle, EmuProcess>,
desktop_finder: DesktopFinder,
general_config: GeneralConfig,
monado_clients: Vec<dash_interface::MonadoClient>,
@ -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::<EmuProcessHandle, EmuProcess>::default();
let process_handle = processes.insert(EmuProcess {
name: String::from("My app"),
});
let mut windows = EmuWindowVec::new();
windows.add(EmuWindow {
let mut windows = DenseSlotMap::<EmuWindowHandle, EmuWindow>::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<WvrProcess> {
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<WvrProcessHandle> {
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<Vec<WvrProcess>> {
@ -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(())

View File

@ -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<Option<ThingCell>>
pub vec: Vec<Option<$cell_name>>,
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<Item = ($handle_name, &$instance_name)> {
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<Item = ($handle_name, &mut $instance_name)> {
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<u32> {
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 {}
*/

View File

@ -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;