source: trunk/src/gui/painting/qbackingstore.cpp@ 448

Last change on this file since 448 was 2, checked in by Dmitry A. Kuminov, 17 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 52.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qbackingstore_p.h"
43
44#include <QtCore/qglobal.h>
45#include <QtCore/qdebug.h>
46#include <QtCore/qvarlengtharray.h>
47#include <QtGui/qevent.h>
48#include <QtGui/qapplication.h>
49#include <QtGui/qpaintengine.h>
50#include <QtGui/qgraphicsproxywidget.h>
51
52#include <private/qwidget_p.h>
53#include <private/qwindowsurface_raster_p.h>
54#include <private/qapplication_p.h>
55#include <private/qpaintengine_raster_p.h>
56
57#include "qgraphicssystem_p.h"
58
59#ifdef Q_WS_QWS
60#include <QtGui/qwsmanager_qws.h>
61#include <private/qwsmanager_p.h>
62#endif
63
64QT_BEGIN_NAMESPACE
65
66extern QRegion qt_dirtyRegion(QWidget *);
67
68/*
69 A version of QRect::intersects() that does not normalize the rects.
70*/
71static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
72{
73 return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
74 && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
75}
76
77/**
78 * Flushes the contents of the \a windowSurface into the screen area of \a widget.
79 * \a tlwOffset is the position of the top level widget relative to the window surface.
80 * \a region is the region to be updated in \a widget coordinates.
81 */
82static inline void qt_flush(QWidget *widget, const QRegion &region, QWindowSurface *windowSurface,
83 QWidget *tlw, const QPoint &tlwOffset)
84{
85 Q_ASSERT(widget);
86 Q_ASSERT(!region.isEmpty());
87 Q_ASSERT(windowSurface);
88 Q_ASSERT(tlw);
89
90#if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS)
91 // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc).
92 static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
93 if (flushUpdate > 0)
94 QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
95#endif
96
97 if (widget != tlw)
98 windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint()));
99 else
100 windowSurface->flush(widget, region, tlwOffset);
101}
102
103#ifndef QT_NO_PAINT_DEBUG
104#ifdef Q_WS_WIN
105static void showYellowThing_win(QWidget *widget, const QRegion &region, int msec)
106{
107 HBRUSH brush;
108 static int i = 0;
109 switch (i) {
110 case 0:
111 brush = CreateSolidBrush(RGB(255, 255, 0));
112 break;
113 case 1:
114 brush = CreateSolidBrush(RGB(255, 200, 55));
115 break;
116 case 2:
117 brush = CreateSolidBrush(RGB(200, 255, 55));
118 break;
119 case 3:
120 brush = CreateSolidBrush(RGB(200, 200, 0));
121 break;
122 }
123 i = (i + 1) & 3;
124
125 HDC hdc = widget->getDC();
126
127 const QVector<QRect> &rects = region.rects();
128 foreach (QRect rect, rects) {
129 RECT winRect;
130 SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom());
131 FillRect(hdc, &winRect, brush);
132 }
133
134 widget->releaseDC(hdc);
135 ::Sleep(msec);
136}
137#endif
138
139void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
140{
141#ifdef Q_WS_QWS
142 Q_UNUSED(widget);
143 Q_UNUSED(unclipped);
144 static QWSYellowSurface surface(true);
145 surface.setDelay(msec);
146 surface.flush(widget, toBePainted, QPoint());
147#else
148 QRegion paintRegion = toBePainted;
149 QRect widgetRect = widget->rect();
150
151 if (!widget->internalWinId()) {
152 QWidget *nativeParent = widget->nativeParentWidget();
153 const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0));
154 paintRegion.translate(offset);
155 widgetRect.translate(offset);
156 widget = nativeParent;
157 }
158
159#ifdef Q_WS_WIN
160 Q_UNUSED(unclipped);
161 showYellowThing_win(widget, paintRegion, msec);
162#else
163 //flags to fool painter
164 bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
165 if (unclipped && !widget->d_func()->paintOnScreen())
166 widget->setAttribute(Qt::WA_PaintUnclipped);
167
168 const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
169 if (setFlag)
170 widget->setAttribute(Qt::WA_WState_InPaintEvent);
171
172 //setup the engine
173 QPaintEngine *pe = widget->paintEngine();
174 if (pe) {
175 pe->setSystemClip(paintRegion);
176 {
177 QPainter p(widget);
178 p.setClipRegion(paintRegion);
179 static int i = 0;
180 switch (i) {
181 case 0:
182 p.fillRect(widgetRect, QColor(255,255,0));
183 break;
184 case 1:
185 p.fillRect(widgetRect, QColor(255,200,55));
186 break;
187 case 2:
188 p.fillRect(widgetRect, QColor(200,255,55));
189 break;
190 case 3:
191 p.fillRect(widgetRect, QColor(200,200,0));
192 break;
193 }
194 i = (i+1) & 3;
195 p.end();
196 }
197 }
198
199 if (setFlag)
200 widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
201
202 //restore
203 widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
204
205 if (pe)
206 pe->setSystemClip(QRegion());
207
208 QApplication::syncX();
209
210#if defined(Q_OS_UNIX)
211 ::usleep(1000 * msec);
212#endif
213#endif // Q_WS_WIN
214#endif // Q_WS_QWS
215}
216
217bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn)
218{
219 if (!widget)
220 return false;
221
222 int delay = 0;
223 if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
224 static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt();
225 if (!flushPaintEvent)
226 return false;
227 delay = flushPaintEvent;
228 } else {
229 static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt();
230 if (!flushPaint)
231 return false;
232 delay = flushPaint;
233 }
234
235 QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true);
236 return true;
237}
238
239void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn)
240{
241 if (widget->d_func()->paintOnScreen() || rgn.isEmpty())
242 return;
243
244 QWidget *tlw = widget->window();
245 QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
246 if (!tlwExtra)
247 return;
248
249 const QPoint offset = widget->mapTo(tlw, QPoint());
250 qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset);
251}
252#endif // QT_NO_PAINT_DEBUG
253
254/*
255 Moves the whole rect by (dx, dy) in widget's coordinate system.
256 Doesn't generate any updates.
257*/
258bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
259{
260 const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft()));
261 return windowSurface->scroll(QRect(pos, rect.size()), dx, dy);
262}
263
264void QWidgetBackingStore::releaseBuffer()
265{
266 if (windowSurface)
267 windowSurface->setGeometry(QRect());
268#ifdef Q_BACKINGSTORE_SUBSURFACES
269 for (int i = 0; i < subSurfaces.size(); ++i)
270 subSurfaces.at(i)->setGeometry(QRect());
271#endif
272}
273
274/*!
275 Prepares the window surface to paint a\ toClean region of the \a widget and
276 updates the BeginPaintInfo struct accordingly.
277
278 The \a toClean region might be clipped by the window surface.
279*/
280void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface,
281 BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates)
282{
283#ifdef Q_WS_QWS
284 QWSWindowSurface *surface = static_cast<QWSWindowSurface *>(windowSurface);
285 QWidget *surfaceWidget = surface->window();
286
287 if (!surface->isValid()) {
288 // this looks strange but it really just releases the surface
289 surface->releaseSurface();
290 // the old window surface is deleted in setWindowSurface, which is
291 // called from QWindowSurface constructor.
292 windowSurface = tlw->d_func()->createDefaultWindowSurface();
293 surface = static_cast<QWSWindowSurface *>(windowSurface);
294 // createDefaultWindowSurface() will set topdata->windowSurface on the
295 // widget to zero. However, if this is a sub-surface, it should point
296 // to the widget's sub windowSurface, so we set that here:
297 if (!surfaceWidget->isWindow())
298 surfaceWidget->d_func()->topData()->windowSurface = windowSurface;
299 surface->setGeometry(topLevelRect());
300 returnInfo->windowSurfaceRecreated = true;
301 }
302
303 const QRegion toCleanUnclipped(toClean);
304
305 if (surfaceWidget->isWindow())
306 tlwOffset = surface->painterOffset();
307#ifdef Q_BACKINGSTORE_SUBSURFACES
308 else if (toCleanIsInTopLevelCoordinates)
309 toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint()));
310 if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface)
311 toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint()));
312#else
313 toClean &= surface->clipRegion();
314#endif
315
316 if (toClean.isEmpty()) {
317 if (surfaceWidget->isWindow()) {
318 dirtyFromPreviousSync += toCleanUnclipped;
319 hasDirtyFromPreviousSync = true;
320 }
321
322 returnInfo->nothingToPaint = true;
323 // Nothing to repaint. However, we might have newly exposed areas on the
324 // screen, so we have to make sure those are flushed.
325 flush();