Massive moved some dirs from $(srcdir)/src into $(srcdir)/lib
[midnight-commander.git] / lib / tty / tty-slang.c
blobe20ae6d3e2cb8bfd7872a5b68d5f3617d9ea67de
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 "../../src/global.h"
44 #include "../../src/tty/tty-internal.h" /* slow_tty */
45 #include "../../src/tty/tty.h"
46 #include "../../src/tty/color-slang.h"
47 #include "../../src/tty/color-internal.h"
48 #include "../../src/tty/mouse.h" /* Gpm_Event is required in key.h */
49 #include "../../src/tty/key.h" /* define_sequence */
50 #include "../../src/tty/win.h"
52 #include "../../src/strutil.h" /* str_term_form */
54 /*** global variables **************************************************/
55 extern int reset_hp_softkeys;
57 /*** file scope macro definitions **************************************/
59 /* Taken from S-Lang's slutty.c */
60 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
61 # define NULL_VALUE -1
62 #else
63 # ifdef _POSIX_VDISABLE
64 # define NULL_VALUE _POSIX_VDISABLE
65 # else
66 # define NULL_VALUE 255
67 # endif
68 #endif /* ultrix */
70 #ifndef SA_RESTART
71 # define SA_RESTART 0
72 #endif
74 #ifndef SLTT_MAX_SCREEN_COLS
75 #define SLTT_MAX_SCREEN_COLS 512
76 #endif
78 #ifndef SLTT_MAX_SCREEN_ROWS
79 #define SLTT_MAX_SCREEN_ROWS 512
80 #endif
83 /*** file scope type declarations **************************************/
85 /*** file scope variables **********************************************/
87 /* Various saved termios settings that we control here */
88 static struct termios boot_mode;
89 static struct termios new_mode;
91 /* Controls whether we should wait for input in tty_lowlevel_getch */
92 static gboolean no_slang_delay;
94 /* This table describes which capabilities we want and which values we
95 * assign to them.
97 static const struct {
98 int key_code;
99 const char *key_name;
100 } key_table[] = {
102 KEY_F (0), "k0"}, {
103 KEY_F (1), "k1"}, {
104 KEY_F (2), "k2"}, {
105 KEY_F (3), "k3"}, {
106 KEY_F (4), "k4"}, {
107 KEY_F (5), "k5"}, {
108 KEY_F (6), "k6"}, {
109 KEY_F (7), "k7"}, {
110 KEY_F (8), "k8"}, {
111 KEY_F (9), "k9"}, {
112 KEY_F (10), "k;"}, {
113 KEY_F (11), "F1"}, {
114 KEY_F (12), "F2"}, {
115 KEY_F (13), "F3"}, {
116 KEY_F (14), "F4"}, {
117 KEY_F (15), "F5"}, {
118 KEY_F (16), "F6"}, {
119 KEY_F (17), "F7"}, {
120 KEY_F (18), "F8"}, {
121 KEY_F (19), "F9"}, {
122 KEY_F (20), "FA"}, {
123 KEY_IC, "kI"}, {
124 KEY_NPAGE, "kN"}, {
125 KEY_PPAGE, "kP"}, {
126 KEY_LEFT, "kl"}, {
127 KEY_RIGHT, "kr"}, {
128 KEY_UP, "ku"}, {
129 KEY_DOWN, "kd"}, {
130 KEY_DC, "kD"}, {
131 KEY_BACKSPACE, "kb"}, {
132 KEY_HOME, "kh"}, {
133 KEY_END, "@7"}, {
134 0, NULL}
137 /*** file scope functions **********************************************/
139 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
140 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
141 consequence is that function keys don't work in MC sometimes...
142 Unfortunately I don't now the one and only escape sequence to turn off.
143 softkeys (elm uses three different capabilities to turn on softkeys and two.
144 capabilities to turn them off)..
145 Among other things elm uses the pair we already use in slang_keypad. That's.
146 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
147 something better the softkeys are programmed to their defaults from the
148 termcap/terminfo database.
149 The escape sequence to program the softkeys is taken from elm and it is.
150 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
151 sequence. -- Norbert
154 static void
155 slang_reset_softkeys (void)
157 int key;
158 char *send;
159 static const char display[] = " ";
160 char tmp[BUF_SMALL];
162 for (key = 1; key < 9; key++) {
163 g_snprintf (tmp, sizeof (tmp), "k%d", key);
164 send = (char *) SLtt_tgetstr (tmp);
165 if (send != NULL) {
166 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
167 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
168 SLtt_write_string (tmp);
173 static void
174 do_define_key (int code, const char *strcap)
176 char *seq;
178 seq = (char *) SLtt_tgetstr ((char *) strcap);
179 if (seq != NULL)
180 define_sequence (code, seq, MCKEY_NOACTION);
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 {
203 const char *line;
204 int line_code;
205 } const lines_codes[] = {
206 {"\342\224\214", SLSMG_ULCORN_CHAR},
207 {"\342\224\220", SLSMG_URCORN_CHAR},
208 {"\342\224\224", SLSMG_LLCORN_CHAR},
209 {"\342\224\230", SLSMG_LRCORN_CHAR},
210 {"\342\224\234", SLSMG_LTEE_CHAR},
211 {"\342\224\244", SLSMG_RTEE_CHAR},
212 {"\342\224\254", SLSMG_UTEE_CHAR},
213 {"\342\224\264", SLSMG_DTEE_CHAR},
214 {"\342\224\200", SLSMG_HLINE_CHAR},
215 {"\342\224\202", SLSMG_VLINE_CHAR},
216 {"\342\224\274", SLSMG_PLUS_CHAR},
218 {NULL, 0}
221 if (!str)
222 return (int) ' ';
224 for (res = 0; lines_codes[res].line; res++) {
225 if (strcmp (str, lines_codes[res].line) == 0)
226 return lines_codes[res].line_code;
229 str2 = mc_tty_normalize_from_utf8 (str);
230 res = g_utf8_get_char_validated (str2, -1);
232 if (res < 0)
233 res = (unsigned char) str2[0];
234 g_free (str2);
236 return res;
239 /* --------------------------------------------------------------------------------------------- */
240 void
241 tty_init (gboolean slow, gboolean ugly_lines)
243 slow_tty = slow;
244 ugly_line_drawing = ugly_lines;
246 SLtt_get_terminfo ();
247 SLutf8_enable (-1);
249 * If the terminal in not in terminfo but begins with a well-known
250 * string such as "linux" or "xterm" S-Lang will go on, but the
251 * terminal size and several other variables won't be initialized
252 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
253 * small, large and negative screen dimensions.
255 if ((COLS < 10) || (LINES < 5)
256 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS)) {
257 fprintf (stderr,
258 _("Screen size %dx%d is not supported.\n"
259 "Check the TERM environment variable.\n"), COLS, LINES);
260 exit (1);
263 tcgetattr (fileno (stdin), &boot_mode);
264 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
265 SLang_init_tty (XCTRL ('g'), 1, 0);
267 if (ugly_lines)
268 SLtt_Has_Alt_Charset = 0;
270 /* If SLang uses fileno(stderr) for terminal input MC will hang
271 if we call SLang_getkey between calls to open_error_pipe and
272 close_error_pipe, e.g. when we do a growing view of an gzipped
273 file. */
274 if (SLang_TT_Read_FD == fileno (stderr))
275 SLang_TT_Read_FD = fileno (stdin);
277 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
278 #ifdef VDSUSP
279 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
280 #endif
281 #ifdef VLNEXT
282 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
283 #endif
284 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
287 tty_reset_prog_mode ();
288 load_terminfo_keys ();
289 SLtt_Blink_Mode = 0;
291 tty_start_interrupt_key ();
293 /* It's the small part from the previous init_key() */
294 init_key_input_fd ();
296 SLsmg_init_smg ();
297 do_enter_ca_mode ();
298 tty_keypad (TRUE);
299 tty_nodelay (FALSE);
302 void
303 tty_shutdown (void)
305 char *op_cap;
307 SLsmg_reset_smg ();
308 tty_reset_shell_mode ();
309 do_exit_ca_mode ();
310 SLang_reset_tty ();
312 /* Load the op capability to reset the colors to those that were
313 * active when the program was started up
315 op_cap = SLtt_tgetstr ((char *) "op");
316 if (op_cap != NULL) {
317 fputs (op_cap, stdout);
318 fflush (stdout);
322 /* Done each time we come back from done mode */
323 void
324 tty_reset_prog_mode (void)
326 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
327 SLsmg_init_smg ();
328 SLsmg_touch_lines (0, LINES);
331 /* Called each time we want to shutdown slang screen manager */
332 void
333 tty_reset_shell_mode (void)
335 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
338 void
339 tty_raw_mode (void)
341 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
344 void
345 tty_noraw_mode (void)
349 void
350 tty_noecho (void)
355 tty_flush_input (void)
357 return 0; /* OK */
360 void
361 tty_keypad (gboolean set)
363 char *keypad_string;
365 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
366 if (keypad_string != NULL)
367 SLtt_write_string (keypad_string);
368 if (set && reset_hp_softkeys)
369 slang_reset_softkeys ();
372 void
373 tty_nodelay (gboolean set)
375 no_slang_delay = set;
379 tty_baudrate (void)
381 return SLang_TT_Baud_Rate;
385 tty_lowlevel_getch (void)
387 int c;
389 if (no_slang_delay && (SLang_input_pending (0) == 0))
390 return -1;
392 c = SLang_getkey ();
393 if (c == SLANG_GETKEY_ERROR) {
394 fprintf (stderr,
395 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
396 "Assuming EOF on stdin and exiting\n");
397 exit (1);
400 return c;
404 tty_reset_screen (void)
406 SLsmg_reset_smg ();
407 return 0; /* OK */
410 void
411 tty_touch_screen (void)
413 SLsmg_touch_lines (0, LINES);
416 void
417 tty_gotoyx (int y, int x)
419 SLsmg_gotorc (y, x);
422 void
423 tty_getyx (int *py, int *px)
425 *py = SLsmg_get_row ();
426 *px = SLsmg_get_column ();
429 /* if x < 0 or y < 0, draw line staring from current position */
430 void
431 tty_draw_hline (int y, int x, int ch, int len)
433 if (ch == ACS_HLINE)
434 ch = mc_tty_ugly_frm[MC_TTY_FRM_thinhoriz];
436 if ((y < 0) || (x < 0)) {
437 y = SLsmg_get_row ();
438 x = SLsmg_get_column ();
439 } else
440 SLsmg_gotorc (y, x);
442 if (ch == 0)
443 ch = ACS_HLINE;
445 if (ch == ACS_HLINE)
446 SLsmg_draw_hline (len);
447 else
448 while (len-- != 0)
449 tty_print_char (ch);
451 SLsmg_gotorc (y, x);
454 /* if x < 0 or y < 0, draw line staring from current position */
455 void
456 tty_draw_vline (int y, int x, int ch, int len)
458 if (ch == ACS_VLINE)
459 ch = mc_tty_ugly_frm[MC_TTY_FRM_thinvert];
461 if ((y < 0) || (x < 0)) {
462 y = SLsmg_get_row ();
463 x = SLsmg_get_column ();
464 } else
465 SLsmg_gotorc (y, x);
467 if (ch == 0)
468 ch = ACS_VLINE;
470 if (ch == ACS_VLINE)
471 SLsmg_draw_vline (len);
472 else {
473 int pos = 0;
475 while (len-- != 0) {
476 SLsmg_gotorc (y + pos, x);
477 tty_print_char (ch);
478 pos++;
482 SLsmg_gotorc (y, x);
485 void
486 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
488 SLsmg_fill_region (y, x, rows, cols, ch);
491 void
492 tty_set_alt_charset (gboolean alt_charset)
494 SLsmg_set_char_set ((int) alt_charset);
497 void
498 tty_display_8bit (gboolean what)
500 SLsmg_Display_Eight_Bit = what ? 128 : 160;
503 void
504 tty_print_char (int c)
506 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
509 void
510 tty_print_alt_char (int c)
512 #define DRAW(x, y) (x == y) \
513 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
514 : SLsmg_write_char ((unsigned int) y)
515 switch (c) {
516 case ACS_VLINE:
517 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_thinvert]);
518 break;
519 case ACS_HLINE:
520 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_thinhoriz]);
521 break;
522 case ACS_LTEE:
523 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_leftmiddle]);
524 break;
525 case ACS_RTEE:
526 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_rightmiddle]);
527 break;
528 case ACS_ULCORNER:
529 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_lefttop]);
530 break;
531 case ACS_LLCORNER:
532 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_leftbottom]);
533 break;
534 case ACS_URCORNER:
535 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_righttop]);
536 break;
537 case ACS_LRCORNER:
538 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_rightbottom]);
539 break;
540 case ACS_PLUS:
541 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_centermiddle]);
542 break;
543 default:
544 SLsmg_write_char ((unsigned int) c);
546 #undef DRAW
549 void
550 tty_print_anychar (int c)
552 char str[6 + 1];
554 if (c > 255) {
555 int res = g_unichar_to_utf8 (c, str);
556 if (res == 0) {
557 str[0] = '.';
558 str[1] = '\0';
559 } else {
560 str[res] = '\0';
562 SLsmg_write_string ((char *) str_term_form (str));
563 } else {
564 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
568 void
569 tty_print_string (const char *s)
571 SLsmg_write_string ((char *) str_term_form (s));
574 void
575 tty_printf (const char *fmt, ...)
577 va_list args;
579 va_start (args, fmt);
580 SLsmg_vprintf ((char *) fmt, args);
581 va_end (args);
584 char *
585 tty_tgetstr (const char *cap)
587 return SLtt_tgetstr ((char *) cap);
590 void
591 tty_refresh (void)
593 SLsmg_refresh ();
596 void
597 tty_setup_sigwinch (void (*handler) (int))
599 #ifdef SIGWINCH
600 struct sigaction act, oact;
601 act.sa_handler = handler;
602 sigemptyset (&act.sa_mask);
603 act.sa_flags = 0;
604 #ifdef SA_RESTART
605 act.sa_flags |= SA_RESTART;
606 #endif /* SA_RESTART */
607 sigaction (SIGWINCH, &act, &oact);
608 #endif /* SIGWINCH */
611 void
612 tty_beep (void)
614 SLtt_beep ();