Add edit_add_window() function.
[midnight-commander.git] / lib / tty / tty-ncurses.c
blob7481a3e00bed6a7cace2a0bfe5e856cfd879a5e4
1 /*
2 Interface to the terminal controlling library.
3 Ncurses wrapper.
5 Copyright (C) 2005, 2006, 2007, 2009, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Andrew Borodin <aborodin@vmail.ru>, 2009.
10 Ilia Maslakov <il.smind@gmail.com>, 2009.
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: NCurses-based tty layer of Midnight-commander
32 #include <config.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <signal.h>
38 #include "lib/global.h"
39 #include "lib/strutil.h" /* str_term_form */
41 #ifndef WANT_TERM_H
42 #define WANT_TERM_H
43 #endif
45 #include "tty-internal.h" /* mc_tty_normalize_from_utf8() */
46 #include "tty.h"
47 #include "color-internal.h"
48 #include "mouse.h"
49 #include "win.h"
51 /* include at last !!! */
52 #ifdef WANT_TERM_H
53 #ifdef HAVE_NCURSES_TERM_H
54 #include <ncurses/term.h>
55 #else
56 #include <term.h>
57 #endif /* HAVE_NCURSES_TERM_H */
58 #endif /* WANT_TERM_H */
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
64 #if defined(_AIX) && !defined(CTRL)
65 #define CTRL(x) ((x) & 0x1f)
66 #endif
68 #define yx_in_screen(y, x) \
69 (y >= 0 && y < LINES && x >= 0 && x < COLS)
71 /*** global variables ****************************************************************************/
73 /*** file scope type declarations ****************************************************************/
75 /*** file scope variables ************************************************************************/
77 /* ncurses supports cursor positions only within window */
78 /* We use our own cursor coordibates to support partially visible widgets */
79 static int mc_curs_row, mc_curs_col;
81 /*** file scope functions ************************************************************************/
82 /* --------------------------------------------------------------------------------------------- */
84 /* --------------------------------------------------------------------------------------------- */
86 static void
87 tty_setup_sigwinch (void (*handler) (int))
89 #if (NCURSES_VERSION_MAJOR >= 4) && defined (SIGWINCH)
90 struct sigaction act, oact;
91 act.sa_handler = handler;
92 sigemptyset (&act.sa_mask);
93 act.sa_flags = 0;
94 #ifdef SA_RESTART
95 act.sa_flags |= SA_RESTART;
96 #endif /* SA_RESTART */
97 sigaction (SIGWINCH, &act, &oact);
98 #endif /* SIGWINCH */
101 /* --------------------------------------------------------------------------------------------- */
103 static void
104 sigwinch_handler (int dummy)
106 (void) dummy;
108 mc_global.tty.winch_flag = TRUE;
111 /* --------------------------------------------------------------------------------------------- */
112 /*** public functions ****************************************************************************/
113 /* --------------------------------------------------------------------------------------------- */
116 mc_tty_normalize_lines_char (const char *ch)
118 char *str2;
119 int res;
121 struct mc_tty_lines_struct
123 const char *line;
124 int line_code;
125 } const lines_codes[] = {
126 {"\342\224\230", ACS_LRCORNER}, /* ┌ */
127 {"\342\224\224", ACS_LLCORNER}, /* └ */
128 {"\342\224\220", ACS_URCORNER}, /* ┐ */
129 {"\342\224\214", ACS_ULCORNER}, /* ┘ */
130 {"\342\224\234", ACS_LTEE}, /* ├ */
131 {"\342\224\244", ACS_RTEE}, /* ┤ */
132 {"\342\224\254", ACS_TTEE}, /* ┬ */
133 {"\342\224\264", ACS_BTEE}, /* ┴ */
134 {"\342\224\200", ACS_HLINE}, /* ─ */
135 {"\342\224\202", ACS_VLINE}, /* │ */
136 {"\342\224\274", ACS_PLUS}, /* ┼ */
138 {"\342\225\235", ACS_LRCORNER | A_BOLD}, /* ╔ */
139 {"\342\225\232", ACS_LLCORNER | A_BOLD}, /* ╚ */
140 {"\342\225\227", ACS_URCORNER | A_BOLD}, /* ╗ */
141 {"\342\225\224", ACS_ULCORNER | A_BOLD}, /* ╝ */
142 {"\342\225\237", ACS_LTEE | A_BOLD}, /* ╟ */
143 {"\342\225\242", ACS_RTEE | A_BOLD}, /* ╢ */
144 {"\342\225\244", ACS_TTEE | A_BOLD}, /* ╤ */
145 {"\342\225\247", ACS_BTEE | A_BOLD}, /* ╧ */
146 {"\342\225\220", ACS_HLINE | A_BOLD}, /* ═ */
147 {"\342\225\221", ACS_VLINE | A_BOLD}, /* ║ */
149 {NULL, 0}
152 if (ch == NULL)
153 return (int) ' ';
155 for (res = 0; lines_codes[res].line; res++)
157 if (strcmp (ch, lines_codes[res].line) == 0)
158 return lines_codes[res].line_code;
161 str2 = mc_tty_normalize_from_utf8 (ch);
162 res = g_utf8_get_char_validated (str2, -1);
164 if (res < 0)
165 res = (unsigned char) str2[0];
166 g_free (str2);
168 return res;
171 /* --------------------------------------------------------------------------------------------- */
173 void
174 tty_init (gboolean mouse_enable, gboolean is_xterm)
176 initscr ();
178 #ifdef HAVE_ESCDELAY
180 * If ncurses exports the ESCDELAY variable, it should be set to
181 * a low value, or you'll experience a delay in processing escape
182 * sequences that are recognized by mc (e.g. Esc-Esc). On the other
183 * hand, making ESCDELAY too small can result in some sequences
184 * (e.g. cursor arrows) being reported as separate keys under heavy
185 * processor load, and this can be a problem if mc hasn't learned
186 * them in the "Learn Keys" dialog. The value is in milliseconds.
188 ESCDELAY = 200;
189 #endif /* HAVE_ESCDELAY */
191 /* use Ctrl-g to generate SIGINT */
192 cur_term->Nttyb.c_cc[VINTR] = CTRL ('g'); /* ^g */
193 /* disable SIGQUIT to allow use Ctrl-\ key */
194 cur_term->Nttyb.c_cc[VQUIT] = NULL_VALUE;
195 tcsetattr (cur_term->Filedes, TCSANOW, &cur_term->Nttyb);
197 tty_start_interrupt_key ();
199 if (!mouse_enable)
200 use_mouse_p = MOUSE_DISABLED;
201 tty_init_xterm_support (is_xterm); /* do it before do_enter_ca_mode() call */
202 init_mouse ();
203 do_enter_ca_mode ();
204 tty_raw_mode ();
205 noecho ();
206 keypad (stdscr, TRUE);
207 nodelay (stdscr, FALSE);
209 tty_setup_sigwinch (sigwinch_handler);
212 /* --------------------------------------------------------------------------------------------- */
214 void
215 tty_shutdown (void)
217 disable_mouse ();
218 tty_reset_shell_mode ();
219 tty_noraw_mode ();
220 tty_keypad (FALSE);
221 tty_reset_screen ();
222 do_exit_ca_mode ();
225 /* --------------------------------------------------------------------------------------------- */
227 void
228 tty_reset_prog_mode (void)
230 reset_prog_mode ();
233 /* --------------------------------------------------------------------------------------------- */
235 void
236 tty_reset_shell_mode (void)
238 reset_shell_mode ();
241 /* --------------------------------------------------------------------------------------------- */
243 void
244 tty_raw_mode (void)
246 raw (); /* FIXME: uneeded? */
247 cbreak ();
250 /* --------------------------------------------------------------------------------------------- */
252 void
253 tty_noraw_mode (void)
255 nocbreak (); /* FIXME: unneeded? */
256 noraw ();
259 /* --------------------------------------------------------------------------------------------- */
261 void
262 tty_noecho (void)
264 noecho ();
267 /* --------------------------------------------------------------------------------------------- */
270 tty_flush_input (void)
272 return flushinp ();
275 /* --------------------------------------------------------------------------------------------- */
277 void
278 tty_keypad (gboolean set)
280 keypad (stdscr, (bool) set);
283 /* --------------------------------------------------------------------------------------------- */
285 void
286 tty_nodelay (gboolean set)
288 nodelay (stdscr, (bool) set);
291 /* --------------------------------------------------------------------------------------------- */
294 tty_baudrate (void)
296 return baudrate ();
299 /* --------------------------------------------------------------------------------------------- */
302 tty_lowlevel_getch (void)
304 return getch ();
307 /* --------------------------------------------------------------------------------------------- */
310 tty_reset_screen (void)
312 return endwin ();
315 /* --------------------------------------------------------------------------------------------- */
317 void
318 tty_touch_screen (void)
320 touchwin (stdscr);
323 /* --------------------------------------------------------------------------------------------- */
325 void
326 tty_gotoyx (int y, int x)
328 mc_curs_row = y;
329 mc_curs_col = x;
331 if (y < 0)
332 y = 0;
333 if (y >= LINES)
334 y = LINES - 1;
336 if (x < 0)
337 x = 0;
338 if (x >= COLS)
339 x = COLS - 1;
341 move (y, x);
344 /* --------------------------------------------------------------------------------------------- */
346 void
347 tty_getyx (int *py, int *px)
349 *py = mc_curs_row;
350 *px = mc_curs_col;
353 /* --------------------------------------------------------------------------------------------- */
355 void
356 tty_draw_hline (int y, int x, int ch, int len)
358 int x1;
360 if (y < 0 || y >= LINES || x >= COLS)
361 return;
363 x1 = x;
365 if (x < 0)
367 len += x;
368 if (len <= 0)
369 return;
370 x = 0;
373 if ((chtype) ch == ACS_HLINE)
374 ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
376 move (y, x);
377 hline (ch, len);
378 move (y, x1);
380 mc_curs_row = y;
381 mc_curs_col = x1;
384 /* --------------------------------------------------------------------------------------------- */
386 void
387 tty_draw_vline (int y, int x, int ch, int len)
389 int y1;
391 if (x < 0 || x >= COLS || y >= LINES)
392 return;
394 y1 = y;
396 if (y < 0)
398 len += y;
399 if (len <= 0)
400 return;
401 y = 0;
404 if ((chtype) ch == ACS_VLINE)
405 ch = mc_tty_frm[MC_TTY_FRM_VERT];
407 move (y, x);
408 vline (ch, len);
409 move (y1, x);
411 mc_curs_row = y1;
412 mc_curs_col = x;
415 /* --------------------------------------------------------------------------------------------- */
417 void
418 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
420 int i;
422 if (y < 0)
424 rows += y;
426 if (rows <= 0)
427 return;
429 y = 0;
432 if (x < 0)
434 cols += x;
436 if (cols <= 0)
437 return;
439 x = 0;
442 if (y + rows > LINES)
443 rows = LINES - y;
444 if (x + cols > COLS)
445 cols = COLS - x;
447 for (i = 0; i < rows; i++)
449 move (y + i, x);
450 hline (ch, cols);
453 move (y, x);
455 mc_curs_row = y;
456 mc_curs_col = x;
459 /* --------------------------------------------------------------------------------------------- */
461 void
462 tty_set_alt_charset (gboolean alt_charset)
464 (void) alt_charset;
467 /* --------------------------------------------------------------------------------------------- */
469 void
470 tty_display_8bit (gboolean what)
472 meta (stdscr, (int) what);
475 /* --------------------------------------------------------------------------------------------- */
477 void
478 tty_print_char (int c)
480 if (yx_in_screen (mc_curs_row, mc_curs_col))
481 addch (c);
482 mc_curs_col++;
485 /* --------------------------------------------------------------------------------------------- */
487 void
488 tty_print_anychar (int c)
490 unsigned char str[6 + 1];
492 if (mc_global.utf8_display || c > 255)
494 int res;
496 res = g_unichar_to_utf8 (c, (char *) str);
497 if (res == 0)
499 if (yx_in_screen (mc_curs_row, mc_curs_col))
500 addch ('.');
501 mc_curs_col++;
503 else
505 const char *s;
507 str[res] = '\0';
508 s = str_term_form ((char *) str);
510 if (yx_in_screen (mc_curs_row, mc_curs_col))
511 addstr (s);
513 if (g_unichar_iswide (c))
514 mc_curs_col += 2;
515 else if (!g_unichar_iszerowidth (c))
516 mc_curs_col++;
519 else
521 if (yx_in_screen (mc_curs_row, mc_curs_col))
522 addch (c);
523 mc_curs_col++;
527 /* --------------------------------------------------------------------------------------------- */
529 void
530 tty_print_alt_char (int c, gboolean single)
532 if (yx_in_screen (mc_curs_row, mc_curs_col))
534 if ((chtype) c == ACS_VLINE)
535 c = mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT];
536 else if ((chtype) c == ACS_HLINE)
537 c = mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ];
538 else if ((chtype) c == ACS_LTEE)
539 c = mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE];
540 else if ((chtype) c == ACS_RTEE)
541 c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE];
542 else if ((chtype) c == ACS_ULCORNER)
543 c = mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP];
544 else if ((chtype) c == ACS_LLCORNER)
545 c = mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM];
546 else if ((chtype) c == ACS_URCORNER)
547 c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP];
548 else if ((chtype) c == ACS_LRCORNER)
549 c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM];
550 else if ((chtype) c == ACS_PLUS)
551 c = mc_tty_frm[MC_TTY_FRM_CROSS];
553 addch (c);
556 mc_curs_col++;
559 /* --------------------------------------------------------------------------------------------- */
561 void
562 tty_print_string (const char *s)
564 int len;
565 int start = 0;
567 s = str_term_form (s);
568 len = str_term_width1 (s);
570 /* line is upper or below the screen or entire line is before or after scrren */
571 if (mc_curs_row < 0 || mc_curs_row >= LINES || mc_curs_col + len <= 0 || mc_curs_col >= COLS)
573 mc_curs_col += len;
574 return;
577 /* skip invisible left part */
578 if (mc_curs_col < 0)
580 start = -mc_curs_col;
581 len += mc_curs_col;
582 mc_curs_col = 0;
585 mc_curs_col += len;
586 if (mc_curs_col >= COLS)
587 len = COLS - (mc_curs_col - len);
589 addstr (str_term_substring (s, start, len));
592 /* --------------------------------------------------------------------------------------------- */
594 void
595 tty_printf (const char *fmt, ...)
597 va_list args;
598 char buf[BUF_1K]; /* FIXME: is it enough? */
600 va_start (args, fmt);
601 g_vsnprintf (buf, sizeof (buf), fmt, args);
602 va_end (args);
603 tty_print_string (buf);
606 /* --------------------------------------------------------------------------------------------- */
608 char *
609 tty_tgetstr (const char *cap)
611 char *unused = NULL;
612 return tgetstr ((char *) cap, &unused);
615 /* --------------------------------------------------------------------------------------------- */
617 void
618 tty_refresh (void)
620 refresh ();
621 doupdate ();
624 /* --------------------------------------------------------------------------------------------- */
626 void
627 tty_beep (void)
629 beep ();
632 /* --------------------------------------------------------------------------------------------- */