Originally created by @crosstyan on GitHub (Aug 18, 2021).
Originally assigned to: @LGUG2Z on GitHub.
komorebi 0725549d45 will stuck after closing an application identified with identify-tray-application when there's a maximized window (maximized with toggle-maximize) in workspace.
Step to reproduce:
start komorebi and identify an application with identify-tray-application
maximized a window with toggle-maximize
close the application identified as tray application
komorebi is stuck
Suggestion: maybe a maximized window should be treated as a kind of monocle_container, As I described in #12. That is, a maximized window should have the highest priority (like pinned down at the top) as monocle layout.
Here are the logs
Aug 19 05:09:40.694 INFO init: komorebi::window_manager: initialising
Aug 19 05:09:40.728 INFO init:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:40.736 INFO komorebi::process_command: listening
Aug 19 05:09:40.736 INFO komorebi::process_event: listening
Aug 19 05:09:45.007 INFO read_commands:process_command{IdentifyTrayApplication(Exe, "Telegram.exe")}: komorebi::process_command: processed
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_container{idx=2}: komorebi::workspace: focusing container
Aug 19 05:09:52.188 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}: komorebi::process_event: processed: (hwnd: 2490962, title: AutoHotkey64.ahk - Visual Studio Code, exe: Code.exe, class: Chrome_WidgetWin_1)
Aug 19 05:09:52.920 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:maximize_window: komorebi::window_manager: maximizing windowj
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:maximize_window:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}: komorebi::process_command: processed
Aug 19 05:09:54.686 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.686 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:54.687 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:09:54.688 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}: komorebi::process_event: processed: (hwnd: 3346006, title: PowerShell, exe: WindowsTerminal.exe, class: CASCADIA_HOSTING_WINDOW_CLASS)
Aug 19 05:09:54.843 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.846 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:54.877 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.878 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:54.889 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:09:54.891 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}: komorebi::process_event: processed: (hwnd: 3346006, title: PowerShell, exe: WindowsTerminal.exe, class: CASCADIA_HOSTING_WINDOW_CLASS)
Aug 19 05:09:56.357 INFO read_commands:process_command{State}: komorebi::process_command: processed
Aug 19 05:09:56.842 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:56.845 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:57.606 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:57.607 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:57.610 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:57.617 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:09:57.726 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:57.753 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:58.057 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:58.057 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:58.060 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:58.066 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:09:59.335 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:59.335 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}: komorebi::process_event: moving with mouse
Aug 19 05:09:59.336 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:59.336 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:59.337 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:10:00.284 INFO process_event{event=Hide(ObjectHide, Window { hwnd: 3867284 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:10:00.285 INFO process_event{event=Hide(ObjectHide, Window { hwnd: 3867284 })}:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Originally created by @crosstyan on GitHub (Aug 18, 2021).
Originally assigned to: @LGUG2Z on GitHub.
komorebi 0725549d45184530cbff36c95ccefb9290fae9b0 will stuck after closing an application identified with `identify-tray-application` when there's a maximized window (maximized with `toggle-maximize`) in workspace.
Step to reproduce:
1. start komorebi and identify an application with `identify-tray-application`
2. maximized a window with `toggle-maximize`
3. close the application identified as tray application
4. komorebi is stuck

**Suggestion:** maybe a maximized window should be treated as a kind of `monocle_container`, As I described in #12. That is, a maximized window should have the highest priority (like pinned down at the top) as monocle layout.
Here are the logs
```logs
Aug 19 05:09:40.694 INFO init: komorebi::window_manager: initialising
Aug 19 05:09:40.728 INFO init:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:40.736 INFO komorebi::process_command: listening
Aug 19 05:09:40.736 INFO komorebi::process_event: listening
Aug 19 05:09:45.007 INFO read_commands:process_command{IdentifyTrayApplication(Exe, "Telegram.exe")}: komorebi::process_command: processed
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:52.187 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_container{idx=2}: komorebi::workspace: focusing container
Aug 19 05:09:52.188 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}: komorebi::process_event: processed: (hwnd: 2490962, title: AutoHotkey64.ahk - Visual Studio Code, exe: Code.exe, class: Chrome_WidgetWin_1)
Aug 19 05:09:52.920 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:maximize_window: komorebi::window_manager: maximizing windowj
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:maximize_window:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}:toggle_maximize:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:52.937 INFO read_commands:process_command{ToggleMaximize}: komorebi::process_command: processed
Aug 19 05:09:54.686 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.686 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:54.687 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:09:54.688 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}: komorebi::process_event: processed: (hwnd: 3346006, title: PowerShell, exe: WindowsTerminal.exe, class: CASCADIA_HOSTING_WINDOW_CLASS)
Aug 19 05:09:54.843 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.846 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:54.877 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:54.878 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:54.889 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:09:54.891 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3346006 })}: komorebi::process_event: processed: (hwnd: 3346006, title: PowerShell, exe: WindowsTerminal.exe, class: CASCADIA_HOSTING_WINDOW_CLASS)
Aug 19 05:09:56.357 INFO read_commands:process_command{State}: komorebi::process_command: processed
Aug 19 05:09:56.842 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:56.845 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:57.606 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:57.607 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:57.610 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:57.617 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:09:57.726 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 2490962 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:57.753 ERROR komorebi::process_event: there is no container/window
Aug 19 05:09:58.057 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:58.057 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_window{idx=0}: komorebi::container: focusing window
Aug 19 05:09:58.060 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:58.066 INFO process_event{event=FocusChange(SystemForeground, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:09:59.335 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:focus_monitor{idx=0}: komorebi::window_manager: focusing monitor
Aug 19 05:09:59.335 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}: komorebi::process_event: moving with mouse
Aug 19 05:09:59.336 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:focus_container{idx=1}: komorebi::workspace: focusing container
Aug 19 05:09:59.336 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
Aug 19 05:09:59.337 INFO process_event{event=MoveResizeEnd(SystemMoveSizeEnd, Window { hwnd: 3867284 })}: komorebi::process_event: processed: (hwnd: 3867284, title: Telegram (1268225), exe: Telegram.exe, class: Qt5152QWindowIcon)
Aug 19 05:10:00.284 INFO process_event{event=Hide(ObjectHide, Window { hwnd: 3867284 })}:focus_container{idx=0}: komorebi::workspace: focusing container
Aug 19 05:10:00.285 INFO process_event{event=Hide(ObjectHide, Window { hwnd: 3867284 })}:update_focused_workspace{mouse_follows_focus=false}: komorebi::window_manager: updating
```
adam
added the bug label 2026-01-05 14:47:39 +01:00
I'm able to reproduce this; there is no panic, so I think that this is a case of a deadlock with multiple attempts to access one of the same global state holders.
From the logs, it looks like it is probably this call that triggers the deadlock.
I have done a quick grep and I think that this actually doesn't need to be a global static and can be part of the WindowManager struct; I'll try refactoring this tomorrow and see if that helps avoid the deadlock. 🙏
@LGUG2Z commented on GitHub (Aug 19, 2021):
I'm able to reproduce this; there is no panic, so I think that this is a case of a deadlock with multiple attempts to access one of the same [global state holders](https://github.com/LGUG2Z/komorebi/blob/master/komorebi/src/main.rs#L42).
From the logs, it looks like it is probably [this call](https://github.com/LGUG2Z/komorebi/blob/master/komorebi/src/process_event.rs#L103) that triggers the deadlock.
I have done a quick grep and I think that this actually doesn't need to be a global static and can be part of the `WindowManager` struct; I'll try refactoring this tomorrow and see if that helps avoid the deadlock. 🙏
My hunch was right, the lock on HIDDEN_HWNDS is still held by the WindowManagerEvent::Hide ( .. ) handler in process_event.rs, so when window.maximize() gets called in the final part of the same handler, and tries to obtain the same lock, it results in a deadlock which makes komorebi.exe unresponsive.
I was able to track down the deadlock by swapping out std::sync::Mutex with parking_lot::Mutex from the parking_lot crate and running this deadlock detector in a separate thread:
use parking_lot::deadlock;
use std::thread;
use std::time::Duration;
// Create a background thread which checks for deadlocks every 10s
thread::spawn(move || loop {
thread::sleep(Duration::from_secs(2));
let deadlocks = deadlock::check_deadlock();
if deadlocks.is_empty() {
continue;
}
println!("{} deadlocks detected", deadlocks.len());
for (i, threads) in deadlocks.iter().enumerate() {
println!("Deadlock #{}", i);
for t in threads {
println!("Thread Id {:#?}", t.thread_id());
println!("{:#?}", t.backtrace());
}
}
});
}
I'm going to spend some time evaluating whether I should swap out std::sync::Mutex for the implementation in that crate, and seeing if I can ship the deadlock detection in komorebi.exe binaries and have it integrate nicely with the current approach to logging.
@LGUG2Z commented on GitHub (Aug 19, 2021):
My hunch was right, the lock on `HIDDEN_HWNDS` is still held by the `WindowManagerEvent::Hide ( .. )` handler in `process_event.rs`, so when [`window.maximize()`](https://github.com/LGUG2Z/komorebi/blob/master/komorebi/src/window.rs#L134) gets called in the final part of the same handler, and tries to obtain the same lock, it results in a deadlock which makes `komorebi.exe` unresponsive.
I was able to track down the deadlock by swapping out `std::sync::Mutex` with `parking_lot::Mutex` from the `parking_lot` crate and running this deadlock detector in a separate thread:
``` {
use parking_lot::deadlock;
use std::thread;
use std::time::Duration;
// Create a background thread which checks for deadlocks every 10s
thread::spawn(move || loop {
thread::sleep(Duration::from_secs(2));
let deadlocks = deadlock::check_deadlock();
if deadlocks.is_empty() {
continue;
}
println!("{} deadlocks detected", deadlocks.len());
for (i, threads) in deadlocks.iter().enumerate() {
println!("Deadlock #{}", i);
for t in threads {
println!("Thread Id {:#?}", t.thread_id());
println!("{:#?}", t.backtrace());
}
}
});
}
```
I'm going to spend some time evaluating whether I should swap out `std::sync::Mutex` for the implementation in that crate, and seeing if I can ship the deadlock detection in `komorebi.exe` binaries and have it integrate nicely with the current approach to logging.
@crosstyan Try building from https://github.com/LGUG2Z/komorebi/tree/hotfix/hidden-hwnds-deadlock with cargo install --locked --path komorebi --features deadlock_detection - I have tried reproducing the issue above a number of times on this commit and so far I haven't seen the issue again. 🤞
@LGUG2Z commented on GitHub (Aug 19, 2021):
@crosstyan Try building from https://github.com/LGUG2Z/komorebi/tree/hotfix/hidden-hwnds-deadlock with `cargo install --locked --path komorebi --features deadlock_detection` - I have tried reproducing the issue above a number of times on this commit and so far I haven't seen the issue again. 🤞
@LGUG2Z By the way, is it intended to differentiate toggle-monocle from toggle-maximize by allowing window to pop up on a maximized window in toggle-maximize? I'm satisfied with the result but I wonder how you design these things.
@crosstyan commented on GitHub (Aug 19, 2021):
@LGUG2Z By the way, is it intended to differentiate `toggle-monocle` from `toggle-maximize` by allowing window to pop up on a maximized window in `toggle-maximize`? I'm satisfied with the result but I wonder how you design these things.
@crosstyan for toggle-maximize and anything else that links in to native Windows functionality, I just aim to respect as much as possible the native system behaviour.
@LGUG2Z commented on GitHub (Aug 19, 2021):
@crosstyan for `toggle-maximize` and anything else that links in to native Windows functionality, I just aim to respect as much as possible the native system behaviour.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @crosstyan on GitHub (Aug 18, 2021).
Originally assigned to: @LGUG2Z on GitHub.
komorebi
0725549d45will stuck after closing an application identified withidentify-tray-applicationwhen there's a maximized window (maximized withtoggle-maximize) in workspace.Step to reproduce:
identify-tray-applicationtoggle-maximizeSuggestion: maybe a maximized window should be treated as a kind of
monocle_container, As I described in #12. That is, a maximized window should have the highest priority (like pinned down at the top) as monocle layout.Here are the logs
@LGUG2Z commented on GitHub (Aug 19, 2021):
I'm able to reproduce this; there is no panic, so I think that this is a case of a deadlock with multiple attempts to access one of the same global state holders.
From the logs, it looks like it is probably this call that triggers the deadlock.
I have done a quick grep and I think that this actually doesn't need to be a global static and can be part of the
WindowManagerstruct; I'll try refactoring this tomorrow and see if that helps avoid the deadlock. 🙏@LGUG2Z commented on GitHub (Aug 19, 2021):
My hunch was right, the lock on
HIDDEN_HWNDSis still held by theWindowManagerEvent::Hide ( .. )handler inprocess_event.rs, so whenwindow.maximize()gets called in the final part of the same handler, and tries to obtain the same lock, it results in a deadlock which makeskomorebi.exeunresponsive.I was able to track down the deadlock by swapping out
std::sync::Mutexwithparking_lot::Mutexfrom theparking_lotcrate and running this deadlock detector in a separate thread:I'm going to spend some time evaluating whether I should swap out
std::sync::Mutexfor the implementation in that crate, and seeing if I can ship the deadlock detection inkomorebi.exebinaries and have it integrate nicely with the current approach to logging.@LGUG2Z commented on GitHub (Aug 19, 2021):
@crosstyan Try building from https://github.com/LGUG2Z/komorebi/tree/hotfix/hidden-hwnds-deadlock with
cargo install --locked --path komorebi --features deadlock_detection- I have tried reproducing the issue above a number of times on this commit and so far I haven't seen the issue again. 🤞@crosstyan commented on GitHub (Aug 19, 2021):
Looks good to me! That's really fast!
@crosstyan commented on GitHub (Aug 19, 2021):
@LGUG2Z By the way, is it intended to differentiate
toggle-monoclefromtoggle-maximizeby allowing window to pop up on a maximized window intoggle-maximize? I'm satisfied with the result but I wonder how you design these things.@LGUG2Z commented on GitHub (Aug 19, 2021):
@crosstyan for
toggle-maximizeand anything else that links in to native Windows functionality, I just aim to respect as much as possible the native system behaviour.