tty.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /*
  2. Interface to the terminal controlling library.
  3. Copyright (C) 2005, 2006, 2007, 2009, 2011
  4. The Free Software Foundation, Inc.
  5. Written by:
  6. Roland Illig <roland.illig@gmx.de>, 2005.
  7. Andrew Borodin <aborodin@vmail.ru>, 2009.
  8. This file is part of the Midnight Commander.
  9. The Midnight Commander is free software: you can redistribute it
  10. and/or modify it under the terms of the GNU General Public License as
  11. published by the Free Software Foundation, either version 3 of the License,
  12. or (at your option) any later version.
  13. The Midnight Commander is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /** \file tty.c
  21. * \brief Source: %interface to the terminal controlling library
  22. */
  23. #include <config.h>
  24. #include <signal.h>
  25. #include <stdarg.h>
  26. #include <stdlib.h>
  27. #include <unistd.h> /* exit() */
  28. #ifdef HAVE_SYS_IOCTL_H
  29. #include <sys/ioctl.h>
  30. #endif
  31. #include "lib/global.h"
  32. #include "lib/strutil.h"
  33. #include "tty.h"
  34. #include "tty-internal.h"
  35. #include "mouse.h" /* use_mouse_p */
  36. #include "win.h"
  37. /*** global variables ****************************************************************************/
  38. /* If true program softkeys (HP terminals only) on startup and after every
  39. command ran in the subshell to the description found in the termcap/terminfo
  40. database */
  41. int reset_hp_softkeys = 0;
  42. int mc_tty_frm[MC_TTY_FRM_MAX];
  43. /*** file scope macro definitions ****************************************************************/
  44. /*** file scope type declarations ****************************************************************/
  45. /*** file scope variables ************************************************************************/
  46. static volatile sig_atomic_t got_interrupt = 0;
  47. /*** file scope functions ************************************************************************/
  48. /* --------------------------------------------------------------------------------------------- */
  49. static void
  50. sigintr_handler (int signo)
  51. {
  52. (void) &signo;
  53. got_interrupt = 1;
  54. }
  55. /* --------------------------------------------------------------------------------------------- */
  56. /*** public functions ****************************************************************************/
  57. /* --------------------------------------------------------------------------------------------- */
  58. void
  59. show_clock (void)
  60. {
  61. int lngstr;
  62. time_t curtime;
  63. int yt, xt;
  64. char timestr[11] = "";
  65. clock_type = op_clock_type;
  66. if (clock_type)
  67. {
  68. curtime = time (0);
  69. if (clock_type == HOUR_MIN)
  70. {
  71. lngstr = 6;
  72. if (!(strftime (timestr, lngstr, "%R", localtime (&curtime))))
  73. strcpy (timestr, "??:??");
  74. }
  75. else if (clock_type == HOUR_MIN_SEC)
  76. {
  77. lngstr = 9;
  78. if (!(strftime (timestr, lngstr, "%X", localtime (&curtime))))
  79. strcpy (timestr, "??:??:??");
  80. }
  81. tty_getyx (&yt, &xt);
  82. tty_gotoyx (0, COLS - lngstr);
  83. tty_print_string (timestr);
  84. tty_gotoyx (yt, xt);
  85. }
  86. }
  87. /* --------------------------------------------------------------------------------------------- */
  88. void
  89. clock_interrupt_handler (void)
  90. {
  91. if (clock_type)
  92. {
  93. show_clock ();
  94. #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__)
  95. mc_refresh ();
  96. #endif
  97. #ifdef SIGACT
  98. sigaction (SIGALRM, &clock_new, &clock_dummy);
  99. #else
  100. signal (SIGALRM, clock_interrupt_handler);
  101. #endif
  102. alarm (clock_ticks);
  103. }
  104. }
  105. /* --------------------------------------------------------------------------------------------- */
  106. void
  107. set_clock_type (int ct)
  108. {
  109. if (ct == HOUR_MIN_SEC)
  110. {
  111. /* update every seconds */
  112. clock_type = ct;
  113. clock_ticks = 1;
  114. }
  115. else if (ct == HOUR_MIN)
  116. {
  117. /* update every minits */
  118. clock_type = ct;
  119. clock_ticks = 60;
  120. }
  121. else
  122. {
  123. /* no clock at all */
  124. clock_type = 0;
  125. clock_ticks = 0;
  126. }
  127. }
  128. /* --------------------------------------------------------------------------------------------- */
  129. void
  130. clock_init (void)
  131. {
  132. if (op_clock_type)
  133. {
  134. set_clock_type (op_clock_type);
  135. show_clock ();
  136. #ifdef SIGACT
  137. clock_new.sa_handler = clock_interrupt_handler;
  138. sigemptyset (&clock_new.sa_mask);
  139. clock_new.sa_flags = 0;
  140. sigaction (SIGALRM, &clock_new, &clock_old);
  141. #else
  142. clock_alarm = signal (SIGALRM, clock_interrupt_handler);
  143. #endif
  144. clock_remain = alarm (clock_ticks);
  145. }
  146. }
  147. /* --------------------------------------------------------------------------------------------- */
  148. void
  149. clock_cancel (void)
  150. {
  151. if (clock_type)
  152. {
  153. #ifdef SIGACT
  154. sigaction (SIGALRM, &clock_old, &clock_dummy);
  155. if (clock_old.sa_handler != SIG_IGN)
  156. alarm (clock_remain);
  157. #else
  158. signal (SIGALRM, clock_alarm);
  159. if (clock_alarm != SIG_IGN)
  160. alarm (clock_remain);
  161. #endif
  162. }
  163. }
  164. /* --------------------------------------------------------------------------------------------- */
  165. void
  166. clock_resume (void)
  167. {
  168. if (clock_type)
  169. clock_interrupt_handler ();
  170. }
  171. /* --------------------------------------------------------------------------------------------- */
  172. /**
  173. * Check terminal type. If $TERM is not set or value is empty, mc finishes with EXIT_FAILURE.
  174. *
  175. * @param force_xterm Set forced the XTerm type
  176. *
  177. * @return true if @param force_xterm is true or value of $TERM is one of term*, konsole*
  178. * rxvt*, Eterm or dtterm
  179. */
  180. gboolean
  181. tty_check_term (gboolean force_xterm)
  182. {
  183. const char *termvalue;
  184. termvalue = getenv ("TERM");
  185. if (termvalue == NULL || *termvalue == '\0')
  186. {
  187. fputs (_("The TERM environment variable is unset!\n"), stderr);
  188. exit (EXIT_FAILURE);
  189. }
  190. return force_xterm || strncmp (termvalue, "xterm", 5) == 0
  191. || strncmp (termvalue, "konsole", 7) == 0
  192. || strncmp (termvalue, "rxvt", 4) == 0
  193. || strcmp (termvalue, "Eterm") == 0 || strcmp (termvalue, "dtterm") == 0;
  194. }
  195. /* --------------------------------------------------------------------------------------------- */
  196. extern void
  197. tty_start_interrupt_key (void)
  198. {
  199. struct sigaction act;
  200. act.sa_handler = sigintr_handler;
  201. sigemptyset (&act.sa_mask);
  202. act.sa_flags = SA_RESTART;
  203. sigaction (SIGINT, &act, NULL);
  204. }
  205. /* --------------------------------------------------------------------------------------------- */
  206. extern void
  207. tty_enable_interrupt_key (void)
  208. {
  209. struct sigaction act;
  210. act.sa_handler = sigintr_handler;
  211. sigemptyset (&act.sa_mask);
  212. act.sa_flags = 0;
  213. sigaction (SIGINT, &act, NULL);
  214. got_interrupt = 0;
  215. }
  216. /* --------------------------------------------------------------------------------------------- */
  217. extern void
  218. tty_disable_interrupt_key (void)
  219. {
  220. struct sigaction act;
  221. act.sa_handler = SIG_IGN;
  222. sigemptyset (&act.sa_mask);
  223. act.sa_flags = 0;
  224. sigaction (SIGINT, &act, NULL);
  225. }
  226. /* --------------------------------------------------------------------------------------------- */
  227. extern gboolean
  228. tty_got_interrupt (void)
  229. {
  230. gboolean rv;
  231. rv = (got_interrupt != 0);
  232. got_interrupt = 0;
  233. return rv;
  234. }
  235. /* --------------------------------------------------------------------------------------------- */
  236. void
  237. tty_print_one_hline (gboolean single)
  238. {
  239. tty_print_alt_char (ACS_HLINE, single);
  240. }
  241. /* --------------------------------------------------------------------------------------------- */
  242. void
  243. tty_print_one_vline (gboolean single)
  244. {
  245. tty_print_alt_char (ACS_VLINE, single);
  246. }
  247. /* --------------------------------------------------------------------------------------------- */
  248. void
  249. tty_draw_box (int y, int x, int ys, int xs, gboolean single)
  250. {
  251. int y2, x2;
  252. if (ys <= 0 || xs <= 0)
  253. return;
  254. ys--;
  255. xs--;
  256. y2 = y + ys;
  257. x2 = x + xs;
  258. tty_draw_vline (y, x, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
  259. tty_draw_vline (y, x2, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT], ys);
  260. tty_draw_hline (y, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
  261. tty_draw_hline (y2, x, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ], xs);
  262. tty_gotoyx (y, x);
  263. tty_print_alt_char (ACS_ULCORNER, single);
  264. tty_gotoyx (y2, x);
  265. tty_print_alt_char (ACS_LLCORNER, single);
  266. tty_gotoyx (y, x2);
  267. tty_print_alt_char (ACS_URCORNER, single);
  268. tty_gotoyx (y2, x2);
  269. tty_print_alt_char (ACS_LRCORNER, single);
  270. }
  271. /* --------------------------------------------------------------------------------------------- */
  272. char *
  273. mc_tty_normalize_from_utf8 (const char *str)
  274. {
  275. GIConv conv;
  276. GString *buffer;
  277. const char *_system_codepage = str_detect_termencoding ();
  278. if (str_isutf8 (_system_codepage))
  279. return g_strdup (str);
  280. conv = g_iconv_open (_system_codepage, "UTF-8");
  281. if (conv == INVALID_CONV)
  282. return g_strdup (str);
  283. buffer = g_string_new ("");
  284. if (str_convert (conv, str, buffer) == ESTR_FAILURE)
  285. {
  286. g_string_free (buffer, TRUE);
  287. str_close_conv (conv);
  288. return g_strdup (str);
  289. }
  290. str_close_conv (conv);
  291. return g_string_free (buffer, FALSE);
  292. }
  293. /* --------------------------------------------------------------------------------------------- */
  294. /** Resize given terminal using TIOCSWINSZ, return ioctl() result */
  295. int
  296. tty_resize (int fd)
  297. {
  298. #if defined TIOCSWINSZ
  299. struct winsize tty_size;
  300. tty_size.ws_row = LINES;
  301. tty_size.ws_col = COLS;
  302. tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
  303. return ioctl (fd, TIOCSWINSZ, &tty_size);
  304. #else
  305. return 0;
  306. #endif
  307. }
  308. /* --------------------------------------------------------------------------------------------- */
  309. void
  310. tty_change_screen_size (void)
  311. {
  312. #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
  313. #if defined TIOCGWINSZ
  314. struct winsize winsz;
  315. winsz.ws_col = winsz.ws_row = 0;
  316. /* Ioctl on the STDIN_FILENO */
  317. ioctl (0, TIOCGWINSZ, &winsz);
  318. if (winsz.ws_col && winsz.ws_row)
  319. {
  320. #if defined(NCURSES_VERSION) && defined(HAVE_RESIZETERM)
  321. resizeterm (winsz.ws_row, winsz.ws_col);
  322. clearok (stdscr, TRUE); /* sigwinch's should use a semaphore! */
  323. #else
  324. COLS = winsz.ws_col;
  325. LINES = winsz.ws_row;
  326. #endif
  327. #ifdef HAVE_SUBSHELL_SUPPORT
  328. if (!mc_global.tty.use_subshell)
  329. return;
  330. tty_resize (mc_global.tty.subshell_pty);
  331. #endif
  332. }
  333. #endif /* TIOCGWINSZ */
  334. #endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
  335. }
  336. /* --------------------------------------------------------------------------------------------- */
  337. void
  338. tty_init_xterm_support (gboolean is_xterm)
  339. {
  340. const char *termvalue;
  341. termvalue = getenv ("TERM");
  342. /* Check mouse and ca capabilities */
  343. /* terminfo/termcap structures have been already initialized,
  344. in slang_init() or/and init_curses() */
  345. /* Check terminfo at first, then check termcap */
  346. xmouse_seq = tty_tgetstr ("kmous");
  347. if (xmouse_seq == NULL)
  348. xmouse_seq = tty_tgetstr ("Km");
  349. smcup = tty_tgetstr ("smcup");
  350. if (smcup == NULL)
  351. smcup = tty_tgetstr ("ti");
  352. rmcup = tty_tgetstr ("rmcup");
  353. if (rmcup == NULL)
  354. rmcup = tty_tgetstr ("te");
  355. if (strcmp (termvalue, "cygwin") == 0)
  356. {
  357. is_xterm = TRUE;
  358. use_mouse_p = MOUSE_DISABLED;
  359. }
  360. if (is_xterm)
  361. {
  362. /* Default to the standard xterm sequence */
  363. if (xmouse_seq == NULL)
  364. xmouse_seq = ESC_STR "[M";
  365. /* Enable mouse unless explicitly disabled by --nomouse */
  366. if (use_mouse_p != MOUSE_DISABLED)
  367. {
  368. if (mc_global.tty.old_mouse)
  369. use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
  370. else
  371. {
  372. /* FIXME: this dirty hack to set supported type of tracking the mouse */
  373. const char *color_term = getenv ("COLORTERM");
  374. if (strncmp (termvalue, "rxvt", 4) == 0 ||
  375. (color_term != NULL && strncmp (color_term, "rxvt", 4) == 0) ||
  376. strcmp (termvalue, "Eterm") == 0)
  377. use_mouse_p = MOUSE_XTERM_NORMAL_TRACKING;
  378. else
  379. use_mouse_p = MOUSE_XTERM_BUTTON_EVENT_TRACKING;
  380. }
  381. }
  382. }
  383. }
  384. /* --------------------------------------------------------------------------------------------- */