Merge branch '2451_no_subst_var'
[midnight-commander.git] / lib / tty / tty-slang.c
blob99af2384b7c67b6126817c23c2318cdd5970a06f
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 <termios.h>
38 #include <sys/types.h> /* size_t */
39 #include <unistd.h>
40 #include <signal.h>
42 #include "lib/global.h"
43 #include "lib/strutil.h" /* str_term_form */
44 #include "lib/util.h" /* is_printable() */
46 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
47 #include "tty.h"
48 #include "color.h"
49 #include "color-slang.h"
50 #include "color-internal.h"
51 #include "mouse.h" /* Gpm_Event is required in key.h */
52 #include "key.h" /* define_sequence */
53 #include "win.h"
56 /*** global variables ****************************************************************************/
58 extern int reset_hp_softkeys;
60 /*** file scope macro definitions ****************************************************************/
62 #ifndef SA_RESTART
63 #define SA_RESTART 0
64 #endif
66 #ifndef SLTT_MAX_SCREEN_COLS
67 #define SLTT_MAX_SCREEN_COLS 512
68 #endif
70 #ifndef SLTT_MAX_SCREEN_ROWS
71 #define SLTT_MAX_SCREEN_ROWS 512
72 #endif
74 /*** file scope type declarations ****************************************************************/
76 /*** file scope variables ************************************************************************/
78 /* Various saved termios settings that we control here */
79 static struct termios boot_mode;
80 static struct termios new_mode;
82 /* Controls whether we should wait for input in tty_lowlevel_getch */
83 static gboolean no_slang_delay;
85 /* This table describes which capabilities we want and which values we
86 * assign to them.
88 static const struct
90 int key_code;
91 const char *key_name;
92 } key_table[] =
94 /* *INDENT-OFF* */
95 { KEY_F (0), "k0" },
96 { KEY_F (1), "k1" },
97 { KEY_F (2), "k2" },
98 { KEY_F (3), "k3" },
99 { KEY_F (4), "k4" },
100 { KEY_F (5), "k5" },
101 { KEY_F (6), "k6" },
102 { KEY_F (7), "k7" },
103 { KEY_F (8), "k8" },
104 { KEY_F (9), "k9" },
105 { KEY_F (10), "k;" },
106 { KEY_F (11), "F1" },
107 { KEY_F (12), "F2" },
108 { KEY_F (13), "F3" },
109 { KEY_F (14), "F4" },
110 { KEY_F (15), "F5" },
111 { KEY_F (16), "F6" },
112 { KEY_F (17), "F7" },
113 { KEY_F (18), "F8" },
114 { KEY_F (19), "F9" },
115 { KEY_F (20), "FA" },
116 { KEY_IC, "kI" },
117 { KEY_NPAGE, "kN" },
118 { KEY_PPAGE, "kP" },
119 { KEY_LEFT, "kl" },
120 { KEY_RIGHT, "kr" },
121 { KEY_UP, "ku" },
122 { KEY_DOWN, "kd" },
123 { KEY_DC, "kD" },
124 { KEY_BACKSPACE, "kb" },
125 { KEY_HOME, "kh" },
126 { KEY_END, "@7" },
127 { 0, NULL }
128 /* *INDENT-ON* */
131 /*** file scope functions ************************************************************************/
132 /* --------------------------------------------------------------------------------------------- */
134 static void
135 tty_setup_sigwinch (void (*handler) (int))
137 #ifdef SIGWINCH
138 struct sigaction act, oact;
139 act.sa_handler = handler;
140 sigemptyset (&act.sa_mask);
141 act.sa_flags = 0;
142 #ifdef SA_RESTART
143 act.sa_flags |= SA_RESTART;
144 #endif /* SA_RESTART */
145 sigaction (SIGWINCH, &act, &oact);
146 #endif /* SIGWINCH */
149 /* --------------------------------------------------------------------------------------------- */
151 static void
152 sigwinch_handler (int dummy)
154 (void) dummy;
156 tty_change_screen_size ();
157 mc_global.tty.winch_flag = TRUE;
160 /* --------------------------------------------------------------------------------------------- */
162 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
163 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
164 consequence is that function keys don't work in MC sometimes...
165 Unfortunately I don't now the one and only escape sequence to turn off.
166 softkeys (elm uses three different capabilities to turn on softkeys and two.
167 capabilities to turn them off)..
168 Among other things elm uses the pair we already use in slang_keypad. That's.
169 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
170 something better the softkeys are programmed to their defaults from the
171 termcap/terminfo database.
172 The escape sequence to program the softkeys is taken from elm and it is.
173 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
174 sequence. -- Norbert
177 static void
178 slang_reset_softkeys (void)
180 int key;
181 char *send;
182 static const char display[] = " ";
183 char tmp[BUF_SMALL];
185 for (key = 1; key < 9; key++)
187 g_snprintf (tmp, sizeof (tmp), "k%d", key);
188 send = (char *) SLtt_tgetstr (tmp);
189 if (send != NULL)
191 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
192 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
193 SLtt_write_string (tmp);
198 /* --------------------------------------------------------------------------------------------- */
200 static void
201 do_define_key (int code, const char *strcap)
203 char *seq;
205 seq = (char *) SLtt_tgetstr ((char *) strcap);
206 if (seq != NULL)
207 define_sequence (code, seq, MCKEY_NOACTION);
210 /* --------------------------------------------------------------------------------------------- */
212 static void
213 load_terminfo_keys (void)
215 int i;
217 for (i = 0; key_table[i].key_code; i++)
218 do_define_key (key_table[i].key_code, key_table[i].key_name);
221 /* --------------------------------------------------------------------------------------------- */
222 /*** public functions ****************************************************************************/
223 /* --------------------------------------------------------------------------------------------- */
226 mc_tty_normalize_lines_char (const char *str)
228 char *str2;
229 int res;
231 struct mc_tty_lines_struct
233 const char *line;
234 int line_code;
235 } const lines_codes[] = {
236 {"\342\224\214", SLSMG_ULCORN_CHAR},
237 {"\342\224\220", SLSMG_URCORN_CHAR},
238 {"\342\224\224", SLSMG_LLCORN_CHAR},
239 {"\342\224\230", SLSMG_LRCORN_CHAR},
240 {"\342\224\234", SLSMG_LTEE_CHAR},
241 {"\342\224\244", SLSMG_RTEE_CHAR},
242 {"\342\224\254", SLSMG_UTEE_CHAR},
243 {"\342\224\264", SLSMG_DTEE_CHAR},
244 {"\342\224\200", SLSMG_HLINE_CHAR},
245 {"\342\224\202", SLSMG_VLINE_CHAR},
246 {"\342\224\274", SLSMG_PLUS_CHAR},
248 {NULL, 0}
251 if (!str)
252 return (int) ' ';
254 for (res = 0; lines_codes[res].line; res++)
256 if (strcmp (str, lines_codes[res].line) == 0)
257 return lines_codes[res].line_code;
260 str2 = mc_tty_normalize_from_utf8 (str);
261 res = g_utf8_get_char_validated (str2, -1);
263 if (res < 0)
264 res = (unsigned char) str2[0];
265 g_free (str2);
267 return res;
270 /* --------------------------------------------------------------------------------------------- */
272 void
273 tty_init (gboolean mouse_enable, gboolean is_xterm)
275 SLtt_Ignore_Beep = 1;
277 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
278 SLtt_get_terminfo ();
280 * If the terminal in not in terminfo but begins with a well-known
281 * string such as "linux" or "xterm" S-Lang will go on, but the
282 * terminal size and several other variables won't be initialized
283 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
284 * small, large and negative screen dimensions.
286 if ((COLS < 10) || (LINES < 5)
287 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
289 fprintf (stderr,
290 _("Screen size %dx%d is not supported.\n"
291 "Check the TERM environment variable.\n"), COLS, LINES);
292 exit (EXIT_FAILURE);
295 tcgetattr (fileno (stdin), &boot_mode);
296 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
297 SLang_init_tty (XCTRL ('g'), 1, 0);
299 if (mc_global.tty.ugly_line_drawing)
300 SLtt_Has_Alt_Charset = 0;
302 /* If SLang uses fileno(stderr) for terminal input MC will hang
303 if we call SLang_getkey between calls to open_error_pipe and
304 close_error_pipe, e.g. when we do a growing view of an gzipped
305 file. */
306 if (SLang_TT_Read_FD == fileno (stderr))
307 SLang_TT_Read_FD = fileno (stdin);
309 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
311 #ifdef VDSUSP
312 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
313 #endif
314 #ifdef VLNEXT
315 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
316 #endif
317 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
320 tty_reset_prog_mode ();
321 load_terminfo_keys ();
323 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
325 tty_start_interrupt_key ();
327 /* It's the small part from the previous init_key() */
328 init_key_input_fd ();
330 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
331 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
332 * detected - but checking TERM would fail under screen, OR running xterm
333 * with allowC1Printable).
335 tty_display_8bit (FALSE);
337 SLsmg_init_smg ();
338 if (!mouse_enable)
339 use_mouse_p = MOUSE_DISABLED;
340 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
341 init_mouse ();
342 do_enter_ca_mode ();
343 tty_keypad (TRUE);
344 tty_nodelay (FALSE);
346 tty_setup_sigwinch (sigwinch_handler);
349 /* --------------------------------------------------------------------------------------------- */
351 void
352 tty_shutdown (void)
354 char *op_cap;
356 disable_mouse ();
357 tty_reset_shell_mode ();
358 tty_noraw_mode ();
359 tty_keypad (FALSE);
360 tty_reset_screen ();
361 do_exit_ca_mode ();
362 SLang_reset_tty ();
364 /* Load the op capability to reset the colors to those that were
365 * active when the program was started up
367 op_cap = SLtt_tgetstr ((char *) "op");
368 if (op_cap != NULL)
370 fputs (op_cap, stdout);
371 fflush (stdout);
375 /* --------------------------------------------------------------------------------------------- */
376 /* Done each time we come back from done mode */
378 void
379 tty_reset_prog_mode (void)
381 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
382 SLsmg_init_smg ();
383 SLsmg_touch_lines (0, LINES);
386 /* --------------------------------------------------------------------------------------------- */
387 /* Called each time we want to shutdown slang screen manager */
389 void
390 tty_reset_shell_mode (void)
392 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
395 /* --------------------------------------------------------------------------------------------- */
397 void
398 tty_raw_mode (void)
400 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
403 /* --------------------------------------------------------------------------------------------- */
405 void
406 tty_noraw_mode (void)
410 /* --------------------------------------------------------------------------------------------- */
412 void
413 tty_noecho (void)
417 /* --------------------------------------------------------------------------------------------- */
420 tty_flush_input (void)
422 return 0; /* OK */
425 /* --------------------------------------------------------------------------------------------- */
427 void
428 tty_keypad (gboolean set)
430 char *keypad_string;
432 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
433 if (keypad_string != NULL)
434 SLtt_write_string (keypad_string);
435 if (set && reset_hp_softkeys)
436 slang_reset_softkeys ();
439 /* --------------------------------------------------------------------------------------------- */
441 void
442 tty_nodelay (gboolean set)
444 no_slang_delay = set;
447 /* --------------------------------------------------------------------------------------------- */
450 tty_baudrate (void)
452 return SLang_TT_Baud_Rate;
455 /* --------------------------------------------------------------------------------------------- */
458 tty_lowlevel_getch (void)
460 int c;
462 if (no_slang_delay && (SLang_input_pending (0) == 0))
463 return -1;
465 c = SLang_getkey ();
466 if (c == SLANG_GETKEY_ERROR)
468 fprintf (stderr,
469 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
470 "Assuming EOF on stdin and exiting\n");
471 exit (EXIT_FAILURE);
474 return c;
477 /* --------------------------------------------------------------------------------------------- */
480 tty_reset_screen (void)
482 SLsmg_reset_smg ();
483 return 0; /* OK */
486 /* --------------------------------------------------------------------------------------------- */
488 void
489 tty_touch_screen (void)
491 SLsmg_touch_lines (0, LINES);
494 /* --------------------------------------------------------------------------------------------- */
496 void
497 tty_gotoyx (int y, int x)
499 SLsmg_gotorc (y, x);
502 /* --------------------------------------------------------------------------------------------- */
504 void
505 tty_getyx (int *py, int *px)
507 *py = SLsmg_get_row ();
508 *px = SLsmg_get_column ();
511 /* --------------------------------------------------------------------------------------------- */
512 /* if x < 0 or y < 0, draw line staring from current position */
514 void
515 tty_draw_hline (int y, int x, int ch, int len)
517 if (ch == ACS_HLINE)
518 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
520 if ((y < 0) || (x < 0))
522 y = SLsmg_get_row ();
523 x = SLsmg_get_column ();
525 else
526 SLsmg_gotorc (y, x);
528 if (ch == 0)
529 ch = ACS_HLINE;
531 if (ch == ACS_HLINE)
532 SLsmg_draw_hline (len);
533 else
534 while (len-- != 0)
535 tty_print_char (ch);
537 SLsmg_gotorc (y, x);
540 /* --------------------------------------------------------------------------------------------- */
541 /* if x < 0 or y < 0, draw line staring from current position */
543 void
544 tty_draw_vline (int y, int x, int ch, int len)
546 if (ch == ACS_VLINE)
547 ch = mc_tty_frm[MC_TTY_FRM_VERT];
549 if ((y < 0) || (x < 0))
551 y = SLsmg_get_row ();
552 x = SLsmg_get_column ();
554 else
555 SLsmg_gotorc (y, x);
557 if (ch == 0)
558 ch = ACS_VLINE;
560 if (ch == ACS_VLINE)
561 SLsmg_draw_vline (len);
562 else
564 int pos = 0;
566 while (len-- != 0)
568 SLsmg_gotorc (y + pos, x);
569 tty_print_char (ch);
570 pos++;
574 SLsmg_gotorc (y, x);
577 /* --------------------------------------------------------------------------------------------- */
579 void
580 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
582 SLsmg_fill_region (y, x, rows, cols, ch);
585 /* --------------------------------------------------------------------------------------------- */
587 void
588 tty_set_alt_charset (gboolean alt_charset)
590 SLsmg_set_char_set ((int) alt_charset);
593 /* --------------------------------------------------------------------------------------------- */
595 void
596 tty_display_8bit (gboolean what)
598 SLsmg_Display_Eight_Bit = what ? 128 : 160;
601 /* --------------------------------------------------------------------------------------------- */
603 void
604 tty_print_char (int c)
606 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
609 /* --------------------------------------------------------------------------------------------- */
611 void
612 tty_print_alt_char (int c, gboolean single)
614 #define DRAW(x, y) (x == y) \
615 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
616 : SLsmg_write_char ((unsigned int) y)
617 switch (c)
619 case ACS_VLINE:
620 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
621 break;
622 case ACS_HLINE:
623 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
624 break;
625 case ACS_LTEE:
626 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
627 break;
628 case ACS_RTEE:
629 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
630 break;
631 case ACS_ULCORNER:
632 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
633 break;
634 case ACS_LLCORNER:
635 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
636 break;
637 case ACS_URCORNER:
638 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
639 break;
640 case ACS_LRCORNER:
641 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
642 break;
643 case ACS_PLUS:
644 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
645 break;
646 default:
647 SLsmg_write_char ((unsigned int) c);
649 #undef DRAW
652 /* --------------------------------------------------------------------------------------------- */
654 void
655 tty_print_anychar (int c)
657 char str[6 + 1];
659 if (c > 255)
661 int res = g_unichar_to_utf8 (c, str);
662 if (res == 0)
664 str[0] = '.';
665 str[1] = '\0';
667 else
669 str[res] = '\0';
671 SLsmg_write_string ((char *) str_term_form (str));
673 else
675 if (!is_printable (c))
676 c = '.';
677 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
681 /* --------------------------------------------------------------------------------------------- */
683 void
684 tty_print_string (const char *s)
686 SLsmg_write_string ((char *) str_term_form (s));
689 /* --------------------------------------------------------------------------------------------- */
691 void
692 tty_printf (const char *fmt, ...)
694 va_list args;
696 va_start (args, fmt);
697 SLsmg_vprintf ((char *) fmt, args);
698 va_end (args);
701 /* --------------------------------------------------------------------------------------------- */
703 char *
704 tty_tgetstr (const char *cap)
706 return SLtt_tgetstr ((char *) cap);
709 /* --------------------------------------------------------------------------------------------- */
711 void
712 tty_refresh (void)
714 SLsmg_refresh ();
717 /* --------------------------------------------------------------------------------------------- */
719 void
720 tty_beep (void)
722 SLtt_beep ();
725 /* --------------------------------------------------------------------------------------------- */