3554bc507321b23d5951d8d0ee4728a41913fe2b
[midnight-commander.git] / lib / tty / tty-slang.c
blob3554bc507321b23d5951d8d0ee4728a41913fe2b
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 <sys/types.h> /* size_t */
38 #include <unistd.h>
39 #include <signal.h>
40 #ifdef HAVE_SYS_IOCTL_H
41 #include <sys/ioctl.h>
42 #endif
43 #include <termios.h>
45 #include "lib/global.h"
46 #include "lib/strutil.h" /* str_term_form */
47 #include "lib/util.h" /* is_printable() */
49 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
50 #include "tty.h"
51 #include "color.h"
52 #include "color-slang.h"
53 #include "color-internal.h"
54 #include "mouse.h" /* Gpm_Event is required in key.h */
55 #include "key.h" /* define_sequence */
56 #include "win.h"
59 /*** global variables ****************************************************************************/
61 extern int reset_hp_softkeys;
63 /*** file scope macro definitions ****************************************************************/
65 #ifndef SA_RESTART
66 #define SA_RESTART 0
67 #endif
69 #ifndef SLTT_MAX_SCREEN_COLS
70 #define SLTT_MAX_SCREEN_COLS 512
71 #endif
73 #ifndef SLTT_MAX_SCREEN_ROWS
74 #define SLTT_MAX_SCREEN_ROWS 512
75 #endif
77 /*** file scope type declarations ****************************************************************/
79 /*** file scope variables ************************************************************************/
81 /* Various saved termios settings that we control here */
82 static struct termios boot_mode;
83 static struct termios new_mode;
85 /* Controls whether we should wait for input in tty_lowlevel_getch */
86 static gboolean no_slang_delay;
88 /* This table describes which capabilities we want and which values we
89 * assign to them.
91 static const struct
93 int key_code;
94 const char *key_name;
95 } key_table[] =
97 /* *INDENT-OFF* */
98 { KEY_F (0), "k0" },
99 { KEY_F (1), "k1" },
100 { KEY_F (2), "k2" },
101 { KEY_F (3), "k3" },
102 { KEY_F (4), "k4" },
103 { KEY_F (5), "k5" },
104 { KEY_F (6), "k6" },
105 { KEY_F (7), "k7" },
106 { KEY_F (8), "k8" },
107 { KEY_F (9), "k9" },
108 { KEY_F (10), "k;" },
109 { KEY_F (11), "F1" },
110 { KEY_F (12), "F2" },
111 { KEY_F (13), "F3" },
112 { KEY_F (14), "F4" },
113 { KEY_F (15), "F5" },
114 { KEY_F (16), "F6" },
115 { KEY_F (17), "F7" },
116 { KEY_F (18), "F8" },
117 { KEY_F (19), "F9" },
118 { KEY_F (20), "FA" },
119 { KEY_IC, "kI" },
120 { KEY_NPAGE, "kN" },
121 { KEY_PPAGE, "kP" },
122 { KEY_LEFT, "kl" },
123 { KEY_RIGHT, "kr" },
124 { KEY_UP, "ku" },
125 { KEY_DOWN, "kd" },
126 { KEY_DC, "kD" },
127 { KEY_BACKSPACE, "kb" },
128 { KEY_HOME, "kh" },
129 { KEY_END, "@7" },
130 { 0, NULL }
131 /* *INDENT-ON* */
134 /*** file scope functions ************************************************************************/
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 tty_setup_sigwinch (void (*handler) (int))
140 #ifdef SIGWINCH
141 struct sigaction act, oact;
142 act.sa_handler = handler;
143 sigemptyset (&act.sa_mask);
144 act.sa_flags = 0;
145 #ifdef SA_RESTART
146 act.sa_flags |= SA_RESTART;
147 #endif /* SA_RESTART */
148 sigaction (SIGWINCH, &act, &oact);
149 #endif /* SIGWINCH */
152 /* --------------------------------------------------------------------------------------------- */
154 static void
155 sigwinch_handler (int dummy)
157 (void) dummy;
159 mc_global.tty.winch_flag = TRUE;
162 /* --------------------------------------------------------------------------------------------- */
164 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
165 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
166 consequence is that function keys don't work in MC sometimes...
167 Unfortunately I don't now the one and only escape sequence to turn off.
168 softkeys (elm uses three different capabilities to turn on softkeys and two.
169 capabilities to turn them off)..
170 Among other things elm uses the pair we already use in slang_keypad. That's.
171 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
172 something better the softkeys are programmed to their defaults from the
173 termcap/terminfo database.
174 The escape sequence to program the softkeys is taken from elm and it is.
175 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
176 sequence. -- Norbert
179 static void
180 slang_reset_softkeys (void)
182 int key;
183 char *send;
184 static const char display[] = " ";
185 char tmp[BUF_SMALL];
187 for (key = 1; key < 9; key++)
189 g_snprintf (tmp, sizeof (tmp), "k%d", key);
190 send = (char *) SLtt_tgetstr (tmp);
191 if (send != NULL)
193 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
194 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
195 SLtt_write_string (tmp);
200 /* --------------------------------------------------------------------------------------------- */
202 static void
203 do_define_key (int code, const char *strcap)
205 char *seq;
207 seq = (char *) SLtt_tgetstr ((char *) strcap);
208 if (seq != NULL)
209 define_sequence (code, seq, MCKEY_NOACTION);
212 /* --------------------------------------------------------------------------------------------- */
214 static void
215 load_terminfo_keys (void)
217 int i;
219 for (i = 0; key_table[i].key_code; i++)
220 do_define_key (key_table[i].key_code, key_table[i].key_name);
223 /* --------------------------------------------------------------------------------------------- */
224 /*** public functions ****************************************************************************/
225 /* --------------------------------------------------------------------------------------------- */
228 mc_tty_normalize_lines_char (const char *str)
230 char *str2;
231 int res;
233 struct mc_tty_lines_struct
235 const char *line;
236 int line_code;
237 } const lines_codes[] = {
238 {"\342\224\214", SLSMG_ULCORN_CHAR},
239 {"\342\224\220", SLSMG_URCORN_CHAR},
240 {"\342\224\224", SLSMG_LLCORN_CHAR},
241 {"\342\224\230", SLSMG_LRCORN_CHAR},
242 {"\342\224\234", SLSMG_LTEE_CHAR},
243 {"\342\224\244", SLSMG_RTEE_CHAR},
244 {"\342\224\254", SLSMG_UTEE_CHAR},
245 {"\342\224\264", SLSMG_DTEE_CHAR},
246 {"\342\224\200", SLSMG_HLINE_CHAR},
247 {"\342\224\202", SLSMG_VLINE_CHAR},
248 {"\342\224\274", SLSMG_PLUS_CHAR},
250 {NULL, 0}
253 if (!str)
254 return (int) ' ';
256 for (res = 0; lines_codes[res].line; res++)
258 if (strcmp (str, lines_codes[res].line) == 0)
259 return lines_codes[res].line_code;
262 str2 = mc_tty_normalize_from_utf8 (str);
263 res = g_utf8_get_char_validated (str2, -1);
265 if (res < 0)
266 res = (unsigned char) str2[0];
267 g_free (str2);
269 return res;
272 /* --------------------------------------------------------------------------------------------- */
274 void
275 tty_init (gboolean mouse_enable, gboolean is_xterm)
277 SLtt_Ignore_Beep = 1;
279 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
280 SLtt_get_terminfo ();
282 * If the terminal in not in terminfo but begins with a well-known
283 * string such as "linux" or "xterm" S-Lang will go on, but the
284 * terminal size and several other variables won't be initialized
285 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
286 * small, large and negative screen dimensions.
288 if ((COLS < 10) || (LINES < 5)
289 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
291 fprintf (stderr,
292 _("Screen size %dx%d is not supported.\n"
293 "Check the TERM environment variable.\n"), COLS, LINES);
294 exit (EXIT_FAILURE);
297 tcgetattr (fileno (stdin), &boot_mode);
298 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
299 SLang_init_tty (XCTRL ('g'), 1, 0);
301 if (mc_global.tty.ugly_line_drawing)
302 SLtt_Has_Alt_Charset = 0;
304 /* If SLang uses fileno(stderr) for terminal input MC will hang
305 if we call SLang_getkey between calls to open_error_pipe and
306 close_error_pipe, e.g. when we do a growing view of an gzipped
307 file. */
308 if (SLang_TT_Read_FD == fileno (stderr))
309 SLang_TT_Read_FD = fileno (stdin);
311 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
313 #ifdef VDSUSP
314 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
315 #endif
316 #ifdef VLNEXT
317 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
318 #endif
319 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
322 tty_reset_prog_mode ();
323 load_terminfo_keys ();
325 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
327 tty_start_interrupt_key ();
329 /* It's the small part from the previous init_key() */
330 init_key_input_fd ();
332 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
333 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
334 * detected - but checking TERM would fail under screen, OR running xterm
335 * with allowC1Printable).
337 tty_display_8bit (FALSE);
339 SLsmg_init_smg ();
340 if (!mouse_enable)
341 use_mouse_p = MOUSE_DISABLED;
342 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
343 init_mouse ();
344 do_enter_ca_mode ();
345 tty_keypad (TRUE);
346 tty_nodelay (FALSE);
348 tty_setup_sigwinch (sigwinch_handler);
351 /* --------------------------------------------------------------------------------------------- */
353 void
354 tty_shutdown (void)
356 char *op_cap;
358 disable_mouse ();
359 tty_reset_shell_mode ();
360 tty_noraw_mode ();
361 tty_keypad (FALSE);
362 tty_reset_screen ();
363 do_exit_ca_mode ();
364 SLang_reset_tty ();
366 /* Load the op capability to reset the colors to those that were
367 * active when the program was started up
369 op_cap = SLtt_tgetstr ((char *) "op");
370 if (op_cap != NULL)
372 fputs (op_cap, stdout);
373 fflush (stdout);
377 /* --------------------------------------------------------------------------------------------- */
379 void
380 tty_change_screen_size (void)
382 SLtt_get_screen_size ();
383 SLsmg_reinit_smg ();
385 do_enter_ca_mode ();
386 tty_keypad (TRUE);
387 tty_nodelay (FALSE);
390 /* --------------------------------------------------------------------------------------------- */
391 /* Done each time we come back from done mode */
393 void
394 tty_reset_prog_mode (void)
396 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
397 SLsmg_init_smg ();
398 SLsmg_touch_lines (0, LINES);
401 /* --------------------------------------------------------------------------------------------- */
402 /* Called each time we want to shutdown slang screen manager */
404 void
405 tty_reset_shell_mode (void)
407 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
410 /* --------------------------------------------------------------------------------------------- */
412 void
413 tty_raw_mode (void)
415 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
418 /* --------------------------------------------------------------------------------------------- */
420 void
421 tty_noraw_mode (void)
425 /* --------------------------------------------------------------------------------------------- */
427 void
428 tty_noecho (void)
432 /* --------------------------------------------------------------------------------------------- */
435 tty_flush_input (void)
437 return 0; /* OK */
440 /* --------------------------------------------------------------------------------------------- */
442 void
443 tty_keypad (gboolean set)
445 char *keypad_string;
447 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
448 if (keypad_string != NULL)
449 SLtt_write_string (keypad_string);
450 if (set && reset_hp_softkeys)
451 slang_reset_softkeys ();
454 /* --------------------------------------------------------------------------------------------- */
456 void
457 tty_nodelay (gboolean set)
459 no_slang_delay = set;
462 /* --------------------------------------------------------------------------------------------- */
465 tty_baudrate (void)
467 return SLang_TT_Baud_Rate;
470 /* --------------------------------------------------------------------------------------------- */
473 tty_lowlevel_getch (void)
475 int c;
477 if (no_slang_delay && (SLang_input_pending (0) == 0))
478 return -1;
480 c = SLang_getkey ();
481 if (c == SLANG_GETKEY_ERROR)
483 fprintf (stderr,
484 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
485 "Assuming EOF on stdin and exiting\n");
486 exit (EXIT_FAILURE);
489 return c;
492 /* --------------------------------------------------------------------------------------------- */
495 tty_reset_screen (void)
497 SLsmg_reset_smg ();
498 return 0; /* OK */
501 /* --------------------------------------------------------------------------------------------- */
503 void
504 tty_touch_screen (void)
506 SLsmg_touch_lines (0, LINES);
509 /* --------------------------------------------------------------------------------------------- */
511 void
512 tty_gotoyx (int y, int x)
514 SLsmg_gotorc (y, x);
517 /* --------------------------------------------------------------------------------------------- */
519 void
520 tty_getyx (int *py, int *px)
522 *py = SLsmg_get_row ();
523 *px = SLsmg_get_column ();
526 /* --------------------------------------------------------------------------------------------- */
528 void
529 tty_draw_hline (int y, int x, int ch, int len)
531 int x1;
533 if (y < 0 || y >= LINES || x >= COLS)
534 return;
536 x1 = x;
538 if (x < 0)
540 len += x;
541 if (len <= 0)
542 return;
543 x = 0;
546 if (ch == ACS_HLINE)
547 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
548 if (ch == 0)
549 ch = ACS_HLINE;
551 SLsmg_gotorc (y, x);
553 if (ch == ACS_HLINE)
554 SLsmg_draw_hline (len);
555 else
556 while (len-- != 0)
557 tty_print_char (ch);
559 SLsmg_gotorc (y, x1);
562 /* --------------------------------------------------------------------------------------------- */
564 void
565 tty_draw_vline (int y, int x, int ch, int len)
567 int y1;
569 if (x < 0 || x >= COLS || y >= LINES)
570 return;
572 y1 = y;
574 if (y < 0)
576 len += y;
577 if (len <= 0)
578 return;
579 y = 0;
582 if (ch == ACS_VLINE)
583 ch = mc_tty_frm[MC_TTY_FRM_VERT];
584 if (ch == 0)
585 ch = ACS_VLINE;
587 SLsmg_gotorc (y, x);
589 if (ch == ACS_VLINE)
590 SLsmg_draw_vline (len);
591 else
593 int pos = 0;
595 while (len-- != 0)
597 SLsmg_gotorc (y + pos, x);
598 tty_print_char (ch);
599 pos++;
603 SLsmg_gotorc (y1, x);
606 /* --------------------------------------------------------------------------------------------- */
608 void
609 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
611 SLsmg_fill_region (y, x, rows, cols, ch);
614 /* --------------------------------------------------------------------------------------------- */
616 void
617 tty_set_alt_charset (gboolean alt_charset)
619 SLsmg_set_char_set ((int) alt_charset);
622 /* --------------------------------------------------------------------------------------------- */
624 void
625 tty_display_8bit (gboolean what)
627 SLsmg_Display_Eight_Bit = what ? 128 : 160;
630 /* --------------------------------------------------------------------------------------------- */
632 void
633 tty_print_char (int c)
635 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
638 /* --------------------------------------------------------------------------------------------- */
640 void
641 tty_print_alt_char (int c, gboolean single)
643 #define DRAW(x, y) (x == y) \
644 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
645 : SLsmg_write_char ((unsigned int) y)
646 switch (c)
648 case ACS_VLINE:
649 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
650 break;
651 case ACS_HLINE:
652 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
653 break;
654 case ACS_LTEE:
655 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
656 break;
657 case ACS_RTEE:
658 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
659 break;
660 case ACS_ULCORNER:
661 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
662 break;
663 case ACS_LLCORNER:
664 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
665 break;
666 case ACS_URCORNER:
667 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
668 break;
669 case ACS_LRCORNER:
670 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
671 break;
672 case ACS_PLUS:
673 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
674 break;
675 default:
676 SLsmg_write_char ((unsigned int) c);
678 #undef DRAW
681 /* --------------------------------------------------------------------------------------------- */
683 void
684 tty_print_anychar (int c)
686 char str[6 + 1];
688 if (c > 255)
690 int res = g_unichar_to_utf8 (c, str);
691 if (res == 0)
693 str[0] = '.';
694 str[1] = '\0';
696 else
698 str[res] = '\0';
700 SLsmg_write_string ((char *) str_term_form (str));
702 else
704 if (!is_printable (c))
705 c = '.';
706 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
710 /* --------------------------------------------------------------------------------------------- */
712 void
713 tty_print_string (const char *s)
715 SLsmg_write_string ((char *) str_term_form (s));
718 /* --------------------------------------------------------------------------------------------- */
720 void
721 tty_printf (const char *fmt, ...)
723 va_list args;
725 va_start (args, fmt);
726 SLsmg_vprintf ((char *) fmt, args);
727 va_end (args);
730 /* --------------------------------------------------------------------------------------------- */
732 char *
733 tty_tgetstr (const char *cap)
735 return SLtt_tgetstr ((char *) cap);
738 /* --------------------------------------------------------------------------------------------- */
740 void
741 tty_refresh (void)
743 SLsmg_refresh ();
746 /* --------------------------------------------------------------------------------------------- */
748 void
749 tty_beep (void)
751 SLtt_beep ();
754 /* --------------------------------------------------------------------------------------------- */