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

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 14.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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{
65#ifdef QT_NO_DIRECTFB_WM
66 mode = Offscreen;
67#endif
68 setSurfaceFlags(Opaque | Buffered);
69#ifdef QT_DIRECTFB_TIMING
70 frames = 0;
71 timer.start();
72#endif
73}
74
75QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget)
76 : QWSWindowSurface(widget), QDirectFBPaintDevice(scr)
77 , sibling(0)
78#ifndef QT_NO_DIRECTFB_WM
79 , dfbWindow(0)
80#endif
81 , flipFlags(flip)
82 , boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
83{
84 SurfaceFlags flags = 0;
85 if (!widget || widget->window()->windowOpacity() == 0xff)
86 flags |= Opaque;
87#ifdef QT_NO_DIRECTFB_WM
88 if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) {
89 flags = RegionReserved;
90 mode = Primary;
91 } else {
92 mode = Offscreen;
93 flags = Buffered;
94 }
95#else
96 noSystemBackground = widget && widget->testAttribute(Qt::WA_NoSystemBackground);
97 if (noSystemBackground)
98 flags &= ~Opaque;
99#endif
100 setSurfaceFlags(flags);
101#ifdef QT_DIRECTFB_TIMING
102 frames = 0;
103 timer.start();
104#endif
105}
106
107QDirectFBWindowSurface::~QDirectFBWindowSurface()
108{
109 releaseSurface();
110 // these are not tracked by QDirectFBScreen so we don't want QDirectFBPaintDevice to release it
111}
112
113bool QDirectFBWindowSurface::isValid() const
114{
115 return true;
116}
117
118#ifdef QT_DIRECTFB_WM
119void QDirectFBWindowSurface::raise()
120{
121 if (IDirectFBWindow *window = directFBWindow()) {
122 window->RaiseToTop(window);
123 }
124}
125
126IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const
127{
128 return (dfbWindow ? dfbWindow : (sibling ? sibling->dfbWindow : 0));
129}
130
131void QDirectFBWindowSurface::createWindow(const QRect &rect)
132{
133 IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
134 if (!layer)
135 qFatal("QDirectFBWindowSurface: Unable to get primary display layer!");
136
137 DFBWindowDescription description;
138 memset(&description, 0, sizeof(DFBWindowDescription));
139
140 description.caps = DWCAPS_NODECORATION;
141 description.flags = DWDESC_CAPS|DWDESC_SURFACE_CAPS|DWDESC_PIXELFORMAT|DWDESC_HEIGHT|DWDESC_WIDTH|DWDESC_POSX|DWDESC_POSY;
142#if (Q_DIRECTFB_VERSION >= 0x010200)
143 description.flags |= DWDESC_OPTIONS;
144#endif
145
146 if (noSystemBackground) {
147 description.caps |= DWCAPS_ALPHACHANNEL;
148#if (Q_DIRECTFB_VERSION >= 0x010200)
149 description.options |= DWOP_ALPHACHANNEL;
150#endif
151 }
152
153 description.posx = rect.x();
154 description.posy = rect.y();
155 description.width = rect.width();
156 description.height = rect.height();
157 description.surface_caps = DSCAPS_NONE;
158 if (screen->directFBFlags() & QDirectFBScreen::VideoOnly)
159 description.surface_caps |= DSCAPS_VIDEOONLY;
160 const QImage::Format format = (noSystemBackground ? screen->alphaPixmapFormat() : screen->pixelFormat());
161 description.pixelformat = QDirectFBScreen::getSurfacePixelFormat(format);
162 if (QDirectFBScreen::isPremultiplied(format))
163 description.surface_caps = DSCAPS_PREMULTIPLIED;
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 updateFormat();
186}
187
188static DFBResult setWindowGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect)
189{
190 DFBResult result = DFB_OK;
191 const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft();
192 const bool isResize = rect.size() != old.size();
193
194#if (Q_DIRECTFB_VERSION >= 0x010000)
195 if (isResize && isMove) {
196 result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
197 rect.width(), rect.height());
198 } else if (isResize) {
199 result = dfbWindow->Resize(dfbWindow,
200 rect.width(), rect.height());
201 } else if (isMove) {
202 result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
203 }
204#else
205 if (isResize) {
206 result = dfbWindow->Resize(dfbWindow,
207 rect.width(), rect.height());
208 }
209 if (isMove) {
210 result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
211 }
212#endif
213 return result;
214}
215#endif // QT_NO_DIRECTFB_WM
216
217void QDirectFBWindowSurface::setGeometry(const QRect &rect)
218{
219 const QRect oldRect = geometry();
220 if (oldRect == rect)
221 return;
222
223 IDirectFBSurface *oldSurface = dfbSurface;
224 const bool sizeChanged = oldRect.size() != rect.size();
225 if (sizeChanged) {
226 delete engine;
227 engine = 0;
228 releaseSurface();
229 Q_ASSERT(!dfbSurface);
230 }
231
232 if (rect.isNull()) {
233#ifndef QT_NO_DIRECTFB_WM
234 if (dfbWindow) {
235 if (window())
236 window()->setProperty("_q_DirectFBWindowID", QVariant());
237
238 dfbWindow->Release(dfbWindow);
239 dfbWindow = 0;
240 }
241#endif
242 Q_ASSERT(!dfbSurface);
243#ifdef QT_DIRECTFB_SUBSURFACE
244 Q_ASSERT(!subSurface);
245#endif
246 } else {
247#ifdef QT_DIRECTFB_WM
248 if (!dfbWindow) {
249 createWindow(rect);
250 } else {
251 setWindowGeometry(dfbWindow, oldRect, rect);
252 Q_ASSERT(!sizeChanged || !dfbSurface);
253 if (sizeChanged)
254 dfbWindow->GetSurface(dfbWindow, &dfbSurface);
255 }
256#else
257 IDirectFBSurface *primarySurface = screen->primarySurface();
258 DFBResult result = DFB_OK;
259 if (mode == Primary) {
260 Q_ASSERT(primarySurface);
261 if (rect == screen->region().boundingRect()) {
262 dfbSurface = primarySurface;
263 } else {
264 const DFBRectangle r = { rect.x(), rect.y(),
265 rect.width(), rect.height() };
266 result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface);
267 }
268 } else { // mode == Offscreen
269 if (!dfbSurface) {
270 dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface);
271 }
272 }
273 if (result != DFB_OK)
274 DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
275#endif
276 }
277 if (oldSurface != dfbSurface)
278 updateFormat();
279
280 if (oldRect.size() != rect.size()) {
281 QWSWindowSurface::setGeometry(rect);
282 } else {
283 QWindowSurface::setGeometry(rect);
284 }
285}
286
287QByteArray QDirectFBWindowSurface::permanentState() const
288{
289 QByteArray state(sizeof(this), 0);
290 *reinterpret_cast<const QDirectFBWindowSurface**>(state.data()) = this;
291 return state;
292}
293
294void QDirectFBWindowSurface::setPermanentState(const QByteArray &state)
295{
296 if (state.size() == sizeof(this)) {
297 sibling = *reinterpret_cast<QDirectFBWindowSurface *const*>(state.constData());
298 Q_ASSERT(sibling);
299 sibling->setSurfaceFlags(surfaceFlags());
300 }
301}
302
303static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int dx, int dy)
304{
305 const DFBRectangle rect = { r.x(), r.y(), r.width(), r.height() };
306 surface->Blit(surface, surface, &rect, r.x() + dx, r.y() + dy);
307 const DFBRegion region = { rect.x + dx, rect.y + dy, r.right() + dx, r.bottom() + dy };
308 surface->Flip(surface, &region, DSFLIP_BLIT);
309}
310
311bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
312{
313 if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.isEmpty())
314 return false;
315 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
316 if (region.rectCount() == 1) {
317 scrollSurface(dfbSurface, region.boundingRect(), dx, dy);
318 } else {
319 const QVector<QRect> rects = region.rects();
320 const int n = rects.size();
321 for (int i=0; i<n; ++i) {
322 scrollSurface(dfbSurface, rects.at(i), dx, dy);
323 }
324 }
325 return true;
326}
327
328bool QDirectFBWindowSurface::move(const QPoint &moveBy)
329{
330 setGeometry(geometry().translated(moveBy));
331 return true;
332}
333
334void QDirectFBWindowSurface::setOpaque(bool opaque)
335{
336 SurfaceFlags flags = surfaceFlags();
337 if (opaque != (flags & Opaque)) {
338 if (opaque) {
339 flags |= Opaque;
340 } else {
341 flags &= ~Opaque;
342 }
343 setSurfaceFlags(flags);
344 }
345}
346
347
348void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion &region,
349 const QPoint &offset)
350{
351 QWidget *win = window();
352 if (!win)
353 return;
354
355 QWExtra *extra = qt_widget_private(widget)->extraData();
356 if (extra && extra->proxyWidget)
357 return;
358
359 const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff);
360 const QRect windowGeometry = geometry();
361#ifdef QT_DIRECTFB_WM
362 const bool wasNoSystemBackground = noSystemBackground;
363 noSystemBackground = win->testAttribute(Qt::WA_NoSystemBackground);
364 quint8 currentOpacity;
365 Q_ASSERT(dfbWindow);
366 dfbWindow->GetOpacity(dfbWindow, &currentOpacity);
367 if (currentOpacity != windowOpacity) {
368 dfbWindow->SetOpacity(dfbWindow, windowOpacity);
369 }
370
371 setOpaque(noSystemBackground || windowOpacity != 0xff);
372 if (wasNoSystemBackground != noSystemBackground) {
373 releaseSurface();
374 dfbWindow->Release(dfbWindow);
375 dfbWindow = 0;
376 createWindow(windowGeometry);
377 win->update();
378 return;
379 }
380 screen->flipSurface(dfbSurface, flipFlags, region, offset);
381 if (noSystemBackground) {
382 dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
383 }
384#else
385 setOpaque(windowOpacity != 0xff);
386 if (mode == Offscreen) {
387 screen->exposeRegion(region.translated(offset + geometry().topLeft()), 0);
388 } else {
389 screen->flipSurface(dfbSurface, flipFlags, region, offset);
390 }
391#endif
392
393#ifdef QT_DIRECTFB_TIMING
394 enum { Secs = 3 };
395 ++frames;
396 if (timer.elapsed() >= Secs * 1000) {
397 qDebug("%d fps", int(double(frames) / double(Secs)));
398 frames = 0;
399 timer.restart();
400 }
401#endif
402}
403
404void QDirectFBWindowSurface::beginPaint(const QRegion &)
405{
406 if (!engine) {
407 engine = new QDirectFBPaintEngine(this);
408 }
409}
410
411void QDirectFBWindowSurface::endPaint(const QRegion &)
412{
413#ifdef QT_NO_DIRECTFB_SUBSURFACE
414 unlockSurface();
415#endif
416}
417
418IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const
419{
420 if (!dfbSurface && sibling && sibling->dfbSurface)
421 return sibling->dfbSurface;
422 return dfbSurface;
423}
424
425
426IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const
427{
428 Q_ASSERT(widget);
429 if (!dfbSurface) {
430 if (sibling && (!sibling->sibling || sibling->dfbSurface))
431 return sibling->surfaceForWidget(widget, rect);
432 return 0;
433 }
434 QWidget *win = window();
435 Q_ASSERT(win);
436 if (rect) {
437 if (win == widget) {
438 *rect = widget->rect();
439 } else {
440 *rect = QRect(widget->mapTo(win, QPoint(0, 0)), widget->size());
441 }
442 }
443
444 Q_ASSERT(win == widget || win->isAncestorOf(widget));
445 return dfbSurface;
446}
447
448void QDirectFBWindowSurface::updateFormat()
449{
450 imageFormat = dfbSurface ? QDirectFBScreen::getImageFormat(dfbSurface) : QImage::Format_Invalid;
451}
452
453void QDirectFBWindowSurface::releaseSurface()
454{
455 if (dfbSurface) {
456#ifdef QT_DIRECTFB_SUBSURFACE
457 releaseSubSurface();
458#else
459 unlockSurface();
460#endif
461#ifdef QT_NO_DIRECTFB_WM
462 Q_ASSERT(screen->primarySurface());
463 if (dfbSurface != screen->primarySurface())
464#endif
465
466 dfbSurface->Release(dfbSurface);
467 dfbSurface = 0;
468 }
469}
470
471
472QT_END_NAMESPACE
473
474#endif // QT_NO_QWS_DIRECTFB
475
476
Note: See TracBrowser for help on using the repository browser.