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

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