You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

898 lines
22 KiB

  1. /* ply-terminal.c - APIs for terminaling text
  2. *
  3. * Copyright (C) 2009 Red Hat, Inc.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  18. * 02111-1307, USA.
  19. *
  20. * Written by: Ray Strode <rstrode@redhat.com>
  21. */
  22. #include "config.h"
  23. #include "ply-terminal.h"
  24. #include <assert.h>
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #include <stdint.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/socket.h>
  32. #include <sys/stat.h>
  33. #include <sys/types.h>
  34. #include <termios.h>
  35. #include <unistd.h>
  36. #include <wchar.h>
  37. #include <linux/kd.h>
  38. #include <linux/major.h>
  39. #include <linux/vt.h>
  40. #include "ply-buffer.h"
  41. #include "ply-event-loop.h"
  42. #include "ply-list.h"
  43. #include "ply-logger.h"
  44. #include "ply-utils.h"
  45. #ifndef TEXT_PALETTE_SIZE
  46. #define TEXT_PALETTE_SIZE 48
  47. #endif
  48. typedef struct
  49. {
  50. ply_terminal_active_vt_changed_handler_t handler;
  51. void *user_data;
  52. } ply_terminal_active_vt_changed_closure_t;
  53. struct _ply_terminal
  54. {
  55. ply_event_loop_t *loop;
  56. struct termios original_term_attributes;
  57. struct termios original_locked_term_attributes;
  58. char *name;
  59. int fd;
  60. int vt_number;
  61. int initial_vt_number;
  62. ply_list_t *vt_change_closures;
  63. ply_fd_watch_t *fd_watch;
  64. ply_terminal_color_t foreground_color;
  65. ply_terminal_color_t background_color;
  66. uint8_t original_color_palette[TEXT_PALETTE_SIZE];
  67. uint8_t color_palette[TEXT_PALETTE_SIZE];
  68. int number_of_rows;
  69. int number_of_columns;
  70. uint32_t original_term_attributes_saved : 1;
  71. uint32_t original_locked_term_attributes_saved : 1;
  72. uint32_t supports_text_color : 1;
  73. uint32_t is_open : 1;
  74. uint32_t is_active : 1;
  75. uint32_t is_unbuffered : 1;
  76. uint32_t is_watching_for_vt_changes : 1;
  77. uint32_t should_ignore_mode_changes : 1;
  78. };
  79. static bool ply_terminal_open_device (ply_terminal_t *terminal);
  80. ply_terminal_t *
  81. ply_terminal_new (const char *device_name)
  82. {
  83. ply_terminal_t *terminal;
  84. assert (device_name != NULL);
  85. terminal = calloc (1, sizeof (ply_terminal_t));
  86. terminal->loop = ply_event_loop_get_default ();
  87. terminal->vt_change_closures = ply_list_new ();
  88. if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
  89. terminal->name = strdup (device_name);
  90. else
  91. asprintf (&terminal->name, "/dev/%s", device_name);
  92. terminal->fd = -1;
  93. terminal->vt_number = -1;
  94. terminal->initial_vt_number = -1;
  95. return terminal;
  96. }
  97. static void
  98. ply_terminal_look_up_color_palette (ply_terminal_t *terminal)
  99. {
  100. if (ioctl (terminal->fd, GIO_CMAP, terminal->color_palette) < 0)
  101. terminal->supports_text_color = false;
  102. else
  103. terminal->supports_text_color = true;
  104. }
  105. static bool
  106. ply_terminal_change_color_palette (ply_terminal_t *terminal)
  107. {
  108. if (!terminal->supports_text_color)
  109. return true;
  110. if (ioctl (terminal->fd, PIO_CMAP, terminal->color_palette) < 0)
  111. return false;
  112. return true;
  113. }
  114. static void
  115. ply_terminal_save_color_palette (ply_terminal_t *terminal)
  116. {
  117. if (!terminal->supports_text_color)
  118. return;
  119. memcpy (terminal->original_color_palette, terminal->color_palette,
  120. TEXT_PALETTE_SIZE);
  121. }
  122. static void
  123. ply_terminal_restore_color_palette (ply_terminal_t *terminal)
  124. {
  125. if (!terminal->supports_text_color)
  126. return;
  127. memcpy (terminal->color_palette, terminal->original_color_palette,
  128. TEXT_PALETTE_SIZE);
  129. ply_terminal_change_color_palette (terminal);
  130. }
  131. void
  132. ply_terminal_reset_colors (ply_terminal_t *terminal)
  133. {
  134. assert (terminal != NULL);
  135. ply_terminal_restore_color_palette (terminal);
  136. }
  137. bool
  138. ply_terminal_set_unbuffered_input (ply_terminal_t *terminal)
  139. {
  140. struct termios term_attributes;
  141. struct termios locked_term_attributes;
  142. tcgetattr (terminal->fd, &term_attributes);
  143. if (!terminal->original_term_attributes_saved)
  144. {
  145. terminal->original_term_attributes = term_attributes;
  146. terminal->original_term_attributes_saved = true;
  147. }
  148. cfmakeraw (&term_attributes);
  149. /* Make \n return go to the beginning of the next line */
  150. term_attributes.c_oflag |= ONLCR;
  151. if (tcsetattr (terminal->fd, TCSANOW, &term_attributes) != 0)
  152. return false;
  153. if (!terminal->original_locked_term_attributes_saved &&
  154. ioctl (terminal->fd, TIOCGLCKTRMIOS, &locked_term_attributes) == 0)
  155. {
  156. terminal->original_locked_term_attributes = locked_term_attributes;
  157. terminal->original_locked_term_attributes_saved = true;
  158. memset (&locked_term_attributes, 0xff, sizeof (locked_term_attributes));
  159. if (ioctl (terminal->fd, TIOCSLCKTRMIOS, &locked_term_attributes) < 0)
  160. {
  161. ply_trace ("couldn't lock terminal settings: %m");
  162. }
  163. }
  164. terminal->is_unbuffered = true;
  165. return true;
  166. }
  167. bool
  168. ply_terminal_set_buffered_input (ply_terminal_t *terminal)
  169. {
  170. struct termios term_attributes;
  171. if (!terminal->is_unbuffered)
  172. return true;
  173. if (terminal->original_locked_term_attributes_saved)
  174. {
  175. if (ioctl (terminal->fd, TIOCSLCKTRMIOS,
  176. &terminal->original_locked_term_attributes) < 0)
  177. {
  178. ply_trace ("couldn't unlock terminal settings: %m");
  179. }
  180. terminal->original_locked_term_attributes_saved = false;
  181. }
  182. tcgetattr (terminal->fd, &term_attributes);
  183. /* If someone already messed with the terminal settings,
  184. * and they seem good enough, bail
  185. */
  186. if (term_attributes.c_lflag & ICANON)
  187. {
  188. terminal->is_unbuffered = false;
  189. return true;
  190. }
  191. /* If we don't know the original term attributes, or they were originally sucky,
  192. * then invent some that are probably good enough.
  193. */
  194. if (!terminal->original_term_attributes_saved || !(terminal->original_term_attributes.c_lflag & ICANON))
  195. {
  196. term_attributes.c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
  197. term_attributes.c_oflag |= OPOST;
  198. term_attributes.c_lflag |= ECHO | ICANON | ISIG | IEXTEN;
  199. if (tcsetattr (terminal->fd, TCSAFLUSH, &term_attributes) != 0)
  200. return false;
  201. terminal->is_unbuffered = false;
  202. return true;
  203. }
  204. if (tcsetattr (terminal->fd, TCSAFLUSH, &terminal->original_term_attributes) != 0)
  205. return false;
  206. terminal->is_unbuffered = false;
  207. return true;
  208. }
  209. void
  210. ply_terminal_write (ply_terminal_t *terminal,
  211. const char *format,
  212. ...)
  213. {
  214. va_list args;
  215. char *string;
  216. assert (terminal != NULL);
  217. assert (format != NULL);
  218. string = NULL;
  219. va_start (args, format);
  220. vasprintf (&string, format, args);
  221. va_end (args);
  222. write (terminal->fd, string, strlen (string));
  223. free (string);
  224. }
  225. static void
  226. on_tty_disconnected (ply_terminal_t *terminal)
  227. {
  228. ply_trace ("tty disconnected (fd %d)", terminal->fd);
  229. terminal->fd_watch = NULL;
  230. terminal->fd = -1;
  231. ply_trace ("trying to reopen terminal '%s'", terminal->name);
  232. ply_terminal_open_device (terminal);
  233. }
  234. static bool
  235. ply_terminal_look_up_geometry (ply_terminal_t *terminal)
  236. {
  237. struct winsize terminal_size;
  238. ply_trace ("looking up terminal text geometry");
  239. if (ioctl (terminal->fd, TIOCGWINSZ, &terminal_size) < 0)
  240. {
  241. ply_trace ("could not read terminal text geometry: %m");
  242. terminal->number_of_columns = 80;
  243. terminal->number_of_rows = 24;
  244. return false;
  245. }
  246. terminal->number_of_rows = terminal_size.ws_row;
  247. terminal->number_of_columns = terminal_size.ws_col;
  248. ply_trace ("terminal is now %dx%d text cells",
  249. terminal->number_of_columns,
  250. terminal->number_of_rows);
  251. return true;
  252. }
  253. static void
  254. ply_terminal_check_for_vt (ply_terminal_t *terminal)
  255. {
  256. int major_number, minor_number;
  257. struct stat file_attributes;
  258. assert (terminal != NULL);
  259. assert (terminal->fd >= 0);
  260. if (fstat (terminal->fd, &file_attributes) != 0)
  261. return;
  262. major_number = major (file_attributes.st_rdev);
  263. minor_number = minor (file_attributes.st_rdev);
  264. if ((major_number == TTY_MAJOR) && (minor_number <= MAX_NR_CONSOLES))
  265. terminal->vt_number = minor_number;
  266. else
  267. terminal->vt_number = -1;
  268. }
  269. static int
  270. get_active_vt (ply_terminal_t *terminal)
  271. {
  272. struct vt_stat vt_state = { 0 };
  273. if (ioctl (terminal->fd, VT_GETSTATE, &vt_state) < 0)
  274. return -1;
  275. if (terminal->initial_vt_number < 0)
  276. {
  277. terminal->initial_vt_number = vt_state.v_active;
  278. ply_trace ("Remembering that initial vt is %d",
  279. terminal->initial_vt_number);
  280. }
  281. return vt_state.v_active;
  282. }
  283. static void
  284. do_active_vt_changed (ply_terminal_t *terminal)
  285. {
  286. ply_list_node_t *node;
  287. node = ply_list_get_first_node (terminal->vt_change_closures);
  288. while (node != NULL)
  289. {
  290. ply_terminal_active_vt_changed_closure_t *closure;
  291. ply_list_node_t *next_node;
  292. closure = ply_list_node_get_data (node);
  293. next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
  294. if (closure->handler != NULL)
  295. closure->handler (closure->user_data, terminal);
  296. node = next_node;
  297. }
  298. }
  299. static void
  300. on_leave_vt (ply_terminal_t *terminal)
  301. {
  302. ioctl (terminal->fd, VT_RELDISP, 1);
  303. terminal->is_active = false;
  304. do_active_vt_changed (terminal);
  305. }
  306. static void
  307. on_enter_vt (ply_terminal_t *terminal)
  308. {
  309. ioctl (terminal->fd, VT_RELDISP, VT_ACKACQ);
  310. terminal->is_active = true;
  311. do_active_vt_changed (terminal);
  312. }
  313. void
  314. ply_terminal_watch_for_vt_changes (ply_terminal_t *terminal)
  315. {
  316. assert (terminal != NULL);
  317. struct vt_mode mode = { 0 };
  318. if (terminal->fd < 0)
  319. return;
  320. if (!ply_terminal_is_vt (terminal))
  321. return;
  322. if (terminal->is_watching_for_vt_changes)
  323. return;
  324. mode.mode = VT_PROCESS;
  325. mode.relsig = SIGUSR1;
  326. mode.acqsig = SIGUSR2;
  327. if (ioctl (terminal->fd, VT_SETMODE, &mode) < 0)
  328. return;
  329. ply_event_loop_watch_signal (terminal->loop,
  330. SIGUSR1,
  331. (ply_event_handler_t)
  332. on_leave_vt, terminal);
  333. ply_event_loop_watch_signal (terminal->loop,
  334. SIGUSR2,
  335. (ply_event_handler_t)
  336. on_enter_vt, terminal);
  337. terminal->is_watching_for_vt_changes = true;
  338. }
  339. void
  340. ply_terminal_stop_watching_for_vt_changes (ply_terminal_t *terminal)
  341. {
  342. struct vt_mode mode = { 0 };
  343. if (!ply_terminal_is_vt (terminal))
  344. return;
  345. if (!terminal->is_watching_for_vt_changes)
  346. return;
  347. terminal->is_watching_for_vt_changes = false;
  348. ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR1);
  349. ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR2);
  350. mode.mode = VT_AUTO;
  351. ioctl (terminal->fd, VT_SETMODE, &mode);
  352. }
  353. static bool
  354. ply_terminal_open_device (ply_terminal_t *terminal)
  355. {
  356. assert (terminal != NULL);
  357. assert (terminal->name != NULL);
  358. assert (terminal->fd < 0);
  359. assert (terminal->fd_watch == NULL);
  360. terminal->fd = open (terminal->name, O_RDWR | O_NOCTTY);
  361. if (terminal->fd < 0)
  362. return false;
  363. terminal->fd_watch = ply_event_loop_watch_fd (terminal->loop, terminal->fd,
  364. PLY_EVENT_LOOP_FD_STATUS_NONE,
  365. (ply_event_handler_t) NULL,
  366. (ply_event_handler_t) on_tty_disconnected,
  367. terminal);
  368. ply_terminal_check_for_vt (terminal);
  369. if (!ply_terminal_set_unbuffered_input (terminal))
  370. ply_trace ("terminal '%s' will be line buffered", terminal->name);
  371. return true;
  372. }
  373. bool
  374. ply_terminal_open (ply_terminal_t *terminal)
  375. {
  376. assert (terminal != NULL);
  377. if (terminal->is_open)
  378. {
  379. ply_trace ("terminal %s is already open", terminal->name);
  380. return true;
  381. }
  382. ply_trace ("trying to open terminal '%s'", terminal->name);
  383. if (!ply_terminal_open_device (terminal))
  384. {
  385. ply_trace ("could not open %s : %m", terminal->name);
  386. return false;
  387. }
  388. ply_terminal_look_up_geometry (terminal);
  389. ply_terminal_look_up_color_palette (terminal);
  390. ply_terminal_save_color_palette (terminal);
  391. ply_event_loop_watch_signal (terminal->loop,
  392. SIGWINCH,
  393. (ply_event_handler_t)
  394. ply_terminal_look_up_geometry,
  395. terminal);
  396. if (ply_terminal_is_vt (terminal))
  397. {
  398. ply_terminal_watch_for_vt_changes (terminal);
  399. if (get_active_vt (terminal) == terminal->vt_number)
  400. terminal->is_active = true;
  401. else
  402. terminal->is_active = false;
  403. }
  404. terminal->is_open = true;
  405. return true;
  406. }
  407. int
  408. ply_terminal_get_fd (ply_terminal_t *terminal)
  409. {
  410. return terminal->fd;
  411. }
  412. bool
  413. ply_terminal_is_vt (ply_terminal_t *terminal)
  414. {
  415. return terminal->vt_number > 0;
  416. }
  417. bool
  418. ply_terminal_is_open (ply_terminal_t *terminal)
  419. {
  420. return terminal->is_open;
  421. }
  422. bool
  423. ply_terminal_is_active (ply_terminal_t *terminal)
  424. {
  425. return terminal->is_active;
  426. }
  427. void
  428. ply_terminal_close (ply_terminal_t *terminal)
  429. {
  430. if (!terminal->is_open)
  431. {
  432. ply_trace ("terminal %s is already closed", terminal->name);
  433. return;
  434. }
  435. terminal->is_open = false;
  436. ply_terminal_stop_watching_for_vt_changes (terminal);
  437. ply_trace ("restoring color palette");
  438. ply_terminal_restore_color_palette (terminal);
  439. if (terminal->fd_watch != NULL)
  440. {
  441. ply_trace ("stop watching tty fd");
  442. ply_event_loop_stop_watching_fd (terminal->loop, terminal->fd_watch);
  443. terminal->fd_watch = NULL;
  444. }
  445. if (terminal->loop != NULL)
  446. {
  447. ply_trace ("stop watching SIGWINCH signal");
  448. ply_event_loop_stop_watching_signal (terminal->loop, SIGWINCH);
  449. }
  450. ply_trace ("setting buffered input");
  451. ply_terminal_set_buffered_input (terminal);
  452. close (terminal->fd);
  453. terminal->fd = -1;
  454. }
  455. int
  456. ply_terminal_get_number_of_columns (ply_terminal_t *terminal)
  457. {
  458. return terminal->number_of_columns;
  459. }
  460. int
  461. ply_terminal_get_number_of_rows (ply_terminal_t *terminal)
  462. {
  463. return terminal->number_of_rows;
  464. }
  465. uint32_t
  466. ply_terminal_get_color_hex_value (ply_terminal_t *terminal,
  467. ply_terminal_color_t color)
  468. {
  469. uint8_t red, green, blue;
  470. uint32_t hex_value;
  471. assert (terminal != NULL);
  472. assert (color <= PLY_TERMINAL_COLOR_WHITE);
  473. red = (uint8_t) *(terminal->color_palette + 3 * color);
  474. green = (uint8_t) *(terminal->color_palette + 3 * color + 1);
  475. blue = (uint8_t) *(terminal->color_palette + 3 * color + 2);
  476. hex_value = red << 16 | green << 8 | blue;
  477. return hex_value;
  478. }
  479. void
  480. ply_terminal_set_color_hex_value (ply_terminal_t *terminal,
  481. ply_terminal_color_t color,
  482. uint32_t hex_value)
  483. {
  484. uint8_t red, green, blue;
  485. assert (terminal != NULL);
  486. assert (color <= PLY_TERMINAL_COLOR_WHITE);
  487. red = (uint8_t) ((hex_value >> 16) & 0xff);
  488. green = (uint8_t) ((hex_value >> 8) & 0xff);
  489. blue = (uint8_t) (hex_value & 0xff);
  490. *(terminal->color_palette + 3 * color) = red;
  491. *(terminal->color_palette + 3 * color + 1) = green;
  492. *(terminal->color_palette + 3 * color + 2) = blue;
  493. ply_terminal_change_color_palette (terminal);
  494. }
  495. bool
  496. ply_terminal_supports_color (ply_terminal_t *terminal)
  497. {
  498. return terminal->supports_text_color;
  499. }
  500. void
  501. ply_terminal_set_mode (ply_terminal_t *terminal,
  502. ply_terminal_mode_t mode)
  503. {
  504. assert (terminal != NULL);
  505. assert (mode == PLY_TERMINAL_MODE_TEXT || mode == PLY_TERMINAL_MODE_GRAPHICS);
  506. if (!ply_terminal_is_vt (terminal))
  507. return;
  508. if (terminal->should_ignore_mode_changes)
  509. return;
  510. switch (mode)
  511. {
  512. case PLY_TERMINAL_MODE_TEXT:
  513. if (ioctl (terminal->fd, KDSETMODE, KD_TEXT) < 0)
  514. return;
  515. break;
  516. case PLY_TERMINAL_MODE_GRAPHICS:
  517. if (ioctl (terminal->fd, KDSETMODE, KD_GRAPHICS) < 0)
  518. return;
  519. break;
  520. }
  521. }
  522. void
  523. ply_terminal_ignore_mode_changes (ply_terminal_t *terminal,
  524. bool should_ignore)
  525. {
  526. if (!ply_terminal_is_vt (terminal))
  527. return;
  528. terminal->should_ignore_mode_changes = should_ignore;
  529. }
  530. static void
  531. ply_terminal_detach_from_event_loop (ply_terminal_t *terminal)
  532. {
  533. assert (terminal != NULL);
  534. terminal->loop = NULL;
  535. terminal->fd_watch = NULL;
  536. }
  537. static void
  538. free_vt_change_closures (ply_terminal_t *terminal)
  539. {
  540. ply_list_node_t *node;
  541. node = ply_list_get_first_node (terminal->vt_change_closures);
  542. while (node != NULL)
  543. {
  544. ply_terminal_active_vt_changed_closure_t *closure;
  545. ply_list_node_t *next_node;
  546. closure = ply_list_node_get_data (node);
  547. next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
  548. free (closure);
  549. node = next_node;
  550. }
  551. ply_list_free (terminal->vt_change_closures);
  552. }
  553. void
  554. ply_terminal_free (ply_terminal_t *terminal)
  555. {
  556. if (terminal == NULL)
  557. return;
  558. if (terminal->loop != NULL)
  559. ply_event_loop_stop_watching_for_exit (terminal->loop,
  560. (ply_event_loop_exit_handler_t)
  561. ply_terminal_detach_from_event_loop,
  562. terminal);
  563. if (terminal->is_open)
  564. ply_terminal_close (terminal);
  565. free_vt_change_closures (terminal);
  566. free (terminal->name);
  567. free (terminal);
  568. }
  569. int
  570. ply_terminal_get_vt_number (ply_terminal_t *terminal)
  571. {
  572. return terminal->vt_number;
  573. }
  574. static bool
  575. set_active_vt (ply_terminal_t *terminal,
  576. int vt_number)
  577. {
  578. if (ioctl (terminal->fd, VT_ACTIVATE, vt_number) < 0)
  579. return false;
  580. return true;
  581. }
  582. static bool
  583. wait_for_vt_to_become_active (ply_terminal_t *terminal,
  584. int vt_number)
  585. {
  586. if (ioctl (terminal->fd, VT_WAITACTIVE, vt_number) < 0)
  587. return false;
  588. return true;
  589. }
  590. static bool
  591. deallocate_vt (ply_terminal_t *terminal,
  592. int vt_number)
  593. {
  594. if (ioctl (terminal->fd, VT_DISALLOCATE, vt_number) < 0)
  595. return false;
  596. return true;
  597. }
  598. bool
  599. ply_terminal_activate_vt (ply_terminal_t *terminal)
  600. {
  601. assert (terminal != NULL);
  602. if (!ply_terminal_is_vt (terminal))
  603. return false;
  604. if (terminal->is_active)
  605. return true;
  606. if (!set_active_vt (terminal, terminal->vt_number))
  607. {
  608. ply_trace ("unable to set active vt to %d: %m",
  609. terminal->vt_number);
  610. return false;
  611. }
  612. return true;
  613. }
  614. bool
  615. ply_terminal_deactivate_vt (ply_terminal_t *terminal)
  616. {
  617. int old_vt_number;
  618. assert (terminal != NULL);
  619. if (!ply_terminal_is_vt (terminal))
  620. {
  621. ply_trace ("terminal is not for a VT");
  622. return false;
  623. }
  624. if (terminal->initial_vt_number < 0)
  625. {
  626. ply_trace ("Don't know where to jump to");
  627. return false;
  628. }
  629. if (terminal->initial_vt_number == terminal->vt_number)
  630. {
  631. ply_trace ("can't deactivate initial VT");
  632. return false;
  633. }
  634. /* Otherwise we'd close and free the terminal before handling the
  635. * "leaving the VT" signal.
  636. */
  637. ply_terminal_stop_watching_for_vt_changes (terminal);
  638. old_vt_number = terminal->vt_number;
  639. if (ply_terminal_is_active (terminal))
  640. {
  641. ply_trace ("Attempting to set active vt back to %d from %d",
  642. terminal->initial_vt_number, old_vt_number);
  643. if (!set_active_vt (terminal, terminal->initial_vt_number))
  644. {
  645. ply_trace ("Couldn't move console to initial vt: %m");
  646. return false;
  647. }
  648. if (!wait_for_vt_to_become_active (terminal, terminal->initial_vt_number))
  649. {
  650. ply_trace ("Error while waiting for vt %d to become active: %m",
  651. terminal->initial_vt_number);
  652. return false;
  653. }
  654. }
  655. else
  656. {
  657. ply_trace ("terminal for vt %d is inactive", terminal->vt_number);
  658. }
  659. if (!deallocate_vt (terminal, old_vt_number))
  660. {
  661. ply_trace ("couldn't deallocate vt %d: %m", old_vt_number);
  662. return false;
  663. }
  664. return true;
  665. }
  666. void
  667. ply_terminal_watch_for_active_vt_change (ply_terminal_t *terminal,
  668. ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
  669. void *user_data)
  670. {
  671. ply_terminal_active_vt_changed_closure_t *closure;
  672. if (!ply_terminal_is_vt (terminal))
  673. return;
  674. closure = calloc (1, sizeof (*closure));
  675. closure->handler = active_vt_changed_handler;
  676. closure->user_data = user_data;
  677. ply_list_append_data (terminal->vt_change_closures, closure);
  678. }
  679. void
  680. ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal,
  681. ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
  682. void *user_data)
  683. {
  684. ply_list_node_t *node;
  685. if (!ply_terminal_is_vt (terminal))
  686. return;
  687. node = ply_list_get_first_node (terminal->vt_change_closures);
  688. while (node != NULL)
  689. {
  690. ply_terminal_active_vt_changed_closure_t *closure;
  691. ply_list_node_t *next_node;
  692. closure = ply_list_node_get_data (node);
  693. next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
  694. if (closure->handler == active_vt_changed_handler &&
  695. closure->user_data == user_data)
  696. {
  697. free (closure);
  698. ply_list_remove_node (terminal->vt_change_closures, node);
  699. }
  700. node = next_node;
  701. }
  702. }
  703. /* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */