mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-08 22:15:14 +02:00
feat(wm): make invisible borders configurable
Following the changes I witnessed in the invisible window border size following an OS update, this commit makes the invisible border offset configurable via a new komorebic command 'invisible-borders'. When sending a new set of invisible border offset dimensions via komorebic, a full retile across all monitors will take place after the new values have been set. The default values have been set to what is currently correct for my machine, and will likely be updated again in the same way in the future if further changes occur in subsequent OS updates. This commit also updates some dependencies to their latest releases, and removes from the CI workflow a line that attempts to delete the rustup-init.exe binary after installation which has been causing builds to fail. resolve #35
This commit is contained in:
@@ -66,7 +66,6 @@ jobs:
|
|||||||
$ProgressPreference = "SilentlyContinue"
|
$ProgressPreference = "SilentlyContinue"
|
||||||
Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe
|
Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe
|
||||||
.\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --profile=minimal
|
.\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --profile=minimal
|
||||||
del rustup-init.exe
|
|
||||||
shell: powershell
|
shell: powershell
|
||||||
- name: Ensure stable toolchain is up to date
|
- name: Ensure stable toolchain is up to date
|
||||||
run: rustup update stable
|
run: rustup update stable
|
||||||
|
|||||||
Generated
+10
-10
@@ -1101,9 +1101,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.67"
|
version = "1.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
|
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -1244,9 +1244,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.26"
|
version = "0.1.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
|
checksum = "c2ba9ab62b7d6497a8638dfda5e5c4fb3b2d5a7fca4118f2b96151c8ef1a437e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1267,9 +1267,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.15"
|
version = "0.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
|
checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1278,9 +1278,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.19"
|
version = "0.1.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8"
|
checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
@@ -1318,9 +1318,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.2.20"
|
version = "0.2.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9cbe87a2fa7e35900ce5de20220a582a9483a7063811defce79d7cbd59d4cfe"
|
checksum = "62af966210b88ad5776ee3ba12d5f35b8d6a2b2a12168f3080cf02b814d7376b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ send-to-workspace Send the focused window to the specified workspace
|
|||||||
focus-monitor Focus the specified monitor
|
focus-monitor Focus the specified monitor
|
||||||
focus-workspace Focus the specified workspace on the focused monitor
|
focus-workspace Focus the specified workspace on the focused monitor
|
||||||
new-workspace Create and append a new workspace on the focused monitor
|
new-workspace Create and append a new workspace on the focused monitor
|
||||||
|
invisible-borders Set the invisible border dimensions around each window
|
||||||
adjust-container-padding Adjust container padding on the focused workspace
|
adjust-container-padding Adjust container padding on the focused workspace
|
||||||
adjust-workspace-padding Adjust workspace padding on the focused workspace
|
adjust-workspace-padding Adjust workspace padding on the focused workspace
|
||||||
change-layout Set the layout on the focused workspace
|
change-layout Set the layout on the focused workspace
|
||||||
@@ -277,6 +278,7 @@ used [is available here](komorebi.sample.with.lib.ahk).
|
|||||||
- [x] Additional manage rules based on exe name and window class
|
- [x] Additional manage rules based on exe name and window class
|
||||||
- [x] Identify applications which overflow their borders by exe name and class
|
- [x] Identify applications which overflow their borders by exe name and class
|
||||||
- [x] Identify 'close/minimize to tray' applications by exe name and class
|
- [x] Identify 'close/minimize to tray' applications by exe name and class
|
||||||
|
- [x] Configure and compensate for the size of Windows 10's invisible borders
|
||||||
- [x] Toggle floating windows
|
- [x] Toggle floating windows
|
||||||
- [x] Toggle monocle window
|
- [x] Toggle monocle window
|
||||||
- [x] Toggle native maximization
|
- [x] Toggle native maximization
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ pub enum SocketMessage {
|
|||||||
// Configuration
|
// Configuration
|
||||||
ReloadConfiguration,
|
ReloadConfiguration,
|
||||||
WatchConfiguration(bool),
|
WatchConfiguration(bool),
|
||||||
|
InvisibleBorders(Rect),
|
||||||
WorkspaceRule(ApplicationIdentifier, String, usize, usize),
|
WorkspaceRule(ApplicationIdentifier, String, usize, usize),
|
||||||
FloatRule(ApplicationIdentifier, String),
|
FloatRule(ApplicationIdentifier, String),
|
||||||
ManageRule(ApplicationIdentifier, String),
|
ManageRule(ApplicationIdentifier, String),
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use bindings::Windows::Win32::Foundation::RECT;
|
use bindings::Windows::Win32::Foundation::RECT;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Serialize, Eq, PartialEq)]
|
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
pub left: i32,
|
pub left: i32,
|
||||||
pub top: i32,
|
pub top: i32,
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
; Enable hot reloading of changes to this file
|
; Enable hot reloading of changes to this file
|
||||||
Run, komorebic.exe watch-configuration enable, , Hide
|
Run, komorebic.exe watch-configuration enable, , Hide
|
||||||
|
|
||||||
|
; Configure the invisible border dimensions
|
||||||
|
Run, komorebic.exe invisible-borders 7 0 14 7, , Hide
|
||||||
|
|
||||||
; Enable focus follows mouse
|
; Enable focus follows mouse
|
||||||
Run, komorebic.exe focus-follows-mouse enable, , Hide
|
Run, komorebic.exe focus-follows-mouse enable, , Hide
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ WatchConfiguration("enable")
|
|||||||
; Ensure there are 5 workspaces created on monitor 0
|
; Ensure there are 5 workspaces created on monitor 0
|
||||||
EnsureWorkspaces(0, 5)
|
EnsureWorkspaces(0, 5)
|
||||||
|
|
||||||
|
; Configure the invisible border dimensions
|
||||||
|
InvisibleBorders(7, 0, 14, 7)
|
||||||
|
|
||||||
; Configure the 1st workspace
|
; Configure the 1st workspace
|
||||||
WorkspaceName(0, 0, "bsp")
|
WorkspaceName(0, 0, "bsp")
|
||||||
|
|
||||||
|
|||||||
@@ -145,12 +145,12 @@ impl Monitor {
|
|||||||
self.workspaces().len()
|
self.workspaces().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_focused_workspace(&mut self) -> Result<()> {
|
pub fn update_focused_workspace(&mut self, invisible_borders: &Rect) -> Result<()> {
|
||||||
let work_area = *self.work_area_size();
|
let work_area = *self.work_area_size();
|
||||||
|
|
||||||
self.focused_workspace_mut()
|
self.focused_workspace_mut()
|
||||||
.ok_or_else(|| anyhow!("there is no workspace"))?
|
.ok_or_else(|| anyhow!("there is no workspace"))?
|
||||||
.update(&work_area)?;
|
.update(&work_area, invisible_borders)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,21 +124,7 @@ impl WindowManager {
|
|||||||
self.focus_monitor(monitor_idx)?;
|
self.focus_monitor(monitor_idx)?;
|
||||||
self.update_focused_workspace(true)?;
|
self.update_focused_workspace(true)?;
|
||||||
}
|
}
|
||||||
SocketMessage::Retile => {
|
SocketMessage::Retile => self.retile_all()?,
|
||||||
for monitor in self.monitors_mut() {
|
|
||||||
let work_area = *monitor.work_area_size();
|
|
||||||
let workspace = monitor
|
|
||||||
.focused_workspace_mut()
|
|
||||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
|
||||||
|
|
||||||
// Reset any resize adjustments if we want to force a retile
|
|
||||||
for resize in workspace.resize_dimensions_mut() {
|
|
||||||
*resize = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace.update(&work_area)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?,
|
SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?,
|
||||||
SocketMessage::ChangeLayout(layout) => self.change_workspace_layout(layout)?,
|
SocketMessage::ChangeLayout(layout) => self.change_workspace_layout(layout)?,
|
||||||
SocketMessage::WorkspaceTiling(monitor_idx, workspace_idx, tile) => {
|
SocketMessage::WorkspaceTiling(monitor_idx, workspace_idx, tile) => {
|
||||||
@@ -312,7 +298,11 @@ impl WindowManager {
|
|||||||
SocketMessage::UnmanageFocusedWindow => {
|
SocketMessage::UnmanageFocusedWindow => {
|
||||||
self.unmanage_focused_window()?;
|
self.unmanage_focused_window()?;
|
||||||
}
|
}
|
||||||
}
|
SocketMessage::InvisibleBorders(rect) => {
|
||||||
|
self.invisible_borders = rect;
|
||||||
|
self.retile_all()?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
tracing::info!("processed");
|
tracing::info!("processed");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -64,12 +64,14 @@ impl WindowManager {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let invisible_borders = self.invisible_borders;
|
||||||
|
|
||||||
for (i, monitor) in self.monitors_mut().iter_mut().enumerate() {
|
for (i, monitor) in self.monitors_mut().iter_mut().enumerate() {
|
||||||
let work_area = *monitor.work_area_size();
|
let work_area = *monitor.work_area_size();
|
||||||
for (j, workspace) in monitor.workspaces_mut().iter_mut().enumerate() {
|
for (j, workspace) in monitor.workspaces_mut().iter_mut().enumerate() {
|
||||||
let reaped_orphans = workspace.reap_orphans()?;
|
let reaped_orphans = workspace.reap_orphans()?;
|
||||||
if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 {
|
if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 {
|
||||||
workspace.update(&work_area)?;
|
workspace.update(&work_area, &invisible_borders)?;
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}",
|
"reaped {} orphan window(s) and {} orphaned container(s) on monitor: {}, workspace: {}",
|
||||||
reaped_orphans.0,
|
reaped_orphans.0,
|
||||||
@@ -218,19 +220,11 @@ impl WindowManager {
|
|||||||
.ok_or_else(|| anyhow!("there is no latest layout"))?;
|
.ok_or_else(|| anyhow!("there is no latest layout"))?;
|
||||||
let mut new_position = WindowsApi::window_rect(window.hwnd())?;
|
let mut new_position = WindowsApi::window_rect(window.hwnd())?;
|
||||||
|
|
||||||
// See Window.set_position() in window.rs for comments
|
// Adjust for the invisible borders
|
||||||
let border = Rect {
|
new_position.left += invisible_borders.left;
|
||||||
left: 12,
|
new_position.top += invisible_borders.top;
|
||||||
top: 0,
|
new_position.right -= invisible_borders.right;
|
||||||
right: 24,
|
new_position.bottom -= invisible_borders.bottom;
|
||||||
bottom: 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Adjust for the invisible border
|
|
||||||
new_position.left += border.left;
|
|
||||||
new_position.top += border.top;
|
|
||||||
new_position.right -= border.right;
|
|
||||||
new_position.bottom -= border.bottom;
|
|
||||||
|
|
||||||
let resize = Rect {
|
let resize = Rect {
|
||||||
left: new_position.left - old_position.left,
|
left: new_position.left - old_position.left,
|
||||||
@@ -295,7 +289,7 @@ impl WindowManager {
|
|||||||
|
|
||||||
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows
|
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows
|
||||||
if let WindowManagerEvent::Unmanage(window) = event {
|
if let WindowManagerEvent::Unmanage(window) = event {
|
||||||
window.center(&self.focused_monitor_work_area()?)?;
|
window.center(&self.focused_monitor_work_area()?, &invisible_borders)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::trace!("updating list of known hwnds");
|
tracing::trace!("updating list of known hwnds");
|
||||||
|
|||||||
+13
-35
@@ -71,7 +71,7 @@ impl Window {
|
|||||||
HWND(self.hwnd)
|
HWND(self.hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn center(&mut self, work_area: &Rect) -> Result<()> {
|
pub fn center(&mut self, work_area: &Rect, invisible_borders: &Rect) -> Result<()> {
|
||||||
let half_width = work_area.right / 2;
|
let half_width = work_area.right / 2;
|
||||||
let half_weight = work_area.bottom / 2;
|
let half_weight = work_area.bottom / 2;
|
||||||
|
|
||||||
@@ -82,33 +82,18 @@ impl Window {
|
|||||||
right: half_width,
|
right: half_width,
|
||||||
bottom: half_weight,
|
bottom: half_weight,
|
||||||
},
|
},
|
||||||
|
invisible_borders,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_position(&mut self, layout: &Rect, top: bool) -> Result<()> {
|
pub fn set_position(
|
||||||
// NOTE: This is how the border variable below was calculated; every time this code was
|
&mut self,
|
||||||
// run on any window in any position, the generated border was always the same, so I am
|
layout: &Rect,
|
||||||
// hard coding the border Rect to avoid two calls to set_window_pos and making the screen
|
invisible_borders: &Rect,
|
||||||
// flicker on container/window movement. Still not 100% sure if this is DPI-aware.
|
top: bool,
|
||||||
|
) -> Result<()> {
|
||||||
// Set the new position first to be able to get the extended frame bounds
|
|
||||||
// WindowsApi::set_window_pos(self.hwnd(), layout, false, false)?;
|
|
||||||
// let mut rect = WindowsApi::window_rect(self.hwnd())?;
|
|
||||||
|
|
||||||
// Get the extended frame bounds of the new position
|
|
||||||
// let frame = WindowsApi::window_rect_with_extended_frame_bounds(self.hwnd())?;
|
|
||||||
|
|
||||||
// Calculate the invisible border diff
|
|
||||||
// let border = Rect {
|
|
||||||
// left: frame.left - rect.left,
|
|
||||||
// top: frame.top - rect.top,
|
|
||||||
// right: rect.right - frame.right,
|
|
||||||
// bottom: rect.bottom - frame.bottom,
|
|
||||||
// };
|
|
||||||
|
|
||||||
let mut rect = *layout;
|
let mut rect = *layout;
|
||||||
|
|
||||||
let mut should_remove_border = true;
|
let mut should_remove_border = true;
|
||||||
|
|
||||||
let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock();
|
let border_overflows = BORDER_OVERFLOW_IDENTIFIERS.lock();
|
||||||
@@ -120,18 +105,11 @@ impl Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if should_remove_border {
|
if should_remove_border {
|
||||||
let border = Rect {
|
// Remove the invisible borders
|
||||||
left: 12,
|
rect.left -= invisible_borders.left;
|
||||||
top: 0,
|
rect.top -= invisible_borders.top;
|
||||||
right: 24,
|
rect.right += invisible_borders.right;
|
||||||
bottom: 12,
|
rect.bottom += invisible_borders.bottom;
|
||||||
};
|
|
||||||
|
|
||||||
// Remove the invisible border
|
|
||||||
rect.left -= border.left;
|
|
||||||
rect.top -= border.top;
|
|
||||||
rect.right += border.right;
|
|
||||||
rect.bottom += border.bottom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowsApi::position_window(self.hwnd(), &rect, top)
|
WindowsApi::position_window(self.hwnd(), &rect, top)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ pub struct WindowManager {
|
|||||||
pub incoming_events: Arc<Mutex<Receiver<WindowManagerEvent>>>,
|
pub incoming_events: Arc<Mutex<Receiver<WindowManagerEvent>>>,
|
||||||
pub command_listener: UnixListener,
|
pub command_listener: UnixListener,
|
||||||
pub is_paused: bool,
|
pub is_paused: bool,
|
||||||
|
pub invisible_borders: Rect,
|
||||||
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
||||||
pub hotwatch: Hotwatch,
|
pub hotwatch: Hotwatch,
|
||||||
pub virtual_desktop_id: Option<usize>,
|
pub virtual_desktop_id: Option<usize>,
|
||||||
@@ -55,6 +56,7 @@ pub struct WindowManager {
|
|||||||
pub struct State {
|
pub struct State {
|
||||||
pub monitors: Ring<Monitor>,
|
pub monitors: Ring<Monitor>,
|
||||||
pub is_paused: bool,
|
pub is_paused: bool,
|
||||||
|
pub invisible_borders: Rect,
|
||||||
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
pub focus_follows_mouse: Option<FocusFollowsMouseImplementation>,
|
||||||
pub has_pending_raise_op: bool,
|
pub has_pending_raise_op: bool,
|
||||||
pub float_identifiers: Vec<String>,
|
pub float_identifiers: Vec<String>,
|
||||||
@@ -70,6 +72,7 @@ impl From<&mut WindowManager> for State {
|
|||||||
Self {
|
Self {
|
||||||
monitors: wm.monitors.clone(),
|
monitors: wm.monitors.clone(),
|
||||||
is_paused: wm.is_paused,
|
is_paused: wm.is_paused,
|
||||||
|
invisible_borders: wm.invisible_borders,
|
||||||
focus_follows_mouse: wm.focus_follows_mouse.clone(),
|
focus_follows_mouse: wm.focus_follows_mouse.clone(),
|
||||||
has_pending_raise_op: wm.has_pending_raise_op,
|
has_pending_raise_op: wm.has_pending_raise_op,
|
||||||
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(),
|
||||||
@@ -135,6 +138,12 @@ impl WindowManager {
|
|||||||
incoming_events: incoming,
|
incoming_events: incoming,
|
||||||
command_listener: listener,
|
command_listener: listener,
|
||||||
is_paused: false,
|
is_paused: false,
|
||||||
|
invisible_borders: Rect {
|
||||||
|
left: 7,
|
||||||
|
top: 0,
|
||||||
|
right: 14,
|
||||||
|
bottom: 7,
|
||||||
|
},
|
||||||
focus_follows_mouse: None,
|
focus_follows_mouse: None,
|
||||||
hotwatch: Hotwatch::new()?,
|
hotwatch: Hotwatch::new()?,
|
||||||
virtual_desktop_id,
|
virtual_desktop_id,
|
||||||
@@ -379,6 +388,26 @@ impl WindowManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
|
pub fn retile_all(&mut self) -> Result<()> {
|
||||||
|
let invisible_borders = self.invisible_borders;
|
||||||
|
for monitor in self.monitors_mut() {
|
||||||
|
let work_area = *monitor.work_area_size();
|
||||||
|
let workspace = monitor
|
||||||
|
.focused_workspace_mut()
|
||||||
|
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||||
|
|
||||||
|
// Reset any resize adjustments if we want to force a retile
|
||||||
|
for resize in workspace.resize_dimensions_mut() {
|
||||||
|
*resize = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace.update(&work_area, &invisible_borders)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn validate_virtual_desktop_id(&self) {
|
pub fn validate_virtual_desktop_id(&self) {
|
||||||
let virtual_desktop_id = winvd::helpers::get_current_desktop_number().ok();
|
let virtual_desktop_id = winvd::helpers::get_current_desktop_number().ok();
|
||||||
@@ -472,9 +501,11 @@ impl WindowManager {
|
|||||||
pub fn update_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> {
|
pub fn update_focused_workspace(&mut self, mouse_follows_focus: bool) -> Result<()> {
|
||||||
tracing::info!("updating");
|
tracing::info!("updating");
|
||||||
|
|
||||||
|
let invisible_borders = self.invisible_borders;
|
||||||
|
|
||||||
self.focused_monitor_mut()
|
self.focused_monitor_mut()
|
||||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||||
.update_focused_workspace()?;
|
.update_focused_workspace(&invisible_borders)?;
|
||||||
|
|
||||||
if mouse_follows_focus {
|
if mouse_follows_focus {
|
||||||
if let Some(window) = self.focused_workspace()?.maximized_window() {
|
if let Some(window) = self.focused_workspace()?.maximized_window() {
|
||||||
@@ -781,6 +812,7 @@ impl WindowManager {
|
|||||||
tracing::info!("floating window");
|
tracing::info!("floating window");
|
||||||
|
|
||||||
let work_area = self.focused_monitor_work_area()?;
|
let work_area = self.focused_monitor_work_area()?;
|
||||||
|
let invisible_borders = self.invisible_borders;
|
||||||
|
|
||||||
let workspace = self.focused_workspace_mut()?;
|
let workspace = self.focused_workspace_mut()?;
|
||||||
workspace.new_floating_window()?;
|
workspace.new_floating_window()?;
|
||||||
@@ -790,7 +822,7 @@ impl WindowManager {
|
|||||||
.last_mut()
|
.last_mut()
|
||||||
.ok_or_else(|| anyhow!("there is no floating window"))?;
|
.ok_or_else(|| anyhow!("there is no floating window"))?;
|
||||||
|
|
||||||
window.center(&work_area)?;
|
window.center(&work_area, &invisible_borders)?;
|
||||||
window.focus()?;
|
window.focus()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -973,6 +1005,7 @@ impl WindowManager {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
tracing::info!("setting workspace layout");
|
tracing::info!("setting workspace layout");
|
||||||
|
|
||||||
|
let invisible_borders = self.invisible_borders;
|
||||||
let focused_monitor_idx = self.focused_monitor_idx();
|
let focused_monitor_idx = self.focused_monitor_idx();
|
||||||
|
|
||||||
let monitor = self
|
let monitor = self
|
||||||
@@ -992,7 +1025,7 @@ impl WindowManager {
|
|||||||
|
|
||||||
// If this is the focused workspace on a non-focused screen, let's update it
|
// If this is the focused workspace on a non-focused screen, let's update it
|
||||||
if focused_monitor_idx != monitor_idx && focused_workspace_idx == workspace_idx {
|
if focused_monitor_idx != monitor_idx && focused_workspace_idx == workspace_idx {
|
||||||
workspace.update(&work_area)?;
|
workspace.update(&work_area, &invisible_borders)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Ok(self.update_focused_workspace(false)?)
|
Ok(self.update_focused_workspace(false)?)
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ impl Workspace {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, work_area: &Rect) -> Result<()> {
|
pub fn update(&mut self, work_area: &Rect, invisible_borders: &Rect) -> Result<()> {
|
||||||
let mut adjusted_work_area = *work_area;
|
let mut adjusted_work_area = *work_area;
|
||||||
adjusted_work_area.add_padding(self.workspace_padding());
|
adjusted_work_area.add_padding(self.workspace_padding());
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ impl Workspace {
|
|||||||
if *self.tile() {
|
if *self.tile() {
|
||||||
if let Some(container) = self.monocle_container_mut() {
|
if let Some(container) = self.monocle_container_mut() {
|
||||||
if let Some(window) = container.focused_window_mut() {
|
if let Some(window) = container.focused_window_mut() {
|
||||||
window.set_position(&adjusted_work_area, true)?;
|
window.set_position(&adjusted_work_area, invisible_borders, true)?;
|
||||||
};
|
};
|
||||||
} else if let Some(window) = self.maximized_window_mut() {
|
} else if let Some(window) = self.maximized_window_mut() {
|
||||||
window.maximize();
|
window.maximize();
|
||||||
@@ -166,7 +166,7 @@ impl Workspace {
|
|||||||
let windows = self.visible_windows_mut();
|
let windows = self.visible_windows_mut();
|
||||||
for (i, window) in windows.into_iter().enumerate() {
|
for (i, window) in windows.into_iter().enumerate() {
|
||||||
if let (Some(window), Some(layout)) = (window, layouts.get(i)) {
|
if let (Some(window), Some(layout)) = (window, layouts.get(i)) {
|
||||||
window.set_position(layout, false)?;
|
window.set_position(layout, invisible_borders, false)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ NewWorkspace() {
|
|||||||
Run, komorebic.exe new-workspace, , Hide
|
Run, komorebic.exe new-workspace, , Hide
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InvisibleBorders(left, top, right, bottom) {
|
||||||
|
Run, komorebic.exe invisible-borders %left% %top% %right% %bottom%, , Hide
|
||||||
|
}
|
||||||
|
|
||||||
AdjustContainerPadding(sizing, adjustment) {
|
AdjustContainerPadding(sizing, adjustment) {
|
||||||
Run, komorebic.exe adjust-container-padding %sizing% %adjustment%, , Hide
|
Run, komorebic.exe adjust-container-padding %sizing% %adjustment%, , Hide
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use komorebi_core::Flip;
|
|||||||
use komorebi_core::FocusFollowsMouseImplementation;
|
use komorebi_core::FocusFollowsMouseImplementation;
|
||||||
use komorebi_core::Layout;
|
use komorebi_core::Layout;
|
||||||
use komorebi_core::OperationDirection;
|
use komorebi_core::OperationDirection;
|
||||||
|
use komorebi_core::Rect;
|
||||||
use komorebi_core::Sizing;
|
use komorebi_core::Sizing;
|
||||||
use komorebi_core::SocketMessage;
|
use komorebi_core::SocketMessage;
|
||||||
use komorebi_core::StateQuery;
|
use komorebi_core::StateQuery;
|
||||||
@@ -150,6 +151,18 @@ struct Resize {
|
|||||||
sizing: Sizing,
|
sizing: Sizing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clap, AhkFunction)]
|
||||||
|
struct InvisibleBorders {
|
||||||
|
/// Size of the left invisible border
|
||||||
|
left: i32,
|
||||||
|
/// Size of the top invisible border (usually 0)
|
||||||
|
top: i32,
|
||||||
|
/// Size of the right invisible border (usually left * 2)
|
||||||
|
right: i32,
|
||||||
|
/// Size of the bottom invisible border (usually the same as left)
|
||||||
|
bottom: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clap, AhkFunction)]
|
#[derive(Clap, AhkFunction)]
|
||||||
struct EnsureWorkspaces {
|
struct EnsureWorkspaces {
|
||||||
/// Monitor index (zero-indexed)
|
/// Monitor index (zero-indexed)
|
||||||
@@ -305,6 +318,9 @@ enum SubCommand {
|
|||||||
FocusWorkspace(FocusWorkspace),
|
FocusWorkspace(FocusWorkspace),
|
||||||
/// Create and append a new workspace on the focused monitor
|
/// Create and append a new workspace on the focused monitor
|
||||||
NewWorkspace,
|
NewWorkspace,
|
||||||
|
/// Set the invisible border dimensions around each window
|
||||||
|
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
||||||
|
InvisibleBorders(InvisibleBorders),
|
||||||
/// Adjust container padding on the focused workspace
|
/// Adjust container padding on the focused workspace
|
||||||
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
#[clap(setting = AppSettings::ArgRequiredElseHelp)]
|
||||||
AdjustContainerPadding(AdjustContainerPadding),
|
AdjustContainerPadding(AdjustContainerPadding),
|
||||||
@@ -459,6 +475,17 @@ fn main() -> Result<()> {
|
|||||||
SubCommand::SendToWorkspace(arg) => {
|
SubCommand::SendToWorkspace(arg) => {
|
||||||
send_message(&*SocketMessage::SendContainerToWorkspaceNumber(arg.target).as_bytes()?)?;
|
send_message(&*SocketMessage::SendContainerToWorkspaceNumber(arg.target).as_bytes()?)?;
|
||||||
}
|
}
|
||||||
|
SubCommand::InvisibleBorders(arg) => {
|
||||||
|
send_message(
|
||||||
|
&*SocketMessage::InvisibleBorders(Rect {
|
||||||
|
left: arg.left,
|
||||||
|
top: arg.top,
|
||||||
|
right: arg.right,
|
||||||
|
bottom: arg.bottom,
|
||||||
|
})
|
||||||
|
.as_bytes()?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
SubCommand::ContainerPadding(arg) => {
|
SubCommand::ContainerPadding(arg) => {
|
||||||
send_message(
|
send_message(
|
||||||
&*SocketMessage::ContainerPadding(arg.monitor, arg.workspace, arg.size)
|
&*SocketMessage::ContainerPadding(arg.monitor, arg.workspace, arg.size)
|
||||||
|
|||||||
Reference in New Issue
Block a user