diff --git a/Cargo.lock b/Cargo.lock index 96013d6..d85e12a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,18 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nix" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nix" version = "0.14.1" @@ -156,6 +168,15 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "os_pipe" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -229,14 +250,6 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "timerfd" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-xid" version = "0.1.0" @@ -344,9 +357,9 @@ dependencies = [ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", "smithay-client-toolkit 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "timerfd 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -376,11 +389,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +"checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +"checksum os_pipe 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce1d819d394515aae0530eae02156fedfc98b4f0359bf3048a442be89a95157b" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" @@ -389,7 +404,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum smithay-client-toolkit 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8c23093ebdaac1ad67558c7aef153522c6b3be7e0257820909e3a25c4519e78d" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum timerfd 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6c9a7822e546fa39d0b5ae14a93a33903975b62af6597288aea77f0580a6abbe" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" diff --git a/Cargo.toml b/Cargo.toml index 5bdb76a..540f085 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,5 +12,5 @@ byteorder = "1.0" rusttype = "0.7.7" chrono = "0.4" nix = "0.14" -timerfd = "1.0" -memmap = "0.7" \ No newline at end of file +memmap = "0.7" +os_pipe = "0.8.1" \ No newline at end of file diff --git a/src/buffer.rs b/src/buffer.rs new file mode 100644 index 0000000..4ea2354 --- /dev/null +++ b/src/buffer.rs @@ -0,0 +1,104 @@ +use memmap::MmapMut; + +use crate::color::Color; + +pub struct Buffer<'a> { + buf: &'a mut MmapMut, + dimensions: (u32, u32), + subdimensions: Option<(u32, u32, u32, u32)>, +} + +impl<'a> Buffer<'a> { + pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> Buffer { + Buffer { + buf: buf, + dimensions: dimensions, + subdimensions: None, + } + } + + pub fn get_bounds(&self) -> (u32, u32, u32, u32) { + if let Some(subdim) = self.subdimensions { + subdim + } else { + (0, 0, self.dimensions.0, self.dimensions.1) + } + } + + pub fn subdimensions(&mut self, subdimensions: (u32, u32, u32, u32)) -> Buffer { + let bounds = self.get_bounds(); + if subdimensions.0 + subdimensions.2 > bounds.2 + || subdimensions.1 + subdimensions.3 > bounds.3 + { + panic!( + "cannot create subdimensions larger than buffer: {:?} > {:?}", + subdimensions, bounds + ); + } + + Buffer { + buf: self.buf, + dimensions: self.dimensions, + subdimensions: Some(( + subdimensions.0 + bounds.0, + subdimensions.1 + bounds.1, + subdimensions.2, + subdimensions.3, + )), + } + } + + pub fn memset(&mut self, c: &Color) { + unsafe { + let ptr = self.buf.as_mut_ptr(); + for p in 0..(self.dimensions.0 * self.dimensions.1) { + *((ptr as *mut u32).offset(p as isize)) = c.as_argb8888(); + } + } + } + + pub fn highlight_bounds(&mut self, c: &Color) { + let end = if let Some(subdim) = self.subdimensions { + (subdim.2, subdim.3) + } else { + (self.dimensions.0, self.dimensions.1) + }; + + for x in 0..end.0 { + self.put((x, 0), c); + self.put((x, end.1 - 1), c); + } + for y in 0..end.1 { + self.put((0, y), c); + self.put((end.0 - 1, y), c); + } + } + + pub fn put(&mut self, pos: (u32, u32), c: &Color) { + let true_pos = if let Some(subdim) = self.subdimensions { + if pos.0 > subdim.2 || pos.1 > subdim.3 { + panic!( + "put({:?}) is not within subdimensions of buffer ({:?})", + pos, subdim + ); + } + (pos.0 + subdim.0, pos.1 + subdim.1) + } else { + if pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1 { + panic!( + "put({:?}) is not within dimensions of buffer ({:?})", + pos, self.dimensions + ); + } + pos + }; + + unsafe { + let ptr = self + .buf + .as_mut_ptr() + .offset(4 * (true_pos.0 + (true_pos.1 * self.dimensions.0)) as isize); + *(ptr as *mut u32) = c.as_argb8888(); + } + } +} diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..2ea6d6f --- /dev/null +++ b/src/color.rs @@ -0,0 +1,66 @@ +#[derive(Debug)] +pub struct Color { + red: f32, + green: f32, + blue: f32, + opacity: f32, +} + +impl Color { + pub fn new(red: f32, green: f32, blue: f32, opacity: f32) -> Color { + Color { + red: if red > 1.0 { + 1.0 + } else if red < 0.0 { + 0.0 + } else { + red + }, + green: if green > 1.0 { + 1.0 + } else if green < 0.0 { + 0.0 + } else { + green + }, + blue: if blue > 1.0 { + 1.0 + } else if blue < 0.0 { + 0.0 + } else { + blue + }, + opacity: if opacity > 1.0 { + 1.0 + } else if opacity < 0.0 { + 0.0 + } else { + opacity + }, + } + } + + pub fn blend(&self, other: &Color, ratio: f32) -> Color { + let ratio = if ratio > 1.0 { + 1.0 + } else if ratio < 0.0 { + 0.0 + } else { + ratio + }; + + Color { + red: self.red + ((other.red - self.red) * ratio), + green: self.green + ((other.green - self.green) * ratio), + blue: self.blue + ((other.blue - self.blue) * ratio), + opacity: self.opacity + ((other.opacity - self.opacity) * ratio), + } + } + + pub fn as_argb8888(&self) -> u32 { + ((255.0 * self.opacity) as u32) << 24 + | ((255.0 * self.red) as u32) << 16 + | ((255.0 * self.green) as u32) << 8 + | ((255.0 * self.red) as u32) + } +} \ No newline at end of file diff --git a/src/draw.rs b/src/draw.rs new file mode 100644 index 0000000..a61fab3 --- /dev/null +++ b/src/draw.rs @@ -0,0 +1,295 @@ +use crate::color::Color; +use crate::buffer::Buffer; +use rusttype::{point, Font, Scale}; +use chrono::{Date, DateTime, Datelike, Local, Timelike}; + +static DEJAVUSANS_MONO: &'static [u8] = include_bytes!("../fonts/dejavu/DejaVuSansMono.ttf"); +static ROBOTO_REGULAR: &'static [u8] = include_bytes!("../fonts/Roboto-Regular.ttf"); + +fn draw_text( + font_data: &'static [u8], + buf: &mut Buffer, + background_color: &Color, + color: &Color, + size: f32, + s: &str, +) -> Result<(), ::std::io::Error> { + // Load the font + // This only succeeds if collection consists of one font + let font = Font::from_bytes(font_data as &[u8]).expect("Error constructing Font"); + + // The font size to use + let scale = Scale::uniform(size); + + let v_metrics = font.v_metrics(scale); + + // layout the glyphs in a line with 20 pixels padding + let glyphs: Vec<_> = font + .layout(s, scale, point(20.0, 20.0 + v_metrics.ascent)) + .collect(); + + // Loop through the glyphs in the text, positing each one on a line + for glyph in glyphs { + if let Some(bounding_box) = glyph.pixel_bounding_box() { + // Draw the glyph into the image per-pixel by using the draw closure + glyph.draw(|x, y, o| { + let x = x + bounding_box.min.x as u32; + let y = y + bounding_box.min.y as u32; + let o = if o > 1.0 { + 1.0 + } else if o < 0.0 { + 0.0 + } else { + o + }; + buf.put((x, y), &background_color.blend(color, o)); + }); + } + } + + Ok(()) +} + +fn draw_text_fixed_width( + font_data: &'static [u8], + buf: &mut Buffer, + background_color: &Color, + color: &Color, + size: f32, + distances: Vec, + s: &str, +) -> Result<(), ::std::io::Error> { + // Load the font + // This only succeeds if collection consists of one font + let font = Font::from_bytes(font_data as &[u8]).expect("Error constructing Font"); + + // The font size to use + let scale = Scale::uniform(size); + + let v_metrics = font.v_metrics(scale); + + // layout the glyphs in a line with 20 pixels padding + let glyphs: Vec<_> = font + .layout(s, scale, point(20.0, 20.0 + v_metrics.ascent)) + .collect(); + + // Loop through the glyphs in the text, positing each one on a line + let mut x_pos: usize = 0; + let mut x_off: u32 = 0; + for glyph in glyphs { + if let Some(bounding_box) = glyph.pixel_bounding_box() { + let x_dist = distances[x_pos]; + let width = (bounding_box.max.x - bounding_box.min.x) as u32; + let offset = (x_dist - width) / 2; + // Draw the glyph into the image per-pixel by using the draw closure + glyph.draw(|x, y, o| { + let off = x_off + offset + 20; + let x = x + off as u32; + let y = y + bounding_box.min.y as u32; + let o = if o > 1.0 { + 1.0 + } else if o < 0.0 { + 0.0 + } else { + o + }; + buf.put((x, y), &background_color.blend(color, o)); + }); + x_pos += 1; + x_off += x_dist; + } + } + + Ok(()) +} + +pub fn draw_clock( + buf: &mut Buffer, + background_color: &Color, + time: &DateTime, +) -> Result<(), ::std::io::Error> { + draw_text( + ROBOTO_REGULAR, + &mut buf.subdimensions((0, 0, 448, 96)), + background_color, + &Color::new(1.0, 1.0, 1.0, 1.0), + 64.0, + &format!( + "{:?}, {:02}/{:02}/{:4}", + time.weekday(), + time.day(), + time.month(), + time.year() + ), + )?; + + draw_text_fixed_width( + ROBOTO_REGULAR, + &mut buf.subdimensions((0, 64, 288*2+64, 256)), + background_color, + &Color::new(1.0, 1.0, 1.0, 1.0), + 256.0, + vec![120, 120, 64, 120, 120], + &format!("{:02}:{:02}", time.hour(), time.minute()), + )?; + + Ok(()) +} + +fn draw_month( + buf: &mut Buffer, + background_color: &Color, + orig: &Date, + time: &Date, +) -> Result<(), ::std::io::Error> { + let mut time = time.clone(); + let mut y_off = 1; + let mut done = false; + + let month_str = match time.month() { + 1 => "January", + 2 => "February", + 3 => "March", + 4 => "April", + 5 => "May", + 6 => "June", + 7 => "July", + 8 => "August", + 9 => "September", + 10 => "October", + 11 => "November", + 12 => "December", + _ => panic!("impossible value"), + }; + + // + // Draw the of the month + // + + draw_text( + ROBOTO_REGULAR, + &mut buf.subdimensions((0, 0, 364, 96)), + background_color, + &Color::new(1.0, 1.0, 1.0, 1.0), + 68.0, + month_str, + )?; + + // + // Draw the week day + // + + for idx in 1..8 { + let wk_chr = match idx { + 1 => "MON", + 2 => "TUE", + 3 => "WED", + 4 => "THU", + 5 => "FRI", + 6 => "SUN", + 7 => "SAT", + _ => panic!("impossible value"), + }; + + draw_text( + DEJAVUSANS_MONO, + &mut buf.subdimensions((idx * 48 + 4, (y_off * 32) + 64, 64, 64)), + background_color, + &Color::new(0.75, 0.75, 0.75, 1.0), + 16.0, + &wk_chr, + )?; + } + + y_off += 1; + + while !done { + let mut x_pos = 0; + + // + // Find the start of this week + // + let mut wkday = time.weekday(); + while wkday != chrono::Weekday::Mon { + x_pos += 1; + wkday = wkday.pred(); + } + + // + // Draw the week number + // + let wk = time.iso_week(); + draw_text( + DEJAVUSANS_MONO, + &mut buf.subdimensions((0 * 48, (y_off * 32) + 64, 64, 64)), + background_color, + &Color::new(0.75, 0.75, 0.75, 1.0), + 32.0, + &format!("{:02}", wk.week()), + )?; + x_pos += 1; + + // + // Draw the dates + // + while x_pos < 8 { + let c = if time.day() == orig.day() && time.month() == orig.month() { + Color::new(1.0, 1.0, 1.0, 1.0) + } else { + Color::new(0.5, 0.5, 0.5, 1.0) + }; + draw_text( + DEJAVUSANS_MONO, + &mut buf.subdimensions((x_pos * 48, (y_off * 32) + 64, 64, 64)), + background_color, + &c, + 32.0, + &format!("{:02}", time.day()), + )?; + let t = time.with_day(time.day() + 1); + if t.is_none() { + done = true; + break; + } + time = t.unwrap(); + x_pos += 1; + } + + y_off += 1; + } + + Ok(()) +} + +pub fn draw_calendar( + buf: &mut Buffer, + background_color: &Color, + time: &Date, +) -> Result<(), ::std::io::Error> { + // ~1546x384px + let t = time.with_day(1).unwrap(); + draw_month( + &mut buf.subdimensions((0, 0, 448, 384)), + background_color, + time, + &t.pred().with_day(1).unwrap(), + )?; + draw_month( + &mut buf.subdimensions((512, 0, 448, 384)), + background_color, + time, + &t, + )?; + let n = if t.month() == 12 { + t.with_year(t.year() + 1).unwrap().with_month(1).unwrap() + } else { + t.with_month(t.month() + 1).unwrap() + }; + draw_month( + &mut buf.subdimensions((1024, 0, 448, 384)), + background_color, + time, + &n, + )?; + Ok(()) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 72b73e7..9d0fb88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,17 +5,14 @@ extern crate chrono; extern crate smithay_client_toolkit as sctk; use std::collections::VecDeque; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use memmap::MmapMut; use nix::poll::{poll, PollFd, PollFlags}; +use os_pipe::pipe; -use chrono::{Date, DateTime, Datelike, Local, Timelike}; - -use rusttype::{point, Font, Scale}; +use chrono::{Duration as ChronoDuration, Local, Timelike}; use sctk::keyboard::{map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatKind}; use sctk::reexports::client::protocol::wl_shm; @@ -24,9 +21,15 @@ use sctk::utils::DoubleMemPool; use sctk::window::{ConceptFrame, Event as WEvent, Window}; use sctk::Environment; -static DEJAVUSANS_MONO: &'static [u8] = include_bytes!("../fonts/dejavu/DejaVuSansMono.ttf"); -static ROBOTO_REGULAR: &'static [u8] = include_bytes!("../fonts/Roboto-Regular.ttf"); +mod color; +mod buffer; +mod draw; +use crate::color::Color; +use crate::buffer::Buffer; +use crate::draw::{draw_clock, draw_calendar}; + +#[derive(Debug)] enum Cmd { Exit, Configure, @@ -43,207 +46,6 @@ struct App { dimensions: (u32, u32), } -fn draw_text( - font_data: &'static [u8], - mmap: &mut MmapMut, - pos: (u32, u32), - dimensions: (u32, u32), - size: f32, - color: (u8, u8, u8), - s: &str, -) -> Result<(), ::std::io::Error> { - // Load the font - // This only succeeds if collection consists of one font - let font = Font::from_bytes(font_data as &[u8]).expect("Error constructing Font"); - - // The font size to use - let scale = Scale::uniform(size); - - let v_metrics = font.v_metrics(scale); - - // layout the glyphs in a line with 20 pixels padding - let glyphs: Vec<_> = font - .layout(s, scale, point(20.0, 20.0 + v_metrics.ascent)) - .collect(); - - // Loop through the glyphs in the text, positing each one on a line - for glyph in glyphs { - if let Some(bounding_box) = glyph.pixel_bounding_box() { - // Draw the glyph into the image per-pixel by using the draw closure - glyph.draw(|x, y, o| { - let p = (((pos.1 + y + bounding_box.min.y as u32) * dimensions.0) - + (pos.0 + x + bounding_box.min.x as u32)) - * 4; - let a: u32 = 255 << 24; - let r: u32 = (((color.0 as f32) * o) as u32) << 16; - let g: u32 = (((color.1 as f32) * o) as u32) << 8; - let b: u32 = ((color.2 as f32) * o) as u32; - let v = a | r | g | b; - unsafe { - let ptr = mmap.as_mut_ptr().offset(p as isize); - *(ptr as *mut u32) = v; - } - }); - } - } - - Ok(()) -} - -fn draw_clock( - mmap: &mut MmapMut, - time: &DateTime, - pos: (u32, u32), - dimensions: (u32, u32), -) -> Result<(), ::std::io::Error> { - draw_text( - ROBOTO_REGULAR, - mmap, - pos, - dimensions, - 64.0, - (255, 255, 255), - &format!( - "{:?}, {:02}/{:02}/{:4}", - time.weekday(), - time.day(), - time.month(), - time.year() - ), - )?; - - draw_text( - ROBOTO_REGULAR, - mmap, - (pos.0, pos.1 + 64), - dimensions, - 256.0, - (255, 255, 255), - &format!("{:02}", time.hour()), - )?; - - draw_text( - ROBOTO_REGULAR, - mmap, - (pos.0 + 256, pos.1 + 64), - dimensions, - 256.0, - (255, 255, 255), - ":", - )?; - - draw_text( - ROBOTO_REGULAR, - mmap, - (pos.0 + 320, pos.1 + 64), - dimensions, - 256.0, - (255, 255, 255), - &format!("{:02}", time.minute()), - )?; - Ok(()) -} - -fn draw_month( - mmap: &mut MmapMut, - orig: &Date, - time: &Date, - pos: (u32, u32), - dimensions: (u32, u32), -) -> Result<(), ::std::io::Error> { - let mut time = time.clone(); - let mut y_off = 1; - let mut done = false; - - let month_str = match time.month() { - 1 => "January", - 2 => "February", - 3 => "March", - 4 => "April", - 5 => "May", - 6 => "June", - 7 => "July", - 8 => "August", - 9 => "September", - 10 => "October", - 11 => "November", - 12 => "December", - _ => panic!("impossible value"), - }; - - draw_text( - ROBOTO_REGULAR, - mmap, - pos, - dimensions, - 68.0, - (255, 255, 255), - month_str, - )?; - - while !done { - let mut x_pos = 0; - let mut wk = time.weekday(); - while wk != chrono::Weekday::Sun { - x_pos += 1; - wk = wk.pred(); - } - - while x_pos < 7 { - let c = if time.day() == orig.day() && time.month() == orig.month() { - (255, 255, 255) - } else { - (96, 96, 96) - }; - draw_text( - DEJAVUSANS_MONO, - mmap, - (pos.0 + (x_pos * 48), pos.1 + (y_off * 32) + 64), - dimensions, - 32.0, - c, - &format!("{:02}", time.day()), - )?; - let t = time.with_day(time.day() + 1); - if t.is_none() { - done = true; - break; - } - time = t.unwrap(); - x_pos += 1; - } - - y_off += 1; - } - - Ok(()) -} - -fn draw_calendar( - mmap: &mut MmapMut, - time: &Date, - pos: (u32, u32), - dimensions: (u32, u32), -) -> Result<(), ::std::io::Error> { - // ~1546x384px - let t = time.with_day(1).unwrap(); - draw_month( - mmap, - time, - &t.pred().with_day(1).unwrap(), - (pos.0, pos.1), - dimensions, - )?; - draw_month(mmap, time, &t, (pos.0 + 512, pos.1), dimensions)?; - let n = if t.month() == 12 { - t.with_year(t.year() + 1).unwrap().with_month(1).unwrap() - } else { - t.with_month(t.month() + 1).unwrap() - }; - draw_month(mmap, time, &n, (pos.0 + 1024, pos.1), dimensions)?; - Ok(()) -} - impl App { fn redraw(&mut self) -> Result<(), ::std::io::Error> { let pool = match self.pools.pool() { @@ -259,19 +61,18 @@ impl App { .expect("Failed to resize the memory pool."); let mmap = pool.mmap(); - { - unsafe { - let ptr = mmap.as_mut_ptr(); - for p in 0..(buf_x * buf_y) { - *((ptr as *mut u32).offset(p as isize)) = 0xC0000000; - } - } - } + let mut buf = Buffer::new(mmap, self.dimensions); + let bg = Color::new(0.0, 0.0, 0.0, 0.8); + buf.memset(&bg); let time = Local::now(); - draw_clock(mmap, &time, (0, 0), (buf_x, buf_y))?; - draw_calendar(mmap, &time.date(), (0, 384), (buf_x, buf_y))?; + draw_clock(&mut buf.subdimensions((0, 0, 720, 320)), &bg, &time)?; + draw_calendar( + &mut buf.subdimensions((0, 384, 1472, 384)), + &bg, + &time.date(), + )?; mmap.flush().unwrap(); @@ -376,18 +177,32 @@ impl App { } fn main() { - let mut app = App::new((1408u32, 734u32)); + let (mut rx_pipe, mut tx_pipe) = pipe().unwrap(); + + let mut app = App::new((1600u32, 784u32)); let mut last_time = Local::now(); - let mut tfd = timerfd::TimerFd::new_custom(timerfd::ClockId::Monotonic, true, true).unwrap(); - tfd.set_state( - timerfd::TimerState::Periodic { - current: Duration::from_millis(2000), - interval: Duration::from_millis(2000), - }, - timerfd::SetTimeFlags::Default, - ); + 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()); + worker_queue.lock().unwrap().push_back(Cmd::MaybeDraw); + 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), + ]; let q = app.cmd_queue(); loop { @@ -417,10 +232,6 @@ fn main() { None => { app.flush_display(); - let mut fds = [ - PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN), - PollFd::new(tfd.as_raw_fd(), PollFlags::POLLIN), - ]; poll(&mut fds, -1).unwrap(); if fds[0].revents().unwrap().contains(PollFlags::POLLIN) { @@ -441,8 +252,8 @@ fn main() { } if fds[1].revents().unwrap().contains(PollFlags::POLLIN) { - tfd.read(); - q.lock().unwrap().push_back(Cmd::MaybeDraw); + let mut v: Vec = vec![0x00]; + rx_pipe.read_exact(&mut v).unwrap(); } } }