Ticket #1668: Screen and input corruption under xterm [non-UTF]
[midnight-commander.git] / lib / tty / tty-slang.c
bloba80ba81b6583211c8307ad97aac6bdf35e71407b
1 /*
2 Interface to the terminal controlling library.
3 Slang wrapper.
5 Copyright (C) 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
7 Written by:
8 Andrew Borodin <aborodin@vmail.ru>, 2009.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software; you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be
18 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
19 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 MA 02110-1301, USA.
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" /* slow_tty */
47 #include "tty.h"
48 #include "color-slang.h"
49 #include "color-internal.h"
50 #include "mouse.h" /* Gpm_Event is required in key.h */
51 #include "key.h" /* define_sequence */
52 #include "win.h"
55 /*** global variables ****************************************************************************/
57 extern int reset_hp_softkeys;
59 /*** file scope macro definitions ****************************************************************/
61 #ifndef SA_RESTART
62 #define SA_RESTART 0
63 #endif
65 #ifndef SLTT_MAX_SCREEN_COLS
66 #define SLTT_MAX_SCREEN_COLS 512
67 #endif
69 #ifndef SLTT_MAX_SCREEN_ROWS
70 #define SLTT_MAX_SCREEN_ROWS 512
71 #endif
73 /*** file scope type declarations ****************************************************************/
75 /*** file scope variables ************************************************************************/
77 /* Various saved termios settings that we control here */
78 static struct termios boot_mode;
79 static struct termios new_mode;
81 /* Controls whether we should wait for input in tty_lowlevel_getch */
82 static gboolean no_slang_delay;
84 /* This table describes which capabilities we want and which values we
85 * assign to them.
87 static const struct
89 int key_code;
90 const char *key_name;
91 } key_table[] =
93 /* *INDENT-OFF* */
94 { KEY_F (0), "k0" },
95 { KEY_F (1), "k1" },
96 { KEY_F (2), "k2" },
97 { KEY_F (3), "k3" },
98 { KEY_F (4), "k4" },
99 { KEY_F (5), "k5" },
100 { KEY_F (6), "k6" },
101 { KEY_F (7), "k7" },
102 { KEY_F (8), "k8" },
103 { KEY_F (9), "k9" },
104 { KEY_F (10), "k;" },
105 { KEY_F (11), "F1" },
106 { KEY_F (12), "F2" },
107 { KEY_F (13), "F3" },
108 { KEY_F (14), "F4" },
109 { KEY_F (15), "F5" },
110 { KEY_F (16), "F6" },
111 { KEY_F (17), "F7" },
112 { KEY_F (18), "F8" },
113 { KEY_F (19), "F9" },
114 { KEY_F (20), "FA" },
115 { KEY_IC, "kI" },
116 { KEY_NPAGE, "kN" },
117 { KEY_PPAGE, "kP" },
118 { KEY_LEFT, "kl" },
119 { KEY_RIGHT, "kr" },
120 { KEY_UP, "ku" },
121 { KEY_DOWN, "kd" },
122 { KEY_DC, "kD" },
123 { KEY_BACKSPACE, "kb" },
124 { KEY_HOME, "kh" },
125 { KEY_END, "@7" },
126 { 0, NULL }
127 /* *INDENT-ON* */
130 /*** file scope functions ************************************************************************/
131 /* --------------------------------------------------------------------------------------------- */
133 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
134 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
135 consequence is that function keys don't work in MC sometimes...
136 Unfortunately I don't now the one and only escape sequence to turn off.
137 softkeys (elm uses three different capabilities to turn on softkeys and two.
138 capabilities to turn them off)..
139 Among other things elm uses the pair we already use in slang_keypad. That's.
140 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
141 something better the softkeys are programmed to their defaults from the
142 termcap/terminfo database.
143 The escape sequence to program the softkeys is taken from elm and it is.
144 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
145 sequence. -- Norbert
148 static void
149 slang_reset_softkeys (void)
151 int key;
152 char *send;
153 static const char display[] = " ";
154 char tmp[BUF_SMALL];
156 for (key = 1; key < 9; key++)
158 g_snprintf (tmp, sizeof (tmp), "k%d", key);
159 send = (char *) SLtt_tgetstr (tmp);
160 if (send != NULL)
162 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
163 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
164 SLtt_write_string (tmp);
169 /* --------------------------------------------------------------------------------------------- */
171 static void
172 do_define_key (int code, const char *strcap)
174 char *seq;
176 seq = (char *) SLtt_tgetstr ((char *) strcap);
177 if (seq != NULL)
178 define_sequence (code, seq, MCKEY_NOACTION);
181 /* --------------------------------------------------------------------------------------------- */
183 static void
184 load_terminfo_keys (void)
186 int i;
188 for (i = 0; key_table[i].key_code; i++)
189 do_define_key (key_table[i].key_code, key_table[i].key_name);
192 /* --------------------------------------------------------------------------------------------- */
193 /*** public functions ****************************************************************************/
194 /* --------------------------------------------------------------------------------------------- */
197 mc_tty_normalize_lines_char (const char *str)
199 char *str2;
200 int res;
202 struct mc_tty_lines_struct
204 const char *line;
205 int line_code;
206 } const lines_codes[] = {
207 {"\342\224\214", SLSMG_ULCORN_CHAR},
208 {"\342\224\220", SLSMG_URCORN_CHAR},
209 {"\342\224\224", SLSMG_LLCORN_CHAR},
210 {"\342\224\230", SLSMG_LRCORN_CHAR},
211 {"\342\224\234", SLSMG_LTEE_CHAR},
212 {"\342\224\244", SLSMG_RTEE_CHAR},
213 {"\342\224\254", SLSMG_UTEE_CHAR},
214 {"\342\224\264", SLSMG_DTEE_CHAR},
215 {"\342\224\200", SLSMG_HLINE_CHAR},
216 {"\342\224\202", SLSMG_VLINE_CHAR},
217 {"\342\224\274", SLSMG_PLUS_CHAR},
219 {NULL, 0}
222 if (!str)
223 return (int) ' ';
225 for (res = 0; lines_codes[res].line; res++)
227 if (strcmp (str, lines_codes[res].line) == 0)
228 return lines_codes[res].line_code;
231 str2 = mc_tty_normalize_from_utf8 (str);
232 res = g_utf8_get_char_validated (str2, -1);
234 if (res < 0)
235 res = (unsigned char) str2[0];
236 g_free (str2);
238 return res;
241 /* --------------------------------------------------------------------------------------------- */
243 void
244 tty_init (gboolean slow, gboolean ugly_lines)
246 slow_tty = slow;
247 ugly_line_drawing = ugly_lines;
249 SLtt_Ignore_Beep = 1;
250 SLtt_get_terminfo ();
251 SLutf8_enable (-1);
253 * If the terminal in not in terminfo but begins with a well-known
254 * string such as "linux" or "xterm" S-Lang will go on, but the
255 * terminal size and several other variables won't be initialized
256 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
257 * small, large and negative screen dimensions.
259 if ((COLS < 10) || (LINES < 5)
260 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
262 fprintf (stderr,
263 _("Screen size %dx%d is not supported.\n"
264 "Check the TERM environment variable.\n"), COLS, LINES);
265 exit (EXIT_FAILURE);
268 tcgetattr (fileno (stdin), &boot_mode);
269 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
270 SLang_init_tty (XCTRL ('g'), 1, 0);
272 if (ugly_lines)
273 SLtt_Has_Alt_Charset = 0;
275 /* If SLang uses fileno(stderr) for terminal input MC will hang
276 if we call SLang_getkey between calls to open_error_pipe and
277 close_error_pipe, e.g. when we do a growing view of an gzipped
278 file. */
279 if (SLang_TT_Read_FD == fileno (stderr))
280 SLang_TT_Read_FD = fileno (stdin);
282 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
284 #ifdef VDSUSP
285 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
286 #endif
287 #ifdef VLNEXT
288 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
289 #endif
290 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
293 tty_reset_prog_mode ();
294 load_terminfo_keys ();
295 SLtt_Blink_Mode = 0;
297 tty_start_interrupt_key ();
299 /* It's the small part from the previous init_key() */
300 init_key_input_fd ();
302 SLsmg_init_smg ();
303 do_enter_ca_mode ();
304 tty_keypad (TRUE);
305 tty_nodelay (FALSE);
308 /* --------------------------------------------------------------------------------------------- */
310 void
311 tty_shutdown (void)
313 char *op_cap;
315 SLsmg_reset_smg ();
316 tty_reset_shell_mode ();
317 do_exit_ca_mode ();
318 SLang_reset_tty ();
320 /* Load the op capability to reset the colors to those that were
321 * active when the program was started up
323 op_cap = SLtt_tgetstr ((char *) "op");
324 if (op_cap != NULL)
326 fputs (op_cap, stdout);
327 fflush (stdout);
331 /* --------------------------------------------------------------------------------------------- */
332 /* Done each time we come back from done mode */
334 void
335 tty_reset_prog_mode (void)
337 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
338 SLsmg_init_smg ();
339 SLsmg_touch_lines (0, LINES);
342 /* --------------------------------------------------------------------------------------------- */
343 /* Called each time we want to shutdown slang screen manager */
345 void
346 tty_reset_shell_mode (void)
348 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
351 /* --------------------------------------------------------------------------------------------- */
353 void
354 tty_raw_mode (void)
356 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
359 /* --------------------------------------------------------------------------------------------- */
361 void
362 tty_noraw_mode (void)
366 /* --------------------------------------------------------------------------------------------- */
368 void
369 tty_noecho (void)
373 /* --------------------------------------------------------------------------------------------- */
376 tty_flush_input (void)
378 return 0; /* OK */
381 /* --------------------------------------------------------------------------------------------- */
383 void
384 tty_keypad (gboolean set)
386 char *keypad_string;
388 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
389 if (keypad_string != NULL)
390 SLtt_write_string (keypad_string);
391 if (set && reset_hp_softkeys)
392 slang_reset_softkeys ();
395 /* --------------------------------------------------------------------------------------------- */
397 void
398 tty_nodelay (gboolean set)
400 no_slang_delay = set;
403 /* --------------------------------------------------------------------------------------------- */
406 tty_baudrate (void)
408 return SLang_TT_Baud_Rate;
411 /* --------------------------------------------------------------------------------------------- */
414 tty_lowlevel_getch (void)
416 int c;
418 if (no_slang_delay && (SLang_input_pending (0) == 0))
419 return -1;
421 c = SLang_getkey ();
422 if (c == SLANG_GETKEY_ERROR)
424 fprintf (stderr,
425 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
426 "Assuming EOF on stdin and exiting\n");
427 exit (EXIT_FAILURE);
430 return c;
433 /* --------------------------------------------------------------------------------------------- */
436 tty_reset_screen (void)
438 SLsmg_reset_smg ();
439 return 0; /* OK */
442 /* --------------------------------------------------------------------------------------------- */
444 void
445 tty_touch_screen (void)
447 SLsmg_touch_lines (0, LINES);
450 /* --------------------------------------------------------------------------------------------- */
452 void
453 tty_gotoyx (int y, int x)
455 SLsmg_gotorc (y, x);
458 /* --------------------------------------------------------------------------------------------- */
460 void
461 tty_getyx (int *py, int *px)
463 *py = SLsmg_get_row ();
464 *px = SLsmg_get_column ();
467 /* --------------------------------------------------------------------------------------------- */
468 /* if x < 0 or y < 0, draw line staring from current position */
470 void
471 tty_draw_hline (int y, int x, int ch, int len)
473 if (ch == ACS_HLINE)
474 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
476 if ((y < 0) || (x < 0))
478 y = SLsmg_get_row ();
479 x = SLsmg_get_column ();
481 else
482 SLsmg_gotorc (y, x);
484 if (ch == 0)
485 ch = ACS_HLINE;
487 if (ch == ACS_HLINE)
488 SLsmg_draw_hline (len);
489 else
490 while (len-- != 0)
491 tty_print_char (ch);
493 SLsmg_gotorc (y, x);
496 /* --------------------------------------------------------------------------------------------- */
497 /* if x < 0 or y < 0, draw line staring from current position */
499 void
500 tty_draw_vline (int y, int x, int ch, int len)
502 if (ch == ACS_VLINE)
503 ch = mc_tty_frm[MC_TTY_FRM_VERT];
505 if ((y < 0) || (x < 0))
507 y = SLsmg_get_row ();
508 x = SLsmg_get_column ();
510 else
511 SLsmg_gotorc (y, x);
513 if (ch == 0)
514 ch = ACS_VLINE;
516 if (ch == ACS_VLINE)
517 SLsmg_draw_vline (len);
518 else
520 int pos = 0;
522 while (len-- != 0)
524 SLsmg_gotorc (y + pos, x);
525 tty_print_char (ch);
526 pos++;
530 SLsmg_gotorc (y, x);
533 /* --------------------------------------------------------------------------------------------- */
535 void
536 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
538 SLsmg_fill_region (y, x, rows, cols, ch);
541 /* --------------------------------------------------------------------------------------------- */
543 void
544 tty_set_alt_charset (gboolean alt_charset)
546 SLsmg_set_char_set ((int) alt_charset);
549 /* --------------------------------------------------------------------------------------------- */
551 void
552 tty_display_8bit (gboolean what)
554 SLsmg_Display_Eight_Bit = what ? 128 : 160;
557 /* --------------------------------------------------------------------------------------------- */
559 void
560 tty_print_char (int c)
562 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
565 /* --------------------------------------------------------------------------------------------- */
567 void
568 tty_print_alt_char (int c, gboolean single)
570 #define DRAW(x, y) (x == y) \
571 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
572 : SLsmg_write_char ((unsigned int) y)
573 switch (c)
575 case ACS_VLINE:
576 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
577 break;
578 case ACS_HLINE:
579 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
580 break;
581 case ACS_LTEE:
582 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
583 break;
584 case ACS_RTEE:
585 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
586 break;
587 case ACS_ULCORNER:
588 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
589 break;
590 case ACS_LLCORNER:
591 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
592 break;
593 case ACS_URCORNER:
594 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
595 break;
596 case ACS_LRCORNER:
597 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
598 break;
599 case ACS_PLUS:
600 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
601 break;
602 default:
603 SLsmg_write_char ((unsigned int) c);
605 #undef DRAW
608 /* --------------------------------------------------------------------------------------------- */
610 void
611 tty_print_anychar (int c)
613 char str[6 + 1];
615 if (c > 255)
617 int res = g_unichar_to_utf8 (c, str);
618 if (res == 0)
620 str[0] = '.';
621 str[1] = '\0';
623 else
625 str[res] = '\0';
627 SLsmg_write_string ((char *) str_term_form (str));
629 else
631 if (!is_printable (c))
632 c = '.';
633 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
637 /* --------------------------------------------------------------------------------------------- */
639 void
640 tty_print_string (const char *s)
642 SLsmg_write_string ((char *) str_term_form (s));
645 /* --------------------------------------------------------------------------------------------- */
647 void
648 tty_printf (const char *fmt, ...)
650 va_list args;
652 va_start (args, fmt);
653 SLsmg_vprintf ((char *) fmt, args);
654 va_end (args);
657 /* --------------------------------------------------------------------------------------------- */
659 char *
660 tty_tgetstr (const char *cap)
662 return SLtt_tgetstr ((char *) cap);
665 /* --------------------------------------------------------------------------------------------- */
667 void
668 tty_refresh (void)
670 SLsmg_refresh ();
673 /* --------------------------------------------------------------------------------------------- */
675 void
676 tty_setup_sigwinch (void (*handler) (int))
678 #ifdef SIGWINCH
679 struct sigaction act, oact;
680 act.sa_handler = handler;
681 sigemptyset (&act.sa_mask);
682 act.sa_flags = 0;
683 #ifdef SA_RESTART
684 act.sa_flags |= SA_RESTART;
685 #endif /* SA_RESTART */
686 sigaction (SIGWINCH, &act, &oact);
687 #endif /* SIGWINCH */
690 /* --------------------------------------------------------------------------------------------- */
692 void
693 tty_beep (void)
695 SLtt_beep ();
698 /* --------------------------------------------------------------------------------------------- */