2 Interface to the terminal controlling library.
4 Copyright (C) 2005-2023
5 Free Software Foundation, Inc.
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/>.
28 * \brief Source: %interface to the terminal controlling library
37 #include <string.h> /* memset() */
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
43 #include <sys/types.h>
45 #include <unistd.h> /* exit() */
47 #ifdef HAVE_SYS_IOCTL_H
48 #include <sys/ioctl.h>
51 /* In some systems (like Solaris 11.4 SPARC), TIOCSWINSZ is defined in termios.h */
54 #include "lib/global.h"
55 #include "lib/strutil.h"
58 #include "tty-internal.h"
59 #include "color.h" /* tty_set_normal_attrs() */
60 #include "mouse.h" /* use_mouse_p */
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 /* --------------------------------------------------------------------------------------------- */
82 sigintr_handler (int signo
)
88 /* --------------------------------------------------------------------------------------------- */
89 /*** public functions ****************************************************************************/
90 /* --------------------------------------------------------------------------------------------- */
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:
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
);
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;
136 /* --------------------------------------------------------------------------------------------- */
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
);
147 act
.sa_flags
= SA_RESTART
;
148 #endif /* SA_RESTART */
149 sigaction (SIGINT
, &act
, NULL
);
152 /* --------------------------------------------------------------------------------------------- */
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
);
166 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
182 tty_got_interrupt (void)
186 rv
= (got_interrupt
!= 0);
191 /* --------------------------------------------------------------------------------------------- */
198 /* instant timeout */
199 struct timeval timeout
= { .tv_sec
= 0, .tv_usec
= 0 };
204 FD_SET (sigwinch_pipe
[0], &fdset
);
206 while ((ok
= select (sigwinch_pipe
[0] + 1, &fdset
, NULL
, NULL
, &timeout
)) < 0)
209 perror (_("Cannot check SIGWINCH pipe"));
213 return (ok
!= 0 && FD_ISSET (sigwinch_pipe
[0], &fdset
));
216 /* --------------------------------------------------------------------------------------------- */
219 tty_flush_winch (void)
223 /* merge all SIGWINCH events raised to this moment */
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 /* --------------------------------------------------------------------------------------------- */
237 tty_print_one_hline (gboolean single
)
239 tty_print_alt_char (ACS_HLINE
, single
);
242 /* --------------------------------------------------------------------------------------------- */
245 tty_print_one_vline (gboolean single
)
247 tty_print_alt_char (ACS_VLINE
, single
);
250 /* --------------------------------------------------------------------------------------------- */
253 tty_draw_box (int y
, int x
, int ys
, int xs
, gboolean single
)
257 if (ys
<= 0 || xs
<= 0)
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
);
271 tty_print_alt_char (ACS_ULCORNER
, single
);
273 tty_print_alt_char (ACS_LLCORNER
, single
);
275 tty_print_alt_char (ACS_URCORNER
, single
);
277 tty_print_alt_char (ACS_LRCORNER
, single
);
280 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
294 mc_tty_normalize_from_utf8 (const char *str
)
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 */
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
);
339 /* --------------------------------------------------------------------------------------------- */
343 tty_clear_screen (void)
345 tty_set_normal_attrs ();
346 tty_fill_region (0, 0, LINES
, COLS
, ' ');
350 /* --------------------------------------------------------------------------------------------- */
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");
368 smcup
= tty_tgetstr ("ti");
369 rmcup
= tty_tgetstr ("rmcup");
371 rmcup
= tty_tgetstr ("te");
373 if (strcmp (termvalue
, "cygwin") == 0)
376 use_mouse_p
= MOUSE_DISABLED
;
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
;
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
;
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 /* --------------------------------------------------------------------------------------------- */