WayVR: Display removal support
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4582,7 +4582,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wayvr_ipc"
|
name = "wayvr_ipc"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ wayland-client = { version = "0.31.6", optional = true }
|
|||||||
wayland-egl = { version = "0.32.4", optional = true }
|
wayland-egl = { version = "0.32.4", optional = true }
|
||||||
interprocess = { version = "2.2.2", optional = true }
|
interprocess = { version = "2.2.2", optional = true }
|
||||||
bytes = { version = "1.9.0", 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]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -484,6 +484,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
TaskType::DropOverlay(sel) => {
|
TaskType::DropOverlay(sel) => {
|
||||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||||
if o.state.birthframe < cur_frame {
|
if o.state.birthframe < cur_frame {
|
||||||
|
log::debug!("{}: destroy", o.state.name);
|
||||||
if let Some(o) = overlays.remove_by_selector(&sel) {
|
if let Some(o) = overlays.remove_by_selector(&sel) {
|
||||||
// set for deletion after all images are done showing
|
// set for deletion after all images are done showing
|
||||||
delete_queue.push((o, cur_frame + 5));
|
delete_queue.push((o, cur_frame + 5));
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use smithay::{
|
|||||||
use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask};
|
use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
comp::{self},
|
comp::{self, ClientState},
|
||||||
display, process, ProcessWayVREnv,
|
display, process, ProcessWayVREnv,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,6 +86,20 @@ impl WayVRCompositor {
|
|||||||
self.clients.push(client);
|
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(
|
fn accept_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: UnixStream,
|
stream: UnixStream,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use smithay::{
|
|||||||
};
|
};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::fd::OwnedFd;
|
use std::os::fd::OwnedFd;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use smithay::utils::Serial;
|
use smithay::utils::Serial;
|
||||||
use smithay::wayland::compositor::{
|
use smithay::wayland::compositor::{
|
||||||
@@ -116,6 +117,7 @@ impl SelectionHandler for Application {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
compositor_state: compositor::CompositorClientState,
|
compositor_state: compositor::CompositorClientState,
|
||||||
|
pub disconnected: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientData for ClientState {
|
impl ClientData for ClientState {
|
||||||
@@ -124,6 +126,7 @@ impl ClientData for ClientState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
|
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
|
||||||
|
*self.disconnected.lock().unwrap() = true;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Client ID {:?} disconnected. Reason: {:?}",
|
"Client ID {:?} disconnected. Reason: {:?}",
|
||||||
client_id,
|
client_id,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub struct Display {
|
|||||||
pub overlay_id: Option<OverlayID>,
|
pub overlay_id: Option<OverlayID>,
|
||||||
pub wants_redraw: bool,
|
pub wants_redraw: bool,
|
||||||
pub primary: bool,
|
pub primary: bool,
|
||||||
wm: Rc<RefCell<window::WindowManager>>,
|
pub wm: Rc<RefCell<window::WindowManager>>,
|
||||||
pub displayed_windows: Vec<DisplayWindow>,
|
pub displayed_windows: Vec<DisplayWindow>,
|
||||||
wayland_env: super::WaylandEnv,
|
wayland_env: super::WaylandEnv,
|
||||||
last_pressed_time_ms: u64,
|
last_pressed_time_ms: u64,
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ pub struct ExternalProcessRequest {
|
|||||||
pub enum WayVRTask {
|
pub enum WayVRTask {
|
||||||
NewToplevel(ClientId, ToplevelSurface),
|
NewToplevel(ClientId, ToplevelSurface),
|
||||||
NewExternalProcess(ExternalProcessRequest),
|
NewExternalProcess(ExternalProcessRequest),
|
||||||
|
DropOverlay(super::overlay::OverlayID),
|
||||||
ProcessTerminationRequest(process::ProcessHandle),
|
ProcessTerminationRequest(process::ProcessHandle),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +93,13 @@ pub struct WayVRState {
|
|||||||
pub processes: process::ProcessVec,
|
pub processes: process::ProcessVec,
|
||||||
config: Config,
|
config: Config,
|
||||||
dashboard_display: Option<display::DisplayHandle>,
|
dashboard_display: Option<display::DisplayHandle>,
|
||||||
|
tasks: SyncEventQueue<WayVRTask>,
|
||||||
|
ticks: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WayVR {
|
pub struct WayVR {
|
||||||
pub state: WayVRState,
|
pub state: WayVRState,
|
||||||
ipc_server: WayVRServer,
|
ipc_server: WayVRServer,
|
||||||
tasks: SyncEventQueue<WayVRTask>,
|
|
||||||
pub signals: SyncEventQueue<WayVRSignal>,
|
pub signals: SyncEventQueue<WayVRSignal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +115,7 @@ pub enum TickTask {
|
|||||||
packet_client::WvrDisplayCreateParams,
|
packet_client::WvrDisplayCreateParams,
|
||||||
Option<display::DisplayHandle>, /* existing handle? */
|
Option<display::DisplayHandle>, /* existing handle? */
|
||||||
),
|
),
|
||||||
|
DropOverlay(super::overlay::OverlayID),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WayVR {
|
impl WayVR {
|
||||||
@@ -230,12 +233,13 @@ impl WayVR {
|
|||||||
wm: Rc::new(RefCell::new(window::WindowManager::new())),
|
wm: Rc::new(RefCell::new(window::WindowManager::new())),
|
||||||
config,
|
config,
|
||||||
dashboard_display: None,
|
dashboard_display: None,
|
||||||
|
ticks: 0,
|
||||||
|
tasks,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state,
|
state,
|
||||||
signals: SyncEventQueue::new(),
|
signals: SyncEventQueue::new(),
|
||||||
tasks,
|
|
||||||
ipc_server,
|
ipc_server,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -313,11 +317,14 @@ impl WayVR {
|
|||||||
display.tick(&self.state.config, &handle, &mut self.signals);
|
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 {
|
match task {
|
||||||
WayVRTask::NewExternalProcess(req) => {
|
WayVRTask::NewExternalProcess(req) => {
|
||||||
tasks.push(TickTask::NewExternalProcess(req));
|
tasks.push(TickTask::NewExternalProcess(req));
|
||||||
}
|
}
|
||||||
|
WayVRTask::DropOverlay(overlay_id) => {
|
||||||
|
tasks.push(TickTask::DropOverlay(overlay_id));
|
||||||
|
}
|
||||||
WayVRTask::NewToplevel(client_id, toplevel) => {
|
WayVRTask::NewToplevel(client_id, toplevel) => {
|
||||||
// Attach newly created toplevel surfaces to displays
|
// Attach newly created toplevel surfaces to displays
|
||||||
for client in &self.state.manager.clients {
|
for client in &self.state.manager.clients {
|
||||||
@@ -358,6 +365,12 @@ impl WayVR {
|
|||||||
.manager
|
.manager
|
||||||
.tick_wayland(&mut self.state.displays, &mut self.state.processes)?;
|
.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)
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +412,8 @@ impl WayVR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
|
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
|
||||||
self.tasks
|
self.state
|
||||||
|
.tasks
|
||||||
.send(WayVRTask::ProcessTerminationRequest(process_handle));
|
.send(WayVRTask::ProcessTerminationRequest(process_handle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,6 +479,46 @@ impl WayVRState {
|
|||||||
Ok(self.displays.add(display))
|
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(
|
pub fn get_or_create_dashboard_display(
|
||||||
&mut self,
|
&mut self,
|
||||||
width: u16,
|
width: u16,
|
||||||
@@ -484,10 +538,6 @@ impl WayVRState {
|
|||||||
Ok((true, new_disp))
|
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
|
// Check if process with given arguments already exists
|
||||||
pub fn process_query(
|
pub fn process_query(
|
||||||
&self,
|
&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 {
|
pub fn to_packet(&self, handle: ProcessHandle) -> packet_server::WvrProcess {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => packet_server::WvrProcess {
|
Process::Managed(p) => packet_server::WvrProcess {
|
||||||
|
|||||||
@@ -205,6 +205,24 @@ impl Connection {
|
|||||||
Ok(())
|
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(
|
fn handle_wvr_process_launch(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
@@ -317,6 +335,9 @@ impl Connection {
|
|||||||
PacketClient::WvrDisplayGet(serial, display_handle) => {
|
PacketClient::WvrDisplayGet(serial, display_handle) => {
|
||||||
self.handle_wvr_process_get(params, 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) => {
|
PacketClient::WvrProcessList(serial) => {
|
||||||
self.handle_wvr_process_list(params, 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 ctx = self.context.borrow();
|
||||||
let mut wayvr = ctx.wayvr.borrow_mut();
|
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
|
let dmabuf_data = wayvr
|
||||||
.data
|
.data
|
||||||
|
|||||||
Reference in New Issue
Block a user