diff options
author | Rudolf Polzer <divverent@xonotic.org> | 2013-01-23 15:47:49 +0100 |
---|---|---|
committer | Rudolf Polzer <divverent@xonotic.org> | 2013-01-23 18:05:34 +0100 |
commit | 3b22404e07df265af221112e2970084a15766c9a (patch) | |
tree | 868869e61a17389edd435342f64fd4dca8aa0485 /osdep/getch2.c | |
parent | d275e21d6a210064ab62e56334005c923481a6bd (diff) | |
download | mpv-3b22404e07df265af221112e2970084a15766c9a.tar.bz2 mpv-3b22404e07df265af221112e2970084a15766c9a.tar.xz |
mp_msg, getch2: unix tty background support
Now, when backgrounded, mpv plays and outputs messages to stdout, but
statusline is not output.
Background<->foreground transitions are detected by signals and polling
the process groups.
Diffstat (limited to 'osdep/getch2.c')
-rw-r--r-- | osdep/getch2.c | 113 |
1 files changed, 97 insertions, 16 deletions
diff --git a/osdep/getch2.c b/osdep/getch2.c index c722922f88..63aaa75bf1 100644 --- a/osdep/getch2.c +++ b/osdep/getch2.c @@ -55,11 +55,13 @@ #include "core/bstr.h" #include "core/mp_fifo.h" +#include "core/input/input.h" #include "core/input/keycodes.h" #include "getch2.h" #ifdef HAVE_TERMIOS -static struct termios tio_orig; +static volatile struct termios tio_orig; +static volatile int tio_orig_set; #endif static int getch2_len=0; static unsigned char getch2_buf[BUF_LEN]; @@ -284,39 +286,118 @@ bool getch2(struct mp_fifo *fifo) return true; } -static volatile int getch2_status=0; +static volatile int getch2_active=0; +static volatile int getch2_enabled=0; -static void do_enable_getch2(void) +static void do_activate_getch2(void) { + if (getch2_active) + return; #ifdef HAVE_TERMIOS struct termios tio_new; tcgetattr(0,&tio_new); + if (!tio_orig_set) { + tio_orig = tio_new; + tio_orig_set = 1; + } tio_new.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tio_new.c_cc[VMIN] = 1; tio_new.c_cc[VTIME] = 0; tcsetattr(0,TCSANOW,&tio_new); #endif + getch2_active=1; +} + +static void do_deactivate_getch2(void) +{ + if (!getch2_active) + return; +#ifdef HAVE_TERMIOS + if (tio_orig_set) { + // once set, it will never be set again + // so we can cast away volatile here + tcsetattr(0, TCSANOW, (const struct termios *) &tio_orig); + } +#endif + getch2_active=0; +} + +// sigaction wrapper +static int setsigaction(int signo, void (*handler) (int), + int flags, bool do_mask) +{ + struct sigaction sa; + sa.sa_handler = handler; + if(do_mask) + sigfillset(&sa.sa_mask); + else + sigemptyset(&sa.sa_mask); + sa.sa_flags = flags; + return sigaction(signo, &sa, NULL); +} + +void getch2_poll(void){ + if (!getch2_enabled) + return; + + // check if we are in the foreground process group + int newstatus = (tcgetpgrp(0) == getpgrp()); + + // and activate getch2 if we are, deactivate otherwise + if (newstatus) + do_activate_getch2(); + else + do_deactivate_getch2(); +} + +static void stop_sighandler(int signum) +{ + do_deactivate_getch2(); + + // note: for this signal, we use SA_RESETHAND but do NOT mask signals + // so this will invoke the default handler + raise(SIGTSTP); } static void continue_sighandler(int signum) { - if (getch2_status) - do_enable_getch2(); + // SA_RESETHAND has reset SIGTSTP, so we need to restore it here + setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false); + + getch2_poll(); +} + +static void quit_request_sighandler(int signum) +{ + async_quit_request = 1; } void getch2_enable(void){ -#ifdef HAVE_TERMIOS - tcgetattr(0,&tio_orig); - do_enable_getch2(); -#endif - getch2_status=1; - signal(SIGCONT,continue_sighandler); + if (getch2_enabled) + return; + + // handlers to fix terminal settings + setsigaction(SIGCONT, continue_sighandler, 0, true); + setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false); + setsigaction(SIGINT, quit_request_sighandler, SA_RESETHAND, false); + setsigaction(SIGTTIN, SIG_IGN, 0, true); + + do_activate_getch2(); + + getch2_enabled = 1; } void getch2_disable(void){ - if(!getch2_status) return; // already disabled / never enabled - getch2_status=0; -#ifdef HAVE_TERMIOS - tcsetattr(0,TCSANOW,&tio_orig); -#endif + if (!getch2_enabled) + return; + + // restore signals + setsigaction(SIGCONT, SIG_DFL, 0, false); + setsigaction(SIGTSTP, SIG_DFL, 0, false); + setsigaction(SIGINT, SIG_DFL, 0, false); + setsigaction(SIGTTIN, SIG_DFL, 0, false); + + do_deactivate_getch2(); + + getch2_enabled = 0; } |