mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-02-11 07:47:39 +01:00
Compare commits
8 Commits
feature/sp
...
feature/cu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4968b0fe37 | ||
|
|
b4b400b236 | ||
|
|
2ee0bbc0c7 | ||
|
|
d38d3c956d | ||
|
|
052eb1c763 | ||
|
|
58730b81b4 | ||
|
|
274ae43e8f | ||
|
|
2a30f09bbd |
815
Cargo.lock
generated
815
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,8 @@ feature-depth = 1
|
||||
[advisories]
|
||||
ignore = [
|
||||
{ id = "RUSTSEC-2020-0016", reason = "local tcp connectivity is an opt-in feature, and there is no upgrade path for TcpStreamExt" },
|
||||
{ id = "RUSTSEC-2024-0436", reason = "paste being unmaintained is not an issue in our use" }
|
||||
{ id = "RUSTSEC-2024-0436", reason = "paste being unmaintained is not an issue in our use" },
|
||||
{ id = "RUSTSEC-2024-0320", reason = "not using any yaml features from this library" }
|
||||
]
|
||||
|
||||
[licenses]
|
||||
@@ -93,4 +94,6 @@ allow-git = [
|
||||
"https://github.com/LGUG2Z/catppuccin-egui",
|
||||
"https://github.com/LGUG2Z/windows-icons",
|
||||
"https://github.com/LGUG2Z/win32-display-data",
|
||||
"https://github.com/LGUG2Z/flavours",
|
||||
"https://github.com/LGUG2Z/base16_color_scheme",
|
||||
]
|
||||
|
||||
@@ -49,6 +49,7 @@ use komorebi_client::NotificationEvent;
|
||||
use komorebi_client::SocketMessage;
|
||||
use komorebi_themes::catppuccin_egui;
|
||||
use komorebi_themes::Base16Value;
|
||||
use komorebi_themes::Base16Wrapper;
|
||||
use komorebi_themes::Catppuccin;
|
||||
use komorebi_themes::CatppuccinValue;
|
||||
use std::cell::RefCell;
|
||||
@@ -155,7 +156,7 @@ pub fn apply_theme(
|
||||
} => {
|
||||
ctx.set_style(base16.style());
|
||||
let base16_value = base16_value.unwrap_or_default();
|
||||
let accent = base16_value.color32(base16);
|
||||
let accent = base16_value.color32(Base16Wrapper::Base16(base16));
|
||||
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.selection.stroke.color = accent;
|
||||
@@ -165,6 +166,23 @@ pub fn apply_theme(
|
||||
|
||||
bg_color.replace(base16.background());
|
||||
}
|
||||
KomobarTheme::Custom {
|
||||
colours,
|
||||
accent: base16_value,
|
||||
} => {
|
||||
let background = colours.background();
|
||||
ctx.set_style(colours.style());
|
||||
let base16_value = base16_value.unwrap_or_default();
|
||||
let accent = base16_value.color32(Base16Wrapper::Custom(colours));
|
||||
|
||||
ctx.style_mut(|style| {
|
||||
style.visuals.selection.stroke.color = accent;
|
||||
style.visuals.widgets.hovered.fg_stroke.color = accent;
|
||||
style.visuals.widgets.active.fg_stroke.color = accent;
|
||||
});
|
||||
|
||||
bg_color.replace(background);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply transparency_alpha
|
||||
@@ -431,11 +449,11 @@ impl Komobar {
|
||||
}
|
||||
|
||||
fn try_apply_theme(&mut self, ctx: &Context) {
|
||||
match self.config.theme {
|
||||
match &self.config.theme {
|
||||
Some(theme) => {
|
||||
apply_theme(
|
||||
ctx,
|
||||
theme,
|
||||
theme.clone(),
|
||||
self.bg_color.clone(),
|
||||
self.bg_color_with_alpha.clone(),
|
||||
self.config.transparency_alpha,
|
||||
@@ -463,6 +481,26 @@ impl Komobar {
|
||||
match komorebi_client::StaticConfig::read(&config) {
|
||||
Ok(config) => {
|
||||
if let Some(theme) = config.theme {
|
||||
let stack_accent = match theme {
|
||||
KomorebiTheme::Catppuccin {
|
||||
name, stack_border, ..
|
||||
} => stack_border
|
||||
.unwrap_or(CatppuccinValue::Green)
|
||||
.color32(name.as_theme()),
|
||||
KomorebiTheme::Base16 {
|
||||
name, stack_border, ..
|
||||
} => stack_border
|
||||
.unwrap_or(Base16Value::Base0B)
|
||||
.color32(Base16Wrapper::Base16(name)),
|
||||
KomorebiTheme::Custom {
|
||||
ref colours,
|
||||
stack_border,
|
||||
..
|
||||
} => stack_border
|
||||
.unwrap_or(Base16Value::Base0B)
|
||||
.color32(Base16Wrapper::Custom(colours.clone())),
|
||||
};
|
||||
|
||||
apply_theme(
|
||||
ctx,
|
||||
KomobarTheme::from(theme),
|
||||
@@ -473,17 +511,6 @@ impl Komobar {
|
||||
self.render_config.clone(),
|
||||
);
|
||||
|
||||
let stack_accent = match theme {
|
||||
KomorebiTheme::Catppuccin {
|
||||
name, stack_border, ..
|
||||
} => stack_border
|
||||
.unwrap_or(CatppuccinValue::Green)
|
||||
.color32(name.as_theme()),
|
||||
KomorebiTheme::Base16 {
|
||||
name, stack_border, ..
|
||||
} => stack_border.unwrap_or(Base16Value::Base0B).color32(name),
|
||||
};
|
||||
|
||||
if let Some(state) = &self.komorebi_notification_state {
|
||||
state.borrow_mut().stack_accent = Some(stack_accent);
|
||||
}
|
||||
@@ -782,7 +809,7 @@ impl eframe::App for Komobar {
|
||||
self.bg_color_with_alpha.clone(),
|
||||
self.config.transparency_alpha,
|
||||
self.config.grouping,
|
||||
self.config.theme,
|
||||
self.config.theme.clone(),
|
||||
self.render_config.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ impl From<Position> for Pos2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[serde(tag = "palette")]
|
||||
pub enum KomobarTheme {
|
||||
@@ -389,6 +389,12 @@ pub enum KomobarTheme {
|
||||
name: komorebi_themes::Base16,
|
||||
accent: Option<komorebi_themes::Base16Value>,
|
||||
},
|
||||
/// A custom Base16 theme
|
||||
Custom {
|
||||
/// Colours of the custom Base16 theme palette
|
||||
colours: Box<komorebi_themes::Base16ColourPalette>,
|
||||
accent: Option<komorebi_themes::Base16Value>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<KomorebiTheme> for KomobarTheme {
|
||||
@@ -406,6 +412,14 @@ impl From<KomorebiTheme> for KomobarTheme {
|
||||
name,
|
||||
accent: bar_accent,
|
||||
},
|
||||
KomorebiTheme::Custom {
|
||||
colours,
|
||||
bar_accent,
|
||||
..
|
||||
} => Self::Custom {
|
||||
colours,
|
||||
accent: bar_accent,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ use crate::widgets::widget::BarWidget;
|
||||
use crate::ICON_CACHE;
|
||||
use crate::MAX_LABEL_WIDTH;
|
||||
use crate::MONITOR_INDEX;
|
||||
use eframe::egui::text::LayoutJob;
|
||||
use eframe::egui::vec2;
|
||||
use eframe::egui::Align;
|
||||
use eframe::egui::Color32;
|
||||
use eframe::egui::ColorImage;
|
||||
use eframe::egui::Context;
|
||||
@@ -24,6 +26,7 @@ use eframe::egui::RichText;
|
||||
use eframe::egui::Sense;
|
||||
use eframe::egui::Stroke;
|
||||
use eframe::egui::StrokeKind;
|
||||
use eframe::egui::TextFormat;
|
||||
use eframe::egui::TextureHandle;
|
||||
use eframe::egui::TextureOptions;
|
||||
use eframe::egui::Ui;
|
||||
@@ -55,8 +58,11 @@ pub struct KomorebiConfig {
|
||||
pub layout: Option<KomorebiLayoutConfig>,
|
||||
/// Configure the Workspace Layer widget
|
||||
pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>,
|
||||
/// Configure the Focused Window widget
|
||||
pub focused_window: Option<KomorebiFocusedWindowConfig>,
|
||||
/// Configure the Focused Container widget
|
||||
#[serde(alias = "focused_window")]
|
||||
pub focused_container: Option<KomorebiFocusedContainerConfig>,
|
||||
/// Configure the Locked Container widget
|
||||
pub locked_container: Option<KomorebiLockedContainerConfig>,
|
||||
/// Configure the Configuration Switcher widget
|
||||
pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>,
|
||||
}
|
||||
@@ -96,15 +102,26 @@ pub struct KomorebiWorkspaceLayerConfig {
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct KomorebiFocusedWindowConfig {
|
||||
/// Enable the Komorebi Focused Window widget
|
||||
pub struct KomorebiFocusedContainerConfig {
|
||||
/// Enable the Komorebi Focused Container widget
|
||||
pub enable: bool,
|
||||
/// DEPRECATED: use 'display' instead (Show the icon of the currently focused window)
|
||||
/// DEPRECATED: use 'display' instead (Show the icon of the currently focused container)
|
||||
pub show_icon: Option<bool>,
|
||||
/// Display format of the currently focused window
|
||||
/// Display format of the currently focused container
|
||||
pub display: Option<DisplayFormat>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct KomorebiLockedContainerConfig {
|
||||
/// Enable the Komorebi Locked Container widget
|
||||
pub enable: bool,
|
||||
/// Display format of the current locked state
|
||||
pub display: Option<DisplayFormat>,
|
||||
/// Show the widget event if the layer is unlocked
|
||||
pub show_when_unlocked: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct KomorebiConfigurationSwitcherConfig {
|
||||
@@ -140,15 +157,19 @@ impl From<&KomorebiConfig> for Komorebi {
|
||||
.unwrap_or_default(),
|
||||
mouse_follows_focus: true,
|
||||
work_area_offset: None,
|
||||
focused_container_information: KomorebiNotificationStateContainerInformation::EMPTY,
|
||||
focused_container_information: (
|
||||
false,
|
||||
KomorebiNotificationStateContainerInformation::EMPTY,
|
||||
),
|
||||
stack_accent: None,
|
||||
monitor_index: MONITOR_INDEX.load(Ordering::SeqCst),
|
||||
monitor_usr_idx_map: HashMap::new(),
|
||||
})),
|
||||
workspaces: value.workspaces,
|
||||
layout: value.layout.clone(),
|
||||
focused_window: value.focused_window,
|
||||
focused_container: value.focused_container,
|
||||
workspace_layer: value.workspace_layer,
|
||||
locked_container: value.locked_container,
|
||||
configuration_switcher,
|
||||
}
|
||||
}
|
||||
@@ -159,8 +180,9 @@ pub struct Komorebi {
|
||||
pub komorebi_notification_state: Rc<RefCell<KomorebiNotificationState>>,
|
||||
pub workspaces: Option<KomorebiWorkspacesConfig>,
|
||||
pub layout: Option<KomorebiLayoutConfig>,
|
||||
pub focused_window: Option<KomorebiFocusedWindowConfig>,
|
||||
pub focused_container: Option<KomorebiFocusedContainerConfig>,
|
||||
pub workspace_layer: Option<KomorebiWorkspaceLayerConfig>,
|
||||
pub locked_container: Option<KomorebiLockedContainerConfig>,
|
||||
pub configuration_switcher: Option<KomorebiConfigurationSwitcherConfig>,
|
||||
}
|
||||
|
||||
@@ -178,9 +200,10 @@ impl BarWidget for Komorebi {
|
||||
let format = workspaces.display.unwrap_or(DisplayFormat::Text.into());
|
||||
|
||||
config.apply_on_widget(false, ui, |ui| {
|
||||
for (i, (ws, containers, _)) in
|
||||
for (i, (ws, containers, _, should_show)) in
|
||||
komorebi_notification_state.workspaces.iter().enumerate()
|
||||
{
|
||||
if *should_show {
|
||||
let is_selected = komorebi_notification_state.selected_workspace.eq(ws);
|
||||
|
||||
if SelectableFrame::new(
|
||||
@@ -302,6 +325,7 @@ impl BarWidget for Komorebi {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -318,7 +342,7 @@ impl BarWidget for Komorebi {
|
||||
.workspaces
|
||||
.iter()
|
||||
.find(|o| komorebi_notification_state.selected_workspace.eq(&o.0))
|
||||
.map(|(_, _, layer)| layer);
|
||||
.map(|(_, _, layer, _)| layer);
|
||||
|
||||
if let Some(layer) = layer {
|
||||
if (layer_config.show_when_tiling.unwrap_or_default()
|
||||
@@ -335,7 +359,7 @@ impl BarWidget for Komorebi {
|
||||
if matches!(layer, WorkspaceLayer::Tiling) {
|
||||
let (response, painter) =
|
||||
ui.allocate_painter(size, Sense::hover());
|
||||
let color = ui.style().visuals.text_color();
|
||||
let color = ctx.style().visuals.selection.stroke.color;
|
||||
let stroke = Stroke::new(1.0, color);
|
||||
let mut rect = response.rect;
|
||||
let corner =
|
||||
@@ -365,7 +389,7 @@ impl BarWidget for Komorebi {
|
||||
} else {
|
||||
let (response, painter) =
|
||||
ui.allocate_painter(size, Sense::hover());
|
||||
let color = ui.style().visuals.text_color();
|
||||
let color = ctx.style().visuals.selection.stroke.color;
|
||||
let stroke = Stroke::new(1.0, color);
|
||||
let mut rect = response.rect;
|
||||
let corner =
|
||||
@@ -502,18 +526,85 @@ impl BarWidget for Komorebi {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(focused_window) = self.focused_window {
|
||||
if focused_window.enable {
|
||||
if let Some(locked_container_config) = self.locked_container {
|
||||
if locked_container_config.enable {
|
||||
let is_locked = komorebi_notification_state.focused_container_information.0;
|
||||
|
||||
if locked_container_config
|
||||
.show_when_unlocked
|
||||
.unwrap_or_default()
|
||||
|| is_locked
|
||||
{
|
||||
let titles = &komorebi_notification_state
|
||||
.focused_container_information
|
||||
.1
|
||||
.titles;
|
||||
|
||||
if !titles.is_empty() {
|
||||
let display_format = locked_container_config
|
||||
.display
|
||||
.unwrap_or(DisplayFormat::Text);
|
||||
|
||||
let mut layout_job = LayoutJob::simple(
|
||||
if display_format != DisplayFormat::Text {
|
||||
if is_locked {
|
||||
egui_phosphor::regular::LOCK_KEY.to_string()
|
||||
} else {
|
||||
egui_phosphor::regular::LOCK_SIMPLE_OPEN.to_string()
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
config.icon_font_id.clone(),
|
||||
ctx.style().visuals.selection.stroke.color,
|
||||
100.0,
|
||||
);
|
||||
|
||||
if display_format != DisplayFormat::Icon {
|
||||
layout_job.append(
|
||||
if is_locked { "Locked" } else { "Unlocked" },
|
||||
10.0,
|
||||
TextFormat {
|
||||
font_id: config.text_font_id.clone(),
|
||||
color: ctx.style().visuals.text_color(),
|
||||
valign: Align::Center,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
config.apply_on_widget(false, ui, |ui| {
|
||||
if SelectableFrame::new(false)
|
||||
.show(ui, |ui| ui.add(Label::new(layout_job).selectable(false)))
|
||||
.clicked()
|
||||
&& komorebi_client::send_batch([
|
||||
SocketMessage::FocusMonitorAtCursor,
|
||||
SocketMessage::ToggleLock,
|
||||
])
|
||||
.is_err()
|
||||
{
|
||||
tracing::error!("could not send ToggleLock");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(focused_container_config) = self.focused_container {
|
||||
if focused_container_config.enable {
|
||||
let titles = &komorebi_notification_state
|
||||
.focused_container_information
|
||||
.1
|
||||
.titles;
|
||||
|
||||
if !titles.is_empty() {
|
||||
config.apply_on_widget(false, ui, |ui| {
|
||||
let icons = &komorebi_notification_state
|
||||
.focused_container_information
|
||||
.focused_container_information.1
|
||||
.icons;
|
||||
let focused_window_idx = komorebi_notification_state
|
||||
.focused_container_information
|
||||
.focused_container_information.1
|
||||
.focused_window_idx;
|
||||
|
||||
let iter = titles.iter().zip(icons.iter());
|
||||
@@ -521,13 +612,13 @@ impl BarWidget for Komorebi {
|
||||
|
||||
for (i, (title, icon)) in iter.enumerate() {
|
||||
let selected = i == focused_window_idx && len != 1;
|
||||
let text_color = if selected { ctx.style().visuals.selection.stroke.color} else { ui.style().visuals.text_color() };
|
||||
let text_color = if selected { ctx.style().visuals.selection.stroke.color } else { ui.style().visuals.text_color() };
|
||||
|
||||
if SelectableFrame::new(selected)
|
||||
.show(ui, |ui| {
|
||||
// handle legacy setting
|
||||
let format = focused_window.display.unwrap_or(
|
||||
if focused_window.show_icon.unwrap_or(false) {
|
||||
let format = focused_container_config.display.unwrap_or(
|
||||
if focused_container_config.show_icon.unwrap_or(false) {
|
||||
DisplayFormat::IconAndText
|
||||
} else {
|
||||
DisplayFormat::Text
|
||||
@@ -627,9 +718,10 @@ pub struct KomorebiNotificationState {
|
||||
String,
|
||||
Vec<(bool, KomorebiNotificationStateContainerInformation)>,
|
||||
WorkspaceLayer,
|
||||
bool,
|
||||
)>,
|
||||
pub selected_workspace: String,
|
||||
pub focused_container_information: KomorebiNotificationStateContainerInformation,
|
||||
pub focused_container_information: (bool, KomorebiNotificationStateContainerInformation),
|
||||
pub layout: KomorebiLayout,
|
||||
pub hide_empty_workspaces: bool,
|
||||
pub mouse_follows_focus: bool,
|
||||
@@ -695,7 +787,7 @@ impl KomorebiNotificationState {
|
||||
SocketMessage::Theme(theme) => {
|
||||
apply_theme(
|
||||
ctx,
|
||||
KomobarTheme::from(theme),
|
||||
KomobarTheme::from(*theme),
|
||||
bg_color,
|
||||
bg_color_with_alpha.clone(),
|
||||
transparency_alpha,
|
||||
@@ -742,42 +834,41 @@ impl KomorebiNotificationState {
|
||||
true
|
||||
};
|
||||
|
||||
if should_show {
|
||||
workspaces.push((
|
||||
ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)),
|
||||
if show_all_icons {
|
||||
let mut containers = vec![];
|
||||
let mut has_monocle = false;
|
||||
workspaces.push((
|
||||
ws.name().to_owned().unwrap_or_else(|| format!("{}", i + 1)),
|
||||
if show_all_icons {
|
||||
let mut containers = vec![];
|
||||
let mut has_monocle = false;
|
||||
|
||||
// add monocle container
|
||||
if let Some(container) = ws.monocle_container() {
|
||||
containers.push((true, container.into()));
|
||||
has_monocle = true;
|
||||
}
|
||||
// add monocle container
|
||||
if let Some(container) = ws.monocle_container() {
|
||||
containers.push((true, container.into()));
|
||||
has_monocle = true;
|
||||
}
|
||||
|
||||
// add all tiled windows
|
||||
for (i, container) in ws.containers().iter().enumerate() {
|
||||
containers.push((
|
||||
!has_monocle && i == ws.focused_container_idx(),
|
||||
container.into(),
|
||||
));
|
||||
}
|
||||
// add all tiled windows
|
||||
for (i, container) in ws.containers().iter().enumerate() {
|
||||
containers.push((
|
||||
!has_monocle && i == ws.focused_container_idx(),
|
||||
container.into(),
|
||||
));
|
||||
}
|
||||
|
||||
// add all floating windows
|
||||
for floating_window in ws.floating_windows() {
|
||||
containers.push((
|
||||
!has_monocle && floating_window.is_focused(),
|
||||
floating_window.into(),
|
||||
));
|
||||
}
|
||||
// add all floating windows
|
||||
for floating_window in ws.floating_windows() {
|
||||
containers.push((
|
||||
!has_monocle && floating_window.is_focused(),
|
||||
floating_window.into(),
|
||||
));
|
||||
}
|
||||
|
||||
containers
|
||||
} else {
|
||||
vec![(true, ws.into())]
|
||||
},
|
||||
ws.layer().to_owned(),
|
||||
));
|
||||
}
|
||||
containers
|
||||
} else {
|
||||
vec![(true, ws.into())]
|
||||
},
|
||||
ws.layer().to_owned(),
|
||||
should_show,
|
||||
));
|
||||
}
|
||||
|
||||
self.workspaces = workspaces;
|
||||
@@ -798,7 +889,12 @@ impl KomorebiNotificationState {
|
||||
};
|
||||
}
|
||||
|
||||
self.focused_container_information = (&monitor.workspaces()[focused_workspace_idx]).into();
|
||||
let focused_workspace = &monitor.workspaces()[focused_workspace_idx];
|
||||
let is_focused = focused_workspace
|
||||
.locked_containers()
|
||||
.contains(&focused_workspace.focused_container_idx());
|
||||
|
||||
self.focused_container_information = (is_focused, focused_workspace.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ impl KomorebiLayout {
|
||||
let layout_frame = SelectableFrame::new(false)
|
||||
.show(ui, |ui| {
|
||||
if let DisplayFormat::Icon | DisplayFormat::IconAndText = format {
|
||||
self.show_icon(false, font_id.clone(), ctx, ui);
|
||||
self.show_icon(true, font_id.clone(), ctx, ui);
|
||||
}
|
||||
|
||||
if let DisplayFormat::Text | DisplayFormat::IconAndText = format {
|
||||
|
||||
@@ -72,7 +72,7 @@ impl WidgetConfig {
|
||||
WidgetConfig::Komorebi(config) => {
|
||||
config.workspaces.as_ref().is_some_and(|w| w.enable)
|
||||
|| config.layout.as_ref().is_some_and(|w| w.enable)
|
||||
|| config.focused_window.as_ref().is_some_and(|w| w.enable)
|
||||
|| config.focused_container.as_ref().is_some_and(|w| w.enable)
|
||||
|| config
|
||||
.configuration_switcher
|
||||
.as_ref()
|
||||
|
||||
@@ -5,8 +5,6 @@ pub use komorebi::animation::prefix::AnimationPrefix;
|
||||
pub use komorebi::animation::PerAnimationPrefixConfig;
|
||||
pub use komorebi::asc::ApplicationSpecificConfiguration;
|
||||
pub use komorebi::border_manager::BorderInfo;
|
||||
pub use komorebi::colour::Colour;
|
||||
pub use komorebi::colour::Rgb;
|
||||
pub use komorebi::config_generation::ApplicationConfiguration;
|
||||
pub use komorebi::config_generation::IdWithIdentifier;
|
||||
pub use komorebi::config_generation::IdWithIdentifierAndComment;
|
||||
@@ -57,6 +55,7 @@ pub use komorebi::AnimationsConfig;
|
||||
pub use komorebi::AppSpecificConfigurationPath;
|
||||
pub use komorebi::AspectRatio;
|
||||
pub use komorebi::BorderColours;
|
||||
pub use komorebi::Colour;
|
||||
pub use komorebi::CrossBoundaryBehaviour;
|
||||
pub use komorebi::GlobalState;
|
||||
pub use komorebi::KomorebiTheme;
|
||||
@@ -64,6 +63,7 @@ pub use komorebi::MonitorConfig;
|
||||
pub use komorebi::Notification;
|
||||
pub use komorebi::NotificationEvent;
|
||||
pub use komorebi::PredefinedAspectRatio;
|
||||
pub use komorebi::Rgb;
|
||||
pub use komorebi::RuleDebug;
|
||||
pub use komorebi::StackbarConfig;
|
||||
pub use komorebi::State;
|
||||
|
||||
@@ -41,7 +41,9 @@ struct BorderColours {
|
||||
single: Color32,
|
||||
stack: Color32,
|
||||
monocle: Color32,
|
||||
floating: Color32,
|
||||
unfocused: Color32,
|
||||
unfocused_locked: Color32,
|
||||
}
|
||||
|
||||
struct BorderConfig {
|
||||
@@ -154,7 +156,9 @@ impl KomorebiGui {
|
||||
single: colour32(global_state.border_colours.single),
|
||||
stack: colour32(global_state.border_colours.stack),
|
||||
monocle: colour32(global_state.border_colours.monocle),
|
||||
floating: colour32(global_state.border_colours.floating),
|
||||
unfocused: colour32(global_state.border_colours.unfocused),
|
||||
unfocused_locked: colour32(global_state.border_colours.unfocused_locked),
|
||||
};
|
||||
|
||||
let border_config = BorderConfig {
|
||||
@@ -377,6 +381,22 @@ impl eframe::App for KomorebiGui {
|
||||
}
|
||||
});
|
||||
|
||||
ui.collapsing("Floating", |ui| {
|
||||
if egui::color_picker::color_picker_color32(
|
||||
ui,
|
||||
&mut self.border_config.border_colours.floating,
|
||||
Alpha::Opaque,
|
||||
) {
|
||||
komorebi_client::send_message(&SocketMessage::BorderColour(
|
||||
WindowKind::Floating,
|
||||
self.border_config.border_colours.floating.r() as u32,
|
||||
self.border_config.border_colours.floating.g() as u32,
|
||||
self.border_config.border_colours.floating.b() as u32,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
ui.collapsing("Unfocused", |ui| {
|
||||
if egui::color_picker::color_picker_color32(
|
||||
ui,
|
||||
@@ -391,6 +411,22 @@ impl eframe::App for KomorebiGui {
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
ui.collapsing("Unfocused Locked", |ui| {
|
||||
if egui::color_picker::color_picker_color32(
|
||||
ui,
|
||||
&mut self.border_config.border_colours.unfocused_locked,
|
||||
Alpha::Opaque,
|
||||
) {
|
||||
komorebi_client::send_message(&SocketMessage::BorderColour(
|
||||
WindowKind::UnfocusedLocked,
|
||||
self.border_config.border_colours.unfocused_locked.r() as u32,
|
||||
self.border_config.border_colours.unfocused_locked.g() as u32,
|
||||
self.border_config.border_colours.unfocused_locked.b() as u32,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,13 @@ base16-egui-themes = { git = "https://github.com/LGUG2Z/base16-egui-themes", rev
|
||||
catppuccin-egui = { git = "https://github.com/LGUG2Z/catppuccin-egui", rev = "bdaff30959512c4f7ee7304117076a48633d777f", default-features = false, features = ["egui31"] }
|
||||
#catppuccin-egui = { version = "5", default-features = false, features = ["egui30"] }
|
||||
eframe = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
serde_variant = "0.1"
|
||||
strum = { workspace = true }
|
||||
hex_color = { version = "3", features = ["serde"] }
|
||||
flavours = { git = "https://github.com/LGUG2Z/flavours", version = "0.7.2" }
|
||||
|
||||
[features]
|
||||
default = ["schemars"]
|
||||
schemars = ["dep:schemars"]
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use hex_color::HexColor;
|
||||
use komorebi_themes::Color32;
|
||||
#[cfg(feature = "schemars")]
|
||||
use schemars::gen::SchemaGenerator;
|
||||
#[cfg(feature = "schemars")]
|
||||
@@ -9,6 +8,7 @@ use schemars::schema::Schema;
|
||||
#[cfg(feature = "schemars")]
|
||||
use schemars::schema::SchemaObject;
|
||||
|
||||
use crate::Color32;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -57,7 +57,7 @@ impl From<Colour> for Color32 {
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Hex(HexColor);
|
||||
pub struct Hex(pub HexColor);
|
||||
|
||||
#[cfg(feature = "schemars")]
|
||||
impl schemars::JsonSchema for Hex {
|
||||
77
komorebi-themes/src/generator.rs
Normal file
77
komorebi-themes/src/generator.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::colour::Colour;
|
||||
use crate::colour::Hex;
|
||||
use crate::Base16ColourPalette;
|
||||
use hex_color::HexColor;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum ThemeVariant {
|
||||
#[default]
|
||||
Dark,
|
||||
Light,
|
||||
}
|
||||
|
||||
impl Display for ThemeVariant {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ThemeVariant::Dark => write!(f, "dark"),
|
||||
ThemeVariant::Light => write!(f, "light"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ThemeVariant> for flavours::operations::generate::Mode {
|
||||
fn from(value: ThemeVariant) -> Self {
|
||||
match value {
|
||||
ThemeVariant::Dark => Self::Dark,
|
||||
ThemeVariant::Light => Self::Light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_base16_palette(
|
||||
image_path: &Path,
|
||||
variant: ThemeVariant,
|
||||
) -> Result<Base16ColourPalette, hex_color::ParseHexColorError> {
|
||||
Base16ColourPalette::try_from(
|
||||
&flavours::operations::generate::generate(image_path, variant.into(), false)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
impl TryFrom<&VecDeque<String>> for Base16ColourPalette {
|
||||
type Error = hex_color::ParseHexColorError;
|
||||
|
||||
fn try_from(value: &VecDeque<String>) -> Result<Self, Self::Error> {
|
||||
let fixed = value.iter().map(|s| format!("#{s}")).collect::<Vec<_>>();
|
||||
if fixed.len() != 16 {
|
||||
return Err(hex_color::ParseHexColorError::Empty);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
base_00: Colour::Hex(Hex(HexColor::parse(&fixed[0])?)),
|
||||
base_01: Colour::Hex(Hex(HexColor::parse(&fixed[1])?)),
|
||||
base_02: Colour::Hex(Hex(HexColor::parse(&fixed[2])?)),
|
||||
base_03: Colour::Hex(Hex(HexColor::parse(&fixed[3])?)),
|
||||
base_04: Colour::Hex(Hex(HexColor::parse(&fixed[4])?)),
|
||||
base_05: Colour::Hex(Hex(HexColor::parse(&fixed[5])?)),
|
||||
base_06: Colour::Hex(Hex(HexColor::parse(&fixed[6])?)),
|
||||
base_07: Colour::Hex(Hex(HexColor::parse(&fixed[7])?)),
|
||||
base_08: Colour::Hex(Hex(HexColor::parse(&fixed[8])?)),
|
||||
base_09: Colour::Hex(Hex(HexColor::parse(&fixed[9])?)),
|
||||
base_0a: Colour::Hex(Hex(HexColor::parse(&fixed[10])?)),
|
||||
base_0b: Colour::Hex(Hex(HexColor::parse(&fixed[11])?)),
|
||||
base_0c: Colour::Hex(Hex(HexColor::parse(&fixed[12])?)),
|
||||
base_0d: Colour::Hex(Hex(HexColor::parse(&fixed[13])?)),
|
||||
base_0e: Colour::Hex(Hex(HexColor::parse(&fixed[14])?)),
|
||||
base_0f: Colour::Hex(Hex(HexColor::parse(&fixed[15])?)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,32 @@
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
pub mod colour;
|
||||
mod generator;
|
||||
|
||||
pub use generator::generate_base16_palette;
|
||||
pub use generator::ThemeVariant;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use strum::Display;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::colour::Colour;
|
||||
pub use base16_egui_themes::Base16;
|
||||
pub use catppuccin_egui;
|
||||
use eframe::egui::style::Selection;
|
||||
use eframe::egui::style::WidgetVisuals;
|
||||
use eframe::egui::style::Widgets;
|
||||
pub use eframe::egui::Color32;
|
||||
use eframe::egui::Shadow;
|
||||
use eframe::egui::Stroke;
|
||||
use eframe::egui::Style;
|
||||
use eframe::egui::Visuals;
|
||||
use serde_variant::to_variant_name;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Theme {
|
||||
/// A theme from catppuccin-egui
|
||||
@@ -25,6 +39,140 @@ pub enum Theme {
|
||||
name: Base16,
|
||||
accent: Option<Base16Value>,
|
||||
},
|
||||
/// A custom base16 palette
|
||||
Custom {
|
||||
palette: Box<Base16ColourPalette>,
|
||||
accent: Option<Base16Value>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||
pub struct Base16ColourPalette {
|
||||
pub base_00: Colour,
|
||||
pub base_01: Colour,
|
||||
pub base_02: Colour,
|
||||
pub base_03: Colour,
|
||||
pub base_04: Colour,
|
||||
pub base_05: Colour,
|
||||
pub base_06: Colour,
|
||||
pub base_07: Colour,
|
||||
pub base_08: Colour,
|
||||
pub base_09: Colour,
|
||||
pub base_0a: Colour,
|
||||
pub base_0b: Colour,
|
||||
pub base_0c: Colour,
|
||||
pub base_0d: Colour,
|
||||
pub base_0e: Colour,
|
||||
pub base_0f: Colour,
|
||||
}
|
||||
|
||||
impl Base16ColourPalette {
|
||||
pub fn background(self) -> Color32 {
|
||||
self.base_01.into()
|
||||
}
|
||||
pub fn style(self) -> Style {
|
||||
let original = Style::default();
|
||||
Style {
|
||||
visuals: Visuals {
|
||||
widgets: Widgets {
|
||||
noninteractive: WidgetVisuals {
|
||||
bg_fill: self.base_01.into(),
|
||||
weak_bg_fill: self.base_01.into(),
|
||||
bg_stroke: Stroke {
|
||||
color: self.base_02.into(),
|
||||
..original.visuals.widgets.noninteractive.bg_stroke
|
||||
},
|
||||
fg_stroke: Stroke {
|
||||
color: self.base_05.into(),
|
||||
..original.visuals.widgets.noninteractive.fg_stroke
|
||||
},
|
||||
..original.visuals.widgets.noninteractive
|
||||
},
|
||||
inactive: WidgetVisuals {
|
||||
bg_fill: self.base_02.into(),
|
||||
weak_bg_fill: self.base_02.into(),
|
||||
bg_stroke: Stroke {
|
||||
color: Color32::from_rgba_premultiplied(0, 0, 0, 0),
|
||||
..original.visuals.widgets.inactive.bg_stroke
|
||||
},
|
||||
fg_stroke: Stroke {
|
||||
color: self.base_05.into(),
|
||||
..original.visuals.widgets.inactive.fg_stroke
|
||||
},
|
||||
..original.visuals.widgets.inactive
|
||||
},
|
||||
hovered: WidgetVisuals {
|
||||
bg_fill: self.base_02.into(),
|
||||
weak_bg_fill: self.base_02.into(),
|
||||
bg_stroke: Stroke {
|
||||
color: self.base_03.into(),
|
||||
..original.visuals.widgets.hovered.bg_stroke
|
||||
},
|
||||
fg_stroke: Stroke {
|
||||
color: self.base_06.into(),
|
||||
..original.visuals.widgets.hovered.fg_stroke
|
||||
},
|
||||
..original.visuals.widgets.hovered
|
||||
},
|
||||
active: WidgetVisuals {
|
||||
bg_fill: self.base_02.into(),
|
||||
weak_bg_fill: self.base_02.into(),
|
||||
bg_stroke: Stroke {
|
||||
color: self.base_03.into(),
|
||||
..original.visuals.widgets.hovered.bg_stroke
|
||||
},
|
||||
fg_stroke: Stroke {
|
||||
color: self.base_06.into(),
|
||||
..original.visuals.widgets.hovered.fg_stroke
|
||||
},
|
||||
..original.visuals.widgets.active
|
||||
},
|
||||
open: WidgetVisuals {
|
||||
bg_fill: self.base_01.into(),
|
||||
weak_bg_fill: self.base_01.into(),
|
||||
bg_stroke: Stroke {
|
||||
color: self.base_02.into(),
|
||||
..original.visuals.widgets.open.bg_stroke
|
||||
},
|
||||
fg_stroke: Stroke {
|
||||
color: self.base_06.into(),
|
||||
..original.visuals.widgets.open.fg_stroke
|
||||
},
|
||||
..original.visuals.widgets.open
|
||||
},
|
||||
},
|
||||
selection: Selection {
|
||||
bg_fill: self.base_02.into(),
|
||||
stroke: Stroke {
|
||||
color: self.base_06.into(),
|
||||
..original.visuals.selection.stroke
|
||||
},
|
||||
},
|
||||
hyperlink_color: self.base_08.into(),
|
||||
faint_bg_color: Color32::from_rgba_premultiplied(0, 0, 0, 0),
|
||||
extreme_bg_color: self.base_00.into(),
|
||||
code_bg_color: self.base_02.into(),
|
||||
warn_fg_color: self.base_0c.into(),
|
||||
error_fg_color: self.base_0b.into(),
|
||||
window_shadow: Shadow {
|
||||
color: Color32::from_rgba_premultiplied(0, 0, 0, 96),
|
||||
..original.visuals.window_shadow
|
||||
},
|
||||
window_fill: self.base_01.into(),
|
||||
window_stroke: Stroke {
|
||||
color: self.base_02.into(),
|
||||
..original.visuals.window_stroke
|
||||
},
|
||||
panel_fill: self.base_01.into(),
|
||||
popup_shadow: Shadow {
|
||||
color: Color32::from_rgba_premultiplied(0, 0, 0, 96),
|
||||
..original.visuals.popup_shadow
|
||||
},
|
||||
..original.visuals
|
||||
},
|
||||
..original
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Theme {
|
||||
@@ -45,6 +193,7 @@ impl Theme {
|
||||
.to_string()
|
||||
})
|
||||
.collect(),
|
||||
Theme::Custom { .. } => vec!["Custom".to_string()],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,25 +219,50 @@ pub enum Base16Value {
|
||||
Base0F,
|
||||
}
|
||||
|
||||
pub enum Base16Wrapper {
|
||||
Base16(Base16),
|
||||
Custom(Box<Base16ColourPalette>),
|
||||
}
|
||||
|
||||
impl Base16Value {
|
||||
pub fn color32(&self, theme: Base16) -> Color32 {
|
||||
match self {
|
||||
Base16Value::Base00 => theme.base00(),
|
||||
Base16Value::Base01 => theme.base01(),
|
||||
Base16Value::Base02 => theme.base02(),
|
||||
Base16Value::Base03 => theme.base03(),
|
||||
Base16Value::Base04 => theme.base04(),
|
||||
Base16Value::Base05 => theme.base05(),
|
||||
Base16Value::Base06 => theme.base06(),
|
||||
Base16Value::Base07 => theme.base07(),
|
||||
Base16Value::Base08 => theme.base08(),
|
||||
Base16Value::Base09 => theme.base09(),
|
||||
Base16Value::Base0A => theme.base0a(),
|
||||
Base16Value::Base0B => theme.base0b(),
|
||||
Base16Value::Base0C => theme.base0c(),
|
||||
Base16Value::Base0D => theme.base0d(),
|
||||
Base16Value::Base0E => theme.base0e(),
|
||||
Base16Value::Base0F => theme.base0f(),
|
||||
pub fn color32(&self, theme: Base16Wrapper) -> Color32 {
|
||||
match theme {
|
||||
Base16Wrapper::Base16(theme) => match self {
|
||||
Base16Value::Base00 => theme.base00(),
|
||||
Base16Value::Base01 => theme.base01(),
|
||||
Base16Value::Base02 => theme.base02(),
|
||||
Base16Value::Base03 => theme.base03(),
|
||||
Base16Value::Base04 => theme.base04(),
|
||||
Base16Value::Base05 => theme.base05(),
|
||||
Base16Value::Base06 => theme.base06(),
|
||||
Base16Value::Base07 => theme.base07(),
|
||||
Base16Value::Base08 => theme.base08(),
|
||||
Base16Value::Base09 => theme.base09(),
|
||||
Base16Value::Base0A => theme.base0a(),
|
||||
Base16Value::Base0B => theme.base0b(),
|
||||
Base16Value::Base0C => theme.base0c(),
|
||||
Base16Value::Base0D => theme.base0d(),
|
||||
Base16Value::Base0E => theme.base0e(),
|
||||
Base16Value::Base0F => theme.base0f(),
|
||||
},
|
||||
Base16Wrapper::Custom(colours) => match self {
|
||||
Base16Value::Base00 => colours.base_00.into(),
|
||||
Base16Value::Base01 => colours.base_01.into(),
|
||||
Base16Value::Base02 => colours.base_02.into(),
|
||||
Base16Value::Base03 => colours.base_03.into(),
|
||||
Base16Value::Base04 => colours.base_04.into(),
|
||||
Base16Value::Base05 => colours.base_05.into(),
|
||||
Base16Value::Base06 => colours.base_06.into(),
|
||||
Base16Value::Base07 => colours.base_07.into(),
|
||||
Base16Value::Base08 => colours.base_08.into(),
|
||||
Base16Value::Base09 => colours.base_09.into(),
|
||||
Base16Value::Base0A => colours.base_0a.into(),
|
||||
Base16Value::Base0B => colours.base_0b.into(),
|
||||
Base16Value::Base0C => colours.base_0c.into(),
|
||||
Base16Value::Base0D => colours.base_0d.into(),
|
||||
Base16Value::Base0E => colours.base_0e.into(),
|
||||
Base16Value::Base0F => colours.base_0f.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ ctrlc = { version = "3", features = ["termination"] }
|
||||
dirs = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
getset = "0.1"
|
||||
hex_color = { version = "3", features = ["serde"] }
|
||||
hotwatch = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
miow = "0.6"
|
||||
|
||||
@@ -7,8 +7,6 @@ use crate::core::WindowKind;
|
||||
use crate::ring::Ring;
|
||||
use crate::windows_api;
|
||||
use crate::workspace::WorkspaceLayer;
|
||||
use crate::Colour;
|
||||
use crate::Rgb;
|
||||
use crate::WindowManager;
|
||||
use crate::WindowsApi;
|
||||
use border::border_hwnds;
|
||||
@@ -17,6 +15,8 @@ use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use crossbeam_utils::atomic::AtomicConsume;
|
||||
use komorebi_themes::colour::Colour;
|
||||
use komorebi_themes::colour::Rgb;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -163,7 +163,7 @@ pub enum SocketMessage {
|
||||
WatchConfiguration(bool),
|
||||
CompleteConfiguration,
|
||||
AltFocusHack(bool),
|
||||
Theme(KomorebiTheme),
|
||||
Theme(Box<KomorebiTheme>),
|
||||
Animation(bool, Option<AnimationPrefix>),
|
||||
AnimationDuration(u64, Option<AnimationPrefix>),
|
||||
AnimationFps(u64),
|
||||
@@ -329,6 +329,7 @@ pub enum StateQuery {
|
||||
FocusedContainerIndex,
|
||||
FocusedWindowIndex,
|
||||
FocusedWorkspaceName,
|
||||
Version,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
|
||||
@@ -5,7 +5,6 @@ pub mod border_manager;
|
||||
pub mod com;
|
||||
#[macro_use]
|
||||
pub mod ring;
|
||||
pub mod colour;
|
||||
pub mod container;
|
||||
pub mod core;
|
||||
pub mod focus_manager;
|
||||
@@ -47,8 +46,8 @@ use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use colour::*;
|
||||
pub use core::*;
|
||||
pub use komorebi_themes::colour::*;
|
||||
pub use process_command::*;
|
||||
pub use process_event::*;
|
||||
pub use static_config::*;
|
||||
@@ -239,6 +238,8 @@ pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub static SLOW_APPLICATION_COMPENSATION_TIME: AtomicU64 = AtomicU64::new(20);
|
||||
|
||||
shadow_rs::shadow!(build);
|
||||
|
||||
#[must_use]
|
||||
pub fn current_virtual_desktop() -> Option<Vec<u8>> {
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
|
||||
@@ -56,8 +56,6 @@ use komorebi::HOME_DIR;
|
||||
use komorebi::INITIAL_CONFIGURATION_LOADED;
|
||||
use komorebi::SESSION_ID;
|
||||
|
||||
shadow_rs::shadow!(build);
|
||||
|
||||
fn setup(log_level: LogLevel) -> Result<(WorkerGuard, WorkerGuard)> {
|
||||
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
|
||||
std::env::set_var("RUST_LIB_BACKTRACE", "1");
|
||||
@@ -165,7 +163,7 @@ enum LogLevel {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, about, version = build::CLAP_LONG_VERSION)]
|
||||
#[clap(author, about, version = komorebi::build::CLAP_LONG_VERSION)]
|
||||
struct Opts {
|
||||
/// Allow the use of komorebi's custom focus-follows-mouse implementation
|
||||
#[clap(short, long = "ffm")]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::OptionExt;
|
||||
use color_eyre::Result;
|
||||
use komorebi_themes::colour::Rgb;
|
||||
use miow::pipe::connect;
|
||||
use net2::TcpStreamExt;
|
||||
use parking_lot::Mutex;
|
||||
@@ -19,9 +20,18 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
use crate::animation::ANIMATION_DURATION_GLOBAL;
|
||||
use crate::animation::ANIMATION_DURATION_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
use crate::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
||||
use crate::animation::ANIMATION_FPS;
|
||||
use crate::animation::ANIMATION_STYLE_GLOBAL;
|
||||
use crate::animation::ANIMATION_STYLE_PER_ANIMATION;
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::IMPLEMENTATION;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::build;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::core::config_generation::IdWithIdentifier;
|
||||
use crate::core::config_generation::MatchingRule;
|
||||
use crate::core::config_generation::MatchingStrategy;
|
||||
@@ -38,16 +48,6 @@ use crate::core::SocketMessage;
|
||||
use crate::core::StateQuery;
|
||||
use crate::core::WindowContainerBehaviour;
|
||||
use crate::core::WindowKind;
|
||||
|
||||
use crate::animation::ANIMATION_DURATION_GLOBAL;
|
||||
use crate::animation::ANIMATION_ENABLED_GLOBAL;
|
||||
use crate::animation::ANIMATION_FPS;
|
||||
use crate::animation::ANIMATION_STYLE_GLOBAL;
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::IMPLEMENTATION;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::colour::Rgb;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::current_virtual_desktop;
|
||||
use crate::monitor::MonitorInformation;
|
||||
use crate::notify_subscribers;
|
||||
@@ -1377,6 +1377,7 @@ impl WindowManager {
|
||||
.focused_workspace_name()
|
||||
.unwrap_or_else(|| focused_monitor.focused_workspace_idx().to_string())
|
||||
}
|
||||
StateQuery::Version => build::RUST_VERSION.to_string(),
|
||||
};
|
||||
|
||||
reply.write_all(response.as_bytes())?;
|
||||
@@ -2091,8 +2092,8 @@ impl WindowManager {
|
||||
|
||||
reply.write_all(schema.as_bytes())?;
|
||||
}
|
||||
SocketMessage::Theme(theme) => {
|
||||
theme_manager::send_notification(theme);
|
||||
SocketMessage::Theme(ref theme) => {
|
||||
theme_manager::send_notification(*theme.clone());
|
||||
}
|
||||
// Deprecated commands
|
||||
SocketMessage::AltFocusHack(_)
|
||||
|
||||
@@ -296,8 +296,8 @@ impl WindowManager {
|
||||
tracing::info!("ignoring uncloak after monocle move by mouse across monitors");
|
||||
self.uncloack_to_ignore = self.uncloack_to_ignore.saturating_sub(1);
|
||||
} else {
|
||||
let mut focused_monitor_idx = self.focused_monitor_idx();
|
||||
let mut focused_workspace_idx =
|
||||
let focused_monitor_idx = self.focused_monitor_idx();
|
||||
let focused_workspace_idx =
|
||||
self.focused_workspace_idx_for_monitor_idx(focused_monitor_idx)?;
|
||||
|
||||
let mut needs_reconciliation = None;
|
||||
@@ -346,18 +346,6 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
if proceed {
|
||||
if matches!(event, WindowManagerEvent::Show(_, _)) {
|
||||
let initial_monitor_idx = initial_state.monitors.focused_idx();
|
||||
if focused_monitor_idx != initial_monitor_idx {
|
||||
tracing::info!("assuming focused monitor index should be {initial_monitor_idx} for WindowManagerEvent::Show");
|
||||
self.focus_monitor(initial_monitor_idx)?;
|
||||
}
|
||||
|
||||
focused_monitor_idx = self.focused_monitor_idx();
|
||||
focused_workspace_idx =
|
||||
self.focused_workspace_idx_for_monitor_idx(focused_monitor_idx)?;
|
||||
}
|
||||
|
||||
let mut behaviour = self.window_management_behaviour(
|
||||
focused_monitor_idx,
|
||||
focused_workspace_idx,
|
||||
|
||||
@@ -13,7 +13,6 @@ use crate::border_manager;
|
||||
use crate::border_manager::ZOrder;
|
||||
use crate::border_manager::IMPLEMENTATION;
|
||||
use crate::border_manager::STYLE;
|
||||
use crate::colour::Colour;
|
||||
use crate::config_generation::WorkspaceMatchingRule;
|
||||
use crate::core::config_generation::ApplicationConfiguration;
|
||||
use crate::core::config_generation::ApplicationConfigurationGenerator;
|
||||
@@ -87,6 +86,7 @@ use color_eyre::Result;
|
||||
use crossbeam_channel::Receiver;
|
||||
use hotwatch::EventKind;
|
||||
use hotwatch::Hotwatch;
|
||||
use komorebi_themes::colour::Colour;
|
||||
use parking_lot::Mutex;
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
@@ -119,6 +119,60 @@ pub struct BorderColours {
|
||||
/// Border colour when the container is unfocused
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused: Option<Colour>,
|
||||
/// Border colour when the container is unfocused and locked
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused_locked: Option<Colour>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct ThemeOptions {
|
||||
/// Specify Light or Dark variant for theme generation (default: Dark)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub theme_variant: Option<komorebi_themes::ThemeVariant>,
|
||||
/// Border colour when the container contains a single window (default: Base0D)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub single_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container contains multiple windows (default: Base0B)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stack_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is in monocle mode (default: Base0F)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub monocle_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the window is floating (default: Base09)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub floating_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is unfocused (default: Base01)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is unfocused and locked (default: Base08)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unfocused_locked_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar focused tab text colour (default: Base0B)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stackbar_focused_text: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar unfocused tab text colour (default: Base05)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar tab background colour (default: Base01)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub stackbar_background: Option<komorebi_themes::Base16Value>,
|
||||
/// Komorebi status bar accent (default: Base0D)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bar_accent: Option<komorebi_themes::Base16Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Wallpaper {
|
||||
/// Path to the wallpaper image file
|
||||
pub path: PathBuf,
|
||||
/// Generate and apply Base16 theme for this wallpaper (default: true)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub generate_theme: Option<bool>,
|
||||
/// Specify Light or Dark variant for theme generation (default: Dark)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub theme_options: Option<ThemeOptions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
@@ -168,6 +222,9 @@ pub struct WorkspaceConfig {
|
||||
/// Determine what happens to a new window when the Floating workspace layer is active (default: Tile)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub floating_layer_behaviour: Option<FloatingLayerBehaviour>,
|
||||
/// Specify a wallpaper for this workspace
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
}
|
||||
|
||||
impl From<&Workspace> for WorkspaceConfig {
|
||||
@@ -244,6 +301,7 @@ impl From<&Workspace> for WorkspaceConfig {
|
||||
float_override: *value.float_override(),
|
||||
layout_flip: value.layout_flip(),
|
||||
floating_layer_behaviour: Option::from(*value.floating_layer_behaviour()),
|
||||
wallpaper: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,7 +540,7 @@ pub struct AnimationsConfig {
|
||||
pub fps: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[serde(tag = "palette")]
|
||||
pub enum KomorebiTheme {
|
||||
@@ -556,6 +614,41 @@ pub enum KomorebiTheme {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
bar_accent: Option<komorebi_themes::Base16Value>,
|
||||
},
|
||||
/// A custom Base16 theme
|
||||
Custom {
|
||||
/// Colours of the custom Base16 theme palette
|
||||
colours: Box<komorebi_themes::Base16ColourPalette>,
|
||||
/// Border colour when the container contains a single window (default: Base0D)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
single_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container contains multiple windows (default: Base0B)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
stack_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is in monocle mode (default: Base0F)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
monocle_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the window is floating (default: Base09)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
floating_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is unfocused (default: Base01)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
unfocused_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Border colour when the container is unfocused and locked (default: Base08)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
unfocused_locked_border: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar focused tab text colour (default: Base0B)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
stackbar_focused_text: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar unfocused tab text colour (default: Base05)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
stackbar_unfocused_text: Option<komorebi_themes::Base16Value>,
|
||||
/// Stackbar tab background colour (default: Base01)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
stackbar_background: Option<komorebi_themes::Base16Value>,
|
||||
/// Komorebi status bar accent (default: Base0D)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
bar_accent: Option<komorebi_themes::Base16Value>,
|
||||
},
|
||||
}
|
||||
|
||||
impl StaticConfig {
|
||||
@@ -700,6 +793,9 @@ impl From<&WindowManager> for StaticConfig {
|
||||
unfocused: Option::from(Colour::from(
|
||||
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||
)),
|
||||
unfocused_locked: Option::from(Colour::from(
|
||||
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
|
||||
)),
|
||||
})
|
||||
};
|
||||
|
||||
@@ -881,6 +977,11 @@ impl StaticConfig {
|
||||
if let Some(unfocused) = colours.unfocused {
|
||||
border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
if let Some(unfocused_locked) = colours.unfocused_locked {
|
||||
border_manager::UNFOCUSED_LOCKED
|
||||
.store(u32::from(unfocused_locked), Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
STYLE.store(self.border_style.unwrap_or_default());
|
||||
@@ -1021,7 +1122,7 @@ impl StaticConfig {
|
||||
}
|
||||
|
||||
if let Some(theme) = &self.theme {
|
||||
theme_manager::send_notification(*theme);
|
||||
theme_manager::send_notification(theme.clone());
|
||||
}
|
||||
|
||||
if let Some(path) = &self.app_specific_configuration_path {
|
||||
|
||||
@@ -5,11 +5,12 @@ use crate::stackbar_manager;
|
||||
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_TAB_BACKGROUND_COLOUR;
|
||||
use crate::stackbar_manager::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||
use crate::Colour;
|
||||
use crate::KomorebiTheme;
|
||||
use crossbeam_channel::Receiver;
|
||||
use crossbeam_channel::Sender;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use komorebi_themes::colour::Colour;
|
||||
use komorebi_themes::Base16Wrapper;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::OnceLock;
|
||||
@@ -157,39 +158,100 @@ pub fn handle_notifications() -> color_eyre::Result<()> {
|
||||
} => {
|
||||
let single_border = single_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0D)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let stack_border = stack_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0B)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let monocle_border = monocle_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0F)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let unfocused_border = unfocused_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base01)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let unfocused_locked_border = unfocused_locked_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base08)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let floating_border = floating_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base09)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let stackbar_focused_text = stackbar_focused_text
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0B)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let stackbar_unfocused_text = stackbar_unfocused_text
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base05)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
let stackbar_background = stackbar_background
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base01)
|
||||
.color32(*name);
|
||||
.color32(Base16Wrapper::Base16(*name));
|
||||
|
||||
(
|
||||
single_border,
|
||||
stack_border,
|
||||
monocle_border,
|
||||
floating_border,
|
||||
unfocused_border,
|
||||
unfocused_locked_border,
|
||||
stackbar_focused_text,
|
||||
stackbar_unfocused_text,
|
||||
stackbar_background,
|
||||
)
|
||||
}
|
||||
KomorebiTheme::Custom {
|
||||
colours,
|
||||
single_border,
|
||||
stack_border,
|
||||
monocle_border,
|
||||
floating_border,
|
||||
unfocused_border,
|
||||
unfocused_locked_border,
|
||||
stackbar_focused_text,
|
||||
stackbar_unfocused_text,
|
||||
stackbar_background,
|
||||
..
|
||||
} => {
|
||||
let single_border = single_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0D)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let stack_border = stack_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0B)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let monocle_border = monocle_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0F)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let unfocused_border = unfocused_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base01)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let unfocused_locked_border = unfocused_locked_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base08)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let floating_border = floating_border
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base09)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let stackbar_focused_text = stackbar_focused_text
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base0B)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let stackbar_unfocused_text = stackbar_unfocused_text
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base05)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
let stackbar_background = stackbar_background
|
||||
.unwrap_or(komorebi_themes::Base16Value::Base01)
|
||||
.color32(Base16Wrapper::Custom(colours.clone()));
|
||||
|
||||
(
|
||||
single_border,
|
||||
|
||||
@@ -248,6 +248,9 @@ impl Default for GlobalState {
|
||||
unfocused: Option::from(Colour::Rgb(Rgb::from(
|
||||
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||
))),
|
||||
unfocused_locked: Option::from(Colour::Rgb(Rgb::from(
|
||||
border_manager::UNFOCUSED_LOCKED.load(Ordering::SeqCst),
|
||||
))),
|
||||
},
|
||||
border_style: STYLE.load(),
|
||||
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
|
||||
@@ -345,6 +348,7 @@ impl From<&WindowManager> for State {
|
||||
floating_layer_behaviour: workspace.floating_layer_behaviour,
|
||||
globals: workspace.globals,
|
||||
locked_containers: workspace.locked_containers.clone(),
|
||||
wallpaper: workspace.wallpaper.clone(),
|
||||
workspace_config: None,
|
||||
})
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::eyre::Error;
|
||||
use color_eyre::Result;
|
||||
use core::ffi::c_void;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::mem::size_of;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::eyre::bail;
|
||||
use color_eyre::eyre::Error;
|
||||
use color_eyre::Result;
|
||||
use std::path::Path;
|
||||
use windows::core::Result as WindowsCrateResult;
|
||||
use windows::core::PCWSTR;
|
||||
use windows::core::PWSTR;
|
||||
@@ -47,6 +47,8 @@ use windows::Win32::Graphics::Gdi::HMONITOR;
|
||||
use windows::Win32::Graphics::Gdi::MONITORENUMPROC;
|
||||
use windows::Win32::Graphics::Gdi::MONITORINFOEXW;
|
||||
use windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST;
|
||||
use windows::Win32::System::Com::CoCreateInstance;
|
||||
use windows::Win32::System::Com::CLSCTX_ALL;
|
||||
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
|
||||
use windows::Win32::System::Power::RegisterPowerSettingNotification;
|
||||
use windows::Win32::System::Power::HPOWERNOTIFY;
|
||||
@@ -72,6 +74,9 @@ use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTUP;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::VK_LBUTTON;
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::VK_MENU;
|
||||
use windows::Win32::UI::Shell::DesktopWallpaper;
|
||||
use windows::Win32::UI::Shell::IDesktopWallpaper;
|
||||
use windows::Win32::UI::Shell::DWPOS_FILL;
|
||||
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
|
||||
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
|
||||
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
|
||||
@@ -141,6 +146,7 @@ use windows::Win32::UI::WindowsAndMessaging::WS_EX_TOPMOST;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_POPUP;
|
||||
use windows::Win32::UI::WindowsAndMessaging::WS_SYSMENU;
|
||||
use windows_core::BOOL;
|
||||
use windows_core::HSTRING;
|
||||
|
||||
use crate::core::Rect;
|
||||
|
||||
@@ -1345,4 +1351,22 @@ impl WindowsApi {
|
||||
pub fn wts_register_session_notification(hwnd: isize) -> Result<()> {
|
||||
unsafe { WTSRegisterSessionNotification(HWND(as_ptr!(hwnd)), 1) }.process()
|
||||
}
|
||||
|
||||
pub fn set_wallpaper(path: &Path) -> Result<()> {
|
||||
let path = path.canonicalize()?;
|
||||
|
||||
let wallpaper: IDesktopWallpaper =
|
||||
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL)? };
|
||||
|
||||
let wallpaper_path = HSTRING::from(path.to_str().unwrap_or_default());
|
||||
unsafe {
|
||||
wallpaper.SetPosition(DWPOS_FILL)?;
|
||||
}
|
||||
|
||||
// Set the wallpaper
|
||||
unsafe {
|
||||
wallpaper.SetWallpaper(PCWSTR::null(), PCWSTR::from_raw(wallpaper_path.as_ptr()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::VecDeque;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::Formatter;
|
||||
use std::io::Write;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use getset::CopyGetters;
|
||||
use getset::Getters;
|
||||
use getset::MutGetters;
|
||||
use getset::Setters;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::border_manager;
|
||||
use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::container::Container;
|
||||
use crate::core::Axis;
|
||||
use crate::core::CustomLayout;
|
||||
use crate::core::CycleDirection;
|
||||
@@ -22,11 +18,6 @@ use crate::core::DefaultLayout;
|
||||
use crate::core::Layout;
|
||||
use crate::core::OperationDirection;
|
||||
use crate::core::Rect;
|
||||
use crate::FloatingLayerBehaviour;
|
||||
|
||||
use crate::border_manager::BORDER_OFFSET;
|
||||
use crate::border_manager::BORDER_WIDTH;
|
||||
use crate::container::Container;
|
||||
use crate::locked_deque::LockedDeque;
|
||||
use crate::ring::Ring;
|
||||
use crate::should_act;
|
||||
@@ -36,13 +27,28 @@ use crate::static_config::WorkspaceConfig;
|
||||
use crate::window::Window;
|
||||
use crate::window::WindowDetails;
|
||||
use crate::windows_api::WindowsApi;
|
||||
use crate::FloatingLayerBehaviour;
|
||||
use crate::KomorebiTheme;
|
||||
use crate::SocketMessage;
|
||||
use crate::Wallpaper;
|
||||
use crate::WindowContainerBehaviour;
|
||||
use crate::DATA_DIR;
|
||||
use crate::DEFAULT_CONTAINER_PADDING;
|
||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||
use crate::INITIAL_CONFIGURATION_LOADED;
|
||||
use crate::NO_TITLEBAR;
|
||||
use crate::REGEX_IDENTIFIERS;
|
||||
use crate::REMOVE_TITLEBARS;
|
||||
use color_eyre::eyre::anyhow;
|
||||
use color_eyre::Result;
|
||||
use getset::CopyGetters;
|
||||
use getset::Getters;
|
||||
use getset::MutGetters;
|
||||
use getset::Setters;
|
||||
use komorebi_themes::Base16ColourPalette;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use uds_windows::UnixStream;
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
#[derive(
|
||||
@@ -96,6 +102,8 @@ pub struct Workspace {
|
||||
pub floating_layer_behaviour: FloatingLayerBehaviour,
|
||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||
pub locked_containers: BTreeSet<usize>,
|
||||
#[getset(get = "pub", get_mut = "pub", set = "pub")]
|
||||
pub wallpaper: Option<Wallpaper>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[getset(get = "pub", set = "pub")]
|
||||
pub workspace_config: Option<WorkspaceConfig>,
|
||||
@@ -148,6 +156,7 @@ impl Default for Workspace {
|
||||
globals: Default::default(),
|
||||
workspace_config: None,
|
||||
locked_containers: Default::default(),
|
||||
wallpaper: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +264,7 @@ impl Workspace {
|
||||
self.set_float_override(config.float_override);
|
||||
self.set_layout_flip(config.layout_flip);
|
||||
self.set_floating_layer_behaviour(config.floating_layer_behaviour.unwrap_or_default());
|
||||
self.set_wallpaper(config.wallpaper.clone());
|
||||
|
||||
self.set_workspace_config(Some(config.clone()));
|
||||
|
||||
@@ -291,12 +301,129 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_wallpaper(&self) -> Result<()> {
|
||||
if let Some(wallpaper) = &self.wallpaper {
|
||||
if let Err(error) = WindowsApi::set_wallpaper(&wallpaper.path) {
|
||||
tracing::error!("failed to set wallpaper: {error}");
|
||||
}
|
||||
|
||||
// if !cfg!(debug_assertions) && wallpaper.generate_theme.unwrap_or(true) {
|
||||
if wallpaper.generate_theme.unwrap_or(true) {
|
||||
let variant = wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|t| t.theme_variant)
|
||||
.unwrap_or_default();
|
||||
|
||||
let cached_palette = DATA_DIR.join(format!(
|
||||
"{}.base16.{variant}.json",
|
||||
wallpaper
|
||||
.path
|
||||
.file_name()
|
||||
.unwrap_or(OsStr::new("tmp"))
|
||||
.to_string_lossy()
|
||||
));
|
||||
|
||||
let mut base16_palette = None;
|
||||
|
||||
if cached_palette.is_file() {
|
||||
tracing::info!(
|
||||
"colour palette for wallpaper {} found in cache",
|
||||
cached_palette.display()
|
||||
);
|
||||
|
||||
// this code is VERY slow on debug builds - should only be a one-time issue when loading
|
||||
// an uncached wallpaper
|
||||
if let Ok(palette) = serde_json::from_str::<Base16ColourPalette>(
|
||||
&std::fs::read_to_string(&cached_palette)?,
|
||||
) {
|
||||
base16_palette = Some(palette);
|
||||
}
|
||||
};
|
||||
|
||||
if base16_palette.is_none() {
|
||||
base16_palette =
|
||||
komorebi_themes::generate_base16_palette(&wallpaper.path, variant).ok();
|
||||
|
||||
std::fs::write(
|
||||
&cached_palette,
|
||||
serde_json::to_string_pretty(&base16_palette)?,
|
||||
)?;
|
||||
|
||||
tracing::info!(
|
||||
"colour palette for wallpaper {} cached",
|
||||
cached_palette.display()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(palette) = base16_palette {
|
||||
let komorebi_theme = KomorebiTheme::Custom {
|
||||
colours: Box::new(palette),
|
||||
single_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.single_border),
|
||||
stack_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.stack_border),
|
||||
monocle_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.monocle_border),
|
||||
floating_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.floating_border),
|
||||
unfocused_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.unfocused_border),
|
||||
unfocused_locked_border: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.unfocused_locked_border),
|
||||
stackbar_focused_text: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.stackbar_focused_text),
|
||||
stackbar_unfocused_text: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.stackbar_unfocused_text),
|
||||
stackbar_background: wallpaper
|
||||
.theme_options
|
||||
.as_ref()
|
||||
.and_then(|o| o.stackbar_background),
|
||||
bar_accent: wallpaper.theme_options.as_ref().and_then(|o| o.bar_accent),
|
||||
};
|
||||
|
||||
let bytes = SocketMessage::Theme(Box::new(komorebi_theme)).as_bytes()?;
|
||||
|
||||
let socket = DATA_DIR.join("komorebi.sock");
|
||||
match UnixStream::connect(socket) {
|
||||
Ok(mut stream) => {
|
||||
if let Err(error) = stream.write_all(&bytes) {
|
||||
tracing::error!("failed to send theme update message: {error}")
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!("{error}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, mouse_follows_focus: bool) -> Result<()> {
|
||||
if let Some(container) = self.monocle_container() {
|
||||
if let Some(window) = container.focused_window() {
|
||||
container.restore();
|
||||
window.focus(mouse_follows_focus)?;
|
||||
return Ok(());
|
||||
return self.apply_wallpaper();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +467,7 @@ impl Workspace {
|
||||
floating_window.focus(mouse_follows_focus)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
self.apply_wallpaper()
|
||||
}
|
||||
|
||||
pub fn update(&mut self) -> Result<()> {
|
||||
@@ -559,13 +686,13 @@ impl Workspace {
|
||||
|
||||
for window in self.visible_windows().into_iter().flatten() {
|
||||
if !window.is_window()
|
||||
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
|
||||
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
|
||||
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
|
||||
// docs is closed
|
||||
//
|
||||
// I hate every single person who worked on Microsoft Office 365, especially Word
|
||||
|| !window.is_visible()
|
||||
// This one is a hack because WINWORD.EXE is an absolute trainwreck of an app
|
||||
// when multiple docs are open, it keeps open an invisible window, with WS_EX_LAYERED
|
||||
// (A STYLE THAT THE REGULAR WINDOWS NEED IN ORDER TO BE MANAGED!) when one of the
|
||||
// docs is closed
|
||||
//
|
||||
// I hate every single person who worked on Microsoft Office 365, especially Word
|
||||
|| !window.is_visible()
|
||||
{
|
||||
hwnds.push(window.hwnd);
|
||||
}
|
||||
|
||||
870
schema.bar.json
870
schema.bar.json
@@ -365,15 +365,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"focused_window": {
|
||||
"description": "Configure the Focused Window widget",
|
||||
"focused_container": {
|
||||
"description": "Configure the Focused Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the currently focused window",
|
||||
"description": "Display format of the currently focused container",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
@@ -413,11 +413,11 @@
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Focused Window widget",
|
||||
"description": "Enable the Komorebi Focused Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_icon": {
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused window)",
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused container)",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -508,6 +508,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"locked_container": {
|
||||
"description": "Configure the Locked Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the current locked state",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Icon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show only text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and text on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"TextAndIconOnSelected"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show both icon and text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndText"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and icons on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndTextOnSelected"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Locked Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_when_unlocked": {
|
||||
"description": "Show the widget event if the layer is unlocked",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspace_layer": {
|
||||
"description": "Configure the Workspace Layer widget",
|
||||
"type": "object",
|
||||
@@ -1775,15 +1832,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"focused_window": {
|
||||
"description": "Configure the Focused Window widget",
|
||||
"focused_container": {
|
||||
"description": "Configure the Focused Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the currently focused window",
|
||||
"description": "Display format of the currently focused container",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
@@ -1823,11 +1880,11 @@
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Focused Window widget",
|
||||
"description": "Enable the Komorebi Focused Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_icon": {
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused window)",
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused container)",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -1918,6 +1975,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"locked_container": {
|
||||
"description": "Configure the Locked Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the current locked state",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Icon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show only text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and text on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"TextAndIconOnSelected"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show both icon and text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndText"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and icons on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndTextOnSelected"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Locked Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_when_unlocked": {
|
||||
"description": "Show the widget event if the layer is unlocked",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspace_layer": {
|
||||
"description": "Configure the Workspace Layer widget",
|
||||
"type": "object",
|
||||
@@ -3118,15 +3232,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"focused_window": {
|
||||
"description": "Configure the Focused Window widget",
|
||||
"focused_container": {
|
||||
"description": "Configure the Focused Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the currently focused window",
|
||||
"description": "Display format of the currently focused container",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
@@ -3166,11 +3280,11 @@
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Focused Window widget",
|
||||
"description": "Enable the Komorebi Focused Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_icon": {
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused window)",
|
||||
"description": "DEPRECATED: use 'display' instead (Show the icon of the currently focused container)",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
@@ -3261,6 +3375,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"locked_container": {
|
||||
"description": "Configure the Locked Container widget",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"enable"
|
||||
],
|
||||
"properties": {
|
||||
"display": {
|
||||
"description": "Display format of the current locked state",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Show only icon",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Icon"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show only text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and text on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"TextAndIconOnSelected"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show both icon and text",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndText"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Show an icon and text for the selected element, and icons on the rest",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IconAndTextOnSelected"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"enable": {
|
||||
"description": "Enable the Komorebi Locked Container widget",
|
||||
"type": "boolean"
|
||||
},
|
||||
"show_when_unlocked": {
|
||||
"description": "Show the widget event if the layer is unlocked",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspace_layer": {
|
||||
"description": "Configure the Workspace Layer widget",
|
||||
"type": "object",
|
||||
@@ -4193,6 +4364,675 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "A custom Base16 theme",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"colours",
|
||||
"palette"
|
||||
],
|
||||
"properties": {
|
||||
"accent": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Base00",
|
||||
"Base01",
|
||||
"Base02",
|
||||
"Base03",
|
||||
"Base04",
|
||||
"Base05",
|
||||
"Base06",
|
||||
"Base07",
|
||||
"Base08",
|
||||
"Base09",
|
||||
"Base0A",
|
||||
"Base0B",
|
||||
"Base0C",
|
||||
"Base0D",
|
||||
"Base0E",
|
||||
"Base0F"
|
||||
]
|
||||
},
|
||||
"colours": {
|
||||
"description": "Colours of the custom Base16 theme palette",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"base_00",
|
||||
"base_01",
|
||||
"base_02",
|
||||
"base_03",
|
||||
"base_04",
|
||||
"base_05",
|
||||
"base_06",
|
||||
"base_07",
|
||||
"base_08",
|
||||
"base_09",
|
||||
"base_0a",
|
||||
"base_0b",
|
||||
"base_0c",
|
||||
"base_0d",
|
||||
"base_0e",
|
||||
"base_0f"
|
||||
],
|
||||
"properties": {
|
||||
"base_00": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_01": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_02": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_03": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_04": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_05": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_06": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_07": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_08": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_09": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0a": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0b": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0c": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0d": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0e": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"base_0f": {
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"palette": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Custom"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
1158
schema.json
1158
schema.json
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user