From c62d090f9f4d89c9dd5e3c4a52e9cbc2a59ef438 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Thu, 19 Oct 2023 18:18:34 -0500 Subject: [PATCH] Add most of the output stuff --- api/rust/src/lib.rs | 4 ++ api/rust/src/output.rs | 113 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 api/rust/src/output.rs diff --git a/api/rust/src/lib.rs b/api/rust/src/lib.rs index 1160e93..95b42d6 100644 --- a/api/rust/src/lib.rs +++ b/api/rust/src/lib.rs @@ -1,5 +1,6 @@ mod input; mod msg; +mod output; mod process; mod window; @@ -7,6 +8,7 @@ use input::Input; pub use input::MouseButton; pub use msg::Modifier; pub use msg::MouseEdge; +use output::Output; use window::Window; pub use xkbcommon::xkb::keysyms; pub use xkbcommon::xkb::Keysym; @@ -46,6 +48,7 @@ pub fn setup(config_func: impl FnOnce(Pinnacle)) -> anyhow::Result<()> { process: Process, input: Input, window: Window, + output: Output, }; config_func(pinnacle); @@ -170,4 +173,5 @@ pub struct Pinnacle { pub process: Process, pub window: Window, pub input: Input, + pub output: Output, } diff --git a/api/rust/src/output.rs b/api/rust/src/output.rs new file mode 100644 index 0000000..5d688f1 --- /dev/null +++ b/api/rust/src/output.rs @@ -0,0 +1,113 @@ +use crate::{ + msg::{OutputName, Request, RequestResponse}, + request, +}; + +/// 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 { + 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 { + 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 { + 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)) + } +} + +/// 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. +pub struct OutputHandle(OutputName); + +/// Properties of an output. +pub struct OutputProperties { + /// The make. + make: Option, + /// The model. + /// + /// This is something like `27GL850` or whatever gibberish monitor manufacturers name their + /// displays. + model: Option, + /// The location of the output in the global space. + loc: Option<(i32, i32)>, + /// The resolution of the output in pixels, where `res.0` is the width and `res.1` is the + /// height. + res: Option<(i32, i32)>, + /// The refresh rate of the output in millihertz. + /// + /// For example, 60Hz is returned as 60000. + refresh_rate: Option, + /// The physical size of the output in millimeters. + physical_size: Option<(i32, i32)>, + /// Whether or not the output is focused. + focused: Option, + // TODO: tags +} + +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, + } + } +}