Update hints translations from Transifex
[midnight-commander.git] / lib / tty / tty.c
blobcae0a05ecd934e1f899996a54a91f0786d8d8aa3
1 /*
2 Interface to the terminal controlling library.
4 Copyright (C) 2005-2023
5 Free Software Foundation, Inc.
7 Written by:
8 Roland Illig <roland.illig@gmx.de>, 2005.
9 Andrew Borodin <aborodin@vmail.ru>, 2009.
11 This file is part of the Midnight Commander.
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.
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.
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/>.
27 /** \file tty.c
28 * \brief Source: %interface to the terminal controlling library
31 #include <config.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h> /* memset() */
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() */
47 #ifdef HAVE_SYS_IOCTL_H
48 #include <sys/ioctl.h>
49 #endif
51 /* In some systems (like Solaris 11.4 SPARC), TIOCSWINSZ is defined in termios.h */
52 #include <termios.h>
54 #include "lib/global.h"
55 #include "lib/strutil.h"
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"
63 /*** global variables ****************************************************************************/
65 int mc_tty_frm[MC_TTY_FRM_MAX];
67 /*** file scope macro definitions ****************************************************************/
69 /*** file scope type declarations ****************************************************************/
71 /*** forward declarations (file scope functions) *************************************************/
73 /*** file scope variables ************************************************************************/
75 static SIG_ATOMIC_VOLATILE_T got_interrupt = 0;
77 /* --------------------------------------------------------------------------------------------- */
78 /*** file scope functions ************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
81 static void
82 sigintr_handler (int signo)
84 (void) &signo;
85 got_interrupt = 1;
88 /* --------------------------------------------------------------------------------------------- */
89 /*** public functions ****************************************************************************/
90 /* --------------------------------------------------------------------------------------------- */
92 /**
93 * Check terminal type. If $TERM is not set or value is empty, mc finishes with EXIT_FAILURE.
95 * @param force_xterm Set forced the XTerm type
97 * @return true if @param force_xterm is true or value of $TERM is one of following:
98 * term*
99 * konsole*
100 * rxvt*
101 * Eterm
102 * dtterm
103 * alacritty*
104 * foot*
105 * screen*
106 * tmux*
107 * contour*
109 gboolean
110 tty_check_term (gboolean force_xterm)
112 const char *termvalue;
114 termvalue = getenv ("TERM");
115 if (termvalue == NULL || *termvalue == '\0')
117 fputs (_("The TERM environment variable is unset!\n"), stderr);
118 exit (EXIT_FAILURE);
121 /* *INDENT-OFF* */
122 return force_xterm
123 || strncmp (termvalue, "xterm", 5) == 0
124 || strncmp (termvalue, "konsole", 7) == 0
125 || strncmp (termvalue, "rxvt", 4) == 0
126 || strcmp (termvalue, "Eterm") == 0
127 || strcmp (termvalue, "dtterm") == 0
128 || strncmp (termvalue, "alacritty", 9) == 0
129 || strncmp (termvalue, "foot", 4) == 0
130 || strncmp (termvalue, "screen", 6) == 0
131 || strncmp (termvalue, "tmux", 4) == 0
132 || strncmp (termvalue, "contour", 7) == 0;
133 /* *INDENT-ON* */
136 /* --------------------------------------------------------------------------------------------- */
138 extern void
139 tty_start_interrupt_key (void)
141 struct sigaction act;
143 memset (&act, 0, sizeof (act));
144 act.sa_handler = sigintr_handler;
145 sigemptyset (&act.sa_mask);
146 #ifdef SA_RESTART
147 act.sa_flags = SA_RESTART;
148 #endif /* SA_RESTART */
149 sigaction (SIGINT, &act, NULL);
152 /* --------------------------------------------------------------------------------------------- */
154 extern void
155 tty_enable_interrupt_key (void)
157 struct sigaction act;
159 memset (&act, 0, sizeof (act));
160 act.sa_handler = sigintr_handler;
161 sigemptyset (&act.sa_mask);
162 sigaction (SIGINT, &act, NULL);
163 got_interrupt = 0;
166 /* --------------------------------------------------------------------------------------------- */
168 extern void
169 tty_disable_interrupt_key (void)
171 struct sigaction act;
173 memset (&act, 0, sizeof (act));
174 act.sa_handler = SIG_IGN;
175 sigemptyset (&act.sa_mask);
176 sigaction (SIGINT, &act, NULL);
179 /* --------------------------------------------------------------------------------------------- */
181 extern gboolean
182 tty_got_interrupt (void)
184 gboolean rv;
186 rv = (got_interrupt != 0);
187 got_interrupt = 0;
188 return rv;
191 /* --------------------------------------------------------------------------------------------- */
193 gboolean
194 tty_got_winch (void)
196 fd_set fdset;
197 /* *INDENT-OFF* */
198 /* instant timeout */
199 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
200 /* *INDENT-ON* */
201 int ok;
203 FD_ZERO (&fdset);
204 FD_SET (sigwinch_pipe[0], &fdset);
206 while ((ok = select (sigwinch_pipe[0] + 1, &fdset, NULL, NULL, &timeout)) < 0)
207 if (errno != EINTR)
209 perror (_("Cannot check SIGWINCH pipe"));
210 exit (EXIT_FAILURE);
213 return (ok != 0 && FD_ISSET (sigwinch_pipe[0], &fdset));
216 /* --------------------------------------------------------------------------------------------- */
218 void
219 tty_flush_winch (void)
221 ssize_t n;
223 /* merge all SIGWINCH events raised to this moment */
226 char x[16];
228 /* read multiple events at a time */
229 n = read (sigwinch_pipe[0], &x, sizeof (x));
231 while (n > 0 || (n == -1 && errno == EINTR));
234 /* --------------------------------------------------------------------------------------------- */
236 void
237 tty_print_one_hline (gboolean single)
239 tty_print_alt_char (ACS_HLINE, single);
242 /* --------------------------------------------------------------------------------------------- */
244 void
245 tty_print_one_vline (gboolean single)
247 tty_print_alt_char (ACS_VLINE, single);
250 /* --------------------------------------------------------------------------------------------- */
252 void
253 tty_draw_box (int y, int x, int ys, int xs, gboolean single)
255 int y2, x2;
257 if (ys <= 0 || xs <= 0)
258 return;
260 ys--;
261 xs--;
263 y2 = y + ys;
264 x2 = x + xs;
266 tty_draw_vline (y, x, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
267 tty_draw_vline (y, x2, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
268 tty_draw_hline (y, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
269 tty_draw_hline (y2, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
270 tty_gotoyx (y, x);
271 tty_print_alt_char (ACS_ULCORNER, single);
272 tty_gotoyx (y2, x);
273 tty_print_alt_char (ACS_LLCORNER, single);
274 tty_gotoyx (y, x2);
275 tty_print_alt_char (ACS_URCORNER, single);
276 tty_gotoyx (y2, x2);
277 tty_print_alt_char (ACS_LRCORNER, single);
280 /* --------------------------------------------------------------------------------------------- */
282 void
283 tty_draw_box_shadow (int y, int x, int rows, int cols, int shadow_color)
285 /* draw right shadow */
286 tty_colorize_area (y + 1, x + cols, rows - 1, 2, shadow_color);
287 /* draw bottom shadow */
288 tty_colorize_area (y + rows, x + 2, 1, cols, shadow_color);
291 /* --------------------------------------------------------------------------------------------- */
293 char *
294 mc_tty_normalize_from_utf8 (const char *str)
296 GIConv conv;
297 GString *buffer;
298 const char *_system_codepage = str_detect_termencoding ();
300 if (str_isutf8 (_system_codepage))
301 return g_strdup (str);
303 conv = g_iconv_open (_system_codepage, "UTF-8");
304 if (conv == INVALID_CONV)
305 return g_strdup (str);
307 buffer = g_string_new ("");
309 if (str_convert (conv, str, buffer) == ESTR_FAILURE)
311 g_string_free (buffer, TRUE);
312 str_close_conv (conv);
313 return g_strdup (str);
315 str_close_conv (conv);
317 return g_string_free (buffer, FALSE);
320 /* --------------------------------------------------------------------------------------------- */
322 /** Resize given terminal using TIOCSWINSZ, return ioctl() result */
324 tty_resize (int fd)
326 #if defined TIOCSWINSZ
327 struct winsize tty_size;
329 tty_size.ws_row = LINES;
330 tty_size.ws_col = COLS;
331 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
333 return ioctl (fd, TIOCSWINSZ, &tty_size);
334 #else
335 return 0;
336 #endif
339 /* --------------------------------------------------------------------------------------------- */
341 /** Clear screen */
342 void
343 tty_clear_screen (void)
345 tty_set_normal_attrs ();
346 tty_fill_region (0, 0, LINES, COLS, ' ');
347 tty_refresh ();
350 /* --------------------------------------------------------------------------------------------- */
352 void
353 tty_init_xterm_support (gboolean is_xterm)
355 const char *termvalue;
357 termvalue = getenv ("TERM");
359 /* Check mouse and ca capabilities */
360 /* terminfo/termcap structures have been already initialized,
361 in slang_init() or/and init_curses() */
362 /* Check terminfo at first, then check termcap */
363 xmouse_seq = tty_tgetstr ("kmous");
364 if (xmouse_seq == NULL)
365 xmouse_seq = tty_tgetstr ("Km");
366 smcup = tty_tgetstr ("smcup");
367 if (smcup == NULL)
368 smcup = tty_tgetstr ("ti");
369 rmcup = tty_tgetstr ("rmcup");
370 if (rmcup == NULL)
371 rmcup = tty_tgetstr ("te");
373 if (strcmp (termvalue, "cygwin") == 0)
375 is_xterm = TRUE;
376 use_mouse_p = MOUSE_DISABLED;
379 if (is_xterm)
381 /* Default to the standard xterm sequence */
382 if (xmouse_seq == NULL)
383 xmouse_seq = ESC_STR "[M";
385 /* Enable mouse unless explicitly disabled by --nomouse */
386 if (use_mouse_p != MOUSE_DISABLED)
388 if (mc_global.tty.old_mouse)
389 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
390 else
392 /* FIXME: this dirty hack to set supported type of tracking the mouse */
393 const char *color_term = getenv ("COLORTERM");
394 if (strncmp (termvalue, "rxvt", 4) == 0 ||
395 (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
396 strcmp (termvalue, "Eterm") == 0)
397 use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
398 else
399 use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
404 /* There's only one termcap entry "kmous", typically containing "\E[M" or "\E[<".
405 * We need the former in xmouse_seq, the latter in xmouse_extended_seq.
406 * See tickets 2956, 3954, and 4063 for details. */
407 if (xmouse_seq != NULL)
409 if (strcmp (xmouse_seq, ESC_STR "[<") == 0)
410 xmouse_seq = ESC_STR "[M";
412 xmouse_extended_seq = ESC_STR "[<";
416 /* --------------------------------------------------------------------------------------------- */