source: trunk/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp@ 944

Last change on this file since 944 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdirectfbwindowsurface.h"
43#include "qdirectfbscreen.h"
44#include "qdirectfbpaintengine.h"
45
46#include <private/qwidget_p.h>
47#include <qwidget.h>
48#include <qwindowsystem_qws.h>
49#include <qpaintdevice.h>
50#include <qvarlengtharray.h>
51
52#ifndef QT_NO_QWS_DIRECTFB
53
54QT_BEGIN_NAMESPACE
55
56QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr)
57 : QDirectFBPaintDevice(scr)
58 , sibling(0)
59#ifndef QT_NO_DIRECTFB_WM
60 , dfbWindow(0)
61#endif
62 , flipFlags(flip)
63 , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
64 , flushPending(false)
65{
66#ifdef QT_NO_DIRECTFB_WM
67 mode = Offscreen;
68#endif
69 setSurfaceFlags(Opaque | Buffered);
70#ifdef QT_DIRECTFB_TIMING
71 frames = 0;
72 timer.start();
73#endif
74}
75
76QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget)
77 : QWSWindowSurface(widget), QDirectFBPaintDevice(scr)
78 , sibling(0)
79#ifndef QT_NO_DIRECTFB_WM
80 , dfbWindow(0)
81#endif
82 , flipFlags(flip)
83 , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
84 , flushPending(false)
85{
86 SurfaceFlags flags = 0;
87 if (!widget || widget->window()->windowOpacity() == 0xff)
88 flags |= Opaque;
89#ifdef QT_NO_DIRECTFB_WM
90 if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) {
91 flags = RegionReserved;
92 mode = Primary;
93 } else {
94 mode = Offscreen;
95 flags = Buffered;
96 }
97#endif
98 setSurfaceFlags(flags);
99#ifdef QT_DIRECTFB_TIMING
100 frames = 0;
101 timer.start();
102#endif
103}
104
105QDirectFBWindowSurface::~QDirectFBWindowSurface()
106{
107 releaseSurface();
108 // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it
109}
110
111bool QDirectFBWindowSurface::isValid() const
112{
113 return true;
114}
115
116#ifdef QT_DIRECTFB_WM
117void QDirectFBWindowSurface::raise()
118{
119 if (IDirectFBWindow *window = directFBWindow()) {
120 window->RaiseToTop(window);
121 }
122}
123
124IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const
125{
126 return (dfbWindow ? dfbWindow : (sibling ? sibling->dfbWindow : 0));
127}
128
129void QDirectFBWindowSurface::createWindow(const QRect &rect)
130{
131 IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
132 if (!layer)
133 qFatal("QDirectFBWindowSurface: Unable to get primary display layer!");
134
135 updateIsOpaque();
136
137 DFBWindowDescription description;
138 memset(&description, 0, sizeof(DFBWindowDescription));
139
140 description.flags = DWDESC_CAPS|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT;
141 description.caps = DWCAPS_NODECORATION;
142 description.surface_caps = DSCAPS_NONE;
143 imageFormat = screen->pixelFormat();
144
145 if (!(surfaceFlags() & Opaque)) {
146 imageFormat = screen->alphaPixmapFormat();
147 description.caps |= DWCAPS_ALPHACHANNEL;
148#if (Q_DIRECTFB_VERSION >= 0x010200)
149 description.flags |= DWDESC_OPTIONS;
150 description.options |= DWOP_ALPHACHANNEL;
151#endif
152 }
153 description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(imageFormat);
154 description.posx = rect.x();
155 description.posy = rect.y();
156 description.width = rect.width();
157 description.height = rect.height();
158
159 if (QDirectFBScreen::isPremultiplied(imageFormat))
160 description.surface_caps = DSCAPS_PREMULTIPLIED;
161
162 if (screen->directFBFlags() & QDirectFBScreen::VideoOnly)
163 description.surface_caps |= DSCAPS_VIDEOONLY;
164
165 DFBResult result = layer->CreateWindow(layer, &description, &dfbWindow);
166
167 if (result != DFB_OK)
168 DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result);
169
170 if (window()) {
171 if (window()->windowFlags() & Qt::WindowStaysOnTopHint) {
172 dfbWindow->SetStackingClass(dfbWindow, DWSC_UPPER);
173 }
174 DFBWindowID winid;
175 result = dfbWindow->GetID(dfbWindow, &winid);
176 if (result != DFB_OK) {
177 DirectFBError("QDirectFBWindowSurface::createWindow. Can't get ID", result);
178 } else {
179 window()->setProperty("_q_DirectFBWindowID", winid);
180 }
181 }
182
183 Q_ASSERT(!dfbSurface);
184 dfbWindow->GetSurface(dfbWindow, &dfbSurface);
185}
186
187static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect)
188{
189 DFBResult result = DFB_OK;
190 const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft();
191 const bool isResize = rect.size() != old.size();
192
193#if (Q_DIRECTFB_VERSION >= 0x010000)
194 if (isResize && isMove) {
195 result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
196 rect.width(), rect.height());
197 } else if (isResize) {
198 result = dfbWindow->Resize(dfbWindow,
199 rect.width(), rect.height());
200 } else if (isMove) {
201 result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
202 }
203#else
204 if (isResize) {
205 result = dfbWindow->Resize(dfbWindow,
206 rect.width(), rect.height());
207 }
208 if (isMove) {
209 result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
210 }
211#endif
212 return result;
213}
214#endif // QT_NO_DIRECTFB_WM
215
216void QDirectFBWindowSurface::setGeometry(const QRect &rect)
217{
218 const QRect oldRect = geometry();
219 if (oldRect == rect)
220 return;
221
222 IDirectFBSurface *oldSurface = dfbSurface;
223 const bool sizeChanged = oldRect.size() != rect.size();
224 if (sizeChanged) {
225 delete engine;
226 engine = 0;
227 releaseSurface();
228 Q_ASSERT(!dfbSurface);
229 }
230
231 if (rect.isNull()) {
232#ifndef QT_NO_DIRECTFB_WM
233 if (dfbWindow) {
234 if (window())
235 window()->setProperty("_q_DirectFBWindowID", QVariant());
236
237 dfbWindow->Release(dfbWindow);
238 dfbWindow = 0;
239 }
240#endif
241 Q_ASSERT(!dfbSurface);
242#ifdef QT_DIRECTFB_SUBSURFACE
243 Q_ASSERT(!subSurface);
244#endif
245 } else {
246#ifdef QT_DIRECTFB_WM
247 if (!dfbWindow) {
248 createWindow(rect);
249 } else {
250 setWindowGeometry(dfbWindow, oldRect, rect);
251 Q_ASSERT(!sizeChanged || !dfbSurface);
252 if (sizeChanged)
253 dfbWindow->GetSurface(dfbWindow, &dfbSurface);
254 }
255#else
256 IDirectFBSurface *primarySurface = screen->primarySurface();
257 DFBResult result = DFB_OK;
258 if (mode == Primary) {
259 Q_ASSERT(primarySurface);
260 if (rect == screen->region().boundingRect()) {
261 dfbSurface = primarySurface;
262 } else {
263 const DFBRectangle r = { rect.x(), rect.y(),
264 rect.width(), rect.height() };
265 result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface);
266 }
267 } else { // mode == Offscreen
268 if (!dfbSurface) {
269 dfbSurface = screen->createDFBSurface(rect.size(), surfaceFlags() & Opaque ? screen->pixelFormat() : screen->alphaPixmapFormat(),
270 QDirectFBScreen::DontTrackSurface);
271 }
272 }
273 if (result != DFB_OK)
274 DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
275#endif
276 }
277 if (oldSurface != dfbSurface) {
278 imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid;
279 }
280
281 if (oldRect.size() != rect.size()) {
282 QWSWindowSurface::setGeometry(rect);
283 } else {
284 QWindowSurface::setGeometry(rect);
285 }
286}
287
288QByteArray QDirectFBWindowSurface::permanentState() const
289{
290 QByteArray state(sizeof(this), 0);
291 *reinterpret_cast<const QDirectFBWindowSurface**>(state.data()) = this;
292 return state;
293}
294
295void QDirectFBWindowSurface::setPermanentState(const QByteArray &state)
296{
297 if (state.size() == sizeof(this)) {
298 sibling = *reinterpret_cast<QDirectFBWindowSurface *const*>(state.constData());
299 Q_ASSERT(sibling);
300 setSurfaceFlags(sibling->surfaceFlags());
301 }
302}
303
304bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
305{
306 if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.rectCount() != 1)
307 return false;
308 if (flushPending) {
309 dfbSurface->Flip(dfbSurface, 0, DSFLIP_BLIT);
310 } else {
311 flushPending = true;
312 }
313 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
314 const QRect r = region.boundingRect();
315 const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() };
316 dfbSurface->Blit(dfbSurface, dfbSurface, &rect, r.x() + dx, r.y() + dy);
317 return true;
318}
319
320bool QDirectFBWindowSurface::move(const QPoint &moveBy)
321{
322 setGeometry(geometry().translated(moveBy));
323 return true;
324}
325
326void QDirectFBWindowSurface::setOpaque(bool opaque)
327{
328 SurfaceFlags flags = surfaceFlags();
329 if (opaque != (flags & Opaque)) {
330 if (opaque) {
331 flags |= Opaque;
332 } else {
333 flags &= ~Opaque;
334 }
335 setSurfaceFlags(flags);
336 }
337}
338
339
340void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion &region,
341 const QPoint &offset)
342{
343 QWidget *win = window();
344 if (!win)
345 return;
346
347#ifndef QT_NO_QWS_PROXYSCREEN
348 QWExtra *extra = qt_widget_private(widget)->extraData();
349 if (extra && extra->proxyWidget)
350 return;
351#endif
352
353 const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff);
354 const QRect windowGeometry = geometry();
355#ifdef QT_DIRECTFB_WM
356 quint8 currentOpacity;
357 Q_ASSERT(dfbWindow);
358 dfbWindow->GetOpacity(dfbWindow, &currentOpacity);
359 if (currentOpacity != windowOpacity) {
360 dfbWindow->SetOpacity(dfbWindow, windowOpacity);
361 }
362
363 screen->flipSurface(dfbSurface, flipFlags, region, offset);
364#else
365 setOpaque(windowOpacity == 0xff);
366 if (mode == Offscreen) {
367 screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0);
368 } else {
369 screen->flipSurface(dfbSurface, flipFlags, region, offset);
370 }
371#endif
372
373#ifdef QT_DIRECTFB_TIMING
374 enum { Secs = 3 };
375 ++frames;
376 if (timer.elapsed() >= Secs * 1000) {
377 qDebug("%d fps", int(double(frames) / double(Secs)));
378 frames = 0;
379 timer.restart();
380 }
381#endif
382 flushPending = false;
383}
384
385void QDirectFBWindowSurface::beginPaint(const QRegion &region)
386{
387 if (!engine) {
388 engine = new QDirectFBPaintEngine(this);
389 }
390
391 if (dfbSurface) {
392 const QWidget *win = window();
393 if (win && win->testAttribute(Qt::WA_NoSystemBackground)) {
394 QDirectFBScreen::solidFill(dfbSurface, Qt::transparent, region);
395 }
396 }
397 flushPending = true;
398}
399
400void QDirectFBWindowSurface::endPaint(const QRegion &)
401{
402#ifdef QT_NO_DIRECTFB_SUBSURFACE
403 unlockSurface();
404#endif
405}
406
407IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const
408{
409 if (!dfbSurface && sibling && sibling->dfbSurface)
410 return sibling->dfbSurface;
411 return dfbSurface;
412}
413
414
415IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const
416{
417 Q_ASSERT(widget);
418 if (!dfbSurface) {
419 if (sibling && (!sibling->sibling || sibling->dfbSurface))
420 return sibling->surfaceForWidget(widget, rect);
421 return 0;
422 }
423 QWidget *win = window();
424 Q_ASSERT(win);
425 if (rect) {
426 if (win == widget) {
427 *rect = widget->rect();
428 } else {
429 *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size());
430 }
431 }
432
433 Q_ASSERT(win == widget || win->isAncestorOf(widget));
434 return dfbSurface;
435}
436
437void QDirectFBWindowSurface::releaseSurface()
438{
439 if (dfbSurface) {
440#ifdef QT_DIRECTFB_SUBSURFACE
441 releaseSubSurface();
442#else
443 unlockSurface();
444#endif
445#ifdef QT_NO_DIRECTFB_WM
446 Q_ASSERT(screen->primarySurface());
447 if (dfbSurface != screen->primarySurface())
448#endif
449
450 dfbSurface->Release(dfbSurface);
451 dfbSurface = 0;
452 }
453}
454
455void QDirectFBWindowSurface::updateIsOpaque()
456{
457 const QWidget *win = window();
458 Q_ASSERT(win);
459 if (win->testAttribute(Qt::WA_OpaquePaintEvent) || win->testAttribute(Qt::WA_PaintOnScreen)) {
460 setOpaque(true);
461 return;
462 }
463
464 if (qFuzzyCompare(static_cast<float>(win->windowOpacity()), 1.0f)) {
465 const QPalette &pal = win->palette();
466
467 if (win->autoFillBackground()) {
468 const QBrush &autoFillBrush = pal.brush(win->backgroundRole());
469 if (autoFillBrush.style() != Qt::NoBrush && autoFillBrush.isOpaque()) {
470 setOpaque(true);
471 return;
472 }
473 }
474
475 if (win->isWindow() && !win->testAttribute(Qt::WA_NoSystemBackground)) {
476 const QBrush &windowBrush = win->palette().brush(QPalette::Window);
477 if (windowBrush.style() != Qt::NoBrush && windowBrush.isOpaque()) {
478 setOpaque(true);
479 return;
480 }
481 }
482 }
483 setOpaque(false);
484}
485
486QT_END_NAMESPACE
487
488#endif // QT_NO_QWS_DIRECTFB
Note: See TracBrowser for help on using the repository browser.