pinnacle/api/rust/src/output.rs

144 lines
4.2 KiB
Rust
Raw Normal View History

2023-10-20 01:18:34 +02:00
use crate::{
2023-10-20 02:26:12 +02:00
msg::{Args, CallbackId, Msg, OutputName, Request, RequestResponse},
request, send_msg,
tag::TagHandle,
CALLBACK_VEC,
2023-10-20 01:18:34 +02:00
};
/// Output management.
pub struct Output;
impl Output {
/// Get an [`OutputHandle`] by its name.
///
/// `name` is the name of the port the output is plugged in to.
/// This is something like `HDMI-1` or `eDP-0`.
pub fn get_by_name(&self, name: &str) -> Option<OutputHandle> {
let RequestResponse::Outputs { output_names } = request(Request::GetOutputs) else {
unreachable!()
};
output_names
.into_iter()
.find(|s| s == name)
.map(|s| OutputHandle(OutputName(s)))
}
/// Get a handle to all connected outputs.
pub fn get_all(&self) -> impl Iterator<Item = OutputHandle> {
let RequestResponse::Outputs { output_names } = request(Request::GetOutputs) else {
unreachable!()
};
output_names
.into_iter()
.map(|name| OutputHandle(OutputName(name)))
}
/// Get the currently focused output.
///
/// This is currently defined as the one with the cursor on it.
pub fn get_focused(&self) -> Option<OutputHandle> {
let RequestResponse::Outputs { output_names } = request(Request::GetOutputs) else {
unreachable!()
};
output_names
.into_iter()
.map(|s| OutputHandle(OutputName(s)))
.find(|op| op.properties().focused == Some(true))
}
2023-10-20 02:26:12 +02:00
pub fn connect_for_all<F>(&self, mut func: F)
where
F: FnMut(OutputHandle) + Send + 'static,
{
let args_callback = move |args: Option<Args>| {
if let Some(Args::ConnectForAllOutputs { output_name }) = args {
func(OutputHandle(OutputName(output_name)));
}
};
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
let len = callback_vec.len();
callback_vec.push(Box::new(args_callback));
let msg = Msg::ConnectForAllOutputs {
callback_id: CallbackId(len as u32),
};
send_msg(msg).unwrap();
}
2023-10-20 01:18:34 +02:00
}
/// An output handle.
///
/// This is a handle to one of your monitors.
/// It serves to make it easier to deal with them, defining methods for getting properties and
/// helpers for things like positioning multiple monitors.
2023-10-20 02:26:12 +02:00
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct OutputHandle(pub OutputName);
2023-10-20 01:18:34 +02:00
/// Properties of an output.
pub struct OutputProperties {
/// The make.
2023-10-20 02:26:12 +02:00
pub make: Option<String>,
2023-10-20 01:18:34 +02:00
/// The model.
///
/// This is something like `27GL850` or whatever gibberish monitor manufacturers name their
/// displays.
2023-10-20 02:26:12 +02:00
pub model: Option<String>,
2023-10-20 01:18:34 +02:00
/// The location of the output in the global space.
2023-10-20 02:26:12 +02:00
pub loc: Option<(i32, i32)>,
2023-10-20 01:18:34 +02:00
/// The resolution of the output in pixels, where `res.0` is the width and `res.1` is the
/// height.
2023-10-20 02:26:12 +02:00
pub res: Option<(i32, i32)>,
2023-10-20 01:18:34 +02:00
/// The refresh rate of the output in millihertz.
///
/// For example, 60Hz is returned as 60000.
2023-10-20 02:26:12 +02:00
pub refresh_rate: Option<i32>,
2023-10-20 01:18:34 +02:00
/// The physical size of the output in millimeters.
2023-10-20 02:26:12 +02:00
pub physical_size: Option<(i32, i32)>,
2023-10-20 01:18:34 +02:00
/// Whether or not the output is focused.
2023-10-20 02:26:12 +02:00
pub focused: Option<bool>,
/// The tags on this output.
pub tags: Vec<TagHandle>,
2023-10-20 01:18:34 +02:00
}
impl OutputHandle {
// TODO: Make OutputProperties an option, make non null fields not options
/// Get all properties of this output.
pub fn properties(&self) -> OutputProperties {
let RequestResponse::OutputProps {
make,
model,
loc,
res,
refresh_rate,
physical_size,
focused,
tag_ids,
} = request(Request::GetOutputProps {
output_name: self.0 .0.clone(),
})
else {
unreachable!()
};
OutputProperties {
make,
model,
loc,
res,
refresh_rate,
physical_size,
focused,
2023-10-20 02:26:12 +02:00
tags: tag_ids
.unwrap_or(vec![])
.into_iter()
.map(TagHandle)
.collect(),
2023-10-20 01:18:34 +02:00
}
}
}