mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-25 01:58:51 +02:00
feat(wm): add cmd for unmanaged hwnd op behaviour
This commit adds a new command, 'unmanaged-window-operation-behaviour' which allows the user to configure their desired behaviour in situations when sending window container commands which operate on the focused window container in the workspace state, but having an unmanaged window as the foreground hwnd. The default previously was previously Op (and this remains the default with these new changes), but the user can now select NoOp, which will return an error when the focused hwnd is unmanaged and not allow any write operations to take place on the focused workspace state. resolve #133
This commit is contained in:
@@ -475,6 +475,7 @@ unmanage Unmanage a window that was forcibly m
|
|||||||
reload-configuration Reload ~/komorebi.ahk (if it exists)
|
reload-configuration Reload ~/komorebi.ahk (if it exists)
|
||||||
watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists)
|
watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists)
|
||||||
window-hiding-behaviour Set the window behaviour when switching workspaces / cycling stacks
|
window-hiding-behaviour Set the window behaviour when switching workspaces / cycling stacks
|
||||||
|
unmanaged-window-operation-behaviour Set the operation behaviour when the focused window is not managed
|
||||||
float-rule Add a rule to always float the specified application
|
float-rule Add a rule to always float the specified application
|
||||||
manage-rule Add a rule to always manage the specified application
|
manage-rule Add a rule to always manage the specified application
|
||||||
workspace-rule Add a rule to associate an application with a workspace
|
workspace-rule Add a rule to associate an application with a workspace
|
||||||
@@ -487,6 +488,8 @@ toggle-focus-follows-mouse Toggle focus follows mouse for the op
|
|||||||
mouse-follows-focus Enable or disable mouse follows focus on all workspaces
|
mouse-follows-focus Enable or disable mouse follows focus on all workspaces
|
||||||
toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces
|
toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces
|
||||||
ahk-library Generate a library of AutoHotKey helper functions
|
ahk-library Generate a library of AutoHotKey helper functions
|
||||||
|
ahk-app-specific-configuration Generate common app-specific configurations and fixes to use in komorebi.ahk
|
||||||
|
format-app-specific-configuration Format a YAML file for use with the 'ahk-app-specific-configuration' command
|
||||||
notification-schema Generate a JSON Schema of subscription notifications
|
notification-schema Generate a JSON Schema of subscription notifications
|
||||||
help Print this message or the help of the given subcommand(s)
|
help Print this message or the help of the given subcommand(s)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub enum SocketMessage {
|
|||||||
ToggleMaximize,
|
ToggleMaximize,
|
||||||
ToggleWindowContainerBehaviour,
|
ToggleWindowContainerBehaviour,
|
||||||
WindowHidingBehaviour(HidingBehaviour),
|
WindowHidingBehaviour(HidingBehaviour),
|
||||||
|
UnmanagedWindowOperationBehaviour(OperationBehaviour),
|
||||||
// Current Workspace Commands
|
// Current Workspace Commands
|
||||||
ManageFocusedWindow,
|
ManageFocusedWindow,
|
||||||
UnmanageFocusedWindow,
|
UnmanageFocusedWindow,
|
||||||
@@ -167,6 +168,13 @@ pub enum HidingBehaviour {
|
|||||||
Minimize,
|
Minimize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
|
||||||
|
#[strum(serialize_all = "snake_case")]
|
||||||
|
pub enum OperationBehaviour {
|
||||||
|
Op,
|
||||||
|
NoOp,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum, JsonSchema)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum Sizing {
|
pub enum Sizing {
|
||||||
|
|||||||
@@ -681,6 +681,9 @@ impl WindowManager {
|
|||||||
let mut hiding_behaviour = HIDING_BEHAVIOUR.lock();
|
let mut hiding_behaviour = HIDING_BEHAVIOUR.lock();
|
||||||
*hiding_behaviour = behaviour;
|
*hiding_behaviour = behaviour;
|
||||||
}
|
}
|
||||||
|
SocketMessage::UnmanagedWindowOperationBehaviour(behaviour) => {
|
||||||
|
self.unmanaged_window_operation_behaviour = behaviour;
|
||||||
|
}
|
||||||
SocketMessage::NotificationSchema => {
|
SocketMessage::NotificationSchema => {
|
||||||
let notification = schema_for!(Notification);
|
let notification = schema_for!(Notification);
|
||||||
let schema = serde_json::to_string_pretty(¬ification)?;
|
let schema = serde_json::to_string_pretty(¬ification)?;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use komorebi_core::CycleDirection;
|
|||||||
use komorebi_core::DefaultLayout;
|
use komorebi_core::DefaultLayout;
|
||||||
use komorebi_core::FocusFollowsMouseImplementation;
|
use komorebi_core::FocusFollowsMouseImplementation;
|
||||||
use komorebi_core::Layout;
|
use komorebi_core::Layout;
|
||||||
|
use komorebi_core::OperationBehaviour;
|
||||||
use komorebi_core::OperationDirection;
|
use komorebi_core::OperationDirection;
|
||||||
use komorebi_core::Rect;
|
use komorebi_core::Rect;
|
||||||
use komorebi_core::Sizing;
|
use komorebi_core::Sizing;
|
||||||
@@ -56,6 +57,7 @@ pub struct WindowManager {
|
|||||||
pub work_area_offset: Option<Rect>,
|
pub work_area_offset: Option<Rect>,
|
||||||
pub resize_delta: i32,
|
pub resize_delta: i32,
|
||||||
pub window_container_behaviour: WindowContainerBehaviour,
|
pub window_container_behaviour: WindowContainerBehaviour,
|
||||||
|
pub unmanaged_window_operation_behaviour: OperationBehaviour,
|
||||||
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
||||||
pub mouse_follows_focus: bool,
|
pub mouse_follows_focus: bool,
|
||||||
pub hotwatch: Hotwatch,
|
pub hotwatch: Hotwatch,
|
||||||
@@ -172,6 +174,7 @@ impl WindowManager {
|
|||||||
virtual_desktop_id: current_virtual_desktop(),
|
virtual_desktop_id: current_virtual_desktop(),
|
||||||
work_area_offset: None,
|
work_area_offset: None,
|
||||||
window_container_behaviour: WindowContainerBehaviour::Create,
|
window_container_behaviour: WindowContainerBehaviour::Create,
|
||||||
|
unmanaged_window_operation_behaviour: OperationBehaviour::Op,
|
||||||
resize_delta: 50,
|
resize_delta: 50,
|
||||||
focus_follows_mouse: None,
|
focus_follows_mouse: None,
|
||||||
mouse_follows_focus: true,
|
mouse_follows_focus: true,
|
||||||
@@ -785,6 +788,21 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
fn handle_unmanaged_window_behaviour(&self) -> Result<()> {
|
||||||
|
if let OperationBehaviour::NoOp = self.unmanaged_window_operation_behaviour {
|
||||||
|
let workspace = self.focused_workspace()?;
|
||||||
|
let focused_hwnd = WindowsApi::foreground_window()?;
|
||||||
|
if !workspace.contains_managed_window(focused_hwnd) {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"ignoring commands while active window is not managed by komorebi"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn move_container_to_monitor(
|
pub fn move_container_to_monitor(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -792,6 +810,8 @@ impl WindowManager {
|
|||||||
workspace_idx: Option<usize>,
|
workspace_idx: Option<usize>,
|
||||||
follow: bool,
|
follow: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("moving container");
|
tracing::info!("moving container");
|
||||||
|
|
||||||
let invisible_borders = self.invisible_borders;
|
let invisible_borders = self.invisible_borders;
|
||||||
@@ -835,6 +855,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> {
|
pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("moving container");
|
tracing::info!("moving container");
|
||||||
|
|
||||||
let mouse_follows_focus = self.mouse_follows_focus;
|
let mouse_follows_focus = self.mouse_follows_focus;
|
||||||
@@ -879,7 +901,10 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn focus_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
pub fn focus_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("focusing container");
|
tracing::info!("focusing container");
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
|
|
||||||
let new_idx = workspace
|
let new_idx = workspace
|
||||||
@@ -894,6 +919,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn move_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
pub fn move_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("moving container");
|
tracing::info!("moving container");
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
@@ -910,6 +937,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn focus_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
pub fn focus_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("focusing container");
|
tracing::info!("focusing container");
|
||||||
let mut maximize_next = false;
|
let mut maximize_next = false;
|
||||||
let mut monocle_next = false;
|
let mut monocle_next = false;
|
||||||
@@ -945,6 +974,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn move_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
pub fn move_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("moving container");
|
tracing::info!("moving container");
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
@@ -961,6 +992,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn cycle_container_window_in_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
pub fn cycle_container_window_in_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("cycling container windows");
|
tracing::info!("cycling container windows");
|
||||||
|
|
||||||
let container = self.focused_container_mut()?;
|
let container = self.focused_container_mut()?;
|
||||||
@@ -983,6 +1016,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn add_window_to_container(&mut self, direction: OperationDirection) -> Result<()> {
|
pub fn add_window_to_container(&mut self, direction: OperationDirection) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("adding window to container");
|
tracing::info!("adding window to container");
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
@@ -1019,6 +1054,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn promote_container_to_front(&mut self) -> Result<()> {
|
pub fn promote_container_to_front(&mut self) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("promoting container");
|
tracing::info!("promoting container");
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
@@ -1028,6 +1065,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn remove_window_from_container(&mut self) -> Result<()> {
|
pub fn remove_window_from_container(&mut self) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
tracing::info!("removing window");
|
tracing::info!("removing window");
|
||||||
|
|
||||||
if self.focused_container()?.windows().len() == 1 {
|
if self.focused_container()?.windows().len() == 1 {
|
||||||
@@ -1100,6 +1139,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn toggle_monocle(&mut self) -> Result<()> {
|
pub fn toggle_monocle(&mut self) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
|
|
||||||
match workspace.monocle_container() {
|
match workspace.monocle_container() {
|
||||||
@@ -1128,6 +1169,8 @@ impl WindowManager {
|
|||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn toggle_maximize(&mut self) -> Result<()> {
|
pub fn toggle_maximize(&mut self) -> Result<()> {
|
||||||
|
self.handle_unmanaged_window_behaviour()?;
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
|
|
||||||
match workspace.maximized_window() {
|
match workspace.maximized_window() {
|
||||||
|
|||||||
@@ -334,6 +334,28 @@ impl Workspace {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains_managed_window(&self, hwnd: isize) -> bool {
|
||||||
|
for container in self.containers() {
|
||||||
|
if container.contains_window(hwnd) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(window) = self.maximized_window() {
|
||||||
|
if hwnd == window.hwnd {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(container) = self.monocle_container() {
|
||||||
|
if container.contains_window(hwnd) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains_window(&self, hwnd: isize) -> bool {
|
pub fn contains_window(&self, hwnd: isize) -> bool {
|
||||||
for container in self.containers() {
|
for container in self.containers() {
|
||||||
if container.contains_window(hwnd) {
|
if container.contains_window(hwnd) {
|
||||||
|
|||||||
@@ -256,6 +256,10 @@ WindowHidingBehaviour(hiding_behaviour) {
|
|||||||
Run, komorebic.exe window-hiding-behaviour %hiding_behaviour%, , Hide
|
Run, komorebic.exe window-hiding-behaviour %hiding_behaviour%, , Hide
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnmanagedWindowOperationBehaviour(operation_behaviour) {
|
||||||
|
Run, komorebic.exe unmanaged-window-operation-behaviour %operation_behaviour%, , Hide
|
||||||
|
}
|
||||||
|
|
||||||
FloatRule(identifier, id) {
|
FloatRule(identifier, id) {
|
||||||
Run, komorebic.exe float-rule %identifier% "%id%", , Hide
|
Run, komorebic.exe float-rule %identifier% "%id%", , Hide
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use komorebi_core::CycleDirection;
|
|||||||
use komorebi_core::DefaultLayout;
|
use komorebi_core::DefaultLayout;
|
||||||
use komorebi_core::FocusFollowsMouseImplementation;
|
use komorebi_core::FocusFollowsMouseImplementation;
|
||||||
use komorebi_core::HidingBehaviour;
|
use komorebi_core::HidingBehaviour;
|
||||||
|
use komorebi_core::OperationBehaviour;
|
||||||
use komorebi_core::OperationDirection;
|
use komorebi_core::OperationDirection;
|
||||||
use komorebi_core::Rect;
|
use komorebi_core::Rect;
|
||||||
use komorebi_core::Sizing;
|
use komorebi_core::Sizing;
|
||||||
@@ -114,6 +115,7 @@ gen_enum_subcommand_args! {
|
|||||||
MouseFollowsFocus: BooleanState,
|
MouseFollowsFocus: BooleanState,
|
||||||
Query: StateQuery,
|
Query: StateQuery,
|
||||||
WindowHidingBehaviour: HidingBehaviour,
|
WindowHidingBehaviour: HidingBehaviour,
|
||||||
|
UnmanagedWindowOperationBehaviour: OperationBehaviour,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! gen_target_subcommand_args {
|
macro_rules! gen_target_subcommand_args {
|
||||||
@@ -622,6 +624,9 @@ enum SubCommand {
|
|||||||
/// Set the window behaviour when switching workspaces / cycling stacks
|
/// Set the window behaviour when switching workspaces / cycling stacks
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
WindowHidingBehaviour(WindowHidingBehaviour),
|
WindowHidingBehaviour(WindowHidingBehaviour),
|
||||||
|
/// Set the operation behaviour when the focused window is not managed
|
||||||
|
#[clap(arg_required_else_help = true)]
|
||||||
|
UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour),
|
||||||
/// Add a rule to always float the specified application
|
/// Add a rule to always float the specified application
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
FloatRule(FloatRule),
|
FloatRule(FloatRule),
|
||||||
@@ -1162,6 +1167,12 @@ fn main() -> Result<()> {
|
|||||||
SubCommand::WindowHidingBehaviour(arg) => {
|
SubCommand::WindowHidingBehaviour(arg) => {
|
||||||
send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?;
|
send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::UnmanagedWindowOperationBehaviour(arg) => {
|
||||||
|
send_message(
|
||||||
|
&*SocketMessage::UnmanagedWindowOperationBehaviour(arg.operation_behaviour)
|
||||||
|
.as_bytes()?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
SubCommand::AhkAppSpecificConfiguration(arg) => {
|
SubCommand::AhkAppSpecificConfiguration(arg) => {
|
||||||
let content = fs::read_to_string(resolve_windows_path(&arg.path)?)?;
|
let content = fs::read_to_string(resolve_windows_path(&arg.path)?)?;
|
||||||
let lines = if let Some(override_path) = arg.override_path {
|
let lines = if let Some(override_path) = arg.override_path {
|
||||||
|
|||||||
Reference in New Issue
Block a user