root/lib/tty/tty-ncurses.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. tty_setup_sigwinch
  2. sigwinch_handler
  3. tty_clip
  4. mc_tty_normalize_lines_char
  5. tty_init
  6. tty_shutdown
  7. tty_enter_ca_mode
  8. tty_exit_ca_mode
  9. tty_change_screen_size
  10. tty_reset_prog_mode
  11. tty_reset_shell_mode
  12. tty_raw_mode
  13. tty_noraw_mode
  14. tty_noecho
  15. tty_flush_input
  16. tty_keypad
  17. tty_nodelay
  18. tty_baudrate
  19. tty_lowlevel_getch
  20. tty_reset_screen
  21. tty_touch_screen
  22. tty_gotoyx
  23. tty_getyx
  24. tty_draw_hline
  25. tty_draw_vline
  26. tty_fill_region
  27. tty_colorize_area
  28. tty_set_alt_charset
  29. tty_display_8bit
  30. tty_print_char
  31. tty_print_anychar
  32. tty_print_alt_char
  33. tty_print_string
  34. tty_printf
  35. tty_tgetstr
  36. tty_refresh
  37. tty_beep

   1 /*
   2    Interface to the terminal controlling library.
   3    Ncurses wrapper.
   4 
   5    Copyright (C) 2005-2024
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Andrew Borodin <aborodin@vmail.ru>, 2009.
  10    Ilia Maslakov <il.smind@gmail.com>, 2009.
  11 
  12    This file is part of the Midnight Commander.
  13 
  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.
  18 
  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.
  23 
  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/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: NCurses-based tty layer of Midnight-commander
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <stdlib.h>
  35 #include <stdarg.h>
  36 #include <signal.h>
  37 #ifdef HAVE_SYS_IOCTL_H
  38 #include <sys/ioctl.h>
  39 #endif
  40 #include <termios.h>
  41 
  42 #include "lib/global.h"
  43 #include "lib/strutil.h"        /* str_term_form */
  44 #include "lib/util.h"
  45 
  46 #ifndef WANT_TERM_H
  47 #define WANT_TERM_H
  48 #endif
  49 
  50 #include "tty-internal.h"       /* mc_tty_normalize_from_utf8() */
  51 #include "tty.h"
  52 #include "color.h"              /* tty_setcolor */
  53 #include "color-internal.h"
  54 #include "key.h"
  55 #include "mouse.h"
  56 #include "win.h"
  57 
  58 /* include at last !!! */
  59 #ifdef WANT_TERM_H
  60 #ifdef HAVE_NCURSES_TERM_H
  61 #include <ncurses/term.h>
  62 #else
  63 #include <term.h>
  64 #endif /* HAVE_NCURSES_TERM_H */
  65 #endif /* WANT_TERM_H */
  66 
  67 /*** global variables ****************************************************************************/
  68 
  69 /*** file scope macro definitions ****************************************************************/
  70 
  71 #if !defined(CTRL)
  72 #define CTRL(x) ((x) & 0x1f)
  73 #endif
  74 
  75 #define yx_in_screen(y, x) \
  76     (y >= 0 && y < LINES && x >= 0 && x < COLS)
  77 
  78 /*** global variables ****************************************************************************/
  79 
  80 /*** file scope type declarations ****************************************************************/
  81 
  82 /*** forward declarations (file scope functions) *************************************************/
  83 
  84 /*** file scope variables ************************************************************************/
  85 
  86 /* ncurses supports cursor positions only within window */
  87 /* We use our own cursor coordinates to support partially visible widgets */
  88 static int mc_curs_row, mc_curs_col;
  89 
  90 /* --------------------------------------------------------------------------------------------- */
  91 /*** file scope functions ************************************************************************/
  92 /* --------------------------------------------------------------------------------------------- */
  93 
  94 static void
  95 tty_setup_sigwinch (void (*handler) (int))
     /* [previous][next][first][last][top][bottom][index][help]  */
  96 {
  97 #if (NCURSES_VERSION_MAJOR >= 4) && defined (SIGWINCH)
  98     struct sigaction act, oact;
  99 
 100     memset (&act, 0, sizeof (act));
 101     act.sa_handler = handler;
 102     sigemptyset (&act.sa_mask);
 103 #ifdef SA_RESTART
 104     act.sa_flags = SA_RESTART;
 105 #endif /* SA_RESTART */
 106     my_sigaction (SIGWINCH, &act, &oact);
 107 #endif /* SIGWINCH */
 108 
 109     tty_create_winch_pipe ();
 110 }
 111 
 112 /* --------------------------------------------------------------------------------------------- */
 113 
 114 static void
 115 sigwinch_handler (int dummy)
     /* [previous][next][first][last][top][bottom][index][help]  */
 116 {
 117     ssize_t n = 0;
 118 
 119     (void) dummy;
 120 
 121     n = write (sigwinch_pipe[1], "", 1);
 122     (void) n;
 123 }
 124 
 125 /* --------------------------------------------------------------------------------------------- */
 126 
 127 /**
 128  * Get visible part of area.
 129  *
 130  * @returns TRUE if any part of area is in screen bounds, FALSE otherwise.
 131  */
 132 static gboolean
 133 tty_clip (int *y, int *x, int *rows, int *cols)
     /* [previous][next][first][last][top][bottom][index][help]  */
 134 {
 135     if (*y < 0)
 136     {
 137         *rows += *y;
 138 
 139         if (*rows <= 0)
 140             return FALSE;
 141 
 142         *y = 0;
 143     }
 144 
 145     if (*x < 0)
 146     {
 147         *cols += *x;
 148 
 149         if (*cols <= 0)
 150             return FALSE;
 151 
 152         *x = 0;
 153     }
 154 
 155     if (*y + *rows > LINES)
 156         *rows = LINES - *y;
 157 
 158     if (*rows <= 0)
 159         return FALSE;
 160 
 161     if (*x + *cols > COLS)
 162         *cols = COLS - *x;
 163 
 164     if (*cols <= 0)
 165         return FALSE;
 166 
 167     return TRUE;
 168 }
 169 
 170 /* --------------------------------------------------------------------------------------------- */
 171 /*** public functions ****************************************************************************/
 172 /* --------------------------------------------------------------------------------------------- */
 173 
 174 int
 175 mc_tty_normalize_lines_char (const char *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 176 {
 177     char *str2;
 178     int res;
 179 
 180     struct mc_tty_lines_struct
 181     {
 182         const char *line;
 183         int line_code;
 184     } const lines_codes[] = {
 185         {"\342\224\230", ACS_LRCORNER}, /* ┌ */
 186         {"\342\224\224", ACS_LLCORNER}, /* └ */
 187         {"\342\224\220", ACS_URCORNER}, /* ┐ */
 188         {"\342\224\214", ACS_ULCORNER}, /* ┘ */
 189         {"\342\224\234", ACS_LTEE},     /* ├ */
 190         {"\342\224\244", ACS_RTEE},     /* ┤ */
 191         {"\342\224\254", ACS_TTEE},     /* ┬ */
 192         {"\342\224\264", ACS_BTEE},     /* ┴ */
 193         {"\342\224\200", ACS_HLINE},    /* ─ */
 194         {"\342\224\202", ACS_VLINE},    /* │ */
 195         {"\342\224\274", ACS_PLUS},     /* ┼ */
 196 
 197         {"\342\225\235", ACS_LRCORNER | A_BOLD},        /* ╔ */
 198         {"\342\225\232", ACS_LLCORNER | A_BOLD},        /* ╚ */
 199         {"\342\225\227", ACS_URCORNER | A_BOLD},        /* ╗ */
 200         {"\342\225\224", ACS_ULCORNER | A_BOLD},        /* ╝ */
 201         {"\342\225\237", ACS_LTEE | A_BOLD},    /* ╟ */
 202         {"\342\225\242", ACS_RTEE | A_BOLD},    /* ╢ */
 203         {"\342\225\244", ACS_TTEE | A_BOLD},    /* ╤ */
 204         {"\342\225\247", ACS_BTEE | A_BOLD},    /* ╧ */
 205         {"\342\225\220", ACS_HLINE | A_BOLD},   /* ═ */
 206         {"\342\225\221", ACS_VLINE | A_BOLD},   /* ║ */
 207 
 208         {NULL, 0}
 209     };
 210 
 211     if (ch == NULL)
 212         return (int) ' ';
 213 
 214     for (res = 0; lines_codes[res].line; res++)
 215     {
 216         if (strcmp (ch, lines_codes[res].line) == 0)
 217             return lines_codes[res].line_code;
 218     }
 219 
 220     str2 = mc_tty_normalize_from_utf8 (ch);
 221     res = g_utf8_get_char_validated (str2, -1);
 222 
 223     if (res < 0)
 224         res = (unsigned char) str2[0];
 225     g_free (str2);
 226 
 227     return res;
 228 }
 229 
 230 /* --------------------------------------------------------------------------------------------- */
 231 
 232 void
 233 tty_init (gboolean mouse_enable, gboolean is_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     struct termios mode;
 236 
 237     initscr ();
 238 
 239 #ifdef HAVE_ESCDELAY
 240     /*
 241      * If ncurses exports the ESCDELAY variable, it should be set to
 242      * a low value, or you'll experience a delay in processing escape
 243      * sequences that are recognized by mc (e.g. Esc-Esc).  On the other
 244      * hand, making ESCDELAY too small can result in some sequences
 245      * (e.g. cursor arrows) being reported as separate keys under heavy
 246      * processor load, and this can be a problem if mc hasn't learned
 247      * them in the "Learn Keys" dialog.  The value is in milliseconds.
 248      */
 249     ESCDELAY = 200;
 250 #endif /* HAVE_ESCDELAY */
 251 
 252     tcgetattr (STDIN_FILENO, &mode);
 253     /* use Ctrl-g to generate SIGINT */
 254     mode.c_cc[VINTR] = CTRL ('g');      /* ^g */
 255     /* disable SIGQUIT to allow use Ctrl-\ key */
 256     mode.c_cc[VQUIT] = NULL_VALUE;
 257     tcsetattr (STDIN_FILENO, TCSANOW, &mode);
 258 
 259     /* curses remembers the "in-program" modes after this call */
 260     def_prog_mode ();
 261 
 262     tty_start_interrupt_key ();
 263 
 264     if (!mouse_enable)
 265         use_mouse_p = MOUSE_DISABLED;
 266     tty_init_xterm_support (is_xterm);  /* do it before tty_enter_ca_mode() call */
 267     tty_enter_ca_mode ();
 268     tty_raw_mode ();
 269     noecho ();
 270     keypad (stdscr, TRUE);
 271     nodelay (stdscr, FALSE);
 272 
 273     tty_setup_sigwinch (sigwinch_handler);
 274 }
 275 
 276 /* --------------------------------------------------------------------------------------------- */
 277 
 278 void
 279 tty_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 280 {
 281     tty_destroy_winch_pipe ();
 282     tty_reset_shell_mode ();
 283     tty_noraw_mode ();
 284     tty_keypad (FALSE);
 285     tty_reset_screen ();
 286     tty_exit_ca_mode ();
 287 }
 288 
 289 /* --------------------------------------------------------------------------------------------- */
 290 
 291 void
 292 tty_enter_ca_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 293 {
 294     if (mc_global.tty.xterm_flag && smcup != NULL)
 295     {
 296         fprintf (stdout, /* ESC_STR ")0" */ ESC_STR "7" ESC_STR "[?47h");
 297         fflush (stdout);
 298     }
 299 }
 300 
 301 /* --------------------------------------------------------------------------------------------- */
 302 
 303 void
 304 tty_exit_ca_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 305 {
 306     if (mc_global.tty.xterm_flag && rmcup != NULL)
 307     {
 308         fprintf (stdout, ESC_STR "[?47l" ESC_STR "8" ESC_STR "[m");
 309         fflush (stdout);
 310     }
 311 }
 312 
 313 /* --------------------------------------------------------------------------------------------- */
 314 
 315 void
 316 tty_change_screen_size (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 317 {
 318 #if defined(TIOCGWINSZ) && NCURSES_VERSION_MAJOR >= 4
 319     struct winsize winsz;
 320 
 321     winsz.ws_col = winsz.ws_row = 0;
 322 
 323 #ifndef NCURSES_VERSION
 324     tty_noraw_mode ();
 325     tty_reset_screen ();
 326 #endif
 327 
 328     /* Ioctl on the STDIN_FILENO */
 329     ioctl (fileno (stdout), TIOCGWINSZ, &winsz);
 330     if (winsz.ws_col != 0 && winsz.ws_row != 0)
 331     {
 332 #if defined(NCURSES_VERSION) && defined(HAVE_RESIZETERM)
 333         resizeterm (winsz.ws_row, winsz.ws_col);
 334         clearok (stdscr, TRUE); /* sigwinch's should use a semaphore! */
 335 #else
 336         COLS = winsz.ws_col;
 337         LINES = winsz.ws_row;
 338 #endif
 339     }
 340 #endif /* defined(TIOCGWINSZ) || NCURSES_VERSION_MAJOR >= 4 */
 341 
 342 #ifdef ENABLE_SUBSHELL
 343     if (mc_global.tty.use_subshell)
 344         tty_resize (mc_global.tty.subshell_pty);
 345 #endif
 346 }
 347 
 348 /* --------------------------------------------------------------------------------------------- */
 349 
 350 void
 351 tty_reset_prog_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 352 {
 353     reset_prog_mode ();
 354 }
 355 
 356 /* --------------------------------------------------------------------------------------------- */
 357 
 358 void
 359 tty_reset_shell_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 360 {
 361     reset_shell_mode ();
 362 }
 363 
 364 /* --------------------------------------------------------------------------------------------- */
 365 
 366 void
 367 tty_raw_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 368 {
 369     raw ();                     /* FIXME: unneeded? */
 370     cbreak ();
 371 }
 372 
 373 /* --------------------------------------------------------------------------------------------- */
 374 
 375 void
 376 tty_noraw_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 377 {
 378     nocbreak ();                /* FIXME: unneeded? */
 379     noraw ();
 380 }
 381 
 382 /* --------------------------------------------------------------------------------------------- */
 383 
 384 void
 385 tty_noecho (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 386 {
 387     noecho ();
 388 }
 389 
 390 /* --------------------------------------------------------------------------------------------- */
 391 
 392 int
 393 tty_flush_input (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 394 {
 395     return flushinp ();
 396 }
 397 
 398 /* --------------------------------------------------------------------------------------------- */
 399 
 400 void
 401 tty_keypad (gboolean set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 402 {
 403     keypad (stdscr, (bool) set);
 404 }
 405 
 406 /* --------------------------------------------------------------------------------------------- */
 407 
 408 void
 409 tty_nodelay (gboolean set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 410 {
 411     nodelay (stdscr, (bool) set);
 412 }
 413 
 414 /* --------------------------------------------------------------------------------------------- */
 415 
 416 int
 417 tty_baudrate (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 418 {
 419     return baudrate ();
 420 }
 421 
 422 /* --------------------------------------------------------------------------------------------- */
 423 
 424 int
 425 tty_lowlevel_getch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 426 {
 427     return getch ();
 428 }
 429 
 430 /* --------------------------------------------------------------------------------------------- */
 431 
 432 int
 433 tty_reset_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 434 {
 435     return endwin ();
 436 }
 437 
 438 /* --------------------------------------------------------------------------------------------- */
 439 
 440 void
 441 tty_touch_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 442 {
 443     touchwin (stdscr);
 444 }
 445 
 446 /* --------------------------------------------------------------------------------------------- */
 447 
 448 void
 449 tty_gotoyx (int y, int x)
     /* [previous][next][first][last][top][bottom][index][help]  */
 450 {
 451     mc_curs_row = y;
 452     mc_curs_col = x;
 453 
 454     if (y < 0)
 455         y = 0;
 456     if (y >= LINES)
 457         y = LINES - 1;
 458 
 459     if (x < 0)
 460         x = 0;
 461     if (x >= COLS)
 462         x = COLS - 1;
 463 
 464     move (y, x);
 465 }
 466 
 467 /* --------------------------------------------------------------------------------------------- */
 468 
 469 void
 470 tty_getyx (int *py, int *px)
     /* [previous][next][first][last][top][bottom][index][help]  */
 471 {
 472     *py = mc_curs_row;
 473     *px = mc_curs_col;
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 void
 479 tty_draw_hline (int y, int x, int ch, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     int x1;
 482 
 483     if (y < 0 || y >= LINES || x >= COLS)
 484         return;
 485 
 486     x1 = x;
 487 
 488     if (x < 0)
 489     {
 490         len += x;
 491         if (len <= 0)
 492             return;
 493         x = 0;
 494     }
 495 
 496     if ((chtype) ch == ACS_HLINE)
 497         ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
 498 
 499     move (y, x);
 500     hline (ch, len);
 501     move (y, x1);
 502 
 503     mc_curs_row = y;
 504     mc_curs_col = x1;
 505 }
 506 
 507 /* --------------------------------------------------------------------------------------------- */
 508 
 509 void
 510 tty_draw_vline (int y, int x, int ch, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 511 {
 512     int y1;
 513 
 514     if (x < 0 || x >= COLS || y >= LINES)
 515         return;
 516 
 517     y1 = y;
 518 
 519     if (y < 0)
 520     {
 521         len += y;
 522         if (len <= 0)
 523             return;
 524         y = 0;
 525     }
 526 
 527     if ((chtype) ch == ACS_VLINE)
 528         ch = mc_tty_frm[MC_TTY_FRM_VERT];
 529 
 530     move (y, x);
 531     vline (ch, len);
 532     move (y1, x);
 533 
 534     mc_curs_row = y1;
 535     mc_curs_col = x;
 536 }
 537 
 538 /* --------------------------------------------------------------------------------------------- */
 539 
 540 void
 541 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 542 {
 543     int i;
 544 
 545     if (!tty_clip (&y, &x, &rows, &cols))
 546         return;
 547 
 548     for (i = 0; i < rows; i++)
 549     {
 550         move (y + i, x);
 551         hline (ch, cols);
 552     }
 553 
 554     move (y, x);
 555 
 556     mc_curs_row = y;
 557     mc_curs_col = x;
 558 }
 559 
 560 /* --------------------------------------------------------------------------------------------- */
 561 
 562 void
 563 tty_colorize_area (int y, int x, int rows, int cols, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 564 {
 565 #ifdef ENABLE_SHADOWS
 566     cchar_t *ctext;
 567     wchar_t wch[10];            /* TODO not sure if the length is correct */
 568     attr_t attrs;
 569     short color_pair;
 570 
 571     if (!use_colors || !tty_clip (&y, &x, &rows, &cols))
 572         return;
 573 
 574     tty_setcolor (color);
 575     ctext = g_malloc (sizeof (cchar_t) * (cols + 1));
 576 
 577     for (int row = 0; row < rows; row++)
 578     {
 579         mvin_wchnstr (y + row, x, ctext, cols);
 580 
 581         for (int col = 0; col < cols; col++)
 582         {
 583             getcchar (&ctext[col], wch, &attrs, &color_pair, NULL);
 584             setcchar (&ctext[col], wch, attrs, color, NULL);
 585         }
 586 
 587         mvadd_wchnstr (y + row, x, ctext, cols);
 588     }
 589 
 590     g_free (ctext);
 591 #else
 592     (void) y;
 593     (void) x;
 594     (void) rows;
 595     (void) cols;
 596     (void) color;
 597 #endif /* ENABLE_SHADOWS */
 598 }
 599 
 600 /* --------------------------------------------------------------------------------------------- */
 601 
 602 void
 603 tty_set_alt_charset (gboolean alt_charset)
     /* [previous][next][first][last][top][bottom][index][help]  */
 604 {
 605     (void) alt_charset;
 606 }
 607 
 608 /* --------------------------------------------------------------------------------------------- */
 609 
 610 void
 611 tty_display_8bit (gboolean what)
     /* [previous][next][first][last][top][bottom][index][help]  */
 612 {
 613     meta (stdscr, (int) what);
 614 }
 615 
 616 /* --------------------------------------------------------------------------------------------- */
 617 
 618 void
 619 tty_print_char (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 620 {
 621     if (yx_in_screen (mc_curs_row, mc_curs_col))
 622         addch (c);
 623     mc_curs_col++;
 624 }
 625 
 626 /* --------------------------------------------------------------------------------------------- */
 627 
 628 void
 629 tty_print_anychar (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 630 {
 631     if (mc_global.utf8_display || c > 255)
 632     {
 633         int res;
 634         unsigned char str[UTF8_CHAR_LEN + 1];
 635 
 636         res = g_unichar_to_utf8 (c, (char *) str);
 637         if (res == 0)
 638         {
 639             if (yx_in_screen (mc_curs_row, mc_curs_col))
 640                 addch ('.');
 641             mc_curs_col++;
 642         }
 643         else
 644         {
 645             const char *s;
 646 
 647             str[res] = '\0';
 648             s = str_term_form ((char *) str);
 649 
 650             if (yx_in_screen (mc_curs_row, mc_curs_col))
 651                 addstr (s);
 652 
 653             if (g_unichar_iswide (c))
 654                 mc_curs_col += 2;
 655             else if (!g_unichar_iszerowidth (c))
 656                 mc_curs_col++;
 657         }
 658     }
 659     else
 660     {
 661         if (yx_in_screen (mc_curs_row, mc_curs_col))
 662             addch (c);
 663         mc_curs_col++;
 664     }
 665 }
 666 
 667 /* --------------------------------------------------------------------------------------------- */
 668 
 669 void
 670 tty_print_alt_char (int c, gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 671 {
 672     if (yx_in_screen (mc_curs_row, mc_curs_col))
 673     {
 674         if ((chtype) c == ACS_VLINE)
 675             c = mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT];
 676         else if ((chtype) c == ACS_HLINE)
 677             c = mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ];
 678         else if ((chtype) c == ACS_LTEE)
 679             c = mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE];
 680         else if ((chtype) c == ACS_RTEE)
 681             c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE];
 682         else if ((chtype) c == ACS_ULCORNER)
 683             c = mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP];
 684         else if ((chtype) c == ACS_LLCORNER)
 685             c = mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM];
 686         else if ((chtype) c == ACS_URCORNER)
 687             c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP];
 688         else if ((chtype) c == ACS_LRCORNER)
 689             c = mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM];
 690         else if ((chtype) c == ACS_PLUS)
 691             c = mc_tty_frm[MC_TTY_FRM_CROSS];
 692 
 693         addch (c);
 694     }
 695 
 696     mc_curs_col++;
 697 }
 698 
 699 /* --------------------------------------------------------------------------------------------- */
 700 
 701 void
 702 tty_print_string (const char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 703 {
 704     int len;
 705     int start = 0;
 706 
 707     s = str_term_form (s);
 708     len = str_term_width1 (s);
 709 
 710     /* line is upper or below the screen or entire line is before or after screen */
 711     if (mc_curs_row < 0 || mc_curs_row >= LINES || mc_curs_col + len <= 0 || mc_curs_col >= COLS)
 712     {
 713         mc_curs_col += len;
 714         return;
 715     }
 716 
 717     /* skip invisible left part */
 718     if (mc_curs_col < 0)
 719     {
 720         start = -mc_curs_col;
 721         len += mc_curs_col;
 722         mc_curs_col = 0;
 723     }
 724 
 725     mc_curs_col += len;
 726     if (mc_curs_col >= COLS)
 727         len = COLS - (mc_curs_col - len);
 728 
 729     addstr (str_term_substring (s, start, len));
 730 }
 731 
 732 /* --------------------------------------------------------------------------------------------- */
 733 
 734 void
 735 tty_printf (const char *fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 736 {
 737     va_list args;
 738     char buf[BUF_1K];           /* FIXME: is it enough? */
 739 
 740     va_start (args, fmt);
 741     g_vsnprintf (buf, sizeof (buf), fmt, args);
 742     va_end (args);
 743     tty_print_string (buf);
 744 }
 745 
 746 /* --------------------------------------------------------------------------------------------- */
 747 
 748 char *
 749 tty_tgetstr (const char *cap)
     /* [previous][next][first][last][top][bottom][index][help]  */
 750 {
 751     char *unused = NULL;
 752 
 753     return tgetstr ((NCURSES_CONST char *) cap, &unused);
 754 }
 755 
 756 /* --------------------------------------------------------------------------------------------- */
 757 
 758 void
 759 tty_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 760 {
 761     refresh ();
 762     doupdate ();
 763 }
 764 
 765 /* --------------------------------------------------------------------------------------------- */
 766 
 767 void
 768 tty_beep (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 769 {
 770     beep ();
 771 }
 772 
 773 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */