Moar speed
This commit is contained in:
+15
-16
@@ -244,31 +244,30 @@ impl<'a> BufferView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limit(&mut self, dimensions: (u32, u32)) -> BufferView {
|
||||
let bounds = self.get_bounds();
|
||||
if cfg!(debug_assertions) && (dimensions.0 > bounds.2 || dimensions.1 > bounds.3) {
|
||||
panic!("cannot create offset outside buffer: {:?} > {:?}", dimensions, bounds);
|
||||
}
|
||||
|
||||
BufferView {
|
||||
view: self.view,
|
||||
dimensions: self.dimensions,
|
||||
subdimensions: Some((bounds.0, bounds.1, dimensions.0, dimensions.1)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memset(&mut self, c: Color) {
|
||||
if let Some(subdim) = self.subdimensions {
|
||||
for y in subdim.1..(subdim.1 + subdim.3) {
|
||||
for x in subdim.0..(subdim.0 + subdim.2) {
|
||||
self.view[(x + y * self.dimensions.0) as usize] = c.0;
|
||||
}
|
||||
let start = (subdim.0 + y * self.dimensions.0) as usize;
|
||||
let end = start + subdim.2 as usize;
|
||||
self.view[start..end].fill(c.0);
|
||||
}
|
||||
} else {
|
||||
self.view.fill(c.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
if let Some(subdim) = self.subdimensions {
|
||||
for y in subdim.1..(subdim.1 + subdim.3) {
|
||||
let start = (subdim.0 + y * self.dimensions.0) as usize;
|
||||
let end = start + subdim.2 as usize;
|
||||
self.view[start..end].fill(0x0);
|
||||
}
|
||||
} else {
|
||||
self.view.fill(0x0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put(&mut self, pos: (u32, u32), c: Color) {
|
||||
let true_pos = if let Some(subdim) = self.subdimensions {
|
||||
if cfg!(debug_assertions) && (pos.0 >= subdim.2 || pos.1 >= subdim.3) {
|
||||
|
||||
+8
-15
@@ -75,18 +75,11 @@ fn blend_f32(a: f32, b: f32, r: f32) -> f32 {
|
||||
a + ((b - a) * r)
|
||||
}
|
||||
*/
|
||||
#[inline]
|
||||
fn blend_u8(a: u8, b: u8, r: f32) -> u32 {
|
||||
let af = a as f32;
|
||||
let bf = b as f32;
|
||||
(af + ((bf - af) * r)) as u32
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Color(pub u32);
|
||||
|
||||
impl Color {
|
||||
pub const BLACK: Color = Color(0xFF000000);
|
||||
pub const WHITE: Color = Color(0xFFFFFFFF);
|
||||
pub const GREY50: Color = Color(0xFF7F7F7F);
|
||||
pub const GREY75: Color = Color(0xFFBFBFBF);
|
||||
@@ -104,17 +97,17 @@ impl Color {
|
||||
Color((opacity as u32) << 24 | (red as u32) << 16 | (green as u32) << 8 | (blue as u32))
|
||||
}
|
||||
|
||||
fn opacity(self) -> u8 {((self.0 >> 24) & 0xFF) as u8 }
|
||||
fn red(self) -> u8 {((self.0 >> 16) & 0xFF) as u8 }
|
||||
fn green(self) -> u8 {((self.0 >> 8) & 0xFF) as u8 }
|
||||
fn blue(self) -> u8 {(self.0 & 0xFF) as u8 }
|
||||
|
||||
pub fn blend(self, other: Color, ratio: f32) -> Color {
|
||||
Color(
|
||||
blend_u8(self.opacity(), other.opacity(), ratio) << 24 |
|
||||
blend_u8(self.red(), other.red(), ratio) << 16 |
|
||||
blend_u8(self.green(), other.green(), ratio) << 8 |
|
||||
blend_u8(self.blue(), other.blue(), ratio)
|
||||
)
|
||||
pub fn alpha(self, alpha: f32) -> Color {
|
||||
unsafe {
|
||||
Color(
|
||||
(255. * alpha).to_int_unchecked::<u32>() << 24 |
|
||||
(self.red() as f32 * alpha).to_int_unchecked::<u32>() << 16 |
|
||||
(self.green() as f32 * alpha).to_int_unchecked::<u32>() << 8 |
|
||||
(self.blue() as f32 * alpha).to_int_unchecked::<u32>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-16
@@ -47,7 +47,7 @@ impl CachedGlyph {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), bg: Color, c: Color) {
|
||||
fn draw(&self, buf: &mut BufferView, pos: (i32, i32), c: Color) {
|
||||
let mut x = 0;
|
||||
let mut y = 0;
|
||||
for v in &self.render {
|
||||
@@ -56,7 +56,7 @@ impl CachedGlyph {
|
||||
(x + pos.0 + self.origin.0) as u32,
|
||||
(y + pos.1 + self.origin.1) as u32,
|
||||
),
|
||||
bg.blend(c, *v),
|
||||
c.alpha(*v)
|
||||
);
|
||||
|
||||
if x == self.dimensions.0 as i32 - 1 {
|
||||
@@ -102,7 +102,6 @@ impl<'a> Font<'a> {
|
||||
pub fn draw_text(
|
||||
&self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
c: Color,
|
||||
s: &str,
|
||||
) -> Result<(u32, u32), ::std::io::Error> {
|
||||
@@ -125,7 +124,7 @@ impl<'a> Font<'a> {
|
||||
}
|
||||
}
|
||||
for glyph in glyphs {
|
||||
glyph.draw(buf, (x_off, -off), bg, c);
|
||||
glyph.draw(buf, (x_off, -off), c);
|
||||
x_off += glyph.advance;
|
||||
}
|
||||
|
||||
@@ -135,7 +134,6 @@ impl<'a> Font<'a> {
|
||||
pub fn draw_text_with_cursor(
|
||||
&self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
c: Color,
|
||||
s: &str,
|
||||
cursor: usize,
|
||||
@@ -164,7 +162,7 @@ impl<'a> Font<'a> {
|
||||
if i == cursor {
|
||||
self.draw_cursor(buf, c, x_off as u32, height)?;
|
||||
}
|
||||
glyph.draw(buf, (x_off, -off), bg, c);
|
||||
glyph.draw(buf, (x_off, -off), c);
|
||||
x_off += glyph.advance;
|
||||
}
|
||||
if cursor == glyphs.len() {
|
||||
@@ -212,30 +210,27 @@ impl<'a> Font<'a> {
|
||||
pub fn auto_draw_text(
|
||||
&mut self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
c: Color,
|
||||
s: &str,
|
||||
) -> Result<(u32, u32), ::std::io::Error> {
|
||||
self.add_str_to_cache(s);
|
||||
self.draw_text(buf, bg, c, s)
|
||||
self.draw_text(buf, c, s)
|
||||
}
|
||||
|
||||
pub fn auto_draw_text_with_cursor(
|
||||
&mut self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
c: Color,
|
||||
s: &str,
|
||||
cursor: usize,
|
||||
) -> Result<(u32, u32), ::std::io::Error> {
|
||||
self.add_str_to_cache(s);
|
||||
self.draw_text_with_cursor(buf, bg, c, s, cursor)
|
||||
self.draw_text_with_cursor(buf, c, s, cursor)
|
||||
}
|
||||
|
||||
pub fn draw_text_fixed_width(
|
||||
&self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
c: Color,
|
||||
distances: &[u32],
|
||||
s: &str,
|
||||
@@ -259,7 +254,7 @@ impl<'a> Font<'a> {
|
||||
}
|
||||
}
|
||||
for (idx, glyph) in glyphs.into_iter().enumerate() {
|
||||
glyph.draw(buf, (x_off, -off), bg, c);
|
||||
glyph.draw(buf, (x_off, -off), c);
|
||||
x_off += distances[idx] as i32;
|
||||
}
|
||||
|
||||
@@ -269,7 +264,6 @@ impl<'a> Font<'a> {
|
||||
pub fn draw_text_individual_colors(
|
||||
&self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
color: &[Color],
|
||||
s: &str,
|
||||
) -> Result<(u32, u32), ::std::io::Error> {
|
||||
@@ -292,7 +286,7 @@ impl<'a> Font<'a> {
|
||||
}
|
||||
}
|
||||
for (idx, glyph) in glyphs.into_iter().enumerate() {
|
||||
glyph.draw(buf, (x_off, -off), bg, color[idx]);
|
||||
glyph.draw(buf, (x_off, -off), color[idx]);
|
||||
x_off += glyph.advance;
|
||||
}
|
||||
|
||||
@@ -302,12 +296,11 @@ impl<'a> Font<'a> {
|
||||
pub fn auto_draw_text_individual_colors(
|
||||
&mut self,
|
||||
buf: &mut BufferView,
|
||||
bg: Color,
|
||||
color: &[Color],
|
||||
s: &str,
|
||||
) -> Result<(u32, u32), ::std::io::Error> {
|
||||
self.add_str_to_cache(s);
|
||||
self.draw_text_individual_colors(buf, bg, color, s)
|
||||
self.draw_text_individual_colors(buf, color, s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -40,20 +40,18 @@ pub struct KeyEvent {
|
||||
|
||||
pub struct Keyboard {
|
||||
state: Option<KbState>,
|
||||
fd: Option<(OwnedFd, u32)>,
|
||||
}
|
||||
|
||||
impl Keyboard {
|
||||
pub fn new() -> Keyboard {
|
||||
Keyboard { state: None }
|
||||
Keyboard { state: None, fd: None, }
|
||||
}
|
||||
|
||||
pub fn keymap(&mut self, format: WEnum<wl_keyboard::KeymapFormat>, fd: OwnedFd, size: u32) {
|
||||
match format {
|
||||
WEnum::Value(wl_keyboard::KeymapFormat::XkbV1) => {
|
||||
self.state = Some(
|
||||
KbState::new_from_fd(fd.as_raw_fd(), size as usize)
|
||||
.expect("unable to load keymap"),
|
||||
);
|
||||
self.fd = Some((fd, size));
|
||||
}
|
||||
WEnum::Value(wl_keyboard::KeymapFormat::NoKeymap) => {
|
||||
// TODO: how to handle this (hopefully never occuring) case?
|
||||
@@ -62,6 +60,19 @@ impl Keyboard {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn realize(&mut self) {
|
||||
if self.state.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((fd, size)) = &self.fd {
|
||||
self.state = Some(
|
||||
KbState::new_from_fd(fd.as_raw_fd(), *size as usize)
|
||||
.expect("unable to load keymap"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key(
|
||||
&mut self,
|
||||
serial: u32,
|
||||
|
||||
+8
-18
@@ -17,12 +17,11 @@ use calloop::{
|
||||
use chrono::{Duration, Local, Timelike};
|
||||
|
||||
use buffer::BufferView;
|
||||
use color::Color;
|
||||
use fonts::{FontMap, MaybeFontMap};
|
||||
use state::{State, OperationMode};
|
||||
use event::{Event, Events};
|
||||
use widgets::{
|
||||
Audio, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||
PulseAudio, Backlight, Battery, Calendar, Clock, Date, Geometry, HorizontalLayout, IndexedLayout,
|
||||
Interface, InvertedHorizontalLayout, Line, Margin, VerticalLayout, Widget, Layout,
|
||||
};
|
||||
|
||||
@@ -38,8 +37,6 @@ enum UIVersion {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// let now = Local::now();
|
||||
|
||||
let mut args = env::args();
|
||||
// Skip program name
|
||||
_ = args.next();
|
||||
@@ -135,7 +132,7 @@ fn main() {
|
||||
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 backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let audio = Box::new(Audio::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 l = Rc::new(Margin::new(
|
||||
@@ -168,7 +165,7 @@ fn main() {
|
||||
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 backlight = Box::new(Backlight::new("intel_backlight", &mut fm, "sans", 24.));
|
||||
let audio = Box::new(Audio::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 l = Rc::new(VerticalLayout::new(vec![
|
||||
HorizontalLayout::new(vec![
|
||||
@@ -232,30 +229,24 @@ fn main() {
|
||||
(state.dimensions.0 as u32, state.dimensions.1 as u32),
|
||||
);
|
||||
|
||||
// eprintln!("time: {}", (Local::now() - now).num_milliseconds());
|
||||
|
||||
let surface = state.base_surface.as_ref().unwrap().clone();
|
||||
let surface = state.main_surface.wl_surface.as_ref().unwrap().clone();
|
||||
if force {
|
||||
if state.needs_memset {
|
||||
bufview.memset(Color::BLACK);
|
||||
}
|
||||
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
||||
if force || widget.get_dirty() {
|
||||
let geo = widget.geometry();
|
||||
let mut subview = bufview.subgeometry(geo);
|
||||
damage[idx] = widget.draw(&mut state.fonts.unwrap().borrow_mut(), &mut subview);
|
||||
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
||||
}
|
||||
}
|
||||
surface.damage_buffer(0, 0, 0x7FFFFFFF, 0x7FFFFFFF)
|
||||
} else {
|
||||
let mut drew = false;
|
||||
for (idx, widget) in state.widgets.iter_mut().enumerate() {
|
||||
if force || widget.get_dirty() {
|
||||
if widget.get_dirty() {
|
||||
drew = true;
|
||||
|
||||
let old_damage = damage[idx];
|
||||
bufview.subgeometry(old_damage).memset(Color::BLACK);
|
||||
bufview.subgeometry(old_damage).clear();
|
||||
|
||||
let geo = widget.geometry();
|
||||
let mut subview = bufview.subgeometry(geo);
|
||||
@@ -271,7 +262,6 @@ fn main() {
|
||||
combined_damage.width as i32,
|
||||
combined_damage.height as i32,
|
||||
);
|
||||
//draw_box(&mut subview, &Color::new(1.0, 0.5, 0.0, 1.0), (geo.width, geo.height));
|
||||
}
|
||||
}
|
||||
if !drew {
|
||||
@@ -282,7 +272,7 @@ fn main() {
|
||||
|
||||
surface.attach(Some(&buf.buffer), 0, 0);
|
||||
surface.commit();
|
||||
// eprintln!("draw time: {}", (Local::now() - now).num_milliseconds());
|
||||
// std::process::exit(0);
|
||||
conn.flush().unwrap();
|
||||
state.keyboard.realize();
|
||||
}
|
||||
}
|
||||
|
||||
+193
-90
@@ -3,19 +3,29 @@ use std::{
|
||||
process::exit,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
default::Default,
|
||||
};
|
||||
|
||||
use wayland_client::{
|
||||
protocol::{
|
||||
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||
wl_surface, wl_pointer,
|
||||
wl_buffer, wl_compositor, wl_subcompositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||
wl_surface, wl_subsurface, wl_pointer,
|
||||
},
|
||||
Connection, Dispatch, QueueHandle, WEnum,
|
||||
};
|
||||
|
||||
use wayland_protocols::xdg::{
|
||||
activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1},
|
||||
shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base},
|
||||
use wayland_protocols::{
|
||||
xdg::{
|
||||
activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1},
|
||||
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::{
|
||||
@@ -30,29 +40,46 @@ use crate::{
|
||||
event::{Event, Events, PointerEvent, PointerButton},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OperationMode {
|
||||
LayerSurface((u32, u32)),
|
||||
XdgToplevel,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MainSurface {
|
||||
pub wl_surface: Option<wl_surface::WlSurface>,
|
||||
xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
|
||||
layer_surface: Option<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BackgroundSurface {
|
||||
wl_surface: Option<wl_surface::WlSurface>,
|
||||
subsurface: Option<wl_subsurface::WlSubsurface>,
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Protocols {
|
||||
wl_shm: Option<wl_shm::WlShm>,
|
||||
xdg_activation: Option<xdg_activation_v1::XdgActivationV1>,
|
||||
viewporter: Option<wp_viewporter::WpViewporter>,
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
mode: OperationMode,
|
||||
pub main_surface: MainSurface,
|
||||
pub bg_surface: BackgroundSurface,
|
||||
pub protocols: Protocols,
|
||||
pub running: bool,
|
||||
pub dirty: bool,
|
||||
activated: bool,
|
||||
pub needs_memset: bool,
|
||||
pub base_surface: Option<wl_surface::WlSurface>,
|
||||
layer_shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
|
||||
layer_surface: Option<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
|
||||
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
||||
xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
|
||||
wl_shm: Option<wl_shm::WlShm>,
|
||||
xdg_activation: Option<xdg_activation_v1::XdgActivationV1>,
|
||||
pub configured: bool,
|
||||
pub dimensions: (i32, i32),
|
||||
pub bufmgr: BufferManager,
|
||||
pub widgets: Vec<Box<dyn Widget>>,
|
||||
keyboard: Keyboard,
|
||||
pub keyboard: Keyboard,
|
||||
pointer: Option<(f64, f64)>,
|
||||
pub fonts: MaybeFontMap,
|
||||
pub events: Arc<Mutex<Events>>,
|
||||
@@ -68,17 +95,12 @@ impl State {
|
||||
events: Arc<Mutex<Events>>,
|
||||
) -> State {
|
||||
State {
|
||||
protocols: Default::default(),
|
||||
bg_surface: Default::default(),
|
||||
main_surface: Default::default(),
|
||||
running: true,
|
||||
dirty: true,
|
||||
activated: false,
|
||||
needs_memset: true,
|
||||
base_surface: None,
|
||||
layer_shell: None,
|
||||
layer_surface: None,
|
||||
wm_base: None,
|
||||
xdg_surface: None,
|
||||
wl_shm: None,
|
||||
xdg_activation: None,
|
||||
configured: false,
|
||||
dimensions: (320, 240),
|
||||
bufmgr: BufferManager::new(),
|
||||
@@ -94,7 +116,7 @@ impl State {
|
||||
|
||||
pub fn add_buffer(&mut self, qh: &QueueHandle<Self>) {
|
||||
self.bufmgr.add_buffer(
|
||||
self.wl_shm.as_ref().expect("missing wl_shm"),
|
||||
self.protocols.wl_shm.as_ref().expect("missing wl_shm"),
|
||||
self.dimensions,
|
||||
qh,
|
||||
);
|
||||
@@ -105,7 +127,7 @@ impl State {
|
||||
Ok(token) => token,
|
||||
Err(_) => return,
|
||||
};
|
||||
match (&self.base_surface, &self.xdg_activation) {
|
||||
match (&self.main_surface.wl_surface, &self.protocols.xdg_activation) {
|
||||
(Some(surface), Some(activation)) => {
|
||||
activation.activate(key, surface);
|
||||
let activation_token = activation.get_activation_token(qh, ());
|
||||
@@ -115,31 +137,6 @@ impl State {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_xdg_surface(&mut self, qh: &QueueHandle<State>) {
|
||||
let wm_base = self.wm_base.as_ref().unwrap();
|
||||
let base_surface = self.base_surface.as_ref().unwrap();
|
||||
|
||||
let xdg_surface = wm_base.get_xdg_surface(base_surface, qh, ());
|
||||
let toplevel = xdg_surface.get_toplevel(qh, ());
|
||||
toplevel.set_title("wldash".into());
|
||||
|
||||
base_surface.commit();
|
||||
|
||||
self.xdg_surface = Some((xdg_surface, toplevel));
|
||||
}
|
||||
|
||||
fn init_layer_surface(&mut self, qh: &QueueHandle<State>, size: (u32, u32)) {
|
||||
let layer_shell = self.layer_shell.as_ref().unwrap();
|
||||
let base_surface = self.base_surface.as_ref().unwrap();
|
||||
|
||||
let layer_surface = layer_shell.get_layer_surface(base_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(size.0, size.1);
|
||||
|
||||
base_surface.commit();
|
||||
self.layer_surface = Some(layer_surface);
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetUpdater for State {
|
||||
@@ -170,54 +167,88 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||
"wl_compositor" => {
|
||||
let compositor =
|
||||
registry.bind::<wl_compositor::WlCompositor, _, _>(name, 5, qh, ());
|
||||
let surface = compositor.create_surface(qh, ());
|
||||
state.base_surface = Some(surface);
|
||||
let main_surface = compositor.create_surface(qh, ());
|
||||
let bg_surface = compositor.create_surface(qh, ());
|
||||
state.main_surface.wl_surface = Some(main_surface);
|
||||
state.bg_surface.wl_surface = Some(bg_surface);
|
||||
state.activate(qh);
|
||||
}
|
||||
"wl_subcompositor" => {
|
||||
let subcompositor =
|
||||
registry.bind::<wl_subcompositor::WlSubcompositor, _, _>(name, 1, qh, ());
|
||||
|
||||
if state.wm_base.is_some() && state.xdg_surface.is_none() && state.layer_surface.is_none() {
|
||||
match state.mode {
|
||||
OperationMode::XdgToplevel => state.init_xdg_surface(qh),
|
||||
OperationMode::LayerSurface(size) => state.init_layer_surface(qh, size),
|
||||
}
|
||||
match (&state.main_surface.wl_surface, &state.bg_surface.wl_surface) {
|
||||
(Some(parent), Some(child)) => {
|
||||
let subsurface = subcompositor.get_subsurface(child, parent, qh, ());
|
||||
subsurface.place_below(parent);
|
||||
state.bg_surface.subsurface = Some(subsurface);
|
||||
},
|
||||
_ => todo!("handle early subcompositor creation"),
|
||||
}
|
||||
}
|
||||
"wl_shm" => {
|
||||
state.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" => {
|
||||
registry.bind::<wl_seat::WlSeat, _, _>(name, 8, qh, ());
|
||||
}
|
||||
"xdg_wm_base" => if let OperationMode::XdgToplevel = state.mode {
|
||||
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 2, qh, ());
|
||||
state.wm_base = Some(wm_base);
|
||||
|
||||
if state.base_surface.is_some() && state.xdg_surface.is_none() {
|
||||
state.init_xdg_surface(qh);
|
||||
match &state.main_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let xdg_surface = wm_base.get_xdg_surface(surface, qh, ());
|
||||
let toplevel = xdg_surface.get_toplevel(qh, ());
|
||||
toplevel.set_title("wldash".into());
|
||||
|
||||
surface.commit();
|
||||
|
||||
state.main_surface.xdg_surface = Some((xdg_surface, toplevel));
|
||||
}
|
||||
_ => todo!("handle early xdg_shell creation"),
|
||||
}
|
||||
}
|
||||
"xdg_activation_v1" => {
|
||||
state.xdg_activation = Some(
|
||||
state.protocols.xdg_activation = Some(
|
||||
registry.bind::<xdg_activation_v1::XdgActivationV1, _, _>(name, 1, qh, ()),
|
||||
);
|
||||
state.activate(qh);
|
||||
}
|
||||
"zwlr_layer_shell_v1" => if let OperationMode::LayerSurface(size) = state.mode {
|
||||
state.layer_shell = Some(
|
||||
registry.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ()),
|
||||
);
|
||||
if state.base_surface.is_some() && state.layer_surface.is_none() {
|
||||
state.init_layer_surface(qh, size);
|
||||
let layer_shell = registry.bind::<zwlr_layer_shell_v1::ZwlrLayerShellV1, _, _>(name, 4, qh, ());
|
||||
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(size.0, size.1);
|
||||
|
||||
surface.commit();
|
||||
state.main_surface.layer_surface = Some(layer_surface);
|
||||
}
|
||||
_ => todo!("handle early layer_shell creation"),
|
||||
}
|
||||
},
|
||||
"clay_control_v1" => {
|
||||
// Buffers are zeroed by default, which is equivalent to zero alpha black. This
|
||||
// is not a particularly good background, but memsetting is slow. On clay,
|
||||
// toplevels that adhere to their requested dimensions only have black behind
|
||||
// them, so we can save the memset in this case, speeding things up.
|
||||
if let OperationMode::XdgToplevel = state.mode {
|
||||
state.needs_memset = false;
|
||||
"wp_viewporter" => {
|
||||
let viewporter = registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ());
|
||||
match &state.bg_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
state.bg_surface.viewport = Some(viewporter.get_viewport(surface, qh, ()));
|
||||
},
|
||||
_ => todo!("handle early viewporter creation"),
|
||||
}
|
||||
}
|
||||
state.protocols.viewporter = Some(viewporter);
|
||||
},
|
||||
"wp_single_pixel_buffer_manager_v1" => {
|
||||
let singlepixel = registry.bind::<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, _, _>(name, 1, qh, ());
|
||||
match &state.bg_surface.wl_surface {
|
||||
Some(surface) => {
|
||||
let buffer = singlepixel.create_u32_rgba_buffer(0, 0, 0, 0xFFFFFFFF, qh, ());
|
||||
surface.attach(Some(&buffer), 0, 0);
|
||||
surface.damage_buffer(0, 0, 1, 1);
|
||||
},
|
||||
_ => todo!("handle early single_pixel_buffer creation"),
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -236,6 +267,18 @@ impl Dispatch<wl_compositor::WlCompositor, ()> for State {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_subcompositor::WlSubcompositor, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_subcompositor::WlSubcompositor,
|
||||
_: wl_subcompositor::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_surface::WlSurface, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
@@ -248,6 +291,18 @@ impl Dispatch<wl_surface::WlSurface, ()> for State {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_subsurface::WlSubsurface, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_subsurface::WlSubsurface,
|
||||
_: wl_subsurface::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_shm::WlShm, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
@@ -317,22 +372,33 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
|
||||
state.configured = true;
|
||||
state.dirty = true;
|
||||
|
||||
if state.dimensions != (width as i32, height as i32) {
|
||||
state.bufmgr.clear_buffers();
|
||||
state.dimensions = (width as i32, height as i32);
|
||||
state.fonts.resolve();
|
||||
let fonts = state.fonts.unwrap();
|
||||
let layout = state.layout.clone();
|
||||
layout.geometry_update(
|
||||
&mut fonts.borrow_mut(),
|
||||
&Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
},
|
||||
state,
|
||||
);
|
||||
let dim = (width as i32, height as i32);
|
||||
|
||||
if state.dimensions == dim {
|
||||
return;
|
||||
}
|
||||
state.bufmgr.clear_buffers();
|
||||
state.dimensions = dim;
|
||||
state.fonts.resolve();
|
||||
let fonts = state.fonts.unwrap();
|
||||
let layout = state.layout.clone();
|
||||
layout.geometry_update(
|
||||
&mut fonts.borrow_mut(),
|
||||
&Geometry {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
},
|
||||
state,
|
||||
);
|
||||
|
||||
match (&state.bg_surface.wl_surface, &state.bg_surface.viewport) {
|
||||
(Some(surface), Some(viewport)) => {
|
||||
viewport.set_destination(dim.0, dim.1);
|
||||
surface.commit();
|
||||
},
|
||||
_ => todo!("handle early layer shell creation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -496,6 +562,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move to dedicated pointer module
|
||||
const BTN_LEFT: u32 = 0x110;
|
||||
const BTN_RIGHT: u32 = 0x111;
|
||||
const BTN_MIDDLE: u32 = 0x112;
|
||||
@@ -574,6 +641,42 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1,
|
||||
_: wp_single_pixel_buffer_manager_v1::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_viewporter::WpViewporter, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wp_viewporter::WpViewporter,
|
||||
_: wp_viewporter::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wp_viewport::WpViewport, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wp_viewport::WpViewport,
|
||||
_: wp_viewport::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<xdg_activation_v1::XdgActivationV1, ()> for State {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
use std::{
|
||||
thread,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
fonts::FontMap,
|
||||
event::{Event, Events, PointerButton},
|
||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||
};
|
||||
|
||||
use alsa::mixer::{
|
||||
Mixer, Selem, SelemChannelId, SelemId,
|
||||
};
|
||||
|
||||
#[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
|
||||
}
|
||||
|
||||
fn get_master_volume(selem: &mut Selem) -> f32 {
|
||||
let (min, max) = selem.get_playback_volume_range();
|
||||
selem
|
||||
.get_playback_volume(SelemChannelId::mono())
|
||||
.map(|volume| alsa_volume_to_f32(volume, min, max))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn get_mute(selem: &mut Selem) -> bool {
|
||||
let res = selem.get_playback_switch(SelemChannelId::FrontLeft);
|
||||
false
|
||||
}
|
||||
|
||||
fn set_master_volume(selem: &mut Selem, volume: f32) {
|
||||
let (min, max) = selem.get_playback_volume_range();
|
||||
let volume = f32_to_alsa_volume(volume, min, max);
|
||||
selem.set_playback_volume_all(volume).unwrap();
|
||||
}
|
||||
|
||||
fn start_monitor(inner: Arc<Mutex<Inner>>) {
|
||||
thread::Builder::new()
|
||||
.name("audiomon".to_string())
|
||||
.spawn(move || {
|
||||
let mixer = Mixer::new("default", true).unwrap();
|
||||
let id = SelemId::new("Master", 0);
|
||||
let mut selem = mixer.find_selem(&id).unwrap();
|
||||
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.volume = get_master_volume(&mut selem);
|
||||
inner.mute = get_mute(&mut selem);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
volume: f32,
|
||||
mute: bool,
|
||||
}
|
||||
|
||||
pub struct AlsaAudio {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
|
||||
impl AlsaAudio {
|
||||
pub fn new(fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||
let inner = Arc::new(Mutex::new(Inner{
|
||||
mute: false,
|
||||
volume: 0.,
|
||||
}));
|
||||
start_monitor(inner.clone());
|
||||
let dev = AlsaAudio{ inner };
|
||||
BarWidget::new(Box::new(dev), fm, font, size)
|
||||
}
|
||||
}
|
||||
|
||||
impl BarWidgetImpl for AlsaAudio {
|
||||
fn name(&self) -> &'static str {
|
||||
"audio"
|
||||
}
|
||||
fn get_dirty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn value(&mut self) -> f32 {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
inner.volume
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
if inner.mute {
|
||||
Color::DARKORANGE
|
||||
} else {
|
||||
Color::WHITE
|
||||
}
|
||||
}
|
||||
fn click(&mut self, pos: f32, btn: PointerButton) {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
match btn {
|
||||
// PointerButton::Left => inner.set_master_volume(pos),
|
||||
//PointerButton::Right => Some(Change::ToggleMute),
|
||||
//PointerButton::ScrollVertical(val) => Some(Change::VolumeInc((val / 512.) as f32)),
|
||||
//PointerButton::ScrollHorizontal(val) => Some(Change::VolumeInc((val / 100.) as f32)),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,7 +45,7 @@ impl BarWidgetImpl for Backlight {
|
||||
fn name(&self) -> &'static str {
|
||||
"backlight"
|
||||
}
|
||||
fn value(&self) -> f32 {
|
||||
fn value(&mut self) -> f32 {
|
||||
if self.cur > self.max {
|
||||
// what.
|
||||
return 1.0;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub trait BarWidgetImpl {
|
||||
false
|
||||
}
|
||||
fn name(&self) -> &'static str;
|
||||
fn value(&self) -> f32;
|
||||
fn value(&mut self) -> f32;
|
||||
fn color(&self) -> Color;
|
||||
fn click(&mut self, _pos: f32, _btn: PointerButton) {}
|
||||
}
|
||||
@@ -50,9 +50,8 @@ impl Widget for BarWidget {
|
||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
|
||||
font.draw_text(view, bg, fg, self.inner_widget.name())
|
||||
font.draw_text(view, fg, self.inner_widget.name())
|
||||
.unwrap();
|
||||
let size = self.size.ceil() as u32;
|
||||
let bar_offset = 4 * size;
|
||||
|
||||
+93
-67
@@ -1,81 +1,111 @@
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
error::Error,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use dbus::blocking::{
|
||||
stdintf::org_freedesktop_dbus::{Properties, PropertiesPropertiesChanged},
|
||||
LocalConnection,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
event::{Event, Events},
|
||||
fonts::FontMap,
|
||||
event::{Event, Events},
|
||||
widgets::bar_widget::{BarWidget, BarWidgetImpl},
|
||||
};
|
||||
|
||||
use upower_dbus::BatteryState;
|
||||
enum UpowerBatteryState {
|
||||
Charging,
|
||||
Discharging,
|
||||
Empty,
|
||||
Full,
|
||||
NotCharging,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
struct InnerBattery {
|
||||
value: f32,
|
||||
state: BatteryState,
|
||||
state: UpowerBatteryState,
|
||||
dirty: bool,
|
||||
}
|
||||
|
||||
async fn monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) -> Result<(), Box<dyn Error>> {
|
||||
use zbus::Connection;
|
||||
use upower_dbus::UPowerProxy;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
let conn = Connection::system().await?;
|
||||
let proxy = UPowerProxy::new(&conn).await?;
|
||||
|
||||
let device = proxy.get_display_device().await?;
|
||||
|
||||
let local_inner = inner.clone();
|
||||
let local_events = events.clone();
|
||||
let mut percent_stream = device.receive_percentage_changed().await;
|
||||
let a = tokio::spawn(async move {
|
||||
while let Some(percent) = percent_stream.next().await {
|
||||
let percent = percent.get().await.unwrap() as f32 / 100.;
|
||||
let mut inner = local_inner.lock().unwrap();
|
||||
inner.value = percent;
|
||||
inner.dirty = true;
|
||||
drop(inner);
|
||||
|
||||
let mut events = local_events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
}
|
||||
});
|
||||
|
||||
let local_inner = inner.clone();
|
||||
let local_events = events.clone();
|
||||
let mut state_stream = device.receive_state_changed().await;
|
||||
let b = tokio::spawn(async move {
|
||||
while let Some(state) = state_stream.next().await {
|
||||
let state = state.get().await.unwrap();
|
||||
let mut inner = local_inner.lock().unwrap();
|
||||
inner.state = state;
|
||||
inner.dirty = true;
|
||||
drop(inner);
|
||||
|
||||
let mut events = local_events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
}
|
||||
});
|
||||
a.await?;
|
||||
b.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_monitor(inner: Arc<Mutex<InnerBattery>>, events: Arc<Mutex<Events>>) {
|
||||
use tokio::runtime;
|
||||
thread::Builder::new()
|
||||
.name("battmon".to_string())
|
||||
.spawn(move || {
|
||||
let rt = runtime::Builder::new_current_thread()
|
||||
.enable_io()
|
||||
.build()
|
||||
let conn = LocalConnection::new_system().unwrap();
|
||||
let device_path = "/org/freedesktop/UPower/devices/DisplayDevice";
|
||||
let proxy = conn.with_proxy(
|
||||
"org.freedesktop.UPower",
|
||||
device_path,
|
||||
Duration::from_millis(500),
|
||||
);
|
||||
|
||||
let capacity: f64 = proxy
|
||||
.get("org.freedesktop.UPower.Device", "Percentage")
|
||||
.expect("unable to get property");
|
||||
let state: u32 = proxy
|
||||
.get("org.freedesktop.UPower.Device", "State")
|
||||
.expect("unable to get state");
|
||||
|
||||
{
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.value = capacity as f32 / 100.;
|
||||
inner.state = match state {
|
||||
1 => UpowerBatteryState::Charging,
|
||||
2 => UpowerBatteryState::Discharging,
|
||||
3 => UpowerBatteryState::Empty,
|
||||
4 => UpowerBatteryState::Full,
|
||||
5 => UpowerBatteryState::NotCharging,
|
||||
6 => UpowerBatteryState::Discharging,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
proxy
|
||||
.match_signal(
|
||||
move |c: PropertiesPropertiesChanged,
|
||||
_: &LocalConnection,
|
||||
_: &dbus::Message| {
|
||||
if c.interface_name != "org.freedesktop.UPower.Device" {
|
||||
return true;
|
||||
}
|
||||
let mut inner = inner.lock().unwrap();
|
||||
for (key, value) in c.changed_properties {
|
||||
match key.as_str() {
|
||||
"State" => {
|
||||
inner.state = match value.0.as_u64().unwrap() {
|
||||
1 => UpowerBatteryState::Charging,
|
||||
2 => UpowerBatteryState::Discharging,
|
||||
3 => UpowerBatteryState::Empty,
|
||||
4 => UpowerBatteryState::Full,
|
||||
5 => UpowerBatteryState::NotCharging,
|
||||
6 => UpowerBatteryState::Discharging,
|
||||
_ => UpowerBatteryState::Unknown,
|
||||
};
|
||||
inner.dirty = true;
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
}
|
||||
"Percentage" => {
|
||||
inner.value = value.0.as_f64().unwrap() as f32 / 100.;
|
||||
inner.dirty = true;
|
||||
let mut events = events.lock().unwrap();
|
||||
events.add_event(Event::PowerUpdate);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
true
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
rt.block_on(async move { monitor(inner, events).await }).unwrap();
|
||||
|
||||
loop {
|
||||
conn.process(Duration::from_millis(60000)).unwrap();
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
@@ -89,7 +119,7 @@ impl Battery {
|
||||
let battery = Battery {
|
||||
inner: Arc::new(Mutex::new(InnerBattery {
|
||||
value: 0.,
|
||||
state: BatteryState::Unknown,
|
||||
state: UpowerBatteryState::Unknown,
|
||||
dirty: false,
|
||||
})),
|
||||
};
|
||||
@@ -105,7 +135,7 @@ impl BarWidgetImpl for Battery {
|
||||
fn name(&self) -> &'static str {
|
||||
"battery"
|
||||
}
|
||||
fn value(&self) -> f32 {
|
||||
fn value(&mut self) -> f32 {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.dirty = false;
|
||||
inner.value
|
||||
@@ -113,15 +143,11 @@ impl BarWidgetImpl for Battery {
|
||||
fn color(&self) -> Color {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
match inner.state {
|
||||
BatteryState::Charging | BatteryState::FullyCharged => Color::LIGHTGREEN,
|
||||
BatteryState::PendingCharge => Color::LIGHTRED,
|
||||
_ => if inner.value > 0.25 {
|
||||
Color::WHITE
|
||||
} else if inner.value > 0.1 {
|
||||
Color::DARKORANGE
|
||||
} else {
|
||||
Color::RED
|
||||
}
|
||||
UpowerBatteryState::Charging | UpowerBatteryState::Full => Color::LIGHTGREEN,
|
||||
UpowerBatteryState::NotCharging => Color::LIGHTRED,
|
||||
_ if inner.value > 0.25 => Color::WHITE,
|
||||
_ if inner.value > 0.1 => Color::DARKORANGE,
|
||||
_ => Color::RED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ impl Calendar {
|
||||
orig: NaiveDate,
|
||||
mut time: NaiveDate,
|
||||
) {
|
||||
let black = Color::BLACK;
|
||||
let white = Color::WHITE;
|
||||
let dim = Color::GREY80;
|
||||
let dimmer = Color::GREY75;
|
||||
@@ -85,7 +84,6 @@ impl Calendar {
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * 1.).ceil() as u32,
|
||||
)),
|
||||
black,
|
||||
white,
|
||||
&wk_chr,
|
||||
)
|
||||
@@ -100,7 +98,6 @@ impl Calendar {
|
||||
year_font
|
||||
.draw_text(
|
||||
&mut view.offset(((self.size * 17.).ceil() as u32, 0)),
|
||||
black,
|
||||
dim,
|
||||
&format!("{:}", time.year()),
|
||||
)
|
||||
@@ -124,7 +121,7 @@ impl Calendar {
|
||||
_ => panic!("impossible value"),
|
||||
};
|
||||
cal_font
|
||||
.draw_text(&mut view, black, white, month_str)
|
||||
.draw_text(&mut view, white, month_str)
|
||||
.unwrap();
|
||||
|
||||
let mut done = false;
|
||||
@@ -152,7 +149,6 @@ impl Calendar {
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
black,
|
||||
dimmer,
|
||||
&format!("{:02}", wk.week()),
|
||||
)
|
||||
@@ -177,7 +173,6 @@ impl Calendar {
|
||||
y_off * (self.size * LINE_HEIGHT).ceil() as u32
|
||||
+ (self.size * MONTH_FACTOR).ceil() as u32,
|
||||
)),
|
||||
black,
|
||||
c,
|
||||
&format!("{:02}", time.day()),
|
||||
)
|
||||
|
||||
@@ -54,14 +54,12 @@ impl<'a> Widget for Clock {
|
||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||
let time = Local::now().naive_local();
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
|
||||
let digit = self.digit_width;
|
||||
let colon = self.colon_width;
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
font.draw_text_fixed_width(
|
||||
view,
|
||||
bg,
|
||||
fg,
|
||||
&[digit, digit, colon, digit, digit],
|
||||
&format!("{:02}:{:02}", time.hour(), time.minute()),
|
||||
|
||||
@@ -50,11 +50,9 @@ impl<'a> Widget for Date {
|
||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||
let time = Local::now().naive_local();
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
let font = fonts.get_font(self.font, self.size);
|
||||
font.draw_text(
|
||||
view,
|
||||
bg,
|
||||
fg,
|
||||
&format!(
|
||||
"{}, {:02}/{:02}/{:4}",
|
||||
|
||||
+7
-13
@@ -287,7 +287,6 @@ impl InterfaceWidget for Launcher {
|
||||
view: &mut BufferView,
|
||||
) -> Geometry {
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
|
||||
let line_height = intf.size.ceil() as u32;
|
||||
|
||||
@@ -299,14 +298,13 @@ impl InterfaceWidget for Launcher {
|
||||
let mut x_max = font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
bg,
|
||||
fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
font.auto_draw_text(&mut prompt_line, bg, fg, ">")
|
||||
font.auto_draw_text(&mut prompt_line, fg, ">")
|
||||
.unwrap();
|
||||
|
||||
// Draw entries
|
||||
@@ -336,13 +334,13 @@ impl InterfaceWidget for Launcher {
|
||||
}
|
||||
x_max = max(
|
||||
x_max,
|
||||
font.auto_draw_text_individual_colors(&mut line, bg, &colors, &m.name)
|
||||
font.auto_draw_text_individual_colors(&mut line, &colors, &m.name)
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
x_max = max(
|
||||
x_max,
|
||||
font.auto_draw_text(&mut line, bg, dimfg, &m.name)
|
||||
font.auto_draw_text(&mut line, dimfg, &m.name)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
@@ -386,7 +384,6 @@ impl InterfaceWidget for Shell {
|
||||
view: &mut BufferView,
|
||||
) -> Geometry {
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
|
||||
let line_height = intf.size.ceil() as u32;
|
||||
|
||||
@@ -399,13 +396,12 @@ impl InterfaceWidget for Shell {
|
||||
let x_max = font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
bg,
|
||||
fg,
|
||||
&format!(" {}", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "!")
|
||||
font.auto_draw_text(&mut prompt_line, Color::BUFF, "!")
|
||||
.unwrap();
|
||||
|
||||
Geometry {
|
||||
@@ -447,7 +443,6 @@ impl InterfaceWidget for Calc {
|
||||
view: &mut BufferView,
|
||||
) -> Geometry {
|
||||
let fg = Color::WHITE;
|
||||
let bg = Color::BLACK;
|
||||
|
||||
let line_height = intf.size.ceil() as u32;
|
||||
|
||||
@@ -460,20 +455,19 @@ impl InterfaceWidget for Calc {
|
||||
let res_off = font
|
||||
.auto_draw_text_with_cursor(
|
||||
&mut prompt_line,
|
||||
bg,
|
||||
fg,
|
||||
&format!(" {} ", &intf.prompt.input),
|
||||
intf.prompt.cursor + 3,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
font.auto_draw_text(&mut prompt_line, bg, Color::BUFF, "=")
|
||||
font.auto_draw_text(&mut prompt_line, Color::BUFF, "=")
|
||||
.unwrap();
|
||||
|
||||
if let Some(res) = &self.result {
|
||||
let resfg = Color::LIGHTORANGE;
|
||||
let mut result_line = view.offset((res_off.0, prompt_offset));
|
||||
font.auto_draw_text(&mut result_line, bg, resfg, &format!(" = {}", &res))
|
||||
font.auto_draw_text(&mut result_line, resfg, &format!(" = {}", &res))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -484,7 +478,7 @@ impl InterfaceWidget for Calc {
|
||||
}
|
||||
prompt_offset -= line_height;
|
||||
let mut result_line = view.offset((0, prompt_offset));
|
||||
font.auto_draw_text(&mut result_line, bg, dimfg, &m)
|
||||
font.auto_draw_text(&mut result_line, dimfg, &m)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -1,4 +1,5 @@
|
||||
mod audio;
|
||||
//mod alsaaudio;
|
||||
mod pulseaudio;
|
||||
mod backlight;
|
||||
mod bar_widget;
|
||||
mod battery;
|
||||
@@ -10,7 +11,8 @@ mod line;
|
||||
mod widget;
|
||||
mod layout;
|
||||
|
||||
pub use audio::Audio;
|
||||
//pub use alsaaudio::AlsaAudio;
|
||||
pub use pulseaudio::PulseAudio;
|
||||
pub use backlight::Backlight;
|
||||
pub use battery::Battery;
|
||||
pub use calendar::Calendar;
|
||||
|
||||
@@ -177,7 +177,7 @@ enum Change {
|
||||
ToggleMute,
|
||||
}
|
||||
|
||||
pub struct InnerAudio {
|
||||
struct InnerAudio {
|
||||
volume: f32,
|
||||
channel_volume: Option<ChannelVolumes>,
|
||||
mute: bool,
|
||||
@@ -186,14 +186,14 @@ pub struct InnerAudio {
|
||||
pipe: RawFd,
|
||||
}
|
||||
|
||||
pub struct Audio {
|
||||
pub struct PulseAudio {
|
||||
inner: Arc<Mutex<InnerAudio>>,
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
impl PulseAudio {
|
||||
pub fn new(events: Arc<Mutex<Events>>, fm: &mut FontMap, font: &'static str, size: f32) -> BarWidget {
|
||||
let (a, b) = pipe().unwrap();
|
||||
let audio = Audio {
|
||||
let audio = PulseAudio {
|
||||
inner: Arc::new(Mutex::new(InnerAudio{
|
||||
volume: 0.0,
|
||||
channel_volume: None,
|
||||
@@ -208,15 +208,17 @@ impl Audio {
|
||||
}
|
||||
}
|
||||
|
||||
impl BarWidgetImpl for Audio {
|
||||
impl BarWidgetImpl for PulseAudio {
|
||||
fn get_dirty(&self) -> bool {
|
||||
self.inner.lock().unwrap().dirty
|
||||
}
|
||||
fn name(&self) -> &'static str {
|
||||
"volume"
|
||||
}
|
||||
fn value(&self) -> f32 {
|
||||
self.inner.lock().unwrap().volume
|
||||
fn value(&mut self) -> f32 {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.dirty = false;
|
||||
inner.volume
|
||||
}
|
||||
fn color(&self) -> Color {
|
||||
match self.inner.lock().unwrap().mute {
|
||||
Reference in New Issue
Block a user