Fix umpnpmgr build
[reactos.git] / rosapps / mc / src / slint.c
1 /* Slang interface to the Midnight Commander
2 This emulates some features of ncurses on top of slang
3
4 Copyright (C) 1995, 1996 The Free Software Foundation.
5
6 Author Miguel de Icaza
7 Norbert Warmuth
8
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.
13
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.
18
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., 675 Mass Ave, Cambridge, MA 02139, 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>
29 #include "tty.h"
30 #include "mad.h"
31 #include "color.h"
32 #include "util.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 "background.h" /* we_are_background definition */
38 #include "setup.h"
39
40 #ifdef HAVE_SLANG
41
42 /* Taken from S-Lang's slutty.c */
43 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
44 # define NULL_VALUE -1
45 #else
46 # ifdef _POSIX_VDISABLE
47 # define NULL_VALUE _POSIX_VDISABLE
48 # else
49 # define NULL_VALUE 255
50 # endif
51 #endif
52
53 /* Taken from S-Lang's sldisply.c file */
54 #ifndef USE_TERMCAP
55 # define tgetstr(a,b) SLtt_tgetstr (a)
56 #else
57 extern char *tgetstr(char *, char **);
58 #endif
59
60 #ifndef SA_RESTART
61 # define SA_RESTART 0
62 #endif
63
64 /* Various saved termios settings that we control here */
65 static struct termios boot_mode;
66 static struct termios new_mode;
67
68 /* Set if we get an interrupt */
69 static int slinterrupt;
70
71 /* Controls whether we should wait for input in getch */
72 static int no_slang_delay;
73
74 /* {{{ Copied from ../slang/slgetkey.c, removed the DEC_8Bit_HACK, */
75 extern unsigned int SLang_Input_Buffer_Len;
76 extern unsigned char SLang_Input_Buffer [];
77 #if SLANG_VERSION >= 10000
78 extern unsigned int _SLsys_getkey (void);
79 extern int _SLsys_input_pending (int);
80 #else
81 extern unsigned int SLsys_getkey (void);
82 extern int SLsys_input_pending (int);
83 #endif
84
85 static unsigned int SLang_getkey2 (void)
86 {
87 unsigned int imax;
88 unsigned int ch;
89
90 if (SLang_Input_Buffer_Len)
91 {
92 ch = (unsigned int) *SLang_Input_Buffer;
93 SLang_Input_Buffer_Len--;
94 imax = SLang_Input_Buffer_Len;
95
96 memcpy ((char *) SLang_Input_Buffer,
97 (char *) (SLang_Input_Buffer + 1), imax);
98 return(ch);
99 }
100 #if SLANG_VERSION >= 10000
101 else return(_SLsys_getkey ());
102 #else
103 else return(SLsys_getkey());
104 #endif
105 }
106
107 static int SLang_input_pending2 (int tsecs)
108 {
109 int n;
110 unsigned char c;
111 if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
112 #if SLANG_VERSION >= 10000
113 n = _SLsys_input_pending (tsecs);
114 #else
115 n = SLsys_input_pending (tsecs);
116 #endif
117 if (n <= 0) return 0;
118
119 c = (unsigned char) SLang_getkey2 ();
120 SLang_ungetkey_string (&c, 1);
121
122 return n;
123 }
124 /* }}} */
125
126 static void
127 slang_intr (int signo)
128 {
129 slinterrupt = 1;
130 }
131
132 int
133 interrupts_enabled (void)
134 {
135 struct sigaction current_act;
136
137 sigaction (SIGINT, NULL, &current_act);
138 return current_act.sa_handler == slang_intr;
139 }
140
141 void
142 enable_interrupt_key(void)
143 {
144 struct sigaction act;
145
146 act.sa_handler = slang_intr;
147 sigemptyset (&act.sa_mask);
148 act.sa_flags = 0;
149 sigaction (SIGINT, &act, NULL);
150 slinterrupt = 0;
151 }
152
153 void
154 disable_interrupt_key(void)
155 {
156 struct sigaction act;
157
158 act.sa_handler = SIG_IGN;
159 act.sa_flags = 0;
160 sigemptyset (&act.sa_mask);
161 sigaction (SIGINT, &act, NULL);
162 }
163
164 int
165 got_interrupt ()
166 {
167 int t;
168
169 t = slinterrupt;
170 slinterrupt = 0;
171 return t;
172 }
173
174 /* Only done the first time */
175 void
176 slang_init (void)
177 {
178 extern int SLtt_Blink_Mode;
179 extern int SLtt_Has_Alt_Charset;
180 extern int force_ugly_line_drawing;
181 struct sigaction act, oact;
182
183 SLtt_get_terminfo ();
184 tcgetattr (fileno (stdin), &boot_mode);
185 /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
186 SLang_init_tty (XCTRL('c'), 1, 0);
187
188 /* If SLang uses fileno(stderr) for terminal input MC will hang
189 if we call SLang_getkey between calls to open_error_pipe and
190 close_error_pipe, e.g. when we do a growing view of an gzipped
191 file. */
192 if (SLang_TT_Read_FD == fileno (stderr))
193 SLang_TT_Read_FD = fileno (stdin);
194
195 if (force_ugly_line_drawing)
196 SLtt_Has_Alt_Charset = 0;
197 if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
198 #ifdef VDSUSP
199 new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
200 #endif
201 #ifdef VLNEXT
202 new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
203 #endif
204 tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
205 }
206 slang_prog_mode ();
207 load_terminfo_keys ();
208 act.sa_handler = slang_intr;
209 sigemptyset (&act.sa_mask);
210 act.sa_flags = SA_RESTART;
211 sigaction (SIGINT, &act, &oact);
212 SLtt_Blink_Mode = 0;
213 }
214
215 void
216 slang_set_raw_mode (void)
217 {
218 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
219 }
220
221 /* Done each time we come back from done mode */
222 void
223 slang_prog_mode (void)
224 {
225 tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
226 SLsmg_init_smg ();
227 SLsmg_touch_lines (0, LINES);
228 }
229
230 /* Called each time we want to shutdown slang screen manager */
231 void
232 slang_shell_mode (void)
233 {
234 tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
235 }
236
237 void
238 slang_shutdown ()
239 {
240 char *op_cap;
241
242 slang_shell_mode ();
243 do_exit_ca_mode ();
244 SLang_reset_tty ();
245
246 /* Load the op capability to reset the colors to those that were
247 * active when the program was started up
248 */
249 op_cap = SLtt_tgetstr ("op");
250 if (op_cap){
251 fprintf (stdout, "%s", op_cap);
252 fflush (stdout);
253 }
254 }
255
256 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
257 elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
258 consequence is that function keys don't work in MC sometimes.
259 Unfortunately I don't now the one and only escape sequence to turn off
260 softkeys (elm uses three different capabilities to turn on softkeys and two
261 capabilities to turn them off).
262 Among other things elm uses the pair we already use in slang_keypad. That's
263 the reason why I call slang_reset_softkeys from slang_keypad. In lack of
264 something better the softkeys are programmed to their defaults from the
265 termcap/terminfo database.
266 The escape sequence to program the softkeys is taken from elm and it is
267 hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this
268 sequence. -- Norbert
269 */
270
271 void
272 slang_reset_softkeys (void)
273 {
274 int key;
275 char *send;
276 char *display = " ";
277 char tmp[100];
278
279 for ( key = 1; key < 9; key++ ) {
280 sprintf ( tmp, "k%d", key);
281 send = (char *) SLtt_tgetstr (tmp);
282 if (send) {
283 sprintf(tmp, "\033&f%dk%dd%dL%s%s", key,
284 strlen(display), strlen(send), display, send);
285 SLtt_write_string (tmp);
286 }
287 }
288 }
289
290 /* keypad routines */
291 void
292 slang_keypad (int set)
293 {
294 char *keypad_string;
295 extern int reset_hp_softkeys;
296
297 keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
298 if (keypad_string)
299 SLtt_write_string (keypad_string);
300 if (set && reset_hp_softkeys)
301 slang_reset_softkeys ();
302 }
303
304 void
305 set_slang_delay (int v)
306 {
307 no_slang_delay = v;
308 }
309
310 void
311 hline (int ch, int len)
312 {
313 int last_x, last_y;
314
315 last_x = SLsmg_get_column ();
316 last_y = SLsmg_get_row ();
317
318 if (ch == 0)
319 ch = ACS_HLINE;
320
321 if (ch == ACS_HLINE){
322 SLsmg_draw_hline (len);
323 } else {
324 while (len--)
325 addch (ch);
326 }
327 move (last_y, last_x);
328 }
329
330 void
331 vline (int character, int len)
332 {
333 if (!slow_terminal){
334 SLsmg_draw_vline (len);
335 } else {
336 int last_x, last_y, pos = 0;
337
338 last_x = SLsmg_get_column ();
339 last_y = SLsmg_get_row ();
340
341 while (len--){
342 move (last_y + pos++, last_x);
343 addch (' ');
344 }
345 move (last_x, last_y);
346 }
347 }
348
349 int max_index = 0;
350
351 void
352 init_pair (int index, char *foreground, char *background)
353 {
354
355 SLtt_set_color (index, "", foreground, background);
356 if (index > max_index)
357 max_index = index;
358 }
359
360 int
361 alloc_color_pair (char *foreground, char *background)
362 {
363 init_pair (++max_index, foreground, background);
364 return max_index;
365 }
366
367 int
368 try_alloc_color_pair (char *fg, char *bg)
369 {
370 static struct colors_avail {
371 struct colors_avail *next;
372 char *fg, *bg;
373 int index;
374 } *p, c =
375 {
376 0, 0, 0, 0
377 };
378
379 c.index = NORMAL_COLOR;
380 p = &c;
381 for (;;) {
382 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
383 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
384 return p->index;
385 if (!p->next)
386 break;
387 p = p->next;
388 }
389 p->next = malloc (sizeof (c));
390 p = p->next;
391 p->next = 0;
392 p->fg = fg ? strdup (fg) : 0;
393 p->bg = bg ? strdup (bg) : 0;
394 if (!fg)
395 fg = "white";
396 if (!bg)
397 bg = "blue";
398 p->index = alloc_color_pair (fg, bg);
399 return p->index;
400 }
401
402 char *color_terminals [] = {
403 #ifdef __linux__
404 "console",
405 #endif
406 "linux",
407 "xterm-color",
408 "color-xterm",
409 "dtterm",
410 "xtermc",
411 "ansi",
412 /* 'qnx*' terminals have non-ANSI-compatible color sequences... */
413 "qansi",
414 "qansi-g",
415 "qansi-m",
416 "qansi-t",
417 "qansi-w",
418 0
419 };
420
421 int has_colors ()
422 {
423 char *terminal = getenv ("TERM");
424 char *cts = color_terminal_string, *s;
425 int i;
426
427 SLtt_Use_Ansi_Colors = force_colors;
428 if (NULL != getenv ("COLORTERM"))
429 SLtt_Use_Ansi_Colors = 1;
430
431 /* We want to allow overwriding */
432 if (!disable_colors){
433 if (!*cts)
434 {
435 /* check hard-coded terminals */
436 for (i = 0; color_terminals [i]; i++)
437 if (strcmp (color_terminals [i], terminal) == 0)
438 SLtt_Use_Ansi_Colors = 1;
439 }
440 else
441 /* check color_terminal_string */
442 {
443 while (*cts)
444 {
445 while (*cts == ' ' || *cts == '\t') cts++;
446
447 s = cts;
448 i = 0;
449
450 while (*cts && *cts != ',')
451 {
452 cts++;
453 i++;
454 }
455 if (i && i == strlen(terminal) && strncmp(s, terminal, i) == 0)
456 SLtt_Use_Ansi_Colors = 1;
457
458 if (*cts == ',') cts++;
459 }
460 }
461 }
462
463 /* Setup emulated colors */
464 if (SLtt_Use_Ansi_Colors){
465 if (use_colors){
466 init_pair (A_REVERSE, "black", "white");
467 init_pair (A_BOLD, "white", "black");
468 } else {
469 init_pair (A_REVERSE, "black", "lightgray");
470 init_pair (A_BOLD, "white", "black");
471 init_pair (A_BOLD_REVERSE, "white", "lightgray");
472 }
473 } else {
474 SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
475 SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
476 SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
477 }
478 return SLtt_Use_Ansi_Colors;
479 }
480
481 void
482 attrset (int color)
483 {
484 if (!SLtt_Use_Ansi_Colors){
485 SLsmg_set_color (color);
486 return;
487 }
488
489 if (color & A_BOLD){
490 if (color == A_BOLD)
491 SLsmg_set_color (A_BOLD);
492 else
493 SLsmg_set_color ((color & (~A_BOLD)) + 8);
494 return;
495 }
496
497 if (color == A_REVERSE)
498 SLsmg_set_color (A_REVERSE);
499 else
500 SLsmg_set_color (color);
501 }
502
503 /* This table describes which capabilities we want and which values we
504 * assign to them.
505 */
506 struct {
507 int key_code;
508 char *key_name;
509 } key_table [] = {
510 { KEY_F(0), "k0" },
511 { KEY_F(1), "k1" },
512 { KEY_F(2), "k2" },
513 { KEY_F(3), "k3" },
514 { KEY_F(4), "k4" },
515 { KEY_F(5), "k5" },
516 { KEY_F(6), "k6" },
517 { KEY_F(7), "k7" },
518 { KEY_F(8), "k8" },
519 { KEY_F(9), "k9" },
520 { KEY_F(10), "k;" },
521 { KEY_F(11), "F1" },
522 { KEY_F(12), "F2" },
523 { KEY_F(13), "F3" },
524 { KEY_F(14), "F4" },
525 { KEY_F(15), "F5" },
526 { KEY_F(16), "F6" },
527 { KEY_F(17), "F7" },
528 { KEY_F(18), "F8" },
529 { KEY_F(19), "F9" },
530 { KEY_F(20), "FA" },
531 { KEY_IC, "kI" },
532 { KEY_NPAGE, "kN" },
533 { KEY_PPAGE, "kP" },
534 { KEY_LEFT, "kl" },
535 { KEY_RIGHT, "kr" },
536 { KEY_UP, "ku" },
537 { KEY_DOWN, "kd" },
538 { KEY_DC, "kD" },
539 { KEY_BACKSPACE, "kb" },
540 { KEY_HOME, "kh" },
541 { KEY_END, "@7" },
542 { 0, 0}
543 };
544
545 void
546 do_define_key (int code, char *strcap)
547 {
548 char *seq;
549
550 seq = (char *) SLtt_tgetstr (strcap);
551 if (seq)
552 define_sequence (code, seq, MCKEY_NOACTION);
553 }
554
555 void
556 load_terminfo_keys ()
557 {
558 int i;
559
560 for (i = 0; key_table [i].key_code; i++)
561 do_define_key (key_table [i].key_code, key_table [i].key_name);
562 }
563
564 int getch ()
565 {
566 if (no_slang_delay)
567 if (SLang_input_pending2 (0) == 0)
568 return -1;
569
570 return (SLang_getkey2 ());
571 }
572
573 extern int slow_terminal;
574
575 #else
576
577 /* Non slang builds do not understand got_interrupt */
578 int got_interrupt ()
579 {
580 return 0;
581 }
582 #endif /* HAVE_SLANG */
583
584 void
585 mc_refresh (void)
586 {
587 if (!we_are_background)
588 refresh ();
589 }