config: Generate configs
This commit is contained in:
@@ -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"] }
|
||||
|
||||
+116
-43
@@ -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>>,
|
||||
|
||||
+6
-12
@@ -9,12 +9,9 @@ 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()
|
||||
@@ -22,14 +19,11 @@ mod fc {
|
||||
.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
@@ -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
@@ -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>,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user