xref: /minix3/lib/libcurses/tstp.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: tstp.c,v 1.40 2013/10/15 13:00:52 christos Exp $	*/
251ffecc1SBen Gras 
351ffecc1SBen Gras /*
451ffecc1SBen Gras  * Copyright (c) 1981, 1993, 1994
551ffecc1SBen Gras  *	The Regents of the University of California.  All rights reserved.
651ffecc1SBen Gras  *
751ffecc1SBen Gras  * Redistribution and use in source and binary forms, with or without
851ffecc1SBen Gras  * modification, are permitted provided that the following conditions
951ffecc1SBen Gras  * are met:
1051ffecc1SBen Gras  * 1. Redistributions of source code must retain the above copyright
1151ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer.
1251ffecc1SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
1351ffecc1SBen Gras  *    notice, this list of conditions and the following disclaimer in the
1451ffecc1SBen Gras  *    documentation and/or other materials provided with the distribution.
1551ffecc1SBen Gras  * 3. Neither the name of the University nor the names of its contributors
1651ffecc1SBen Gras  *    may be used to endorse or promote products derived from this software
1751ffecc1SBen Gras  *    without specific prior written permission.
1851ffecc1SBen Gras  *
1951ffecc1SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2051ffecc1SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2151ffecc1SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2251ffecc1SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2351ffecc1SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2451ffecc1SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2551ffecc1SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2651ffecc1SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2751ffecc1SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2851ffecc1SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2951ffecc1SBen Gras  * SUCH DAMAGE.
3051ffecc1SBen Gras  */
3151ffecc1SBen Gras 
3251ffecc1SBen Gras #include <sys/cdefs.h>
3351ffecc1SBen Gras #ifndef lint
3451ffecc1SBen Gras #if 0
3551ffecc1SBen Gras static char sccsid[] = "@(#)tstp.c	8.3 (Berkeley) 5/4/94";
3651ffecc1SBen Gras #else
37*84d9c625SLionel Sambuc __RCSID("$NetBSD: tstp.c,v 1.40 2013/10/15 13:00:52 christos Exp $");
3851ffecc1SBen Gras #endif
3951ffecc1SBen Gras #endif				/* not lint */
4051ffecc1SBen Gras 
4151ffecc1SBen Gras #include <sys/ioctl.h>
4251ffecc1SBen Gras 
4351ffecc1SBen Gras #include <errno.h>
4451ffecc1SBen Gras #include <signal.h>
4551ffecc1SBen Gras #include <termios.h>
4651ffecc1SBen Gras #include <unistd.h>
4751ffecc1SBen Gras 
4851ffecc1SBen Gras #include "curses.h"
4951ffecc1SBen Gras #include "curses_private.h"
5051ffecc1SBen Gras 
5151ffecc1SBen Gras static int tstp_set = 0;
5251ffecc1SBen Gras static int winch_set = 0;
5351ffecc1SBen Gras 
5451ffecc1SBen Gras static void (*otstpfn)
5551ffecc1SBen Gras __P((int)) = SIG_DFL;
5651ffecc1SBen Gras 
5751ffecc1SBen Gras static struct sigaction	owsa;
580c3ae37fSLionel Sambuc #ifndef TCSASOFT
590c3ae37fSLionel Sambuc #define TCSASOFT 0
600c3ae37fSLionel Sambuc #endif
6151ffecc1SBen Gras 
6251ffecc1SBen Gras /*
6351ffecc1SBen Gras  * stop_signal_handler --
6451ffecc1SBen Gras  *	Handle stop signals.
6551ffecc1SBen Gras  */
6651ffecc1SBen Gras void
__stop_signal_handler(int signo)6751ffecc1SBen Gras __stop_signal_handler(/*ARGSUSED*/int signo)
6851ffecc1SBen Gras {
6951ffecc1SBen Gras 	sigset_t oset, set;
7051ffecc1SBen Gras 
7151ffecc1SBen Gras 	/*
7251ffecc1SBen Gras 	 * Block window change and timer signals.  The latter is because
7351ffecc1SBen Gras 	 * applications use timers to decide when to repaint the screen.
7451ffecc1SBen Gras 	 */
7551ffecc1SBen Gras 	(void) sigemptyset(&set);
7651ffecc1SBen Gras 	(void) sigaddset(&set, SIGALRM);
7751ffecc1SBen Gras 	(void) sigaddset(&set, SIGWINCH);
7851ffecc1SBen Gras 	(void) sigprocmask(SIG_BLOCK, &set, &oset);
7951ffecc1SBen Gras 
8051ffecc1SBen Gras 	/*
8151ffecc1SBen Gras 	 * End the window, which also resets the terminal state to the
8251ffecc1SBen Gras 	 * original modes.
8351ffecc1SBen Gras 	 */
8451ffecc1SBen Gras 	__stopwin();
8551ffecc1SBen Gras 
8651ffecc1SBen Gras 	/* Unblock SIGTSTP. */
8751ffecc1SBen Gras 	(void) sigemptyset(&set);
8851ffecc1SBen Gras 	(void) sigaddset(&set, SIGTSTP);
8951ffecc1SBen Gras 	(void) sigprocmask(SIG_UNBLOCK, &set, NULL);
9051ffecc1SBen Gras 
9151ffecc1SBen Gras 	/* Stop ourselves. */
9251ffecc1SBen Gras 	(void) kill(0, SIGTSTP);
9351ffecc1SBen Gras 
9451ffecc1SBen Gras 	/* Time passes ... */
9551ffecc1SBen Gras 
9651ffecc1SBen Gras 	/* restart things */
9751ffecc1SBen Gras 	__restartwin();
9851ffecc1SBen Gras 
9951ffecc1SBen Gras 	/* Reset the signals. */
10051ffecc1SBen Gras 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
10151ffecc1SBen Gras }
10251ffecc1SBen Gras 
10351ffecc1SBen Gras /*
10451ffecc1SBen Gras  * Set the TSTP handler.
10551ffecc1SBen Gras  */
10651ffecc1SBen Gras void
__set_stophandler(void)10751ffecc1SBen Gras __set_stophandler(void)
10851ffecc1SBen Gras {
10951ffecc1SBen Gras #ifdef DEBUG
11051ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__set_stophandler: %d\n", tstp_set);
11151ffecc1SBen Gras #endif
11251ffecc1SBen Gras 	if (!tstp_set) {
11351ffecc1SBen Gras 		otstpfn = signal(SIGTSTP, __stop_signal_handler);
11451ffecc1SBen Gras 		tstp_set = 1;
11551ffecc1SBen Gras 	}
11651ffecc1SBen Gras }
11751ffecc1SBen Gras 
11851ffecc1SBen Gras /*
11951ffecc1SBen Gras  * Restore the TSTP handler.
12051ffecc1SBen Gras  */
12151ffecc1SBen Gras void
__restore_stophandler(void)12251ffecc1SBen Gras __restore_stophandler(void)
12351ffecc1SBen Gras {
12451ffecc1SBen Gras #ifdef DEBUG
12551ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__restore_stophandler: %d\n", tstp_set);
12651ffecc1SBen Gras #endif
12751ffecc1SBen Gras 	if (tstp_set) {
12851ffecc1SBen Gras 		(void) signal(SIGTSTP, otstpfn);
12951ffecc1SBen Gras 		tstp_set = 0;
13051ffecc1SBen Gras 	}
13151ffecc1SBen Gras }
13251ffecc1SBen Gras 
13351ffecc1SBen Gras /*
13451ffecc1SBen Gras  * winch_signal_handler --
13551ffecc1SBen Gras  *	Handle winch signals by pushing KEY_RESIZE into the input stream.
13651ffecc1SBen Gras  */
13751ffecc1SBen Gras void
__winch_signal_handler(int signo)13851ffecc1SBen Gras __winch_signal_handler(/*ARGSUSED*/int signo)
13951ffecc1SBen Gras {
14051ffecc1SBen Gras 	struct winsize win;
14151ffecc1SBen Gras 
14251ffecc1SBen Gras 	if (ioctl(fileno(_cursesi_screen->outfd), TIOCGWINSZ, &win) != -1 &&
14351ffecc1SBen Gras 	    win.ws_row != 0 && win.ws_col != 0) {
14451ffecc1SBen Gras 		LINES = win.ws_row;
14551ffecc1SBen Gras 		COLS = win.ws_col;
14651ffecc1SBen Gras 	}
14751ffecc1SBen Gras 	/*
14851ffecc1SBen Gras 	 * If there was a previous handler, call that,
14951ffecc1SBen Gras 	 * otherwise tell getch() to send KEY_RESIZE.
15051ffecc1SBen Gras 	 */
15151ffecc1SBen Gras 	if (owsa.sa_handler !=  NULL)
15251ffecc1SBen Gras 		owsa.sa_handler(signo);
15351ffecc1SBen Gras 	else
15451ffecc1SBen Gras 		_cursesi_screen->resized = 1;
15551ffecc1SBen Gras }
15651ffecc1SBen Gras 
15751ffecc1SBen Gras /*
15851ffecc1SBen Gras  * Set the WINCH handler.
15951ffecc1SBen Gras  */
16051ffecc1SBen Gras void
__set_winchhandler(void)16151ffecc1SBen Gras __set_winchhandler(void)
16251ffecc1SBen Gras {
16351ffecc1SBen Gras #ifdef DEBUG
16451ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__set_winchhandler: %d\n", winch_set);
16551ffecc1SBen Gras #endif
16651ffecc1SBen Gras 	if (!winch_set) {
16751ffecc1SBen Gras 		struct sigaction sa;
16851ffecc1SBen Gras 
16951ffecc1SBen Gras 		sa.sa_handler = __winch_signal_handler;
17051ffecc1SBen Gras 		sa.sa_flags = 0;
17151ffecc1SBen Gras 		sigemptyset(&sa.sa_mask);
17251ffecc1SBen Gras 		sigaction(SIGWINCH, &sa, &owsa);
17351ffecc1SBen Gras 		winch_set = 1;
17451ffecc1SBen Gras #ifdef DEBUG
17551ffecc1SBen Gras 		__CTRACE(__CTRACE_MISC,
17651ffecc1SBen Gras 		    "__set_winchhandler: owsa.sa_handler=%p\n",
17751ffecc1SBen Gras 		    owsa.sa_handler);
17851ffecc1SBen Gras #endif
17951ffecc1SBen Gras 	}
18051ffecc1SBen Gras }
18151ffecc1SBen Gras 
18251ffecc1SBen Gras /*
18351ffecc1SBen Gras  * Restore the WINCH handler.
18451ffecc1SBen Gras  */
18551ffecc1SBen Gras void
__restore_winchhandler(void)18651ffecc1SBen Gras __restore_winchhandler(void)
18751ffecc1SBen Gras {
18851ffecc1SBen Gras #ifdef DEBUG
18951ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__restore_winchhandler: %d\n", winch_set);
19051ffecc1SBen Gras #endif
19151ffecc1SBen Gras 	if (winch_set > 0) {
19251ffecc1SBen Gras 		struct sigaction cwsa;
19351ffecc1SBen Gras 
19451ffecc1SBen Gras 		sigaction(SIGWINCH, NULL, &cwsa);
19551ffecc1SBen Gras 		if (cwsa.sa_handler == owsa.sa_handler) {
19651ffecc1SBen Gras 			sigaction(SIGWINCH, &owsa, NULL);
19751ffecc1SBen Gras 			winch_set = 0;
19851ffecc1SBen Gras 		} else {
19951ffecc1SBen Gras 			/*
20051ffecc1SBen Gras 			 * We're now using the programs WINCH handler,
20151ffecc1SBen Gras 			 * so don't restore the previous one.
20251ffecc1SBen Gras 			 */
20351ffecc1SBen Gras 			winch_set = -1;
20451ffecc1SBen Gras #ifdef DEBUG
20551ffecc1SBen Gras 			__CTRACE(__CTRACE_MISC, "cwsa.sa_handler = %p\n",
20651ffecc1SBen Gras 			    cwsa.sa_handler);
20751ffecc1SBen Gras #endif
20851ffecc1SBen Gras 		}
20951ffecc1SBen Gras 	}
21051ffecc1SBen Gras }
21151ffecc1SBen Gras 
21251ffecc1SBen Gras /* To allow both SIGTSTP and endwin() to come back nicely, we provide
21351ffecc1SBen Gras    the following routines. */
21451ffecc1SBen Gras 
21551ffecc1SBen Gras int
__stopwin(void)21651ffecc1SBen Gras __stopwin(void)
21751ffecc1SBen Gras {
21851ffecc1SBen Gras #ifdef DEBUG
21951ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__stopwin\n");
22051ffecc1SBen Gras #endif
22151ffecc1SBen Gras 	if (_cursesi_screen->endwin)
22251ffecc1SBen Gras 		return OK;
22351ffecc1SBen Gras 
22451ffecc1SBen Gras 	/* Get the current terminal state (which the user may have changed). */
22551ffecc1SBen Gras 	(void) tcgetattr(fileno(_cursesi_screen->infd),
22651ffecc1SBen Gras 			 &_cursesi_screen->save_termios);
22751ffecc1SBen Gras 
22851ffecc1SBen Gras 	__restore_stophandler();
22951ffecc1SBen Gras 	__restore_winchhandler();
23051ffecc1SBen Gras 
23151ffecc1SBen Gras 	if (curscr != NULL) {
23251ffecc1SBen Gras 		__unsetattr(0);
23351ffecc1SBen Gras 		__mvcur((int) curscr->cury, (int) curscr->curx,
23451ffecc1SBen Gras 		    (int) curscr->maxy - 1, 0, 0);
23551ffecc1SBen Gras 	}
23651ffecc1SBen Gras 
237*84d9c625SLionel Sambuc 	if (meta_on != NULL)
238*84d9c625SLionel Sambuc 		(void) tputs(meta_on, 0, __cputchar);
23951ffecc1SBen Gras 
24051ffecc1SBen Gras 	if ((curscr != NULL) && (curscr->flags & __KEYPAD))
24151ffecc1SBen Gras 		(void) tputs(keypad_local, 0, __cputchar);
24251ffecc1SBen Gras 	(void) tputs(cursor_normal, 0, __cputchar);
24351ffecc1SBen Gras 	(void) tputs(exit_ca_mode, 0, __cputchar);
24451ffecc1SBen Gras 	(void) fflush(_cursesi_screen->outfd);
24551ffecc1SBen Gras 	(void) setvbuf(_cursesi_screen->outfd, NULL, _IOLBF, (size_t) 0);
24651ffecc1SBen Gras 
24751ffecc1SBen Gras 	_cursesi_screen->endwin = 1;
24851ffecc1SBen Gras 
2490c3ae37fSLionel Sambuc 	return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
2500c3ae37fSLionel Sambuc 	    &_cursesi_screen->orig_termios) ? ERR : OK;
25151ffecc1SBen Gras }
25251ffecc1SBen Gras 
25351ffecc1SBen Gras 
25451ffecc1SBen Gras void
__restartwin(void)25551ffecc1SBen Gras __restartwin(void)
25651ffecc1SBen Gras {
25751ffecc1SBen Gras 	struct winsize win;
25851ffecc1SBen Gras 	int nlines, ncols;
25951ffecc1SBen Gras 
26051ffecc1SBen Gras #ifdef DEBUG
26151ffecc1SBen Gras 	__CTRACE(__CTRACE_MISC, "__restartwin\n");
26251ffecc1SBen Gras #endif
26351ffecc1SBen Gras 	if (!_cursesi_screen->endwin)
26451ffecc1SBen Gras 		return;
26551ffecc1SBen Gras 
26651ffecc1SBen Gras 	/* Reset the curses SIGTSTP and SIGWINCH signal handlers. */
26751ffecc1SBen Gras 	__set_stophandler();
26851ffecc1SBen Gras 	__set_winchhandler();
26951ffecc1SBen Gras 
27051ffecc1SBen Gras 	/*
27151ffecc1SBen Gras 	 * Check to see if the window size has changed.
27251ffecc1SBen Gras 	 * If the application didn't update LINES and COLS,
27351ffecc1SBen Gras 	 * set the * resized flag to tell getch() to push KEY_RESIZE.
27451ffecc1SBen Gras 	 * Update curscr (which also updates __virtscr) and stdscr
27551ffecc1SBen Gras 	 * to match the new size.
27651ffecc1SBen Gras 	 */
27751ffecc1SBen Gras 	if (ioctl(fileno(_cursesi_screen->outfd), TIOCGWINSZ, &win) != -1 &&
27851ffecc1SBen Gras 	    win.ws_row != 0 && win.ws_col != 0) {
27951ffecc1SBen Gras 		if (win.ws_row != LINES) {
28051ffecc1SBen Gras 			LINES = win.ws_row;
28151ffecc1SBen Gras 			_cursesi_screen->resized = 1;
28251ffecc1SBen Gras 		}
28351ffecc1SBen Gras 		if (win.ws_col != COLS) {
28451ffecc1SBen Gras 			COLS = win.ws_col;
28551ffecc1SBen Gras 			_cursesi_screen->resized = 1;
28651ffecc1SBen Gras 		}
28751ffecc1SBen Gras 	}
28851ffecc1SBen Gras 	/*
28951ffecc1SBen Gras 	 * We need to make local copies of LINES and COLS, otherwise we
29051ffecc1SBen Gras 	 * could lose if they are changed between wresize() calls.
29151ffecc1SBen Gras 	 */
29251ffecc1SBen Gras 	nlines = LINES;
29351ffecc1SBen Gras 	ncols = COLS;
29451ffecc1SBen Gras 	if (curscr->maxy != nlines || curscr->maxx != ncols)
29551ffecc1SBen Gras 		wresize(curscr, nlines, ncols);
29651ffecc1SBen Gras 	if (stdscr->maxy != nlines || stdscr->maxx != ncols)
29751ffecc1SBen Gras 		wresize(stdscr, nlines, ncols);
29851ffecc1SBen Gras 
29951ffecc1SBen Gras 	/* save the new "default" terminal state */
30051ffecc1SBen Gras 	(void) tcgetattr(fileno(_cursesi_screen->infd),
30151ffecc1SBen Gras 			 &_cursesi_screen->orig_termios);
30251ffecc1SBen Gras 
30351ffecc1SBen Gras 	/* Reset the terminal state to the mode just before we stopped. */
3040c3ae37fSLionel Sambuc 	(void) tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
30551ffecc1SBen Gras 	    &_cursesi_screen->save_termios);
30651ffecc1SBen Gras 
30751ffecc1SBen Gras 	/* Restore colours */
30851ffecc1SBen Gras 	__restore_colors();
30951ffecc1SBen Gras 
31051ffecc1SBen Gras 	/* Reset meta */
31151ffecc1SBen Gras 	__restore_meta_state();
31251ffecc1SBen Gras 
31351ffecc1SBen Gras 	/* Restart the screen. */
31451ffecc1SBen Gras 	__startwin(_cursesi_screen);
31551ffecc1SBen Gras 
31651ffecc1SBen Gras 	/* Reset cursor visibility */
31751ffecc1SBen Gras 	__restore_cursor_vis();
31851ffecc1SBen Gras 
31951ffecc1SBen Gras 	/* Repaint the screen. */
32051ffecc1SBen Gras 	wrefresh(curscr);
32151ffecc1SBen Gras }
32251ffecc1SBen Gras 
32351ffecc1SBen Gras int
def_prog_mode(void)32451ffecc1SBen Gras def_prog_mode(void)
32551ffecc1SBen Gras {
32651ffecc1SBen Gras 	if (_cursesi_screen->endwin)
32751ffecc1SBen Gras 		return ERR;
32851ffecc1SBen Gras 
3290c3ae37fSLionel Sambuc 	return tcgetattr(fileno(_cursesi_screen->infd),
3300c3ae37fSLionel Sambuc 	    &_cursesi_screen->save_termios) ? ERR : OK;
33151ffecc1SBen Gras }
33251ffecc1SBen Gras 
33351ffecc1SBen Gras int
reset_prog_mode(void)33451ffecc1SBen Gras reset_prog_mode(void)
33551ffecc1SBen Gras {
33651ffecc1SBen Gras 
3370c3ae37fSLionel Sambuc 	return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN,
33851ffecc1SBen Gras 	    &_cursesi_screen->save_termios) ? ERR : OK;
33951ffecc1SBen Gras }
34051ffecc1SBen Gras 
34151ffecc1SBen Gras int
def_shell_mode(void)34251ffecc1SBen Gras def_shell_mode(void)
34351ffecc1SBen Gras {
3440c3ae37fSLionel Sambuc 	return tcgetattr(fileno(_cursesi_screen->infd),
3450c3ae37fSLionel Sambuc 	    &_cursesi_screen->orig_termios) ? ERR : OK;
34651ffecc1SBen Gras }
34751ffecc1SBen Gras 
34851ffecc1SBen Gras int
reset_shell_mode(void)34951ffecc1SBen Gras reset_shell_mode(void)
35051ffecc1SBen Gras {
3510c3ae37fSLionel Sambuc 	return __stopwin();
35251ffecc1SBen Gras }
353