diff --git a/Cargo.lock b/Cargo.lock index d75a83c..8f593fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -586,6 +586,14 @@ dependencies = [ "winapi 0.3.8 (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.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typenum" version = "1.11.2" @@ -723,6 +731,7 @@ dependencies = [ "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "smithay-client-toolkit 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "timerfd 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-client 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-protocols 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -818,6 +827,7 @@ dependencies = [ "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "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 typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/Cargo.toml b/Cargo.toml index 13c4f31..3ede7a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ lazy_static = "1.4" rcalc_lib = { version = "0.9" } rust-ini = "0.13" shlex = "0.1" +timerfd = "1.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } diff --git a/src/config.rs b/src/config.rs index 8339c71..7778eff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -91,7 +91,7 @@ impl Widget { .map(|x| x.unwrap()) .collect(), )), - Widget::Clock { font_size } => Some(widgets::clock::Clock::new(font_size, tx.clone())), + Widget::Clock { font_size } => Some(widgets::clock::Clock::new(font_size)), Widget::Date { font_size } => Some(widgets::date::Date::new(font_size)), Widget::Calendar { font_size, diff --git a/src/main.rs b/src/main.rs index e9e1aba..e01797e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,10 @@ use std::os::unix::io::AsRawFd; use std::os::unix::net::{UnixListener, UnixStream}; use std::sync::mpsc::channel; +use timerfd::{TimerFd, TimerState, SetTimeFlags}; use nix::poll::{poll, PollFd, PollFlags}; use os_pipe::pipe; +use chrono::{Local, Duration}; mod app; mod buffer; @@ -24,6 +26,7 @@ use app::{App, OutputMode}; use cmd::Cmd; use config::Config; use configfmt::ConfigFmt; +use widget::WaitContext; enum Mode { Start, @@ -222,14 +225,19 @@ fn main() { } }); - let mut fds = [ - PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN), - PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN), - ]; + let mut timer = TimerFd::new().unwrap(); + let ev_fd = PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN); + let rx_fd = PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN); + let tm_fd = PollFd::new(timer.as_raw_fd(), PollFlags::POLLIN); app.cmd_queue().lock().unwrap().push_back(Cmd::Draw); let mut visible = !daemon; + let mut wait_ctx = WaitContext{ + fds: Vec::new(), + target_time: None, + }; + let q = app.cmd_queue(); loop { let cmd = q.lock().unwrap().pop_front(); @@ -287,9 +295,27 @@ fn main() { None => { app.flush_display(); - poll(&mut fds, -1).unwrap(); + wait_ctx.fds.clear(); + wait_ctx.fds.push(ev_fd); + wait_ctx.fds.push(rx_fd); + wait_ctx.target_time = None; - if fds[0].revents().unwrap().contains(PollFlags::POLLIN) { + app.get_widget().wait(&mut wait_ctx); + + if let Some(target_time) = wait_ctx.target_time { + let n = Local::now(); + let sleep = if target_time > n { + target_time - n + } else { + Duration::seconds(0) + }; + timer.set_state(TimerState::Oneshot(sleep.to_std().unwrap()), SetTimeFlags::Default); + wait_ctx.fds.push(tm_fd); + } + + poll(&mut wait_ctx.fds, -1).unwrap(); + + if wait_ctx.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 { @@ -306,10 +332,16 @@ fn main() { .expect("Failed to dispatch all messages."); } - if fds[1].revents().unwrap().contains(PollFlags::POLLIN) { + if wait_ctx.fds[1].revents().unwrap().contains(PollFlags::POLLIN) { let mut v = [0x00]; rx_pipe.read_exact(&mut v).unwrap(); } + + if wait_ctx.target_time.is_some() && + wait_ctx.fds[wait_ctx.fds.len()-1].revents().unwrap().contains(PollFlags::POLLIN) { + timer.read(); + q.lock().unwrap().push_back(Cmd::Draw); + } } } } diff --git a/src/widget.rs b/src/widget.rs index 670bd18..827fb7e 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1,3 +1,4 @@ +use nix::poll::{PollFd}; use crate::buffer::Buffer; use crate::color::Color; use chrono::{DateTime, Local}; @@ -29,7 +30,25 @@ impl DrawReport { } } +pub struct WaitContext { + pub fds: Vec, + pub target_time: Option>, +} + +impl WaitContext { + pub fn set_time(&mut self, new_time: DateTime) { + if let Some(ot) = self.target_time { + if new_time < ot { + self.target_time = Some(new_time); + } + } else { + self.target_time = Some(new_time); + } + } +} + pub trait Widget { + fn wait(&self, ctx: &mut WaitContext); fn enter(&mut self); fn leave(&mut self); fn size(&self) -> (u32, u32); @@ -62,6 +81,11 @@ impl VerticalLayout { } impl Widget for VerticalLayout { + fn wait(&self, ctx: &mut WaitContext) { + for child in &self.children { + child.wait(ctx); + } + } fn enter(&mut self) { for child in &mut self.children { child.enter(); @@ -168,6 +192,11 @@ impl HorizontalLayout { } impl Widget for HorizontalLayout { + fn wait(&self, ctx: &mut WaitContext) { + for child in &self.children { + child.wait(ctx); + } + } fn enter(&mut self) { for child in &mut self.children { child.enter(); @@ -280,6 +309,9 @@ impl Margin { } impl Widget for Margin { + fn wait(&self, ctx: &mut WaitContext) { + self.child.wait(ctx) + } fn enter(&mut self) { self.child.enter() } @@ -354,6 +386,9 @@ impl Fixed { } impl Widget for Fixed { + fn wait(&self, ctx: &mut WaitContext) { + self.child.wait(ctx) + } fn enter(&mut self) { self.child.enter() } diff --git a/src/widgets/bar_widget.rs b/src/widgets/bar_widget.rs index a451bc0..2de4d0b 100644 --- a/src/widgets/bar_widget.rs +++ b/src/widgets/bar_widget.rs @@ -1,6 +1,6 @@ use crate::color::Color; use crate::draw::{draw_bar, draw_box, Font, ROBOTO_REGULAR}; -use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget}; +use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, WaitContext}; use std::sync::{Arc, Mutex}; @@ -61,6 +61,7 @@ impl BarWidget { } impl Widget for BarWidget { + fn wait(&self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) {} fn size(&self) -> (u32, u32) { diff --git a/src/widgets/calendar.rs b/src/widgets/calendar.rs index 898a4b8..74bf13b 100644 --- a/src/widgets/calendar.rs +++ b/src/widgets/calendar.rs @@ -1,7 +1,7 @@ use crate::buffer::Buffer; use crate::color::Color; use crate::draw::{Font, DEJAVUSANS_MONO, ROBOTO_REGULAR}; -use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget}; +use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, WaitContext}; use chrono::{Date, Datelike, Local}; @@ -177,6 +177,7 @@ impl Calendar { } impl Widget for Calendar { + fn wait(&self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) {} diff --git a/src/widgets/clock.rs b/src/widgets/clock.rs index 76e4015..cb56aee 100644 --- a/src/widgets/clock.rs +++ b/src/widgets/clock.rs @@ -1,9 +1,6 @@ -use crate::cmd::Cmd; use crate::color::Color; use crate::draw::{Font, ROBOTO_REGULAR}; -use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget}; - -use std::sync::mpsc::Sender; +use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, WaitContext}; use chrono::{DateTime, Datelike, Duration, Local, Timelike}; @@ -14,23 +11,7 @@ pub struct Clock { } impl Clock { - pub fn new(size: f32, ch: Sender) -> Box { - let _ = std::thread::Builder::new() - .name("clock_ticker".to_string()) - .spawn(move || loop { - let n = Local::now(); - let target = (n + Duration::seconds(60)) - .with_second(0) - .unwrap() - .with_nanosecond(0) - .unwrap(); - - let d = target - n; - - std::thread::sleep(d.to_std().unwrap()); - ch.send(Cmd::Draw).unwrap(); - }); - + pub fn new(size: f32) -> Box { let mut clock_cache = Font::new(&ROBOTO_REGULAR, size); clock_cache.add_str_to_cache("0123456789:"); @@ -45,6 +26,14 @@ impl Clock { } impl Widget for Clock { + fn wait(&self, ctx: &mut WaitContext) { + let target = (self.cur_time + Duration::seconds(60)) + .with_second(0) + .unwrap() + .with_nanosecond(0) + .unwrap(); + ctx.set_time(target); + } fn enter(&mut self) {} fn leave(&mut self) {} fn size(&self) -> (u32, u32) { diff --git a/src/widgets/date.rs b/src/widgets/date.rs index b09eb82..f6a843d 100644 --- a/src/widgets/date.rs +++ b/src/widgets/date.rs @@ -1,6 +1,6 @@ use crate::color::Color; use crate::draw::{Font, ROBOTO_REGULAR}; -use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget}; +use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, WaitContext}; use chrono::{DateTime, Datelike, Local}; @@ -27,6 +27,7 @@ impl Date { } impl Widget for Date { + fn wait(&self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) {} fn size(&self) -> (u32, u32) { diff --git a/src/widgets/launcher.rs b/src/widgets/launcher.rs index bc9e39d..64855ef 100644 --- a/src/widgets/launcher.rs +++ b/src/widgets/launcher.rs @@ -3,7 +3,7 @@ use crate::cmd::Cmd; use crate::color::Color; use crate::desktop::{load_desktop_files, Desktop}; use crate::draw::{Font, ROBOTO_REGULAR}; -use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget}; +use crate::widget::{DrawContext, DrawReport, KeyState, ModifiersState, Widget, WaitContext}; use std::cell::RefCell; use std::cmp::Ordering; @@ -192,6 +192,7 @@ fn wlcopy(s: &str) -> Result<(), String> { } impl Widget for Launcher { + fn wait(&self, _: &mut WaitContext) {} fn enter(&mut self) {} fn leave(&mut self) { self.input = "".to_string();