cppcheck: reduce variable scope.
[midnight-commander.git] / lib / tty / tty-slang.c
blob6e6f2388e1e9b85a89fe0fb15c3be0dd5ab9c432
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 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 #include <termios.h>
44 #include "lib/global.h"
45 #include "lib/strutil.h" /* str_term_form */
46 #include "lib/util.h" /* is_printable() */
48 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
49 #include "tty.h"
50 #include "color.h"
51 #include "color-slang.h"
52 #include "color-internal.h"
53 #include "mouse.h" /* Gpm_Event is required in key.h */
54 #include "key.h" /* define_sequence */
55 #include "win.h"
58 /*** global variables ****************************************************************************/
60 extern int reset_hp_softkeys;
62 /*** file scope macro definitions ****************************************************************/
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
88 int key_code;
89 const char *key_name;
90 } key_table[] =
92 /* *INDENT-OFF* */
93 { KEY_F (0), "k0" },
94 { KEY_F (1), "k1" },
95 { KEY_F (2), "k2" },
96 { KEY_F (3), "k3" },
97 { KEY_F (4), "k4" },
98 { KEY_F (5), "k5" },
99 { KEY_F (6), "k6" },
100 { KEY_F (7), "k7" },
101 { KEY_F (8), "k8" },
102 { KEY_F (9), "k9" },
103 { KEY_F (10), "k;" },
104 { KEY_F (11), "F1" },
105 { KEY_F (12), "F2" },
106 { KEY_F (13), "F3" },
107 { KEY_F (14), "F4" },
108 { KEY_F (15), "F5" },
109 { KEY_F (16), "F6" },
110 { KEY_F (17), "F7" },
111 { KEY_F (18), "F8" },
112 { KEY_F (19), "F9" },
113 { KEY_F (20), "FA" },
114 { KEY_IC, "kI" },
115 { KEY_NPAGE, "kN" },
116 { KEY_PPAGE, "kP" },
117 { KEY_LEFT, "kl" },
118 { KEY_RIGHT, "kr" },
119 { KEY_UP, "ku" },
120 { KEY_DOWN, "kd" },
121 { KEY_DC, "kD" },
122 { KEY_BACKSPACE, "kb" },
123 { KEY_HOME, "kh" },
124 { KEY_END, "@7" },
125 { 0, NULL }
126 /* *INDENT-ON* */
129 /* --------------------------------------------------------------------------------------------- */
130 /*** file scope functions ************************************************************************/
131 /* --------------------------------------------------------------------------------------------- */
133 static void
134 tty_setup_sigwinch (void (*handler) (int))
136 (void) SLsignal (SIGWINCH, handler);
139 /* --------------------------------------------------------------------------------------------- */
141 static void
142 sigwinch_handler (int dummy)
144 (void) dummy;
146 mc_global.tty.winch_flag = 1;
147 (void) SLsignal (SIGWINCH, sigwinch_handler);
150 /* --------------------------------------------------------------------------------------------- */
152 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
153 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
154 consequence is that function keys don't work in MC sometimes...
155 Unfortunately I don't now the one and only escape sequence to turn off.
156 softkeys (elm uses three different capabilities to turn on softkeys and two.
157 capabilities to turn them off)..
158 Among other things elm uses the pair we already use in slang_keypad. That's.
159 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
160 something better the softkeys are programmed to their defaults from the
161 termcap/terminfo database.
162 The escape sequence to program the softkeys is taken from elm and it is.
163 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
164 sequence. -- Norbert
167 static void
168 slang_reset_softkeys (void)
170 int key;
171 static const char display[] = " ";
172 char tmp[BUF_SMALL];
174 for (key = 1; key < 9; key++)
176 char *send;
178 g_snprintf (tmp, sizeof (tmp), "k%d", key);
179 send = (char *) SLtt_tgetstr (tmp);
180 if (send != NULL)
182 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
183 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
184 SLtt_write_string (tmp);
189 /* --------------------------------------------------------------------------------------------- */
191 static void
192 do_define_key (int code, const char *strcap)
194 char *seq;
196 seq = (char *) SLtt_tgetstr ((char *) strcap);
197 if (seq != NULL)
198 define_sequence (code, seq, MCKEY_NOACTION);
201 /* --------------------------------------------------------------------------------------------- */
203 static void
204 load_terminfo_keys (void)
206 int i;
208 for (i = 0; key_table[i].key_code; i++)
209 do_define_key (key_table[i].key_code, key_table[i].key_name);
212 /* --------------------------------------------------------------------------------------------- */
213 /*** public functions ****************************************************************************/
214 /* --------------------------------------------------------------------------------------------- */
217 mc_tty_normalize_lines_char (const char *str)
219 char *str2;
220 int res;
222 struct mc_tty_lines_struct
224 const char *line;
225 int line_code;
226 } const lines_codes[] = {
227 {"\342\224\214", SLSMG_ULCORN_CHAR},
228 {"\342\224\220", SLSMG_URCORN_CHAR},
229 {"\342\224\224", SLSMG_LLCORN_CHAR},
230 {"\342\224\230", SLSMG_LRCORN_CHAR},
231 {"\342\224\234", SLSMG_LTEE_CHAR},
232 {"\342\224\244", SLSMG_RTEE_CHAR},
233 {"\342\224\254", SLSMG_UTEE_CHAR},
234 {"\342\224\264", SLSMG_DTEE_CHAR},
235 {"\342\224\200", SLSMG_HLINE_CHAR},
236 {"\342\224\202", SLSMG_VLINE_CHAR},
237 {"\342\224\274", SLSMG_PLUS_CHAR},
239 {NULL, 0}
242 if (!str)
243 return (int) ' ';
245 for (res = 0; lines_codes[res].line; res++)
247 if (strcmp (str, lines_codes[res].line) == 0)
248 return lines_codes[res].line_code;
251 str2 = mc_tty_normalize_from_utf8 (str);
252 res = g_utf8_get_char_validated (str2, -1);
254 if (res < 0)
255 res = (unsigned char) str2[0];
256 g_free (str2);
258 return res;
261 /* --------------------------------------------------------------------------------------------- */
263 void
264 tty_init (gboolean mouse_enable, gboolean is_xterm)
266 SLtt_Ignore_Beep = 1;
268 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
269 SLtt_get_terminfo ();
271 * If the terminal in not in terminfo but begins with a well-known
272 * string such as "linux" or "xterm" S-Lang will go on, but the
273 * terminal size and several other variables won't be initialized
274 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
275 * small, large and negative screen dimensions.
277 if ((COLS < 10) || (LINES < 5)
278 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
280 fprintf (stderr,
281 _("Screen size %dx%d is not supported.\n"
282 "Check the TERM environment variable.\n"), COLS, LINES);
283 exit (EXIT_FAILURE);
286 tcgetattr (fileno (stdin), &boot_mode);
287 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
288 SLang_init_tty (XCTRL ('g'), 1, 0);
290 if (mc_global.tty.ugly_line_drawing)
291 SLtt_Has_Alt_Charset = 0;
293 /* If SLang uses fileno(stderr) for terminal input MC will hang
294 if we call SLang_getkey between calls to open_error_pipe and
295 close_error_pipe, e.g. when we do a growing view of an gzipped
296 file. */
297 if (SLang_TT_Read_FD == fileno (stderr))
298 SLang_TT_Read_FD = fileno (stdin);
300 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
302 #ifdef VDSUSP
303 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
304 #endif
305 #ifdef VLNEXT
306 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
307 #endif
308 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
311 tty_reset_prog_mode ();
312 load_terminfo_keys ();
314 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
316 tty_start_interrupt_key ();
318 /* It's the small part from the previous init_key() */
319 init_key_input_fd ();
321 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
322 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
323 * detected - but checking TERM would fail under screen, OR running xterm
324 * with allowC1Printable).
326 tty_display_8bit (FALSE);
328 SLsmg_init_smg ();
329 if (!mouse_enable)
330 use_mouse_p = MOUSE_DISABLED;
331 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
332 do_enter_ca_mode ();
333 tty_keypad (TRUE);
334 tty_nodelay (FALSE);
336 tty_setup_sigwinch (sigwinch_handler);
339 /* --------------------------------------------------------------------------------------------- */
341 void
342 tty_shutdown (void)
344 char *op_cap;
346 disable_mouse ();
347 disable_bracketed_paste ();
348 tty_reset_shell_mode ();
349 tty_noraw_mode ();
350 tty_keypad (FALSE);
351 tty_reset_screen ();
352 do_exit_ca_mode ();
353 SLang_reset_tty ();
355 /* Load the op capability to reset the colors to those that were
356 * active when the program was started up
358 op_cap = SLtt_tgetstr ((char *) "op");
359 if (op_cap != NULL)
361 fputs (op_cap, stdout);
362 fflush (stdout);
366 /* --------------------------------------------------------------------------------------------- */
368 void
369 tty_change_screen_size (void)
371 SLtt_get_screen_size ();
372 SLsmg_reinit_smg ();
374 #ifdef ENABLE_SUBSHELL
375 if (mc_global.tty.use_subshell)
376 tty_resize (mc_global.tty.subshell_pty);
377 #endif
380 /* --------------------------------------------------------------------------------------------- */
381 /* Done each time we come back from done mode */
383 void
384 tty_reset_prog_mode (void)
386 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
387 SLsmg_init_smg ();
388 SLsmg_touch_lines (0, LINES);
391 /* --------------------------------------------------------------------------------------------- */
392 /* Called each time we want to shutdown slang screen manager */
394 void
395 tty_reset_shell_mode (void)
397 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
400 /* --------------------------------------------------------------------------------------------- */
402 void
403 tty_raw_mode (void)
405 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
408 /* --------------------------------------------------------------------------------------------- */
410 void
411 tty_noraw_mode (void)
415 /* --------------------------------------------------------------------------------------------- */
417 void
418 tty_noecho (void)
422 /* --------------------------------------------------------------------------------------------- */
425 tty_flush_input (void)
427 return 0; /* OK */
430 /* --------------------------------------------------------------------------------------------- */
432 void
433 tty_keypad (gboolean set)
435 char *keypad_string;
437 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
438 if (keypad_string != NULL)
439 SLtt_write_string (keypad_string);
440 if (set && reset_hp_softkeys)
441 slang_reset_softkeys ();
444 /* --------------------------------------------------------------------------------------------- */
446 void
447 tty_nodelay (gboolean set)
449 no_slang_delay = set;
452 /* --------------------------------------------------------------------------------------------- */
455 tty_baudrate (void)
457 return SLang_TT_Baud_Rate;
460 /* --------------------------------------------------------------------------------------------- */
463 tty_lowlevel_getch (void)
465 int c;
467 if (no_slang_delay && (SLang_input_pending (0) == 0))
468 return -1;
470 c = SLang_getkey ();
471 if (c == SLANG_GETKEY_ERROR)
473 fprintf (stderr,
474 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
475 "Assuming EOF on stdin and exiting\n");
476 exit (EXIT_FAILURE);
479 return c;
482 /* --------------------------------------------------------------------------------------------- */
485 tty_reset_screen (void)
487 SLsmg_reset_smg ();
488 return 0; /* OK */
491 /* --------------------------------------------------------------------------------------------- */
493 void
494 tty_touch_screen (void)
496 SLsmg_touch_lines (0, LINES);
499 /* --------------------------------------------------------------------------------------------- */
501 void
502 tty_gotoyx (int y, int x)
504 SLsmg_gotorc (y, x);
507 /* --------------------------------------------------------------------------------------------- */
509 void
510 tty_getyx (int *py, int *px)
512 *py = SLsmg_get_row ();
513 *px = SLsmg_get_column ();
516 /* --------------------------------------------------------------------------------------------- */
518 void
519 tty_draw_hline (int y, int x, int ch, int len)
521 int x1;
523 if (y < 0 || y >= LINES || x >= COLS)
524 return;
526 x1 = x;
528 if (x < 0)
530 len += x;
531 if (len <= 0)
532 return;
533 x = 0;
536 if (ch == ACS_HLINE)
537 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
538 if (ch == 0)
539 ch = ACS_HLINE;
541 SLsmg_gotorc (y, x);
543 if (ch == ACS_HLINE)
544 SLsmg_draw_hline (len);
545 else
546 while (len-- != 0)
547 tty_print_char (ch);
549 SLsmg_gotorc (y, x1);
552 /* --------------------------------------------------------------------------------------------- */
554 void
555 tty_draw_vline (int y, int x, int ch, int len)
557 int y1;
559 if (x < 0 || x >= COLS || y >= LINES)
560 return;
562 y1 = y;
564 if (y < 0)
566 len += y;
567 if (len <= 0)
568 return;
569 y = 0;
572 if (ch == ACS_VLINE)
573 ch = mc_tty_frm[MC_TTY_FRM_VERT];
574 if (ch == 0)
575 ch = ACS_VLINE;
577 SLsmg_gotorc (y, x);
579 if (ch == ACS_VLINE)
580 SLsmg_draw_vline (len);
581 else
583 int pos = 0;
585 while (len-- != 0)
587 SLsmg_gotorc (y + pos, x);
588 tty_print_char (ch);
589 pos++;
593 SLsmg_gotorc (y1, x);
596 /* --------------------------------------------------------------------------------------------- */
598 void
599 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
601 SLsmg_fill_region (y, x, rows, cols, ch);
604 /* --------------------------------------------------------------------------------------------- */
606 void
607 tty_set_alt_charset (gboolean alt_charset)
609 SLsmg_set_char_set ((int) alt_charset);
612 /* --------------------------------------------------------------------------------------------- */
614 void
615 tty_display_8bit (gboolean what)
617 SLsmg_Display_Eight_Bit = what ? 128 : 160;
620 /* --------------------------------------------------------------------------------------------- */
622 void
623 tty_print_char (int c)
625 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
628 /* --------------------------------------------------------------------------------------------- */
630 void
631 tty_print_alt_char (int c, gboolean single)
633 #define DRAW(x, y) (x == y) \
634 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
635 : SLsmg_write_char ((unsigned int) y)
636 switch (c)
638 case ACS_VLINE:
639 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
640 break;
641 case ACS_HLINE:
642 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
643 break;
644 case ACS_LTEE:
645 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
646 break;
647 case ACS_RTEE:
648 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
649 break;
650 case ACS_ULCORNER:
651 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
652 break;
653 case ACS_LLCORNER:
654 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
655 break;
656 case ACS_URCORNER:
657 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
658 break;
659 case ACS_LRCORNER:
660 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
661 break;
662 case ACS_PLUS:
663 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
664 break;
665 default:
666 SLsmg_write_char ((unsigned int) c);
668 #undef DRAW
671 /* --------------------------------------------------------------------------------------------- */
673 void
674 tty_print_anychar (int c)
676 if (c > 255)
678 char str[UTF8_CHAR_LEN + 1];
679 int res;
681 res = g_unichar_to_utf8 (c, str);
682 if (res == 0)
684 str[0] = '.';
685 str[1] = '\0';
687 else
689 str[res] = '\0';
691 SLsmg_write_string ((char *) str_term_form (str));
693 else
695 if (!is_printable (c))
696 c = '.';
697 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
701 /* --------------------------------------------------------------------------------------------- */
703 void
704 tty_print_string (const char *s)
706 SLsmg_write_string ((char *) str_term_form (s));
709 /* --------------------------------------------------------------------------------------------- */
711 void
712 tty_printf (const char *fmt, ...)
714 va_list args;
716 va_start (args, fmt);
717 SLsmg_vprintf ((char *) fmt, args);
718 va_end (args);
721 /* --------------------------------------------------------------------------------------------- */
723 char *
724 tty_tgetstr (const char *cap)
726 return SLtt_tgetstr ((char *) cap);
729 /* --------------------------------------------------------------------------------------------- */
731 void
732 tty_refresh (void)
734 SLsmg_refresh ();
737 /* --------------------------------------------------------------------------------------------- */
739 void
740 tty_beep (void)
742 SLtt_beep ();
745 /* --------------------------------------------------------------------------------------------- */