Fix broken handling of inactive transient surfaces
[profile/ivi/qtwayland.git] / src / compositor / wayland_wrapper / wlsurface.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 Qt Compositor.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 **     the names of its contributors may be used to endorse or promote
22 **     products derived from this software without specific prior written
23 **     permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "wlsurface.h"
42
43 #include "waylandsurface.h"
44 #ifdef QT_COMPOSITOR_QUICK
45 #include "waylandsurfaceitem.h"
46 #endif
47
48 #include "wlcompositor.h"
49 #include "wlinputdevice.h"
50 #include "wlextendedsurface.h"
51 #include "wlregion.h"
52 #include "wlsubsurface.h"
53 #include "wlsurfacebuffer.h"
54 #include "wlshellsurface.h"
55
56 #include <QtCore/QDebug>
57 #include <QTouchEvent>
58
59 #include <wayland-server.h>
60
61 #ifdef QT_COMPOSITOR_WAYLAND_GL
62 #include "hardware_integration/graphicshardwareintegration.h"
63 #include <qpa/qplatformopenglcontext.h>
64 #endif
65
66 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
67 #include "waylandwindowmanagerintegration.h"
68 #endif
69
70 namespace Wayland {
71
72 void destroy_surface(struct wl_resource *resource)
73 {
74     Surface *surface = resolve<Surface>(resource);
75     surface->compositor()->surfaceDestroyed(surface);
76     delete surface;
77 }
78
79 Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor)
80     : m_compositor(compositor)
81     , m_waylandSurface(new WaylandSurface(this))
82     , m_backBuffer(0)
83     , m_frontBuffer(0)
84     , m_surfaceMapped(false)
85     , m_extendedSurface(0)
86     , m_subSurface(0)
87     , m_shellSurface(0)
88     , m_transientInactive(false)
89 {
90     wl_list_init(&m_frame_callback_list);
91     addClientResource(client, &base()->resource, id, &wl_surface_interface,
92             &Surface::surface_interface, destroy_surface);
93     for (int i = 0; i < buffer_pool_size; i++) {
94         m_bufferPool[i] = new SurfaceBuffer(this);
95     }
96 }
97
98 Surface::~Surface()
99 {
100     delete m_waylandSurface;
101     delete m_extendedSurface;
102     delete m_subSurface;
103     delete m_shellSurface;
104
105     for (int i = 0; i < buffer_pool_size; i++) {
106         if (!m_bufferPool[i]->pageFlipperHasBuffer())
107             delete m_bufferPool[i];
108     }
109 }
110
111 WaylandSurface::Type Surface::type() const
112 {
113     SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
114     if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) {
115         if (surfaceBuffer->isShmBuffer()) {
116             return WaylandSurface::Shm;
117         } else {
118             return WaylandSurface::Texture;
119         }
120     }
121     return WaylandSurface::Invalid;
122 }
123
124 bool Surface::isYInverted() const
125 {
126     bool ret = false;
127     static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt();
128     GraphicsHardwareIntegration *graphicsHWIntegration = m_compositor->graphicsHWIntegration();
129
130 #ifdef QT_COMPOSITOR_WAYLAND_GL
131     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
132     if (!surfacebuffer) {
133         ret = false;
134     } else if (graphicsHWIntegration && surfacebuffer->waylandBufferHandle() && type() != WaylandSurface::Shm) {
135         ret = graphicsHWIntegration->isYInverted(surfacebuffer->waylandBufferHandle());
136     } else
137 #endif
138         ret = true;
139
140     return ret != negateReturn;
141 }
142
143 bool Surface::visible() const
144 {
145
146     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
147     return surfacebuffer->waylandBufferHandle();
148 }
149
150 QPointF Surface::pos() const
151 {
152     return m_shellSurface ? m_shellSurface->adjustedPosToTransientParent() : m_position;
153 }
154
155 QPointF Surface::nonAdjustedPos() const
156 {
157     return m_position;
158 }
159
160 void Surface::setPos(const QPointF &pos)
161 {
162     bool emitChange = pos != m_position;
163     m_position = pos;
164     if (emitChange)
165         m_waylandSurface->posChanged();
166 }
167
168 QSize Surface::size() const
169 {
170     return m_size;
171 }
172
173 void Surface::setSize(const QSize &size)
174 {
175     if (size != m_size) {
176         m_opaqueRegion = QRegion();
177         m_inputRegion = QRegion(QRect(QPoint(), size));
178         m_size = size;
179         if (m_shellSurface) {
180             m_shellSurface->adjustPosInResize();
181         }
182         m_waylandSurface->sizeChanged();
183     }
184 }
185
186 QRegion Surface::inputRegion() const
187 {
188     return m_inputRegion;
189 }
190
191 QRegion Surface::opaqueRegion() const
192 {
193     return m_opaqueRegion;
194 }
195
196 QImage Surface::image() const
197 {
198     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
199     if (surfacebuffer && !surfacebuffer->isDestroyed() && type() == WaylandSurface::Shm) {
200         struct wl_buffer *buffer = surfacebuffer->waylandBufferHandle();
201         int stride = wl_shm_buffer_get_stride(buffer);
202         uint format = wl_shm_buffer_get_format(buffer);
203         (void) format;
204         void *data = wl_shm_buffer_get_data(buffer);
205         const uchar *char_data = static_cast<const uchar *>(data);
206         QImage img(char_data, buffer->width, buffer->height, stride, QImage::Format_ARGB32_Premultiplied);
207         return img;
208     }
209     return QImage();
210 }
211
212 #ifdef QT_COMPOSITOR_WAYLAND_GL
213 GLuint Surface::textureId(QOpenGLContext *context) const
214 {
215     const SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
216
217     if (m_compositor->graphicsHWIntegration() && type() == WaylandSurface::Texture
218          && !surfacebuffer->textureCreated()) {
219         GraphicsHardwareIntegration *hwIntegration = m_compositor->graphicsHWIntegration();
220         const_cast<SurfaceBuffer *>(surfacebuffer)->createTexture(hwIntegration,context);
221     }
222     return surfacebuffer->texture();
223 }
224 #endif // QT_COMPOSITOR_WAYLAND_GL
225
226 void Surface::sendFrameCallback()
227 {
228     SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
229     surfacebuffer->setDisplayed();
230     if (m_backBuffer) {
231         if (m_frontBuffer)
232             m_frontBuffer->disown();
233         m_frontBuffer = m_backBuffer;
234     }
235
236     bool updateNeeded = advanceBufferQueue();
237
238     uint time = Compositor::currentTimeMsecs();
239     struct wl_resource *frame_callback;
240     wl_list_for_each(frame_callback, &m_frame_callback_list, link) {
241         wl_callback_send_done(frame_callback, time);
242         wl_resource_destroy(frame_callback);
243     }
244     wl_list_init(&m_frame_callback_list);
245
246     if (updateNeeded)
247         doUpdate();
248 }
249
250 void Surface::frameFinished()
251 {
252     m_compositor->frameFinished(this);
253 }
254
255 WaylandSurface * Surface::waylandSurface() const
256 {
257     return m_waylandSurface;
258 }
259
260 QPoint Surface::lastMousePos() const
261 {
262     return m_lastLocalMousePos;
263 }
264
265 void Surface::setExtendedSurface(ExtendedSurface *extendedSurface)
266 {
267     m_extendedSurface = extendedSurface;
268     if (m_extendedSurface)
269         emit m_waylandSurface->extendedSurfaceReady();
270 }
271
272 ExtendedSurface *Surface::extendedSurface() const
273 {
274     return m_extendedSurface;
275 }
276
277 void Surface::setSubSurface(SubSurface *subSurface)
278 {
279     m_subSurface = subSurface;
280 }
281
282 SubSurface *Surface::subSurface() const
283 {
284     return m_subSurface;
285 }
286
287 void Surface::setShellSurface(ShellSurface *shellSurface)
288 {
289     m_shellSurface = shellSurface;
290 }
291
292 ShellSurface *Surface::shellSurface() const
293 {
294     return m_shellSurface;
295 }
296
297 Compositor *Surface::compositor() const
298 {
299     return m_compositor;
300 }
301
302 bool Surface::advanceBufferQueue()
303 {
304     //has current buffer been displayed,
305     //do we have another buffer in the queue
306     //and does it have a valid damage rect
307
308     if (m_bufferQueue.size()) {
309         int width = 0;
310         int height = 0;
311         if (m_backBuffer) {
312             width = m_backBuffer->width();
313             height = m_backBuffer->height();
314         }
315
316         m_backBuffer = m_bufferQueue.takeFirst();
317         while (m_backBuffer && m_backBuffer->isDestroyed()) {
318             m_backBuffer->disown();
319             m_backBuffer = m_bufferQueue.size() ? m_bufferQueue.takeFirst() : 0;
320         }
321
322         if (!m_backBuffer)
323             return false; //we have no new backbuffer;
324
325         if (m_backBuffer->waylandBufferHandle()) {
326             width = m_backBuffer->width();
327             height = m_backBuffer->height();
328         }
329         setSize(QSize(width,height));
330
331
332         if (m_backBuffer &&  (!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) {
333             m_surfaceMapped = true;
334             emit m_waylandSurface->mapped();
335         } else if (m_backBuffer && !m_backBuffer->waylandBufferHandle() && m_surfaceMapped) {
336             m_surfaceMapped = false;
337             emit m_waylandSurface->unmapped();
338         }
339
340     } else {
341         m_backBuffer = 0;
342         return false;
343     }
344
345     return true;
346 }
347
348 void Surface::doUpdate() {
349     if (postBuffer()) {
350 #ifdef QT_COMPOSITOR_QUICK
351         WaylandSurfaceItem *surfaceItem = waylandSurface()->surfaceItem();
352         if (surfaceItem)
353             surfaceItem->setDamagedFlag(true); // avoid flicker when we switch back to composited mode
354 #endif
355         sendFrameCallback();
356     } else {
357         SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
358         if (surfaceBuffer) {
359             if (surfaceBuffer->damageRect().isValid()) {
360                 m_compositor->markSurfaceAsDirty(this);
361                 emit m_waylandSurface->damaged(surfaceBuffer->damageRect());
362             }
363         }
364     }
365 }
366
367 SurfaceBuffer *Surface::createSurfaceBuffer(struct wl_buffer *buffer)
368 {
369     SurfaceBuffer *newBuffer = 0;
370     for (int i = 0; i < Surface::buffer_pool_size; i++) {
371         if (!m_bufferPool[i]->isRegisteredWithBuffer()) {
372             newBuffer = m_bufferPool[i];
373             newBuffer->initialize(buffer);
374             break;
375         }
376     }
377
378     Q_ASSERT(newBuffer);
379     return newBuffer;
380 }
381
382 bool Surface::postBuffer() {
383 #ifdef QT_COMPOSITOR_WAYLAND_GL
384     if (m_waylandSurface->handle() == m_compositor->directRenderSurface()) {
385         SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
386         if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) {
387             if (m_compositor->pageFlipper()) {
388                 if (m_compositor->pageFlipper()->displayBuffer(surfaceBuffer)) {
389                     surfaceBuffer->setPageFlipperHasBuffer(true);
390                     m_compositor->setDirectRenderingActive(true);
391                     return true;
392                 } else {
393                     qDebug() << "could not post buffer";
394                 }
395             }
396         }
397     }
398 #endif
399     return false;
400 }
401
402 void Surface::attach(struct wl_buffer *buffer)
403 {
404     SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0;
405     if (last) {
406         if (last->waylandBufferHandle() == buffer)
407             return;
408         if (!last->damageRect().isValid()) {
409             last->disown();
410             m_bufferQueue.takeLast();
411         }
412     }
413
414     m_bufferQueue <<  createSurfaceBuffer(buffer);
415
416     if (!buffer) {
417         InputDevice *inputDevice = m_compositor->defaultInputDevice();
418         if (inputDevice->keyboardFocus() == this)
419             inputDevice->setKeyboardFocus(0);
420         if (inputDevice->mouseFocus() == this)
421             inputDevice->setMouseFocus(0, QPointF(), QPointF());
422     }
423 }
424
425 void Surface::damage(const QRect &rect)
426 {
427     SurfaceBuffer *surfaceBuffer = m_bufferQueue.isEmpty() ? currentSurfaceBuffer() : m_bufferQueue.last();
428     if (surfaceBuffer)
429         surfaceBuffer->setDamage(rect);
430     else
431         qWarning() << "Surface::damage() null buffer";
432
433     if (!m_bufferQueue.isEmpty() && !m_backBuffer)
434         advanceBufferQueue();
435
436     doUpdate();
437 }
438
439 const struct wl_surface_interface Surface::surface_interface = {
440         Surface::surface_destroy,
441         Surface::surface_attach,
442         Surface::surface_damage,
443         Surface::surface_frame,
444         Surface::surface_set_opaque_region,
445         Surface::surface_set_input_region
446 };
447
448 void Surface::surface_destroy(struct wl_client *, struct wl_resource *surface_resource)
449 {
450     wl_resource_destroy(surface_resource);
451 }
452
453 void Surface::surface_attach(struct wl_client *client, struct wl_resource *surface,
454                     struct wl_resource *buffer, int x, int y)
455 {
456     Q_UNUSED(client);
457     Q_UNUSED(x);
458     Q_UNUSED(y);
459     resolve<Surface>(surface)->attach(buffer ? reinterpret_cast<wl_buffer *>(buffer->data) : 0);
460 }
461
462 void Surface::surface_damage(struct wl_client *client, struct wl_resource *surface,
463                     int32_t x, int32_t y, int32_t width, int32_t height)
464 {
465     Q_UNUSED(client);
466     resolve<Surface>(surface)->damage(QRect(x, y, width, height));
467 }
468
469 void Surface::surface_frame(struct wl_client *client,
470                    struct wl_resource *resource,
471                    uint32_t callback)
472 {
473     Surface *surface = resolve<Surface>(resource);
474     struct wl_resource *frame_callback = wl_client_add_object(client,&wl_callback_interface,0,callback,surface);
475     wl_list_insert(&surface->m_frame_callback_list,&frame_callback->link);
476 }
477
478 void Surface::surface_set_opaque_region(struct wl_client *client, struct wl_resource *surfaceResource,
479                                         struct wl_resource *region)
480 {
481     Q_UNUSED(client);
482     Surface *surface = resolve<Surface>(surfaceResource);
483     surface->m_opaqueRegion = region ? resolve<Region>(region)->region() : QRegion();
484 }
485
486 void Surface::surface_set_input_region(struct wl_client *client, struct wl_resource *surfaceResource,
487                                        struct wl_resource *region)
488 {
489     Q_UNUSED(client);
490     Surface *surface = resolve<Surface>(surfaceResource);
491     surface->m_inputRegion = region ? resolve<Region>(region)->region() : QRegion(QRect(QPoint(), surface->size()));
492 }
493
494 void Surface::setTitle(const QString &title)
495 {
496     if (m_title != title) {
497         m_title = title;
498         emit waylandSurface()->titleChanged();
499     }
500 }
501
502 } // namespace Wayland
503