Home | History | Annotate | Line # | Download | only in libcurses
tstp.c revision 1.31
      1 /*	$NetBSD: tstp.c,v 1.31 2004/03/22 18:57:10 jdc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1981, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)tstp.c	8.3 (Berkeley) 5/4/94";
     36 #else
     37 __RCSID("$NetBSD: tstp.c,v 1.31 2004/03/22 18:57:10 jdc Exp $");
     38 #endif
     39 #endif				/* not lint */
     40 
     41 #include <sys/ioctl.h>
     42 
     43 #include <errno.h>
     44 #include <signal.h>
     45 #include <termios.h>
     46 #include <unistd.h>
     47 
     48 #include "curses.h"
     49 #include "curses_private.h"
     50 
     51 static struct sigaction	otsa, owsa;
     52 
     53 /*
     54  * stop_signal_handler --
     55  *	Handle stop signals.
     56  */
     57 void
     58 __stop_signal_handler(/*ARGSUSED*/int signo)
     59 {
     60 	sigset_t oset, set;
     61 
     62 	/*
     63 	 * Block window change and timer signals.  The latter is because
     64 	 * applications use timers to decide when to repaint the screen.
     65 	 */
     66 	(void) sigemptyset(&set);
     67 	(void) sigaddset(&set, SIGALRM);
     68 	(void) sigaddset(&set, SIGWINCH);
     69 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
     70 
     71 	/*
     72 	 * End the window, which also resets the terminal state to the
     73 	 * original modes.
     74 	 */
     75 	__stopwin();
     76 
     77 	/* Unblock SIGTSTP. */
     78 	(void) sigemptyset(&set);
     79 	(void) sigaddset(&set, SIGTSTP);
     80 	(void) sigprocmask(SIG_UNBLOCK, &set, NULL);
     81 
     82 	/* Stop ourselves. */
     83 	(void) kill(0, SIGTSTP);
     84 
     85 	/* Time passes ... */
     86 
     87 	/* restart things */
     88 	__restartwin();
     89 
     90 	/* Reset the signals. */
     91 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
     92 }
     93 
     94 /*
     95  * Set the TSTP handler.
     96  */
     97 void
     98 __set_stophandler(void)
     99 {
    100 	struct sigaction sa;
    101 	sa.sa_handler = __stop_signal_handler;
    102 	sa.sa_flags = SA_RESTART;
    103 	sigemptyset(&sa.sa_mask);
    104 	sigaction(SIGTSTP, &sa, &otsa);
    105 }
    106 
    107 /*
    108  * Restore the TSTP handler.
    109  */
    110 void
    111 __restore_stophandler(void)
    112 {
    113 	sigaction(SIGTSTP, &otsa, NULL);
    114 }
    115 
    116 /*
    117  * winch_signal_handler --
    118  *	Handle winch signals by pushing KEY_RESIZE into the input stream.
    119  */
    120 void
    121 __winch_signal_handler(/*ARGSUSED*/int signo)
    122 {
    123 	struct winsize win;
    124 
    125 	if (ioctl(fileno(_cursesi_screen->outfd), TIOCGWINSZ, &win) != -1 &&
    126 	    win.ws_row != 0 && win.ws_col != 0) {
    127 		LINES = win.ws_row;
    128 		COLS = win.ws_col;
    129 	}
    130 	/*
    131 	 * If there was a previous handler, call that,
    132 	 * otherwise tell getch() to send KEY_RESIZE.
    133 	 */
    134 	if (owsa.sa_handler != __winch_signal_handler)
    135 		owsa.sa_handler(signo);
    136 	else
    137 		_cursesi_screen->resized = 1;
    138 }
    139 
    140 /*
    141  * Set the WINCH handler.
    142  */
    143 void
    144 __set_winchhandler(void)
    145 {
    146 	struct sigaction sa;
    147 	sa.sa_handler = __winch_signal_handler;
    148 	sa.sa_flags = 0;
    149 	sigemptyset(&sa.sa_mask);
    150 	sigaction(SIGWINCH, &sa, &owsa);
    151 }
    152 
    153 /*
    154  * Restore the TSTP handler.
    155  */
    156 void
    157 __restore_winchhandler(void)
    158 {
    159 	sigaction(SIGTSTP, &owsa, NULL);
    160 }
    161 
    162 /* To allow both SIGTSTP and endwin() to come back nicely, we provide
    163    the following routines. */
    164 
    165 int
    166 __stopwin(void)
    167 {
    168 	if (_cursesi_screen->endwin)
    169 		return OK;
    170 
    171 	/* Get the current terminal state (which the user may have changed). */
    172 	(void) tcgetattr(fileno(_cursesi_screen->infd),
    173 			 &_cursesi_screen->save_termios);
    174 
    175 	__restore_stophandler();
    176 	__restore_winchhandler();
    177 
    178 	if (curscr != NULL) {
    179 		__unsetattr(0);
    180 		__mvcur((int) curscr->cury, (int) curscr->curx, (int) curscr->maxy - 1, 0, 0);
    181 	}
    182 
    183 	if (__tc_mo != NULL)
    184 		(void) tputs(__tc_mo, 0, __cputchar);
    185 
    186 	if ((curscr != NULL) && (curscr->flags & __KEYPAD))
    187 		(void) tputs(__tc_ke, 0, __cputchar);
    188 	(void) tputs(__tc_ve, 0, __cputchar);
    189 	(void) tputs(__tc_te, 0, __cputchar);
    190 	(void) fflush(_cursesi_screen->outfd);
    191 	(void) setvbuf(_cursesi_screen->outfd, NULL, _IOLBF, (size_t) 0);
    192 
    193 	_cursesi_screen->endwin = 1;
    194 
    195 	return (tcsetattr(fileno(_cursesi_screen->infd),
    196 			  __tcaction ? TCSASOFT | TCSADRAIN : TCSADRAIN,
    197 			  &_cursesi_screen->orig_termios) ? ERR : OK);
    198 }
    199 
    200 
    201 void
    202 __restartwin(void)
    203 {
    204 	struct winsize win;
    205 
    206 	if (!_cursesi_screen->endwin)
    207 		return;
    208 
    209 	/* Reset the curses SIGTSTP and SIGWINCH signal handlers. */
    210 	__set_stophandler();
    211 	__set_winchhandler();
    212 
    213 	/* Check to see if the window size has changed */
    214 	if (ioctl(fileno(_cursesi_screen->outfd), TIOCGWINSZ, &win) != -1 &&
    215 	    win.ws_row != 0 && win.ws_col != 0) {
    216 		if (win.ws_row != LINES) {
    217 			LINES = win.ws_row;
    218 			_cursesi_screen->resized = 1;
    219 		}
    220 		if (win.ws_col != COLS) {
    221 			COLS = win.ws_col;
    222 			_cursesi_screen->resized = 1;
    223 		}
    224 	}
    225 
    226 	/* save the new "default" terminal state */
    227 	(void) tcgetattr(fileno(_cursesi_screen->infd),
    228 			 &_cursesi_screen->orig_termios);
    229 
    230 	/* Reset the terminal state to the mode just before we stopped. */
    231 	(void) tcsetattr(fileno(_cursesi_screen->infd),
    232 			 __tcaction ? TCSASOFT | TCSADRAIN : TCSADRAIN,
    233 			 &_cursesi_screen->save_termios);
    234 
    235 	/* Restore colours */
    236 	__restore_colors();
    237 
    238 	/* Reset meta */
    239 	__restore_meta_state();
    240 
    241 	/* Restart the screen. */
    242 	__startwin(_cursesi_screen);
    243 
    244 	/* Reset cursor visibility */
    245 	__restore_cursor_vis();
    246 
    247 	/* Repaint the screen. */
    248 	wrefresh(curscr);
    249 }
    250 
    251 int
    252 def_prog_mode(void)
    253 {
    254 	if (_cursesi_screen->endwin)
    255 		return ERR;
    256 
    257 	return (tcgetattr(fileno(_cursesi_screen->infd),
    258 			  &_cursesi_screen->save_termios) ? ERR : OK);
    259 }
    260 
    261 int
    262 reset_prog_mode(void)
    263 {
    264 
    265 	return tcsetattr(fileno(_cursesi_screen->infd),
    266 			 __tcaction ? TCSASOFT | TCSADRAIN : TCSADRAIN,
    267 			 &_cursesi_screen->save_termios) ? ERR : OK;
    268 }
    269 
    270 int
    271 def_shell_mode(void)
    272 {
    273 	return (tcgetattr(fileno(_cursesi_screen->infd),
    274 			  &_cursesi_screen->orig_termios) ? ERR : OK);
    275 }
    276 
    277 int
    278 reset_shell_mode(void)
    279 {
    280 	return (__stopwin());
    281 }
    282