Skip to content

Commit

Permalink
feat(wm): add stackbar for multi-window containers
Browse files Browse the repository at this point in the history
This commit introduces the stackbar feature through careful extracting
and refactoring of code from the Komorebi-UI hard-fork.

Unfortunately on the fork, this feature was not implemented using atomic
commits, which resulted in the implementation here being more of a
"reinterpretation" than a lift-and-shit of the referenced code.

Nevertheless, this commit represents a working version of the stackbar
feature.

resolve #681
  • Loading branch information
LGUG2Z committed Mar 25, 2024
1 parent 50a851a commit c65060f
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 34 deletions.
34 changes: 29 additions & 5 deletions komorebi-core/src/rect.rs
Expand Up @@ -26,13 +26,29 @@ impl From<RECT> for Rect {
}
}

impl From<Rect> for RECT {
fn from(rect: Rect) -> Self {
Self {
left: rect.left,
top: rect.top,
right: rect.right,
bottom: rect.bottom,
}
}
}

impl Rect {
/// decrease the size of self by the padding amount.
pub fn add_padding(&mut self, padding: i32) {
self.left += padding;
self.top += padding;
self.right -= padding * 2;
self.bottom -= padding * 2;
pub fn add_padding<T>(&mut self, padding: T)
where
T: Into<Option<i32>>,
{
if let Some(padding) = padding.into() {
self.left += padding;
self.top += padding;
self.right -= padding * 2;
self.bottom -= padding * 2;
}
}

/// increase the size of self by the margin amount.
Expand All @@ -43,6 +59,14 @@ impl Rect {
self.bottom += margin * 2;
}

pub fn left_padding(&mut self, padding: i32) {
self.left += padding;
}

pub fn right_padding(&mut self, padding: i32) {
self.right -= padding;
}

#[must_use]
pub const fn contains_point(&self, point: (i32, i32)) -> bool {
point.0 >= self.left
Expand Down
53 changes: 53 additions & 0 deletions komorebi/src/container.rs
Expand Up @@ -7,13 +7,18 @@ use serde::Deserialize;
use serde::Serialize;

use crate::ring::Ring;
use crate::stackbar::Stackbar;
use crate::window::Window;
use crate::StackbarMode;
use crate::STACKBAR_MODE;

#[derive(Debug, Clone, Serialize, Deserialize, Getters, JsonSchema)]
pub struct Container {
#[getset(get = "pub")]
id: String,
windows: Ring<Window>,
#[getset(get = "pub", get_mut = "pub")]
stackbar: Option<Stackbar>,
}

impl_ring_elements!(Container, Window);
Expand All @@ -23,6 +28,10 @@ impl Default for Container {
Self {
id: nanoid!(),
windows: Ring::default(),
stackbar: match *STACKBAR_MODE.lock() {
StackbarMode::Always => Stackbar::create().ok(),
StackbarMode::Never | StackbarMode::OnStack => None,
},
}
}
}
Expand All @@ -34,6 +43,38 @@ impl PartialEq for Container {
}

impl Container {
pub fn hide(&self, omit: Option<isize>) {
if let Some(stackbar) = self.stackbar() {
stackbar.hide();
}

for window in self.windows().iter().rev() {
let mut should_hide = omit.is_none();

if !should_hide {
if let Some(omit) = omit {
if omit != window.hwnd {
should_hide = true
}
}
}

if should_hide {
window.hide();
}
}
}

pub fn restore(&self) {
if let Some(stackbar) = self.stackbar() {
stackbar.restore();
}

if let Some(window) = self.focused_window() {
window.restore();
}
}

pub fn load_focused_window(&mut self) {
let focused_idx = self.focused_window_idx();
for (i, window) in self.windows_mut().iter_mut().enumerate() {
Expand Down Expand Up @@ -81,6 +122,10 @@ impl Container {
pub fn remove_window_by_idx(&mut self, idx: usize) -> Option<Window> {
let window = self.windows_mut().remove(idx);

if matches!(*STACKBAR_MODE.lock(), StackbarMode::OnStack) && self.windows().len() <= 1 {
self.stackbar = None;
}

if idx != 0 {
self.focus_window(idx - 1);
};
Expand All @@ -95,6 +140,14 @@ impl Container {

pub fn add_window(&mut self, window: Window) {
self.windows_mut().push_back(window);

if matches!(*STACKBAR_MODE.lock(), StackbarMode::OnStack)
&& self.windows().len() > 1
&& self.stackbar.is_none()
{
self.stackbar = Stackbar::create().ok();
}

self.focus_window(self.windows().len() - 1);
}

Expand Down
14 changes: 14 additions & 0 deletions komorebi/src/lib.rs
Expand Up @@ -10,6 +10,7 @@ pub mod process_command;
pub mod process_event;
pub mod process_movement;
pub mod set_window_position;
pub mod stackbar;
pub mod static_config;
pub mod styles;
pub mod window;
Expand All @@ -23,6 +24,7 @@ pub mod workspace;

use lazy_static::lazy_static;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Write;
use std::net::TcpStream;
Expand All @@ -38,6 +40,7 @@ use std::sync::Arc;
pub use hidden::*;
pub use process_command::*;
pub use process_event::*;
pub use stackbar::*;
pub use static_config::*;
pub use window_manager::*;
pub use window_manager_event::*;
Expand Down Expand Up @@ -198,6 +201,11 @@ lazy_static! {
// Use app-specific titlebar removal options where possible
// eg. Windows Terminal, IntelliJ IDEA, Firefox
static ref NO_TITLEBAR: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));

static ref STACKBAR_MODE: Arc<Mutex<StackbarMode >> = Arc::new(Mutex::new(StackbarMode::Never));
static ref WINDOWS_BY_BAR_HWNDS: Arc<Mutex<HashMap<isize, VecDeque<isize>>>> =
Arc::new(Mutex::new(HashMap::new()));

}

pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10);
Expand All @@ -222,6 +230,12 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);

pub static HIDDEN_HWND: AtomicIsize = AtomicIsize::new(0);

pub static STACKBAR_FOCUSED_TEXT_COLOUR: AtomicU32 = AtomicU32::new(16777215); // white
pub static STACKBAR_UNFOCUSED_TEXT_COLOUR: AtomicU32 = AtomicU32::new(11776947); // gray text
pub static STACKBAR_TAB_BACKGROUND_COLOUR: AtomicU32 = AtomicU32::new(3355443); // gray
pub static STACKBAR_TAB_HEIGHT: AtomicI32 = AtomicI32::new(40);
pub static STACKBAR_TAB_WIDTH: AtomicI32 = AtomicI32::new(200);

#[must_use]
pub fn current_virtual_desktop() -> Option<Vec<u8>> {
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
Expand Down
2 changes: 1 addition & 1 deletion komorebi/src/monitor.rs
Expand Up @@ -71,7 +71,7 @@ impl Monitor {
if i == focused_idx {
workspace.restore(mouse_follows_focus)?;
} else {
workspace.hide();
workspace.hide(None);
}
}

Expand Down
1 change: 1 addition & 0 deletions komorebi/src/process_command.rs
Expand Up @@ -217,6 +217,7 @@ impl WindowManager {
SocketMessage::UnstackWindow => self.remove_window_from_container()?,
SocketMessage::CycleStack(direction) => {
self.cycle_container_window_in_direction(direction)?;
self.focused_window()?.focus(self.mouse_follows_focus)?;
}
SocketMessage::ForceFocus => {
let focused_window = self.focused_window()?;
Expand Down
3 changes: 3 additions & 0 deletions komorebi/src/process_event.rs
Expand Up @@ -518,6 +518,9 @@ impl WindowManager {
}
}
}
WindowManagerEvent::ForceUpdate(_) => {
self.update_focused_workspace(false)?;
}
WindowManagerEvent::DisplayChange(..)
| WindowManagerEvent::MouseCapture(..)
| WindowManagerEvent::Cloak(..)
Expand Down

0 comments on commit c65060f

Please sign in to comment.