Updated Russian translation.
[midnight-commander.git] / lib / tty / tty-slang.c
blobacb436305c55c89040543d3e4ac1ef4549e35839
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), ESC_STR "&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, gboolean mouse_enable, gboolean is_xterm)
246 slow_tty = slow;
247 ugly_line_drawing = ugly_lines;
249 SLtt_Ignore_Beep = 1;
251 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
252 SLtt_get_terminfo ();
254 * If the terminal in not in terminfo but begins with a well-known
255 * string such as "linux" or "xterm" S-Lang will go on, but the
256 * terminal size and several other variables won't be initialized
257 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
258 * small, large and negative screen dimensions.
260 if ((COLS < 10) || (LINES < 5)
261 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
263 fprintf (stderr,
264 _("Screen size %dx%d is not supported.\n"
265 "Check the TERM environment variable.\n"), COLS, LINES);
266 exit (EXIT_FAILURE);
269 tcgetattr (fileno (stdin), &boot_mode);
270 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
271 SLang_init_tty (XCTRL ('g'), 1, 0);
273 if (ugly_lines)
274 SLtt_Has_Alt_Charset = 0;
276 /* If SLang uses fileno(stderr) for terminal input MC will hang
277 if we call SLang_getkey between calls to open_error_pipe and
278 close_error_pipe, e.g. when we do a growing view of an gzipped
279 file. */
280 if (SLang_TT_Read_FD == fileno (stderr))
281 SLang_TT_Read_FD = fileno (stdin);
283 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
285 #ifdef VDSUSP
286 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
287 #endif
288 #ifdef VLNEXT
289 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
290 #endif
291 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
294 tty_reset_prog_mode ();
295 load_terminfo_keys ();
296 SLtt_Blink_Mode = 0;
298 tty_start_interrupt_key ();
300 /* It's the small part from the previous init_key() */
301 init_key_input_fd ();
303 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
304 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
305 * detected - but checking TERM would fail under screen, OR running xterm
306 * with allowC1Printable).
308 tty_display_8bit (FALSE);
310 SLsmg_init_smg ();
311 if (!mouse_enable)
312 use_mouse_p = MOUSE_DISABLED;
313 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
314 init_mouse ();
315 do_enter_ca_mode ();
316 tty_keypad (TRUE);
317 tty_nodelay (FALSE);
320 /* --------------------------------------------------------------------------------------------- */
322 void
323 tty_shutdown (void)
325 char *op_cap;
327 disable_mouse ();
328 tty_reset_shell_mode ();
329 tty_noraw_mode ();
330 tty_keypad (FALSE);
331 tty_reset_screen ();
332 do_exit_ca_mode ();
333 SLang_reset_tty ();
335 /* Load the op capability to reset the colors to those that were
336 * active when the program was started up
338 op_cap = SLtt_tgetstr ((char *) "op");
339 if (op_cap != NULL)
341 fputs (op_cap, stdout);
342 fflush (stdout);
346 /* --------------------------------------------------------------------------------------------- */
347 /* Done each time we come back from done mode */
349 void
350 tty_reset_prog_mode (void)
352 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
353 SLsmg_init_smg ();
354 SLsmg_touch_lines (0, LINES);
357 /* --------------------------------------------------------------------------------------------- */
358 /* Called each time we want to shutdown slang screen manager */
360 void
361 tty_reset_shell_mode (void)
363 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
366 /* --------------------------------------------------------------------------------------------- */
368 void
369 tty_raw_mode (void)
371 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
374 /* --------------------------------------------------------------------------------------------- */
376 void
377 tty_noraw_mode (void)
381 /* --------------------------------------------------------------------------------------------- */
383 void
384 tty_noecho (void)
388 /* --------------------------------------------------------------------------------------------- */
391 tty_flush_input (void)
393 return 0; /* OK */
396 /* --------------------------------------------------------------------------------------------- */
398 void
399 tty_keypad (gboolean set)
401 char *keypad_string;
403 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
404 if (keypad_string != NULL)
405 SLtt_write_string (keypad_string);
406 if (set && reset_hp_softkeys)
407 slang_reset_softkeys ();
410 /* --------------------------------------------------------------------------------------------- */
412 void
413 tty_nodelay (gboolean set)
415 no_slang_delay = set;
418 /* --------------------------------------------------------------------------------------------- */
421 tty_baudrate (void)
423 return SLang_TT_Baud_Rate;
426 /* --------------------------------------------------------------------------------------------- */
429 tty_lowlevel_getch (void)
431 int c;
433 if (no_slang_delay && (SLang_input_pending (0) == 0))
434 return -1;
436 c = SLang_getkey ();
437 if (c == SLANG_GETKEY_ERROR)
439 fprintf (stderr,
440 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
441 "Assuming EOF on stdin and exiting\n");
442 exit (EXIT_FAILURE);
445 return c;
448 /* --------------------------------------------------------------------------------------------- */
451 tty_reset_screen (void)
453 SLsmg_reset_smg ();
454 return 0; /* OK */
457 /* --------------------------------------------------------------------------------------------- */
459 void
460 tty_touch_screen (void)
462 SLsmg_touch_lines (0, LINES);
465 /* --------------------------------------------------------------------------------------------- */
467 void
468 tty_gotoyx (int y, int x)
470 SLsmg_gotorc (y, x);
473 /* --------------------------------------------------------------------------------------------- */
475 void
476 tty_getyx (int *py, int *px)
478 *py = SLsmg_get_row ();
479 *px = SLsmg_get_column ();
482 /* --------------------------------------------------------------------------------------------- */
483 /* if x < 0 or y < 0, draw line staring from current position */
485 void
486 tty_draw_hline (int y, int x, int ch, int len)
488 if (ch == ACS_HLINE)
489 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
491 if ((y < 0) || (x < 0))
493 y = SLsmg_get_row ();
494 x = SLsmg_get_column ();
496 else
497 SLsmg_gotorc (y, x);
499 if (ch == 0)
500 ch = ACS_HLINE;
502 if (ch == ACS_HLINE)
503 SLsmg_draw_hline (len);
504 else
505 while (len-- != 0)
506 tty_print_char (ch);
508 SLsmg_gotorc (y, x);
511 /* --------------------------------------------------------------------------------------------- */
512 /* if x < 0 or y < 0, draw line staring from current position */
514 void
515 tty_draw_vline (int y, int x, int ch, int len)
517 if (ch == ACS_VLINE)
518 ch = mc_tty_frm[MC_TTY_FRM_VERT];
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_VLINE;
531 if (ch == ACS_VLINE)
532 SLsmg_draw_vline (len);
533 else
535 int pos = 0;
537 while (len-- != 0)
539 SLsmg_gotorc (y + pos, x);
540 tty_print_char (ch);
541 pos++;
545 SLsmg_gotorc (y, x);
548 /* --------------------------------------------------------------------------------------------- */
550 void
551 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
553 SLsmg_fill_region (y, x, rows, cols, ch);
556 /* --------------------------------------------------------------------------------------------- */
558 void
559 tty_set_alt_charset (gboolean alt_charset)
561 SLsmg_set_char_set ((int) alt_charset);
564 /* --------------------------------------------------------------------------------------------- */
566 void
567 tty_display_8bit (gboolean what)
569 SLsmg_Display_Eight_Bit = what ? 128 : 160;
572 /* --------------------------------------------------------------------------------------------- */
574 void
575 tty_print_char (int c)
577 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
580 /* --------------------------------------------------------------------------------------------- */
582 void
583 tty_print_alt_char (int c, gboolean single)
585 #define DRAW(x, y) (x == y) \
586 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
587 : SLsmg_write_char ((unsigned int) y)
588 switch (c)
590 case ACS_VLINE:
591 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
592 break;
593 case ACS_HLINE:
594 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
595 break;
596 case ACS_LTEE:
597 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
598 break;
599 case ACS_RTEE:
600 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
601 break;
602 case ACS_ULCORNER:
603 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
604 break;
605 case ACS_LLCORNER:
606 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
607 break;
608 case ACS_URCORNER:
609 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
610 break;
611 case ACS_LRCORNER:
612 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
613 break;
614 case ACS_PLUS:
615 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
616 break;
617 default:
618 SLsmg_write_char ((unsigned int) c);
620 #undef DRAW
623 /* --------------------------------------------------------------------------------------------- */
625 void
626 tty_print_anychar (int c)
628 char str[6 + 1];
630 if (c > 255)
632 int res = g_unichar_to_utf8 (c, str);
633 if (res == 0)
635 str[0] = '.';
636 str[1] = '\0';
638 else
640 str[res] = '\0';
642 SLsmg_write_string ((char *) str_term_form (str));
644 else
646 if (!is_printable (c))
647 c = '.';
648 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
652 /* --------------------------------------------------------------------------------------------- */
654 void
655 tty_print_string (const char *s)
657 SLsmg_write_string ((char *) str_term_form (s));
660 /* --------------------------------------------------------------------------------------------- */
662 void
663 tty_printf (const char *fmt, ...)
665 va_list args;
667 va_start (args, fmt);
668 SLsmg_vprintf ((char *) fmt, args);
669 va_end (args);
672 /* --------------------------------------------------------------------------------------------- */
674 char *
675 tty_tgetstr (const char *cap)
677 return SLtt_tgetstr ((char *) cap);
680 /* --------------------------------------------------------------------------------------------- */
682 void
683 tty_refresh (void)
685 SLsmg_refresh ();
688 /* --------------------------------------------------------------------------------------------- */
690 void
691 tty_setup_sigwinch (void (*handler) (int))
693 #ifdef SIGWINCH
694 struct sigaction act, oact;
695 act.sa_handler = handler;
696 sigemptyset (&act.sa_mask);
697 act.sa_flags = 0;
698 #ifdef SA_RESTART
699 act.sa_flags |= SA_RESTART;
700 #endif /* SA_RESTART */
701 sigaction (SIGWINCH, &act, &oact);
702 #endif /* SIGWINCH */
705 /* --------------------------------------------------------------------------------------------- */
707 void
708 tty_beep (void)
710 SLtt_beep ();
713 /* --------------------------------------------------------------------------------------------- */