mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-24 01:28:39 +02:00
feat(wm): add focus follows mouse toggle
This commit is contained in:
52
README.md
52
README.md
@@ -6,26 +6,26 @@ Tiling Window Management for Windows.
|
|||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
*komorebi* is a tiling window manager that works as an extension to
|
_komorebi_ is a tiling window manager that works as an extension to
|
||||||
Microsoft's [Desktop Window Manager](https://docs.microsoft.com/en-us/windows/win32/dwm/dwm-overview) in Windows 10 and
|
Microsoft's [Desktop Window Manager](https://docs.microsoft.com/en-us/windows/win32/dwm/dwm-overview) in Windows 10 and
|
||||||
above.
|
above.
|
||||||
|
|
||||||
*komorebi* allows you to control application windows, virtual workspaces and display monitors with a CLI which can be used
|
_komorebi_ allows you to control application windows, virtual workspaces and display monitors with a CLI which can be used
|
||||||
with third-party software such as [AutoHotKey](https://github.com/Lexikos/AutoHotkey_L) to set user-defined keyboard
|
with third-party software such as [AutoHotKey](https://github.com/Lexikos/AutoHotkey_L) to set user-defined keyboard
|
||||||
shortcuts.
|
shortcuts.
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
*komorebi* only responds to [WinEvents](https://docs.microsoft.com/en-us/windows/win32/winauto/event-constants) and the
|
_komorebi_ only responds to [WinEvents](https://docs.microsoft.com/en-us/windows/win32/winauto/event-constants) and the
|
||||||
messages it receives on a dedicated socket.
|
messages it receives on a dedicated socket.
|
||||||
|
|
||||||
*komorebic* is a CLI that writes messages on *komorebi*'s socket.
|
_komorebic_ is a CLI that writes messages on _komorebi_'s socket.
|
||||||
|
|
||||||
*komorebi* doesn't handle any keyboard or mouse inputs; a third party program (e.g. AutoHotKey) is needed in order to
|
_komorebi_ doesn't handle any keyboard or mouse inputs; a third party program (e.g. AutoHotKey) is needed in order to
|
||||||
translate keyboard and mouse events to *komorebic* commands.
|
translate keyboard and mouse events to _komorebic_ commands.
|
||||||
|
|
||||||
This architecture, popularised by [*bspwm*](https://github.com/baskerville/bspwm) on Linux and
|
This architecture, popularised by [_bspwm_](https://github.com/baskerville/bspwm) on Linux and
|
||||||
[*yabai*](https://github.com/koekeishiya/yabai) on macOS, is outlined as follows:
|
[_yabai_](https://github.com/koekeishiya/yabai) on macOS, is outlined as follows:
|
||||||
|
|
||||||
```
|
```
|
||||||
PROCESS SOCKET
|
PROCESS SOCKET
|
||||||
@@ -34,15 +34,15 @@ ahk --------> komorebic <------> komorebi
|
|||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
*komorebi* is the successor to [*yatta*](https://github.com/LGUG2Z/yatta) and as such aims to build on the learnings
|
_komorebi_ is the successor to [_yatta_](https://github.com/LGUG2Z/yatta) and as such aims to build on the learnings
|
||||||
from that project.
|
from that project.
|
||||||
|
|
||||||
While *yatta* was primary an attempt to learn how to work with and call Windows APIs from Rust, while secondarily
|
While _yatta_ was primary an attempt to learn how to work with and call Windows APIs from Rust, while secondarily
|
||||||
implementing a minimal viable tiling window manager for my own needs (largely single monitor, single workspace),
|
implementing a minimal viable tiling window manager for my own needs (largely single monitor, single workspace),
|
||||||
*komorebi* has been redesigned from the ground-up to support more complex features that have become standard in tiling
|
_komorebi_ has been redesigned from the ground-up to support more complex features that have become standard in tiling
|
||||||
window managers on other platforms.
|
window managers on other platforms.
|
||||||
|
|
||||||
*komorebi* holds a list of physical monitors.
|
_komorebi_ holds a list of physical monitors.
|
||||||
|
|
||||||
A monitor is just a rectangle of the available work area which contains one or more virtual workspaces.
|
A monitor is just a rectangle of the available work area which contains one or more virtual workspaces.
|
||||||
|
|
||||||
@@ -52,16 +52,16 @@ A container is just a rectangle where one or more application windows can be dis
|
|||||||
|
|
||||||
This means that:
|
This means that:
|
||||||
|
|
||||||
* Every monitor has its own collection of virtual workspaces
|
- Every monitor has its own collection of virtual workspaces
|
||||||
* Workspaces only know about containers and their dimensions, not about individual application windows
|
- Workspaces only know about containers and their dimensions, not about individual application windows
|
||||||
* Every application window must belong to a container, even if that container only contains one application window
|
- Every application window must belong to a container, even if that container only contains one application window
|
||||||
* Many application windows can be stacked and cycled through in the same container within a workspace
|
- Many application windows can be stacked and cycled through in the same container within a workspace
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
This project is still heavily under development and there are no prebuilt binaries available yet.
|
This project is still heavily under development and there are no prebuilt binaries available yet.
|
||||||
|
|
||||||
If you would like to use *komorebi*, you will need
|
If you would like to use _komorebi_, you will need
|
||||||
a [working Rust development environment on Windows 10](https://rustup.rs/). If you are using
|
a [working Rust development environment on Windows 10](https://rustup.rs/). If you are using
|
||||||
the `x86_64-pc-windows-msvc` toolchain, make sure you have also installed
|
the `x86_64-pc-windows-msvc` toolchain, make sure you have also installed
|
||||||
the [Build Tools for Visual Studio 2019](https://stackoverflow.com/a/55603112).
|
the [Build Tools for Visual Studio 2019](https://stackoverflow.com/a/55603112).
|
||||||
@@ -100,6 +100,7 @@ sample [komorebi.ahk](komorebi.sample.ahk) AHK script that you can use as a star
|
|||||||
- [x] Move focused window container in direction
|
- [x] Move focused window container in direction
|
||||||
- [x] Move focused window container to monitor
|
- [x] Move focused window container to monitor
|
||||||
- [x] Move focused window container to workspace
|
- [x] Move focused window container to workspace
|
||||||
|
- [x] Mouse follows focused container
|
||||||
- [x] Resize window container in direction
|
- [x] Resize window container in direction
|
||||||
- [ ] Resize child window containers by split ratio
|
- [ ] Resize child window containers by split ratio
|
||||||
- [x] Mouse drag to swap window container position
|
- [x] Mouse drag to swap window container position
|
||||||
@@ -113,6 +114,7 @@ sample [komorebi.ahk](komorebi.sample.ahk) AHK script that you can use as a star
|
|||||||
- [x] Floating rules based on window class
|
- [x] Floating rules based on window class
|
||||||
- [x] Toggle floating windows
|
- [x] Toggle floating windows
|
||||||
- [x] Toggle monocle window
|
- [x] Toggle monocle window
|
||||||
|
- [x] Toggle focus follows mouse
|
||||||
- [x] Pause all window management
|
- [x] Pause all window management
|
||||||
- [x] View window manager state
|
- [x] View window manager state
|
||||||
|
|
||||||
@@ -121,15 +123,15 @@ sample [komorebi.ahk](komorebi.sample.ahk) AHK script that you can use as a star
|
|||||||
If you would like to contribute code to this repository, there are a few requests that I have to ensure a foundation of
|
If you would like to contribute code to this repository, there are a few requests that I have to ensure a foundation of
|
||||||
code quality, consistency and commit hygiene:
|
code quality, consistency and commit hygiene:
|
||||||
|
|
||||||
* Flatten all `use` statements except in `bindings/build.rs`
|
- Flatten all `use` statements except in `bindings/build.rs`
|
||||||
* Run `cargo +nightly clippy` and ensure that all lints and suggestions have been addressed before committing
|
- Run `cargo +nightly clippy` and ensure that all lints and suggestions have been addressed before committing
|
||||||
* Run `cargo +nightly fmt --all` to ensure consistent formatting before committing
|
- Run `cargo +nightly fmt --all` to ensure consistent formatting before committing
|
||||||
* Use `git cz` with
|
- Use `git cz` with
|
||||||
the [Commitizen CLI](https://github.com/commitizen/cz-cli#conventional-commit-messages-as-a-global-utility) to prepare
|
the [Commitizen CLI](https://github.com/commitizen/cz-cli#conventional-commit-messages-as-a-global-utility) to prepare
|
||||||
commit messages
|
commit messages
|
||||||
* Provide at least one short sentence or paragraph in your commit message body to describe your thought process for the
|
- Provide at least one short sentence or paragraph in your commit message body to describe your thought process for the
|
||||||
changes being committed
|
changes being committed
|
||||||
|
|
||||||
## Logs and Debugging
|
## Logs and Debugging
|
||||||
|
|
||||||
Logs from `komorebi` will be appended to `~/komorebi.log`; this file is never rotated or overwritten, so it will keep
|
Logs from `komorebi` will be appended to `~/komorebi.log`; this file is never rotated or overwritten, so it will keep
|
||||||
@@ -261,7 +263,7 @@ like [Stackline](https://github.com/AdamWagner/stackline) for Windows, you could
|
|||||||
"layout_flip": null,
|
"layout_flip": null,
|
||||||
"workspace_padding": 10,
|
"workspace_padding": 10,
|
||||||
"container_padding": 10
|
"container_padding": 10
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
"focused": 0
|
"focused": 0
|
||||||
}
|
}
|
||||||
@@ -271,4 +273,4 @@ like [Stackline](https://github.com/AdamWagner/stackline) for Windows, you could
|
|||||||
},
|
},
|
||||||
"is_paused": false
|
"is_paused": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ pub enum SocketMessage {
|
|||||||
FloatExe(String),
|
FloatExe(String),
|
||||||
FloatTitle(String),
|
FloatTitle(String),
|
||||||
State,
|
State,
|
||||||
|
FocusFollowsMouse(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SocketMessage {
|
impl SocketMessage {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
; Enable focus follows mouse
|
||||||
|
Run, komorebic.exe focus-follows-mouse enable
|
||||||
|
|
||||||
; Ensure there are 3 workspaces created on monitor 0
|
; Ensure there are 3 workspaces created on monitor 0
|
||||||
Run, komorebic.exe ensure-workspaces 0 4
|
Run, komorebic.exe ensure-workspaces 0 4
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use uds_windows::UnixStream;
|
|||||||
use komorebi_core::SocketMessage;
|
use komorebi_core::SocketMessage;
|
||||||
|
|
||||||
use crate::window_manager::WindowManager;
|
use crate::window_manager::WindowManager;
|
||||||
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::FLOAT_CLASSES;
|
use crate::FLOAT_CLASSES;
|
||||||
use crate::FLOAT_EXES;
|
use crate::FLOAT_EXES;
|
||||||
use crate::FLOAT_TITLES;
|
use crate::FLOAT_TITLES;
|
||||||
@@ -153,6 +154,13 @@ impl WindowManager {
|
|||||||
SocketMessage::ResizeWindow(direction, sizing) => {
|
SocketMessage::ResizeWindow(direction, sizing) => {
|
||||||
self.resize_window(direction, sizing, Option::from(50))?;
|
self.resize_window(direction, sizing, Option::from(50))?;
|
||||||
}
|
}
|
||||||
|
SocketMessage::FocusFollowsMouse(enable) => {
|
||||||
|
if enable {
|
||||||
|
WindowsApi::enable_focus_follows_mouse()?;
|
||||||
|
} else {
|
||||||
|
WindowsApi::disable_focus_follows_mouse()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::info!("processed");
|
tracing::info!("processed");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
use color_eyre::eyre::ContextCompat;
|
use color_eyre::eyre::ContextCompat;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
@@ -56,6 +57,7 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
|
|||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::ShowWindow;
|
||||||
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
||||||
@@ -63,8 +65,12 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_NOTOPMOST;
|
|||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_TOPMOST;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_TOPMOST;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD;
|
||||||
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SPIF_SENDCHANGE;
|
||||||
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SPI_SETACTIVEWINDOWTRACKING;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_HIDE;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_RESTORE;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_RESTORE;
|
||||||
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
|
||||||
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
||||||
use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
|
use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
|
||||||
use komorebi_core::Rect;
|
use komorebi_core::Rect;
|
||||||
@@ -519,4 +525,33 @@ impl WindowsApi {
|
|||||||
monitor_info.rcWork.into(),
|
monitor_info.rcWork.into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn system_parameters_info_w(
|
||||||
|
action: SYSTEM_PARAMETERS_INFO_ACTION,
|
||||||
|
ui_param: u32,
|
||||||
|
pv_param: *mut c_void,
|
||||||
|
update_flags: SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS,
|
||||||
|
) -> Result<()> {
|
||||||
|
Result::from(WindowsResult::from(unsafe {
|
||||||
|
SystemParametersInfoW(action, ui_param, pv_param, update_flags)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_focus_follows_mouse() -> Result<()> {
|
||||||
|
Self::system_parameters_info_w(
|
||||||
|
SPI_SETACTIVEWINDOWTRACKING,
|
||||||
|
0,
|
||||||
|
1 as *mut c_void,
|
||||||
|
SPIF_SENDCHANGE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_focus_follows_mouse() -> Result<()> {
|
||||||
|
Self::system_parameters_info_w(
|
||||||
|
SPI_SETACTIVEWINDOWTRACKING,
|
||||||
|
0,
|
||||||
|
std::ptr::null_mut::<c_void>(),
|
||||||
|
SPIF_SENDCHANGE,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ enum SubCommand {
|
|||||||
AdjustContainerPadding(SizingAdjustment),
|
AdjustContainerPadding(SizingAdjustment),
|
||||||
AdjustWorkspacePadding(SizingAdjustment),
|
AdjustWorkspacePadding(SizingAdjustment),
|
||||||
FlipLayout(LayoutFlip),
|
FlipLayout(LayoutFlip),
|
||||||
|
FocusFollowsMouse(BooleanState),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clap)]
|
#[derive(Clap)]
|
||||||
@@ -111,6 +112,12 @@ struct Resize {
|
|||||||
sizing: Sizing,
|
sizing: Sizing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clap)]
|
||||||
|
enum BooleanState {
|
||||||
|
Enable,
|
||||||
|
Disable,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_message(bytes: &[u8]) -> Result<()> {
|
pub fn send_message(bytes: &[u8]) -> Result<()> {
|
||||||
let mut socket = dirs::home_dir().context("there is no home directory")?;
|
let mut socket = dirs::home_dir().context("there is no home directory")?;
|
||||||
socket.push("komorebi.sock");
|
socket.push("komorebi.sock");
|
||||||
@@ -322,6 +329,15 @@ fn main() -> Result<()> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
send_message(&*bytes)?;
|
send_message(&*bytes)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::FocusFollowsMouse(enable) => {
|
||||||
|
let enable = match enable {
|
||||||
|
BooleanState::Enable => true,
|
||||||
|
BooleanState::Disable => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = SocketMessage::FocusFollowsMouse(enable).as_bytes().unwrap();
|
||||||
|
send_message(&*bytes)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user