Compare commits

..

3 Commits

Author SHA1 Message Date
LGUG2Z
57825db886 wip 2024-05-19 11:51:10 -07:00
LGUG2Z
bdf66cc362 feat(wm): auto toggle-monocle on alt-tab
This commit adds a change to automatically toggle monocle mode off on
the focused workspace when a window on the same workspace is
foregrounded by alt-tab.

resolve #834
2024-05-19 11:08:06 -07:00
LGUG2Z
2a45f981e6 feat(stackbar): add stackbar manager module
This commit removes all stackbar-related code from Container, Workspace,
process_command, process_event etc. and centralizes it in the new
stackbar_manager module.

Instead of trying to figure out where in process_event and
process_command we should make stackbar-related changes, a notification
gets sent to a channel that stackbar_manager listens to whenever an
event or command has finished processing.

The stackbar_manager listener, upon receiving a notification, acquires a
lock on the WindowManager instance and updates stackbars for the focused
workspace on every monitor; this allows us to centralize all edge case
handling within the stackbar_manager listener's loop.

Global state related to stackbars has also been moved into the
stackbar_manager module, which also tracks the state of stackbar objects
(STACKBAR_STATE), mappings between stackbars and containers
(STACKBARS_CONTAINERS) and the mappings between stackbars and monitors
(STACKBARS_MONITORS).

A number of edge cases around stackbar behaviour have been addressed in
this commit (re #832), and stackbars now respect the "border_style"
configuration option.
2024-05-19 10:55:40 -07:00
7 changed files with 32 additions and 64 deletions

View File

@@ -6,7 +6,6 @@ use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use crossbeam_utils::atomic::AtomicConsume;
use komorebi_core::BorderStyle;
use komorebi_core::StackbarMode;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use schemars::JsonSchema;
@@ -23,8 +22,6 @@ use std::time::Duration;
use std::time::Instant;
use windows::Win32::Foundation::HWND;
use crate::stackbar_manager;
use crate::stackbar_manager::STACKBAR_MODE;
use crate::workspace_reconciliator::ALT_TAB_HWND;
use crate::Colour;
use crate::Rect;
@@ -59,10 +56,7 @@ lazy_static! {
static ref FOCUS_STATE: Mutex<HashMap<isize, WindowKind>> = Mutex::new(HashMap::new());
}
pub enum Notification {
Default,
Move,
}
pub struct Notification;
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
@@ -130,9 +124,9 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
let receiver = event_rx();
let mut instant: Option<Instant> = None;
event_tx().send(Notification::Default)?;
event_tx().send(Notification)?;
'receiver: for notification in receiver {
'receiver: for _ in receiver {
if let Some(instant) = instant {
if instant.elapsed().lt(&Duration::from_millis(50)) {
continue 'receiver;
@@ -276,40 +270,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
borders.remove(id);
}
let workspace_has_stack = {
let mut should = false;
for c in ws.containers() {
if stackbar_manager::should_have_stackbar(c.windows().len()) {
should = true;
}
}
should
};
let stackbar_mode = STACKBAR_MODE.load();
let workspace_has_stackbar = matches!(stackbar_mode, StackbarMode::Always)
|| workspace_has_stack && matches!(stackbar_mode, StackbarMode::OnStack);
if matches!(notification, Notification::Move) && workspace_has_stackbar {
let focus_state = FOCUS_STATE.lock();
let mut to_remove = vec![];
for (id, border) in borders.iter() {
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
&& container_ids.contains(id)
&& matches!(focus_state.get(&border.hwnd), Some(&WindowKind::Unfocused))
{
border.destroy()?;
to_remove.push(id.clone());
}
}
for id in &to_remove {
borders.remove(id);
}
}
for (idx, c) in ws.containers().iter().enumerate() {
// Update border when moving or resizing with mouse
if state.pending_move_op.is_some() && idx == ws.focused_container_idx() {

View File

@@ -160,7 +160,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
if should_update {
tracing::info!("updated work area for {}", monitor.device_id());
monitor.update_focused_workspace(offset)?;
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
} else {
tracing::debug!(
"work areas match, reconciliation not required for {}",
@@ -207,7 +207,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
);
monitor.update_focused_workspace(offset)?;
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
} else {
tracing::debug!(
"resolutions match, reconciliation not required for {}",
@@ -394,7 +394,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
// Second retile to fix DPI/resolution related jank
wm.retile_all(true)?;
// Border updates to fix DPI/resolution related jank
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
}
}
}

View File

@@ -196,7 +196,6 @@ impl WindowManager {
}
SocketMessage::MoveWindow(direction) => {
self.move_container_in_direction(direction)?;
border_manager::event_tx().send(border_manager::Notification::Move)?;
}
SocketMessage::CycleFocusWindow(direction) => {
self.focus_container_in_cycle_direction(direction)?;
@@ -1335,7 +1334,7 @@ impl WindowManager {
};
notify_subscribers(&serde_json::to_string(&notification)?)?;
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
stackbar_manager::event_tx().send(stackbar_manager::Notification)?;
tracing::info!("processed");

View File

@@ -334,8 +334,10 @@ impl WindowManager {
if proceed {
let behaviour = self.window_container_behaviour;
let workspace = self.focused_workspace_mut()?;
let workspace_contains_window = workspace.contains_window(window.hwnd);
let workspace_has_monocle_container = workspace.monocle_container().is_some();
if !workspace.contains_window(window.hwnd) && !needs_reconciliation {
if !workspace_contains_window && !needs_reconciliation {
match behaviour {
WindowContainerBehaviour::Create => {
workspace.new_container_for_window(window);
@@ -350,6 +352,13 @@ impl WindowManager {
}
}
}
if matches!(event, WindowManagerEvent::Uncloak(_, _)) {
if workspace_contains_window && workspace_has_monocle_container {
self.toggle_monocle()?;
window.focus(self.mouse_follows_focus)?;
}
}
}
}
WindowManagerEvent::MoveResizeStart(_, window) => {
@@ -442,10 +451,7 @@ impl WindowManager {
// If we have moved across the monitors, use that override, otherwise determine
// if a move has taken place by ruling out a resize
let right_bottom_constant = ((BORDER_WIDTH.load(Ordering::SeqCst)
+ BORDER_OFFSET.load(Ordering::SeqCst))
* 2)
.abs();
let right_bottom_constant = 0;
let is_move = moved_across_monitors
|| resize.right.abs() == right_bottom_constant
@@ -620,7 +626,7 @@ impl WindowManager {
};
notify_subscribers(&serde_json::to_string(&notification)?)?;
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
stackbar_manager::event_tx().send(stackbar_manager::Notification)?;
tracing::info!("processed: {}", event.window().to_string());

View File

@@ -1129,7 +1129,11 @@ impl WindowManager {
tracing::info!("focusing container");
let new_idx = workspace.new_idx_for_direction(direction);
let new_idx = if workspace.monocle_container().is_some() {
None
} else {
workspace.new_idx_for_direction(direction)
};
let mut cross_monitor_monocle = false;

View File

@@ -305,7 +305,7 @@ impl Workspace {
} else if let Some(window) = self.maximized_window_mut() {
window.maximize();
} else if !self.containers().is_empty() {
let layouts = self.layout().as_boxed_arrangement().calculate(
let mut layouts = self.layout().as_boxed_arrangement().calculate(
&adjusted_work_area,
NonZeroUsize::new(self.containers().len()).ok_or_else(|| {
anyhow!(
@@ -327,7 +327,7 @@ impl Workspace {
let window_count = container.windows().len();
if let (Some(window), Some(layout)) =
(container.focused_window_mut(), layouts.get(i))
(container.focused_window_mut(), layouts.get_mut(i))
{
if should_remove_titlebars && no_titlebar.contains(&window.exe()?) {
window.remove_title_bar()?;
@@ -341,24 +341,23 @@ impl Workspace {
WindowsApi::restore_window(window.hwnd());
}
let mut rect = *layout;
{
let border_offset = BORDER_OFFSET.load(Ordering::SeqCst);
rect.add_padding(border_offset);
layout.add_padding(border_offset);
let width = BORDER_WIDTH.load(Ordering::SeqCst);
rect.add_padding(width);
layout.add_padding(width);
}
if stackbar_manager::should_have_stackbar(window_count) {
let tab_height = STACKBAR_TAB_HEIGHT.load(Ordering::SeqCst);
let total_height = tab_height + container_padding;
rect.top += total_height;
rect.bottom -= total_height;
layout.top += total_height;
layout.bottom -= total_height;
}
window.set_position(&rect, false)?;
window.set_position(&layout, false)?;
}
}

View File

@@ -106,7 +106,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
// Unblock the border manager
ALT_TAB_HWND.store(None);
// Send a notification to the border manager to update the borders
border_manager::event_tx().send(border_manager::Notification::Default)?;
border_manager::event_tx().send(border_manager::Notification)?;
}
}
}