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