Skip to content

Commit

Permalink
feat(wm): add float override option
Browse files Browse the repository at this point in the history
This commit introduces a new option `float_override`, which makes it so
every every window opened, shown or uncloaked will be set to floating,
but it won't be ignored. It will be added to the floating_windows of the
workspace, meaning that the user can later tile that window with
toggle-float command.

This allows the users to have all windows open as floating and then
manually tile the ones they want.

This interactively rebased commit contains changes from the following
individual commits:

0e8dc85
feat(wm): add new float override option

30bdaf3
feat(cli): add command for new option `ToggleFloatOverride`

b7bedce
feat(wm): add window_container_behaviour and float_override to workspaces

221e4ea
feat(cli): add commands for workspace new window behaviour and float_override

b182cb5
fix(wm): show floating apps in front of stacked windows as well

7c9cb11
fix(wm): Remove unecessary duplicated code
  • Loading branch information
alex-ds13 authored and LGUG2Z committed Oct 13, 2024
1 parent 6db317d commit d5b6584
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 30 deletions.
18 changes: 17 additions & 1 deletion komorebi/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub enum SocketMessage {
ToggleMonocle,
ToggleMaximize,
ToggleWindowContainerBehaviour,
ToggleFloatOverride,
WindowHidingBehaviour(HidingBehaviour),
ToggleCrossMonitorMoveBehaviour,
CrossMonitorMoveBehaviour(MoveBehaviour),
Expand All @@ -90,6 +91,8 @@ pub enum SocketMessage {
CycleLayout(CycleDirection),
ChangeLayoutCustom(PathBuf),
FlipLayout(Axis),
ToggleWorkspaceWindowContainerBehaviour,
ToggleWorkspaceFloatOverride,
// Monitor and Workspace Commands
MonitorIndexPreference(usize, i32, i32, i32, i32),
DisplayIndexPreference(usize, String),
Expand Down Expand Up @@ -343,10 +346,23 @@ pub enum FocusFollowsMouseImplementation {
}

#[derive(
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq,
)]
pub struct WindowManagementBehaviour {
/// The current WindowContainerBehaviour to be used
pub current_behaviour: WindowContainerBehaviour,
/// Override of `current_behaviour` to open new windows as floating windows
/// that can be later toggled to tiled, when false it will default to
/// `current_behaviour` again.
pub float_override: bool,
}

#[derive(
Clone, Copy, Debug, Default, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, PartialEq
)]
pub enum WindowContainerBehaviour {
/// Create a new container for each new window
#[default]
Create,
/// Append new windows to the focused window container
Append,
Expand Down
33 changes: 30 additions & 3 deletions komorebi/src/process_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,15 +1346,42 @@ impl WindowManager {
self.resize_delta = delta;
}
SocketMessage::ToggleWindowContainerBehaviour => {
match self.window_container_behaviour {
match self.window_management_behaviour.current_behaviour {
WindowContainerBehaviour::Create => {
self.window_container_behaviour = WindowContainerBehaviour::Append;
self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Append;
}
WindowContainerBehaviour::Append => {
self.window_container_behaviour = WindowContainerBehaviour::Create;
self.window_management_behaviour.current_behaviour = WindowContainerBehaviour::Create;
}
}
}
SocketMessage::ToggleFloatOverride => {
self.window_management_behaviour.float_override = !self.window_management_behaviour.float_override;
}
SocketMessage::ToggleWorkspaceWindowContainerBehaviour => {
let current_global_behaviour = self.window_management_behaviour.current_behaviour;
if let Some(behaviour) = self.focused_workspace_mut()?.window_container_behaviour_mut() {
match behaviour {
WindowContainerBehaviour::Create => *behaviour = WindowContainerBehaviour::Append,
WindowContainerBehaviour::Append => *behaviour = WindowContainerBehaviour::Create,
}
} else {
self.focused_workspace_mut()?.set_window_container_behaviour(
Some(match current_global_behaviour {
WindowContainerBehaviour::Create => WindowContainerBehaviour::Append,
WindowContainerBehaviour::Append => WindowContainerBehaviour::Create,
})
);
};
}
SocketMessage::ToggleWorkspaceFloatOverride => {
let current_global_override = self.window_management_behaviour.float_override;
if let Some(float_override) = self.focused_workspace_mut()?.float_override_mut() {
*float_override = !*float_override;
} else {
self.focused_workspace_mut()?.set_float_override(Some(!current_global_override));
};
}
SocketMessage::WindowHidingBehaviour(behaviour) => {
let mut hiding_behaviour = HIDING_BEHAVIOUR.lock();
*hiding_behaviour = behaviour;
Expand Down
22 changes: 13 additions & 9 deletions komorebi/src/process_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,8 @@ impl WindowManager {
}

if proceed {
let behaviour =
self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx);
let mut behaviour =
self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx);
let workspace = self.focused_workspace_mut()?;
let workspace_contains_window = workspace.contains_window(window.hwnd);
let monocle_container = workspace.monocle_container().clone();
Expand All @@ -360,11 +360,13 @@ impl WindowManager {
}
}

if should_float && !matches!(event, WindowManagerEvent::Manage(_)) {
behaviour.float_override = behaviour.float_override || (should_float && !matches!(event, WindowManagerEvent::Manage(_)));

if behaviour.float_override {
workspace.floating_windows_mut().push(window);
self.update_focused_workspace(false, true)?;
self.update_focused_workspace(false, false)?;
} else {
match behaviour {
match behaviour.current_behaviour {
WindowContainerBehaviour::Create => {
workspace.new_container_for_window(window);
self.update_focused_workspace(false, false)?;
Expand All @@ -375,7 +377,6 @@ impl WindowManager {
.ok_or_else(|| anyhow!("there is no focused container"))?
.add_window(window);
self.update_focused_workspace(true, false)?;

stackbar_manager::send_notification();
}
}
Expand Down Expand Up @@ -431,8 +432,8 @@ impl WindowManager {

let focused_monitor_idx = self.focused_monitor_idx();
let focused_workspace_idx = self.focused_workspace_idx().unwrap_or_default();
let window_container_behaviour =
self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx);
let window_management_behaviour =
self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx);

let workspace = self.focused_workspace_mut()?;
let focused_container_idx = workspace.focused_container_idx();
Expand Down Expand Up @@ -550,8 +551,11 @@ impl WindowManager {
}
// Here we handle a simple move on the same monitor which is treated as
// a container swap
} else if window_management_behaviour.float_override {
workspace.floating_windows_mut().push(window);
self.update_focused_workspace(false, false)?;
} else {
match window_container_behaviour {
match window_management_behaviour.current_behaviour {
WindowContainerBehaviour::Create => {
match workspace.container_idx_from_current_point() {
Some(target_idx) => {
Expand Down
30 changes: 25 additions & 5 deletions komorebi/src/static_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ use crate::core::OperationBehaviour;
use crate::core::Rect;
use crate::core::SocketMessage;
use crate::core::WindowContainerBehaviour;
use crate::core::WindowManagementBehaviour;
use color_eyre::Result;
use crossbeam_channel::Receiver;
use hotwatch::EventKind;
Expand Down Expand Up @@ -130,6 +131,13 @@ pub struct WorkspaceConfig {
/// Apply this monitor's window-based work area offset (default: true)
#[serde(skip_serializing_if = "Option::is_none")]
pub apply_window_based_work_area_offset: Option<bool>,
/// Determine what happens when a new window is opened (default: Create)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour: Option<WindowContainerBehaviour>,
/// Enable or disable float override, which makes it so every new window opens in floating mode
/// (default: false)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_override: Option<bool>,
}

impl From<&Workspace> for WorkspaceConfig {
Expand Down Expand Up @@ -182,6 +190,8 @@ impl From<&Workspace> for WorkspaceConfig {
initial_workspace_rules: None,
workspace_rules: None,
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()),
window_container_behaviour: *value.window_container_behaviour(),
float_override: *value.float_override(),
}
}
}
Expand Down Expand Up @@ -235,6 +245,10 @@ pub struct StaticConfig {
/// Determine what happens when a new window is opened (default: Create)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour: Option<WindowContainerBehaviour>,
/// Enable or disable float override, which makes it so every new window opens in floating mode
/// (default: false)
#[serde(skip_serializing_if = "Option::is_none")]
pub float_override: Option<bool>,
/// Determine what happens when a window is moved across a monitor boundary (default: Swap)
#[serde(skip_serializing_if = "Option::is_none")]
pub cross_monitor_move_behaviour: Option<MoveBehaviour>,
Expand Down Expand Up @@ -520,7 +534,8 @@ impl From<&WindowManager> for StaticConfig {
Self {
invisible_borders: None,
resize_delta: Option::from(value.resize_delta),
window_container_behaviour: Option::from(value.window_container_behaviour),
window_container_behaviour: Option::from(value.window_management_behaviour.current_behaviour),
float_override: Option::from(value.window_management_behaviour.float_override),
cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour),
cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour),
unmanaged_window_operation_behaviour: Option::from(
Expand Down Expand Up @@ -1031,9 +1046,10 @@ impl StaticConfig {
is_paused: false,
virtual_desktop_id: current_virtual_desktop(),
work_area_offset: value.global_work_area_offset,
window_container_behaviour: value
.window_container_behaviour
.unwrap_or(WindowContainerBehaviour::Create),
window_management_behaviour: WindowManagementBehaviour {
current_behaviour: value.window_container_behaviour.unwrap_or(WindowContainerBehaviour::Create),
float_override: value.float_override.unwrap_or_default(),
},
cross_monitor_move_behaviour: value
.cross_monitor_move_behaviour
.unwrap_or(MoveBehaviour::Swap),
Expand Down Expand Up @@ -1208,7 +1224,11 @@ impl StaticConfig {
}

if let Some(val) = value.window_container_behaviour {
wm.window_container_behaviour = val;
wm.window_management_behaviour.current_behaviour = val;
}

if let Some(val) = value.float_override {
wm.window_management_behaviour.float_override = val;
}

if let Some(val) = value.cross_monitor_move_behaviour {
Expand Down
43 changes: 35 additions & 8 deletions komorebi/src/window_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::core::Rect;
use crate::core::Sizing;
use crate::core::StackbarLabel;
use crate::core::WindowContainerBehaviour;
use crate::core::WindowManagementBehaviour;

use crate::border_manager;
use crate::border_manager::STYLE;
Expand Down Expand Up @@ -92,7 +93,7 @@ pub struct WindowManager {
pub is_paused: bool,
pub work_area_offset: Option<Rect>,
pub resize_delta: i32,
pub window_container_behaviour: WindowContainerBehaviour,
pub window_management_behaviour: WindowManagementBehaviour,
pub cross_monitor_move_behaviour: MoveBehaviour,
pub cross_boundary_behaviour: CrossBoundaryBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour,
Expand All @@ -112,6 +113,7 @@ pub struct State {
pub is_paused: bool,
pub resize_delta: i32,
pub new_window_behaviour: WindowContainerBehaviour,
pub float_override: bool,
pub cross_monitor_move_behaviour: MoveBehaviour,
pub unmanaged_window_operation_behaviour: OperationBehaviour,
pub work_area_offset: Option<Rect>,
Expand Down Expand Up @@ -215,7 +217,8 @@ impl From<&WindowManager> for State {
is_paused: wm.is_paused,
work_area_offset: wm.work_area_offset,
resize_delta: wm.resize_delta,
new_window_behaviour: wm.window_container_behaviour,
new_window_behaviour: wm.window_management_behaviour.current_behaviour,
float_override: wm.window_management_behaviour.float_override,
cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour,
focus_follows_mouse: wm.focus_follows_mouse,
mouse_follows_focus: wm.mouse_follows_focus,
Expand Down Expand Up @@ -275,7 +278,7 @@ impl WindowManager {
is_paused: false,
virtual_desktop_id: current_virtual_desktop(),
work_area_offset: None,
window_container_behaviour: WindowContainerBehaviour::Create,
window_management_behaviour: WindowManagementBehaviour::default(),
cross_monitor_move_behaviour: MoveBehaviour::Swap,
cross_boundary_behaviour: CrossBoundaryBehaviour::Workspace,
unmanaged_window_operation_behaviour: OperationBehaviour::Op,
Expand Down Expand Up @@ -308,22 +311,44 @@ impl WindowManager {
StaticConfig::reload(pathbuf, self)
}

pub fn window_container_behaviour(
pub fn window_management_behaviour(
&self,
monitor_idx: usize,
workspace_idx: usize,
) -> WindowContainerBehaviour {
) -> WindowManagementBehaviour {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.workspaces().get(workspace_idx) {
return if workspace.containers().is_empty() {
let current_behaviour = if let Some(behaviour) = workspace.window_container_behaviour() {
if workspace.containers().is_empty() && matches!(behaviour, WindowContainerBehaviour::Append) {
// You can't append to an empty workspace
WindowContainerBehaviour::Create
} else {
*behaviour
}
} else if workspace.containers().is_empty() && matches!(self.window_management_behaviour.current_behaviour, WindowContainerBehaviour::Append) {
// You can't append to an empty workspace
WindowContainerBehaviour::Create
} else {
self.window_container_behaviour
self.window_management_behaviour.current_behaviour
};

let float_override = if let Some(float_override) = workspace.float_override() {
*float_override
} else {
self.window_management_behaviour.float_override
};

return WindowManagementBehaviour {
current_behaviour,
float_override
};
}
}

WindowContainerBehaviour::Create
WindowManagementBehaviour {
current_behaviour: WindowContainerBehaviour::Create,
float_override: self.window_management_behaviour.float_override,
}
}

#[tracing::instrument(skip(self))]
Expand Down Expand Up @@ -846,6 +871,8 @@ impl WindowManager {
&& self.focused_workspace()?.maximized_window().is_none()
// and we don't have a monocle container
&& self.focused_workspace()?.monocle_container().is_none()
// and we don't have any floating windows that should show on top
&& self.focused_workspace()?.floating_windows().is_empty()
{
if let Ok(window) = self.focused_window_mut() {
if trigger_focus {
Expand Down
19 changes: 15 additions & 4 deletions komorebi/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::static_config::WorkspaceConfig;
use crate::window::Window;
use crate::window::WindowDetails;
use crate::windows_api::WindowsApi;
use crate::WindowContainerBehaviour;
use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING;
use crate::INITIAL_CONFIGURATION_LOADED;
Expand Down Expand Up @@ -83,6 +84,10 @@ pub struct Workspace {
tile: bool,
#[getset(get_copy = "pub", set = "pub")]
apply_window_based_work_area_offset: bool,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
window_container_behaviour: Option<WindowContainerBehaviour>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
float_override: Option<bool>,
}

impl_ring_elements!(Workspace, Container);
Expand All @@ -106,6 +111,8 @@ impl Default for Workspace {
resize_dimensions: vec![],
tile: true,
apply_window_based_work_area_offset: true,
window_container_behaviour: None,
float_override: None,
}
}
}
Expand Down Expand Up @@ -162,6 +169,14 @@ impl Workspace {
config.apply_window_based_work_area_offset.unwrap_or(true),
);

if config.window_container_behaviour.is_some() {
self.set_window_container_behaviour(config.window_container_behaviour);
}

if config.float_override.is_some() {
self.set_float_override(config.float_override);
}

Ok(())
}

Expand Down Expand Up @@ -217,10 +232,6 @@ impl Workspace {
container.restore();
}

for container in self.containers_mut() {
container.restore();
}

if let Some(container) = self.focused_container_mut() {
container.focus_window(container.focused_window_idx());
}
Expand Down
Loading

0 comments on commit d5b6584

Please sign in to comment.