Make WayVR IPC independent of the built-in Wayland server
- Rename state -> wayland_state - Move WayVR IPC server outside "wayvr" (wayland server) feature - WayVR IPC server is now available without "wayvr" (wayland server) feature - Remove run_compositor_at_start (run wayland server instantly)
This commit is contained in:
@@ -303,11 +303,10 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
let _ = sender.send_params(&overlays, &app.input_state.devices);
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
if let Err(e) =
|
||||
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut app, &mut overlays)
|
||||
crate::ipc::events::tick_events::<OpenVrOverlayData>(&mut app, &mut overlays)
|
||||
{
|
||||
log::error!("WayVR tick_events failed: {e:?}");
|
||||
log::error!("WayVR IPC tick_events failed: {e:?}");
|
||||
}
|
||||
|
||||
log::trace!("Rendering frame");
|
||||
@@ -336,9 +335,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
.for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &app.gfx));
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
if let Some(wayvr) = &app.wayvr {
|
||||
wayvr.borrow_mut().data.tick_finish()?;
|
||||
}
|
||||
app.wayvr.borrow_mut().data.tick_finish()?;
|
||||
|
||||
// chaperone
|
||||
} // main_loop
|
||||
|
||||
@@ -373,9 +373,9 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
if let Err(e) =
|
||||
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app, &mut overlays)
|
||||
crate::ipc::events::tick_events::<OpenXrOverlayData>(&mut app, &mut overlays)
|
||||
{
|
||||
log::error!("WayVR tick_events failed: {e:?}");
|
||||
log::error!("WayVR IPC tick_events failed: {e:?}");
|
||||
}
|
||||
|
||||
// Begin rendering
|
||||
@@ -459,9 +459,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
||||
// End layer composition
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
if let Some(wayvr) = &app.wayvr {
|
||||
wayvr.borrow_mut().data.tick_finish()?;
|
||||
}
|
||||
app.wayvr.borrow_mut().data.tick_finish()?;
|
||||
|
||||
// Begin layer submit
|
||||
layers.sort_by(|a, b| b.0.total_cmp(&a.0));
|
||||
|
||||
@@ -37,8 +37,9 @@ use wayland_server::Client;
|
||||
use wayland_server::backend::{ClientData, ClientId, DisconnectReason};
|
||||
use wayland_server::protocol::wl_surface::WlSurface;
|
||||
|
||||
use crate::ipc::event_queue::SyncEventQueue;
|
||||
|
||||
use super::WayVRTask;
|
||||
use super::event_queue::SyncEventQueue;
|
||||
|
||||
pub struct Application {
|
||||
pub gles_renderer: GlesRenderer,
|
||||
|
||||
@@ -17,12 +17,13 @@ use smithay::{
|
||||
use wayvr_ipc::packet_server;
|
||||
|
||||
use crate::{
|
||||
backend::wayvr::time::get_millis, gen_id, subsystem::hid::WheelDelta, windowing::OverlayID,
|
||||
backend::wayvr::time::get_millis, gen_id, ipc::event_queue::SyncEventQueue,
|
||||
subsystem::hid::WheelDelta, windowing::OverlayID,
|
||||
};
|
||||
|
||||
use super::{
|
||||
BlitMethod, WayVRSignal, client::WayVRCompositor, comp::send_frames_surface_tree, egl_data,
|
||||
event_queue::SyncEventQueue, process, smithay_wrapper, time, window,
|
||||
process, smithay_wrapper, time, window,
|
||||
};
|
||||
|
||||
fn generate_auth_key() -> String {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Data<DataType> {
|
||||
queue: VecDeque<DataType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SyncEventQueue<DataType> {
|
||||
data: Rc<RefCell<Data<DataType>>>,
|
||||
}
|
||||
|
||||
impl<DataType> SyncEventQueue<DataType> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Rc::new(RefCell::new(Data {
|
||||
queue: VecDeque::default(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, message: DataType) {
|
||||
let mut data = self.data.borrow_mut();
|
||||
data.queue.push_back(message);
|
||||
}
|
||||
|
||||
pub fn read(&self) -> Option<DataType> {
|
||||
let mut data = self.data.borrow_mut();
|
||||
data.queue.pop_front()
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,16 @@ mod comp;
|
||||
pub mod display;
|
||||
pub mod egl_data;
|
||||
mod egl_ex;
|
||||
pub mod event_queue;
|
||||
mod handle;
|
||||
mod process;
|
||||
pub mod server_ipc;
|
||||
pub mod process;
|
||||
mod smithay_wrapper;
|
||||
mod time;
|
||||
mod window;
|
||||
pub mod window;
|
||||
use anyhow::Context;
|
||||
use comp::Application;
|
||||
use display::{Display, DisplayInitParams, DisplayVec};
|
||||
use event_queue::SyncEventQueue;
|
||||
use process::ProcessVec;
|
||||
use serde::Deserialize;
|
||||
use server_ipc::WayVRServer;
|
||||
use smallvec::SmallVec;
|
||||
use smithay::{
|
||||
backend::{
|
||||
@@ -48,6 +44,7 @@ use wayvr_ipc::{
|
||||
use xkbcommon::xkb;
|
||||
|
||||
use crate::{
|
||||
ipc::{event_queue::SyncEventQueue, ipc_server, signal::WayVRSignal},
|
||||
state::AppState,
|
||||
subsystem::hid::{MODS_TO_KEYS, WheelDelta},
|
||||
};
|
||||
@@ -87,19 +84,6 @@ pub enum WayVRTask {
|
||||
ProcessTerminationRequest(process::ProcessHandle),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum WayVRSignal {
|
||||
DisplayVisibility(display::DisplayHandle, bool),
|
||||
DisplayWindowLayout(
|
||||
display::DisplayHandle,
|
||||
packet_server::WvrDisplayWindowLayout,
|
||||
),
|
||||
BroadcastStateChanged(packet_server::WvrStateChanged),
|
||||
DropOverlay(crate::windowing::OverlayID),
|
||||
Haptics(super::input::Haptics),
|
||||
CustomTask(crate::backend::task::ModifyPanelTask),
|
||||
}
|
||||
|
||||
pub enum BlitMethod {
|
||||
Dmabuf,
|
||||
Software,
|
||||
@@ -127,20 +111,19 @@ pub struct WayVRState {
|
||||
time_start: u64,
|
||||
pub displays: display::DisplayVec,
|
||||
pub manager: client::WayVRCompositor,
|
||||
wm: Rc<RefCell<window::WindowManager>>,
|
||||
pub wm: Rc<RefCell<window::WindowManager>>,
|
||||
egl_data: Rc<egl_data::EGLData>,
|
||||
pub processes: process::ProcessVec,
|
||||
pub config: Config,
|
||||
dashboard_display: Option<display::DisplayHandle>,
|
||||
pub tasks: SyncEventQueue<WayVRTask>,
|
||||
pub signals: SyncEventQueue<WayVRSignal>,
|
||||
ticks: u64,
|
||||
cur_modifiers: u8,
|
||||
signals: SyncEventQueue<WayVRSignal>,
|
||||
}
|
||||
|
||||
pub struct WayVR {
|
||||
pub state: WayVRState,
|
||||
pub ipc_server: WayVRServer,
|
||||
}
|
||||
|
||||
pub enum MouseIndex {
|
||||
@@ -159,7 +142,7 @@ pub enum TickTask {
|
||||
|
||||
impl WayVR {
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
pub fn new(config: Config) -> anyhow::Result<Self> {
|
||||
pub fn new(config: Config, signals: SyncEventQueue<WayVRSignal>) -> anyhow::Result<Self> {
|
||||
log::info!("Initializing WayVR");
|
||||
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
||||
let dh = display.handle();
|
||||
@@ -264,8 +247,6 @@ impl WayVR {
|
||||
|
||||
let time_start = get_millis();
|
||||
|
||||
let ipc_server = WayVRServer::new()?;
|
||||
|
||||
let state = WayVRState {
|
||||
time_start,
|
||||
manager: client::WayVRCompositor::new(state, display, seat_keyboard, seat_pointer)?,
|
||||
@@ -277,11 +258,11 @@ impl WayVR {
|
||||
dashboard_display: None,
|
||||
ticks: 0,
|
||||
tasks,
|
||||
signals: SyncEventQueue::new(),
|
||||
cur_modifiers: 0,
|
||||
signals,
|
||||
};
|
||||
|
||||
Ok(Self { state, ipc_server })
|
||||
Ok(Self { state })
|
||||
}
|
||||
|
||||
pub fn render_display(&mut self, display: display::DisplayHandle) -> anyhow::Result<bool> {
|
||||
@@ -312,13 +293,14 @@ impl WayVR {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
pub fn tick_events(&mut self, app: &AppState) -> anyhow::Result<Vec<TickTask>> {
|
||||
pub fn tick_events(&mut self, app: &mut AppState) -> anyhow::Result<Vec<TickTask>> {
|
||||
let mut tasks: Vec<TickTask> = Vec::new();
|
||||
|
||||
self.ipc_server.tick(&mut server_ipc::TickParams {
|
||||
state: &mut self.state,
|
||||
app.ipc_server.tick(&mut ipc_server::TickParams {
|
||||
wayland_state: &mut self.state,
|
||||
input_state: &app.input_state,
|
||||
tasks: &mut tasks,
|
||||
app,
|
||||
signals: &app.wayvr_signals,
|
||||
});
|
||||
|
||||
// Check for redraw events
|
||||
@@ -357,11 +339,11 @@ impl WayVR {
|
||||
}
|
||||
|
||||
for (handle, display) in self.state.displays.iter_mut() {
|
||||
display.tick(&self.state.config, &handle, &mut self.state.signals);
|
||||
display.tick(&self.state.config, &handle, &mut app.wayvr_signals);
|
||||
}
|
||||
|
||||
if !to_remove.is_empty() {
|
||||
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
|
||||
app.wayvr_signals.send(WayVRSignal::BroadcastStateChanged(
|
||||
packet_server::WvrStateChanged::ProcessRemoved,
|
||||
));
|
||||
}
|
||||
@@ -402,7 +384,7 @@ impl WayVR {
|
||||
};
|
||||
|
||||
display.add_window(window_handle, process_handle, &toplevel);
|
||||
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
|
||||
app.wayvr_signals.send(WayVRSignal::BroadcastStateChanged(
|
||||
packet_server::WvrStateChanged::WindowCreated,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1,697 +0,0 @@
|
||||
use crate::state::AppState;
|
||||
|
||||
use super::{TickTask, WayVRSignal, display, process, window};
|
||||
use bytes::BufMut;
|
||||
use glam::Vec3A;
|
||||
use interprocess::local_socket::{self, ToNsName, traits::Listener};
|
||||
use smallvec::SmallVec;
|
||||
use std::io::{Read, Write};
|
||||
use wayvr_ipc::{
|
||||
ipc::{self},
|
||||
packet_client::{self, PacketClient},
|
||||
packet_server::{self, PacketServer, WlxInputStatePointer},
|
||||
};
|
||||
|
||||
pub struct AuthInfo {
|
||||
pub client_name: String,
|
||||
pub protocol_version: u32, // client protocol version
|
||||
}
|
||||
|
||||
pub struct Connection {
|
||||
alive: bool,
|
||||
conn: local_socket::Stream,
|
||||
next_packet: Option<u32>,
|
||||
auth: Option<AuthInfo>,
|
||||
}
|
||||
|
||||
pub fn send_packet(conn: &mut local_socket::Stream, data: &[u8]) -> anyhow::Result<()> {
|
||||
let mut bytes = bytes::BytesMut::new();
|
||||
|
||||
// packet size
|
||||
bytes.put_u32(data.len() as u32);
|
||||
|
||||
// packet data
|
||||
bytes.put_slice(data);
|
||||
|
||||
conn.write_all(&bytes)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_check(expected_size: u32, res: std::io::Result<usize>) -> bool {
|
||||
match res {
|
||||
Ok(count) => {
|
||||
if count == 0 {
|
||||
return false;
|
||||
}
|
||||
if count as u32 == expected_size {
|
||||
true // read succeeded
|
||||
} else {
|
||||
log::error!("count {count} is not {expected_size}");
|
||||
false
|
||||
}
|
||||
}
|
||||
Err(_e) => {
|
||||
//log::error!("failed to get packet size: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Payload = SmallVec<[u8; 64]>;
|
||||
|
||||
fn read_payload(conn: &mut local_socket::Stream, size: u32) -> Option<Payload> {
|
||||
let mut payload = Payload::new();
|
||||
payload.resize(size as usize, 0);
|
||||
if read_check(size, conn.read(&mut payload)) {
|
||||
Some(payload)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TickParams<'a> {
|
||||
pub state: &'a mut super::WayVRState,
|
||||
pub tasks: &'a mut Vec<TickTask>,
|
||||
pub app: &'a AppState,
|
||||
}
|
||||
|
||||
pub fn gen_args_vec(input: &str) -> Vec<&str> {
|
||||
input.split_whitespace().collect()
|
||||
}
|
||||
|
||||
pub fn gen_env_vec(input: &[String]) -> Vec<(&str, &str)> {
|
||||
input
|
||||
.iter()
|
||||
.filter_map(|e| e.as_str().split_once('='))
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
const fn new(conn: local_socket::Stream) -> Self {
|
||||
Self {
|
||||
conn,
|
||||
alive: true,
|
||||
auth: None,
|
||||
next_packet: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn kill(&mut self, reason: &str) {
|
||||
let _dont_care = send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::Disconnect(packet_server::Disconnect {
|
||||
reason: String::from(reason),
|
||||
})),
|
||||
);
|
||||
self.alive = false;
|
||||
}
|
||||
|
||||
fn process_handshake(&mut self, handshake: &packet_client::Handshake) -> anyhow::Result<()> {
|
||||
if self.auth.is_some() {
|
||||
anyhow::bail!("You were already authenticated");
|
||||
}
|
||||
|
||||
if handshake.protocol_version != ipc::PROTOCOL_VERSION {
|
||||
anyhow::bail!(
|
||||
"Unsupported protocol version {}",
|
||||
handshake.protocol_version
|
||||
);
|
||||
}
|
||||
|
||||
if handshake.magic != ipc::CONNECTION_MAGIC {
|
||||
anyhow::bail!("Invalid magic");
|
||||
}
|
||||
|
||||
match handshake.client_name.len() {
|
||||
0 => anyhow::bail!("Client name is empty"),
|
||||
1..32 => {}
|
||||
_ => anyhow::bail!("Client name is too long"),
|
||||
}
|
||||
|
||||
log::info!("IPC: Client \"{}\" connected.", handshake.client_name);
|
||||
|
||||
self.auth = Some(AuthInfo {
|
||||
client_name: handshake.client_name.clone(),
|
||||
protocol_version: handshake.protocol_version,
|
||||
});
|
||||
|
||||
// Send auth response
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::HandshakeSuccess(
|
||||
packet_server::HandshakeSuccess {
|
||||
runtime: String::from("wlx-overlay-s"),
|
||||
},
|
||||
)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_display_list(
|
||||
&mut self,
|
||||
params: &TickParams,
|
||||
serial: ipc::Serial,
|
||||
) -> anyhow::Result<()> {
|
||||
let list: Vec<packet_server::WvrDisplay> = params
|
||||
.state
|
||||
.displays
|
||||
.vec
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, opt_cell)| {
|
||||
let Some(cell) = opt_cell else {
|
||||
return None;
|
||||
};
|
||||
let display = &cell.obj;
|
||||
Some(display.as_packet(display::DisplayHandle::new(idx as u32, cell.generation)))
|
||||
})
|
||||
.collect();
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrDisplayListResponse(
|
||||
serial,
|
||||
packet_server::WvrDisplayList { list },
|
||||
)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wlx_input_state(
|
||||
&mut self,
|
||||
params: &TickParams,
|
||||
serial: ipc::Serial,
|
||||
) -> anyhow::Result<()> {
|
||||
let input_state = ¶ms.app.input_state;
|
||||
|
||||
let to_arr = |vec: &Vec3A| -> [f32; 3] { [vec.x, vec.y, vec.z] };
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WlxInputStateResponse(
|
||||
serial,
|
||||
packet_server::WlxInputState {
|
||||
hmd_pos: to_arr(&input_state.hmd.translation),
|
||||
left: WlxInputStatePointer {
|
||||
pos: to_arr(&input_state.pointers[0].raw_pose.translation),
|
||||
},
|
||||
right: WlxInputStatePointer {
|
||||
pos: to_arr(&input_state.pointers[0].raw_pose.translation),
|
||||
},
|
||||
},
|
||||
)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_display_create(
|
||||
&mut self,
|
||||
params: &mut TickParams,
|
||||
serial: ipc::Serial,
|
||||
packet_params: packet_client::WvrDisplayCreateParams,
|
||||
) -> anyhow::Result<()> {
|
||||
let display_handle = params.state.create_display(
|
||||
packet_params.width,
|
||||
packet_params.height,
|
||||
&packet_params.name,
|
||||
false,
|
||||
)?;
|
||||
|
||||
params
|
||||
.tasks
|
||||
.push(TickTask::NewDisplay(packet_params, Some(display_handle)));
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrDisplayCreateResponse(
|
||||
serial,
|
||||
display_handle.as_packet(),
|
||||
)),
|
||||
)?;
|
||||
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_display_set_visible(
|
||||
params: &mut TickParams,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
visible: bool,
|
||||
) {
|
||||
params.state.signals.send(WayVRSignal::DisplayVisibility(
|
||||
display::DisplayHandle::from_packet(handle),
|
||||
visible,
|
||||
));
|
||||
}
|
||||
|
||||
fn handle_wvr_display_set_window_layout(
|
||||
params: &mut TickParams,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
layout: packet_server::WvrDisplayWindowLayout,
|
||||
) {
|
||||
params.state.signals.send(WayVRSignal::DisplayWindowLayout(
|
||||
display::DisplayHandle::from_packet(handle),
|
||||
layout,
|
||||
));
|
||||
}
|
||||
|
||||
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(
|
||||
params: &mut TickParams,
|
||||
handle: packet_server::WvrWindowHandle,
|
||||
visible: bool,
|
||||
) {
|
||||
let to_resize = if let Some(window) = params
|
||||
.state
|
||||
.wm
|
||||
.borrow_mut()
|
||||
.windows
|
||||
.get_mut(&window::WindowHandle::from_packet(handle))
|
||||
{
|
||||
window.visible = visible;
|
||||
Some(window.display_handle)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(to_resize) = to_resize
|
||||
&& let Some(display) = params.state.displays.get_mut(&to_resize)
|
||||
{
|
||||
display.reposition_windows();
|
||||
display.trigger_rerender();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_wvr_process_launch(
|
||||
&mut self,
|
||||
params: &mut TickParams,
|
||||
serial: ipc::Serial,
|
||||
packet_params: packet_client::WvrProcessLaunchParams,
|
||||
) -> anyhow::Result<()> {
|
||||
let args_vec = gen_args_vec(&packet_params.args);
|
||||
let env_vec = gen_env_vec(&packet_params.env);
|
||||
|
||||
let res = params.state.spawn_process(
|
||||
super::display::DisplayHandle::from_packet(packet_params.target_display),
|
||||
&packet_params.exec,
|
||||
&args_vec,
|
||||
&env_vec,
|
||||
None,
|
||||
packet_params.userdata,
|
||||
);
|
||||
|
||||
let res = res.map(|r| r.as_packet()).map_err(|e| e.to_string());
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrProcessLaunchResponse(serial, res)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_display_get(
|
||||
&mut self,
|
||||
params: &TickParams,
|
||||
serial: ipc::Serial,
|
||||
display_handle: packet_server::WvrDisplayHandle,
|
||||
) -> anyhow::Result<()> {
|
||||
let native_handle = &display::DisplayHandle::from_packet(display_handle);
|
||||
let disp = params
|
||||
.state
|
||||
.displays
|
||||
.get(native_handle)
|
||||
.map(|disp| disp.as_packet(*native_handle));
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrDisplayGetResponse(serial, disp)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_wvr_process_list(
|
||||
&mut self,
|
||||
params: &TickParams,
|
||||
serial: ipc::Serial,
|
||||
) -> anyhow::Result<()> {
|
||||
let list: Vec<packet_server::WvrProcess> = params
|
||||
.state
|
||||
.processes
|
||||
.vec
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, opt_cell)| {
|
||||
let Some(cell) = opt_cell else {
|
||||
return None;
|
||||
};
|
||||
let process = &cell.obj;
|
||||
Some(process.to_packet(process::ProcessHandle::new(idx as u32, cell.generation)))
|
||||
})
|
||||
.collect();
|
||||
|
||||
send_packet(
|
||||
&mut self.conn,
|
||||
&ipc::data_encode(&PacketServer::WvrProcessListResponse(
|
||||
serial,
|
||||
packet_server::WvrProcessList { list },
|
||||
)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This request doesn't return anything to the client
|
||||
fn handle_wvr_process_terminate(
|
||||
params: &mut TickParams,
|
||||
process_handle: packet_server::WvrProcessHandle,
|
||||
) {
|
||||
let native_handle = &process::ProcessHandle::from_packet(process_handle);
|
||||
let process = params.state.processes.get_mut(native_handle);
|
||||
|
||||
let Some(process) = process else {
|
||||
return;
|
||||
};
|
||||
|
||||
process.terminate();
|
||||
}
|
||||
|
||||
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);
|
||||
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(
|
||||
params: &mut TickParams,
|
||||
haptics_params: packet_client::WlxHapticsParams,
|
||||
) {
|
||||
params.state.signals.send(super::WayVRSignal::Haptics(
|
||||
crate::backend::input::Haptics {
|
||||
duration: haptics_params.duration,
|
||||
frequency: haptics_params.frequency,
|
||||
intensity: haptics_params.intensity,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
fn handle_wlx_panel(
|
||||
params: &mut TickParams,
|
||||
custom_params: packet_client::WlxModifyPanelParams,
|
||||
) {
|
||||
use crate::backend::task::{ModifyPanelCommand, ModifyPanelTask};
|
||||
|
||||
params
|
||||
.state
|
||||
.signals
|
||||
.send(super::WayVRSignal::CustomTask(ModifyPanelTask {
|
||||
overlay: custom_params.overlay,
|
||||
element: custom_params.element,
|
||||
command: match custom_params.command {
|
||||
packet_client::WlxModifyPanelCommand::SetText(text) => {
|
||||
ModifyPanelCommand::SetText(text)
|
||||
}
|
||||
packet_client::WlxModifyPanelCommand::SetImage(sprite) => {
|
||||
ModifyPanelCommand::SetImage(sprite)
|
||||
}
|
||||
packet_client::WlxModifyPanelCommand::SetStickyState(sticky) => {
|
||||
ModifyPanelCommand::SetStickyState(sticky)
|
||||
}
|
||||
packet_client::WlxModifyPanelCommand::SetVisible(visible) => {
|
||||
ModifyPanelCommand::SetVisible(visible)
|
||||
}
|
||||
packet_client::WlxModifyPanelCommand::SetColor(color) => {
|
||||
ModifyPanelCommand::SetColor(color)
|
||||
}
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
fn process_payload(&mut self, params: &mut TickParams, payload: Payload) -> anyhow::Result<()> {
|
||||
let packet: PacketClient = ipc::data_decode(&payload)?;
|
||||
|
||||
if let PacketClient::Handshake(handshake) = &packet {
|
||||
self.process_handshake(handshake)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match packet {
|
||||
PacketClient::Handshake(_) => unreachable!(), // handled previously
|
||||
PacketClient::WlxInputState(serial) => {
|
||||
self.handle_wlx_input_state(params, serial)?;
|
||||
}
|
||||
PacketClient::WvrDisplayList(serial) => {
|
||||
self.handle_wvr_display_list(params, serial)?;
|
||||
}
|
||||
PacketClient::WvrDisplayGet(serial, display_handle) => {
|
||||
self.handle_wvr_display_get(params, serial, display_handle)?;
|
||||
}
|
||||
PacketClient::WvrDisplayRemove(serial, display_handle) => {
|
||||
self.handle_wvr_display_remove(params, serial, display_handle)?;
|
||||
}
|
||||
PacketClient::WvrDisplaySetVisible(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) => {
|
||||
self.handle_wvr_process_list(params, serial)?;
|
||||
}
|
||||
PacketClient::WvrProcessLaunch(serial, packet_params) => {
|
||||
self.handle_wvr_process_launch(params, serial, packet_params)?;
|
||||
}
|
||||
PacketClient::WvrDisplayCreate(serial, packet_params) => {
|
||||
self.handle_wvr_display_create(params, serial, packet_params)?;
|
||||
}
|
||||
PacketClient::WvrProcessTerminate(process_handle) => {
|
||||
Self::handle_wvr_process_terminate(params, process_handle);
|
||||
}
|
||||
PacketClient::WlxHaptics(haptics_params) => {
|
||||
Self::handle_wlx_haptics(params, haptics_params);
|
||||
}
|
||||
PacketClient::WlxModifyPanel(custom_params) => {
|
||||
Self::handle_wlx_panel(params, custom_params);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_check_payload(&mut self, params: &mut TickParams, payload: Payload) -> bool {
|
||||
log::debug!("payload size {}", payload.len());
|
||||
|
||||
if let Err(e) = self.process_payload(params, payload) {
|
||||
log::error!("Invalid payload from the client, closing connection: {e}");
|
||||
// send also error message directly to the client before disconnecting
|
||||
self.kill(format!("{e}").as_str());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn read_packet(&mut self, params: &mut TickParams) -> bool {
|
||||
if let Some(payload_size) = self.next_packet {
|
||||
let Some(payload) = read_payload(&mut self.conn, payload_size) else {
|
||||
// still failed to read payload, try in next tick
|
||||
return false;
|
||||
};
|
||||
|
||||
if !self.process_check_payload(params, payload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.next_packet = None;
|
||||
}
|
||||
|
||||
let mut buf_packet_header: [u8; 4] = [0; 4];
|
||||
if !read_check(4, self.conn.read(&mut buf_packet_header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let payload_size = u32::from_be_bytes(buf_packet_header[0..4].try_into().unwrap()); // 0-3 bytes (u32 size)
|
||||
|
||||
let size_limit: u32 = 128 * 1024;
|
||||
|
||||
if payload_size > size_limit {
|
||||
// over 128 KiB?
|
||||
log::error!(
|
||||
"Client sent a packet header with the size over {size_limit} bytes, closing connection."
|
||||
);
|
||||
self.kill("Too big packet received (over 128 KiB)");
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(payload) = read_payload(&mut self.conn, payload_size) else {
|
||||
// failed to read payload, try in next tick
|
||||
self.next_packet = Some(payload_size);
|
||||
return false;
|
||||
};
|
||||
|
||||
if !self.process_check_payload(params, payload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn tick(&mut self, params: &mut TickParams) {
|
||||
while self.read_packet(params) {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Connection {
|
||||
fn drop(&mut self) {
|
||||
log::info!("Connection closed");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WayVRServer {
|
||||
listener: local_socket::Listener,
|
||||
connections: Vec<Connection>,
|
||||
}
|
||||
|
||||
impl WayVRServer {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let printname = "/tmp/wayvr_ipc.sock";
|
||||
let name = printname.to_ns_name::<local_socket::GenericNamespaced>()?;
|
||||
let opts = local_socket::ListenerOptions::new()
|
||||
.name(name)
|
||||
.nonblocking(local_socket::ListenerNonblockingMode::Both);
|
||||
let listener = match opts.create_sync() {
|
||||
Ok(listener) => listener,
|
||||
Err(e) => anyhow::bail!("Failed to start WayVRServer IPC listener. Reason: {e}"),
|
||||
};
|
||||
|
||||
log::info!("WayVRServer IPC running at {printname}");
|
||||
|
||||
Ok(Self {
|
||||
listener,
|
||||
connections: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn accept_connections(&mut self) {
|
||||
let Ok(conn) = self.listener.accept() else {
|
||||
return; // No new connection or other error
|
||||
};
|
||||
|
||||
self.connections.push(Connection::new(conn));
|
||||
}
|
||||
|
||||
fn tick_connections(&mut self, params: &mut TickParams) {
|
||||
for c in &mut self.connections {
|
||||
c.tick(params);
|
||||
}
|
||||
|
||||
// remove killed connections
|
||||
self.connections.retain(|c| c.alive);
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, params: &mut TickParams) {
|
||||
self.accept_connections();
|
||||
self.tick_connections(params);
|
||||
}
|
||||
|
||||
pub fn broadcast(&mut self, packet: packet_server::PacketServer) {
|
||||
for connection in &mut self.connections {
|
||||
if let Err(e) = send_packet(&mut connection.conn, &ipc::data_encode(&packet)) {
|
||||
log::error!("failed to broadcast packet: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user