Skip to content

Commit

Permalink
WayVR: External process support, various tweaks and bugfixes
Browse files Browse the repository at this point in the history
- Support for foreign wayland clients, WayVR process is now separated into
  managed and external one
- Add `run_compositor_at_start` global param
- Add `primary` display param
- Export WAYLAND_DISPLAY number into XDG_RUNTIME_DIR directory
- Bugfix: Redraw event is not triggered after despawning a process
- Sanitization in WayVRConfig::post_load()
  • Loading branch information
olekolek1000 committed Oct 27, 2024
1 parent 66fb2fc commit 7e09c01
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 123 deletions.
4 changes: 1 addition & 3 deletions src/backend/openvr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
};

#[cfg(feature = "wayvr")]
if let Some(wayvr) = &state.wayvr {
wayvr.borrow_mut().tick_events()?;
}
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut state, &mut overlays)?;

log::trace!("Rendering frame");

Expand Down
4 changes: 1 addition & 3 deletions src/backend/openxr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
}

#[cfg(feature = "wayvr")]
if let Some(wayvr) = &app_state.wayvr {
wayvr.borrow_mut().tick_events()?;
}
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app_state, &mut overlays)?;

for o in overlays.iter_mut() {
if !o.state.want_visible {
Expand Down
85 changes: 64 additions & 21 deletions src/backend/wayvr/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{io::Read, os::unix::net::UnixStream, sync::Arc};
use std::{io::Read, os::unix::net::UnixStream, path::PathBuf, sync::Arc};

use smithay::{
backend::input::Keycode,
Expand All @@ -7,9 +7,11 @@ use smithay::{
utils::SerialCounter,
};

use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask};

use super::{
comp::{self},
display, process,
display, process, ProcessWayVREnv,
};

pub struct WayVRClient {
Expand All @@ -33,22 +35,29 @@ pub struct WayVRManager {
pub clients: Vec<WayVRClient>,
}

fn get_display_auth_from_pid(pid: i32) -> anyhow::Result<String> {
fn get_wayvr_env_from_pid(pid: i32) -> anyhow::Result<ProcessWayVREnv> {
let path = format!("/proc/{}/environ", pid);
let mut env_data = String::new();
std::fs::File::open(path)?.read_to_string(&mut env_data)?;

let lines: Vec<&str> = env_data.split('\0').filter(|s| !s.is_empty()).collect();

let mut env = ProcessWayVREnv {
display_auth: None,
display_name: None,
};

for line in lines {
if let Some((key, value)) = line.split_once('=') {
if key == "WAYVR_DISPLAY_AUTH" {
return Ok(String::from(value));
env.display_auth = Some(String::from(value));
} else if key == "WAYVR_DISPLAY_NAME" {
env.display_name = Some(String::from(value));
}
}
}

anyhow::bail!("Failed to get display auth from PID {}", pid);
Ok(env)
}

impl WayVRManager {
Expand All @@ -73,6 +82,10 @@ impl WayVRManager {
})
}

pub fn add_client(&mut self, client: WayVRClient) {
self.clients.push(client);
}

fn accept_connection(
&mut self,
stream: UnixStream,
Expand All @@ -86,27 +99,46 @@ impl WayVRManager {
.unwrap();

let creds = client.get_credentials(&self.display.handle())?;
let auth_key = get_display_auth_from_pid(creds.pid)?;

let process_env = get_wayvr_env_from_pid(creds.pid)?;

// Find suitable auth key from the process list
for process in processes.vec.iter().flatten() {
let process = &process.obj;

// Find process with matching auth key
if process.auth_key.as_str() == auth_key {
// Check if display handle is valid
if displays.get(&process.display_handle).is_some() {
// Add client
self.clients.push(WayVRClient {
client,
display_handle: process.display_handle,
pid: creds.pid as u32,
});
return Ok(());
for p in processes.vec.iter().flatten() {
if let process::Process::Managed(process) = &p.obj {
if let Some(auth_key) = &process_env.display_auth {
// Find process with matching auth key
if process.auth_key.as_str() == auth_key {
// Check if display handle is valid
if displays.get(&process.display_handle).is_some() {
// Add client
self.add_client(WayVRClient {
client,
display_handle: process.display_handle,
pid: creds.pid as u32,
});
return Ok(());
}
}
}
}
}
anyhow::bail!("Process auth key is invalid or selected display is non-existent");

// This is a new process which we didn't met before.
// Treat external processes exclusively (spawned by the user or external program)
log::warn!(
"External process ID {} connected to this Wayland server",
creds.pid
);

self.state
.wayvr_tasks
.send(WayVRTask::NewExternalProcess(ExternalProcessRequest {
env: process_env,
client,
pid: creds.pid as u32,
}));

Ok(())
}

fn accept_connections(
Expand Down Expand Up @@ -164,6 +196,15 @@ impl WayVRManager {

const STARTING_WAYLAND_ADDR_IDX: u32 = 20;

fn export_display_number(display_num: u32) -> anyhow::Result<()> {
let mut path = std::env::var("XDG_RUNTIME_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("/tmp"));
path.push("wayvr.disp");
std::fs::write(path, format!("{}\n", display_num)).unwrap();
Ok(())
}

fn create_wayland_listener() -> anyhow::Result<(super::WaylandEnv, wayland_server::ListeningSocket)>
{
let mut env = super::WaylandEnv {
Expand Down Expand Up @@ -194,5 +235,7 @@ fn create_wayland_listener() -> anyhow::Result<(super::WaylandEnv, wayland_serve
}
};

let _ = export_display_number(env.display_num);

Ok((env, listener))
}
10 changes: 9 additions & 1 deletion src/backend/wayvr/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub struct Display {
pub visible: bool,
pub overlay_id: Option<OverlayID>,
pub wants_redraw: bool,
pub primary: bool,
wm: Rc<RefCell<window::WindowManager>>,
pub displayed_windows: Vec<DisplayWindow>,
wayland_env: super::WaylandEnv,
Expand Down Expand Up @@ -81,6 +82,7 @@ impl Display {
width: u32,
height: u32,
name: &str,
primary: bool,
) -> anyhow::Result<Self> {
let tex_format = ffi::RGBA;
let internal_format = ffi::RGBA8;
Expand Down Expand Up @@ -116,6 +118,7 @@ impl Display {
gles_texture,
wayland_env,
visible: true,
primary,
overlay_id: None,
tasks: SyncEventQueue::new(),
})
Expand Down Expand Up @@ -239,7 +242,12 @@ impl Display {

pub fn set_visible(&mut self, visible: bool) {
log::info!("Display \"{}\" visible: {}", self.name.as_str(), visible);
self.visible = visible;
if self.visible != visible {
self.visible = visible;
if visible {
self.wants_redraw = true;
}
}
}

pub fn send_mouse_move(&self, manager: &mut WayVRManager, x: u32, y: u32) {
Expand Down
Loading

0 comments on commit 7e09c01

Please sign in to comment.