179 lines
6.0 KiB
Rust
179 lines
6.0 KiB
Rust
use std::{
|
|
any::Any,
|
|
env,
|
|
error::Error,
|
|
sync::{
|
|
Arc,
|
|
mpsc::{self},
|
|
},
|
|
};
|
|
|
|
use rxscreen::monitor::Monitor;
|
|
|
|
use crate::{
|
|
WlxCapture,
|
|
frame::{DRM_FORMAT_XRGB8888, DrmFormat, FrameFormat, MemPtrFrame, MouseMeta, WlxFrame},
|
|
};
|
|
|
|
pub struct XshmScreen {
|
|
pub name: Arc<str>,
|
|
pub monitor: Monitor,
|
|
}
|
|
|
|
pub struct XshmCapture<U, R>
|
|
where
|
|
U: Any + Send,
|
|
R: Any + Send,
|
|
{
|
|
pub screen: Arc<XshmScreen>,
|
|
sender: Option<mpsc::SyncSender<()>>,
|
|
receiver: Option<mpsc::Receiver<R>>,
|
|
_dummy: Option<Box<U>>,
|
|
}
|
|
|
|
impl<U, R> XshmCapture<U, R>
|
|
where
|
|
U: Any + Send,
|
|
R: Any + Send,
|
|
{
|
|
pub fn new(screen: Arc<XshmScreen>) -> Self {
|
|
Self {
|
|
screen,
|
|
sender: None,
|
|
receiver: None,
|
|
_dummy: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn xshm_get_monitors() -> Result<Vec<Arc<XshmScreen>>, Box<dyn Error>> {
|
|
let display = env::var("DISPLAY").inspect_err(|e| log::info!("DISPLAY: {e:?}"))?;
|
|
let Ok(d) = rxscreen::Display::new(display) else {
|
|
return Err("X11: Failed to open display".into());
|
|
};
|
|
Ok(d.monitors()
|
|
.into_iter()
|
|
.enumerate()
|
|
.map(|x| {
|
|
Arc::new(XshmScreen {
|
|
name: x.1.name().replace("DisplayPort", "DP").into(),
|
|
monitor: x.1,
|
|
})
|
|
})
|
|
.collect())
|
|
}
|
|
|
|
impl<U, R> WlxCapture<U, R> for XshmCapture<U, R>
|
|
where
|
|
U: Any + Send,
|
|
R: Any + Send,
|
|
{
|
|
fn init(
|
|
&mut self,
|
|
_: &[DrmFormat],
|
|
user_data: U,
|
|
receive_callback: fn(&U, WlxFrame) -> Option<R>,
|
|
) {
|
|
let (tx_frame, rx_frame) = std::sync::mpsc::sync_channel(4);
|
|
let (tx_cmd, rx_cmd) = std::sync::mpsc::sync_channel(2);
|
|
self.sender = Some(tx_cmd);
|
|
self.receiver = Some(rx_frame);
|
|
|
|
std::thread::spawn({
|
|
let monitor = self.screen.monitor.clone();
|
|
move || {
|
|
let display = env::var("DISPLAY").expect("DISPLAY not set");
|
|
let Ok(d) = rxscreen::Display::new(display) else {
|
|
log::error!("{}: failed to open display", monitor.name());
|
|
return;
|
|
};
|
|
let Ok(shm) = d.shm().monitor(&monitor).build() else {
|
|
log::error!("{}: failed to create shm", monitor.name());
|
|
return;
|
|
};
|
|
|
|
loop {
|
|
match rx_cmd.recv() {
|
|
Ok(_) => {
|
|
if let Ok(image) = shm.capture() {
|
|
let size = unsafe { image.as_bytes().len() };
|
|
let memptr_frame = MemPtrFrame {
|
|
format: FrameFormat {
|
|
width: image.width() as _,
|
|
height: image.height() as _,
|
|
fourcc: DRM_FORMAT_XRGB8888.into(),
|
|
..Default::default()
|
|
},
|
|
ptr: unsafe { image.as_ptr() as _ },
|
|
size,
|
|
mouse: d.root_mouse_position().and_then(|root_pos| {
|
|
monitor.mouse_to_local(root_pos).map(|(x, y)| MouseMeta {
|
|
x: (x as f32) / (image.width() as f32),
|
|
y: (y as f32) / (image.height() as f32),
|
|
})
|
|
}),
|
|
};
|
|
log::trace!("{}: captured frame", &monitor.name());
|
|
|
|
let frame = WlxFrame::MemPtr(memptr_frame);
|
|
if let Some(r) = receive_callback(&user_data, frame) {
|
|
match tx_frame.try_send(r) {
|
|
Ok(_) => (),
|
|
Err(mpsc::TrySendError::Full(_)) => {
|
|
log::debug!("{}: channel full", &monitor.name());
|
|
}
|
|
Err(mpsc::TrySendError::Disconnected(_)) => {
|
|
log::warn!(
|
|
"{}: capture thread channel closed (send)",
|
|
&monitor.name(),
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
log::debug!("{}: XShmGetImage failed", &monitor.name());
|
|
}
|
|
}
|
|
Err(_) => {
|
|
log::warn!("{}: capture thread channel closed (recv)", monitor.name());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
log::warn!("{}: capture thread stopped", monitor.name());
|
|
}
|
|
});
|
|
}
|
|
fn is_ready(&self) -> bool {
|
|
self.receiver.is_some()
|
|
}
|
|
fn supports_dmbuf(&self) -> bool {
|
|
false
|
|
}
|
|
fn receive(&mut self) -> Option<R> {
|
|
if let Some(rx) = self.receiver.as_ref() {
|
|
return rx.try_iter().last();
|
|
}
|
|
None
|
|
}
|
|
fn pause(&mut self) {}
|
|
fn resume(&mut self) {
|
|
if let Some(rx) = self.receiver.as_ref() {
|
|
log::debug!(
|
|
"{}: dropped {} old frames before resuming",
|
|
&self.screen.name,
|
|
rx.try_iter().count()
|
|
);
|
|
}
|
|
self.request_new_frame();
|
|
}
|
|
fn request_new_frame(&mut self) {
|
|
if let Some(sender) = &self.sender
|
|
&& let Err(e) = sender.send(())
|
|
{
|
|
log::debug!("Failed to send frame request: {}", e);
|
|
}
|
|
}
|
|
}
|