Author SHA1 Message Date
Kenny Levinsen 6bb65c28c7 Minor bump 2019-09-07 00:39:10 +02:00
Kenny Levinsen 64ddb16147 rustfmt 2019-09-07 00:33:34 +02:00
Kenny Levinsen 1c02bfd339 clock: Sizing error 2019-09-07 00:33:24 +02:00
22 changed files with 145 additions and 1255 deletions
Generated
-707
View File
File diff suppressed because it is too large Load Diff
+3 -16
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "wldash" name = "wldash"
version = "0.2.0" version = "0.2.1"
authors = ["Kenny Levinsen <kl@kl.wtf>"] authors = ["Kenny Levinsen <kl@kl.wtf>"]
edition = "2018" edition = "2018"
@@ -8,37 +8,24 @@ edition = "2018"
lto = "fat" lto = "fat"
[features] [features]
default = ["alsa-widget", "pulseaudio-widget", "yaml-cfg", "json-cfg"]
damage_debug = [] damage_debug = []
yaml-cfg = ["serde_yaml"]
json-cfg = ["serde_json"]
alsa-widget = ["alsa"]
pulseaudio-widget = ["libpulse-binding"]
[dependencies] [dependencies]
smithay-client-toolkit = "0.6.4" smithay-client-toolkit = "0.6.4"
byteorder = "1.3" byteorder = "1.3"
rusttype = "0.7" rusttype = "0.7"
failure = "0.1.5"
chrono = "0.4" chrono = "0.4"
nix = "0.15" nix = "0.15"
memmap = "0.7" memmap = "0.7"
os_pipe = "0.8" os_pipe = "0.8"
wayland-client = { version = "0.23", features = ["dlopen"] } wayland-client = { version = "0.23", features = ["dlopen"] }
wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] } wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] }
wl-clipboard-rs = { version = "0.3" } libpulse-binding = { version = "2.11"}
dbus = "0.6" dbus = "0.6"
fuzzy-matcher = "0.2" fuzzy-matcher = "0.2"
lazy_static = "1.4" lazy_static = "1.4"
rcalc_lib = { version = "0.9" } rcalc_lib = { version = "0.9" }
rust-ini = "0.13" rust-ini = "0.13"
shlex = "0.1" shlex = "0.1"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true }
serde_yaml = { version = "0.8", optional = true }
libpulse-binding = { version = "2.11", optional = true }
alsa = { version = "0.3.0", optional = true }
+2 -2
View File
@@ -11,7 +11,7 @@ Consider this alpha-quality: While it works, *everything* is subject to change w
3. Put somewhere: `cp target/release/wldash /usr/local/bin/wldash` 3. Put somewhere: `cp target/release/wldash /usr/local/bin/wldash`
4. Run: `wldash` 4. Run: `wldash`
To see the default configuration, run `wldash print-config`. To configure, place a file in `$XDG_CONFIG_HOME/wldash/config.yaml` (or if `XDG_CONFIG_HOME` is not set, `~/.config/wldash/config.yaml`). JSON is also currently supported. To see the default configuration, run `wldash print-config`. To configure, place a file in `$XDG_CONFIG_HOME/wldash/config.json` (or if `XDG_CONFIG_HOME` is not set, `~/.config/wldash/config.json`).
Notable settings: `outptuMode` can be `active` or `all`, `scale` can be set to `2` to half the buffer size, and the widgets (and their layout) can be configured. Notable settings: `outptuMode` can be `active` or `all`, `scale` can be set to `2` to half the buffer size, and the widgets (and their layout) can be configured.
@@ -62,4 +62,4 @@ The launcher also accepts prefix operators to change its mode:
- Scaling of any kind - all sizes are currently hardcoded in pixels - Scaling of any kind - all sizes are currently hardcoded in pixels
- Configurability - Configurability
- Cleanup and reorganization - Cleanup and reorganization
- Proper line editor for the launcher - Proper line editor for the launcher
+1 -7
View File
@@ -34,13 +34,7 @@
} }
]}, ]},
{"calendar": {"font_size": 16.0,"sections": 3}}, {"calendar": {"font_size": 16.0,"sections": 3}},
{"launcher": { {"launcher": {"font_size": 32.0,"length": 1200}}
"font_size": 32.0,
"length": 1200,
"app_opener": "swaymsg exec ",
"term_opener": "alacritty -e ",
"url_opener": "xdg-open "
}}
]} ]}
} }
}, },
-49
View File
@@ -1,49 +0,0 @@
outputMode: active
scale: 1
background:
red: 0.0
green: 0.0
blue: 0.0
opacity: 0.9
widget:
margin:
margins: [20, 20, 20, 20]
widget:
verticalLayout:
- horizontalLayout:
- margin:
margins: [0, 88, 0, 32]
widget:
verticalLayout:
- date:
font_size: 64.0
- clock:
font_size: 256.0
- verticalLayout:
- margin:
margins: [0, 0, 0, 8]
widget:
battery:
font_size: 24.0
length: 600
- margin:
margins: [0, 0, 0, 8]
widget:
backlight:
font_size: 24.0
length: 600
- margin:
margins: [0, 0, 0, 8]
widget:
pulseAudio:
font_size: 24.0
length: 600
- calendar:
font_size: 16.0
sections: 3
- launcher:
font_size: 32.0
length: 1200
app_opener: "swaymsg exec "
term_opener: "alacritty -e "
url_opener: "xdg-open "
+52 -70
View File
@@ -21,7 +21,6 @@ use crate::widget::{DrawContext, Widget};
use crate::cmd::Cmd; use crate::cmd::Cmd;
use crate::doublemempool::DoubleMemPool; use crate::doublemempool::DoubleMemPool;
#[derive(Debug)]
pub enum OutputMode { pub enum OutputMode {
Active, Active,
All, All,
@@ -124,49 +123,47 @@ impl AppInner {
self.configured_surfaces = Arc::new(Mutex::new(0)); self.configured_surfaces = Arc::new(Mutex::new(0));
if !self.visible { if self.visible {
self.surfaces = Vec::new(); match self.output_mode {
self.shell_surfaces = Vec::new(); OutputMode::Active => {
return; if self.shell_surfaces.len() > 0 {
} return;
}
match self.output_mode {
OutputMode::Active => {
if self.shell_surfaces.len() > 0 {
return;
}
let (surface, shell_surface) = AppInner::add_shell_surface(
&compositor,
&shell,
self.scale,
self.configured_surfaces.clone(),
self.draw_tx.clone(),
None,
);
self.surfaces = vec![surface];
self.shell_surfaces = vec![shell_surface];
}
OutputMode::All => {
let mut surfaces = Vec::new();
let mut shell_surfaces = Vec::new();
for output in self.outputs.iter() {
let (surface, shell_surface) = AppInner::add_shell_surface( let (surface, shell_surface) = AppInner::add_shell_surface(
&compositor, &compositor,
&shell, &shell,
self.scale, self.scale,
self.configured_surfaces.clone(), self.configured_surfaces.clone(),
self.draw_tx.clone(), self.draw_tx.clone(),
Some(&output.1), None,
); );
surfaces.push(surface); self.surfaces = vec![surface];
shell_surfaces.push(shell_surface); self.shell_surfaces = vec![shell_surface];
}
OutputMode::All => {
let mut surfaces = Vec::new();
let mut shell_surfaces = Vec::new();
for output in self.outputs.iter() {
let (surface, shell_surface) = AppInner::add_shell_surface(
&compositor,
&shell,
self.scale,
self.configured_surfaces.clone(),
self.draw_tx.clone(),
Some(&output.1),
);
surfaces.push(surface);
shell_surfaces.push(shell_surface);
}
self.surfaces = surfaces;
self.shell_surfaces = shell_surfaces;
} }
self.surfaces = surfaces;
self.shell_surfaces = shell_surfaces;
} }
self.draw_tx.send(Cmd::ForceDraw).unwrap();
} else {
self.surfaces = Vec::new();
self.shell_surfaces = Vec::new();
} }
self.draw_tx.send(Cmd::ForceDraw).unwrap();
} }
fn add_output(&mut self, id: u32, output: wl_output::WlOutput) { fn add_output(&mut self, id: u32, output: wl_output::WlOutput) {
@@ -213,7 +210,7 @@ pub struct App {
} }
impl App { impl App {
pub fn redraw(&mut self, force: bool) -> Result<(), ::std::io::Error> { pub fn redraw(&mut self, mut force: bool) -> Result<(), ::std::io::Error> {
let widget = match self.widget { let widget = match self.widget {
Some(ref mut widget) => widget, Some(ref mut widget) => widget,
None => return Ok(()), None => return Ok(()),
@@ -222,10 +219,7 @@ impl App {
let inner = self.inner.lock().unwrap(); let inner = self.inner.lock().unwrap();
let time = Local::now(); let time = Local::now();
if !inner.visible if inner.shell_surfaces.len() != *inner.configured_surfaces.lock().unwrap() {
|| inner.shell_surfaces.len() != *inner.configured_surfaces.lock().unwrap()
|| inner.surfaces.len() == 0
{
// Not ready yet // Not ready yet
return Ok(()); return Ok(());
} }
@@ -237,7 +231,6 @@ impl App {
let size = widget.size(); let size = widget.size();
let size_changed = self.last_dim != size; let size_changed = self.last_dim != size;
let force = force | size_changed;
// resize the pool if relevant // resize the pool if relevant
pool.resize((4 * size.0 * size.1) as usize) pool.resize((4 * size.0 * size.1) as usize)
@@ -246,8 +239,8 @@ impl App {
let mut buf = Buffer::new(mmap, size); let mut buf = Buffer::new(mmap, size);
// Copy old damage // Copy old damage
let force = match (force, &self.last_damage) { if let Some(d) = &self.last_damage {
(false, Some(d)) => { if !size_changed {
let lastmmap = last.mmap(); let lastmmap = last.mmap();
let last = Buffer::new(lastmmap, size); let last = Buffer::new(lastmmap, size);
@@ -257,10 +250,12 @@ impl App {
for d in d { for d in d {
last.copy_to(&mut buf, d.clone()); last.copy_to(&mut buf, d.clone());
} }
false } else {
force = true;
} }
_ => true, } else {
}; force = true;
}
if force { if force {
buf.memset(&self.bg); buf.memset(&self.bg);
@@ -277,9 +272,8 @@ impl App {
mmap.flush().unwrap(); mmap.flush().unwrap();
if !force && !report.full_damage && report.damage.len() == 0 { if !size_changed && !report.full_damage && report.damage.len() == 0 {
// Nothing to do // Nothing to do
self.pools.never_mind();
return Ok(()); return Ok(());
} }
@@ -316,17 +310,9 @@ impl App {
Ok(()) Ok(())
} }
pub fn hide(&mut self) { pub fn toggle_visible(&mut self) {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.visible = false; inner.visible = !inner.visible;
self.last_dim = (0, 0);
inner.outputs_changed();
}
pub fn show(&mut self) {
let mut inner = self.inner.lock().unwrap();
inner.visible = true;
self.last_dim = (0, 0);
inner.outputs_changed(); inner.outputs_changed();
} }
@@ -436,14 +422,6 @@ impl App {
// Keyboard processing // Keyboard processing
// //
let kbd_clone = cmd_queue.clone(); let kbd_clone = cmd_queue.clone();
let modifiers_state = Arc::new(Mutex::new(ModifiersState {
ctrl: false,
alt: false,
shift: false,
caps_lock: false,
logo: false,
num_lock: false,
}));
map_keyboard_auto(&seat, move |event: KbEvent, _| match event { map_keyboard_auto(&seat, move |event: KbEvent, _| match event {
KbEvent::Key { KbEvent::Key {
keysym, keysym,
@@ -453,19 +431,22 @@ impl App {
} => match state { } => match state {
KeyState::Pressed => match keysym { KeyState::Pressed => match keysym {
keysyms::XKB_KEY_Escape => kbd_clone.lock().unwrap().push_back(Cmd::Exit), keysyms::XKB_KEY_Escape => kbd_clone.lock().unwrap().push_back(Cmd::Exit),
keysyms::XKB_KEY_c if modifiers_state.lock().unwrap().ctrl => {
kbd_clone.lock().unwrap().push_back(Cmd::Exit)
}
v => kbd_clone.lock().unwrap().push_back(Cmd::Keyboard { v => kbd_clone.lock().unwrap().push_back(Cmd::Keyboard {
key: v, key: v,
key_state: state, key_state: state,
modifiers_state: modifiers_state.lock().unwrap().clone(), modifiers_state: ModifiersState {
ctrl: false,
alt: false,
shift: false,
caps_lock: false,
logo: false,
num_lock: false,
},
interpreted: utf8, interpreted: utf8,
}), }),
}, },
_ => (), _ => (),
}, },
KbEvent::Modifiers { modifiers } => *modifiers_state.lock().unwrap() = modifiers,
_ => (), _ => (),
}) })
.expect("Failed to map keyboard"); .expect("Failed to map keyboard");
@@ -486,6 +467,7 @@ impl App {
}, },
)); ));
inner.lock().unwrap().outputs_changed();
event_queue.sync_roundtrip().unwrap(); event_queue.sync_roundtrip().unwrap();
// //
+39 -42
View File
@@ -10,27 +10,55 @@ pub struct Color {
impl Color { impl Color {
pub fn new(red: f32, green: f32, blue: f32, opacity: f32) -> Color { pub fn new(red: f32, green: f32, blue: f32, opacity: f32) -> Color {
let (red, green, blue, opacity) = clamp(red, green, blue, opacity);
Color { Color {
red, red: if red > 1.0 {
green, 1.0
blue, } else if red < 0.0 {
opacity, 0.0
} else {
red
},
green: if green > 1.0 {
1.0
} else if green < 0.0 {
0.0
} else {
green
},
blue: if blue > 1.0 {
1.0
} else if blue < 0.0 {
0.0
} else {
blue
},
opacity: if opacity > 1.0 {
1.0
} else if opacity < 0.0 {
0.0
} else {
opacity
},
} }
} }
pub fn blend(&self, other: &Color, ratio: f32) -> Color { pub fn blend(&self, other: &Color, ratio: f32) -> Color {
let ratio = clamp_f32(ratio, 0.0, 1.0); let ratio = if ratio > 1.0 {
1.0
} else if ratio < 0.0 {
0.0
} else {
ratio
};
Color { Color {
red: blend_f32(self.red, other.red, ratio), red: self.red + ((other.red - self.red) * ratio),
green: blend_f32(self.green, other.green, ratio), green: self.green + ((other.green - self.green) * ratio),
blue: blend_f32(self.blue, other.blue, ratio), blue: self.blue + ((other.blue - self.blue) * ratio),
opacity: blend_f32(self.opacity, other.opacity, ratio), opacity: self.opacity + ((other.opacity - self.opacity) * ratio),
} }
} }
#[inline]
pub fn as_argb8888(&self) -> u32 { pub fn as_argb8888(&self) -> u32 {
((255.0 * self.opacity) as u32 & 0xFF) << 24 ((255.0 * self.opacity) as u32 & 0xFF) << 24
| ((255.0 * self.red) as u32 & 0xFF) << 16 | ((255.0 * self.red) as u32 & 0xFF) << 16
@@ -38,34 +66,3 @@ impl Color {
| ((255.0 * self.blue) as u32 & 0xFF) | ((255.0 * self.blue) as u32 & 0xFF)
} }
} }
#[inline]
fn clamp(r: f32, g: f32, b: f32, o: f32) -> (f32, f32, f32, f32) {
clamp_naive(r, g, b, o)
}
#[inline]
fn clamp_naive(r: f32, g: f32, b: f32, o: f32) -> (f32, f32, f32, f32) {
(
clamp_f32(r, 0.0, 1.0),
clamp_f32(g, 0.0, 1.0),
clamp_f32(b, 0.0, 1.0),
clamp_f32(o, 0.0, 1.0),
)
}
#[inline]
fn clamp_f32(v: f32, a: f32, b: f32) -> f32 {
if v > b {
b
} else if v < a {
a
} else {
v
}
}
#[inline]
fn blend_f32(a: f32, b: f32, r: f32) -> f32 {
a + ((b - a) * r)
}
+2 -17
View File
@@ -48,16 +48,10 @@ pub enum Widget {
font_size: f32, font_size: f32,
length: u32, length: u32,
}, },
#[cfg(feature = "pulseaudio-widget")]
PulseAudio { PulseAudio {
font_size: f32, font_size: f32,
length: u32, length: u32,
}, },
#[cfg(feature = "alsa-widget")]
AlsaSound {
font_size: f32,
length: u32,
},
} }
impl Widget { impl Widget {
@@ -127,16 +121,8 @@ impl Widget {
Err(_) => None, Err(_) => None,
} }
} }
#[cfg(feature = "pulseaudio-widget")]
Widget::PulseAudio { font_size, length } => { Widget::PulseAudio { font_size, length } => {
match widgets::audio::PulseAudio::new(font_size, length, tx.clone()) { match widgets::sound::PulseAudio::new(font_size, length, tx.clone()) {
Ok(w) => Some(w),
Err(_) => None,
}
}
#[cfg(feature = "alsa-widget")]
Widget::AlsaSound { font_size, length } => {
match widgets::audio::Alsa::new(font_size, length) {
Ok(w) => Some(w), Ok(w) => Some(w),
Err(_) => None, Err(_) => None,
} }
@@ -161,10 +147,10 @@ impl Default for OutputMode {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Config { pub struct Config {
pub widget: Widget,
pub output_mode: OutputMode, pub output_mode: OutputMode,
pub scale: u32, pub scale: u32,
pub background: Color, pub background: Color,
pub widget: Widget,
} }
impl Default for Config { impl Default for Config {
@@ -196,7 +182,6 @@ impl Default for Config {
length: 600, length: 600,
}), }),
}), }),
#[cfg(feature = "pulseaudio-widget")]
Box::new(Widget::Margin { Box::new(Widget::Margin {
margins: (0, 0, 0, 8), margins: (0, 0, 0, 8),
widget: Box::new(Widget::PulseAudio { widget: Box::new(Widget::PulseAudio {
-61
View File
@@ -1,61 +0,0 @@
use serde::{de::DeserializeOwned, Serialize};
use std::io::BufRead;
pub enum ConfigFmt {
#[cfg(feature = "yaml-cfg")]
Yaml,
#[cfg(feature = "json-cfg")]
Json,
}
pub const CONFIG_NAMES: &'static [&'static str] = &[
#[cfg(feature = "yaml-cfg")]
"config.yaml",
#[cfg(feature = "json-cfg")]
"config.json",
];
impl ConfigFmt {
#[inline]
pub fn new(ext: &str) -> Option<Self> {
match ext {
#[cfg(feature = "yaml-cfg")]
"yaml" => Some(ConfigFmt::Yaml),
#[cfg(feature = "json-cfg")]
"json" => Some(ConfigFmt::Json),
_ => None,
}
}
#[inline]
pub fn from_reader<B: BufRead, T: DeserializeOwned>(&self, r: B) -> T {
match self {
#[cfg(feature = "yaml-cfg")]
ConfigFmt::Yaml => serde_yaml::from_reader(r).unwrap(),
#[cfg(feature = "json-cfg")]
ConfigFmt::Json => serde_json::from_reader(r).unwrap(),
}
}
#[inline]
pub fn to_string<T: Serialize + ?Sized>(&self, src: &T) -> String {
match self {
#[cfg(feature = "yaml-cfg")]
ConfigFmt::Yaml => serde_yaml::to_string(&src).unwrap(),
#[cfg(feature = "json-cfg")]
ConfigFmt::Json => serde_json::to_string_pretty(&src).unwrap(),
}
}
}
impl Default for ConfigFmt {
fn default() -> Self {
// attributes require curly braces to work
#[cfg(feature = "yaml-cfg")]
{
ConfigFmt::Yaml
}
#[cfg(all(feature = "json-cfg", not(feature = "yaml-cfg")))]
{
ConfigFmt::Json
}
}
}
+2 -2
View File
@@ -27,7 +27,7 @@ impl Desktop {
enabled_escape: false, enabled_escape: false,
}, },
)?; )?;
match file.section(Some("Desktop Entry")) { match file.section(Some("Desktop Entry").to_owned()) {
Some(desktop) => Ok(Desktop { Some(desktop) => Ok(Desktop {
entry_type: desktop.get("Type").unwrap_or(&"".to_string()).to_string(), entry_type: desktop.get("Type").unwrap_or(&"".to_string()).to_string(),
name: desktop.get("Name").unwrap_or(&"".to_string()).to_string(), name: desktop.get("Name").unwrap_or(&"".to_string()).to_string(),
@@ -45,7 +45,7 @@ impl Desktop {
} }
fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> { fn parse_dir(d: &str) -> Result<Vec<Desktop>, Box<dyn Error>> {
let mut files: Vec<Desktop> = Vec::with_capacity(16); let mut files: Vec<Desktop> = Vec::new();
for entry in fs::read_dir(d)? { for entry in fs::read_dir(d)? {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
+1 -5
View File
@@ -19,7 +19,7 @@ impl DoubleMemPool {
pub fn pool(&mut self) -> Option<(&mut MemPool, &mut MemPool)> { pub fn pool(&mut self) -> Option<(&mut MemPool, &mut MemPool)> {
let switch = self.switch; let switch = self.switch;
self.switch = !self.switch; self.switch = !self.switch;
let (last, cur) = if !switch { let (last, cur) = if switch {
(&mut self.pool2, &mut self.pool1) (&mut self.pool2, &mut self.pool1)
} else { } else {
(&mut self.pool1, &mut self.pool2) (&mut self.pool1, &mut self.pool2)
@@ -31,8 +31,4 @@ impl DoubleMemPool {
Some((last, cur)) Some((last, cur))
} }
} }
pub fn never_mind(&mut self) {
self.switch = !self.switch;
}
} }
+26 -92
View File
@@ -1,3 +1,4 @@
use std::default::Default;
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
@@ -13,7 +14,6 @@ mod buffer;
mod cmd; mod cmd;
mod color; mod color;
mod config; mod config;
mod configfmt;
mod desktop; mod desktop;
mod doublemempool; mod doublemempool;
mod draw; mod draw;
@@ -22,15 +22,12 @@ mod widgets;
use app::{App, OutputMode}; use app::{App, OutputMode};
use cmd::Cmd; use cmd::Cmd;
use config::Config;
use configfmt::ConfigFmt;
enum Mode { enum Mode {
Start, Start,
Daemonize,
StartOrKill, StartOrKill,
ToggleVisible, ToggleVisible,
PrintConfig(ConfigFmt), PrintConfig,
} }
fn main() { fn main() {
@@ -46,69 +43,34 @@ fn main() {
}, },
}; };
// From all existing files take the first readable one and write it's extension to `ext` let config: config::Config = match File::open(config_home + "/config.json") {
let mut ext = [0x0; 8]; Ok(f) => {
let file = configfmt::CONFIG_NAMES let reader = BufReader::new(f);
.iter() serde_json::from_reader(reader).unwrap()
.map(|name| std::path::Path::new(&config_home).join(name)) }
.filter_map(|path| { Err(_) => Default::default(),
match File::open(&path) { };
Ok(file) => {
let e = path.extension().and_then(|e| e.to_str())?;
let len = e.len();
let from = len.saturating_sub(8); // the longest possible extension
ext[0..len - from].copy_from_slice(&e.as_bytes()[from..]);
Some(file)
}
Err(_) => None,
}
})
.next();
let fmt = std::str::from_utf8(&ext)
.ok()
.and_then(ConfigFmt::new)
.unwrap_or_default();
let config: Config = file
.map(|f| fmt.from_reader(BufReader::new(f)))
.unwrap_or_default();
let scale = config.scale; let scale = config.scale;
let mut args = env::args(); let args: Vec<String> = env::args().collect();
let _ = args.next(); let mode = match args.len() {
let mode = match args.next() { 1 => Mode::Start,
Some(arg) => match arg.as_str() { 2 => match args[1].as_str() {
"start" => Mode::Daemonize, "start" => Mode::Start,
"start-or-kill" => Mode::StartOrKill, "start-or-kill" => Mode::StartOrKill,
"toggle-visible" => Mode::ToggleVisible, "toggle-visible" => Mode::ToggleVisible,
"print-config" => Mode::PrintConfig(fmt), "print-config" => Mode::PrintConfig,
s => { s => {
let p = "print-config-"; eprintln!("unsupported sub-command {}", s);
let l = p.len(); std::process::exit(1);
let fmt = if s.starts_with(p) {
ConfigFmt::new(&s[l..])
} else {
None
};
if let Some(fmt) = fmt {
Mode::PrintConfig(fmt)
} else {
eprintln!("unsupported sub-command {}", s);
std::process::exit(1);
}
} }
}, },
None => Mode::Start, v => {
eprintln!("expected 0 or 1 arguments, got {}", v);
std::process::exit(1);
}
}; };
if let Some(_) = args.next() {
// total = args.count + 2 (the two we skipped + the rest)
eprintln!("expected 0 or 1 arguments, got {}", args.count() + 2);
std::process::exit(1);
}
let mut daemon = false;
match mode { match mode {
Mode::ToggleVisible => { Mode::ToggleVisible => {
@@ -131,15 +93,8 @@ fn main() {
std::process::exit(1); std::process::exit(1);
}; };
} }
Mode::Daemonize => { Mode::PrintConfig => {
if let Ok(_) = UnixStream::connect(socket_path.clone()) { println!("{}", serde_json::to_string_pretty(&config).unwrap());
eprintln!("wldash is already running");
std::process::exit(1);
};
daemon = true;
}
Mode::PrintConfig(fmt) => {
println!("{}", fmt.to_string(&config));
std::process::exit(0); std::process::exit(0);
} }
} }
@@ -166,11 +121,6 @@ fn main() {
}); });
let mut app = App::new(tx_draw, output_mode, background, scale); let mut app = App::new(tx_draw, output_mode, background, scale);
if daemon {
app.hide();
} else {
app.show();
}
let widget = mod_rx.recv().unwrap(); let widget = mod_rx.recv().unwrap();
app.set_widget(widget).unwrap(); app.set_widget(widget).unwrap();
@@ -229,7 +179,6 @@ fn main() {
app.cmd_queue().lock().unwrap().push_back(Cmd::Draw); app.cmd_queue().lock().unwrap().push_back(Cmd::Draw);
let mut visible = !daemon;
let q = app.cmd_queue(); let q = app.cmd_queue();
loop { loop {
let cmd = q.lock().unwrap().pop_front(); let cmd = q.lock().unwrap().pop_front();
@@ -262,26 +211,11 @@ fn main() {
q.lock().unwrap().push_back(Cmd::Draw); q.lock().unwrap().push_back(Cmd::Draw);
} }
Cmd::ToggleVisible => { Cmd::ToggleVisible => {
visible = !visible; app.toggle_visible();
if visible {
app.get_widget().enter();
app.show();
} else {
app.hide();
app.get_widget().leave();
}
app.flush_display();
} }
Cmd::Exit => { Cmd::Exit => {
if daemon { let _ = std::fs::remove_file(socket_path);
visible = false; return;
app.hide();
app.get_widget().leave();
app.flush_display();
} else {
let _ = std::fs::remove_file(socket_path);
return;
}
} }
}, },
None => { None => {
-34
View File
@@ -30,8 +30,6 @@ impl DrawReport {
} }
pub trait Widget { pub trait Widget {
fn enter(&mut self);
fn leave(&mut self);
fn size(&self) -> (u32, u32); fn size(&self) -> (u32, u32);
fn draw( fn draw(
&mut self, &mut self,
@@ -62,16 +60,6 @@ impl VerticalLayout {
} }
impl Widget for VerticalLayout { impl Widget for VerticalLayout {
fn enter(&mut self) {
for child in &mut self.children {
child.enter();
}
}
fn leave(&mut self) {
for child in &mut self.children {
child.leave();
}
}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
let mut width = 0; let mut width = 0;
let mut height = 0; let mut height = 0;
@@ -168,16 +156,6 @@ impl HorizontalLayout {
} }
impl Widget for HorizontalLayout { impl Widget for HorizontalLayout {
fn enter(&mut self) {
for child in &mut self.children {
child.enter();
}
}
fn leave(&mut self) {
for child in &mut self.children {
child.leave();
}
}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
let mut width = 0; let mut width = 0;
let mut height = 0; let mut height = 0;
@@ -280,12 +258,6 @@ impl Margin {
} }
impl Widget for Margin { impl Widget for Margin {
fn enter(&mut self) {
self.child.enter()
}
fn leave(&mut self) {
self.child.leave()
}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
let size = self.child.size(); let size = self.child.size();
( (
@@ -354,12 +326,6 @@ impl Fixed {
} }
impl Widget for Fixed { impl Widget for Fixed {
fn enter(&mut self) {
self.child.enter()
}
fn leave(&mut self) {
self.child.leave()
}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
self.size self.size
} }
-109
View File
@@ -1,109 +0,0 @@
use crate::color::Color;
use crate::widgets::bar_widget::{BarWidget, BarWidgetImpl};
use alsa::mixer::{Mixer, Selem, SelemChannelId, SelemId};
const CARD_NAME: &'static str = "default";
const SELEM_NAME: &'static str = "Master";
const SELEM_ID: u32 = 0u32;
#[inline]
fn alsa_error_to_io_error(fail: &'static str, err: &alsa::Error) -> ::std::io::Error {
let kind = ::std::io::ErrorKind::Other;
let func = err.func();
let errno = err
.errno()
.map(|errno| format!("; errno = {}", errno))
.unwrap_or(String::new());
return ::std::io::Error::new(kind, format!("{}: {}{}", fail, func, errno));
}
#[inline]
fn alsa_volume_to_f32(volume: i64, min: i64, max: i64) -> f32 {
(volume - min) as f32 / (max - min) as f32
}
#[inline]
fn f32_to_alsa_volume(volume: f32, min: i64, max: i64) -> i64 {
min + ((max - min) as f32 * volume) as i64
}
pub struct Alsa {
pub mixer: Mixer,
}
impl Alsa {
pub fn new(font_size: f32, length: u32) -> ::std::io::Result<Box<BarWidget>> {
let mixer = Mixer::new(CARD_NAME, true)
.map_err(|err| alsa_error_to_io_error("Failed to create ALSA mixer", &err))?;
let mixer = Self { mixer };
mixer.get_master_volume()?; // probing
Ok(BarWidget::new_simple(font_size, length, Box::new(mixer)))
}
#[inline]
pub fn get_master<'a>(&'a self) -> ::std::io::Result<Selem<'a>> {
let master_id = SelemId::new(SELEM_NAME, SELEM_ID);
match self.mixer.find_selem(&master_id) {
Some(master) => Ok(master),
None => {
let kind = ::std::io::ErrorKind::NotFound;
let desc = "`Master` not found";
Err(::std::io::Error::new(kind, desc))
}
}
}
pub fn get_master_volume(&self) -> ::std::io::Result<f32> {
let master = self.get_master()?;
let (min, max) = master.get_playback_volume_range();
master
.get_playback_volume(SelemChannelId::mono())
.map(|volume| alsa_volume_to_f32(volume, min, max))
.map_err(|e| alsa_error_to_io_error("Failed to get `Master` volume", &e))
}
pub fn set_master_volume(&self, volume: f32) -> ::std::io::Result<()> {
let master = self.get_master()?;
let (min, max) = master.get_playback_volume_range();
let volume = f32_to_alsa_volume(volume, min, max);
master
.set_playback_volume_all(volume)
.map_err(|e| alsa_error_to_io_error("Failed to set `Master` volume", &e))
}
pub fn inc_master_volume(&self, diff: f32) -> ::std::io::Result<()> {
let master = self.get_master()?;
let (min, max) = master.get_playback_volume_range();
master
.get_playback_volume(SelemChannelId::mono())
.and_then(|volume| {
let volume = alsa_volume_to_f32(volume, min, max);
let volume = f32_to_alsa_volume(volume + diff, min, max);
master.set_playback_volume_all(volume)
})
.map_err(|e| alsa_error_to_io_error("Failed to inc/dec `Master` volume", &e))
}
}
impl BarWidgetImpl for Alsa {
fn name(&self) -> &str {
"volume"
}
fn value(&self) -> f32 {
match self.get_master_volume() {
Ok(v) => v,
Err(e) => panic!(e),
}
}
fn color(&self) -> Color {
Color::new(1.0, 1.0, 1.0, 1.0)
}
fn inc(&mut self, diff: f32) {
if let Err(e) = self.inc_master_volume(diff) {
panic!(e)
}
}
fn set(&mut self, abs: f32) {
if let Err(e) = self.set_master_volume(abs) {
panic!(e)
}
}
fn toggle(&mut self) {}
}
-9
View File
@@ -1,9 +0,0 @@
#[cfg(feature = "alsa-widget")]
mod alsa_sound;
#[cfg(feature = "alsa-widget")]
pub use alsa_sound::Alsa;
#[cfg(feature = "pulseaudio-widget")]
mod pulse_sound;
#[cfg(feature = "pulseaudio-widget")]
pub use pulse_sound::PulseAudio;
-2
View File
@@ -61,8 +61,6 @@ impl BarWidget {
} }
impl Widget for BarWidget { impl Widget for BarWidget {
fn enter(&mut self) {}
fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
(self.length, self.font_size) (self.length, self.font_size)
} }
-3
View File
@@ -177,9 +177,6 @@ impl Calendar {
} }
impl Widget for Calendar { impl Widget for Calendar {
fn enter(&mut self) {}
fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
let cal_width = 7 * self.font_size * 3 + self.font_size * 2; let cal_width = 7 * self.font_size * 3 + self.font_size * 2;
let cal_pad = self.font_size * 3; let cal_pad = self.font_size * 3;
+1 -3
View File
@@ -45,8 +45,6 @@ impl Clock {
} }
impl Widget for Clock { impl Widget for Clock {
fn enter(&mut self) {}
fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
let digit = (self.size * 0.45).ceil() as u32; let digit = (self.size * 0.45).ceil() as u32;
let colon = (self.size * 0.20).ceil() as u32; let colon = (self.size * 0.20).ceil() as u32;
@@ -74,7 +72,7 @@ impl Widget for Clock {
let digit = (self.size * 0.45).ceil() as u32; let digit = (self.size * 0.45).ceil() as u32;
let colon = (self.size * 0.20).ceil() as u32; let colon = (self.size * 0.20).ceil() as u32;
self.clock_cache.draw_text_fixed_width( let dim = self.clock_cache.draw_text_fixed_width(
buf, buf,
ctx.bg, ctx.bg,
&Color::new(1.0, 1.0, 1.0, 1.0), &Color::new(1.0, 1.0, 1.0, 1.0),
-2
View File
@@ -27,8 +27,6 @@ impl Date {
} }
impl Widget for Date { impl Widget for Date {
fn enter(&mut self) {}
fn leave(&mut self) {}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
((6.5 * self.size).ceil() as u32, self.size.ceil() as u32) ((6.5 * self.size).ceil() as u32, self.size.ceil() as u32)
} }
+14 -16
View File
@@ -101,8 +101,8 @@ impl Launcher {
)? )?
}; };
x_off += size.0 + self.font_size / 2; x_off += size.0 + self.font_size / 4;
width_remaining -= (size.0 + self.font_size / 2) as i32; width_remaining -= (size.0 + self.font_size / 4) as i32;
if width_remaining < 0 { if width_remaining < 0 {
break; break;
@@ -178,21 +178,20 @@ fn calc(s: &str) -> Result<String, String> {
} }
fn wlcopy(s: &str) -> Result<(), String> { fn wlcopy(s: &str) -> Result<(), String> {
use wl_clipboard_rs::copy::{MimeType, Options, Source}; let mut child = std::process::Command::new("wl-copy")
use failure::Fail; .stdin(std::process::Stdio::null())
let opts = Options::new(); .stdout(std::process::Stdio::null())
opts.copy(Source::Bytes(s.as_bytes()), MimeType::Text).map_err(|e|e.name().unwrap_or("unknown error").to_string()) .stderr(std::process::Stdio::null())
.arg(s)
.spawn()
.map_err(|_| "wl-copy not available".to_string())?;
child
.wait()
.map_err(|_| "unable to run wl-copy".to_string())?;
Ok(())
} }
impl Widget for Launcher { impl Widget for Launcher {
fn enter(&mut self) {}
fn leave(&mut self) {
self.input = "".to_string();
self.offset = 0;
self.result = None;
self.dirty = true;
}
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
(self.length, self.font_size) (self.length, self.font_size)
} }
@@ -270,12 +269,11 @@ impl Widget for Launcher {
fn keyboard_input( fn keyboard_input(
&mut self, &mut self,
key: u32, key: u32,
modifiers: ModifiersState, _: ModifiersState,
_: KeyState, _: KeyState,
interpreted: Option<String>, interpreted: Option<String>,
) { ) {
match key { match key {
keysyms::XKB_KEY_u if modifiers.ctrl => self.leave(),
keysyms::XKB_KEY_BackSpace => { keysyms::XKB_KEY_BackSpace => {
if self.input.len() > 0 { if self.input.len() > 0 {
self.input = self.input[..self.input.len() - 1].to_string(); self.input = self.input[..self.input.len() - 1].to_string();
+1 -3
View File
@@ -5,6 +5,4 @@ pub mod calendar;
pub mod clock; pub mod clock;
pub mod date; pub mod date;
pub mod launcher; pub mod launcher;
pub mod sound;
#[cfg(any(feature = "alsa-widget", feature = "pulseaudio-widget"))]
pub mod audio;
@@ -245,10 +245,7 @@ impl PulseAudioClient {
conn.mainloop.borrow_mut().run().unwrap(); conn.mainloop.borrow_mut().run().unwrap();
}); });
let pa_writer_res = rx1.recv().unwrap(); if !rx1.recv().unwrap() || !rx2.recv().unwrap() {
let pa_reader_res = rx2.recv().unwrap();
if !pa_writer_res || !pa_reader_res {
return Err(::std::io::Error::new( return Err(::std::io::Error::new(
::std::io::ErrorKind::Other, ::std::io::ErrorKind::Other,
"unable to start pulseaudio thread", "unable to start pulseaudio thread",