feat(wm): separate floating and ignored apps

This commit introduces a distinction between ignored applications
(previously identified with float_rules) and floating applications.

All instances of "float_" with the initial meaning of "ignored" have
been renamed with backwards compatibility aliases.

Floating applications will be managed under Workspace.floating_windows
if identified using a rule, and this allows them to now be moved across
workspaces.

A new border type has been added for floating applications, and the
colour can be configured via theme.floating_border.

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

17ea1e6869
feat(wm): separate floating and ignored apps

8b344496e6
feat(wm): allow ws moves of floating apps

7d8e2ad814
refactor(wm): float_rules > ignore_rules w/ compat

d68346a640
fix(borders): no redraws on floating win title change

a93e937772
fix(borders): update on floating win drag

68e9365dda
fix(borders): send notif on ignored hwnd events
This commit is contained in:
LGUG2Z
2024-09-28 17:03:37 -07:00
parent 2325d750c5
commit 6b28d76446
15 changed files with 374 additions and 167 deletions
+142 -8
View File
@@ -49,6 +49,8 @@ lazy_static! {
pub static ref MONOCLE: AtomicU32 = pub static ref MONOCLE: AtomicU32 =
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(255, 51, 153)))); AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(255, 51, 153))));
pub static ref STACK: AtomicU32 = AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(0, 165, 66)))); pub static ref STACK: AtomicU32 = AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(0, 165, 66))));
pub static ref FLOATING: AtomicU32 =
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(245, 245, 165))));
} }
lazy_static! { lazy_static! {
@@ -57,7 +59,7 @@ lazy_static! {
static ref FOCUS_STATE: Mutex<HashMap<isize, WindowKind>> = Mutex::new(HashMap::new()); static ref FOCUS_STATE: Mutex<HashMap<isize, WindowKind>> = Mutex::new(HashMap::new());
} }
pub struct Notification; pub struct Notification(pub Option<isize>);
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new(); static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
@@ -73,8 +75,8 @@ fn event_rx() -> Receiver<Notification> {
channel().1.clone() channel().1.clone()
} }
pub fn send_notification() { pub fn send_notification(hwnd: Option<isize>) {
if event_tx().try_send(Notification).is_err() { if event_tx().try_send(Notification(hwnd)).is_err() {
tracing::warn!("channel is full; dropping notification") tracing::warn!("channel is full; dropping notification")
} }
} }
@@ -118,6 +120,7 @@ fn window_kind_colour(focus_kind: WindowKind) -> u32 {
WindowKind::Single => FOCUSED.load(Ordering::SeqCst), WindowKind::Single => FOCUSED.load(Ordering::SeqCst),
WindowKind::Stack => STACK.load(Ordering::SeqCst), WindowKind::Stack => STACK.load(Ordering::SeqCst),
WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst), WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst),
WindowKind::Floating => FLOATING.load(Ordering::SeqCst),
} }
} }
@@ -139,19 +142,29 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst);
let receiver = event_rx(); let receiver = event_rx();
event_tx().send(Notification)?; event_tx().send(Notification(None))?;
let mut previous_snapshot = Ring::default(); let mut previous_snapshot = Ring::default();
let mut previous_pending_move_op = None; let mut previous_pending_move_op = None;
let mut previous_is_paused = false; let mut previous_is_paused = false;
let mut previous_notification: Option<Notification> = None;
'receiver: for _ in receiver { 'receiver: for notification in receiver {
// Check the wm state every time we receive a notification // Check the wm state every time we receive a notification
let state = wm.lock(); let state = wm.lock();
let is_paused = state.is_paused; let is_paused = state.is_paused;
let focused_monitor_idx = state.focused_monitor_idx(); let focused_monitor_idx = state.focused_monitor_idx();
let focused_workspace_idx =
state.monitors.elements()[focused_monitor_idx].focused_workspace_idx();
let monitors = state.monitors.clone(); let monitors = state.monitors.clone();
let pending_move_op = state.pending_move_op; let pending_move_op = state.pending_move_op;
let floating_window_hwnds = state.monitors.elements()[focused_monitor_idx].workspaces()
[focused_workspace_idx]
.floating_windows()
.iter()
.map(|w| w.hwnd)
.collect::<Vec<_>>();
drop(state); drop(state);
match IMPLEMENTATION.load() { match IMPLEMENTATION.load() {
@@ -220,6 +233,21 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
should_process_notification = true; should_process_notification = true;
} }
// when we switch focus to a floating window
if !should_process_notification
&& floating_window_hwnds.contains(&notification.0.unwrap_or_default())
{
should_process_notification = true;
}
if !should_process_notification {
if let Some(ref previous) = previous_notification {
if previous.0.unwrap_or_default() != notification.0.unwrap_or_default() {
should_process_notification = true;
}
}
}
if !should_process_notification { if !should_process_notification {
tracing::trace!("monitor state matches latest snapshot, skipping notification"); tracing::trace!("monitor state matches latest snapshot, skipping notification");
continue 'receiver; continue 'receiver;
@@ -345,16 +373,20 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
} }
// Destroy any borders not associated with the focused workspace // Destroy any borders not associated with the focused workspace
let container_ids = ws let mut container_and_floating_window_ids = ws
.containers() .containers()
.iter() .iter()
.map(|c| c.id().clone()) .map(|c| c.id().clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for w in ws.floating_windows() {
container_and_floating_window_ids.push(w.hwnd.to_string());
}
let mut to_remove = vec![]; let mut to_remove = vec![];
for (id, border) in borders.iter() { for (id, border) in borders.iter() {
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
&& !container_ids.contains(id) && !container_and_floating_window_ids.contains(id)
{ {
border.destroy()?; border.destroy()?;
to_remove.push(id.clone()); to_remove.push(id.clone());
@@ -366,8 +398,14 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
} }
for (idx, c) in ws.containers().iter().enumerate() { for (idx, c) in ws.containers().iter().enumerate() {
let hwnd = c.focused_window().copied().unwrap_or_default().hwnd;
let notification_hwnd = notification.0.unwrap_or_default();
// Update border when moving or resizing with mouse // Update border when moving or resizing with mouse
if pending_move_op.is_some() && idx == ws.focused_container_idx() { if pending_move_op.is_some()
&& idx == ws.focused_container_idx()
&& hwnd == notification_hwnd
{
let restore_z_order = Z_ORDER.load(); let restore_z_order = Z_ORDER.load();
Z_ORDER.store(ZOrder::TopMost); Z_ORDER.store(ZOrder::TopMost);
@@ -446,6 +484,101 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
border.update(&rect, should_invalidate)?; border.update(&rect, should_invalidate)?;
} }
{
let restore_z_order = Z_ORDER.load();
Z_ORDER.store(ZOrder::TopMost);
'windows: for window in ws.floating_windows() {
let hwnd = window.hwnd;
let notification_hwnd = notification.0.unwrap_or_default();
if pending_move_op.is_some() && hwnd == notification_hwnd {
let mut rect = WindowsApi::window_rect(hwnd)?;
while WindowsApi::lbutton_is_pressed() {
let border = match borders.entry(hwnd.to_string()) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
if let Ok(border) =
Border::create(&hwnd.to_string())
{
entry.insert(border)
} else {
continue 'monitors;
}
}
};
let new_rect = WindowsApi::window_rect(hwnd)?;
if rect != new_rect {
rect = new_rect;
border.update(&rect, true)?;
}
}
Z_ORDER.store(restore_z_order);
continue 'monitors;
}
let border = match borders.entry(window.hwnd.to_string()) {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => {
if let Ok(border) = Border::create(&window.hwnd.to_string())
{
entry.insert(border)
} else {
continue 'monitors;
}
}
};
borders_monitors.insert(window.hwnd.to_string(), monitor_idx);
let mut should_destroy = false;
if let Some(notification_hwnd) = notification.0 {
if notification_hwnd != window.hwnd {
should_destroy = true;
}
}
if WindowsApi::foreground_window().unwrap_or_default()
!= window.hwnd
{
should_destroy = true;
}
if should_destroy {
border.destroy()?;
borders.remove(&window.hwnd.to_string());
borders_monitors.remove(&window.hwnd.to_string());
continue 'windows;
}
#[allow(unused_assignments)]
let mut last_focus_state = None;
let new_focus_state = WindowKind::Floating;
{
let mut focus_state = FOCUS_STATE.lock();
last_focus_state =
focus_state.insert(border.hwnd, new_focus_state);
}
let rect = WindowsApi::window_rect(window.hwnd)?;
let should_invalidate = match last_focus_state {
None => true,
Some(last_focus_state) => last_focus_state != new_focus_state,
};
border.update(&rect, should_invalidate)?;
}
Z_ORDER.store(restore_z_order);
}
} }
} }
} }
@@ -454,6 +587,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
previous_snapshot = monitors; previous_snapshot = monitors;
previous_pending_move_op = pending_move_op; previous_pending_move_op = pending_move_op;
previous_is_paused = is_paused; previous_is_paused = is_paused;
previous_notification = Some(notification);
} }
Ok(()) Ok(())
+12 -11
View File
@@ -116,7 +116,8 @@ pub struct ApplicationConfiguration {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<Vec<ApplicationOptions>>, pub options: Option<Vec<ApplicationOptions>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub float_identifiers: Option<Vec<MatchingRule>>, #[serde(alias = "float_identifiers")]
pub ignore_identifiers: Option<Vec<MatchingRule>>,
} }
impl ApplicationConfiguration { impl ApplicationConfiguration {
@@ -187,7 +188,7 @@ impl ApplicationConfigurationGenerator {
let mut lines = vec![String::from("# Generated by komorebic.exe"), String::new()]; let mut lines = vec![String::from("# Generated by komorebic.exe"), String::new()];
let mut float_rules = vec![]; let mut ignore_rules = vec![];
for app in cfgen { for app in cfgen {
lines.push(format!("# {}", app.name)); lines.push(format!("# {}", app.name));
@@ -201,15 +202,15 @@ impl ApplicationConfigurationGenerator {
} }
} }
if let Some(float_identifiers) = app.float_identifiers { if let Some(ignore_identifiers) = app.ignore_identifiers {
for matching_rule in float_identifiers { for matching_rule in ignore_identifiers {
if let MatchingRule::Simple(float) = matching_rule { if let MatchingRule::Simple(float) = matching_rule {
let float_rule = let float_rule =
format!("komorebic.exe float-rule {} \"{}\"", float.kind, float.id); format!("komorebic.exe float-rule {} \"{}\"", float.kind, float.id);
// Don't want to send duped signals especially as configs get larger // Don't want to send duped signals especially as configs get larger
if !float_rules.contains(&float_rule) { if !ignore_rules.contains(&float_rule) {
float_rules.push(float_rule.clone()); ignore_rules.push(float_rule.clone());
// if let Some(comment) = float.comment { // if let Some(comment) = float.comment {
// lines.push(format!("# {comment}")); // lines.push(format!("# {comment}"));
@@ -238,7 +239,7 @@ impl ApplicationConfigurationGenerator {
let mut lines = vec![String::from("; Generated by komorebic.exe"), String::new()]; let mut lines = vec![String::from("; Generated by komorebic.exe"), String::new()];
let mut float_rules = vec![]; let mut ignore_rules = vec![];
for app in cfgen { for app in cfgen {
lines.push(format!("; {}", app.name)); lines.push(format!("; {}", app.name));
@@ -252,8 +253,8 @@ impl ApplicationConfigurationGenerator {
} }
} }
if let Some(float_identifiers) = app.float_identifiers { if let Some(ignore_identifiers) = app.ignore_identifiers {
for matching_rule in float_identifiers { for matching_rule in ignore_identifiers {
if let MatchingRule::Simple(float) = matching_rule { if let MatchingRule::Simple(float) = matching_rule {
let float_rule = format!( let float_rule = format!(
"RunWait('komorebic.exe float-rule {} \"{}\"', , \"Hide\")", "RunWait('komorebic.exe float-rule {} \"{}\"', , \"Hide\")",
@@ -261,8 +262,8 @@ impl ApplicationConfigurationGenerator {
); );
// Don't want to send duped signals especially as configs get larger // Don't want to send duped signals especially as configs get larger
if !float_rules.contains(&float_rule) { if !ignore_rules.contains(&float_rule) {
float_rules.push(float_rule.clone()); ignore_rules.push(float_rule.clone());
// if let Some(comment) = float.comment { // if let Some(comment) = float.comment {
// lines.push(format!("; {comment}")); // lines.push(format!("; {comment}"));
+3 -1
View File
@@ -174,7 +174,8 @@ pub enum SocketMessage {
ClearWorkspaceRules(usize, usize), ClearWorkspaceRules(usize, usize),
ClearNamedWorkspaceRules(String), ClearNamedWorkspaceRules(String),
ClearAllWorkspaceRules, ClearAllWorkspaceRules,
FloatRule(ApplicationIdentifier, String), #[serde(alias = "FloatRule")]
IgnoreRule(ApplicationIdentifier, String),
ManageRule(ApplicationIdentifier, String), ManageRule(ApplicationIdentifier, String),
IdentifyObjectNameChangeApplication(ApplicationIdentifier, String), IdentifyObjectNameChangeApplication(ApplicationIdentifier, String),
IdentifyTrayApplication(ApplicationIdentifier, String), IdentifyTrayApplication(ApplicationIdentifier, String),
@@ -294,6 +295,7 @@ pub enum WindowKind {
Stack, Stack,
Monocle, Monocle,
Unfocused, Unfocused,
Floating,
} }
#[derive( #[derive(
+2 -2
View File
@@ -139,7 +139,7 @@ lazy_static! {
static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> = static ref REGEX_IDENTIFIERS: Arc<Mutex<HashMap<String, Regex>>> =
Arc::new(Mutex::new(HashMap::new())); Arc::new(Mutex::new(HashMap::new()));
static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![])); static ref MANAGE_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![]));
static ref FLOAT_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![ static ref IGNORE_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
// mstsc.exe creates these on Windows 11 when a WSL process is launched // mstsc.exe creates these on Windows 11 when a WSL process is launched
// https://github.com/LGUG2Z/komorebi/issues/74 // https://github.com/LGUG2Z/komorebi/issues/74
MatchingRule::Simple(IdWithIdentifier { MatchingRule::Simple(IdWithIdentifier {
@@ -158,6 +158,7 @@ lazy_static! {
matching_strategy: Option::from(MatchingStrategy::Equals), matching_strategy: Option::from(MatchingStrategy::Equals),
}) })
])); ]));
static ref FLOATING_APPLICATIONS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(Vec::new()));
static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![ static ref PERMAIGNORE_CLASSES: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![
"Chrome_RenderWidgetHostHWND".to_string(), "Chrome_RenderWidgetHostHWND".to_string(),
])); ]));
@@ -224,7 +225,6 @@ lazy_static! {
static ref WINDOWS_BY_BAR_HWNDS: Arc<Mutex<HashMap<isize, VecDeque<isize>>>> = static ref WINDOWS_BY_BAR_HWNDS: Arc<Mutex<HashMap<isize, VecDeque<isize>>>> =
Arc::new(Mutex::new(HashMap::new())); Arc::new(Mutex::new(HashMap::new()));
} }
pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10); pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10);
+27 -2
View File
@@ -20,6 +20,7 @@ use crate::workspace::Workspace;
use crate::DefaultLayout; use crate::DefaultLayout;
use crate::Layout; use crate::Layout;
use crate::OperationDirection; use crate::OperationDirection;
use crate::WindowsApi;
#[derive( #[derive(
Debug, Debug,
@@ -178,6 +179,27 @@ impl Monitor {
bail!("cannot move native maximized window to another monitor or workspace"); bail!("cannot move native maximized window to another monitor or workspace");
} }
let foreground_hwnd = WindowsApi::foreground_window()?;
let floating_window_index = workspace
.floating_windows()
.iter()
.position(|w| w.hwnd == foreground_hwnd);
if let Some(idx) = floating_window_index {
let window = workspace.floating_windows_mut().remove(idx);
let workspaces = self.workspaces_mut();
#[allow(clippy::option_if_let_else)]
let target_workspace = match workspaces.get_mut(target_workspace_idx) {
None => {
workspaces.resize(target_workspace_idx + 1, Workspace::default());
workspaces.get_mut(target_workspace_idx).unwrap()
}
Some(workspace) => workspace,
};
target_workspace.floating_windows_mut().push(window);
} else {
let container = workspace let container = workspace
.remove_focused_container() .remove_focused_container()
.ok_or_else(|| anyhow!("there is no container"))?; .ok_or_else(|| anyhow!("there is no container"))?;
@@ -216,7 +238,8 @@ impl Monitor {
}, },
Some(OperationDirection::Right) => match target_workspace.layout() { Some(OperationDirection::Right) => match target_workspace.layout() {
Layout::Default(layout) => { Layout::Default(layout) => {
let target_index = layout.leftmost_index(target_workspace.containers().len()); let target_index =
layout.leftmost_index(target_workspace.containers().len());
match layout { match layout {
DefaultLayout::RightMainVerticalStack DefaultLayout::RightMainVerticalStack
@@ -224,7 +247,8 @@ impl Monitor {
if target_workspace.containers().len() == 1 { if target_workspace.containers().len() == 1 {
target_workspace.add_container_to_back(container); target_workspace.add_container_to_back(container);
} else { } else {
target_workspace.insert_container_at_idx(target_index, container); target_workspace
.insert_container_at_idx(target_index, container);
} }
} }
_ => { _ => {
@@ -240,6 +264,7 @@ impl Monitor {
target_workspace.add_container_to_back(container); target_workspace.add_container_to_back(container);
} }
} }
}
if follow { if follow {
self.focus_workspace(target_workspace_idx)?; self.focus_workspace(target_workspace_idx)?;
+3 -3
View File
@@ -172,7 +172,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
if should_update { if should_update {
tracing::info!("updated work area for {}", monitor.device_id()); tracing::info!("updated work area for {}", monitor.device_id());
monitor.update_focused_workspace(offset)?; monitor.update_focused_workspace(offset)?;
border_manager::send_notification(); border_manager::send_notification(None);
} else { } else {
tracing::debug!( tracing::debug!(
"work areas match, reconciliation not required for {}", "work areas match, reconciliation not required for {}",
@@ -219,7 +219,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
); );
monitor.update_focused_workspace(offset)?; monitor.update_focused_workspace(offset)?;
border_manager::send_notification(); border_manager::send_notification(None);
} else { } else {
tracing::debug!( tracing::debug!(
"resolutions match, reconciliation not required for {}", "resolutions match, reconciliation not required for {}",
@@ -406,7 +406,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
// Second retile to fix DPI/resolution related jank // Second retile to fix DPI/resolution related jank
wm.retile_all(true)?; wm.retile_all(true)?;
// Border updates to fix DPI/resolution related jank // Border updates to fix DPI/resolution related jank
border_manager::send_notification(); border_manager::send_notification(None);
} }
} }
} }
+12 -9
View File
@@ -68,8 +68,8 @@ use crate::ANIMATION_STYLE;
use crate::CUSTOM_FFM; use crate::CUSTOM_FFM;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES; use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDING_BEHAVIOUR; use crate::HIDING_BEHAVIOUR;
use crate::IGNORE_IDENTIFIERS;
use crate::INITIAL_CONFIGURATION_LOADED; use crate::INITIAL_CONFIGURATION_LOADED;
use crate::LAYERED_WHITELIST; use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS;
@@ -394,20 +394,20 @@ impl WindowManager {
})); }));
} }
} }
SocketMessage::FloatRule(identifier, ref id) => { SocketMessage::IgnoreRule(identifier, ref id) => {
let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock();
let mut should_push = true; let mut should_push = true;
for f in &*float_identifiers { for i in &*ignore_identifiers {
if let MatchingRule::Simple(f) = f { if let MatchingRule::Simple(i) = i {
if f.id.eq(id) { if i.id.eq(id) {
should_push = false; should_push = false;
} }
} }
} }
if should_push { if should_push {
float_identifiers.push(MatchingRule::Simple(IdWithIdentifier { ignore_identifiers.push(MatchingRule::Simple(IdWithIdentifier {
kind: identifier, kind: identifier,
id: id.clone(), id: id.clone(),
matching_strategy: Option::from(MatchingStrategy::Legacy), matching_strategy: Option::from(MatchingStrategy::Legacy),
@@ -1395,7 +1395,7 @@ impl WindowManager {
} }
} }
border_manager::send_notification(); border_manager::send_notification(None);
} }
} }
SocketMessage::BorderColour(kind, r, g, b) => match kind { SocketMessage::BorderColour(kind, r, g, b) => match kind {
@@ -1411,6 +1411,9 @@ impl WindowManager {
WindowKind::Unfocused => { WindowKind::Unfocused => {
border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst); border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
} }
WindowKind::Floating => {
border_manager::FLOATING.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
}
}, },
SocketMessage::BorderStyle(style) => { SocketMessage::BorderStyle(style) => {
STYLE.store(style); STYLE.store(style);
@@ -1540,7 +1543,7 @@ impl WindowManager {
}; };
notify_subscribers(&serde_json::to_string(&notification)?)?; notify_subscribers(&serde_json::to_string(&notification)?)?;
border_manager::send_notification(); border_manager::send_notification(None);
transparency_manager::send_notification(); transparency_manager::send_notification();
stackbar_manager::send_notification(); stackbar_manager::send_notification();
+43 -14
View File
@@ -33,6 +33,7 @@ use crate::workspace_reconciliator::ALT_TAB_HWND_INSTANT;
use crate::Notification; use crate::Notification;
use crate::NotificationEvent; use crate::NotificationEvent;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::FLOATING_APPLICATIONS;
use crate::HIDDEN_HWNDS; use crate::HIDDEN_HWNDS;
use crate::REGEX_IDENTIFIERS; use crate::REGEX_IDENTIFIERS;
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
@@ -101,6 +102,10 @@ impl WindowManager {
} }
if !transparency_override { if !transparency_override {
if rule_debug.matches_ignore_identifier.is_some() {
border_manager::send_notification(Option::from(event.hwnd()));
}
return Ok(()); return Ok(());
} }
} }
@@ -149,14 +154,6 @@ impl WindowManager {
_ => {} _ => {}
} }
for monitor in self.monitors_mut() {
for workspace in monitor.workspaces_mut() {
if let WindowManagerEvent::FocusChange(_, window) = event {
let _ = workspace.focus_changed(window.hwnd);
}
}
}
self.enforce_workspace_rules()?; self.enforce_workspace_rules()?;
if matches!(event, WindowManagerEvent::MouseCapture(..)) { if matches!(event, WindowManagerEvent::MouseCapture(..)) {
@@ -246,11 +243,13 @@ impl WindowManager {
self.update_focused_workspace(self.mouse_follows_focus, false)?; self.update_focused_workspace(self.mouse_follows_focus, false)?;
let workspace = self.focused_workspace_mut()?; let workspace = self.focused_workspace_mut()?;
if !workspace let floating_window_idx = workspace
.floating_windows() .floating_windows()
.iter() .iter()
.any(|w| w.hwnd == window.hwnd) .position(|w| w.hwnd == window.hwnd);
{
match floating_window_idx {
None => {
if let Some(w) = workspace.maximized_window() { if let Some(w) = workspace.maximized_window() {
if w.hwnd == window.hwnd { if w.hwnd == window.hwnd {
return Ok(()); return Ok(());
@@ -262,8 +261,13 @@ impl WindowManager {
window.focus(false)?; window.focus(false)?;
} }
} else { } else {
self.focused_workspace_mut()? workspace.focus_container_by_window(window.hwnd)?;
.focus_container_by_window(window.hwnd)?; }
}
Some(idx) => {
if let Some(window) = workspace.floating_windows().get(idx) {
window.focus(false)?;
}
} }
} }
} }
@@ -336,6 +340,30 @@ impl WindowManager {
let monocle_container = workspace.monocle_container().clone(); let monocle_container = workspace.monocle_container().clone();
if !workspace_contains_window && !needs_reconciliation { if !workspace_contains_window && !needs_reconciliation {
let floating_applications = FLOATING_APPLICATIONS.lock();
let regex_identifiers = REGEX_IDENTIFIERS.lock();
let mut should_float = false;
if !floating_applications.is_empty() {
if let (Ok(title), Ok(exe_name), Ok(class), Ok(path)) =
(window.title(), window.exe(), window.class(), window.path())
{
should_float = should_act(
&title,
&exe_name,
&class,
&path,
&floating_applications,
&regex_identifiers,
)
.is_some();
}
}
if should_float && !matches!(event, WindowManagerEvent::Manage(_)) {
workspace.floating_windows_mut().push(window);
self.update_focused_workspace(false, true)?;
} else {
match behaviour { match behaviour {
WindowContainerBehaviour::Create => { WindowContainerBehaviour::Create => {
workspace.new_container_for_window(window); workspace.new_container_for_window(window);
@@ -352,6 +380,7 @@ impl WindowManager {
} }
} }
} }
}
if workspace_contains_window { if workspace_contains_window {
let mut monocle_window_event = false; let mut monocle_window_event = false;
@@ -642,7 +671,7 @@ impl WindowManager {
}; };
notify_subscribers(&serde_json::to_string(&notification)?)?; notify_subscribers(&serde_json::to_string(&notification)?)?;
border_manager::send_notification(); border_manager::send_notification(Some(event.hwnd()));
transparency_manager::send_notification(); transparency_manager::send_notification();
stackbar_manager::send_notification(); stackbar_manager::send_notification();
+1 -1
View File
@@ -51,7 +51,7 @@ pub fn find_orphans(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
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, offset, window_based_work_area_offset)?; workspace.update(&work_area, offset, window_based_work_area_offset)?;
border_manager::send_notification(); border_manager::send_notification(None);
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,
+39 -9
View File
@@ -35,8 +35,9 @@ use crate::DATA_DIR;
use crate::DEFAULT_CONTAINER_PADDING; use crate::DEFAULT_CONTAINER_PADDING;
use crate::DEFAULT_WORKSPACE_PADDING; use crate::DEFAULT_WORKSPACE_PADDING;
use crate::DISPLAY_INDEX_PREFERENCES; use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS; use crate::FLOATING_APPLICATIONS;
use crate::HIDING_BEHAVIOUR; use crate::HIDING_BEHAVIOUR;
use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST; use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES; use crate::MONITOR_INDEX_PREFERENCES;
@@ -304,10 +305,14 @@ pub struct StaticConfig {
pub global_work_area_offset: Option<Rect>, pub global_work_area_offset: Option<Rect>,
/// Individual window floating rules /// Individual window floating rules
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub float_rules: Option<Vec<MatchingRule>>, #[serde(alias = "float_rules")]
pub ignore_rules: Option<Vec<MatchingRule>>,
/// Individual window force-manage rules /// Individual window force-manage rules
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub manage_rules: Option<Vec<MatchingRule>>, pub manage_rules: Option<Vec<MatchingRule>>,
/// Identify applications which should be managed as floating windows
#[serde(skip_serializing_if = "Option::is_none")]
pub floating_applications: Option<Vec<MatchingRule>>,
/// Identify border overflow applications /// Identify border overflow applications
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub border_overflow_applications: Option<Vec<MatchingRule>>, pub border_overflow_applications: Option<Vec<MatchingRule>>,
@@ -371,6 +376,8 @@ pub enum KomorebiTheme {
stack_border: Option<komorebi_themes::CatppuccinValue>, stack_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the container is in monocle mode (default: Pink) /// Border colour when the container is in monocle mode (default: Pink)
monocle_border: Option<komorebi_themes::CatppuccinValue>, monocle_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the window is floating (default: Yellow)
floating_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the container is unfocused (default: Base) /// Border colour when the container is unfocused (default: Base)
unfocused_border: Option<komorebi_themes::CatppuccinValue>, unfocused_border: Option<komorebi_themes::CatppuccinValue>,
/// Stackbar focused tab text colour (default: Green) /// Stackbar focused tab text colour (default: Green)
@@ -392,6 +399,8 @@ pub enum KomorebiTheme {
stack_border: Option<komorebi_themes::Base16Value>, stack_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is in monocle mode (default: Base0F) /// Border colour when the container is in monocle mode (default: Base0F)
monocle_border: Option<komorebi_themes::Base16Value>, monocle_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the window is floating (default: Base09)
floating_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused (default: Base01) /// Border colour when the container is unfocused (default: Base01)
unfocused_border: Option<komorebi_themes::Base16Value>, unfocused_border: Option<komorebi_themes::Base16Value>,
/// Stackbar focused tab text colour (default: Base0B) /// Stackbar focused tab text colour (default: Base0B)
@@ -545,7 +554,8 @@ impl From<&WindowManager> for StaticConfig {
monitors: Option::from(monitors), monitors: Option::from(monitors),
window_hiding_behaviour: Option::from(*HIDING_BEHAVIOUR.lock()), window_hiding_behaviour: Option::from(*HIDING_BEHAVIOUR.lock()),
global_work_area_offset: value.work_area_offset, global_work_area_offset: value.work_area_offset,
float_rules: None, ignore_rules: None,
floating_applications: None,
manage_rules: None, manage_rules: None,
border_overflow_applications: None, border_overflow_applications: None,
tray_and_multi_window_applications: None, tray_and_multi_window_applications: None,
@@ -654,7 +664,7 @@ impl StaticConfig {
} }
} }
border_manager::send_notification(); border_manager::send_notification(None);
} }
transparency_manager::TRANSPARENCY_ENABLED transparency_manager::TRANSPARENCY_ENABLED
@@ -662,7 +672,7 @@ impl StaticConfig {
transparency_manager::TRANSPARENCY_ALPHA transparency_manager::TRANSPARENCY_ALPHA
.store(self.transparency_alpha.unwrap_or(200), Ordering::SeqCst); .store(self.transparency_alpha.unwrap_or(200), Ordering::SeqCst);
let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); let mut ignore_identifiers = IGNORE_IDENTIFIERS.lock();
let mut regex_identifiers = REGEX_IDENTIFIERS.lock(); let mut regex_identifiers = REGEX_IDENTIFIERS.lock();
let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); let mut manage_identifiers = MANAGE_IDENTIFIERS.lock();
let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock();
@@ -670,9 +680,14 @@ impl StaticConfig {
let mut layered_identifiers = LAYERED_WHITELIST.lock(); let mut layered_identifiers = LAYERED_WHITELIST.lock();
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock(); let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock(); let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
let mut floating_applications = FLOATING_APPLICATIONS.lock();
if let Some(rules) = &mut self.float_rules { if let Some(rules) = &mut self.ignore_rules {
populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?; populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?;
}
if let Some(rules) = &mut self.floating_applications {
populate_rules(rules, &mut floating_applications, &mut regex_identifiers)?;
} }
if let Some(rules) = &mut self.manage_rules { if let Some(rules) = &mut self.manage_rules {
@@ -752,6 +767,7 @@ impl StaticConfig {
single_border, single_border,
stack_border, stack_border,
monocle_border, monocle_border,
floating_border,
unfocused_border, unfocused_border,
stackbar_focused_text, stackbar_focused_text,
stackbar_unfocused_text, stackbar_unfocused_text,
@@ -762,6 +778,7 @@ impl StaticConfig {
single_border, single_border,
stack_border, stack_border,
monocle_border, monocle_border,
floating_border,
unfocused_border, unfocused_border,
stackbar_focused_text, stackbar_focused_text,
stackbar_unfocused_text, stackbar_unfocused_text,
@@ -780,6 +797,10 @@ impl StaticConfig {
.unwrap_or(komorebi_themes::CatppuccinValue::Pink) .unwrap_or(komorebi_themes::CatppuccinValue::Pink)
.color32(name.as_theme()); .color32(name.as_theme());
let floating_border = floating_border
.unwrap_or(komorebi_themes::CatppuccinValue::Yellow)
.color32(name.as_theme());
let unfocused_border = unfocused_border let unfocused_border = unfocused_border
.unwrap_or(komorebi_themes::CatppuccinValue::Base) .unwrap_or(komorebi_themes::CatppuccinValue::Base)
.color32(name.as_theme()); .color32(name.as_theme());
@@ -800,6 +821,7 @@ impl StaticConfig {
single_border, single_border,
stack_border, stack_border,
monocle_border, monocle_border,
floating_border,
unfocused_border, unfocused_border,
stackbar_focused_text, stackbar_focused_text,
stackbar_unfocused_text, stackbar_unfocused_text,
@@ -811,6 +833,7 @@ impl StaticConfig {
single_border, single_border,
stack_border, stack_border,
monocle_border, monocle_border,
floating_border,
unfocused_border, unfocused_border,
stackbar_focused_text, stackbar_focused_text,
stackbar_unfocused_text, stackbar_unfocused_text,
@@ -833,6 +856,10 @@ impl StaticConfig {
.unwrap_or(komorebi_themes::Base16Value::Base01) .unwrap_or(komorebi_themes::Base16Value::Base01)
.color32(*name); .color32(*name);
let floating_border = floating_border
.unwrap_or(komorebi_themes::Base16Value::Base09)
.color32(*name);
let stackbar_focused_text = stackbar_focused_text let stackbar_focused_text = stackbar_focused_text
.unwrap_or(komorebi_themes::Base16Value::Base0B) .unwrap_or(komorebi_themes::Base16Value::Base0B)
.color32(*name); .color32(*name);
@@ -849,6 +876,7 @@ impl StaticConfig {
single_border, single_border,
stack_border, stack_border,
monocle_border, monocle_border,
floating_border,
unfocused_border, unfocused_border,
stackbar_focused_text, stackbar_focused_text,
stackbar_unfocused_text, stackbar_unfocused_text,
@@ -861,6 +889,8 @@ impl StaticConfig {
border_manager::MONOCLE border_manager::MONOCLE
.store(u32::from(Colour::from(monocle_border)), Ordering::SeqCst); .store(u32::from(Colour::from(monocle_border)), Ordering::SeqCst);
border_manager::STACK.store(u32::from(Colour::from(stack_border)), Ordering::SeqCst); border_manager::STACK.store(u32::from(Colour::from(stack_border)), Ordering::SeqCst);
border_manager::FLOATING
.store(u32::from(Colour::from(floating_border)), Ordering::SeqCst);
border_manager::UNFOCUSED border_manager::UNFOCUSED
.store(u32::from(Colour::from(unfocused_border)), Ordering::SeqCst); .store(u32::from(Colour::from(unfocused_border)), Ordering::SeqCst);
@@ -886,8 +916,8 @@ impl StaticConfig {
let asc = ApplicationConfigurationGenerator::load(&content)?; let asc = ApplicationConfigurationGenerator::load(&content)?;
for mut entry in asc { for mut entry in asc {
if let Some(rules) = &mut entry.float_identifiers { if let Some(rules) = &mut entry.ignore_identifiers {
populate_rules(rules, &mut float_identifiers, &mut regex_identifiers)?; populate_rules(rules, &mut ignore_identifiers, &mut regex_identifiers)?;
} }
if let Some(ref options) = entry.options { if let Some(ref options) = entry.options {
+7 -7
View File
@@ -41,9 +41,9 @@ use crate::styles::WindowStyle;
use crate::transparency_manager; use crate::transparency_manager;
use crate::window_manager_event::WindowManagerEvent; use crate::window_manager_event::WindowManagerEvent;
use crate::windows_api::WindowsApi; use crate::windows_api::WindowsApi;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDDEN_HWNDS; use crate::HIDDEN_HWNDS;
use crate::HIDING_BEHAVIOUR; use crate::HIDING_BEHAVIOUR;
use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST; use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS;
use crate::NO_TITLEBAR; use crate::NO_TITLEBAR;
@@ -181,7 +181,7 @@ impl Window {
let mut animation = self.animation; let mut animation = self.animation;
border_manager::BORDER_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); border_manager::BORDER_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst);
border_manager::send_notification(); border_manager::send_notification(Some(self.hwnd));
stackbar_manager::STACKBAR_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); stackbar_manager::STACKBAR_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst);
stackbar_manager::send_notification(); stackbar_manager::send_notification();
@@ -203,7 +203,7 @@ impl Window {
stackbar_manager::STACKBAR_TEMPORARILY_DISABLED stackbar_manager::STACKBAR_TEMPORARILY_DISABLED
.store(false, Ordering::SeqCst); .store(false, Ordering::SeqCst);
border_manager::send_notification(); border_manager::send_notification(Some(hwnd));
stackbar_manager::send_notification(); stackbar_manager::send_notification();
transparency_manager::send_notification(); transparency_manager::send_notification();
} }
@@ -537,7 +537,7 @@ pub struct RuleDebug {
pub class: Option<String>, pub class: Option<String>,
pub path: Option<String>, pub path: Option<String>,
pub matches_permaignore_class: Option<String>, pub matches_permaignore_class: Option<String>,
pub matches_float_identifier: Option<MatchingRule>, pub matches_ignore_identifier: Option<MatchingRule>,
pub matches_managed_override: Option<MatchingRule>, pub matches_managed_override: Option<MatchingRule>,
pub matches_layered_whitelist: Option<MatchingRule>, pub matches_layered_whitelist: Option<MatchingRule>,
pub matches_wsl2_gui: Option<String>, pub matches_wsl2_gui: Option<String>,
@@ -566,16 +566,16 @@ fn window_is_eligible(
let regex_identifiers = REGEX_IDENTIFIERS.lock(); let regex_identifiers = REGEX_IDENTIFIERS.lock();
let float_identifiers = FLOAT_IDENTIFIERS.lock(); let ignore_identifiers = IGNORE_IDENTIFIERS.lock();
let should_float = if let Some(rule) = should_act( let should_float = if let Some(rule) = should_act(
title, title,
exe_name, exe_name,
class, class,
path, path,
&float_identifiers, &ignore_identifiers,
&regex_identifiers, &regex_identifiers,
) { ) {
debug.matches_float_identifier = Some(rule); debug.matches_ignore_identifier = Some(rule);
true true
} else { } else {
false false
+4 -3
View File
@@ -71,9 +71,9 @@ use crate::Rgb;
use crate::CUSTOM_FFM; use crate::CUSTOM_FFM;
use crate::DATA_DIR; use crate::DATA_DIR;
use crate::DISPLAY_INDEX_PREFERENCES; use crate::DISPLAY_INDEX_PREFERENCES;
use crate::FLOAT_IDENTIFIERS;
use crate::HIDING_BEHAVIOUR; use crate::HIDING_BEHAVIOUR;
use crate::HOME_DIR; use crate::HOME_DIR;
use crate::IGNORE_IDENTIFIERS;
use crate::LAYERED_WHITELIST; use crate::LAYERED_WHITELIST;
use crate::MANAGE_IDENTIFIERS; use crate::MANAGE_IDENTIFIERS;
use crate::MONITOR_INDEX_PREFERENCES; use crate::MONITOR_INDEX_PREFERENCES;
@@ -136,7 +136,8 @@ pub struct GlobalState {
pub stackbar_tab_width: i32, pub stackbar_tab_width: i32,
pub stackbar_height: i32, pub stackbar_height: i32,
pub remove_titlebars: bool, pub remove_titlebars: bool,
pub float_identifiers: Vec<MatchingRule>, #[serde(alias = "float_identifiers")]
pub ignore_identifiers: Vec<MatchingRule>,
pub manage_identifiers: Vec<MatchingRule>, pub manage_identifiers: Vec<MatchingRule>,
pub layered_whitelist: Vec<MatchingRule>, pub layered_whitelist: Vec<MatchingRule>,
pub tray_and_multi_window_identifiers: Vec<MatchingRule>, pub tray_and_multi_window_identifiers: Vec<MatchingRule>,
@@ -185,7 +186,7 @@ impl Default for GlobalState {
stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst), stackbar_tab_width: STACKBAR_TAB_WIDTH.load(Ordering::SeqCst),
stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst), stackbar_height: STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst),
remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst), remove_titlebars: REMOVE_TITLEBARS.load(Ordering::SeqCst),
float_identifiers: FLOAT_IDENTIFIERS.lock().clone(), ignore_identifiers: IGNORE_IDENTIFIERS.lock().clone(),
manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(), manage_identifiers: MANAGE_IDENTIFIERS.lock().clone(),
layered_whitelist: LAYERED_WHITELIST.lock().clone(), layered_whitelist: LAYERED_WHITELIST.lock().clone(),
tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(), tray_and_multi_window_identifiers: TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock().clone(),
+7 -26
View File
@@ -221,18 +221,19 @@ impl Workspace {
container.restore(); container.restore();
} }
for window in self.floating_windows() {
window.restore();
}
if let Some(container) = self.focused_container_mut() { if let Some(container) = self.focused_container_mut() {
container.focus_window(container.focused_window_idx()); container.focus_window(container.focused_window_idx());
} }
for window in self.floating_windows() {
window.restore();
}
// Do this here to make sure that an error doesn't stop the restoration of other windows // Do this here to make sure that an error doesn't stop the restoration of other windows
// Maximised windows should always be drawn at the top of the Z order // Maximised windows and floating windows should always be drawn at the top of the Z order
// when switching to a workspace
if let Some(window) = to_focus { if let Some(window) = to_focus {
if self.maximized_window().is_none() { if self.maximized_window().is_none() && self.floating_windows().is_empty() {
window.focus(mouse_follows_focus)?; window.focus(mouse_follows_focus)?;
} }
} }
@@ -393,26 +394,6 @@ impl Workspace {
Ok(()) Ok(())
} }
// focus_changed performs updates in response to the fact that a focus
// change event has occurred. The focus change is assumed to be valid, and
// should not result in a new focus change - the intent here is to update
// focus-reactive elements, such as the stackbar.
pub fn focus_changed(&mut self, hwnd: isize) -> Result<()> {
if !self.tile() {
return Ok(());
}
let containers = self.containers_mut();
for container in containers.iter_mut() {
if let Some(idx) = container.idx_for_window(hwnd) {
container.focus_window(idx);
container.restore();
}
}
Ok(())
}
pub fn reap_orphans(&mut self) -> Result<(usize, usize)> { pub fn reap_orphans(&mut self) -> Result<(usize, usize)> {
let mut hwnds = vec![]; let mut hwnds = vec![];
let mut floating_hwnds = vec![]; let mut floating_hwnds = vec![];
+1 -1
View File
@@ -118,7 +118,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
// Unblock the border manager // Unblock the border manager
ALT_TAB_HWND.store(None); ALT_TAB_HWND.store(None);
// Send a notification to the border manager to update the borders // Send a notification to the border manager to update the borders
border_manager::send_notification(); border_manager::send_notification(None);
} }
} }
} }
+6 -5
View File
@@ -583,7 +583,7 @@ macro_rules! gen_application_target_subcommand_args {
} }
gen_application_target_subcommand_args! { gen_application_target_subcommand_args! {
FloatRule, IgnoreRule,
ManageRule, ManageRule,
IdentifyTrayApplication, IdentifyTrayApplication,
IdentifyLayeredApplication, IdentifyLayeredApplication,
@@ -1208,9 +1208,10 @@ enum SubCommand {
/// Set the operation behaviour when the focused window is not managed /// Set the operation behaviour when the focused window is not managed
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour), UnmanagedWindowOperationBehaviour(UnmanagedWindowOperationBehaviour),
/// Add a rule to always float the specified application /// Add a rule to ignore the specified application
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
FloatRule(FloatRule), #[clap(alias = "float-rule")]
IgnoreRule(IgnoreRule),
/// Add a rule to always manage the specified application /// Add a rule to always manage the specified application
#[clap(arg_required_else_help = true)] #[clap(arg_required_else_help = true)]
ManageRule(ManageRule), ManageRule(ManageRule),
@@ -2154,8 +2155,8 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
} }
} }
} }
SubCommand::FloatRule(arg) => { SubCommand::IgnoreRule(arg) => {
send_message(&SocketMessage::FloatRule(arg.identifier, arg.id))?; send_message(&SocketMessage::IgnoreRule(arg.identifier, arg.id))?;
} }
SubCommand::ManageRule(arg) => { SubCommand::ManageRule(arg) => {
send_message(&SocketMessage::ManageRule(arg.identifier, arg.id))?; send_message(&SocketMessage::ManageRule(arg.identifier, arg.id))?;