|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
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 |
|
355 #ifdef QT_NO_PAINT_DEBUG |
|
356 windowSurface->beginPaint(toClean); |
|
357 #else |
|
358 returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean); |
|
359 // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for |
|
360 // the BackingStore lock, so if we hold that, the server will |
|
361 // never release the Communication lock that we are waiting for in |
|
362 // sendSynchronousCommand |
|
363 if (!returnInfo->wasFlushed) |
|
364 windowSurface->beginPaint(toClean); |
|
365 #endif |
|
366 |
|
367 Q_UNUSED(returnInfo); |
|
368 } |
|
369 |
|
370 void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface, |
|
371 BeginPaintInfo *beginPaintInfo) |
|
372 { |
|
373 #ifndef QT_NO_PAINT_DEBUG |
|
374 if (!beginPaintInfo->wasFlushed) |
|
375 windowSurface->endPaint(cleaned); |
|
376 else |
|
377 QWidgetBackingStore::unflushPaint(tlw, cleaned); |
|
378 #else |
|
379 Q_UNUSED(beginPaintInfo); |
|
380 windowSurface->endPaint(cleaned); |
|
381 #endif |
|
382 |
|
383 #ifdef Q_BACKINGSTORE_SUBSURFACES |
|
384 flush(static_cast<QWSWindowSurface *>(windowSurface)->window(), windowSurface); |
|
385 #else |
|
386 flush(); |
|
387 #endif |
|
388 } |
|
389 |
|
390 /*! |
|
391 Returns the region (in top-level coordinates) that needs repaint and/or flush. |
|
392 |
|
393 If the widget is non-zero, only the dirty region for the widget is returned |
|
394 and the region will be in widget coordinates. |
|
395 */ |
|
396 QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const |
|
397 { |
|
398 const bool widgetDirty = widget && widget != tlw; |
|
399 const QRect tlwRect(topLevelRect()); |
|
400 const QRect surfaceGeometry(windowSurface->geometry()); |
|
401 if (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size()) { |
|
402 if (widgetDirty) { |
|
403 const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size()); |
|
404 const QPoint offset(widget->mapTo(tlw, QPoint())); |
|
405 const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset)); |
|
406 return dirtyWidgetRect.translated(-offset); |
|
407 } |
|
408 return QRect(QPoint(), tlwRect.size()); |
|
409 } |
|
410 |
|
411 // Calculate the region that needs repaint. |
|
412 QRegion r(dirty); |
|
413 for (int i = 0; i < dirtyWidgets.size(); ++i) { |
|
414 QWidget *w = dirtyWidgets.at(i); |
|
415 if (widgetDirty && w != widget && !widget->isAncestorOf(w)) |
|
416 continue; |
|
417 r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint())); |
|
418 } |
|
419 |
|
420 // Append the region that needs flush. |
|
421 r += dirtyOnScreen; |
|
422 |
|
423 if (dirtyOnScreenWidgets) { // Only in use with native child widgets. |
|
424 for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { |
|
425 QWidget *w = dirtyOnScreenWidgets->at(i); |
|
426 if (widgetDirty && w != widget && !widget->isAncestorOf(w)) |
|
427 continue; |
|
428 QWidgetPrivate *wd = w->d_func(); |
|
429 Q_ASSERT(wd->needsFlush); |
|
430 r += wd->needsFlush->translated(w->mapTo(tlw, QPoint())); |
|
431 } |
|
432 } |
|
433 |
|
434 if (widgetDirty) { |
|
435 // Intersect with the widget geometry and translate to its coordinates. |
|
436 const QPoint offset(widget->mapTo(tlw, QPoint())); |
|
437 r &= widget->rect().translated(offset); |
|
438 r.translate(-offset); |
|
439 } |
|
440 return r; |
|
441 } |
|
442 |
|
443 /*! |
|
444 Returns the static content inside the \a parent if non-zero; otherwise the static content |
|
445 for the entire backing store is returned. The content will be clipped to \a withingClipRect |
|
446 if non-empty. |
|
447 */ |
|
448 QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const |
|
449 { |
|
450 if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) { |
|
451 const QRect surfaceGeometry(windowSurface->geometry()); |
|
452 QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); |
|
453 if (!withinClipRect.isEmpty()) |
|
454 surfaceRect &= withinClipRect; |
|
455 return QRegion(surfaceRect); |
|
456 } |
|
457 |
|
458 QRegion region; |
|
459 if (parent && parent->d_func()->children.isEmpty()) |
|
460 return region; |
|
461 |
|
462 const bool clipToRect = !withinClipRect.isEmpty(); |
|
463 const int count = staticWidgets.count(); |
|
464 for (int i = 0; i < count; ++i) { |
|
465 QWidget *w = staticWidgets.at(i); |
|
466 QWidgetPrivate *wd = w->d_func(); |
|
467 if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() |
|
468 || !w->isVisible() || (parent && !parent->isAncestorOf(w))) { |
|
469 continue; |
|
470 } |
|
471 |
|
472 QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height()); |
|
473 const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint()); |
|
474 if (clipToRect) |
|
475 rect &= withinClipRect.translated(-offset); |
|
476 if (rect.isEmpty()) |
|
477 continue; |
|
478 |
|
479 rect &= wd->clipRect(); |
|
480 if (rect.isEmpty()) |
|
481 continue; |
|
482 |
|
483 QRegion visible(rect); |
|
484 wd->clipToEffectiveMask(visible); |
|
485 if (visible.isEmpty()) |
|
486 continue; |
|
487 wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true); |
|
488 |
|
489 visible.translate(offset); |
|
490 region += visible; |
|
491 } |
|
492 |
|
493 return region; |
|
494 } |
|
495 |
|
496 static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately) |
|
497 { |
|
498 if (!widget) |
|
499 return; |
|
500 |
|
501 #if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) |
|
502 if (QApplicationPrivate::inSizeMove && widget->internalWinId() && !updateImmediately |
|
503 && !widget->testAttribute(Qt::WA_DontShowOnScreen)) { |
|
504 // Tell Windows to send us a paint event if we're in WM_SIZE/WM_MOVE; posted events |
|
505 // are blocked until the mouse button is released. See task 146849. |
|
506 const QRegion rgn(qt_dirtyRegion(widget)); |
|
507 InvalidateRgn(widget->internalWinId(), rgn.handle(), false); |
|
508 qt_widget_private(widget)->dirty = QRegion(); |
|
509 return; |
|
510 } |
|
511 #endif |
|
512 |
|
513 if (updateImmediately) { |
|
514 QEvent event(QEvent::UpdateRequest); |
|
515 QApplication::sendEvent(widget, &event); |
|
516 } else { |
|
517 QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); |
|
518 } |
|
519 } |
|
520 |
|
521 /*! |
|
522 Marks the region of the widget as dirty (if not already marked as dirty) and |
|
523 posts an UpdateRequest event to the top-level widget (if not already posted). |
|
524 |
|
525 If updateImmediately is true, the event is sent immediately instead of posted. |
|
526 |
|
527 If invalidateBuffer is true, all widgets intersecting with the region will be dirty. |
|
528 |
|
529 If the widget paints directly on screen, the event is sent to the widget |
|
530 instead of the top-level widget, and invalidateBuffer is completely ignored. |
|
531 |
|
532 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
533 */ |
|
534 void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately, |
|
535 bool invalidateBuffer) |
|
536 { |
|
537 Q_ASSERT(tlw->d_func()->extra); |
|
538 Q_ASSERT(tlw->d_func()->extra->topextra); |
|
539 Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); |
|
540 Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); |
|
541 Q_ASSERT(widget->window() == tlw); |
|
542 Q_ASSERT(!rgn.isEmpty()); |
|
543 |
|
544 widget->d_func()->invalidateGraphicsEffectsRecursively(); |
|
545 |
|
546 if (widget->d_func()->paintOnScreen()) { |
|
547 if (widget->d_func()->dirty.isEmpty()) { |
|
548 widget->d_func()->dirty = rgn; |
|
549 sendUpdateRequest(widget, updateImmediately); |
|
550 return; |
|
551 } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) { |
|
552 if (updateImmediately) |
|
553 sendUpdateRequest(widget, updateImmediately); |
|
554 return; // Already dirty. |
|
555 } |
|
556 |
|
557 const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty(); |
|
558 widget->d_func()->dirty += rgn; |
|
559 if (!eventAlreadyPosted || updateImmediately) |
|
560 sendUpdateRequest(widget, updateImmediately); |
|
561 return; |
|
562 } |
|
563 |
|
564 const QPoint offset = widget->mapTo(tlw, QPoint()); |
|
565 const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect()); |
|
566 if (qt_region_strictContains(dirty, widgetRect.translated(offset))) { |
|
567 if (updateImmediately) |
|
568 sendUpdateRequest(tlw, updateImmediately); |
|
569 return; // Already dirty. |
|
570 } |
|
571 |
|
572 if (invalidateBuffer) { |
|
573 const bool eventAlreadyPosted = !dirty.isEmpty(); |
|
574 if (widget->d_func()->graphicsEffect) |
|
575 dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset); |
|
576 else |
|
577 dirty += rgn.translated(offset); |
|
578 if (!eventAlreadyPosted || updateImmediately) |
|
579 sendUpdateRequest(tlw, updateImmediately); |
|
580 return; |
|
581 } |
|
582 |
|
583 if (dirtyWidgets.isEmpty()) { |
|
584 addDirtyWidget(widget, rgn); |
|
585 sendUpdateRequest(tlw, updateImmediately); |
|
586 return; |
|
587 } |
|
588 |
|
589 if (widget->d_func()->inDirtyList) { |
|
590 if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) { |
|
591 if (widget->d_func()->graphicsEffect) |
|
592 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()); |
|
593 else |
|
594 widget->d_func()->dirty += rgn; |
|
595 } |
|
596 } else { |
|
597 addDirtyWidget(widget, rgn); |
|
598 } |
|
599 |
|
600 if (updateImmediately) |
|
601 sendUpdateRequest(tlw, updateImmediately); |
|
602 } |
|
603 |
|
604 /*! |
|
605 This function is equivalent to calling markDirty(QRegion(rect), ...), but |
|
606 is more efficient as it eliminates QRegion operations/allocations and can |
|
607 use the rect more precisely for additional cut-offs. |
|
608 |
|
609 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
610 */ |
|
611 void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately, |
|
612 bool invalidateBuffer) |
|
613 { |
|
614 Q_ASSERT(tlw->d_func()->extra); |
|
615 Q_ASSERT(tlw->d_func()->extra->topextra); |
|
616 Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize); |
|
617 Q_ASSERT(widget->isVisible() && widget->updatesEnabled()); |
|
618 Q_ASSERT(widget->window() == tlw); |
|
619 Q_ASSERT(!rect.isEmpty()); |
|
620 |
|
621 widget->d_func()->invalidateGraphicsEffectsRecursively(); |
|
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 |
|
773 windowSurface->beginPaint(decorationRegion); |
|
774 |
|
775 QPaintEngine *engine = windowSurface->paintDevice()->paintEngine(); |
|
776 Q_ASSERT(engine); |
|
777 const QRegion oldSystemClip(engine->systemClip()); |
|
778 engine->setSystemClip(decorationRegion.translated(tlwOffset)); |
|
779 |
|
780 QPainter painter(windowSurface->paintDevice()); |
|
781 painter.setFont(QApplication::font()); |
|
782 painter.translate(tlwOffset); |
|
783 |
|
784 const int numDirty = managerPrivate->dirtyRegions.size(); |
|
785 for (int i = 0; i < numDirty; ++i) { |
|
786 const int area = managerPrivate->dirtyRegions.at(i); |
|
787 |
|
788 QRegion clipRegion = decoration.region(tlw, decorationRect, area); |
|
789 if (!clipRegion.isEmpty()) { |
|
790 // Decoration styles changes the clip and assumes the old clip is non-empty, |
|
791 // so we have to set it, but in theory it shouldn't be required. |
|
792 painter.setClipRegion(clipRegion); |
|
793 decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i)); |
|
794 } |
|
795 } |
|
796 markDirtyOnScreen(decorationRegion, tlw, QPoint()); |
|
797 |
|
798 painter.end(); |
|
799 windowSurface->endPaint(decorationRegion); |
|
800 managerPrivate->clearDirtyRegions(); |
|
801 engine->setSystemClip(oldSystemClip); |
|
802 } |
|
803 #endif |
|
804 |
|
805 void QWidgetBackingStore::updateLists(QWidget *cur) |
|
806 { |
|
807 if (!cur) |
|
808 return; |
|
809 |
|
810 QList<QObject*> children = cur->children(); |
|
811 for (int i = 0; i < children.size(); ++i) { |
|
812 QWidget *child = qobject_cast<QWidget*>(children.at(i)); |
|
813 if (!child) |
|
814 continue; |
|
815 |
|
816 updateLists(child); |
|
817 } |
|
818 |
|
819 if (cur->testAttribute(Qt::WA_StaticContents)) |
|
820 addStaticWidget(cur); |
|
821 |
|
822 #ifdef Q_BACKINGSTORE_SUBSURFACES |
|
823 QTLWExtra *extra = cur->d_func()->maybeTopData(); |
|
824 if (extra && extra->windowSurface && cur != tlw) |
|
825 subSurfaces.append(extra->windowSurface); |
|
826 #endif |
|
827 } |
|
828 |
|
829 QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel) |
|
830 : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false) |
|
831 { |
|
832 windowSurface = tlw->windowSurface(); |
|
833 if (!windowSurface) |
|
834 windowSurface = topLevel->d_func()->createDefaultWindowSurface(); |
|
835 |
|
836 // The QWindowSurface constructor will call QWidget::setWindowSurface(), |
|
837 // but automatically created surfaces should not be added to the topdata. |
|
838 #ifdef Q_BACKINGSTORE_SUBSURFACES |
|
839 Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface); |
|
840 #endif |
|
841 topLevel->d_func()->topData()->windowSurface = 0; |
|
842 |
|
843 // Ensure all existing subsurfaces and static widgets are added to their respective lists. |
|
844 updateLists(topLevel); |
|
845 } |
|
846 |
|
847 QWidgetBackingStore::~QWidgetBackingStore() |
|
848 { |
|
849 for (int c = 0; c < dirtyWidgets.size(); ++c) { |
|
850 resetWidget(dirtyWidgets.at(c)); |
|
851 } |
|
852 |
|
853 delete windowSurface; |
|
854 windowSurface = 0; |
|
855 delete dirtyOnScreenWidgets; |
|
856 dirtyOnScreenWidgets = 0; |
|
857 } |
|
858 |
|
859 //parent's coordinates; move whole rect; update parent and widget |
|
860 //assume the screen blt has already been done, so we don't need to refresh that part |
|
861 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy) |
|
862 { |
|
863 Q_Q(QWidget); |
|
864 if (!q->isVisible() || (dx == 0 && dy == 0)) |
|
865 return; |
|
866 |
|
867 QWidget *tlw = q->window(); |
|
868 QTLWExtra* x = tlw->d_func()->topData(); |
|
869 if (x->inTopLevelResize) |
|
870 return; |
|
871 |
|
872 static int accelEnv = -1; |
|
873 if (accelEnv == -1) { |
|
874 accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0; |
|
875 } |
|
876 |
|
877 QWidget *pw = q->parentWidget(); |
|
878 QPoint toplevelOffset = pw->mapTo(tlw, QPoint()); |
|
879 QWidgetPrivate *pd = pw->d_func(); |
|
880 QRect clipR(pd->clipRect()); |
|
881 #ifdef Q_WS_QWS |
|
882 QWidgetBackingStore *wbs = x->backingStore; |
|
883 QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
884 clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect()); |
|
885 #endif |
|
886 const QRect newRect(rect.translated(dx, dy)); |
|
887 QRect destRect = rect.intersected(clipR); |
|
888 if (destRect.isValid()) |
|
889 destRect = destRect.translated(dx, dy).intersected(clipR); |
|
890 const QRect sourceRect(destRect.translated(-dx, -dy)); |
|
891 const QRect parentRect(rect & clipR); |
|
892 |
|
893 bool accelerateMove = accelEnv && isOpaque |
|
894 #ifndef QT_NO_GRAPHICSCVIEW |
|
895 // No accelerate move for proxy widgets. |
|
896 && !tlw->d_func()->extra->proxyWidget |
|
897 #endif |
|
898 && !isOverlapped(sourceRect) && !isOverlapped(destRect); |
|
899 |
|
900 if (!accelerateMove) { |
|
901 QRegion parentR(effectiveRectFor(parentRect)); |
|
902 if (!extra || !extra->hasMask) { |
|
903 parentR -= newRect; |
|
904 } else { |
|
905 // invalidateBuffer() excludes anything outside the mask |
|
906 parentR += newRect & clipR; |
|
907 } |
|
908 pd->invalidateBuffer(parentR); |
|
909 invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft())); |
|
910 } else { |
|
911 |
|
912 QWidgetBackingStore *wbs = x->backingStore; |
|
913 QRegion childExpose(newRect & clipR); |
|
914 |
|
915 if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw)) |
|
916 childExpose -= destRect; |
|
917 |
|
918 if (!pw->updatesEnabled()) |
|
919 return; |
|
920 |
|
921 const bool childUpdatesEnabled = q->updatesEnabled(); |
|
922 if (childUpdatesEnabled && !childExpose.isEmpty()) { |
|
923 childExpose.translate(-data.crect.topLeft()); |
|
924 wbs->markDirty(childExpose, q); |
|
925 isMoved = true; |
|
926 } |
|
927 |
|
928 QRegion parentExpose(parentRect); |
|
929 parentExpose -= newRect; |
|
930 if (extra && extra->hasMask) |
|
931 parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft()); |
|
932 |
|
933 if (!parentExpose.isEmpty()) { |
|
934 wbs->markDirty(parentExpose, pw); |
|
935 pd->isMoved = true; |
|
936 } |
|
937 |
|
938 if (childUpdatesEnabled) { |
|
939 QRegion needsFlush(sourceRect); |
|
940 needsFlush += destRect; |
|
941 wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset); |
|
942 } |
|
943 } |
|
944 } |
|
945 |
|
946 //widget's coordinates; scroll within rect; only update widget |
|
947 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) |
|
948 { |
|
949 Q_Q(QWidget); |
|
950 QWidget *tlw = q->window(); |
|
951 QTLWExtra* x = tlw->d_func()->topData(); |
|
952 if (x->inTopLevelResize) |
|
953 return; |
|
954 |
|
955 QWidgetBackingStore *wbs = x->backingStore; |
|
956 |
|
957 static int accelEnv = -1; |
|
958 if (accelEnv == -1) { |
|
959 accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0; |
|
960 } |
|
961 |
|
962 QRect scrollRect = rect & clipRect(); |
|
963 bool overlapped = false; |
|
964 bool accelerateScroll = accelEnv && isOpaque |
|
965 && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); |
|
966 |
|
967 #if defined(Q_WS_QWS) |
|
968 QWSWindowSurface *surface; |
|
969 surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
970 |
|
971 if (accelerateScroll && !surface->isBuffered()) { |
|
972 const QRegion surfaceClip = surface->clipRegion(); |
|
973 const QRegion outsideClip = QRegion(rect) - surfaceClip; |
|
974 if (!outsideClip.isEmpty()) { |
|
975 const QVector<QRect> clipped = (surfaceClip & rect).rects(); |
|
976 if (clipped.size() < 8) { |
|
977 for (int i = 0; i < clipped.size(); ++i) |
|
978 this->scrollRect(clipped.at(i), dx, dy); |
|
979 return; |
|
980 } else { |
|
981 accelerateScroll = false; |
|
982 } |
|
983 } |
|
984 } |
|
985 #endif // Q_WS_QWS |
|
986 |
|
987 if (!accelerateScroll) { |
|
988 if (overlapped) { |
|
989 QRegion region(scrollRect); |
|
990 subtractOpaqueSiblings(region); |
|
991 invalidateBuffer(region); |
|
992 }else { |
|
993 invalidateBuffer(scrollRect); |
|
994 } |
|
995 } else { |
|
996 const QPoint toplevelOffset = q->mapTo(tlw, QPoint()); |
|
997 #ifdef Q_WS_QWS |
|
998 QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface); |
|
999 const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect; |
|
1000 const QRect clipBoundingRect = clip.boundingRect(); |
|
1001 scrollRect &= clipBoundingRect; |
|
1002 #endif |
|
1003 const QRect destRect = scrollRect.translated(dx, dy) & scrollRect; |
|
1004 const QRect sourceRect = destRect.translated(-dx, -dy); |
|
1005 |
|
1006 QRegion childExpose(scrollRect); |
|
1007 if (sourceRect.isValid()) { |
|
1008 if (wbs->bltRect(sourceRect, dx, dy, q)) |
|
1009 childExpose -= destRect; |
|
1010 } |
|
1011 |
|
1012 if (inDirtyList) { |
|
1013 if (rect == q->rect()) { |
|
1014 dirty.translate(dx, dy); |
|
1015 } else { |
|
1016 QRegion dirtyScrollRegion = dirty.intersected(scrollRect); |
|
1017 if (!dirtyScrollRegion.isEmpty()) { |
|
1018 dirty -= dirtyScrollRegion; |
|
1019 dirtyScrollRegion.translate(dx, dy); |
|
1020 dirty += dirtyScrollRegion; |
|
1021 } |
|
1022 } |
|
1023 } |
|
1024 |
|
1025 if (!q->updatesEnabled()) |
|
1026 return; |
|
1027 |
|
1028 if (!childExpose.isEmpty()) { |
|
1029 wbs->markDirty(childExpose, q); |
|
1030 isScrolled = true; |
|
1031 } |
|
1032 |
|
1033 // Instead of using native scroll-on-screen, we copy from |
|
1034 // backingstore, giving only one screen update for each |
|
1035 // scroll, and a solid appearance |
|
1036 wbs->markDirtyOnScreen(destRect, q, toplevelOffset); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra) |
|
1041 { |
|
1042 if (!tlw || !tlwExtra) |
|
1043 return true; |
|
1044 |
|
1045 #ifdef Q_WS_X11 |
|
1046 // Delay the sync until we get an Expose event from X11 (initial show). |
|
1047 // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred. |
|
1048 // However, we must repaint immediately regardless of the state if someone calls repaint(). |
|
1049 if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint) |
|
1050 return true; |
|
1051 #endif |
|
1052 |
|
1053 if (!tlw->testAttribute(Qt::WA_Mapped)) |
|
1054 return true; |
|
1055 |
|
1056 if (!tlw->isVisible() |
|
1057 #ifndef Q_WS_X11 |
|
1058 // If we're minimized on X11, WA_Mapped will be false and we |
|
1059 // will return in the case above. Some window managers on X11 |
|
1060 // sends us the PropertyNotify to change the minimized state |
|
1061 // *AFTER* we've received the expose event, which is baaad. |
|
1062 || tlw->isMinimized() |
|
1063 #endif |
|
1064 ) |
|
1065 return true; |
|
1066 |
|
1067 return false; |
|
1068 } |
|
1069 |
|
1070 /*! |
|
1071 Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store. |
|
1072 |
|
1073 If there's nothing to repaint, the area is flushed and painting does not occur; |
|
1074 otherwise the area is marked as dirty on screen and will be flushed right after |
|
1075 we are done with all painting. |
|
1076 */ |
|
1077 void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion) |
|
1078 { |
|
1079 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
1080 if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize) |
|
1081 return; |
|
1082 |
|
1083 if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible() |
|
1084 || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) { |
|
1085 return; |
|
1086 } |
|
1087 |
|
1088 // Nothing to repaint. |
|
1089 if (!isDirty()) { |
|
1090 qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset); |
|
1091 return; |
|
1092 } |
|
1093 |
|
1094 if (exposedWidget != tlw) |
|
1095 markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint())); |
|
1096 else |
|
1097 markDirtyOnScreen(exposedRegion, exposedWidget, QPoint()); |
|
1098 sync(); |
|
1099 } |
|
1100 |
|
1101 /*! |
|
1102 Synchronizes the backing store, i.e. dirty areas are repainted and flushed. |
|
1103 */ |
|
1104 void QWidgetBackingStore::sync() |
|
1105 { |
|
1106 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData(); |
|
1107 if (discardSyncRequest(tlw, tlwExtra)) { |
|
1108 // If the top-level is minimized, it's not visible on the screen so we can delay the |
|
1109 // update until it's shown again. In order to do that we must keep the dirty states. |
|
1110 // These will be cleared when we receive the first expose after showNormal(). |
|
1111 // However, if the widget is not visible (isVisible() returns false), everything will |
|
1112 // be invalidated once the widget is shown again, so clear all dirty states. |
|
1113 if (!tlw->isVisible()) { |
|
1114 dirty = QRegion(); |
|
1115 for (int i = 0; i < dirtyWidgets.size(); ++i) |
|
1116 resetWidget(dirtyWidgets.at(i)); |
|
1117 dirtyWidgets.clear(); |
|
1118 } |
|
1119 return; |
|
1120 } |
|
1121 |
|
1122 const bool inTopLevelResize = tlwExtra->inTopLevelResize; |
|
1123 const bool updatesDisabled = !tlw->updatesEnabled(); |
|
1124 const QRect tlwRect(topLevelRect()); |
|
1125 const QRect surfaceGeometry(windowSurface->geometry()); |
|
1126 bool repaintAllWidgets = false; |
|
1127 |
|
1128 if (inTopLevelResize || surfaceGeometry != tlwRect) { |
|
1129 if ((inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) { |
|
1130 if (hasStaticContents()) { |
|
1131 // Repaint existing dirty area and newly visible area. |
|
1132 const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height()); |
|
1133 const QRegion staticRegion(staticContents(0, clipRect)); |
|
1134 QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height()); |
|
1135 newVisible -= staticRegion; |
|
1136 dirty += newVisible; |
|
1137 windowSurface->setStaticContents(staticRegion); |
|
1138 } else { |
|
1139 // Repaint everything. |
|
1140 dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height()); |
|
1141 for (int i = 0; i < dirtyWidgets.size(); ++i) |
|
1142 resetWidget(dirtyWidgets.at(i)); |
|
1143 dirtyWidgets.clear(); |
|
1144 repaintAllWidgets = true; |
|
1145 } |
|
1146 } |
|
1147 windowSurface->setGeometry(tlwRect); |
|
1148 } |
|
1149 |
|
1150 if (updatesDisabled) |
|
1151 return; |
|
1152 |
|
1153 if (hasDirtyFromPreviousSync) |
|
1154 dirty += dirtyFromPreviousSync; |
|
1155 |
|
1156 // Contains everything that needs repaint. |
|
1157 QRegion toClean(dirty); |
|
1158 |
|
1159 // Loop through all update() widgets and remove them from the list before they are |
|
1160 // painted (in case someone calls update() in paintEvent). If the widget is opaque |
|
1161 // and does not have transparent overlapping siblings, append it to the |
|
1162 // opaqueNonOverlappedWidgets list and paint it directly without composition. |
|
1163 QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets; |
|
1164 for (int i = 0; i < dirtyWidgets.size(); ++i) { |
|
1165 QWidget *w = dirtyWidgets.at(i); |
|
1166 QWidgetPrivate *wd = w->d_func(); |
|
1167 if (wd->data.in_destructor) |
|
1168 continue; |
|
1169 |
|
1170 // Clip with mask() and clipRect(). |
|
1171 wd->dirty &= wd->clipRect(); |
|
1172 wd->clipToEffectiveMask(wd->dirty); |
|
1173 |
|
1174 // Subtract opaque siblings and children. |
|
1175 bool hasDirtySiblingsAbove = false; |
|
1176 // We know for sure that the widget isn't overlapped if 'isMoved' is true. |
|
1177 if (!wd->isMoved) |
|
1178 wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); |
|
1179 // Scrolled and moved widgets must draw all children. |
|
1180 if (!wd->isScrolled && !wd->isMoved) |
|
1181 wd->subtractOpaqueChildren(wd->dirty, w->rect()); |
|
1182 |
|
1183 if (wd->dirty.isEmpty()) { |
|
1184 resetWidget(w); |
|
1185 continue; |
|
1186 } |
|
1187 |
|
1188 const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint())) |
|
1189 : wd->dirty); |
|
1190 toClean += widgetDirty; |
|
1191 |
|
1192 #ifndef QT_NO_GRAPHICSCVIEW |
|
1193 if (tlw->d_func()->extra->proxyWidget) { |
|
1194 resetWidget(w); |
|
1195 continue; |
|
1196 } |
|
1197 #endif |
|
1198 |
|
1199 if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) { |
|
1200 opaqueNonOverlappedWidgets.append(w); |
|
1201 } else { |
|
1202 resetWidget(w); |
|
1203 dirty += widgetDirty; |
|
1204 } |
|
1205 } |
|
1206 dirtyWidgets.clear(); |
|
1207 |
|
1208 if (toClean.isEmpty()) { |
|
1209 // Nothing to repaint. However, we might have newly exposed areas on the |
|
1210 // screen if this function was called from sync(QWidget *, QRegion)), so |
|
1211 // we have to make sure those are flushed. |
|
1212 flush(); |
|
1213 return; |
|
1214 } |
|
1215 |
|
1216 #ifndef QT_NO_GRAPHICSVIEW |
|
1217 if (tlw->d_func()->extra->proxyWidget) { |
|
1218 updateStaticContentsSize(); |
|
1219 dirty = QRegion(); |
|
1220 const QVector<QRect> rects(toClean.rects()); |
|
1221 for (int i = 0; i < rects.size(); ++i) |
|
1222 tlw->d_func()->extra->proxyWidget->update(rects.at(i)); |
|
1223 return; |
|
1224 } |
|
1225 #endif |
|
1226 |
|
1227 #ifndef Q_BACKINGSTORE_SUBSURFACES |
|
1228 BeginPaintInfo beginPaintInfo; |
|
1229 beginPaint(toClean, tlw, windowSurface, &beginPaintInfo); |
|
1230 if (beginPaintInfo.nothingToPaint) { |
|
1231 for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) |
|
1232 resetWidget(opaqueNonOverlappedWidgets[i]); |
|
1233 dirty = QRegion(); |
|
1234 return; |
|
1235 } |
|
1236 #endif |
|
1237 |
|
1238 // Must do this before sending any paint events because |
|
1239 // the size may change in the paint event. |
|
1240 updateStaticContentsSize(); |
|
1241 const QRegion dirtyCopy(dirty); |
|
1242 dirty = QRegion(); |
|
1243 |
|
1244 // Paint opaque non overlapped widgets. |
|
1245 for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) { |
|
1246 QWidget *w = opaqueNonOverlappedWidgets[i]; |
|
1247 QWidgetPrivate *wd = w->d_func(); |
|
1248 |
|
1249 int flags = QWidgetPrivate::DrawRecursive; |
|
1250 // Scrolled and moved widgets must draw all children. |
|
1251 if (!wd->isScrolled && !wd->isMoved) |
|
1252 flags |= QWidgetPrivate::DontDrawOpaqueChildren; |
|
1253 if (w == tlw) |
|
1254 flags |= QWidgetPrivate::DrawAsRoot; |
|
1255 |
|
1256 QRegion toBePainted(wd->dirty); |
|
1257 resetWidget(w); |
|
1258 |
|
1259 #ifdef Q_BACKINGSTORE_SUBSURFACES |
|
1260 QWindowSurface *subSurface = w->windowSurface(); |
|
1261 BeginPaintInfo beginPaintInfo; |
|
1262 beginPaint(toBePainted, w, subSurface, &beginPaintInfo, false); |
|
1263 if (beginPaintInfo.nothingToPaint) |
|
1264 continue; |
|
1265 |
|
1266 if (beginPaintInfo.windowSurfaceRecreated) { |
|
1267 // Eep the window surface has changed. The old one may have been |
|
1268 // deleted, in which case we will segfault on the call to |
|
1269 // painterOffset() below. Use the new window surface instead. |
|
1270 subSurface = w->windowSurface(); |
|
1271 } |
|
1272 |
|
1273 QPoint offset(tlwOffset); |
|
1274 if (subSurface == windowSurface) |
|
1275 offset += w->mapTo(tlw, QPoint()); |
|
1276 else |
|
1277 offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); |
|
1278 wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this); |
|
1279 |
|
1280 endPaint(toBePainted, subSurface, &beginPaintInfo); |
|
1281 #else |
|
1282 QPoint offset(tlwOffset); |
|
1283 if (w != tlw) |
|
1284 offset += w->mapTo(tlw, QPoint()); |
|
1285 wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this); |
|
1286 #endif |
|
1287 } |
|
1288 |
|
1289 // Paint the rest with composition. |
|
1290 #ifndef Q_BACKINGSTORE_SUBSURFACES |
|
1291 if (repaintAllWidgets || !dirtyCopy.isEmpty()) { |
|
1292 const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive; |
|
1293 tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this); |
|
1294 } |
|
1295 |
|
1296 endPaint(toClean, windowSurface, &beginPaintInfo); |
|
1297 #else |
|
1298 if (!repaintAllWidgets && dirtyCopy.isEmpty()) |
|
1299 return; // Nothing more to paint. |
|
1300 |
|
1301 QList<QWindowSurface *> surfaceList(subSurfaces); |
|
1302 surfaceList.prepend(windowSurface); |
|
1303 const QRect dirtyBoundingRect(dirtyCopy.boundingRect()); |
|
1304 |
|
1305 // Loop through all window surfaces (incl. the top-level surface) and |
|
1306 // repaint those intersecting with the bounding rect of the dirty region. |
|
1307 for (int i = 0; i < surfaceList.size(); ++i) { |
|
1308 QWindowSurface *subSurface = surfaceList.at(i); |
|
1309 QWidget *w = subSurface->window(); |
|
1310 QWidgetPrivate *wd = w->d_func(); |
|
1311 |
|
1312 const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint())); |
|
1313 if (!qRectIntersects(dirtyBoundingRect, clipRect)) |
|
1314 continue; |
|
1315 |
|
1316 toClean = dirtyCopy; |
|
1317 BeginPaintInfo beginPaintInfo; |
|
1318 beginPaint(toClean, w, subSurface, &beginPaintInfo); |
|
1319 if (beginPaintInfo.nothingToPaint) |
|
1320 continue; |
|
1321 |
|
1322 if (beginPaintInfo.windowSurfaceRecreated) { |
|
1323 // Eep the window surface has changed. The old one may have been |
|
1324 // deleted, in which case we will segfault on the call to |
|
1325 // painterOffset() below. Use the new window surface instead. |
|
1326 subSurface = w->windowSurface(); |
|
1327 } |
|
1328 |
|
1329 int flags = QWidgetPrivate::DrawRecursive; |
|
1330 if (w == tlw) |
|
1331 flags |= QWidgetPrivate::DrawAsRoot; |
|
1332 const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset(); |
|
1333 wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this); |
|
1334 |
|
1335 endPaint(toClean, subSurface, &beginPaintInfo); |
|
1336 } |
|
1337 #endif |
|
1338 } |
|
1339 |
|
1340 /*! |
|
1341 Flushes the contents of the backing store into the top-level widget. |
|
1342 If the \a widget is non-zero, the content is flushed to the \a widget. |
|
1343 If the \a surface is non-zero, the content of the \a surface is flushed. |
|
1344 */ |
|
1345 void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface) |
|
1346 { |
|
1347 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) |
|
1348 paintWindowDecoration(); |
|
1349 #endif |
|
1350 |
|
1351 if (!dirtyOnScreen.isEmpty()) { |
|
1352 QWidget *target = widget ? widget : tlw; |
|
1353 QWindowSurface *source = surface ? surface : windowSurface; |
|
1354 qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset); |
|
1355 dirtyOnScreen = QRegion(); |
|
1356 } |
|
1357 |
|
1358 if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) |
|
1359 return; |
|
1360 |
|
1361 for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) { |
|
1362 QWidget *w = dirtyOnScreenWidgets->at(i); |
|
1363 QWidgetPrivate *wd = w->d_func(); |
|
1364 Q_ASSERT(wd->needsFlush); |
|
1365 qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset); |
|
1366 *wd->needsFlush = QRegion(); |
|
1367 } |
|
1368 dirtyOnScreenWidgets->clear(); |
|
1369 } |
|
1370 |
|
1371 static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra) |
|
1372 { |
|
1373 Q_ASSERT(widget); |
|
1374 if (QApplication::closingDown()) |
|
1375 return true; |
|
1376 |
|
1377 if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore) |
|
1378 return true; |
|
1379 |
|
1380 if (!widget->isVisible() || !widget->updatesEnabled()) |
|
1381 return true; |
|
1382 |
|
1383 return false; |
|
1384 } |
|
1385 |
|
1386 /*! |
|
1387 Invalidates the buffer when the widget is resized. |
|
1388 Static areas are never invalidated unless absolutely needed. |
|
1389 */ |
|
1390 void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize) |
|
1391 { |
|
1392 Q_Q(QWidget); |
|
1393 Q_ASSERT(!q->isWindow()); |
|
1394 Q_ASSERT(q->parentWidget()); |
|
1395 |
|
1396 const bool staticContents = q->testAttribute(Qt::WA_StaticContents); |
|
1397 const bool sizeDecreased = (data.crect.width() < oldSize.width()) |
|
1398 || (data.crect.height() < oldSize.height()); |
|
1399 |
|
1400 const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y()); |
|
1401 const bool parentAreaExposed = !offset.isNull() || sizeDecreased; |
|
1402 const QRect newWidgetRect(q->rect()); |
|
1403 const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height()); |
|
1404 |
|
1405 if (!staticContents || graphicsEffect) { |
|
1406 QRegion staticChildren; |
|
1407 QWidgetBackingStore *bs = 0; |
|
1408 if (offset.isNull() && (bs = maybeBackingStore())) |
|
1409 staticChildren = bs->staticContents(q, oldWidgetRect); |
|
1410 const bool hasStaticChildren = !staticChildren.isEmpty(); |
|
1411 |
|
1412 if (hasStaticChildren) { |
|
1413 QRegion dirty(newWidgetRect); |
|
1414 dirty -= staticChildren; |
|
1415 invalidateBuffer(dirty); |
|
1416 } else { |
|
1417 // Entire widget needs repaint. |
|
1418 invalidateBuffer(newWidgetRect); |
|
1419 } |
|
1420 |
|
1421 if (!parentAreaExposed) |
|
1422 return; |
|
1423 |
|
1424 // Invalidate newly exposed area of the parent. |
|
1425 if (!graphicsEffect && extra && extra->hasMask) { |
|
1426 QRegion parentExpose(extra->mask.translated(oldPos)); |
|
1427 parentExpose &= QRect(oldPos, oldSize); |
|
1428 if (hasStaticChildren) |
|
1429 parentExpose -= data.crect; // Offset is unchanged, safe to do this. |
|
1430 q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1431 } else { |
|
1432 if (hasStaticChildren && !graphicsEffect) { |
|
1433 QRegion parentExpose(QRect(oldPos, oldSize)); |
|
1434 parentExpose -= data.crect; // Offset is unchanged, safe to do this. |
|
1435 q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1436 } else { |
|
1437 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize))); |
|
1438 } |
|
1439 } |
|
1440 return; |
|
1441 } |
|
1442 |
|
1443 // Move static content to its new position. |
|
1444 if (!offset.isNull()) { |
|
1445 if (sizeDecreased) { |
|
1446 const QSize minSize(qMin(oldSize.width(), data.crect.width()), |
|
1447 qMin(oldSize.height(), data.crect.height())); |
|
1448 moveRect(QRect(oldPos, minSize), offset.x(), offset.y()); |
|
1449 } else { |
|
1450 moveRect(QRect(oldPos, oldSize), offset.x(), offset.y()); |
|
1451 } |
|
1452 } |
|
1453 |
|
1454 // Invalidate newly visible area of the widget. |
|
1455 if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) { |
|
1456 QRegion newVisible(newWidgetRect); |
|
1457 newVisible -= oldWidgetRect; |
|
1458 invalidateBuffer(newVisible); |
|
1459 } |
|
1460 |
|
1461 if (!parentAreaExposed) |
|
1462 return; |
|
1463 |
|
1464 // Invalidate newly exposed area of the parent. |
|
1465 const QRect oldRect(oldPos, oldSize); |
|
1466 if (extra && extra->hasMask) { |
|
1467 QRegion parentExpose(oldRect); |
|
1468 parentExpose &= extra->mask.translated(oldPos); |
|
1469 parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect); |
|
1470 q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1471 } else { |
|
1472 QRegion parentExpose(oldRect); |
|
1473 parentExpose -= data.crect; |
|
1474 q->parentWidget()->d_func()->invalidateBuffer(parentExpose); |
|
1475 } |
|
1476 } |
|
1477 |
|
1478 /*! |
|
1479 Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e. |
|
1480 all widgets intersecting with the region will be repainted when the backing store |
|
1481 is synced. |
|
1482 |
|
1483 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
1484 */ |
|
1485 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn) |
|
1486 { |
|
1487 Q_Q(QWidget); |
|
1488 |
|
1489 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); |
|
1490 if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty()) |
|
1491 return; |
|
1492 |
|
1493 QRegion wrgn(rgn); |
|
1494 wrgn &= clipRect(); |
|
1495 if (!graphicsEffect && extra && extra->hasMask) |
|
1496 wrgn &= extra->mask; |
|
1497 if (wrgn.isEmpty()) |
|
1498 return; |
|
1499 |
|
1500 tlwExtra->backingStore->markDirty(wrgn, q, false, true); |
|
1501 } |
|
1502 |
|
1503 /*! |
|
1504 This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but |
|
1505 is more efficient as it eliminates QRegion operations/allocations and can |
|
1506 use the rect more precisely for additional cut-offs. |
|
1507 |
|
1508 ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). |
|
1509 */ |
|
1510 void QWidgetPrivate::invalidateBuffer(const QRect &rect) |
|
1511 { |
|
1512 Q_Q(QWidget); |
|
1513 |
|
1514 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); |
|
1515 if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty()) |
|
1516 return; |
|
1517 |
|
1518 QRect wRect(rect); |
|
1519 wRect &= clipRect(); |
|
1520 if (wRect.isEmpty()) |
|
1521 return; |
|
1522 |
|
1523 if (graphicsEffect || !extra || !extra->hasMask) { |
|
1524 tlwExtra->backingStore->markDirty(wRect, q, false, true); |
|
1525 return; |
|
1526 } |
|
1527 |
|
1528 QRegion wRgn(extra->mask); |
|
1529 wRgn &= wRect; |
|
1530 if (wRgn.isEmpty()) |
|
1531 return; |
|
1532 |
|
1533 tlwExtra->backingStore->markDirty(wRgn, q, false, true); |
|
1534 } |
|
1535 |
|
1536 void QWidgetPrivate::repaint_sys(const QRegion &rgn) |
|
1537 { |
|
1538 if (data.in_destructor) |
|
1539 return; |
|
1540 |
|
1541 Q_Q(QWidget); |
|
1542 if (q->testAttribute(Qt::WA_StaticContents)) { |
|
1543 if (!extra) |
|
1544 createExtra(); |
|
1545 extra->staticContentsSize = data.crect.size(); |
|
1546 } |
|
1547 |
|
1548 QPaintEngine *engine = q->paintEngine(); |
|
1549 // QGLWidget does not support partial updates if: |
|
1550 // 1) The context is double buffered |
|
1551 // 2) The context is single buffered and auto-fill background is enabled. |
|
1552 const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL |
|
1553 || engine->type() == QPaintEngine::OpenGL2)) |
|
1554 && (usesDoubleBufferedGLContext || q->autoFillBackground()); |
|
1555 QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn); |
|
1556 |
|
1557 #ifdef Q_WS_MAC |
|
1558 // No difference between update() and repaint() on the Mac. |
|
1559 update_sys(toBePainted); |
|
1560 return; |
|
1561 #endif |
|
1562 |
|
1563 toBePainted &= clipRect(); |
|
1564 clipToEffectiveMask(toBePainted); |
|
1565 if (toBePainted.isEmpty()) |
|
1566 return; // Nothing to repaint. |
|
1567 |
|
1568 #ifndef QT_NO_PAINT_DEBUG |
|
1569 bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted); |
|
1570 #endif |
|
1571 |
|
1572 drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0); |
|
1573 |
|
1574 #ifndef QT_NO_PAINT_DEBUG |
|
1575 if (flushed) |
|
1576 QWidgetBackingStore::unflushPaint(q, toBePainted); |
|
1577 #endif |
|
1578 |
|
1579 if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive()) |
|
1580 qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent"); |
|
1581 } |
|
1582 |
|
1583 |
|
1584 QT_END_NAMESPACE |