Files
wldash/src/main.rs
T

477 lines
15 KiB
Rust
Raw Normal View History

2019-07-30 00:42:05 +02:00
#![feature(seek_convenience)]
use std::collections::VecDeque;
2019-07-30 16:31:42 +02:00
use std::io::{Read, Write};
2019-07-30 00:42:05 +02:00
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use nix::poll::{poll, PollFd, PollFlags};
2019-07-30 16:31:42 +02:00
use os_pipe::pipe;
2019-07-30 00:42:05 +02:00
2019-07-30 16:31:42 +02:00
use chrono::{Duration as ChronoDuration, Local, Timelike};
2019-07-30 00:42:05 +02:00
2019-07-31 16:44:13 +02:00
use smithay_client_toolkit::keyboard::{
map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind,
};
use smithay_client_toolkit::utils::DoubleMemPool;
use wayland_client::protocol::{wl_compositor, wl_pointer, wl_shm, wl_surface};
use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy};
use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
zwlr_layer_shell_v1, zwlr_layer_surface_v1,
};
2019-07-30 00:42:05 +02:00
2019-07-31 00:42:03 +02:00
mod backlight;
2019-07-31 10:26:12 +02:00
mod buffer;
mod calendar;
mod clock;
mod color;
mod draw;
mod module;
2019-07-30 00:42:05 +02:00
2019-07-31 00:42:03 +02:00
use crate::backlight::Backlight;
2019-07-31 10:26:12 +02:00
use crate::buffer::Buffer;
2019-07-31 00:42:03 +02:00
use crate::calendar::Calendar;
2019-07-31 10:26:12 +02:00
use crate::clock::Clock;
use crate::color::Color;
use crate::module::{Input, Module};
2019-07-30 16:31:42 +02:00
2019-07-30 00:42:05 +02:00
enum Cmd {
Exit,
Configure,
Draw,
2019-07-31 10:26:12 +02:00
Input { pos: (u32, u32), input: Input },
2019-07-30 00:42:05 +02:00
}
struct App {
pools: DoubleMemPool,
display: Display,
event_queue: EventQueue,
2019-07-31 16:44:13 +02:00
surface: wl_surface::WlSurface,
shell_surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
2019-07-30 00:42:05 +02:00
cmd_queue: Arc<Mutex<VecDeque<Cmd>>>,
dimensions: (u32, u32),
2019-07-31 00:42:03 +02:00
modules: Vec<Module>,
2019-07-30 00:42:05 +02:00
}
impl App {
2019-07-31 00:42:03 +02:00
fn redraw(&mut self, force: bool) -> Result<(), ::std::io::Error> {
let time = Local::now();
2019-07-30 00:42:05 +02:00
let pool = match self.pools.pool() {
Some(pool) => pool,
None => return Ok(()),
};
let (buf_x, buf_y) = self.dimensions;
// resize the pool if relevant
pool.resize((4 * buf_x * buf_y) as usize)
.expect("Failed to resize the memory pool.");
let mmap = pool.mmap();
2019-07-30 16:31:42 +02:00
let mut buf = Buffer::new(mmap, self.dimensions);
2019-07-31 00:42:03 +02:00
let mut margin_buf = buf.subdimensions((20, 20, buf_x - 40, buf_y - 40));
2019-07-31 10:26:12 +02:00
2019-07-31 00:42:03 +02:00
let bg = Color::new(0.0, 0.0, 0.0, 0.9);
2019-07-30 00:42:05 +02:00
2019-07-31 00:42:03 +02:00
let mut damage = vec![];
for module in self.modules.iter() {
2019-07-31 10:26:12 +02:00
if module.update(&time, force)? {
let mut b = &mut margin_buf.subdimensions(module.get_bounds());
let mut d = module.draw(&mut b, &bg, &time)?;
damage.append(&mut d);
}
2019-07-31 00:42:03 +02:00
}
2019-07-30 00:42:05 +02:00
mmap.flush().unwrap();
// get a buffer and attach it
let new_buffer = pool.buffer(
0,
buf_x as i32,
buf_y as i32,
4 * buf_x as i32,
wl_shm::Format::Argb8888,
);
2019-07-31 16:44:13 +02:00
self.surface.attach(Some(&new_buffer), 0, 0);
2019-07-31 00:42:03 +02:00
for d in damage {
2019-07-31 16:44:13 +02:00
self.surface.damage(d.0, d.1, d.2, d.3);
2019-07-31 00:42:03 +02:00
}
2019-07-31 16:44:13 +02:00
self.surface.commit();
2019-07-30 00:42:05 +02:00
Ok(())
}
2019-07-31 16:44:13 +02:00
fn shell_surface(&mut self) -> &mut zwlr_layer_surface_v1::ZwlrLayerSurfaceV1 {
&mut self.shell_surface
2019-07-30 00:42:05 +02:00
}
fn cmd_queue(&self) -> Arc<Mutex<VecDeque<Cmd>>> {
self.cmd_queue.clone()
}
fn flush_display(&mut self) {
self.display.flush().expect("unable to flush display");
}
fn dimensions(&self) -> (u32, u32) {
self.dimensions
}
fn event_queue(&mut self) -> &mut EventQueue {
&mut self.event_queue
}
2019-07-31 00:42:03 +02:00
fn wipe(&mut self) {
let pool = match self.pools.pool() {
Some(pool) => pool,
None => return,
};
pool.resize((4 * self.dimensions.0 * self.dimensions.1) as usize)
.expect("Failed to resize the memory pool.");
let mmap = pool.mmap();
let mut buf = Buffer::new(mmap, self.dimensions);
let bg = Color::new(0.0, 0.0, 0.0, 0.9);
buf.memset(&bg);
}
fn get_module(&self, pos: (u32, u32)) -> Option<&Module> {
2019-07-31 10:26:12 +02:00
for m in self.modules.iter() {
if m.intersect(pos) {
return Some(&m);
}
}
None
2019-07-31 00:42:03 +02:00
}
2019-07-30 00:42:05 +02:00
fn new(dimensions: (u32, u32)) -> App {
let cmd_queue = Arc::new(Mutex::new(VecDeque::new()));
let (display, mut event_queue) = Display::connect_to_env().unwrap();
2019-07-31 16:44:13 +02:00
let display_wrapper = display
.as_ref()
.make_wrapper(&event_queue.get_token())
.unwrap()
.into();
2019-07-30 00:42:05 +02:00
2019-07-31 16:44:13 +02:00
//
// Set up global manager
//
let manager = GlobalManager::new_with_cb(&display_wrapper, move |event, _| match event {
GlobalEvent::New {
id: _,
interface: _,
version: _,
} => {}
GlobalEvent::Removed {
id: _,
interface: _,
} => {}
});
// double sync to retrieve the global list
// and the globals metadata
event_queue.sync_roundtrip().unwrap();
event_queue.sync_roundtrip().unwrap();
// wl_compositor
let compositor: wl_compositor::WlCompositor = manager
.instantiate_range(1, 4, NewProxy::implement_dummy)
.expect("server didn't advertise `wl_compositor`");
// wl_shm
let shm_formats = Arc::new(Mutex::new(Vec::new()));
let shm_formats2 = shm_formats.clone();
let shm = manager
.instantiate_range(1, 1, |shm| {
shm.implement_closure(
move |evt, _| {
if let wl_shm::Event::Format { format } = evt {
shm_formats2.lock().unwrap().push(format);
}
},
(),
)
})
.expect("server didn't advertise `wl_shm`");
let pools = DoubleMemPool::new(&shm, || {}).expect("Failed to create a memory pool !");
//
// Prepare shell so that we can create our shell surface
//
// shells
let shell = if let Ok(layer) = manager.instantiate_exact(
1,
|layer: NewProxy<zwlr_layer_shell_v1::ZwlrLayerShellV1>| {
layer.implement_closure(|_, _| {}, ())
},
) {
layer
} else {
panic!("server didn't advertise `zwlr_layer_shell_v1`");
};
// sync to retrieve the global events
event_queue.sync_roundtrip().unwrap();
let surface = compositor
2019-07-30 00:42:05 +02:00
.create_surface(NewProxy::implement_dummy)
.unwrap();
let event_clone = cmd_queue.clone();
2019-07-31 16:44:13 +02:00
let shell_surface = shell
.get_layer_surface(
&surface,
None,
zwlr_layer_shell_v1::Layer::Overlay,
"".to_string(),
move |layer| {
layer.implement_closure(
move |evt, layer| match evt {
zwlr_layer_surface_v1::Event::Configure {
serial,
width: _,
height: _,
} => {
layer.ack_configure(serial);
event_clone.lock().unwrap().push_back(Cmd::Configure);
}
_ => unreachable!(),
},
(),
)
},
)
2019-07-30 00:42:05 +02:00
.unwrap();
2019-07-31 16:44:13 +02:00
shell_surface.set_keyboard_interactivity(1);
surface.commit();
event_queue.sync_roundtrip().unwrap();
2019-07-30 00:42:05 +02:00
2019-07-31 16:44:13 +02:00
//
// Get our seat
//
let seat = manager
.instantiate_range(1, 6, NewProxy::implement_dummy)
.unwrap();
//
// Keyboard processing
//
2019-07-30 00:42:05 +02:00
let kbd_clone = cmd_queue.clone();
map_keyboard_auto_with_repeat(
&seat,
KeyRepeatKind::System,
move |event: KbEvent, _| match event {
KbEvent::Key { keysym, .. } => match keysym {
0xFF1B => kbd_clone.lock().unwrap().push_back(Cmd::Exit),
_ => (),
},
_ => (),
},
|_, _| {},
)
.expect("Failed to map keyboard");
2019-07-31 16:44:13 +02:00
//
// Cursor processing
//
2019-07-31 00:42:03 +02:00
let pointer_clone = cmd_queue.clone();
seat.get_pointer(move |ptr| {
2019-07-31 10:26:12 +02:00
let mut pos: (u32, u32) = (0, 0);
let mut vert_scroll: f64 = 0.0;
let mut horiz_scroll: f64 = 0.0;
let mut btn: u32 = 0;
let mut btn_clicked = false;
ptr.implement_closure(
move |evt, _| match evt {
wl_pointer::Event::Enter {
serial: _,
surface: _,
surface_x,
surface_y,
} => {
pos = (surface_x as u32, surface_y as u32);
}
wl_pointer::Event::Leave {
serial: _,
surface: _,
} => {
pos = (0, 0);
}
wl_pointer::Event::Motion {
time: _,
surface_x,
surface_y,
} => {
pos = (surface_x as u32, surface_y as u32);
}
wl_pointer::Event::Axis {
time: _,
axis,
value,
} => {
if axis == wl_pointer::Axis::VerticalScroll {
vert_scroll += value;
}
}
wl_pointer::Event::Button {
serial: _,
time: _,
button,
state,
} => match state {
wl_pointer::ButtonState::Released => {
btn = button;
btn_clicked = true;
}
_ => {}
},
wl_pointer::Event::Frame => {
if pos.0 < 20 || pos.1 < 20 {
// Ignore stuff outside our margins
return;
}
let pos = (pos.0 - 20, pos.1 - 20);
if vert_scroll != 0.0 || horiz_scroll != 0.0 {
pointer_clone.lock().unwrap().push_back(Cmd::Input {
pos: pos,
input: Input::Scroll {
pos: pos,
x: horiz_scroll,
y: vert_scroll,
},
});
vert_scroll = 0.0;
horiz_scroll = 0.0;
}
if btn_clicked {
pointer_clone.lock().unwrap().push_back(Cmd::Input {
pos: pos,
input: Input::Click {
pos: pos,
button: btn,
},
});
btn_clicked = false;
}
}
_ => {}
},
(),
)
})
.unwrap();
2019-07-31 00:42:03 +02:00
2019-07-31 10:26:12 +02:00
let mut modules = vec![
Module::new(Box::new(Clock::new()), (0, 0, 720, 320)),
Module::new(Box::new(Calendar::new()), (0, 384, 1280, 344)),
];
if let Ok(m) = Backlight::new() {
modules.push(Module::new(Box::new(m), (720, 0, 256, 24)));
}
2019-07-31 00:42:03 +02:00
2019-07-30 00:42:05 +02:00
App {
2019-07-31 16:44:13 +02:00
surface: surface,
shell_surface: shell_surface,
2019-07-30 00:42:05 +02:00
display: display,
event_queue: event_queue,
cmd_queue: cmd_queue,
pools: pools,
dimensions: dimensions,
2019-07-31 00:42:03 +02:00
modules: modules,
2019-07-30 00:42:05 +02:00
}
}
}
fn main() {
2019-07-30 16:31:42 +02:00
let (mut rx_pipe, mut tx_pipe) = pipe().unwrap();
2019-07-31 00:42:03 +02:00
let mut app = App::new((1320u32, 784u32));
2019-07-30 00:42:05 +02:00
2019-07-30 16:31:42 +02:00
let worker_queue = app.cmd_queue();
std::thread::spawn(move || loop {
let n = Local::now();
let target = (n + ChronoDuration::seconds(60))
.with_second(0)
.unwrap()
.with_nanosecond(0)
.unwrap();
let d = target - n;
std::thread::sleep(d.to_std().unwrap());
2019-07-31 00:42:03 +02:00
worker_queue.lock().unwrap().push_back(Cmd::Draw);
2019-07-30 16:31:42 +02:00
tx_pipe.write_all(&[0x1]).unwrap();
});
let mut fds = [
PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN),
PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN),
];
2019-07-30 00:42:05 +02:00
let q = app.cmd_queue();
loop {
let cmd = q.lock().unwrap().pop_front();
match cmd {
Some(cmd) => match cmd {
Cmd::Configure => {
let d = app.dimensions();
2019-07-31 16:44:13 +02:00
app.shell_surface().set_size(d.0, d.1);
2019-07-31 00:42:03 +02:00
app.wipe();
app.redraw(true).expect("Failed to draw");
app.flush_display();
2019-07-30 00:42:05 +02:00
}
Cmd::Draw => {
2019-07-31 00:42:03 +02:00
app.redraw(false).expect("Failed to draw");
2019-07-30 00:42:05 +02:00
app.flush_display();
2019-07-31 10:26:12 +02:00
}
Cmd::Input { pos, input } => {
if pos.0 >= 20 || pos.1 >= 20 {
// We need to deal with our margin.
if let Some(m) = app.get_module(pos) {
m.input(input);
q.lock().unwrap().push_back(Cmd::Draw);
}
}
2019-07-30 00:42:05 +02:00
}
Cmd::Exit => {
std::process::exit(0);
}
},
None => {
app.flush_display();
poll(&mut fds, -1).unwrap();
if fds[0].revents().unwrap().contains(PollFlags::POLLIN) {
if let Some(guard) = app.event_queue().prepare_read() {
if let Err(e) = guard.read_events() {
if e.kind() != ::std::io::ErrorKind::WouldBlock {
eprintln!(
"Error while trying to read from the wayland socket: {:?}",
e
);
}
}
}
app.event_queue()
.dispatch_pending()
.expect("Failed to dispatch all messages.");
}
if fds[1].revents().unwrap().contains(PollFlags::POLLIN) {
2019-07-30 16:31:42 +02:00
let mut v: Vec<u8> = vec![0x00];
rx_pipe.read_exact(&mut v).unwrap();
2019-07-30 00:42:05 +02:00
}
}
}
}
}