Revert "Suppress QWindowSystemInterface inclusion warnings."
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandshmbackingstore.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include "qwaylandshmbackingstore.h"
42
43 #include <QtCore/qdebug.h>
44
45 #include "qwaylanddisplay.h"
46 #include "qwaylandshmwindow.h"
47 #include "qwaylandscreen.h"
48 #include "qwaylanddecoration.h"
49
50 #include <QtGui/QPainter>
51
52 #include <wayland-client.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <errno.h>
56 #include <sys/mman.h>
57
58 QT_BEGIN_NAMESPACE
59
60 QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
61                      const QSize &size, QImage::Format format)
62     : mMarginsImage(0)
63 {
64     int stride = size.width() * 4;
65     int alloc = stride * size.height();
66     char filename[] = "/tmp/wayland-shm-XXXXXX";
67     int fd = mkstemp(filename);
68     if (fd < 0) {
69         qWarning("mkstemp %s failed: %s", filename, strerror(errno));
70         return;
71     }
72     int flags = fcntl(fd, F_GETFD);
73     if (flags != -1)
74         fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
75
76     if (ftruncate(fd, alloc) < 0) {
77         qWarning("ftruncate failed: %s", strerror(errno));
78         close(fd);
79         return;
80     }
81     uchar *data = (uchar *)
82             mmap(NULL, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
83     unlink(filename);
84
85     if (data == (uchar *) MAP_FAILED) {
86         qWarning("mmap /dev/zero failed: %s", strerror(errno));
87         close(fd);
88         return;
89     }
90
91     mImage = QImage(data, size.width(), size.height(), stride, format);
92     mShmPool = wl_shm_create_pool(display->shm(), fd, alloc);
93     mBuffer = wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(),
94                                        stride, WL_SHM_FORMAT_ARGB8888);
95     close(fd);
96 }
97
98 QWaylandShmBuffer::~QWaylandShmBuffer(void)
99 {
100     munmap((void *) mImage.constBits(), mImage.byteCount());
101     wl_buffer_destroy(mBuffer);
102     wl_shm_pool_destroy(mShmPool);
103 }
104
105 QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &margins)
106 {
107     if (!margins.isNull() && margins != mMargins) {
108         if (mMarginsImage) {
109             delete mMarginsImage;
110         }
111         uchar *bits = const_cast<uchar *>(mImage.constBits());
112         uchar *b_s_data = bits + margins.top() * mImage.bytesPerLine() + margins.left() * 4;
113         int b_s_width = mImage.size().width() - margins.left() - margins.right();
114         int b_s_height = mImage.size().height() - margins.top() - margins.bottom();
115         mMarginsImage = new QImage(b_s_data, b_s_width,b_s_height,mImage.bytesPerLine(),mImage.format());
116     }
117     if (margins.isNull()) {
118         delete mMarginsImage;
119         mMarginsImage = 0;
120     }
121
122     mMargins = margins;
123     if (!mMarginsImage)
124         return &mImage;
125
126     return mMarginsImage;
127
128 }
129
130 QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window)
131     : QPlatformBackingStore(window)
132     , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display())
133     , mFrontBuffer(0)
134     , mBackBuffer(0)
135     , mFrontBufferIsDirty(false)
136     , mPainting(false)
137     , mWindowDecoration(0)
138     , mFrameCallback(0)
139 {
140 }
141
142 QWaylandShmBackingStore::~QWaylandShmBackingStore()
143 {
144     if (mFrameCallback)
145         wl_callback_destroy(mFrameCallback);
146
147 //    if (mFrontBuffer == waylandWindow()->attached())
148 //        waylandWindow()->attach(0);
149
150     if (mFrontBuffer != mBackBuffer)
151         delete mFrontBuffer;
152
153     delete mBackBuffer;
154 }
155
156 QPaintDevice *QWaylandShmBackingStore::paintDevice()
157 {
158     if (!mWindowDecoration)
159         return mBackBuffer->image();
160     return mBackBuffer->imageInsideMargins(mWindowDecoration->margins());
161 }
162
163 void QWaylandShmBackingStore::beginPaint(const QRegion &)
164 {
165     mPainting = true;
166     ensureSize();
167
168     if (waylandWindow()->attached() && mBackBuffer == waylandWindow()->attached()) {
169         QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle());
170         Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm);
171         waylandWindow->waitForFrameSync();
172     }
173
174 }
175
176 void QWaylandShmBackingStore::endPaint()
177 {
178     mPainting = false;
179 }
180
181 void QWaylandShmBackingStore::ensureSize()
182 {
183     bool decoration = false;
184     switch (window()->windowType()) {
185         case Qt::Window:
186     case Qt::Widget:
187     case Qt::Dialog:
188     case Qt::Tool:
189     case Qt::Drawer:
190         decoration = true;
191         break;
192     default:
193         break;
194     }
195     if (window()->windowFlags() & Qt::FramelessWindowHint) {
196         decoration = false;
197     }
198
199     if (decoration) {
200         if (!mWindowDecoration) {
201             mWindowDecoration = new QWaylandDecoration(window(), this);
202         }
203     } else {
204         delete mWindowDecoration;
205         mWindowDecoration = 0;
206     }
207     resize(mRequestedSize);
208 }
209
210 void QWaylandShmBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
211 {
212     Q_UNUSED(window);
213     Q_UNUSED(offset);
214     Q_ASSERT(waylandWindow()->windowType() == QWaylandWindow::Shm);
215
216     mFrontBuffer = mBackBuffer;
217
218     if (mFrameCallback) {
219         mFrontBufferIsDirty = true;
220         return;
221     }
222
223     mFrameCallback = wl_surface_frame(waylandWindow()->wl_surface());
224     wl_callback_add_listener(mFrameCallback,&frameCallbackListener,this);
225     QMargins margins = windowDecorationMargins();
226
227     if (waylandWindow()->attached() != mFrontBuffer) {
228         delete waylandWindow()->attached();
229         waylandWindow()->attach(mFrontBuffer);
230     }
231
232     QVector<QRect> rects = region.rects();
233     for (int i = 0; i < rects.size(); i++) {
234         QRect rect = rects.at(i);
235         rect.translate(margins.left(),margins.top());
236         waylandWindow()->damage(rect);
237     }
238     mFrontBufferIsDirty = false;
239 }
240
241 void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &)
242 {
243     mRequestedSize = size;
244 }
245
246 void QWaylandShmBackingStore::resize(const QSize &size)
247 {
248
249     QMargins margins = windowDecorationMargins();
250     QSize sizeWithMargins = size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom());
251
252     QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format();
253
254     if (mBackBuffer != NULL && mBackBuffer->size() == sizeWithMargins)
255         return;
256
257     if (mBackBuffer != mFrontBuffer) {
258         delete mBackBuffer; //we delete the attached buffer when we flush
259     }
260
261     mBackBuffer = new QWaylandShmBuffer(mDisplay, sizeWithMargins, format);
262
263     if (mWindowDecoration)
264         mWindowDecoration->paintDecoration();
265 }
266
267 QImage *QWaylandShmBackingStore::entireSurface() const
268 {
269     return mBackBuffer->image();
270 }
271
272 void QWaylandShmBackingStore::done(void *data, wl_callback *callback, uint32_t time)
273 {
274     Q_UNUSED(time);
275     QWaylandShmBackingStore *self =
276             static_cast<QWaylandShmBackingStore *>(data);
277     if (callback != self->mFrameCallback) // others, like QWaylandWindow, may trigger callbacks too
278         return;
279     QWaylandWindow *window = self->waylandWindow();
280     wl_callback_destroy(self->mFrameCallback);
281     self->mFrameCallback = 0;
282     if (self->mFrontBuffer != window->attached()) {
283         delete window->attached();
284         window->attach(self->mFrontBuffer);
285     }
286
287     if (self->mFrontBufferIsDirty && !self->mPainting) {
288         self->mFrontBufferIsDirty = false;
289         self->mFrameCallback = wl_surface_frame(window->wl_surface());
290         wl_callback_add_listener(self->mFrameCallback,&self->frameCallbackListener,self);
291         window->damage(QRect(QPoint(0,0),self->mFrontBuffer->size()));
292     }
293 }
294
295 const struct wl_callback_listener QWaylandShmBackingStore::frameCallbackListener = {
296     QWaylandShmBackingStore::done
297 };
298
299 QT_END_NAMESPACE