1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfbvthandler_p.h"
5#include <QtCore/QSocketNotifier>
6#include <QtCore/private/qglobal_p.h>
7
8#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && (QT_CONFIG(evdev) || QT_CONFIG(libinput))
9
10#define VTH_ENABLED
11
12#include <private/qcore_unix_p.h>
13#include <unistd.h>
14#include <signal.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <sys/ioctl.h>
18#include <linux/kd.h>
19
20#ifndef KDSKBMUTE
21#define KDSKBMUTE 0x4B51
22#endif
23
24#ifdef K_OFF
25#define KBD_OFF_MODE K_OFF
26#else
27#define KBD_OFF_MODE K_RAW
28#endif
29
30#endif
31
32QT_BEGIN_NAMESPACE
33
34#ifdef VTH_ENABLED
35static void setTTYCursor(bool enable)
36{
37 static bool ignore = qEnvironmentVariableIntValue(varName: "QT_QPA_PRESERVE_CONSOLE_STATE");
38 if (ignore)
39 return;
40
41 const char * const devs[] = { "/dev/tty0", "/dev/tty", "/dev/console", 0 };
42 int fd = -1;
43 for (const char * const *dev = devs; *dev; ++dev) {
44 fd = QT_OPEN(pathname: *dev, O_RDWR);
45 if (fd != -1) {
46 // Enable/disable screen blanking and the blinking cursor.
47 const char *termctl = enable ? "\033[9;15]\033[?33h\033[?25h\033[?0c" : "\033[9;0]\033[?33l\033[?25l\033[?1c";
48 QT_WRITE(fd, data: termctl, len: strlen(s: termctl) + 1);
49 QT_CLOSE(fd);
50 return;
51 }
52 }
53}
54#endif
55
56#ifdef VTH_ENABLED
57static QFbVtHandler *vth;
58
59void QFbVtHandler::signalHandler(int sigNo)
60{
61 char a = sigNo;
62 QT_WRITE(fd: vth->m_sigFd[0], data: &a, len: sizeof(a));
63}
64#endif
65
66QFbVtHandler::QFbVtHandler(QObject *parent)
67 : QObject(parent),
68 m_tty(-1),
69 m_signalNotifier(0)
70{
71#ifdef VTH_ENABLED
72 if (isatty(fd: 0))
73 m_tty = 0;
74
75 if (::socketpair(AF_UNIX, SOCK_STREAM, protocol: 0, fds: m_sigFd)) {
76 qErrnoWarning(errno, msg: "QFbVtHandler: socketpair() failed");
77 return;
78 }
79
80 vth = this;
81 setTTYCursor(false);
82 setKeyboardEnabled(false);
83
84 m_signalNotifier = new QSocketNotifier(m_sigFd[1], QSocketNotifier::Read, this);
85 connect(sender: m_signalNotifier, signal: &QSocketNotifier::activated, context: this, slot: &QFbVtHandler::handleSignal);
86
87 if (!qEnvironmentVariableIntValue(varName: "QT_QPA_NO_SIGNAL_HANDLER")) {
88 struct sigaction sa;
89 sa.sa_flags = 0;
90 sa.sa_handler = signalHandler;
91 sigemptyset(set: &sa.sa_mask);
92 sigaction(SIGINT, act: &sa, oact: 0); // Ctrl+C
93 sigaction(SIGTSTP, act: &sa, oact: 0); // Ctrl+Z
94 sigaction(SIGCONT, act: &sa, oact: 0);
95 sigaction(SIGTERM, act: &sa, oact: 0); // default signal used by kill
96 }
97#endif
98}
99
100QFbVtHandler::~QFbVtHandler()
101{
102#ifdef VTH_ENABLED
103 setKeyboardEnabled(true);
104 setTTYCursor(true);
105
106 if (m_signalNotifier) {
107 close(fd: m_sigFd[0]);
108 close(fd: m_sigFd[1]);
109 }
110#endif
111}
112
113void QFbVtHandler::setKeyboardEnabled(bool enable)
114{
115#ifdef VTH_ENABLED
116 if (m_tty == -1)
117 return;
118
119 if (enable) {
120 ::ioctl(fd: m_tty, KDSKBMUTE, 0);
121 ::ioctl(fd: m_tty, KDSKBMODE, m_oldKbdMode);
122 } else {
123 ::ioctl(fd: m_tty, KDGKBMODE, &m_oldKbdMode);
124 if (!qEnvironmentVariableIntValue(varName: "QT_QPA_ENABLE_TERMINAL_KEYBOARD")) {
125 ::ioctl(fd: m_tty, KDSKBMUTE, 1);
126 ::ioctl(fd: m_tty, KDSKBMODE, KBD_OFF_MODE);
127 }
128 }
129#else
130 Q_UNUSED(enable);
131#endif
132}
133
134void QFbVtHandler::handleSignal()
135{
136#ifdef VTH_ENABLED
137 m_signalNotifier->setEnabled(false);
138
139 char sigNo;
140 if (QT_READ(fd: m_sigFd[1], data: &sigNo, maxlen: sizeof(sigNo)) == sizeof(sigNo)) {
141 switch (sigNo) {
142 case SIGINT:
143 case SIGTERM:
144 handleInt();
145 break;
146 case SIGTSTP:
147 emit aboutToSuspend();
148 setKeyboardEnabled(true);
149 setTTYCursor(true);
150 ::kill(pid: getpid(), SIGSTOP);
151 break;
152 case SIGCONT:
153 setTTYCursor(false);
154 setKeyboardEnabled(false);
155 emit resumed();
156 break;
157 default:
158 break;
159 }
160 }
161
162 m_signalNotifier->setEnabled(true);
163#endif
164}
165
166void QFbVtHandler::handleInt()
167{
168#ifdef VTH_ENABLED
169 emit interrupted();
170 setKeyboardEnabled(true);
171 setTTYCursor(true);
172 _exit(status: 1);
173#endif
174}
175
176QT_END_NAMESPACE
177
178#include "moc_qfbvthandler_p.cpp"
179

source code of qtbase/src/platformsupport/fbconvenience/qfbvthandler.cpp