config: Generate configs

This commit is contained in:
Kenny Levinsen
2023-02-12 17:02:44 +01:00
parent db085168dc
commit 9e48eb053d
7 changed files with 179 additions and 104 deletions
-4
View File
@@ -8,10 +8,6 @@ edition = "2021"
lto = "fat"
panic = "abort"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
fontloading = ["fontconfig"]
[dependencies]
wayland-client = { version = "0.30", features = ["calloop", "log"] }
wayland-protocols = { version = "0.30", features = ["client", "unstable", "staging"] }
+117 -44
View File
@@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex};
use crate::{
event::Events,
fonts::FontMap,
fonts::{FontMap, find_font},
widgets::{
Backlight, Battery, Calendar, Clock, Date, HorizontalLayout, IndexedLayout, Interface,
InvertedHorizontalLayout, Layout, Line, Margin, PulseAudio, VerticalLayout, Widget as RealWidget,
@@ -14,7 +14,14 @@ use crate::{
};
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "snake_case")]
pub enum OperationMode {
LayerSurface((u32, u32)),
XdgToplevel,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Widget {
Margin {
margins: (u32, u32, u32, u32),
@@ -58,38 +65,47 @@ pub enum Widget {
},
}
impl Default for OperationMode {
fn default() -> OperationMode {
OperationMode::LayerSurface((1024, 768))
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "snake_case")]
pub struct Config {
pub font_paths: Option<HashMap<String, String>>,
pub widget: Option<Widget>,
pub widget: Widget,
pub mode: OperationMode,
}
impl Default for Config {
fn default() -> Config {
Config{
font_paths: None,
widget: None,
widget: Default::default(),
mode: Default::default(),
}
}
}
fn leak_or_default(v: Option<String>, d: &'static str) -> &'static str {
match v {
Some(v) => Box::leak(v.into_boxed_str()),
None => d,
}
}
impl Config {
pub fn generate_v1() -> Config {
let has_battery = Battery::detect();
let has_backlight = Backlight::detect("intel_backlight");
let sans = find_font("sans");
let monospace = find_font("monospace");
impl Default for Widget {
fn default() -> Widget {
Self::v2()
}
}
let mut bars = Vec::new();
if has_battery {
bars.push(Widget::Margin{ margins: (0, 0, 0, 8), widget: Box::new(Widget::Battery { font: None, font_size: 24. })});
}
if has_backlight {
bars.push(Widget::Margin{ margins: (0, 0, 0, 8), widget: Box::new(Widget::Backlight { device: Some("intel_backlight".to_string()), font: None, font_size: 24. })});
}
bars.push(Widget::Margin{ margins: (0, 0, 0, 8), widget: Box::new(Widget::PulseAudio { font: None, font_size: 24. })});
impl Widget {
pub fn v1() -> Widget {
Widget::Margin {
let widget = Widget::Margin {
margins: (20, 20, 20, 20),
widget: Box::new(Widget::VerticalLayout(vec![
Widget::HorizontalLayout(vec![
@@ -105,30 +121,7 @@ impl Widget {
]),
Widget::Margin {
margins: (88, 0, 0, 0),
widget: Box::new(Widget::VerticalLayout(vec![
Widget::Margin {
margins: (0, 0, 0, 8),
widget: Box::new(Widget::Battery {
font: None,
font_size: 24.,
}),
},
Widget::Margin {
margins: (0, 0, 0, 8),
widget: Box::new(Widget::Backlight {
device: None,
font: None,
font_size: 24.,
}),
},
Widget::Margin {
margins: (0, 0, 0, 8),
widget: Box::new(Widget::PulseAudio {
font: None,
font_size: 24.,
}),
},
])),
widget: Box::new(Widget::VerticalLayout(bars)),
},
]),
Widget::Calendar {
@@ -143,10 +136,88 @@ impl Widget {
font_size: 32.,
},
])),
};
let map = HashMap::from([
("sans".to_string(), sans),
("monospace".to_string(), monospace),
]);
Config{
font_paths: Some(map),
widget: widget,
mode: OperationMode::LayerSurface((1024, 768)),
}
}
pub fn v2() -> Widget {
pub fn generate_v2(clay: bool) -> Config {
let has_battery = Battery::detect();
let has_backlight = Backlight::detect("intel_backlight");
let sans = find_font("sans");
let monospace = find_font("monospace");
let mut bars = Vec::new();
if has_battery {
bars.push(Widget::Margin{ margins: (16, 8, 8, 0), widget: Box::new(Widget::Battery { font: None, font_size: 24. })});
}
if has_backlight {
bars.push(Widget::Margin{ margins: (16, 8, 8, 0), widget: Box::new(Widget::Backlight { device: Some("intel_backlight".to_string()), font: None, font_size: 24. })});
}
bars.push(Widget::Margin{ margins: (16, 8, 8, 0), widget: Box::new(Widget::PulseAudio { font: None, font_size: 24. })});
let widget = Widget::VerticalLayout(vec![
Widget::HorizontalLayout(vec![
Widget::Clock {
font: None,
font_size: 128.,
},
Widget::Margin {
margins: (16, 16, 0, 0),
widget: Box::new(Widget::Date {
font: None,
font_size: 48.,
}),
},
Widget::VerticalLayout(bars),
]),
Widget::Line(1),
Widget::InvertedHorizontalLayout(vec![
Widget::Calendar {
font_primary: None,
font_secondary: None,
font_size: 24.,
sections_x: 1,
sections_y: -1,
},
Widget::Launcher {
font: None,
font_size: 32.,
},
]),
]);
let map = HashMap::from([
("sans".to_string(), sans),
("monospace".to_string(), monospace),
]);
Config{
font_paths: Some(map),
widget: widget,
mode: if clay { OperationMode::XdgToplevel } else { OperationMode::LayerSurface((1024, 768)) },
}
}
}
fn leak_or_default(v: Option<String>, d: &'static str) -> &'static str {
match v {
Some(v) => Box::leak(v.into_boxed_str()),
None => d,
}
}
impl Default for Widget {
fn default() -> Widget {
Widget::VerticalLayout(vec![
Widget::HorizontalLayout(vec![
Widget::Clock {
@@ -201,7 +272,9 @@ impl Widget {
]),
])
}
}
impl Widget {
pub fn construct_widgets(
self,
v: &mut Vec<Box<dyn RealWidget>>,
+13 -19
View File
@@ -9,27 +9,21 @@ use std::{
/// FontRef is used to store Fonts on widgets.
pub type FontRef<'a> = &'a rusttype::Font<'a>;
#[cfg(feature = "fontloading")]
mod fc {
#[cfg(feature = "fontconfig")]
pub(crate) fn find_font(name: &str) -> String {
use fontconfig::Fontconfig as FontConfig;
/// Acts like fc-match.
/// Given a string, it matches it to a font file and returns its path.
pub(crate) fn from_string(name: &str) -> String {
let fc = FontConfig::new().unwrap();
fc.find(name, None)
.unwrap()
.path
.to_str()
.unwrap()
.to_string()
}
let fc = FontConfig::new().unwrap();
fc.find(name, None)
.unwrap()
.path
.to_str()
.unwrap()
.to_string()
}
#[cfg(not(feature = "fontloading"))]
mod fc {
pub(crate) fn from_string(_name: &str) -> String {
panic!("fontloading feature not enabled");
}
#[cfg(not(feature = "fontconfig"))]
pub(crate) fn find_font(_name: &str) -> String {
panic!("fontconfig not enabled so font search not available");
}
/// FontLoader is a marker struct that is used to load files
@@ -110,7 +104,7 @@ impl FontMap {
let path = match self.font_paths.get(font_name) {
Some(res) => res,
_ => {
let s = fc::from_string(font_name);
let s = find_font(font_name);
self.font_paths.insert(font_name, s);
self.font_paths.get(font_name).unwrap()
}
+19 -31
View File
@@ -20,39 +20,36 @@ use calloop::{
use chrono::{Duration, Local, Timelike};
use buffer::BufferView;
use config::{Config, Widget as ConfigWidget};
use config::Config;
use event::{Event, Events};
use fonts::{FontMap, MaybeFontMap};
use state::{OperationMode, State};
use state::State;
use widgets::{Geometry, Widget};
use std::{env, rc::Rc, thread};
enum UIVersion {
V1,
V2,
}
fn main() {
let mut args = env::args();
// Skip program name
_ = args.next();
let mut version = UIVersion::V2;
let mut mode = OperationMode::XdgToplevel;
loop {
match args.next() {
Some(ref s) if s == "layer_shell" => {
let width = args.next().map(|x| x.parse::<u32>().ok()).flatten();
let height = args.next().map(|x| x.parse::<u32>().ok()).flatten();
match (width, height) {
(Some(w), Some(h)) => mode = OperationMode::LayerSurface((w, h)),
_ => panic!("invalid arguments"),
Some(ref s) if s == "generate" => {
let config = match args.next() {
Some(ref s) if s == "v1" => Config::generate_v1(),
Some(ref s) if s == "v2" => Config::generate_v2(false),
Some(ref s) if s == "clay" => Config::generate_v2(true),
None => Config::generate_v2(false),
Some(s) => panic!("unknown argument: {}", s),
};
let home = env::var_os("HOME").unwrap().into_string().unwrap();
match File::create(format!("{}/.config/wldash/config.yml", home)) {
Ok(f) => serde_yaml::to_writer(f, &config).unwrap(),
Err(_) => panic!("uh"),
}
}
Some(ref s) if s == "xdg_shell" => mode = OperationMode::XdgToplevel,
Some(ref s) if s == "v1" => version = UIVersion::V1,
Some(ref s) if s == "v2" => version = UIVersion::V2,
std::process::exit(0);
},
Some(_) => panic!("unknown argument"),
None => break,
}
@@ -122,24 +119,15 @@ fn main() {
Err(_) => Default::default(),
};
let widget = match config.widget {
Some(w) => w,
None => match version {
UIVersion::V1 => ConfigWidget::v1(),
UIVersion::V2 => ConfigWidget::v2(),
},
};
if let Some(font_paths) = config.font_paths {
for (key, value) in font_paths.into_iter() {
fm.add_font_path(Box::leak(key.into_boxed_str()), value);
}
}
let layout = Rc::new(widget.construct_layout(&mut 0));
let layout = Rc::new(config.widget.construct_layout(&mut 0));
let mut widgets: Vec<Box<dyn Widget>> = Vec::new();
widget.construct_widgets(&mut widgets, &mut fm, &events);
config.widget.construct_widgets(&mut widgets, &mut fm, &events);
let font_thread = thread::Builder::new()
.name("fontloader".to_string())
@@ -150,7 +138,7 @@ fn main() {
.unwrap();
let mut state = State::new(
mode,
config.mode,
widgets,
layout,
MaybeFontMap::Waiting(font_thread),
+1 -6
View File
@@ -29,6 +29,7 @@ use wayland_protocols::{
use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
use crate::{
config::OperationMode,
buffer::BufferManager,
event::{Event, Events, PointerButton, PointerEvent},
fonts::{FontMap, MaybeFontMap},
@@ -36,12 +37,6 @@ use crate::{
widgets::{Geometry, Layout, Widget, WidgetUpdater},
};
#[derive(Debug)]
pub enum OperationMode {
LayerSurface((u32, u32)),
XdgToplevel,
}
#[derive(Default)]
pub struct MainSurface {
pub wl_surface: Option<wl_surface::WlSurface>,
+8
View File
@@ -39,6 +39,14 @@ impl Backlight {
dev.update();
BarWidget::new(Box::new(dev), fm, font, size)
}
pub fn detect(path: &str) -> bool {
let path = Path::new("/sys/class/backlight").to_path_buf().join(path);
match read_file_as_u64(path.join("brightness").as_path()) {
Ok(_) => true,
Err(_) => false,
}
}
}
impl BarWidgetImpl for Backlight {
+21
View File
@@ -2,6 +2,7 @@ use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
error::Error,
};
use dbus::blocking::{
@@ -46,6 +47,19 @@ struct InnerBattery {
dirty: bool,
}
fn get_battery_state() -> Result<UpowerBatteryState, Box<dyn Error>> {
let conn = LocalConnection::new_system()?;
let device_path = "/org/freedesktop/UPower/devices/DisplayDevice";
let proxy = conn.with_proxy(
"org.freedesktop.UPower",
device_path,
Duration::from_millis(500),
);
let state: u32 = proxy
.get("org.freedesktop.UPower.Device", "State")?;
Ok(UpowerBatteryState::from_dbus(state as u64))
}
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
thread::Builder::new()
.name("battmon".to_string())
@@ -131,6 +145,13 @@ impl Battery {
start_monitor(battery.inner.clone(), events);
BarWidget::new(Box::new(battery), fm, font, size)
}
pub fn detect() -> bool {
match get_battery_state() {
Ok(_) => true,
Err(_) => false,
}
}
}
impl BarWidgetImpl for Battery {