Define winch_flag as volatile sig_atomic_t.
[midnight-commander.git] / lib / tty / tty-slang.c
blobc4026f9610b38cb3c03d2acb8bfec3dd77311800
1 /*
2 Interface to the terminal controlling library.
3 Slang wrapper.
5 Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Andrew Borodin <aborodin@vmail.ru>, 2009
10 Egmont Koblinger <egmont@gmail.com>, 2010
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 /** \file
29 * \brief Source: S-Lang-based tty layer of Midnight Commander
32 #include <config.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h> /* size_t */
38 #include <unistd.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 #include <termios.h>
44 #include "lib/global.h"
45 #include "lib/strutil.h" /* str_term_form */
46 #include "lib/util.h" /* is_printable() */
48 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
49 #include "tty.h"
50 #include "color.h"
51 #include "color-slang.h"
52 #include "color-internal.h"
53 #include "mouse.h" /* Gpm_Event is required in key.h */
54 #include "key.h" /* define_sequence */
55 #include "win.h"
58 /*** global variables ****************************************************************************/
60 extern int reset_hp_softkeys;
62 /*** file scope macro definitions ****************************************************************/
64 #ifndef SA_RESTART
65 #define SA_RESTART 0
66 #endif
68 #ifndef SLTT_MAX_SCREEN_COLS
69 #define SLTT_MAX_SCREEN_COLS 512
70 #endif
72 #ifndef SLTT_MAX_SCREEN_ROWS
73 #define SLTT_MAX_SCREEN_ROWS 512
74 #endif
76 /*** file scope type declarations ****************************************************************/
78 /*** file scope variables ************************************************************************/
80 /* Various saved termios settings that we control here */
81 static struct termios boot_mode;
82 static struct termios new_mode;
84 /* Controls whether we should wait for input in tty_lowlevel_getch */
85 static gboolean no_slang_delay;
87 /* This table describes which capabilities we want and which values we
88 * assign to them.
90 static const struct
92 int key_code;
93 const char *key_name;
94 } key_table[] =
96 /* *INDENT-OFF* */
97 { KEY_F (0), "k0" },
98 { KEY_F (1), "k1" },
99 { KEY_F (2), "k2" },
100 { KEY_F (3), "k3" },
101 { KEY_F (4), "k4" },
102 { KEY_F (5), "k5" },
103 { KEY_F (6), "k6" },
104 { KEY_F (7), "k7" },
105 { KEY_F (8), "k8" },
106 { KEY_F (9), "k9" },
107 { KEY_F (10), "k;" },
108 { KEY_F (11), "F1" },
109 { KEY_F (12), "F2" },
110 { KEY_F (13), "F3" },
111 { KEY_F (14), "F4" },
112 { KEY_F (15), "F5" },
113 { KEY_F (16), "F6" },
114 { KEY_F (17), "F7" },
115 { KEY_F (18), "F8" },
116 { KEY_F (19), "F9" },
117 { KEY_F (20), "FA" },
118 { KEY_IC, "kI" },
119 { KEY_NPAGE, "kN" },
120 { KEY_PPAGE, "kP" },
121 { KEY_LEFT, "kl" },
122 { KEY_RIGHT, "kr" },
123 { KEY_UP, "ku" },
124 { KEY_DOWN, "kd" },
125 { KEY_DC, "kD" },
126 { KEY_BACKSPACE, "kb" },
127 { KEY_HOME, "kh" },
128 { KEY_END, "@7" },
129 { 0, NULL }
130 /* *INDENT-ON* */
133 /* --------------------------------------------------------------------------------------------- */
134 /*** file scope functions ************************************************************************/
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 tty_setup_sigwinch (void (*handler) (int))
140 (void) SLsignal (SIGWINCH, handler);
143 /* --------------------------------------------------------------------------------------------- */
145 static void
146 sigwinch_handler (int dummy)
148 (void) dummy;
150 mc_global.tty.winch_flag = 1;
151 (void) SLsignal (SIGWINCH, sigwinch_handler);
154 /* --------------------------------------------------------------------------------------------- */
156 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
157 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
158 consequence is that function keys don't work in MC sometimes...
159 Unfortunately I don't now the one and only escape sequence to turn off.
160 softkeys (elm uses three different capabilities to turn on softkeys and two.
161 capabilities to turn them off)..
162 Among other things elm uses the pair we already use in slang_keypad. That's.
163 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
164 something better the softkeys are programmed to their defaults from the
165 termcap/terminfo database.
166 The escape sequence to program the softkeys is taken from elm and it is.
167 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
168 sequence. -- Norbert
171 static void
172 slang_reset_softkeys (void)
174 int key;
175 char *send;
176 static const char display[] = " ";
177 char tmp[BUF_SMALL];
179 for (key = 1; key < 9; key++)
181 g_snprintf (tmp, sizeof (tmp), "k%d", key);
182 send = (char *) SLtt_tgetstr (tmp);
183 if (send != NULL)
185 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
186 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
187 SLtt_write_string (tmp);
192 /* --------------------------------------------------------------------------------------------- */
194 static void
195 do_define_key (int code, const char *strcap)
197 char *seq;
199 seq = (char *) SLtt_tgetstr ((char *) strcap);
200 if (seq != NULL)
201 define_sequence (code, seq, MCKEY_NOACTION);
204 /* --------------------------------------------------------------------------------------------- */
206 static void
207 load_terminfo_keys (void)
209 int i;
211 for (i = 0; key_table[i].key_code; i++)
212 do_define_key (key_table[i].key_code, key_table[i].key_name);
215 /* --------------------------------------------------------------------------------------------- */
216 /*** public functions ****************************************************************************/
217 /* --------------------------------------------------------------------------------------------- */
220 mc_tty_normalize_lines_char (const char *str)
222 char *str2;
223 int res;
225 struct mc_tty_lines_struct
227 const char *line;
228 int line_code;
229 } const lines_codes[] = {
230 {"\342\224\214", SLSMG_ULCORN_CHAR},
231 {"\342\224\220", SLSMG_URCORN_CHAR},
232 {"\342\224\224", SLSMG_LLCORN_CHAR},
233 {"\342\224\230", SLSMG_LRCORN_CHAR},
234 {"\342\224\234", SLSMG_LTEE_CHAR},
235 {"\342\224\244", SLSMG_RTEE_CHAR},
236 {"\342\224\254", SLSMG_UTEE_CHAR},
237 {"\342\224\264", SLSMG_DTEE_CHAR},
238 {"\342\224\200", SLSMG_HLINE_CHAR},
239 {"\342\224\202", SLSMG_VLINE_CHAR},
240 {"\342\224\274", SLSMG_PLUS_CHAR},
242 {NULL, 0}
245 if (!str)
246 return (int) ' ';
248 for (res = 0; lines_codes[res].line; res++)
250 if (strcmp (str, lines_codes[res].line) == 0)
251 return lines_codes[res].line_code;
254 str2 = mc_tty_normalize_from_utf8 (str);
255 res = g_utf8_get_char_validated (str2, -1);
257 if (res < 0)
258 res = (unsigned char) str2[0];
259 g_free (str2);
261 return res;
264 /* --------------------------------------------------------------------------------------------- */
266 void
267 tty_init (gboolean mouse_enable, gboolean is_xterm)
269 SLtt_Ignore_Beep = 1;
271 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
272 SLtt_get_terminfo ();
274 * If the terminal in not in terminfo but begins with a well-known
275 * string such as "linux" or "xterm" S-Lang will go on, but the
276 * terminal size and several other variables won't be initialized
277 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
278 * small, large and negative screen dimensions.
280 if ((COLS < 10) || (LINES < 5)
281 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
283 fprintf (stderr,
284 _("Screen size %dx%d is not supported.\n"
285 "Check the TERM environment variable.\n"), COLS, LINES);
286 exit (EXIT_FAILURE);
289 tcgetattr (fileno (stdin), &boot_mode);
290 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
291 SLang_init_tty (XCTRL ('g'), 1, 0);
293 if (mc_global.tty.ugly_line_drawing)
294 SLtt_Has_Alt_Charset = 0;
296 /* If SLang uses fileno(stderr) for terminal input MC will hang
297 if we call SLang_getkey between calls to open_error_pipe and
298 close_error_pipe, e.g. when we do a growing view of an gzipped
299 file. */
300 if (SLang_TT_Read_FD == fileno (stderr))
301 SLang_TT_Read_FD = fileno (stdin);
303 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
305 #ifdef VDSUSP
306 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
307 #endif
308 #ifdef VLNEXT
309 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
310 #endif
311 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
314 tty_reset_prog_mode ();
315 load_terminfo_keys ();
317 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
319 tty_start_interrupt_key ();
321 /* It's the small part from the previous init_key() */
322 init_key_input_fd ();
324 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
325 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
326 * detected - but checking TERM would fail under screen, OR running xterm
327 * with allowC1Printable).
329 tty_display_8bit (FALSE);
331 SLsmg_init_smg ();
332 if (!mouse_enable)
333 use_mouse_p = MOUSE_DISABLED;
334 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
335 init_mouse ();
336 do_enter_ca_mode ();
337 tty_keypad (TRUE);
338 tty_nodelay (FALSE);
340 tty_setup_sigwinch (sigwinch_handler);
343 /* --------------------------------------------------------------------------------------------- */
345 void
346 tty_shutdown (void)
348 char *op_cap;
350 disable_mouse ();
351 tty_reset_shell_mode ();
352 tty_noraw_mode ();
353 tty_keypad (FALSE);
354 tty_reset_screen ();
355 do_exit_ca_mode ();
356 SLang_reset_tty ();
358 /* Load the op capability to reset the colors to those that were
359 * active when the program was started up
361 op_cap = SLtt_tgetstr ((char *) "op");
362 if (op_cap != NULL)
364 fputs (op_cap, stdout);
365 fflush (stdout);
369 /* --------------------------------------------------------------------------------------------- */
371 void
372 tty_change_screen_size (void)
374 SLtt_get_screen_size ();
375 SLsmg_reinit_smg ();
377 #ifdef ENABLE_SUBSHELL
378 if (mc_global.tty.use_subshell)
379 tty_resize (mc_global.tty.subshell_pty);
380 #endif
383 /* --------------------------------------------------------------------------------------------- */
384 /* Done each time we come back from done mode */
386 void
387 tty_reset_prog_mode (void)
389 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
390 SLsmg_init_smg ();
391 SLsmg_touch_lines (0, LINES);
394 /* --------------------------------------------------------------------------------------------- */
395 /* Called each time we want to shutdown slang screen manager */
397 void
398 tty_reset_shell_mode (void)
400 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
403 /* --------------------------------------------------------------------------------------------- */
405 void
406 tty_raw_mode (void)
408 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
411 /* --------------------------------------------------------------------------------------------- */
413 void
414 tty_noraw_mode (void)
418 /* --------------------------------------------------------------------------------------------- */
420 void
421 tty_noecho (void)
425 /* --------------------------------------------------------------------------------------------- */
428 tty_flush_input (void)
430 return 0; /* OK */
433 /* --------------------------------------------------------------------------------------------- */
435 void
436 tty_keypad (gboolean set)
438 char *keypad_string;
440 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
441 if (keypad_string != NULL)
442 SLtt_write_string (keypad_string);
443 if (set && reset_hp_softkeys)
444 slang_reset_softkeys ();
447 /* --------------------------------------------------------------------------------------------- */
449 void
450 tty_nodelay (gboolean set)
452 no_slang_delay = set;
455 /* --------------------------------------------------------------------------------------------- */
458 tty_baudrate (void)
460 return SLang_TT_Baud_Rate;
463 /* --------------------------------------------------------------------------------------------- */
466 tty_lowlevel_getch (void)
468 int c;
470 if (no_slang_delay && (SLang_input_pending (0) == 0))
471 return -1;
473 c = SLang_getkey ();
474 if (c == SLANG_GETKEY_ERROR)
476 fprintf (stderr,
477 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
478 "Assuming EOF on stdin and exiting\n");
479 exit (EXIT_FAILURE);
482 return c;
485 /* --------------------------------------------------------------------------------------------- */
488 tty_reset_screen (void)
490 SLsmg_reset_smg ();
491 return 0; /* OK */
494 /* --------------------------------------------------------------------------------------------- */
496 void
497 tty_touch_screen (void)
499 SLsmg_touch_lines (0, LINES);
502 /* --------------------------------------------------------------------------------------------- */
504 void
505 tty_gotoyx (int y, int x)
507 SLsmg_gotorc (y, x);
510 /* --------------------------------------------------------------------------------------------- */
512 void
513 tty_getyx (int *py, int *px)
515 *py = SLsmg_get_row ();
516 *px = SLsmg_get_column ();
519 /* --------------------------------------------------------------------------------------------- */
521 void
522 tty_draw_hline (int y, int x, int ch, int len)
524 int x1;
526 if (y < 0 || y >= LINES || x >= COLS)
527 return;
529 x1 = x;
531 if (x < 0)
533 len += x;
534 if (len <= 0)
535 return;
536 x = 0;
539 if (ch == ACS_HLINE)
540 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
541 if (ch == 0)
542 ch = ACS_HLINE;
544 SLsmg_gotorc (y, x);
546 if (ch == ACS_HLINE)
547 SLsmg_draw_hline (len);
548 else
549 while (len-- != 0)
550 tty_print_char (ch);
552 SLsmg_gotorc (y, x1);
555 /* --------------------------------------------------------------------------------------------- */
557 void
558 tty_draw_vline (int y, int x, int ch, int len)
560 int y1;
562 if (x < 0 || x >= COLS || y >= LINES)
563 return;
565 y1 = y;
567 if (y < 0)
569 len += y;
570 if (len <= 0)
571 return;
572 y = 0;
575 if (ch == ACS_VLINE)
576 ch = mc_tty_frm[MC_TTY_FRM_VERT];
577 if (ch == 0)
578 ch = ACS_VLINE;
580 SLsmg_gotorc (y, x);
582 if (ch == ACS_VLINE)
583 SLsmg_draw_vline (len);
584 else
586 int pos = 0;
588 while (len-- != 0)
590 SLsmg_gotorc (y + pos, x);
591 tty_print_char (ch);
592 pos++;
596 SLsmg_gotorc (y1, x);
599 /* --------------------------------------------------------------------------------------------- */
601 void
602 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
604 SLsmg_fill_region (y, x, rows, cols, ch);
607 /* --------------------------------------------------------------------------------------------- */
609 void
610 tty_set_alt_charset (gboolean alt_charset)
612 SLsmg_set_char_set ((int) alt_charset);
615 /* --------------------------------------------------------------------------------------------- */
617 void
618 tty_display_8bit (gboolean what)
620 SLsmg_Display_Eight_Bit = what ? 128 : 160;
623 /* --------------------------------------------------------------------------------------------- */
625 void
626 tty_print_char (int c)
628 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
631 /* --------------------------------------------------------------------------------------------- */
633 void
634 tty_print_alt_char (int c, gboolean single)
636 #define DRAW(x, y) (x == y) \
637 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
638 : SLsmg_write_char ((unsigned int) y)
639 switch (c)
641 case ACS_VLINE:
642 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
643 break;
644 case ACS_HLINE:
645 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
646 break;
647 case ACS_LTEE:
648 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
649 break;
650 case ACS_RTEE:
651 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
652 break;
653 case ACS_ULCORNER:
654 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
655 break;
656 case ACS_LLCORNER:
657 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
658 break;
659 case ACS_URCORNER:
660 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
661 break;
662 case ACS_LRCORNER:
663 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
664 break;
665 case ACS_PLUS:
666 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
667 break;
668 default:
669 SLsmg_write_char ((unsigned int) c);
671 #undef DRAW
674 /* --------------------------------------------------------------------------------------------- */
676 void
677 tty_print_anychar (int c)
679 char str[6 + 1];
681 if (c > 255)
683 int res = g_unichar_to_utf8 (c, str);
684 if (res == 0)
686 str[0] = '.';
687 str[1] = '\0';
689 else
691 str[res] = '\0';
693 SLsmg_write_string ((char *) str_term_form (str));
695 else
697 if (!is_printable (c))
698 c = '.';
699 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
703 /* --------------------------------------------------------------------------------------------- */
705 void
706 tty_print_string (const char *s)
708 SLsmg_write_string ((char *) str_term_form (s));
711 /* --------------------------------------------------------------------------------------------- */
713 void
714 tty_printf (const char *fmt, ...)
716 va_list args;
718 va_start (args, fmt);
719 SLsmg_vprintf ((char *) fmt, args);
720 va_end (args);
723 /* --------------------------------------------------------------------------------------------- */
725 char *
726 tty_tgetstr (const char *cap)
728 return SLtt_tgetstr ((char *) cap);
731 /* --------------------------------------------------------------------------------------------- */
733 void
734 tty_refresh (void)
736 SLsmg_refresh ();
739 /* --------------------------------------------------------------------------------------------- */
741 void
742 tty_beep (void)
744 SLtt_beep ();
747 /* --------------------------------------------------------------------------------------------- */