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. tty_draw_box_shadow
  13. mc_tty_normalize_from_utf8
  14. tty_resize
  15. tty_clear_screen
  16. tty_init_xterm_support

   1 /*
   2    Interface to the terminal controlling library.
   3 
   4    Copyright (C) 2005-2021
   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 "color.h"              /* tty_set_normal_attrs() */
  60 #include "mouse.h"              /* use_mouse_p */
  61 #include "win.h"
  62 
  63 /*** global variables ****************************************************************************/
  64 
  65 int mc_tty_frm[MC_TTY_FRM_MAX];
  66 
  67 /*** file scope macro definitions ****************************************************************/
  68 
  69 /*** file scope type declarations ****************************************************************/
  70 
  71 /*** file scope variables ************************************************************************/
  72 
  73 static SIG_ATOMIC_VOLATILE_T got_interrupt = 0;
  74 
  75 /*** file scope functions ************************************************************************/
  76 /* --------------------------------------------------------------------------------------------- */
  77 
  78 static void
  79 sigintr_handler (int signo)
     /* [previous][next][first][last][top][bottom][index][help]  */
  80 {
  81     (void) &signo;
  82     got_interrupt = 1;
  83 }
  84 
  85 /* --------------------------------------------------------------------------------------------- */
  86 /*** public functions ****************************************************************************/
  87 /* --------------------------------------------------------------------------------------------- */
  88 
  89 /**
  90  * Check terminal type. If $TERM is not set or value is empty, mc finishes with EXIT_FAILURE.
  91  *
  92  * @param force_xterm Set forced the XTerm type
  93  *
  94  * @return true if @param force_xterm is true or value of $TERM is one of term*, konsole*
  95  *              rxvt*, Eterm or dtterm
  96  */
  97 gboolean
  98 tty_check_term (gboolean force_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
  99 {
 100     const char *termvalue;
 101     const char *xdisplay;
 102 
 103     termvalue = getenv ("TERM");
 104     if (termvalue == NULL || *termvalue == '\0')
 105     {
 106         fputs (_("The TERM environment variable is unset!\n"), stderr);
 107         exit (EXIT_FAILURE);
 108     }
 109 
 110     xdisplay = getenv ("DISPLAY");
 111     if (xdisplay != NULL && *xdisplay == '\0')
 112         xdisplay = NULL;
 113 
 114     return force_xterm || strncmp (termvalue, "xterm", 5) == 0
 115         || strncmp (termvalue, "konsole", 7) == 0
 116         || strncmp (termvalue, "rxvt", 4) == 0
 117         || strcmp (termvalue, "Eterm") == 0
 118         || strcmp (termvalue, "dtterm") == 0
 119         || (strncmp (termvalue, "screen", 6) == 0 && xdisplay != NULL);
 120 }
 121 
 122 /* --------------------------------------------------------------------------------------------- */
 123 
 124 extern void
 125 tty_start_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 126 {
 127     struct sigaction act;
 128 
 129     memset (&act, 0, sizeof (act));
 130     act.sa_handler = sigintr_handler;
 131     sigemptyset (&act.sa_mask);
 132 #ifdef SA_RESTART
 133     act.sa_flags = SA_RESTART;
 134 #endif /* SA_RESTART */
 135     sigaction (SIGINT, &act, NULL);
 136 }
 137 
 138 /* --------------------------------------------------------------------------------------------- */
 139 
 140 extern void
 141 tty_enable_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 142 {
 143     struct sigaction act;
 144 
 145     memset (&act, 0, sizeof (act));
 146     act.sa_handler = sigintr_handler;
 147     sigemptyset (&act.sa_mask);
 148     sigaction (SIGINT, &act, NULL);
 149     got_interrupt = 0;
 150 }
 151 
 152 /* --------------------------------------------------------------------------------------------- */
 153 
 154 extern void
 155 tty_disable_interrupt_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 156 {
 157     struct sigaction act;
 158 
 159     memset (&act, 0, sizeof (act));
 160     act.sa_handler = SIG_IGN;
 161     sigemptyset (&act.sa_mask);
 162     sigaction (SIGINT, &act, NULL);
 163 }
 164 
 165 /* --------------------------------------------------------------------------------------------- */
 166 
 167 extern gboolean
 168 tty_got_interrupt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 169 {
 170     gboolean rv;
 171 
 172     rv = (got_interrupt != 0);
 173     got_interrupt = 0;
 174     return rv;
 175 }
 176 
 177 /* --------------------------------------------------------------------------------------------- */
 178 
 179 gboolean
 180 tty_got_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 181 {
 182     fd_set fdset;
 183     /* *INDENT-OFF* */
 184     /* instant timeout */
 185     struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
 186     /* *INDENT-ON* */
 187     int ok;
 188 
 189     FD_ZERO (&fdset);
 190     FD_SET (sigwinch_pipe[0], &fdset);
 191 
 192     while ((ok = select (sigwinch_pipe[0] + 1, &fdset, NULL, NULL, &timeout)) < 0)
 193         if (errno != EINTR)
 194         {
 195             perror (_("Cannot check SIGWINCH pipe"));
 196             exit (EXIT_FAILURE);
 197         }
 198 
 199     return (ok != 0 && FD_ISSET (sigwinch_pipe[0], &fdset));
 200 }
 201 
 202 /* --------------------------------------------------------------------------------------------- */
 203 
 204 void
 205 tty_flush_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 206 {
 207     ssize_t n;
 208 
 209     /* merge all SIGWINCH events raised to this moment */
 210     do
 211     {
 212         char x[16];
 213 
 214         /* read multiple events at a time  */
 215         n = read (sigwinch_pipe[0], &x, sizeof (x));
 216     }
 217     while (n > 0 || (n == -1 && errno == EINTR));
 218 }
 219 
 220 /* --------------------------------------------------------------------------------------------- */
 221 
 222 void
 223 tty_print_one_hline (gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 224 {
 225     tty_print_alt_char (ACS_HLINE, single);
 226 }
 227 
 228 /* --------------------------------------------------------------------------------------------- */
 229 
 230 void
 231 tty_print_one_vline (gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 232 {
 233     tty_print_alt_char (ACS_VLINE, single);
 234 }
 235 
 236 /* --------------------------------------------------------------------------------------------- */
 237 
 238 void
 239 tty_draw_box (int y, int x, int ys, int xs, gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 240 {
 241     int y2, x2;
 242 
 243     if (ys <= 0 || xs <= 0)
 244         return;
 245 
 246     ys--;
 247     xs--;
 248 
 249     y2 = y + ys;
 250     x2 = x + xs;
 251 
 252     tty_draw_vline (y, x, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
 253     tty_draw_vline (y, x2, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
 254     tty_draw_hline (y, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
 255     tty_draw_hline (y2, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
 256     tty_gotoyx (y, x);
 257     tty_print_alt_char (ACS_ULCORNER, single);
 258     tty_gotoyx (y2, x);
 259     tty_print_alt_char (ACS_LLCORNER, single);
 260     tty_gotoyx (y, x2);
 261     tty_print_alt_char (ACS_URCORNER, single);
 262     tty_gotoyx (y2, x2);
 263     tty_print_alt_char (ACS_LRCORNER, single);
 264 }
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 
 268 void
 269 tty_draw_box_shadow (int y, int x, int rows, int cols, int shadow_color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 270 {
 271     /* draw right shadow */
 272     tty_colorize_area (y + 1, x + cols, rows - 1, 2, shadow_color);
 273     /* draw bottom shadow */
 274     tty_colorize_area (y + rows, x + 2, 1, cols, shadow_color);
 275 }
 276 
 277 /* --------------------------------------------------------------------------------------------- */
 278 
 279 char *
 280 mc_tty_normalize_from_utf8 (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 281 {
 282     GIConv conv;
 283     GString *buffer;
 284     const char *_system_codepage = str_detect_termencoding ();
 285 
 286     if (str_isutf8 (_system_codepage))
 287         return g_strdup (str);
 288 
 289     conv = g_iconv_open (_system_codepage, "UTF-8");
 290     if (conv == INVALID_CONV)
 291         return g_strdup (str);
 292 
 293     buffer = g_string_new ("");
 294 
 295     if (str_convert (conv, str, buffer) == ESTR_FAILURE)
 296     {
 297         g_string_free (buffer, TRUE);
 298         str_close_conv (conv);
 299         return g_strdup (str);
 300     }
 301     str_close_conv (conv);
 302 
 303     return g_string_free (buffer, FALSE);
 304 }
 305 
 306 /* --------------------------------------------------------------------------------------------- */
 307 
 308 /** Resize given terminal using TIOCSWINSZ, return ioctl() result */
 309 int
 310 tty_resize (int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 311 {
 312 #if defined TIOCSWINSZ
 313     struct winsize tty_size;
 314 
 315     tty_size.ws_row = LINES;
 316     tty_size.ws_col = COLS;
 317     tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
 318 
 319     return ioctl (fd, TIOCSWINSZ, &tty_size);
 320 #else
 321     return 0;
 322 #endif
 323 }
 324 
 325 /* --------------------------------------------------------------------------------------------- */
 326 
 327 /** Clear screen */
 328 void
 329 tty_clear_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 330 {
 331     tty_set_normal_attrs ();
 332     tty_fill_region (0, 0, LINES, COLS, ' ');
 333     tty_refresh ();
 334 }
 335 
 336 /* --------------------------------------------------------------------------------------------- */
 337 
 338 void
 339 tty_init_xterm_support (gboolean is_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 340 {
 341     const char *termvalue;
 342 
 343     termvalue = getenv ("TERM");
 344 
 345     /* Check mouse and ca capabilities */
 346     /* terminfo/termcap structures have been already initialized,
 347        in slang_init() or/and init_curses()  */
 348     /* Check terminfo at first, then check termcap */
 349     xmouse_seq = tty_tgetstr ("kmous");
 350     if (xmouse_seq == NULL)
 351         xmouse_seq = tty_tgetstr ("Km");
 352     smcup = tty_tgetstr ("smcup");
 353     if (smcup == NULL)
 354         smcup = tty_tgetstr ("ti");
 355     rmcup = tty_tgetstr ("rmcup");
 356     if (rmcup == NULL)
 357         rmcup = tty_tgetstr ("te");
 358 
 359     if (strcmp (termvalue, "cygwin") == 0)
 360     {
 361         is_xterm = TRUE;
 362         use_mouse_p = MOUSE_DISABLED;
 363     }
 364 
 365     if (is_xterm)
 366     {
 367         /* Default to the standard xterm sequence */
 368         if (xmouse_seq == NULL)
 369             xmouse_seq = ESC_STR "[M";
 370 
 371         /* Enable mouse unless explicitly disabled by --nomouse */
 372         if (use_mouse_p != MOUSE_DISABLED)
 373         {
 374             if (mc_global.tty.old_mouse)
 375                 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
 376             else
 377             {
 378                 /* FIXME: this dirty hack to set supported type of tracking the mouse */
 379                 const char *color_term = getenv ("COLORTERM");
 380                 if (strncmp (termvalue, "rxvt", 4) == 0 ||
 381                     (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
 382                     strcmp (termvalue, "Eterm") == 0)
 383                     use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
 384                 else
 385                     use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
 386             }
 387         }
 388     }
 389 
 390     /* There's only one termcap entry "kmous", typically containing "\E[M" or "\E[<".
 391      * We need the former in xmouse_seq, the latter in xmouse_extended_seq.
 392      * See tickets 2956, 3954, and 4063 for details. */
 393     if (xmouse_seq != NULL)
 394     {
 395         if (strcmp (xmouse_seq, ESC_STR "[<") == 0)
 396             xmouse_seq = ESC_STR "[M";
 397 
 398         xmouse_extended_seq = ESC_STR "[<";
 399     }
 400 }
 401 
 402 /* --------------------------------------------------------------------------------------------- */

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