Merge branch '132_search_skip_hidden'
[midnight-commander.git] / src / slint.c
blob5945b428eadc230dc6960ea2c39544971ed3fed3
1 /* Slang interface to the Midnight Commander
2 This emulates some features of ncurses on top of slang
4 Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2007 Free Software Foundation, Inc.
7 Author Miguel de Icaza
8 Norbert Warmuth
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include <config.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #ifdef HAVE_TERMIOS_H
32 #include <termios.h>
33 #endif
34 #include <unistd.h>
36 #include "global.h"
37 #include "tty.h"
38 #include "color.h"
39 #include "mouse.h" /* Gpm_Event is required in key.h */
40 #include "key.h" /* define_sequence */
41 #include "main.h" /* extern: force_colors */
42 #include "win.h" /* do_exit_ca_mode */
43 #include "setup.h"
44 #include "background.h" /* we_are_background */
46 #ifdef HAVE_SLANG
48 /* Taken from S-Lang's slutty.c */
49 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
50 # define NULL_VALUE -1
51 #else
52 # ifdef _POSIX_VDISABLE
53 # define NULL_VALUE _POSIX_VDISABLE
54 # else
55 # define NULL_VALUE 255
56 # endif
57 #endif
59 #ifndef SA_RESTART
60 # define SA_RESTART 0
61 #endif
63 /* Various saved termios settings that we control here */
64 static struct termios boot_mode;
65 static struct termios new_mode;
67 /* Controls whether we should wait for input in getch */
68 static int no_slang_delay;
70 /* Forward declarations */
71 static void load_terminfo_keys (void);
73 #ifndef HAVE_SLANG_PRIVATE
74 /* Private interfaces have been stripped, so we cannot use them */
75 #define SLang_getkey2() SLang_getkey()
76 #define SLang_input_pending2(s) SLang_input_pending(s)
77 #else
78 /* Copied from ../slang/slgetkey.c, removed the DEC_8Bit_HACK. */
79 extern unsigned char SLang_Input_Buffer [];
80 #if SLANG_VERSION >= 10000
81 extern unsigned int _SLsys_getkey (void);
82 extern int _SLsys_input_pending (int);
83 #else
84 extern unsigned int SLsys_getkey (void);
85 extern int SLsys_input_pending (int);
86 #endif
88 static unsigned int SLang_getkey2 (void)
90 unsigned int imax;
91 unsigned int ch;
93 if (SLang_Input_Buffer_Len)
95 ch = (unsigned int) *SLang_Input_Buffer;
96 SLang_Input_Buffer_Len--;
97 imax = SLang_Input_Buffer_Len;
99 memmove ((char *) SLang_Input_Buffer,
100 (char *) (SLang_Input_Buffer + 1), imax);
101 return(ch);
103 #if SLANG_VERSION >= 10000
104 else return(_SLsys_getkey ());
105 #else
106 else return(SLsys_getkey());
107 #endif
110 static int SLang_input_pending2 (int tsecs)
112 int n, i;
113 unsigned char c;
115 if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
116 #if SLANG_VERSION >= 10000
117 n = _SLsys_input_pending (tsecs);
118 #else
119 n = SLsys_input_pending (tsecs);
120 #endif
121 if (n <= 0) return 0;
123 i = SLang_getkey2 ();
124 if (i == SLANG_GETKEY_ERROR)
125 return 0; /* don't put crippled error codes into the input buffer */
126 c = (unsigned char)i;
127 SLang_ungetkey_string (&c, 1);
129 return n;
131 #endif /* HAVE_SLANG_PRIVATE */
133 /* Only done the first time */
134 void
135 slang_init (void)
137 SLtt_get_terminfo ();
140 * If the terminal in not in terminfo but begins with a well-known
141 * string such as "linux" or "xterm" S-Lang will go on, but the
142 * terminal size and several other variables won't be initialized
143 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
144 * small, large and negative screen dimensions.
146 if ((COLS < 10) || (LINES < 5) ||
147 (SLang_Version < 10407 && (COLS > 255 || LINES > 255)) ||
148 (SLang_Version >= 10407 && (COLS > 512 || LINES > 512))) {
150 fprintf (stderr,
151 _("Screen size %dx%d is not supported.\n"
152 "Check the TERM environment variable.\n"),
153 COLS, LINES);
154 exit (1);
157 tcgetattr (fileno (stdin), &boot_mode);
158 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
159 SLang_init_tty (XCTRL('c'), 1, 0);
161 /* If SLang uses fileno(stderr) for terminal input MC will hang
162 if we call SLang_getkey between calls to open_error_pipe and
163 close_error_pipe, e.g. when we do a growing view of an gzipped
164 file. */
165 if (SLang_TT_Read_FD == fileno (stderr))
166 SLang_TT_Read_FD = fileno (stdin);
168 if (force_ugly_line_drawing)
169 SLtt_Has_Alt_Charset = 0;
170 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
171 #ifdef VDSUSP
172 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
173 #endif
174 #ifdef VLNEXT
175 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
176 #endif
177 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
179 slang_prog_mode ();
180 load_terminfo_keys ();
181 SLtt_Blink_Mode = 0;
184 void
185 slang_set_raw_mode (void)
187 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
190 /* Done each time we come back from done mode */
191 void
192 slang_prog_mode (void)
194 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
195 SLsmg_init_smg ();
196 SLsmg_touch_lines (0, LINES);
199 /* Called each time we want to shutdown slang screen manager */
200 void
201 slang_shell_mode (void)
203 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
206 void
207 slang_shutdown (void)
209 char *op_cap;
211 slang_shell_mode ();
212 do_exit_ca_mode ();
213 SLang_reset_tty ();
215 /* Load the op capability to reset the colors to those that were
216 * active when the program was started up
218 op_cap = SLtt_tgetstr ("op");
219 if (op_cap){
220 fprintf (stdout, "%s", op_cap);
221 fflush (stdout);
225 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
226 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
227 consequence is that function keys don't work in MC sometimes.
228 Unfortunately I don't now the one and only escape sequence to turn off
229 softkeys (elm uses three different capabilities to turn on softkeys and two
230 capabilities to turn them off).
231 Among other things elm uses the pair we already use in slang_keypad. That's
232 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
233 something better the softkeys are programmed to their defaults from the
234 termcap/terminfo database.
235 The escape sequence to program the softkeys is taken from elm and it is
236 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this
237 sequence. -- Norbert
240 static void
241 slang_reset_softkeys (void)
243 int key;
244 char *send;
245 static const char display[] = " ";
246 char tmp[BUF_SMALL];
248 for (key = 1; key < 9; key++) {
249 g_snprintf (tmp, sizeof (tmp), "k%d", key);
250 send = (char *) SLtt_tgetstr (tmp);
251 if (send) {
252 g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
253 (int) (sizeof (display) - 1), (int) strlen (send),
254 display, send);
255 SLtt_write_string (tmp);
260 /* keypad routines */
261 void
262 slang_keypad (int set)
264 char *keypad_string;
265 extern int reset_hp_softkeys;
267 keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
268 if (keypad_string)
269 SLtt_write_string (keypad_string);
270 if (set && reset_hp_softkeys)
271 slang_reset_softkeys ();
274 void
275 set_slang_delay (int v)
277 no_slang_delay = v;
280 void
281 hline (int ch, int len)
283 int last_x, last_y;
285 last_x = SLsmg_get_column ();
286 last_y = SLsmg_get_row ();
288 if (ch == 0)
289 ch = ACS_HLINE;
291 if (ch == ACS_HLINE){
292 SLsmg_draw_hline (len);
293 } else {
294 while (len--)
295 addch (ch);
297 move (last_y, last_x);
300 void
301 vline (int character, int len)
303 if (!slow_terminal){
304 SLsmg_draw_vline (len);
305 } else {
306 int last_x, last_y, pos = 0;
308 last_x = SLsmg_get_column ();
309 last_y = SLsmg_get_row ();
311 while (len--){
312 move (last_y + pos++, last_x);
313 addch (' ');
315 move (last_x, last_y);
319 int has_colors (void)
321 const char *terminal = getenv ("TERM");
322 char *cts = color_terminal_string, *s;
323 size_t i;
325 if (force_colors)
326 SLtt_Use_Ansi_Colors = 1;
327 if (NULL != getenv ("COLORTERM"))
328 SLtt_Use_Ansi_Colors = 1;
330 /* We want to allow overwriding */
331 if (!disable_colors){
332 /* check color_terminal_string */
333 if (*cts)
335 while (*cts)
337 while (*cts == ' ' || *cts == '\t') cts++;
339 s = cts;
340 i = 0;
342 while (*cts && *cts != ',')
344 cts++;
345 i++;
347 if (i && i == strlen(terminal) && strncmp(s, terminal, i) == 0)
348 SLtt_Use_Ansi_Colors = 1;
350 if (*cts == ',') cts++;
355 /* Setup emulated colors */
356 if (SLtt_Use_Ansi_Colors){
357 if (use_colors){
358 mc_init_pair (A_REVERSE, "black", "white");
359 mc_init_pair (A_BOLD, "white", "black");
360 } else {
361 mc_init_pair (A_REVERSE, "black", "lightgray");
362 mc_init_pair (A_BOLD, "white", "black");
363 mc_init_pair (A_BOLD_REVERSE, "white", "lightgray");
365 } else {
366 SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
367 SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
368 SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
370 return SLtt_Use_Ansi_Colors;
373 void
374 attrset (int color)
376 if (!SLtt_Use_Ansi_Colors){
377 SLsmg_set_color (color);
378 return;
381 if (color & A_BOLD){
382 if (color == A_BOLD)
383 SLsmg_set_color (A_BOLD);
384 else
385 SLsmg_set_color ((color & (~A_BOLD)) + 8);
386 return;
389 if (color == A_REVERSE)
390 SLsmg_set_color (A_REVERSE);
391 else
392 SLsmg_set_color (color);
395 /* This table describes which capabilities we want and which values we
396 * assign to them.
398 static const struct {
399 int key_code;
400 const char *key_name;
401 } key_table [] = {
402 { KEY_F(0), "k0" },
403 { KEY_F(1), "k1" },
404 { KEY_F(2), "k2" },
405 { KEY_F(3), "k3" },
406 { KEY_F(4), "k4" },
407 { KEY_F(5), "k5" },
408 { KEY_F(6), "k6" },
409 { KEY_F(7), "k7" },
410 { KEY_F(8), "k8" },
411 { KEY_F(9), "k9" },
412 { KEY_F(10), "k;" },
413 { KEY_F(11), "F1" },
414 { KEY_F(12), "F2" },
415 { KEY_F(13), "F3" },
416 { KEY_F(14), "F4" },
417 { KEY_F(15), "F5" },
418 { KEY_F(16), "F6" },
419 { KEY_F(17), "F7" },
420 { KEY_F(18), "F8" },
421 { KEY_F(19), "F9" },
422 { KEY_F(20), "FA" },
423 { KEY_IC, "kI" },
424 { KEY_NPAGE, "kN" },
425 { KEY_PPAGE, "kP" },
426 { KEY_LEFT, "kl" },
427 { KEY_RIGHT, "kr" },
428 { KEY_UP, "ku" },
429 { KEY_DOWN, "kd" },
430 { KEY_DC, "kD" },
431 { KEY_BACKSPACE, "kb" },
432 { KEY_HOME, "kh" },
433 { KEY_END, "@7" },
434 { 0, 0}
437 static void
438 do_define_key (int code, const char *strcap)
440 char *seq;
442 seq = (char *) SLtt_tgetstr ((char*) strcap);
443 if (seq)
444 define_sequence (code, seq, MCKEY_NOACTION);
447 static void
448 load_terminfo_keys (void)
450 int i;
452 for (i = 0; key_table [i].key_code; i++)
453 do_define_key (key_table [i].key_code, key_table [i].key_name);
457 getch (void)
459 int c;
460 if (no_slang_delay)
461 if (SLang_input_pending2 (0) == 0)
462 return -1;
464 c = SLang_getkey2 ();
465 if (c == SLANG_GETKEY_ERROR) {
466 fprintf (stderr,
467 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
468 "Assuming EOF on stdin and exiting\n");
469 exit (1);
471 return c;
473 #endif /* HAVE_SLANG */
475 void
476 mc_refresh (void)
478 #ifdef WITH_BACKGROUND
479 if (!we_are_background)
480 #endif /* WITH_BACKGROUND */
481 refresh ();