Add initial launcher implementation

This commit is contained in:
Kenny Levinsen
2019-08-02 15:59:52 +02:00
parent a52bc3f126
commit a2bc6190ce
12 changed files with 277 additions and 57 deletions
Generated
+11
View File
@@ -29,6 +29,15 @@ dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.5"
@@ -394,6 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "wldash"
version = "0.1.0"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"dbus 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -421,6 +431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e"
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+1
View File
@@ -16,3 +16,4 @@ wayland-client = { version = "0.23", features = ["dlopen"] }
wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] }
libpulse-binding = { version = "2.6.0"}
dbus = "0.6"
atty = "0.2"
+4 -3
View File
@@ -105,21 +105,21 @@ impl ModuleImpl for Backlight {
let c = Color::new(1.0, 1.0, 1.0, 1.0);
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 128, 24)),
&mut buf.subdimensions((0, 0, 128, 24))?,
bg,
&c,
24.0,
"backlight",
)?;
draw_bar(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
432,
24,
self.brightness() / 100.0,
)?;
draw_box(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
(432, 24),
)?;
@@ -171,6 +171,7 @@ impl ModuleImpl for Backlight {
_ => {}
}
}
_ => {}
}
}
}
+3 -3
View File
@@ -157,14 +157,14 @@ impl ModuleImpl for UpowerBattery {
let inner = self.inner.lock().unwrap();
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 128, 24)),
&mut buf.subdimensions((0, 0, 128, 24))?,
bg,
&c,
24.0,
"battery",
)?;
draw_bar(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
432,
24,
@@ -172,7 +172,7 @@ impl ModuleImpl for UpowerBattery {
)?;
draw_box(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
(432, 24),
)?;
+13 -15
View File
@@ -38,18 +38,17 @@ impl<'a> Buffer<'a> {
}
}
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> Buffer {
pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> Result<Buffer, ::std::io::Error> {
let bounds = self.get_bounds();
if subdimensions.0 + subdimensions.2 > bounds.2
|| subdimensions.1 + subdimensions.3 > bounds.3
{
panic!(
"cannot create subdimensions larger than buffer: {:?} > {:?}",
return Err(::std::io::Error::new(::std::io::ErrorKind::Other, format!("cannot create subdimensions larger than buffer: {:?} > {:?}",
subdimensions, bounds
);
)));
}
Buffer {
Ok(Buffer {
buf: self.buf,
dimensions: self.dimensions,
subdimensions: Some((
@@ -58,7 +57,7 @@ impl<'a> Buffer<'a> {
subdimensions.2,
subdimensions.3,
)),
}
})
}
pub fn memset(&mut self, c: &Color) {
@@ -82,21 +81,18 @@ impl<'a> Buffer<'a> {
}
}
pub fn put(&mut self, pos: (u32, u32), c: &Color) {
pub fn put(&mut self, pos: (u32, u32), c: &Color) -> Result<(), ::std::io::Error> {
let true_pos = if let Some(subdim) = self.subdimensions {
if pos.0 > subdim.2 || pos.1 > subdim.3 {
panic!(
"put({:?}) is not within subdimensions of buffer ({:?})",
pos, subdim
);
return Err(::std::io::Error::new(::std::io::ErrorKind::Other, format!("put({:?}) is not within subdimensions of buffer ({:?})",
pos, subdim)));
}
(pos.0 + subdim.0, pos.1 + subdim.1)
} else {
if pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1 {
panic!(
"put({:?}) is not within dimensions of buffer ({:?})",
return Err(::std::io::Error::new(::std::io::ErrorKind::Other, format!("put({:?}) is not within dimensions of buffer ({:?})",
pos, self.dimensions
);
)));
}
pos
};
@@ -107,6 +103,8 @@ impl<'a> Buffer<'a> {
.as_mut_ptr()
.offset(4 * (true_pos.0 + (true_pos.1 * self.dimensions.0)) as isize);
*(ptr as *mut u32) = c.as_argb8888();
}
};
Ok(())
}
}
+9 -8
View File
@@ -44,7 +44,7 @@ fn draw_month(
//
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 304, 72)),
&mut buf.subdimensions((0, 0, 304, 72))?,
background_color,
&Color::new(1.0, 1.0, 1.0, 1.0),
64.0,
@@ -54,7 +54,7 @@ fn draw_month(
if time.year() != orig.year() {
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((320, 0, 64, 32)),
&mut buf.subdimensions((320, 0, 64, 32))?,
background_color,
&Color::new(0.8, 0.8, 0.8, 1.0),
24.0,
@@ -80,7 +80,7 @@ fn draw_month(
draw_text(
DEJAVUSANS_MONO,
&mut buf.subdimensions((idx * 48 + 4, (y_off * 32) + 64, 32, 16)),
&mut buf.subdimensions((idx * 48 + 4, (y_off * 32) + 64, 32, 16))?,
background_color,
&Color::new(1.0, 1.0, 1.0, 1.0),
16.0,
@@ -108,7 +108,7 @@ fn draw_month(
let wk = time.iso_week();
draw_text(
DEJAVUSANS_MONO,
&mut buf.subdimensions((0 * 48, (y_off * 32) + 64, 38, 32)),
&mut buf.subdimensions((0 * 48, (y_off * 32) + 64, 38, 32))?,
background_color,
&Color::new(0.75, 0.75, 0.75, 1.0),
32.0,
@@ -127,7 +127,7 @@ fn draw_month(
};
draw_text(
DEJAVUSANS_MONO,
&mut buf.subdimensions((x_pos * 48, (y_off * 32) + 64, 38, 32)),
&mut buf.subdimensions((x_pos * 48, (y_off * 32) + 64, 38, 32))?,
background_color,
&c,
32.0,
@@ -186,13 +186,13 @@ impl ModuleImpl for Calendar {
}
let mut damage: Vec<(i32, i32, i32, i32)> = Vec::new();
damage.push(draw_month(
&mut buf.subdimensions((0, 0, 384, 344)),
&mut buf.subdimensions((0, 0, 384, 344))?,
background_color,
&time,
&t.pred().with_day(1).unwrap(),
)?);
damage.push(draw_month(
&mut buf.subdimensions((448, 0, 384, 344)),
&mut buf.subdimensions((448, 0, 384, 344))?,
background_color,
&time,
&t,
@@ -203,7 +203,7 @@ impl ModuleImpl for Calendar {
t.with_month(t.month() + 1).unwrap()
};
damage.push(draw_month(
&mut buf.subdimensions((896, 0, 384, 344)),
&mut buf.subdimensions((896, 0, 384, 344))?,
background_color,
&time,
&n,
@@ -237,6 +237,7 @@ impl ModuleImpl for Calendar {
self.offset = 0;
self.first_draw = true;
}
_ => {}
}
}
}
+2 -2
View File
@@ -44,7 +44,7 @@ impl ModuleImpl for Clock {
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 448, 64)),
&mut buf.subdimensions((0, 0, 448, 64))?,
bg,
&Color::new(1.0, 1.0, 1.0, 1.0),
64.0,
@@ -59,7 +59,7 @@ impl ModuleImpl for Clock {
draw_text_fixed_width(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 64, 288 * 2 + 64, 256)),
&mut buf.subdimensions((0, 64, 288 * 2 + 64, 256))?,
bg,
&Color::new(1.0, 1.0, 1.0, 1.0),
256.0,
+20 -11
View File
@@ -12,7 +12,7 @@ pub fn draw_text(
color: &Color,
size: f32,
s: &str,
) -> Result<(), ::std::io::Error> {
) -> Result<(u32, u32), ::std::io::Error> {
// Load the font
// This only succeeds if collection consists of one font
let font = Font::from_bytes(font_data as &[u8]).expect("Error constructing Font");
@@ -27,9 +27,18 @@ pub fn draw_text(
.layout(s, scale, point(0.0, v_metrics.ascent))
.collect();
let mut x_max: u32 = 0;
let mut y_max: u32 = 0;
// Loop through the glyphs in the text, positing each one on a line
for glyph in glyphs {
if let Some(bounding_box) = glyph.pixel_bounding_box() {
if bounding_box.max.x > x_max as i32 {
x_max = bounding_box.max.x as u32;
}
if bounding_box.max.y > y_max as i32 {
y_max = bounding_box.max.y as u32;
}
// Draw the glyph into the image per-pixel by using the draw closure
glyph.draw(|x, y, o| {
let x = x + bounding_box.min.x as u32;
@@ -41,12 +50,12 @@ pub fn draw_text(
} else {
o
};
buf.put((x, y), &background_color.blend(color, o));
let _ = buf.put((x, y), &background_color.blend(color, o));
});
}
}
Ok(())
Ok((x_max, y_max))
}
pub fn draw_text_fixed_width(
@@ -92,7 +101,7 @@ pub fn draw_text_fixed_width(
} else {
o
};
buf.put((x, y), &background_color.blend(color, o));
let _ = buf.put((x, y), &background_color.blend(color, o));
});
x_pos += 1;
x_off += x_dist;
@@ -107,15 +116,15 @@ pub fn draw_box(
c: &Color,
dim: (u32, u32),
) -> Result<(), ::std::io::Error> {
let mut buf = buf.subdimensions((0, 0, dim.0, dim.1));
let mut buf = buf.subdimensions((0, 0, dim.0, dim.1))?;
for x in 0..dim.0 {
buf.put((x, 0), c);
buf.put((x, dim.1 - 1), c);
let _ = buf.put((x, 0), c);
let _ = buf.put((x, dim.1 - 1), c);
}
for y in 0..dim.1 {
buf.put((0, y), c);
buf.put((dim.0 - 1, y), c);
buf.put((0, y), c)?;
buf.put((dim.0 - 1, y), c)?;
}
Ok(())
@@ -128,7 +137,7 @@ pub fn draw_bar(
height: u32,
fill: f32,
) -> Result<(), ::std::io::Error> {
let mut buf = buf.subdimensions((0, 0, length, height));
let mut buf = buf.subdimensions((0, 0, length, height))?;
let mut fill_pos = ((length as f32) * fill) as u32;
if fill_pos > length {
@@ -136,7 +145,7 @@ pub fn draw_bar(
}
for y in 0..height {
for x in 0..fill_pos {
buf.put((x, y), color);
let _ = buf.put((x, y), color);
}
}
+180
View File
@@ -0,0 +1,180 @@
use crate::buffer::Buffer;
use crate::color::Color;
use crate::draw::{draw_text, ROBOTO_REGULAR};
use crate::module::{Input, ModuleImpl};
use std::io::Read;
use atty::Stream;
use chrono::{DateTime, Local};
use smithay_client_toolkit::keyboard::keysyms;
pub struct Launcher {
options: Vec<String>,
matches: Vec<String>,
cur: String,
offset: usize,
dirty: bool
}
impl Launcher {
pub fn new() -> Result<Launcher, ::std::io::Error> {
if !atty::is(Stream::Stdin) {
let mut inbuf = String::new();
std::io::stdin().read_to_string(&mut inbuf).unwrap();
let options = inbuf.split("\n").into_iter().map(|s| s.to_string()).collect();
Ok(Launcher {
options: options,
matches: vec![],
cur: "".to_string(),
offset: 0,
dirty: true,
})
} else {
Err(::std::io::Error::new(::std::io::ErrorKind::Other, "input is a tty"))
}
}
}
impl ModuleImpl for Launcher {
fn draw(
&self,
buf: &mut Buffer,
bg: &Color,
_time: &DateTime<Local>,
) -> Result<Vec<(i32, i32, i32, i32)>, ::std::io::Error> {
buf.memset(bg);
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 128, 32))?,
bg,
&Color::new(0.5, 0.5, 0.5, 1.0),
32.0,
"run: ",
)?;
let mut x_off: i32 = 0;
let mut width_remaining: i32 = 1280 - 64;
for (idx, m) in self.matches.iter().enumerate() {
let mut b = match buf.subdimensions((64 + x_off as u32, 0, width_remaining as u32, 32)) {
Ok(b) => b,
Err(_) => break,
};
let size = if idx == self.offset && self.cur.len() > 0 {
let l = self.cur.len();
let s1 = draw_text(
ROBOTO_REGULAR,
&mut b,
bg,
&Color::new(1.0, 1.0, 1.0, 1.0),
32.0,
&m[0..l],
)?;
let mut b2 = b.subdimensions((s1.0+1, 0, width_remaining as u32 - s1.0-1, 32))?;
let s2 = draw_text(
ROBOTO_REGULAR,
&mut b2,
bg,
&Color::new(0.75, 0.75, 0.75, 1.0),
32.0,
&m[l..],
)?;
(s1.0 + s2.0 + 1, s1.1 + s2.1)
} else {
draw_text(
ROBOTO_REGULAR,
&mut b,
bg,
&Color::new(0.5, 0.5, 0.5, 1.0),
32.0,
m,
)?
};
x_off += (size.0 + 8) as i32;
width_remaining -= (size.0 + 8) as i32;
if width_remaining < 0 {
break;
}
}
// draw_text_fixed_width(
// ROBOTO_REGULAR,
// &mut buf.subdimensions((0, 64, 288 * 2 + 64, 256))?,
// bg,
// &Color::new(1.0, 1.0, 1.0, 1.0),
// 256.0,
// vec![120, 120, 64, 120, 120],
// &format!("{:02}:{:02}", time.hour(), time.minute()),
// )?;
Ok(vec![buf.get_signed_bounds()])
}
fn update(&mut self, _time: &DateTime<Local>, force: bool) -> Result<bool, ::std::io::Error> {
if self.dirty || force {
self.matches = self
.options
.iter()
.filter(|x| x.len() >= self.cur.len() && x[0..self.cur.len()] == self.cur)
.map(|x| x.to_string())
.collect();
self.matches.sort();
self.dirty = false;
Ok(true)
} else {
Ok(false)
}
}
fn input(&mut self, input: Input) {
match input {
Input::Keypress { key, interpreted } => match key {
keysyms::XKB_KEY_BackSpace => {
if self.cur.len() > 0 {
self.cur = self.cur[..self.cur.len()-1].to_string();
self.offset = 0;
self.dirty = true
}
},
keysyms::XKB_KEY_Return => {
if self.matches.len() > self.offset {
println!("{}", self.matches[self.offset]);
std::process::exit(0);
}
},
keysyms::XKB_KEY_Right => {
if self.matches.len() > 0 && self.offset < self.matches.len() - 1{
self.offset += 1;
self.dirty = true;
}
},
keysyms::XKB_KEY_Left => {
if self.matches.len() > 0 && self.offset > 0 {
self.offset -= 1;
self.dirty = true;
}
},
_ => match interpreted {
Some(v) => {
self.cur += &v;
self.offset = 0;
self.dirty = true
},
None => {}
}
}
_ => {}
}
}
}
+26 -11
View File
@@ -10,7 +10,7 @@ use os_pipe::pipe;
use chrono::{Local};
use smithay_client_toolkit::keyboard::{
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind,
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind, KeyState, keysyms,
};
use smithay_client_toolkit::utils::DoubleMemPool;
@@ -29,6 +29,7 @@ mod draw;
mod module;
mod sound;
mod battery;
mod launcher;
use crate::backlight::Backlight;
use crate::buffer::Buffer;
@@ -38,14 +39,14 @@ use crate::color::Color;
use crate::module::{Input, Module};
use crate::sound::PulseAudio;
use crate::battery::UpowerBattery;
use crate::launcher::Launcher;
enum Cmd {
Exit,
Configure,
Draw,
Input { pos: (u32, u32), input: Input },
MouseInput { pos: (u32, u32), input: Input },
KeyboardInput { input: Input },
}
struct App {
@@ -81,10 +82,10 @@ impl App {
let mut damage = vec![];
{
let mut margin_buf = buf.subdimensions((20, 20, buf_x - 40, buf_y - 40));
let mut margin_buf = buf.subdimensions((20, 20, buf_x - 40, buf_y - 40))?;
for module in self.modules.iter() {
if module.update(&time, force)? {
let mut b = &mut margin_buf.subdimensions(module.get_bounds());
let mut b = &mut margin_buf.subdimensions(module.get_bounds())?;
let mut d = module.draw(&mut b, &bg, &time)?;
damage.append(&mut d);
}
@@ -154,6 +155,10 @@ impl App {
Module::new(Box::new(Calendar::new()), (0, 384, 1280, 344)),
];
if let Ok(m) = Launcher::new() {
modules.push(Module::new(Box::new(m), (0, 712, 1280, 32)));
}
let mut vert_off = 0;
if let Ok(m) = UpowerBattery::new(tx.clone()) {
modules.push(Module::new(Box::new(m), (720, vert_off, 560, 32)));
@@ -235,8 +240,11 @@ impl App {
&seat,
KeyRepeatKind::System,
move |event: KbEvent, _| match event {
KbEvent::Key { keysym, .. } => match keysym {
0xFF1B => kbd_clone.lock().unwrap().push_back(Cmd::Exit),
KbEvent::Key { keysym, utf8, state, .. } => match state {
KeyState::Pressed => match keysym {
keysyms::XKB_KEY_Escape => kbd_clone.lock().unwrap().push_back(Cmd::Exit),
v => kbd_clone.lock().unwrap().push_back(Cmd::KeyboardInput{input: Input::Keypress{ key: v, interpreted: utf8 }}),
},
_ => (),
},
_ => (),
@@ -356,7 +364,7 @@ impl App {
}
let pos = (pos.0 - 20, pos.1 - 20);
if vert_scroll != 0.0 || horiz_scroll != 0.0 {
pointer_clone.lock().unwrap().push_back(Cmd::Input {
pointer_clone.lock().unwrap().push_back(Cmd::MouseInput {
pos: pos,
input: Input::Scroll {
pos: pos,
@@ -368,7 +376,7 @@ impl App {
horiz_scroll = 0.0;
}
if btn_clicked {
pointer_clone.lock().unwrap().push_back(Cmd::Input {
pointer_clone.lock().unwrap().push_back(Cmd::MouseInput {
pos: pos,
input: Input::Click {
pos: pos,
@@ -400,6 +408,7 @@ impl App {
}
fn main() {
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
let (tx_draw, rx_draw) = channel();
@@ -431,7 +440,7 @@ fn main() {
app.redraw(false).expect("Failed to draw");
app.flush_display();
}
Cmd::Input { pos, input } => {
Cmd::MouseInput { pos, input } => {
if let Some(m) = app.get_module(pos) {
let bounds = m.get_bounds();
let input = input.offset((bounds.0, bounds.1));
@@ -439,6 +448,12 @@ fn main() {
q.lock().unwrap().push_back(Cmd::Draw);
}
}
Cmd::KeyboardInput { input } => {
for m in app.modules.iter() {
m.input(input.clone());
}
q.lock().unwrap().push_back(Cmd::Draw);
}
Cmd::Exit => {
std::process::exit(0);
}
+3
View File
@@ -5,9 +5,11 @@ use std::sync::{Arc, Mutex};
use chrono::{DateTime, Local};
#[derive(Clone)]
pub enum Input {
Click { pos: (u32, u32), button: u32 },
Scroll { pos: (u32, u32), x: f64, y: f64 },
Keypress { key: u32, interpreted: Option<String> },
}
impl Input {
@@ -22,6 +24,7 @@ impl Input {
x: *x,
y: *y,
},
Input::Keypress { key, interpreted } => Input::Keypress { key: *key, interpreted: interpreted.clone() },
}
}
}
+5 -4
View File
@@ -442,14 +442,14 @@ impl ModuleImpl for Arc<Mutex<PulseAudio>> {
};
draw_text(
ROBOTO_REGULAR,
&mut buf.subdimensions((0, 0, 128, 24)),
&mut buf.subdimensions((0, 0, 128, 24))?,
bg,
&Color::new(1.0, 1.0, 1.0, 1.0),
24.0,
"volume",
)?;
draw_bar(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
432,
24,
@@ -461,7 +461,7 @@ impl ModuleImpl for Arc<Mutex<PulseAudio>> {
vol -= 1.0;
iter += 1.0;
draw_bar(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
432,
24,
@@ -469,7 +469,7 @@ impl ModuleImpl for Arc<Mutex<PulseAudio>> {
)?;
}
draw_box(
&mut buf.subdimensions((128, 0, 432, 24)),
&mut buf.subdimensions((128, 0, 432, 24))?,
&c,
(432, 24),
)?;
@@ -508,6 +508,7 @@ impl ModuleImpl for Arc<Mutex<PulseAudio>> {
}
_ => {}
},
_ => {}
}
}
}