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

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