More better

This commit is contained in:
Kenny Levinsen
2023-02-08 22:53:41 +01:00
parent 3c69a31030
commit 6e90b1f0e8
19 changed files with 681 additions and 511 deletions
+21 -21
View File
@@ -199,15 +199,16 @@ impl<'a> BufferView<'a> {
} }
} }
pub fn subdimensions( pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> BufferView {
&mut self,
subdimensions: (u32, u32, u32, u32),
) -> BufferView {
let bounds = self.get_bounds(); let bounds = self.get_bounds();
if cfg!(debug_assertions) && (subdimensions.0 + subdimensions.2 > bounds.2 if cfg!(debug_assertions)
|| subdimensions.1 + subdimensions.3 > bounds.3) && (subdimensions.0 + subdimensions.2 > bounds.2
|| subdimensions.1 + subdimensions.3 > bounds.3)
{ {
panic!("cannot create subdimensions larger than buffer: {:?} > {:?}", subdimensions, bounds); panic!(
"cannot create subdimensions larger than buffer: {:?} > {:?}",
subdimensions, bounds
);
} }
BufferView { BufferView {
@@ -229,7 +230,10 @@ impl<'a> BufferView<'a> {
pub fn offset(&mut self, offset: (u32, u32)) -> BufferView { pub fn offset(&mut self, offset: (u32, u32)) -> BufferView {
let bounds = self.get_bounds(); let bounds = self.get_bounds();
if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) { if cfg!(debug_assertions) && (offset.0 > bounds.2 || offset.1 > bounds.3) {
panic!("cannot create offset outside buffer: {:?} > {:?}", offset, bounds); panic!(
"cannot create offset outside buffer: {:?} > {:?}",
offset, bounds
);
} }
BufferView { BufferView {
@@ -268,19 +272,15 @@ impl<'a> BufferView<'a> {
} }
} }
pub fn put(&mut self, pos: (u32, u32), c: Color) { #[inline]
let true_pos = if let Some(subdim) = self.subdimensions { pub fn put_raw(&mut self, pos: (u32, u32), c: Color) {
if cfg!(debug_assertions) && (pos.0 >= subdim.2 || pos.1 >= subdim.3) { self.view[(pos.0 + pos.1 * self.dimensions.0) as usize] = c.0
panic!("put({:?}) is not within subdimensions of buffer ({:?})", pos, subdim); }
}
(pos.0 + subdim.0, pos.1 + subdim.1)
} else {
if cfg!(debug_assertions) && (pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1) {
panic!("put({:?}) is not within dimensions of buffer ({:?})", pos, self.dimensions);
}
pos
};
self.view[(true_pos.0 + (true_pos.1 * self.dimensions.0)) as usize] = c.0; #[inline]
pub fn put_line_raw(&mut self, pos: (u32, u32), len: u32, c: Color) {
let start = (pos.0 + (pos.1 * self.dimensions.0)) as usize;
let len = len as usize;
self.view[start..start + len].fill(c.0);
} }
} }
+24 -95
View File
@@ -1,113 +1,42 @@
//use serde::{Deserialize, Serialize};
/*
//#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
pub struct Color {
red: f32,
green: f32,
blue: f32,
opacity: f32,
}
impl Color {
pub fn new(red: f32, green: f32, blue: f32, opacity: f32) -> Color {
let (red, green, blue, opacity) = clamp(red, green, blue, opacity);
Color {
red,
green,
blue,
opacity,
}
}
pub fn blend(&self, other: &Color, ratio: f32) -> Color {
let ratio = clamp_f32(ratio, 0.0, 1.0);
Color {
red: blend_f32(self.red, other.red, ratio),
green: blend_f32(self.green, other.green, ratio),
blue: blend_f32(self.blue, other.blue, ratio),
opacity: blend_f32(self.opacity, other.opacity, ratio),
}
}
#[inline]
pub fn as_argb8888(&self) -> u32 {
((255.0 * self.opacity) as u32 & 0xFF) << 24
| ((255.0 * self.red) as u32 & 0xFF) << 16
| ((255.0 * self.green) as u32 & 0xFF) << 8
| ((255.0 * self.blue) as u32 & 0xFF)
}
#[inline]
pub fn as_integer(&self) -> IntegerColor {
IntegerColor(self.as_argb8888())
}
}
#[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)
}
*/
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Color(pub u32); pub struct Color(pub u32);
impl Color { impl Color {
pub const WHITE: Color = Color(0xFFFFFFFF); pub const WHITE: Color = Color(0xFFFFFFFF);
pub const GREY50: Color = Color(0xFF7F7F7F); pub const GREY35: Color = Color(0xFF595959);
pub const GREY75: Color = Color(0xFFBFBFBF); pub const GREY50: Color = Color(0xFF7F7F7F);
pub const GREY80: Color = Color(0xFFCCCCCC); pub const GREY75: Color = Color(0xFFBFBFBF);
pub const RED: Color = Color(0xFFFF0000); pub const GREY80: Color = Color(0xFFCCCCCC);
pub const YELLOW: Color = Color(0xFFFFFF00); pub const RED: Color = Color(0xFFFF0000);
pub const LIGHTGREEN: Color = Color(0xFF7FFF7F); pub const YELLOW: Color = Color(0xFFFFFF00);
pub const LIGHTRED: Color = Color(0xFFFF7F7F); pub const LIGHTGREEN: Color = Color(0xFF7FFF7F);
pub const LIGHTORANGE: Color = Color(0xFFFFBF00); pub const LIGHTORANGE: Color = Color(0xFFFFBF00);
pub const DARKORANGE: Color = Color(0xFFFF7F00); pub const DARKORANGE: Color = Color(0xFFFF7F00);
pub const BUFF: Color = Color(0xFFFFBF7F); pub const BUFF: Color = Color(0xFFFFBF7F);
#[allow(unused)] #[allow(unused)]
pub fn new(red: u8, green: u8, blue: u8, opacity: u8) -> Color { pub fn new(red: u8, green: u8, blue: u8, opacity: u8) -> Color {
Color((opacity as u32) << 24 | (red as u32) << 16 | (green as u32) << 8 | (blue as u32)) Color((opacity as u32) << 24 | (red as u32) << 16 | (green as u32) << 8 | (blue as u32))
} }
fn red(self) -> u8 {((self.0 >> 16) & 0xFF) as u8 } fn red(self) -> u8 {
fn green(self) -> u8 {((self.0 >> 8) & 0xFF) as u8 } ((self.0 >> 16) & 0xFF) as u8
fn blue(self) -> u8 {(self.0 & 0xFF) as u8 } }
fn green(self) -> u8 {
((self.0 >> 8) & 0xFF) as u8
}
fn blue(self) -> u8 {
(self.0 & 0xFF) as u8
}
pub fn alpha(self, alpha: f32) -> Color { pub fn alpha(self, alpha: f32) -> Color {
unsafe { unsafe {
Color( Color(
(255. * alpha).to_int_unchecked::<u32>() << 24 | (255. * alpha).to_int_unchecked::<u32>() << 24
(self.red() as f32 * alpha).to_int_unchecked::<u32>() << 16 | | (self.red() as f32 * alpha).to_int_unchecked::<u32>() << 16
(self.green() as f32 * alpha).to_int_unchecked::<u32>() << 8 | | (self.green() as f32 * alpha).to_int_unchecked::<u32>() << 8
(self.blue() as f32 * alpha).to_int_unchecked::<u32>()) | (self.blue() as f32 * alpha).to_int_unchecked::<u32>(),
)
} }
} }
} }
+18 -18
View File
@@ -21,7 +21,6 @@ impl CachedGlyph {
if let Some(bounding_box) = glyph.pixel_bounding_box() { if let Some(bounding_box) = glyph.pixel_bounding_box() {
let origin = (bounding_box.min.x, bounding_box.min.y); let origin = (bounding_box.min.x, bounding_box.min.y);
let dimensions = ( let dimensions = (
(bounding_box.max.x - bounding_box.min.x) as u32, (bounding_box.max.x - bounding_box.min.x) as u32,
(bounding_box.max.y - bounding_box.min.y) as u32, (bounding_box.max.y - bounding_box.min.y) as u32,
@@ -50,13 +49,15 @@ impl CachedGlyph {
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), c: Color) { fn draw(&self, buf: &mut BufferView, pos: (i32, i32), c: Color) {
let mut x = 0; let mut x = 0;
let mut y = 0; let mut y = 0;
let bounds = buf.get_bounds();
let offset = (bounds.0 as i32, bounds.1 as i32);
for v in &self.render { for v in &self.render {
let _ = buf.put( buf.put_raw(
( (
(x + pos.0 + self.origin.0) as u32, (x + pos.0 + self.origin.0 + offset.0) as u32,
(y + pos.1 + self.origin.1) as u32, (y + pos.1 + self.origin.1 + offset.1) as u32,
), ),
c.alpha(*v) c.alpha(*v),
); );
if x == self.dimensions.0 as i32 - 1 { if x == self.dimensions.0 as i32 - 1 {
@@ -180,8 +181,9 @@ impl<'a> Font<'a> {
height: u32, height: u32,
) -> Result<(), ::std::io::Error> { ) -> Result<(), ::std::io::Error> {
// draw cursor // draw cursor
for i in 1..height { let bounds = buf.get_bounds();
buf.put((offset, i), c); for i in bounds.1 + 1..height + bounds.1 {
buf.put_raw((bounds.0 + offset, i), c);
} }
Ok(()) Ok(())
} }
@@ -305,13 +307,12 @@ impl<'a> Font<'a> {
} }
pub fn draw_box(buf: &mut BufferView, c: Color, dim: (u32, u32)) -> Result<(), ::std::io::Error> { pub fn draw_box(buf: &mut BufferView, c: Color, dim: (u32, u32)) -> Result<(), ::std::io::Error> {
for x in 0..dim.0 { let bounds = buf.get_bounds();
buf.put((x, 0), c); buf.put_line_raw((bounds.0, bounds.1), dim.0, c);
buf.put((x, dim.1 - 1), c); buf.put_line_raw((bounds.0, bounds.1 + dim.1 - 1), dim.0, c);
} for y in bounds.1..dim.1 + bounds.1 {
for y in 0..dim.1 { buf.put_raw((bounds.0, y), c);
buf.put((0, y), c); buf.put_raw((bounds.0 + dim.0 - 1, y), c);
buf.put((dim.0 - 1, y), c);
} }
Ok(()) Ok(())
@@ -328,10 +329,9 @@ pub fn draw_bar(
if fill_pos > length { if fill_pos > length {
fill_pos = length; fill_pos = length;
} }
for y in 0..height { let bounds = buf.get_bounds();
for x in 0..fill_pos { for y in bounds.1..height + bounds.1 {
let _ = buf.put((x, y), color); buf.put_line_raw((bounds.0, y), fill_pos, color);
}
} }
Ok(()) Ok(())
-1
View File
@@ -58,4 +58,3 @@ impl Events {
self.events.drain(..).collect() self.events.drain(..).collect()
} }
} }
+9 -11
View File
@@ -3,15 +3,7 @@
use crate::draw; use crate::draw;
use rusttype::Font; use rusttype::Font;
use std::{ use std::{
cell::RefCell, cell::RefCell, collections::HashMap, fs::File, hash, io::Read, mem, path::Path, rc::Rc, thread,
collections::HashMap,
fs::File,
hash,
io::Read,
mem,
path::Path,
rc::Rc,
thread,
}; };
/// FontRef is used to store Fonts on widgets. /// FontRef is used to store Fonts on widgets.
@@ -24,7 +16,12 @@ mod fc {
/// Given a string, it matches it to a font file and returns its path. /// Given a string, it matches it to a font file and returns its path.
pub(crate) fn from_string(name: &str) -> String { pub(crate) fn from_string(name: &str) -> String {
let fc = FontConfig::new().unwrap(); let fc = FontConfig::new().unwrap();
fc.find(name, None).unwrap().path.to_str().unwrap().to_string() fc.find(name, None)
.unwrap()
.path
.to_str()
.unwrap()
.to_string()
} }
} }
@@ -98,7 +95,8 @@ impl FontMap {
match self.required_fonts.get_mut(font_name) { match self.required_fonts.get_mut(font_name) {
Some(v) => v.1.push((size, preload)), Some(v) => v.1.push((size, preload)),
None => { None => {
self.required_fonts.insert(font_name, (font_name, vec![(size, preload)])); self.required_fonts
.insert(font_name, (font_name, vec![(size, preload)]));
} }
} }
} }
+4 -1
View File
@@ -45,7 +45,10 @@ pub struct Keyboard {
impl Keyboard { impl Keyboard {
pub fn new() -> Keyboard { pub fn new() -> Keyboard {
Keyboard { state: None, fd: None, } Keyboard {
state: None,
fd: None,
}
} }
pub fn keymap(&mut self, format: WEnum<wl_keyboard::KeymapFormat>, fd: OwnedFd, size: u32) { pub fn keymap(&mut self, format: WEnum<wl_keyboard::KeymapFormat>, fd: OwnedFd, size: u32) {
+39 -29
View File
@@ -1,12 +1,12 @@
mod buffer; mod buffer;
mod color; mod color;
mod draw; mod draw;
mod event;
mod fonts; mod fonts;
mod keyboard; mod keyboard;
mod state; mod state;
mod utils; mod utils;
mod widgets; mod widgets;
mod event;
use wayland_client::{Connection, QueueHandle, WaylandSource}; use wayland_client::{Connection, QueueHandle, WaylandSource};
@@ -17,19 +17,15 @@ use calloop::{
use chrono::{Duration, Local, Timelike}; use chrono::{Duration, Local, Timelike};
use buffer::BufferView; use buffer::BufferView;
use fonts::{FontMap, MaybeFontMap};
use state::{State, OperationMode};
use event::{Event, Events}; use event::{Event, Events};
use fonts::{FontMap, MaybeFontMap};
use state::{OperationMode, State};
use widgets::{ use widgets::{
PulseAudio, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget, Layout, Interface, InvertedHorizontalLayout, Layout, Line, Margin, PulseAudio, VerticalLayout, Widget,
}; };
use std::{ use std::{env, rc::Rc, thread};
env,
rc::Rc,
thread
};
enum UIVersion { enum UIVersion {
V1, V1,
@@ -52,7 +48,7 @@ fn main() {
(Some(w), Some(h)) => mode = OperationMode::LayerSurface((w, h)), (Some(w), Some(h)) => mode = OperationMode::LayerSurface((w, h)),
_ => panic!("invalid arguments"), _ => panic!("invalid arguments"),
} }
}, }
Some(ref s) if s == "xdg_shell" => mode = OperationMode::XdgToplevel, Some(ref s) if s == "xdg_shell" => mode = OperationMode::XdgToplevel,
Some(ref s) if s == "v1" => version = UIVersion::V1, Some(ref s) if s == "v1" => version = UIVersion::V1,
Some(ref s) if s == "v2" => version = UIVersion::V2, Some(ref s) if s == "v2" => version = UIVersion::V2,
@@ -120,27 +116,31 @@ fn main() {
let mut fm = FontMap::new(); let mut fm = FontMap::new();
// TODO: Cache in a file // TODO: Cache in a file
fm.add_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf".to_string()); fm.add_font_path(
fm.add_font_path("monospace", "/usr/share/fonts/noto/NotoSansMono-Regular.ttf".to_string()); "sans",
"/usr/share/fonts/noto/NotoSans-Regular.ttf".to_string(),
);
fm.add_font_path(
"monospace",
"/usr/share/fonts/noto/NotoSansMono-Regular.ttf".to_string(),
);
let (widgets, layout): (Vec<Box<dyn Widget>>, Rc<Box<dyn Layout>>) = match version { let (widgets, layout): (Vec<Box<dyn Widget>>, Rc<Box<dyn Layout>>) = match version {
UIVersion::V1 => { UIVersion::V1 => {
let clock = Box::new(Clock::new(&mut fm, "sans", 256.)); let clock = Box::new(Clock::new(&mut fm, "sans", 256.));
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 18.0, -1, 1)); let calendar = Box::new(Calendar::new(&mut fm, "monospace", "sans", 36.0, 3, 1));
let date = Box::new(Date::new(&mut fm, "sans", 48.)); let date = Box::new(Date::new(&mut fm, "sans", 48.));
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.)); let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.)); let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.)); let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.)); let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.));
let v: Vec<Box<dyn Widget>> = vec![clock, date, battery, backlight, audio, calendar, launcher]; let v: Vec<Box<dyn Widget>> =
vec![clock, date, battery, backlight, audio, calendar, launcher];
let l = Rc::new(Margin::new( let l = Rc::new(Margin::new(
VerticalLayout::new(vec![ VerticalLayout::new(vec![
HorizontalLayout::new(vec![ HorizontalLayout::new(vec![
VerticalLayout::new(vec![ VerticalLayout::new(vec![IndexedLayout::new(1), IndexedLayout::new(0)]),
IndexedLayout::new(1),
IndexedLayout::new(0),
]),
Margin::new( Margin::new(
VerticalLayout::new(vec![ VerticalLayout::new(vec![
Margin::new(IndexedLayout::new(2), (0, 0, 0, 8)), Margin::new(IndexedLayout::new(2), (0, 0, 0, 8)),
@@ -152,20 +152,23 @@ fn main() {
]), ]),
IndexedLayout::new(5), IndexedLayout::new(5),
IndexedLayout::new(6), IndexedLayout::new(6),
]), (20, 20, 20, 20)) ]),
); (20, 20, 20, 20),
));
(v, l) (v, l)
} }
UIVersion::V2 => { UIVersion::V2 => {
let clock = Box::new(Clock::new(&mut fm, "sans", 128.)); let clock = Box::new(Clock::new(&mut fm, "sans", 128.));
let calendar = Box::new(Calendar::new(&mut fm, "monospace", 12.0, 1, -1)); let calendar = Box::new(Calendar::new(&mut fm, "monospace", "sans", 24.0, 1, -1));
let date = Box::new(Date::new(&mut fm, "sans", 48.)); let date = Box::new(Date::new(&mut fm, "sans", 48.));
let line = Box::new(Line::new(1)); let line = Box::new(Line::new(1));
let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.)); let launcher = Box::new(Interface::new(events.clone(), &mut fm, "monospace", 32.));
let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.)); let battery = Box::new(Battery::new(events.clone(), &mut fm, "sans", 24.));
let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.)); let backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.)); let audio = Box::new(PulseAudio::new(events.clone(), &mut fm, "sans", 24.));
let v: Vec<Box<dyn Widget>> = vec![clock, date, battery, backlight, audio, line, calendar, launcher]; let v: Vec<Box<dyn Widget>> = vec![
clock, date, battery, backlight, audio, line, calendar, launcher,
];
let l = Rc::new(VerticalLayout::new(vec![ let l = Rc::new(VerticalLayout::new(vec![
HorizontalLayout::new(vec![ HorizontalLayout::new(vec![
IndexedLayout::new(0), IndexedLayout::new(0),
@@ -186,11 +189,18 @@ fn main() {
let font_thread = thread::Builder::new() let font_thread = thread::Builder::new()
.name("fontloader".to_string()) .name("fontloader".to_string())
.spawn(move || { .spawn(move || {
fm.load_fonts(); fm.load_fonts();
fm fm
}).unwrap(); })
.unwrap();
let mut state = State::new(mode, widgets, layout, MaybeFontMap::Waiting(font_thread), events); let mut state = State::new(
mode,
widgets,
layout,
MaybeFontMap::Waiting(font_thread),
events,
);
let mut damage = Vec::new(); let mut damage = Vec::new();
for _ in 0..state.widgets.len() { for _ in 0..state.widgets.len() {
+112 -64
View File
@@ -1,43 +1,39 @@
use std::{ use std::{
cmp::max,
default::Default,
env, env,
process::exit, process::exit,
rc::Rc, rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
default::Default,
}; };
use wayland_client::{ use wayland_client::{
protocol::{ protocol::{
wl_buffer, wl_compositor, wl_subcompositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm,
wl_surface, wl_subsurface, wl_pointer, wl_shm_pool, wl_subcompositor, wl_subsurface, wl_surface,
}, },
Connection, Dispatch, QueueHandle, WEnum, Connection, Dispatch, QueueHandle, WEnum,
}; };
use wayland_protocols::{ use wayland_protocols::{
wp::{
single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1,
viewporter::client::{wp_viewport, wp_viewporter},
},
xdg::{ xdg::{
activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1}, activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1},
shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}, shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base},
}, },
wp::{
single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1,
viewporter::client::{
wp_viewport,
wp_viewporter,
},
},
}; };
use wayland_protocols_wlr::layer_shell::v1::client::{ use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
zwlr_layer_shell_v1, zwlr_layer_surface_v1,
};
use crate::{ use crate::{
buffer::BufferManager, buffer::BufferManager,
event::{Event, Events, PointerButton, PointerEvent},
fonts::{FontMap, MaybeFontMap}, fonts::{FontMap, MaybeFontMap},
keyboard::Keyboard, keyboard::Keyboard,
widgets::{Geometry, Layout, Widget, WidgetUpdater}, widgets::{Geometry, Layout, Widget, WidgetUpdater},
event::{Event, Events, PointerEvent, PointerButton},
}; };
#[derive(Debug)] #[derive(Debug)]
@@ -127,7 +123,10 @@ impl State {
Ok(token) => token, Ok(token) => token,
Err(_) => return, Err(_) => return,
}; };
match (&self.main_surface.wl_surface, &self.protocols.xdg_activation) { match (
&self.main_surface.wl_surface,
&self.protocols.xdg_activation,
) {
(Some(surface), Some(activation)) => { (Some(surface), Some(activation)) => {
activation.activate(key, surface); activation.activate(key, surface);
let activation_token = activation.get_activation_token(qh, ()); let activation_token = activation.get_activation_token(qh, ());
@@ -148,6 +147,10 @@ impl WidgetUpdater for State {
) -> Geometry { ) -> Geometry {
self.widgets[idx].geometry_update(fonts, geometry) self.widgets[idx].geometry_update(fonts, geometry)
} }
fn minimum_size(&mut self, idx: usize, fonts: &mut FontMap) -> Geometry {
self.widgets[idx].minimum_size(fonts)
}
} }
impl Dispatch<wl_registry::WlRegistry, ()> for State { impl Dispatch<wl_registry::WlRegistry, ()> for State {
@@ -182,30 +185,34 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
let subsurface = subcompositor.get_subsurface(child, parent, qh, ()); let subsurface = subcompositor.get_subsurface(child, parent, qh, ());
subsurface.place_below(parent); subsurface.place_below(parent);
state.bg_surface.subsurface = Some(subsurface); state.bg_surface.subsurface = Some(subsurface);
}, }
_ => todo!("handle early subcompositor creation"), _ => todo!("handle early subcompositor creation"),
} }
} }
"wl_shm" => { "wl_shm" => {
state.protocols.wl_shm = Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ())); state.protocols.wl_shm =
Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
} }
"wl_seat" => { "wl_seat" => {
registry.bind::<wl_seat::WlSeat, _, _>(name, 8, qh, ()); registry.bind::<wl_seat::WlSeat, _, _>(name, 8, qh, ());
} }
"xdg_wm_base" => if let OperationMode::XdgToplevel = state.mode { "xdg_wm_base" => {
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 2, qh, ()); if let OperationMode::XdgToplevel = state.mode {
let wm_base =
registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 2, qh, ());
match &state.main_surface.wl_surface { match &state.main_surface.wl_surface {
Some(surface) => { Some(surface) => {
let xdg_surface = wm_base.get_xdg_surface(surface, qh, ()); let xdg_surface = wm_base.get_xdg_surface(surface, qh, ());
let toplevel = xdg_surface.get_toplevel(qh, ()); let toplevel = xdg_surface.get_toplevel(qh, ());
toplevel.set_title("wldash".into()); toplevel.set_title("wldash".into());
surface.commit(); surface.commit();
state.main_surface.xdg_surface = Some((xdg_surface, toplevel)); state.main_surface.xdg_surface = Some((xdg_surface, toplevel));
}
_ => todo!("handle early xdg_shell creation"),
} }
_ => todo!("handle early xdg_shell creation"),
} }
} }
"xdg_activation_v1" => { "xdg_activation_v1" => {
@@ -214,41 +221,63 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
); );
state.activate(qh); state.activate(qh);
} }
"zwlr_layer_shell_v1" => if let OperationMode::LayerSurface(size) = state.mode { "zwlr_layer_shell_v1" => {
let layer_shell = registry.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ()); if let OperationMode::LayerSurface(size) = state.mode {
match &state.main_surface.wl_surface { let layer_shell = registry
Some(surface) => { .bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ());
let layer_surface = layer_shell.get_layer_surface(surface, None, zwlr_layer_shell_v1::Layer::Top, "launcher".to_string(), qh, ()); state.fonts.resolve();
layer_surface.set_keyboard_interactivity(zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive); let fonts = state.fonts.unwrap();
layer_surface.set_size(size.0, size.1); let layout = state.layout.clone();
let min_size = layout.minimum_size(&mut fonts.borrow_mut(), state);
match &state.main_surface.wl_surface {
Some(surface) => {
let layer_surface = layer_shell.get_layer_surface(
surface,
None,
zwlr_layer_shell_v1::Layer::Top,
"launcher".to_string(),
qh,
(),
);
layer_surface.set_keyboard_interactivity(
zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive,
);
layer_surface.set_size(
max(size.0, min_size.width),
max(size.1, min_size.height),
);
surface.commit(); surface.commit();
state.main_surface.layer_surface = Some(layer_surface); state.main_surface.layer_surface = Some(layer_surface);
}
_ => todo!("handle early layer_shell creation"),
} }
_ => todo!("handle early layer_shell creation"),
} }
}, }
"wp_viewporter" => { "wp_viewporter" => {
let viewporter = registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ()); let viewporter =
registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ());
match &state.bg_surface.wl_surface { match &state.bg_surface.wl_surface {
Some(surface) => { Some(surface) => {
state.bg_surface.viewport = Some(viewporter.get_viewport(surface, qh, ())); state.bg_surface.viewport =
}, Some(viewporter.get_viewport(surface, qh, ()));
}
_ => todo!("handle early viewporter creation"), _ => todo!("handle early viewporter creation"),
} }
state.protocols.viewporter = Some(viewporter); state.protocols.viewporter = Some(viewporter);
}, }
"wp_single_pixel_buffer_manager_v1" => { "wp_single_pixel_buffer_manager_v1" => {
let singlepixel = registry.bind::<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, _, _>(name, 1, qh, ()); let singlepixel = registry.bind::<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, _, _>(name, 1, qh, ());
match &state.bg_surface.wl_surface { match &state.bg_surface.wl_surface {
Some(surface) => { Some(surface) => {
let buffer = singlepixel.create_u32_rgba_buffer(0, 0, 0, 0xFFFFFFFF, qh, ()); let buffer =
singlepixel.create_u32_rgba_buffer(0, 0, 0, 0xFFFFFFFF, qh, ());
surface.attach(Some(&buffer), 0, 0); surface.attach(Some(&buffer), 0, 0);
surface.damage_buffer(0, 0, 1, 1); surface.damage_buffer(0, 0, 1, 1);
}, }
_ => todo!("handle early single_pixel_buffer creation"), _ => todo!("handle early single_pixel_buffer creation"),
} }
}, }
_ => {} _ => {}
} }
} }
@@ -352,7 +381,8 @@ impl Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, ()> for State {
_: &(), _: &(),
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) {} ) {
}
} }
impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State { impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
@@ -364,7 +394,12 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) { ) {
if let zwlr_layer_surface_v1::Event::Configure { serial, width, height } = event { if let zwlr_layer_surface_v1::Event::Configure {
serial,
width,
height,
} = event
{
if (width, height) == (0, 0) { if (width, height) == (0, 0) {
return; return;
} }
@@ -397,7 +432,7 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
(Some(surface), Some(viewport)) => { (Some(surface), Some(viewport)) => {
viewport.set_destination(dim.0, dim.1); viewport.set_destination(dim.0, dim.1);
surface.commit(); surface.commit();
}, }
_ => todo!("handle early layer shell creation"), _ => todo!("handle early layer shell creation"),
} }
} }
@@ -577,20 +612,30 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) { ) {
match event { match event {
wl_pointer::Event::Enter { surface_x, surface_y, .. } => { wl_pointer::Event::Enter {
surface_x,
surface_y,
..
} => {
state.pointer = Some((surface_x, surface_y)); state.pointer = Some((surface_x, surface_y));
}, }
wl_pointer::Event::Motion { surface_x, surface_y, .. } => { wl_pointer::Event::Motion {
surface_x,
surface_y,
..
} => {
state.pointer = Some((surface_x, surface_y)); state.pointer = Some((surface_x, surface_y));
}, }
wl_pointer::Event::Leave { .. } => { wl_pointer::Event::Leave { .. } => state.pointer = None,
state.pointer = None wl_pointer::Event::Axis { axis, value, .. } => match state.pointer {
},
wl_pointer::Event::Axis { axis, value, .. } => match state.pointer {
Some((x, y)) => { Some((x, y)) => {
let axis = match axis { let axis = match axis {
WEnum::Value(wl_pointer::Axis::VerticalScroll) => PointerButton::ScrollVertical(value), WEnum::Value(wl_pointer::Axis::VerticalScroll) => {
WEnum::Value(wl_pointer::Axis::HorizontalScroll) => PointerButton::ScrollHorizontal(value), PointerButton::ScrollVertical(value)
}
WEnum::Value(wl_pointer::Axis::HorizontalScroll) => {
PointerButton::ScrollHorizontal(value)
}
_ => return, _ => return,
}; };
let pos = (x as u32, y as u32); let pos = (x as u32, y as u32);
@@ -598,7 +643,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
let geo = widget.geometry(); let geo = widget.geometry();
if geo.contains(pos) { if geo.contains(pos) {
let pos = (pos.0 - geo.x, pos.1 - geo.y); let pos = (pos.0 - geo.x, pos.1 - geo.y);
let ev = Event::PointerEvent(PointerEvent{ let ev = Event::PointerEvent(PointerEvent {
button: axis, button: axis,
pos: pos, pos: pos,
}); });
@@ -607,10 +652,14 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
break; break;
} }
} }
}, }
_ => (), _ => (),
}, },
wl_pointer::Event::Button { button, state: button_state, .. } => match (button, button_state, state.pointer) { wl_pointer::Event::Button {
button,
state: button_state,
..
} => match (button, button_state, state.pointer) {
(button, WEnum::Value(wl_pointer::ButtonState::Pressed), Some((x, y))) => { (button, WEnum::Value(wl_pointer::ButtonState::Pressed), Some((x, y))) => {
let button = match button { let button = match button {
BTN_LEFT => PointerButton::Left, BTN_LEFT => PointerButton::Left,
@@ -622,9 +671,8 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
for widget in state.widgets.iter_mut() { for widget in state.widgets.iter_mut() {
let geo = widget.geometry(); let geo = widget.geometry();
if geo.contains(pos) { if geo.contains(pos) {
let pos = (pos.0 - geo.x, pos.1 - geo.y); let pos = (pos.0 - geo.x, pos.1 - geo.y);
let ev = Event::PointerEvent(PointerEvent{ let ev = Event::PointerEvent(PointerEvent {
button: button, button: button,
pos: pos, pos: pos,
}); });
@@ -633,7 +681,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
break; break;
} }
} }
}, }
_ => (), _ => (),
}, },
_ => (), _ => (),
+18 -6
View File
@@ -4,9 +4,9 @@ use crate::{
buffer::BufferView, buffer::BufferView,
color::Color, color::Color,
draw::{draw_bar, draw_box}, draw::{draw_bar, draw_box},
event::{Event, PointerButton},
fonts::FontMap, fonts::FontMap,
widgets::{Geometry, Widget}, widgets::{Geometry, Widget},
event::{Event, PointerButton},
}; };
pub trait BarWidgetImpl { pub trait BarWidgetImpl {
@@ -27,7 +27,12 @@ pub struct BarWidget {
} }
impl BarWidget { impl BarWidget {
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget { pub fn new(
inner_widget: Box<dyn BarWidgetImpl>,
fm: &mut FontMap,
font: &'static str,
size: f32,
) -> BarWidget {
fm.queue_font(font, size, inner_widget.name()); fm.queue_font(font, size, inner_widget.name());
BarWidget { BarWidget {
geometry: Default::default(), geometry: Default::default(),
@@ -51,8 +56,7 @@ impl Widget for BarWidget {
let font = fonts.get_font(self.font, self.size); let font = fonts.get_font(self.font, self.size);
let fg = Color::WHITE; let fg = Color::WHITE;
font.draw_text(view, fg, self.inner_widget.name()) font.draw_text(view, fg, self.inner_widget.name()).unwrap();
.unwrap();
let size = self.size.ceil() as u32; let size = self.size.ceil() as u32;
let bar_offset = 4 * size; let bar_offset = 4 * size;
let val = self.inner_widget.value(); let val = self.inner_widget.value();
@@ -91,6 +95,15 @@ impl Widget for BarWidget {
self.geometry self.geometry
} }
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
Geometry {
x: 0,
y: 0,
width: self.size.ceil() as u32 * 6,
height: self.size.ceil() as u32,
}
}
fn event(&mut self, event: &Event) { fn event(&mut self, event: &Event) {
match event { match event {
Event::PointerEvent(ev) => { Event::PointerEvent(ev) => {
@@ -99,9 +112,8 @@ impl Widget for BarWidget {
let val = (ev.pos.0 - offset) as f32 / (self.geometry.width - offset) as f32; let val = (ev.pos.0 - offset) as f32 / (self.geometry.width - offset) as f32;
self.inner_widget.click(val, ev.button); self.inner_widget.click(val, ev.button);
} }
}, }
_ => (), _ => (),
} }
} }
} }
+29 -25
View File
@@ -11,18 +11,33 @@ use dbus::blocking::{
use crate::{ use crate::{
color::Color, color::Color,
fonts::FontMap,
event::{Event, Events}, event::{Event, Events},
fonts::FontMap,
widgets::bar_widget::{BarWidget, BarWidgetImpl}, widgets::bar_widget::{BarWidget, BarWidgetImpl},
}; };
enum UpowerBatteryState { enum UpowerBatteryState {
Unknown,
Charging, Charging,
Discharging, Discharging,
Empty, Empty,
Full, FullyCharged,
NotCharging, PendingCharge,
Unknown, PendingDischarge,
}
impl UpowerBatteryState {
fn from_dbus(val: u64) -> UpowerBatteryState {
match val {
1 => UpowerBatteryState::Charging,
2 => UpowerBatteryState::Discharging,
3 => UpowerBatteryState::Empty,
4 => UpowerBatteryState::FullyCharged,
5 => UpowerBatteryState::PendingCharge,
6 => UpowerBatteryState::PendingDischarge,
_ => UpowerBatteryState::Unknown,
}
}
} }
struct InnerBattery { struct InnerBattery {
@@ -53,15 +68,7 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
{ {
let mut inner = inner.lock().unwrap(); let mut inner = inner.lock().unwrap();
inner.value = capacity as f32 / 100.; inner.value = capacity as f32 / 100.;
inner.state = match state { inner.state = UpowerBatteryState::from_dbus(state as u64);
1 => UpowerBatteryState::Charging,
2 => UpowerBatteryState::Discharging,
3 => UpowerBatteryState::Empty,
4 => UpowerBatteryState::Full,
5 => UpowerBatteryState::NotCharging,
6 => UpowerBatteryState::Discharging,
_ => UpowerBatteryState::Unknown,
}
} }
proxy proxy
@@ -76,15 +83,8 @@ fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
for (key, value) in c.changed_properties { for (key, value) in c.changed_properties {
match key.as_str() { match key.as_str() {
"State" => { "State" => {
inner.state = match value.0.as_u64().unwrap() { inner.state =
1 => UpowerBatteryState::Charging, UpowerBatteryState::from_dbus(value.0.as_u64().unwrap());
2 => UpowerBatteryState::Discharging,
3 => UpowerBatteryState::Empty,
4 => UpowerBatteryState::Full,
5 => UpowerBatteryState::NotCharging,
6 => UpowerBatteryState::Discharging,
_ => UpowerBatteryState::Unknown,
};
inner.dirty = true; inner.dirty = true;
let mut events = events.lock().unwrap(); let mut events = events.lock().unwrap();
events.add_event(Event::PowerUpdate); events.add_event(Event::PowerUpdate);
@@ -115,7 +115,12 @@ pub struct Battery {
} }
impl Battery { impl Battery {
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget { pub fn new(
events: Arc<Mutex<Events>>,
fm: &mut FontMap,
font: &'static str,
size: f32,
) -> BarWidget {
let battery = Battery { let battery = Battery {
inner: Arc::new(Mutex::new(InnerBattery { inner: Arc::new(Mutex::new(InnerBattery {
value: 0., value: 0.,
@@ -143,8 +148,7 @@ impl BarWidgetImpl for Battery {
fn color(&self) -> Color { fn color(&self) -> Color {
let inner = self.inner.lock().unwrap(); let inner = self.inner.lock().unwrap();
match inner.state { match inner.state {
UpowerBatteryState::Charging | UpowerBatteryState::Full => Color::LIGHTGREEN, UpowerBatteryState::Charging | UpowerBatteryState::FullyCharged => Color::LIGHTGREEN,
UpowerBatteryState::NotCharging => Color::LIGHTRED,
_ if inner.value > 0.25 => Color::WHITE, _ if inner.value > 0.25 => Color::WHITE,
_ if inner.value > 0.1 => Color::DARKORANGE, _ if inner.value > 0.1 => Color::DARKORANGE,
_ => Color::RED, _ => Color::RED,
+163 -108
View File
@@ -3,8 +3,8 @@ use std::default::Default;
use crate::{ use crate::{
buffer::BufferView, buffer::BufferView,
color::Color, color::Color,
fonts::FontMap,
event::Event, event::Event,
fonts::FontMap,
widgets::{Geometry, Widget}, widgets::{Geometry, Widget},
}; };
@@ -12,6 +12,7 @@ use chrono::{Datelike, Local, NaiveDate};
pub struct Calendar { pub struct Calendar {
font: &'static str, font: &'static str,
month_font: &'static str,
sections_x: i32, sections_x: i32,
sections_y: i32, sections_y: i32,
shown_sections_x: u32, shown_sections_x: u32,
@@ -19,22 +20,35 @@ pub struct Calendar {
size: f32, size: f32,
dirty: bool, dirty: bool,
geometry: Geometry, geometry: Geometry,
year_width: u32,
date_width: u32,
day_width: u32,
} }
const DAY_FACTOR: f32 = 1.; const DAY_FACTOR: f32 = 0.6;
const YEAR_FACTOR: f32 = 1.5; const YEAR_FACTOR: f32 = 0.75;
const MONTH_FACTOR: f32 = 2.; const MONTH_FACTOR: f32 = 1.25;
const DATE_FACTOR: f32 = 2.; const DATE_FACTOR: f32 = 1.;
const LINE_HEIGHT: f32 = 1.8;
const LINE_HEIGHT: f32 = 0.85;
impl Calendar { impl Calendar {
pub fn new(fm: &mut FontMap, font: &'static str, size: f32, sections_x: i32, sections_y: i32) -> Calendar { pub fn new(
fm.queue_font(font, size, "ADEFHIMNORSTUW"); fm: &mut FontMap,
fm.queue_font(font, size * 1.5, "0123456789"); font: &'static str,
fm.queue_font(font, size * 2.0, "0123456789 ADFJMOSabcehgilmnoprstuvy"); month_font: &'static str,
size: f32,
sections_x: i32,
sections_y: i32,
) -> Calendar {
fm.queue_font(font, size * DAY_FACTOR, "ADEFHIMNORSTUW");
fm.queue_font(font, size * YEAR_FACTOR, "0123456789");
fm.queue_font(font, size * DATE_FACTOR, "0123456789");
fm.queue_font(month_font, size * MONTH_FACTOR, "ADFJMOSabcehgilmnoprstuvy");
Calendar { Calendar {
font, font,
month_font,
size, size,
sections_x, sections_x,
sections_y, sections_y,
@@ -42,6 +56,9 @@ impl Calendar {
shown_sections_y: 0, shown_sections_y: 0,
dirty: true, dirty: true,
geometry: Default::default(), geometry: Default::default(),
date_width: 0,
day_width: 0,
year_width: 0,
} }
} }
@@ -52,39 +69,33 @@ impl Calendar {
orig: NaiveDate, orig: NaiveDate,
mut time: NaiveDate, mut time: NaiveDate,
) { ) {
let white = Color::WHITE; let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
let dim = Color::GREY80;
let dimmer = Color::GREY75;
let mut y_off = 1;
// TODO: Fix offsets:
// - Headline font is not correctly accounted for
// //
// Draw the week day // Draw the week day
// //
let day_offset = (self.date_width - self.day_width) / 2;
let date_offset = self.date_width + self.date_width / 2;
for idx in 1..8 { for idx in 1..8 {
let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR); let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR);
let wk_chr = match idx { let (wk_chr, c) = match idx {
1 => "MON", 1 => ("MON", Color::WHITE),
2 => "TUE", 2 => ("TUE", Color::WHITE),
3 => "WED", 3 => ("WED", Color::WHITE),
4 => "THU", 4 => ("THU", Color::WHITE),
5 => "FRI", 5 => ("FRI", Color::WHITE),
6 => "SAT", 6 => ("SAT", Color::GREY80),
7 => "SUN", 7 => ("SUN", Color::GREY80),
_ => panic!("impossible value"), _ => panic!("impossible value"),
}; };
day_font day_font
.draw_text( .draw_text(
&mut view &mut view.offset((
.offset(( idx * date_offset + day_offset,
idx * (self.size * 2.5).ceil() as u32 + (self.size / 5.).ceil() as u32, (self.size * MONTH_FACTOR).ceil() as u32
y_off * (self.size * LINE_HEIGHT).ceil() as u32 + (self.size * DAY_FACTOR * 0.2).ceil() as u32,
+ (self.size * 1.).ceil() as u32, )),
)), c,
white,
&wk_chr, &wk_chr,
) )
.unwrap(); .unwrap();
@@ -93,18 +104,7 @@ impl Calendar {
// //
// Draw the month // Draw the month
// //
if time.year() != orig.year() { let month_font = fonts.get_font(self.month_font, self.size * MONTH_FACTOR);
let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
year_font
.draw_text(
&mut view.offset(((self.size * 17.).ceil() as u32, 0)),
dim,
&format!("{:}", time.year()),
)
.unwrap();
}
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
let month_str = match time.month() { let month_str = match time.month() {
1 => "January", 1 => "January",
2 => "February", 2 => "February",
@@ -120,59 +120,62 @@ impl Calendar {
12 => "December", 12 => "December",
_ => panic!("impossible value"), _ => panic!("impossible value"),
}; };
cal_font month_font
.draw_text(&mut view, white, month_str) .draw_text(&mut view, Color::WHITE, month_str)
.unwrap(); .unwrap();
let mut done = false; //
while !done { // Draw the year
let mut x_pos = 0; //
if time.year() != orig.year() {
// let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
// Find the start of this week year_font
// .draw_text(
let mut wkday = time.weekday(); &mut view.offset((cal_width - self.year_width, 0)),
while wkday != chrono::Weekday::Mon { Color::GREY80,
x_pos += 1; &format!("{:}", time.year()),
wkday = wkday.pred(); )
} .unwrap();
}
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
'row: for y_off in 1.. {
// //
// Draw the week number // Draw the week number
// //
let wk = time.iso_week(); let wk = time.iso_week();
cal_font cal_font
.draw_text( .draw_text(
&mut view &mut view.offset((
.offset(( 0,
0, y_off * (self.size * LINE_HEIGHT).ceil() as u32
y_off * (self.size * LINE_HEIGHT).ceil() as u32 + (self.size * MONTH_FACTOR).ceil() as u32,
+ (self.size * MONTH_FACTOR).ceil() as u32, )),
)), Color::GREY75,
dimmer,
&format!("{:02}", wk.week()), &format!("{:02}", wk.week()),
) )
.unwrap(); .unwrap();
x_pos += 1;
// //
// Draw the dates // Draw the dates
// //
while x_pos < 8 { let x_off = time.weekday().number_from_monday();
for x_pos in x_off..8 {
let c = if time.day() == orig.day() && time.month() == orig.month() { let c = if time.day() == orig.day() && time.month() == orig.month() {
Color::WHITE Color::WHITE
} else { } else if x_pos < 6 {
Color::GREY50 Color::GREY50
} else {
Color::GREY35
}; };
cal_font cal_font
.draw_text( .draw_text(
&mut view &mut view.offset((
.offset(( x_pos * date_offset,
x_pos * (self.size * 2.5).ceil() as u32, y_off * (self.size * LINE_HEIGHT).ceil() as u32
y_off * (self.size * LINE_HEIGHT).ceil() as u32 + (self.size * MONTH_FACTOR).ceil() as u32,
+ (self.size * MONTH_FACTOR).ceil() as u32, )),
)),
c, c,
&format!("{:02}", time.day()), &format!("{:02}", time.day()),
) )
@@ -180,14 +183,10 @@ impl Calendar {
let t = time.with_day(time.day() + 1); let t = time.with_day(time.day() + 1);
if t.is_none() { if t.is_none() {
done = true; break 'row;
break;
} }
time = t.unwrap(); time = t.unwrap();
x_pos += 1;
} }
y_off += 1;
} }
} }
} }
@@ -222,9 +221,10 @@ impl<'a> Widget for Calendar {
let time = Local::now().naive_local().date(); let time = Local::now().naive_local().date();
let cal_height = (self.size * 16.25).ceil() as u32; let cal_height =
let cal_width = (7. * self.size * 2.5 + self.size * 2.).ceil() as u32; (self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
let cal_pad = (3. * self.size).ceil() as u32; let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
let cal_pad = self.date_width * 2;
let mut t = time.with_day(1).unwrap(); let mut t = time.with_day(1).unwrap();
let cals = self.shown_sections_y * self.shown_sections_x; let cals = self.shown_sections_y * self.shown_sections_x;
@@ -236,8 +236,7 @@ impl<'a> Widget for Calendar {
for idx in 0..self.shown_sections_x { for idx in 0..self.shown_sections_x {
self.draw_month( self.draw_month(
fonts, fonts,
&mut view &mut view.offset(((cal_width + cal_pad) * idx, cal_height * ydx)),
.offset(((cal_width + cal_pad) * idx, (cal_height) * ydx)),
time, time,
t, t,
); );
@@ -252,35 +251,91 @@ impl<'a> Widget for Calendar {
self.geometry self.geometry
} }
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry { fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
let cal_width = 7 * (self.size * 2.5).ceil() as u32 + (self.size * 2.).ceil() as u32; let year_font = fonts.get_font(self.font, self.size * YEAR_FACTOR);
let cal_height = (self.size * MONTH_FACTOR).ceil() as u32 self.year_width = year_font.auto_widest("0123456789").unwrap() * 4;
+ (self.size * LINE_HEIGHT * 8.).ceil() as u32; let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
let cal_pad = (self.size * 3.).ceil() as u32; self.date_width = cal_font.auto_widest("0123456789").unwrap() * 2;
let day_font = fonts.get_font(self.font, self.size * DAY_FACTOR);
self.day_width = day_font.auto_widest("ADEFHIMNORSTUW").unwrap() * 3;
let possible_sections_x = geometry.width / (cal_width + cal_pad); let cal_width = 8 * self.date_width + 7 * (self.date_width / 2);
let possible_sections_y = geometry.height / cal_height; let cal_height =
(self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
let cal_pad = self.date_width * 2;
if geometry.width < cal_width || geometry.height < cal_height {
self.geometry = Default::default();
return self.geometry;
}
let possible_sections_x = 1 + (geometry.width - cal_width) / (cal_width + cal_pad);
let possible_sections_y = 1 + (geometry.height - cal_height) / cal_height;
self.shown_sections_x =
if self.sections_x > 0 && self.sections_x < possible_sections_x as i32 {
self.sections_x as u32
} else {
possible_sections_x
};
self.shown_sections_y =
if self.sections_y > 0 && self.sections_y < possible_sections_y as i32 {
self.sections_y as u32
} else {
possible_sections_y
};
let width = if self.sections_x > 0 && self.sections_x < possible_sections_x as i32 {
self.shown_sections_x = self.sections_x as u32;
cal_width * self.sections_x as u32 + cal_pad * (self.sections_x as u32 - 1)
} else {
self.shown_sections_x = possible_sections_x;
(geometry.width / (cal_width + cal_pad)) * (cal_width + cal_pad)
};
let height = if self.sections_y > 0 && self.sections_y < possible_sections_y as i32 {
self.shown_sections_y = self.sections_y as u32;
cal_height * self.sections_y as u32
} else {
self.shown_sections_y = possible_sections_y;
(geometry.height / cal_height) * cal_height
};
self.geometry = Geometry { self.geometry = Geometry {
x: geometry.x, x: geometry.x,
y: geometry.y, y: geometry.y,
width: width, width: cal_width * self.shown_sections_x as u32
height: height, + cal_pad * (self.shown_sections_x as u32 - 1),
height: cal_height * self.shown_sections_y as u32,
}; };
self.geometry self.geometry
} }
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
let cal_font = fonts.get_font(self.font, self.size * DATE_FACTOR);
let date_width = cal_font.auto_widest("0123456789").unwrap() * 2;
let cal_width = 8 * date_width + 7 * (date_width / 2);
let cal_height =
(self.size * MONTH_FACTOR).ceil() as u32 + (self.size * LINE_HEIGHT * 8.).ceil() as u32;
let cal_pad = date_width * 2;
let sections_x = match self.sections_x {
-1 => 1,
0 => {
return Geometry {
x: 0,
y: 0,
width: 0,
height: 0,
}
}
x => x,
};
let sections_y = match self.sections_y {
-1 => 1,
0 => {
return Geometry {
x: 0,
y: 0,
width: 0,
height: 0,
}
}
y => y,
};
let width = cal_width * sections_x as u32 + cal_pad * (sections_x as u32 - 1);
let height = cal_height * sections_y as u32;
Geometry {
x: 0,
y: 0,
width: width,
height: height,
}
}
} }
+13 -1
View File
@@ -3,8 +3,8 @@ use std::default::Default;
use crate::{ use crate::{
buffer::BufferView, buffer::BufferView,
color::Color, color::Color,
fonts::FontMap,
event::Event, event::Event,
fonts::FontMap,
widgets::{Geometry, Widget}, widgets::{Geometry, Widget},
}; };
@@ -81,4 +81,16 @@ impl<'a> Widget for Clock {
}; };
self.geometry self.geometry
} }
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
let font = fonts.get_font(self.font, self.size);
let digit_width = font.auto_widest("0123456789").unwrap();
let colon_width = font.auto_widest(":").unwrap();
Geometry {
x: 0,
y: 0,
width: digit_width * 4 + colon_width,
height: self.size.ceil() as u32,
}
}
} }
+12 -1
View File
@@ -3,8 +3,8 @@ use std::default::Default;
use crate::{ use crate::{
buffer::BufferView, buffer::BufferView,
color::Color, color::Color,
fonts::FontMap,
event::Event, event::Event,
fonts::FontMap,
widgets::{Geometry, Widget}, widgets::{Geometry, Widget},
}; };
@@ -78,4 +78,15 @@ impl<'a> Widget for Date {
}; };
self.geometry self.geometry
} }
fn minimum_size(&mut self, fonts: &mut FontMap) -> Geometry {
let width = (3. + 2. + 2. + 2. + 4.) * self.size / 2.;
let font = fonts.get_font(self.font, self.size);
Geometry {
x: 0,
y: 0,
width: width.ceil() as u32,
height: font.height().ceil() as u32,
}
}
} }
+35 -24
View File
@@ -1,10 +1,10 @@
use std::{ use std::{
cmp::{max, min, Ordering}, cmp::{max, min, Ordering},
collections::HashMap, collections::HashMap,
env,
io::Write,
fs::{read_to_string, File},
default::Default, default::Default,
env,
fs::{read_to_string, File},
io::Write,
process::{exit, Command}, process::{exit, Command},
sync::{Arc, Mutex}, sync::{Arc, Mutex},
thread, thread,
@@ -13,9 +13,9 @@ use std::{
use crate::{ use crate::{
buffer::BufferView, buffer::BufferView,
color::Color, color::Color,
event::{Event, Events, PointerButton, PointerEvent},
fonts::FontMap, fonts::FontMap,
keyboard::{keysyms, KeyEvent}, keyboard::{keysyms, KeyEvent},
event::{Event, Events, PointerEvent, PointerButton},
utils::desktop::{load_desktop_files, Desktop}, utils::desktop::{load_desktop_files, Desktop},
widgets::{Geometry, Widget}, widgets::{Geometry, Widget},
}; };
@@ -312,8 +312,7 @@ impl InterfaceWidget for Launcher {
) )
.unwrap(); .unwrap();
font.auto_draw_text(&mut prompt_line, fg, ">") font.auto_draw_text(&mut prompt_line, fg, ">").unwrap();
.unwrap();
// Draw entries // Draw entries
let dimfg = Color::GREY50; let dimfg = Color::GREY50;
@@ -348,8 +347,7 @@ impl InterfaceWidget for Launcher {
} else { } else {
x_max = max( x_max = max(
x_max, x_max,
font.auto_draw_text(&mut line, dimfg, &m.name) font.auto_draw_text(&mut line, dimfg, &m.name).unwrap(),
.unwrap(),
); );
} }
} }
@@ -452,10 +450,7 @@ impl Calc {
}) })
.unwrap(); .unwrap();
Calc{ Calc { old, result: None }
old,
result: None,
}
} }
fn sync(&self) { fn sync(&self) {
@@ -521,18 +516,18 @@ impl InterfaceWidget for Calc {
// Draw prompt // Draw prompt
let font = fonts.get_font(intf.font, intf.size); let font = fonts.get_font(intf.font, intf.size);
font font.auto_draw_text_with_cursor(
.auto_draw_text_with_cursor( &mut prompt_line,
&mut prompt_line, fg,
fg, &format!(" {} ", &intf.prompt.input),
&format!(" {} ", &intf.prompt.input), intf.prompt.cursor + 3,
intf.prompt.cursor + 3, )
) .unwrap();
.unwrap();
font.auto_draw_text(&mut prompt_line, Color::BUFF, "=") font.auto_draw_text(&mut prompt_line, Color::BUFF, "=")
.unwrap(); .unwrap();
prompt_offset -= 16;
prompt_offset -= line_height; prompt_offset -= line_height;
if let Some(res) = &self.result { if let Some(res) = &self.result {
let c = if intf.selection == 0 { let c = if intf.selection == 0 {
@@ -555,7 +550,8 @@ impl InterfaceWidget for Calc {
}; };
prompt_offset -= line_height; prompt_offset -= line_height;
let mut result_line = view.offset((0, prompt_offset)); let mut result_line = view.offset((0, prompt_offset));
font.auto_draw_text(&mut result_line, c, &format!("{} = {}", input, res)).unwrap(); font.auto_draw_text(&mut result_line, c, &format!("{} = {}", input, res))
.unwrap();
} }
let content_height = min( let content_height = min(
@@ -588,9 +584,15 @@ pub struct Interface {
} }
impl Interface { impl Interface {
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> Interface { pub fn new(
events: Arc<Mutex<Events>>,
fm: &mut FontMap,
font: &'static str,
size: f32,
) -> Interface {
fm.queue_font( fm.queue_font(
font, size, font,
size,
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 >=!,.-/()", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 >=!,.-/()",
); );
@@ -708,6 +710,15 @@ impl Widget for Interface {
self.inner.geometry self.inner.geometry
} }
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
Geometry {
x: 0,
y: 0,
width: 256,
height: (self.inner.size.ceil() as u32) * 4 + 16,
}
}
fn event(&mut self, event: &Event) { fn event(&mut self, event: &Event) {
match event { match event {
Event::KeyEvent(e) => self.keyboard_input(e), Event::KeyEvent(e) => self.keyboard_input(e),
@@ -715,7 +726,7 @@ impl Widget for Interface {
Event::LauncherUpdate => { Event::LauncherUpdate => {
self.inner.dirty = true; self.inner.dirty = true;
self.launcher.update(&self.inner); self.launcher.update(&self.inner);
}, }
Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()), Event::TokenUpdate(t) => self.launcher.next_token = Some(t.to_string()),
_ => (), _ => (),
} }
+66 -5
View File
@@ -1,10 +1,6 @@
use std::cmp::max; use std::cmp::max;
use crate::{ use crate::{fonts::FontMap, state::State, widgets::Geometry};
fonts::FontMap,
state::State,
widgets::{Geometry},
};
pub trait Layout { pub trait Layout {
fn geometry_update( fn geometry_update(
@@ -13,6 +9,8 @@ pub trait Layout {
geometry: &Geometry, geometry: &Geometry,
state: &mut State, state: &mut State,
) -> Geometry; ) -> Geometry;
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry;
} }
pub struct HorizontalLayout { pub struct HorizontalLayout {
@@ -46,6 +44,22 @@ impl Layout for HorizontalLayout {
geo.height = max_height; geo.height = max_height;
geo geo
} }
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
let mut max_width = 0;
let mut max_height = 0;
for w in self.widgets.iter() {
let result = w.minimum_size(fonts, state);
max_width += result.x + result.width;
max_height = max(result.y + result.height, max_height);
}
Geometry {
width: max_width,
height: max_height,
x: 0,
y: 0,
}
}
} }
pub struct VerticalLayout { pub struct VerticalLayout {
@@ -79,11 +93,28 @@ impl Layout for VerticalLayout {
geo.height = max_height; geo.height = max_height;
geo geo
} }
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
let mut max_width = 0;
let mut max_height = 0;
for w in self.widgets.iter() {
let result = w.minimum_size(fonts, state);
max_width = max(result.x + result.width, max_width);
max_height += result.y + result.height;
}
Geometry {
width: max_width,
height: max_height,
x: 0,
y: 0,
}
}
} }
pub trait WidgetUpdater { pub trait WidgetUpdater {
fn geometry_update(&mut self, idx: usize, fonts: &mut FontMap, geometry: &Geometry) fn geometry_update(&mut self, idx: usize, fonts: &mut FontMap, geometry: &Geometry)
-> Geometry; -> Geometry;
fn minimum_size(&mut self, idx: usize, fonts: &mut FontMap) -> Geometry;
} }
pub struct IndexedLayout { pub struct IndexedLayout {
@@ -105,6 +136,10 @@ impl Layout for IndexedLayout {
) -> Geometry { ) -> Geometry {
state.geometry_update(self.widget_idx, fonts, geometry) state.geometry_update(self.widget_idx, fonts, geometry)
} }
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
state.minimum_size(self.widget_idx, fonts)
}
} }
pub struct Margin { pub struct Margin {
@@ -139,6 +174,16 @@ impl Layout for Margin {
height: out.height + self.margin.1 + self.margin.3, height: out.height + self.margin.1 + self.margin.3,
} }
} }
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
let size = self.widget.minimum_size(fonts, state);
Geometry {
width: size.x + size.width + self.margin.0 + self.margin.2,
height: size.y + size.height + self.margin.1 + self.margin.3,
x: 0,
y: 0,
}
}
} }
pub struct InvertedHorizontalLayout { pub struct InvertedHorizontalLayout {
@@ -171,4 +216,20 @@ impl Layout for InvertedHorizontalLayout {
geo.height = max_height; geo.height = max_height;
geo geo
} }
fn minimum_size(&self, fonts: &mut FontMap, state: &mut State) -> Geometry {
let mut max_width = 0;
let mut max_height = 0;
for w in self.widgets.iter() {
let result = w.minimum_size(fonts, state);
max_width += result.x + result.width;
max_height = max(result.y + result.height, max_height);
}
Geometry {
width: max_width,
height: max_height,
x: 0,
y: 0,
}
}
} }
+12 -1
View File
@@ -14,7 +14,7 @@ pub struct Line {
impl Line { impl Line {
pub fn new(thickness: u32) -> Line { pub fn new(thickness: u32) -> Line {
Line{ Line {
geometry: Default::default(), geometry: Default::default(),
thickness, thickness,
} }
@@ -25,10 +25,12 @@ impl Widget for Line {
fn geometry(&self) -> Geometry { fn geometry(&self) -> Geometry {
self.geometry self.geometry
} }
fn draw(&mut self, _fonts: &mut FontMap, view: &mut BufferView) -> Geometry { fn draw(&mut self, _fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
view.memset(Color::WHITE); view.memset(Color::WHITE);
self.geometry self.geometry
} }
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry { fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
self.geometry = Geometry { self.geometry = Geometry {
x: geometry.x, x: geometry.x,
@@ -38,4 +40,13 @@ impl Widget for Line {
}; };
self.geometry self.geometry
} }
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
Geometry {
x: 0,
y: 0,
width: 0,
height: self.thickness,
}
}
} }
+8 -5
View File
@@ -1,5 +1,4 @@
//mod alsaaudio; //mod alsaaudio;
mod pulseaudio;
mod backlight; mod backlight;
mod bar_widget; mod bar_widget;
mod battery; mod battery;
@@ -7,18 +6,22 @@ mod calendar;
mod clock; mod clock;
mod date; mod date;
mod launcher; mod launcher;
mod line;
mod widget;
mod layout; mod layout;
mod line;
mod pulseaudio;
mod widget;
//pub use alsaaudio::AlsaAudio; //pub use alsaaudio::AlsaAudio;
pub use pulseaudio::PulseAudio;
pub use backlight::Backlight; pub use backlight::Backlight;
pub use battery::Battery; pub use battery::Battery;
pub use calendar::Calendar; pub use calendar::Calendar;
pub use clock::Clock; pub use clock::Clock;
pub use date::Date; pub use date::Date;
pub use launcher::Interface; pub use launcher::Interface;
pub use layout::{
HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin, VerticalLayout,
WidgetUpdater,
};
pub use line::Line; pub use line::Line;
pub use layout::{VerticalLayout, HorizontalLayout, IndexedLayout, InvertedHorizontalLayout, Layout, Margin, WidgetUpdater}; pub use pulseaudio::PulseAudio;
pub use widget::{Geometry, Widget}; pub use widget::{Geometry, Widget};
+90 -87
View File
@@ -1,16 +1,13 @@
use std::{ use std::{
cell::RefCell,
error::Error,
os::fd::RawFd,
rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
thread, thread,
error::Error,
rc::Rc,
cell::RefCell,
os::fd::RawFd,
}; };
use nix::unistd::{ use nix::unistd::{pipe, read, write};
pipe, write, read,
};
use crate::{ use crate::{
color::Color, color::Color,
@@ -21,22 +18,19 @@ use crate::{
use libpulse_binding::volume::ChannelVolumes; use libpulse_binding::volume::ChannelVolumes;
fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) -> Result<(), Box<dyn Error>> { fn monitor(
events: Arc<Mutex<Events>>,
inner: Arc<Mutex<InnerAudio>>,
pipe: RawFd,
) -> Result<(), Box<dyn Error>> {
use libpulse_binding::{ use libpulse_binding::{
mainloop::{
self,
standard::{
IterateResult,
},
api::Mainloop,
events::io::FlagSet as IoFlagSet,
},
callbacks::ListResult, callbacks::ListResult,
context::{ context::{
Context, subscribe::{Facility, InterestMaskSet},
FlagSet, Context, FlagSet, State,
subscribe::{InterestMaskSet, Facility}, },
State, mainloop::{
self, api::Mainloop, events::io::FlagSet as IoFlagSet, standard::IterateResult,
}, },
proplist::{properties, Proplist}, proplist::{properties, Proplist},
volume::Volume, volume::Volume,
@@ -48,7 +42,9 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
.unwrap(); .unwrap();
let mut mainloop = mainloop::standard::Mainloop::new().unwrap(); let mut mainloop = mainloop::standard::Mainloop::new().unwrap();
let context = Rc::new(RefCell::new(Context::new_with_proplist(&mainloop, "wldash_context", &proplist).unwrap())); let context = Rc::new(RefCell::new(
Context::new_with_proplist(&mainloop, "wldash_context", &proplist).unwrap(),
));
context.borrow_mut().connect(None, FlagSet::NOFLAGS, None)?; context.borrow_mut().connect(None, FlagSet::NOFLAGS, None)?;
loop { loop {
@@ -63,33 +59,31 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
let local_context = context.clone(); let local_context = context.clone();
let local_inner = inner.clone(); let local_inner = inner.clone();
let local_events = events.clone(); let local_events = events.clone();
context context.borrow_mut().set_subscribe_callback(Some(Box::new(
.borrow_mut() move |facility, _operation, index| match facility {
.set_subscribe_callback(Some(Box::new(move |facility, _operation, index| { Some(Facility::Sink) => {
match facility { let introspector = local_context.borrow_mut().introspect();
Some(Facility::Sink) => { let inner = local_inner.clone();
let introspector = local_context.borrow_mut().introspect(); let events = local_events.clone();
let inner = local_inner.clone(); introspector.get_sink_info_by_index(index, move |res| match res {
let events = local_events.clone(); ListResult::End | ListResult::Error => (),
introspector.get_sink_info_by_index(index, move |res| { ListResult::Item(sink_info) => {
match res { if let Some(_) = &sink_info.name {
ListResult::End | ListResult::Error => (), let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name { let mut inner = inner.lock().unwrap();
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32; inner.volume = avg;
let mut inner = inner.lock().unwrap(); inner.mute = sink_info.mute;
inner.volume = avg; inner.dirty = true;
inner.mute = sink_info.mute; drop(inner);
inner.dirty = true; let mut events = events.lock().unwrap();
drop(inner); events.add_event(Event::AudioUpdate);
let mut events = events.lock().unwrap();
events.add_event(Event::AudioUpdate);
},
} }
}); }
}, });
_ => (),
} }
}))); _ => (),
},
)));
context context
.borrow_mut() .borrow_mut()
@@ -97,10 +91,10 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
let introspector = context.borrow_mut().introspect(); let introspector = context.borrow_mut().introspect();
let local_inner = inner.clone(); let local_inner = inner.clone();
introspector.get_sink_info_by_name("@DEFAULT_SINK@", move |res| { introspector.get_sink_info_by_name("@DEFAULT_SINK@", move |res| match res {
match res { ListResult::End | ListResult::Error => (),
ListResult::End | ListResult::Error => (), ListResult::Item(sink_info) => {
ListResult::Item(sink_info) => if let Some(_) = &sink_info.name { if let Some(_) = &sink_info.name {
let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32; let avg = sink_info.volume.avg().0 as f32 / Volume::NORMAL.0 as f32;
let mut inner = local_inner.lock().unwrap(); let mut inner = local_inner.lock().unwrap();
inner.volume = avg; inner.volume = avg;
@@ -110,46 +104,50 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
drop(inner); drop(inner);
let mut events = events.lock().unwrap(); let mut events = events.lock().unwrap();
events.add_event(Event::AudioUpdate); events.add_event(Event::AudioUpdate);
}, }
} }
}); });
drop(introspector); drop(introspector);
let local_context = context.clone(); let local_context = context.clone();
let local_inner = inner.clone(); let local_inner = inner.clone();
let event_source = mainloop.new_io_event(pipe as i32, IoFlagSet::INPUT, Box::new(move |_, _, _| { let event_source = mainloop.new_io_event(
let mut buf = [0; 8]; pipe as i32,
_ = read(pipe, &mut buf); IoFlagSet::INPUT,
Box::new(move |_, _, _| {
let mut buf = [0; 8];
_ = read(pipe, &mut buf);
let mut inner = local_inner.lock().unwrap(); let mut inner = local_inner.lock().unwrap();
let mut introspector = local_context.borrow_mut().introspect(); let mut introspector = local_context.borrow_mut().introspect();
match inner.last_click.take() { match inner.last_click.take() {
Some(Change::Volume(volume)) => { Some(Change::Volume(volume)) => {
// do something // do something
let mut vol = inner.channel_volume.unwrap(); let mut vol = inner.channel_volume.unwrap();
vol.scale(Volume((volume * Volume::NORMAL.0 as f32).round() as u32)); vol.scale(Volume((volume * Volume::NORMAL.0 as f32).round() as u32));
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None); introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
},
Some(Change::VolumeInc(value)) => {
let mut vol = inner.channel_volume.unwrap();
// apply step to volumes
let step = (value * Volume::NORMAL.0 as f32).round() as i32;
if step > 0 {
vol.inc_clamp(Volume(step as u32), Volume::NORMAL);
} else {
vol.decrease(Volume(-step as u32));
} }
// HACK: It would be better to only update the volume from feedback, but axis Some(Change::VolumeInc(value)) => {
// events fire fast and require the last set volume immediately for reference. let mut vol = inner.channel_volume.unwrap();
inner.channel_volume = Some(vol); // apply step to volumes
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None); let step = (value * Volume::NORMAL.0 as f32).round() as i32;
}, if step > 0 {
Some(Change::ToggleMute) => { vol.inc_clamp(Volume(step as u32), Volume::NORMAL);
introspector.set_sink_mute_by_name("@DEFAULT_SINK@", !inner.mute, None); } else {
}, vol.decrease(Volume(-step as u32));
None => (), }
} // HACK: It would be better to only update the volume from feedback, but axis
})); // events fire fast and require the last set volume immediately for reference.
inner.channel_volume = Some(vol);
introspector.set_sink_volume_by_name("@DEFAULT_SINK@", &vol, None);
}
Some(Change::ToggleMute) => {
introspector.set_sink_mute_by_name("@DEFAULT_SINK@", !inner.mute, None);
}
None => (),
}
}),
);
loop { loop {
match mainloop.iterate(true) { match mainloop.iterate(true) {
@@ -167,7 +165,7 @@ fn monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawF
fn start_monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) { fn start_monitor(events: Arc<Mutex<Events>>, inner: Arc<Mutex<InnerAudio>>, pipe: RawFd) {
thread::Builder::new() thread::Builder::new()
.name("audiomon".to_string()) .name("audiomon".to_string())
.spawn(move || { monitor(events, inner, pipe).unwrap() }) .spawn(move || monitor(events, inner, pipe).unwrap())
.unwrap(); .unwrap();
} }
@@ -191,10 +189,15 @@ pub struct PulseAudio {
} }
impl PulseAudio { impl PulseAudio {
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget { pub fn new(
events: Arc<Mutex<Events>>,
fm: &mut FontMap,
font: &'static str,
size: f32,
) -> BarWidget {
let (a, b) = pipe().unwrap(); let (a, b) = pipe().unwrap();
let audio = PulseAudio { let audio = PulseAudio {
inner: Arc::new(Mutex::new(InnerAudio{ inner: Arc::new(Mutex::new(InnerAudio {
volume: 0.0, volume: 0.0,
channel_volume: None, channel_volume: None,
mute: false, mute: false,
@@ -229,7 +232,7 @@ impl BarWidgetImpl for PulseAudio {
fn click(&mut self, pos: f32, btn: PointerButton) { fn click(&mut self, pos: f32, btn: PointerButton) {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.last_click = match btn { inner.last_click = match btn {
PointerButton::Left => Some(Change::Volume(pos)), PointerButton::Left => Some(Change::Volume(pos)),
PointerButton::Right => Some(Change::ToggleMute), PointerButton::Right => Some(Change::ToggleMute),
PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)), PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)),
PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)), PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)),
+8 -8
View File
@@ -3,11 +3,7 @@ use std::{
fmt, fmt,
}; };
use crate::{ use crate::{buffer::BufferView, event::Event, fonts::FontMap};
buffer::BufferView,
fonts::FontMap,
event::Event,
};
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
pub struct Geometry { pub struct Geometry {
@@ -49,8 +45,10 @@ impl Geometry {
} }
pub fn contains(&self, position: (u32, u32)) -> bool { pub fn contains(&self, position: (u32, u32)) -> bool {
position.0 >= self.x && position.0 < self.x + self.width && position.0 >= self.x
position.1 >= self.y && position.1 < self.y + self.height && position.0 < self.x + self.width
&& position.1 >= self.y
&& position.1 < self.y + self.height
} }
} }
@@ -60,7 +58,9 @@ pub trait Widget {
} }
fn geometry(&self) -> Geometry; fn geometry(&self) -> Geometry;
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry; fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry;
fn minimum_size(&mut self, _fonts: &mut FontMap) -> Geometry {
Default::default()
}
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry; fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry;
fn event(&mut self, _event: &Event) {} fn event(&mut self, _event: &Event) {}
} }