Merge pull request #92 from olekolek1000/wayvr_extprocess
WayVR: External process support, various tweaks and bugfixes
This commit is contained in:
@@ -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");
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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,
|
||||
@@ -86,18 +99,19 @@ 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;
|
||||
|
||||
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.clients.push(WayVRClient {
|
||||
self.add_client(WayVRClient {
|
||||
client,
|
||||
display_handle: process.display_handle,
|
||||
pid: creds.pid as u32,
|
||||
@@ -106,7 +120,25 @@ impl WayVRManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
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(
|
||||
@@ -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 {
|
||||
@@ -194,5 +235,7 @@ fn create_wayland_listener() -> anyhow::Result<(super::WaylandEnv, wayland_serve
|
||||
}
|
||||
};
|
||||
|
||||
let _ = export_display_number(env.display_num);
|
||||
|
||||
Ok((env, listener))
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
@@ -116,6 +118,7 @@ impl Display {
|
||||
gles_texture,
|
||||
wayland_env,
|
||||
visible: true,
|
||||
primary,
|
||||
overlay_id: None,
|
||||
tasks: SyncEventQueue::new(),
|
||||
})
|
||||
@@ -239,7 +242,12 @@ impl Display {
|
||||
|
||||
pub fn set_visible(&mut self, visible: bool) {
|
||||
log::info!("Display \"{}\" visible: {}", self.name.as_str(), 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) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mod client;
|
||||
pub mod client;
|
||||
mod comp;
|
||||
pub mod display;
|
||||
pub mod egl_data;
|
||||
@@ -45,9 +45,23 @@ impl WaylandEnv {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProcessWayVREnv {
|
||||
pub display_auth: Option<String>,
|
||||
pub display_name: Option<String>, // Externally spawned process by a user script
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExternalProcessRequest {
|
||||
pub env: ProcessWayVREnv,
|
||||
pub client: wayland_server::Client,
|
||||
pub pid: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum WayVRTask {
|
||||
NewToplevel(ClientId, ToplevelSurface),
|
||||
NewExternalProcess(ExternalProcessRequest),
|
||||
ProcessTerminationRequest(process::ProcessHandle),
|
||||
}
|
||||
|
||||
@@ -56,7 +70,7 @@ pub struct WayVR {
|
||||
time_start: u64,
|
||||
gles_renderer: GlesRenderer,
|
||||
pub displays: display::DisplayVec,
|
||||
manager: client::WayVRManager,
|
||||
pub manager: client::WayVRManager,
|
||||
wm: Rc<RefCell<window::WindowManager>>,
|
||||
egl_data: Rc<egl_data::EGLData>,
|
||||
pub processes: process::ProcessVec,
|
||||
@@ -70,8 +84,13 @@ pub enum MouseIndex {
|
||||
Right,
|
||||
}
|
||||
|
||||
pub enum TickResult {
|
||||
NewExternalProcess(ExternalProcessRequest), // Call WayVRManager::add_client after receiving this message
|
||||
}
|
||||
|
||||
impl WayVR {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
log::info!("Initializing WayVR");
|
||||
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
||||
let dh = display.handle();
|
||||
let compositor = compositor::CompositorState::new::<Application>(&dh);
|
||||
@@ -140,7 +159,9 @@ impl WayVR {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn tick_events(&mut self) -> anyhow::Result<()> {
|
||||
pub fn tick_events(&mut self) -> anyhow::Result<Vec<TickResult>> {
|
||||
let mut res: Vec<TickResult> = Vec::new();
|
||||
|
||||
// Check for redraw events
|
||||
self.displays.iter_mut(&mut |_, disp| {
|
||||
for disp_window in &disp.displayed_windows {
|
||||
@@ -159,17 +180,18 @@ impl WayVR {
|
||||
SmallVec::new();
|
||||
self.processes.iter_mut(&mut |handle, process| {
|
||||
if !process.is_running() {
|
||||
to_remove.push((handle, process.display_handle));
|
||||
to_remove.push((handle, process.display_handle()));
|
||||
}
|
||||
});
|
||||
|
||||
for (p_handle, disp_handle) in to_remove {
|
||||
self.processes.remove(&p_handle);
|
||||
|
||||
if let Some(display) = self.displays.get(&disp_handle) {
|
||||
if let Some(display) = self.displays.get_mut(&disp_handle) {
|
||||
display
|
||||
.tasks
|
||||
.send(display::DisplayTask::ProcessCleanup(p_handle));
|
||||
display.wants_redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +201,9 @@ impl WayVR {
|
||||
|
||||
while let Some(task) = self.tasks.read() {
|
||||
match task {
|
||||
WayVRTask::NewExternalProcess(req) => {
|
||||
res.push(TickResult::NewExternalProcess(req));
|
||||
}
|
||||
WayVRTask::NewToplevel(client_id, toplevel) => {
|
||||
// Attach newly created toplevel surfaces to displays
|
||||
for client in &self.manager.clients {
|
||||
@@ -197,7 +222,7 @@ impl WayVR {
|
||||
}
|
||||
} else {
|
||||
log::error!(
|
||||
"Failed to find process by PID {}. It was probably spawned externally.",
|
||||
"WayVR window creation failed: Unexpected process PID {}. It wasn't registered before.",
|
||||
client.pid
|
||||
);
|
||||
}
|
||||
@@ -215,7 +240,9 @@ impl WayVR {
|
||||
}
|
||||
|
||||
self.manager
|
||||
.tick_wayland(&mut self.displays, &mut self.processes)
|
||||
.tick_wayland(&mut self.displays, &mut self.processes)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn tick_finish(&mut self) -> anyhow::Result<()> {
|
||||
@@ -266,8 +293,22 @@ impl WayVR {
|
||||
.map(|display| display.dmabuf_data.clone())
|
||||
}
|
||||
|
||||
pub fn get_display_by_name(&self, name: &str) -> Option<display::DisplayHandle> {
|
||||
for (idx, cell) in self.displays.vec.iter().enumerate() {
|
||||
pub fn get_primary_display(displays: &DisplayVec) -> Option<display::DisplayHandle> {
|
||||
for (idx, cell) in displays.vec.iter().enumerate() {
|
||||
if let Some(cell) = cell {
|
||||
if cell.obj.primary {
|
||||
return Some(DisplayVec::get_handle(cell, idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_display_by_name(
|
||||
displays: &DisplayVec,
|
||||
name: &str,
|
||||
) -> Option<display::DisplayHandle> {
|
||||
for (idx, cell) in displays.vec.iter().enumerate() {
|
||||
if let Some(cell) = cell {
|
||||
if cell.obj.name == name {
|
||||
return Some(DisplayVec::get_handle(cell, idx));
|
||||
@@ -276,11 +317,13 @@ impl WayVR {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn create_display(
|
||||
&mut self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
name: &str,
|
||||
primary: bool,
|
||||
) -> anyhow::Result<display::DisplayHandle> {
|
||||
let display = display::Display::new(
|
||||
self.wm.clone(),
|
||||
@@ -290,6 +333,7 @@ impl WayVR {
|
||||
width,
|
||||
height,
|
||||
name,
|
||||
primary,
|
||||
)?;
|
||||
Ok(self.displays.add(display))
|
||||
}
|
||||
@@ -308,17 +352,17 @@ impl WayVR {
|
||||
) -> Option<process::ProcessHandle> {
|
||||
for (idx, cell) in self.processes.vec.iter().enumerate() {
|
||||
if let Some(cell) = &cell {
|
||||
let process = &cell.obj;
|
||||
if let process::Process::Managed(process) = &cell.obj {
|
||||
if process.display_handle != display_handle
|
||||
|| process.exec_path != exec_path
|
||||
|| process.args != args
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(process::ProcessVec::get_handle(cell, idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -328,6 +372,18 @@ impl WayVR {
|
||||
.send(WayVRTask::ProcessTerminationRequest(process_handle));
|
||||
}
|
||||
|
||||
pub fn add_external_process(
|
||||
&mut self,
|
||||
display_handle: display::DisplayHandle,
|
||||
pid: u32,
|
||||
) -> process::ProcessHandle {
|
||||
self.processes
|
||||
.add(process::Process::External(process::ExternalProcess {
|
||||
display_handle,
|
||||
pid,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn spawn_process(
|
||||
&mut self,
|
||||
display_handle: display::DisplayHandle,
|
||||
@@ -341,7 +397,9 @@ impl WayVR {
|
||||
.ok_or(anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
|
||||
|
||||
let res = display.spawn_process(exec_path, args, env)?;
|
||||
Ok(self.processes.add(process::Process {
|
||||
Ok(self
|
||||
.processes
|
||||
.add(process::Process::Managed(process::WayVRProcess {
|
||||
auth_key: res.auth_key,
|
||||
child: res.child,
|
||||
display_handle,
|
||||
@@ -351,6 +409,6 @@ impl WayVR {
|
||||
.iter()
|
||||
.map(|(a, b)| (String::from(*a), String::from(*b)))
|
||||
.collect(),
|
||||
}))
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::gen_id;
|
||||
|
||||
use super::display;
|
||||
|
||||
pub struct Process {
|
||||
pub struct WayVRProcess {
|
||||
pub auth_key: String,
|
||||
pub child: std::process::Child,
|
||||
pub display_handle: display::DisplayHandle,
|
||||
@@ -12,7 +12,40 @@ pub struct Process {
|
||||
pub env: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl Drop for Process {
|
||||
pub struct ExternalProcess {
|
||||
pub pid: u32,
|
||||
pub display_handle: display::DisplayHandle,
|
||||
}
|
||||
|
||||
pub enum Process {
|
||||
Managed(WayVRProcess), // Process spawned by WayVR
|
||||
External(ExternalProcess), // External process not directly controlled by us
|
||||
}
|
||||
|
||||
impl Process {
|
||||
pub fn display_handle(&self) -> display::DisplayHandle {
|
||||
match self {
|
||||
Process::Managed(p) => p.display_handle,
|
||||
Process::External(p) => p.display_handle,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_running(&mut self) -> bool {
|
||||
match self {
|
||||
Process::Managed(p) => p.is_running(),
|
||||
Process::External(p) => p.is_running(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn terminate(&mut self) {
|
||||
match self {
|
||||
Process::Managed(p) => p.terminate(),
|
||||
Process::External(p) => p.terminate(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WayVRProcess {
|
||||
fn drop(&mut self) {
|
||||
log::info!(
|
||||
"Sending SIGTERM (graceful exit) to process {}",
|
||||
@@ -22,8 +55,8 @@ impl Drop for Process {
|
||||
}
|
||||
}
|
||||
|
||||
impl Process {
|
||||
pub fn is_running(&mut self) -> bool {
|
||||
impl WayVRProcess {
|
||||
fn is_running(&mut self) -> bool {
|
||||
match self.child.try_wait() {
|
||||
Ok(Some(_exit_status)) => false,
|
||||
Ok(None) => true,
|
||||
@@ -35,7 +68,7 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn terminate(&mut self) {
|
||||
fn terminate(&mut self) {
|
||||
unsafe {
|
||||
// Gracefully stop process
|
||||
libc::kill(self.child.id() as i32, libc::SIGTERM);
|
||||
@@ -43,15 +76,44 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalProcess {
|
||||
fn is_running(&self) -> bool {
|
||||
if self.pid == 0 {
|
||||
false
|
||||
} else {
|
||||
std::fs::metadata(format!("/proc/{}", self.pid)).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn terminate(&mut self) {
|
||||
if self.pid != 0 {
|
||||
unsafe {
|
||||
// send SIGINT (^C)
|
||||
libc::kill(self.pid as i32, libc::SIGINT);
|
||||
}
|
||||
}
|
||||
self.pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gen_id!(ProcessVec, Process, ProcessCell, ProcessHandle);
|
||||
|
||||
pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option<ProcessHandle> {
|
||||
for (idx, cell) in processes.vec.iter().enumerate() {
|
||||
if let Some(cell) = cell {
|
||||
if cell.obj.child.id() == pid {
|
||||
match &cell.obj {
|
||||
Process::Managed(wayvr_process) => {
|
||||
if wayvr_process.child.id() == pid {
|
||||
return Some(ProcessVec::get_handle(cell, idx));
|
||||
}
|
||||
}
|
||||
Process::External(external_process) => {
|
||||
if external_process.pid == pid {
|
||||
return Some(ProcessVec::get_handle(cell, idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
compile_error!("WayVR feature is not enabled");
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{BTreeMap, HashMap},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
@@ -12,6 +14,7 @@ use crate::{
|
||||
backend::{
|
||||
overlay::RelativeTo,
|
||||
task::{TaskContainer, TaskType},
|
||||
wayvr,
|
||||
},
|
||||
config::{load_known_yaml, ConfigType},
|
||||
overlays::wayvr::WayVRAction,
|
||||
@@ -63,6 +66,7 @@ pub struct WayVRDisplay {
|
||||
pub rotation: Option<Rotation>,
|
||||
pub pos: Option<[f32; 3]>,
|
||||
pub attach_to: Option<AttachTo>,
|
||||
pub primary: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
@@ -79,6 +83,7 @@ impl WayVRCatalog {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct WayVRConfig {
|
||||
pub version: u32,
|
||||
pub run_compositor_at_start: bool,
|
||||
pub catalogs: HashMap<String, WayVRCatalog>,
|
||||
pub displays: BTreeMap<String, WayVRDisplay>, // sorted alphabetically
|
||||
}
|
||||
@@ -92,7 +97,31 @@ impl WayVRConfig {
|
||||
self.displays.get(name)
|
||||
}
|
||||
|
||||
pub fn post_load(&self, tasks: &mut TaskContainer) {
|
||||
pub fn get_default_display(&self) -> Option<(String, &WayVRDisplay)> {
|
||||
for (disp_name, disp) in &self.displays {
|
||||
if disp.primary.unwrap_or(false) {
|
||||
return Some((disp_name.clone(), disp));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn post_load(
|
||||
&self,
|
||||
tasks: &mut TaskContainer,
|
||||
) -> anyhow::Result<Option<Rc<RefCell<wayvr::WayVR>>>> {
|
||||
let primary_count = self
|
||||
.displays
|
||||
.iter()
|
||||
.filter(|d| d.1.primary.unwrap_or(false))
|
||||
.count();
|
||||
|
||||
if primary_count > 1 {
|
||||
anyhow::bail!("Number of primary displays is more than 1")
|
||||
} else if primary_count == 0 {
|
||||
log::warn!("No primary display specified");
|
||||
}
|
||||
|
||||
for (catalog_name, catalog) in &self.catalogs {
|
||||
for app in &catalog.apps {
|
||||
if let Some(b) = app.shown_at_start {
|
||||
@@ -105,6 +134,14 @@ impl WayVRConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.run_compositor_at_start {
|
||||
// Start Wayland server instantly
|
||||
Ok(Some(Rc::new(RefCell::new(wayvr::WayVR::new()?))))
|
||||
} else {
|
||||
// Lazy-init WayVR later if the user requested
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
common::OverlayContainer,
|
||||
input::{self, InteractionHandler},
|
||||
overlay::{ui_transform, OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
|
||||
wayvr,
|
||||
wayvr::{self, display, WayVR},
|
||||
},
|
||||
graphics::WlxGraphics,
|
||||
state::{self, AppState, KeyboardFocus},
|
||||
@@ -119,6 +119,121 @@ impl WayVRRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_create_display<O>(
|
||||
app: &mut AppState,
|
||||
wayvr: &mut WayVR,
|
||||
disp_name: &str,
|
||||
) -> anyhow::Result<(display::DisplayHandle, Option<OverlayData<O>>)>
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
let created_overlay: Option<OverlayData<O>>;
|
||||
|
||||
let disp_handle = if let Some(disp) = WayVR::get_display_by_name(&wayvr.displays, disp_name) {
|
||||
created_overlay = None;
|
||||
disp
|
||||
} else {
|
||||
let conf_display = app
|
||||
.session
|
||||
.wayvr_config
|
||||
.get_display(disp_name)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"Cannot find display named \"{}\"",
|
||||
disp_name
|
||||
))?
|
||||
.clone();
|
||||
|
||||
let disp_handle = wayvr.create_display(
|
||||
conf_display.width,
|
||||
conf_display.height,
|
||||
disp_name,
|
||||
conf_display.primary.unwrap_or(false),
|
||||
)?;
|
||||
|
||||
let mut overlay = create_wayvr_display_overlay::<O>(
|
||||
app,
|
||||
conf_display.width,
|
||||
conf_display.height,
|
||||
disp_handle,
|
||||
conf_display.scale.unwrap_or(1.0),
|
||||
)?;
|
||||
|
||||
if let Some(attach_to) = &conf_display.attach_to {
|
||||
overlay.state.relative_to = attach_to.get_relative_to();
|
||||
}
|
||||
|
||||
if let Some(rot) = &conf_display.rotation {
|
||||
overlay.state.spawn_rotation = glam::Quat::from_axis_angle(
|
||||
Vec3::from_slice(&rot.axis),
|
||||
f32::to_radians(rot.angle),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(pos) = &conf_display.pos {
|
||||
overlay.state.spawn_point = Vec3A::from_slice(pos);
|
||||
}
|
||||
|
||||
let display = wayvr.displays.get_mut(&disp_handle).unwrap(); // Never fails
|
||||
display.overlay_id = Some(overlay.state.id);
|
||||
|
||||
created_overlay = Some(overlay);
|
||||
|
||||
disp_handle
|
||||
};
|
||||
|
||||
Ok((disp_handle, created_overlay))
|
||||
}
|
||||
|
||||
pub fn tick_events<O>(app: &mut AppState, overlays: &mut OverlayContainer<O>) -> anyhow::Result<()>
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
if let Some(wayvr) = app.wayvr.clone() {
|
||||
let res = wayvr.borrow_mut().tick_events()?;
|
||||
|
||||
for result in res {
|
||||
match result {
|
||||
wayvr::TickResult::NewExternalProcess(req) => {
|
||||
let config = &app.session.wayvr_config;
|
||||
|
||||
let disp_name = if let Some(display_name) = req.env.display_name {
|
||||
config
|
||||
.get_display(display_name.as_str())
|
||||
.map(|_| display_name)
|
||||
} else {
|
||||
config
|
||||
.get_default_display()
|
||||
.map(|(display_name, _)| display_name)
|
||||
};
|
||||
|
||||
if let Some(disp_name) = disp_name {
|
||||
let mut wayvr = wayvr.borrow_mut();
|
||||
|
||||
log::info!("Registering external process with PID {}", req.pid);
|
||||
|
||||
let (disp_handle, created_overlay) =
|
||||
get_or_create_display::<O>(app, &mut wayvr, &disp_name)?;
|
||||
|
||||
wayvr.add_external_process(disp_handle, req.pid);
|
||||
|
||||
wayvr.manager.add_client(wayvr::client::WayVRClient {
|
||||
client: req.client,
|
||||
display_handle: disp_handle,
|
||||
pid: req.pid,
|
||||
});
|
||||
|
||||
if let Some(created_overlay) = created_overlay {
|
||||
overlays.add(created_overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl WayVRRenderer {
|
||||
fn ensure_dmabuf(&mut self, data: wayvr::egl_data::DMAbufData) -> anyhow::Result<()> {
|
||||
if self.dmabuf_image.is_none() {
|
||||
@@ -285,10 +400,6 @@ fn action_app_click<O>(
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
use crate::overlays::wayvr::create_wayvr_display_overlay;
|
||||
|
||||
let mut created_overlay: Option<OverlayData<O>> = None;
|
||||
|
||||
let wayvr = app.get_wayvr()?.clone();
|
||||
|
||||
let catalog = app
|
||||
@@ -304,54 +415,8 @@ where
|
||||
if let Some(app_entry) = catalog.get_app(app_name) {
|
||||
let mut wayvr = wayvr.borrow_mut();
|
||||
|
||||
let disp_handle = if let Some(disp) = wayvr.get_display_by_name(&app_entry.target_display) {
|
||||
disp
|
||||
} else {
|
||||
let conf_display = app
|
||||
.session
|
||||
.wayvr_config
|
||||
.get_display(&app_entry.target_display)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"Cannot find display named \"{}\"",
|
||||
app_entry.target_display
|
||||
))?
|
||||
.clone();
|
||||
|
||||
let display_handle = wayvr.create_display(
|
||||
conf_display.width,
|
||||
conf_display.height,
|
||||
&app_entry.target_display,
|
||||
)?;
|
||||
|
||||
let mut overlay = create_wayvr_display_overlay::<O>(
|
||||
app,
|
||||
conf_display.width,
|
||||
conf_display.height,
|
||||
display_handle,
|
||||
conf_display.scale.unwrap_or(1.0),
|
||||
)?;
|
||||
|
||||
if let Some(attach_to) = &conf_display.attach_to {
|
||||
overlay.state.relative_to = attach_to.get_relative_to();
|
||||
}
|
||||
|
||||
if let Some(rot) = &conf_display.rotation {
|
||||
overlay.state.spawn_rotation = glam::Quat::from_axis_angle(
|
||||
Vec3::from_slice(&rot.axis),
|
||||
f32::to_radians(rot.angle),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(pos) = &conf_display.pos {
|
||||
overlay.state.spawn_point = Vec3A::from_slice(pos);
|
||||
}
|
||||
|
||||
let display = wayvr.displays.get_mut(&display_handle).unwrap(); // Never fails
|
||||
display.overlay_id = Some(overlay.state.id);
|
||||
|
||||
created_overlay = Some(overlay);
|
||||
display_handle
|
||||
};
|
||||
let (disp_handle, created_overlay) =
|
||||
get_or_create_display::<O>(app, &mut wayvr, &app_entry.target_display)?;
|
||||
|
||||
// Parse additional args
|
||||
let args_vec: Vec<&str> = if let Some(args) = &app_entry.args {
|
||||
@@ -380,9 +445,10 @@ where
|
||||
// Spawn process
|
||||
wayvr.spawn_process(disp_handle, &app_entry.exec, &args_vec, &env_vec)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(created_overlay)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action_display_click<O>(
|
||||
@@ -397,7 +463,7 @@ where
|
||||
let wayvr = app.get_wayvr()?;
|
||||
let mut wayvr = wayvr.borrow_mut();
|
||||
|
||||
if let Some(handle) = wayvr.get_display_by_name(display_name) {
|
||||
if let Some(handle) = WayVR::get_display_by_name(&wayvr.displays, display_name) {
|
||||
if let Some(display) = wayvr.displays.get_mut(&handle) {
|
||||
if let Some(overlay_id) = display.overlay_id {
|
||||
if let Some(overlay) = overlays.mut_by_id(overlay_id) {
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
version: 1
|
||||
|
||||
# Set to true if you want to make Wyland server instantly available
|
||||
# (used for remote starting external processes)
|
||||
run_compositor_at_start: false
|
||||
|
||||
displays:
|
||||
Watch:
|
||||
width: 400
|
||||
@@ -16,6 +20,7 @@ displays:
|
||||
Disp1:
|
||||
width: 640
|
||||
height: 480
|
||||
primary: true # Required if you want to attach external processes (not spawned by WayVR itself) without WAYVR_DISPLAY_NAME set
|
||||
Disp2:
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
@@ -100,7 +100,7 @@ impl AppState {
|
||||
let session = AppSession::load();
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
session.wayvr_config.post_load(&mut tasks);
|
||||
let wayvr = session.wayvr_config.post_load(&mut tasks)?;
|
||||
|
||||
Ok(AppState {
|
||||
fc: FontCache::new(session.config.primary_font.clone())?,
|
||||
@@ -116,7 +116,7 @@ impl AppState {
|
||||
keyboard_focus: KeyboardFocus::PhysicalScreen,
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
wayvr: None,
|
||||
wayvr,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ impl AppState {
|
||||
if let Some(wvr) = &self.wayvr {
|
||||
Ok(wvr.clone())
|
||||
} else {
|
||||
log::info!("Initializing WayVR");
|
||||
let wayvr = Rc::new(RefCell::new(WayVR::new()?));
|
||||
self.wayvr = Some(wayvr.clone());
|
||||
Ok(wayvr)
|
||||
|
||||
Reference in New Issue
Block a user