Refactor slightly
This commit is contained in:
@@ -4,6 +4,10 @@ use crate::draw;
|
|||||||
use fontconfig::Fontconfig as FontConfig;
|
use fontconfig::Fontconfig as FontConfig;
|
||||||
use rusttype::Font;
|
use rusttype::Font;
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
mem,
|
||||||
|
rc::Rc,
|
||||||
|
thread,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
hash,
|
hash,
|
||||||
@@ -11,6 +15,7 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// FontRef is used to store Fonts on widgets.
|
/// FontRef is used to store Fonts on widgets.
|
||||||
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
pub type FontRef<'a> = &'a rusttype::Font<'a>;
|
||||||
|
|
||||||
@@ -126,3 +131,31 @@ impl FontMap {
|
|||||||
.expect("no font at specified size")
|
.expect("no font at specified size")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MaybeFontMap {
|
||||||
|
Waiting(thread::JoinHandle<FontMap>),
|
||||||
|
Ready(Rc<RefCell<FontMap>>),
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeFontMap {
|
||||||
|
pub fn unwrap(&self) -> Rc<RefCell<FontMap>> {
|
||||||
|
match self {
|
||||||
|
MaybeFontMap::Ready(f) => f.clone(),
|
||||||
|
_ => panic!("fontmap not yet ready"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve(&mut self) {
|
||||||
|
if matches!(self, MaybeFontMap::Waiting(_)) {
|
||||||
|
let s = mem::replace(self, MaybeFontMap::Invalid);
|
||||||
|
match s {
|
||||||
|
MaybeFontMap::Waiting(handle) => {
|
||||||
|
*self = MaybeFontMap::Ready(Rc::new(RefCell::new(handle.join().unwrap())));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-435
@@ -5,19 +5,9 @@ mod fonts;
|
|||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
mod state;
|
||||||
|
|
||||||
use wayland_client::{
|
use wayland_client::{Connection, QueueHandle, WaylandSource,};
|
||||||
protocol::{
|
|
||||||
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
|
||||||
wl_surface,
|
|
||||||
},
|
|
||||||
Connection, Dispatch, QueueHandle, WEnum, WaylandSource,
|
|
||||||
};
|
|
||||||
|
|
||||||
use wayland_protocols::xdg::{
|
|
||||||
activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1},
|
|
||||||
shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base},
|
|
||||||
};
|
|
||||||
|
|
||||||
use calloop::{
|
use calloop::{
|
||||||
timer::{TimeoutAction, Timer},
|
timer::{TimeoutAction, Timer},
|
||||||
@@ -27,84 +17,14 @@ use chrono::{Duration, Local, Timelike};
|
|||||||
|
|
||||||
use buffer::{BufferManager, BufferView};
|
use buffer::{BufferManager, BufferView};
|
||||||
use color::Color;
|
use color::Color;
|
||||||
use fonts::FontMap;
|
use fonts::{MaybeFontMap, FontMap};
|
||||||
use keyboard::Keyboard;
|
use keyboard::Keyboard;
|
||||||
use widgets::{
|
use widgets::{
|
||||||
Backlight, Battery, Clock, Date, Geometry, HorizontalLayout, IndexedLayout, Interface, Layout,
|
Backlight, Battery, Clock, Date, Geometry, Interface, Line, WidgetUpdater,
|
||||||
Line, Margin, VerticalLayout, Widget, WidgetUpdater,
|
|
||||||
};
|
};
|
||||||
|
use state::State;
|
||||||
|
|
||||||
use std::{cell::RefCell, env, mem, process::exit, rc::Rc, thread};
|
use std::thread;
|
||||||
|
|
||||||
enum MaybeFontMap {
|
|
||||||
Waiting(thread::JoinHandle<FontMap>),
|
|
||||||
Ready(Rc<RefCell<FontMap>>),
|
|
||||||
Invalid,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaybeFontMap {
|
|
||||||
fn unwrap(&self) -> Rc<RefCell<FontMap>> {
|
|
||||||
match self {
|
|
||||||
MaybeFontMap::Ready(f) => f.clone(),
|
|
||||||
_ => panic!("fontmap not yet ready"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(&mut self) {
|
|
||||||
if matches!(self, MaybeFontMap::Waiting(_)) {
|
|
||||||
let s = mem::replace(self, MaybeFontMap::Invalid);
|
|
||||||
match s {
|
|
||||||
MaybeFontMap::Waiting(handle) => {
|
|
||||||
*self = MaybeFontMap::Ready(Rc::new(RefCell::new(handle.join().unwrap())));
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
running: bool,
|
|
||||||
dirty: bool,
|
|
||||||
activated: bool,
|
|
||||||
base_surface: Option<wl_surface::WlSurface>,
|
|
||||||
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>,
|
|
||||||
configured: bool,
|
|
||||||
dimensions: (i32, i32),
|
|
||||||
bufmgr: BufferManager,
|
|
||||||
widgets: Vec<Box<dyn Widget>>,
|
|
||||||
keyboard: Keyboard,
|
|
||||||
fonts: MaybeFontMap,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn add_buffer(&mut self, qh: &QueueHandle<Self>) {
|
|
||||||
self.bufmgr.add_buffer(
|
|
||||||
self.wl_shm.as_ref().expect("missing wl_shm"),
|
|
||||||
self.dimensions,
|
|
||||||
qh,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&mut self, qh: &QueueHandle<Self>) {
|
|
||||||
let key = match env::var("XDG_ACTIVATION_TOKEN") {
|
|
||||||
Ok(token) => token,
|
|
||||||
Err(_) => return,
|
|
||||||
};
|
|
||||||
match (&self.base_surface, &self.xdg_activation) {
|
|
||||||
(Some(surface), Some(activation)) => {
|
|
||||||
activation.activate(key, surface);
|
|
||||||
let activation_token = activation.get_activation_token(qh, ());
|
|
||||||
activation_token.commit();
|
|
||||||
env::remove_var("XDG_ACTIVATION_TOKEN");
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WidgetUpdater for State {
|
impl WidgetUpdater for State {
|
||||||
fn geometry_update(
|
fn geometry_update(
|
||||||
@@ -121,8 +41,8 @@ fn main() {
|
|||||||
let font_thread = thread::spawn(move || {
|
let font_thread = thread::spawn(move || {
|
||||||
let mut fm = FontMap::new();
|
let mut fm = FontMap::new();
|
||||||
// Hard-coding font paths make things a lot faster
|
// Hard-coding font paths make things a lot faster
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 96.);
|
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 128.);
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 40.);
|
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 48.);
|
||||||
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 24.);
|
fm.queue_font_path("sans", "/usr/share/fonts/noto/NotoSans-Regular.ttf", 24.);
|
||||||
fm.queue_font_path(
|
fm.queue_font_path(
|
||||||
"monospace",
|
"monospace",
|
||||||
@@ -146,12 +66,12 @@ fn main() {
|
|||||||
|
|
||||||
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
let (ping_sender, ping_source) = calloop::ping::make_ping().unwrap();
|
||||||
|
|
||||||
let clock = Box::new(Clock::new());
|
let clock = Box::new(Clock::new("sans", 128.));
|
||||||
let date = Box::new(Date::new());
|
let date = Box::new(Date::new("sans", 48.));
|
||||||
let line = Box::new(Line::new());
|
let line = Box::new(Line::new());
|
||||||
let launcher = Box::new(Interface::new());
|
let launcher = Box::new(Interface::new("monospace", 32.));
|
||||||
let battery = Box::new(Battery::new(ping_sender));
|
let battery = Box::new(Battery::new(ping_sender, "sans", 24.));
|
||||||
let backlight = Box::new(Backlight::new("intel_backlight"));
|
let backlight = Box::new(Backlight::new("intel_backlight", "sans", 24.));
|
||||||
|
|
||||||
let mut event_loop: EventLoop<State> =
|
let mut event_loop: EventLoop<State> =
|
||||||
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
EventLoop::try_new().expect("Failed to initialize the event loop!");
|
||||||
@@ -288,345 +208,3 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
registry: &wl_registry::WlRegistry,
|
|
||||||
event: wl_registry::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
qh: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
if let wl_registry::Event::Global {
|
|
||||||
name, interface, ..
|
|
||||||
} = event
|
|
||||||
{
|
|
||||||
match &interface[..] {
|
|
||||||
"wl_compositor" => {
|
|
||||||
let compositor =
|
|
||||||
registry.bind::<wl_compositor::WlCompositor, _, _>(name, 4, qh, ());
|
|
||||||
let surface = compositor.create_surface(qh, ());
|
|
||||||
state.base_surface = Some(surface);
|
|
||||||
state.activate(qh);
|
|
||||||
|
|
||||||
if state.wm_base.is_some() && state.xdg_surface.is_none() {
|
|
||||||
state.init_xdg_surface(qh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"wl_shm" => {
|
|
||||||
state.wl_shm = Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
|
|
||||||
}
|
|
||||||
"wl_seat" => {
|
|
||||||
registry.bind::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
|
|
||||||
}
|
|
||||||
"xdg_wm_base" => {
|
|
||||||
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, qh, ());
|
|
||||||
state.wm_base = Some(wm_base);
|
|
||||||
|
|
||||||
if state.base_surface.is_some() && state.xdg_surface.is_none() {
|
|
||||||
state.init_xdg_surface(qh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"xdg_activation_v1" => {
|
|
||||||
state.xdg_activation = Some(
|
|
||||||
registry.bind::<xdg_activation_v1::XdgActivationV1, _, _>(name, 1, qh, ()),
|
|
||||||
);
|
|
||||||
state.activate(qh);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_compositor::WlCompositor, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
_: &wl_compositor::WlCompositor,
|
|
||||||
_: wl_compositor::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_surface::WlSurface, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
_: &wl_surface::WlSurface,
|
|
||||||
_: wl_surface::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_shm::WlShm, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
_: &wl_shm::WlShm,
|
|
||||||
_: wl_shm::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_shm_pool::WlShmPool, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
_: &wl_shm_pool::WlShmPool,
|
|
||||||
_: wl_shm_pool::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_buffer::WlBuffer, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
buffer: &wl_buffer::WlBuffer,
|
|
||||||
_: wl_buffer::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
for buf in state.bufmgr.buffers.iter_mut() {
|
|
||||||
if &buf.buffer == buffer {
|
|
||||||
buf.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
wm_base: &xdg_wm_base::XdgWmBase,
|
|
||||||
event: xdg_wm_base::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
if let xdg_wm_base::Event::Ping { serial } = event {
|
|
||||||
wm_base.pong(serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<xdg_surface::XdgSurface, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
xdg_surface: &xdg_surface::XdgSurface,
|
|
||||||
event: xdg_surface::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
if let xdg_surface::Event::Configure { serial, .. } = event {
|
|
||||||
xdg_surface.ack_configure(serial);
|
|
||||||
state.configured = true;
|
|
||||||
state.dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<xdg_toplevel::XdgToplevel, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_: &xdg_toplevel::XdgToplevel,
|
|
||||||
event: xdg_toplevel::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
xdg_toplevel::Event::Configure {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
states,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if (width, height) == (0, 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let activated = states
|
|
||||||
.iter()
|
|
||||||
.find(|&st| *st as u32 == xdg_toplevel::State::Activated as u32)
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
if activated {
|
|
||||||
state.activated = true;
|
|
||||||
} else if state.activated && !activated {
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if state.dimensions != (width, height) {
|
|
||||||
state.bufmgr.clear_buffers();
|
|
||||||
state.dimensions = (width, height);
|
|
||||||
let mut layout = VerticalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(HorizontalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(IndexedLayout { widget_idx: 0 }),
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 1 }),
|
|
||||||
margin: (16, 8, 0, 0),
|
|
||||||
}),
|
|
||||||
Box::new(VerticalLayout {
|
|
||||||
widgets: vec![
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 2 }),
|
|
||||||
margin: (16, 8, 8, 0),
|
|
||||||
}),
|
|
||||||
Box::new(Margin {
|
|
||||||
widget: Box::new(IndexedLayout { widget_idx: 3 }),
|
|
||||||
margin: (16, 8, 8, 0),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Box::new(IndexedLayout { widget_idx: 4 }),
|
|
||||||
Box::new(IndexedLayout { widget_idx: 5 }),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
state.fonts.resolve();
|
|
||||||
let fonts = state.fonts.unwrap();
|
|
||||||
layout.geometry_update(
|
|
||||||
&mut fonts.borrow_mut(),
|
|
||||||
&Geometry {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: width as u32,
|
|
||||||
height: height as u32,
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xdg_toplevel::Event::Close => {
|
|
||||||
state.running = false;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_seat::WlSeat, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
seat: &wl_seat::WlSeat,
|
|
||||||
event: wl_seat::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
qh: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
if let wl_seat::Event::Capabilities {
|
|
||||||
capabilities: WEnum::Value(capabilities),
|
|
||||||
} = event
|
|
||||||
{
|
|
||||||
if capabilities.contains(wl_seat::Capability::Keyboard) {
|
|
||||||
seat.get_keyboard(qh, ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_: &wl_keyboard::WlKeyboard,
|
|
||||||
event: wl_keyboard::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
wl_keyboard::Event::Key {
|
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
key,
|
|
||||||
state: kbstate,
|
|
||||||
} => {
|
|
||||||
if key == 1 {
|
|
||||||
state.running = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let k = state.keyboard.key(serial, time, key, kbstate);
|
|
||||||
for widget in state.widgets.iter_mut() {
|
|
||||||
widget.keyboard_input(&k);
|
|
||||||
}
|
|
||||||
state.dirty = true;
|
|
||||||
}
|
|
||||||
wl_keyboard::Event::Modifiers {
|
|
||||||
mods_depressed,
|
|
||||||
mods_latched,
|
|
||||||
mods_locked,
|
|
||||||
group,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
state
|
|
||||||
.keyboard
|
|
||||||
.modifiers(mods_depressed, mods_latched, mods_locked, group);
|
|
||||||
}
|
|
||||||
wl_keyboard::Event::Keymap { format, fd, size } => {
|
|
||||||
state.keyboard.keymap(format, fd, size);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<xdg_activation_v1::XdgActivationV1, ()> for State {
|
|
||||||
fn event(
|
|
||||||
_: &mut Self,
|
|
||||||
_: &xdg_activation_v1::XdgActivationV1,
|
|
||||||
_: xdg_activation_v1::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ()> for State {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_: &xdg_activation_token_v1::XdgActivationTokenV1,
|
|
||||||
event: xdg_activation_token_v1::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
_: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
xdg_activation_token_v1::Event::Done { token } => {
|
|
||||||
for widget in state.widgets.iter_mut() {
|
|
||||||
widget.token_update(&token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+412
@@ -0,0 +1,412 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
process::exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
use wayland_client::{
|
||||||
|
protocol::{
|
||||||
|
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool,
|
||||||
|
wl_surface,
|
||||||
|
},
|
||||||
|
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 crate::{
|
||||||
|
buffer::BufferManager,
|
||||||
|
fonts::MaybeFontMap,
|
||||||
|
keyboard::Keyboard,
|
||||||
|
widgets::{
|
||||||
|
Geometry, HorizontalLayout, IndexedLayout, Layout, Margin, VerticalLayout, Widget,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
pub running: bool,
|
||||||
|
pub dirty: bool,
|
||||||
|
pub activated: bool,
|
||||||
|
pub base_surface: Option<wl_surface::WlSurface>,
|
||||||
|
pub wm_base: Option<xdg_wm_base::XdgWmBase>,
|
||||||
|
pub xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
|
||||||
|
pub wl_shm: Option<wl_shm::WlShm>,
|
||||||
|
pub xdg_activation: Option<xdg_activation_v1::XdgActivationV1>,
|
||||||
|
pub configured: bool,
|
||||||
|
pub dimensions: (i32, i32),
|
||||||
|
pub bufmgr: BufferManager,
|
||||||
|
pub widgets: Vec<Box<dyn Widget>>,
|
||||||
|
pub keyboard: Keyboard,
|
||||||
|
pub fonts: MaybeFontMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.dimensions,
|
||||||
|
qh,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate(&mut self, qh: &QueueHandle<Self>) {
|
||||||
|
let key = match env::var("XDG_ACTIVATION_TOKEN") {
|
||||||
|
Ok(token) => token,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
match (&self.base_surface, &self.xdg_activation) {
|
||||||
|
(Some(surface), Some(activation)) => {
|
||||||
|
activation.activate(key, surface);
|
||||||
|
let activation_token = activation.get_activation_token(qh, ());
|
||||||
|
activation_token.commit();
|
||||||
|
env::remove_var("XDG_ACTIVATION_TOKEN");
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
registry: &wl_registry::WlRegistry,
|
||||||
|
event: wl_registry::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
qh: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
if let wl_registry::Event::Global {
|
||||||
|
name, interface, ..
|
||||||
|
} = event
|
||||||
|
{
|
||||||
|
match &interface[..] {
|
||||||
|
"wl_compositor" => {
|
||||||
|
let compositor =
|
||||||
|
registry.bind::<wl_compositor::WlCompositor, _, _>(name, 4, qh, ());
|
||||||
|
let surface = compositor.create_surface(qh, ());
|
||||||
|
state.base_surface = Some(surface);
|
||||||
|
state.activate(qh);
|
||||||
|
|
||||||
|
if state.wm_base.is_some() && state.xdg_surface.is_none() {
|
||||||
|
state.init_xdg_surface(qh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"wl_shm" => {
|
||||||
|
state.wl_shm = Some(registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ()));
|
||||||
|
}
|
||||||
|
"wl_seat" => {
|
||||||
|
registry.bind::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
|
||||||
|
}
|
||||||
|
"xdg_wm_base" => {
|
||||||
|
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, qh, ());
|
||||||
|
state.wm_base = Some(wm_base);
|
||||||
|
|
||||||
|
if state.base_surface.is_some() && state.xdg_surface.is_none() {
|
||||||
|
state.init_xdg_surface(qh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"xdg_activation_v1" => {
|
||||||
|
state.xdg_activation = Some(
|
||||||
|
registry.bind::<xdg_activation_v1::XdgActivationV1, _, _>(name, 1, qh, ()),
|
||||||
|
);
|
||||||
|
state.activate(qh);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_compositor::WlCompositor, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &wl_compositor::WlCompositor,
|
||||||
|
_: wl_compositor::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_surface::WlSurface, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &wl_surface::WlSurface,
|
||||||
|
_: wl_surface::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_shm::WlShm, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &wl_shm::WlShm,
|
||||||
|
_: wl_shm::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_shm_pool::WlShmPool, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &wl_shm_pool::WlShmPool,
|
||||||
|
_: wl_shm_pool::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_buffer::WlBuffer, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
buffer: &wl_buffer::WlBuffer,
|
||||||
|
_: wl_buffer::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
for buf in state.bufmgr.buffers.iter_mut() {
|
||||||
|
if &buf.buffer == buffer {
|
||||||
|
buf.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
wm_base: &xdg_wm_base::XdgWmBase,
|
||||||
|
event: xdg_wm_base::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
if let xdg_wm_base::Event::Ping { serial } = event {
|
||||||
|
wm_base.pong(serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<xdg_surface::XdgSurface, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
xdg_surface: &xdg_surface::XdgSurface,
|
||||||
|
event: xdg_surface::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
if let xdg_surface::Event::Configure { serial, .. } = event {
|
||||||
|
xdg_surface.ack_configure(serial);
|
||||||
|
state.configured = true;
|
||||||
|
state.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<xdg_toplevel::XdgToplevel, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &xdg_toplevel::XdgToplevel,
|
||||||
|
event: xdg_toplevel::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
xdg_toplevel::Event::Configure {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
states,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if (width, height) == (0, 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let activated = states
|
||||||
|
.iter()
|
||||||
|
.find(|&st| *st as u32 == xdg_toplevel::State::Activated as u32)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
if activated {
|
||||||
|
state.activated = true;
|
||||||
|
} else if state.activated && !activated {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.dimensions != (width, height) {
|
||||||
|
state.bufmgr.clear_buffers();
|
||||||
|
state.dimensions = (width, height);
|
||||||
|
let mut layout = VerticalLayout {
|
||||||
|
widgets: vec![
|
||||||
|
Box::new(HorizontalLayout {
|
||||||
|
widgets: vec![
|
||||||
|
Box::new(IndexedLayout { widget_idx: 0 }),
|
||||||
|
Box::new(Margin {
|
||||||
|
widget: Box::new(IndexedLayout { widget_idx: 1 }),
|
||||||
|
margin: (16, 8, 0, 0),
|
||||||
|
}),
|
||||||
|
Box::new(VerticalLayout {
|
||||||
|
widgets: vec![
|
||||||
|
Box::new(Margin {
|
||||||
|
widget: Box::new(IndexedLayout { widget_idx: 2 }),
|
||||||
|
margin: (16, 8, 8, 0),
|
||||||
|
}),
|
||||||
|
Box::new(Margin {
|
||||||
|
widget: Box::new(IndexedLayout { widget_idx: 3 }),
|
||||||
|
margin: (16, 8, 8, 0),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Box::new(IndexedLayout { widget_idx: 4 }),
|
||||||
|
Box::new(IndexedLayout { widget_idx: 5 }),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
state.fonts.resolve();
|
||||||
|
let fonts = state.fonts.unwrap();
|
||||||
|
layout.geometry_update(
|
||||||
|
&mut fonts.borrow_mut(),
|
||||||
|
&Geometry {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: width as u32,
|
||||||
|
height: height as u32,
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xdg_toplevel::Event::Close => {
|
||||||
|
state.running = false;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_seat::WlSeat, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
seat: &wl_seat::WlSeat,
|
||||||
|
event: wl_seat::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
qh: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
if let wl_seat::Event::Capabilities {
|
||||||
|
capabilities: WEnum::Value(capabilities),
|
||||||
|
} = event
|
||||||
|
{
|
||||||
|
if capabilities.contains(wl_seat::Capability::Keyboard) {
|
||||||
|
seat.get_keyboard(qh, ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &wl_keyboard::WlKeyboard,
|
||||||
|
event: wl_keyboard::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
wl_keyboard::Event::Key {
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
key,
|
||||||
|
state: kbstate,
|
||||||
|
} => {
|
||||||
|
if key == 1 {
|
||||||
|
state.running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let k = state.keyboard.key(serial, time, key, kbstate);
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
widget.keyboard_input(&k);
|
||||||
|
}
|
||||||
|
state.dirty = true;
|
||||||
|
}
|
||||||
|
wl_keyboard::Event::Modifiers {
|
||||||
|
mods_depressed,
|
||||||
|
mods_latched,
|
||||||
|
mods_locked,
|
||||||
|
group,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
state
|
||||||
|
.keyboard
|
||||||
|
.modifiers(mods_depressed, mods_latched, mods_locked, group);
|
||||||
|
}
|
||||||
|
wl_keyboard::Event::Keymap { format, fd, size } => {
|
||||||
|
state.keyboard.keymap(format, fd, size);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<xdg_activation_v1::XdgActivationV1, ()> for State {
|
||||||
|
fn event(
|
||||||
|
_: &mut Self,
|
||||||
|
_: &xdg_activation_v1::XdgActivationV1,
|
||||||
|
_: xdg_activation_v1::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ()> for State {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_: &xdg_activation_token_v1::XdgActivationTokenV1,
|
||||||
|
event: xdg_activation_token_v1::Event,
|
||||||
|
_: &(),
|
||||||
|
_: &Connection,
|
||||||
|
_: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
xdg_activation_token_v1::Event::Done { token } => {
|
||||||
|
for widget in state.widgets.iter_mut() {
|
||||||
|
widget.token_update(&token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ impl Backlight {
|
|||||||
self.max = read_file_as_u64(self.device_path.join("max_brightness").as_path()).unwrap();
|
self.max = read_file_as_u64(self.device_path.join("max_brightness").as_path()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(path: &str) -> BarWidget {
|
pub fn new(path: &str, font: &'static str, size: f32) -> BarWidget {
|
||||||
let mut dev = Backlight {
|
let mut dev = Backlight {
|
||||||
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
device_path: Path::new("/sys/class/backlight").to_path_buf().join(path),
|
||||||
cur: 0,
|
cur: 0,
|
||||||
@@ -38,7 +38,7 @@ impl Backlight {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dev.update();
|
dev.update();
|
||||||
BarWidget::new(Box::new(dev))
|
BarWidget::new(Box::new(dev), font, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,6 @@ use crate::{
|
|||||||
widgets::{Geometry, Widget},
|
widgets::{Geometry, Widget},
|
||||||
};
|
};
|
||||||
|
|
||||||
const BAR_FONT: &str = "sans";
|
|
||||||
const BAR_SIZE: f32 = 24.;
|
|
||||||
|
|
||||||
pub trait BarWidgetImpl {
|
pub trait BarWidgetImpl {
|
||||||
fn get_dirty(&self) -> bool;
|
fn get_dirty(&self) -> bool;
|
||||||
fn set_dirty(&mut self, dirty: bool);
|
fn set_dirty(&mut self, dirty: bool);
|
||||||
@@ -20,15 +17,17 @@ pub trait BarWidgetImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct BarWidget {
|
pub struct BarWidget {
|
||||||
|
font: &'static str,
|
||||||
|
size: f32,
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
inner_widget: Box<dyn BarWidgetImpl>,
|
inner_widget: Box<dyn BarWidgetImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BarWidget {
|
impl BarWidget {
|
||||||
pub fn new(inner_widget: Box<dyn BarWidgetImpl>) -> BarWidget {
|
pub fn new(inner_widget: Box<dyn BarWidgetImpl>, font: &'static str, size: f32) -> BarWidget {
|
||||||
BarWidget {
|
BarWidget {
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
inner_widget,
|
inner_widget, font, size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,13 +46,13 @@ impl Widget for BarWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
fn draw(&mut self, fonts: &mut FontMap, view: &mut BufferView) -> Geometry {
|
||||||
let font = fonts.get_font(BAR_FONT, BAR_SIZE);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
|
|
||||||
font.auto_draw_text(view, &bg, &fg, self.inner_widget.name())
|
font.auto_draw_text(view, &bg, &fg, self.inner_widget.name())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let size = BAR_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();
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ impl Widget for BarWidget {
|
|||||||
x: x,
|
x: x,
|
||||||
y: geometry.y,
|
y: geometry.y,
|
||||||
width: w,
|
width: w,
|
||||||
height: BAR_SIZE.ceil() as u32,
|
height: self.size.ceil() as u32,
|
||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ pub struct Battery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Battery {
|
impl Battery {
|
||||||
pub fn new(ping: Ping) -> BarWidget {
|
pub fn new(ping: Ping, 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.,
|
||||||
@@ -120,7 +120,7 @@ impl Battery {
|
|||||||
dirty: false,
|
dirty: false,
|
||||||
};
|
};
|
||||||
start_monitor(battery.inner.clone(), ping);
|
start_monitor(battery.inner.clone(), ping);
|
||||||
BarWidget::new(Box::new(battery))
|
BarWidget::new(Box::new(battery), font, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ use crate::{
|
|||||||
|
|
||||||
use chrono::{Local, Timelike};
|
use chrono::{Local, Timelike};
|
||||||
|
|
||||||
const CLOCK_FONT: &str = "sans";
|
|
||||||
const CLOCK_SIZE: f32 = 96.;
|
|
||||||
|
|
||||||
pub struct Clock {
|
pub struct Clock {
|
||||||
|
font: &'static str,
|
||||||
|
size: f32,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
digit_width: u32,
|
digit_width: u32,
|
||||||
@@ -20,8 +19,9 @@ pub struct Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Clock {
|
impl<'a> Clock {
|
||||||
pub fn new() -> Clock {
|
pub fn new(font: &'static str, size: f32) -> Clock {
|
||||||
Clock {
|
Clock {
|
||||||
|
font, size,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
digit_width: 0,
|
digit_width: 0,
|
||||||
@@ -49,7 +49,7 @@ impl<'a> Widget for Clock {
|
|||||||
|
|
||||||
let digit = self.digit_width;
|
let digit = self.digit_width;
|
||||||
let colon = self.colon_width;
|
let colon = self.colon_width;
|
||||||
let font = fonts.get_font(CLOCK_FONT, CLOCK_SIZE);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
font.draw_text_fixed_width(
|
font.draw_text_fixed_width(
|
||||||
view,
|
view,
|
||||||
&bg,
|
&bg,
|
||||||
@@ -62,14 +62,14 @@ impl<'a> Widget for Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
fn geometry_update(&mut self, fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
let font = fonts.get_font(CLOCK_FONT, CLOCK_SIZE);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
self.digit_width = font.auto_widest("0123456789").unwrap();
|
self.digit_width = font.auto_widest("0123456789").unwrap();
|
||||||
self.colon_width = font.auto_widest(":").unwrap();
|
self.colon_width = font.auto_widest(":").unwrap();
|
||||||
self.geometry = Geometry {
|
self.geometry = Geometry {
|
||||||
x: geometry.x,
|
x: geometry.x,
|
||||||
y: geometry.y,
|
y: geometry.y,
|
||||||
width: self.digit_width * 4 + self.colon_width,
|
width: self.digit_width * 4 + self.colon_width,
|
||||||
height: CLOCK_SIZE.ceil() as u32,
|
height: self.size.ceil() as u32,
|
||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -9,17 +9,17 @@ use crate::{
|
|||||||
|
|
||||||
use chrono::{Datelike, Local};
|
use chrono::{Datelike, Local};
|
||||||
|
|
||||||
const DATE_FONT: &str = "sans";
|
|
||||||
const DATE_SIZE: f32 = 40.;
|
|
||||||
|
|
||||||
pub struct Date {
|
pub struct Date {
|
||||||
|
font: &'static str,
|
||||||
|
size: f32,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Date {
|
impl Date {
|
||||||
pub fn new() -> Date {
|
pub fn new(font: &'static str, size: f32) -> Date {
|
||||||
Date {
|
Date {
|
||||||
|
font, size,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ impl<'a> Widget for Date {
|
|||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
let mut date_line = view.offset((0, 8)).unwrap();
|
let mut date_line = view.offset((0, 8)).unwrap();
|
||||||
let font = fonts.get_font(DATE_FONT, DATE_SIZE);
|
let font = fonts.get_font(self.font, self.size);
|
||||||
font.auto_draw_text(
|
font.auto_draw_text(
|
||||||
&mut date_line,
|
&mut date_line,
|
||||||
&bg,
|
&bg,
|
||||||
@@ -61,11 +61,12 @@ impl<'a> Widget for Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
fn geometry_update(&mut self, _fonts: &mut FontMap, geometry: &Geometry) -> Geometry {
|
||||||
|
let width = (3. + 2. + 2. + 2. + 4.) * self.size / 2.;
|
||||||
self.geometry = Geometry {
|
self.geometry = Geometry {
|
||||||
x: geometry.x,
|
x: geometry.x,
|
||||||
y: geometry.y,
|
y: geometry.y,
|
||||||
width: 256,
|
width: width.ceil() as u32,
|
||||||
height: DATE_SIZE.ceil() as u32,
|
height: self.size.ceil() as u32,
|
||||||
};
|
};
|
||||||
self.geometry
|
self.geometry
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-32
@@ -1,7 +1,11 @@
|
|||||||
use std::cmp::{min, Ordering};
|
use std::{
|
||||||
use std::collections::HashMap;
|
cmp::{min, max, Ordering},
|
||||||
use std::default::Default;
|
collections::HashMap,
|
||||||
use std::process::{exit, Command};
|
default::Default,
|
||||||
|
process::{exit, Command},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::BufferView,
|
buffer::BufferView,
|
||||||
@@ -17,12 +21,6 @@ use fuzzy_matcher::FuzzyMatcher;
|
|||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use wayland_client::{protocol::wl_keyboard, WEnum};
|
use wayland_client::{protocol::wl_keyboard, WEnum};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
const LAUNCHER_FONT: &str = "monospace";
|
|
||||||
const LAUNCHER_SIZE: f32 = 32.;
|
|
||||||
|
|
||||||
struct Matcher {
|
struct Matcher {
|
||||||
matches: HashMap<Desktop, i64>,
|
matches: HashMap<Desktop, i64>,
|
||||||
}
|
}
|
||||||
@@ -284,7 +282,7 @@ impl InterfaceWidget for Launcher {
|
|||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
|
|
||||||
let line_height = LAUNCHER_SIZE.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - line_height;
|
let mut prompt_offset = intf.geometry.height - line_height;
|
||||||
@@ -292,9 +290,8 @@ impl InterfaceWidget for Launcher {
|
|||||||
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
||||||
prompt_border.memset(&fg);
|
prompt_border.memset(&fg);
|
||||||
|
|
||||||
// Draw prompt
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
let mut x_max = font.auto_draw_text_with_cursor(
|
||||||
font.auto_draw_text_with_cursor(
|
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
&bg,
|
&bg,
|
||||||
&fg,
|
&fg,
|
||||||
@@ -303,7 +300,6 @@ impl InterfaceWidget for Launcher {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
font.auto_draw_text(&mut prompt_line, &bg, &fg, ">")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -332,11 +328,11 @@ impl InterfaceWidget for Launcher {
|
|||||||
colors.push(Color::new(0.75, 0.75, 0.75, 1.0));
|
colors.push(Color::new(0.75, 0.75, 0.75, 1.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
x_max = max(x_max, font.auto_draw_text_individual_colors(&mut line, &bg, &colors, &m.name)
|
||||||
.unwrap();
|
.unwrap());
|
||||||
} else {
|
} else {
|
||||||
font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
x_max = max(x_max, font.auto_draw_text(&mut line, &bg, &dimfg, &m.name)
|
||||||
.unwrap();
|
.unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +343,7 @@ impl InterfaceWidget for Launcher {
|
|||||||
Geometry {
|
Geometry {
|
||||||
x: intf.geometry.x,
|
x: intf.geometry.x,
|
||||||
y: intf.geometry.y + intf.geometry.height - content_height,
|
y: intf.geometry.y + intf.geometry.height - content_height,
|
||||||
width: intf.geometry.width,
|
width: x_max.0+1,
|
||||||
height: content_height,
|
height: content_height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,7 +376,7 @@ impl InterfaceWidget for Shell {
|
|||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
|
|
||||||
let line_height = LAUNCHER_SIZE.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let prompt_offset = intf.geometry.height - line_height;
|
let prompt_offset = intf.geometry.height - line_height;
|
||||||
@@ -389,8 +385,8 @@ impl InterfaceWidget for Shell {
|
|||||||
prompt_border.memset(&fg);
|
prompt_border.memset(&fg);
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
font.auto_draw_text_with_cursor(
|
let x_max = font.auto_draw_text_with_cursor(
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
&bg,
|
&bg,
|
||||||
&fg,
|
&fg,
|
||||||
@@ -398,14 +394,13 @@ impl InterfaceWidget for Shell {
|
|||||||
intf.prompt.cursor + 3,
|
intf.prompt.cursor + 3,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "!")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Geometry {
|
Geometry {
|
||||||
x: intf.geometry.x,
|
x: intf.geometry.x,
|
||||||
y: intf.geometry.y + intf.geometry.height - line_height,
|
y: intf.geometry.y + intf.geometry.height - line_height,
|
||||||
width: intf.geometry.width,
|
width: x_max.0 + 1,
|
||||||
height: line_height,
|
height: line_height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,16 +438,16 @@ impl InterfaceWidget for Calc {
|
|||||||
let fg = Color::new(1., 1., 1., 1.);
|
let fg = Color::new(1., 1., 1., 1.);
|
||||||
let bg = Color::new(0., 0., 0., 1.);
|
let bg = Color::new(0., 0., 0., 1.);
|
||||||
|
|
||||||
let line_height = LAUNCHER_SIZE.ceil() as u32;
|
let line_height = intf.size.ceil() as u32;
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
let mut prompt_offset = intf.geometry.height - (LAUNCHER_SIZE.ceil() as u32);
|
let mut prompt_offset = intf.geometry.height - (line_height);
|
||||||
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
let mut prompt_line = view.offset((0, prompt_offset)).unwrap();
|
||||||
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
let mut prompt_border = prompt_line.limit((intf.geometry.width, 1)).unwrap();
|
||||||
prompt_border.memset(&fg);
|
prompt_border.memset(&fg);
|
||||||
|
|
||||||
// Draw prompt
|
// Draw prompt
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
let font = fonts.get_font(intf.font, intf.size);
|
||||||
let res_off = font
|
let res_off = font
|
||||||
.auto_draw_text_with_cursor(
|
.auto_draw_text_with_cursor(
|
||||||
&mut prompt_line,
|
&mut prompt_line,
|
||||||
@@ -463,7 +458,6 @@ impl InterfaceWidget for Calc {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let font = fonts.get_font(LAUNCHER_FONT, LAUNCHER_SIZE);
|
|
||||||
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "=")
|
font.auto_draw_text(&mut prompt_line, &bg, &Color::new(1., 0.75, 0.5, 1.), "=")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -476,10 +470,10 @@ impl InterfaceWidget for Calc {
|
|||||||
|
|
||||||
for m in self.old.iter().rev() {
|
for m in self.old.iter().rev() {
|
||||||
let dimfg = Color::new(0.5, 0.5, 0.5, 1.0);
|
let dimfg = Color::new(0.5, 0.5, 0.5, 1.0);
|
||||||
if prompt_offset < LAUNCHER_SIZE.ceil() as u32 {
|
if prompt_offset < line_height {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prompt_offset -= LAUNCHER_SIZE.ceil() as u32;
|
prompt_offset -= line_height;
|
||||||
let mut result_line = view.offset((0, prompt_offset)).unwrap();
|
let mut result_line = view.offset((0, prompt_offset)).unwrap();
|
||||||
font.auto_draw_text(&mut result_line, &bg, &dimfg, &m)
|
font.auto_draw_text(&mut result_line, &bg, &dimfg, &m)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -499,6 +493,8 @@ impl InterfaceWidget for Calc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct InnerInterface {
|
struct InnerInterface {
|
||||||
|
font: &'static str,
|
||||||
|
size: f32,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
geometry: Geometry,
|
geometry: Geometry,
|
||||||
selection: usize,
|
selection: usize,
|
||||||
@@ -513,7 +509,7 @@ pub struct Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Interface {
|
impl Interface {
|
||||||
pub fn new() -> Interface {
|
pub fn new(font: &'static str, size: f32) -> Interface {
|
||||||
Interface {
|
Interface {
|
||||||
launcher: Launcher::new(),
|
launcher: Launcher::new(),
|
||||||
shell: Shell {},
|
shell: Shell {},
|
||||||
@@ -522,6 +518,7 @@ impl Interface {
|
|||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
inner: InnerInterface {
|
inner: InnerInterface {
|
||||||
|
font, size,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
geometry: Default::default(),
|
geometry: Default::default(),
|
||||||
selection: 0,
|
selection: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user