author | Eckhart Koeppen <eckhart.koppen@nokia.com> |
Wed, 21 Apr 2010 20:15:53 +0300 | |
branch | RCL_3 |
changeset 14 | c0432d11811c |
parent 8 | 3f74d0d4af4c |
child 30 | 5dc02b23752f |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 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 |
||
43 |
#include "qplatformdefs.h" |
|
44 |
||
45 |
#include "qbackingstore_p.h" |
|
46 |
||
47 |
#include <QtCore/qglobal.h> |
|
48 |
#include <QtCore/qdebug.h> |
|
49 |
#include <QtCore/qvarlengtharray.h> |
|
50 |
#include <QtGui/qevent.h> |
|
51 |
#include <QtGui/qapplication.h> |
|
52 |
#include <QtGui/qpaintengine.h> |
|
53 |
#include <QtGui/qgraphicsproxywidget.h> |
|
54 |
||
55 |
#include <private/qwidget_p.h> |
|
56 |
#include <private/qwindowsurface_raster_p.h> |
|
57 |
#include <private/qapplication_p.h> |
|
58 |
#include <private/qpaintengine_raster_p.h> |
|
59 |
#include <private/qgraphicseffect_p.h> |
|
60 |
||
61 |
#include "qgraphicssystem_p.h" |
|
62 |
||
63 |
#ifdef Q_WS_QWS |
|
64 |
#include <QtGui/qwsmanager_qws.h> |
|
65 |
#include <private/qwsmanager_p.h> |
|
66 |
#endif |
|
67 |
||
68 |
QT_BEGIN_NAMESPACE |
|
69 |
||
70 |
extern QRegion qt_dirtyRegion(QWidget *); |
|
71 |
||
72 |
/* |
|
73 |
A version of QRect::intersects() that does not normalize the rects. |
|
74 |
*/ |
|
75 |
static inline bool qRectIntersects(const QRect &r1, const QRect &r2) |
|
76 |
{ |
|
77 |
return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) |
|
78 |
&& qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom())); |
|
79 |
} |
|
80 |
||
81 |
/** |
|
82 |
* Flushes the contents of the \a windowSurface into the screen area of \a widget. |
|
83 |
* \a tlwOffset is the position of the top level widget relative to the window surface. |
|
84 |
* \a region is the region to be updated in \a widget coordinates. |
|
85 |
*/ |
|
86 |
static inline void qt_flush(QWidget *widget, const QRegion ®ion, QWindowSurface *windowSurface, |
|
87 |
QWidget *tlw, const QPoint &tlwOffset) |
|
88 |
{ |
|
89 |
Q_ASSERT(widget); |
|
90 |
Q_ASSERT(!region.isEmpty()); |
|
91 |
Q_ASSERT(windowSurface); |
|
92 |
Q_ASSERT(tlw); |
|
93 |
||
94 |
#if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS) |
|
95 |
// QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc). |
|
96 |
static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt(); |
|
97 |
if (flushUpdate > 0) |
|
98 |
QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false); |
|
99 |
#endif |
|
100 |
||
101 |
if (widget != tlw) |
|
102 |
windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint())); |
|
103 |
else |
|
104 |
windowSurface->flush(widget, region, tlwOffset); |
|
105 |
} |
|
106 |
||
107 |
#ifndef QT_NO_PAINT_DEBUG |
|
108 |
#ifdef Q_WS_WIN |
|
109 |
static void showYellowThing_win(QWidget *widget, const QRegion ®ion, int msec) |
|
110 |
{ |
|
111 |
HBRUSH brush; |
|
112 |
static int i = 0; |
|
113 |
switch (i) { |
|
114 |
case 0: |
|
115 |
brush = CreateSolidBrush(RGB(255, 255, 0)); |
|
116 |
break; |
|
117 |
case 1: |
|
118 |
brush = CreateSolidBrush(RGB(255, 200, 55)); |
|
119 |
break; |
|
120 |
case 2: |
|
121 |
brush = CreateSolidBrush(RGB(200, 255, 55)); |
|
122 |
break; |
|
123 |
case 3: |
|
124 |
brush = CreateSolidBrush(RGB(200, 200, 0)); |
|
125 |
break; |
|
126 |
} |
|
127 |
i = (i + 1) & 3; |
|
128 |
||
129 |
HDC hdc = widget->getDC(); |
|
130 |
||
131 |
const QVector<QRect> &rects = region.rects(); |
|
132 |
foreach (QRect rect, rects) { |
|
133 |
RECT winRect; |
|
134 |
SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom()); |
|
135 |
FillRect(hdc, &winRect, brush); |
|
136 |
} |
|
137 |
||
138 |
widget->releaseDC(hdc); |
|
139 |
::Sleep(msec); |
|
140 |
} |
|
141 |
#endif |
|
142 |
||
143 |
void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped) |
|
144 |
{ |
|
145 |
#ifdef Q_WS_QWS |
|
146 |
Q_UNUSED(widget); |
|
147 |
Q_UNUSED(unclipped); |
|
148 |
static QWSYellowSurface surface(true); |
|
149 |
surface.setDelay(msec); |
|
150 |
surface.flush(widget, toBePainted, QPoint()); |
|
151 |
#else |
|
152 |
QRegion paintRegion = toBePainted; |
|
153 |
QRect widgetRect = widget->rect(); |
|
154 |
||
155 |
if (!widget->internalWinId()) { |
|
156 |
QWidget *nativeParent = widget->nativeParentWidget(); |
|
157 |
const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0)); |
|
158 |
paintRegion.translate(offset); |
|
159 |
widgetRect.translate(offset); |
|
160 |
widget = nativeParent; |
|
161 |
} |
|
162 |
||
163 |
#ifdef Q_WS_WIN |
|
164 |
Q_UNUSED(unclipped); |
|
165 |
showYellowThing_win(widget, paintRegion, msec); |
|
166 |
#else |
|
167 |
//flags to fool painter |
|
168 |
bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped); |
|
169 |
if (unclipped && !widget->d_func()->paintOnScreen()) |
|
170 |
widget->setAttribute(Qt::WA_PaintUnclipped); |
|
171 |
||
172 |
const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent); |
|
173 |
if (setFlag) |
|
174 |
widget->setAttribute(Qt::WA_WState_InPaintEvent); |
|
175 |
||
176 |
//setup the engine |
|
177 |
QPaintEngine *pe = widget->paintEngine(); |
|
178 |
if (pe) { |
|
179 |
pe->setSystemClip(paintRegion); |
|
180 |
{ |
|
181 |
QPainter p(widget); |
|
182 |
p.setClipRegion(paintRegion); |
|
183 |
static int i = 0; |
|
184 |
switch (i) { |
|
185 |
case 0: |
|
186 |
p.fillRect(widgetRect, QColor(255,255,0)); |
|
187 |
break; |
|
188 |
case 1: |
|
189 |
p.fillRect(widgetRect, QColor(255,200,55)); |
|
190 |
break; |
|
191 |
case 2: |
|
192 |
p.fillRect(widgetRect, QColor(200,255,55)); |
|
193 |
break; |
|
194 |
case 3: |
|
195 |
p.fillRect(widgetRect, QColor(200,200,0)); |
|
196 |
break; |
|
197 |
} |
|
198 |
i = (i+1) & 3; |
|
199 |
p.end(); |
|
200 |
} |
|
201 |
} |
|
202 |
||
203 |
if (setFlag) |
|
204 |
widget->setAttribute(Qt::WA_WState_InPaintEvent, false); |
|
205 |
||
206 |
//restore |
|
207 |
widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped); |
|
208 |
||
209 |
if (pe) |
|
210 |
pe->setSystemClip(QRegion()); |
|
211 |
||
212 |
QApplication::syncX(); |
|
213 |
||
214 |
#if defined(Q_OS_UNIX) |
|
215 |
::usleep(1000 * msec); |
|
216 |
#endif |
|
217 |
#endif // Q_WS_WIN |
|
218 |
#endif // Q_WS_QWS |
|
219 |
} |
|
220 |
||
221 |
bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn) |
|
222 |
{ |
|
223 |
if (!widget) |
|
224 |
return false; |
|
225 |
||
226 |
int delay = 0; |
|
227 |
if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) { |
|
228 |
static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt(); |
|
229 |
if (!flushPaintEvent) |
|
230 |
return false; |
|
231 |
delay = flushPaintEvent; |
|
232 |
} else { |
|
233 |
static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt(); |
|
234 |
if (!flushPaint) |
|
235 |
return false; |
|
236 |
delay = flushPaint; |
|
237 |
} |
|
238 |
||
239 |
QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true); |
|
240 |
return true; |
|
241 |
} |
|
242 |
||
243 |
void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn) |
|
244 |
{ |
|
245 |
if (widget->d_func()->paintOnScreen() || rgn.isEmpty()) |
|
246 |
return; |
|
247 |
||
248 |
QWidget *tlw = widget->window(); |
|
249 |
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
250 |
if (!tlwExtra) |
|
251 |
return; |
|
252 |
||
253 |
const QPoint offset = widget->mapTo(tlw, QPoint()); |
|
254 |
qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset); |
|
255 |
} |
|
256 |
#endif // QT_NO_PAINT_DEBUG |
|
257 |
||
258 |
/* |
|
259 |
Moves the whole rect by (dx, dy) in widget's coordinate system. |
|
260 |
Doesn't generate any updates. |
|
261 |
*/ |
|
262 |
bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget) |
|
263 |
{ |
|
264 |
const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft())); |
|
265 |
const QRect tlwRect(QRect(pos, rect.size())); |
|
266 |
if (dirty.intersects(tlwRect)) |
|
267 |
return false; // We don't want to scroll junk. |
|
268 |
return windowSurface->scroll(tlwRect, dx, dy); |
|
269 |
} |
|
270 |
||
271 |
void QWidgetBackingStore::releaseBuffer() |
|
272 |
{ |
|
273 |
if (windowSurface) |
|
274 |
windowSurface->setGeometry(QRect()); |
|
275 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
276 |
for (int i = 0; i < subSurfaces.size(); ++i) |
|
277 |
subSurfaces.at(i)->setGeometry(QRect()); |
|
278 |
#endif |
|
279 |
} |
|
280 |
||
281 |
/*! |
|
282 |
Prepares the window surface to paint a\ toClean region of the \a widget and |
|
283 |
updates the BeginPaintInfo struct accordingly. |
|
284 |
||
285 |
The \a toClean region might be clipped by the window surface. |
|
286 |
*/ |
|
287 |
void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface, |
|
288 |
BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates) |
|
289 |
{ |
|
290 |
#ifdef Q_WS_QWS |
|
291 |
QWSWindowSurface *surface = static_cast<QWSWindowSurface *>(windowSurface); |
|
292 |
QWidget *surfaceWidget = surface->window(); |
|
293 |
||
294 |
if (!surface->isValid()) { |
|
295 |
// this looks strange but it really just releases the surface |
|
296 |
surface->releaseSurface(); |
|
297 |
// the old window surface is deleted in setWindowSurface, which is |
|
298 |
// called from QWindowSurface constructor. |
|
299 |
windowSurface = tlw->d_func()->createDefaultWindowSurface(); |
|
300 |
surface = static_cast<QWSWindowSurface *>(windowSurface); |
|
301 |
// createDefaultWindowSurface() will set topdata->windowSurface on the |
|
302 |
// widget to zero. However, if this is a sub-surface, it should point |
|
303 |
// to the widget's sub windowSurface, so we set that here: |
|
304 |
if (!surfaceWidget->isWindow()) |
|
305 |
surfaceWidget->d_func()->topData()->windowSurface = windowSurface; |
|
306 |
surface->setGeometry(topLevelRect()); |
|
307 |
returnInfo->windowSurfaceRecreated = true; |
|
308 |
} |
|
309 |
||
310 |
const QRegion toCleanUnclipped(toClean); |
|
311 |
||
312 |
if (surfaceWidget->isWindow()) |
|
313 |
tlwOffset = surface->painterOffset(); |
|
314 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
315 |
else if (toCleanIsInTopLevelCoordinates) |
|
316 |
toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint())); |
|
317 |
if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface) |
|
318 |
toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint())); |
|
319 |
#else |
|
320 |
toClean &= surface->clipRegion(); |
|
321 |
#endif |
|
322 |
||
323 |
if (toClean.isEmpty()) { |
|
324 |
if (surfaceWidget->isWindow()) { |
|
325 |
dirtyFromPreviousSync += toCleanUnclipped; |
|
326 |
hasDirtyFromPreviousSync = true; |
|
327 |
} |
|
328 |
||
329 |
returnInfo->nothingToPaint = true; |
|
330 |
// Nothing to repaint. However, we might have newly exposed areas on the |
|
331 |
// screen, so we have to make sure those are flushed. |
|
332 |
flush(); |
|
333 |
return; |
|
334 |
} |
|
335 |
||
336 |
if (surfaceWidget->isWindow()) { |
|
337 |
if (toCleanUnclipped != toClean) { |
|
338 |
dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion()); |
|
339 |
hasDirtyFromPreviousSync = true; |
|
340 |
} |
|
341 |
if (hasDirtyFromPreviousSync) { |
|
342 |
dirtyFromPreviousSync -= toClean; |
|
343 |
hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty(); |
|
344 |
} |
|
345 |
} |
|
346 |
||
347 |
#endif // Q_WS_QWS |
|
348 |
||
349 |
Q_UNUSED(widget); |
|
350 |
Q_UNUSED(toCleanIsInTopLevelCoordinates); |
|
351 |
||
352 |
// Always flush repainted areas. |
|
353 |
dirtyOnScreen += toClean; |
|
354 |
||
8
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
355 |
#ifdef Q_WS_QWS |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
356 |
toClean.translate(tlwOffset); |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
357 |
#endif |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
358 |
|
0 | 359 |
#ifdef QT_NO_PAINT_DEBUG |
360 |
windowSurface->beginPaint(toClean); |
|
361 |
#else |
|
362 |
returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean); |
|
363 |
// Avoid deadlock with QT_FLUSH_PAINT: the server will wait for |
|
364 |
// the BackingStore lock, so if we hold that, the server will |
|
365 |
// never release the Communication lock that we are waiting for in |
|
366 |
// sendSynchronousCommand |
|
367 |
if (!returnInfo->wasFlushed) |
|
368 |
windowSurface->beginPaint(toClean); |
|
369 |
#endif |
|
370 |
||
371 |
Q_UNUSED(returnInfo); |
|
372 |
} |
|
373 |
||
374 |
void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, |
|
375 |
BeginPaintInfo *beginPaintInfo) |
|
376 |
{ |
|
377 |
#ifndef QT_NO_PAINT_DEBUG |
|
378 |
if (!beginPaintInfo->wasFlushed) |
|
379 |
windowSurface->endPaint(cleaned); |
|
380 |
else |
|
381 |
QWidgetBackingStore::unflushPaint(tlw, cleaned); |
|
382 |
#else |
|
383 |
Q_UNUSED(beginPaintInfo); |
|
384 |
windowSurface->endPaint(cleaned); |
|
385 |
#endif |
|
386 |
||
387 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
388 |
flush(static_cast<QWSWindowSurface *>(windowSurface)->window(), windowSurface); |
|
389 |
#else |
|
390 |
flush(); |
|
391 |
#endif |
|
392 |
} |
|
393 |
||
394 |
/*! |
|
395 |
Returns the region (in top-level coordinates) that needs repaint and/or flush. |
|
396 |
||
397 |
If the widget is non-zero, only the dirty region for the widget is returned |
|
398 |
and the region will be in widget coordinates. |
|
399 |
*/ |
|
400 |
QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const |
|
401 |
{ |
|
402 |
const bool widgetDirty = widget && widget != tlw; |
|
403 |
const QRect tlwRect(topLevelRect()); |
|
404 |
const QRect surfaceGeometry(windowSurface->geometry()); |
|
405 |
if (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size()) { |
|
406 |
if (widgetDirty) { |
|
407 |
const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); |
|
408 |
const QPoint offset(widget->mapTo(tlw, QPoint())); |
|
409 |
const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset)); |
|
410 |
return dirtyWidgetRect.translated(-offset); |
|
411 |
} |
|
412 |
return QRect(QPoint(), tlwRect.size()); |
|
413 |
} |
|
414 |
||
415 |
// Calculate the region that needs repaint. |
|
416 |
QRegion r(dirty); |
|
417 |
for (int i = 0; i < dirtyWidgets.size(); ++i) { |
|
418 |
QWidget *w = dirtyWidgets.at(i); |
|
419 |
if (widgetDirty && w != widget && !widget->isAncestorOf(w)) |
|
420 |
continue; |
|
421 |
r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint())); |
|
422 |
} |
|
423 |
||
424 |
// Append the region that needs flush. |
|
425 |
r += dirtyOnScreen; |
|
426 |
||
427 |
if (dirtyOnScreenWidgets) { // Only in use with native child widgets. |
|
428 |
for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { |
|
429 |
QWidget *w = dirtyOnScreenWidgets->at(i); |
|
430 |
if (widgetDirty && w != widget && !widget->isAncestorOf(w)) |
|
431 |
continue; |
|
432 |
QWidgetPrivate *wd = w->d_func(); |
|
433 |
Q_ASSERT(wd->needsFlush); |
|
434 |
r += wd->needsFlush->translated(w->mapTo(tlw, QPoint())); |
|
435 |
} |
|
436 |
} |
|
437 |
||
438 |
if (widgetDirty) { |
|
439 |
// Intersect with the widget geometry and translate to its coordinates. |
|
440 |
const QPoint offset(widget->mapTo(tlw, QPoint())); |
|
441 |
r &= widget->rect().translated(offset); |
|
442 |
r.translate(-offset); |
|
443 |
} |
|
444 |
return r; |
|
445 |
} |
|
446 |
||
447 |
/*! |
|
448 |
Returns the static content inside the \a parent if non-zero; otherwise the static content |
|
449 |
for the entire backing store is returned. The content will be clipped to \a withingClipRect |
|
450 |
if non-empty. |
|
451 |
*/ |
|
452 |
QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const |
|
453 |
{ |
|
454 |
if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { |
|
455 |
const QRect surfaceGeometry(windowSurface->geometry()); |
|
456 |
QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); |
|
457 |
if (!withinClipRect.isEmpty()) |
|
458 |
surfaceRect &= withinClipRect; |
|
459 |
return QRegion(surfaceRect); |
|
460 |
} |
|
461 |
||
462 |
QRegion region; |
|
463 |
if (parent && parent->d_func()->children.isEmpty()) |
|
464 |
return region; |
|
465 |
||
466 |
const bool clipToRect = !withinClipRect.isEmpty(); |
|
467 |
const int count = staticWidgets.count(); |
|
468 |
for (int i = 0; i < count; ++i) { |
|
469 |
QWidget *w = staticWidgets.at(i); |
|
470 |
QWidgetPrivate *wd = w->d_func(); |
|
471 |
if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() |
|
472 |
|| !w->isVisible() || (parent && !parent->isAncestorOf(w))) { |
|
473 |
continue; |
|
474 |
} |
|
475 |
||
476 |
QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height()); |
|
477 |
const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint()); |
|
478 |
if (clipToRect) |
|
479 |
rect &= withinClipRect.translated(-offset); |
|
480 |
if (rect.isEmpty()) |
|
481 |
continue; |
|
482 |
||
483 |
rect &= wd->clipRect(); |
|
484 |
if (rect.isEmpty()) |
|
485 |
continue; |
|
486 |
||
487 |
QRegion visible(rect); |
|
488 |
wd->clipToEffectiveMask(visible); |
|
489 |
if (visible.isEmpty()) |
|
490 |
continue; |
|
491 |
wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true); |
|
492 |
||
493 |
visible.translate(offset); |
|
494 |
region += visible; |
|
495 |
} |
|
496 |
||
497 |
return region; |
|
498 |
} |
|
499 |
||
500 |
static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) |
|
501 |
{ |
|
502 |
if (!widget) |
|
503 |
return; |
|
504 |
||
505 |
if (updateImmediately) { |
|
506 |
QEvent event(QEvent::UpdateRequest); |
|
507 |
QApplication::sendEvent(widget, &event); |
|
508 |
} else { |
|
509 |
QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); |
|
510 |
} |
|
511 |
} |
|
512 |
||
513 |
/*! |
|
514 |
Marks the region of the widget as dirty (if not already marked as dirty) and |
|
515 |
posts an UpdateRequest event to the top-level widget (if not already posted). |
|
516 |
||
517 |
If updateImmediately is true, the event is sent immediately instead of posted. |
|
518 |
||
519 |
If invalidateBuffer is true, all widgets intersecting with the region will be dirty. |
|
520 |
||
521 |
If the widget paints directly on screen, the event is sent to the widget |
|
522 |
instead of the top-level widget, and invalidateBuffer is completely ignored. |
|
523 |
||
524 |
### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
525 |
*/ |
|
526 |
void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, |
|
527 |
bool invalidateBuffer) |
|
528 |
{ |
|
529 |
Q_ASSERT(tlw->d_func()->extra); |
|
530 |
Q_ASSERT(tlw->d_func()->extra->topextra); |
|
531 |
Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); |
|
532 |
Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); |
|
533 |
Q_ASSERT(widget->window() == tlw); |
|
534 |
Q_ASSERT(!rgn.isEmpty()); |
|
535 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
536 |
#ifndef QT_NO_GRAPHICSEFFECT |
0 | 537 |
widget->d_func()->invalidateGraphicsEffectsRecursively(); |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
538 |
#endif //QT_NO_GRAPHICSEFFECT |
0 | 539 |
|
540 |
if (widget->d_func()->paintOnScreen()) { |
|
541 |
if (widget->d_func()->dirty.isEmpty()) { |
|
542 |
widget->d_func()->dirty = rgn; |
|
543 |
sendUpdateRequest(widget, updateImmediately); |
|
544 |
return; |
|
545 |
} else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { |
|
546 |
if (updateImmediately) |
|
547 |
sendUpdateRequest(widget, updateImmediately); |
|
548 |
return; // Already dirty. |
|
549 |
} |
|
550 |
||
551 |
const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); |
|
552 |
widget->d_func()->dirty += rgn; |
|
553 |
if (!eventAlreadyPosted || updateImmediately) |
|
554 |
sendUpdateRequest(widget, updateImmediately); |
|
555 |
return; |
|
556 |
} |
|
557 |
||
558 |
const QPoint offset = widget->mapTo(tlw, QPoint()); |
|
559 |
const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); |
|
560 |
if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { |
|
561 |
if (updateImmediately) |
|
562 |
sendUpdateRequest(tlw, updateImmediately); |
|
563 |
return; // Already dirty. |
|
564 |
} |
|
565 |
||
566 |
if (invalidateBuffer) { |
|
567 |
const bool eventAlreadyPosted = !dirty.isEmpty(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
568 |
#ifndef QT_NO_GRAPHICSEFFECT |
0 | 569 |
if (widget->d_func()->graphicsEffect) |
570 |
dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); |
|
571 |
else |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
572 |
#endif //QT_NO_GRAPHICSEFFECT |
0 | 573 |
dirty += rgn.translated(offset); |
574 |
if (!eventAlreadyPosted || updateImmediately) |
|
575 |
sendUpdateRequest(tlw, updateImmediately); |
|
576 |
return; |
|
577 |
} |
|
578 |
||
579 |
if (dirtyWidgets.isEmpty()) { |
|
580 |
addDirtyWidget(widget, rgn); |
|
581 |
sendUpdateRequest(tlw, updateImmediately); |
|
582 |
return; |
|
583 |
} |
|
584 |
||
585 |
if (widget->d_func()->inDirtyList) { |
|
586 |
if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) { |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
587 |
#ifndef QT_NO_GRAPHICSEFFECT |
0 | 588 |
if (widget->d_func()->graphicsEffect) |
589 |
widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()); |
|
590 |
else |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
591 |
#endif //QT_NO_GRAPHICSEFFECT |
0 | 592 |
widget->d_func()->dirty += rgn; |
593 |
} |
|
594 |
} else { |
|
595 |
addDirtyWidget(widget, rgn); |
|
596 |
} |
|
597 |
||
598 |
if (updateImmediately) |
|
599 |
sendUpdateRequest(tlw, updateImmediately); |
|
600 |
} |
|
601 |
||
602 |
/*! |
|
603 |
This function is equivalent to calling markDirty(QRegion(rect), ...), but |
|
604 |
is more efficient as it eliminates QRegion operations/allocations and can |
|
605 |
use the rect more precisely for additional cut-offs. |
|
606 |
||
607 |
### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
608 |
*/ |
|
609 |
void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, |
|
610 |
bool invalidateBuffer) |
|
611 |
{ |
|
612 |
Q_ASSERT(tlw->d_func()->extra); |
|
613 |
Q_ASSERT(tlw->d_func()->extra->topextra); |
|
614 |
Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); |
|
615 |
Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); |
|
616 |
Q_ASSERT(widget->window() == tlw); |
|
617 |
Q_ASSERT(!rect.isEmpty()); |
|
618 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
619 |
#ifndef QT_NO_GRAPHICSEFFECT |
0 | 620 |
widget->d_func()->invalidateGraphicsEffectsRecursively(); |
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
621 |
#endif //QT_NO_GRAPHICSEFFECT |
0 | 622 |
|
623 |
if (widget->d_func()->paintOnScreen()) { |
|
624 |
if (widget->d_func()->dirty.isEmpty()) { |
|
625 |
widget->d_func()->dirty = QRegion(rect); |
|
626 |
sendUpdateRequest(widget, updateImmediately); |
|
627 |
return; |
|
628 |
} else if (qt_region_strictContains(widget->d_func()->dirty, rect)) { |
|
629 |
if (updateImmediately) |
|
630 |
sendUpdateRequest(widget, updateImmediately); |
|
631 |
return; // Already dirty. |
|
632 |
} |
|
633 |
||
634 |
const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); |
|
635 |
widget->d_func()->dirty += rect; |
|
636 |
if (!eventAlreadyPosted || updateImmediately) |
|
637 |
sendUpdateRequest(widget, updateImmediately); |
|
638 |
return; |
|
639 |
} |
|
640 |
||
641 |
const QRect widgetRect = widget->d_func()->effectiveRectFor(rect); |
|
642 |
const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint()))); |
|
643 |
if (qt_region_strictContains(dirty, translatedRect)) { |
|
644 |
if (updateImmediately) |
|
645 |
sendUpdateRequest(tlw, updateImmediately); |
|
646 |
return; // Already dirty |
|
647 |
} |
|
648 |
||
649 |
if (invalidateBuffer) { |
|
650 |
const bool eventAlreadyPosted = !dirty.isEmpty(); |
|
651 |
dirty += translatedRect; |
|
652 |
if (!eventAlreadyPosted || updateImmediately) |
|
653 |
sendUpdateRequest(tlw, updateImmediately); |
|
654 |
return; |
|
655 |
} |
|
656 |
||
657 |
if (dirtyWidgets.isEmpty()) { |
|
658 |
addDirtyWidget(widget, rect); |
|
659 |
sendUpdateRequest(tlw, updateImmediately); |
|
660 |
return; |
|
661 |
} |
|
662 |
||
663 |
if (widget->d_func()->inDirtyList) { |
|
664 |
if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) |
|
665 |
widget->d_func()->dirty += widgetRect; |
|
666 |
} else { |
|
667 |
addDirtyWidget(widget, rect); |
|
668 |
} |
|
669 |
||
670 |
if (updateImmediately) |
|
671 |
sendUpdateRequest(tlw, updateImmediately); |
|
672 |
} |
|
673 |
||
674 |
/*! |
|
675 |
Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from |
|
676 |
the backing store to the \a widget's native parent next time flush() is called. |
|
677 |
||
678 |
Paint on screen widgets are ignored. |
|
679 |
*/ |
|
680 |
void QWidgetBackingStore::markDirtyOnScreen(const QRegion ®ion, QWidget *widget, const QPoint &topLevelOffset) |
|
681 |
{ |
|
682 |
if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty()) |
|
683 |
return; |
|
684 |
||
685 |
#if defined(Q_WS_QWS) || defined(Q_WS_MAC) |
|
686 |
if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) |
|
687 |
dirtyOnScreen += region.translated(topLevelOffset); |
|
688 |
return; |
|
689 |
#endif |
|
690 |
||
691 |
// Top-level. |
|
692 |
if (widget == tlw) { |
|
693 |
if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) |
|
694 |
dirtyOnScreen += region; |
|
695 |
return; |
|
696 |
} |
|
697 |
||
698 |
// Alien widgets. |
|
699 |
if (!widget->internalWinId()) { |
|
700 |
QWidget *nativeParent = widget->nativeParentWidget(); |
|
701 |
// Alien widgets with the top-level as the native parent (common case). |
|
702 |
if (nativeParent == tlw) { |
|
703 |
if (!widget->testAttribute(Qt::WA_WState_InPaintEvent)) |
|
704 |
dirtyOnScreen += region.translated(topLevelOffset); |
|
705 |
return; |
|
706 |
} |
|
707 |
||
708 |
// Alien widgets with native parent != tlw. |
|
709 |
QWidgetPrivate *nativeParentPrivate = nativeParent->d_func(); |
|
710 |
if (!nativeParentPrivate->needsFlush) |
|
711 |
nativeParentPrivate->needsFlush = new QRegion; |
|
712 |
const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint()); |
|
713 |
*nativeParentPrivate->needsFlush += region.translated(nativeParentOffset); |
|
714 |
appendDirtyOnScreenWidget(nativeParent); |
|
715 |
return; |
|
716 |
} |
|
717 |
||
718 |
// Native child widgets. |
|
719 |
QWidgetPrivate *widgetPrivate = widget->d_func(); |
|
720 |
if (!widgetPrivate->needsFlush) |
|
721 |
widgetPrivate->needsFlush = new QRegion; |
|
722 |
*widgetPrivate->needsFlush += region; |
|
723 |
appendDirtyOnScreenWidget(widget); |
|
724 |
} |
|
725 |
||
726 |
void QWidgetBackingStore::removeDirtyWidget(QWidget *w) |
|
727 |
{ |
|
728 |
if (!w) |
|
729 |
return; |
|
730 |
||
731 |
dirtyWidgetsRemoveAll(w); |
|
732 |
dirtyOnScreenWidgetsRemoveAll(w); |
|
733 |
resetWidget(w); |
|
734 |
||
735 |
QWidgetPrivate *wd = w->d_func(); |
|
736 |
const int n = wd->children.count(); |
|
737 |
for (int i = 0; i < n; ++i) { |
|
738 |
if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i))) |
|
739 |
removeDirtyWidget(child); |
|
740 |
} |
|
741 |
} |
|
742 |
||
743 |
#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) |
|
744 |
bool QWidgetBackingStore::hasDirtyWindowDecoration() const |
|
745 |
{ |
|
746 |
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
747 |
if (tlwExtra && tlwExtra->qwsManager) |
|
748 |
return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty(); |
|
749 |
return false; |
|
750 |
} |
|
751 |
||
752 |
void QWidgetBackingStore::paintWindowDecoration() |
|
753 |
{ |
|
754 |
if (!hasDirtyWindowDecoration()) |
|
755 |
return; |
|
756 |
||
757 |
QDecoration &decoration = QApplication::qwsDecoration(); |
|
758 |
const QRect decorationRect = tlw->rect(); |
|
759 |
QRegion decorationRegion = decoration.region(tlw, decorationRect); |
|
760 |
||
761 |
QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func(); |
|
762 |
const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint |
|
763 |
&& !managerPrivate->dirtyClip.isEmpty(); |
|
764 |
||
765 |
if (doClipping) { |
|
766 |
decorationRegion &= static_cast<QWSWindowSurface *>(windowSurface)->clipRegion(); |
|
767 |
decorationRegion &= managerPrivate->dirtyClip; |
|
768 |
} |
|
769 |
||
770 |
if (decorationRegion.isEmpty()) |
|
771 |
return; |
|
772 |
||
8
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
773 |
//### The QWS decorations do not always paint the pixels they promise to paint. |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
774 |
// This causes painting problems with QWSMemorySurface. Since none of the other |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
775 |
// window surfaces actually use the region, passing an empty region is a safe |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
776 |
// workaround. |
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
777 |
|
3f74d0d4af4c
qt:70947f0f93d948bc89b3b43d00da758a51f1ef84
Eckhart Koeppen <eckhart.koppen@nokia.com>
parents:
4
diff
changeset
|
778 |
windowSurface->beginPaint(QRegion()); |
0 | 779 |
|
780 |
QPaintEngine *engine = windowSurface->paintDevice()->paintEngine(); |
|
781 |
Q_ASSERT(engine); |
|
782 |
const QRegion oldSystemClip(engine->systemClip()); |
|
783 |
engine->setSystemClip(decorationRegion.translated(tlwOffset)); |
|
784 |
||
785 |
QPainter painter(windowSurface->paintDevice()); |
|
786 |
painter.setFont(QApplication::font()); |
|
787 |
painter.translate(tlwOffset); |
|
788 |
||
789 |
const int numDirty = managerPrivate->dirtyRegions.size(); |
|
790 |
for (int i = 0; i < numDirty; ++i) { |
|
791 |
const int area = managerPrivate->dirtyRegions.at(i); |
|
792 |
||
793 |
QRegion clipRegion = decoration.region(tlw, decorationRect, area); |
|
794 |
if (!clipRegion.isEmpty()) { |
|
795 |
// Decoration styles changes the clip and assumes the old clip is non-empty, |
|
796 |
// so we have to set it, but in theory it shouldn't be required. |
|
797 |
painter.setClipRegion(clipRegion); |
|
798 |
decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i)); |
|
799 |
} |
|
800 |
} |
|
801 |
markDirtyOnScreen(decorationRegion, tlw, QPoint()); |
|
802 |
||
803 |
painter.end(); |
|
804 |
windowSurface->endPaint(decorationRegion); |
|
805 |
managerPrivate->clearDirtyRegions(); |
|
806 |
engine->setSystemClip(oldSystemClip); |
|
807 |
} |
|
808 |
#endif |
|
809 |
||
810 |
void QWidgetBackingStore::updateLists(QWidget *cur) |
|
811 |
{ |
|
812 |
if (!cur) |
|
813 |
return; |
|
814 |
||
815 |
QList<QObject*> children = cur->children(); |
|
816 |
for (int i = 0; i < children.size(); ++i) { |
|
817 |
QWidget *child = qobject_cast<QWidget*>(children.at(i)); |
|
818 |
if (!child) |
|
819 |
continue; |
|
820 |
||
821 |
updateLists(child); |
|
822 |
} |
|
823 |
||
824 |
if (cur->testAttribute(Qt::WA_StaticContents)) |
|
825 |
addStaticWidget(cur); |
|
826 |
||
827 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
828 |
QTLWExtra *extra = cur->d_func()->maybeTopData(); |
|
829 |
if (extra && extra->windowSurface && cur != tlw) |
|
830 |
subSurfaces.append(extra->windowSurface); |
|
831 |
#endif |
|
832 |
} |
|
833 |
||
834 |
QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) |
|
835 |
: tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) |
|
836 |
{ |
|
837 |
windowSurface = tlw->windowSurface(); |
|
838 |
if (!windowSurface) |
|
839 |
windowSurface = topLevel->d_func()->createDefaultWindowSurface(); |
|
840 |
||
841 |
// The QWindowSurface constructor will call QWidget::setWindowSurface(), |
|
842 |
// but automatically created surfaces should not be added to the topdata. |
|
843 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
844 |
Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface); |
|
845 |
#endif |
|
846 |
topLevel->d_func()->topData()->windowSurface = 0; |
|
847 |
||
848 |
// Ensure all existing subsurfaces and static widgets are added to their respective lists. |
|
849 |
updateLists(topLevel); |
|
850 |
} |
|
851 |
||
852 |
QWidgetBackingStore::~QWidgetBackingStore() |
|
853 |
{ |
|
854 |
for (int c = 0; c < dirtyWidgets.size(); ++c) { |
|
855 |
resetWidget(dirtyWidgets.at(c)); |
|
856 |
} |
|
857 |
||
858 |
delete windowSurface; |
|
859 |
windowSurface = 0; |
|
860 |
delete dirtyOnScreenWidgets; |
|
861 |
dirtyOnScreenWidgets = 0; |
|
862 |
} |
|
863 |
||
864 |
//parent's coordinates; move whole rect; update parent and widget |
|
865 |
//assume the screen blt has already been done, so we don't need to refresh that part |
|
866 |
void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) |
|
867 |
{ |
|
868 |
Q_Q(QWidget); |
|
869 |
if (!q->isVisible() || (dx == 0 && dy == 0)) |
|
870 |
return; |
|
871 |
||
872 |
QWidget *tlw = q->window(); |
|
873 |
QTLWExtra* x = tlw->d_func()->topData(); |
|
874 |
if (x->inTopLevelResize) |
|
875 |
return; |
|
876 |
||
877 |
static int accelEnv = -1; |
|
878 |
if (accelEnv == -1) { |
|
879 |
accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0; |
|
880 |
} |
|
881 |
||
882 |
QWidget *pw = q->parentWidget(); |
|
883 |
QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); |
|
884 |
QWidgetPrivate *pd = pw->d_func(); |
|
885 |
QRect clipR(pd->clipRect()); |
|
886 |
#ifdef Q_WS_QWS |
|
887 |
QWidgetBackingStore *wbs = x->backingStore; |
|
888 |
QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
889 |
clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect()); |
|
890 |
#endif |
|
891 |
const QRect newRect(rect.translated(dx, dy)); |
|
892 |
QRect destRect = rect.intersected(clipR); |
|
893 |
if (destRect.isValid()) |
|
894 |
destRect = destRect.translated(dx, dy).intersected(clipR); |
|
895 |
const QRect sourceRect(destRect.translated(-dx, -dy)); |
|
896 |
const QRect parentRect(rect & clipR); |
|
897 |
||
898 |
bool accelerateMove = accelEnv && isOpaque |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
899 |
#ifndef QT_NO_GRAPHICSVIEW |
0 | 900 |
// No accelerate move for proxy widgets. |
901 |
&& !tlw->d_func()->extra->proxyWidget |
|
902 |
#endif |
|
903 |
&& !isOverlapped(sourceRect) && !isOverlapped(destRect); |
|
904 |
||
905 |
if (!accelerateMove) { |
|
906 |
QRegion parentR(effectiveRectFor(parentRect)); |
|
907 |
if (!extra || !extra->hasMask) { |
|
908 |
parentR -= newRect; |
|
909 |
} else { |
|
910 |
// invalidateBuffer() excludes anything outside the mask |
|
911 |
parentR += newRect & clipR; |
|
912 |
} |
|
913 |
pd->invalidateBuffer(parentR); |
|
914 |
invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); |
|
915 |
} else { |
|
916 |
||
917 |
QWidgetBackingStore *wbs = x->backingStore; |
|
918 |
QRegion childExpose(newRect & clipR); |
|
919 |
||
920 |
if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) |
|
921 |
childExpose -= destRect; |
|
922 |
||
923 |
if (!pw->updatesEnabled()) |
|
924 |
return; |
|
925 |
||
926 |
const bool childUpdatesEnabled = q->updatesEnabled(); |
|
927 |
if (childUpdatesEnabled && !childExpose.isEmpty()) { |
|
928 |
childExpose.translate(-data.crect.topLeft()); |
|
929 |
wbs->markDirty(childExpose, q); |
|
930 |
isMoved = true; |
|
931 |
} |
|
932 |
||
933 |
QRegion parentExpose(parentRect); |
|
934 |
parentExpose -= newRect; |
|
935 |
if (extra && extra->hasMask) |
|
936 |
parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); |
|
937 |
||
938 |
if (!parentExpose.isEmpty()) { |
|
939 |
wbs->markDirty(parentExpose, pw); |
|
940 |
pd->isMoved = true; |
|
941 |
} |
|
942 |
||
943 |
if (childUpdatesEnabled) { |
|
944 |
QRegion needsFlush(sourceRect); |
|
945 |
needsFlush += destRect; |
|
946 |
wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset); |
|
947 |
} |
|
948 |
} |
|
949 |
} |
|
950 |
||
951 |
//widget's coordinates; scroll within rect; only update widget |
|
952 |
void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) |
|
953 |
{ |
|
954 |
Q_Q(QWidget); |
|
955 |
QWidget *tlw = q->window(); |
|
956 |
QTLWExtra* x = tlw->d_func()->topData(); |
|
957 |
if (x->inTopLevelResize) |
|
958 |
return; |
|
959 |
||
960 |
QWidgetBackingStore *wbs = x->backingStore; |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
961 |
if (!wbs) |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
962 |
return; |
0 | 963 |
|
964 |
static int accelEnv = -1; |
|
965 |
if (accelEnv == -1) { |
|
966 |
accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0; |
|
967 |
} |
|
968 |
||
969 |
QRect scrollRect = rect & clipRect(); |
|
970 |
bool overlapped = false; |
|
971 |
bool accelerateScroll = accelEnv && isOpaque |
|
972 |
&& !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); |
|
973 |
||
974 |
#if defined(Q_WS_QWS) |
|
975 |
QWSWindowSurface *surface; |
|
976 |
surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
977 |
||
978 |
if (accelerateScroll && !surface->isBuffered()) { |
|
979 |
const QRegion surfaceClip = surface->clipRegion(); |
|
980 |
const QRegion outsideClip = QRegion(rect) - surfaceClip; |
|
981 |
if (!outsideClip.isEmpty()) { |
|
982 |
const QVector<QRect> clipped = (surfaceClip & rect).rects(); |
|
983 |
if (clipped.size() < 8) { |
|
984 |
for (int i = 0; i < clipped.size(); ++i) |
|
985 |
this->scrollRect(clipped.at(i), dx, dy); |
|
986 |
return; |
|
987 |
} else { |
|
988 |
accelerateScroll = false; |
|
989 |
} |
|
990 |
} |
|
991 |
} |
|
992 |
#endif // Q_WS_QWS |
|
993 |
||
994 |
if (!accelerateScroll) { |
|
995 |
if (overlapped) { |
|
996 |
QRegion region(scrollRect); |
|
997 |
subtractOpaqueSiblings(region); |
|
998 |
invalidateBuffer(region); |
|
999 |
}else { |
|
1000 |
invalidateBuffer(scrollRect); |
|
1001 |
} |
|
1002 |
} else { |
|
1003 |
const QPoint toplevelOffset = q->mapTo(tlw, QPoint()); |
|
1004 |
#ifdef Q_WS_QWS |
|
1005 |
QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
1006 |
const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect; |
|
1007 |
const QRect clipBoundingRect = clip.boundingRect(); |
|
1008 |
scrollRect &= clipBoundingRect; |
|
1009 |
#endif |
|
1010 |
const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; |
|
1011 |
const QRect sourceRect = destRect.translated(-dx, -dy); |
|
1012 |
||
1013 |
QRegion childExpose(scrollRect); |
|
1014 |
if (sourceRect.isValid()) { |
|
1015 |
if (wbs->bltRect(sourceRect, dx, dy, q)) |
|
1016 |
childExpose -= destRect; |
|
1017 |
} |
|
1018 |
||
1019 |
if (inDirtyList) { |
|
1020 |
if (rect == q->rect()) { |
|
1021 |
dirty.translate(dx, dy); |
|
1022 |
} else { |
|
1023 |
QRegion dirtyScrollRegion = dirty.intersected(scrollRect); |
|
1024 |
if (!dirtyScrollRegion.isEmpty()) { |
|
1025 |
dirty -= dirtyScrollRegion; |
|
1026 |
dirtyScrollRegion.translate(dx, dy); |
|
1027 |
dirty += dirtyScrollRegion; |
|
1028 |
} |
|
1029 |
} |
|
1030 |
} |
|
1031 |
||
1032 |
if (!q->updatesEnabled()) |
|
1033 |
return; |
|
1034 |
||
1035 |
if (!childExpose.isEmpty()) { |
|
1036 |
wbs->markDirty(childExpose, q); |
|
1037 |
isScrolled = true; |
|
1038 |
} |
|
1039 |
||
1040 |
// Instead of using native scroll-on-screen, we copy from |
|
1041 |
// backingstore, giving only one screen update for each |
|
1042 |
// scroll, and a solid appearance |
|
1043 |
wbs->markDirtyOnScreen(destRect, q, toplevelOffset); |
|
1044 |
} |
|
1045 |
} |
|
1046 |
||
1047 |
static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) |
|
1048 |
{ |
|
1049 |
if (!tlw || !tlwExtra) |
|
1050 |
return true; |
|
1051 |
||
1052 |
#ifdef Q_WS_X11 |
|
1053 |
// Delay the sync until we get an Expose event from X11 (initial show). |
|
1054 |
// Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred. |
|
1055 |
// However, we must repaint immediately regardless of the state if someone calls repaint(). |
|
1056 |
if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint) |
|
1057 |
return true; |
|
1058 |
#endif |
|
1059 |
||
1060 |
if (!tlw->testAttribute(Qt::WA_Mapped)) |
|
1061 |
return true; |
|
1062 |
||
1063 |
if (!tlw->isVisible() |
|
1064 |
#ifndef Q_WS_X11 |
|
1065 |
// If we're minimized on X11, WA_Mapped will be false and we |
|
1066 |
// will return in the case above. Some window managers on X11 |
|
1067 |
// sends us the PropertyNotify to change the minimized state |
|
1068 |
// *AFTER* we've received the expose event, which is baaad. |
|
1069 |
|| tlw->isMinimized() |
|
1070 |
#endif |
|
1071 |
) |
|
1072 |
return true; |
|
1073 |
||
1074 |
return false; |
|
1075 |
} |
|
1076 |
||
1077 |
/*! |
|
1078 |
Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store. |
|
1079 |
||
1080 |
If there's nothing to repaint, the area is flushed and painting does not occur; |
|
1081 |
otherwise the area is marked as dirty on screen and will be flushed right after |
|
1082 |
we are done with all painting. |
|
1083 |
*/ |
|
1084 |
void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) |
|
1085 |
{ |
|
1086 |
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
1087 |
if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) |
|
1088 |
return; |
|
1089 |
||
1090 |
if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() |
|
1091 |
|| !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { |
|
1092 |
return; |
|
1093 |
} |
|
1094 |
||
1095 |
// Nothing to repaint. |
|
1096 |
if (!isDirty()) { |
|
1097 |
qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset); |
|
1098 |
return; |
|
1099 |
} |
|
1100 |
||
1101 |
if (exposedWidget != tlw) |
|
1102 |
markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); |
|
1103 |
else |
|
1104 |
markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); |
|
1105 |
sync(); |
|
1106 |
} |
|
1107 |
||
1108 |
/*! |
|
1109 |
Synchronizes the backing store, i.e. dirty areas are repainted and flushed. |
|
1110 |
*/ |
|
1111 |
void QWidgetBackingStore::sync() |
|
1112 |
{ |
|
1113 |
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
1114 |
if (discardSyncRequest(tlw, tlwExtra)) { |
|
1115 |
// If the top-level is minimized, it's not visible on the screen so we can delay the |
|
1116 |
// update until it's shown again. In order to do that we must keep the dirty states. |
|
1117 |
// These will be cleared when we receive the first expose after showNormal(). |
|
1118 |
// However, if the widget is not visible (isVisible() returns false), everything will |
|
1119 |
// be invalidated once the widget is shown again, so clear all dirty states. |
|
1120 |
if (!tlw->isVisible()) { |
|
1121 |
dirty = QRegion(); |
|
1122 |
for (int i = 0; i < dirtyWidgets.size(); ++i) |
|
1123 |
resetWidget(dirtyWidgets.at(i)); |
|
1124 |
dirtyWidgets.clear(); |
|
1125 |
} |
|
1126 |
return; |
|
1127 |
} |
|
1128 |
||
1129 |
const bool inTopLevelResize = tlwExtra->inTopLevelResize; |
|
1130 |
const bool updatesDisabled = !tlw->updatesEnabled(); |
|
1131 |
const QRect tlwRect(topLevelRect()); |
|
1132 |
const QRect surfaceGeometry(windowSurface->geometry()); |
|
1133 |
bool repaintAllWidgets = false; |
|
1134 |
||
1135 |
if (inTopLevelResize || surfaceGeometry != tlwRect) { |
|
1136 |
if ((inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { |
|
1137 |
if (hasStaticContents()) { |
|
1138 |
// Repaint existing dirty area and newly visible area. |
|
1139 |
const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); |
|
1140 |
const QRegion staticRegion(staticContents(0, clipRect)); |
|
1141 |
QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); |
|
1142 |
newVisible -= staticRegion; |
|
1143 |
dirty += newVisible; |
|
1144 |
windowSurface->setStaticContents(staticRegion); |
|
1145 |
} else { |
|
1146 |
// Repaint everything. |
|
1147 |
dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); |
|
1148 |
for (int i = 0; i < dirtyWidgets.size(); ++i) |
|
1149 |
resetWidget(dirtyWidgets.at(i)); |
|
1150 |
dirtyWidgets.clear(); |
|
1151 |
repaintAllWidgets = true; |
|
1152 |
} |
|
1153 |
} |
|
1154 |
windowSurface->setGeometry(tlwRect); |
|
1155 |
} |
|
1156 |
||
1157 |
if (updatesDisabled) |
|
1158 |
return; |
|
1159 |
||
1160 |
if (hasDirtyFromPreviousSync) |
|
1161 |
dirty += dirtyFromPreviousSync; |
|
1162 |
||
1163 |
// Contains everything that needs repaint. |
|
1164 |
QRegion toClean(dirty); |
|
1165 |
||
1166 |
// Loop through all update() widgets and remove them from the list before they are |
|
1167 |
// painted (in case someone calls update() in paintEvent). If the widget is opaque |
|
1168 |
// and does not have transparent overlapping siblings, append it to the |
|
1169 |
// opaqueNonOverlappedWidgets list and paint it directly without composition. |
|
1170 |
QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets; |
|
1171 |
for (int i = 0; i < dirtyWidgets.size(); ++i) { |
|
1172 |
QWidget *w = dirtyWidgets.at(i); |
|
1173 |
QWidgetPrivate *wd = w->d_func(); |
|
1174 |
if (wd->data.in_destructor) |
|
1175 |
continue; |
|
1176 |
||
1177 |
// Clip with mask() and clipRect(). |
|
1178 |
wd->dirty &= wd->clipRect(); |
|
1179 |
wd->clipToEffectiveMask(wd->dirty); |
|
1180 |
||
1181 |
// Subtract opaque siblings and children. |
|
1182 |
bool hasDirtySiblingsAbove = false; |
|
1183 |
// We know for sure that the widget isn't overlapped if 'isMoved' is true. |
|
1184 |
if (!wd->isMoved) |
|
1185 |
wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); |
|
1186 |
// Scrolled and moved widgets must draw all children. |
|
1187 |
if (!wd->isScrolled && !wd->isMoved) |
|
1188 |
wd->subtractOpaqueChildren(wd->dirty, w->rect()); |
|
1189 |
||
1190 |
if (wd->dirty.isEmpty()) { |
|
1191 |
resetWidget(w); |
|
1192 |
continue; |
|
1193 |
} |
|
1194 |
||
1195 |
const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) |
|
1196 |
: wd->dirty); |
|
1197 |
toClean += widgetDirty; |
|
1198 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
1199 |
#ifndef QT_NO_GRAPHICSVIEW |
0 | 1200 |
if (tlw->d_func()->extra->proxyWidget) { |
1201 |
resetWidget(w); |
|
1202 |
continue; |
|
1203 |
} |
|
1204 |
#endif |
|
1205 |
||
1206 |
if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { |
|
1207 |
opaqueNonOverlappedWidgets.append(w); |
|
1208 |
} else { |
|
1209 |
resetWidget(w); |
|
1210 |
dirty += widgetDirty; |
|
1211 |
} |
|
1212 |
} |
|
1213 |
dirtyWidgets.clear(); |
|
1214 |
||
1215 |
if (toClean.isEmpty()) { |
|
1216 |
// Nothing to repaint. However, we might have newly exposed areas on the |
|
1217 |
// screen if this function was called from sync(QWidget *, QRegion)), so |
|
1218 |
// we have to make sure those are flushed. |
|
1219 |
flush(); |
|
1220 |
return; |
|
1221 |
} |
|
1222 |
||
1223 |
#ifndef QT_NO_GRAPHICSVIEW |
|
1224 |
if (tlw->d_func()->extra->proxyWidget) { |
|
1225 |
updateStaticContentsSize(); |
|
1226 |
dirty = QRegion(); |
|
1227 |
const QVector<QRect> rects(toClean.rects()); |
|
1228 |
for (int i = 0; i < rects.size(); ++i) |
|
1229 |
tlw->d_func()->extra->proxyWidget->update(rects.at(i)); |
|
1230 |
return; |
|
1231 |
} |
|
1232 |
#endif |
|
1233 |
||
1234 |
#ifndef Q_BACKINGSTORE_SUBSURFACES |
|
1235 |
BeginPaintInfo beginPaintInfo; |
|
1236 |
beginPaint(toClean, tlw, windowSurface, &beginPaintInfo); |
|
1237 |
if (beginPaintInfo.nothingToPaint) { |
|
1238 |
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) |
|
1239 |
resetWidget(opaqueNonOverlappedWidgets[i]); |
|
1240 |
dirty = QRegion(); |
|
1241 |
return; |
|
1242 |
} |
|
1243 |
#endif |
|
1244 |
||
1245 |
// Must do this before sending any paint events because |
|
1246 |
// the size may change in the paint event. |
|
1247 |
updateStaticContentsSize(); |
|
1248 |
const QRegion dirtyCopy(dirty); |
|
1249 |
dirty = QRegion(); |
|
1250 |
||
1251 |
// Paint opaque non overlapped widgets. |
|
1252 |
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { |
|
1253 |
QWidget *w = opaqueNonOverlappedWidgets[i]; |
|
1254 |
QWidgetPrivate *wd = w->d_func(); |
|
1255 |
||
1256 |
int flags = QWidgetPrivate::DrawRecursive; |
|
1257 |
// Scrolled and moved widgets must draw all children. |
|
1258 |
if (!wd->isScrolled && !wd->isMoved) |
|
1259 |
flags |= QWidgetPrivate::DontDrawOpaqueChildren; |
|
1260 |
if (w == tlw) |
|
1261 |
flags |= QWidgetPrivate::DrawAsRoot; |
|
1262 |
||
1263 |
QRegion toBePainted(wd->dirty); |
|
1264 |
resetWidget(w); |
|
1265 |
||
1266 |
#ifdef Q_BACKINGSTORE_SUBSURFACES |
|
1267 |
QWindowSurface *subSurface = w->windowSurface(); |
|
1268 |
BeginPaintInfo beginPaintInfo; |
|
1269 |
beginPaint(toBePainted, w, subSurface, &beginPaintInfo, false); |
|
1270 |
if (beginPaintInfo.nothingToPaint) |
|
1271 |
continue; |
|
1272 |
||
1273 |
if (beginPaintInfo.windowSurfaceRecreated) { |
|
1274 |
// Eep the window surface has changed. The old one may have been |
|
1275 |
// deleted, in which case we will segfault on the call to |
|
1276 |
// painterOffset() below. Use the new window surface instead. |
|
1277 |
subSurface = w->windowSurface(); |
|
1278 |
} |
|
1279 |
||
1280 |
QPoint offset(tlwOffset); |
|
1281 |
if (subSurface == windowSurface) |
|
1282 |
offset += w->mapTo(tlw, QPoint()); |
|
1283 |
else |
|
1284 |
offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); |
|
1285 |
wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this); |
|
1286 |
||
1287 |
endPaint(toBePainted, subSurface, &beginPaintInfo); |
|
1288 |
#else |
|
1289 |
QPoint offset(tlwOffset); |
|
1290 |
if (w != tlw) |
|
1291 |
offset += w->mapTo(tlw, QPoint()); |
|
1292 |
wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this); |
|
1293 |
#endif |
|
1294 |
} |
|
1295 |
||
1296 |
// Paint the rest with composition. |
|
1297 |
#ifndef Q_BACKINGSTORE_SUBSURFACES |
|
1298 |
if (repaintAllWidgets || !dirtyCopy.isEmpty()) { |
|
1299 |
const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; |
|
1300 |
tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); |
|
1301 |
} |
|
1302 |
||
1303 |
endPaint(toClean, windowSurface, &beginPaintInfo); |
|
1304 |
#else |
|
1305 |
if (!repaintAllWidgets && dirtyCopy.isEmpty()) |
|
1306 |
return; // Nothing more to paint. |
|
1307 |
||
1308 |
QList<QWindowSurface *> surfaceList(subSurfaces); |
|
1309 |
surfaceList.prepend(windowSurface); |
|
1310 |
const QRect dirtyBoundingRect(dirtyCopy.boundingRect()); |
|
1311 |
||
1312 |
// Loop through all window surfaces (incl. the top-level surface) and |
|
1313 |
// repaint those intersecting with the bounding rect of the dirty region. |
|
1314 |
for (int i = 0; i < surfaceList.size(); ++i) { |
|
1315 |
QWindowSurface *subSurface = surfaceList.at(i); |
|
1316 |
QWidget *w = subSurface->window(); |
|
1317 |
QWidgetPrivate *wd = w->d_func(); |
|
1318 |
||
1319 |
const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint())); |
|
1320 |
if (!qRectIntersects(dirtyBoundingRect, clipRect)) |
|
1321 |
continue; |
|
1322 |
||
1323 |
toClean = dirtyCopy; |
|
1324 |
BeginPaintInfo beginPaintInfo; |
|
1325 |
beginPaint(toClean, w, subSurface, &beginPaintInfo); |
|
1326 |
if (beginPaintInfo.nothingToPaint) |
|
1327 |
continue; |
|
1328 |
||
1329 |
if (beginPaintInfo.windowSurfaceRecreated) { |
|
1330 |
// Eep the window surface has changed. The old one may have been |
|
1331 |
// deleted, in which case we will segfault on the call to |
|
1332 |
// painterOffset() below. Use the new window surface instead. |
|
1333 |
subSurface = w->windowSurface(); |
|
1334 |
} |
|
1335 |
||
1336 |
int flags = QWidgetPrivate::DrawRecursive; |
|
1337 |
if (w == tlw) |
|
1338 |
flags |= QWidgetPrivate::DrawAsRoot; |
|
1339 |
const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); |
|
1340 |
wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this); |
|
1341 |
||
1342 |
endPaint(toClean, subSurface, &beginPaintInfo); |
|
1343 |
} |
|
1344 |
#endif |
|
1345 |
} |
|
1346 |
||
1347 |
/*! |
|
1348 |
Flushes the contents of the backing store into the top-level widget. |
|
1349 |
If the \a widget is non-zero, the content is flushed to the \a widget. |
|
1350 |
If the \a surface is non-zero, the content of the \a surface is flushed. |
|
1351 |
*/ |
|
1352 |
void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface) |
|
1353 |
{ |
|
1354 |
#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) |
|
1355 |
paintWindowDecoration(); |
|
1356 |
#endif |
|
1357 |
||
1358 |
if (!dirtyOnScreen.isEmpty()) { |
|
1359 |
QWidget *target = widget ? widget : tlw; |
|
1360 |
QWindowSurface *source = surface ? surface : windowSurface; |
|
1361 |
qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset); |
|
1362 |
dirtyOnScreen = QRegion(); |
|
1363 |
} |
|
1364 |
||
1365 |
if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) |
|
1366 |
return; |
|
1367 |
||
1368 |
for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { |
|
1369 |
QWidget *w = dirtyOnScreenWidgets->at(i); |
|
1370 |
QWidgetPrivate *wd = w->d_func(); |
|
1371 |
Q_ASSERT(wd->needsFlush); |
|
1372 |
qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset); |
|
1373 |
*wd->needsFlush = QRegion(); |
|
1374 |
} |
|
1375 |
dirtyOnScreenWidgets->clear(); |
|
1376 |
} |
|
1377 |
||
1378 |
static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra) |
|
1379 |
{ |
|
1380 |
Q_ASSERT(widget); |
|
1381 |
if (QApplication::closingDown()) |
|
1382 |
return true; |
|
1383 |
||
1384 |
if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore) |
|
1385 |
return true; |
|
1386 |
||
1387 |
if (!widget->isVisible() || !widget->updatesEnabled()) |
|
1388 |
return true; |
|
1389 |
||
1390 |
return false; |
|
1391 |
} |
|
1392 |
||
1393 |
/*! |
|
1394 |
Invalidates the buffer when the widget is resized. |
|
1395 |
Static areas are never invalidated unless absolutely needed. |
|
1396 |
*/ |
|
1397 |
void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize) |
|
1398 |
{ |
|
1399 |
Q_Q(QWidget); |
|
1400 |
Q_ASSERT(!q->isWindow()); |
|
1401 |
Q_ASSERT(q->parentWidget()); |
|
1402 |
||
1403 |
const bool staticContents = q->testAttribute(Qt::WA_StaticContents); |
|
1404 |
const bool sizeDecreased = (data.crect.width() < oldSize.width()) |
|
1405 |
|| (data.crect.height() < oldSize.height()); |
|
1406 |
||
1407 |
const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y()); |
|
1408 |
const bool parentAreaExposed = !offset.isNull() || sizeDecreased; |
|
1409 |
const QRect newWidgetRect(q->rect()); |
|
1410 |
const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height()); |
|
1411 |
||
1412 |
if (!staticContents || graphicsEffect) { |
|
1413 |
QRegion staticChildren; |
|
1414 |
QWidgetBackingStore *bs = 0; |
|
1415 |
if (offset.isNull() && (bs = maybeBackingStore())) |
|
1416 |
staticChildren = bs->staticContents(q, oldWidgetRect); |
|
1417 |
const bool hasStaticChildren = !staticChildren.isEmpty(); |
|
1418 |
||
1419 |
if (hasStaticChildren) { |
|
1420 |
QRegion dirty(newWidgetRect); |
|
1421 |
dirty -= staticChildren; |
|
1422 |
invalidateBuffer(dirty); |
|
1423 |
} else { |
|
1424 |
// Entire widget needs repaint. |
|
1425 |
invalidateBuffer(newWidgetRect); |
|
1426 |
} |
|
1427 |
||
1428 |
if (!parentAreaExposed) |
|
1429 |
return; |
|
1430 |
||
1431 |
// Invalidate newly exposed area of the parent. |
|
1432 |
if (!graphicsEffect && extra && extra->hasMask) { |
|
1433 |
QRegion parentExpose(extra->mask.translated(oldPos)); |
|
1434 |
parentExpose &= QRect(oldPos, oldSize); |
|
1435 |
if (hasStaticChildren) |
|
1436 |
parentExpose -= data.crect; // Offset is unchanged, safe to do this. |
|
1437 |
q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1438 |
} else { |
|
1439 |
if (hasStaticChildren && !graphicsEffect) { |
|
1440 |
QRegion parentExpose(QRect(oldPos, oldSize)); |
|
1441 |
parentExpose -= data.crect; // Offset is unchanged, safe to do this. |
|
1442 |
q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1443 |
} else { |
|
1444 |
q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize))); |
|
1445 |
} |
|
1446 |
} |
|
1447 |
return; |
|
1448 |
} |
|
1449 |
||
1450 |
// Move static content to its new position. |
|
1451 |
if (!offset.isNull()) { |
|
1452 |
if (sizeDecreased) { |
|
1453 |
const QSize minSize(qMin(oldSize.width(), data.crect.width()), |
|
1454 |
qMin(oldSize.height(), data.crect.height())); |
|
1455 |
moveRect(QRect(oldPos, minSize), offset.x(), offset.y()); |
|
1456 |
} else { |
|
1457 |
moveRect(QRect(oldPos, oldSize), offset.x(), offset.y()); |
|
1458 |
} |
|
1459 |
} |
|
1460 |
||
1461 |
// Invalidate newly visible area of the widget. |
|
1462 |
if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) { |
|
1463 |
QRegion newVisible(newWidgetRect); |
|
1464 |
newVisible -= oldWidgetRect; |
|
1465 |
invalidateBuffer(newVisible); |
|
1466 |
} |
|
1467 |
||
1468 |
if (!parentAreaExposed) |
|
1469 |
return; |
|
1470 |
||
1471 |
// Invalidate newly exposed area of the parent. |
|
1472 |
const QRect oldRect(oldPos, oldSize); |
|
1473 |
if (extra && extra->hasMask) { |
|
1474 |
QRegion parentExpose(oldRect); |
|
1475 |
parentExpose &= extra->mask.translated(oldPos); |
|
1476 |
parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect); |
|
1477 |
q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1478 |
} else { |
|
1479 |
QRegion parentExpose(oldRect); |
|
1480 |
parentExpose -= data.crect; |
|
1481 |
q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1482 |
} |
|
1483 |
} |
|
1484 |
||
1485 |
/*! |
|
1486 |
Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e. |
|
1487 |
all widgets intersecting with the region will be repainted when the backing store |
|
1488 |
is synced. |
|
1489 |
||
1490 |
### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
1491 |
*/ |
|
1492 |
void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) |
|
1493 |
{ |
|
1494 |
Q_Q(QWidget); |
|
1495 |
||
1496 |
QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); |
|
1497 |
if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty()) |
|
1498 |
return; |
|
1499 |
||
1500 |
QRegion wrgn(rgn); |
|
1501 |
wrgn &= clipRect(); |
|
1502 |
if (!graphicsEffect && extra && extra->hasMask) |
|
1503 |
wrgn &= extra->mask; |
|
1504 |
if (wrgn.isEmpty()) |
|
1505 |
return; |
|
1506 |
||
1507 |
tlwExtra->backingStore->markDirty(wrgn, q, false, true); |
|
1508 |
} |
|
1509 |
||
1510 |
/*! |
|
1511 |
This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but |
|
1512 |
is more efficient as it eliminates QRegion operations/allocations and can |
|
1513 |
use the rect more precisely for additional cut-offs. |
|
1514 |
||
1515 |
### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
1516 |
*/ |
|
1517 |
void QWidgetPrivate::invalidateBuffer(const QRect &rect) |
|
1518 |
{ |
|
1519 |
Q_Q(QWidget); |
|
1520 |
||
1521 |
QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); |
|
1522 |
if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty()) |
|
1523 |
return; |
|
1524 |
||
1525 |
QRect wRect(rect); |
|
1526 |
wRect &= clipRect(); |
|
1527 |
if (wRect.isEmpty()) |
|
1528 |
return; |
|
1529 |
||
1530 |
if (graphicsEffect || !extra || !extra->hasMask) { |
|
1531 |
tlwExtra->backingStore->markDirty(wRect, q, false, true); |
|
1532 |
return; |
|
1533 |
} |
|
1534 |
||
1535 |
QRegion wRgn(extra->mask); |
|
1536 |
wRgn &= wRect; |
|
1537 |
if (wRgn.isEmpty()) |
|
1538 |
return; |
|
1539 |
||
1540 |
tlwExtra->backingStore->markDirty(wRgn, q, false, true); |
|
1541 |
} |
|
1542 |
||
1543 |
void QWidgetPrivate::repaint_sys(const QRegion &rgn) |
|
1544 |
{ |
|
1545 |
if (data.in_destructor) |
|
1546 |
return; |
|
1547 |
||
1548 |
Q_Q(QWidget); |
|
1549 |
if (q->testAttribute(Qt::WA_StaticContents)) { |
|
1550 |
if (!extra) |
|
1551 |
createExtra(); |
|
1552 |
extra->staticContentsSize = data.crect.size(); |
|
1553 |
} |
|
1554 |
||
1555 |
QPaintEngine *engine = q->paintEngine(); |
|
1556 |
// QGLWidget does not support partial updates if: |
|
1557 |
// 1) The context is double buffered |
|
1558 |
// 2) The context is single buffered and auto-fill background is enabled. |
|
1559 |
const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL |
|
1560 |
|| engine->type() == QPaintEngine::OpenGL2)) |
|
1561 |
&& (usesDoubleBufferedGLContext || q->autoFillBackground()); |
|
1562 |
QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn); |
|
1563 |
||
1564 |
#ifdef Q_WS_MAC |
|
1565 |
// No difference between update() and repaint() on the Mac. |
|
1566 |
update_sys(toBePainted); |
|
1567 |
return; |
|
1568 |
#endif |
|
1569 |
||
1570 |
toBePainted &= clipRect(); |
|
1571 |
clipToEffectiveMask(toBePainted); |
|
1572 |
if (toBePainted.isEmpty()) |
|
1573 |
return; // Nothing to repaint. |
|
1574 |
||
1575 |
#ifndef QT_NO_PAINT_DEBUG |
|
1576 |
bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); |
|
1577 |
#endif |
|
1578 |
||
1579 |
drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0); |
|
1580 |
||
1581 |
#ifndef QT_NO_PAINT_DEBUG |
|
1582 |
if (flushed) |
|
1583 |
QWidgetBackingStore::unflushPaint(q, toBePainted); |
|
1584 |
#endif |
|
1585 |
||
1586 |
if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive()) |
|
1587 |
qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); |
|
1588 |
} |
|
1589 |
||
1590 |
||
1591 |
QT_END_NAMESPACE |