From 851c9506251581cd650df35fb1e474a33fdfc5c8 Mon Sep 17 00:00:00 2001 From: shy Date: Mon, 5 Apr 2021 21:07:00 +0200 Subject: [PATCH] Make use of SIGWINCH. --- src/alarm.rs | 3 ++- src/layout.rs | 15 ++++++++------- src/main.rs | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/alarm.rs b/src/alarm.rs index a64b20b..dfbef04 100644 --- a/src/alarm.rs +++ b/src/alarm.rs @@ -1,5 +1,6 @@ use std::io::Write; use std::process::{Command, Stdio}; +use std::sync::atomic::Ordering; use termion::{color, cursor, style}; use termion::raw::RawTerminal; use crate::{Clock, Config, Layout, Position}; @@ -239,7 +240,7 @@ impl AlarmRoster { // Update layout information. if layout.roster_width != width { layout.roster_width = width; - layout.force_recalc = true; + layout.force_recalc.store(true, Ordering::Relaxed); } } diff --git a/src/layout.rs b/src/layout.rs index 867198e..65b63ff 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use crate::Config; use crate::common::*; @@ -13,7 +15,7 @@ pub struct Position { pub struct Layout { pub force_redraw: bool, // Redraw elements on screen. - pub force_recalc: bool, // Recalculate position of elements. + pub force_recalc: Arc, // Recalculate position of elements. pub plain: bool, // Plain style clock. pub width: u16, pub height: u16, @@ -34,7 +36,8 @@ impl Layout { pub fn new(config: &Config) -> Layout { Layout { force_redraw: true, - force_recalc: false, + // May be set by signal handler (SIGWINCH). + force_recalc: Arc::new(AtomicBool::new(true)), plain: config.plain, width: 0, height: 0, @@ -53,15 +56,13 @@ impl Layout { } pub fn update(&mut self, display_hours: bool) { - let (width, height) = termion::terminal_size() - .expect("Could not read terminal size!"); - - if self.force_recalc || self.width != width || self.height != height { + if self.force_recalc.swap(false, Ordering::Relaxed) { + let (width, height) = termion::terminal_size() + .expect("Could not read terminal size!"); self.width = width; self.height = height; self.compute(display_hours); self.force_redraw = true; - self.force_recalc = false; } } diff --git a/src/main.rs b/src/main.rs index 28218f9..cdc5ab6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,8 @@ const MENUBAR_SHORT: &str = "[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit"; // Needed for signal_hook. 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; @@ -71,8 +73,9 @@ fn main() { // Register signal handlers. let signal = Arc::new(AtomicUsize::new(0)); register_signal_handlers(&signal); + flag::register(SIGWINCH as i32, Arc::clone(&layout.force_recalc)).unwrap(); - // Clear screen and hide cursor. + // Clear window and hide cursor. write!(stdout, "{}{}", clear::All, @@ -91,6 +94,14 @@ fn main() { // Suspend execution on SIGTSTP. SIGTSTP => { suspend(&mut stdout); + // Clear SIGCONT and continue from here. + signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed); + continue_after_suspend(&mut stdout); + layout.force_redraw = true; + }, + // Continuing after SIGSTOP. + SIGCONT => { + continue_after_suspend(&mut stdout); layout.force_redraw = true; }, // Exit main loop on SIGTERM and SIGINT. @@ -103,6 +114,8 @@ fn main() { }, // (Un-)Pause clock on SIGUSR2. SIGUSR2 => clock.toggle(), + // Window size changed. + //SIGWINCH => layout.force_recalc = true, // We didn't register anything else. _ => unreachable!(), } @@ -141,6 +154,9 @@ fn main() { // Suspend an ^Z. Key::Ctrl('z') => { suspend(&mut stdout); + // Clear SIGCONT and continue from here. + signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed); + continue_after_suspend(&mut stdout); layout.force_redraw = true; }, // Enter. @@ -197,7 +213,7 @@ fn main() { clock.start.elapsed().as_secs() as u32 }; - // Update screen content if necessary. + // Update window content if necessary. if elapsed != clock.elapsed || layout.force_redraw { // Update clock. Advance one day after 24 hours. if elapsed < 24 * 60 * 60 { @@ -206,12 +222,14 @@ fn main() { clock.next_day(); // "clock.elapsed" set by "clock.next_day()". alarm_roster.reset_all(); - layout.force_recalc = true; + layout.force_recalc.store(true, Ordering::Relaxed); } // Force recalculation of layout if we start displaying hours. - if clock.elapsed == 3600 { layout.force_recalc = true }; - // Update screen size information and calculate the clock position. + if clock.elapsed == 3600 { + layout.force_recalc.store(true, Ordering::Relaxed); + } + // Update window size information and calculate the clock position. layout.update(clock.elapsed >= 3600); // Check for exceeded alarms. @@ -226,7 +244,7 @@ fn main() { } } - // Clear the screen and redraw menu bar, alarm roster and buffer if + // Clear the window and redraw menu bar, alarm roster and buffer if // requested. if layout.force_redraw { write!(stdout, @@ -268,7 +286,7 @@ fn main() { thread::sleep(time::Duration::from_millis(100)); } - // Main loop exited. Clear screen and restore cursor. + // Main loop exited. Clear window and restore cursor. write!(stdout, "{}{}{}", clear::BeforeCursor, @@ -312,6 +330,7 @@ fn parse_args(config: &mut Config) { fn register_signal_handlers(signal: &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(); @@ -335,7 +354,10 @@ fn suspend(stdout: &mut RawTerminal) { if let Err(error) = signal_hook::low_level::emulate_default_handler(SIGTSTP as i32) { eprintln!("Error raising SIGTSTP: {}", error); } +} +// Set up terminal when continuing from SIGTSTP or SIGSTOP. +fn continue_after_suspend(stdout: &mut RawTerminal) { stdout.activate_raw_mode() .unwrap_or_else(|error| { eprintln!("Failed to re-enter raw terminal mode after suspend: {}", error); @@ -349,6 +371,7 @@ fn suspend(stdout: &mut RawTerminal) { eprintln!("Error writing to stdout: {}", error); std::process::exit(1); }); + stdout.flush().unwrap(); } // Draw input buffer.