Ticket #2206: Add jump support to target line in some external editors
[midnight-commander.git] / lib / tty / tty-slang.c
blobc74db6093879512b7da59aaa6756bc77813cf58d
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 SA_RESTART
65 #define SA_RESTART 0
66 #endif
68 #ifndef SLTT_MAX_SCREEN_COLS
69 #define SLTT_MAX_SCREEN_COLS 512
70 #endif
72 #ifndef SLTT_MAX_SCREEN_ROWS
73 #define SLTT_MAX_SCREEN_ROWS 512
74 #endif
76 /*** file scope type declarations ****************************************************************/
78 /*** file scope variables ************************************************************************/
80 /* Various saved termios settings that we control here */
81 static struct termios boot_mode;
82 static struct termios new_mode;
84 /* Controls whether we should wait for input in tty_lowlevel_getch */
85 static gboolean no_slang_delay;
87 /* This table describes which capabilities we want and which values we
88 * assign to them.
90 static const struct
92 int key_code;
93 const char *key_name;
94 } key_table[] =
96 /* *INDENT-OFF* */
97 { KEY_F (0), "k0" },
98 { KEY_F (1), "k1" },
99 { KEY_F (2), "k2" },
100 { KEY_F (3), "k3" },
101 { KEY_F (4), "k4" },
102 { KEY_F (5), "k5" },
103 { KEY_F (6), "k6" },
104 { KEY_F (7), "k7" },
105 { KEY_F (8), "k8" },
106 { KEY_F (9), "k9" },
107 { KEY_F (10), "k;" },
108 { KEY_F (11), "F1" },
109 { KEY_F (12), "F2" },
110 { KEY_F (13), "F3" },
111 { KEY_F (14), "F4" },
112 { KEY_F (15), "F5" },
113 { KEY_F (16), "F6" },
114 { KEY_F (17), "F7" },
115 { KEY_F (18), "F8" },
116 { KEY_F (19), "F9" },
117 { KEY_F (20), "FA" },
118 { KEY_IC, "kI" },
119 { KEY_NPAGE, "kN" },
120 { KEY_PPAGE, "kP" },
121 { KEY_LEFT, "kl" },
122 { KEY_RIGHT, "kr" },
123 { KEY_UP, "ku" },
124 { KEY_DOWN, "kd" },
125 { KEY_DC, "kD" },
126 { KEY_BACKSPACE, "kb" },
127 { KEY_HOME, "kh" },
128 { KEY_END, "@7" },
129 { 0, NULL }
130 /* *INDENT-ON* */
133 /* --------------------------------------------------------------------------------------------- */
134 /*** file scope functions ************************************************************************/
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 tty_setup_sigwinch (void (*handler) (int))
140 (void) SLsignal (SIGWINCH, handler);
143 /* --------------------------------------------------------------------------------------------- */
145 static void
146 sigwinch_handler (int dummy)
148 (void) dummy;
150 mc_global.tty.winch_flag = 1;
151 (void) SLsignal (SIGWINCH, sigwinch_handler);
154 /* --------------------------------------------------------------------------------------------- */
156 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
157 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
158 consequence is that function keys don't work in MC sometimes...
159 Unfortunately I don't now the one and only escape sequence to turn off.
160 softkeys (elm uses three different capabilities to turn on softkeys and two.
161 capabilities to turn them off)..
162 Among other things elm uses the pair we already use in slang_keypad. That's.
163 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
164 something better the softkeys are programmed to their defaults from the
165 termcap/terminfo database.
166 The escape sequence to program the softkeys is taken from elm and it is.
167 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
168 sequence. -- Norbert
171 static void
172 slang_reset_softkeys (void)
174 int key;
175 char *send;
176 static const char display[] = " ";
177 char tmp[BUF_SMALL];
179 for (key = 1; key < 9; key++)
181 g_snprintf (tmp, sizeof (tmp), "k%d", key);
182 send = (char *) SLtt_tgetstr (tmp);
183 if (send != NULL)
185 g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
186 (int) (sizeof (display) - 1), (int) strlen (send), display, send);
187 SLtt_write_string (tmp);
192 /* --------------------------------------------------------------------------------------------- */
194 static void
195 do_define_key (int code, const char *strcap)
197 char *seq;
199 seq = (char *) SLtt_tgetstr ((char *) strcap);
200 if (seq != NULL)
201 define_sequence (code, seq, MCKEY_NOACTION);
204 /* --------------------------------------------------------------------------------------------- */
206 static void
207 load_terminfo_keys (void)
209 int i;
211 for (i = 0; key_table[i].key_code; i++)
212 do_define_key (key_table[i].key_code, key_table[i].key_name);
215 /* --------------------------------------------------------------------------------------------- */
216 /*** public functions ****************************************************************************/
217 /* --------------------------------------------------------------------------------------------- */
220 mc_tty_normalize_lines_char (const char *str)
222 char *str2;
223 int res;
225 struct mc_tty_lines_struct
227 const char *line;
228 int line_code;
229 } const lines_codes[] = {
230 {"\342\224\214", SLSMG_ULCORN_CHAR},
231 {"\342\224\220", SLSMG_URCORN_CHAR},
232 {"\342\224\224", SLSMG_LLCORN_CHAR},
233 {"\342\224\230", SLSMG_LRCORN_CHAR},
234 {"\342\224\234", SLSMG_LTEE_CHAR},
235 {"\342\224\244", SLSMG_RTEE_CHAR},
236 {"\342\224\254", SLSMG_UTEE_CHAR},
237 {"\342\224\264", SLSMG_DTEE_CHAR},
238 {"\342\224\200", SLSMG_HLINE_CHAR},
239 {"\342\224\202", SLSMG_VLINE_CHAR},
240 {"\342\224\274", SLSMG_PLUS_CHAR},
242 {NULL, 0}
245 if (!str)
246 return (int) ' ';
248 for (res = 0; lines_codes[res].line; res++)
250 if (strcmp (str, lines_codes[res].line) == 0)
251 return lines_codes[res].line_code;
254 str2 = mc_tty_normalize_from_utf8 (str);
255 res = g_utf8_get_char_validated (str2, -1);
257 if (res < 0)
258 res = (unsigned char) str2[0];
259 g_free (str2);
261 return res;
264 /* --------------------------------------------------------------------------------------------- */
266 void
267 tty_init (gboolean mouse_enable, gboolean is_xterm)
269 SLtt_Ignore_Beep = 1;
271 SLutf8_enable (-1); /* has to be called first before any of the other functions. */
272 SLtt_get_terminfo ();
274 * If the terminal in not in terminfo but begins with a well-known
275 * string such as "linux" or "xterm" S-Lang will go on, but the
276 * terminal size and several other variables won't be initialized
277 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
278 * small, large and negative screen dimensions.
280 if ((COLS < 10) || (LINES < 5)
281 || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
283 fprintf (stderr,
284 _("Screen size %dx%d is not supported.\n"
285 "Check the TERM environment variable.\n"), COLS, LINES);
286 exit (EXIT_FAILURE);
289 tcgetattr (fileno (stdin), &boot_mode);
290 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
291 SLang_init_tty (XCTRL ('g'), 1, 0);
293 if (mc_global.tty.ugly_line_drawing)
294 SLtt_Has_Alt_Charset = 0;
296 /* If SLang uses fileno(stderr) for terminal input MC will hang
297 if we call SLang_getkey between calls to open_error_pipe and
298 close_error_pipe, e.g. when we do a growing view of an gzipped
299 file. */
300 if (SLang_TT_Read_FD == fileno (stderr))
301 SLang_TT_Read_FD = fileno (stdin);
303 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
305 #ifdef VDSUSP
306 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
307 #endif
308 #ifdef VLNEXT
309 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
310 #endif
311 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
314 tty_reset_prog_mode ();
315 load_terminfo_keys ();
317 SLtt_Blink_Mode = tty_use_256colors ()? 1 : 0;
319 tty_start_interrupt_key ();
321 /* It's the small part from the previous init_key() */
322 init_key_input_fd ();
324 /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
325 * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
326 * detected - but checking TERM would fail under screen, OR running xterm
327 * with allowC1Printable).
329 tty_display_8bit (FALSE);
331 SLsmg_init_smg ();
332 if (!mouse_enable)
333 use_mouse_p = MOUSE_DISABLED;
334 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
335 do_enter_ca_mode ();
336 tty_keypad (TRUE);
337 tty_nodelay (FALSE);
339 tty_setup_sigwinch (sigwinch_handler);
342 /* --------------------------------------------------------------------------------------------- */
344 void
345 tty_shutdown (void)
347 char *op_cap;
349 disable_mouse ();
350 tty_reset_shell_mode ();
351 tty_noraw_mode ();
352 tty_keypad (FALSE);
353 tty_reset_screen ();
354 do_exit_ca_mode ();
355 SLang_reset_tty ();
357 /* Load the op capability to reset the colors to those that were
358 * active when the program was started up
360 op_cap = SLtt_tgetstr ((char *) "op");
361 if (op_cap != NULL)
363 fputs (op_cap, stdout);
364 fflush (stdout);
368 /* --------------------------------------------------------------------------------------------- */
370 void
371 tty_change_screen_size (void)
373 SLtt_get_screen_size ();
374 SLsmg_reinit_smg ();
376 #ifdef ENABLE_SUBSHELL
377 if (mc_global.tty.use_subshell)
378 tty_resize (mc_global.tty.subshell_pty);
379 #endif
382 /* --------------------------------------------------------------------------------------------- */
383 /* Done each time we come back from done mode */
385 void
386 tty_reset_prog_mode (void)
388 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
389 SLsmg_init_smg ();
390 SLsmg_touch_lines (0, LINES);
393 /* --------------------------------------------------------------------------------------------- */
394 /* Called each time we want to shutdown slang screen manager */
396 void
397 tty_reset_shell_mode (void)
399 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
402 /* --------------------------------------------------------------------------------------------- */
404 void
405 tty_raw_mode (void)
407 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
410 /* --------------------------------------------------------------------------------------------- */
412 void
413 tty_noraw_mode (void)
417 /* --------------------------------------------------------------------------------------------- */
419 void
420 tty_noecho (void)
424 /* --------------------------------------------------------------------------------------------- */
427 tty_flush_input (void)
429 return 0; /* OK */
432 /* --------------------------------------------------------------------------------------------- */
434 void
435 tty_keypad (gboolean set)
437 char *keypad_string;
439 keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
440 if (keypad_string != NULL)
441 SLtt_write_string (keypad_string);
442 if (set && reset_hp_softkeys)
443 slang_reset_softkeys ();
446 /* --------------------------------------------------------------------------------------------- */
448 void
449 tty_nodelay (gboolean set)
451 no_slang_delay = set;
454 /* --------------------------------------------------------------------------------------------- */
457 tty_baudrate (void)
459 return SLang_TT_Baud_Rate;
462 /* --------------------------------------------------------------------------------------------- */
465 tty_lowlevel_getch (void)
467 int c;
469 if (no_slang_delay && (SLang_input_pending (0) == 0))
470 return -1;
472 c = SLang_getkey ();
473 if (c == SLANG_GETKEY_ERROR)
475 fprintf (stderr,
476 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
477 "Assuming EOF on stdin and exiting\n");
478 exit (EXIT_FAILURE);
481 return c;
484 /* --------------------------------------------------------------------------------------------- */
487 tty_reset_screen (void)
489 SLsmg_reset_smg ();
490 return 0; /* OK */
493 /* --------------------------------------------------------------------------------------------- */
495 void
496 tty_touch_screen (void)
498 SLsmg_touch_lines (0, LINES);
501 /* --------------------------------------------------------------------------------------------- */
503 void
504 tty_gotoyx (int y, int x)
506 SLsmg_gotorc (y, x);
509 /* --------------------------------------------------------------------------------------------- */
511 void
512 tty_getyx (int *py, int *px)
514 *py = SLsmg_get_row ();
515 *px = SLsmg_get_column ();
518 /* --------------------------------------------------------------------------------------------- */
520 void
521 tty_draw_hline (int y, int x, int ch, int len)
523 int x1;
525 if (y < 0 || y >= LINES || x >= COLS)
526 return;
528 x1 = x;
530 if (x < 0)
532 len += x;
533 if (len <= 0)
534 return;
535 x = 0;
538 if (ch == ACS_HLINE)
539 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
540 if (ch == 0)
541 ch = ACS_HLINE;
543 SLsmg_gotorc (y, x);
545 if (ch == ACS_HLINE)
546 SLsmg_draw_hline (len);
547 else
548 while (len-- != 0)
549 tty_print_char (ch);
551 SLsmg_gotorc (y, x1);
554 /* --------------------------------------------------------------------------------------------- */
556 void
557 tty_draw_vline (int y, int x, int ch, int len)
559 int y1;
561 if (x < 0 || x >= COLS || y >= LINES)
562 return;
564 y1 = y;
566 if (y < 0)
568 len += y;
569 if (len <= 0)
570 return;
571 y = 0;
574 if (ch == ACS_VLINE)
575 ch = mc_tty_frm[MC_TTY_FRM_VERT];
576 if (ch == 0)
577 ch = ACS_VLINE;
579 SLsmg_gotorc (y, x);
581 if (ch == ACS_VLINE)
582 SLsmg_draw_vline (len);
583 else
585 int pos = 0;
587 while (len-- != 0)
589 SLsmg_gotorc (y + pos, x);
590 tty_print_char (ch);
591 pos++;
595 SLsmg_gotorc (y1, x);
598 /* --------------------------------------------------------------------------------------------- */
600 void
601 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
603 SLsmg_fill_region (y, x, rows, cols, ch);
606 /* --------------------------------------------------------------------------------------------- */
608 void
609 tty_set_alt_charset (gboolean alt_charset)
611 SLsmg_set_char_set ((int) alt_charset);
614 /* --------------------------------------------------------------------------------------------- */
616 void
617 tty_display_8bit (gboolean what)
619 SLsmg_Display_Eight_Bit = what ? 128 : 160;
622 /* --------------------------------------------------------------------------------------------- */
624 void
625 tty_print_char (int c)
627 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
630 /* --------------------------------------------------------------------------------------------- */
632 void
633 tty_print_alt_char (int c, gboolean single)
635 #define DRAW(x, y) (x == y) \
636 ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
637 : SLsmg_write_char ((unsigned int) y)
638 switch (c)
640 case ACS_VLINE:
641 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
642 break;
643 case ACS_HLINE:
644 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
645 break;
646 case ACS_LTEE:
647 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
648 break;
649 case ACS_RTEE:
650 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
651 break;
652 case ACS_ULCORNER:
653 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
654 break;
655 case ACS_LLCORNER:
656 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
657 break;
658 case ACS_URCORNER:
659 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
660 break;
661 case ACS_LRCORNER:
662 DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
663 break;
664 case ACS_PLUS:
665 DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
666 break;
667 default:
668 SLsmg_write_char ((unsigned int) c);
670 #undef DRAW
673 /* --------------------------------------------------------------------------------------------- */
675 void
676 tty_print_anychar (int c)
678 char str[6 + 1];
680 if (c > 255)
682 int res = g_unichar_to_utf8 (c, str);
683 if (res == 0)
685 str[0] = '.';
686 str[1] = '\0';
688 else
690 str[res] = '\0';
692 SLsmg_write_string ((char *) str_term_form (str));
694 else
696 if (!is_printable (c))
697 c = '.';
698 SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
702 /* --------------------------------------------------------------------------------------------- */
704 void
705 tty_print_string (const char *s)
707 SLsmg_write_string ((char *) str_term_form (s));
710 /* --------------------------------------------------------------------------------------------- */
712 void
713 tty_printf (const char *fmt, ...)
715 va_list args;
717 va_start (args, fmt);
718 SLsmg_vprintf ((char *) fmt, args);
719 va_end (args);
722 /* --------------------------------------------------------------------------------------------- */
724 char *
725 tty_tgetstr (const char *cap)
727 return SLtt_tgetstr ((char *) cap);
730 /* --------------------------------------------------------------------------------------------- */
732 void
733 tty_refresh (void)
735 SLsmg_refresh ();
738 /* --------------------------------------------------------------------------------------------- */
740 void
741 tty_beep (void)
743 SLtt_beep ();
746 /* --------------------------------------------------------------------------------------------- */