root/lib/tty/tty.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. sigintr_handler
  2. tty_check_term
  3. tty_start_interrupt_key
  4. tty_enable_interrupt_key
  5. tty_disable_interrupt_key
  6. tty_got_interrupt
  7. tty_got_winch
  8. tty_flush_winch
  9. tty_print_one_hline
  10. tty_print_one_vline
  11. tty_draw_box
  12. mc_tty_normalize_from_utf8
  13. tty_resize
  14. tty_init_xterm_support

   1 /*
   2    Interface to the terminal controlling library.
   3 
   4    Copyright (C) 2005-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Roland Illig <roland.illig@gmx.de>, 2005.
   9    Andrew Borodin <aborodin@vmail.ru>, 2009.
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 /** \file tty.c
  28  *  \brief Source: %interface to the terminal controlling library
  29  */
  30 
  31 #include <config.h>
  32 
  33 #include <errno.h>
  34 #include <signal.h>
  35 #include <stdarg.h>
  36 #include <stdlib.h>
  37 #include <string.h>             /* memset() */
  38 
  39 #ifdef HAVE_SYS_SELECT_H
  40 #include <sys/select.h>
  41 #else
  42 #include <sys/time.h>
  43 #include <sys/types.h>
  44 #endif
  45 #include <unistd.h>             /* exit() */
  46 
  47 #ifdef HAVE_SYS_IOCTL_H
  48 #include <sys/ioctl.h>
  49 #endif
  50 
  51 /* In some systems (like Solaris 11.4 SPARC), TIOCSWINSZ is defined in termios.h */
  52 #include <termios.h>
  53 
  54 #include "lib/global.h"
  55 #include "lib/strutil.h"
  56 
  57 #include "tty.h"
  58 #include "tty-internal.h"
  59 #include "mouse.h"              /* use_mouse_p */
  60 #include "win.h"
  61 
  62 /*** global variables ****************************************************************************/
  63 
  64 int mc_tty_frm[MC_TTY_FRM_MAX];
  65 
  66 /*** file scope macro definitions ****************************************************************/
  67 
  68 /*** file scope type declarations ****************************************************************/
  69 
  70 /*** file scope variables ************************************************************************/
  71 
  72 static SIG_ATOMIC_VOLATILE_T got_interrupt = 0;
  73 
  74 /*** file scope functions ************************************************************************/
  75 /* --------------------------------------------------------------------------------------------- */
  76 
  77 static void
  78 sigintr_handler (int signo)
     /* [previous][next][first][last][top][bottom][index][help]  */
  79 {
  80     (void) &signo;
  81     got_interrupt = 1;
  82 }
  83 
  84 /* --------------------------------------------------------------------------------------------- */
  85 /*** public functions ****************************************************************************/
  86 /* --------------------------------------------------------------------------------------------- */
  87 
  88 /**
  89  * Check terminal type. If $TERM is not set or value is empty, mc finishes with EXIT_FAILURE.
  90  *
  91  * @param force_xterm Set forced the XTerm type
  92  *
  93  * @return true if @param force_xterm is true or value of $TERM is one of term*, konsole*
  94  *              rxvt*, Eterm or dtterm
  95  */
  96 gboolean
  97 tty_check_term (gboolean force_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
  98 {
  99     const char *termvalue;
 100     const char *xdisplay;
 101 
 102     termvalue = getenv ("TERM");
 103     if (termvalue == NULL || *termvalue == '\0')
 104     {
 105         fputs (_("The TERM environment variable is unset!\n"), stderr);
 106         exit (EXIT_FAILURE);
 107     }
 108 
 109     xdisplay = getenv ("DISPLAY");
 110     if (xdisplay != NULL && *xdisplay == '\0')
 111         xdisplay = NULL;
 112 
 113     return force_xterm || strncmp (termvalue, "xterm", 5) == 0
 114         || strncmp (termvalue, "konsole", 7) == 0
 115         || strncmp (termvalue, "rxvt", 4) == 0
 116         || strcmp (termvalue, "Eterm") == 0
 117         || strcmp (termvalue, "dtterm") == 0
 118         || (strncmp (termvalue, "screen", 6) == 0 && xdisplay != NULL);
 119 }
 120 
 121 /* --------------------------------------------------------------------------------------------- */
 122 
 123 extern void
 124 tty_start_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 125 {
 126     struct sigaction act;
 127 
 128     memset (&act, 0, sizeof (act));
 129     act.sa_handler = sigintr_handler;
 130     sigemptyset (&act.sa_mask);
 131 #ifdef SA_RESTART
 132     act.sa_flags = SA_RESTART;
 133 #endif /* SA_RESTART */
 134     sigaction (SIGINT, &act, NULL);
 135 }
 136 
 137 /* --------------------------------------------------------------------------------------------- */
 138 
 139 extern void
 140 tty_enable_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 141 {
 142     struct sigaction act;
 143 
 144     memset (&act, 0, sizeof (act));
 145     act.sa_handler = sigintr_handler;
 146     sigemptyset (&act.sa_mask);
 147     sigaction (SIGINT, &act, NULL);
 148     got_interrupt = 0;
 149 }
 150 
 151 /* --------------------------------------------------------------------------------------------- */
 152 
 153 extern void
 154 tty_disable_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 155 {
 156     struct sigaction act;
 157 
 158     memset (&act, 0, sizeof (act));
 159     act.sa_handler = SIG_IGN;
 160     sigemptyset (&act.sa_mask);
 161     sigaction (SIGINT, &act, NULL);
 162 }
 163 
 164 /* --------------------------------------------------------------------------------------------- */
 165 
 166 extern gboolean
 167 tty_got_interrupt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 168 {
 169     gboolean rv;
 170 
 171     rv = (got_interrupt != 0);
 172     got_interrupt = 0;
 173     return rv;
 174 }
 175 
 176 /* --------------------------------------------------------------------------------------------- */
 177 
 178 gboolean
 179 tty_got_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     fd_set fdset;
 182     /* *INDENT-OFF* */
 183     /* instant timeout */
 184     struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
 185     /* *INDENT-ON* */
 186     int ok;
 187 
 188     FD_ZERO (&fdset);
 189     FD_SET (sigwinch_pipe[0], &fdset);
 190 
 191     while ((ok = select (sigwinch_pipe[0] + 1, &fdset, NULL, NULL, &timeout)) < 0)
 192         if (errno != EINTR)
 193         {
 194             perror (_("Cannot check SIGWINCH pipe"));
 195             exit (EXIT_FAILURE);
 196         }
 197 
 198     return (ok != 0 && FD_ISSET (sigwinch_pipe[0], &fdset));
 199 }
 200 
 201 /* --------------------------------------------------------------------------------------------- */
 202 
 203 void
 204 tty_flush_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 205 {
 206     ssize_t n;
 207 
 208     /* merge all SIGWINCH events raised to this moment */
 209     do
 210     {
 211         char x[16];
 212 
 213         /* read multiple events at a time  */
 214         n = read (sigwinch_pipe[0], &x, sizeof (x));
 215     }
 216     while (n > 0 || (n == -1 && errno == EINTR));
 217 }
 218 
 219 /* --------------------------------------------------------------------------------------------- */
 220 
 221 void
 222 tty_print_one_hline (gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 223 {
 224     tty_print_alt_char (ACS_HLINE, single);
 225 }
 226 
 227 /* --------------------------------------------------------------------------------------------- */
 228 
 229 void
 230 tty_print_one_vline (gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 231 {
 232     tty_print_alt_char (ACS_VLINE, single);
 233 }
 234 
 235 /* --------------------------------------------------------------------------------------------- */
 236 
 237 void
 238 tty_draw_box (int y, int x, int ys, int xs, gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 239 {
 240     int y2, x2;
 241 
 242     if (ys <= 0 || xs <= 0)
 243         return;
 244 
 245     ys--;
 246     xs--;
 247 
 248     y2 = y + ys;
 249     x2 = x + xs;
 250 
 251     tty_draw_vline (y, x, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
 252     tty_draw_vline (y, x2, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
 253     tty_draw_hline (y, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
 254     tty_draw_hline (y2, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
 255     tty_gotoyx (y, x);
 256     tty_print_alt_char (ACS_ULCORNER, single);
 257     tty_gotoyx (y2, x);
 258     tty_print_alt_char (ACS_LLCORNER, single);
 259     tty_gotoyx (y, x2);
 260     tty_print_alt_char (ACS_URCORNER, single);
 261     tty_gotoyx (y2, x2);
 262     tty_print_alt_char (ACS_LRCORNER, single);
 263 }
 264 
 265 /* --------------------------------------------------------------------------------------------- */
 266 
 267 char *
 268 mc_tty_normalize_from_utf8 (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 269 {
 270     GIConv conv;
 271     GString *buffer;
 272     const char *_system_codepage = str_detect_termencoding ();
 273 
 274     if (str_isutf8 (_system_codepage))
 275         return g_strdup (str);
 276 
 277     conv = g_iconv_open (_system_codepage, "UTF-8");
 278     if (conv == INVALID_CONV)
 279         return g_strdup (str);
 280 
 281     buffer = g_string_new ("");
 282 
 283     if (str_convert (conv, str, buffer) == ESTR_FAILURE)
 284     {
 285         g_string_free (buffer, TRUE);
 286         str_close_conv (conv);
 287         return g_strdup (str);
 288     }
 289     str_close_conv (conv);
 290 
 291     return g_string_free (buffer, FALSE);
 292 }
 293 
 294 /* --------------------------------------------------------------------------------------------- */
 295 
 296 /** Resize given terminal using TIOCSWINSZ, return ioctl() result */
 297 int
 298 tty_resize (int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 299 {
 300 #if defined TIOCSWINSZ
 301     struct winsize tty_size;
 302 
 303     tty_size.ws_row = LINES;
 304     tty_size.ws_col = COLS;
 305     tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
 306 
 307     return ioctl (fd, TIOCSWINSZ, &tty_size);
 308 #else
 309     return 0;
 310 #endif
 311 }
 312 
 313 /* --------------------------------------------------------------------------------------------- */
 314 
 315 void
 316 tty_init_xterm_support (gboolean is_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 317 {
 318     const char *termvalue;
 319 
 320     termvalue = getenv ("TERM");
 321 
 322     /* Check mouse and ca capabilities */
 323     /* terminfo/termcap structures have been already initialized,
 324        in slang_init() or/and init_curses()  */
 325     /* Check terminfo at first, then check termcap */
 326     xmouse_seq = tty_tgetstr ("kmous");
 327     if (xmouse_seq == NULL)
 328         xmouse_seq = tty_tgetstr ("Km");
 329     smcup = tty_tgetstr ("smcup");
 330     if (smcup == NULL)
 331         smcup = tty_tgetstr ("ti");
 332     rmcup = tty_tgetstr ("rmcup");
 333     if (rmcup == NULL)
 334         rmcup = tty_tgetstr ("te");
 335 
 336     if (strcmp (termvalue, "cygwin") == 0)
 337     {
 338         is_xterm = TRUE;
 339         use_mouse_p = MOUSE_DISABLED;
 340     }
 341 
 342     if (is_xterm)
 343     {
 344         /* Default to the standard xterm sequence */
 345         if (xmouse_seq == NULL)
 346             xmouse_seq = ESC_STR "[M";
 347 
 348         /* Enable mouse unless explicitly disabled by --nomouse */
 349         if (use_mouse_p != MOUSE_DISABLED)
 350         {
 351             if (mc_global.tty.old_mouse)
 352                 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
 353             else
 354             {
 355                 /* FIXME: this dirty hack to set supported type of tracking the mouse */
 356                 const char *color_term = getenv ("COLORTERM");
 357                 if (strncmp (termvalue, "rxvt", 4) == 0 ||
 358                     (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
 359                     strcmp (termvalue, "Eterm") == 0)
 360                     use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
 361                 else
 362                     use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
 363             }
 364         }
 365     }
 366 
 367     /* There's only one termcap entry "kmous", typically containing "\E[M" or "\E[<".
 368      * We need the former in xmouse_seq, the latter in xmouse_extended_seq.
 369      * See tickets 2956, 3954, and 4063 for details. */
 370     if (xmouse_seq != NULL)
 371     {
 372         if (strcmp (xmouse_seq, ESC_STR "[<") == 0)
 373             xmouse_seq = ESC_STR "[M";
 374 
 375         xmouse_extended_seq = ESC_STR "[<";
 376     }
 377 }
 378 
 379 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */