Last fuzzy updated...
[midnight-commander.git] / src / slint.c
blob12b5a37f8bc12129563a76b4448e435f74128dbd
1 /* Slang interface to the Midnight Commander
2 This emulates some features of ncurses on top of slang
4 Copyright (C) 1995, 1996 The Free Software Foundation.
6 Author Miguel de Icaza
7 Norbert Warmuth
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <termios.h>
27 #include <signal.h>
28 #include <string.h>
30 #include "global.h"
31 #include "tty.h"
32 #include "color.h"
33 #include "mouse.h" /* Gpm_Event is required in key.h */
34 #include "key.h" /* define_sequence */
35 #include "main.h" /* extern: force_colors */
36 #include "win.h" /* do_exit_ca_mode */
37 #include "setup.h"
39 #ifdef HAVE_SLANG
41 /* Taken from S-Lang's slutty.c */
42 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
43 # define NULL_VALUE -1
44 #else
45 # ifdef _POSIX_VDISABLE
46 # define NULL_VALUE _POSIX_VDISABLE
47 # else
48 # define NULL_VALUE 255
49 # endif
50 #endif
52 /* Taken from S-Lang's sldisply.c file */
53 #ifndef USE_TERMCAP
54 # define tgetstr(a,b) SLtt_tgetstr (a)
55 #else
56 extern char *tgetstr(char *, char **);
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 /* Set if we get an interrupt */
68 static int slinterrupt;
70 /* Controls whether we should wait for input in getch */
71 static int no_slang_delay;
73 /* {{{ Copied from ../slang/slgetkey.c, removed the DEC_8Bit_HACK, */
74 extern unsigned char SLang_Input_Buffer [];
75 #if SLANG_VERSION >= 10000
76 extern unsigned int _SLsys_getkey (void);
77 extern int _SLsys_input_pending (int);
78 #else
79 extern unsigned int SLsys_getkey (void);
80 extern int SLsys_input_pending (int);
81 #endif
83 /* Forward declarations */
84 static void load_terminfo_keys (void);
86 static unsigned int SLang_getkey2 (void)
88 unsigned int imax;
89 unsigned int ch;
91 if (SLang_Input_Buffer_Len)
93 ch = (unsigned int) *SLang_Input_Buffer;
94 SLang_Input_Buffer_Len--;
95 imax = SLang_Input_Buffer_Len;
97 memcpy ((char *) SLang_Input_Buffer,
98 (char *) (SLang_Input_Buffer + 1), imax);
99 return(ch);
101 #if SLANG_VERSION >= 10000
102 else return(_SLsys_getkey ());
103 #else
104 else return(SLsys_getkey());
105 #endif
108 static int SLang_input_pending2 (int tsecs)
110 int n, i;
111 unsigned char c;
113 if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
114 #if SLANG_VERSION >= 10000
115 n = _SLsys_input_pending (tsecs);
116 #else
117 n = SLsys_input_pending (tsecs);
118 #endif
119 if (n <= 0) return 0;
121 i = SLang_getkey2 ();
122 if (i == SLANG_GETKEY_ERROR)
123 return 0; /* don't put crippled error codes into the input buffer */
124 c = (unsigned char)i;
125 SLang_ungetkey_string (&c, 1);
127 return n;
129 /* }}} */
131 static void
132 slang_intr (int signo)
134 slinterrupt = 1;
137 void
138 enable_interrupt_key(void)
140 struct sigaction act;
142 act.sa_handler = slang_intr;
143 sigemptyset (&act.sa_mask);
144 act.sa_flags = 0;
145 sigaction (SIGINT, &act, NULL);
146 slinterrupt = 0;
149 void
150 disable_interrupt_key(void)
152 struct sigaction act;
154 act.sa_handler = SIG_IGN;
155 act.sa_flags = 0;
156 sigemptyset (&act.sa_mask);
157 sigaction (SIGINT, &act, NULL);
161 got_interrupt (void)
163 int t;
165 t = slinterrupt;
166 slinterrupt = 0;
167 return t;
170 /* Only done the first time */
171 void
172 slang_init (void)
174 struct sigaction act, oact;
176 SLtt_get_terminfo ();
179 * If the terminal in not in terminfo but begins with a well-known
180 * string such as "linux" or "xterm" S-Lang will go on, but the
181 * terminal size and several other variables won't be initialized
182 * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
183 * small, large and negative screen dimensions.
185 if ((COLS < 10) || (LINES < 5) || (COLS > 1024) || (LINES > 1024)) {
186 fprintf (stderr,
187 _("Screen size %dx%d is not supported.\n"
188 "Check the TERM environment variable.\n"),
189 COLS, LINES);
190 exit (1);
193 tcgetattr (fileno (stdin), &boot_mode);
194 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
195 SLang_init_tty (XCTRL('c'), 1, 0);
197 /* If SLang uses fileno(stderr) for terminal input MC will hang
198 if we call SLang_getkey between calls to open_error_pipe and
199 close_error_pipe, e.g. when we do a growing view of an gzipped
200 file. */
201 if (SLang_TT_Read_FD == fileno (stderr))
202 SLang_TT_Read_FD = fileno (stdin);
204 if (force_ugly_line_drawing)
205 SLtt_Has_Alt_Charset = 0;
206 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
207 #ifdef VDSUSP
208 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
209 #endif
210 #ifdef VLNEXT
211 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
212 #endif
213 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
215 slang_prog_mode ();
216 load_terminfo_keys ();
217 act.sa_handler = slang_intr;
218 sigemptyset (&act.sa_mask);
219 act.sa_flags = SA_RESTART;
220 sigaction (SIGINT, &act, &oact);
221 SLtt_Blink_Mode = 0;
224 void
225 slang_set_raw_mode (void)
227 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
230 /* Done each time we come back from done mode */
231 void
232 slang_prog_mode (void)
234 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
235 SLsmg_init_smg ();
236 SLsmg_touch_lines (0, LINES);
239 /* Called each time we want to shutdown slang screen manager */
240 void
241 slang_shell_mode (void)
243 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
246 void
247 slang_shutdown (void)
249 char *op_cap;
251 slang_shell_mode ();
252 do_exit_ca_mode ();
253 SLang_reset_tty ();
254 dealloc_color_pairs ();
256 /* Load the op capability to reset the colors to those that were
257 * active when the program was started up
259 op_cap = SLtt_tgetstr ("op");
260 if (op_cap){
261 fprintf (stdout, "%s", op_cap);
262 fflush (stdout);
266 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
267 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
268 consequence is that function keys don't work in MC sometimes.
269 Unfortunately I don't now the one and only escape sequence to turn off
270 softkeys (elm uses three different capabilities to turn on softkeys and two
271 capabilities to turn them off).
272 Among other things elm uses the pair we already use in slang_keypad. That's
273 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
274 something better the softkeys are programmed to their defaults from the
275 termcap/terminfo database.
276 The escape sequence to program the softkeys is taken from elm and it is
277 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this
278 sequence. -- Norbert
281 static void
282 slang_reset_softkeys (void)
284 int key;
285 char *send;
286 static const char display [] = " ";
287 char tmp[BUF_SMALL];
289 for ( key = 1; key < 9; key++ ) {
290 g_snprintf (tmp, sizeof (tmp), "k%d", key);
291 send = (char *) SLtt_tgetstr (tmp);
292 if (send) {
293 g_snprintf(tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
294 sizeof (display) - 1, strlen(send), display, send);
295 SLtt_write_string (tmp);
300 /* keypad routines */
301 void
302 slang_keypad (int set)
304 char *keypad_string;
305 extern int reset_hp_softkeys;
307 keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
308 if (keypad_string)
309 SLtt_write_string (keypad_string);
310 if (set && reset_hp_softkeys)
311 slang_reset_softkeys ();
314 void
315 set_slang_delay (int v)
317 no_slang_delay = v;
320 void
321 hline (int ch, int len)
323 int last_x, last_y;
325 last_x = SLsmg_get_column ();
326 last_y = SLsmg_get_row ();
328 if (ch == 0)
329 ch = ACS_HLINE;
331 if (ch == ACS_HLINE){
332 SLsmg_draw_hline (len);
333 } else {
334 while (len--)
335 addch (ch);
337 move (last_y, last_x);
340 void
341 vline (int character, int len)
343 if (!slow_terminal){
344 SLsmg_draw_vline (len);
345 } else {
346 int last_x, last_y, pos = 0;
348 last_x = SLsmg_get_column ();
349 last_y = SLsmg_get_row ();
351 while (len--){
352 move (last_y + pos++, last_x);
353 addch (' ');
355 move (last_x, last_y);
359 int has_colors (void)
361 char *terminal = getenv ("TERM");
362 char *cts = color_terminal_string, *s;
363 int i;
365 if (force_colors)
366 SLtt_Use_Ansi_Colors = 1;
367 if (NULL != getenv ("COLORTERM"))
368 SLtt_Use_Ansi_Colors = 1;
370 /* We want to allow overwriding */
371 if (!disable_colors){
372 /* check color_terminal_string */
373 if (*cts)
375 while (*cts)
377 while (*cts == ' ' || *cts == '\t') cts++;
379 s = cts;
380 i = 0;
382 while (*cts && *cts != ',')
384 cts++;
385 i++;
387 if (i && i == strlen(terminal) && strncmp(s, terminal, i) == 0)
388 SLtt_Use_Ansi_Colors = 1;
390 if (*cts == ',') cts++;
395 /* Setup emulated colors */
396 if (SLtt_Use_Ansi_Colors){
397 if (use_colors){
398 mc_init_pair (A_REVERSE, "black", "white");
399 mc_init_pair (A_BOLD, "white", "black");
400 } else {
401 mc_init_pair (A_REVERSE, "black", "lightgray");
402 mc_init_pair (A_BOLD, "white", "black");
403 mc_init_pair (A_BOLD_REVERSE, "white", "lightgray");
405 } else {
406 SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
407 SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
408 SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
410 return SLtt_Use_Ansi_Colors;
413 void
414 attrset (int color)
416 if (!SLtt_Use_Ansi_Colors){
417 SLsmg_set_color (color);
418 return;
421 if (color & A_BOLD){
422 if (color == A_BOLD)
423 SLsmg_set_color (A_BOLD);
424 else
425 SLsmg_set_color ((color & (~A_BOLD)) + 8);
426 return;
429 if (color == A_REVERSE)
430 SLsmg_set_color (A_REVERSE);
431 else
432 SLsmg_set_color (color);
435 /* This table describes which capabilities we want and which values we
436 * assign to them.
438 static const struct {
439 int key_code;
440 char *key_name;
441 } key_table [] = {
442 { KEY_F(0), "k0" },
443 { KEY_F(1), "k1" },
444 { KEY_F(2), "k2" },
445 { KEY_F(3), "k3" },
446 { KEY_F(4), "k4" },
447 { KEY_F(5), "k5" },
448 { KEY_F(6), "k6" },
449 { KEY_F(7), "k7" },
450 { KEY_F(8), "k8" },
451 { KEY_F(9), "k9" },
452 { KEY_F(10), "k;" },
453 { KEY_F(11), "F1" },
454 { KEY_F(12), "F2" },
455 { KEY_F(13), "F3" },
456 { KEY_F(14), "F4" },
457 { KEY_F(15), "F5" },
458 { KEY_F(16), "F6" },
459 { KEY_F(17), "F7" },
460 { KEY_F(18), "F8" },
461 { KEY_F(19), "F9" },
462 { KEY_F(20), "FA" },
463 { KEY_IC, "kI" },
464 { KEY_NPAGE, "kN" },
465 { KEY_PPAGE, "kP" },
466 { KEY_LEFT, "kl" },
467 { KEY_RIGHT, "kr" },
468 { KEY_UP, "ku" },
469 { KEY_DOWN, "kd" },
470 { KEY_DC, "kD" },
471 { KEY_BACKSPACE, "kb" },
472 { KEY_HOME, "kh" },
473 { KEY_END, "@7" },
474 { 0, 0}
477 static void
478 do_define_key (int code, char *strcap)
480 char *seq;
482 seq = (char *) SLtt_tgetstr (strcap);
483 if (seq)
484 define_sequence (code, seq, MCKEY_NOACTION);
487 static void
488 load_terminfo_keys (void)
490 int i;
492 for (i = 0; key_table [i].key_code; i++)
493 do_define_key (key_table [i].key_code, key_table [i].key_name);
497 getch (void)
499 int c;
500 if (no_slang_delay)
501 if (SLang_input_pending2 (0) == 0)
502 return -1;
504 c = SLang_getkey2 ();
505 if (c == SLANG_GETKEY_ERROR) {
506 fprintf (stderr,
507 "SLang_getkey returned SLANG_GETKEY_ERROR\n"
508 "Assuming EOF on stdin and exiting\n");
509 quiet_quit_cmd ();
510 return -1;
512 return c;
515 #else
517 /* Non slang builds do not understand got_interrupt */
518 int got_interrupt (void)
520 return 0;
522 #endif /* HAVE_SLANG */
524 void
525 mc_refresh (void)
527 if (!we_are_background)
528 refresh ();