tty-slang.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. /*
  2. Interface to the terminal controlling library.
  3. Slang wrapper.
  4. Copyright (C) 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
  5. Written by:
  6. Andrew Borodin <aborodin@vmail.ru>, 2009.
  7. This file is part of the Midnight Commander.
  8. The Midnight Commander is free software; you can redistribute it
  9. and/or modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation; either version 2 of the
  11. License, or (at your option) any later version.
  12. The Midnight Commander is distributed in the hope that it will be
  13. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  14. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. MA 02110-1301, USA.
  20. */
  21. /** \file
  22. * \brief Source: S-Lang-based tty layer of Midnight Commander
  23. */
  24. #include <config.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <termios.h>
  29. #include <sys/types.h> /* size_t */
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include "lib/global.h"
  33. #include "lib/strutil.h" /* str_term_form */
  34. #include "tty-internal.h" /* slow_tty */
  35. #include "tty.h"
  36. #include "color-slang.h"
  37. #include "color-internal.h"
  38. #include "mouse.h" /* Gpm_Event is required in key.h */
  39. #include "key.h" /* define_sequence */
  40. #include "win.h"
  41. /*** global variables ****************************************************************************/
  42. extern int reset_hp_softkeys;
  43. /*** file scope macro definitions ****************************************************************/
  44. #ifndef SA_RESTART
  45. #define SA_RESTART 0
  46. #endif
  47. #ifndef SLTT_MAX_SCREEN_COLS
  48. #define SLTT_MAX_SCREEN_COLS 512
  49. #endif
  50. #ifndef SLTT_MAX_SCREEN_ROWS
  51. #define SLTT_MAX_SCREEN_ROWS 512
  52. #endif
  53. /*** file scope type declarations ****************************************************************/
  54. /*** file scope variables ************************************************************************/
  55. /* Various saved termios settings that we control here */
  56. static struct termios boot_mode;
  57. static struct termios new_mode;
  58. /* Controls whether we should wait for input in tty_lowlevel_getch */
  59. static gboolean no_slang_delay;
  60. /* This table describes which capabilities we want and which values we
  61. * assign to them.
  62. */
  63. static const struct
  64. {
  65. int key_code;
  66. const char *key_name;
  67. } key_table[] =
  68. {
  69. /* *INDENT-OFF* */
  70. { KEY_F (0), "k0" },
  71. { KEY_F (1), "k1" },
  72. { KEY_F (2), "k2" },
  73. { KEY_F (3), "k3" },
  74. { KEY_F (4), "k4" },
  75. { KEY_F (5), "k5" },
  76. { KEY_F (6), "k6" },
  77. { KEY_F (7), "k7" },
  78. { KEY_F (8), "k8" },
  79. { KEY_F (9), "k9" },
  80. { KEY_F (10), "k;" },
  81. { KEY_F (11), "F1" },
  82. { KEY_F (12), "F2" },
  83. { KEY_F (13), "F3" },
  84. { KEY_F (14), "F4" },
  85. { KEY_F (15), "F5" },
  86. { KEY_F (16), "F6" },
  87. { KEY_F (17), "F7" },
  88. { KEY_F (18), "F8" },
  89. { KEY_F (19), "F9" },
  90. { KEY_F (20), "FA" },
  91. { KEY_IC, "kI" },
  92. { KEY_NPAGE, "kN" },
  93. { KEY_PPAGE, "kP" },
  94. { KEY_LEFT, "kl" },
  95. { KEY_RIGHT, "kr" },
  96. { KEY_UP, "ku" },
  97. { KEY_DOWN, "kd" },
  98. { KEY_DC, "kD" },
  99. { KEY_BACKSPACE, "kb" },
  100. { KEY_HOME, "kh" },
  101. { KEY_END, "@7" },
  102. { 0, NULL }
  103. /* *INDENT-ON* */
  104. };
  105. /*** file scope functions ************************************************************************/
  106. /* --------------------------------------------------------------------------------------------- */
  107. /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
  108. elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
  109. consequence is that function keys don't work in MC sometimes...
  110. Unfortunately I don't now the one and only escape sequence to turn off.
  111. softkeys (elm uses three different capabilities to turn on softkeys and two.
  112. capabilities to turn them off)..
  113. Among other things elm uses the pair we already use in slang_keypad. That's.
  114. the reason why I call slang_reset_softkeys from slang_keypad. In lack of
  115. something better the softkeys are programmed to their defaults from the
  116. termcap/terminfo database.
  117. The escape sequence to program the softkeys is taken from elm and it is.
  118. hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
  119. sequence. -- Norbert
  120. */
  121. static void
  122. slang_reset_softkeys (void)
  123. {
  124. int key;
  125. char *send;
  126. static const char display[] = " ";
  127. char tmp[BUF_SMALL];
  128. for (key = 1; key < 9; key++)
  129. {
  130. g_snprintf (tmp, sizeof (tmp), "k%d", key);
  131. send = (char *) SLtt_tgetstr (tmp);
  132. if (send != NULL)
  133. {
  134. g_snprintf (tmp, sizeof (tmp), "\033&f%dk%dd%dL%s%s", key,
  135. (int) (sizeof (display) - 1), (int) strlen (send), display, send);
  136. SLtt_write_string (tmp);
  137. }
  138. }
  139. }
  140. /* --------------------------------------------------------------------------------------------- */
  141. static void
  142. do_define_key (int code, const char *strcap)
  143. {
  144. char *seq;
  145. seq = (char *) SLtt_tgetstr ((char *) strcap);
  146. if (seq != NULL)
  147. define_sequence (code, seq, MCKEY_NOACTION);
  148. }
  149. /* --------------------------------------------------------------------------------------------- */
  150. static void
  151. load_terminfo_keys (void)
  152. {
  153. int i;
  154. for (i = 0; key_table[i].key_code; i++)
  155. do_define_key (key_table[i].key_code, key_table[i].key_name);
  156. }
  157. /* --------------------------------------------------------------------------------------------- */
  158. /*** public functions ****************************************************************************/
  159. /* --------------------------------------------------------------------------------------------- */
  160. int
  161. mc_tty_normalize_lines_char (const char *str)
  162. {
  163. char *str2;
  164. int res;
  165. struct mc_tty_lines_struct
  166. {
  167. const char *line;
  168. int line_code;
  169. } const lines_codes[] = {
  170. {"\342\224\214", SLSMG_ULCORN_CHAR},
  171. {"\342\224\220", SLSMG_URCORN_CHAR},
  172. {"\342\224\224", SLSMG_LLCORN_CHAR},
  173. {"\342\224\230", SLSMG_LRCORN_CHAR},
  174. {"\342\224\234", SLSMG_LTEE_CHAR},
  175. {"\342\224\244", SLSMG_RTEE_CHAR},
  176. {"\342\224\254", SLSMG_UTEE_CHAR},
  177. {"\342\224\264", SLSMG_DTEE_CHAR},
  178. {"\342\224\200", SLSMG_HLINE_CHAR},
  179. {"\342\224\202", SLSMG_VLINE_CHAR},
  180. {"\342\224\274", SLSMG_PLUS_CHAR},
  181. {NULL, 0}
  182. };
  183. if (!str)
  184. return (int) ' ';
  185. for (res = 0; lines_codes[res].line; res++)
  186. {
  187. if (strcmp (str, lines_codes[res].line) == 0)
  188. return lines_codes[res].line_code;
  189. }
  190. str2 = mc_tty_normalize_from_utf8 (str);
  191. res = g_utf8_get_char_validated (str2, -1);
  192. if (res < 0)
  193. res = (unsigned char) str2[0];
  194. g_free (str2);
  195. return res;
  196. }
  197. /* --------------------------------------------------------------------------------------------- */
  198. void
  199. tty_init (gboolean slow, gboolean ugly_lines)
  200. {
  201. slow_tty = slow;
  202. ugly_line_drawing = ugly_lines;
  203. SLtt_Ignore_Beep = 1;
  204. SLtt_get_terminfo ();
  205. SLutf8_enable (-1);
  206. /*
  207. * If the terminal in not in terminfo but begins with a well-known
  208. * string such as "linux" or "xterm" S-Lang will go on, but the
  209. * terminal size and several other variables won't be initialized
  210. * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
  211. * small, large and negative screen dimensions.
  212. */
  213. if ((COLS < 10) || (LINES < 5)
  214. || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS))
  215. {
  216. fprintf (stderr,
  217. _("Screen size %dx%d is not supported.\n"
  218. "Check the TERM environment variable.\n"), COLS, LINES);
  219. exit (EXIT_FAILURE);
  220. }
  221. tcgetattr (fileno (stdin), &boot_mode);
  222. /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
  223. SLang_init_tty (XCTRL ('g'), 1, 0);
  224. if (ugly_lines)
  225. SLtt_Has_Alt_Charset = 0;
  226. /* If SLang uses fileno(stderr) for terminal input MC will hang
  227. if we call SLang_getkey between calls to open_error_pipe and
  228. close_error_pipe, e.g. when we do a growing view of an gzipped
  229. file. */
  230. if (SLang_TT_Read_FD == fileno (stderr))
  231. SLang_TT_Read_FD = fileno (stdin);
  232. if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0)
  233. {
  234. #ifdef VDSUSP
  235. new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
  236. #endif
  237. #ifdef VLNEXT
  238. new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
  239. #endif
  240. tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
  241. }
  242. tty_reset_prog_mode ();
  243. load_terminfo_keys ();
  244. SLtt_Blink_Mode = 0;
  245. tty_start_interrupt_key ();
  246. /* It's the small part from the previous init_key() */
  247. init_key_input_fd ();
  248. SLsmg_init_smg ();
  249. do_enter_ca_mode ();
  250. tty_keypad (TRUE);
  251. tty_nodelay (FALSE);
  252. }
  253. /* --------------------------------------------------------------------------------------------- */
  254. void
  255. tty_shutdown (void)
  256. {
  257. char *op_cap;
  258. SLsmg_reset_smg ();
  259. tty_reset_shell_mode ();
  260. do_exit_ca_mode ();
  261. SLang_reset_tty ();
  262. /* Load the op capability to reset the colors to those that were
  263. * active when the program was started up
  264. */
  265. op_cap = SLtt_tgetstr ((char *) "op");
  266. if (op_cap != NULL)
  267. {
  268. fputs (op_cap, stdout);
  269. fflush (stdout);
  270. }
  271. }
  272. /* --------------------------------------------------------------------------------------------- */
  273. /* Done each time we come back from done mode */
  274. void
  275. tty_reset_prog_mode (void)
  276. {
  277. tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
  278. SLsmg_init_smg ();
  279. SLsmg_touch_lines (0, LINES);
  280. }
  281. /* --------------------------------------------------------------------------------------------- */
  282. /* Called each time we want to shutdown slang screen manager */
  283. void
  284. tty_reset_shell_mode (void)
  285. {
  286. tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
  287. }
  288. /* --------------------------------------------------------------------------------------------- */
  289. void
  290. tty_raw_mode (void)
  291. {
  292. tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
  293. }
  294. /* --------------------------------------------------------------------------------------------- */
  295. void
  296. tty_noraw_mode (void)
  297. {
  298. }
  299. /* --------------------------------------------------------------------------------------------- */
  300. void
  301. tty_noecho (void)
  302. {
  303. }
  304. /* --------------------------------------------------------------------------------------------- */
  305. int
  306. tty_flush_input (void)
  307. {
  308. return 0; /* OK */
  309. }
  310. /* --------------------------------------------------------------------------------------------- */
  311. void
  312. tty_keypad (gboolean set)
  313. {
  314. char *keypad_string;
  315. keypad_string = (char *) SLtt_tgetstr ((char *) (set ? "ks" : "ke"));
  316. if (keypad_string != NULL)
  317. SLtt_write_string (keypad_string);
  318. if (set && reset_hp_softkeys)
  319. slang_reset_softkeys ();
  320. }
  321. /* --------------------------------------------------------------------------------------------- */
  322. void
  323. tty_nodelay (gboolean set)
  324. {
  325. no_slang_delay = set;
  326. }
  327. /* --------------------------------------------------------------------------------------------- */
  328. int
  329. tty_baudrate (void)
  330. {
  331. return SLang_TT_Baud_Rate;
  332. }
  333. /* --------------------------------------------------------------------------------------------- */
  334. int
  335. tty_lowlevel_getch (void)
  336. {
  337. int c;
  338. if (no_slang_delay && (SLang_input_pending (0) == 0))
  339. return -1;
  340. c = SLang_getkey ();
  341. if (c == SLANG_GETKEY_ERROR)
  342. {
  343. fprintf (stderr,
  344. "SLang_getkey returned SLANG_GETKEY_ERROR\n"
  345. "Assuming EOF on stdin and exiting\n");
  346. exit (EXIT_FAILURE);
  347. }
  348. return c;
  349. }
  350. /* --------------------------------------------------------------------------------------------- */
  351. int
  352. tty_reset_screen (void)
  353. {
  354. SLsmg_reset_smg ();
  355. return 0; /* OK */
  356. }
  357. /* --------------------------------------------------------------------------------------------- */
  358. void
  359. tty_touch_screen (void)
  360. {
  361. SLsmg_touch_lines (0, LINES);
  362. }
  363. /* --------------------------------------------------------------------------------------------- */
  364. void
  365. tty_gotoyx (int y, int x)
  366. {
  367. SLsmg_gotorc (y, x);
  368. }
  369. /* --------------------------------------------------------------------------------------------- */
  370. void
  371. tty_getyx (int *py, int *px)
  372. {
  373. *py = SLsmg_get_row ();
  374. *px = SLsmg_get_column ();
  375. }
  376. /* --------------------------------------------------------------------------------------------- */
  377. /* if x < 0 or y < 0, draw line staring from current position */
  378. void
  379. tty_draw_hline (int y, int x, int ch, int len)
  380. {
  381. if (ch == ACS_HLINE)
  382. ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
  383. if ((y < 0) || (x < 0))
  384. {
  385. y = SLsmg_get_row ();
  386. x = SLsmg_get_column ();
  387. }
  388. else
  389. SLsmg_gotorc (y, x);
  390. if (ch == 0)
  391. ch = ACS_HLINE;
  392. if (ch == ACS_HLINE)
  393. SLsmg_draw_hline (len);
  394. else
  395. while (len-- != 0)
  396. tty_print_char (ch);
  397. SLsmg_gotorc (y, x);
  398. }
  399. /* --------------------------------------------------------------------------------------------- */
  400. /* if x < 0 or y < 0, draw line staring from current position */
  401. void
  402. tty_draw_vline (int y, int x, int ch, int len)
  403. {
  404. if (ch == ACS_VLINE)
  405. ch = mc_tty_frm[MC_TTY_FRM_VERT];
  406. if ((y < 0) || (x < 0))
  407. {
  408. y = SLsmg_get_row ();
  409. x = SLsmg_get_column ();
  410. }
  411. else
  412. SLsmg_gotorc (y, x);
  413. if (ch == 0)
  414. ch = ACS_VLINE;
  415. if (ch == ACS_VLINE)
  416. SLsmg_draw_vline (len);
  417. else
  418. {
  419. int pos = 0;
  420. while (len-- != 0)
  421. {
  422. SLsmg_gotorc (y + pos, x);
  423. tty_print_char (ch);
  424. pos++;
  425. }
  426. }
  427. SLsmg_gotorc (y, x);
  428. }
  429. /* --------------------------------------------------------------------------------------------- */
  430. void
  431. tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
  432. {
  433. SLsmg_fill_region (y, x, rows, cols, ch);
  434. }
  435. /* --------------------------------------------------------------------------------------------- */
  436. void
  437. tty_set_alt_charset (gboolean alt_charset)
  438. {
  439. SLsmg_set_char_set ((int) alt_charset);
  440. }
  441. /* --------------------------------------------------------------------------------------------- */
  442. void
  443. tty_display_8bit (gboolean what)
  444. {
  445. SLsmg_Display_Eight_Bit = what ? 128 : 160;
  446. }
  447. /* --------------------------------------------------------------------------------------------- */
  448. void
  449. tty_print_char (int c)
  450. {
  451. SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
  452. }
  453. /* --------------------------------------------------------------------------------------------- */
  454. void
  455. tty_print_alt_char (int c, gboolean single)
  456. {
  457. #define DRAW(x, y) (x == y) \
  458. ? SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), x) \
  459. : SLsmg_write_char ((unsigned int) y)
  460. switch (c)
  461. {
  462. case ACS_VLINE:
  463. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
  464. break;
  465. case ACS_HLINE:
  466. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
  467. break;
  468. case ACS_LTEE:
  469. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
  470. break;
  471. case ACS_RTEE:
  472. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
  473. break;
  474. case ACS_ULCORNER:
  475. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
  476. break;
  477. case ACS_LLCORNER:
  478. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
  479. break;
  480. case ACS_URCORNER:
  481. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
  482. break;
  483. case ACS_LRCORNER:
  484. DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
  485. break;
  486. case ACS_PLUS:
  487. DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
  488. break;
  489. default:
  490. SLsmg_write_char ((unsigned int) c);
  491. }
  492. #undef DRAW
  493. }
  494. /* --------------------------------------------------------------------------------------------- */
  495. void
  496. tty_print_anychar (int c)
  497. {
  498. char str[6 + 1];
  499. if (c > 255)
  500. {
  501. int res = g_unichar_to_utf8 (c, str);
  502. if (res == 0)
  503. {
  504. str[0] = '.';
  505. str[1] = '\0';
  506. }
  507. else
  508. {
  509. str[res] = '\0';
  510. }
  511. SLsmg_write_string ((char *) str_term_form (str));
  512. }
  513. else
  514. {
  515. SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
  516. }
  517. }
  518. /* --------------------------------------------------------------------------------------------- */
  519. void
  520. tty_print_string (const char *s)
  521. {
  522. SLsmg_write_string ((char *) str_term_form (s));
  523. }
  524. /* --------------------------------------------------------------------------------------------- */
  525. void
  526. tty_printf (const char *fmt, ...)
  527. {
  528. va_list args;
  529. va_start (args, fmt);
  530. SLsmg_vprintf ((char *) fmt, args);
  531. va_end (args);
  532. }
  533. /* --------------------------------------------------------------------------------------------- */
  534. char *
  535. tty_tgetstr (const char *cap)
  536. {
  537. return SLtt_tgetstr ((char *) cap);
  538. }
  539. /* --------------------------------------------------------------------------------------------- */
  540. void
  541. tty_refresh (void)
  542. {
  543. SLsmg_refresh ();
  544. }
  545. /* --------------------------------------------------------------------------------------------- */
  546. void
  547. tty_setup_sigwinch (void (*handler) (int))
  548. {
  549. #ifdef SIGWINCH
  550. struct sigaction act, oact;
  551. act.sa_handler = handler;
  552. sigemptyset (&act.sa_mask);
  553. act.sa_flags = 0;
  554. #ifdef SA_RESTART
  555. act.sa_flags |= SA_RESTART;
  556. #endif /* SA_RESTART */
  557. sigaction (SIGWINCH, &act, &oact);
  558. #endif /* SIGWINCH */
  559. }
  560. /* --------------------------------------------------------------------------------------------- */
  561. void
  562. tty_beep (void)
  563. {
  564. SLtt_beep ();
  565. }
  566. /* --------------------------------------------------------------------------------------------- */