/* Interface to the terminal controlling library. Ncurses wrapper. Copyright (C) 2005, 2006, 2007, 2009 Free Software Foundation, Inc. Written by: Andrew Borodin , 2009. Ilia Maslakov , 2009. This file is part of the Midnight Commander. The Midnight Commander is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Midnight Commander is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** \file * \brief Source: NCurses-based tty layer of Midnight-commander */ #include #include #include #include #include "lib/global.h" #include "lib/strutil.h" /* str_term_form */ #include "src/main.h" #ifndef WANT_TERM_H # define WANT_TERM_H #endif #include "tty-internal.h" /* slow_tty */ #include "tty.h" #include "color-internal.h" #include "win.h" /* include at last !!! */ #ifdef WANT_TERM_H #ifdef HAVE_NCURSES_TERM_H # include #else # include #endif /* HAVE_NCURSES_TERM_H */ #endif /* WANT_TERM_H */ /*** global variables **************************************************/ /*** file scope macro definitions **************************************/ #if defined(_AIX) && !defined(CTRL) # define CTRL(x) ((x) & 0x1f) #endif /*** global variables **************************************************/ /*** file scope type declarations **************************************/ /*** file scope variables **********************************************/ /*** file scope functions **********************************************/ /* --------------------------------------------------------------------------------------------- */ /*** public functions **************************************************/ /* --------------------------------------------------------------------------------------------- */ int mc_tty_normalize_lines_char (const char *ch) { char *str2; int res; struct mc_tty_lines_struct { const char *line; int line_code; } const lines_codes[] = { {"\342\224\230", ACS_LRCORNER}, /* ┌ */ {"\342\224\224", ACS_LLCORNER}, /* └ */ {"\342\224\220", ACS_URCORNER}, /* ┐ */ {"\342\224\214", ACS_ULCORNER}, /* ┘ */ {"\342\224\234", ACS_LTEE}, /* ├ */ {"\342\224\244", ACS_RTEE}, /* ┤ */ {"\342\224\254", ACS_TTEE}, /* ┬ */ {"\342\224\264", ACS_BTEE}, /* ┴ */ {"\342\224\200", ACS_HLINE}, /* ─ */ {"\342\224\202", ACS_VLINE}, /* │ */ {"\342\224\274", ACS_PLUS}, /* ┼ */ {"\342\225\235", ACS_LRCORNER | A_BOLD}, /* ╔ */ {"\342\225\232", ACS_LLCORNER | A_BOLD}, /* ╚ */ {"\342\225\227", ACS_URCORNER | A_BOLD}, /* ╗ */ {"\342\225\224", ACS_ULCORNER | A_BOLD}, /* ╝ */ {"\342\225\237", ACS_LTEE | A_BOLD}, /* ╟ */ {"\342\225\242", ACS_RTEE | A_BOLD}, /* ╢ */ {"\342\225\244", ACS_TTEE | A_BOLD}, /* ╤ */ {"\342\225\247", ACS_BTEE | A_BOLD}, /* ╧ */ {"\342\225\220", ACS_HLINE | A_BOLD}, /* ═ */ {"\342\225\221", ACS_VLINE | A_BOLD}, /* ║ */ {NULL, 0} }; if (ch == NULL) return (int) ' '; for (res = 0; lines_codes[res].line; res++) { if (strcmp (ch, lines_codes[res].line) == 0) return lines_codes[res].line_code; } str2 = mc_tty_normalize_from_utf8 (ch); res = g_utf8_get_char_validated (str2, -1); if (res < 0) res = (unsigned char) str2[0]; g_free (str2); return res; } /* --------------------------------------------------------------------------------------------- */ void tty_init (gboolean slow, gboolean ugly_lines) { slow_tty = slow; (void) ugly_lines; initscr (); #ifdef HAVE_ESCDELAY /* * If ncurses exports the ESCDELAY variable, it should be set to * a low value, or you'll experience a delay in processing escape * sequences that are recognized by mc (e.g. Esc-Esc). On the other * hand, making ESCDELAY too small can result in some sequences * (e.g. cursor arrows) being reported as separate keys under heavy * processor load, and this can be a problem if mc hasn't learned * them in the "Learn Keys" dialog. The value is in milliseconds. */ ESCDELAY = 200; #endif /* HAVE_ESCDELAY */ /* use Ctrl-g to generate SIGINT */ cur_term->Nttyb.c_cc[VINTR] = CTRL ('g'); /* ^g */ /* disable SIGQUIT to allow use Ctrl-\ key */ cur_term->Nttyb.c_cc[VQUIT] = NULL_VALUE; tcsetattr (cur_term->Filedes, TCSANOW, &cur_term->Nttyb); tty_start_interrupt_key (); do_enter_ca_mode (); tty_raw_mode (); noecho (); keypad (stdscr, TRUE); nodelay (stdscr, FALSE); } void tty_shutdown (void) { endwin (); } void tty_reset_prog_mode (void) { reset_prog_mode (); } void tty_reset_shell_mode (void) { reset_shell_mode (); } void tty_raw_mode (void) { raw (); /* FIXME: uneeded? */ cbreak (); } void tty_noraw_mode (void) { nocbreak (); /* FIXME: unneeded? */ noraw (); } void tty_noecho (void) { noecho (); } int tty_flush_input (void) { return flushinp (); } void tty_keypad (gboolean set) { keypad (stdscr, (bool) set); } void tty_nodelay (gboolean set) { nodelay (stdscr, (bool) set); } int tty_baudrate (void) { return baudrate (); } int tty_lowlevel_getch (void) { return getch (); } int tty_reset_screen (void) { return endwin (); } void tty_touch_screen (void) { touchwin (stdscr); } void tty_gotoyx (int y, int x) { move (y, x); } void tty_getyx (int *py, int *px) { getyx (stdscr, *py, *px); } /* if x < 0 or y < 0, draw line starting from current position */ void tty_draw_hline (int y, int x, int ch, int len) { if ((chtype) ch == ACS_HLINE) ch = mc_tty_frm[MC_TTY_FRM_HORIZ]; if ((y >= 0) && (x >= 0)) move (y, x); hline (ch, len); } /* if x < 0 or y < 0, draw line starting from current position */ void tty_draw_vline (int y, int x, int ch, int len) { if ((chtype) ch == ACS_VLINE) ch = mc_tty_frm[MC_TTY_FRM_VERT]; if ((y >= 0) && (x >= 0)) move (y, x); vline (ch, len); } void tty_fill_region (int y, int x, int rows, int cols, unsigned char ch) { int i; if (y < 0) { rows += y; if (rows <= 0) return; y = 0; } if (x < 0) { cols += x; if (cols <= 0) return; x = 0; } if (y + rows > LINES) rows = LINES - y; if (x + cols > COLS) cols = COLS - x; for (i = 0; i < rows; i++) { move (y + i, x); hline (ch, cols); } move (y, x); } void tty_set_alt_charset (gboolean alt_charset) { (void) alt_charset; } void tty_display_8bit (gboolean what) { meta (stdscr, (int) what); } void tty_print_char (int c) { addch (c); } void tty_print_anychar (int c) { unsigned char str[6 + 1]; if (utf8_display || c > 255) { int res = g_unichar_to_utf8 (c, (char *) str); if (res == 0) { str[0] = '.'; str[1] = '\0'; } else str[res] = '\0'; addstr (str_term_form ((char *) str)); } else addch (c); } void tty_print_alt_char (int c, gboolean single) { if ((chtype) c == ACS_VLINE) c = mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]; else if ((chtype) c == ACS_HLINE) c = mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]; else if ((chtype) c == ACS_LTEE) c = mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]; else if ((chtype) c == ACS_RTEE) c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]; else if ((chtype) c == ACS_ULCORNER) c = mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]; else if ((chtype) c == ACS_LLCORNER) c = mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]; else if ((chtype) c == ACS_URCORNER) c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]; else if ((chtype) c == ACS_LRCORNER) c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]; else if ((chtype) c == ACS_PLUS) c = mc_tty_frm[MC_TTY_FRM_CROSS]; addch (c); } void tty_print_string (const char *s) { addstr (str_term_form (s)); } void tty_printf (const char *fmt, ...) { va_list args; va_start (args, fmt); vw_printw (stdscr, fmt, args); va_end (args); } char * tty_tgetstr (const char *cap) { char *unused = NULL; return tgetstr ((char *) cap, &unused); } void tty_refresh (void) { refresh (); doupdate (); } void tty_setup_sigwinch (void (*handler) (int)) { #if (NCURSES_VERSION_MAJOR >= 4) && defined (SIGWINCH) struct sigaction act, oact; act.sa_handler = handler; sigemptyset (&act.sa_mask); act.sa_flags = 0; #ifdef SA_RESTART act.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ sigaction (SIGWINCH, &act, &oact); #endif /* SIGWINCH */ } void tty_beep (void) { beep (); }