#![forbid(unsafe_code)]
#[cfg(feature = "cli")]
pub use conf::CLI_CONFIG_PATH;
pub use {crate::ui::build_window, conf::Config};
use {gtk::CssProvider, gtk4 as gtk};
mod conf;
mod log;
mod ui;
pub fn init_gtk() {
if let Err(err) = gtk::init() {
crate::log::error("gtk", &format!("cannot initialize GTK: {err}"));
std::process::exit(1);
}
}
pub fn load_css() {
let Some(display) = gtk::gdk::Display::default() else {
crate::log::error("gtk", "no default display");
std::process::exit(1);
};
let provider = CssProvider::new();
provider.load_from_string(THEME_CSS);
gtk::style_context_add_provider_for_display(
&display,
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
#[cfg(feature = "config")]
load_custom_css(&display);
}
#[cfg(feature = "config")]
fn load_custom_css(display: >k::gdk::Display) {
let Some(base) = directories::BaseDirs::new() else {
return;
};
let path = base.config_dir().join("tkbar").join("style.css");
let css = match std::fs::read_to_string(&path) {
Ok(css) => css,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return,
Err(err) => {
crate::log::warn("config", &format!("cannot read {}: {err}", path.display()));
return;
},
};
let provider = CssProvider::new();
provider.load_from_string(&css);
gtk::style_context_add_provider_for_display(
display,
&provider,
gtk::STYLE_PROVIDER_PRIORITY_USER,
);
}
#[cfg(feature = "black")]
const THEME_CSS: &str = include_str!("ui/styles/black.css");
#[cfg(feature = "blue")]
const THEME_CSS: &str = include_str!("ui/styles/blue.css");
#[cfg(feature = "cyan")]
const THEME_CSS: &str = include_str!("ui/styles/cyan.css");
#[cfg(feature = "green")]
const THEME_CSS: &str = include_str!("ui/styles/green.css");
#[cfg(feature = "orange")]
const THEME_CSS: &str = include_str!("ui/styles/orange.css");
#[cfg(feature = "pink")]
const THEME_CSS: &str = include_str!("ui/styles/pink.css");
#[cfg(feature = "purple")]
const THEME_CSS: &str = include_str!("ui/styles/purple.css");
#[cfg(feature = "red")]
const THEME_CSS: &str = include_str!("ui/styles/red.css");
#[cfg(feature = "white")]
const THEME_CSS: &str = include_str!("ui/styles/white.css");
#[cfg(feature = "yellow")]
const THEME_CSS: &str = include_str!("ui/styles/yellow.css");
const fn color_feature_count() -> usize {
let mut n = 0;
if cfg!(feature = "black") {
n += 1;
}
if cfg!(feature = "blue") {
n += 1;
}
if cfg!(feature = "cyan") {
n += 1;
}
if cfg!(feature = "green") {
n += 1;
}
if cfg!(feature = "orange") {
n += 1;
}
if cfg!(feature = "pink") {
n += 1;
}
if cfg!(feature = "purple") {
n += 1;
}
if cfg!(feature = "red") {
n += 1;
}
if cfg!(feature = "white") {
n += 1;
}
if cfg!(feature = "yellow") {
n += 1;
}
n
}
const _: () = assert!(
color_feature_count() == 1,
"exactly one color feature must be enabled: black, blue, cyan, green, orange, pink, purple, red, white, yellow"
);
const fn workspace_backend_count() -> usize {
let mut n = 0;
if cfg!(feature = "niri") {
n += 1;
}
if cfg!(feature = "hyprland") {
n += 1;
}
if cfg!(feature = "sway") {
n += 1;
}
n
}
const _: () = assert!(
workspace_backend_count() <= 1,
"zero or one of the workspace backends must be enabled: niri, hyprland, sway"
);