~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/embedded/qscreenqnx_qws.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
 
5
** Contact: Nokia Corporation (qt-info@nokia.com)
 
6
**
 
7
** This file is part of the QtGui module of the Qt Toolkit.
 
8
**
 
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
 
14
** this package.
 
15
**
 
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.
 
23
**
 
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.
 
27
**
 
28
** If you have questions regarding the use of this file, please contact
 
29
** Nokia at qt-info@nokia.com.
 
30
**
 
31
**
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qscreenqnx_qws.h"
 
43
#include "qdebug.h"
 
44
 
 
45
#include <gf/gf.h>
 
46
 
 
47
QT_BEGIN_NAMESPACE
 
48
 
 
49
// This struct holds all the pointers to QNX's internals
 
50
struct QQnxScreenContext
 
51
{
 
52
    inline QQnxScreenContext()
 
53
        : device(0), display(0), layer(0), hwSurface(0), memSurface(0), context(0)
 
54
    {}
 
55
 
 
56
    gf_dev_t device;
 
57
    gf_dev_info_t deviceInfo;
 
58
    gf_display_t display;
 
59
    gf_display_info_t displayInfo;
 
60
    gf_layer_t layer;
 
61
    gf_surface_t hwSurface;
 
62
    gf_surface_t memSurface;
 
63
    gf_surface_info_t memSurfaceInfo;
 
64
    gf_context_t context;
 
65
};
 
66
 
 
67
/*!
 
68
    \class QQnxScreen
 
69
    \preliminary
 
70
    \ingroup qws
 
71
    \since 4.6
 
72
    \internal
 
73
 
 
74
    \brief The QQnxScreen class implements a screen driver
 
75
    for QNX io-display based devices.
 
76
 
 
77
    Note - you never have to instanciate this class, the QScreenDriverFactory
 
78
    does that for us based on the \c{QWS_DISPLAY} environment variable.
 
79
 
 
80
    To activate this driver, set \c{QWS_DISPLAY} to \c{qnx}.
 
81
 
 
82
    Example:
 
83
    \c{QWS_DISPLAY=qnx; export QWS_DISPLAY}
 
84
 
 
85
    By default, the main layer of the first display of the first device is used.
 
86
    If you have multiple graphic cards, multiple displays or multiple layers and
 
87
    don't want to connect to the default, you can override that with setting
 
88
    the corresponding options \c{device}, \c{display} or \c{layer} in the \c{QWS_DISPLAY} variable:
 
89
 
 
90
    \c{QWS_DISPLAY=qnx:device=3:display=4:layer=5}
 
91
 
 
92
    In addition, it is suggested to set the physical width and height of the display.
 
93
    QQnxScreen will use that information to compute the dots per inch (DPI) in order to render
 
94
    fonts correctly. If this informaiton is omitted, QQnxScreen defaults to 72 dpi.
 
95
 
 
96
    \c{QWS_DISPLAY=qnx:mmWidth=120:mmHeight=80}
 
97
 
 
98
    \c{mmWidth} and \c{mmHeight} are the physical width/height of the screen in millimeters.
 
99
 
 
100
    \sa QScreen, QScreenDriverPlugin, {Running Qt for Embedded Linux Applications}{Running Applications}
 
101
*/
 
102
 
 
103
/*!
 
104
    Constructs a QQnxScreen object. The \a display_id argument
 
105
    identifies the Qt for Embedded Linux server to connect to.
 
106
*/
 
107
QQnxScreen::QQnxScreen(int display_id)
 
108
    : QScreen(display_id), d(new QQnxScreenContext)
 
109
{
 
110
}
 
111
 
 
112
/*!
 
113
    Destroys this QQnxScreen object.
 
114
*/
 
115
QQnxScreen::~QQnxScreen()
 
116
{
 
117
    delete d;
 
118
}
 
119
 
 
120
/*! \reimp
 
121
*/
 
122
bool QQnxScreen::initDevice()
 
123
{
 
124
    // implement this if you have multiple processes that want to access the display
 
125
    // (not required if QT_NO_QWS_MULTIPROCESS is set)
 
126
    return true;
 
127
}
 
128
 
 
129
/*! \internal
 
130
  Attaches to the named device \a name.
 
131
*/
 
132
static bool attachDevice(QQnxScreenContext * const d, const char *name)
 
133
{
 
134
    int ret = gf_dev_attach(&d->device, name, &d->deviceInfo);
 
135
    if (ret != GF_ERR_OK) {
 
136
        qWarning("QQnxScreen: gf_dev_attach(%s) failed with error code %d", name, ret);
 
137
        return false;
 
138
    }
 
139
    return true;
 
140
}
 
141
 
 
142
/*! \internal
 
143
  Attaches to the display at index \a displayIndex.
 
144
 */
 
145
static bool attachDisplay(QQnxScreenContext * const d, int displayIndex)
 
146
{
 
147
    int ret = gf_display_attach(&d->display, d->device, displayIndex, &d->displayInfo);
 
148
    if (ret != GF_ERR_OK) {
 
149
        qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d",
 
150
                displayIndex, ret);
 
151
        return false;
 
152
    }
 
153
    return true;
 
154
}
 
155
 
 
156
/*! \internal
 
157
  Attaches to the layer \a layerIndex.
 
158
 */
 
159
static bool attachLayer(QQnxScreenContext * const d, int layerIndex)
 
160
{
 
161
    int ret = gf_layer_attach(&d->layer, d->display, layerIndex, 0);
 
162
    if (ret != GF_ERR_OK) {
 
163
        qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex,
 
164
                ret);
 
165
        return false;
 
166
    }
 
167
    gf_layer_enable(d->layer);
 
168
 
 
169
    return true;
 
170
}
 
171
 
 
172
/*! \internal
 
173
  Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h.
 
174
 */
 
175
static bool createHwSurface(QQnxScreenContext * const d, int w, int h)
 
176
{
 
177
    int ret = gf_surface_create_layer(&d->hwSurface, &d->layer, 1, 0,
 
178
                w, h, GF_FORMAT_ARGB8888, 0, 0);
 
179
    if (ret != GF_ERR_OK) {
 
180
        qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d",
 
181
                w, h, ret);
 
182
        return false;
 
183
    }
 
184
 
 
185
    gf_layer_set_surfaces(d->layer, &d->hwSurface, 1);
 
186
 
 
187
    ret = gf_layer_update(d->layer, 0);
 
188
    if (ret != GF_ERR_OK) {
 
189
        qWarning("QQnxScreen: gf_layer_update() failed with error code %d\n", ret);
 
190
        return false;
 
191
    }
 
192
 
 
193
    return true;
 
194
}
 
195
 
 
196
/*! \internal
 
197
  Creates an in-memory, linear accessible surface of dimensions \a w * \a h.
 
198
  This is the main surface that QWS blits to.
 
199
 */
 
200
static bool createMemSurface(QQnxScreenContext * const d, int w, int h)
 
201
{
 
202
    // Note: gf_surface_attach() could also be used, so we'll create the buffer
 
203
    // and let the surface point to it. Here, we use surface_create instead.
 
204
 
 
205
    int ret = gf_surface_create(&d->memSurface, d->device, w, h,
 
206
                GF_FORMAT_ARGB8888, 0,
 
207
                GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE
 
208
                | GF_SURFACE_PHYS_CONTIG);
 
209
    if (ret != GF_ERR_OK) {
 
210
        qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d",
 
211
                w, h, ret);
 
212
        return false;
 
213
    }
 
214
 
 
215
    gf_surface_get_info(d->memSurface, &d->memSurfaceInfo);
 
216
 
 
217
    if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) {
 
218
        qWarning("QQnxScreen: gf_surface_get_info() failed.");
 
219
        return false;
 
220
    }
 
221
 
 
222
    return true;
 
223
}
 
224
 
 
225
/* \internal
 
226
   Creates a QNX gf context and sets our memory surface on it.
 
227
 */
 
228
static bool createContext(QQnxScreenContext * const d)
 
229
{
 
230
    int ret = gf_context_create(&d->context);
 
231
    if (ret != GF_ERR_OK) {
 
232
        qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret);
 
233
        return false;
 
234
    }
 
235
 
 
236
    ret = gf_context_set_surface(d->context, d->memSurface);
 
237
    if (ret != GF_ERR_OK) {
 
238
        qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret);
 
239
        return false;
 
240
    }
 
241
 
 
242
    return true;
 
243
}
 
244
 
 
245
/*! \reimp
 
246
  Connects to QNX's io-display based device based on the \a displaySpec parameters
 
247
  from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation
 
248
  for possible parameters.
 
249
 
 
250
  \sa QQnxScreen
 
251
 */
 
252
bool QQnxScreen::connect(const QString &displaySpec)
 
253
{
 
254
    const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts);
 
255
 
 
256
    bool isOk = false;
 
257
    QRegExp deviceRegExp(QLatin1String("^device=(.+)$"));
 
258
    if (params.indexOf(deviceRegExp) != -1) {
 
259
        isOk = attachDevice(d, deviceRegExp.cap(1).toLocal8Bit().constData());
 
260
    } else {
 
261
        // no device specified - attach to device 0 (the default)
 
262
        isOk = attachDevice(d, GF_DEVICE_INDEX(0));
 
263
    }
 
264
 
 
265
    if (!isOk)
 
266
        return false;
 
267
 
 
268
    qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays);
 
269
 
 
270
    // default to display 0
 
271
    int displayIndex = 0;
 
272
    QRegExp displayRegexp(QLatin1String("^display=(\\d+)$"));
 
273
    if (params.indexOf(displayRegexp) != -1) {
 
274
        displayIndex = displayRegexp.cap(1).toInt();
 
275
    }
 
276
 
 
277
    if (!attachDisplay(d, displayIndex))
 
278
        return false;
 
279
 
 
280
    qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz",
 
281
            displayIndex, d->displayInfo.xres, d->displayInfo.yres,
 
282
            d->displayInfo.refresh);
 
283
 
 
284
 
 
285
    // default to main_layer_index from the displayInfo struct
 
286
    int layerIndex = 0;
 
287
    QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$"));
 
288
    if (params.indexOf(layerRegexp) != -1) {
 
289
        layerIndex = layerRegexp.cap(1).toInt();
 
290
    } else {
 
291
        layerIndex = d->displayInfo.main_layer_index;
 
292
    }
 
293
 
 
294
    if (!attachLayer(d, layerIndex))
 
295
        return false;
 
296
 
 
297
    // tell QWSDisplay the width and height of the display
 
298
    w = dw = d->displayInfo.xres;
 
299
    h = dh = d->displayInfo.yres;
 
300
 
 
301
    // we only support 32 bit displays for now.
 
302
    QScreen::d = 32;
 
303
 
 
304
    // assume 72 dpi as default, to calculate the physical dimensions if not specified
 
305
    const int defaultDpi = 72;
 
306
 
 
307
    // Handle display physical size spec.
 
308
    QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$"));
 
309
    if (params.indexOf(mmWidthRegexp) == -1) {
 
310
        physWidth = qRound(dw * 25.4 / defaultDpi);
 
311
    } else {
 
312
        physWidth = mmWidthRegexp.cap(1).toInt();
 
313
    }
 
314
 
 
315
    QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$"));
 
316
    if (params.indexOf(mmHeightRegexp) == -1) {
 
317
        physHeight = qRound(dh * 25.4 / defaultDpi);
 
318
    } else {
 
319
        physHeight = mmHeightRegexp.cap(1).toInt();
 
320
    }
 
321
 
 
322
    // create a hardware surface with our dimensions. In the old days, it was possible
 
323
    // to get a pointer directly to the hw surface, so we could blit directly. Now, we
 
324
    // have to use one indirection more, because it's not guaranteed that the hw surface
 
325
    // is mappable into our process.
 
326
    if (!createHwSurface(d, w, h))
 
327
        return false;
 
328
 
 
329
    // create an in-memory linear surface that is used by QWS. QWS will blit directly in here.
 
330
    if (!createMemSurface(d, w, h))
 
331
        return false;
 
332
 
 
333
    // set the address of the in-memory buffer that QWS is blitting to
 
334
    data = d->memSurfaceInfo.vaddr;
 
335
    // set the line stepping
 
336
    lstep = d->memSurfaceInfo.stride;
 
337
 
 
338
    // the overall size of the in-memory buffer is linestep * height
 
339
    size = mapsize = lstep * h;
 
340
 
 
341
    // create a QNX drawing context
 
342
    if (!createContext(d))
 
343
        return false;
 
344
 
 
345
    // we're always using a software cursor for now. Initialize it here.
 
346
    QScreenCursor::initSoftwareCursor();
 
347
 
 
348
    // done, the driver should be connected to the display now.
 
349
    return true;
 
350
}
 
351
 
 
352
/*! \reimp
 
353
 */
 
354
void QQnxScreen::disconnect()
 
355
{
 
356
    if (d->context)
 
357
        gf_context_free(d->context);
 
358
 
 
359
    if (d->memSurface)
 
360
        gf_surface_free(d->memSurface);
 
361
 
 
362
    if (d->hwSurface)
 
363
        gf_surface_free(d->hwSurface);
 
364
 
 
365
    if (d->layer)
 
366
        gf_layer_detach(d->layer);
 
367
 
 
368
    if (d->display)
 
369
        gf_display_detach(d->display);
 
370
 
 
371
    if (d->device)
 
372
        gf_dev_detach(d->device);
 
373
 
 
374
    d->memSurface = 0;
 
375
    d->hwSurface = 0;
 
376
    d->context = 0;
 
377
    d->layer = 0;
 
378
    d->display = 0;
 
379
    d->device = 0;
 
380
}
 
381
 
 
382
/*! \reimp
 
383
 */
 
384
void QQnxScreen::shutdownDevice()
 
385
{
 
386
}
 
387
 
 
388
 
 
389
/*! \reimp
 
390
  QQnxScreen doesn't support setting the mode, use io-display instead.
 
391
 */
 
392
void QQnxScreen::setMode(int,int,int)
 
393
{
 
394
    qWarning("QQnxScreen: Unable to change mode, use io-display instead.");
 
395
}
 
396
 
 
397
/*! \reimp
 
398
 */
 
399
bool QQnxScreen::supportsDepth(int depth) const
 
400
{
 
401
    // only 32-bit for the moment
 
402
    return depth == 32;
 
403
}
 
404
 
 
405
/*! \reimp
 
406
 */
 
407
void QQnxScreen::exposeRegion(QRegion r, int changing)
 
408
{
 
409
    // here is where the actual magic happens. QWS will call exposeRegion whenever
 
410
    // a region on the screen is dirty and needs to be updated on the actual screen.
 
411
 
 
412
    // first, call the parent implementation. The parent implementation will update
 
413
    // the region on our in-memory surface
 
414
    QScreen::exposeRegion(r, changing);
 
415
 
 
416
    // now our in-memory surface should be up to date with the latest changes.
 
417
    // the code below copies the region from the in-memory surface to the hardware.
 
418
 
 
419
    // just get the bounding rectangle of the region. Most screen updates are rectangular
 
420
    // anyways. Code could be optimized to blit each and every member of the region
 
421
    // individually, but in real life, the speed-up is neglectable
 
422
    const QRect br = r.boundingRect();
 
423
    if (br.isEmpty())
 
424
        return; // ignore empty regions because gf_draw_blit2 doesn't like 0x0 dimensions
 
425
 
 
426
    // start drawing.
 
427
    int ret = gf_draw_begin(d->context);
 
428
    if (ret != GF_ERR_OK) {
 
429
        qWarning("QQnxScreen: gf_draw_begin() failed with error code %d", ret);
 
430
        return;
 
431
    }
 
432
 
 
433
    // blit the changed region from the memory surface to the hardware surface
 
434
    ret = gf_draw_blit2(d->context, d->memSurface, d->hwSurface,
 
435
            br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y());
 
436
    if (ret != GF_ERR_OK) {
 
437
        qWarning("QQnxScreen: gf_draw_blit2() failed with error code %d", ret);
 
438
    }
 
439
 
 
440
    // flush all drawing commands (in our case, a single blit)
 
441
    ret = gf_draw_flush(d->context);
 
442
    if (ret != GF_ERR_OK) {
 
443
        qWarning("QQnxScreen: gf_draw_flush() failed with error code %d", ret);
 
444
    }
 
445
 
 
446
    // tell QNX that we're done drawing.
 
447
    gf_draw_end(d->context);
 
448
}
 
449
 
 
450
QT_END_NAMESPACE