diff --git a/src/layout.rs b/src/layout.rs index 9fb324c..03ab1cd 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; use crate::clock::Clock; pub struct Position { @@ -9,7 +7,7 @@ pub struct Position { pub struct Layout { pub force_redraw: bool, // Redraw elements on screen. - pub force_recalc: Arc, // Recalculate position of elements. + pub force_recalc: bool, // Recalculate position of elements. pub width: u16, pub height: u16, clock_width: u16, @@ -28,11 +26,10 @@ pub struct Layout { } impl Layout { - pub fn new(sigwinch: Arc) -> Layout { + pub fn new() -> Layout { Layout { force_redraw: true, - // May be set by signal handler (SIGWINCH). - force_recalc: sigwinch, + force_recalc: true, width: 0, height: 0, clock_width: 0, @@ -51,10 +48,12 @@ impl Layout { } } - pub fn update(&mut self, clock: &Clock, force: bool) { - if self.force_recalc.swap(false, Ordering::Relaxed) || force { - let (width, height) = termion::terminal_size() - .expect("Could not read terminal size!"); + pub fn update(&mut self, clock: &Clock, force: bool) + -> Result<(), std::io::Error> + { + if self.force_recalc || force { + self.force_recalc = false; + let (width, height) = termion::terminal_size()?; self.width = width; self.height = height; self.clock_width = clock.get_width(); @@ -63,6 +62,7 @@ impl Layout { self.compute(clock.elapsed >= 3600); self.force_redraw = true; } + Ok(()) } #[cfg(test)] @@ -146,7 +146,7 @@ impl Layout { pub fn set_roster_width(&mut self, width: u16) { if self.width != width { self.roster_width = width; - self.force_recalc.store(true, Ordering::Relaxed); + self.force_recalc = true; } } } diff --git a/src/lib.rs b/src/lib.rs index f49680f..86f47e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ extern crate termion; +extern crate signal_hook; pub mod alarm; mod buffer; pub mod clock; @@ -10,9 +11,9 @@ mod tests; use std::{env, process, thread, time}; use std::io::Write; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use signal_hook::{flag, low_level}; +use signal_hook::consts::signal::*; +use signal_hook::iterator::Signals; +use signal_hook::low_level; use termion::{clear, cursor, style}; use termion::raw::{IntoRawMode, RawTerminal}; use termion::event::Key; @@ -24,86 +25,70 @@ use alarm::{Countdown, exec_command}; pub use alarm::AlarmRoster; pub use consts::ui::*; -const SIGTSTP: usize = signal_hook::consts::SIGTSTP as usize; -const SIGWINCH: usize = signal_hook::consts::SIGWINCH as usize; -const SIGCONT: usize = signal_hook::consts::SIGCONT as usize; -const SIGTERM: usize = signal_hook::consts::SIGTERM as usize; -const SIGINT: usize = signal_hook::consts::SIGINT as usize; -const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize; -const SIGUSR2: usize = signal_hook::consts::SIGUSR2 as usize; - pub fn run( config: Config, mut alarm_roster: AlarmRoster, - signal: Arc, - sigwinch: Arc, spawned: &mut Option, ) -> Result<(), std::io::Error> { - let mut layout = Layout::new(sigwinch); + let mut layout = Layout::new(); // Initialise roster_width. layout.set_roster_width(alarm_roster.width()); let mut clock = Clock::new(&config); let mut countdown = Countdown::new(); let mut buffer = Buffer::new(); - - // Are we in insert mode? - let mut insert_mode = false; - let async_stdin = termion::async_stdin(); let mut input_keys = async_stdin.keys(); let stdout = std::io::stdout(); let mut stdout = stdout.lock().into_raw_mode()?; + // Are we in insert mode? + let mut insert_mode = false; + + // Register signals. + let mut signals = Signals::new(&[ + SIGTSTP, + SIGCONT, + SIGWINCH, + SIGTERM, + SIGINT, + SIGUSR1, + SIGUSR2, + ]).unwrap(); + // Clear window and hide cursor. write!(stdout, "{}{}", clear::All, cursor::Hide)?; // Main loop entry. loop { // Process received signals. - match signal.swap(0, Ordering::Relaxed) { - // No signal received. - 0 => (), - // Suspend execution on SIGTSTP. - SIGTSTP => { - suspend(&mut stdout)?; - // Clear SIGCONT, as we have already taken care to reset the - // terminal. - signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed); - layout.force_redraw = true; - // Jump to the start of the main loop. - continue; - }, - // Continuing after SIGSTOP. - SIGCONT => { - // This is reached when the process was suspended by SIGSTOP. - restore_after_suspend(&mut stdout)?; - layout.force_redraw = true; - }, - // Exit main loop on SIGTERM and SIGINT. - SIGTERM | SIGINT => break, - // Reset clock on SIGUSR1. - SIGUSR1 => { - clock.reset(); - alarm_roster.reset_all(); - layout.force_recalc.store(true, Ordering::Relaxed); - layout.force_redraw = true; - }, - // (Un-)Pause clock on SIGUSR2. - SIGUSR2 => clock.toggle(), - // We didn't register anything else. - _ => unreachable!(), + 'outer: for signal in signals.pending() { + match signal { + // Suspend execution on SIGTSTP. + SIGTSTP => suspend(&mut stdout)?, + // Continuing after SIGTSTP or SIGSTOP. + SIGCONT => { + restore_after_suspend(&mut stdout)?; + layout.force_redraw = true; + }, + SIGWINCH => layout.force_recalc = true, + // Exit main loop on SIGTERM and SIGINT. + SIGTERM | SIGINT => break 'outer, + // Reset clock on SIGUSR1. + SIGUSR1 => { + clock.reset(); + alarm_roster.reset_all(); + layout.force_recalc = true; + layout.force_redraw = true; + }, + // (Un-)Pause clock on SIGUSR2. + SIGUSR2 => clock.toggle(), + // We didn't register anything else. + _ => unreachable!(), + } } - // Update input buffer display, if requested. - /* - if buffer.altered { - buffer.draw(&mut stdout, &mut layout)?; - stdout.flush()?; - } - */ - // Update elapsed time. let elapsed = if clock.paused { clock.elapsed @@ -123,13 +108,13 @@ pub fn run( clock.next_day(); // "clock.elapsed" set by "clock.next_day()". alarm_roster.reset_all(); - layout.force_recalc.store(true, Ordering::Relaxed); + layout.force_recalc = true; } // Update window size information and calculate the clock position. // Also enforce recalculation of layout if we start displaying // hours. - layout.update(&clock, clock.elapsed == 3600); + layout.update(&clock, clock.elapsed == 3600)?; // Check for exceeded alarms. if let Some((time, label)) = alarm_roster.check(&mut clock, &layout, &mut countdown) { @@ -269,7 +254,7 @@ pub fn run( Key::Char('r') => { clock.reset(); alarm_roster.reset_all(); - layout.force_recalc.store(true, Ordering::Relaxed); + layout.force_recalc = true; layout.force_redraw = true; }, // (Un-)Pause on space. @@ -301,7 +286,7 @@ pub fn run( suspend(&mut stdout)?; // Clear SIGCONT, as we have already taken care to reset // the terminal. - signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed); + //signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed); layout.force_redraw = true; // Jump to the start of the main loop. continue; @@ -430,22 +415,8 @@ impl Config { } } -pub fn register_signals( - signal: &Arc, - recalc_flag: &Arc, -) { - flag::register_usize(SIGTSTP as i32, Arc::clone(&signal), SIGTSTP).unwrap(); - flag::register_usize(SIGCONT as i32, Arc::clone(&signal), SIGCONT).unwrap(); - flag::register_usize(SIGTERM as i32, Arc::clone(&signal), SIGTERM).unwrap(); - flag::register_usize(SIGINT as i32, Arc::clone(&signal), SIGINT).unwrap(); - flag::register_usize(SIGUSR1 as i32, Arc::clone(&signal), SIGUSR1).unwrap(); - flag::register_usize(SIGUSR2 as i32, Arc::clone(&signal), SIGUSR2).unwrap(); - // SIGWINCH sets "force_recalc" directly. - flag::register(SIGWINCH as i32, Arc::clone(&recalc_flag)).unwrap(); -} - // Prepare to suspend execution. Called on SIGTSTP. -fn suspend(mut stdout: &mut RawTerminal) +fn suspend(stdout: &mut RawTerminal) -> Result<(), std::io::Error> { write!(stdout, @@ -463,7 +434,8 @@ fn suspend(mut stdout: &mut RawTerminal) eprintln!("Error raising SIGTSTP: {}", error); } - restore_after_suspend(&mut stdout) + //restore_after_suspend(&mut stdout) + Ok(()) } // Set up terminal after SIGTSTP or SIGSTOP. diff --git a/src/main.rs b/src/main.rs index 85b934b..3476a8c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,6 @@ -extern crate signal_hook; - use std::{env, process}; use std::io::Write; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use kitchentimer::{Config, AlarmRoster, register_signals, run}; +use kitchentimer::{Config, AlarmRoster, run}; fn main() { @@ -17,15 +13,11 @@ fn main() { process::exit(1); }); - // Register signal handlers. - let signal = Arc::new(AtomicUsize::new(0)); - let sigwinch = Arc::new(AtomicBool::new(true)); - register_signals(&signal, &sigwinch); // Holds spawned child process if any. let mut spawned: Option = None; // Run main loop. - if let Err(e) = run(config, alarm_roster, signal, sigwinch, &mut spawned) { + if let Err(e) = run(config, alarm_roster, &mut spawned) { println!("Main loop exited with error: {}", e); process::exit(1); }