Ticket #2572: Patchfs with filenames containing whitespaces.
[midnight-commander.git] / lib / tty / tty-slang.c
blobf610140a0914b28a73ce996fe4867a906d9a2b8d
1 /*
2 Interface to the terminal controlling library.
3 Slang wrapper.
5 Copyright (C) 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
7 Written by:
8 Andrew Borodin <aborodin@vmail.ru>, 2009
9 Egmont Koblinger <egmont@gmail.com>, 2010
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software; you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be
19 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
20 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 MA 02110-1301, USA.
29 /** \file
30 * \brief Source: S-Lang-based tty layer of Midnight Commander
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <sys/types.h> /* size_t */
40 #include <unistd.h>
41 #include <signal.h>
43 #include "lib/global.h"
44 #include "lib/strutil.h" /* str_term_form */
45 #include "lib/util.h" /* is_printable() */
47 #include "tty-internal.h" /* slow_tty */
48 #include "tty.h"
49 #include "color.h"
50 #include "color-slang.h"
51 #include "color-internal.h"
52 #include "mouse.h" /* Gpm_Event is required in key.h */
53 #include "key.h" /* define_sequence */
54 #include "win.h"
57 /*** global variables ****************************************************************************/
59 extern int reset_hp_softkeys;
61 /*** file scope macro definitions ****************************************************************/
63 #ifndef SA_RESTART
64 #define SA_RESTART 0
65 #endif
67 #ifndef SLTT_MAX_SCREEN_COLS
68 #define SLTT_MAX_SCREEN_COLS 512
69 #endif
71 #ifndef SLTT_MAX_SCREEN_ROWS
72 #define SLTT_MAX_SCREEN_ROWS 512
73 #endif
75 /*** file scope type declarations ****************************************************************/
77 /*** file scope variables ************************************************************************/
79 /* Various saved termios settings that we control here */
80 static struct termios boot_mode;
81 static struct termios new_mode;
83 /* Controls whether we should wait for input in tty_lowlevel_getch */
84 static gboolean no_slang_delay;
86 /* This table describes which capabilities we want and which values we
87 * assign to them.
89 static const struct
91 int key_code;
92 const char *key_name;
93 } key_table[] =
95 /* *INDENT-OFF* */
96 { KEY_F (0), "k0" },
97 { KEY_F (1), "k1" },
98 { KEY_F (2), "k2" },
99 { KEY_F (3), "k3" },
100 { KEY_F (4), "k4" },
101 { KEY_F (5), "k5" },
102 { KEY_F (6), "k6" },
103 { KEY_F (7), "k7" },
104 { KEY_F (8), "k8" },
105 { KEY_F (9), "k9" },
106 { KEY_F (10), "k;" },
107 { KEY_F (11), "F1" },
108 { KEY_F (12), "F2" },
109 { KEY_F (13), "F3" },
110 { KEY_F (14), "F4" },
111 { KEY_F (15), "F5" },
112 { KEY_F (16), "F6" },
113 { KEY_F (17), "F7" },
114 { KEY_F (18), "F8" },
115 { KEY_F (19), "F9" },
116 { KEY_F (20), "FA" },
117 { KEY_IC, "kI" },
118 { KEY_NPAGE, "kN" },
119 { KEY_PPAGE, "kP" },
120 { KEY_LEFT, "kl" },
121 { KEY_RIGHT, "kr" },
122 { KEY_UP, "ku" },
123 { KEY_DOWN, "kd" },
124 { KEY_DC, "kD" },
125 { KEY_BACKSPACE, "kb" },
126 { KEY_HOME, "kh" },
127 { KEY_END, "@7" },
128 { 0, NULL }
129 /* *INDENT-ON* */
132 /*** file scope functions ************************************************************************/
133 /* --------------------------------------------------------------------------------------------- */
135 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
136 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
137 consequence is that function keys don't work in MC sometimes...
138 Unfortunately I don't now the one and only escape sequence to turn off.
139 softkeys (elm uses three different capabilities to turn on softkeys and two.
140 capabilities to turn them off)..
141 Among other things elm uses the pair we already use in slang_keypad. That's.
142 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
143 something better the softkeys are programmed to their defaults from the
144 termcap/terminfo database.
145 The escape sequence to program the softkeys is taken from elm and it is.
146 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
147 sequence. -- Norbert
150 static void
151 slang_reset_softkeys (void)
153 int key;
154 char *send;
155 static const char display[] = " ";
156 char tmp[BUF_SMALL];
158 for (key = 1; key < 9; key++)
160 g_snprintf (tmp, sizeof (tmp), "k%d", key);
161 send = (char *) SLtt_tgetstr (tmp);
162 if (send != NULL)
164 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
165 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
166 SLtt_write_string (tmp);
171 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
185 static void
186 load_terminfo_keys (void)
188 int i;
190 for (i = 0; key_table[i].key_code; i++)
191 do_define_key (key_table[i].key_code, key_table[i].key_name);
194 /* --------------------------------------------------------------------------------------------- */
195 /*** public functions ****************************************************************************/
196 /* --------------------------------------------------------------------------------------------- */
199 mc_tty_normalize_lines_char (const char *str)
201 char *str2;
202 int res;
204 struct mc_tty_lines_struct
206 const char *line;
207 int line_code;
208 } const lines_codes[] = {
209 {"\342\224\214", SLSMG_ULCORN_CHAR},
210 {"\342\224\220", SLSMG_URCORN_CHAR},
211 {"\342\224\224", SLSMG_LLCORN_CHAR},
212 {"\342\224\230", SLSMG_LRCORN_CHAR},
213 {"\342\224\234", SLSMG_LTEE_CHAR},
214 {"\342\224\244", SLSMG_RTEE_CHAR},
215 {"\342\224\254", SLSMG_UTEE_CHAR},
216 {"\342\224\264", SLSMG_DTEE_CHAR},
217 {"\342\224\200", SLSMG_HLINE_CHAR},
218 {"\342\224\202", SLSMG_VLINE_CHAR},
219 {"\342\224\274", SLSMG_PLUS_CHAR},
221 {NULL, 0}
224 if (!str)
225 return (int) ' ';
227 for (res = 0; lines_codes[res].line; res++)
229 if (strcmp (str, lines_codes[res].line) == 0)
230 return lines_codes[res].line_code;
233 str2 = mc_tty_normalize_from_utf8 (str);
234 res = g_utf8_get_char_validated (str2, -1);
236 if (res < 0)
237 res = (unsigned char) str2[0];
238 g_free (str2);
240 return res;
243 /* --------------------------------------------------------------------------------------------- */
245 void
246 tty_init (gboolean slow, gboolean ugly_lines)
248 slow_tty = slow;
249 ugly_line_drawing = ugly_lines;
251 SLtt_Ignore_Beep = 1;
253 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
254 SLtt_get_terminfo ();
256 * If the terminal in not in terminfo but begins with a well-known
257 * string such as "linux" or "xterm" S-Lang will go on, but the
258 * terminal size and several other variables won't be initialized
259 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
260 * small, large and negative screen dimensions.
262 if ((COLS < 10) || (LINES < 5)
263 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
265 fprintf (stderr,
266 _("Screen size %dx%d is not supported.\n"
267 "Check the TERM environment variable.\n"), COLS, LINES);
268 exit (EXIT_FAILURE);
271 tcgetattr (fileno (stdin), &boot_mode);
272 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
273 SLang_init_tty (XCTRL ('g'), 1, 0);
275 if (ugly_lines)
276 SLtt_Has_Alt_Charset = 0;
278 /* If SLang uses fileno(stderr) for terminal input MC will hang
279 if we call SLang_getkey between calls to open_error_pipe and
280 close_error_pipe, e.g. when we do a growing view of an gzipped
281 file. */
282 if (SLang_TT_Read_FD == fileno (stderr))
283 SLang_TT_Read_FD = fileno (stdin);
285 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
287 #ifdef VDSUSP
288 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
289 #endif
290 #ifdef VLNEXT
291 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
292 #endif
293 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
296 tty_reset_prog_mode ();
297 load_terminfo_keys ();
299 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
301 tty_start_interrupt_key ();
303 /* It's the small part from the previous init_key() */
304 init_key_input_fd ();
306 SLsmg_init_smg ();
307 do_enter_ca_mode ();
308 tty_keypad (TRUE);
309 tty_nodelay (FALSE);
312 /* --------------------------------------------------------------------------------------------- */
314 void
315 tty_shutdown (void)
317 char *op_cap;
319 SLsmg_reset_smg ();
320 tty_reset_shell_mode ();
321 do_exit_ca_mode ();
322 SLang_reset_tty ();
324 /* Load the op capability to reset the colors to those that were
325 * active when the program was started up
327 op_cap = SLtt_tgetstr ((char *) "op");
328 if (op_cap != NULL)
330 fputs (op_cap, stdout);
331 fflush (stdout);
335 /* --------------------------------------------------------------------------------------------- */
336 /* Done each time we come back from done mode */
338 void
339 tty_reset_prog_mode (void)
341 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
342 SLsmg_init_smg ();
343 SLsmg_touch_lines (0, LINES);
346 /* --------------------------------------------------------------------------------------------- */
347 /* Called each time we want to shutdown slang screen manager */
349 void
350 tty_reset_shell_mode (void)
352 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
355 /* --------------------------------------------------------------------------------------------- */
357 void
358 tty_raw_mode (void)
360 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
363 /* --------------------------------------------------------------------------------------------- */
365 void
366 tty_noraw_mode (void)
370 /* --------------------------------------------------------------------------------------------- */
372 void
373 tty_noecho (void)
377 /* --------------------------------------------------------------------------------------------- */
380 tty_flush_input (void)
382 return 0; /* OK */
385 /* --------------------------------------------------------------------------------------------- */
387 void
388 tty_keypad (gboolean set)
390 char *keypad_string;
392 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
393 if (keypad_string != NULL)
394 SLtt_write_string (keypad_string);
395 if (set && reset_hp_softkeys)
396 slang_reset_softkeys ();
399 /* --------------------------------------------------------------------------------------------- */
401 void
402 tty_nodelay (gboolean set)
404 no_slang_delay = set;
407 /* --------------------------------------------------------------------------------------------- */
410 tty_baudrate (void)
412 return SLang_TT_Baud_Rate;
415 /* --------------------------------------------------------------------------------------------- */
418 tty_lowlevel_getch (void)
420 int c;
422 if (no_slang_delay && (SLang_input_pending (0) == 0))
423 return -1;
425 c = SLang_getkey ();
426 if (c == SLANG_GETKEY_ERROR)
428 fprintf (stderr,
429 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
430 "Assuming EOF on stdin and exiting\n");
431 exit (EXIT_FAILURE);
434 return c;
437 /* --------------------------------------------------------------------------------------------- */
440 tty_reset_screen (void)
442 SLsmg_reset_smg ();
443 return 0; /* OK */
446 /* --------------------------------------------------------------------------------------------- */
448 void
449 tty_touch_screen (void)
451 SLsmg_touch_lines (0, LINES);
454 /* --------------------------------------------------------------------------------------------- */
456 void
457 tty_touch_lines (int start, int num)
459 SLsmg_touch_lines (start, num);
462 /* --------------------------------------------------------------------------------------------- */
464 void
465 tty_gotoyx (int y, int x)
467 SLsmg_gotorc (y, x);
470 /* --------------------------------------------------------------------------------------------- */
472 void
473 tty_getyx (int *py, int *px)
475 *py = SLsmg_get_row ();
476 *px = SLsmg_get_column ();
479 /* --------------------------------------------------------------------------------------------- */
480 /* if x < 0 or y < 0, draw line staring from current position */
482 void
483 tty_draw_hline (int y, int x, int ch, int len)
485 if (ch == ACS_HLINE)
486 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
488 if ((y < 0) || (x < 0))
490 y = SLsmg_get_row ();
491 x = SLsmg_get_column ();
493 else
494 SLsmg_gotorc (y, x);
496 if (ch == 0)
497 ch = ACS_HLINE;
499 if (ch == ACS_HLINE)
500 SLsmg_draw_hline (len);
501 else
502 while (len-- != 0)
503 tty_print_char (ch);
505 SLsmg_gotorc (y, x);
508 /* --------------------------------------------------------------------------------------------- */
509 /* if x < 0 or y < 0, draw line staring from current position */
511 void
512 tty_draw_vline (int y, int x, int ch, int len)
514 if (ch == ACS_VLINE)
515 ch = mc_tty_frm[MC_TTY_FRM_VERT];
517 if ((y < 0) || (x < 0))
519 y = SLsmg_get_row ();
520 x = SLsmg_get_column ();
522 else
523 SLsmg_gotorc (y, x);
525 if (ch == 0)
526 ch = ACS_VLINE;
528 if (ch == ACS_VLINE)
529 SLsmg_draw_vline (len);
530 else
532 int pos = 0;
534 while (len-- != 0)
536 SLsmg_gotorc (y + pos, x);
537 tty_print_char (ch);
538 pos++;
542 SLsmg_gotorc (y, x);
545 /* --------------------------------------------------------------------------------------------- */
547 void
548 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
550 SLsmg_fill_region (y, x, rows, cols, ch);
553 /* --------------------------------------------------------------------------------------------- */
555 void
556 tty_set_alt_charset (gboolean alt_charset)
558 SLsmg_set_char_set ((int) alt_charset);
561 /* --------------------------------------------------------------------------------------------- */
563 void
564 tty_display_8bit (gboolean what)
566 SLsmg_Display_Eight_Bit = what ? 128 : 160;
569 /* --------------------------------------------------------------------------------------------- */
571 void
572 tty_print_char (int c)
574 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
577 /* --------------------------------------------------------------------------------------------- */
579 void
580 tty_print_alt_char (int c, gboolean single)
582 #define DRAW(x, y) (x == y) \
583 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
584 : SLsmg_write_char ((unsigned int) y)
585 switch (c)
587 case ACS_VLINE:
588 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
589 break;
590 case ACS_HLINE:
591 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
592 break;
593 case ACS_LTEE:
594 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
595 break;
596 case ACS_RTEE:
597 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
598 break;
599 case ACS_ULCORNER:
600 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
601 break;
602 case ACS_LLCORNER:
603 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
604 break;
605 case ACS_URCORNER:
606 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
607 break;
608 case ACS_LRCORNER:
609 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
610 break;
611 case ACS_PLUS:
612 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
613 break;
614 default:
615 SLsmg_write_char ((unsigned int) c);
617 #undef DRAW
620 /* --------------------------------------------------------------------------------------------- */
622 void
623 tty_print_anychar (int c)
625 char str[6 + 1];
627 if (c > 255)
629 int res = g_unichar_to_utf8 (c, str);
630 if (res == 0)
632 str[0] = '.';
633 str[1] = '\0';
635 else
637 str[res] = '\0';
639 SLsmg_write_string ((char *) str_term_form (str));
641 else
643 if (!is_printable (c))
644 c = '.';
645 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
649 /* --------------------------------------------------------------------------------------------- */
651 void
652 tty_print_string (const char *s)
654 SLsmg_write_string ((char *) str_term_form (s));
657 /* --------------------------------------------------------------------------------------------- */
659 void
660 tty_printf (const char *fmt, ...)
662 va_list args;
664 va_start (args, fmt);
665 SLsmg_vprintf ((char *) fmt, args);
666 va_end (args);
669 /* --------------------------------------------------------------------------------------------- */
671 char *
672 tty_tgetstr (const char *cap)
674 return SLtt_tgetstr ((char *) cap);
677 /* --------------------------------------------------------------------------------------------- */
679 void
680 tty_refresh (void)
682 SLsmg_refresh ();
685 /* --------------------------------------------------------------------------------------------- */
687 void
688 tty_setup_sigwinch (void (*handler) (int))
690 #ifdef SIGWINCH
691 struct sigaction act, oact;
692 act.sa_handler = handler;
693 sigemptyset (&act.sa_mask);
694 act.sa_flags = 0;
695 #ifdef SA_RESTART
696 act.sa_flags |= SA_RESTART;
697 #endif /* SA_RESTART */
698 sigaction (SIGWINCH, &act, &oact);
699 #endif /* SIGWINCH */
702 /* --------------------------------------------------------------------------------------------- */
704 void
705 tty_beep (void)
707 SLtt_beep ();
710 /* --------------------------------------------------------------------------------------------- */