1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the Qt Compositor.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
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
20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 ** of its contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
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."
39 ****************************************************************************/
41 #include "wlsurface.h"
43 #include "waylandsurface.h"
44 #ifdef QT_COMPOSITOR_QUICK
45 #include "waylandsurfaceitem.h"
48 #include "wlcompositor.h"
49 #include "wlinputdevice.h"
50 #include "wlextendedsurface.h"
52 #include "wlsubsurface.h"
53 #include "wlsurfacebuffer.h"
54 #include "wlshellsurface.h"
56 #include <QtCore/QDebug>
57 #include <QTouchEvent>
59 #include <wayland-server.h>
61 #ifdef QT_COMPOSITOR_WAYLAND_GL
62 #include "hardware_integration/graphicshardwareintegration.h"
63 #include <qpa/qplatformopenglcontext.h>
66 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
67 #include "waylandwindowmanagerintegration.h"
72 void destroy_surface(struct wl_resource *resource)
74 Surface *surface = resolve<Surface>(resource);
75 surface->compositor()->surfaceDestroyed(surface);
79 Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor)
80 : m_compositor(compositor)
81 , m_waylandSurface(new WaylandSurface(this))
84 , m_surfaceMapped(false)
85 , m_extendedSurface(0)
88 , m_transientInactive(false)
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);
100 delete m_waylandSurface;
101 delete m_extendedSurface;
103 delete m_shellSurface;
105 for (int i = 0; i < buffer_pool_size; i++) {
106 if (!m_bufferPool[i]->pageFlipperHasBuffer())
107 delete m_bufferPool[i];
111 WaylandSurface::Type Surface::type() const
113 SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
114 if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) {
115 if (surfaceBuffer->isShmBuffer()) {
116 return WaylandSurface::Shm;
118 return WaylandSurface::Texture;
121 return WaylandSurface::Invalid;
124 bool Surface::isYInverted() const
127 static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt();
128 GraphicsHardwareIntegration *graphicsHWIntegration = m_compositor->graphicsHWIntegration();
130 #ifdef QT_COMPOSITOR_WAYLAND_GL
131 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
132 if (!surfacebuffer) {
134 } else if (graphicsHWIntegration && surfacebuffer->waylandBufferHandle() && type() != WaylandSurface::Shm) {
135 ret = graphicsHWIntegration->isYInverted(surfacebuffer->waylandBufferHandle());
140 return ret != negateReturn;
143 bool Surface::visible() const
146 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
147 return surfacebuffer->waylandBufferHandle();
150 QPointF Surface::pos() const
152 return m_shellSurface ? m_shellSurface->adjustedPosToTransientParent() : m_position;
155 QPointF Surface::nonAdjustedPos() const
160 void Surface::setPos(const QPointF &pos)
162 bool emitChange = pos != m_position;
165 m_waylandSurface->posChanged();
168 QSize Surface::size() const
173 void Surface::setSize(const QSize &size)
175 if (size != m_size) {
176 m_opaqueRegion = QRegion();
177 m_inputRegion = QRegion(QRect(QPoint(), size));
179 if (m_shellSurface) {
180 m_shellSurface->adjustPosInResize();
182 m_waylandSurface->sizeChanged();
186 QRegion Surface::inputRegion() const
188 return m_inputRegion;
191 QRegion Surface::opaqueRegion() const
193 return m_opaqueRegion;
196 QImage Surface::image() const
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);
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);
212 #ifdef QT_COMPOSITOR_WAYLAND_GL
213 GLuint Surface::textureId(QOpenGLContext *context) const
215 const SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
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);
222 return surfacebuffer->texture();
224 #endif // QT_COMPOSITOR_WAYLAND_GL
226 void Surface::sendFrameCallback()
228 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
229 surfacebuffer->setDisplayed();
232 m_frontBuffer->disown();
233 m_frontBuffer = m_backBuffer;
236 bool updateNeeded = advanceBufferQueue();
238 uint time = Compositor::currentTimeMsecs();
239 struct wl_resource *frame_callback, *next;
240 wl_list_for_each_safe(frame_callback, next, &m_frame_callback_list, link) {
241 wl_callback_send_done(frame_callback, time);
242 wl_resource_destroy(frame_callback);
244 wl_list_init(&m_frame_callback_list);
250 void Surface::frameFinished()
252 m_compositor->frameFinished(this);
255 WaylandSurface * Surface::waylandSurface() const
257 return m_waylandSurface;
260 QPoint Surface::lastMousePos() const
262 return m_lastLocalMousePos;
265 void Surface::setExtendedSurface(ExtendedSurface *extendedSurface)
267 m_extendedSurface = extendedSurface;
268 if (m_extendedSurface)
269 emit m_waylandSurface->extendedSurfaceReady();
272 ExtendedSurface *Surface::extendedSurface() const
274 return m_extendedSurface;
277 void Surface::setSubSurface(SubSurface *subSurface)
279 m_subSurface = subSurface;
282 SubSurface *Surface::subSurface() const
287 void Surface::setShellSurface(ShellSurface *shellSurface)
289 m_shellSurface = shellSurface;
292 ShellSurface *Surface::shellSurface() const
294 return m_shellSurface;
297 Compositor *Surface::compositor() const
302 bool Surface::advanceBufferQueue()
304 //has current buffer been displayed,
305 //do we have another buffer in the queue
306 //and does it have a valid damage rect
308 if (m_bufferQueue.size()) {
312 width = m_backBuffer->width();
313 height = m_backBuffer->height();
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;
323 return false; //we have no new backbuffer;
325 if (m_backBuffer->waylandBufferHandle()) {
326 width = m_backBuffer->width();
327 height = m_backBuffer->height();
329 setSize(QSize(width,height));
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();
348 void Surface::doUpdate() {
350 #ifdef QT_COMPOSITOR_QUICK
351 WaylandSurfaceItem *surfaceItem = waylandSurface()->surfaceItem();
353 surfaceItem->setDamagedFlag(true); // avoid flicker when we switch back to composited mode
357 SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
359 if (surfaceBuffer->damageRect().isValid()) {
360 m_compositor->markSurfaceAsDirty(this);
361 emit m_waylandSurface->damaged(surfaceBuffer->damageRect());
367 SurfaceBuffer *Surface::createSurfaceBuffer(struct wl_buffer *buffer)
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);
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);
393 qDebug() << "could not post buffer";
402 void Surface::attach(struct wl_buffer *buffer)
404 SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0;
406 if (last->waylandBufferHandle() == buffer)
408 if (!last->damageRect().isValid()) {
410 m_bufferQueue.takeLast();
414 m_bufferQueue << createSurfaceBuffer(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());
425 void Surface::damage(const QRect &rect)
427 SurfaceBuffer *surfaceBuffer = m_bufferQueue.isEmpty() ? currentSurfaceBuffer() : m_bufferQueue.last();
429 surfaceBuffer->setDamage(rect);
431 qWarning() << "Surface::damage() null buffer";
433 if (!m_bufferQueue.isEmpty() && !m_backBuffer)
434 advanceBufferQueue();
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
448 void Surface::surface_destroy(struct wl_client *, struct wl_resource *surface_resource)
450 wl_resource_destroy(surface_resource);
453 void Surface::surface_attach(struct wl_client *client, struct wl_resource *surface,
454 struct wl_resource *buffer, int x, int y)
459 resolve<Surface>(surface)->attach(buffer ? reinterpret_cast<wl_buffer *>(buffer->data) : 0);
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)
466 resolve<Surface>(surface)->damage(QRect(x, y, width, height));
469 void Surface::surface_frame(struct wl_client *client,
470 struct wl_resource *resource,
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);
478 void Surface::surface_set_opaque_region(struct wl_client *client, struct wl_resource *surfaceResource,
479 struct wl_resource *region)
482 Surface *surface = resolve<Surface>(surfaceResource);
483 surface->m_opaqueRegion = region ? resolve<Region>(region)->region() : QRegion();
486 void Surface::surface_set_input_region(struct wl_client *client, struct wl_resource *surfaceResource,
487 struct wl_resource *region)
490 Surface *surface = resolve<Surface>(surfaceResource);
491 surface->m_inputRegion = region ? resolve<Region>(region)->region() : QRegion(QRect(QPoint(), surface->size()));
494 void Surface::setTitle(const QString &title)
496 if (m_title != title) {
498 emit waylandSurface()->titleChanged();
502 } // namespace Wayland