mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-02-13 16:57:40 +01:00
Compare commits
8 Commits
feature/re
...
feature/fl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
261daedcf5 | ||
|
|
bd24940173 | ||
|
|
9034122447 | ||
|
|
105957b5fa | ||
|
|
bf5b675498 | ||
|
|
8c8d1175ba | ||
|
|
bf2b73837b | ||
|
|
04cde3f757 |
52
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
52
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]: Short descriptive title"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See bug
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots and Videos**
|
||||
Add screenshots and videos to help explain your problem.
|
||||
|
||||
**Operating System**
|
||||
Provide the output of `systeminfo | grep "^OS Name\|^OS Version"`
|
||||
|
||||
For example:
|
||||
```
|
||||
OS Name: Microsoft Windows 11 Pro
|
||||
OS Version: 10.0.22000 N/A Build 22000
|
||||
```
|
||||
|
||||
**`komorebic check` Output**
|
||||
Provide the output of `komorebic check`
|
||||
|
||||
For example:
|
||||
```
|
||||
No KOMOREBI_CONFIG_HOME detected, defaulting to C:\Users\LGUG2Z
|
||||
|
||||
Looking for configuration files in C:\Users\LGUG2Z
|
||||
|
||||
No komorebi configuration found in C:\Users\LGUG2Z
|
||||
|
||||
If running 'komorebic start --await-configuration', you will manually have to call the following command to begin tiling: komorebic complete-configuration
|
||||
```
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
In particular, if you have any other AHK scripts or software running that handle any aspect of window management or manipulation
|
||||
55
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
55
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: Bug report
|
||||
description: File a bug report
|
||||
labels: [ bug ]
|
||||
body:
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Summary
|
||||
description: >
|
||||
Please provide a short summary of the bug, along with any information
|
||||
you feel is relevant to replicating the bug.
|
||||
|
||||
You may include screenshots and videos in this section.
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Version Information
|
||||
description: >
|
||||
Please provide information about the versions of Windows and komorebi
|
||||
running on your machine.
|
||||
|
||||
Do not submit a bug if you are not using an official version of Windows
|
||||
such as AtlasOS; only official versions of Windows are supported.
|
||||
|
||||
```
|
||||
systeminfo | findstr /B /C:"OS Name" /B /C:"OS Version"
|
||||
```
|
||||
|
||||
```
|
||||
komorebic --version
|
||||
```
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Komorebi Configuration
|
||||
description: >
|
||||
Please provide your configuration file (komorebi.json or komorebi.bar.json)
|
||||
render: json
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Hotkey Configuration
|
||||
description: >
|
||||
Please provide your whkdrc or komorebi.ahk hotkey configuration file
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Output of komorebic check
|
||||
description: >
|
||||
Please provide the output of `komorebic check`
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Komorebi Documentation
|
||||
url: https://lgug2z.github.io/komorebi/
|
||||
about: Please search the documentation website before opening an issue
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FEAT]: Short descriptive title"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
18
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
18
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Feature request
|
||||
description: Suggest an improvement
|
||||
labels: [ enhancement ]
|
||||
body:
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Suggestion
|
||||
description: >
|
||||
Please share your suggestion here. Be sure to include all necessary context.
|
||||
- type: textarea
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: >
|
||||
Please share share alternatives you have considered here.
|
||||
1384
Cargo.lock
generated
1384
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,8 @@ chrono = "0.4"
|
||||
crossbeam-channel = "0.5"
|
||||
crossbeam-utils = "0.8"
|
||||
color-eyre = "0.6"
|
||||
eframe = "0.29"
|
||||
egui_extras = "0.29"
|
||||
eframe = "0.28"
|
||||
egui_extras = "0.28"
|
||||
dirs = "5"
|
||||
dunce = "1"
|
||||
hotwatch = "0.5"
|
||||
@@ -63,6 +63,3 @@ features = [
|
||||
"Media",
|
||||
"Media_Control"
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
@@ -82,7 +82,7 @@ A [detailed installation and quickstart
|
||||
guide](https://lgug2z.github.io/komorebi/installation.html) is available which shows how to get started
|
||||
using `scoop`, `winget` or building from source.
|
||||
|
||||
[](https://www.youtube.com/watch?v=MMZUAtHbTYY)
|
||||
[](https://www.youtube.com/watch?v=H9-_c1egQ4g)
|
||||
|
||||
# Comparison With Fancy Zones
|
||||
|
||||
|
||||
@@ -16,15 +16,14 @@ crossbeam-channel = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
eframe = { workspace = true }
|
||||
egui-phosphor = "0.7"
|
||||
egui-phosphor = "0.6.0"
|
||||
font-loader = "0.11"
|
||||
hotwatch = { workspace = true }
|
||||
image = "0.25"
|
||||
netdev = "0.31"
|
||||
num = "0.4"
|
||||
num-derive = "0.4"
|
||||
num-traits = "0.2"
|
||||
random_word = { version = "0.4", features = ["en"] }
|
||||
num = "0.4.3"
|
||||
num-derive = "0.4.2"
|
||||
num-traits = "0.2.19"
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
use crate::config::KomobarConfig;
|
||||
use crate::config::KomobarTheme;
|
||||
use crate::config::Position;
|
||||
use crate::config::PositionConfig;
|
||||
use crate::komorebi::Komorebi;
|
||||
use crate::komorebi::KomorebiNotificationState;
|
||||
use crate::process_hwnd;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::widget::WidgetConfig;
|
||||
use crate::BAR_HEIGHT;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_LEFT;
|
||||
use crate::MONITOR_RIGHT;
|
||||
use crate::MONITOR_TOP;
|
||||
use crossbeam_channel::Receiver;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::CentralPanel;
|
||||
@@ -26,6 +19,8 @@ use eframe::egui::Layout;
|
||||
use eframe::egui::Margin;
|
||||
use eframe::egui::Style;
|
||||
use eframe::egui::TextStyle;
|
||||
use eframe::egui::Vec2;
|
||||
use eframe::egui::ViewportCommand;
|
||||
use font_loader::system_fonts;
|
||||
use font_loader::system_fonts::FontPropertyBuilder;
|
||||
use komorebi_client::KomorebiTheme;
|
||||
@@ -149,43 +144,14 @@ impl Komobar {
|
||||
Self::add_custom_font(ctx, font_family);
|
||||
}
|
||||
|
||||
let position = config.position.clone().unwrap_or(PositionConfig {
|
||||
start: Some(Position {
|
||||
x: MONITOR_LEFT.load(Ordering::SeqCst) as f32,
|
||||
y: MONITOR_TOP.load(Ordering::SeqCst) as f32,
|
||||
}),
|
||||
end: Some(Position {
|
||||
x: MONITOR_RIGHT.load(Ordering::SeqCst) as f32,
|
||||
y: BAR_HEIGHT,
|
||||
}),
|
||||
});
|
||||
|
||||
if let Some(hwnd) = process_hwnd() {
|
||||
let start = position.start.unwrap_or(Position {
|
||||
x: MONITOR_LEFT.load(Ordering::SeqCst) as f32,
|
||||
y: MONITOR_TOP.load(Ordering::SeqCst) as f32,
|
||||
});
|
||||
|
||||
let end = position.end.unwrap_or(Position {
|
||||
x: MONITOR_RIGHT.load(Ordering::SeqCst) as f32,
|
||||
y: BAR_HEIGHT,
|
||||
});
|
||||
|
||||
let rect = komorebi_client::Rect {
|
||||
left: start.x as i32,
|
||||
top: start.y as i32,
|
||||
right: end.x as i32,
|
||||
bottom: end.y as i32,
|
||||
};
|
||||
|
||||
let window = komorebi_client::Window::from(hwnd);
|
||||
match window.set_position(&rect, false) {
|
||||
Ok(_) => {
|
||||
tracing::info!("updated bar position");
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!("{}", error.to_string())
|
||||
if let Some(viewport) = &config.viewport {
|
||||
if let Some(inner_size) = viewport.inner_size {
|
||||
let mut vec2 = Vec2::new(inner_size.x, inner_size.y * 2.0);
|
||||
if self.scale_factor != 1.0 {
|
||||
vec2 = Vec2::new(inner_size.x / self.scale_factor, inner_size.y * 2.0);
|
||||
}
|
||||
|
||||
ctx.send_viewport_cmd(ViewportCommand::InnerSize(vec2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,8 +290,6 @@ impl Komobar {
|
||||
scale_factor: cc.egui_ctx.native_pixels_per_point().unwrap_or(1.0),
|
||||
};
|
||||
|
||||
komobar.apply_config(&cc.egui_ctx, &config, None);
|
||||
// needs a double apply the first time for some reason
|
||||
komobar.apply_config(&cc.egui_ctx, &config, None);
|
||||
|
||||
komobar
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -24,8 +23,6 @@ pub struct BatteryConfig {
|
||||
pub enable: bool,
|
||||
/// Data refresh interval (default: 10 seconds)
|
||||
pub data_refresh_interval: Option<u64>,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<BatteryConfig> for Battery {
|
||||
@@ -33,7 +30,6 @@ impl From<BatteryConfig> for Battery {
|
||||
let manager = Manager::new().unwrap();
|
||||
let mut last_state = String::new();
|
||||
let mut state = None;
|
||||
let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon);
|
||||
|
||||
if let Ok(mut batteries) = manager.batteries() {
|
||||
if let Some(Ok(first)) = batteries.nth(0) {
|
||||
@@ -44,12 +40,7 @@ impl From<BatteryConfig> for Battery {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
last_state = match prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("BAT: {percentage:.0}%")
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"),
|
||||
}
|
||||
last_state = format!("{percentage}%");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +49,6 @@ impl From<BatteryConfig> for Battery {
|
||||
manager,
|
||||
last_state,
|
||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||
label_prefix: prefix,
|
||||
state: state.unwrap_or(BatteryState::Discharging),
|
||||
last_updated: Instant::now(),
|
||||
}
|
||||
@@ -75,7 +65,6 @@ pub struct Battery {
|
||||
manager: Manager,
|
||||
pub state: BatteryState,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
last_state: String,
|
||||
last_updated: Instant,
|
||||
}
|
||||
@@ -97,12 +86,7 @@ impl Battery {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
output = match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("BAT: {percentage:.0}%")
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => format!("{percentage:.0}%"),
|
||||
}
|
||||
output = format!("{percentage:.0}%");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,10 +116,7 @@ impl BarWidget for Battery {
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => emoji.to_string(),
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
emoji.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
|
||||
@@ -7,15 +7,13 @@ use komorebi_client::Rect;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
/// The `komorebi.bar.json` configuration file reference for `v0.1.30`
|
||||
pub struct KomobarConfig {
|
||||
/// Bar positioning options
|
||||
#[serde(alias = "viewport")]
|
||||
pub position: Option<PositionConfig>,
|
||||
/// Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html)
|
||||
pub viewport: Option<ViewportConfig>,
|
||||
/// Frame options (see: https://docs.rs/egui/latest/egui/containers/struct.Frame.html)
|
||||
pub frame: Option<FrameConfig>,
|
||||
/// Monitor options
|
||||
@@ -34,43 +32,12 @@ pub struct KomobarConfig {
|
||||
pub right_widgets: Vec<WidgetConfig>,
|
||||
}
|
||||
|
||||
impl KomobarConfig {
|
||||
pub fn aliases(raw: &str) {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("position", ["viewport"]);
|
||||
map.insert("end", ["inner_frame"]);
|
||||
|
||||
let mut display = false;
|
||||
|
||||
for aliases in map.values() {
|
||||
for a in aliases {
|
||||
if raw.contains(a) {
|
||||
display = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if display {
|
||||
println!("\nYour bar configuration file contains some options that have been renamed or deprecated:\n");
|
||||
for (canonical, aliases) in map {
|
||||
for alias in aliases {
|
||||
if raw.contains(alias) {
|
||||
println!(r#""{alias}" is now "{canonical}""#);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PositionConfig {
|
||||
pub struct ViewportConfig {
|
||||
/// The desired starting position of the bar (0,0 = top left of the screen)
|
||||
#[serde(alias = "position")]
|
||||
pub start: Option<Position>,
|
||||
pub position: Option<Position>,
|
||||
/// The desired size of the bar from the starting position (usually monitor width x desired height)
|
||||
#[serde(alias = "inner_size")]
|
||||
pub end: Option<Position>,
|
||||
pub inner_size: Option<Position>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
@@ -164,15 +131,3 @@ impl From<KomorebiTheme> for KomobarTheme {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum LabelPrefix {
|
||||
/// Show no prefix
|
||||
None,
|
||||
/// Show an icon
|
||||
Icon,
|
||||
/// Show text
|
||||
Text,
|
||||
/// Show an icon and text
|
||||
IconAndText,
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Context;
|
||||
use eframe::egui::FontId;
|
||||
use eframe::egui::Label;
|
||||
use eframe::egui::Sense;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::TextStyle;
|
||||
use eframe::egui::Ui;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
use sysinfo::RefreshKind;
|
||||
use sysinfo::System;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CpuConfig {
|
||||
/// Enable the Cpu widget
|
||||
pub enable: bool,
|
||||
/// Data refresh interval (default: 10 seconds)
|
||||
pub data_refresh_interval: Option<u64>,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<CpuConfig> for Cpu {
|
||||
fn from(value: CpuConfig) -> Self {
|
||||
let mut system =
|
||||
System::new_with_specifics(RefreshKind::default().without_memory().without_processes());
|
||||
|
||||
system.refresh_cpu_usage();
|
||||
|
||||
Self {
|
||||
enable: value.enable,
|
||||
system,
|
||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||
last_updated: Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cpu {
|
||||
pub enable: bool,
|
||||
system: System,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
last_updated: Instant,
|
||||
}
|
||||
|
||||
impl Cpu {
|
||||
fn output(&mut self) -> String {
|
||||
let now = Instant::now();
|
||||
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||
self.system.refresh_cpu_usage();
|
||||
self.last_updated = now;
|
||||
}
|
||||
|
||||
let used = self.system.global_cpu_usage();
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => format!("CPU: {:.0}%", used),
|
||||
LabelPrefix::None | LabelPrefix::Icon => format!("{:.0}%", used),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BarWidget for Cpu {
|
||||
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||
if self.enable {
|
||||
let output = self.output();
|
||||
if !output.is_empty() {
|
||||
let font_id = ctx
|
||||
.style()
|
||||
.text_styles
|
||||
.get(&TextStyle::Body)
|
||||
.cloned()
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::CPU.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
);
|
||||
|
||||
layout_job.append(
|
||||
&output,
|
||||
10.0,
|
||||
TextFormat::simple(font_id, ctx.style().visuals.text_color()),
|
||||
);
|
||||
|
||||
if ui
|
||||
.add(
|
||||
Label::new(layout_job)
|
||||
.selectable(false)
|
||||
.sense(Sense::click()),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if let Err(error) = Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn()
|
||||
{
|
||||
eprintln!("{}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(WIDGET_SPACING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -20,8 +19,6 @@ pub struct DateConfig {
|
||||
pub enable: bool,
|
||||
/// Set the Date format
|
||||
pub format: DateFormat,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<DateConfig> for Date {
|
||||
@@ -29,7 +26,6 @@ impl From<DateConfig> for Date {
|
||||
Self {
|
||||
enable: value.enable,
|
||||
format: value.format,
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +70,6 @@ impl DateFormat {
|
||||
pub struct Date {
|
||||
pub enable: bool,
|
||||
pub format: DateFormat,
|
||||
label_prefix: LabelPrefix,
|
||||
}
|
||||
|
||||
impl Date {
|
||||
@@ -88,7 +83,7 @@ impl Date {
|
||||
impl BarWidget for Date {
|
||||
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||
if self.enable {
|
||||
let mut output = self.output();
|
||||
let output = self.output();
|
||||
if !output.is_empty() {
|
||||
let font_id = ctx
|
||||
.style()
|
||||
@@ -98,21 +93,12 @@ impl BarWidget for Date {
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::CALENDAR_DOTS.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
egui_phosphor::regular::CALENDAR_DOTS.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
);
|
||||
|
||||
if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix {
|
||||
output.insert_str(0, "DATE: ");
|
||||
}
|
||||
|
||||
layout_job.append(
|
||||
&output,
|
||||
10.0,
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::widget::BarWidget;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::WIDGET_SPACING;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::TryRecvError;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::ColorImage;
|
||||
@@ -84,6 +83,14 @@ impl From<&KomorebiConfig> for Komorebi {
|
||||
if let Some(configuration_switcher) = &value.configuration_switcher {
|
||||
let mut configuration_switcher = configuration_switcher.clone();
|
||||
for (_, location) in configuration_switcher.configurations.iter_mut() {
|
||||
if let Ok(expanded) = std::env::var("KOMOREBI_CONFIG_HOME") {
|
||||
*location = location.replace("$Env:KOMOREBI_CONFIG_HOME", &expanded);
|
||||
}
|
||||
|
||||
if let Ok(expanded) = std::env::var("USERPROFILE") {
|
||||
*location = location.replace("$Env:USERPROFILE", &expanded);
|
||||
}
|
||||
|
||||
*location = dunce::simplified(&PathBuf::from(location.clone()))
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
@@ -438,105 +445,93 @@ impl KomorebiNotificationState {
|
||||
rx_gui: Receiver<komorebi_client::Notification>,
|
||||
bg_color: Rc<RefCell<Color32>>,
|
||||
) {
|
||||
match rx_gui.try_recv() {
|
||||
Err(error) => match error {
|
||||
TryRecvError::Empty => {}
|
||||
TryRecvError::Disconnected => {
|
||||
tracing::error!(
|
||||
"failed to receive komorebi notification on gui thread: {error}"
|
||||
);
|
||||
}
|
||||
},
|
||||
Ok(notification) => {
|
||||
if let NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(path)) =
|
||||
notification.event
|
||||
{
|
||||
if let Ok(config) = komorebi_client::StaticConfig::read(&path) {
|
||||
if let Some(theme) = config.theme {
|
||||
apply_theme(ctx, KomobarTheme::from(theme), bg_color);
|
||||
tracing::info!("applied theme from updated komorebi.json");
|
||||
}
|
||||
if let Ok(notification) = rx_gui.try_recv() {
|
||||
if let NotificationEvent::Socket(SocketMessage::ReloadStaticConfiguration(path)) =
|
||||
notification.event
|
||||
{
|
||||
if let Ok(config) = komorebi_client::StaticConfig::read(&path) {
|
||||
if let Some(theme) = config.theme {
|
||||
apply_theme(ctx, KomobarTheme::from(theme), bg_color);
|
||||
tracing::info!("applied theme from updated komorebi.json");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.mouse_follows_focus = notification.state.mouse_follows_focus;
|
||||
self.mouse_follows_focus = notification.state.mouse_follows_focus;
|
||||
|
||||
let monitor = ¬ification.state.monitors.elements()[monitor_index];
|
||||
self.work_area_offset =
|
||||
notification.state.monitors.elements()[monitor_index].work_area_offset();
|
||||
let monitor = ¬ification.state.monitors.elements()[monitor_index];
|
||||
self.work_area_offset =
|
||||
notification.state.monitors.elements()[monitor_index].work_area_offset();
|
||||
|
||||
let focused_workspace_idx = monitor.focused_workspace_idx();
|
||||
let focused_workspace_idx = monitor.focused_workspace_idx();
|
||||
|
||||
let mut workspaces = vec![];
|
||||
self.selected_workspace = monitor.workspaces()[focused_workspace_idx]
|
||||
.name()
|
||||
.to_owned()
|
||||
.unwrap_or_else(|| format!("{}", focused_workspace_idx + 1));
|
||||
let mut workspaces = vec![];
|
||||
self.selected_workspace = monitor.workspaces()[focused_workspace_idx]
|
||||
.name()
|
||||
.to_owned()
|
||||
.unwrap_or_else(|| format!("{}", focused_workspace_idx + 1));
|
||||
|
||||
for (i, ws) in monitor.workspaces().iter().enumerate() {
|
||||
let should_add = if self.hide_empty_workspaces {
|
||||
focused_workspace_idx == i || !ws.containers().is_empty()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if should_add {
|
||||
workspaces
|
||||
.push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
self.workspaces = workspaces;
|
||||
self.layout = match monitor.workspaces()[focused_workspace_idx].layout() {
|
||||
komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(*layout),
|
||||
komorebi_client::Layout::Custom(_) => KomorebiLayout::Custom,
|
||||
for (i, ws) in monitor.workspaces().iter().enumerate() {
|
||||
let should_add = if self.hide_empty_workspaces {
|
||||
focused_workspace_idx == i || !ws.containers().is_empty()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if !*monitor.workspaces()[focused_workspace_idx].tile() {
|
||||
self.layout = KomorebiLayout::Floating;
|
||||
if should_add {
|
||||
workspaces.push(ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
if notification.state.is_paused {
|
||||
self.layout = KomorebiLayout::Paused;
|
||||
}
|
||||
self.workspaces = workspaces;
|
||||
self.layout = match monitor.workspaces()[focused_workspace_idx].layout() {
|
||||
komorebi_client::Layout::Default(layout) => KomorebiLayout::Default(*layout),
|
||||
komorebi_client::Layout::Custom(_) => KomorebiLayout::Custom,
|
||||
};
|
||||
|
||||
if let Some(container) =
|
||||
monitor.workspaces()[focused_workspace_idx].monocle_container()
|
||||
{
|
||||
self.focused_container_information = (
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.title().unwrap_or_default())
|
||||
.collect::<Vec<_>>(),
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| windows_icons::get_icon_by_process_id(w.process_id()))
|
||||
.collect::<Vec<_>>(),
|
||||
container.focused_window_idx(),
|
||||
);
|
||||
} else if let Some(container) =
|
||||
monitor.workspaces()[focused_workspace_idx].focused_container()
|
||||
{
|
||||
self.focused_container_information = (
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.title().unwrap_or_default())
|
||||
.collect::<Vec<_>>(),
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| windows_icons::get_icon_by_process_id(w.process_id()))
|
||||
.collect::<Vec<_>>(),
|
||||
container.focused_window_idx(),
|
||||
);
|
||||
} else {
|
||||
self.focused_container_information.0.clear();
|
||||
self.focused_container_information.1.clear();
|
||||
self.focused_container_information.2 = 0;
|
||||
}
|
||||
if !*monitor.workspaces()[focused_workspace_idx].tile() {
|
||||
self.layout = KomorebiLayout::Floating;
|
||||
}
|
||||
|
||||
if notification.state.is_paused {
|
||||
self.layout = KomorebiLayout::Paused;
|
||||
}
|
||||
|
||||
if let Some(container) = monitor.workspaces()[focused_workspace_idx].monocle_container()
|
||||
{
|
||||
self.focused_container_information = (
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.title().unwrap_or_default())
|
||||
.collect::<Vec<_>>(),
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| windows_icons::get_icon_by_process_id(w.process_id()))
|
||||
.collect::<Vec<_>>(),
|
||||
container.focused_window_idx(),
|
||||
);
|
||||
} else if let Some(container) =
|
||||
monitor.workspaces()[focused_workspace_idx].focused_container()
|
||||
{
|
||||
self.focused_container_information = (
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.title().unwrap_or_default())
|
||||
.collect::<Vec<_>>(),
|
||||
container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| windows_icons::get_icon_by_process_id(w.process_id()))
|
||||
.collect::<Vec<_>>(),
|
||||
container.focused_window_idx(),
|
||||
);
|
||||
} else {
|
||||
self.focused_container_information.0.clear();
|
||||
self.focused_container_information.1.clear();
|
||||
self.focused_container_information.2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
mod bar;
|
||||
mod battery;
|
||||
mod config;
|
||||
mod cpu;
|
||||
mod date;
|
||||
mod komorebi;
|
||||
mod media;
|
||||
@@ -15,40 +14,23 @@ mod widget;
|
||||
use crate::bar::Komobar;
|
||||
use crate::config::KomobarConfig;
|
||||
use crate::config::Position;
|
||||
use crate::config::PositionConfig;
|
||||
use clap::Parser;
|
||||
use eframe::egui::ViewportBuilder;
|
||||
use font_loader::system_fonts;
|
||||
use hotwatch::EventKind;
|
||||
use hotwatch::Hotwatch;
|
||||
use komorebi_client::SocketMessage;
|
||||
use komorebi_client::SubscribeOptions;
|
||||
use schemars::gen::SchemaSettings;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicI32;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use windows::Win32::Foundation::BOOL;
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::Foundation::LPARAM;
|
||||
use windows::Win32::System::Threading::GetCurrentProcessId;
|
||||
use windows::Win32::System::Threading::GetCurrentThreadId;
|
||||
use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext;
|
||||
use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
|
||||
use windows::Win32::UI::WindowsAndMessaging::EnumThreadWindows;
|
||||
use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId;
|
||||
|
||||
pub static WIDGET_SPACING: f32 = 10.0;
|
||||
|
||||
pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400);
|
||||
pub static MONITOR_LEFT: AtomicI32 = AtomicI32::new(0);
|
||||
pub static MONITOR_TOP: AtomicI32 = AtomicI32::new(0);
|
||||
pub static MONITOR_RIGHT: AtomicI32 = AtomicI32::new(0);
|
||||
pub static BAR_HEIGHT: f32 = 50.0;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, about, version)]
|
||||
@@ -65,46 +47,9 @@ struct Opts {
|
||||
/// Write an example komorebi.bar.json to disk
|
||||
#[clap(long)]
|
||||
quickstart: bool,
|
||||
/// Print a list of aliases that can be renamed to canonical variants
|
||||
#[clap(long)]
|
||||
#[clap(hide = true)]
|
||||
aliases: bool,
|
||||
}
|
||||
|
||||
extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
unsafe {
|
||||
let mut process_id = 0;
|
||||
GetWindowThreadProcessId(hwnd, Some(&mut process_id));
|
||||
|
||||
if process_id == GetCurrentProcessId() {
|
||||
*(lparam.0 as *mut HWND) = hwnd;
|
||||
BOOL::from(false) // Stop enumeration
|
||||
} else {
|
||||
BOOL::from(true) // Continue enumeration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_hwnd() -> Option<isize> {
|
||||
unsafe {
|
||||
let mut hwnd = HWND::default();
|
||||
let _ = EnumThreadWindows(
|
||||
GetCurrentThreadId(),
|
||||
Some(enum_window),
|
||||
LPARAM(&mut hwnd as *mut HWND as isize),
|
||||
);
|
||||
|
||||
if hwnd.0 as isize == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(hwnd.0 as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) }?;
|
||||
|
||||
let opts: Opts = Opts::parse();
|
||||
|
||||
if opts.schema {
|
||||
@@ -183,7 +128,7 @@ fn main() -> color_eyre::Result<()> {
|
||||
Option::from,
|
||||
);
|
||||
|
||||
let mut config = match config_path {
|
||||
let config = match config_path {
|
||||
None => {
|
||||
let komorebi_bar_json =
|
||||
include_str!("../../docs/komorebi.bar.example.json").to_string();
|
||||
@@ -197,12 +142,10 @@ fn main() -> color_eyre::Result<()> {
|
||||
KomobarConfig::read(&default_config_path)?
|
||||
}
|
||||
Some(ref config) => {
|
||||
if !opts.aliases {
|
||||
tracing::info!(
|
||||
"found configuration file: {}",
|
||||
config.as_path().to_string_lossy()
|
||||
);
|
||||
}
|
||||
tracing::info!(
|
||||
"found configuration file: {}",
|
||||
config.as_path().to_string_lossy()
|
||||
);
|
||||
|
||||
KomobarConfig::read(config)?
|
||||
}
|
||||
@@ -210,64 +153,33 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let config_path = config_path.unwrap_or(default_config_path);
|
||||
|
||||
if opts.aliases {
|
||||
KomobarConfig::aliases(&std::fs::read_to_string(&config_path)?);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let state = serde_json::from_str::<komorebi_client::State>(&komorebi_client::send_query(
|
||||
&SocketMessage::State,
|
||||
)?)?;
|
||||
|
||||
MONITOR_RIGHT.store(
|
||||
state.monitors.elements()[config.monitor.index].size().right,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
MONITOR_TOP.store(
|
||||
state.monitors.elements()[config.monitor.index].size().top,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
MONITOR_TOP.store(
|
||||
state.monitors.elements()[config.monitor.index].size().left,
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
match config.position {
|
||||
None => {
|
||||
config.position = Some(PositionConfig {
|
||||
start: Some(Position {
|
||||
x: state.monitors.elements()[config.monitor.index].size().left as f32,
|
||||
y: state.monitors.elements()[config.monitor.index].size().top as f32,
|
||||
}),
|
||||
end: Some(Position {
|
||||
x: state.monitors.elements()[config.monitor.index].size().right as f32,
|
||||
y: 50.0,
|
||||
}),
|
||||
})
|
||||
}
|
||||
Some(ref mut position) => {
|
||||
if position.start.is_none() {
|
||||
position.start = Some(Position {
|
||||
x: state.monitors.elements()[config.monitor.index].size().left as f32,
|
||||
y: state.monitors.elements()[config.monitor.index].size().top as f32,
|
||||
});
|
||||
}
|
||||
|
||||
if position.end.is_none() {
|
||||
position.end = Some(Position {
|
||||
x: state.monitors.elements()[config.monitor.index].size().right as f32,
|
||||
y: 50.0,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let viewport_builder = ViewportBuilder::default()
|
||||
let mut viewport_builder = ViewportBuilder::default()
|
||||
.with_decorations(false)
|
||||
// .with_transparent(config.transparent)
|
||||
.with_taskbar(false);
|
||||
.with_taskbar(false)
|
||||
.with_position(Position { x: 0.0, y: 0.0 })
|
||||
.with_inner_size({
|
||||
Position {
|
||||
x: state.monitors.elements()[config.monitor.index].size().right as f32,
|
||||
y: 20.0,
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(viewport) = &config.viewport {
|
||||
if let Some(position) = &viewport.position {
|
||||
let b = viewport_builder.clone();
|
||||
viewport_builder = b.with_position(*position);
|
||||
}
|
||||
|
||||
if let Some(inner_size) = &viewport.inner_size {
|
||||
let b = viewport_builder.clone();
|
||||
viewport_builder = b.with_inner_size(*inner_size);
|
||||
}
|
||||
}
|
||||
|
||||
let native_options = eframe::NativeOptions {
|
||||
viewport: viewport_builder,
|
||||
@@ -327,14 +239,10 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
let ctx_komorebi = cc.egui_ctx.clone();
|
||||
std::thread::spawn(move || {
|
||||
let subscriber_name = format!("komorebi-bar-{}", random_word::gen(random_word::Lang::En));
|
||||
|
||||
let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions {
|
||||
filter_state_changes: true,
|
||||
})
|
||||
let listener = komorebi_client::subscribe("komorebi-bar")
|
||||
.expect("could not subscribe to komorebi notifications");
|
||||
|
||||
tracing::info!("subscribed to komorebi notifications: \"{}\"", subscriber_name);
|
||||
tracing::info!("subscribed to komorebi notifications: \"komorebi-bar\"");
|
||||
|
||||
for client in listener.incoming() {
|
||||
match client {
|
||||
@@ -348,7 +256,9 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
// keep trying to reconnect to komorebi
|
||||
while komorebi_client::send_message(
|
||||
&SocketMessage::AddSubscriberSocket(subscriber_name.clone()),
|
||||
&SocketMessage::AddSubscriberSocket(String::from(
|
||||
"komorebi-bar",
|
||||
)),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
@@ -373,21 +283,18 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
match String::from_utf8(buffer) {
|
||||
Ok(notification_string) => {
|
||||
match serde_json::from_str::<komorebi_client::Notification>(
|
||||
¬ification_string,
|
||||
) {
|
||||
Ok(notification) => {
|
||||
tracing::debug!("received notification from komorebi");
|
||||
if let Ok(notification) =
|
||||
serde_json::from_str::<komorebi_client::Notification>(
|
||||
¬ification_string,
|
||||
)
|
||||
{
|
||||
tracing::debug!("received notification from komorebi");
|
||||
|
||||
if let Err(error) = tx_gui.send(notification) {
|
||||
tracing::error!("could not send komorebi notification update to gui thread: {error}")
|
||||
}
|
||||
if let Err(error) = tx_gui.send(notification) {
|
||||
tracing::error!("could not send komorebi notification update to gui: {error}")
|
||||
}
|
||||
|
||||
ctx_komorebi.request_repaint();
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!("could not deserialize komorebi notification: {error}");
|
||||
}
|
||||
ctx_komorebi.request_repaint();
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -24,8 +23,6 @@ pub struct MemoryConfig {
|
||||
pub enable: bool,
|
||||
/// Data refresh interval (default: 10 seconds)
|
||||
pub data_refresh_interval: Option<u64>,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<MemoryConfig> for Memory {
|
||||
@@ -39,7 +36,6 @@ impl From<MemoryConfig> for Memory {
|
||||
enable: value.enable,
|
||||
system,
|
||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||
last_updated: Instant::now(),
|
||||
}
|
||||
}
|
||||
@@ -49,7 +45,6 @@ pub struct Memory {
|
||||
pub enable: bool,
|
||||
system: System,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
last_updated: Instant,
|
||||
}
|
||||
|
||||
@@ -63,12 +58,7 @@ impl Memory {
|
||||
|
||||
let used = self.system.used_memory();
|
||||
let total = self.system.total_memory();
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("RAM: {}%", (used * 100) / total)
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
|
||||
}
|
||||
format!("RAM: {}%", (used * 100) / total)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +75,7 @@ impl BarWidget for Memory {
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::MEMORY.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
egui_phosphor::regular::MEMORY.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -31,8 +30,6 @@ pub struct NetworkConfig {
|
||||
pub network_activity_fill_characters: Option<usize>,
|
||||
/// Data refresh interval (default: 10 seconds)
|
||||
pub data_refresh_interval: Option<u64>,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<NetworkConfig> for Network {
|
||||
@@ -45,8 +42,6 @@ impl From<NetworkConfig> for Network {
|
||||
|
||||
let mut default_interface = String::new();
|
||||
|
||||
let prefix = value.label_prefix.unwrap_or(LabelPrefix::Icon);
|
||||
|
||||
if let Ok(interface) = netdev::get_default_interface() {
|
||||
if let Some(friendly_name) = interface.friendly_name {
|
||||
default_interface.clone_from(&friendly_name);
|
||||
@@ -55,32 +50,13 @@ impl From<NetworkConfig> for Network {
|
||||
networks_total_data_transmitted.refresh();
|
||||
for (interface_name, data) in &networks_total_data_transmitted {
|
||||
if friendly_name.eq(interface_name) {
|
||||
last_state_data.push(match prefix {
|
||||
LabelPrefix::None => format!(
|
||||
"{} | {}",
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::Icon => format!(
|
||||
"{} {} | {} {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::Text => format!(
|
||||
"\u{2211}DOWN: {} | \u{2211}UP: {}",
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::IconAndText => format!(
|
||||
"{} \u{2211}DOWN: {} | {} \u{2211}UP: {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
})
|
||||
last_state_data.push(format!(
|
||||
"{} {} / {} {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,40 +65,14 @@ impl From<NetworkConfig> for Network {
|
||||
networks_network_activity.refresh();
|
||||
for (interface_name, data) in &networks_network_activity {
|
||||
if friendly_name.eq(interface_name) {
|
||||
last_state_transmitted.push(match prefix {
|
||||
LabelPrefix::None => format!(
|
||||
"{: >width$}/s | {: >width$}/s",
|
||||
to_pretty_bytes(data.received(), 1),
|
||||
to_pretty_bytes(data.transmitted(), 1),
|
||||
width =
|
||||
value.network_activity_fill_characters.unwrap_or_default(),
|
||||
),
|
||||
LabelPrefix::Icon => format!(
|
||||
"{} {: >width$}/s | {} {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.transmitted(), 1),
|
||||
width =
|
||||
value.network_activity_fill_characters.unwrap_or_default(),
|
||||
),
|
||||
LabelPrefix::Text => format!(
|
||||
"DOWN: {: >width$}/s | UP: {: >width$}/s",
|
||||
to_pretty_bytes(data.received(), 1),
|
||||
to_pretty_bytes(data.transmitted(), 1),
|
||||
width =
|
||||
value.network_activity_fill_characters.unwrap_or_default(),
|
||||
),
|
||||
LabelPrefix::IconAndText => format!(
|
||||
"{} DOWN: {: >width$}/s | {} UP: {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.transmitted(), 1),
|
||||
width =
|
||||
value.network_activity_fill_characters.unwrap_or_default(),
|
||||
),
|
||||
})
|
||||
last_state_transmitted.push(format!(
|
||||
"{} {: >width$}/s {} {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.transmitted(), 1),
|
||||
width = value.network_activity_fill_characters.unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +85,6 @@ impl From<NetworkConfig> for Network {
|
||||
networks_network_activity,
|
||||
default_interface,
|
||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||
label_prefix: prefix,
|
||||
show_total_data_transmitted: value.show_total_data_transmitted,
|
||||
show_network_activity: value.show_network_activity,
|
||||
network_activity_fill_characters: value
|
||||
@@ -156,7 +105,6 @@ pub struct Network {
|
||||
networks_total_data_transmitted: Networks,
|
||||
networks_network_activity: Networks,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
default_interface: String,
|
||||
last_state_total_data_transmitted: Vec<String>,
|
||||
last_state_network_activity: Vec<String>,
|
||||
@@ -190,62 +138,14 @@ impl Network {
|
||||
self.networks_network_activity.refresh();
|
||||
for (interface_name, data) in &self.networks_network_activity {
|
||||
if friendly_name.eq(interface_name) {
|
||||
outputs.push(match self.label_prefix {
|
||||
LabelPrefix::None => format!(
|
||||
"{: >width$}/s | {: >width$}/s",
|
||||
to_pretty_bytes(
|
||||
data.received(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
to_pretty_bytes(
|
||||
data.transmitted(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
width = self.network_activity_fill_characters,
|
||||
),
|
||||
LabelPrefix::Icon => format!(
|
||||
"{} {: >width$}/s | {} {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(
|
||||
data.received(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(
|
||||
data.transmitted(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
width = self.network_activity_fill_characters,
|
||||
),
|
||||
LabelPrefix::Text => format!(
|
||||
"DOWN: {: >width$}/s | UP: {: >width$}/s",
|
||||
to_pretty_bytes(
|
||||
data.received(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
to_pretty_bytes(
|
||||
data.transmitted(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
width = self.network_activity_fill_characters,
|
||||
),
|
||||
LabelPrefix::IconAndText => {
|
||||
format!(
|
||||
"{} DOWN: {: >width$}/s | {} UP: {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(
|
||||
data.received(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(
|
||||
data.transmitted(),
|
||||
self.data_refresh_interval
|
||||
),
|
||||
width = self.network_activity_fill_characters,
|
||||
)
|
||||
}
|
||||
})
|
||||
outputs.push(format!(
|
||||
"{} {: >width$}/s {} {: >width$}/s",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.received(), self.data_refresh_interval),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.transmitted(), self.data_refresh_interval),
|
||||
width = self.network_activity_fill_characters,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,32 +176,13 @@ impl Network {
|
||||
|
||||
for (interface_name, data) in &self.networks_total_data_transmitted {
|
||||
if friendly_name.eq(interface_name) {
|
||||
outputs.push(match self.label_prefix {
|
||||
LabelPrefix::None => format!(
|
||||
"{} | {}",
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::Icon => format!(
|
||||
"{} {} | {} {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::Text => format!(
|
||||
"\u{2211}DOWN: {} | \u{2211}UP: {}",
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
LabelPrefix::IconAndText => format!(
|
||||
"{} \u{2211}DOWN: {} | {} \u{2211}UP: {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
),
|
||||
})
|
||||
outputs.push(format!(
|
||||
"{} {} / {} {}",
|
||||
egui_phosphor::regular::ARROW_FAT_DOWN,
|
||||
to_pretty_bytes(data.total_received(), 1),
|
||||
egui_phosphor::regular::ARROW_FAT_UP,
|
||||
to_pretty_bytes(data.total_transmitted(), 1),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,21 +227,12 @@ impl BarWidget for Network {
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::WIFI_HIGH.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
egui_phosphor::regular::WIFI_HIGH.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
);
|
||||
|
||||
if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix {
|
||||
self.default_interface.insert_str(0, "NET: ");
|
||||
}
|
||||
|
||||
layout_job.append(
|
||||
&self.default_interface,
|
||||
10.0,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -23,8 +22,6 @@ pub struct StorageConfig {
|
||||
pub enable: bool,
|
||||
/// Data refresh interval (default: 10 seconds)
|
||||
pub data_refresh_interval: Option<u64>,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<StorageConfig> for Storage {
|
||||
@@ -33,7 +30,6 @@ impl From<StorageConfig> for Storage {
|
||||
enable: value.enable,
|
||||
disks: Disks::new_with_refreshed_list(),
|
||||
data_refresh_interval: value.data_refresh_interval.unwrap_or(10),
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::IconAndText),
|
||||
last_updated: Instant::now(),
|
||||
}
|
||||
}
|
||||
@@ -43,7 +39,6 @@ pub struct Storage {
|
||||
pub enable: bool,
|
||||
disks: Disks,
|
||||
data_refresh_interval: u64,
|
||||
label_prefix: LabelPrefix,
|
||||
last_updated: Instant,
|
||||
}
|
||||
|
||||
@@ -63,12 +58,11 @@ impl Storage {
|
||||
let available = disk.available_space();
|
||||
let used = total - available;
|
||||
|
||||
disks.push(match self.label_prefix {
|
||||
LabelPrefix::Text | LabelPrefix::IconAndText => {
|
||||
format!("{} {}%", mount.to_string_lossy(), (used * 100) / total)
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Icon => format!("{}%", (used * 100) / total),
|
||||
})
|
||||
disks.push(format!(
|
||||
"{} {}%",
|
||||
mount.to_string_lossy(),
|
||||
(used * 100) / total
|
||||
))
|
||||
}
|
||||
|
||||
disks.sort();
|
||||
@@ -90,12 +84,7 @@ impl BarWidget for Storage {
|
||||
|
||||
for output in self.output() {
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::HARD_DRIVES.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
egui_phosphor::regular::HARD_DRIVES.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::config::LabelPrefix;
|
||||
use crate::widget::BarWidget;
|
||||
use crate::WIDGET_SPACING;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
@@ -19,8 +18,6 @@ pub struct TimeConfig {
|
||||
pub enable: bool,
|
||||
/// Set the Time format
|
||||
pub format: TimeFormat,
|
||||
/// Display label prefix
|
||||
pub label_prefix: Option<LabelPrefix>,
|
||||
}
|
||||
|
||||
impl From<TimeConfig> for Time {
|
||||
@@ -28,7 +25,6 @@ impl From<TimeConfig> for Time {
|
||||
Self {
|
||||
enable: value.enable,
|
||||
format: value.format,
|
||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +61,6 @@ impl TimeFormat {
|
||||
pub struct Time {
|
||||
pub enable: bool,
|
||||
pub format: TimeFormat,
|
||||
label_prefix: LabelPrefix,
|
||||
}
|
||||
|
||||
impl Time {
|
||||
@@ -79,7 +74,7 @@ impl Time {
|
||||
impl BarWidget for Time {
|
||||
fn render(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||
if self.enable {
|
||||
let mut output = self.output();
|
||||
let output = self.output();
|
||||
if !output.is_empty() {
|
||||
let font_id = ctx
|
||||
.style()
|
||||
@@ -89,21 +84,12 @@ impl BarWidget for Time {
|
||||
.unwrap_or_else(FontId::default);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
match self.label_prefix {
|
||||
LabelPrefix::Icon | LabelPrefix::IconAndText => {
|
||||
egui_phosphor::regular::CLOCK.to_string()
|
||||
}
|
||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||
},
|
||||
egui_phosphor::regular::CLOCK.to_string(),
|
||||
font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
);
|
||||
|
||||
if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix {
|
||||
output.insert_str(0, "TIME: ");
|
||||
}
|
||||
|
||||
layout_job.append(
|
||||
&output,
|
||||
10.0,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use crate::battery::Battery;
|
||||
use crate::battery::BatteryConfig;
|
||||
use crate::cpu::Cpu;
|
||||
use crate::cpu::CpuConfig;
|
||||
use crate::date::Date;
|
||||
use crate::date::DateConfig;
|
||||
use crate::komorebi::Komorebi;
|
||||
@@ -29,7 +27,6 @@ pub trait BarWidget {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum WidgetConfig {
|
||||
Battery(BatteryConfig),
|
||||
Cpu(CpuConfig),
|
||||
Date(DateConfig),
|
||||
Komorebi(KomorebiConfig),
|
||||
Media(MediaConfig),
|
||||
@@ -43,7 +40,6 @@ impl WidgetConfig {
|
||||
pub fn as_boxed_bar_widget(&self) -> Box<dyn BarWidget> {
|
||||
match self {
|
||||
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::Komorebi(config) => Box::new(Komorebi::from(config)),
|
||||
WidgetConfig::Media(config) => Box::new(Media::from(*config)),
|
||||
|
||||
@@ -44,7 +44,6 @@ pub use komorebi::RuleDebug;
|
||||
pub use komorebi::StackbarConfig;
|
||||
pub use komorebi::State;
|
||||
pub use komorebi::StaticConfig;
|
||||
pub use komorebi::SubscribeOptions;
|
||||
pub use komorebi::TabsConfig;
|
||||
|
||||
use komorebi::DATA_DIR;
|
||||
@@ -97,29 +96,3 @@ pub fn subscribe(name: &str) -> std::io::Result<UnixListener> {
|
||||
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
pub fn subscribe_with_options(
|
||||
name: &str,
|
||||
options: SubscribeOptions,
|
||||
) -> std::io::Result<UnixListener> {
|
||||
let socket = DATA_DIR.join(name);
|
||||
|
||||
match std::fs::remove_file(&socket) {
|
||||
Ok(()) => {}
|
||||
Err(error) => match error.kind() {
|
||||
std::io::ErrorKind::NotFound => {}
|
||||
_ => {
|
||||
return Err(error);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let listener = UnixListener::bind(&socket)?;
|
||||
|
||||
send_message(&SocketMessage::AddSubscriberSocketWithOptions(
|
||||
name.to_string(),
|
||||
options,
|
||||
))?;
|
||||
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ fn main() {
|
||||
viewport: ViewportBuilder::default()
|
||||
.with_always_on_top()
|
||||
.with_inner_size([320.0, 500.0]),
|
||||
follow_system_theme: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -233,8 +234,7 @@ extern "system" fn enum_window(
|
||||
|
||||
fn json_view_ui(ui: &mut egui::Ui, code: &str) {
|
||||
let language = "json";
|
||||
let theme =
|
||||
egui_extras::syntax_highlighting::CodeTheme::from_memory(ui.ctx(), &ui.ctx().style());
|
||||
let theme = egui_extras::syntax_highlighting::CodeTheme::from_memory(ui.ctx());
|
||||
egui_extras::syntax_highlighting::code_view_ui(ui, &theme, code, language);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ version = "0.1.30"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "57c38257cb0c6434321320d3746049bd58c34674" }
|
||||
catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "f579847bf2f552b144361d5a78ed8cf360b55cbb" }
|
||||
#catppuccin-egui = { version = "5", default-features = false, features = ["egui28"] }
|
||||
base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev = "a2c48f45782c5604bf5482d3873021a9fe45ea1a" }
|
||||
catppuccin-egui = { version = "5.1", default-features = false, features = ["egui28"] }
|
||||
eframe = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -124,39 +124,35 @@ pub enum CatppuccinValue {
|
||||
Crust,
|
||||
}
|
||||
|
||||
pub fn color32_compat(rgba: [u8; 4]) -> Color32 {
|
||||
Color32::from_rgba_unmultiplied(rgba[0], rgba[1], rgba[2], rgba[3])
|
||||
}
|
||||
|
||||
impl CatppuccinValue {
|
||||
pub fn color32(&self, theme: catppuccin_egui::Theme) -> Color32 {
|
||||
match self {
|
||||
CatppuccinValue::Rosewater => color32_compat(theme.rosewater.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Flamingo => color32_compat(theme.flamingo.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Pink => color32_compat(theme.pink.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Mauve => color32_compat(theme.mauve.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Red => color32_compat(theme.red.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Maroon => color32_compat(theme.maroon.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Peach => color32_compat(theme.peach.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Yellow => color32_compat(theme.yellow.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Green => color32_compat(theme.green.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Teal => color32_compat(theme.teal.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Sky => color32_compat(theme.sky.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Sapphire => color32_compat(theme.sapphire.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Blue => color32_compat(theme.blue.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Lavender => color32_compat(theme.lavender.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Text => color32_compat(theme.text.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Subtext1 => color32_compat(theme.subtext1.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Subtext0 => color32_compat(theme.subtext0.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Overlay2 => color32_compat(theme.overlay2.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Overlay1 => color32_compat(theme.overlay1.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Overlay0 => color32_compat(theme.overlay0.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Surface2 => color32_compat(theme.surface2.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Surface1 => color32_compat(theme.surface1.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Surface0 => color32_compat(theme.surface0.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Base => color32_compat(theme.base.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Mantle => color32_compat(theme.mantle.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Crust => color32_compat(theme.crust.to_srgba_unmultiplied()),
|
||||
CatppuccinValue::Rosewater => theme.rosewater,
|
||||
CatppuccinValue::Flamingo => theme.flamingo,
|
||||
CatppuccinValue::Pink => theme.pink,
|
||||
CatppuccinValue::Mauve => theme.mauve,
|
||||
CatppuccinValue::Red => theme.red,
|
||||
CatppuccinValue::Maroon => theme.maroon,
|
||||
CatppuccinValue::Peach => theme.peach,
|
||||
CatppuccinValue::Yellow => theme.yellow,
|
||||
CatppuccinValue::Green => theme.green,
|
||||
CatppuccinValue::Teal => theme.teal,
|
||||
CatppuccinValue::Sky => theme.sky,
|
||||
CatppuccinValue::Sapphire => theme.sapphire,
|
||||
CatppuccinValue::Blue => theme.blue,
|
||||
CatppuccinValue::Lavender => theme.lavender,
|
||||
CatppuccinValue::Text => theme.text,
|
||||
CatppuccinValue::Subtext1 => theme.subtext1,
|
||||
CatppuccinValue::Subtext0 => theme.subtext0,
|
||||
CatppuccinValue::Overlay2 => theme.overlay2,
|
||||
CatppuccinValue::Overlay1 => theme.overlay1,
|
||||
CatppuccinValue::Overlay0 => theme.overlay0,
|
||||
CatppuccinValue::Surface2 => theme.surface2,
|
||||
CatppuccinValue::Surface1 => theme.surface1,
|
||||
CatppuccinValue::Surface0 => theme.surface0,
|
||||
CatppuccinValue::Base => theme.base,
|
||||
CatppuccinValue::Mantle => theme.mantle,
|
||||
CatppuccinValue::Crust => theme.crust,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use serde::Serialize;
|
||||
use crate::ring::Ring;
|
||||
use crate::window::Window;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Getters, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Getters, JsonSchema)]
|
||||
pub struct Container {
|
||||
#[getset(get = "pub")]
|
||||
id: String,
|
||||
@@ -27,6 +27,12 @@ impl Default for Container {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Container {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
pub fn hide(&self, omit: Option<isize>) {
|
||||
for window in self.windows().iter().rev() {
|
||||
|
||||
@@ -77,7 +77,6 @@ pub enum SocketMessage {
|
||||
ToggleMonocle,
|
||||
ToggleMaximize,
|
||||
ToggleWindowContainerBehaviour,
|
||||
ToggleFloatOverride,
|
||||
WindowHidingBehaviour(HidingBehaviour),
|
||||
ToggleCrossMonitorMoveBehaviour,
|
||||
CrossMonitorMoveBehaviour(MoveBehaviour),
|
||||
@@ -91,8 +90,6 @@ pub enum SocketMessage {
|
||||
CycleLayout(CycleDirection),
|
||||
ChangeLayoutCustom(PathBuf),
|
||||
FlipLayout(Axis),
|
||||
ToggleWorkspaceWindowContainerBehaviour,
|
||||
ToggleWorkspaceFloatOverride,
|
||||
// Monitor and Workspace Commands
|
||||
MonitorIndexPreference(usize, i32, i32, i32, i32),
|
||||
DisplayIndexPreference(usize, String),
|
||||
@@ -196,7 +193,6 @@ pub enum SocketMessage {
|
||||
RemoveTitleBar(ApplicationIdentifier, String),
|
||||
ToggleTitleBars,
|
||||
AddSubscriberSocket(String),
|
||||
AddSubscriberSocketWithOptions(String, SubscribeOptions),
|
||||
RemoveSubscriberSocket(String),
|
||||
AddSubscriberPipe(String),
|
||||
RemoveSubscriberPipe(String),
|
||||
@@ -222,12 +218,6 @@ impl FromStr for SocketMessage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct SubscribeOptions {
|
||||
/// Only emit notifications when the window manager state has changed
|
||||
pub filter_state_changes: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Display, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum StackbarMode {
|
||||
Always,
|
||||
@@ -343,16 +333,7 @@ pub enum ApplicationIdentifier {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum FocusFollowsMouseImplementation {
|
||||
/// A custom FFM implementation (slightly more CPU-intensive)
|
||||
@@ -361,48 +342,18 @@ pub enum FocusFollowsMouseImplementation {
|
||||
Windows,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
pub struct WindowManagementBehaviour {
|
||||
/// The current WindowContainerBehaviour to be used
|
||||
pub current_behaviour: WindowContainerBehaviour,
|
||||
/// Override of `current_behaviour` to open new windows as floating windows
|
||||
/// that can be later toggled to tiled, when false it will default to
|
||||
/// `current_behaviour` again.
|
||||
pub float_override: bool,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
PartialEq,
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum WindowContainerBehaviour {
|
||||
/// Create a new container for each new window
|
||||
#[default]
|
||||
Create,
|
||||
/// Append new windows to the focused window container
|
||||
Append,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum MoveBehaviour {
|
||||
/// Swap the window container with the window container at the edge of the adjacent monitor
|
||||
@@ -436,16 +387,7 @@ pub enum HidingBehaviour {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
ValueEnum,
|
||||
JsonSchema,
|
||||
Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema,
|
||||
)]
|
||||
pub enum OperationBehaviour {
|
||||
/// Process komorebic commands on temporarily unmanaged/floated windows
|
||||
|
||||
@@ -166,19 +166,10 @@ lazy_static! {
|
||||
"X410.exe".to_string(),
|
||||
"vcxsrv.exe".to_string(),
|
||||
]));
|
||||
static ref SLOW_APPLICATION_IDENTIFIERS: Arc<Mutex<Vec<MatchingRule>>> = Arc::new(Mutex::new(vec![
|
||||
MatchingRule::Simple(IdWithIdentifier {
|
||||
kind: ApplicationIdentifier::Exe,
|
||||
id: String::from("firefox.exe"),
|
||||
matching_strategy: Option::from(MatchingStrategy::Equals),
|
||||
}),
|
||||
]));
|
||||
static ref SUBSCRIPTION_PIPES: Arc<Mutex<HashMap<String, File>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
pub static ref SUBSCRIPTION_SOCKETS: Arc<Mutex<HashMap<String, PathBuf>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
pub static ref SUBSCRIPTION_SOCKET_OPTIONS: Arc<Mutex<HashMap<String, SubscribeOptions>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
static ref TCP_CONNECTIONS: Arc<Mutex<HashMap<String, TcpStream>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
static ref HIDING_BEHAVIOUR: Arc<Mutex<HidingBehaviour>> =
|
||||
@@ -240,8 +231,6 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
|
||||
pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250);
|
||||
|
||||
pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20);
|
||||
|
||||
#[must_use]
|
||||
pub fn current_virtual_desktop() -> Option<Vec<u8>> {
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
@@ -299,34 +288,18 @@ pub struct Notification {
|
||||
pub state: State,
|
||||
}
|
||||
|
||||
pub fn notify_subscribers(notification: Notification, state_has_been_modified: bool) -> Result<()> {
|
||||
let is_subscription_event = matches!(
|
||||
notification.event,
|
||||
NotificationEvent::Socket(SocketMessage::AddSubscriberSocket(_))
|
||||
| NotificationEvent::Socket(SocketMessage::AddSubscriberSocketWithOptions(_, _))
|
||||
);
|
||||
|
||||
let notification = &serde_json::to_string(¬ification)?;
|
||||
pub fn notify_subscribers(notification: &str) -> Result<()> {
|
||||
let mut stale_sockets = vec![];
|
||||
let mut sockets = SUBSCRIPTION_SOCKETS.lock();
|
||||
let options = SUBSCRIPTION_SOCKET_OPTIONS.lock();
|
||||
|
||||
for (socket, path) in &mut *sockets {
|
||||
let apply_state_filter = (*options)
|
||||
.get(socket)
|
||||
.copied()
|
||||
.unwrap_or_default()
|
||||
.filter_state_changes;
|
||||
|
||||
if !apply_state_filter || state_has_been_modified || is_subscription_event {
|
||||
match UnixStream::connect(path) {
|
||||
Ok(mut stream) => {
|
||||
tracing::debug!("pushed notification to subscriber: {socket}");
|
||||
stream.write_all(notification.as_bytes())?;
|
||||
}
|
||||
Err(_) => {
|
||||
stale_sockets.push(socket.clone());
|
||||
}
|
||||
match UnixStream::connect(path) {
|
||||
Ok(mut stream) => {
|
||||
tracing::debug!("pushed notification to subscriber: {socket}");
|
||||
stream.write_all(notification.as_bytes())?;
|
||||
}
|
||||
Err(_) => {
|
||||
stale_sockets.push(socket.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,13 +307,6 @@ pub fn notify_subscribers(notification: Notification, state_has_been_modified: b
|
||||
for socket in stale_sockets {
|
||||
tracing::warn!("removing stale subscription: {socket}");
|
||||
sockets.remove(&socket);
|
||||
let socket_path = DATA_DIR.join(socket);
|
||||
if let Err(error) = std::fs::remove_file(&socket_path) {
|
||||
tracing::error!(
|
||||
"could not remove stale subscriber socket file at {}: {error}",
|
||||
socket_path.display()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let mut stale_pipes = vec![];
|
||||
|
||||
@@ -61,7 +61,6 @@ use crate::winevent_listener;
|
||||
use crate::GlobalState;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::State;
|
||||
use crate::ANIMATION_DURATION;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use crate::ANIMATION_FPS;
|
||||
@@ -80,7 +79,6 @@ use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::REMOVE_TITLEBARS;
|
||||
use crate::SUBSCRIPTION_PIPES;
|
||||
use crate::SUBSCRIPTION_SOCKETS;
|
||||
use crate::SUBSCRIPTION_SOCKET_OPTIONS;
|
||||
use crate::TCP_CONNECTIONS;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WINDOWS_11;
|
||||
@@ -189,10 +187,6 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_asref)]
|
||||
// We don't have From implemented for &mut WindowManager
|
||||
let initial_state = State::from(self.as_ref());
|
||||
|
||||
match message {
|
||||
SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => {
|
||||
if let Some(monitor) = self.focused_monitor_mut() {
|
||||
@@ -238,13 +232,6 @@ impl WindowManager {
|
||||
self.focused_window()?.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
SocketMessage::FocusStackWindow(idx) => {
|
||||
// In case you are using this command on a bar on a monitor
|
||||
// different from the currently focused one, you'd want that
|
||||
// monitor to be focused so that the FocusStackWindow happens
|
||||
// on the monitor with the bar you just pressed.
|
||||
if let Some(monitor_idx) = self.monitor_idx_from_current_pos() {
|
||||
self.focus_monitor(monitor_idx)?;
|
||||
}
|
||||
self.focus_container_window(idx)?;
|
||||
self.focused_window()?.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
@@ -1325,14 +1312,6 @@ impl WindowManager {
|
||||
let socket_path = DATA_DIR.join(socket);
|
||||
sockets.insert(socket.clone(), socket_path);
|
||||
}
|
||||
SocketMessage::AddSubscriberSocketWithOptions(ref socket, options) => {
|
||||
let mut sockets = SUBSCRIPTION_SOCKETS.lock();
|
||||
let socket_path = DATA_DIR.join(socket);
|
||||
sockets.insert(socket.clone(), socket_path);
|
||||
|
||||
let mut socket_options = SUBSCRIPTION_SOCKET_OPTIONS.lock();
|
||||
socket_options.insert(socket.clone(), options);
|
||||
}
|
||||
SocketMessage::RemoveSubscriberSocket(ref socket) => {
|
||||
let mut sockets = SUBSCRIPTION_SOCKETS.lock();
|
||||
sockets.remove(socket);
|
||||
@@ -1360,52 +1339,15 @@ impl WindowManager {
|
||||
self.resize_delta = delta;
|
||||
}
|
||||
SocketMessage::ToggleWindowContainerBehaviour => {
|
||||
match self.window_management_behaviour.current_behaviour {
|
||||
match self.window_container_behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
self.window_management_behaviour.current_behaviour =
|
||||
WindowContainerBehaviour::Append;
|
||||
self.window_container_behaviour = WindowContainerBehaviour::Append;
|
||||
}
|
||||
WindowContainerBehaviour::Append => {
|
||||
self.window_management_behaviour.current_behaviour =
|
||||
WindowContainerBehaviour::Create;
|
||||
self.window_container_behaviour = WindowContainerBehaviour::Create;
|
||||
}
|
||||
}
|
||||
}
|
||||
SocketMessage::ToggleFloatOverride => {
|
||||
self.window_management_behaviour.float_override =
|
||||
!self.window_management_behaviour.float_override;
|
||||
}
|
||||
SocketMessage::ToggleWorkspaceWindowContainerBehaviour => {
|
||||
let current_global_behaviour = self.window_management_behaviour.current_behaviour;
|
||||
if let Some(behaviour) = self
|
||||
.focused_workspace_mut()?
|
||||
.window_container_behaviour_mut()
|
||||
{
|
||||
match behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
*behaviour = WindowContainerBehaviour::Append
|
||||
}
|
||||
WindowContainerBehaviour::Append => {
|
||||
*behaviour = WindowContainerBehaviour::Create
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.focused_workspace_mut()?
|
||||
.set_window_container_behaviour(Some(match current_global_behaviour {
|
||||
WindowContainerBehaviour::Create => WindowContainerBehaviour::Append,
|
||||
WindowContainerBehaviour::Append => WindowContainerBehaviour::Create,
|
||||
}));
|
||||
};
|
||||
}
|
||||
SocketMessage::ToggleWorkspaceFloatOverride => {
|
||||
let current_global_override = self.window_management_behaviour.float_override;
|
||||
if let Some(float_override) = self.focused_workspace_mut()?.float_override_mut() {
|
||||
*float_override = !*float_override;
|
||||
} else {
|
||||
self.focused_workspace_mut()?
|
||||
.set_float_override(Some(!current_global_override));
|
||||
};
|
||||
}
|
||||
SocketMessage::WindowHidingBehaviour(behaviour) => {
|
||||
let mut hiding_behaviour = HIDING_BEHAVIOUR.lock();
|
||||
*hiding_behaviour = behaviour;
|
||||
@@ -1588,14 +1530,12 @@ impl WindowManager {
|
||||
| SocketMessage::IdentifyBorderOverflowApplication(_, _) => {}
|
||||
};
|
||||
|
||||
notify_subscribers(
|
||||
Notification {
|
||||
event: NotificationEvent::Socket(message.clone()),
|
||||
state: self.as_ref().into(),
|
||||
},
|
||||
initial_state.has_been_modified(self.as_ref()),
|
||||
)?;
|
||||
let notification = Notification {
|
||||
event: NotificationEvent::Socket(message.clone()),
|
||||
state: self.as_ref().into(),
|
||||
};
|
||||
|
||||
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||
border_manager::send_notification(None);
|
||||
transparency_manager::send_notification();
|
||||
stackbar_manager::send_notification();
|
||||
|
||||
@@ -32,7 +32,6 @@ use crate::workspace_reconciliator::ALT_TAB_HWND;
|
||||
use crate::workspace_reconciliator::ALT_TAB_HWND_INSTANT;
|
||||
use crate::Notification;
|
||||
use crate::NotificationEvent;
|
||||
use crate::State;
|
||||
use crate::DATA_DIR;
|
||||
use crate::FLOATING_APPLICATIONS;
|
||||
use crate::HIDDEN_HWNDS;
|
||||
@@ -123,10 +122,6 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_asref)]
|
||||
// We don't have From implemented for &mut WindowManager
|
||||
let initial_state = State::from(self.as_ref());
|
||||
|
||||
// Make sure we have the most recently focused monitor from any event
|
||||
match event {
|
||||
WindowManagerEvent::FocusChange(_, window)
|
||||
@@ -338,8 +333,8 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
if proceed {
|
||||
let mut behaviour = self
|
||||
.window_management_behaviour(focused_monitor_idx, focused_workspace_idx);
|
||||
let behaviour =
|
||||
self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx);
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
let workspace_contains_window = workspace.contains_window(window.hwnd);
|
||||
let monocle_container = workspace.monocle_container().clone();
|
||||
@@ -365,14 +360,11 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
behaviour.float_override = behaviour.float_override
|
||||
|| (should_float && !matches!(event, WindowManagerEvent::Manage(_)));
|
||||
|
||||
if behaviour.float_override {
|
||||
if should_float && !matches!(event, WindowManagerEvent::Manage(_)) {
|
||||
workspace.floating_windows_mut().push(window);
|
||||
self.update_focused_workspace(false, false)?;
|
||||
self.update_focused_workspace(false, true)?;
|
||||
} else {
|
||||
match behaviour.current_behaviour {
|
||||
match behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
workspace.new_container_for_window(window);
|
||||
self.update_focused_workspace(false, false)?;
|
||||
@@ -383,6 +375,7 @@ impl WindowManager {
|
||||
.ok_or_else(|| anyhow!("there is no focused container"))?
|
||||
.add_window(window);
|
||||
self.update_focused_workspace(true, false)?;
|
||||
|
||||
stackbar_manager::send_notification();
|
||||
}
|
||||
}
|
||||
@@ -438,8 +431,8 @@ impl WindowManager {
|
||||
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
let focused_workspace_idx = self.focused_workspace_idx().unwrap_or_default();
|
||||
let window_management_behaviour =
|
||||
self.window_management_behaviour(focused_monitor_idx, focused_workspace_idx);
|
||||
let window_container_behaviour =
|
||||
self.window_container_behaviour(focused_monitor_idx, focused_workspace_idx);
|
||||
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
let focused_container_idx = workspace.focused_container_idx();
|
||||
@@ -557,11 +550,8 @@ impl WindowManager {
|
||||
}
|
||||
// Here we handle a simple move on the same monitor which is treated as
|
||||
// a container swap
|
||||
} else if window_management_behaviour.float_override {
|
||||
workspace.floating_windows_mut().push(window);
|
||||
self.update_focused_workspace(false, false)?;
|
||||
} else {
|
||||
match window_management_behaviour.current_behaviour {
|
||||
match window_container_behaviour {
|
||||
WindowContainerBehaviour::Create => {
|
||||
match workspace.container_idx_from_current_point() {
|
||||
Some(target_idx) => {
|
||||
@@ -675,14 +665,12 @@ impl WindowManager {
|
||||
|
||||
serde_json::to_writer_pretty(&file, &known_hwnds)?;
|
||||
|
||||
notify_subscribers(
|
||||
Notification {
|
||||
event: NotificationEvent::WindowManager(event),
|
||||
state: self.as_ref().into(),
|
||||
},
|
||||
initial_state.has_been_modified(self.as_ref()),
|
||||
)?;
|
||||
let notification = Notification {
|
||||
event: NotificationEvent::WindowManager(event),
|
||||
state: self.as_ref().into(),
|
||||
};
|
||||
|
||||
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||
border_manager::send_notification(Some(event.hwnd()));
|
||||
transparency_manager::send_notification();
|
||||
stackbar_manager::send_notification();
|
||||
|
||||
@@ -43,8 +43,6 @@ use crate::MANAGE_IDENTIFIERS;
|
||||
use crate::MONITOR_INDEX_PREFERENCES;
|
||||
use crate::OBJECT_NAME_CHANGE_ON_LAUNCH;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||
use crate::SLOW_APPLICATION_IDENTIFIERS;
|
||||
use crate::TRANSPARENCY_BLACKLIST;
|
||||
use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS;
|
||||
use crate::WINDOWS_11;
|
||||
@@ -68,7 +66,6 @@ use crate::core::OperationBehaviour;
|
||||
use crate::core::Rect;
|
||||
use crate::core::SocketMessage;
|
||||
use crate::core::WindowContainerBehaviour;
|
||||
use crate::core::WindowManagementBehaviour;
|
||||
use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
use hotwatch::EventKind;
|
||||
@@ -96,8 +93,6 @@ pub struct BorderColours {
|
||||
pub stack: Option<Colour>,
|
||||
/// Border colour when the container is in monocle mode
|
||||
pub monocle: Option<Colour>,
|
||||
/// Border colour when the container is in floating mode
|
||||
pub floating: Option<Colour>,
|
||||
/// Border colour when the container is unfocused
|
||||
pub unfocused: Option<Colour>,
|
||||
}
|
||||
@@ -133,13 +128,6 @@ pub struct WorkspaceConfig {
|
||||
/// Apply this monitor's window-based work area offset (default: true)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub apply_window_based_work_area_offset: Option<bool>,
|
||||
/// Determine what happens when a new window is opened (default: Create)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_container_behaviour: Option<WindowContainerBehaviour>,
|
||||
/// Enable or disable float override, which makes it so every new window opens in floating mode
|
||||
/// (default: false)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub float_override: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<&Workspace> for WorkspaceConfig {
|
||||
@@ -192,8 +180,6 @@ impl From<&Workspace> for WorkspaceConfig {
|
||||
initial_workspace_rules: None,
|
||||
workspace_rules: None,
|
||||
apply_window_based_work_area_offset: Some(value.apply_window_based_work_area_offset()),
|
||||
window_container_behaviour: *value.window_container_behaviour(),
|
||||
float_override: *value.float_override(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,10 +233,6 @@ pub struct StaticConfig {
|
||||
/// Determine what happens when a new window is opened (default: Create)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_container_behaviour: Option<WindowContainerBehaviour>,
|
||||
/// Enable or disable float override, which makes it so every new window opens in floating mode
|
||||
/// (default: false)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub float_override: Option<bool>,
|
||||
/// Determine what happens when a window is moved across a monitor boundary (default: Swap)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cross_monitor_move_behaviour: Option<MoveBehaviour>,
|
||||
@@ -356,16 +338,6 @@ pub struct StaticConfig {
|
||||
/// Theme configuration options
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub theme: Option<KomorebiTheme>,
|
||||
/// Identify applications which are slow to send initial event notifications
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub slow_application_identifiers: Option<Vec<MatchingRule>>,
|
||||
/// How long to wait when compensating for slow applications, in milliseconds (default: 20)
|
||||
#[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
|
||||
#[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>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
@@ -527,9 +499,6 @@ impl From<&WindowManager> for StaticConfig {
|
||||
single: Option::from(Colour::from(border_manager::FOCUSED.load(Ordering::SeqCst))),
|
||||
stack: Option::from(Colour::from(border_manager::STACK.load(Ordering::SeqCst))),
|
||||
monocle: Option::from(Colour::from(border_manager::MONOCLE.load(Ordering::SeqCst))),
|
||||
floating: Option::from(Colour::from(
|
||||
border_manager::FLOATING.load(Ordering::SeqCst),
|
||||
)),
|
||||
unfocused: Option::from(Colour::from(
|
||||
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||
)),
|
||||
@@ -539,10 +508,7 @@ impl From<&WindowManager> for StaticConfig {
|
||||
Self {
|
||||
invisible_borders: None,
|
||||
resize_delta: Option::from(value.resize_delta),
|
||||
window_container_behaviour: Option::from(
|
||||
value.window_management_behaviour.current_behaviour,
|
||||
),
|
||||
float_override: Option::from(value.window_management_behaviour.float_override),
|
||||
window_container_behaviour: Option::from(value.window_container_behaviour),
|
||||
cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour),
|
||||
cross_boundary_behaviour: Option::from(value.cross_boundary_behaviour),
|
||||
unmanaged_window_operation_behaviour: Option::from(
|
||||
@@ -588,11 +554,6 @@ impl From<&WindowManager> for StaticConfig {
|
||||
stackbar: None,
|
||||
animation: None,
|
||||
theme: None,
|
||||
slow_application_compensation_time: Option::from(
|
||||
SLOW_APPLICATION_COMPENSATION_TIME.load(Ordering::SeqCst),
|
||||
),
|
||||
slow_application_identifiers: Option::from(SLOW_APPLICATION_IDENTIFIERS.lock().clone()),
|
||||
bar_configurations: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,10 +620,6 @@ impl StaticConfig {
|
||||
border_manager::MONOCLE.store(u32::from(monocle), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(floating) = colours.floating {
|
||||
border_manager::FLOATING.store(u32::from(floating), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(unfocused) = colours.unfocused {
|
||||
border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst);
|
||||
}
|
||||
@@ -705,7 +662,6 @@ impl StaticConfig {
|
||||
let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock();
|
||||
let mut layered_identifiers = LAYERED_WHITELIST.lock();
|
||||
let mut transparency_blacklist = TRANSPARENCY_BLACKLIST.lock();
|
||||
let mut slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
|
||||
let mut floating_applications = FLOATING_APPLICATIONS.lock();
|
||||
|
||||
if let Some(rules) = &mut self.ignore_rules {
|
||||
@@ -744,14 +700,6 @@ impl StaticConfig {
|
||||
populate_rules(rules, &mut transparency_blacklist, &mut regex_identifiers)?;
|
||||
}
|
||||
|
||||
if let Some(rules) = &mut self.slow_application_identifiers {
|
||||
populate_rules(
|
||||
rules,
|
||||
&mut slow_application_identifiers,
|
||||
&mut regex_identifiers,
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(stackbar) = &self.stackbar {
|
||||
if let Some(height) = &stackbar.height {
|
||||
STACKBAR_TAB_HEIGHT.store(*height, Ordering::SeqCst);
|
||||
@@ -990,34 +938,7 @@ impl StaticConfig {
|
||||
|
||||
pub fn read(path: &PathBuf) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut value: Self = serde_json::from_str(&content)?;
|
||||
|
||||
if let Some(path) = &mut value.app_specific_configuration_path {
|
||||
*path = resolve_home_path(&*path)?;
|
||||
}
|
||||
|
||||
if let Some(monitors) = &mut value.monitors {
|
||||
for m in monitors {
|
||||
for w in &mut m.workspaces {
|
||||
if let Some(path) = &mut w.custom_layout {
|
||||
*path = resolve_home_path(&*path)?;
|
||||
}
|
||||
|
||||
if let Some(map) = &mut w.custom_layout_rules {
|
||||
for path in map.values_mut() {
|
||||
*path = resolve_home_path(&*path)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bar_configurations) = &mut value.bar_configurations {
|
||||
for path in bar_configurations {
|
||||
*path = resolve_home_path(&*path)?;
|
||||
}
|
||||
}
|
||||
|
||||
let value: Self = serde_json::from_str(&content)?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
@@ -1027,7 +948,8 @@ impl StaticConfig {
|
||||
incoming: Receiver<WindowManagerEvent>,
|
||||
unix_listener: Option<UnixListener>,
|
||||
) -> Result<WindowManager> {
|
||||
let mut value = Self::read(path)?;
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut value: Self = serde_json::from_str(&content)?;
|
||||
value.apply_globals()?;
|
||||
|
||||
let listener = match unix_listener {
|
||||
@@ -1057,12 +979,9 @@ impl StaticConfig {
|
||||
is_paused: false,
|
||||
virtual_desktop_id: current_virtual_desktop(),
|
||||
work_area_offset: value.global_work_area_offset,
|
||||
window_management_behaviour: WindowManagementBehaviour {
|
||||
current_behaviour: value
|
||||
.window_container_behaviour
|
||||
.unwrap_or(WindowContainerBehaviour::Create),
|
||||
float_override: value.float_override.unwrap_or_default(),
|
||||
},
|
||||
window_container_behaviour: value
|
||||
.window_container_behaviour
|
||||
.unwrap_or(WindowContainerBehaviour::Create),
|
||||
cross_monitor_move_behaviour: value
|
||||
.cross_monitor_move_behaviour
|
||||
.unwrap_or(MoveBehaviour::Swap),
|
||||
@@ -1109,7 +1028,8 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
pub fn postload(path: &PathBuf, wm: &Arc<Mutex<WindowManager>>) -> Result<()> {
|
||||
let value = Self::read(path)?;
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let value: Self = serde_json::from_str(&content)?;
|
||||
let mut wm = wm.lock();
|
||||
|
||||
if let Some(monitors) = value.monitors {
|
||||
@@ -1176,7 +1096,8 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> Result<()> {
|
||||
let mut value = Self::read(path)?;
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let mut value: Self = serde_json::from_str(&content)?;
|
||||
|
||||
value.apply_globals()?;
|
||||
|
||||
@@ -1237,11 +1158,7 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
if let Some(val) = value.window_container_behaviour {
|
||||
wm.window_management_behaviour.current_behaviour = val;
|
||||
}
|
||||
|
||||
if let Some(val) = value.float_override {
|
||||
wm.window_management_behaviour.float_override = val;
|
||||
wm.window_container_behaviour = val;
|
||||
}
|
||||
|
||||
if let Some(val) = value.cross_monitor_move_behaviour {
|
||||
|
||||
@@ -6,8 +6,6 @@ use crate::windows_api;
|
||||
use crate::ANIMATIONS_IN_PROGRESS;
|
||||
use crate::ANIMATION_DURATION;
|
||||
use crate::ANIMATION_ENABLED;
|
||||
use crate::SLOW_APPLICATION_COMPENSATION_TIME;
|
||||
use crate::SLOW_APPLICATION_IDENTIFIERS;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Display;
|
||||
@@ -159,31 +157,6 @@ impl Window {
|
||||
HWND(windows_api::as_ptr!(self.hwnd))
|
||||
}
|
||||
|
||||
pub fn move_to_area(&mut self, current_area: &Rect, target_area: &Rect) -> Result<()> {
|
||||
let current_rect = WindowsApi::window_rect(self.hwnd)?;
|
||||
let x_diff = target_area.left - current_area.left;
|
||||
let y_diff = target_area.top - current_area.top;
|
||||
let x_ratio = f32::abs((target_area.right as f32) / (current_area.right as f32));
|
||||
let y_ratio = f32::abs((target_area.bottom as f32) / (current_area.bottom as f32));
|
||||
let window_relative_x = current_rect.left - current_area.left;
|
||||
let window_relative_y = current_rect.top - current_area.top;
|
||||
let corrected_relative_x = (window_relative_x as f32 * x_ratio) as i32;
|
||||
let corrected_relative_y = (window_relative_y as f32 * y_ratio) as i32;
|
||||
let window_x = current_area.left + corrected_relative_x;
|
||||
let window_y = current_area.top + corrected_relative_y;
|
||||
|
||||
let new_rect = Rect {
|
||||
left: x_diff + window_x,
|
||||
top: y_diff + window_y,
|
||||
right: current_rect.right,
|
||||
bottom: current_rect.bottom,
|
||||
};
|
||||
//TODO: We might need to take into account the differences in DPI for the new_rect, unless
|
||||
//we can use the xy ratios above to the right/bottom (width/height of window) as well?
|
||||
|
||||
self.set_position(&new_rect, true)
|
||||
}
|
||||
|
||||
pub fn center(&mut self, work_area: &Rect) -> Result<()> {
|
||||
let half_width = work_area.right / 2;
|
||||
let half_weight = work_area.bottom / 2;
|
||||
@@ -305,10 +278,7 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn minimize(self) {
|
||||
let exe = self.exe().unwrap_or_default();
|
||||
if !exe.contains("komorebi-bar") {
|
||||
WindowsApi::minimize_window(self.hwnd);
|
||||
}
|
||||
WindowsApi::minimize_window(self.hwnd);
|
||||
}
|
||||
|
||||
pub fn close(self) -> Result<()> {
|
||||
@@ -664,23 +634,8 @@ fn window_is_eligible(
|
||||
titlebars_removed.contains(exe_name)
|
||||
};
|
||||
|
||||
{
|
||||
let slow_application_identifiers = SLOW_APPLICATION_IDENTIFIERS.lock();
|
||||
let should_sleep = should_act(
|
||||
title,
|
||||
exe_name,
|
||||
class,
|
||||
path,
|
||||
&slow_application_identifiers,
|
||||
®ex_identifiers,
|
||||
)
|
||||
.is_some();
|
||||
|
||||
if should_sleep {
|
||||
std::thread::sleep(Duration::from_millis(
|
||||
SLOW_APPLICATION_COMPENSATION_TIME.load(Ordering::SeqCst),
|
||||
));
|
||||
}
|
||||
if exe_name.contains("firefox") {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
|
||||
if (allow_wsl2_gui || allow_titlebar_removed || style.contains(WindowStyle::CAPTION) && ex_style.contains(ExtendedWindowStyle::WINDOWEDGE))
|
||||
|
||||
@@ -39,7 +39,6 @@ use crate::core::Rect;
|
||||
use crate::core::Sizing;
|
||||
use crate::core::StackbarLabel;
|
||||
use crate::core::WindowContainerBehaviour;
|
||||
use crate::core::WindowManagementBehaviour;
|
||||
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::STYLE;
|
||||
@@ -93,7 +92,7 @@ pub struct WindowManager {
|
||||
pub is_paused: bool,
|
||||
pub work_area_offset: Option<Rect>,
|
||||
pub resize_delta: i32,
|
||||
pub window_management_behaviour: WindowManagementBehaviour,
|
||||
pub window_container_behaviour: WindowContainerBehaviour,
|
||||
pub cross_monitor_move_behaviour: MoveBehaviour,
|
||||
pub cross_boundary_behaviour: CrossBoundaryBehaviour,
|
||||
pub unmanaged_window_operation_behaviour: OperationBehaviour,
|
||||
@@ -113,7 +112,6 @@ pub struct State {
|
||||
pub is_paused: bool,
|
||||
pub resize_delta: i32,
|
||||
pub new_window_behaviour: WindowContainerBehaviour,
|
||||
pub float_override: bool,
|
||||
pub cross_monitor_move_behaviour: MoveBehaviour,
|
||||
pub unmanaged_window_operation_behaviour: OperationBehaviour,
|
||||
pub work_area_offset: Option<Rect>,
|
||||
@@ -122,54 +120,6 @@ pub struct State {
|
||||
pub has_pending_raise_op: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn has_been_modified(&self, wm: &WindowManager) -> bool {
|
||||
let new = Self::from(wm);
|
||||
|
||||
if self.monitors != new.monitors {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.is_paused != new.is_paused {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.new_window_behaviour != new.new_window_behaviour {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.float_override != new.float_override {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.cross_monitor_move_behaviour != new.cross_monitor_move_behaviour {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.unmanaged_window_operation_behaviour != new.unmanaged_window_operation_behaviour {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.work_area_offset != new.work_area_offset {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.focus_follows_mouse != new.focus_follows_mouse {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.mouse_follows_focus != new.mouse_follows_focus {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.has_pending_raise_op != new.has_pending_raise_op {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GlobalState {
|
||||
@@ -215,9 +165,6 @@ impl Default for GlobalState {
|
||||
monocle: Option::from(Colour::Rgb(Rgb::from(
|
||||
border_manager::MONOCLE.load(Ordering::SeqCst),
|
||||
))),
|
||||
floating: Option::from(Colour::Rgb(Rgb::from(
|
||||
border_manager::FLOATING.load(Ordering::SeqCst),
|
||||
))),
|
||||
unfocused: Option::from(Colour::Rgb(Rgb::from(
|
||||
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||
))),
|
||||
@@ -268,8 +215,7 @@ impl From<&WindowManager> for State {
|
||||
is_paused: wm.is_paused,
|
||||
work_area_offset: wm.work_area_offset,
|
||||
resize_delta: wm.resize_delta,
|
||||
new_window_behaviour: wm.window_management_behaviour.current_behaviour,
|
||||
float_override: wm.window_management_behaviour.float_override,
|
||||
new_window_behaviour: wm.window_container_behaviour,
|
||||
cross_monitor_move_behaviour: wm.cross_monitor_move_behaviour,
|
||||
focus_follows_mouse: wm.focus_follows_mouse,
|
||||
mouse_follows_focus: wm.mouse_follows_focus,
|
||||
@@ -329,7 +275,7 @@ impl WindowManager {
|
||||
is_paused: false,
|
||||
virtual_desktop_id: current_virtual_desktop(),
|
||||
work_area_offset: None,
|
||||
window_management_behaviour: WindowManagementBehaviour::default(),
|
||||
window_container_behaviour: WindowContainerBehaviour::Create,
|
||||
cross_monitor_move_behaviour: MoveBehaviour::Swap,
|
||||
cross_boundary_behaviour: CrossBoundaryBehaviour::Workspace,
|
||||
unmanaged_window_operation_behaviour: OperationBehaviour::Op,
|
||||
@@ -362,52 +308,22 @@ impl WindowManager {
|
||||
StaticConfig::reload(pathbuf, self)
|
||||
}
|
||||
|
||||
pub fn window_management_behaviour(
|
||||
pub fn window_container_behaviour(
|
||||
&self,
|
||||
monitor_idx: usize,
|
||||
workspace_idx: usize,
|
||||
) -> WindowManagementBehaviour {
|
||||
) -> WindowContainerBehaviour {
|
||||
if let Some(monitor) = self.monitors().get(monitor_idx) {
|
||||
if let Some(workspace) = monitor.workspaces().get(workspace_idx) {
|
||||
let current_behaviour =
|
||||
if let Some(behaviour) = workspace.window_container_behaviour() {
|
||||
if workspace.containers().is_empty()
|
||||
&& matches!(behaviour, WindowContainerBehaviour::Append)
|
||||
{
|
||||
// You can't append to an empty workspace
|
||||
WindowContainerBehaviour::Create
|
||||
} else {
|
||||
*behaviour
|
||||
}
|
||||
} else if workspace.containers().is_empty()
|
||||
&& matches!(
|
||||
self.window_management_behaviour.current_behaviour,
|
||||
WindowContainerBehaviour::Append
|
||||
)
|
||||
{
|
||||
// You can't append to an empty workspace
|
||||
WindowContainerBehaviour::Create
|
||||
} else {
|
||||
self.window_management_behaviour.current_behaviour
|
||||
};
|
||||
|
||||
let float_override = if let Some(float_override) = workspace.float_override() {
|
||||
*float_override
|
||||
return if workspace.containers().is_empty() {
|
||||
WindowContainerBehaviour::Create
|
||||
} else {
|
||||
self.window_management_behaviour.float_override
|
||||
};
|
||||
|
||||
return WindowManagementBehaviour {
|
||||
current_behaviour,
|
||||
float_override,
|
||||
self.window_container_behaviour
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
WindowManagementBehaviour {
|
||||
current_behaviour: WindowContainerBehaviour::Create,
|
||||
float_override: self.window_management_behaviour.float_override,
|
||||
}
|
||||
WindowContainerBehaviour::Create
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
@@ -910,39 +826,28 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.focused_workspace()?.is_empty() {
|
||||
let desktop_window = Window::from(WindowsApi::desktop_window()?);
|
||||
}
|
||||
|
||||
match WindowsApi::raise_and_focus_window(desktop_window.hwnd) {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
tracing::warn!("{} {}:{}", error, file!(), line!());
|
||||
// if we passed false for follow_focus and there is a container on the workspace
|
||||
if !follow_focus && self.focused_container_mut().is_ok() {
|
||||
// and we have a stack with >1 windows
|
||||
if self.focused_container_mut()?.windows().len() > 1
|
||||
// and we don't have a maxed window
|
||||
&& self.focused_workspace()?.maximized_window().is_none()
|
||||
// and we don't have a monocle container
|
||||
&& self.focused_workspace()?.monocle_container().is_none()
|
||||
{
|
||||
if let Ok(window) = self.focused_window_mut() {
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we passed false for follow_focus and there is a container on the workspace
|
||||
if self.focused_container_mut().is_ok() {
|
||||
// and we have a stack with >1 windows
|
||||
if self.focused_container_mut()?.windows().len() > 1
|
||||
// and we don't have a maxed window
|
||||
&& self.focused_workspace()?.maximized_window().is_none()
|
||||
// and we don't have a monocle container
|
||||
&& self.focused_workspace()?.monocle_container().is_none()
|
||||
// and we don't have any floating windows that should show on top
|
||||
&& self.focused_workspace()?.floating_windows().is_empty()
|
||||
{
|
||||
if let Ok(window) = self.focused_window_mut() {
|
||||
if trigger_focus {
|
||||
window.focus(self.mouse_follows_focus)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is to correctly restore and focus when switching to a workspace which
|
||||
// contains a managed maximized window
|
||||
// This is to correctly restore and focus when switching to a workspace which
|
||||
// contains a managed maximized window
|
||||
if !follow_focus {
|
||||
if let Some(window) = self.focused_workspace()?.maximized_window() {
|
||||
window.restore();
|
||||
if trigger_focus {
|
||||
@@ -1055,14 +960,6 @@ impl WindowManager {
|
||||
|
||||
for monitor in self.monitors_mut() {
|
||||
for workspace in monitor.workspaces_mut() {
|
||||
if let Some(monocle) = workspace.monocle_container() {
|
||||
for window in monocle.windows() {
|
||||
if matches!(border_implementation, BorderImplementation::Windows) {
|
||||
window.remove_accent()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for containers in workspace.containers_mut() {
|
||||
for window in containers.windows_mut() {
|
||||
if no_titlebar.contains(&window.exe()?) {
|
||||
@@ -1236,8 +1133,6 @@ impl WindowManager {
|
||||
.focused_monitor_mut()
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
let current_area = *monitor.work_area_size();
|
||||
|
||||
let workspace = monitor
|
||||
.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no workspace"))?;
|
||||
@@ -1246,23 +1141,16 @@ impl WindowManager {
|
||||
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);
|
||||
let container = workspace
|
||||
.remove_focused_container()
|
||||
.ok_or_else(|| anyhow!("there is no container"))?;
|
||||
|
||||
let container_hwnds = container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.hwnd)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let floating_window =
|
||||
floating_window_index.map(|idx| workspace.floating_windows_mut().remove(idx));
|
||||
let container = if floating_window_index.is_none() {
|
||||
Some(
|
||||
workspace
|
||||
.remove_focused_container()
|
||||
.ok_or_else(|| anyhow!("there is no container"))?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
monitor.update_focused_workspace(offset)?;
|
||||
|
||||
let target_monitor = self
|
||||
@@ -1270,36 +1158,18 @@ impl WindowManager {
|
||||
.get_mut(monitor_idx)
|
||||
.ok_or_else(|| anyhow!("there is no monitor"))?;
|
||||
|
||||
target_monitor.add_container(container, workspace_idx)?;
|
||||
|
||||
if let Some(workspace_idx) = workspace_idx {
|
||||
target_monitor.focus_workspace(workspace_idx)?;
|
||||
}
|
||||
let target_workspace = target_monitor
|
||||
.focused_workspace_mut()
|
||||
.ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?;
|
||||
|
||||
if let Some(window) = floating_window {
|
||||
target_workspace.floating_windows_mut().push(window);
|
||||
Window::from(window.hwnd)
|
||||
.move_to_area(¤t_area, target_monitor.work_area_size())?;
|
||||
} else if let Some(container) = container {
|
||||
let container_hwnds = container
|
||||
.windows()
|
||||
.iter()
|
||||
.map(|w| w.hwnd)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
target_monitor.add_container(container, workspace_idx)?;
|
||||
|
||||
if let Some(workspace) = target_monitor.focused_workspace() {
|
||||
if !*workspace.tile() {
|
||||
for hwnd in container_hwnds {
|
||||
Window::from(hwnd)
|
||||
.move_to_area(¤t_area, target_monitor.work_area_size())?;
|
||||
}
|
||||
if let Some(workspace) = target_monitor.focused_workspace() {
|
||||
if !*workspace.tile() {
|
||||
for hwnd in container_hwnds {
|
||||
Window::from(hwnd).center(target_monitor.work_area_size())?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bail!("failed to find a window to move");
|
||||
}
|
||||
|
||||
target_monitor.load_focused_workspace(mouse_follows_focus)?;
|
||||
|
||||
@@ -30,7 +30,6 @@ use crate::static_config::WorkspaceConfig;
|
||||
use crate::window::Window;
|
||||
use crate::window::WindowDetails;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::WindowContainerBehaviour;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::INITIAL_CONFIGURATION_LOADED;
|
||||
@@ -84,10 +83,6 @@ pub struct Workspace {
|
||||
tile: bool,
|
||||
#[getset(get_copy = "pub", set = "pub")]
|
||||
apply_window_based_work_area_offset: bool,
|
||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||
window_container_behaviour: Option<WindowContainerBehaviour>,
|
||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||
float_override: Option<bool>,
|
||||
}
|
||||
|
||||
impl_ring_elements!(Workspace, Container);
|
||||
@@ -111,8 +106,6 @@ impl Default for Workspace {
|
||||
resize_dimensions: vec![],
|
||||
tile: true,
|
||||
apply_window_based_work_area_offset: true,
|
||||
window_container_behaviour: None,
|
||||
float_override: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,14 +162,6 @@ impl Workspace {
|
||||
config.apply_window_based_work_area_offset.unwrap_or(true),
|
||||
);
|
||||
|
||||
if config.window_container_behaviour.is_some() {
|
||||
self.set_window_container_behaviour(config.window_container_behaviour);
|
||||
}
|
||||
|
||||
if config.float_override.is_some() {
|
||||
self.set_float_override(config.float_override);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -232,6 +217,10 @@ impl Workspace {
|
||||
container.restore();
|
||||
}
|
||||
|
||||
for container in self.containers_mut() {
|
||||
container.restore();
|
||||
}
|
||||
|
||||
if let Some(container) = self.focused_container_mut() {
|
||||
container.focus_window(container.focused_window_idx());
|
||||
}
|
||||
@@ -597,13 +586,6 @@ impl Workspace {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.containers().is_empty()
|
||||
&& self.maximized_window().is_none()
|
||||
&& self.monocle_container().is_none()
|
||||
&& self.floating_windows().is_empty()
|
||||
}
|
||||
|
||||
pub fn contains_window(&self, hwnd: isize) -> bool {
|
||||
for container in self.containers() {
|
||||
if container.contains_window(hwnd) {
|
||||
|
||||
@@ -1167,16 +1167,6 @@ enum SubCommand {
|
||||
WorkspaceName(WorkspaceName),
|
||||
/// Toggle the behaviour for new windows (stacking or dynamic tiling)
|
||||
ToggleWindowContainerBehaviour,
|
||||
/// Enable or disable float override, which makes it so every new window opens in floating mode
|
||||
ToggleFloatOverride,
|
||||
/// Toggle the behaviour for new windows (stacking or dynamic tiling) for currently focused
|
||||
/// workspace. If there was no behaviour set for the workspace previously it takes the opposite
|
||||
/// of the global value.
|
||||
ToggleWorkspaceWindowContainerBehaviour,
|
||||
/// Enable or disable float override, which makes it so every new window opens in floating
|
||||
/// mode, for the currently focused workspace. If there was no override value set for the
|
||||
/// workspace previously it takes the opposite of the global value.
|
||||
ToggleWorkspaceFloatOverride,
|
||||
/// Toggle window tiling on the focused workspace
|
||||
TogglePause,
|
||||
/// Toggle window tiling on the focused workspace
|
||||
@@ -1528,15 +1518,26 @@ fn main() -> Result<()> {
|
||||
|
||||
println!("Found komorebi.json; this file can be passed to the start command with the --config flag\n");
|
||||
|
||||
if let Ok(config) = StaticConfig::read(&static_config) {
|
||||
match config.app_specific_configuration_path {
|
||||
None => {
|
||||
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
|
||||
if let Ok(config) = &parsed_config {
|
||||
if let Some(asc_path) = config.get("app_specific_configuration_path") {
|
||||
let mut normalized_asc_path = asc_path
|
||||
.to_string()
|
||||
.replace(
|
||||
"$Env:USERPROFILE",
|
||||
&dirs::home_dir().unwrap().to_string_lossy(),
|
||||
)
|
||||
.replace('"', "")
|
||||
.replace('\\', "/");
|
||||
|
||||
if let Ok(komorebi_config_home) = std::env::var("KOMOREBI_CONFIG_HOME") {
|
||||
normalized_asc_path = normalized_asc_path
|
||||
.replace("$Env:KOMOREBI_CONFIG_HOME", &komorebi_config_home)
|
||||
.replace('"', "")
|
||||
.replace('\\', "/");
|
||||
}
|
||||
Some(path) => {
|
||||
if !Path::exists(Path::new(&path)) {
|
||||
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
|
||||
}
|
||||
|
||||
if !Path::exists(Path::new(&normalized_asc_path)) {
|
||||
println!("Application specific configuration file path '{normalized_asc_path}' does not exist. Try running 'komorebic fetch-asc'\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2025,50 +2026,19 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue))
|
||||
}
|
||||
}
|
||||
|
||||
let static_config = arg.config.clone().map_or_else(
|
||||
|| {
|
||||
let komorebi_json = HOME_DIR.join("komorebi.json");
|
||||
if komorebi_json.is_file() {
|
||||
Option::from(komorebi_json)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Option::from,
|
||||
);
|
||||
|
||||
if arg.bar {
|
||||
if let Some(config) = &static_config {
|
||||
let mut config = StaticConfig::read(config)?;
|
||||
if let Some(display_bar_configurations) = &mut config.bar_configurations {
|
||||
for config_file_path in &mut *display_bar_configurations {
|
||||
let script = r"Start-Process 'komorebi-bar' '--config CONFIGFILE' -WindowStyle hidden"
|
||||
.replace("CONFIGFILE", &config_file_path.to_string_lossy());
|
||||
|
||||
match powershell_script::run(&script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
}
|
||||
Err(error) => {
|
||||
println!("Error: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let script = r"
|
||||
let script = r"
|
||||
if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
|
||||
{
|
||||
Start-Process komorebi-bar -WindowStyle hidden
|
||||
}
|
||||
";
|
||||
match powershell_script::run(script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
}
|
||||
Err(error) => {
|
||||
println!("Error: {error}");
|
||||
}
|
||||
}
|
||||
match powershell_script::run(script) {
|
||||
Ok(_) => {
|
||||
println!("{script}");
|
||||
}
|
||||
Err(error) => {
|
||||
println!("Error: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2081,11 +2051,11 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
|
||||
println!("* Join the Discord https://discord.gg/mGkn66PHkx - Chat, ask questions, share your desktops");
|
||||
println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands");
|
||||
|
||||
let bar_config = arg.config.map_or_else(
|
||||
let static_config = arg.config.map_or_else(
|
||||
|| {
|
||||
let bar_json = HOME_DIR.join("komorebi.bar.json");
|
||||
if bar_json.is_file() {
|
||||
Option::from(bar_json)
|
||||
let komorebi_json = HOME_DIR.join("komorebi.json");
|
||||
if komorebi_json.is_file() {
|
||||
Option::from(komorebi_json)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -2093,18 +2063,12 @@ if (!(Get-Process komorebi-bar -ErrorAction SilentlyContinue))
|
||||
Option::from,
|
||||
);
|
||||
|
||||
if let Some(config) = &static_config {
|
||||
if let Some(config) = static_config {
|
||||
let path = resolve_home_path(config)?;
|
||||
let raw = std::fs::read_to_string(path)?;
|
||||
StaticConfig::aliases(&raw);
|
||||
StaticConfig::deprecated(&raw);
|
||||
}
|
||||
|
||||
if bar_config.is_some() {
|
||||
let output = Command::new("komorebi-bar.exe").arg("--aliases").output()?;
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
println!("{stdout}");
|
||||
}
|
||||
}
|
||||
SubCommand::Stop(arg) => {
|
||||
if arg.whkd {
|
||||
@@ -2480,15 +2444,6 @@ Stop-Process -Name:komorebi -ErrorAction SilentlyContinue
|
||||
SubCommand::ToggleWindowContainerBehaviour => {
|
||||
send_message(&SocketMessage::ToggleWindowContainerBehaviour)?;
|
||||
}
|
||||
SubCommand::ToggleFloatOverride => {
|
||||
send_message(&SocketMessage::ToggleFloatOverride)?;
|
||||
}
|
||||
SubCommand::ToggleWorkspaceWindowContainerBehaviour => {
|
||||
send_message(&SocketMessage::ToggleWorkspaceWindowContainerBehaviour)?;
|
||||
}
|
||||
SubCommand::ToggleWorkspaceFloatOverride => {
|
||||
send_message(&SocketMessage::ToggleWorkspaceFloatOverride)?;
|
||||
}
|
||||
SubCommand::WindowHidingBehaviour(arg) => {
|
||||
send_message(&SocketMessage::WindowHidingBehaviour(arg.hiding_behaviour))?;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"$ref": "#/definitions/IdWithIdentifier"
|
||||
},
|
||||
"ignore_identifiers": {
|
||||
"float_identifiers": {
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
@@ -25,6 +22,9 @@
|
||||
"$ref": "#/definitions/MatchingRule"
|
||||
}
|
||||
},
|
||||
"identifier": {
|
||||
"$ref": "#/definitions/IdWithIdentifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
608
schema.bar.json
608
schema.bar.json
@@ -73,99 +73,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Battery 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": [
|
||||
"Cpu"
|
||||
],
|
||||
"properties": {
|
||||
"Cpu": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"data_refresh_interval": {
|
||||
"description": "Data refresh interval (default: 10 seconds)",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Cpu 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,39 +141,6 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,39 +276,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Memory 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,39 +306,6 @@
|
||||
"description": "Enable the Network 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"network_activity_fill_characters": {
|
||||
"description": "Characters to reserve for network activity data",
|
||||
"type": "integer",
|
||||
@@ -538,39 +346,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Storage 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -625,39 +400,6 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -719,52 +461,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"position": {
|
||||
"description": "Bar positioning options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"end": {
|
||||
"description": "The desired size of the bar from the starting position (usually monitor width x desired height)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"x",
|
||||
"y"
|
||||
],
|
||||
"properties": {
|
||||
"x": {
|
||||
"description": "X coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"y": {
|
||||
"description": "Y coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
}
|
||||
}
|
||||
},
|
||||
"start": {
|
||||
"description": "The desired starting position of the bar (0,0 = top left of the screen)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"x",
|
||||
"y"
|
||||
],
|
||||
"properties": {
|
||||
"x": {
|
||||
"description": "X coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"y": {
|
||||
"description": "Y coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_widgets": {
|
||||
"description": "Right side widgets (ordered left-to-right)",
|
||||
"type": "array",
|
||||
@@ -791,99 +487,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Battery 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": [
|
||||
"Cpu"
|
||||
],
|
||||
"properties": {
|
||||
"Cpu": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"data_refresh_interval": {
|
||||
"description": "Data refresh interval (default: 10 seconds)",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Cpu 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -952,39 +555,6 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1120,39 +690,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Memory 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1183,39 +720,6 @@
|
||||
"description": "Enable the Network 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"network_activity_fill_characters": {
|
||||
"description": "Characters to reserve for network activity data",
|
||||
"type": "integer",
|
||||
@@ -1256,39 +760,6 @@
|
||||
"enable": {
|
||||
"description": "Enable the Storage 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1343,39 +814,6 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1756,6 +1194,52 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"viewport": {
|
||||
"description": "Viewport options (see: https://docs.rs/egui/latest/egui/viewport/struct.ViewportBuilder.html)",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"inner_size": {
|
||||
"description": "The desired size of the bar from the starting position (usually monitor width x desired height)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"x",
|
||||
"y"
|
||||
],
|
||||
"properties": {
|
||||
"x": {
|
||||
"description": "X coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"y": {
|
||||
"description": "Y coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
}
|
||||
}
|
||||
},
|
||||
"position": {
|
||||
"description": "The desired starting position of the bar (0,0 = top left of the screen)",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"x",
|
||||
"y"
|
||||
],
|
||||
"properties": {
|
||||
"x": {
|
||||
"description": "X coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
},
|
||||
"y": {
|
||||
"description": "Y coordinate",
|
||||
"type": "number",
|
||||
"format": "float"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
517
schema.json
517
schema.json
@@ -69,13 +69,6 @@
|
||||
"description": "Path to applications.yaml from komorebi-application-specific-configurations (default: None)",
|
||||
"type": "string"
|
||||
},
|
||||
"bar_configurations": {
|
||||
"description": "Komorebi status bar configuration files for multiple instances on different monitors",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"border": {
|
||||
"description": "Display an active window border (default: false)",
|
||||
"type": "boolean"
|
||||
@@ -84,45 +77,6 @@
|
||||
"description": "Active window border colours for different container types",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"floating": {
|
||||
"description": "Border colour when the container is in floating mode",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Colour represented as RGB",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"b",
|
||||
"g",
|
||||
"r"
|
||||
],
|
||||
"properties": {
|
||||
"b": {
|
||||
"description": "Blue",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"g": {
|
||||
"description": "Green",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"r": {
|
||||
"description": "Red",
|
||||
"type": "integer",
|
||||
"format": "uint32",
|
||||
"minimum": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Colour represented as Hex",
|
||||
"type": "string",
|
||||
"format": "color-hex"
|
||||
}
|
||||
]
|
||||
},
|
||||
"monocle": {
|
||||
"description": "Border colour when the container is in monocle mode",
|
||||
"anyOf": [
|
||||
@@ -491,12 +445,8 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"float_override": {
|
||||
"description": "Enable or disable float override, which makes it so every new window opens in floating mode (default: false)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"floating_applications": {
|
||||
"description": "Identify applications which should be managed as floating windows",
|
||||
"float_rules": {
|
||||
"description": "Individual window floating rules",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
@@ -629,89 +579,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ignore_rules": {
|
||||
"description": "Individual window floating rules",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"invisible_borders": {
|
||||
"description": "DEPRECATED from v0.1.22: no longer required",
|
||||
"type": "object",
|
||||
@@ -1062,91 +929,44 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"float_override": {
|
||||
"description": "Enable or disable float override, which makes it so every new window opens in floating mode (default: false)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"initial_workspace_rules": {
|
||||
"description": "Initial workspace application rules",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
@@ -1184,25 +1004,6 @@
|
||||
"description": "Name",
|
||||
"type": "string"
|
||||
},
|
||||
"window_container_behaviour": {
|
||||
"description": "Determine what happens when a new window is opened (default: Create)",
|
||||
"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",
|
||||
@@ -1212,83 +1013,40 @@
|
||||
"description": "Permanent workspace application rules",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1389,95 +1147,6 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"slow_application_compensation_time": {
|
||||
"description": "How long to wait when compensating for slow applications, in milliseconds (default: 20)",
|
||||
"type": "integer",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"slow_application_identifiers": {
|
||||
"description": "Identify applications which are slow to send initial event notifications",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exe",
|
||||
"Class",
|
||||
"Title",
|
||||
"Path"
|
||||
]
|
||||
},
|
||||
"matching_strategy": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Legacy",
|
||||
"Equals",
|
||||
"StartsWith",
|
||||
"EndsWith",
|
||||
"Contains",
|
||||
"Regex",
|
||||
"DoesNotEndWith",
|
||||
"DoesNotStartWith",
|
||||
"DoesNotEqual",
|
||||
"DoesNotContain"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"stackbar": {
|
||||
"description": "Stackbar configuration options",
|
||||
"type": "object",
|
||||
@@ -1686,38 +1355,6 @@
|
||||
"Crust"
|
||||
]
|
||||
},
|
||||
"floating_border": {
|
||||
"description": "Border colour when the window is floating (default: Yellow)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Rosewater",
|
||||
"Flamingo",
|
||||
"Pink",
|
||||
"Mauve",
|
||||
"Red",
|
||||
"Maroon",
|
||||
"Peach",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Teal",
|
||||
"Sky",
|
||||
"Sapphire",
|
||||
"Blue",
|
||||
"Lavender",
|
||||
"Text",
|
||||
"Subtext1",
|
||||
"Subtext0",
|
||||
"Overlay2",
|
||||
"Overlay1",
|
||||
"Overlay0",
|
||||
"Surface2",
|
||||
"Surface1",
|
||||
"Surface0",
|
||||
"Base",
|
||||
"Mantle",
|
||||
"Crust"
|
||||
]
|
||||
},
|
||||
"monocle_border": {
|
||||
"description": "Border colour when the container is in monocle mode (default: Pink)",
|
||||
"type": "string",
|
||||
@@ -1990,28 +1627,6 @@
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"floating_border": {
|
||||
"description": "Border colour when the window is floating (default: Base09)",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"monocle_border": {
|
||||
"description": "Border colour when the container is in monocle mode (default: Base0F)",
|
||||
"type": "string",
|
||||
|
||||
Reference in New Issue
Block a user