Files
wayvr/wlx-overlay-s/src/overlays/screen/pw.rs
Aleksander b9e5541971 📦📎-fixes, typo fixes
2025-09-20 12:17:17 +02:00

135 lines
3.9 KiB
Rust

use std::{error::Error, path::PathBuf, task, time::Instant};
use serde::{Deserialize, Serialize};
use wlx_capture::{
WlxCapture,
pipewire::{PipewireCapture, PipewireSelectScreenResult},
wayland::WlxOutput,
};
use crate::{
config::{PwTokenMap, def_pw_tokens},
config_io,
state::AppState,
};
use super::{
backend::ScreenBackend,
capture::{MainThreadWlxCapture, new_wlx_capture},
};
#[cfg(feature = "wayland")]
impl ScreenBackend {
pub fn new_pw(
output: &WlxOutput,
token: Option<&str>,
app: &AppState,
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
let name = output.name.clone();
let embed_mouse = !app.session.config.double_cursor_fix;
let select_screen_result = select_pw_screen(
&format!(
"Now select: {} {} {} @ {},{}",
&output.name,
&output.make,
&output.model,
&output.logical_pos.0,
&output.logical_pos.1
),
token,
embed_mouse,
true,
true,
false,
)?;
let node_id = select_screen_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element
let capture = new_wlx_capture!(
app.gfx_extras.queue_capture,
PipewireCapture::new(name, node_id)
);
Ok((
Self::new_raw(output.name.clone(), capture),
select_screen_result.restore_token,
))
}
}
#[allow(clippy::fn_params_excessive_bools)]
pub(super) fn select_pw_screen(
instructions: &str,
token: Option<&str>,
embed_mouse: bool,
screens_only: bool,
persist: bool,
multiple: bool,
) -> Result<PipewireSelectScreenResult, wlx_capture::pipewire::AshpdError> {
use crate::subsystem::notifications::DbusNotificationSender;
use std::time::Duration;
use wlx_capture::pipewire::pipewire_select_screen;
let future = async move {
let print_at = Instant::now() + Duration::from_millis(250);
let mut notify = None;
let f = pipewire_select_screen(token, embed_mouse, screens_only, persist, multiple);
futures::pin_mut!(f);
loop {
match futures::poll!(&mut f) {
task::Poll::Ready(result) => return result,
task::Poll::Pending => {
if Instant::now() >= print_at {
log::info!("{instructions}");
if let Ok(sender) = DbusNotificationSender::new()
&& let Ok(id) = sender.notify_send(instructions, "", 2, 0, 0, true)
{
notify = Some((sender, id));
}
break;
}
futures::future::lazy(|_| {
std::thread::sleep(Duration::from_millis(10));
})
.await;
}
}
}
let result = f.await;
if let Some((sender, id)) = notify {
let _ = sender.notify_close(id);
}
result
};
futures::executor::block_on(future)
}
#[derive(Deserialize, Serialize, Default)]
pub struct TokenConf {
#[serde(default = "def_pw_tokens")]
pub pw_tokens: PwTokenMap,
}
fn get_pw_token_path() -> PathBuf {
let mut path = config_io::ConfigRoot::Generic.get_conf_d_path();
path.push("pw_tokens.yaml");
path
}
pub fn save_pw_token_config(tokens: PwTokenMap) -> Result<(), Box<dyn Error>> {
let conf = TokenConf { pw_tokens: tokens };
let yaml = serde_yaml::to_string(&conf)?;
std::fs::write(get_pw_token_path(), yaml)?;
Ok(())
}
pub fn load_pw_token_config() -> Result<PwTokenMap, Box<dyn Error>> {
let yaml = std::fs::read_to_string(get_pw_token_path())?;
let conf: TokenConf = serde_yaml::from_str(yaml.as_str())?;
Ok(conf.pw_tokens)
}