Make use of SIGWINCH.

This commit is contained in:
shy 2021-04-05 21:07:00 +02:00
parent 074a22f2d9
commit 851c950625
3 changed files with 40 additions and 15 deletions

View file

@ -1,5 +1,6 @@
use std::io::Write; use std::io::Write;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::sync::atomic::Ordering;
use termion::{color, cursor, style}; use termion::{color, cursor, style};
use termion::raw::RawTerminal; use termion::raw::RawTerminal;
use crate::{Clock, Config, Layout, Position}; use crate::{Clock, Config, Layout, Position};
@ -239,7 +240,7 @@ impl AlarmRoster {
// Update layout information. // Update layout information.
if layout.roster_width != width { if layout.roster_width != width {
layout.roster_width = width; layout.roster_width = width;
layout.force_recalc = true; layout.force_recalc.store(true, Ordering::Relaxed);
} }
} }

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::Config; use crate::Config;
use crate::common::*; use crate::common::*;
@ -13,7 +15,7 @@ pub struct Position {
pub struct Layout { pub struct Layout {
pub force_redraw: bool, // Redraw elements on screen. pub force_redraw: bool, // Redraw elements on screen.
pub force_recalc: bool, // Recalculate position of elements. pub force_recalc: Arc<AtomicBool>, // Recalculate position of elements.
pub plain: bool, // Plain style clock. pub plain: bool, // Plain style clock.
pub width: u16, pub width: u16,
pub height: u16, pub height: u16,
@ -34,7 +36,8 @@ impl Layout {
pub fn new(config: &Config) -> Layout { pub fn new(config: &Config) -> Layout {
Layout { Layout {
force_redraw: true, force_redraw: true,
force_recalc: false, // May be set by signal handler (SIGWINCH).
force_recalc: Arc::new(AtomicBool::new(true)),
plain: config.plain, plain: config.plain,
width: 0, width: 0,
height: 0, height: 0,
@ -53,15 +56,13 @@ impl Layout {
} }
pub fn update(&mut self, display_hours: bool) { pub fn update(&mut self, display_hours: bool) {
let (width, height) = termion::terminal_size() if self.force_recalc.swap(false, Ordering::Relaxed) {
.expect("Could not read terminal size!"); let (width, height) = termion::terminal_size()
.expect("Could not read terminal size!");
if self.force_recalc || self.width != width || self.height != height {
self.width = width; self.width = width;
self.height = height; self.height = height;
self.compute(display_hours); self.compute(display_hours);
self.force_redraw = true; self.force_redraw = true;
self.force_recalc = false;
} }
} }

View file

@ -37,6 +37,8 @@ const MENUBAR_SHORT: &str =
"[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit"; "[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit";
// Needed for signal_hook. // Needed for signal_hook.
const SIGTSTP: usize = signal_hook::consts::SIGTSTP as usize; 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 SIGTERM: usize = signal_hook::consts::SIGTERM as usize;
const SIGINT: usize = signal_hook::consts::SIGINT as usize; const SIGINT: usize = signal_hook::consts::SIGINT as usize;
const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize; const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize;
@ -71,8 +73,9 @@ fn main() {
// Register signal handlers. // Register signal handlers.
let signal = Arc::new(AtomicUsize::new(0)); let signal = Arc::new(AtomicUsize::new(0));
register_signal_handlers(&signal); 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, write!(stdout,
"{}{}", "{}{}",
clear::All, clear::All,
@ -91,6 +94,14 @@ fn main() {
// Suspend execution on SIGTSTP. // Suspend execution on SIGTSTP.
SIGTSTP => { SIGTSTP => {
suspend(&mut stdout); 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; layout.force_redraw = true;
}, },
// Exit main loop on SIGTERM and SIGINT. // Exit main loop on SIGTERM and SIGINT.
@ -103,6 +114,8 @@ fn main() {
}, },
// (Un-)Pause clock on SIGUSR2. // (Un-)Pause clock on SIGUSR2.
SIGUSR2 => clock.toggle(), SIGUSR2 => clock.toggle(),
// Window size changed.
//SIGWINCH => layout.force_recalc = true,
// We didn't register anything else. // We didn't register anything else.
_ => unreachable!(), _ => unreachable!(),
} }
@ -141,6 +154,9 @@ fn main() {
// Suspend an ^Z. // Suspend an ^Z.
Key::Ctrl('z') => { Key::Ctrl('z') => {
suspend(&mut stdout); 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; layout.force_redraw = true;
}, },
// Enter. // Enter.
@ -197,7 +213,7 @@ fn main() {
clock.start.elapsed().as_secs() as u32 clock.start.elapsed().as_secs() as u32
}; };
// Update screen content if necessary. // Update window content if necessary.
if elapsed != clock.elapsed || layout.force_redraw { if elapsed != clock.elapsed || layout.force_redraw {
// Update clock. Advance one day after 24 hours. // Update clock. Advance one day after 24 hours.
if elapsed < 24 * 60 * 60 { if elapsed < 24 * 60 * 60 {
@ -206,12 +222,14 @@ fn main() {
clock.next_day(); clock.next_day();
// "clock.elapsed" set by "clock.next_day()". // "clock.elapsed" set by "clock.next_day()".
alarm_roster.reset_all(); alarm_roster.reset_all();
layout.force_recalc = true; layout.force_recalc.store(true, Ordering::Relaxed);
} }
// Force recalculation of layout if we start displaying hours. // Force recalculation of layout if we start displaying hours.
if clock.elapsed == 3600 { layout.force_recalc = true }; if clock.elapsed == 3600 {
// Update screen size information and calculate the clock position. layout.force_recalc.store(true, Ordering::Relaxed);
}
// Update window size information and calculate the clock position.
layout.update(clock.elapsed >= 3600); layout.update(clock.elapsed >= 3600);
// Check for exceeded alarms. // 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. // requested.
if layout.force_redraw { if layout.force_redraw {
write!(stdout, write!(stdout,
@ -268,7 +286,7 @@ fn main() {
thread::sleep(time::Duration::from_millis(100)); 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, write!(stdout,
"{}{}{}", "{}{}{}",
clear::BeforeCursor, clear::BeforeCursor,
@ -312,6 +330,7 @@ fn parse_args(config: &mut Config) {
fn register_signal_handlers(signal: &Arc<AtomicUsize>) { fn register_signal_handlers(signal: &Arc<AtomicUsize>) {
flag::register_usize(SIGTSTP as i32, Arc::clone(&signal), SIGTSTP).unwrap(); 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(SIGTERM as i32, Arc::clone(&signal), SIGTERM).unwrap();
flag::register_usize(SIGINT as i32, Arc::clone(&signal), SIGINT).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(SIGUSR1 as i32, Arc::clone(&signal), SIGUSR1).unwrap();
@ -335,7 +354,10 @@ fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
if let Err(error) = signal_hook::low_level::emulate_default_handler(SIGTSTP as i32) { if let Err(error) = signal_hook::low_level::emulate_default_handler(SIGTSTP as i32) {
eprintln!("Error raising SIGTSTP: {}", error); eprintln!("Error raising SIGTSTP: {}", error);
} }
}
// Set up terminal when continuing from SIGTSTP or SIGSTOP.
fn continue_after_suspend<W: Write>(stdout: &mut RawTerminal<W>) {
stdout.activate_raw_mode() stdout.activate_raw_mode()
.unwrap_or_else(|error| { .unwrap_or_else(|error| {
eprintln!("Failed to re-enter raw terminal mode after suspend: {}", error); eprintln!("Failed to re-enter raw terminal mode after suspend: {}", error);
@ -349,6 +371,7 @@ fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
eprintln!("Error writing to stdout: {}", error); eprintln!("Error writing to stdout: {}", error);
std::process::exit(1); std::process::exit(1);
}); });
stdout.flush().unwrap();
} }
// Draw input buffer. // Draw input buffer.