mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-14 08:01:14 +01:00
Add input and window stuff
This commit is contained in:
parent
3e56450e29
commit
2c3fb2dbd7
7 changed files with 456 additions and 20 deletions
|
@ -11,3 +11,4 @@ rmp = { version = "0.8.12" }
|
||||||
rmp-serde = { version = "1.1.2" }
|
rmp-serde = { version = "1.1.2" }
|
||||||
anyhow = { version = "1.0.75", features = ["backtrace"] }
|
anyhow = { version = "1.0.75", features = ["backtrace"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
xkbcommon = "0.7.0"
|
||||||
|
|
|
@ -1,6 +1,19 @@
|
||||||
|
use pinnacle_api::{Modifier, MouseButton, MouseEdge};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pinnacle_api::setup(|pinnacle| {
|
pinnacle_api::setup(|pinnacle| {
|
||||||
pinnacle.process.spawn(vec!["alacritty"]).unwrap();
|
pinnacle.process.spawn(vec!["alacritty"]).unwrap();
|
||||||
|
|
||||||
|
pinnacle.input.keybind(&[Modifier::Ctrl], 'a', move || {
|
||||||
|
pinnacle.process.spawn(vec!["alacritty"]).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
pinnacle.input.mousebind(
|
||||||
|
&[Modifier::Ctrl],
|
||||||
|
MouseButton::Left,
|
||||||
|
MouseEdge::Press,
|
||||||
|
|| {},
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
99
api/rust/src/input.rs
Normal file
99
api/rust/src/input.rs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
use xkbcommon::xkb::Keysym;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
msg::{Args, CallbackId, KeyIntOrString, Modifier, MouseEdge, Msg},
|
||||||
|
send_msg, CALLBACK_VEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Input;
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
/// Set a keybind.
|
||||||
|
///
|
||||||
|
/// This function takes in three parameters:
|
||||||
|
/// - `modifiers`: A slice of the modifiers you want held for the keybind to trigger.
|
||||||
|
/// - `key`: The key that needs to be pressed. This takes `impl Into<KeyIntOrString>` and can
|
||||||
|
/// take the following three types:
|
||||||
|
/// - [`char`]: A character of the key you want. This can be `a`, `~`, `@`, and so on.
|
||||||
|
/// - [`u32`]: The key in numeric form. You can use the keys defined in
|
||||||
|
/// [`xkbcommon::xkb::keysyms`] for this.
|
||||||
|
/// - [`Keysym`]: The key in `Keysym` form, from [xkbcommon::xkb::Keysym].
|
||||||
|
pub fn keybind<F>(&self, modifiers: &[Modifier], key: impl Into<KeyIntOrString>, mut action: F)
|
||||||
|
where
|
||||||
|
F: FnMut() + Send + 'static,
|
||||||
|
{
|
||||||
|
let args_callback = move |_: Option<Args>| {
|
||||||
|
action();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
|
||||||
|
let len = callback_vec.len();
|
||||||
|
callback_vec.push(Box::new(args_callback));
|
||||||
|
|
||||||
|
let key = key.into();
|
||||||
|
|
||||||
|
let msg = Msg::SetKeybind {
|
||||||
|
key,
|
||||||
|
modifiers: modifiers.to_vec(),
|
||||||
|
callback_id: CallbackId(len as u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
send_msg(msg).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mousebind<F>(
|
||||||
|
&self,
|
||||||
|
modifiers: &[Modifier],
|
||||||
|
button: MouseButton,
|
||||||
|
edge: MouseEdge,
|
||||||
|
mut action: F,
|
||||||
|
) where
|
||||||
|
F: FnMut() + Send + 'static,
|
||||||
|
{
|
||||||
|
let args_callback = move |_: Option<Args>| {
|
||||||
|
action();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
|
||||||
|
let len = callback_vec.len();
|
||||||
|
callback_vec.push(Box::new(args_callback));
|
||||||
|
|
||||||
|
let msg = Msg::SetMousebind {
|
||||||
|
modifiers: modifiers.to_vec(),
|
||||||
|
button: button as u32,
|
||||||
|
edge,
|
||||||
|
callback_id: CallbackId(len as u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
send_msg(msg).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum MouseButton {
|
||||||
|
Left = 0x110,
|
||||||
|
Right,
|
||||||
|
Middle,
|
||||||
|
Side,
|
||||||
|
Extra,
|
||||||
|
Forward,
|
||||||
|
Back,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<char> for KeyIntOrString {
|
||||||
|
fn from(value: char) -> Self {
|
||||||
|
Self::String(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for KeyIntOrString {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
Self::Int(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Keysym> for KeyIntOrString {
|
||||||
|
fn from(value: Keysym) -> Self {
|
||||||
|
Self::Int(value.raw())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,20 +1,40 @@
|
||||||
|
mod input;
|
||||||
mod msg;
|
mod msg;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod window;
|
||||||
|
|
||||||
|
use input::Input;
|
||||||
|
pub use input::MouseButton;
|
||||||
|
pub use msg::Modifier;
|
||||||
|
pub use msg::MouseEdge;
|
||||||
|
use window::Window;
|
||||||
|
pub use xkbcommon::xkb::keysyms;
|
||||||
|
pub use xkbcommon::xkb::Keysym;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
collections::HashMap,
|
||||||
|
io::{Read, Write},
|
||||||
os::unix::net::UnixStream,
|
os::unix::net::UnixStream,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Mutex, OnceLock},
|
sync::{atomic::AtomicU32, Mutex, OnceLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use msg::{Args, Msg, Request};
|
use msg::{Args, CallbackId, IncomingMsg, Msg, Request, RequestResponse};
|
||||||
use process::Process;
|
use process::Process;
|
||||||
|
|
||||||
|
use crate::msg::RequestId;
|
||||||
|
|
||||||
static STREAM: OnceLock<Mutex<UnixStream>> = OnceLock::new();
|
static STREAM: OnceLock<Mutex<UnixStream>> = OnceLock::new();
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
static CALLBACK_VEC: Mutex<Vec<Box<dyn FnMut(Args) + Send>>> = Mutex::new(Vec::new());
|
static CALLBACK_VEC: Mutex<Vec<Box<dyn FnMut(Option<Args>) + Send>>> = Mutex::new(Vec::new());
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref UNREAD_CALLBACK_MSGS: Mutex<HashMap<CallbackId, IncomingMsg>> = Mutex::new(HashMap::new());
|
||||||
|
static ref UNREAD_REQUEST_MSGS: Mutex<HashMap<RequestId, IncomingMsg>> = Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
static REQUEST_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
|
/// Setup Pinnacle.
|
||||||
pub fn setup(config_func: impl FnOnce(Pinnacle)) -> anyhow::Result<()> {
|
pub fn setup(config_func: impl FnOnce(Pinnacle)) -> anyhow::Result<()> {
|
||||||
STREAM
|
STREAM
|
||||||
.set(Mutex::new(UnixStream::connect(PathBuf::from(
|
.set(Mutex::new(UnixStream::connect(PathBuf::from(
|
||||||
|
@ -22,11 +42,46 @@ pub fn setup(config_func: impl FnOnce(Pinnacle)) -> anyhow::Result<()> {
|
||||||
))?))
|
))?))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let pinnacle = Pinnacle { process: Process };
|
let pinnacle = Pinnacle {
|
||||||
|
process: Process,
|
||||||
|
input: Input,
|
||||||
|
window: Window,
|
||||||
|
};
|
||||||
|
|
||||||
config_func(pinnacle);
|
config_func(pinnacle);
|
||||||
|
|
||||||
Ok(())
|
loop {
|
||||||
|
let mut unread_callback_msgs = UNREAD_CALLBACK_MSGS.lock().unwrap();
|
||||||
|
let mut callback_vec = CALLBACK_VEC.lock().unwrap();
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for (cb_id, incoming_msg) in unread_callback_msgs.iter() {
|
||||||
|
let IncomingMsg::CallCallback { callback_id, args } = incoming_msg else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(f) = callback_vec.get_mut(callback_id.0 as usize) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
f(args.clone());
|
||||||
|
to_remove.push(*cb_id);
|
||||||
|
}
|
||||||
|
for id in to_remove {
|
||||||
|
unread_callback_msgs.remove(&id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let incoming_msg = read_msg(None);
|
||||||
|
|
||||||
|
assert!(matches!(incoming_msg, IncomingMsg::CallCallback { .. }));
|
||||||
|
|
||||||
|
let IncomingMsg::CallCallback { callback_id, args } = incoming_msg else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(f) = callback_vec.get_mut(callback_id.0 as usize) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
f(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_msg(msg: Msg) -> anyhow::Result<()> {
|
fn send_msg(msg: Msg) -> anyhow::Result<()> {
|
||||||
|
@ -41,16 +96,78 @@ fn send_msg(msg: Msg) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_msg() {
|
fn read_msg(request_id: Option<RequestId>) -> IncomingMsg {
|
||||||
todo!()
|
loop {
|
||||||
|
if let Some(request_id) = request_id {
|
||||||
|
if let Some(msg) = UNREAD_REQUEST_MSGS.lock().unwrap().remove(&request_id) {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stream = STREAM.get().unwrap().lock().unwrap();
|
||||||
|
let mut msg_len_bytes = [0u8; 4];
|
||||||
|
stream.read_exact(msg_len_bytes.as_mut_slice()).unwrap();
|
||||||
|
|
||||||
|
let msg_len = u32::from_ne_bytes(msg_len_bytes);
|
||||||
|
let mut msg_bytes = vec![0u8; msg_len as usize];
|
||||||
|
stream.read_exact(msg_bytes.as_mut_slice()).unwrap();
|
||||||
|
|
||||||
|
let incoming_msg: IncomingMsg = rmp_serde::from_slice(msg_bytes.as_slice()).unwrap();
|
||||||
|
|
||||||
|
if let Some(request_id) = request_id {
|
||||||
|
match &incoming_msg {
|
||||||
|
IncomingMsg::CallCallback {
|
||||||
|
callback_id,
|
||||||
|
args: _,
|
||||||
|
} => {
|
||||||
|
UNREAD_CALLBACK_MSGS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(*callback_id, incoming_msg);
|
||||||
|
}
|
||||||
|
IncomingMsg::RequestResponse {
|
||||||
|
request_id: req_id,
|
||||||
|
response: _,
|
||||||
|
} => {
|
||||||
|
if req_id != &request_id {
|
||||||
|
UNREAD_REQUEST_MSGS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(*req_id, incoming_msg);
|
||||||
|
} else {
|
||||||
|
return incoming_msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return incoming_msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request(request: Request) {
|
fn request(request: Request) -> RequestResponse {
|
||||||
//
|
use std::sync::atomic::Ordering;
|
||||||
|
let request_id = REQUEST_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let msg = Msg::Request {
|
||||||
|
request_id: RequestId(request_id),
|
||||||
|
request,
|
||||||
|
};
|
||||||
|
send_msg(msg).unwrap(); // TODO: propogate
|
||||||
|
|
||||||
|
let IncomingMsg::RequestResponse {
|
||||||
|
request_id: _,
|
||||||
|
response,
|
||||||
|
} = read_msg(Some(RequestId(request_id)))
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pinnacle {
|
pub struct Pinnacle {
|
||||||
pub process: Process,
|
pub process: Process,
|
||||||
|
pub window: Window,
|
||||||
|
pub input: Input,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pinnacle {}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
#[derive(Debug, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, Clone, Copy)]
|
||||||
pub struct CallbackId(pub u32);
|
pub struct CallbackId(pub u32);
|
||||||
|
|
||||||
#[derive(Debug, Hash, serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Hash, serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -88,8 +88,8 @@ pub enum LibinputSetting {
|
||||||
TapEnabled(bool),
|
TapEnabled(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct RequestId(u32);
|
pub struct RequestId(pub u32);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct WindowRuleCondition {
|
pub struct WindowRuleCondition {
|
||||||
|
@ -116,7 +116,7 @@ pub enum FloatingOrTiled {
|
||||||
Tiled,
|
Tiled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum FullscreenOrMaximized {
|
pub enum FullscreenOrMaximized {
|
||||||
Neither,
|
Neither,
|
||||||
Fullscreen,
|
Fullscreen,
|
||||||
|
@ -300,7 +300,7 @@ pub enum Modifier {
|
||||||
Super,
|
Super,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
|
||||||
pub enum Args {
|
pub enum Args {
|
||||||
/// Send a message with lines from the spawned process.
|
/// Send a message with lines from the spawned process.
|
||||||
Spawn {
|
Spawn {
|
||||||
|
@ -317,3 +317,66 @@ pub enum Args {
|
||||||
output_name: String,
|
output_name: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum IncomingMsg {
|
||||||
|
CallCallback {
|
||||||
|
callback_id: CallbackId,
|
||||||
|
#[serde(default)]
|
||||||
|
args: Option<Args>,
|
||||||
|
},
|
||||||
|
RequestResponse {
|
||||||
|
request_id: RequestId,
|
||||||
|
response: RequestResponse,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum RequestResponse {
|
||||||
|
Window {
|
||||||
|
window_id: Option<WindowId>,
|
||||||
|
},
|
||||||
|
Windows {
|
||||||
|
window_ids: Vec<WindowId>,
|
||||||
|
},
|
||||||
|
WindowProps {
|
||||||
|
size: Option<(i32, i32)>,
|
||||||
|
loc: Option<(i32, i32)>,
|
||||||
|
class: Option<String>,
|
||||||
|
title: Option<String>,
|
||||||
|
focused: Option<bool>,
|
||||||
|
floating: Option<bool>,
|
||||||
|
fullscreen_or_maximized: Option<FullscreenOrMaximized>,
|
||||||
|
},
|
||||||
|
Output {
|
||||||
|
output_name: Option<String>,
|
||||||
|
},
|
||||||
|
Outputs {
|
||||||
|
output_names: Vec<String>,
|
||||||
|
},
|
||||||
|
OutputProps {
|
||||||
|
/// The make of the output.
|
||||||
|
make: Option<String>,
|
||||||
|
/// The model of the output.
|
||||||
|
model: Option<String>,
|
||||||
|
/// The location of the output in the space.
|
||||||
|
loc: Option<(i32, i32)>,
|
||||||
|
/// The resolution of the output.
|
||||||
|
res: Option<(i32, i32)>,
|
||||||
|
/// The refresh rate of the output.
|
||||||
|
refresh_rate: Option<i32>,
|
||||||
|
/// The size of the output, in millimeters.
|
||||||
|
physical_size: Option<(i32, i32)>,
|
||||||
|
/// Whether the output is focused or not.
|
||||||
|
focused: Option<bool>,
|
||||||
|
tag_ids: Option<Vec<TagId>>,
|
||||||
|
},
|
||||||
|
Tags {
|
||||||
|
tag_ids: Vec<TagId>,
|
||||||
|
},
|
||||||
|
TagProps {
|
||||||
|
active: Option<bool>,
|
||||||
|
name: Option<String>,
|
||||||
|
output_name: Option<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@ impl Process {
|
||||||
where
|
where
|
||||||
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>) + Send + 'static,
|
F: FnMut(Option<String>, Option<String>, Option<i32>, Option<String>) + Send + 'static,
|
||||||
{
|
{
|
||||||
let args_callback = move |args: Args| {
|
let args_callback = move |args: Option<Args>| {
|
||||||
if let Args::Spawn {
|
if let Some(Args::Spawn {
|
||||||
stdout,
|
stdout,
|
||||||
stderr,
|
stderr,
|
||||||
exit_code,
|
exit_code,
|
||||||
exit_msg,
|
exit_msg,
|
||||||
} = args
|
}) = args
|
||||||
{
|
{
|
||||||
callback(stdout, stderr, exit_code, exit_msg);
|
callback(stdout, stderr, exit_code, exit_msg);
|
||||||
}
|
}
|
||||||
|
|
143
api/rust/src/window.rs
Normal file
143
api/rust/src/window.rs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
use crate::{
|
||||||
|
msg::{FullscreenOrMaximized, Msg, Request, RequestResponse, WindowId},
|
||||||
|
request, send_msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Window;
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn get_by_class<'a>(&self, class: &'a str) -> impl Iterator<Item = WindowHandle> + 'a {
|
||||||
|
self.get_all()
|
||||||
|
.filter(|win| win.class().as_deref() == Some(class))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_focused(&self) -> Option<WindowHandle> {
|
||||||
|
self.get_all()
|
||||||
|
.find(|win| win.focused().is_some_and(|focused| focused))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all(&self) -> impl Iterator<Item = WindowHandle> {
|
||||||
|
let RequestResponse::Windows { window_ids } = request(Request::GetWindows) else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
window_ids.into_iter().map(WindowHandle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WindowHandle(WindowId);
|
||||||
|
|
||||||
|
impl WindowHandle {
|
||||||
|
pub fn toggle_floating(&self) {
|
||||||
|
send_msg(Msg::ToggleFloating { window_id: self.0 }).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_fullscreen(&self) {
|
||||||
|
send_msg(Msg::ToggleFullscreen { window_id: self.0 }).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_maximized(&self) {
|
||||||
|
send_msg(Msg::ToggleMaximized { window_id: self.0 }).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&self, width: Option<i32>, height: Option<i32>) {
|
||||||
|
send_msg(Msg::SetWindowSize {
|
||||||
|
window_id: self.0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&self) {
|
||||||
|
send_msg(Msg::CloseWindow { window_id: self.0 }).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> Option<(i32, i32)> {
|
||||||
|
let RequestResponse::WindowProps { size, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loc(&self) -> Option<(i32, i32)> {
|
||||||
|
let RequestResponse::WindowProps { loc, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
loc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class(&self) -> Option<String> {
|
||||||
|
let RequestResponse::WindowProps { class, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
class
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(&self) -> Option<String> {
|
||||||
|
let RequestResponse::WindowProps { title, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
title
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn floating(&self) -> Option<bool> {
|
||||||
|
let RequestResponse::WindowProps { floating, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
floating
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maximized(&self) -> Option<bool> {
|
||||||
|
let RequestResponse::WindowProps {
|
||||||
|
fullscreen_or_maximized,
|
||||||
|
..
|
||||||
|
} = request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
fullscreen_or_maximized.map(|fullscreen_or_maximized| {
|
||||||
|
matches!(fullscreen_or_maximized, FullscreenOrMaximized::Maximized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fullscreen(&self) -> Option<bool> {
|
||||||
|
let RequestResponse::WindowProps {
|
||||||
|
fullscreen_or_maximized,
|
||||||
|
..
|
||||||
|
} = request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
fullscreen_or_maximized.map(|fullscreen_or_maximized| {
|
||||||
|
matches!(fullscreen_or_maximized, FullscreenOrMaximized::Fullscreen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn focused(&self) -> Option<bool> {
|
||||||
|
let RequestResponse::WindowProps { focused, .. } =
|
||||||
|
request(Request::GetWindowProps { window_id: self.0 })
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
focused
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue