Merge branch '2621_path_encoding_and_extfs'
[midnight-commander.git] / lib / tty / tty-slang.c
bloba6a1f964d2f7f94fe401ff647f3487a8e6fb1e23
1 /*
2 Interface to the terminal controlling library.
3 Slang wrapper.
5 Copyright (C) 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
7 Written by:
8 Andrew Borodin <aborodin@vmail.ru>, 2009
9 Egmont Koblinger <egmont@gmail.com>, 2010
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 2 of the
16 License, or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be
19 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
20 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 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, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 MA 02110-1301, USA.
29 /** \file
30 * \brief Source: S-Lang-based tty layer of Midnight Commander
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <sys/types.h> /* size_t */
40 #include <unistd.h>
41 #include <signal.h>
43 #include "lib/global.h"
44 #include "lib/strutil.h" /* str_term_form */
45 #include "lib/util.h" /* is_printable() */
47 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
48 #include "tty.h"
49 #include "color.h"
50 #include "color-slang.h"
51 #include "color-internal.h"
52 #include "mouse.h" /* Gpm_Event is required in key.h */
53 #include "key.h" /* define_sequence */
54 #include "win.h"
57 /*** global variables ****************************************************************************/
59 extern int reset_hp_softkeys;
61 /*** file scope macro definitions ****************************************************************/
63 #ifndef SA_RESTART
64 #define SA_RESTART 0
65 #endif
67 #ifndef SLTT_MAX_SCREEN_COLS
68 #define SLTT_MAX_SCREEN_COLS 512
69 #endif
71 #ifndef SLTT_MAX_SCREEN_ROWS
72 #define SLTT_MAX_SCREEN_ROWS 512
73 #endif
75 /*** file scope type declarations ****************************************************************/
77 /*** file scope variables ************************************************************************/
79 /* Various saved termios settings that we control here */
80 static struct termios boot_mode;
81 static struct termios new_mode;
83 /* Controls whether we should wait for input in tty_lowlevel_getch */
84 static gboolean no_slang_delay;
86 /* This table describes which capabilities we want and which values we
87 * assign to them.
89 static const struct
91 int key_code;
92 const char *key_name;
93 } key_table[] =
95 /* *INDENT-OFF* */
96 { KEY_F (0), "k0" },
97 { KEY_F (1), "k1" },
98 { KEY_F (2), "k2" },
99 { KEY_F (3), "k3" },
100 { KEY_F (4), "k4" },
101 { KEY_F (5), "k5" },
102 { KEY_F (6), "k6" },
103 { KEY_F (7), "k7" },
104 { KEY_F (8), "k8" },
105 { KEY_F (9), "k9" },
106 { KEY_F (10), "k;" },
107 { KEY_F (11), "F1" },
108 { KEY_F (12), "F2" },
109 { KEY_F (13), "F3" },
110 { KEY_F (14), "F4" },
111 { KEY_F (15), "F5" },
112 { KEY_F (16), "F6" },
113 { KEY_F (17), "F7" },
114 { KEY_F (18), "F8" },
115 { KEY_F (19), "F9" },
116 { KEY_F (20), "FA" },
117 { KEY_IC, "kI" },
118 { KEY_NPAGE, "kN" },
119 { KEY_PPAGE, "kP" },
120 { KEY_LEFT, "kl" },
121 { KEY_RIGHT, "kr" },
122 { KEY_UP, "ku" },
123 { KEY_DOWN, "kd" },
124 { KEY_DC, "kD" },
125 { KEY_BACKSPACE, "kb" },
126 { KEY_HOME, "kh" },
127 { KEY_END, "@7" },
128 { 0, NULL }
129 /* *INDENT-ON* */
132 /*** file scope functions ************************************************************************/
133 /* --------------------------------------------------------------------------------------------- */
135 static void
136 tty_setup_sigwinch (void (*handler) (int))
138 #ifdef SIGWINCH
139 struct sigaction act, oact;
140 act.sa_handler = handler;
141 sigemptyset (&act.sa_mask);
142 act.sa_flags = 0;
143 #ifdef SA_RESTART
144 act.sa_flags |= SA_RESTART;
145 #endif /* SA_RESTART */
146 sigaction (SIGWINCH, &act, &oact);
147 #endif /* SIGWINCH */
150 /* --------------------------------------------------------------------------------------------- */
152 static void
153 sigwinch_handler (int dummy)
155 (void) dummy;
157 tty_change_screen_size ();
158 mc_global.tty.winch_flag = TRUE;
161 /* --------------------------------------------------------------------------------------------- */
163 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
164 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
165 consequence is that function keys don't work in MC sometimes...
166 Unfortunately I don't now the one and only escape sequence to turn off.
167 softkeys (elm uses three different capabilities to turn on softkeys and two.
168 capabilities to turn them off)..
169 Among other things elm uses the pair we already use in slang_keypad. That's.
170 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
171 something better the softkeys are programmed to their defaults from the
172 termcap/terminfo database.
173 The escape sequence to program the softkeys is taken from elm and it is.
174 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
175 sequence. -- Norbert
178 static void
179 slang_reset_softkeys (void)
181 int key;
182 char *send;
183 static const char display[] = " ";
184 char tmp[BUF_SMALL];
186 for (key = 1; key < 9; key++)
188 g_snprintf (tmp, sizeof (tmp), "k%d", key);
189 send = (char *) SLtt_tgetstr (tmp);
190 if (send != NULL)
192 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
193 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
194 SLtt_write_string (tmp);
199 /* --------------------------------------------------------------------------------------------- */
201 static void
202 do_define_key (int code, const char *strcap)
204 char *seq;
206 seq = (char *) SLtt_tgetstr ((char *) strcap);
207 if (seq != NULL)
208 define_sequence (code, seq, MCKEY_NOACTION);
211 /* --------------------------------------------------------------------------------------------- */
213 static void
214 load_terminfo_keys (void)
216 int i;
218 for (i = 0; key_table[i].key_code; i++)
219 do_define_key (key_table[i].key_code, key_table[i].key_name);
222 /* --------------------------------------------------------------------------------------------- */
223 /*** public functions ****************************************************************************/
224 /* --------------------------------------------------------------------------------------------- */
227 mc_tty_normalize_lines_char (const char *str)
229 char *str2;
230 int res;
232 struct mc_tty_lines_struct
234 const char *line;
235 int line_code;
236 } const lines_codes[] = {
237 {"\342\224\214", SLSMG_ULCORN_CHAR},
238 {"\342\224\220", SLSMG_URCORN_CHAR},
239 {"\342\224\224", SLSMG_LLCORN_CHAR},
240 {"\342\224\230", SLSMG_LRCORN_CHAR},
241 {"\342\224\234", SLSMG_LTEE_CHAR},
242 {"\342\224\244", SLSMG_RTEE_CHAR},
243 {"\342\224\254", SLSMG_UTEE_CHAR},
244 {"\342\224\264", SLSMG_DTEE_CHAR},
245 {"\342\224\200", SLSMG_HLINE_CHAR},
246 {"\342\224\202", SLSMG_VLINE_CHAR},
247 {"\342\224\274", SLSMG_PLUS_CHAR},
249 {NULL, 0}
252 if (!str)
253 return (int) ' ';
255 for (res = 0; lines_codes[res].line; res++)
257 if (strcmp (str, lines_codes[res].line) == 0)
258 return lines_codes[res].line_code;
261 str2 = mc_tty_normalize_from_utf8 (str);
262 res = g_utf8_get_char_validated (str2, -1);
264 if (res < 0)
265 res = (unsigned char) str2[0];
266 g_free (str2);
268 return res;
271 /* --------------------------------------------------------------------------------------------- */
273 void
274 tty_init (gboolean mouse_enable, gboolean is_xterm)
276 SLtt_Ignore_Beep = 1;
278 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
279 SLtt_get_terminfo ();
281 * If the terminal in not in terminfo but begins with a well-known
282 * string such as "linux" or "xterm" S-Lang will go on, but the
283 * terminal size and several other variables won't be initialized
284 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
285 * small, large and negative screen dimensions.
287 if ((COLS < 10) || (LINES < 5)
288 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
290 fprintf (stderr,
291 _("Screen size %dx%d is not supported.\n"
292 "Check the TERM environment variable.\n"), COLS, LINES);
293 exit (EXIT_FAILURE);
296 tcgetattr (fileno (stdin), &boot_mode);
297 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
298 SLang_init_tty (XCTRL ('g'), 1, 0);
300 if (mc_global.tty.ugly_line_drawing)
301 SLtt_Has_Alt_Charset = 0;
303 /* If SLang uses fileno(stderr) for terminal input MC will hang
304 if we call SLang_getkey between calls to open_error_pipe and
305 close_error_pipe, e.g. when we do a growing view of an gzipped
306 file. */
307 if (SLang_TT_Read_FD == fileno (stderr))
308 SLang_TT_Read_FD = fileno (stdin);
310 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
312 #ifdef VDSUSP
313 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
314 #endif
315 #ifdef VLNEXT
316 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
317 #endif
318 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
321 tty_reset_prog_mode ();
322 load_terminfo_keys ();
324 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
326 tty_start_interrupt_key ();
328 /* It's the small part from the previous init_key() */
329 init_key_input_fd ();
331 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
332 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
333 * detected - but checking TERM would fail under screen, OR running xterm
334 * with allowC1Printable).
336 tty_display_8bit (FALSE);
338 SLsmg_init_smg ();
339 if (!mouse_enable)
340 use_mouse_p = MOUSE_DISABLED;
341 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
342 init_mouse ();
343 do_enter_ca_mode ();
344 tty_keypad (TRUE);
345 tty_nodelay (FALSE);
347 tty_setup_sigwinch (sigwinch_handler);
350 /* --------------------------------------------------------------------------------------------- */
352 void
353 tty_shutdown (void)
355 char *op_cap;
357 disable_mouse ();
358 tty_reset_shell_mode ();
359 tty_noraw_mode ();
360 tty_keypad (FALSE);
361 tty_reset_screen ();
362 do_exit_ca_mode ();
363 SLang_reset_tty ();
365 /* Load the op capability to reset the colors to those that were
366 * active when the program was started up
368 op_cap = SLtt_tgetstr ((char *) "op");
369 if (op_cap != NULL)
371 fputs (op_cap, stdout);
372 fflush (stdout);
376 /* --------------------------------------------------------------------------------------------- */
377 /* Done each time we come back from done mode */
379 void
380 tty_reset_prog_mode (void)
382 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
383 SLsmg_init_smg ();
384 SLsmg_touch_lines (0, LINES);
387 /* --------------------------------------------------------------------------------------------- */
388 /* Called each time we want to shutdown slang screen manager */
390 void
391 tty_reset_shell_mode (void)
393 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
396 /* --------------------------------------------------------------------------------------------- */
398 void
399 tty_raw_mode (void)
401 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
404 /* --------------------------------------------------------------------------------------------- */
406 void
407 tty_noraw_mode (void)
411 /* --------------------------------------------------------------------------------------------- */
413 void
414 tty_noecho (void)
418 /* --------------------------------------------------------------------------------------------- */
421 tty_flush_input (void)
423 return 0; /* OK */
426 /* --------------------------------------------------------------------------------------------- */
428 void
429 tty_keypad (gboolean set)
431 char *keypad_string;
433 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
434 if (keypad_string != NULL)
435 SLtt_write_string (keypad_string);
436 if (set && reset_hp_softkeys)
437 slang_reset_softkeys ();
440 /* --------------------------------------------------------------------------------------------- */
442 void
443 tty_nodelay (gboolean set)
445 no_slang_delay = set;
448 /* --------------------------------------------------------------------------------------------- */
451 tty_baudrate (void)
453 return SLang_TT_Baud_Rate;
456 /* --------------------------------------------------------------------------------------------- */
459 tty_lowlevel_getch (void)
461 int c;
463 if (no_slang_delay && (SLang_input_pending (0) == 0))
464 return -1;
466 c = SLang_getkey ();
467 if (c == SLANG_GETKEY_ERROR)
469 fprintf (stderr,
470 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
471 "Assuming EOF on stdin and exiting\n");
472 exit (EXIT_FAILURE);
475 return c;
478 /* --------------------------------------------------------------------------------------------- */
481 tty_reset_screen (void)
483 SLsmg_reset_smg ();
484 return 0; /* OK */
487 /* --------------------------------------------------------------------------------------------- */
489 void
490 tty_touch_screen (void)
492 SLsmg_touch_lines (0, LINES);
495 /* --------------------------------------------------------------------------------------------- */
497 void
498 tty_gotoyx (int y, int x)
500 SLsmg_gotorc (y, x);
503 /* --------------------------------------------------------------------------------------------- */
505 void
506 tty_getyx (int *py, int *px)
508 *py = SLsmg_get_row ();
509 *px = SLsmg_get_column ();
512 /* --------------------------------------------------------------------------------------------- */
513 /* if x < 0 or y < 0, draw line staring from current position */
515 void
516 tty_draw_hline (int y, int x, int ch, int len)
518 if (ch == ACS_HLINE)
519 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
521 if ((y < 0) || (x < 0))
523 y = SLsmg_get_row ();
524 x = SLsmg_get_column ();
526 else
527 SLsmg_gotorc (y, x);
529 if (ch == 0)
530 ch = ACS_HLINE;
532 if (ch == ACS_HLINE)
533 SLsmg_draw_hline (len);
534 else
535 while (len-- != 0)
536 tty_print_char (ch);
538 SLsmg_gotorc (y, x);
541 /* --------------------------------------------------------------------------------------------- */
542 /* if x < 0 or y < 0, draw line staring from current position */
544 void
545 tty_draw_vline (int y, int x, int ch, int len)
547 if (ch == ACS_VLINE)
548 ch = mc_tty_frm[MC_TTY_FRM_VERT];
550 if ((y < 0) || (x < 0))
552 y = SLsmg_get_row ();
553 x = SLsmg_get_column ();
555 else
556 SLsmg_gotorc (y, x);
558 if (ch == 0)
559 ch = ACS_VLINE;
561 if (ch == ACS_VLINE)
562 SLsmg_draw_vline (len);
563 else
565 int pos = 0;
567 while (len-- != 0)
569 SLsmg_gotorc (y + pos, x);
570 tty_print_char (ch);
571 pos++;
575 SLsmg_gotorc (y, x);
578 /* --------------------------------------------------------------------------------------------- */
580 void
581 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
583 SLsmg_fill_region (y, x, rows, cols, ch);
586 /* --------------------------------------------------------------------------------------------- */
588 void
589 tty_set_alt_charset (gboolean alt_charset)
591 SLsmg_set_char_set ((int) alt_charset);
594 /* --------------------------------------------------------------------------------------------- */
596 void
597 tty_display_8bit (gboolean what)
599 SLsmg_Display_Eight_Bit = what ? 128 : 160;
602 /* --------------------------------------------------------------------------------------------- */
604 void
605 tty_print_char (int c)
607 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
610 /* --------------------------------------------------------------------------------------------- */
612 void
613 tty_print_alt_char (int c, gboolean single)
615 #define DRAW(x, y) (x == y) \
616 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
617 : SLsmg_write_char ((unsigned int) y)
618 switch (c)
620 case ACS_VLINE:
621 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
622 break;
623 case ACS_HLINE:
624 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
625 break;
626 case ACS_LTEE:
627 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
628 break;
629 case ACS_RTEE:
630 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
631 break;
632 case ACS_ULCORNER:
633 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
634 break;
635 case ACS_LLCORNER:
636 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
637 break;
638 case ACS_URCORNER:
639 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
640 break;
641 case ACS_LRCORNER:
642 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
643 break;
644 case ACS_PLUS:
645 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
646 break;
647 default:
648 SLsmg_write_char ((unsigned int) c);
650 #undef DRAW
653 /* --------------------------------------------------------------------------------------------- */
655 void
656 tty_print_anychar (int c)
658 char str[6 + 1];
660 if (c > 255)
662 int res = g_unichar_to_utf8 (c, str);
663 if (res == 0)
665 str[0] = '.';
666 str[1] = '\0';
668 else
670 str[res] = '\0';
672 SLsmg_write_string ((char *) str_term_form (str));
674 else
676 if (!is_printable (c))
677 c = '.';
678 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
682 /* --------------------------------------------------------------------------------------------- */
684 void
685 tty_print_string (const char *s)
687 SLsmg_write_string ((char *) str_term_form (s));
690 /* --------------------------------------------------------------------------------------------- */
692 void
693 tty_printf (const char *fmt, ...)
695 va_list args;
697 va_start (args, fmt);
698 SLsmg_vprintf ((char *) fmt, args);
699 va_end (args);
702 /* --------------------------------------------------------------------------------------------- */
704 char *
705 tty_tgetstr (const char *cap)
707 return SLtt_tgetstr ((char *) cap);
710 /* --------------------------------------------------------------------------------------------- */
712 void
713 tty_refresh (void)
715 SLsmg_refresh ();
718 /* --------------------------------------------------------------------------------------------- */
720 void
721 tty_beep (void)
723 SLtt_beep ();
726 /* --------------------------------------------------------------------------------------------- */