mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-04 20:21:35 +02:00
feat(cli): add visible-windows cmd
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!
This commit is contained in:
@@ -147,6 +147,7 @@ pub enum SocketMessage {
|
|||||||
IdentifyLayeredApplication(ApplicationIdentifier, String),
|
IdentifyLayeredApplication(ApplicationIdentifier, String),
|
||||||
IdentifyBorderOverflowApplication(ApplicationIdentifier, String),
|
IdentifyBorderOverflowApplication(ApplicationIdentifier, String),
|
||||||
State,
|
State,
|
||||||
|
VisibleWindows,
|
||||||
Query(StateQuery),
|
Query(StateQuery),
|
||||||
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
FocusFollowsMouse(FocusFollowsMouseImplementation, bool),
|
||||||
ToggleFocusFollowsMouse(FocusFollowsMouseImplementation),
|
ToggleFocusFollowsMouse(FocusFollowsMouseImplementation),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
@@ -701,6 +702,32 @@ impl WindowManager {
|
|||||||
let mut stream = UnixStream::connect(socket)?;
|
let mut stream = UnixStream::connect(socket)?;
|
||||||
stream.write_all(state.as_bytes())?;
|
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) => {
|
SocketMessage::Query(query) => {
|
||||||
let response = match query {
|
let response = match query {
|
||||||
StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(),
|
StateQuery::FocusedMonitorIndex => self.focused_monitor_idx(),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::fmt::Formatter;
|
|||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::anyhow;
|
use color_eyre::eyre::anyhow;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
@@ -46,6 +47,26 @@ pub struct Window {
|
|||||||
pub(crate) hwnd: isize,
|
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 {
|
impl Display for Window {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let mut display = format!("(hwnd: {}", self.hwnd);
|
let mut display = format!("(hwnd: {}", self.hwnd);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use crate::container::Container;
|
|||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::static_config::WorkspaceConfig;
|
use crate::static_config::WorkspaceConfig;
|
||||||
use crate::window::Window;
|
use crate::window::Window;
|
||||||
|
use crate::window::WindowDetails;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::DEFAULT_CONTAINER_PADDING;
|
use crate::DEFAULT_CONTAINER_PADDING;
|
||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
@@ -1087,6 +1088,20 @@ impl Workspace {
|
|||||||
vec
|
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>> {
|
pub fn visible_windows_mut(&mut self) -> Vec<Option<&mut Window>> {
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
for container in self.containers_mut() {
|
for container in self.containers_mut() {
|
||||||
|
|||||||
@@ -773,6 +773,8 @@ enum SubCommand {
|
|||||||
Check,
|
Check,
|
||||||
/// Show a JSON representation of the current window manager state
|
/// Show a JSON representation of the current window manager state
|
||||||
State,
|
State,
|
||||||
|
/// Show a JSON representation of visible windows
|
||||||
|
VisibleWindows,
|
||||||
/// Query the current window manager state
|
/// Query the current window manager state
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
Query(Query),
|
Query(Query),
|
||||||
@@ -1921,6 +1923,9 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue
|
|||||||
SubCommand::State => {
|
SubCommand::State => {
|
||||||
with_komorebic_socket(|| send_message(&SocketMessage::State.as_bytes()?))?;
|
with_komorebic_socket(|| send_message(&SocketMessage::State.as_bytes()?))?;
|
||||||
}
|
}
|
||||||
|
SubCommand::VisibleWindows => {
|
||||||
|
with_komorebic_socket(|| send_message(&SocketMessage::VisibleWindows.as_bytes()?))?;
|
||||||
|
}
|
||||||
SubCommand::Query(arg) => {
|
SubCommand::Query(arg) => {
|
||||||
with_komorebic_socket(|| {
|
with_komorebic_socket(|| {
|
||||||
send_message(&SocketMessage::Query(arg.state_query).as_bytes()?)
|
send_message(&SocketMessage::Query(arg.state_query).as_bytes()?)
|
||||||
|
|||||||
Reference in New Issue
Block a user