Ticket #1648: implemented single-line boxes.
[kaloumi3.git] / lib / tty / tty-slang.c
blobe60d816478e791f392461558ed6c37ac75d5b65c
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 */
45 #include "tty-internal.h" /* slow_tty */
46 #include "tty.h"
47 #include "color-slang.h"
48 #include "color-internal.h"
49 #include "mouse.h" /* Gpm_Event is required in key.h */
50 #include "key.h" /* define_sequence */
51 #include "win.h"
54 /*** global variables **************************************************/
56 extern int reset_hp_softkeys;
58 /*** file scope macro definitions **************************************/
60 #ifndef SA_RESTART
61 # define SA_RESTART 0
62 #endif
64 #ifndef SLTT_MAX_SCREEN_COLS
65 #define SLTT_MAX_SCREEN_COLS 512
66 #endif
68 #ifndef SLTT_MAX_SCREEN_ROWS
69 #define SLTT_MAX_SCREEN_ROWS 512
70 #endif
72 /*** file scope type declarations **************************************/
74 /*** file scope variables **********************************************/
76 /* Various saved termios settings that we control here */
77 static struct termios boot_mode;
78 static struct termios new_mode;
80 /* Controls whether we should wait for input in tty_lowlevel_getch */
81 static gboolean no_slang_delay;
83 /* This table describes which capabilities we want and which values we
84 * assign to them.
86 static const struct {
87 int key_code;
88 const char *key_name;
89 } key_table[] = {
91 KEY_F (0), "k0"}, {
92 KEY_F (1), "k1"}, {
93 KEY_F (2), "k2"}, {
94 KEY_F (3), "k3"}, {
95 KEY_F (4), "k4"}, {
96 KEY_F (5), "k5"}, {
97 KEY_F (6), "k6"}, {
98 KEY_F (7), "k7"}, {
99 KEY_F (8), "k8"}, {
100 KEY_F (9), "k9"}, {
101 KEY_F (10), "k;"}, {
102 KEY_F (11), "F1"}, {
103 KEY_F (12), "F2"}, {
104 KEY_F (13), "F3"}, {
105 KEY_F (14), "F4"}, {
106 KEY_F (15), "F5"}, {
107 KEY_F (16), "F6"}, {
108 KEY_F (17), "F7"}, {
109 KEY_F (18), "F8"}, {
110 KEY_F (19), "F9"}, {
111 KEY_F (20), "FA"}, {
112 KEY_IC, "kI"}, {
113 KEY_NPAGE, "kN"}, {
114 KEY_PPAGE, "kP"}, {
115 KEY_LEFT, "kl"}, {
116 KEY_RIGHT, "kr"}, {
117 KEY_UP, "ku"}, {
118 KEY_DOWN, "kd"}, {
119 KEY_DC, "kD"}, {
120 KEY_BACKSPACE, "kb"}, {
121 KEY_HOME, "kh"}, {
122 KEY_END, "@7"}, {
123 0, NULL}
126 /*** file scope functions **********************************************/
128 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
129 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
130 consequence is that function keys don't work in MC sometimes...
131 Unfortunately I don't now the one and only escape sequence to turn off.
132 softkeys (elm uses three different capabilities to turn on softkeys and two.
133 capabilities to turn them off)..
134 Among other things elm uses the pair we already use in slang_keypad. That's.
135 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
136 something better the softkeys are programmed to their defaults from the
137 termcap/terminfo database.
138 The escape sequence to program the softkeys is taken from elm and it is.
139 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
140 sequence. -- Norbert
143 static void
144 slang_reset_softkeys (void)
146 int key;
147 char *send;
148 static const char display[] = " ";
149 char tmp[BUF_SMALL];
151 for (key = 1; key < 9; key++) {
152 g_snprintf (tmp, sizeof (tmp), "k%d", key);
153 send = (char *) SLtt_tgetstr (tmp);
154 if (send != NULL) {
155 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
156 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
157 SLtt_write_string (tmp);
162 static void
163 do_define_key (int code, const char *strcap)
165 char *seq;
167 seq = (char *) SLtt_tgetstr ((char *) strcap);
168 if (seq != NULL)
169 define_sequence (code, seq, MCKEY_NOACTION);
172 static void
173 load_terminfo_keys (void)
175 int i;
177 for (i = 0; key_table[i].key_code; i++)
178 do_define_key (key_table[i].key_code, key_table[i].key_name);
181 /* --------------------------------------------------------------------------------------------- */
182 /*** public functions **************************************************/
183 /* --------------------------------------------------------------------------------------------- */
186 mc_tty_normalize_lines_char (const char *str)
188 char *str2;
189 int res;
191 struct mc_tty_lines_struct {
192 const char *line;
193 int line_code;
194 } const lines_codes[] = {
195 {"\342\224\214", SLSMG_ULCORN_CHAR},
196 {"\342\224\220", SLSMG_URCORN_CHAR},
197 {"\342\224\224", SLSMG_LLCORN_CHAR},
198 {"\342\224\230", SLSMG_LRCORN_CHAR},
199 {"\342\224\234", SLSMG_LTEE_CHAR},
200 {"\342\224\244", SLSMG_RTEE_CHAR},
201 {"\342\224\254", SLSMG_UTEE_CHAR},
202 {"\342\224\264", SLSMG_DTEE_CHAR},
203 {"\342\224\200", SLSMG_HLINE_CHAR},
204 {"\342\224\202", SLSMG_VLINE_CHAR},
205 {"\342\224\274", SLSMG_PLUS_CHAR},
207 {NULL, 0}
210 if (!str)
211 return (int) ' ';
213 for (res = 0; lines_codes[res].line; res++) {
214 if (strcmp (str, lines_codes[res].line) == 0)
215 return lines_codes[res].line_code;
218 str2 = mc_tty_normalize_from_utf8 (str);
219 res = g_utf8_get_char_validated (str2, -1);
221 if (res < 0)
222 res = (unsigned char) str2[0];
223 g_free (str2);
225 return res;
228 /* --------------------------------------------------------------------------------------------- */
229 void
230 tty_init (gboolean slow, gboolean ugly_lines)
232 slow_tty = slow;
233 ugly_line_drawing = ugly_lines;
235 SLtt_get_terminfo ();
236 SLutf8_enable (-1);
238 * If the terminal in not in terminfo but begins with a well-known
239 * string such as "linux" or "xterm" S-Lang will go on, but the
240 * terminal size and several other variables won't be initialized
241 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
242 * small, large and negative screen dimensions.
244 if ((COLS < 10) || (LINES < 5)
245 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS)) {
246 fprintf (stderr,
247 _("Screen size %dx%d is not supported.\n"
248 "Check the TERM environment variable.\n"), COLS, LINES);
249 exit (1);
252 tcgetattr (fileno (stdin), &boot_mode);
253 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
254 SLang_init_tty (XCTRL ('g'), 1, 0);
256 if (ugly_lines)
257 SLtt_Has_Alt_Charset = 0;
259 /* If SLang uses fileno(stderr) for terminal input MC will hang
260 if we call SLang_getkey between calls to open_error_pipe and
261 close_error_pipe, e.g. when we do a growing view of an gzipped
262 file. */
263 if (SLang_TT_Read_FD == fileno (stderr))
264 SLang_TT_Read_FD = fileno (stdin);
266 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
267 #ifdef VDSUSP
268 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
269 #endif
270 #ifdef VLNEXT
271 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
272 #endif
273 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
276 tty_reset_prog_mode ();
277 load_terminfo_keys ();
278 SLtt_Blink_Mode = 0;
280 tty_start_interrupt_key ();
282 /* It's the small part from the previous init_key() */
283 init_key_input_fd ();
285 SLsmg_init_smg ();
286 do_enter_ca_mode ();
287 tty_keypad (TRUE);
288 tty_nodelay (FALSE);
291 void
292 tty_shutdown (void)
294 char *op_cap;
296 SLsmg_reset_smg ();
297 tty_reset_shell_mode ();
298 do_exit_ca_mode ();
299 SLang_reset_tty ();
301 /* Load the op capability to reset the colors to those that were
302 * active when the program was started up
304 op_cap = SLtt_tgetstr ((char *) "op");
305 if (op_cap != NULL) {
306 fputs (op_cap, stdout);
307 fflush (stdout);
311 /* Done each time we come back from done mode */
312 void
313 tty_reset_prog_mode (void)
315 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
316 SLsmg_init_smg ();
317 SLsmg_touch_lines (0, LINES);
320 /* Called each time we want to shutdown slang screen manager */
321 void
322 tty_reset_shell_mode (void)
324 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
327 void
328 tty_raw_mode (void)
330 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
333 void
334 tty_noraw_mode (void)
338 void
339 tty_noecho (void)
344 tty_flush_input (void)
346 return 0; /* OK */
349 void
350 tty_keypad (gboolean set)
352 char *keypad_string;
354 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
355 if (keypad_string != NULL)
356 SLtt_write_string (keypad_string);
357 if (set && reset_hp_softkeys)
358 slang_reset_softkeys ();
361 void
362 tty_nodelay (gboolean set)
364 no_slang_delay = set;
368 tty_baudrate (void)
370 return SLang_TT_Baud_Rate;
374 tty_lowlevel_getch (void)
376 int c;
378 if (no_slang_delay && (SLang_input_pending (0) == 0))
379 return -1;
381 c = SLang_getkey ();
382 if (c == SLANG_GETKEY_ERROR) {
383 fprintf (stderr,
384 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
385 "Assuming EOF on stdin and exiting\n");
386 exit (1);
389 return c;
393 tty_reset_screen (void)
395 SLsmg_reset_smg ();
396 return 0; /* OK */
399 void
400 tty_touch_screen (void)
402 SLsmg_touch_lines (0, LINES);
405 void
406 tty_gotoyx (int y, int x)
408 SLsmg_gotorc (y, x);
411 void
412 tty_getyx (int *py, int *px)
414 *py = SLsmg_get_row ();
415 *px = SLsmg_get_column ();
418 /* if x < 0 or y < 0, draw line staring from current position */
419 void
420 tty_draw_hline (int y, int x, int ch, int len)
422 if (ch == ACS_HLINE)
423 ch = mc_tty_ugly_frm[MC_TTY_FRM_thinhoriz];
425 if ((y < 0) || (x < 0)) {
426 y = SLsmg_get_row ();
427 x = SLsmg_get_column ();
428 } else
429 SLsmg_gotorc (y, x);
431 if (ch == 0)
432 ch = ACS_HLINE;
434 if (ch == ACS_HLINE)
435 SLsmg_draw_hline (len);
436 else
437 while (len-- != 0)
438 tty_print_char (ch);
440 SLsmg_gotorc (y, x);
443 /* if x < 0 or y < 0, draw line staring from current position */
444 void
445 tty_draw_vline (int y, int x, int ch, int len)
447 if (ch == ACS_VLINE)
448 ch = mc_tty_ugly_frm[MC_TTY_FRM_thinvert];
450 if ((y < 0) || (x < 0)) {
451 y = SLsmg_get_row ();
452 x = SLsmg_get_column ();
453 } else
454 SLsmg_gotorc (y, x);
456 if (ch == 0)
457 ch = ACS_VLINE;
459 if (ch == ACS_VLINE)
460 SLsmg_draw_vline (len);
461 else {
462 int pos = 0;
464 while (len-- != 0) {
465 SLsmg_gotorc (y + pos, x);
466 tty_print_char (ch);
467 pos++;
471 SLsmg_gotorc (y, x);
474 void
475 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
477 SLsmg_fill_region (y, x, rows, cols, ch);
480 void
481 tty_set_alt_charset (gboolean alt_charset)
483 SLsmg_set_char_set ((int) alt_charset);
486 void
487 tty_display_8bit (gboolean what)
489 SLsmg_Display_Eight_Bit = what ? 128 : 160;
492 void
493 tty_print_char (int c)
495 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
498 void
499 tty_print_alt_char (int c, gboolean single)
501 #define DRAW(x, y) (x == y) \
502 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
503 : SLsmg_write_char ((unsigned int) y)
504 switch (c) {
505 case ACS_VLINE:
506 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_thinvert]);
507 break;
508 case ACS_HLINE:
509 DRAW (c, mc_tty_ugly_frm[MC_TTY_FRM_thinhoriz]);
510 break;
511 case ACS_LTEE:
512 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grpleftmiddle : MC_TTY_FRM_leftmiddle]);
513 break;
514 case ACS_RTEE:
515 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grprightmiddle : MC_TTY_FRM_rightmiddle]);
516 break;
517 case ACS_ULCORNER:
518 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grplefttop : MC_TTY_FRM_lefttop]);
519 break;
520 case ACS_LLCORNER:
521 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grpleftbottom : MC_TTY_FRM_leftbottom]);
522 break;
523 case ACS_URCORNER:
524 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grprighttop : MC_TTY_FRM_righttop]);
525 break;
526 case ACS_LRCORNER:
527 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grprightbottom : MC_TTY_FRM_rightbottom]);
528 break;
529 case ACS_PLUS:
530 DRAW (c, mc_tty_ugly_frm[single ? MC_TTY_FRM_grpcentermiddle : MC_TTY_FRM_centermiddle]);
531 break;
532 default:
533 SLsmg_write_char ((unsigned int) c);
535 #undef DRAW
538 void
539 tty_print_anychar (int c)
541 char str[6 + 1];
543 if (c > 255) {
544 int res = g_unichar_to_utf8 (c, str);
545 if (res == 0) {
546 str[0] = '.';
547 str[1] = '\0';
548 } else {
549 str[res] = '\0';
551 SLsmg_write_string ((char *) str_term_form (str));
552 } else {
553 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
557 void
558 tty_print_string (const char *s)
560 SLsmg_write_string ((char *) str_term_form (s));
563 void
564 tty_printf (const char *fmt, ...)
566 va_list args;
568 va_start (args, fmt);
569 SLsmg_vprintf ((char *) fmt, args);
570 va_end (args);
573 char *
574 tty_tgetstr (const char *cap)
576 return SLtt_tgetstr ((char *) cap);
579 void
580 tty_refresh (void)
582 SLsmg_refresh ();
585 void
586 tty_setup_sigwinch (void (*handler) (int))
588 #ifdef SIGWINCH
589 struct sigaction act, oact;
590 act.sa_handler = handler;
591 sigemptyset (&act.sa_mask);
592 act.sa_flags = 0;
593 #ifdef SA_RESTART
594 act.sa_flags |= SA_RESTART;
595 #endif /* SA_RESTART */
596 sigaction (SIGWINCH, &act, &oact);
597 #endif /* SIGWINCH */
600 void
601 tty_beep (void)
603 SLtt_beep ();