Skip to content

Commit

Permalink
feat(cli): add visible-windows cmd
Browse files Browse the repository at this point in the history
This commit adds a new komorebic command, "visible-windows", to make
tracking down ghost windows easier. The returned JSON structure will try
to use the device id to identify a monitor if it is available, or fall
back to the monitor index. Thanks to raggi on Discord for suggesting
this command!
  • Loading branch information
LGUG2Z committed Jan 2, 2024
1 parent d2a06a1 commit b4ae043
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 0 deletions.
1 change: 1 addition & 0 deletions komorebi-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ pub enum SocketMessage {
IdentifyLayeredApplication(ApplicationIdentifier, String),
IdentifyBorderOverflowApplication(ApplicationIdentifier, String),
State,
VisibleWindows,
Query(StateQuery),
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
ToggleFocusFollowsMouse(FocusFollowsMouseImplementation),
Expand Down
27 changes: 27 additions & 0 deletions komorebi/src/process_command.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::BufRead;
Expand Down Expand Up @@ -701,6 +702,32 @@ impl WindowManager {
let mut stream = UnixStream::connect(socket)?;
stream.write_all(state.as_bytes())?;
}
SocketMessage::VisibleWindows => {
let mut monitor_visible_windows = HashMap::new();

for (index, monitor) in self.monitors().iter().enumerate() {
if let Some(ws) = monitor.focused_workspace() {
monitor_visible_windows.insert(
monitor
.device_id()
.clone()
.unwrap_or_else(|| format!("{index}")),
ws.visible_window_details().clone(),
);
}
}

let visible_windows_state =
match serde_json::to_string_pretty(&monitor_visible_windows) {
Ok(state) => state,
Err(error) => error.to_string(),
};

let socket = DATA_DIR.join("komorebic.sock");
let mut stream = UnixStream::connect(socket)?;
stream.write_all(visible_windows_state.as_bytes())?;
}

SocketMessage::Query(query) => {
let response = match query {
StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(),
Expand Down
21 changes: 21 additions & 0 deletions komorebi/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::fmt::Formatter;
use std::fmt::Write as _;
use std::sync::atomic::Ordering;

use color_eyre::eyre;
use color_eyre::eyre::anyhow;
use color_eyre::Result;
use komorebi_core::config_generation::IdWithIdentifier;
Expand Down Expand Up @@ -46,6 +47,26 @@ pub struct Window {
pub(crate) hwnd: isize,
}

#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Serialize, JsonSchema)]
pub struct WindowDetails {
pub title: String,
pub exe: String,
pub class: String,
}

impl TryFrom<Window> for WindowDetails {
type Error = eyre::ErrReport;

fn try_from(value: Window) -> std::result::Result<Self, Self::Error> {
Ok(Self {
title: value.title()?,
exe: value.exe()?,
class: value.class()?,
})
}
}

impl Display for Window {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut display = format!("(hwnd: {}", self.hwnd);
Expand Down
15 changes: 15 additions & 0 deletions komorebi/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::container::Container;
use crate::ring::Ring;
use crate::static_config::WorkspaceConfig;
use crate::window::Window;
use crate::window::WindowDetails;
use crate::windows_api::WindowsApi;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
Expand Down Expand Up @@ -1087,6 +1088,20 @@ impl Workspace {
vec
}

pub fn visible_window_details(&self) -> Vec<WindowDetails> {
let mut vec: Vec<WindowDetails> = vec![];

for container in self.containers() {
if let Some(focused) = container.focused_window() {
if let Ok(details) = (*focused).try_into() {
vec.push(details);
}
}
}

vec
}

pub fn visible_windows_mut(&mut self) -> Vec<Option<&mut Window>> {
let mut vec = vec![];
for container in self.containers_mut() {
Expand Down
5 changes: 5 additions & 0 deletions komorebic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,8 @@ enum SubCommand {
Check,
/// Show a JSON representation of the current window manager state
State,
/// Show a JSON representation of visible windows
VisibleWindows,
/// Query the current window manager state
#[clap(arg_required_else_help = true)]
Query(Query),
Expand Down Expand Up @@ -1921,6 +1923,9 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
SubCommand::State => {
with_komorebic_socket(|| send_message(&SocketMessage::State.as_bytes()?))?;
}
SubCommand::VisibleWindows => {
with_komorebic_socket(|| send_message(&SocketMessage::VisibleWindows.as_bytes()?))?;
}
SubCommand::Query(arg) => {
with_komorebic_socket(|| {
send_message(&SocketMessage::Query(arg.state_query).as_bytes()?)
Expand Down

0 comments on commit b4ae043

Please sign in to comment.