From c2bc19611f105e64ec565c13b2ac8fd9a62ce4b5 Mon Sep 17 00:00:00 2001 From: Nickiel12 Date: Thu, 16 Nov 2023 17:32:49 -0800 Subject: [PATCH] added new utility workspace_switcher --- ewwtilities/src/main.rs | 9 +- ewwtilities/src/workspace_switcher.rs | 139 ++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 ewwtilities/src/workspace_switcher.rs diff --git a/ewwtilities/src/main.rs b/ewwtilities/src/main.rs index 5e4391d..71943b4 100644 --- a/ewwtilities/src/main.rs +++ b/ewwtilities/src/main.rs @@ -3,9 +3,13 @@ use clap::{Parser, ValueEnum}; mod calendar_background; use calendar_background::run_calendar; +mod workspace_switcher; +use workspace_switcher::run_workspace_selector; + #[derive(ValueEnum, Debug, Clone)] enum ProcessType { CalendarBackground, + WorkspaceSelector, } #[derive(Parser, Debug)] @@ -35,7 +39,10 @@ fn main() -> Result<(), Box> { .expect("`action` parameter required when calling command") { ProcessType::CalendarBackground => { - run_calendar(&args); + run_calendar(); + } + ProcessType::WorkspaceSelector => { + run_workspace_selector(); } } Ok(()) diff --git a/ewwtilities/src/workspace_switcher.rs b/ewwtilities/src/workspace_switcher.rs new file mode 100644 index 0000000..da7938d --- /dev/null +++ b/ewwtilities/src/workspace_switcher.rs @@ -0,0 +1,139 @@ +use log::{debug, error}; +use std::io::stdin; +use std::io::IsTerminal; +use std::process::Command; + +use serde::{Deserialize, Serialize}; +use serde_json; + +pub fn run_workspace_selector() { + let in_pipe = stdin(); + if in_pipe.is_terminal() { + error!("Workspace Selector process requires being run as a terminal process"); + panic!("Expected to be run in a terminal process, but was not"); + } + + let mut buffer = String::new(); + let bytes = in_pipe.read_line(&mut buffer).unwrap(); + + debug!("Received from pipe: {buffer}"); + + if bytes == 0 { + error!("The input pipe was empty! Unrecoverable error"); + panic!("The input pipe was empty! Unrecoverable error"); + } + + debug!("Attempting to parse buffer"); + + let src_workspace = match buffer.trim().parse::() { + Ok(val) => val, + Err(e) => { + error!("Error parsing stdin buffer: {e}"); + panic!("Could not parse stdin to i32"); + } + }; + + let output = { + let std_out = match Command::new("hyprctl").arg("monitors").arg("-j").output() { + Ok(val) => val, + Err(e) => { + error!("Error getting the focused monitor: {e}"); + panic!("Error getting focused monitor"); + } + } + .stdout; + + let std_string = match String::from_utf8(std_out) { + Ok(v) => v, + Err(e) => { + error!("Could not parse hyprctl output to string: {e}"); + panic!("Could not parse hyprctl output to string"); + } + }; + + debug!("hyprctl command output: {std_string}"); + + let json_output: Vec = match serde_json::from_str(&std_string) { + Ok(val) => val, + Err(e) => { + error!("Could not parse stdout to json: {e}"); + panic!("Could not parse stdout to json"); + } + }; + json_output + }; + + debug!("Parsed monitor json: {:#?}", output); + + let id: u32 = match output + .iter() + .filter(|x| x.focused) + .map(|x| x.id) + .collect::>() + .first() + { + Some(val) => (*val).clone(), + None => { + error!("Could not get focused monitor from json"); + panic!("Could not get focused monitor from json"); + } + }; + + debug!("Active monitor: {}", id); + + let mut ids: Vec = output.iter().map(|x| x.id).collect(); + ids.sort(); + // Because we might only have a monitor 0 and 3, we need a way to consistently get + // to workspaces within the 10 eww watches + let monitor_num = ids.iter().position(|&r| r == id).unwrap(); + // It should always exist as it came from this list + + debug!("Monitor number adjusted: {}", monitor_num); + + // Because there is a monitor 0, make sure it is always at least monitor 1 + let target_workspace = src_workspace * (monitor_num + 1) as i32; + + debug!("Target workspace: {}", target_workspace); + + print!("{}", target_workspace); +} + + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct MonitorInfo { + id: u32, + name: String, + description: String, + make: String, + model: String, + serial: String, + width: u32, + height: u32, + refresh_rate: f32, + x: u32, + y: u32, + active_workspace: ActiveWorkspace, + special_workspace: SpecialWorkspace, + reserved: Vec, + scale: f32, + transform: i32, + focused: bool, + dpms_status: bool, + vrr: bool, + actively_tearing: bool, +} + +#[derive(Serialize, Deserialize, Debug)] +struct ActiveWorkspace { + id: i32, + name: String, +} + +#[derive(Serialize, Deserialize, Debug)] +struct SpecialWorkspace { + id: i32, + name: String, +} + +