1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
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 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
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 #include "waylandsurfaceitem.h"
46 #include "wlcompositor.h"
47 #include "wlshmbuffer.h"
48 #include "wlinputdevice.h"
49 #include "wlextendedsurface.h"
50 #include "wlsubsurface.h"
51 #include "wlsurfacebuffer.h"
52 #include "wlshellsurface.h"
54 #include <QtCore/QDebug>
55 #include <QTouchEvent>
57 #include <wayland-server.h>
59 #ifdef QT_COMPOSITOR_WAYLAND_GL
60 #include "hardware_integration/graphicshardwareintegration.h"
61 #include <QtGui/QPlatformOpenGLContext>
64 #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
65 #include "waylandwindowmanagerintegration.h"
70 void destroy_surface(struct wl_resource *resource)
72 Surface *surface = wayland_cast<Surface *>((wl_surface *)resource);
73 surface->compositor()->surfaceDestroyed(surface);
77 Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor)
78 : m_compositor(compositor)
79 , m_waylandSurface(new WaylandSurface(this))
82 , m_surfaceMapped(false)
83 , m_extendedSurface(0)
87 wl_list_init(&m_frame_callback_list);
88 addClientResource(client, &base()->resource, id, &wl_surface_interface,
89 &Surface::surface_interface, destroy_surface);
90 for (int i = 0; i < buffer_pool_size; i++) {
91 m_bufferPool[i] = new SurfaceBuffer(this);
97 delete m_waylandSurface;
98 delete m_extendedSurface;
100 delete m_shellSurface;
102 for (int i = 0; i < buffer_pool_size; i++) {
103 if (!m_bufferPool[i]->pageFlipperHasBuffer())
104 delete m_bufferPool[i];
108 WaylandSurface::Type Surface::type() const
110 SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
111 if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) {
112 if (surfaceBuffer->isShmBuffer()) {
113 return WaylandSurface::Shm;
115 return WaylandSurface::Texture;
118 return WaylandSurface::Invalid;
121 bool Surface::isYInverted() const
124 static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt();
125 GraphicsHardwareIntegration *graphicsHWIntegration = m_compositor->graphicsHWIntegration();
127 #ifdef QT_COMPOSITOR_WAYLAND_GL
128 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
129 if (!surfacebuffer) {
131 } else if (graphicsHWIntegration && surfacebuffer->waylandBufferHandle() && type() != WaylandSurface::Shm) {
132 ret = graphicsHWIntegration->isYInverted(surfacebuffer->waylandBufferHandle());
137 return ret != negateReturn;
140 bool Surface::visible() const
143 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
144 return surfacebuffer->waylandBufferHandle();
147 QPointF Surface::pos() const
152 void Surface::setPos(const QPointF &pos)
154 bool emitChange = pos != m_position;
157 m_waylandSurface->posChanged();
160 QSize Surface::size() const
165 void Surface::setSize(const QSize &size)
167 bool emitChange = size != m_size;
170 m_waylandSurface->sizeChanged();
173 QImage Surface::image() const
175 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
176 if (surfacebuffer && !surfacebuffer->isDestroyed() && type() == WaylandSurface::Shm) {
177 ShmBuffer *shmBuffer = static_cast<ShmBuffer *>(surfacebuffer->waylandBufferHandle()->user_data);
178 return shmBuffer->image();
183 #ifdef QT_COMPOSITOR_WAYLAND_GL
184 GLuint Surface::textureId(QOpenGLContext *context) const
186 const SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
188 if (m_compositor->graphicsHWIntegration() && type() == WaylandSurface::Texture
189 && !surfacebuffer->textureCreated()) {
190 GraphicsHardwareIntegration *hwIntegration = m_compositor->graphicsHWIntegration();
191 const_cast<SurfaceBuffer *>(surfacebuffer)->createTexture(hwIntegration,context);
193 return surfacebuffer->texture();
195 #endif // QT_COMPOSITOR_WAYLAND_GL
197 void Surface::sendFrameCallback()
199 SurfaceBuffer *surfacebuffer = currentSurfaceBuffer();
200 surfacebuffer->setDisplayed();
203 m_frontBuffer->disown();
204 m_frontBuffer = m_backBuffer;
207 bool updateNeeded = advanceBufferQueue();
209 uint time = Compositor::currentTimeMsecs();
210 struct wl_resource *frame_callback;
211 wl_list_for_each(frame_callback, &m_frame_callback_list, link) {
212 wl_resource_post_event(frame_callback,WL_CALLBACK_DONE,time);
213 wl_resource_destroy(frame_callback,Compositor::currentTimeMsecs());
215 wl_list_init(&m_frame_callback_list);
221 void Surface::frameFinished()
223 m_compositor->frameFinished(this);
226 WaylandSurface * Surface::waylandSurface() const
228 return m_waylandSurface;
231 QPoint Surface::lastMousePos() const
233 return m_lastLocalMousePos;
236 void Surface::setExtendedSurface(ExtendedSurface *extendedSurface)
238 m_extendedSurface = extendedSurface;
241 ExtendedSurface *Surface::extendedSurface() const
243 return m_extendedSurface;
246 void Surface::setSubSurface(SubSurface *subSurface)
248 m_subSurface = subSurface;
251 SubSurface *Surface::subSurface() const
256 void Surface::setShellSurface(ShellSurface *shellSurface)
258 m_shellSurface = shellSurface;
261 ShellSurface *Surface::shellSurface() const
263 return m_shellSurface;
266 Compositor *Surface::compositor() const
271 bool Surface::advanceBufferQueue()
273 //has current buffer been displayed,
274 //do we have another buffer in the queue
275 //and does it have a valid damage rect
277 if (m_bufferQueue.size()) {
281 width = m_backBuffer->width();
282 height = m_backBuffer->height();
285 m_backBuffer = m_bufferQueue.takeFirst();
286 while (m_backBuffer && m_backBuffer->isDestroyed()) {
287 m_backBuffer->disown();
288 m_bufferQueue.takeFirst();
289 m_backBuffer = m_bufferQueue.size() ? m_bufferQueue.first():0;
293 return false; //we have no new backbuffer;
295 if (m_backBuffer->waylandBufferHandle()) {
296 if (width != m_backBuffer->width() ||
297 height != m_backBuffer->height()) {
298 width = m_backBuffer->width();
299 height = m_backBuffer->height();
302 setSize(QSize(width,height));
305 if (m_backBuffer && (!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) {
306 m_surfaceMapped = true;
307 emit m_waylandSurface->mapped();
308 } else if (m_backBuffer && !m_backBuffer->waylandBufferHandle() && m_surfaceMapped) {
309 m_surfaceMapped = false;
310 emit m_waylandSurface->unmapped();
321 void Surface::doUpdate() {
323 WaylandSurfaceItem *surfaceItem = waylandSurface()->surfaceItem();
325 surfaceItem->setDamagedFlag(true); // avoid flicker when we switch back to composited mode
328 SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer();
330 if (surfaceBuffer->damageRect().isValid()) {
331 m_compositor->markSurfaceAsDirty(this);
332 emit m_waylandSurface->damaged(surfaceBuffer->damageRect());
338 SurfaceBuffer *Surface::createSurfaceBuffer(struct wl_buffer *buffer)
340 SurfaceBuffer *newBuffer = 0;
341 for (int i = 0; i < Surface::buffer_pool_size; i++) {
342 if (!m_bufferPool[i]->isRegisteredWithBuffer()) {
343 newBuffer = m_bufferPool[i];
344 newBuffer->initialize(buffer);
353 bool Surface::postBuffer() {
354 #ifdef QT_COMPOSITOR_WAYLAND_GL
355 if (m_waylandSurface->handle() == m_compositor->directRenderSurface()) {
356 SurfaceBuffer *surfaceBuffer = m_backBuffer? m_backBuffer : m_frontBuffer;
357 if (surfaceBuffer && m_compositor->pageFlipper()) {
358 if (m_compositor->pageFlipper()->displayBuffer(surfaceBuffer)) {
359 surfaceBuffer->setPageFlipperHasBuffer(true);
362 qDebug() << "could not post buffer";
370 void Surface::attach(struct wl_buffer *buffer)
372 SurfaceBuffer *last = m_bufferQueue.size()?m_bufferQueue.last():0;
374 if (last->waylandBufferHandle() == buffer)
376 if (!last->damageRect().isValid()) {
378 m_bufferQueue.takeLast();
382 m_bufferQueue << createSurfaceBuffer(buffer);
385 void Surface::damage(const QRect &rect)
387 if (m_bufferQueue.size()) {
388 SurfaceBuffer *surfaceBuffer = m_bufferQueue.last();
390 surfaceBuffer->setDamage(rect);
392 qWarning() << "Surface::damage() null buffer";
394 advanceBufferQueue();
396 // we've receicved a second damage for the same buffer
397 currentSurfaceBuffer()->setDamage(rect);
402 const struct wl_surface_interface Surface::surface_interface = {
403 Surface::surface_destroy,
404 Surface::surface_attach,
405 Surface::surface_damage,
406 Surface::surface_frame
409 void Surface::surface_destroy(struct wl_client *, struct wl_resource *surface_resource)
411 wl_resource_destroy(surface_resource,Compositor::currentTimeMsecs());
414 void Surface::surface_attach(struct wl_client *client, struct wl_resource *surface,
415 struct wl_resource *buffer, int x, int y)
420 reinterpret_cast<Surface *>(surface)->attach(reinterpret_cast<struct wl_buffer *>(buffer));
423 void Surface::surface_damage(struct wl_client *client, struct wl_resource *surface,
424 int32_t x, int32_t y, int32_t width, int32_t height)
427 reinterpret_cast<Surface *>(surface)->damage(QRect(x, y, width, height));
429 void Surface::surface_frame(struct wl_client *client,
430 struct wl_resource *resource,
433 Surface *surface = reinterpret_cast<Surface *>(resource);
434 struct wl_resource *frame_callback = wl_client_add_object(client,&wl_callback_interface,0,callback,surface);
435 wl_list_insert(&surface->m_frame_callback_list,&frame_callback->link);
438 } // namespace Wayland