void ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal, ply_terminal_active_vt_changed_handler_t active_vt_changed_handler, void *user_data) { ply_list_node_t *node; if (!ply_terminal_is_vt (terminal)) return; node = ply_list_get_first_node (terminal->vt_change_closures); while (node != NULL) { ply_terminal_active_vt_changed_closure_t *closure; ply_list_node_t *next_node; closure = ply_list_node_get_data (node); next_node = ply_list_get_next_node (terminal->vt_change_closures, node); if (closure->handler == active_vt_changed_handler && closure->user_data == user_data) { free (closure); ply_list_remove_node (terminal->vt_change_closures, node); } node = next_node; } }
void ply_terminal_set_mode (ply_terminal_t *terminal, ply_terminal_mode_t mode) { assert (terminal != NULL); assert (mode == PLY_TERMINAL_MODE_TEXT || mode == PLY_TERMINAL_MODE_GRAPHICS); if (!ply_terminal_is_vt (terminal)) return; if (terminal->should_ignore_mode_changes) return; switch (mode) { case PLY_TERMINAL_MODE_TEXT: if (ioctl (terminal->fd, KDSETMODE, KD_TEXT) < 0) return; break; case PLY_TERMINAL_MODE_GRAPHICS: if (ioctl (terminal->fd, KDSETMODE, KD_GRAPHICS) < 0) return; break; } }
void ply_terminal_watch_for_vt_changes (ply_terminal_t *terminal) { assert (terminal != NULL); struct vt_mode mode = { 0 }; if (terminal->fd < 0) return; if (!ply_terminal_is_vt (terminal)) return; if (terminal->is_watching_for_vt_changes) return; mode.mode = VT_PROCESS; mode.relsig = SIGUSR1; mode.acqsig = SIGUSR2; if (ioctl (terminal->fd, VT_SETMODE, &mode) < 0) return; ply_event_loop_watch_signal (terminal->loop, SIGUSR1, (ply_event_handler_t) on_leave_vt, terminal); ply_event_loop_watch_signal (terminal->loop, SIGUSR2, (ply_event_handler_t) on_enter_vt, terminal); terminal->is_watching_for_vt_changes = true; }
static bool open_device (ply_renderer_backend_t *backend) { assert (backend != NULL); assert (backend->device_name != NULL); if (!load_driver (backend)) return false; if (!ply_terminal_open (backend->terminal)) { ply_trace ("could not open terminal: %m"); return false; } if (!ply_terminal_is_vt (backend->terminal)) { ply_trace ("terminal is not a VT"); ply_terminal_close (backend->terminal); return false; } ply_terminal_watch_for_active_vt_change (backend->terminal, (ply_terminal_active_vt_changed_handler_t) on_active_vt_changed, backend); return true; }
void ply_terminal_ignore_mode_changes (ply_terminal_t *terminal, bool should_ignore) { if (!ply_terminal_is_vt (terminal)) return; terminal->should_ignore_mode_changes = should_ignore; }
bool ply_terminal_deactivate_vt (ply_terminal_t *terminal) { int old_vt_number; assert (terminal != NULL); if (!ply_terminal_is_vt (terminal)) { ply_trace ("terminal is not for a VT"); return false; } if (terminal->initial_vt_number < 0) { ply_trace ("Don't know where to jump to"); return false; } if (terminal->initial_vt_number == terminal->vt_number) { ply_trace ("can't deactivate initial VT"); return false; } /* Otherwise we'd close and free the terminal before handling the * "leaving the VT" signal. */ ply_terminal_stop_watching_for_vt_changes (terminal); old_vt_number = terminal->vt_number; if (ply_terminal_is_active (terminal)) { ply_trace ("Attempting to set active vt back to %d from %d", terminal->initial_vt_number, old_vt_number); if (!set_active_vt (terminal, terminal->initial_vt_number)) { ply_trace ("Couldn't move console to initial vt: %m"); return false; } if (!wait_for_vt_to_become_active (terminal, terminal->initial_vt_number)) { ply_trace ("Error while waiting for vt %d to become active: %m", terminal->initial_vt_number); return false; } } else { ply_trace ("terminal for vt %d is inactive", terminal->vt_number); } if (!deallocate_vt (terminal, old_vt_number)) { ply_trace ("couldn't deallocate vt %d: %m", old_vt_number); return false; } return true; }
void ply_terminal_watch_for_active_vt_change (ply_terminal_t *terminal, ply_terminal_active_vt_changed_handler_t active_vt_changed_handler, void *user_data) { ply_terminal_active_vt_changed_closure_t *closure; if (!ply_terminal_is_vt (terminal)) return; closure = calloc (1, sizeof(*closure)); closure->handler = active_vt_changed_handler; closure->user_data = user_data; ply_list_append_data (terminal->vt_change_closures, closure); }
bool ply_terminal_open (ply_terminal_t *terminal) { ply_terminal_open_result_t open_result; assert (terminal != NULL); if (terminal->is_open) { ply_trace ("terminal %s is already open", terminal->name); return true; } ply_trace ("trying to open terminal '%s'", terminal->name); open_result = ply_terminal_open_device (terminal); if (open_result != PLY_TERMINAL_OPEN_RESULT_SUCCESS) { ply_trace ("could not open %s : %m", terminal->name); return false; } ply_terminal_refresh_geometry (terminal); ply_terminal_look_up_color_palette (terminal); ply_terminal_save_color_palette (terminal); ply_event_loop_watch_signal (terminal->loop, SIGWINCH, (ply_event_handler_t) ply_terminal_refresh_geometry, terminal); if (ply_terminal_is_vt (terminal)) { ply_terminal_watch_for_vt_changes (terminal); if (get_active_vt (terminal) == terminal->vt_number) terminal->is_active = true; else terminal->is_active = false; } terminal->is_open = true; return true; }
bool ply_terminal_activate_vt (ply_terminal_t *terminal) { assert (terminal != NULL); if (!ply_terminal_is_vt (terminal)) return false; if (terminal->is_active) return true; if (!set_active_vt (terminal, terminal->vt_number)) { ply_trace ("unable to set active vt to %d: %m", terminal->vt_number); return false; } return true; }
void ply_terminal_stop_watching_for_vt_changes (ply_terminal_t *terminal) { struct vt_mode mode = { 0 }; if (!ply_terminal_is_vt (terminal)) return; if (!terminal->is_watching_for_vt_changes) return; terminal->is_watching_for_vt_changes = false; ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR1); ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR2); mode.mode = VT_AUTO; ioctl (terminal->fd, VT_SETMODE, &mode); }