1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qvfbx11view.h"
43 #include "x11keyfaker.h"
50 #include <QDataStream>
51 #include <QTemporaryFile>
56 QVFbX11View::QVFbX11View
57 (int id
, int w
, int h
, int d
, Rotation r
, QWidget
*parent
)
58 : QVFbAbstractView(parent
)
68 this->touchscreen
= false;
72 this->serverAuthFile
= 0;
73 this->shutdown
= false;
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";
86 QVFbX11View::~QVFbX11View()
95 int QVFbX11View::displayId() const
100 int QVFbX11View::displayWidth() const
102 return ( (int)rotation
& 0x01 ) ? h
: w
;
105 int QVFbX11View::displayHeight() const
107 return ( (int)rotation
& 0x01 ) ? w
: h
;
110 int QVFbX11View::displayDepth() const
115 QVFbX11View::Rotation
QVFbX11View::displayRotation() const
120 void QVFbX11View::skinKeyPressEvent(int code
, const QString
&, bool)
123 keyFaker
->sendKeyEvent(code
, true);
126 void QVFbX11View::skinKeyReleaseEvent(int code
, const QString
&, bool)
129 keyFaker
->sendKeyEvent(code
, false);
132 void QVFbX11View::setGamma(double gr
, double gg
, double gb
)
134 // We remember the values, but don't do anything with them.
140 double QVFbX11View::gammaRed() const
145 double QVFbX11View::gammaGreen() const
150 double QVFbX11View::gammaBlue() const
155 void QVFbX11View::getGamma(int, QRgb
& rgb
)
157 rgb
= qRgb(255, 255, 255);
160 bool QVFbX11View::touchScreenEmulation() const
165 bool QVFbX11View::lcdScreenEmulation() const
170 int QVFbX11View::rate()
172 // We don't support refresh rates, so return a default value.
176 bool QVFbX11View::animating() const
178 // We don't support animation.
182 QImage
QVFbX11View::image() const
184 // We don't support image capture.
188 void QVFbX11View::setRate(int)
190 // We don't support rate adjustments.
194 double QVFbX11View::zoomH() const
196 // Zoom is not possible with Xnest.
200 double QVFbX11View::zoomV() const
202 // Zoom is not possible with Xnest.
206 QSize
QVFbX11View::sizeHint() const
211 void QVFbX11View::setTouchscreenEmulation( bool flag
)
216 void QVFbX11View::setLcdScreenEmulation( bool flag
)
221 void QVFbX11View::setZoom( double, double )
223 // Zoom is not possible with Xnest.
226 void QVFbX11View::setRotation( Rotation
)
228 // Rotation is not possible with Xnest.
231 void QVFbX11View::startAnimation( const QString
& )
233 // Animation is not supported.
236 void QVFbX11View::stopAnimation()
238 // Animation is not supported.
241 // Generate a 16-byte magic cookie string.
242 static QString
generateMagicCookie()
244 static const char hexchars
[] = "0123456789abcdef";
245 QUuid uuid
= QUuid::createUuid();
247 QDataStream
stream(&ba
, QIODevice::WriteOnly
);
250 foreach ( char ch
, ba
) {
251 value
+= QChar( hexchars
[(ch
>> 4) & 0x0F] );
252 value
+= QChar( hexchars
[ch
& 0x0F] );
257 void QVFbX11View::showEvent(QShowEvent
*e
)
261 QWidget::showEvent(e
);
264 void QVFbX11View::keyPressEvent(QKeyEvent
*e
)
267 keyFaker
->sendKeyEvent(e
->key(), true);
268 QWidget::keyPressEvent(e
);
271 void QVFbX11View::keyReleaseEvent(QKeyEvent
*e
)
274 keyFaker
->sendKeyEvent(e
->key(), false);
275 QWidget::keyReleaseEvent(e
);
278 void QVFbX11View::startXnest()
280 // Add authentication credentials to the XAUTHORITY file.
281 QString cookie
= generateMagicCookie();
282 QStringList xauthargs
;
284 xauthargs
+= ":" + QString::number(displayId());
285 xauthargs
+= "MIT-MAGIC-COOKIE-1";
287 if (QProcess::execute("xauth", xauthargs
) != 0)
288 qWarning() << "xauth: failed to add Xnest client authentication credentials";
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();
298 xauthargs
+= authFilename
;
300 xauthargs
+= ":" + QString::number(displayId());
301 xauthargs
+= "MIT-MAGIC-COOKIE-1";
303 if (QProcess::execute("xauth", xauthargs
) != 0)
304 qWarning() << "xauth: failed to add Xnest server authentication credentials";
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
);
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())
326 // Make sure the root window is in the X server before Xnest starts.
327 XSync(QX11Info::display(), False
);
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()));
337 args
+= authFilename
;
338 if (!xserver
.contains("Xephyr")) {
340 args
+= QString::number(w
) + "x" + QString::number(h
) + "+0+0";
342 args
+= QString::number(d
);
344 args
+= "-br"; // Start Xnest with a black background.
346 args
+= "0x" + QString::number(root
, 16);
347 args
+= ":" + QString::number(displayId());
348 xnest
->setProcessChannelMode(QProcess::ForwardedChannels
);
349 xnest
->start(xserver
, args
);
352 QTimer::singleShot(200, this, SLOT(startKeyFaker()));
355 void QVFbX11View::xnestStopped()
358 if (xnest
&& xnest
->error() == QProcess::FailedToStart
)
359 qWarning() << xserver
<< "could not be started";
361 qWarning() << xserver
<< "stopped unexpectedly";
368 xnest
->deleteLater();
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";
377 if (serverAuthFile
) {
378 delete serverAuthFile
;
383 void QVFbX11View::startKeyFaker()
385 if (!keyFaker
&& xnest
)
386 keyFaker
= new X11KeyFaker(":" + QString::number(displayId()), this);