(get_fs_usage): avoid compile warning about mixed declarations and code.
[midnight-commander.git] / lib / tty / tty-slang.c
blob6b7fd32f7b40bbc36108526dd9a0e639a45184c0
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 <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" /* mc_tty_normalize_from_utf8() */
47 #include "tty.h"
48 #include "color.h"
49 #include "color-slang.h"
50 #include "color-internal.h"
51 #include "mouse.h" /* Gpm_Event is required in key.h */
52 #include "key.h" /* define_sequence */
53 #include "win.h"
56 /*** global variables ****************************************************************************/
58 extern int reset_hp_softkeys;
60 /*** file scope macro definitions ****************************************************************/
62 #ifndef SA_RESTART
63 #define SA_RESTART 0
64 #endif
66 #ifndef SLTT_MAX_SCREEN_COLS
67 #define SLTT_MAX_SCREEN_COLS 512
68 #endif
70 #ifndef SLTT_MAX_SCREEN_ROWS
71 #define SLTT_MAX_SCREEN_ROWS 512
72 #endif
74 /*** file scope type declarations ****************************************************************/
76 /*** file scope variables ************************************************************************/
78 /* Various saved termios settings that we control here */
79 static struct termios boot_mode;
80 static struct termios new_mode;
82 /* Controls whether we should wait for input in tty_lowlevel_getch */
83 static gboolean no_slang_delay;
85 /* This table describes which capabilities we want and which values we
86 * assign to them.
88 static const struct
90 int key_code;
91 const char *key_name;
92 } key_table[] =
94 /* *INDENT-OFF* */
95 { KEY_F (0), "k0" },
96 { KEY_F (1), "k1" },
97 { KEY_F (2), "k2" },
98 { KEY_F (3), "k3" },
99 { KEY_F (4), "k4" },
100 { KEY_F (5), "k5" },
101 { KEY_F (6), "k6" },
102 { KEY_F (7), "k7" },
103 { KEY_F (8), "k8" },
104 { KEY_F (9), "k9" },
105 { KEY_F (10), "k;" },
106 { KEY_F (11), "F1" },
107 { KEY_F (12), "F2" },
108 { KEY_F (13), "F3" },
109 { KEY_F (14), "F4" },
110 { KEY_F (15), "F5" },
111 { KEY_F (16), "F6" },
112 { KEY_F (17), "F7" },
113 { KEY_F (18), "F8" },
114 { KEY_F (19), "F9" },
115 { KEY_F (20), "FA" },
116 { KEY_IC, "kI" },
117 { KEY_NPAGE, "kN" },
118 { KEY_PPAGE, "kP" },
119 { KEY_LEFT, "kl" },
120 { KEY_RIGHT, "kr" },
121 { KEY_UP, "ku" },
122 { KEY_DOWN, "kd" },
123 { KEY_DC, "kD" },
124 { KEY_BACKSPACE, "kb" },
125 { KEY_HOME, "kh" },
126 { KEY_END, "@7" },
127 { 0, NULL }
128 /* *INDENT-ON* */
131 /*** file scope functions ************************************************************************/
132 /* --------------------------------------------------------------------------------------------- */
134 static void
135 tty_setup_sigwinch (void (*handler) (int))
137 #ifdef SIGWINCH
138 struct sigaction act, oact;
139 act.sa_handler = handler;
140 sigemptyset (&act.sa_mask);
141 act.sa_flags = 0;
142 #ifdef SA_RESTART
143 act.sa_flags |= SA_RESTART;
144 #endif /* SA_RESTART */
145 sigaction (SIGWINCH, &act, &oact);
146 #endif /* SIGWINCH */
149 /* --------------------------------------------------------------------------------------------- */
151 static void
152 sigwinch_handler (int dummy)
154 (void) dummy;
156 tty_change_screen_size ();
157 mc_global.tty.winch_flag = TRUE;
160 /* --------------------------------------------------------------------------------------------- */
162 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
163 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
164 consequence is that function keys don't work in MC sometimes...
165 Unfortunately I don't now the one and only escape sequence to turn off.
166 softkeys (elm uses three different capabilities to turn on softkeys and two.
167 capabilities to turn them off)..
168 Among other things elm uses the pair we already use in slang_keypad. That's.
169 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
170 something better the softkeys are programmed to their defaults from the
171 termcap/terminfo database.
172 The escape sequence to program the softkeys is taken from elm and it is.
173 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
174 sequence. -- Norbert
177 static void
178 slang_reset_softkeys (void)
180 int key;
181 char *send;
182 static const char display[] = " ";
183 char tmp[BUF_SMALL];
185 for (key = 1; key < 9; key++)
187 g_snprintf (tmp, sizeof (tmp), "k%d", key);
188 send = (char *) SLtt_tgetstr (tmp);
189 if (send != NULL)
191 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
192 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
193 SLtt_write_string (tmp);
198 /* --------------------------------------------------------------------------------------------- */
200 static void
201 do_define_key (int code, const char *strcap)
203 char *seq;
205 seq = (char *) SLtt_tgetstr ((char *) strcap);
206 if (seq != NULL)
207 define_sequence (code, seq, MCKEY_NOACTION);
210 /* --------------------------------------------------------------------------------------------- */
212 static void
213 load_terminfo_keys (void)
215 int i;
217 for (i = 0; key_table[i].key_code; i++)
218 do_define_key (key_table[i].key_code, key_table[i].key_name);
221 /* --------------------------------------------------------------------------------------------- */
222 /*** public functions ****************************************************************************/
223 /* --------------------------------------------------------------------------------------------- */
226 mc_tty_normalize_lines_char (const char *str)
228 char *str2;
229 int res;
231 struct mc_tty_lines_struct
233 const char *line;
234 int line_code;
235 } const lines_codes[] = {
236 {"\342\224\214", SLSMG_ULCORN_CHAR},
237 {"\342\224\220", SLSMG_URCORN_CHAR},
238 {"\342\224\224", SLSMG_LLCORN_CHAR},
239 {"\342\224\230", SLSMG_LRCORN_CHAR},
240 {"\342\224\234", SLSMG_LTEE_CHAR},
241 {"\342\224\244", SLSMG_RTEE_CHAR},
242 {"\342\224\254", SLSMG_UTEE_CHAR},
243 {"\342\224\264", SLSMG_DTEE_CHAR},
244 {"\342\224\200", SLSMG_HLINE_CHAR},
245 {"\342\224\202", SLSMG_VLINE_CHAR},
246 {"\342\224\274", SLSMG_PLUS_CHAR},
248 {NULL, 0}
251 if (!str)
252 return (int) ' ';
254 for (res = 0; lines_codes[res].line; res++)
256 if (strcmp (str, lines_codes[res].line) == 0)
257 return lines_codes[res].line_code;
260 str2 = mc_tty_normalize_from_utf8 (str);
261 res = g_utf8_get_char_validated (str2, -1);
263 if (res < 0)
264 res = (unsigned char) str2[0];
265 g_free (str2);
267 return res;
270 /* --------------------------------------------------------------------------------------------- */
272 void
273 tty_init (gboolean mouse_enable, gboolean is_xterm)
275 SLtt_Ignore_Beep = 1;
277 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
278 SLtt_get_terminfo ();
280 * If the terminal in not in terminfo but begins with a well-known
281 * string such as "linux" or "xterm" S-Lang will go on, but the
282 * terminal size and several other variables won't be initialized
283 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
284 * small, large and negative screen dimensions.
286 if ((COLS < 10) || (LINES < 5)
287 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
289 fprintf (stderr,
290 _("Screen size %dx%d is not supported.\n"
291 "Check the TERM environment variable.\n"), COLS, LINES);
292 exit (EXIT_FAILURE);
295 tcgetattr (fileno (stdin), &boot_mode);
296 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
297 SLang_init_tty (XCTRL ('g'), 1, 0);
299 if (mc_global.tty.ugly_line_drawing)
300 SLtt_Has_Alt_Charset = 0;
302 /* If SLang uses fileno(stderr) for terminal input MC will hang
303 if we call SLang_getkey between calls to open_error_pipe and
304 close_error_pipe, e.g. when we do a growing view of an gzipped
305 file. */
306 if (SLang_TT_Read_FD == fileno (stderr))
307 SLang_TT_Read_FD = fileno (stdin);
309 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
311 #ifdef VDSUSP
312 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
313 #endif
314 #ifdef VLNEXT
315 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
316 #endif
317 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
320 tty_reset_prog_mode ();
321 load_terminfo_keys ();
323 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
325 tty_start_interrupt_key ();
327 /* It's the small part from the previous init_key() */
328 init_key_input_fd ();
330 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
331 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
332 * detected - but checking TERM would fail under screen, OR running xterm
333 * with allowC1Printable).
335 tty_display_8bit (FALSE);
337 SLsmg_init_smg ();
338 if (!mouse_enable)
339 use_mouse_p = MOUSE_DISABLED;
340 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
341 init_mouse ();
342 do_enter_ca_mode ();
343 tty_keypad (TRUE);
344 tty_nodelay (FALSE);
346 tty_setup_sigwinch (sigwinch_handler);
349 /* --------------------------------------------------------------------------------------------- */
351 void
352 tty_shutdown (void)
354 char *op_cap;
356 disable_mouse ();
357 tty_reset_shell_mode ();
358 tty_noraw_mode ();
359 tty_keypad (FALSE);
360 tty_reset_screen ();
361 do_exit_ca_mode ();
362 SLang_reset_tty ();
364 /* Load the op capability to reset the colors to those that were
365 * active when the program was started up
367 op_cap = SLtt_tgetstr ((char *) "op");
368 if (op_cap != NULL)
370 fputs (op_cap, stdout);
371 fflush (stdout);
375 /* --------------------------------------------------------------------------------------------- */
376 /* Done each time we come back from done mode */
378 void
379 tty_reset_prog_mode (void)
381 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
382 SLsmg_init_smg ();
383 SLsmg_touch_lines (0, LINES);
386 /* --------------------------------------------------------------------------------------------- */
387 /* Called each time we want to shutdown slang screen manager */
389 void
390 tty_reset_shell_mode (void)
392 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
395 /* --------------------------------------------------------------------------------------------- */
397 void
398 tty_raw_mode (void)
400 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
403 /* --------------------------------------------------------------------------------------------- */
405 void
406 tty_noraw_mode (void)
410 /* --------------------------------------------------------------------------------------------- */
412 void
413 tty_noecho (void)
417 /* --------------------------------------------------------------------------------------------- */
420 tty_flush_input (void)
422 return 0; /* OK */
425 /* --------------------------------------------------------------------------------------------- */
427 void
428 tty_keypad (gboolean set)
430 char *keypad_string;
432 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
433 if (keypad_string != NULL)
434 SLtt_write_string (keypad_string);
435 if (set && reset_hp_softkeys)
436 slang_reset_softkeys ();
439 /* --------------------------------------------------------------------------------------------- */
441 void
442 tty_nodelay (gboolean set)
444 no_slang_delay = set;
447 /* --------------------------------------------------------------------------------------------- */
450 tty_baudrate (void)
452 return SLang_TT_Baud_Rate;
455 /* --------------------------------------------------------------------------------------------- */
458 tty_lowlevel_getch (void)
460 int c;
462 if (no_slang_delay && (SLang_input_pending (0) == 0))
463 return -1;
465 c = SLang_getkey ();
466 if (c == SLANG_GETKEY_ERROR)
468 fprintf (stderr,
469 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
470 "Assuming EOF on stdin and exiting\n");
471 exit (EXIT_FAILURE);
474 return c;
477 /* --------------------------------------------------------------------------------------------- */
480 tty_reset_screen (void)
482 SLsmg_reset_smg ();
483 return 0; /* OK */
486 /* --------------------------------------------------------------------------------------------- */
488 void
489 tty_touch_screen (void)
491 SLsmg_touch_lines (0, LINES);
494 /* --------------------------------------------------------------------------------------------- */
496 void
497 tty_gotoyx (int y, int x)
499 SLsmg_gotorc (y, x);
502 /* --------------------------------------------------------------------------------------------- */
504 void
505 tty_getyx (int *py, int *px)
507 *py = SLsmg_get_row ();
508 *px = SLsmg_get_column ();
511 /* --------------------------------------------------------------------------------------------- */
513 void
514 tty_draw_hline (int y, int x, int ch, int len)
516 int x1;
518 if (y < 0 || y >= LINES || x >= COLS)
519 return;
521 x1 = x;
523 if (x < 0)
525 len += x;
526 if (len <= 0)
527 return;
528 x = 0;
531 if (ch == ACS_HLINE)
532 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
533 if (ch == 0)
534 ch = ACS_HLINE;
536 SLsmg_gotorc (y, x);
538 if (ch == ACS_HLINE)
539 SLsmg_draw_hline (len);
540 else
541 while (len-- != 0)
542 tty_print_char (ch);
544 SLsmg_gotorc (y, x1);
547 /* --------------------------------------------------------------------------------------------- */
549 void
550 tty_draw_vline (int y, int x, int ch, int len)
552 int y1;
554 if (x < 0 || x >= COLS || y >= LINES)
555 return;
557 y1 = y;
559 if (y < 0)
561 len += y;
562 if (len <= 0)
563 return;
564 y = 0;
567 if (ch == ACS_VLINE)
568 ch = mc_tty_frm[MC_TTY_FRM_VERT];
569 if (ch == 0)
570 ch = ACS_VLINE;
572 SLsmg_gotorc (y, x);
574 if (ch == ACS_VLINE)
575 SLsmg_draw_vline (len);
576 else
578 int pos = 0;
580 while (len-- != 0)
582 SLsmg_gotorc (y + pos, x);
583 tty_print_char (ch);
584 pos++;
588 SLsmg_gotorc (y1, x);
591 /* --------------------------------------------------------------------------------------------- */
593 void
594 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
596 SLsmg_fill_region (y, x, rows, cols, ch);
599 /* --------------------------------------------------------------------------------------------- */
601 void
602 tty_set_alt_charset (gboolean alt_charset)
604 SLsmg_set_char_set ((int) alt_charset);
607 /* --------------------------------------------------------------------------------------------- */
609 void
610 tty_display_8bit (gboolean what)
612 SLsmg_Display_Eight_Bit = what ? 128 : 160;
615 /* --------------------------------------------------------------------------------------------- */
617 void
618 tty_print_char (int c)
620 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
623 /* --------------------------------------------------------------------------------------------- */
625 void
626 tty_print_alt_char (int c, gboolean single)
628 #define DRAW(x, y) (x == y) \
629 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
630 : SLsmg_write_char ((unsigned int) y)
631 switch (c)
633 case ACS_VLINE:
634 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
635 break;
636 case ACS_HLINE:
637 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
638 break;
639 case ACS_LTEE:
640 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
641 break;
642 case ACS_RTEE:
643 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
644 break;
645 case ACS_ULCORNER:
646 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
647 break;
648 case ACS_LLCORNER:
649 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
650 break;
651 case ACS_URCORNER:
652 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
653 break;
654 case ACS_LRCORNER:
655 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
656 break;
657 case ACS_PLUS:
658 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
659 break;
660 default:
661 SLsmg_write_char ((unsigned int) c);
663 #undef DRAW
666 /* --------------------------------------------------------------------------------------------- */
668 void
669 tty_print_anychar (int c)
671 char str[6 + 1];
673 if (c > 255)
675 int res = g_unichar_to_utf8 (c, str);
676 if (res == 0)
678 str[0] = '.';
679 str[1] = '\0';
681 else
683 str[res] = '\0';
685 SLsmg_write_string ((char *) str_term_form (str));
687 else
689 if (!is_printable (c))
690 c = '.';
691 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
695 /* --------------------------------------------------------------------------------------------- */
697 void
698 tty_print_string (const char *s)
700 SLsmg_write_string ((char *) str_term_form (s));
703 /* --------------------------------------------------------------------------------------------- */
705 void
706 tty_printf (const char *fmt, ...)
708 va_list args;
710 va_start (args, fmt);
711 SLsmg_vprintf ((char *) fmt, args);
712 va_end (args);
715 /* --------------------------------------------------------------------------------------------- */
717 char *
718 tty_tgetstr (const char *cap)
720 return SLtt_tgetstr ((char *) cap);
723 /* --------------------------------------------------------------------------------------------- */
725 void
726 tty_refresh (void)
728 SLsmg_refresh ();
731 /* --------------------------------------------------------------------------------------------- */
733 void
734 tty_beep (void)
736 SLtt_beep ();
739 /* --------------------------------------------------------------------------------------------- */