WayVR: Layouting system, state changing feedback, process userdata, various IPC changes

WayVR:
- Layouting system (tiled and stacked)

IPC:
- Implemented routes: `WvrDisplaySetWindowLayout`, `WvrDisplayWindowList`, `WvrWindowSetVisible`, `WvrProcessGet`,

- Packet broadcasting
- State change feedback to the client (displays/windows/processes)
This commit is contained in:
Aleksander
2025-01-31 20:00:56 +01:00
parent 8766999e28
commit 3c67abcebb
10 changed files with 408 additions and 88 deletions

2
Cargo.lock generated
View File

@@ -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=fe2e8be04c7b86adcf972be7ebe46961bd881f35#fe2e8be04c7b86adcf972be7ebe46961bd881f35" source = "git+https://github.com/olekolek1000/wayvr-ipc.git?rev=3c411d09ba1bba2609288e29739c0f1ec736b012#3c411d09ba1bba2609288e29739c0f1ec736b012"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",

View File

@@ -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 = "fe2e8be04c7b86adcf972be7ebe46961bd881f35", default-features = false, optional = true } wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "3c411d09ba1bba2609288e29739c0f1ec736b012", default-features = false, optional = true }
################################ ################################
[build-dependencies] [build-dependencies]

View File

@@ -338,7 +338,11 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut state, &mut overlays)?; if let Err(e) =
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut state, &mut overlays)
{
log::error!("WayVR tick_events failed: {:?}", e);
}
log::trace!("Rendering frame"); log::trace!("Rendering frame");

View File

@@ -386,7 +386,11 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
} }
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app_state, &mut overlays)?; if let Err(e) =
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app_state, &mut overlays)
{
log::error!("WayVR tick_events failed: {:?}", e);
}
for o in overlays.iter_mut() { for o in overlays.iter_mut() {
if !o.state.want_visible { if !o.state.want_visible {

View File

@@ -35,7 +35,7 @@ fn generate_auth_key() -> String {
pub struct DisplayWindow { pub struct DisplayWindow {
pub window_handle: window::WindowHandle, pub window_handle: window::WindowHandle,
pub toplevel: ToplevelSurface, pub toplevel: ToplevelSurface,
process_handle: process::ProcessHandle, pub process_handle: process::ProcessHandle,
} }
pub struct SpawnProcessResult { pub struct SpawnProcessResult {
@@ -57,6 +57,7 @@ pub struct Display {
pub height: u16, pub height: u16,
pub name: String, pub name: String,
pub visible: bool, pub visible: bool,
pub layout: packet_server::WvrDisplayWindowLayout,
pub overlay_id: Option<OverlayID>, pub overlay_id: Option<OverlayID>,
pub wants_redraw: bool, pub wants_redraw: bool,
pub primary: bool, pub primary: bool,
@@ -84,29 +85,31 @@ impl Drop for Display {
} }
} }
pub struct DisplayInitParams<'a> {
pub wm: Rc<RefCell<window::WindowManager>>,
pub renderer: &'a mut GlesRenderer,
pub egl_data: Rc<egl_data::EGLData>,
pub wayland_env: super::WaylandEnv,
pub width: u16,
pub height: u16,
pub name: &'a str,
pub primary: bool,
}
impl Display { impl Display {
pub fn new( pub fn new(params: DisplayInitParams) -> anyhow::Result<Self> {
wm: Rc<RefCell<window::WindowManager>>, if params.width > MAX_DISPLAY_SIZE {
renderer: &mut GlesRenderer,
egl_data: Rc<egl_data::EGLData>,
wayland_env: super::WaylandEnv,
width: u16,
height: u16,
name: &str,
primary: bool,
) -> anyhow::Result<Self> {
if width > MAX_DISPLAY_SIZE {
anyhow::bail!( anyhow::bail!(
"display width ({}) is larger than {}", "display width ({}) is larger than {}",
width, params.width,
MAX_DISPLAY_SIZE MAX_DISPLAY_SIZE
); );
} }
if height > MAX_DISPLAY_SIZE { if params.height > MAX_DISPLAY_SIZE {
anyhow::bail!( anyhow::bail!(
"display height ({}) is larger than {}", "display height ({}) is larger than {}",
height, params.height,
MAX_DISPLAY_SIZE MAX_DISPLAY_SIZE
); );
} }
@@ -114,42 +117,44 @@ impl Display {
let tex_format = ffi::RGBA; let tex_format = ffi::RGBA;
let internal_format = ffi::RGBA8; let internal_format = ffi::RGBA8;
let tex_id = renderer.with_context(|gl| { let tex_id = params.renderer.with_context(|gl| {
smithay_wrapper::create_framebuffer_texture( smithay_wrapper::create_framebuffer_texture(
gl, gl,
width as u32, params.width as u32,
height as u32, params.height as u32,
tex_format, tex_format,
internal_format, internal_format,
) )
})?; })?;
let egl_image = egl_data.create_egl_image(tex_id)?; let egl_image = params.egl_data.create_egl_image(tex_id)?;
let dmabuf_data = egl_data.create_dmabuf_data(&egl_image)?; let dmabuf_data = params.egl_data.create_dmabuf_data(&egl_image)?;
let opaque = false; let opaque = false;
let size = (width as i32, height as i32).into(); let size = (params.width as i32, params.height as i32).into();
let gles_texture = let gles_texture = unsafe {
unsafe { GlesTexture::from_raw(renderer, Some(tex_format), opaque, tex_id, size) }; GlesTexture::from_raw(params.renderer, Some(tex_format), opaque, tex_id, size)
};
Ok(Self { Ok(Self {
wm, egl_data: params.egl_data,
width, width: params.width,
height, height: params.height,
name: String::from(name), name: String::from(params.name),
primary: params.primary,
wayland_env: params.wayland_env,
wm: params.wm,
displayed_windows: Vec::new(), displayed_windows: Vec::new(),
wants_redraw: true,
egl_data,
dmabuf_data, dmabuf_data,
egl_image, egl_image,
gles_texture, gles_texture,
wayland_env,
visible: true,
primary,
overlay_id: None,
tasks: SyncEventQueue::new(),
last_pressed_time_ms: 0, last_pressed_time_ms: 0,
no_windows_since: None, no_windows_since: None,
overlay_id: None,
tasks: SyncEventQueue::new(),
visible: true,
wants_redraw: true,
layout: packet_server::WvrDisplayWindowLayout::Tiling,
}) })
} }
@@ -178,19 +183,62 @@ impl Display {
self.reposition_windows(); self.reposition_windows();
} }
fn reposition_windows(&mut self) { pub fn reposition_windows(&mut self) {
let window_count = self.displayed_windows.len(); let window_count = self.displayed_windows.len();
for (i, win) in self.displayed_windows.iter_mut().enumerate() { match &self.layout {
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) { packet_server::WvrDisplayWindowLayout::Tiling => {
let d_cur = i as f32 / window_count as f32; let mut i = 0;
let d_next = (i + 1) as f32 / window_count as f32; for win in self.displayed_windows.iter_mut() {
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
if !window.visible {
continue;
}
let d_cur = i as f32 / window_count as f32;
let d_next = (i + 1) as f32 / window_count as f32;
let left = (d_cur * self.width as f32) as i32; let left = (d_cur * self.width as f32) as i32;
let right = (d_next * self.width as f32) as i32; let right = (d_next * self.width as f32) as i32;
window.set_pos(left, 0); window.set_pos(left, 0);
window.set_size((right - left) as u32, self.height as u32); window.set_size((right - left) as u32, self.height as u32);
i += 1;
}
}
}
packet_server::WvrDisplayWindowLayout::Stacking(opts) => {
let do_margins = |margins: &packet_server::Margins, window: &mut window::Window| {
let top = margins.top as i32;
let bottom = self.height as i32 - margins.bottom as i32;
let left = margins.left as i32;
let right = self.width as i32 - margins.right as i32;
let width = right - left;
let height = bottom - top;
if width < 0 || height < 0 {
return; // wrong parameters, do nothing!
}
window.set_pos(left, top);
window.set_size(width as u32, height as u32);
};
let mut i = 0;
for win in self.displayed_windows.iter_mut() {
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
if !window.visible {
continue;
}
do_margins(
if i == 0 {
&opts.margins_first
} else {
&opts.margins_rest
},
window,
);
i += 1;
}
}
} }
} }
} }
@@ -217,6 +265,7 @@ impl Display {
while let Some(task) = self.tasks.read() { while let Some(task) = self.tasks.read() {
match task { match task {
DisplayTask::ProcessCleanup(process_handle) => { DisplayTask::ProcessCleanup(process_handle) => {
let count = self.displayed_windows.len();
self.displayed_windows self.displayed_windows
.retain(|win| win.process_handle != process_handle); .retain(|win| win.process_handle != process_handle);
log::info!( log::info!(
@@ -226,6 +275,12 @@ impl Display {
); );
self.no_windows_since = Some(get_millis()); self.no_windows_since = Some(get_millis());
if count != self.displayed_windows.len() {
signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::WindowRemoved,
));
}
self.reposition_windows(); self.reposition_windows();
} }
} }
@@ -245,6 +300,9 @@ impl Display {
.flat_map(|display_window| { .flat_map(|display_window| {
let wm = self.wm.borrow_mut(); let wm = self.wm.borrow_mut();
if let Some(window) = wm.windows.get(&display_window.window_handle) { if let Some(window) = wm.windows.get(&display_window.window_handle) {
if !window.visible {
return vec![];
}
render_elements_from_surface_tree( render_elements_from_surface_tree(
renderer, renderer,
display_window.toplevel.wl_surface(), display_window.toplevel.wl_surface(),
@@ -284,8 +342,12 @@ impl Display {
fn get_hovered_window(&self, cursor_x: u32, cursor_y: u32) -> Option<window::WindowHandle> { fn get_hovered_window(&self, cursor_x: u32, cursor_y: u32) -> Option<window::WindowHandle> {
let wm = self.wm.borrow(); let wm = self.wm.borrow();
for cell in self.displayed_windows.iter() { for cell in self.displayed_windows.iter().rev() {
if let Some(window) = wm.windows.get(&cell.window_handle) { if let Some(window) = wm.windows.get(&cell.window_handle) {
if !window.visible {
continue;
}
if (cursor_x as i32) >= window.pos_x if (cursor_x as i32) >= window.pos_x
&& (cursor_x as i32) < window.pos_x + window.size_x as i32 && (cursor_x as i32) < window.pos_x + window.size_x as i32
&& (cursor_y as i32) >= window.pos_y && (cursor_y as i32) >= window.pos_y
@@ -298,15 +360,30 @@ impl Display {
None None
} }
pub fn trigger_rerender(&mut self) {
self.wants_redraw = true;
}
pub fn set_visible(&mut self, visible: bool) { pub fn set_visible(&mut self, visible: bool) {
log::info!("Display \"{}\" visible: {}", self.name.as_str(), visible); log::info!("Display \"{}\" visible: {}", self.name.as_str(), visible);
if self.visible != visible { if self.visible == visible {
self.visible = visible; return;
if visible {
self.wants_redraw = true;
self.no_windows_since = None;
}
} }
self.visible = visible;
if visible {
self.no_windows_since = None;
self.trigger_rerender();
}
}
pub fn set_layout(&mut self, layout: packet_server::WvrDisplayWindowLayout) {
log::info!("Display \"{}\" layout: {:?}", self.name.as_str(), layout);
if self.layout == layout {
return;
}
self.layout = layout;
self.trigger_rerender();
self.reposition_windows();
} }
pub fn send_mouse_move( pub fn send_mouse_move(

View File

@@ -11,7 +11,7 @@ mod smithay_wrapper;
mod time; mod time;
mod window; mod window;
use comp::Application; use comp::Application;
use display::DisplayVec; use display::{DisplayInitParams, DisplayVec};
use event_queue::SyncEventQueue; use event_queue::SyncEventQueue;
use process::ProcessVec; use process::ProcessVec;
use server_ipc::WayVRServer; use server_ipc::WayVRServer;
@@ -32,9 +32,13 @@ use smithay::{
shm::ShmState, shm::ShmState,
}, },
}; };
use std::{cell::RefCell, collections::HashSet, rc::Rc}; use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
use time::get_millis; use time::get_millis;
use wayvr_ipc::packet_client; use wayvr_ipc::{packet_client, packet_server};
const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle"; const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle";
const STR_INVALID_HANDLE_PROCESS: &str = "Invalid process handle"; const STR_INVALID_HANDLE_PROCESS: &str = "Invalid process handle";
@@ -76,6 +80,11 @@ pub enum WayVRTask {
#[derive(Clone)] #[derive(Clone)]
pub enum WayVRSignal { pub enum WayVRSignal {
DisplayVisibility(display::DisplayHandle, bool), DisplayVisibility(display::DisplayHandle, bool),
DisplayWindowLayout(
display::DisplayHandle,
packet_server::WvrDisplayWindowLayout,
),
BroadcastStateChanged(packet_server::WvrStateChanged),
} }
pub struct Config { pub struct Config {
@@ -102,7 +111,7 @@ pub struct WayVRState {
pub struct WayVR { pub struct WayVR {
pub state: WayVRState, pub state: WayVRState,
ipc_server: WayVRServer, pub ipc_server: WayVRServer,
} }
pub enum MouseIndex { pub enum MouseIndex {
@@ -302,13 +311,13 @@ impl WayVR {
} }
}); });
for (p_handle, disp_handle) in to_remove { for (p_handle, disp_handle) in &to_remove {
self.state.processes.remove(&p_handle); self.state.processes.remove(p_handle);
if let Some(display) = self.state.displays.get_mut(&disp_handle) { if let Some(display) = self.state.displays.get_mut(disp_handle) {
display display
.tasks .tasks
.send(display::DisplayTask::ProcessCleanup(p_handle)); .send(display::DisplayTask::ProcessCleanup(*p_handle));
display.wants_redraw = true; display.wants_redraw = true;
} }
} }
@@ -317,6 +326,12 @@ impl WayVR {
display.tick(&self.state.config, &handle, &mut self.state.signals); display.tick(&self.state.config, &handle, &mut self.state.signals);
}); });
if !to_remove.is_empty() {
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::ProcessRemoved,
));
}
while let Some(task) = self.state.tasks.read() { while let Some(task) = self.state.tasks.read() {
match task { match task {
WayVRTask::NewExternalProcess(req) => { WayVRTask::NewExternalProcess(req) => {
@@ -329,15 +344,22 @@ impl WayVR {
// 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 {
if client.client.id() == client_id { if client.client.id() == client_id {
let window_handle = self.state.wm.borrow_mut().create_window(&toplevel);
if let Some(process_handle) = if let Some(process_handle) =
process::find_by_pid(&self.state.processes, client.pid) process::find_by_pid(&self.state.processes, client.pid)
{ {
let window_handle = self
.state
.wm
.borrow_mut()
.create_window(client.display_handle, &toplevel);
if let Some(display) = if let Some(display) =
self.state.displays.get_mut(&client.display_handle) self.state.displays.get_mut(&client.display_handle)
{ {
display.add_window(window_handle, process_handle, &toplevel); display.add_window(window_handle, process_handle, &toplevel);
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::WindowCreated,
));
} else { } else {
// This shouldn't happen, scream if it does // This shouldn't happen, scream if it does
log::error!("Could not attach window handle into display"); log::error!("Could not attach window handle into display");
@@ -456,6 +478,16 @@ impl WayVRState {
} }
} }
pub fn set_display_layout(
&mut self,
display: display::DisplayHandle,
layout: packet_server::WvrDisplayWindowLayout,
) {
if let Some(display) = self.displays.get_mut(&display) {
display.set_layout(layout);
}
}
pub fn get_dmabuf_data(&self, display: display::DisplayHandle) -> Option<egl_data::DMAbufData> { pub fn get_dmabuf_data(&self, display: display::DisplayHandle) -> Option<egl_data::DMAbufData> {
self.displays self.displays
.get(&display) .get(&display)
@@ -469,17 +501,24 @@ impl WayVRState {
name: &str, name: &str,
primary: bool, primary: bool,
) -> anyhow::Result<display::DisplayHandle> { ) -> anyhow::Result<display::DisplayHandle> {
let display = display::Display::new( let display = display::Display::new(DisplayInitParams {
self.wm.clone(), wm: self.wm.clone(),
&mut self.manager.state.gles_renderer, egl_data: self.egl_data.clone(),
self.egl_data.clone(), renderer: &mut self.manager.state.gles_renderer,
self.manager.wayland_env.clone(), wayland_env: self.manager.wayland_env.clone(),
width, width,
height, height,
name, name,
primary, primary,
)?; })?;
Ok(self.displays.add(display))
let handle = self.displays.add(display);
self.signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::DisplayCreated,
));
Ok(handle)
} }
pub fn destroy_display(&mut self, handle: display::DisplayHandle) -> anyhow::Result<()> { pub fn destroy_display(&mut self, handle: display::DisplayHandle) -> anyhow::Result<()> {
@@ -519,6 +558,10 @@ impl WayVRState {
self.displays.remove(&handle); self.displays.remove(&handle);
self.signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::DisplayRemoved,
));
Ok(()) Ok(())
} }
@@ -584,6 +627,7 @@ impl WayVRState {
exec_path: &str, exec_path: &str,
args: &[&str], args: &[&str],
env: &[(&str, &str)], env: &[(&str, &str)],
userdata: HashMap<String, String>,
) -> anyhow::Result<process::ProcessHandle> { ) -> anyhow::Result<process::ProcessHandle> {
let display = self let display = self
.displays .displays
@@ -591,18 +635,26 @@ impl WayVRState {
.ok_or(anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?; .ok_or(anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
let res = display.spawn_process(exec_path, args, env)?; let res = display.spawn_process(exec_path, args, env)?;
Ok(self
let handle = self
.processes .processes
.add(process::Process::Managed(process::WayVRProcess { .add(process::Process::Managed(process::WayVRProcess {
auth_key: res.auth_key, auth_key: res.auth_key,
child: res.child, child: res.child,
display_handle, display_handle,
exec_path: String::from(exec_path), exec_path: String::from(exec_path),
userdata,
args: args.iter().map(|x| String::from(*x)).collect(), args: args.iter().map(|x| String::from(*x)).collect(),
env: env env: env
.iter() .iter()
.map(|(a, b)| (String::from(*a), String::from(*b))) .map(|(a, b)| (String::from(*a), String::from(*b)))
.collect(), .collect(),
}))) }));
self.signals.send(WayVRSignal::BroadcastStateChanged(
packet_server::WvrStateChanged::ProcessCreated,
));
Ok(handle)
} }
} }

View File

@@ -1,3 +1,5 @@
use std::collections::HashMap;
use wayvr_ipc::packet_server; use wayvr_ipc::packet_server;
use crate::gen_id; use crate::gen_id;
@@ -13,6 +15,8 @@ pub struct WayVRProcess {
pub exec_path: String, pub exec_path: String,
pub args: Vec<String>, pub args: Vec<String>,
pub env: Vec<(String, String)>, pub env: Vec<(String, String)>,
pub userdata: HashMap<String, String>,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -60,11 +64,13 @@ impl Process {
match self { match self {
Process::Managed(p) => packet_server::WvrProcess { Process::Managed(p) => packet_server::WvrProcess {
name: p.get_name().unwrap_or(String::from("unknown")), name: p.get_name().unwrap_or(String::from("unknown")),
userdata: p.userdata.clone(),
display_handle: p.display_handle.as_packet(), display_handle: p.display_handle.as_packet(),
handle: handle.as_packet(), handle: handle.as_packet(),
}, },
Process::External(p) => packet_server::WvrProcess { Process::External(p) => packet_server::WvrProcess {
name: p.get_name().unwrap_or(String::from("unknown")), name: p.get_name().unwrap_or(String::from("unknown")),
userdata: Default::default(),
display_handle: p.display_handle.as_packet(), display_handle: p.display_handle.as_packet(),
handle: handle.as_packet(), handle: handle.as_packet(),
}, },

View File

@@ -1,4 +1,4 @@
use super::{display, process, TickTask, WayVRSignal}; use super::{display, process, window, TickTask, WayVRSignal};
use bytes::BufMut; use bytes::BufMut;
use interprocess::local_socket::{self, traits::Listener, ToNsName}; use interprocess::local_socket::{self, traits::Listener, ToNsName};
use smallvec::SmallVec; use smallvec::SmallVec;
@@ -236,6 +236,97 @@ impl Connection {
Ok(()) Ok(())
} }
fn handle_wvr_display_set_window_layout(
&mut self,
params: &mut TickParams,
handle: packet_server::WvrDisplayHandle,
layout: packet_server::WvrDisplayWindowLayout,
) -> anyhow::Result<()> {
params.state.signals.send(WayVRSignal::DisplayWindowLayout(
display::DisplayHandle::from_packet(handle),
layout,
));
Ok(())
}
fn handle_wvr_display_window_list(
&mut self,
params: &mut TickParams,
serial: ipc::Serial,
display_handle: packet_server::WvrDisplayHandle,
) -> anyhow::Result<()> {
let mut send = |list: Option<packet_server::WvrWindowList>| -> anyhow::Result<()> {
send_packet(
&mut self.conn,
&ipc::data_encode(&PacketServer::WvrDisplayWindowListResponse(serial, list)),
)
};
let Some(display) = params
.state
.displays
.get(&display::DisplayHandle::from_packet(display_handle.clone()))
else {
return send(None);
};
send(Some(packet_server::WvrWindowList {
list: display
.displayed_windows
.iter()
.filter_map(|disp_win| {
params
.state
.wm
.borrow_mut()
.windows
.get(&disp_win.window_handle)
.map(|win| packet_server::WvrWindow {
handle: window::WindowHandle::as_packet(&disp_win.window_handle),
process_handle: process::ProcessHandle::as_packet(
&disp_win.process_handle,
),
pos_x: win.pos_x,
pos_y: win.pos_y,
size_x: win.size_x,
size_y: win.size_y,
visible: win.visible,
display_handle: display_handle.clone(),
})
})
.collect::<Vec<_>>(),
}))
}
fn handle_wvr_window_set_visible(
&mut self,
params: &mut TickParams,
handle: packet_server::WvrWindowHandle,
visible: bool,
) -> anyhow::Result<()> {
let mut to_resize = None;
if let Some(window) = params
.state
.wm
.borrow_mut()
.windows
.get_mut(&window::WindowHandle::from_packet(handle))
{
window.visible = visible;
to_resize = Some(window.display_handle);
}
if let Some(to_resize) = to_resize {
if let Some(display) = params.state.displays.get_mut(&to_resize) {
display.reposition_windows();
display.trigger_rerender();
}
}
Ok(())
}
fn handle_wvr_process_launch( fn handle_wvr_process_launch(
&mut self, &mut self,
params: &mut TickParams, params: &mut TickParams,
@@ -250,6 +341,7 @@ impl Connection {
&packet_params.exec, &packet_params.exec,
&args_vec, &args_vec,
&env_vec, &env_vec,
packet_params.userdata,
); );
let res = res.map(|r| r.as_packet()).map_err(|e| e.to_string()); let res = res.map(|r| r.as_packet()).map_err(|e| e.to_string());
@@ -262,7 +354,7 @@ impl Connection {
Ok(()) Ok(())
} }
fn handle_wvr_process_get( fn handle_wvr_display_get(
&mut self, &mut self,
params: &TickParams, params: &TickParams,
serial: ipc::Serial, serial: ipc::Serial,
@@ -332,6 +424,27 @@ impl Connection {
Ok(()) Ok(())
} }
fn handle_wvr_process_get(
&mut self,
params: &TickParams,
serial: ipc::Serial,
process_handle: packet_server::WvrProcessHandle,
) -> anyhow::Result<()> {
let native_handle = &process::ProcessHandle::from_packet(process_handle.clone());
let process = params
.state
.processes
.get(native_handle)
.map(|process| process.to_packet(*native_handle));
send_packet(
&mut self.conn,
&ipc::data_encode(&PacketServer::WvrProcessGetResponse(serial, process)),
)?;
Ok(())
}
fn handle_wlx_haptics( fn handle_wlx_haptics(
&mut self, &mut self,
params: &mut TickParams, params: &mut TickParams,
@@ -362,7 +475,7 @@ impl Connection {
self.handle_wvr_display_list(params, serial)?; self.handle_wvr_display_list(params, serial)?;
} }
PacketClient::WvrDisplayGet(serial, display_handle) => { PacketClient::WvrDisplayGet(serial, display_handle) => {
self.handle_wvr_process_get(params, serial, display_handle)?; self.handle_wvr_display_get(params, serial, display_handle)?;
} }
PacketClient::WvrDisplayRemove(serial, display_handle) => { PacketClient::WvrDisplayRemove(serial, display_handle) => {
self.handle_wvr_display_remove(params, serial, display_handle)?; self.handle_wvr_display_remove(params, serial, display_handle)?;
@@ -370,6 +483,18 @@ impl Connection {
PacketClient::WvrDisplaySetVisible(display_handle, visible) => { PacketClient::WvrDisplaySetVisible(display_handle, visible) => {
self.handle_wvr_display_set_visible(params, display_handle, visible)?; self.handle_wvr_display_set_visible(params, display_handle, visible)?;
} }
PacketClient::WvrDisplaySetWindowLayout(display_handle, layout) => {
self.handle_wvr_display_set_window_layout(params, display_handle, layout)?;
}
PacketClient::WvrDisplayWindowList(serial, display_handle) => {
self.handle_wvr_display_window_list(params, serial, display_handle)?;
}
PacketClient::WvrWindowSetVisible(window_handle, visible) => {
self.handle_wvr_window_set_visible(params, window_handle, visible)?;
}
PacketClient::WvrProcessGet(serial, process_handle) => {
self.handle_wvr_process_get(params, serial, process_handle)?;
}
PacketClient::WvrProcessList(serial) => { PacketClient::WvrProcessList(serial) => {
self.handle_wvr_process_list(params, serial)?; self.handle_wvr_process_list(params, serial)?;
} }
@@ -507,4 +632,11 @@ impl WayVRServer {
self.tick_connections(params); self.tick_connections(params);
Ok(()) Ok(())
} }
pub fn broadcast(&mut self, packet: packet_server::PacketServer) -> anyhow::Result<()> {
for connection in &mut self.connections {
send_packet(&mut connection.conn, &ipc::data_encode(&packet))?;
}
Ok(())
}
} }

View File

@@ -1,24 +1,31 @@
use smithay::wayland::shell::xdg::ToplevelSurface; use smithay::wayland::shell::xdg::ToplevelSurface;
use wayvr_ipc::packet_server;
use crate::gen_id; use crate::gen_id;
use super::display;
#[derive(Debug)] #[derive(Debug)]
pub struct Window { pub struct Window {
pub pos_x: i32, pub pos_x: i32,
pub pos_y: i32, pub pos_y: i32,
pub size_x: u32, pub size_x: u32,
pub size_y: u32, pub size_y: u32,
pub visible: bool,
pub toplevel: ToplevelSurface, pub toplevel: ToplevelSurface,
pub display_handle: display::DisplayHandle,
} }
impl Window { impl Window {
pub fn new(toplevel: &ToplevelSurface) -> Self { pub fn new(display_handle: display::DisplayHandle, toplevel: &ToplevelSurface) -> Self {
Self { Self {
pos_x: 0, pos_x: 0,
pos_y: 0, pos_y: 0,
size_x: 0, size_x: 0,
size_y: 0, size_y: 0,
visible: true,
toplevel: toplevel.clone(), toplevel: toplevel.clone(),
display_handle,
} }
} }
@@ -63,9 +70,29 @@ impl WindowManager {
None None
} }
pub fn create_window(&mut self, toplevel: &ToplevelSurface) -> WindowHandle { pub fn create_window(
self.windows.add(Window::new(toplevel)) &mut self,
display_handle: display::DisplayHandle,
toplevel: &ToplevelSurface,
) -> WindowHandle {
self.windows.add(Window::new(display_handle, toplevel))
} }
} }
gen_id!(WindowVec, Window, WindowCell, WindowHandle); gen_id!(WindowVec, Window, WindowCell, WindowHandle);
impl WindowHandle {
pub fn from_packet(handle: packet_server::WvrWindowHandle) -> Self {
Self {
generation: handle.generation,
idx: handle.idx,
}
}
pub fn as_packet(&self) -> packet_server::WvrWindowHandle {
packet_server::WvrWindowHandle {
idx: self.idx,
generation: self.generation,
}
}
}

View File

@@ -1,6 +1,7 @@
use glam::{vec3a, Affine2, Vec3, Vec3A}; use glam::{vec3a, Affine2, Vec3, Vec3A};
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
use vulkano::image::SubresourceLayout; use vulkano::image::SubresourceLayout;
use wayvr_ipc::packet_server;
use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
use crate::{ use crate::{
@@ -309,12 +310,17 @@ where
None => vec![], None => vec![],
}; };
let mut userdata = HashMap::new();
userdata.insert(String::from("type"), String::from("dashboard"));
// Start dashboard specified in the WayVR config // Start dashboard specified in the WayVR config
let _process_handle_unused = let _process_handle_unused = wayvr.data.state.spawn_process(
wayvr disp_handle,
.data &conf_dash.exec,
.state &args_vec,
.spawn_process(disp_handle, &conf_dash.exec, &args_vec, &env_vec)?; &env_vec,
userdata,
)?;
wayvr.dashboard_executed = true; wayvr.dashboard_executed = true;
@@ -434,6 +440,15 @@ where
)); ));
} }
} }
wayvr::WayVRSignal::DisplayWindowLayout(display_handle, layout) => {
wayvr.data.state.set_display_layout(display_handle, layout);
}
wayvr::WayVRSignal::BroadcastStateChanged(packet) => {
wayvr
.data
.ipc_server
.broadcast(packet_server::PacketServer::WvrStateChanged(packet))?;
}
} }
} }
@@ -734,10 +749,13 @@ where
wayvr.data.terminate_process(process_handle); wayvr.data.terminate_process(process_handle);
} else { } else {
// Spawn process // Spawn process
wayvr wayvr.data.state.spawn_process(
.data disp_handle,
.state &app_entry.exec,
.spawn_process(disp_handle, &app_entry.exec, &args_vec, &env_vec)?; &args_vec,
&env_vec,
Default::default(),
)?;
show_display::<O>(&mut wayvr, overlays, app_entry.target_display.as_str()); show_display::<O>(&mut wayvr, overlays, app_entry.target_display.as_str());
} }