mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-03-23 18:01:12 +01: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)
|
||||
watch-configuration Enable or disable watching of ~/komorebi.ahk (if it exists)
|
||||
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
|
||||
manage-rule Add a rule to always manage the specified application
|
||||
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
|
||||
toggle-mouse-follows-focus Toggle mouse follows focus on all workspaces
|
||||
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
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
```
|
||||
|
||||
@@ -57,6 +57,7 @@ pub enum SocketMessage {
|
||||
ToggleMaximize,
|
||||
ToggleWindowContainerBehaviour,
|
||||
WindowHidingBehaviour(HidingBehaviour),
|
||||
UnmanagedWindowOperationBehaviour(OperationBehaviour),
|
||||
// Current Workspace Commands
|
||||
ManageFocusedWindow,
|
||||
UnmanageFocusedWindow,
|
||||
@@ -167,6 +168,13 @@ pub enum HidingBehaviour {
|
||||
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)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Sizing {
|
||||
|
||||
@@ -681,6 +681,9 @@ impl WindowManager {
|
||||
let mut hiding_behaviour = HIDING_BEHAVIOUR.lock();
|
||||
*hiding_behaviour = behaviour;
|
||||
}
|
||||
SocketMessage::UnmanagedWindowOperationBehaviour(behaviour) => {
|
||||
self.unmanaged_window_operation_behaviour = behaviour;
|
||||
}
|
||||
SocketMessage::NotificationSchema => {
|
||||
let notification = schema_for!(Notification);
|
||||
let schema = serde_json::to_string_pretty(¬ification)?;
|
||||
|
||||
@@ -22,6 +22,7 @@ use komorebi_core::CycleDirection;
|
||||
use komorebi_core::DefaultLayout;
|
||||
use komorebi_core::FocusFollowsMouseImplementation;
|
||||
use komorebi_core::Layout;
|
||||
use komorebi_core::OperationBehaviour;
|
||||
use komorebi_core::OperationDirection;
|
||||
use komorebi_core::Rect;
|
||||
use komorebi_core::Sizing;
|
||||
@@ -56,6 +57,7 @@ pub struct WindowManager {
|
||||
pub work_area_offset: Option<Rect>,
|
||||
pub resize_delta: i32,
|
||||
pub window_container_behaviour: WindowContainerBehaviour,
|
||||
pub unmanaged_window_operation_behaviour: OperationBehaviour,
|
||||
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
||||
pub mouse_follows_focus: bool,
|
||||
pub hotwatch: Hotwatch,
|
||||
@@ -172,6 +174,7 @@ impl WindowManager {
|
||||
virtual_desktop_id: current_virtual_desktop(),
|
||||
work_area_offset: None,
|
||||
window_container_behaviour: WindowContainerBehaviour::Create,
|
||||
unmanaged_window_operation_behaviour: OperationBehaviour::Op,
|
||||
resize_delta: 50,
|
||||
focus_follows_mouse: None,
|
||||
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))]
|
||||
pub fn move_container_to_monitor(
|
||||
&mut self,
|
||||
@@ -792,6 +810,8 @@ impl WindowManager {
|
||||
workspace_idx: Option<usize>,
|
||||
follow: bool,
|
||||
) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("moving container");
|
||||
|
||||
let invisible_borders = self.invisible_borders;
|
||||
@@ -835,6 +855,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("moving container");
|
||||
|
||||
let mouse_follows_focus = self.mouse_follows_focus;
|
||||
@@ -879,7 +901,10 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn focus_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("focusing container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let new_idx = workspace
|
||||
@@ -894,6 +919,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn move_container_in_direction(&mut self, direction: OperationDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("moving container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -910,6 +937,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn focus_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("focusing container");
|
||||
let mut maximize_next = false;
|
||||
let mut monocle_next = false;
|
||||
@@ -945,6 +974,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn move_container_in_cycle_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("moving container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -961,6 +992,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn cycle_container_window_in_direction(&mut self, direction: CycleDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("cycling container windows");
|
||||
|
||||
let container = self.focused_container_mut()?;
|
||||
@@ -983,6 +1016,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn add_window_to_container(&mut self, direction: OperationDirection) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("adding window to container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -1019,6 +1054,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn promote_container_to_front(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("promoting container");
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
@@ -1028,6 +1065,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn remove_window_from_container(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
tracing::info!("removing window");
|
||||
|
||||
if self.focused_container()?.windows().len() == 1 {
|
||||
@@ -1100,6 +1139,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn toggle_monocle(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
match workspace.monocle_container() {
|
||||
@@ -1128,6 +1169,8 @@ impl WindowManager {
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn toggle_maximize(&mut self) -> Result<()> {
|
||||
self.handle_unmanaged_window_behaviour()?;
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
match workspace.maximized_window() {
|
||||
|
||||
@@ -334,6 +334,28 @@ impl Workspace {
|
||||
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 {
|
||||
for container in self.containers() {
|
||||
if container.contains_window(hwnd) {
|
||||
|
||||
@@ -256,6 +256,10 @@ WindowHidingBehaviour(hiding_behaviour) {
|
||||
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) {
|
||||
Run, komorebic.exe float-rule %identifier% "%id%", , Hide
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use komorebi_core::CycleDirection;
|
||||
use komorebi_core::DefaultLayout;
|
||||
use komorebi_core::FocusFollowsMouseImplementation;
|
||||
use komorebi_core::HidingBehaviour;
|
||||
use komorebi_core::OperationBehaviour;
|
||||
use komorebi_core::OperationDirection;
|
||||
use komorebi_core::Rect;
|
||||
use komorebi_core::Sizing;
|
||||
@@ -114,6 +115,7 @@ gen_enum_subcommand_args! {
|
||||
MouseFollowsFocus: BooleanState,
|
||||
Query: StateQuery,
|
||||
WindowHidingBehaviour: HidingBehaviour,
|
||||
UnmanagedWindowOperationBehaviour: OperationBehaviour,
|
||||
}
|
||||
|
||||
macro_rules! gen_target_subcommand_args {
|
||||
@@ -622,6 +624,9 @@ enum SubCommand {
|
||||
/// Set the window behaviour when switching workspaces / cycling stacks
|
||||
#[clap(arg_required_else_help = true)]
|
||||
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
|
||||
#[clap(arg_required_else_help = true)]
|
||||
FloatRule(FloatRule),
|
||||
@@ -1162,6 +1167,12 @@ fn main() -> Result<()> {
|
||||
SubCommand::WindowHidingBehaviour(arg) => {
|
||||
send_message(&*SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour).as_bytes()?)?;
|
||||
}
|
||||
SubCommand::UnmanagedWindowOperationBehaviour(arg) => {
|
||||
send_message(
|
||||
&*SocketMessage::UnmanagedWindowOperationBehaviour(arg.operation_behaviour)
|
||||
.as_bytes()?,
|
||||
)?;
|
||||
}
|
||||
SubCommand::AhkAppSpecificConfiguration(arg) => {
|
||||
let content = fs::read_to_string(resolve_windows_path(&arg.path)?)?;
|
||||
let lines = if let Some(override_path) = arg.override_path {
|
||||
|
||||
Reference in New Issue
Block a user