source: trunk/tools/qvfb/qvfbx11view.cpp@ 372

Last change on this file since 372 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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