diff options
author | Jorgen Lind <jorgen.lind@digia.com> | 2013-11-14 13:22:13 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-12-27 15:32:17 +0100 |
commit | d250b714f8eb5a60bb048830e723ac76f06215b7 (patch) | |
tree | f6a6334b5ed8d3f3425447bd995f2bbff75e312f /src/client/qwaylandshmbackingstore.cpp | |
parent | 333648ff98558b78ca0464f8b1d606d40234d46f (diff) |
Move wayland into a client directory not under the plugins src folder
And make wayland common files into a library, exporting all classes. Now
there is no need to do bulild hacks to make your own version of the
wayland plugin.
Change-Id: Ib4872863dfb5ab3f2bc0f4a94ae16fc1e7b63b88
Reviewed-by: Andy Nichols <andy.nichols@digia.com>
Diffstat (limited to 'src/client/qwaylandshmbackingstore.cpp')
-rw-r--r-- | src/client/qwaylandshmbackingstore.cpp | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp new file mode 100644 index 000000000..00a4b13a2 --- /dev/null +++ b/src/client/qwaylandshmbackingstore.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qwaylandshmbackingstore.h" + +#include <QtCore/qdebug.h> + +#include "qwaylanddisplay.h" +#include "qwaylandshmwindow.h" +#include "qwaylandscreen.h" +#include "qwaylanddecoration.h" + +#include <QtGui/QPainter> + +#include <wayland-client.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/mman.h> + +QT_BEGIN_NAMESPACE + +QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display, + const QSize &size, QImage::Format format) + : mMarginsImage(0) +{ + int stride = size.width() * 4; + int alloc = stride * size.height(); + char filename[] = "/tmp/wayland-shm-XXXXXX"; + int fd = mkstemp(filename); + if (fd < 0) { + qWarning("mkstemp %s failed: %s", filename, strerror(errno)); + return; + } + int flags = fcntl(fd, F_GETFD); + if (flags != -1) + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + + if (ftruncate(fd, alloc) < 0) { + qWarning("ftruncate failed: %s", strerror(errno)); + close(fd); + return; + } + uchar *data = (uchar *) + mmap(NULL, alloc, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink(filename); + + if (data == (uchar *) MAP_FAILED) { + qWarning("mmap /dev/zero failed: %s", strerror(errno)); + close(fd); + return; + } + + mImage = QImage(data, size.width(), size.height(), stride, format); + mShmPool = wl_shm_create_pool(display->shm(), fd, alloc); + mBuffer = wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(), + stride, WL_SHM_FORMAT_ARGB8888); + close(fd); +} + +QWaylandShmBuffer::~QWaylandShmBuffer(void) +{ + delete mMarginsImage; + munmap((void *) mImage.constBits(), mImage.byteCount()); + wl_buffer_destroy(mBuffer); + wl_shm_pool_destroy(mShmPool); +} + +QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &margins) +{ + if (!margins.isNull() && margins != mMargins) { + if (mMarginsImage) { + delete mMarginsImage; + } + uchar *bits = const_cast<uchar *>(mImage.constBits()); + uchar *b_s_data = bits + margins.top() * mImage.bytesPerLine() + margins.left() * 4; + int b_s_width = mImage.size().width() - margins.left() - margins.right(); + int b_s_height = mImage.size().height() - margins.top() - margins.bottom(); + mMarginsImage = new QImage(b_s_data, b_s_width,b_s_height,mImage.bytesPerLine(),mImage.format()); + } + if (margins.isNull()) { + delete mMarginsImage; + mMarginsImage = 0; + } + + mMargins = margins; + if (!mMarginsImage) + return &mImage; + + return mMarginsImage; + +} + +QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) + , mFrontBuffer(0) + , mBackBuffer(0) + , mFrontBufferIsDirty(false) + , mPainting(false) + , mFrameCallback(0) +{ + +} + +QWaylandShmBackingStore::~QWaylandShmBackingStore() +{ + if (mFrameCallback) + wl_callback_destroy(mFrameCallback); + +// if (mFrontBuffer == waylandWindow()->attached()) +// waylandWindow()->attach(0); + + if (mFrontBuffer != mBackBuffer) + delete mFrontBuffer; + + delete mBackBuffer; +} + +QPaintDevice *QWaylandShmBackingStore::paintDevice() +{ + if (!windowDecoration()) + return mBackBuffer->image(); + return mBackBuffer->imageInsideMargins(windowDecorationMargins()); +} + +void QWaylandShmBackingStore::beginPaint(const QRegion &) +{ + mPainting = true; + ensureSize(); + + if (waylandWindow()->attached() && mBackBuffer == waylandWindow()->attached() && mFrameCallback) { + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle()); + Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); + waylandWindow->waitForFrameSync(); + } + + waylandWindow()->setCanResize(false); +} + +void QWaylandShmBackingStore::endPaint() +{ + mPainting = false; + waylandWindow()->setCanResize(true); +} + +void QWaylandShmBackingStore::ensureSize() +{ + waylandWindow()->setBackingStore(this); + waylandWindow()->createDecoration(); + resize(mRequestedSize); +} + +void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(offset); + Q_ASSERT(waylandWindow()->windowType() == QWaylandWindow::Shm); + + if (windowDecoration() && windowDecoration()->isDirty()) + updateDecorations(); + + mFrontBuffer = mBackBuffer; + + if (mFrameCallback) { + mFrontBufferIsDirty = true; + return; + } + + mFrameCallback = waylandWindow()->frame(); + wl_callback_add_listener(mFrameCallback,&frameCallbackListener,this); + QMargins margins = windowDecorationMargins(); + + bool damageAll = false; + if (waylandWindow()->attached() != mFrontBuffer) { + delete waylandWindow()->attached(); + damageAll = true; + } + waylandWindow()->attachOffset(mFrontBuffer); + + if (damageAll) { + //need to damage it all, otherwise the attach offset may screw up + waylandWindow()->damage(QRect(QPoint(0,0),mFrontBuffer->size())); + } else { + QVector<QRect> rects = region.rects(); + for (int i = 0; i < rects.size(); i++) { + QRect rect = rects.at(i); + rect.translate(margins.left(),margins.top()); + waylandWindow()->damage(rect); + } + } + waylandWindow()->commit(); + mFrontBufferIsDirty = false; +} + +void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) +{ + mRequestedSize = size; +} + +void QWaylandShmBackingStore::resize(const QSize &size) +{ + QMargins margins = windowDecorationMargins(); + QSize sizeWithMargins = size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom()); + + QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); + + if (mBackBuffer != NULL && mBackBuffer->size() == sizeWithMargins) + return; + + if (mBackBuffer != mFrontBuffer) { + delete mBackBuffer; //we delete the attached buffer when we flush + } + + mBackBuffer = new QWaylandShmBuffer(mDisplay, sizeWithMargins, format); + + if (windowDecoration() && window()->isVisible()) + windowDecoration()->update(); +} + +QImage *QWaylandShmBackingStore::entireSurface() const +{ + return mBackBuffer->image(); +} + +void QWaylandShmBackingStore::updateDecorations() +{ + QPainter decorationPainter(entireSurface()); + decorationPainter.setCompositionMode(QPainter::CompositionMode_Source); + QImage sourceImage = windowDecoration()->contentImage(); + QRect target; + //Top + target.setX(0); + target.setY(0); + target.setWidth(sourceImage.width()); + target.setHeight(windowDecorationMargins().top()); + decorationPainter.drawImage(target, sourceImage, target); + + //Left + target.setWidth(windowDecorationMargins().left()); + target.setHeight(sourceImage.height()); + decorationPainter.drawImage(target, sourceImage, target); + + //Right + target.setX(sourceImage.width() - windowDecorationMargins().right()); + decorationPainter.drawImage(target, sourceImage, target); + + //Bottom + target.setX(0); + target.setY(sourceImage.height() - windowDecorationMargins().bottom()); + target.setWidth(sourceImage.width()); + target.setHeight(windowDecorationMargins().bottom()); + decorationPainter.drawImage(target, sourceImage, target); +} + +void QWaylandShmBackingStore::done(void *data, wl_callback *callback, uint32_t time) +{ + Q_UNUSED(time); + QWaylandShmBackingStore *self = + static_cast<QWaylandShmBackingStore *>(data); + if (callback != self->mFrameCallback) // others, like QWaylandWindow, may trigger callbacks too + return; + QWaylandShmWindow *window = self->waylandWindow(); + wl_callback_destroy(self->mFrameCallback); + self->mFrameCallback = 0; + + + if (self->mFrontBufferIsDirty && !self->mPainting) { + self->mFrontBufferIsDirty = false; + self->mFrameCallback = wl_surface_frame(window->object()); + wl_callback_add_listener(self->mFrameCallback,&self->frameCallbackListener,self); + if (self->mFrontBuffer != window->attached()) { + delete window->attached(); + } + window->attachOffset(self->mFrontBuffer); + window->damage(QRect(QPoint(0,0),self->mFrontBuffer->size())); + window->commit(); + } +} + +const struct wl_callback_listener QWaylandShmBackingStore::frameCallbackListener = { + QWaylandShmBackingStore::done +}; + +QT_END_NAMESPACE |