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
54QT_BEGIN_NAMESPACE
55
56QVFbX11View::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
86QVFbX11View::~QVFbX11View()
87{
88 shutdown = true;
89 if (xnest) {
90 xnest->terminate();
91 xnestStopped();
92 }
93}
94
95int QVFbX11View::displayId() const
96{
97 return id;
98}
99
100int QVFbX11View::displayWidth() const
101{
102 return ( (int)rotation & 0x01 ) ? h : w;
103}
104
105int QVFbX11View::displayHeight() const
106{
107 return ( (int)rotation & 0x01 ) ? w : h;
108}
109
110int QVFbX11View::displayDepth() const
111{
112 return d;
113}
114
115QVFbX11View::Rotation QVFbX11View::displayRotation() const
116{
117 return rotation;
118}
119
120void QVFbX11View::skinKeyPressEvent(int code, const QString&, bool)
121{
122 if (keyFaker)
123 keyFaker->sendKeyEvent(code, true);
124}
125
126void QVFbX11View::skinKeyReleaseEvent(int code, const QString&, bool)
127{
128 if (keyFaker)
129 keyFaker->sendKeyEvent(code, false);
130}
131
132void 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
140double QVFbX11View::gammaRed() const
141{
142 return gr;
143}
144
145double QVFbX11View::gammaGreen() const
146{
147 return gg;
148}
149
150double QVFbX11View::gammaBlue() const
151{
152 return gb;
153}
154
155void QVFbX11View::getGamma(int, QRgb& rgb)
156{
157 rgb = qRgb(255, 255, 255);
158}
159
160bool QVFbX11View::touchScreenEmulation() const
161{
162 return touchscreen;
163}
164
165bool QVFbX11View::lcdScreenEmulation() const
166{
167 return lcd;
168}
169
170int QVFbX11View::rate()
171{
172 // We don't support refresh rates, so return a default value.
173 return 30;
174}
175
176bool QVFbX11View::animating() const
177{
178 // We don't support animation.
179 return false;
180}
181
182QImage QVFbX11View::image() const
183{
184 // We don't support image capture.
185 return QImage();
186}
187
188void QVFbX11View::setRate(int)
189{
190 // We don't support rate adjustments.
191}
192
193
194double QVFbX11View::zoomH() const
195{
196 // Zoom is not possible with Xnest.
197 return 1.0;
198}
199
200double QVFbX11View::zoomV() const
201{
202 // Zoom is not possible with Xnest.
203 return 1.0;
204}
205
206QSize QVFbX11View::sizeHint() const
207{
208 return QSize(w, h);
209}
210
211void QVFbX11View::setTouchscreenEmulation( bool flag )
212{
213 touchscreen = flag;
214}
215
216void QVFbX11View::setLcdScreenEmulation( bool flag )
217{
218 lcd = flag;
219}
220
221void QVFbX11View::setZoom( double, double )
222{
223 // Zoom is not possible with Xnest.
224}
225
226void QVFbX11View::setRotation( Rotation )
227{
228 // Rotation is not possible with Xnest.
229}
230
231void QVFbX11View::startAnimation( const QString& )
232{
233 // Animation is not supported.
234}
235
236void QVFbX11View::stopAnimation()
237{
238 // Animation is not supported.
239}
240
241// Generate a 16-byte magic cookie string.
242static 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
257void QVFbX11View::showEvent(QShowEvent *e)
258{
259 if (!xnest)
260 startXnest();
261 QWidget::showEvent(e);
262}
263
264void QVFbX11View::keyPressEvent(QKeyEvent *e)
265{
266 if (keyFaker)
267 keyFaker->sendKeyEvent(e->key(), true);
268 QWidget::keyPressEvent(e);
269}
270
271void QVFbX11View::keyReleaseEvent(QKeyEvent *e)
272{
273 if (keyFaker)
274 keyFaker->sendKeyEvent(e->key(), false);
275 QWidget::keyReleaseEvent(e);
276}
277
278void 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
355void 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
383void QVFbX11View::startKeyFaker()
384{
385 if (!keyFaker && xnest)
386 keyFaker = new X11KeyFaker(":" + QString::number(displayId()), this);
387}
388
389QT_END_NAMESPACE
390

Warning: That file was not part of the compilation database. It may have many parsing errors.