Compare commits

..

4 Commits

Author SHA1 Message Date
LGUG2Z
70a12802db feat(wm): use monitor hardware ids where available
This commit pulls in changes to win32-display-data which provide the
monitor hardware serial number id taken from WmiMonitorID where
available.

No work has yet been done to integrate this with options such as
display_index_preferences.
2025-01-25 15:37:46 -08:00
LGUG2Z
15e443a46b feat(config): add object name change title ignore list
This commit adds a title regex-based ignore list for applications
identified in object_name_change_applications. When a title change on an
EVENT_OBJECT_NAMECHANGE matches one of these regexes, the event will
never be processed as a Show.

This is an edge case workaround specifically targeting the issue of web
apps in Gecko-based browsers which update their page titles at a fixed
regular interval, which was highlighted in #1235.

resolve #1235
2025-01-24 15:50:45 -08:00
LGUG2Z
367ae95cd4 fix(wm): populate ws rules on config reload
This commit fixes a bug where workspace rules would not be populated
properly on file reloads, leading to issues with the
ReplaceConfiguration message handler.
2025-01-24 14:37:43 -08:00
LGUG2Z
edcba65156 fix(bar): consider all window types when hiding empty ws
This commit ensures that floating windows, monocle containers and
maximized windows will be considered when the hide_empty_workspaces
option is enabled for the komorebi widget.

re #1131
2025-01-24 12:48:12 -08:00
42 changed files with 293 additions and 966 deletions

415
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@ crossbeam-utils = "0.8"
color-eyre = "0.6"
eframe = "0.30"
egui_extras = "0.30"
dirs = "6"
dirs = "5"
dunce = "1"
hotwatch = "0.5"
schemars = "0.8"
@@ -37,7 +37,7 @@ win32-display-data = { git = "https://github.com/LGUG2Z/win32-display-data", rev
windows-implement = { version = "0.58" }
windows-interface = { version = "0.58" }
windows-core = { version = "0.58" }
shadow-rs = "0.38"
shadow-rs = "0.37"
which = "7"
[workspace.dependencies.windows]
@@ -48,7 +48,6 @@ features = [
"Win32_System_Com",
"Win32_UI_Shell_Common", # for IObjectArray
"Win32_Foundation",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Win32_Graphics_Gdi",
"Win32_Graphics_Direct2D",

View File

@@ -389,7 +389,7 @@ every `WindowManagerEvent` and `SocketMessage` handled by `komorebi` in a Rust c
Below is a simple example of how to use `komorebi-client` in a basic Rust application.
```rust
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.34"}
// komorebi-client = { git = "https://github.com/LGUG2Z/komorebi", tag = "v0.1.33"}
use anyhow::Result;
use komorebi_client::Notification;

View File

@@ -1,7 +1,7 @@
# flip-layout
```
Flip the layout on the focused workspace
Flip the layout on the focused workspace (BSP only)
Usage: komorebic.exe flip-layout <AXIS>

View File

@@ -1,12 +0,0 @@
# focus-monitor-at-cursor
```
Focus the monitor at the current cursor location
Usage: komorebic.exe focus-monitor-at-cursor
Options:
-h, --help
Print help
```

View File

@@ -7,7 +7,7 @@ Usage: komorebic.exe query <STATE_QUERY>
Arguments:
<STATE_QUERY>
[possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index, focused-workspace-name]
[possible values: focused-monitor-index, focused-workspace-index, focused-container-index, focused-window-index]
Options:
-h, --help

View File

@@ -75,7 +75,7 @@ solo developer.
If you choose to use the active window border, you can set different colours to
give you visual queues when you are focused on a single window, a stack of
windows, or a window that is in monocle mode.
windows, or a window that is in monocole mode.
The example colours given are blue single, green for stack and pink for
monocle.
@@ -254,5 +254,5 @@ stackbars as well as the status bar.
If set in `komorebi.bar.json`, the theme will only be applied to the status bar.
All [Catppuccin palette variants](https://catppuccin.com/)
and [most Base16 palette variants](https://tinted-theming.github.io/tinted-gallery/)
and [most Base16 palette variants](https://tinted-theming.github.io/base16-gallery/)
are available as themes.

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.34/schema.bar.json",
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.33/schema.bar.json",
"monitor": 0,
"font_family": "JetBrains Mono",
"theme": {

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.34/schema.json",
"$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.33/schema.json",
"app_specific_configuration_path": "$Env:USERPROFILE/applications.json",
"window_hiding_behaviour": "Cloak",
"cross_monitor_move_behaviour": "Insert",

View File

@@ -24,15 +24,6 @@ install-target target:
install:
just install-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
build-targets *targets:
"{{ targets }}" -split ' ' | ForEach-Object { just build-target $_ }
build-target target:
cargo +stable build --release --package {{ target }} --locked
build:
just build-targets komorebic komorebic-no-console komorebi komorebi-bar komorebi-gui
run target:
cargo +stable run --bin {{ target }} --locked

View File

@@ -571,7 +571,6 @@ impl Komobar {
fallbacks.insert("Microsoft YaHei", "C:\\Windows\\Fonts\\msyh.ttc"); // chinese
fallbacks.insert("Malgun Gothic", "C:\\Windows\\Fonts\\malgun.ttf"); // korean
fallbacks.insert("Leelawadee UI", "C:\\Windows\\Fonts\\LeelawUI.ttf"); // thai
for (name, path) in fallbacks {
if let Ok(bytes) = std::fs::read(path) {

View File

@@ -366,7 +366,7 @@ pub enum KomobarTheme {
},
/// A theme from base16-egui-themes
Base16 {
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/base16-gallery)
name: komorebi_themes::Base16,
accent: Option<komorebi_themes::Base16Value>,
},

View File

@@ -1,177 +0,0 @@
use crate::config::LabelPrefix;
use crate::render::RenderConfig;
use crate::widget::BarWidget;
use eframe::egui::text::LayoutJob;
use eframe::egui::Align;
use eframe::egui::Context;
use eframe::egui::Label;
use eframe::egui::TextFormat;
use eframe::egui::Ui;
use eframe::egui::WidgetText;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::time::Duration;
use std::time::Instant;
use windows::Win32::Globalization::LCIDToLocaleName;
use windows::Win32::Globalization::LOCALE_ALLOW_NEUTRAL_NAMES;
use windows::Win32::System::SystemServices::LOCALE_NAME_MAX_LENGTH;
use windows::Win32::UI::Input::KeyboardAndMouse::GetKeyboardLayout;
use windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
const DEFAULT_DATA_REFRESH_INTERVAL: u64 = 1;
const ERROR_TEXT: &str = "Error";
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct KeyboardConfig {
/// Enable the Input widget
pub enable: bool,
/// Data refresh interval (default: 1 second)
pub data_refresh_interval: Option<u64>,
/// Display label prefix
pub label_prefix: Option<LabelPrefix>,
}
impl From<KeyboardConfig> for Keyboard {
fn from(value: KeyboardConfig) -> Self {
let data_refresh_interval = value
.data_refresh_interval
.unwrap_or(DEFAULT_DATA_REFRESH_INTERVAL);
Self {
enable: value.enable,
data_refresh_interval,
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
last_updated: Instant::now(),
lang_name: get_lang(),
}
}
}
pub struct Keyboard {
pub enable: bool,
data_refresh_interval: u64,
label_prefix: LabelPrefix,
last_updated: Instant,
lang_name: String,
}
/// Retrieves the name of the active keyboard layout for the current foreground window.
///
/// This function determines the active keyboard layout by querying the system for the
/// foreground window's thread ID and its associated keyboard layout. It then attempts
/// to retrieve the locale name corresponding to the keyboard layout.
///
/// # Failure Cases
///
/// This function can fail in two distinct scenarios:
///
/// 1. **Failure to Retrieve the Locale Name**:
/// If the system fails to retrieve the locale name (e.g., due to an invalid or unsupported
/// language identifier), the function will return `Err(())`.
///
/// 2. **Invalid UTF-16 Characters in the Locale Name**:
/// If the retrieved locale name contains invalid UTF-16 sequences, the conversion to a Rust
/// `String` will fail, and the function will return `Err(())`.
///
/// # Returns
///
/// - `Ok(String)`: The name of the active keyboard layout as a valid UTF-8 string.
/// - `Err(())`: Indicates that the function failed to retrieve the locale name or encountered
/// invalid UTF-16 characters during conversion.
fn get_active_keyboard_layout() -> Result<String, ()> {
let foreground_window_tid = unsafe { GetWindowThreadProcessId(GetForegroundWindow(), None) };
let lcid = unsafe { GetKeyboardLayout(foreground_window_tid) };
// Extract the low word (language identifier) from the keyboard layout handle.
let lang_id = (lcid.0 as u32) & 0xFFFF;
let mut locale_name_buffer = [0; LOCALE_NAME_MAX_LENGTH as usize];
let char_count = unsafe {
LCIDToLocaleName(
lang_id,
Some(&mut locale_name_buffer),
LOCALE_ALLOW_NEUTRAL_NAMES,
)
};
match char_count {
0 => Err(()),
_ => String::from_utf16(&locale_name_buffer[..char_count as usize]).map_err(|_| ()),
}
}
/// Retrieves the name of the active keyboard layout or a fallback error message.
///
/// # Behavior
///
/// - **Success Case**:
/// If [`get_active_keyboard_layout`] succeeds, this function returns the retrieved keyboard
/// layout name as a `String`.
///
/// - **Failure Case**:
/// If [`get_active_keyboard_layout`] fails, this function returns the value of `ERROR_TEXT`
/// as a fallback message. This ensures that the function always returns a valid `String`,
/// even in error scenarios.
///
/// # Returns
///
/// A `String` representing either:
/// - The name of the active keyboard layout, or
/// - The fallback error message (`ERROR_TEXT`) if the layout name cannot be retrieved.
fn get_lang() -> String {
get_active_keyboard_layout()
.map(|l| l.trim_end_matches('\0').to_string())
.unwrap_or_else(|_| ERROR_TEXT.to_string())
}
impl Keyboard {
fn output(&mut self) -> String {
let now = Instant::now();
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
self.last_updated = now;
self.lang_name = get_lang();
}
match self.label_prefix {
LabelPrefix::Text | LabelPrefix::IconAndText => format!("KB: {}", self.lang_name),
LabelPrefix::None | LabelPrefix::Icon => self.lang_name.clone(),
}
}
}
impl BarWidget for Keyboard {
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
if self.enable {
let output = self.output();
if !output.is_empty() {
let mut layout_job = LayoutJob::simple(
match self.label_prefix {
LabelPrefix::Icon | LabelPrefix::IconAndText => {
egui_phosphor::regular::KEYBOARD.to_string()
}
LabelPrefix::None | LabelPrefix::Text => String::new(),
},
config.icon_font_id.clone(),
ctx.style().visuals.selection.stroke.color,
100.0,
);
layout_job.append(
&output,
10.0,
TextFormat {
font_id: config.text_font_id.clone(),
color: ctx.style().visuals.text_color(),
valign: Align::Center,
..Default::default()
},
);
config.apply_on_widget(true, ui, |ui| {
ui.add(Label::new(WidgetText::LayoutJob(layout_job.clone())).selectable(false))
});
}
}
}
}

View File

@@ -570,7 +570,11 @@ impl KomorebiNotificationState {
for (i, ws) in monitor.workspaces().iter().enumerate() {
let should_show = if self.hide_empty_workspaces {
focused_workspace_idx == i || !ws.is_empty()
focused_workspace_idx == i
|| !ws.containers().is_empty()
|| !ws.floating_windows().is_empty()
|| ws.monocle_container().is_some()
|| ws.maximized_window().is_some()
} else {
true
};

View File

@@ -3,7 +3,6 @@ mod battery;
mod config;
mod cpu;
mod date;
mod keyboard;
mod komorebi;
mod komorebi_layout;
mod media;

View File

@@ -148,7 +148,7 @@ impl Network {
LabelPrefix::None | LabelPrefix::Icon => match reading.format {
NetworkReadingFormat::Speed => (
format!(
"{: >width$}/s ",
"{: >width$}/s | ",
reading.received_text,
width = self.network_activity_fill_characters
),
@@ -159,14 +159,14 @@ impl Network {
),
),
NetworkReadingFormat::Total => (
format!("{} ", reading.received_text),
format!("{} | ", reading.received_text),
reading.transmitted_text,
),
},
LabelPrefix::Text | LabelPrefix::IconAndText => match reading.format {
NetworkReadingFormat::Speed => (
format!(
"DOWN: {: >width$}/s ",
"DOWN: {: >width$}/s | ",
reading.received_text,
width = self.network_activity_fill_characters
),
@@ -177,7 +177,7 @@ impl Network {
),
),
NetworkReadingFormat::Total => (
format!("\u{2211}DOWN: {}/s ", reading.received_text),
format!("\u{2211}DOWN: {}/s | ", reading.received_text),
format!("\u{2211}UP: {}/s", reading.transmitted_text),
),
},

View File

@@ -4,8 +4,6 @@ use crate::cpu::Cpu;
use crate::cpu::CpuConfig;
use crate::date::Date;
use crate::date::DateConfig;
use crate::keyboard::Keyboard;
use crate::keyboard::KeyboardConfig;
use crate::komorebi::Komorebi;
use crate::komorebi::KomorebiConfig;
use crate::media::Media;
@@ -36,7 +34,6 @@ pub enum WidgetConfig {
Battery(BatteryConfig),
Cpu(CpuConfig),
Date(DateConfig),
Keyboard(KeyboardConfig),
Komorebi(KomorebiConfig),
Media(MediaConfig),
Memory(MemoryConfig),
@@ -52,7 +49,6 @@ impl WidgetConfig {
WidgetConfig::Battery(config) => Box::new(Battery::from(*config)),
WidgetConfig::Cpu(config) => Box::new(Cpu::from(*config)),
WidgetConfig::Date(config) => Box::new(Date::from(config.clone())),
WidgetConfig::Keyboard(config) => Box::new(Keyboard::from(*config)),
WidgetConfig::Komorebi(config) => Box::new(Komorebi::from(config)),
WidgetConfig::Media(config) => Box::new(Media::from(*config)),
WidgetConfig::Memory(config) => Box::new(Memory::from(*config)),
@@ -68,7 +64,6 @@ impl WidgetConfig {
WidgetConfig::Battery(config) => config.enable,
WidgetConfig::Cpu(config) => config.enable,
WidgetConfig::Date(config) => config.enable,
WidgetConfig::Keyboard(config) => config.enable,
WidgetConfig::Komorebi(config) => {
config.workspaces.as_ref().is_some_and(|w| w.enable)
|| config.layout.as_ref().is_some_and(|w| w.enable)

View File

@@ -2,15 +2,10 @@
#![allow(clippy::missing_errors_doc)]
pub use komorebi::animation::prefix::AnimationPrefix;
pub use komorebi::animation::PerAnimationPrefixConfig;
pub use komorebi::asc::ApplicationSpecificConfiguration;
pub use komorebi::colour::Colour;
pub use komorebi::colour::Rgb;
pub use komorebi::config_generation::ApplicationConfiguration;
pub use komorebi::config_generation::IdWithIdentifier;
pub use komorebi::config_generation::IdWithIdentifierAndComment;
pub use komorebi::config_generation::MatchingRule;
pub use komorebi::config_generation::MatchingStrategy;
pub use komorebi::container::Container;
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
pub use komorebi::core::resolve_home_path;
@@ -20,10 +15,6 @@ pub use komorebi::core::Arrangement;
pub use komorebi::core::Axis;
pub use komorebi::core::BorderImplementation;
pub use komorebi::core::BorderStyle;
pub use komorebi::core::Column;
pub use komorebi::core::ColumnSplit;
pub use komorebi::core::ColumnSplitWithCapacity;
pub use komorebi::core::ColumnWidth;
pub use komorebi::core::CustomLayout;
pub use komorebi::core::CycleDirection;
pub use komorebi::core::DefaultLayout;
@@ -48,24 +39,17 @@ pub use komorebi::ring::Ring;
pub use komorebi::window::Window;
pub use komorebi::window_manager_event::WindowManagerEvent;
pub use komorebi::workspace::Workspace;
pub use komorebi::AnimationsConfig;
pub use komorebi::AspectRatio;
pub use komorebi::BorderColours;
pub use komorebi::CrossBoundaryBehaviour;
pub use komorebi::GlobalState;
pub use komorebi::KomorebiTheme;
pub use komorebi::MonitorConfig;
pub use komorebi::Notification;
pub use komorebi::NotificationEvent;
pub use komorebi::PredefinedAspectRatio;
pub use komorebi::RuleDebug;
pub use komorebi::StackbarConfig;
pub use komorebi::State;
pub use komorebi::StaticConfig;
pub use komorebi::SubscribeOptions;
pub use komorebi::TabsConfig;
pub use komorebi::WindowContainerBehaviour;
pub use komorebi::WorkspaceConfig;
use komorebi::DATA_DIR;

View File

@@ -10,6 +10,6 @@ komorebi-client = { path = "../komorebi-client" }
eframe = { workspace = true }
egui_extras = { workspace = true }
random_word = { version = "0.4", features = ["en"] }
random_word = { version = "0.4.3", features = ["en"] }
serde_json = { workspace = true }
windows = { workspace = true }

View File

@@ -4,11 +4,11 @@ version = "0.1.34"
edition = "2021"
[dependencies]
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "911079d" }
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "24362c4" }
catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "f85cc3c", default-features = false, features = ["egui30"] }
#catppuccin-egui = { version = "5", default-features = false, features = ["egui30"] }
eframe = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
serde_variant = "0.1"
strum = "0.26"
strum = "0.26"

View File

@@ -4,7 +4,6 @@
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use strum::Display;
use strum::IntoEnumIterator;
pub use base16_egui_themes::Base16;
@@ -12,7 +11,7 @@ pub use catppuccin_egui;
pub use eframe::egui::Color32;
use serde_variant::to_variant_name;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type")]
pub enum Theme {
/// A theme from catppuccin-egui
@@ -49,7 +48,7 @@ impl Theme {
}
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, Display, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub enum Base16Value {
Base00,
Base01,
@@ -93,7 +92,7 @@ impl Base16Value {
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Display, PartialEq)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub enum Catppuccin {
Frappe,
Latte,
@@ -118,7 +117,7 @@ impl From<Catppuccin> for catppuccin_egui::Theme {
}
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, Display, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub enum CatppuccinValue {
Rosewater,
Flamingo,

View File

@@ -25,7 +25,7 @@ lazy_static = { workspace = true }
miow = "0.6"
nanoid = "0.4"
net2 = "0.2"
os_info = "3.10"
os_info = "3.8"
parking_lot = "0.12"
paste = { workspace = true }
regex = "1"

View File

@@ -22,7 +22,7 @@ use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum PerAnimationPrefixConfig<T> {
Prefix(HashMap<AnimationPrefix, T>),

View File

@@ -29,7 +29,6 @@ use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::OnceLock;
use strum::Display;
use windows::Win32::Graphics::Direct2D::ID2D1HwndRenderTarget;
pub static BORDER_WIDTH: AtomicI32 = AtomicI32::new(8);
@@ -212,16 +211,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
.unwrap_or_default()
.set_accent(window_kind_colour(window_kind))?;
}
for window in ws.floating_windows() {
let mut window_kind = WindowKind::Unfocused;
if foreground_window == window.hwnd {
window_kind = WindowKind::Floating;
}
window.set_accent(window_kind_colour(window_kind))?;
}
}
}
}
@@ -262,7 +251,6 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
.map(|b| b.window_kind == WindowKind::Floating)
.unwrap_or_default())
});
if !should_process_notification && switch_focus_to_from_floating_window {
should_process_notification = true;
}
@@ -500,7 +488,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
Some(last_focus_state) => last_focus_state != new_focus_state,
};
if new_border || should_invalidate {
if new_border {
border.set_position(&rect, reference_hwnd)?;
}
@@ -580,7 +568,7 @@ pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result
Ok(())
}
#[derive(Debug, Copy, Clone, Display, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
pub enum ZOrder {
Top,
NoTopMost,

View File

@@ -8,7 +8,7 @@ use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum Colour {
/// Colour represented as RGB
@@ -51,7 +51,7 @@ impl From<Colour> for Color32 {
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct Hex(HexColor);
impl JsonSchema for Hex {
@@ -78,7 +78,7 @@ impl From<Colour> for u32 {
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Rgb {
/// Red
pub r: u32,
@@ -120,8 +120,8 @@ impl From<u32> for Rgb {
fn from(value: u32) -> Self {
Self {
r: value & 0xff,
g: (value >> 8) & 0xff,
b: (value >> 16) & 0xff,
g: value >> 8 & 0xff,
b: value >> 16 & 0xff,
}
}
}

View File

@@ -6,16 +6,7 @@ use strum::Display;
use strum::EnumString;
#[derive(
Copy,
Clone,
Debug,
Serialize,
Deserialize,
Display,
EnumString,
ValueEnum,
JsonSchema,
PartialEq,
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
pub enum AnimationStyle {
Linear,

View File

@@ -75,7 +75,7 @@ pub struct IdWithIdentifier {
pub matching_strategy: Option<MatchingStrategy>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Display, JsonSchema)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub enum MatchingStrategy {
Legacy,
Equals,

View File

@@ -19,10 +19,6 @@ use crate::KomorebiTheme;
pub use animation::AnimationStyle;
pub use arrangement::Arrangement;
pub use arrangement::Axis;
pub use custom_layout::Column;
pub use custom_layout::ColumnSplit;
pub use custom_layout::ColumnSplitWithCapacity;
pub use custom_layout::ColumnWidth;
pub use custom_layout::CustomLayout;
pub use cycle_direction::CycleDirection;
pub use default_layout::DefaultLayout;
@@ -123,7 +119,6 @@ pub enum SocketMessage {
CycleFocusMonitor(CycleDirection),
CycleFocusWorkspace(CycleDirection),
FocusMonitorNumber(usize),
FocusMonitorAtCursor,
FocusLastWorkspace,
CloseWorkspace,
FocusWorkspaceNumber(usize),
@@ -436,16 +431,7 @@ pub enum MoveBehaviour {
}
#[derive(
Clone,
Copy,
Debug,
Serialize,
Deserialize,
Display,
EnumString,
ValueEnum,
JsonSchema,
PartialEq,
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
pub enum CrossBoundaryBehaviour {
/// Attempt to perform actions across a workspace boundary
@@ -455,16 +441,7 @@ pub enum CrossBoundaryBehaviour {
}
#[derive(
Copy,
Clone,
Debug,
Serialize,
Deserialize,
Display,
EnumString,
ValueEnum,
JsonSchema,
PartialEq,
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
)]
pub enum HidingBehaviour {
/// Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)

View File

@@ -182,7 +182,7 @@ lazy_static! {
static ref TCP_CONNECTIONS: Arc<Mutex<HashMap<String, TcpStream>>> =
Arc::new(Mutex::new(HashMap::new()));
static ref HIDING_BEHAVIOUR: Arc<Mutex<HidingBehaviour>> =
Arc::new(Mutex::new(HidingBehaviour::Cloak));
Arc::new(Mutex::new(HidingBehaviour::Minimize));
pub static ref HOME_DIR: PathBuf = {
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(|_| dirs::home_dir().expect("there is no home directory"), |home_path| {
let home = PathBuf::from(&home_path);

View File

@@ -176,7 +176,7 @@ fn main() -> Result<()> {
let session_id = WindowsApi::process_id_to_session_id()?;
SESSION_ID.store(session_id, Ordering::SeqCst);
let mut system = sysinfo::System::new();
let mut system = sysinfo::System::new_all();
system.refresh_processes(ProcessesToUpdate::All, true);
let matched_procs: Vec<&Process> = system.processes_by_name("komorebi.exe".as_ref()).collect();

View File

@@ -118,26 +118,6 @@ pub fn new(
}
impl Monitor {
pub fn new(
id: isize,
size: Rect,
work_area_size: Rect,
name: String,
device: String,
device_id: String,
serial_number_id: Option<String>,
) -> Self {
new(
id,
size,
work_area_size,
name,
device,
device_id,
serial_number_id,
)
}
pub fn placeholder() -> Self {
Self {
id: 0,

View File

@@ -735,11 +735,6 @@ impl WindowManager {
self.focus_monitor(monitor_idx)?;
self.update_focused_workspace(self.mouse_follows_focus, true)?;
}
SocketMessage::FocusMonitorAtCursor => {
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
self.focus_monitor(monitor_idx)?;
}
}
SocketMessage::Retile => {
border_manager::destroy_all_borders()?;
self.retile_all(false)?
@@ -853,15 +848,7 @@ impl WindowManager {
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
if monitor_idx != self.focused_monitor_idx() {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.focused_workspace() {
if workspace.is_empty() {
self.focus_monitor(monitor_idx)?;
}
}
}
}
self.focus_monitor(monitor_idx)?;
}
let focused_monitor = self
@@ -884,15 +871,7 @@ impl WindowManager {
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
if monitor_idx != self.focused_monitor_idx() {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.focused_workspace() {
if workspace.is_empty() {
self.focus_monitor(monitor_idx)?;
}
}
}
}
self.focus_monitor(monitor_idx)?;
}
let mut can_close = false;
@@ -928,15 +907,7 @@ impl WindowManager {
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
if monitor_idx != self.focused_monitor_idx() {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.focused_workspace() {
if workspace.is_empty() {
self.focus_monitor(monitor_idx)?;
}
}
}
}
self.focus_monitor(monitor_idx)?;
}
let idx = self
@@ -959,15 +930,7 @@ impl WindowManager {
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
if monitor_idx != self.focused_monitor_idx() {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.focused_workspace() {
if workspace.is_empty() {
self.focus_monitor(monitor_idx)?;
}
}
}
}
self.focus_monitor(monitor_idx)?;
}
if self.focused_workspace_idx().unwrap_or_default() != workspace_idx {
@@ -979,15 +942,7 @@ impl WindowManager {
// secondary monitor where the cursor is focused will be used as the target for
// the workspace switch op
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
if monitor_idx != self.focused_monitor_idx() {
if let Some(monitor) = self.monitors().get(monitor_idx) {
if let Some(workspace) = monitor.focused_workspace() {
if workspace.is_empty() {
self.focus_monitor(monitor_idx)?;
}
}
}
}
self.focus_monitor(monitor_idx)?;
}
let focused_monitor_idx = self.focused_monitor_idx();

View File

@@ -254,12 +254,7 @@ impl WindowManager {
already_moved_window_handles.remove(&window.hwnd);
}
WindowManagerEvent::FocusChange(_, window) => {
// don't want to trigger the full workspace updates when there are no managed
// containers - this makes floating windows on empty workspaces go into very
// annoying focus change loops which prevents users from interacting with them
if !self.focused_workspace()?.containers().is_empty() {
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 floating_window_idx = workspace

View File

@@ -101,26 +101,21 @@ use std::sync::Arc;
use uds_windows::UnixListener;
use uds_windows::UnixStream;
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct BorderColours {
/// Border colour when the container contains a single window
#[serde(skip_serializing_if = "Option::is_none")]
pub single: Option<Colour>,
/// Border colour when the container contains multiple windows
#[serde(skip_serializing_if = "Option::is_none")]
pub stack: Option<Colour>,
/// Border colour when the container is in monocle mode
#[serde(skip_serializing_if = "Option::is_none")]
pub monocle: Option<Colour>,
/// Border colour when the container is in floating mode
#[serde(skip_serializing_if = "Option::is_none")]
pub floating: Option<Colour>,
/// Border colour when the container is unfocused
#[serde(skip_serializing_if = "Option::is_none")]
pub unfocused: Option<Colour>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct WorkspaceConfig {
/// Name
pub name: String,
@@ -130,7 +125,7 @@ pub struct WorkspaceConfig {
/// END OF LIFE FEATURE: Custom Layout (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_layout: Option<PathBuf>,
/// Layout rules in the format of threshold => layout (default: None)
/// Layout rules (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
/// END OF LIFE FEATURE: Custom layout rules (default: None)
@@ -154,10 +149,8 @@ pub struct WorkspaceConfig {
/// Determine what happens when a new window is opened (default: Create)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour: Option<WindowContainerBehaviour>,
/// Window container behaviour rules in the format of threshold => behaviour (default: None)
#[serde(skip_serializing_if = "Option::is_none")]
pub window_container_behaviour_rules: Option<HashMap<usize, WindowContainerBehaviour>>,
/// Enable or disable float override, which makes it so every new window opens in floating mode (default: false)
/// 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>,
/// Specify an axis on which to flip the selected layout (default: None)
@@ -177,11 +170,6 @@ impl From<&Workspace> for WorkspaceConfig {
}
}
let mut window_container_behaviour_rules = HashMap::new();
for (threshold, behaviour) in value.window_container_behaviour_rules().iter().flatten() {
window_container_behaviour_rules.insert(*threshold, *behaviour);
}
let default_container_padding = DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst);
let default_workspace_padding = DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst);
@@ -221,14 +209,13 @@ impl From<&Workspace> for WorkspaceConfig {
workspace_rules: None,
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()),
window_container_behaviour: *value.window_container_behaviour(),
window_container_behaviour_rules: Option::from(window_container_behaviour_rules),
float_override: *value.float_override(),
layout_flip: value.layout_flip(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct MonitorConfig {
/// Workspace configurations
pub workspaces: Vec<WorkspaceConfig>,
@@ -259,7 +246,7 @@ impl From<&Monitor> for MonitorConfig {
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
/// The `komorebi.json` static configuration file reference for `v0.1.34`
pub struct StaticConfig {
/// DEPRECATED from v0.1.22: no longer required
@@ -396,8 +383,8 @@ pub struct StaticConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub slow_application_compensation_time: Option<u64>,
/// Komorebi status bar configuration files for multiple instances on different monitors
// this option is a little special because it is only consumed by komorebic
#[serde(skip_serializing_if = "Option::is_none")]
// this option is a little special because it is only consumed by komorebic
pub bar_configurations: Option<Vec<PathBuf>>,
/// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
#[serde(skip_serializing_if = "Option::is_none")]
@@ -407,22 +394,18 @@ pub struct StaticConfig {
pub floating_window_aspect_ratio: Option<AspectRatio>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct AnimationsConfig {
/// Enable or disable animations (default: false)
pub enabled: PerAnimationPrefixConfig<bool>,
enabled: PerAnimationPrefixConfig<bool>,
/// Set the animation duration in ms (default: 250)
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<PerAnimationPrefixConfig<u64>>,
duration: Option<PerAnimationPrefixConfig<u64>>,
/// Set the animation style (default: Linear)
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<PerAnimationPrefixConfig<AnimationStyle>>,
style: Option<PerAnimationPrefixConfig<AnimationStyle>>,
/// Set the animation FPS (default: 60)
#[serde(skip_serializing_if = "Option::is_none")]
pub fps: Option<u64>,
fps: Option<u64>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "palette")]
pub enum KomorebiTheme {
/// A theme from catppuccin-egui
@@ -430,63 +413,45 @@ pub enum KomorebiTheme {
/// Name of the Catppuccin theme (theme previews: https://github.com/catppuccin/catppuccin)
name: komorebi_themes::Catppuccin,
/// Border colour when the container contains a single window (default: Blue)
#[serde(skip_serializing_if = "Option::is_none")]
single_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the container contains multiple windows (default: Green)
#[serde(skip_serializing_if = "Option::is_none")]
stack_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the container is in monocle mode (default: Pink)
#[serde(skip_serializing_if = "Option::is_none")]
monocle_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the window is floating (default: Yellow)
#[serde(skip_serializing_if = "Option::is_none")]
floating_border: Option<komorebi_themes::CatppuccinValue>,
/// Border colour when the container is unfocused (default: Base)
#[serde(skip_serializing_if = "Option::is_none")]
unfocused_border: Option<komorebi_themes::CatppuccinValue>,
/// Stackbar focused tab text colour (default: Green)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_focused_text: Option<komorebi_themes::CatppuccinValue>,
/// Stackbar unfocused tab text colour (default: Text)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_unfocused_text: Option<komorebi_themes::CatppuccinValue>,
/// Stackbar tab background colour (default: Base)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_background: Option<komorebi_themes::CatppuccinValue>,
/// Komorebi status bar accent (default: Blue)
#[serde(skip_serializing_if = "Option::is_none")]
bar_accent: Option<komorebi_themes::CatppuccinValue>,
},
/// A theme from base16-egui-themes
Base16 {
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)
/// Name of the Base16 theme (theme previews: https://tinted-theming.github.io/base16-gallery)
name: komorebi_themes::Base16,
/// Border colour when the container contains a single window (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
single_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container contains multiple windows (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
stack_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is in monocle mode (default: Base0F)
#[serde(skip_serializing_if = "Option::is_none")]
monocle_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the window is floating (default: Base09)
#[serde(skip_serializing_if = "Option::is_none")]
floating_border: Option<komorebi_themes::Base16Value>,
/// Border colour when the container is unfocused (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
unfocused_border: Option<komorebi_themes::Base16Value>,
/// Stackbar focused tab text colour (default: Base0B)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_focused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar unfocused tab text colour (default: Base05)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
/// Stackbar tab background colour (default: Base01)
#[serde(skip_serializing_if = "Option::is_none")]
stackbar_background: Option<komorebi_themes::Base16Value>,
/// Komorebi status bar accent (default: Base0D)
#[serde(skip_serializing_if = "Option::is_none")]
bar_accent: Option<komorebi_themes::Base16Value>,
},
}
@@ -572,41 +537,31 @@ impl StaticConfig {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct TabsConfig {
/// Width of a stackbar tab
#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<i32>,
width: Option<i32>,
/// Focused tab text colour
#[serde(skip_serializing_if = "Option::is_none")]
pub focused_text: Option<Colour>,
focused_text: Option<Colour>,
/// Unfocused tab text colour
#[serde(skip_serializing_if = "Option::is_none")]
pub unfocused_text: Option<Colour>,
unfocused_text: Option<Colour>,
/// Tab background colour
#[serde(skip_serializing_if = "Option::is_none")]
pub background: Option<Colour>,
background: Option<Colour>,
/// Font family
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family: Option<String>,
font_family: Option<String>,
/// Font size
#[serde(skip_serializing_if = "Option::is_none")]
pub font_size: Option<i32>,
font_size: Option<i32>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct StackbarConfig {
/// Stackbar height
#[serde(skip_serializing_if = "Option::is_none")]
pub height: Option<i32>,
/// Stackbar label
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<StackbarLabel>,
/// Stackbar mode
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<StackbarMode>,
/// Stackbar tab configuration options
#[serde(skip_serializing_if = "Option::is_none")]
pub tabs: Option<TabsConfig>,
}

View File

@@ -40,8 +40,6 @@ use serde::ser::SerializeStruct;
use serde::Deserialize;
use serde::Serialize;
use serde::Serializer;
use strum::Display;
use strum::EnumString;
use windows::Win32::Foundation::HWND;
use crate::core::ApplicationIdentifier;
@@ -299,9 +297,7 @@ impl RenderDispatcher for TransparencyRenderDispatcher {
}
}
#[derive(
Copy, Clone, Debug, Display, EnumString, Serialize, Deserialize, JsonSchema, PartialEq,
)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum AspectRatio {
/// A predefined aspect ratio
@@ -310,22 +306,13 @@ pub enum AspectRatio {
Custom(i32, i32),
}
impl Default for AspectRatio {
fn default() -> Self {
AspectRatio::Predefined(PredefinedAspectRatio::default())
}
}
#[derive(
Copy, Clone, Debug, Default, Display, EnumString, Serialize, Deserialize, JsonSchema, PartialEq,
)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub enum PredefinedAspectRatio {
/// 21:9
Ultrawide,
/// 16:9
Widescreen,
/// 4:3
#[default]
Standard,
}

View File

@@ -115,16 +115,6 @@ pub extern "system" fn win_event_hook(
}
}
// sometimes the border focus state and colors don't get updated because this event comes too
// slow for the value of GetForegroundWindow to be up to date by the time it is inspected in
// the border manager to determine if a window show have its border show as "focused"
//
// so here we can just fire another event at the border manager when the system has finally
// registered the new foreground window and this time the correct border colors will be applied
if matches!(winevent, WinEvent::SystemForeground) && !has_filtered_style(hwnd) {
border_manager::send_notification(Some(hwnd.0 as isize));
}
let event_type = match WindowManagerEvent::from_win_event(winevent, window) {
None => {
tracing::trace!(

View File

@@ -89,8 +89,6 @@ pub struct Workspace {
#[getset(get = "pub", get_mut = "pub", set = "pub")]
window_container_behaviour: Option<WindowContainerBehaviour>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
window_container_behaviour_rules: Option<Vec<(usize, WindowContainerBehaviour)>>,
#[getset(get = "pub", get_mut = "pub", set = "pub")]
float_override: Option<bool>,
}
@@ -116,7 +114,6 @@ impl Default for Workspace {
tile: true,
apply_window_based_work_area_offset: true,
window_container_behaviour: None,
window_container_behaviour_rules: None,
float_override: None,
}
}
@@ -161,53 +158,42 @@ impl Workspace {
self.tile = false;
}
let mut all_layout_rules = vec![];
if let Some(layout_rules) = &config.layout_rules {
let mut all_rules = vec![];
for (count, rule) in layout_rules {
all_layout_rules.push((*count, Layout::Default(*rule)));
all_rules.push((*count, Layout::Default(*rule)));
}
all_layout_rules.sort_by_key(|(i, _)| *i);
self.set_layout_rules(all_rules);
self.tile = true;
}
self.set_layout_rules(all_layout_rules.clone());
if let Some(layout_rules) = &config.custom_layout_rules {
let rules = self.layout_rules_mut();
for (count, pathbuf) in layout_rules {
let rule = CustomLayout::from_path(pathbuf)?;
all_layout_rules.push((*count, Layout::Custom(rule)));
rules.push((*count, Layout::Custom(rule)));
}
all_layout_rules.sort_by_key(|(i, _)| *i);
self.tile = true;
self.set_layout_rules(all_layout_rules);
}
self.set_apply_window_based_work_area_offset(
config.apply_window_based_work_area_offset.unwrap_or(true),
);
self.set_window_container_behaviour(config.window_container_behaviour);
if let Some(window_container_behaviour_rules) = &config.window_container_behaviour_rules {
if window_container_behaviour_rules.is_empty() {
self.set_window_container_behaviour_rules(None);
} else {
let mut all_rules = vec![];
for (count, behaviour) in window_container_behaviour_rules {
all_rules.push((*count, *behaviour));
}
all_rules.sort_by_key(|(i, _)| *i);
self.set_window_container_behaviour_rules(Some(all_rules));
}
} else {
self.set_window_container_behaviour_rules(None);
if config.window_container_behaviour.is_some() {
self.set_window_container_behaviour(config.window_container_behaviour);
}
self.set_float_override(config.float_override);
self.set_layout_flip(config.layout_flip);
if config.float_override.is_some() {
self.set_float_override(config.float_override);
}
if config.layout_flip.is_some() {
self.set_layout_flip(config.layout_flip);
}
Ok(())
}
@@ -340,9 +326,9 @@ impl Workspace {
if !self.layout_rules().is_empty() {
let mut updated_layout = None;
for (threshold, layout) in self.layout_rules() {
if self.containers().len() >= *threshold {
updated_layout = Option::from(layout.clone());
for rule in self.layout_rules() {
if self.containers().len() >= rule.0 {
updated_layout = Option::from(rule.1.clone());
}
}
@@ -351,17 +337,6 @@ impl Workspace {
}
}
if let Some(window_container_behaviour_rules) = self.window_container_behaviour_rules() {
let mut updated_behaviour = None;
for (threshold, behaviour) in window_container_behaviour_rules {
if self.containers().len() >= *threshold {
updated_behaviour = Option::from(*behaviour);
}
}
self.set_window_container_behaviour(updated_behaviour);
}
let managed_maximized_window = self.maximized_window().is_some();
if *self.tile() {
@@ -458,16 +433,7 @@ impl Workspace {
// number of layouts / containers. This should never actually truncate as the remove_window
// function takes care of cleaning up resize dimensions when destroying empty containers
let container_count = self.containers().len();
// since monocle is a toggle, we never want to truncate the resize dimensions since it will
// almost always be toggled off and the container will be reintegrated into layout
//
// without this check, if there are exactly two containers, when one is toggled to monocle
// the resize dimensions will be truncated to len == 1, and when it is reintegrated, if it
// had a resize adjustment before, that will have been lost
if self.monocle_container().is_none() {
self.resize_dimensions_mut().resize(container_count, None);
}
self.resize_dimensions_mut().resize(container_count, None);
Ok(())
}
@@ -499,15 +465,7 @@ impl Workspace {
}
for window in self.visible_windows().into_iter().flatten() {
if !window.is_window()
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
// docs is closed
//
// I hate every single person who worked on Microsoft Office 365, especially Word
|| !window.is_visible()
{
if !window.is_window() {
hwnds.push(window.hwnd);
}
}

View File

@@ -24,10 +24,13 @@ reqwest = { version = "0.12", features = ["blocking"] }
schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = "0.9"
shadow-rs = { workspace = true }
sysinfo = { workspace = true }
thiserror = "2"
uds_windows = { workspace = true }
which = { workspace = true }
win32-display-data = { workspace = true }
windows = { workspace = true }
[build-dependencies]

View File

@@ -1108,8 +1108,6 @@ enum SubCommand {
/// Focus the specified monitor
#[clap(arg_required_else_help = true)]
FocusMonitor(FocusMonitor),
/// Focus the monitor at the current cursor location
FocusMonitorAtCursor,
/// Focus the last focused workspace on the focused monitor
FocusLastWorkspace,
/// Focus the specified workspace on the focused monitor
@@ -2590,9 +2588,6 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
SubCommand::FocusMonitor(arg) => {
send_message(&SocketMessage::FocusMonitorNumber(arg.target))?;
}
SubCommand::FocusMonitorAtCursor => {
send_message(&SocketMessage::FocusMonitorAtCursor)?;
}
SubCommand::FocusLastWorkspace => {
send_message(&SocketMessage::FocusLastWorkspace)?;
}

View File

@@ -127,7 +127,6 @@ nav:
- cli/send-to-monitor-workspace.md
- cli/move-to-monitor-workspace.md
- cli/focus-monitor.md
- cli/focus-monitor-at-cursor.md
- cli/focus-last-workspace.md
- cli/focus-workspace.md
- cli/focus-workspaces.md

View File

@@ -271,66 +271,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"Keyboard"
],
"properties": {
"Keyboard": {
"type": "object",
"required": [
"enable"
],
"properties": {
"data_refresh_interval": {
"description": "Data refresh interval (default: 1 second)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"enable": {
"description": "Enable the Input widget",
"type": "boolean"
},
"label_prefix": {
"description": "Display label prefix",
"oneOf": [
{
"description": "Show no prefix",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Show an icon",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show text",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show an icon and text",
"type": "string",
"enum": [
"IconAndText"
]
}
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -1578,66 +1518,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"Keyboard"
],
"properties": {
"Keyboard": {
"type": "object",
"required": [
"enable"
],
"properties": {
"data_refresh_interval": {
"description": "Data refresh interval (default: 1 second)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"enable": {
"description": "Enable the Input widget",
"type": "boolean"
},
"label_prefix": {
"description": "Display label prefix",
"oneOf": [
{
"description": "Show no prefix",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Show an icon",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show text",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show an icon and text",
"type": "string",
"enum": [
"IconAndText"
]
}
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -2818,66 +2698,6 @@
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"Keyboard"
],
"properties": {
"Keyboard": {
"type": "object",
"required": [
"enable"
],
"properties": {
"data_refresh_interval": {
"description": "Data refresh interval (default: 1 second)",
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"enable": {
"description": "Enable the Input widget",
"type": "boolean"
},
"label_prefix": {
"description": "Display label prefix",
"oneOf": [
{
"description": "Show no prefix",
"type": "string",
"enum": [
"None"
]
},
{
"description": "Show an icon",
"type": "string",
"enum": [
"Icon"
]
},
{
"description": "Show text",
"type": "string",
"enum": [
"Text"
]
},
{
"description": "Show an icon and text",
"type": "string",
"enum": [
"IconAndText"
]
}
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
@@ -3603,7 +3423,7 @@
]
},
"name": {
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)",
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/base16-gallery)",
"type": "string",
"enum": [
"3024",

View File

@@ -1284,7 +1284,7 @@
]
},
"layout_rules": {
"description": "Layout rules in the format of threshold => layout (default: None)",
"description": "Layout rules (default: None)",
"type": "object",
"additionalProperties": {
"type": "string",
@@ -1323,28 +1323,6 @@
}
]
},
"window_container_behaviour_rules": {
"description": "Window container behaviour rules in the format of threshold => behaviour (default: None)",
"type": "object",
"additionalProperties": {
"oneOf": [
{
"description": "Create a new container for each new window",
"type": "string",
"enum": [
"Create"
]
},
{
"description": "Append new windows to the focused window container",
"type": "string",
"enum": [
"Append"
]
}
]
}
},
"workspace_padding": {
"description": "Container padding (default: global)",
"type": "integer",
@@ -2267,7 +2245,7 @@
]
},
"name": {
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/tinted-gallery/)",
"description": "Name of the Base16 theme (theme previews: https://tinted-theming.github.io/base16-gallery)",
"type": "string",
"enum": [
"3024",