From c8bbd6e0aa615407f369d035f45ddc0d05aafbd3 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 25 Jan 2016 16:30:43 +0100 Subject: [PATCH] Restore terminal when games quit. --- games/aquatinspitz.cpp | 44 +++++++++++++++++++++++++++++++++++++++++- games/asteroids.cpp | 42 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/games/aquatinspitz.cpp b/games/aquatinspitz.cpp index f88acceb..d850e13c 100644 --- a/games/aquatinspitz.cpp +++ b/games/aquatinspitz.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2014. + Copyright(C) Jonas 'Sortie' Termansen 2014, 2015, 2016. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -28,8 +28,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -369,9 +372,48 @@ void mainloop(struct dispd_window* window) } } +// Reset the terminal state when the process terminates. +static struct termios saved_tio; + +static void restore_terminal_on_exit(void) +{ + tcsetattr(0, TCSAFLUSH, &saved_tio); +} + +static void restore_terminal_on_signal(int signum) +{ + if ( signum == SIGTSTP ) + { + struct termios tio; + tcgetattr(0, &tio); + tcsetattr(0, TCSAFLUSH, &saved_tio); + raise(SIGSTOP); + tcgetattr(0, &saved_tio); + tcsetattr(0, TCSAFLUSH, &tio); + return; + } + tcsetattr(0, TCSAFLUSH, &saved_tio); + raise(signum); +} + // Create a display context, run the game, and then cleanly exit. int main(int argc, char* argv[]) { + if ( !isatty(0) ) + error(1, errno, "standard input"); + if ( tcgetattr(0, &saved_tio) < 0 ) + error(1, errno, "tcsetattr: standard input"); + if ( atexit(restore_terminal_on_exit) != 0 ) + error(1, errno, "atexit"); + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = restore_terminal_on_signal; + sigaction(SIGTSTP, &sa, NULL); + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + if ( !dispd_initialize(&argc, &argv) ) error(1, 0, "couldn't initialize dispd library"); struct dispd_session* session = dispd_attach_default_session(); diff --git a/games/asteroids.cpp b/games/asteroids.cpp index 58636f35..4557226f 100644 --- a/games/asteroids.cpp +++ b/games/asteroids.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015, 2016. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -28,11 +28,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -1173,8 +1175,46 @@ void InitGame() new AsteroidField; } +static struct termios saved_tio; + +static void restore_terminal_on_exit(void) +{ + tcsetattr(0, TCSAFLUSH, &saved_tio); +} + +static void restore_terminal_on_signal(int signum) +{ + if ( signum == SIGTSTP ) + { + struct termios tio; + tcgetattr(0, &tio); + tcsetattr(0, TCSAFLUSH, &saved_tio); + raise(SIGSTOP); + tcgetattr(0, &saved_tio); + tcsetattr(0, TCSAFLUSH, &tio); + return; + } + tcsetattr(0, TCSAFLUSH, &saved_tio); + raise(signum); +} + int main(int argc, char* argv[]) { + if ( !isatty(0) ) + error(1, errno, "standard input"); + if ( tcgetattr(0, &saved_tio) < 0 ) + error(1, errno, "tcsetattr: standard input"); + if ( atexit(restore_terminal_on_exit) != 0 ) + error(1, errno, "atexit"); + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = restore_terminal_on_signal; + sigaction(SIGTSTP, &sa, NULL); + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + if ( !dispd_initialize(&argc, &argv) ) error(1, 0, "couldn't initialize dispd library"); struct dispd_session* session = dispd_attach_default_session();