/* * This file is part of mpv. * * by rr- * * mpv is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with mpv. If not, see . */ #include #include #include #include #include #include #include "drm_common.h" #include "common/common.h" #include "common/msg.h" #include "osdep/io.h" #define EVT_RELEASE 1 #define EVT_ACQUIRE 2 #define EVT_INTERRUPT 255 #define HANDLER_ACQUIRE 0 #define HANDLER_RELEASE 1 static int vt_switcher_pipe[2]; static void vt_switcher_sighandler(int sig) { unsigned char event = sig == SIGUSR1 ? EVT_RELEASE : EVT_ACQUIRE; write(vt_switcher_pipe[1], &event, sizeof(event)); } int vt_switcher_init(struct vt_switcher *s, struct mp_log *log) { s->log = log; s->tty_fd = -1; vt_switcher_pipe[0] = -1; vt_switcher_pipe[1] = -1; if (mp_make_cloexec_pipe(vt_switcher_pipe)) { MP_ERR(s, "Creating pipe failed: %s", mp_strerror(errno)); return -1; } s->tty_fd = open("/dev/tty", O_RDWR | O_CLOEXEC); if (s->tty_fd < 0) { MP_ERR(s, "Can't open TTY for VT control: %s", mp_strerror(errno)); return -1; } struct sigaction act; act.sa_handler = vt_switcher_sighandler; act.sa_flags = SA_RESTART; sigemptyset(&act.sa_mask); sigaction(SIGUSR1, &act, 0); sigaction(SIGUSR2, &act, 0); struct vt_mode vt_mode; if (ioctl(s->tty_fd, VT_GETMODE, &vt_mode) < 0) { MP_ERR(s, "VT_GETMODE failed: %s", mp_strerror(errno)); return -1; } vt_mode.mode = VT_PROCESS; vt_mode.relsig = SIGUSR1; vt_mode.acqsig = SIGUSR2; if (ioctl(s->tty_fd, VT_SETMODE, &vt_mode) < 0) { MP_ERR(s, "VT_SETMODE failed: %s", mp_strerror(errno)); return -1; } return 0; } void vt_switcher_acquire(struct vt_switcher *s, void (*handler)(void*), void *user_data) { s->handlers[HANDLER_ACQUIRE] = handler; s->handler_data[HANDLER_ACQUIRE] = user_data; } void vt_switcher_release(struct vt_switcher *s, void (*handler)(void*), void *user_data) { s->handlers[HANDLER_RELEASE] = handler; s->handler_data[HANDLER_RELEASE] = user_data; } void vt_switcher_interrupt_poll(struct vt_switcher *s) { unsigned char event = EVT_INTERRUPT; write(vt_switcher_pipe[1], &event, sizeof(event)); } void vt_switcher_destroy(struct vt_switcher *s) { close(s->tty_fd); close(vt_switcher_pipe[0]); close(vt_switcher_pipe[1]); } void vt_switcher_poll(struct vt_switcher *s, int timeout_ms) { struct pollfd fds[1] = { { .events = POLLIN, .fd = vt_switcher_pipe[0] }, }; poll(fds, 1, timeout_ms); if (!fds[0].revents) return; unsigned char event; if (read(fds[0].fd, &event, sizeof(event)) != sizeof(event)) return; switch (event) { case EVT_RELEASE: s->handlers[HANDLER_RELEASE](s->handler_data[HANDLER_RELEASE]); if (ioctl(s->tty_fd, VT_RELDISP, 1) < 0) { MP_ERR(s, "Failed to release virtual terminal\n"); } break; case EVT_ACQUIRE: s->handlers[HANDLER_ACQUIRE](s->handler_data[HANDLER_ACQUIRE]); if (ioctl(s->tty_fd, VT_RELDISP, VT_ACKACQ) < 0) { MP_ERR(s, "Failed to acquire virtual terminal\n"); } break; case EVT_INTERRUPT: break; } }