Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "qvfbx11view.h" |
43 | #include "x11keyfaker.h" |
44 | #include <qevent.h> |
45 | #include <QX11Info> |
46 | #include <QTimer> |
47 | #include <QProcess> |
48 | #include <QDebug> |
49 | #include <QUuid> |
50 | #include <QDataStream> |
51 | #include <QTemporaryFile> |
52 | #include <X11/Xlib.h> |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | QVFbX11View::QVFbX11View |
57 | (int id, int w, int h, int d, Rotation r, QWidget *parent) |
58 | : QVFbAbstractView(parent) |
59 | { |
60 | this->id = id; |
61 | this->w = w; |
62 | this->h = h; |
63 | this->d = d; |
64 | this->rotation = r; |
65 | this->gr = 1.0; |
66 | this->gg = 1.0; |
67 | this->gb = 1.0; |
68 | this->touchscreen = false; |
69 | this->lcd = false; |
70 | this->keyFaker = 0; |
71 | this->xnest = 0; |
72 | this->serverAuthFile = 0; |
73 | this->shutdown = false; |
74 | |
75 | // Try to find Xephyr, as it is better than Xnest in many ways. |
76 | if (QFile::exists("/usr/bin/Xephyr")) |
77 | xserver = "/usr/bin/Xephyr"; |
78 | else if (QFile::exists("/usr/local/bin/Xephyr")) |
79 | xserver = "/usr/local/bin/Xephyr"; |
80 | else if (QFile::exists("/usr/X11R6/bin/Xephyr")) |
81 | xserver = "/usr/X11R6/bin/Xephyr"; |
82 | else |
83 | xserver = "Xnest"; |
84 | } |
85 | |
86 | QVFbX11View::~QVFbX11View() |
87 | { |
88 | shutdown = true; |
89 | if (xnest) { |
90 | xnest->terminate(); |
91 | xnestStopped(); |
92 | } |
93 | } |
94 | |
95 | int QVFbX11View::displayId() const |
96 | { |
97 | return id; |
98 | } |
99 | |
100 | int QVFbX11View::displayWidth() const |
101 | { |
102 | return ( (int)rotation & 0x01 ) ? h : w; |
103 | } |
104 | |
105 | int QVFbX11View::displayHeight() const |
106 | { |
107 | return ( (int)rotation & 0x01 ) ? w : h; |
108 | } |
109 | |
110 | int QVFbX11View::displayDepth() const |
111 | { |
112 | return d; |
113 | } |
114 | |
115 | QVFbX11View::Rotation QVFbX11View::displayRotation() const |
116 | { |
117 | return rotation; |
118 | } |
119 | |
120 | void QVFbX11View::skinKeyPressEvent(int code, const QString&, bool) |
121 | { |
122 | if (keyFaker) |
123 | keyFaker->sendKeyEvent(code, true); |
124 | } |
125 | |
126 | void QVFbX11View::skinKeyReleaseEvent(int code, const QString&, bool) |
127 | { |
128 | if (keyFaker) |
129 | keyFaker->sendKeyEvent(code, false); |
130 | } |
131 | |
132 | void QVFbX11View::setGamma(double gr, double gg, double gb) |
133 | { |
134 | // We remember the values, but don't do anything with them. |
135 | this->gr = gr; |
136 | this->gg = gg; |
137 | this->gb = gb; |
138 | } |
139 | |
140 | double QVFbX11View::gammaRed() const |
141 | { |
142 | return gr; |
143 | } |
144 | |
145 | double QVFbX11View::gammaGreen() const |
146 | { |
147 | return gg; |
148 | } |
149 | |
150 | double QVFbX11View::gammaBlue() const |
151 | { |
152 | return gb; |
153 | } |
154 | |
155 | void QVFbX11View::getGamma(int, QRgb& rgb) |
156 | { |
157 | rgb = qRgb(255, 255, 255); |
158 | } |
159 | |
160 | bool QVFbX11View::touchScreenEmulation() const |
161 | { |
162 | return touchscreen; |
163 | } |
164 | |
165 | bool QVFbX11View::lcdScreenEmulation() const |
166 | { |
167 | return lcd; |
168 | } |
169 | |
170 | int QVFbX11View::rate() |
171 | { |
172 | // We don't support refresh rates, so return a default value. |
173 | return 30; |
174 | } |
175 | |
176 | bool QVFbX11View::animating() const |
177 | { |
178 | // We don't support animation. |
179 | return false; |
180 | } |
181 | |
182 | QImage QVFbX11View::image() const |
183 | { |
184 | // We don't support image capture. |
185 | return QImage(); |
186 | } |
187 | |
188 | void QVFbX11View::setRate(int) |
189 | { |
190 | // We don't support rate adjustments. |
191 | } |
192 | |
193 | |
194 | double QVFbX11View::zoomH() const |
195 | { |
196 | // Zoom is not possible with Xnest. |
197 | return 1.0; |
198 | } |
199 | |
200 | double QVFbX11View::zoomV() const |
201 | { |
202 | // Zoom is not possible with Xnest. |
203 | return 1.0; |
204 | } |
205 | |
206 | QSize QVFbX11View::sizeHint() const |
207 | { |
208 | return QSize(w, h); |
209 | } |
210 | |
211 | void QVFbX11View::setTouchscreenEmulation( bool flag ) |
212 | { |
213 | touchscreen = flag; |
214 | } |
215 | |
216 | void QVFbX11View::setLcdScreenEmulation( bool flag ) |
217 | { |
218 | lcd = flag; |
219 | } |
220 | |
221 | void QVFbX11View::setZoom( double, double ) |
222 | { |
223 | // Zoom is not possible with Xnest. |
224 | } |
225 | |
226 | void QVFbX11View::setRotation( Rotation ) |
227 | { |
228 | // Rotation is not possible with Xnest. |
229 | } |
230 | |
231 | void QVFbX11View::startAnimation( const QString& ) |
232 | { |
233 | // Animation is not supported. |
234 | } |
235 | |
236 | void QVFbX11View::stopAnimation() |
237 | { |
238 | // Animation is not supported. |
239 | } |
240 | |
241 | // Generate a 16-byte magic cookie string. |
242 | static QString generateMagicCookie() |
243 | { |
244 | static const char hexchars[] = "0123456789abcdef"; |
245 | QUuid uuid = QUuid::createUuid(); |
246 | QByteArray ba; |
247 | QDataStream stream(&ba, QIODevice::WriteOnly); |
248 | stream << uuid; |
249 | QString value; |
250 | foreach ( char ch, ba ) { |
251 | value += QChar( hexchars[(ch >> 4) & 0x0F] ); |
252 | value += QChar( hexchars[ch & 0x0F] ); |
253 | } |
254 | return value; |
255 | } |
256 | |
257 | void QVFbX11View::showEvent(QShowEvent *e) |
258 | { |
259 | if (!xnest) |
260 | startXnest(); |
261 | QWidget::showEvent(e); |
262 | } |
263 | |
264 | void QVFbX11View::keyPressEvent(QKeyEvent *e) |
265 | { |
266 | if (keyFaker) |
267 | keyFaker->sendKeyEvent(e->key(), true); |
268 | QWidget::keyPressEvent(e); |
269 | } |
270 | |
271 | void QVFbX11View::keyReleaseEvent(QKeyEvent *e) |
272 | { |
273 | if (keyFaker) |
274 | keyFaker->sendKeyEvent(e->key(), false); |
275 | QWidget::keyReleaseEvent(e); |
276 | } |
277 | |
278 | void QVFbX11View::startXnest() |
279 | { |
280 | // Add authentication credentials to the XAUTHORITY file. |
281 | QString cookie = generateMagicCookie(); |
282 | QStringList xauthargs; |
283 | xauthargs += "add"; |
284 | xauthargs += ":"+ QString::number(displayId()); |
285 | xauthargs += "MIT-MAGIC-COOKIE-1"; |
286 | xauthargs += cookie; |
287 | if (QProcess::execute("xauth", xauthargs) != 0) |
288 | qWarning() << "xauth: failed to add Xnest client authentication credentials"; |
289 | |
290 | // Write the credentials to another authentication file for the server. |
291 | serverAuthFile = new QTemporaryFile(this); |
292 | QString authFilename; |
293 | if (serverAuthFile->open()) { |
294 | authFilename = serverAuthFile->fileName(); |
295 | serverAuthFile->close(); |
296 | xauthargs.clear(); |
297 | xauthargs += "-f"; |
298 | xauthargs += authFilename; |
299 | xauthargs += "add"; |
300 | xauthargs += ":"+ QString::number(displayId()); |
301 | xauthargs += "MIT-MAGIC-COOKIE-1"; |
302 | xauthargs += cookie; |
303 | if (QProcess::execute("xauth", xauthargs) != 0) |
304 | qWarning() << "xauth: failed to add Xnest server authentication credentials"; |
305 | } |
306 | |
307 | // Create a raw X11 window to act as the Xnest's root window. |
308 | // We cannot use winId() directly because qvfb is already |
309 | // selecting for events that Xnest wants to select for. |
310 | WId root = XCreateSimpleWindow |
311 | (QX11Info::display(), winId(), 0, 0, w, h, 0, |
312 | BlackPixel(QX11Info::display(), QX11Info::appScreen()), |
313 | BlackPixel(QX11Info::display(), QX11Info::appScreen())); |
314 | XMapWindow(QX11Info::display(), root); |
315 | |
316 | // Warn the user if the visual number looks wrong. Xnest expects |
317 | // its root window to be on the default visual. |
318 | if (QX11Info::appVisual() != DefaultVisual(QX11Info::display(), QX11Info::appScreen())) { |
319 | qWarning() << "*** Qt is not using the default visual. Xnest may fail " |
320 | "with a BadMatch error."; |
321 | qWarning() << "*** If it fails, then restart qvfb with \" -visual" |
322 | << DefaultVisual(QX11Info::display(), QX11Info::appScreen()) |
323 | ->visualid << "\""; |
324 | } |
325 | |
326 | // Make sure the root window is in the X server before Xnest starts. |
327 | XSync(QX11Info::display(), False); |
328 | |
329 | // Start the Xnest process. |
330 | xnest = new QProcess(this); |
331 | connect(xnest, SIGNAL(error(QProcess::ProcessError)), |
332 | this, SLOT(xnestStopped())); |
333 | connect(xnest, SIGNAL(finished(int,QProcess::ExitStatus)), |
334 | this, SLOT(xnestStopped())); |
335 | QStringList args; |
336 | args += "-auth"; |
337 | args += authFilename; |
338 | if (!xserver.contains("Xephyr")) { |
339 | args += "-geometry"; |
340 | args += QString::number(w) + "x"+ QString::number(h) + "+0+0"; |
341 | args += "-depth"; |
342 | args += QString::number(d); |
343 | } |
344 | args += "-br"; // Start Xnest with a black background. |
345 | args += "-parent"; |
346 | args += "0x"+ QString::number(root, 16); |
347 | args += ":"+ QString::number(displayId()); |
348 | xnest->setProcessChannelMode(QProcess::ForwardedChannels); |
349 | xnest->start(xserver, args); |
350 | //qDebug() << args; |
351 | |
352 | QTimer::singleShot(200, this, SLOT(startKeyFaker())); |
353 | } |
354 | |
355 | void QVFbX11View::xnestStopped() |
356 | { |
357 | if (!shutdown) { |
358 | if (xnest && xnest->error() == QProcess::FailedToStart) |
359 | qWarning() << xserver << "could not be started"; |
360 | else |
361 | qWarning() << xserver << "stopped unexpectedly"; |
362 | } |
363 | if (keyFaker) { |
364 | delete keyFaker; |
365 | keyFaker = 0; |
366 | } |
367 | if (xnest) { |
368 | xnest->deleteLater(); |
369 | xnest = 0; |
370 | |
371 | QStringList xauthargs; |
372 | xauthargs += "remove"; |
373 | xauthargs += ":"+ QString::number(displayId()); |
374 | if (QProcess::execute("xauth", xauthargs) != 0) |
375 | qWarning() << "xauth: failed to remove Xnest authentication credentials"; |
376 | } |
377 | if (serverAuthFile) { |
378 | delete serverAuthFile; |
379 | serverAuthFile = 0; |
380 | } |
381 | } |
382 | |
383 | void QVFbX11View::startKeyFaker() |
384 | { |
385 | if (!keyFaker && xnest) |
386 | keyFaker = new X11KeyFaker(":"+ QString::number(displayId()), this); |
387 | } |
388 | |
389 | QT_END_NAMESPACE |
390 |
Warning: That file was not part of the compilation database. It may have many parsing errors.