WayVR: Display removal support
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4582,7 +4582,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wayvr_ipc"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/olekolek1000/wayvr-ipc.git?rev=b484d1f0607b3f67e2c9e49797819738344bcb5c#b484d1f0607b3f67e2c9e49797819738344bcb5c"
|
||||
source = "git+https://github.com/olekolek1000/wayvr-ipc.git?rev=94ab6125ec07c091099bf71b028d701b58eccccf#94ab6125ec07c091099bf71b028d701b58eccccf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
|
||||
@@ -86,7 +86,7 @@ wayland-client = { version = "0.31.6", optional = true }
|
||||
wayland-egl = { version = "0.32.4", optional = true }
|
||||
interprocess = { version = "2.2.2", optional = true }
|
||||
bytes = { version = "1.9.0", optional = true }
|
||||
wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "b484d1f0607b3f67e2c9e49797819738344bcb5c", default-features = false, optional = true }
|
||||
wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "94ab6125ec07c091099bf71b028d701b58eccccf", default-features = false, optional = true }
|
||||
################################
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -484,6 +484,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
||||
TaskType::DropOverlay(sel) => {
|
||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||
if o.state.birthframe < cur_frame {
|
||||
log::debug!("{}: destroy", o.state.name);
|
||||
if let Some(o) = overlays.remove_by_selector(&sel) {
|
||||
// set for deletion after all images are done showing
|
||||
delete_queue.push((o, cur_frame + 5));
|
||||
|
||||
@@ -10,7 +10,7 @@ use smithay::{
|
||||
use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask};
|
||||
|
||||
use super::{
|
||||
comp::{self},
|
||||
comp::{self, ClientState},
|
||||
display, process, ProcessWayVREnv,
|
||||
};
|
||||
|
||||
@@ -86,6 +86,20 @@ impl WayVRCompositor {
|
||||
self.clients.push(client);
|
||||
}
|
||||
|
||||
pub fn cleanup_clients(&mut self) {
|
||||
self.clients.retain(|client| {
|
||||
let Some(data) = client.client.get_data::<ClientState>() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if *data.disconnected.lock().unwrap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
fn accept_connection(
|
||||
&mut self,
|
||||
stream: UnixStream,
|
||||
|
||||
@@ -19,6 +19,7 @@ use smithay::{
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use std::os::fd::OwnedFd;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use smithay::utils::Serial;
|
||||
use smithay::wayland::compositor::{
|
||||
@@ -116,6 +117,7 @@ impl SelectionHandler for Application {
|
||||
#[derive(Default)]
|
||||
pub struct ClientState {
|
||||
compositor_state: compositor::CompositorClientState,
|
||||
pub disconnected: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl ClientData for ClientState {
|
||||
@@ -124,6 +126,7 @@ impl ClientData for ClientState {
|
||||
}
|
||||
|
||||
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
|
||||
*self.disconnected.lock().unwrap() = true;
|
||||
log::debug!(
|
||||
"Client ID {:?} disconnected. Reason: {:?}",
|
||||
client_id,
|
||||
|
||||
@@ -60,7 +60,7 @@ pub struct Display {
|
||||
pub overlay_id: Option<OverlayID>,
|
||||
pub wants_redraw: bool,
|
||||
pub primary: bool,
|
||||
wm: Rc<RefCell<window::WindowManager>>,
|
||||
pub wm: Rc<RefCell<window::WindowManager>>,
|
||||
pub displayed_windows: Vec<DisplayWindow>,
|
||||
wayland_env: super::WaylandEnv,
|
||||
last_pressed_time_ms: u64,
|
||||
|
||||
@@ -68,6 +68,7 @@ pub struct ExternalProcessRequest {
|
||||
pub enum WayVRTask {
|
||||
NewToplevel(ClientId, ToplevelSurface),
|
||||
NewExternalProcess(ExternalProcessRequest),
|
||||
DropOverlay(super::overlay::OverlayID),
|
||||
ProcessTerminationRequest(process::ProcessHandle),
|
||||
}
|
||||
|
||||
@@ -92,12 +93,13 @@ pub struct WayVRState {
|
||||
pub processes: process::ProcessVec,
|
||||
config: Config,
|
||||
dashboard_display: Option<display::DisplayHandle>,
|
||||
tasks: SyncEventQueue<WayVRTask>,
|
||||
ticks: u64,
|
||||
}
|
||||
|
||||
pub struct WayVR {
|
||||
pub state: WayVRState,
|
||||
ipc_server: WayVRServer,
|
||||
tasks: SyncEventQueue<WayVRTask>,
|
||||
pub signals: SyncEventQueue<WayVRSignal>,
|
||||
}
|
||||
|
||||
@@ -113,6 +115,7 @@ pub enum TickTask {
|
||||
packet_client::WvrDisplayCreateParams,
|
||||
Option<display::DisplayHandle>, /* existing handle? */
|
||||
),
|
||||
DropOverlay(super::overlay::OverlayID),
|
||||
}
|
||||
|
||||
impl WayVR {
|
||||
@@ -230,12 +233,13 @@ impl WayVR {
|
||||
wm: Rc::new(RefCell::new(window::WindowManager::new())),
|
||||
config,
|
||||
dashboard_display: None,
|
||||
ticks: 0,
|
||||
tasks,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
signals: SyncEventQueue::new(),
|
||||
tasks,
|
||||
ipc_server,
|
||||
})
|
||||
}
|
||||
@@ -313,11 +317,14 @@ impl WayVR {
|
||||
display.tick(&self.state.config, &handle, &mut self.signals);
|
||||
});
|
||||
|
||||
while let Some(task) = self.tasks.read() {
|
||||
while let Some(task) = self.state.tasks.read() {
|
||||
match task {
|
||||
WayVRTask::NewExternalProcess(req) => {
|
||||
tasks.push(TickTask::NewExternalProcess(req));
|
||||
}
|
||||
WayVRTask::DropOverlay(overlay_id) => {
|
||||
tasks.push(TickTask::DropOverlay(overlay_id));
|
||||
}
|
||||
WayVRTask::NewToplevel(client_id, toplevel) => {
|
||||
// Attach newly created toplevel surfaces to displays
|
||||
for client in &self.state.manager.clients {
|
||||
@@ -358,6 +365,12 @@ impl WayVR {
|
||||
.manager
|
||||
.tick_wayland(&mut self.state.displays, &mut self.state.processes)?;
|
||||
|
||||
if self.state.ticks % 200 == 0 {
|
||||
self.state.manager.cleanup_clients();
|
||||
}
|
||||
|
||||
self.state.ticks += 1;
|
||||
|
||||
Ok(tasks)
|
||||
}
|
||||
|
||||
@@ -399,7 +412,8 @@ impl WayVR {
|
||||
}
|
||||
|
||||
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
|
||||
self.tasks
|
||||
self.state
|
||||
.tasks
|
||||
.send(WayVRTask::ProcessTerminationRequest(process_handle));
|
||||
}
|
||||
}
|
||||
@@ -465,6 +479,46 @@ impl WayVRState {
|
||||
Ok(self.displays.add(display))
|
||||
}
|
||||
|
||||
pub fn destroy_display(&mut self, handle: display::DisplayHandle) -> anyhow::Result<()> {
|
||||
let Some(display) = self.displays.get(&handle) else {
|
||||
anyhow::bail!("Display not found");
|
||||
};
|
||||
|
||||
if let Some(overlay_id) = display.overlay_id {
|
||||
self.tasks.send(WayVRTask::DropOverlay(overlay_id));
|
||||
} else {
|
||||
log::warn!("Destroying display without OverlayID set"); // This shouldn't happen, but log it anyways.
|
||||
}
|
||||
|
||||
let mut process_names = Vec::<String>::new();
|
||||
|
||||
self.processes.iter_mut(&mut |_, process| {
|
||||
if process.display_handle() == handle {
|
||||
process_names.push(process.get_name());
|
||||
}
|
||||
});
|
||||
|
||||
if !display.displayed_windows.is_empty() || !process_names.is_empty() {
|
||||
anyhow::bail!(
|
||||
"Display is not empty. Attached processes: {}",
|
||||
process_names.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
self.manager.cleanup_clients();
|
||||
|
||||
for client in self.manager.clients.iter() {
|
||||
if client.display_handle == handle {
|
||||
// This shouldn't happen, but make sure we are all set to destroy this display
|
||||
anyhow::bail!("Wayland client still exists");
|
||||
}
|
||||
}
|
||||
|
||||
self.displays.remove(&handle);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_or_create_dashboard_display(
|
||||
&mut self,
|
||||
width: u16,
|
||||
@@ -484,10 +538,6 @@ impl WayVRState {
|
||||
Ok((true, new_disp))
|
||||
}
|
||||
|
||||
pub fn destroy_display(&mut self, handle: display::DisplayHandle) {
|
||||
self.displays.remove(&handle);
|
||||
}
|
||||
|
||||
// Check if process with given arguments already exists
|
||||
pub fn process_query(
|
||||
&self,
|
||||
|
||||
@@ -49,6 +49,13 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
match self {
|
||||
Process::Managed(p) => p.get_name().unwrap_or(String::from("unknown")),
|
||||
Process::External(p) => p.get_name().unwrap_or(String::from("unknown")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_packet(&self, handle: ProcessHandle) -> packet_server::WvrProcess {
|
||||
match self {
|
||||
Process::Managed(p) => packet_server::WvrProcess {
|
||||
|
||||
@@ -205,6 +205,24 @@ impl Connection {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_display_remove(
|
||||
&mut self,
|
||||
params: &mut TickParams,
|
||||
serial: ipc::Serial,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
) -> anyhow::Result<()> {
|
||||
let res = params
|
||||
.state
|
||||
.destroy_display(display::DisplayHandle::from_packet(handle))
|
||||
.map_err(|e| format!("{:?}", e));
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrDisplayRemoveResponse(serial, res)),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_process_launch(
|
||||
&mut self,
|
||||
params: &mut TickParams,
|
||||
@@ -317,6 +335,9 @@ impl Connection {
|
||||
PacketClient::WvrDisplayGet(serial, display_handle) => {
|
||||
self.handle_wvr_process_get(params, serial, display_handle)?;
|
||||
}
|
||||
PacketClient::WvrDisplayRemove(serial, display_handle) => {
|
||||
self.handle_wvr_display_remove(params, serial, display_handle)?;
|
||||
}
|
||||
PacketClient::WvrProcessList(serial) => {
|
||||
self.handle_wvr_process_list(params, serial)?;
|
||||
}
|
||||
|
||||
@@ -495,6 +495,10 @@ where
|
||||
},
|
||||
});
|
||||
}
|
||||
wayvr::TickTask::DropOverlay(overlay_id) => {
|
||||
app.tasks
|
||||
.enqueue(TaskType::DropOverlay(OverlaySelector::Id(overlay_id)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,7 +584,13 @@ impl OverlayRenderer for WayVRRenderer {
|
||||
let ctx = self.context.borrow();
|
||||
let mut wayvr = ctx.wayvr.borrow_mut();
|
||||
|
||||
wayvr.data.tick_display(ctx.display)?;
|
||||
match wayvr.data.tick_display(ctx.display) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("tick_display failed: {}", e);
|
||||
return Ok(()); // do not proceed further
|
||||
}
|
||||
}
|
||||
|
||||
let dmabuf_data = wayvr
|
||||
.data
|
||||
|
||||
Reference in New Issue
Block a user