From 2d19109fb60b3d13e7c3ebf0d9b68c36dc1a3c36 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 2 Sep 2021 12:58:11 -0700 Subject: [PATCH] feat(wm): allow direct querying of focused objects This commit adds a new query command to komorebic, which allows for the current focused monitor, workspace, container and window indices to be queried directly without having to use jq run lookups on the entire output of the state command. resolve #24 --- README.md | 2 ++ komorebi-core/src/lib.rs | 10 +++++++++ komorebi/src/process_command.rs | 25 +++++++++++++++++++++ komorebic.lib.sample.ahk | 4 ++++ komorebic/src/main.rs | 39 +++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/README.md b/README.md index 766e5867..95d1e54e 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ each command. start Start komorebi.exe as a background process stop Stop the komorebi.exe process and restore all hidden windows state Show a JSON representation of the current window manager state +query Query the current window manager state log Tail komorebi.exe's process logs (cancel with Ctrl-C) focus Change focus to the window in the specified direction move Move the focused window in the specified direction @@ -270,6 +271,7 @@ used [is available here](komorebi.sample.with.lib.ahk). - [x] Watch configuration for changes - [x] Helper library for AutoHotKey - [x] View window manager state +- [x] Query window manager state ## Development diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index b13c453e..eb04c497 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -67,6 +67,7 @@ pub enum SocketMessage { ManageRule(ApplicationIdentifier, String), IdentifyTrayApplication(ApplicationIdentifier, String), State, + Query(StateQuery), FocusFollowsMouse(bool), ToggleFocusFollowsMouse, } @@ -89,6 +90,15 @@ impl FromStr for SocketMessage { } } +#[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] +#[strum(serialize_all = "snake_case")] +pub enum StateQuery { + FocusedMonitorIndex, + FocusedWorkspaceIndex, + FocusedContainerIndex, + FocusedWindowIndex, +} + #[derive(Clone, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] #[strum(serialize_all = "snake_case")] pub enum ApplicationIdentifier { diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index ab1b9876..f6f3c66d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -12,6 +12,7 @@ use uds_windows::UnixStream; use komorebi_core::ApplicationIdentifier; use komorebi_core::SocketMessage; +use komorebi_core::StateQuery; use crate::window_manager; use crate::window_manager::WindowManager; @@ -175,6 +176,30 @@ impl WindowManager { let mut stream = UnixStream::connect(&socket)?; stream.write_all(state.as_bytes())?; } + SocketMessage::Query(query) => { + let response = match query { + StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(), + StateQuery::FocusedWorkspaceIndex => self + .focused_monitor() + .ok_or_else(|| anyhow!("there is no monitor"))? + .focused_workspace_idx(), + StateQuery::FocusedContainerIndex => { + self.focused_workspace()?.focused_container_idx() + } + StateQuery::FocusedWindowIndex => { + self.focused_container()?.focused_window_idx() + } + } + .to_string(); + + let mut socket = + dirs::home_dir().ok_or_else(|| anyhow!("there is no home directory"))?; + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + let mut stream = UnixStream::connect(&socket)?; + stream.write_all(response.as_bytes())?; + } SocketMessage::ResizeWindow(direction, sizing) => { self.resize_window(direction, sizing, Option::from(50))?; } diff --git a/komorebic.lib.sample.ahk b/komorebic.lib.sample.ahk index b5cd58d1..c11c6b52 100644 --- a/komorebic.lib.sample.ahk +++ b/komorebic.lib.sample.ahk @@ -12,6 +12,10 @@ State() { Run, komorebic.exe state, , Hide } +Query(state_query) { + Run, komorebic.exe query %state_query%, , Hide +} + Log() { Run, komorebic.exe log, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 94958ad8..9bb78194 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -34,6 +34,7 @@ use komorebi_core::Layout; use komorebi_core::OperationDirection; use komorebi_core::Sizing; use komorebi_core::SocketMessage; +use komorebi_core::StateQuery; trait AhkLibrary { fn generate_ahk_library() -> String; @@ -82,6 +83,7 @@ gen_enum_subcommand_args! { ChangeLayout: Layout, WatchConfiguration: BooleanState, FocusFollowsMouse: BooleanState, + Query: StateQuery, } macro_rules! gen_target_subcommand_args { @@ -246,6 +248,9 @@ enum SubCommand { Stop, /// Show a JSON representation of the current window manager state State, + /// Query the current window manager state + #[clap(setting = AppSettings::ArgRequiredElseHelp)] + Query(Query), /// Tail komorebi.exe's process logs (cancel with Ctrl-C) Log, /// Change focus to the window in the specified direction @@ -607,6 +612,40 @@ fn main() -> Result<()> { } } } + SubCommand::Query(arg) => { + let home = dirs::home_dir().context("there is no home directory")?; + let mut socket = home; + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + match std::fs::remove_file(&socket) { + Ok(_) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; + + send_message(&*SocketMessage::Query(arg.state_query).as_bytes()?)?; + + let listener = UnixListener::bind(&socket)?; + match listener.accept() { + Ok(incoming) => { + let stream = BufReader::new(incoming.0); + for line in stream.lines() { + println!("{}", line?); + } + + return Ok(()); + } + Err(error) => { + panic!("{}", error); + } + } + } SubCommand::RestoreWindows => { let mut hwnd_json = dirs::home_dir().context("there is no home directory")?; hwnd_json.push("komorebi.hwnd.json");