Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / gui / painting / qwindowsurface_x11.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtGui/QPaintDevice>
43 #include <QtGui/QPainter>
44 #include <QtGui/QPixmap>
45 #include <QtGui/QWidget>
46
47 #include "private/qt_x11_p.h"
48 #include "private/qpixmap_x11_p.h"
49 #include "private/qwidget_p.h"
50 #include "qx11info_x11.h"
51 #include "qwindowsurface_x11_p.h"
52
53 QT_BEGIN_NAMESPACE
54
55 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
56
57 struct QX11WindowSurfacePrivate
58 {
59     QWidget *widget;
60     QPixmap device;
61 #ifndef QT_NO_XRENDER
62     bool translucentBackground;
63 #endif
64 };
65
66 QX11WindowSurface::QX11WindowSurface(QWidget *widget)
67     : QWindowSurface(widget), d_ptr(new QX11WindowSurfacePrivate), gc(0)
68 {
69     d_ptr->widget = widget;
70 #ifndef QT_NO_XRENDER
71     d_ptr->translucentBackground = X11->use_xrender
72         && widget->x11Info().depth() == 32;
73 #endif
74 }
75
76
77 QX11WindowSurface::~QX11WindowSurface()
78 {
79     delete d_ptr;
80     if (gc) {
81         XFreeGC(X11->display, gc);
82         gc = 0;
83     }
84 }
85
86 QPaintDevice *QX11WindowSurface::paintDevice()
87 {
88     return &d_ptr->device;
89 }
90
91 void QX11WindowSurface::beginPaint(const QRegion &rgn)
92 {
93 #ifndef QT_NO_XRENDER
94     Q_ASSERT(!d_ptr->device.isNull());
95
96     if (d_ptr->translucentBackground) {
97         if (d_ptr->device.depth() != 32)
98             static_cast<QX11PixmapData *>(d_ptr->device.data_ptr().data())->convertToARGB32();
99         ::Picture src = X11->getSolidFill(d_ptr->device.x11Info().screen(), Qt::transparent);
100         ::Picture dst = d_ptr->device.x11PictureHandle();
101         const QVector<QRect> rects = rgn.rects();
102         const int w = d_ptr->device.width();
103         const int h = d_ptr->device.height();
104         for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it)
105             XRenderComposite(X11->display, PictOpSrc, src, 0, dst,
106                              0, 0, w, h, it->x(), it->y(),
107                              it->width(), it->height());
108     }
109 #endif
110 }
111
112 void QX11WindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
113 {
114     if (d_ptr->device.isNull())
115         return;
116
117     QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
118     QRegion wrgn(rgn);
119     QRect br = rgn.boundingRect();
120     if (!wOffset.isNull())
121         wrgn.translate(-wOffset);
122     QRect wbr = wrgn.boundingRect();
123
124     int num;
125     XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num);
126     if (num <= 0)
127         return;
128 //         qDebug() << "XSetClipRectangles";
129 //         for  (int i = 0; i < num; ++i)
130 //             qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height;
131     if (num != 1)
132         XSetClipRectangles(X11->display, gc, 0, 0, rects, num, YXBanded);
133     XCopyArea(X11->display, d_ptr->device.handle(), widget->handle(), gc,
134               br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), wbr.x(), wbr.y());
135     if (num != 1)
136         XSetClipMask(X11->display, gc, XNone);
137 }
138
139 void QX11WindowSurface::setGeometry(const QRect &rect)
140 {
141     QWindowSurface::setGeometry(rect);
142
143     const QSize size = rect.size();
144
145     if (d_ptr->device.size() == size || size.width() <= 0 || size.height() <= 0)
146         return;
147 #ifndef QT_NO_XRENDER
148     if (d_ptr->translucentBackground) {
149         QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen());
150
151         QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
152         data->xinfo = d_ptr->widget->x11Info();
153         data->resize(size.width(), size.height());
154         d_ptr->device = QPixmap(data);
155     } else
156 #endif
157     {
158         QPixmap::x11SetDefaultScreen(d_ptr->widget->x11Info().screen());
159
160         QX11PixmapData *oldData = static_cast<QX11PixmapData *>(d_ptr->device.pixmapData());
161
162         if (oldData && !(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) {
163             // Copy the content of the old pixmap into the new one.
164             QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType);
165             newData->resize(size.width(), size.height());
166             Q_ASSERT(oldData->d == newData->d);
167
168             QRegion staticRegion(staticContents());
169             // Make sure we're inside the boundaries of the old pixmap.
170             staticRegion &= QRect(0, 0, oldData->w, oldData->h);
171             const QRect boundingRect(staticRegion.boundingRect());
172             const int dx = boundingRect.x();
173             const int dy = boundingRect.y();
174
175             int num;
176             XRectangle *rects = (XRectangle *)qt_getClipRects(staticRegion, num);
177             GC tmpGc = XCreateGC(X11->display, oldData->hd, 0, 0);
178             XSetClipRectangles(X11->display, tmpGc, 0, 0, rects, num, YXBanded);
179             XCopyArea(X11->display, oldData->hd, newData->hd, tmpGc,
180                       dx, dy, qMin(boundingRect.width(), size.width()),
181                       qMin(boundingRect.height(), size.height()), dx, dy);
182             XFreeGC(X11->display, tmpGc);
183             newData->flags &= ~QX11PixmapData::Uninitialized;
184
185             d_ptr->device = QPixmap(newData);
186         } else {
187             d_ptr->device = QPixmap(size);
188         }
189     }
190
191     if (gc) {
192         XFreeGC(X11->display, gc);
193         gc = 0;
194     }
195     if (!d_ptr->device.isNull()) {
196         gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0);
197         XSetGraphicsExposures(X11->display, gc, False);
198     }
199 }
200
201 bool QX11WindowSurface::scroll(const QRegion &area, int dx, int dy)
202 {
203     QRect rect = area.boundingRect();
204
205     if (d_ptr->device.isNull())
206         return false;
207
208     GC gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0);
209     XCopyArea(X11->display, d_ptr->device.handle(), d_ptr->device.handle(), gc,
210               rect.x(), rect.y(), rect.width(), rect.height(),
211               rect.x()+dx, rect.y()+dy);
212     XFreeGC(X11->display, gc);
213
214     return true;
215 }
216
217 QPixmap QX11WindowSurface::grabWidget(const QWidget *widget,
218                                       const QRect& rect) const
219 {
220     if (!widget || d_ptr->device.isNull())
221         return QPixmap();
222
223     QRect srcRect;
224
225     // make sure the rect is inside the widget & clip to widget's rect
226     if (!rect.isEmpty())
227         srcRect = rect & widget->rect();
228     else
229         srcRect = widget->rect();
230
231     if (srcRect.isEmpty())
232         return QPixmap();
233
234     // If it's a child widget we have to translate the coordinates
235     if (widget != window())
236         srcRect.translate(widget->mapTo(window(), QPoint(0, 0)));
237
238     QPixmap::x11SetDefaultScreen(widget->x11Info().screen());
239     QPixmap px(srcRect.width(), srcRect.height());
240
241     GC tmpGc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0);
242
243     // Copy srcRect from the backing store to the new pixmap
244     XSetGraphicsExposures(X11->display, tmpGc, False);
245     XCopyArea(X11->display, d_ptr->device.handle(), px.handle(), tmpGc,
246               srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), 0, 0);
247
248     XFreeGC(X11->display, tmpGc);
249
250     return px;
251 }
252
253 QWindowSurface::WindowSurfaceFeatures QX11WindowSurface::features() const
254 {
255     WindowSurfaceFeatures features = QWindowSurface::PartialUpdates | QWindowSurface::PreservedContents;
256 #ifndef QT_NO_XRENDER
257     if (!d_ptr->translucentBackground)
258         features |= QWindowSurface::StaticContents;
259 #else
260     features |= QWindowSurface::StaticContents;
261 #endif
262     return features;
263 }
264
265 QT_END_NAMESPACE