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 | |
parent | 333648ff98558b78ca0464f8b1d606d40234d46f (diff) | |
download | qtwayland-d250b714f8eb5a60bb048830e723ac76f06215b7.tar.gz |
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')
55 files changed, 8486 insertions, 0 deletions
diff --git a/src/client/client.pro b/src/client/client.pro new file mode 100644 index 00000000..66dc1a47 --- /dev/null +++ b/src/client/client.pro @@ -0,0 +1,103 @@ +TARGET = QtWaylandClient +QT += core-private gui-private +QT_FOR_PRIVATE += platformsupport-private + +MODULE=waylandclient +load(qt_module) + +CONFIG += link_pkgconfig qpa/genericunixfontdatabase wayland-scanner + +!equals(QT_WAYLAND_GL_CONFIG, nogl) { + DEFINES += QT_WAYLAND_GL_SUPPORT +} + +config_xkbcommon { + !contains(QT_CONFIG, no-pkg-config) { + PKGCONFIG += xkbcommon + } else { + LIBS += -lxkbcommon + } +} else { + DEFINES += QT_NO_WAYLAND_XKB +} + +!contains(QT_CONFIG, no-pkg-config) { + PKGCONFIG += wayland-client wayland-cursor + contains(QT_CONFIG, glib): PKGCONFIG_PRIVATE += glib-2.0 +} else { + LIBS += -lwayland-client -lwayland-cursor $$QT_LIBS_GLIB +} + +INCLUDEPATH += $$PWD/../shared + +WAYLANDCLIENTSOURCES += \ + ../3rdparty/protocol/wayland.xml \ + ../extensions/surface-extension.xml \ + ../extensions/sub-surface-extension.xml \ + ../extensions/output-extension.xml \ + ../extensions/touch-extension.xml \ + ../extensions/qtkey-extension.xml \ + ../extensions/windowmanager.xml \ + ../3rdparty/protocol/text.xml \ + + +SOURCES += qwaylandintegration.cpp \ + qwaylandnativeinterface.cpp \ + qwaylandshmbackingstore.cpp \ + qwaylandinputdevice.cpp \ + qwaylandcursor.cpp \ + qwaylanddisplay.cpp \ + qwaylandwindow.cpp \ + qwaylandscreen.cpp \ + qwaylandshmwindow.cpp \ + qwaylandclipboard.cpp \ + qwaylanddnd.cpp \ + qwaylanddataoffer.cpp \ + qwaylanddatadevicemanager.cpp \ + qwaylanddatasource.cpp \ + qwaylandshellsurface.cpp \ + qwaylandextendedoutput.cpp \ + qwaylandextendedsurface.cpp \ + qwaylandsubsurface.cpp \ + qwaylandtouch.cpp \ + qwaylandqtkey.cpp \ + ../shared/qwaylandmimehelper.cpp \ + qwaylanddecoration.cpp \ + qwaylandeventthread.cpp\ + qwaylandwindowmanagerintegration.cpp \ + qwaylandinputcontext.cpp \ + qwaylanddatadevice.cpp \ + +HEADERS += qwaylandintegration.h \ + qwaylandnativeinterface.h \ + qwaylandcursor.h \ + qwaylanddisplay.h \ + qwaylandwindow.h \ + qwaylandscreen.h \ + qwaylandshmbackingstore.h \ + qwaylandinputdevice.h \ + qwaylandbuffer.h \ + qwaylandshmwindow.h \ + qwaylandclipboard.h \ + qwaylanddnd.h \ + qwaylanddataoffer.h \ + qwaylanddatadevicemanager.h \ + qwaylanddatasource.h \ + qwaylandshellsurface.h \ + qwaylandextendedoutput.h \ + qwaylandextendedsurface.h \ + qwaylandsubsurface.h \ + qwaylandtouch.h \ + qwaylandqtkey.h \ + ../shared/qwaylandmimehelper.h \ + qwaylanddecoration.h \ + qwaylandeventthread.h \ + qwaylandwindowmanagerintegration.h \ + qwaylandinputcontext.h \ + qwaylanddatadevice.h \ + +contains(DEFINES, QT_WAYLAND_GL_SUPPORT) { + SOURCES += qwaylandglintegration.cpp + HEADERS += qwaylandglintegration.h +} + diff --git a/src/client/qwaylandbuffer.h b/src/client/qwaylandbuffer.h new file mode 100644 index 00000000..8d9ceaa8 --- /dev/null +++ b/src/client/qwaylandbuffer.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDBUFFER_H +#define QWAYLANDBUFFER_H + +#include "qwaylandclientexport.h" + +#include <QtCore/QSize> +#include <QtCore/QRect> + +#include <wayland-client.h> +#include <wayland-client-protocol.h> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_CLIENT_EXPORT QWaylandBuffer { +public: + QWaylandBuffer() { } + virtual ~QWaylandBuffer() { } + wl_buffer *buffer() {return mBuffer;} + virtual QSize size() const = 0; + +protected: + struct wl_buffer *mBuffer; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDBUFFER_H diff --git a/src/client/qwaylandclientexport.h b/src/client/qwaylandclientexport.h new file mode 100644 index 00000000..d9d6d7f7 --- /dev/null +++ b/src/client/qwaylandclientexport.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDCLIENTEXPORT_H +#define QWAYLANDCLIENTEXPORT_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#if !defined(Q_WAYLAND_CLIENT_EXPORT) +# if defined(QT_SHARED) +# define Q_WAYLAND_CLIENT_EXPORT Q_DECL_EXPORT +# else +# define Q_WAYLAND_CLIENT_EXPORT +# endif +#endif + +QT_END_NAMESPACE + +#endif //QWAYLANDCLIENTEXPORT_H + diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp new file mode 100644 index 00000000..838f6d23 --- /dev/null +++ b/src/client/qwaylandclipboard.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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 "qwaylandclipboard.h" +#include "qwaylanddisplay.h" +#include "qwaylandinputdevice.h" +#include "qwaylanddataoffer.h" +#include "qwaylanddatasource.h" +#include "qwaylanddatadevice.h" + +QT_BEGIN_NAMESPACE + +QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display) + : mDisplay(display) +{ +} + +QWaylandClipboard::~QWaylandClipboard() +{ +} + +QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return 0; + + QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); + if (!inputDevice || !inputDevice->dataDevice()) + return 0; + + QWaylandDataSource *source = inputDevice->dataDevice()->selectionSource(); + if (source) { + return source->mimeData(); + } + + if (inputDevice->dataDevice()->selectionOffer()) + return inputDevice->dataDevice()->selectionOffer()->mimeData(); + + return 0; +} + +void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return; + + QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); + if (!inputDevice || !inputDevice->dataDevice()) + return; + + inputDevice->dataDevice()->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : 0); + + emitChanged(mode); +} + +bool QWaylandClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +bool QWaylandClipboard::ownsMode(QClipboard::Mode mode) const +{ + if (mode != QClipboard::Clipboard) + return false; + + QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); + if (!inputDevice || !inputDevice->dataDevice()) + return false; + + return inputDevice->dataDevice()->selectionSource() != 0; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandclipboard.h b/src/client/qwaylandclipboard.h new file mode 100644 index 00000000..692a3125 --- /dev/null +++ b/src/client/qwaylandclipboard.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDCLIPBOARD_H +#define QWAYLANDCLIPBOARD_H + +#include <qpa/qplatformclipboard.h> +#include <QtCore/QVariant> + +#include <QtWaylandClient/qwaylandclientexport.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandClipboard : public QPlatformClipboard +{ +public: + QWaylandClipboard(QWaylandDisplay *display); + + ~QWaylandClipboard(); + + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + +private: + QWaylandDisplay *mDisplay; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDCLIPBOARD_H diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp new file mode 100644 index 00000000..05ab6d49 --- /dev/null +++ b/src/client/qwaylandcursor.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** 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 "qwaylandcursor.h" + +#include "qwaylanddisplay.h" +#include "qwaylandinputdevice.h" +#include "qwaylandscreen.h" +#include "qwaylandshmbackingstore.h" + +#include <QtGui/QImageReader> +#include <QDebug> + +#include <wayland-cursor.h> + +QT_BEGIN_NAMESPACE + +QWaylandCursor::QWaylandCursor(QWaylandScreen *screen) + : mDisplay(screen->display()) +{ + //TODO: Make wl_cursor_theme_load arguments configurable here + QByteArray cursorTheme = qgetenv("XCURSOR_THEME"); + if (cursorTheme.isEmpty()) + cursorTheme = QByteArray("default"); + QByteArray cursorSizeFromEnv = qgetenv("XCURSOR_SIZE"); + bool hasCursorSize = false; + int cursorSize = cursorSizeFromEnv.toInt(&hasCursorSize); + if (!hasCursorSize || cursorSize <= 0) + cursorSize = 32; + mCursorTheme = wl_cursor_theme_load(cursorTheme, cursorSize, mDisplay->shm()); + initCursorMap(); +} + +QWaylandCursor::~QWaylandCursor() +{ + wl_cursor_theme_destroy(mCursorTheme); +} + +struct wl_cursor_image *QWaylandCursor::cursorImage(Qt::CursorShape newShape) +{ + struct wl_cursor *waylandCursor = 0; + + /* Hide cursor */ + if (newShape == Qt::BlankCursor) + { + mDisplay->setCursor(NULL, NULL); + return NULL; + } + + if (newShape < Qt::BitmapCursor) { + waylandCursor = requestCursor((WaylandCursor)newShape); + } else if (newShape == Qt::BitmapCursor) { + //TODO: Bitmap cursor logic + } else { + //TODO: Custom cursor logic (for resize arrows) + } + + if (!waylandCursor) { + qDebug("Could not find cursor for shape %d", newShape); + return NULL; + } + + struct wl_cursor_image *image = waylandCursor->images[0]; + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + if (!buffer) { + qDebug("Could not find buffer for cursor"); + return NULL; + } + + return image; +} + +void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window) +{ + Q_UNUSED(window) + + const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor; + + struct wl_cursor_image *image = cursorImage(newShape); + if (!image) { + return; + } + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + mDisplay->setCursor(buffer, image); +} + +void QWaylandDisplay::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image) +{ + /* Qt doesn't tell us which input device we should set the cursor + * for, so set it for all devices. */ + for (int i = 0; i < mInputDevices.count(); i++) { + QWaylandInputDevice *inputDevice = mInputDevices.at(i); + inputDevice->setCursor(buffer, image); + } +} + +QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const +{ + return mInputDevices.isEmpty() ? 0 : mInputDevices.first(); +} + +void QWaylandCursor::pointerEvent(const QMouseEvent &event) +{ + mLastPos = event.globalPos(); +} + +QPoint QWaylandCursor::pos() const +{ + return mLastPos; +} + +void QWaylandCursor::setPos(const QPoint &pos) +{ + Q_UNUSED(pos); + qWarning() << "QWaylandCursor::setPos: not implemented"; +} + +wl_cursor *QWaylandCursor::requestCursor(WaylandCursor shape) +{ + struct wl_cursor *cursor = mCursors.value(shape, 0); + + //If the cursor has not been loaded already, load it + if (!cursor) { + QList<QByteArray> cursorNames = mCursorNamesMap.values(shape); + foreach (QByteArray name, cursorNames) { + cursor = wl_cursor_theme_get_cursor(mCursorTheme, name.constData()); + if (cursor) { + mCursors.insert(shape, cursor); + break; + } + } + } + + //If there still no cursor for a shape, use the default cursor + if (!cursor && shape != ArrowCursor) { + cursor = requestCursor(ArrowCursor); + } + + return cursor; +} + + +void QWaylandCursor::initCursorMap() +{ + //Fill the cursor name map will the table of xcursor names + mCursorNamesMap.insert(ArrowCursor, "left_ptr"); + mCursorNamesMap.insert(ArrowCursor, "default"); + mCursorNamesMap.insert(ArrowCursor, "top_left_arrow"); + mCursorNamesMap.insert(ArrowCursor, "left_arrow"); + + mCursorNamesMap.insert(UpArrowCursor, "up_arrow"); + + mCursorNamesMap.insert(CrossCursor, "cross"); + + mCursorNamesMap.insert(WaitCursor, "wait"); + mCursorNamesMap.insert(WaitCursor, "watch"); + mCursorNamesMap.insert(WaitCursor, "0426c94ea35c87780ff01dc239897213"); + + mCursorNamesMap.insert(IBeamCursor, "ibeam"); + mCursorNamesMap.insert(IBeamCursor, "text"); + mCursorNamesMap.insert(IBeamCursor, "xterm"); + + mCursorNamesMap.insert(SizeVerCursor, "size_ver"); + mCursorNamesMap.insert(SizeVerCursor, "ns-resize"); + mCursorNamesMap.insert(SizeVerCursor, "v_double_arrow"); + mCursorNamesMap.insert(SizeVerCursor, "00008160000006810000408080010102"); + + mCursorNamesMap.insert(SizeHorCursor, "size_hor"); + mCursorNamesMap.insert(SizeHorCursor, "ew-resize"); + mCursorNamesMap.insert(SizeHorCursor, "h_double_arrow"); + mCursorNamesMap.insert(SizeHorCursor, "028006030e0e7ebffc7f7070c0600140"); + + mCursorNamesMap.insert(SizeBDiagCursor, "size_bdiag"); + mCursorNamesMap.insert(SizeBDiagCursor, "nesw-resize"); + mCursorNamesMap.insert(SizeBDiagCursor, "50585d75b494802d0151028115016902"); + mCursorNamesMap.insert(SizeBDiagCursor, "fcf1c3c7cd4491d801f1e1c78f100000"); + + mCursorNamesMap.insert(SizeFDiagCursor, "size_fdiag"); + mCursorNamesMap.insert(SizeFDiagCursor, "nwse-resize"); + mCursorNamesMap.insert(SizeFDiagCursor, "38c5dff7c7b8962045400281044508d2"); + mCursorNamesMap.insert(SizeFDiagCursor, "c7088f0f3e6c8088236ef8e1e3e70000"); + + mCursorNamesMap.insert(SizeAllCursor, "size_all"); + + mCursorNamesMap.insert(SplitVCursor, "split_v"); + mCursorNamesMap.insert(SplitVCursor, "row-resize"); + mCursorNamesMap.insert(SplitVCursor, "sb_v_double_arrow"); + mCursorNamesMap.insert(SplitVCursor, "2870a09082c103050810ffdffffe0204"); + mCursorNamesMap.insert(SplitVCursor, "c07385c7190e701020ff7ffffd08103c"); + + mCursorNamesMap.insert(SplitHCursor, "split_h"); + mCursorNamesMap.insert(SplitHCursor, "col-resize"); + mCursorNamesMap.insert(SplitHCursor, "sb_h_double_arrow"); + mCursorNamesMap.insert(SplitHCursor, "043a9f68147c53184671403ffa811cc5"); + mCursorNamesMap.insert(SplitHCursor, "14fef782d02440884392942c11205230"); + + mCursorNamesMap.insert(PointingHandCursor, "pointing_hand"); + mCursorNamesMap.insert(PointingHandCursor, "pointer"); + mCursorNamesMap.insert(PointingHandCursor, "hand1"); + mCursorNamesMap.insert(PointingHandCursor, "e29285e634086352946a0e7090d73106"); + + mCursorNamesMap.insert(ForbiddenCursor, "forbidden"); + mCursorNamesMap.insert(ForbiddenCursor, "not-allowed"); + mCursorNamesMap.insert(ForbiddenCursor, "crossed_circle"); + mCursorNamesMap.insert(ForbiddenCursor, "circle"); + mCursorNamesMap.insert(ForbiddenCursor, "03b6e0fcb3499374a867c041f52298f0"); + + mCursorNamesMap.insert(WhatsThisCursor, "whats_this"); + mCursorNamesMap.insert(WhatsThisCursor, "help"); + mCursorNamesMap.insert(WhatsThisCursor, "question_arrow"); + mCursorNamesMap.insert(WhatsThisCursor, "5c6cd98b3f3ebcb1f9c7f1c204630408"); + mCursorNamesMap.insert(WhatsThisCursor, "d9ce0ab605698f320427677b458ad60b"); + + mCursorNamesMap.insert(BusyCursor, "left_ptr_watch"); + mCursorNamesMap.insert(BusyCursor, "half-busy"); + mCursorNamesMap.insert(BusyCursor, "progress"); + mCursorNamesMap.insert(BusyCursor, "00000000000000020006000e7e9ffc3f"); + mCursorNamesMap.insert(BusyCursor, "08e8e1c95fe2fc01f976f1e063a24ccd"); + + mCursorNamesMap.insert(OpenHandCursor, "openhand"); + mCursorNamesMap.insert(OpenHandCursor, "fleur"); + mCursorNamesMap.insert(OpenHandCursor, "5aca4d189052212118709018842178c0"); + mCursorNamesMap.insert(OpenHandCursor, "9d800788f1b08800ae810202380a0822"); + + mCursorNamesMap.insert(ClosedHandCursor, "closedhand"); + mCursorNamesMap.insert(ClosedHandCursor, "grabbing"); + mCursorNamesMap.insert(ClosedHandCursor, "208530c400c041818281048008011002"); + + mCursorNamesMap.insert(DragCopyCursor, "dnd-copy"); + mCursorNamesMap.insert(DragCopyCursor, "copy"); + + mCursorNamesMap.insert(DragMoveCursor, "dnd-move"); + mCursorNamesMap.insert(DragMoveCursor, "move"); + + mCursorNamesMap.insert(DragLinkCursor, "dnd-link"); + mCursorNamesMap.insert(DragLinkCursor, "link"); + + mCursorNamesMap.insert(ResizeNorthCursor, "n-resize"); + mCursorNamesMap.insert(ResizeNorthCursor, "top_side"); + + mCursorNamesMap.insert(ResizeSouthCursor, "s-resize"); + mCursorNamesMap.insert(ResizeSouthCursor, "bottom_side"); + + mCursorNamesMap.insert(ResizeEastCursor, "e-resize"); + mCursorNamesMap.insert(ResizeEastCursor, "right_side"); + + mCursorNamesMap.insert(ResizeWestCursor, "w-resize"); + mCursorNamesMap.insert(ResizeWestCursor, "left_side"); + + mCursorNamesMap.insert(ResizeNorthWestCursor, "nw-resize"); + mCursorNamesMap.insert(ResizeNorthWestCursor, "top_left_corner"); + + mCursorNamesMap.insert(ResizeSouthEastCursor, "se-resize"); + mCursorNamesMap.insert(ResizeSouthEastCursor, "bottom_right_corner"); + + mCursorNamesMap.insert(ResizeNorthEastCursor, "ne-resize"); + mCursorNamesMap.insert(ResizeNorthEastCursor, "top_right_corner"); + + mCursorNamesMap.insert(ResizeSouthWestCursor, "sw-resize"); + mCursorNamesMap.insert(ResizeSouthWestCursor, "bottom_left_corner"); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandcursor.h b/src/client/qwaylandcursor.h new file mode 100644 index 00000000..894d322a --- /dev/null +++ b/src/client/qwaylandcursor.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDCURSOR_H +#define QWAYLANDCURSOR_H + +#include <qpa/qplatformcursor.h> +#include <QtCore/QMap> +#include <QtWaylandClient/qwaylandclientexport.h> + +struct wl_cursor; +struct wl_cursor_image; +struct wl_cursor_theme; + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandScreen; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandCursor : public QPlatformCursor +{ +public: + QWaylandCursor(QWaylandScreen *screen); + ~QWaylandCursor(); + + void changeCursor(QCursor *cursor, QWindow *window); + void pointerEvent(const QMouseEvent &event); + QPoint pos() const; + void setPos(const QPoint &pos); + + struct wl_cursor_image *cursorImage(Qt::CursorShape shape); + +private: + enum WaylandCursor { + ArrowCursor = Qt::ArrowCursor, + UpArrowCursor, + CrossCursor, + WaitCursor, + IBeamCursor, + SizeVerCursor, + SizeHorCursor, + SizeBDiagCursor, + SizeFDiagCursor, + SizeAllCursor, + BlankCursor, + SplitVCursor, + SplitHCursor, + PointingHandCursor, + ForbiddenCursor, + WhatsThisCursor, + BusyCursor, + OpenHandCursor, + ClosedHandCursor, + DragCopyCursor, + DragMoveCursor, + DragLinkCursor, + ResizeNorthCursor = Qt::CustomCursor + 1, + ResizeSouthCursor, + ResizeEastCursor, + ResizeWestCursor, + ResizeNorthWestCursor, + ResizeSouthEastCursor, + ResizeNorthEastCursor, + ResizeSouthWestCursor + }; + + struct wl_cursor* requestCursor(WaylandCursor shape); + void initCursorMap(); + QWaylandDisplay *mDisplay; + struct wl_cursor_theme *mCursorTheme; + QPoint mLastPos; + QMap<WaylandCursor, wl_cursor *> mCursors; + QMultiMap<WaylandCursor, QByteArray> mCursorNamesMap; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDCURSOR_H diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp new file mode 100644 index 00000000..2a70a338 --- /dev/null +++ b/src/client/qwaylanddatadevice.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylanddatadevice.h" + +#include "qwaylanddatadevicemanager.h" +#include "qwaylanddataoffer.h" +#include "qwaylanddatasource.h" +#include "qwaylanddnd.h" +#include "qwaylandinputdevice.h" + +#include <QtCore/QMimeData> +#include <QtGui/QGuiApplication> +#include <QtGui/private/qguiapplication_p.h> + +#include <qpa/qplatformclipboard.h> +#include <qpa/qplatformdrag.h> +#include <qpa/qwindowsysteminterface.h> + +#include <QDebug> + +QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWaylandInputDevice *inputDevice) + : QtWayland::wl_data_device(manager->get_data_device(inputDevice->wl_seat())) + , m_display(manager->display()) + , m_enterSerial(0) + , m_dragWindow(0) + , m_dragPoint() + , m_dragOffer() + , m_selectionOffer() +{ +} + +QWaylandDataDevice::~QWaylandDataDevice() +{ +} + +QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const +{ + return m_selectionOffer.data(); +} + +QWaylandDataSource *QWaylandDataDevice::selectionSource() const +{ + return m_selectionSource.data(); +} + +void QWaylandDataDevice::setSelectionSource(QWaylandDataSource *source) +{ + m_selectionSource.reset(source); + set_selection(source ? source->object() : 0, 0 /* TODO m_display->serial() */); +} + +QWaylandDataOffer *QWaylandDataDevice::dragOffer() const +{ + return m_dragOffer.data(); +} + +void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) +{ + m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); + + QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus(); + + start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial()); +} + +void QWaylandDataDevice::cancelDrag() +{ + m_dragSource.reset(); +} + +void QWaylandDataDevice::data_device_data_offer(struct ::wl_data_offer *id) +{ + QWaylandDataOffer *offer = new QWaylandDataOffer(m_display, id); +} + +void QWaylandDataDevice::data_device_drop() +{ + QDrag *drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->currentDrag(); + + qDebug() << Q_FUNC_INFO << drag << m_dragOffer.data(); + + QMimeData *dragData; + Qt::DropActions supportedActions; + if (drag) { + dragData = drag->mimeData(); + supportedActions = drag->supportedActions(); + } else if (m_dragOffer) { + dragData = m_dragOffer->mimeData(); + supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + } else { + return; + } + + QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_dragWindow, dragData, m_dragPoint, supportedActions); + + if (drag) { + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response); + } +} + +void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id) +{ + m_enterSerial = serial; + m_dragWindow = QWaylandWindow::fromWlSurface(surface)->window(); + m_dragPoint = QPoint(wl_fixed_to_int(x), wl_fixed_to_int(y)); + + QDrag *drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->currentDrag(); + + QMimeData *dragData; + Qt::DropActions supportedActions; + if (drag) { + dragData = drag->mimeData(); + supportedActions = drag->supportedActions(); + } else { + m_dragOffer.reset(static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id))); + if (m_dragOffer) { + dragData = m_dragOffer->mimeData(); + supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + } + } + + const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions); + + if (drag) { + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response); + } else { + if (response.isAccepted()) { + wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData()); + } else { + wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, 0); + } + } +} + +void QWaylandDataDevice::data_device_leave() +{ + QWindowSystemInterface::handleDrag(m_dragWindow, 0, QPoint(), Qt::IgnoreAction); + + QDrag *drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->currentDrag(); + if (!drag) { + m_dragOffer.reset(); + } +} + +void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixed_t y) +{ + Q_UNUSED(time); + + QDrag *drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->currentDrag(); + + if (!drag && !m_dragOffer) + return; + + m_dragPoint = QPoint(wl_fixed_to_int(x), wl_fixed_to_int(y)); + + QMimeData *dragData; + Qt::DropActions supportedActions; + if (drag) { + dragData = drag->mimeData(); + supportedActions = drag->supportedActions(); + } else { + dragData = m_dragOffer->mimeData(); + supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction; + } + + QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions); + + if (drag) { + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response); + } else { + if (response.isAccepted()) { + wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData()); + } else { + wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, 0); + } + } +} + +void QWaylandDataDevice::data_device_selection(wl_data_offer *id) +{ + if (id) + m_selectionOffer.reset(static_cast<QWaylandDataOffer *>(wl_data_offer_get_user_data(id))); + else + m_selectionOffer.reset(); + + QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard); +} + +void QWaylandDataDevice::selectionSourceCancelled() +{ + m_selectionSource.reset(); + QGuiApplicationPrivate::platformIntegration()->clipboard()->emitChanged(QClipboard::Clipboard); +} + +void QWaylandDataDevice::dragSourceCancelled() +{ + m_dragSource.reset(); + +} + +void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType) +{ + static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType); +} diff --git a/src/client/qwaylanddatadevice.h b/src/client/qwaylanddatadevice.h new file mode 100644 index 00000000..e258d877 --- /dev/null +++ b/src/client/qwaylanddatadevice.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDDATADEVICE_H +#define QWAYLANDDATADEVICE_H + +#include "qwaylanddisplay.h" + +QT_BEGIN_NAMESPACE + +class QMimeData; +class QWaylandDataDeviceManager; +class QWaylandDataOffer; +class QWaylandDataSource; +class QWindow; + +class QWaylandDataDevice : public QObject, public QtWayland::wl_data_device +{ + Q_OBJECT +public: + QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWaylandInputDevice *inputDevice); + ~QWaylandDataDevice(); + + QWaylandDataOffer *selectionOffer() const; + QWaylandDataSource *selectionSource() const; + void setSelectionSource(QWaylandDataSource *source); + + QWaylandDataOffer *dragOffer() const; + void startDrag(QMimeData *mimeData, QWaylandWindow *icon); + void cancelDrag(); + +protected: + void data_device_data_offer(struct ::wl_data_offer *id) Q_DECL_OVERRIDE; + void data_device_drop() Q_DECL_OVERRIDE; + void data_device_enter(uint32_t serial, struct ::wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct ::wl_data_offer *id) Q_DECL_OVERRIDE; + void data_device_leave() Q_DECL_OVERRIDE; + void data_device_motion(uint32_t time, wl_fixed_t x, wl_fixed_t y) Q_DECL_OVERRIDE; + void data_device_selection(struct ::wl_data_offer *id) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void selectionSourceCancelled(); + void dragSourceCancelled(); + void dragSourceTargetChanged(const QString &mimeType); + +private: + QWaylandDisplay *m_display; + + uint32_t m_enterSerial; + QWindow *m_dragWindow; + QPoint m_dragPoint; + QScopedPointer<QWaylandDataOffer> m_dragOffer; + QScopedPointer<QWaylandDataOffer> m_selectionOffer; + QScopedPointer<QWaylandDataSource> m_selectionSource; + + QScopedPointer<QWaylandDataSource> m_dragSource; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDATADEVICE_H diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp new file mode 100644 index 00000000..4a96dbce --- /dev/null +++ b/src/client/qwaylanddatadevicemanager.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 "qwaylanddatadevicemanager.h" + +#include "qwaylandinputdevice.h" +#include "qwaylanddatadevice.h" +#include "qwaylanddataoffer.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id) + : wl_data_device_manager(display->wl_registry(), id) + , m_display(display) +{ + // Create transfer devices for all input devices. + // ### This only works if we get the global before all devices and is surely wrong when hotplugging. + QList<QWaylandInputDevice *> inputDevices = m_display->inputDevices(); + for (int i = 0; i < inputDevices.size();i++) { + inputDevices.at(i)->setDataDevice(getDataDevice(inputDevices.at(i))); + } +} + +QWaylandDataDeviceManager::~QWaylandDataDeviceManager() +{ + wl_data_device_manager_destroy(object()); +} + +QWaylandDataDevice *QWaylandDataDeviceManager::getDataDevice(QWaylandInputDevice *inputDevice) +{ + return new QWaylandDataDevice(this, inputDevice); +} + +QWaylandDisplay *QWaylandDataDeviceManager::display() const +{ + return m_display; +} + + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddatadevicemanager.h b/src/client/qwaylanddatadevicemanager.h new file mode 100644 index 00000000..6b3ad177 --- /dev/null +++ b/src/client/qwaylanddatadevicemanager.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDATADEVICEMANAGER_H +#define QWAYLANDDATADEVICEMANAGER_H + +#include "qwaylanddisplay.h" + +QT_BEGIN_NAMESPACE + +class QWaylandDataDevice; +class QWaylandDataSource; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager +{ +public: + QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id); + ~QWaylandDataDeviceManager(); + + QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice); + + QWaylandDisplay *display() const; + +private: + struct wl_data_device_manager *m_data_device_manager; + QWaylandDisplay *m_display; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDATADEVICEMANAGER_H diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp new file mode 100644 index 00000000..e237d0b9 --- /dev/null +++ b/src/client/qwaylanddataoffer.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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 "qwaylanddataoffer.h" +#include "qwaylanddatadevicemanager.h" + +#include <QtCore/private/qcore_unix_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <qpa/qplatformclipboard.h> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer) + : QtWayland::wl_data_offer(offer) + , m_mimeData(new QWaylandMimeData(this, display)) +{ +} + +QWaylandDataOffer::~QWaylandDataOffer() +{ + destroy(); +} + + +QString QWaylandDataOffer::firstFormat() const +{ + if (m_mimeData->formats().isEmpty()) + return QString(); + + return m_mimeData->formats().first(); +} + +QMimeData *QWaylandDataOffer::mimeData() +{ + return m_mimeData.data(); +} + +void QWaylandDataOffer::data_offer_offer(const QString &mime_type) +{ + m_mimeData->appendFormat(mime_type); +} + +QWaylandMimeData::QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display) + : QInternalMimeData() + , m_dataOffer(dataOffer) + , m_display(display) + , m_offered_mime_types() +{ +} + +QWaylandMimeData::~QWaylandMimeData() +{ +} + +void QWaylandMimeData::appendFormat(const QString &mimeType) +{ + m_offered_mime_types.append(mimeType); +} + +bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const +{ + return m_offered_mime_types.contains(mimeType); +} + +QStringList QWaylandMimeData::formats_sys() const +{ + return m_offered_mime_types; +} + +QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const +{ + Q_UNUSED(type); + + if (m_offered_mime_types.isEmpty()) + return QVariant(); + + int pipefd[2]; + if (qt_safe_pipe(pipefd, O_CLOEXEC) == -1) { + qWarning("QWaylandMimeData: pipe() failed"); + return QVariant(); + } + + m_dataOffer->receive(mimeType, pipefd[1]); + close(pipefd[1]); + +// m_display->forceRoundTrip(); + + QByteArray content; + char buf[4096]; + int n; + while ((n = QT_READ(pipefd[0], &buf, sizeof buf)) > 0) { + content.append(buf, n); + } + close(pipefd[0]); + + return content; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddataoffer.h b/src/client/qwaylanddataoffer.h new file mode 100644 index 00000000..7dc3baa3 --- /dev/null +++ b/src/client/qwaylanddataoffer.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDATAOFFER_H +#define QWAYLANDDATAOFFER_H + +#include "qwaylanddisplay.h" + +#include <QtGui/private/qdnd_p.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandMimeData; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDataOffer : public QtWayland::wl_data_offer +{ +public: + explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer); + ~QWaylandDataOffer(); + + QString firstFormat() const; + + QMimeData *mimeData(); + +protected: + void data_offer_offer(const QString &mime_type) Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWaylandMimeData> m_mimeData; +}; + + +class QWaylandMimeData : public QInternalMimeData { +public: + explicit QWaylandMimeData(QWaylandDataOffer *dataOffer, QWaylandDisplay *display); + ~QWaylandMimeData(); + + void appendFormat(const QString &mimeType); + +protected: + bool hasFormat_sys(const QString &mimeType) const Q_DECL_OVERRIDE; + QStringList formats_sys() const Q_DECL_OVERRIDE; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const Q_DECL_OVERRIDE; + +private: + mutable QWaylandDataOffer *m_dataOffer; + QWaylandDisplay *m_display; + QStringList m_offered_mime_types; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp new file mode 100644 index 00000000..ba4b6811 --- /dev/null +++ b/src/client/qwaylanddatasource.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 "qwaylanddatasource.h" +#include "qwaylanddataoffer.h" +#include "qwaylanddatadevicemanager.h" +#include "qwaylandinputdevice.h" +#include "qwaylandmimehelper.h" + +#include <QtCore/QFile> + +#include <QtCore/QDebug> + +#include <unistd.h> + +QT_BEGIN_NAMESPACE + +QWaylandDataSource::QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData) + : QtWayland::wl_data_source(dataDeviceManager->create_data_source()) + , m_mime_data(mimeData) +{ + if (!mimeData) + return; + Q_FOREACH (const QString &format, mimeData->formats()) { + offer(format); + } +} + +QWaylandDataSource::~QWaylandDataSource() +{ + destroy(); +} + +QMimeData * QWaylandDataSource::mimeData() const +{ + return m_mime_data; +} + +void QWaylandDataSource::data_source_cancelled() +{ + Q_EMIT cancelled(); +} + +void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd) +{ + QByteArray content = QWaylandMimeHelper::getByteArray(m_mime_data, mime_type); + if (!content.isEmpty()) { + write(fd, content.constData(), content.size()); + } + close(fd); +} + +void QWaylandDataSource::data_source_target(const QString &mime_type) +{ + Q_EMIT targetChanged(mime_type); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddatasource.h b/src/client/qwaylanddatasource.h new file mode 100644 index 00000000..670a8872 --- /dev/null +++ b/src/client/qwaylanddatasource.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDATASOURCE_H +#define QWAYLANDDATASOURCE_H + +#include "qwaylanddisplay.h" + +QT_BEGIN_NAMESPACE + +class QMimeData; +class QWaylandDataDeviceManager; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDataSource : public QObject, public QtWayland::wl_data_source +{ + Q_OBJECT +public: + QWaylandDataSource(QWaylandDataDeviceManager *dataDeviceManager, QMimeData *mimeData); + ~QWaylandDataSource(); + + QMimeData *mimeData() const; + +Q_SIGNALS: + void targetChanged(const QString &mime_type); + void cancelled(); + +protected: + void data_source_cancelled() Q_DECL_OVERRIDE; + void data_source_send(const QString &mime_type, int32_t fd) Q_DECL_OVERRIDE; + void data_source_target(const QString &mime_type) Q_DECL_OVERRIDE; + +private: + QWaylandDisplay *m_display; + QMimeData *m_mime_data; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDATASOURCE_H diff --git a/src/client/qwaylanddecoration.cpp b/src/client/qwaylanddecoration.cpp new file mode 100644 index 00000000..74c01f93 --- /dev/null +++ b/src/client/qwaylanddecoration.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** 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 "qwaylanddecoration.h" + +#include "qwaylandwindow.h" +#include "qwaylandshellsurface.h" +#include "qwaylandinputdevice.h" +#include "qwaylandscreen.h" + +#include <QtGui/QGuiApplication> +#include <QtGui/QImage> +#include <QtGui/QCursor> +#include <QtGui/QPainter> +#include <QtGui/QPalette> +#include <QtGui/QLinearGradient> + +QT_BEGIN_NAMESPACE + +#define BUTTON_SPACING 5 + +#ifndef QT_NO_IMAGEFORMAT_XPM +# define BUTTON_WIDTH 10 + +static const char * const qt_close_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +".##....##.", +"..##..##..", +"...####...", +"....##....", +"...####...", +"..##..##..", +".##....##.", +"..........", +".........."}; + +static const char * const qt_maximize_xpm[]={ +"10 10 2 1", +"# c #000000", +". c None", +"#########.", +"#########.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#.......#.", +"#########.", +".........."}; + +static const char * const qt_minimize_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +"..........", +".#######..", +".#######..", +".........."}; + +static const char * const qt_normalizeup_xpm[] = { +"10 10 2 1", +"# c #000000", +". c None", +"...######.", +"...######.", +"...#....#.", +".######.#.", +".######.#.", +".#....###.", +".#....#...", +".#....#...", +".######...", +".........."}; +#else +# define BUTTON_WIDTH 22 +#endif + +QWaylandDecoration::QWaylandDecoration(QWaylandWindow *window) + : m_window(window->window()) + , m_wayland_window(window) + , m_isDirty(true) + , m_decorationContentImage(0) + , m_margins(3,30,3,3) + , m_mouseButtons(Qt::NoButton) +{ + m_wayland_window->setDecoration(this); + + QPalette palette; + m_foregroundColor = palette.color(QPalette::Active, QPalette::HighlightedText); + m_backgroundColor = palette.color(QPalette::Active, QPalette::Highlight); + + QTextOption option(Qt::AlignHCenter | Qt::AlignVCenter); + option.setWrapMode(QTextOption::NoWrap); + m_windowTitle.setTextOption(option); +} + +QWaylandDecoration::~QWaylandDecoration() +{ + m_wayland_window->setDecoration(0); +} + +const QImage &QWaylandDecoration::contentImage() +{ + if (m_isDirty) { + //Update the decoration backingstore + + m_decorationContentImage = QImage(window()->frameGeometry().size(), QImage::Format_ARGB32_Premultiplied); + m_decorationContentImage.fill(Qt::transparent); + this->paint(&m_decorationContentImage); + + m_isDirty = false; + } + + return m_decorationContentImage; +} + +void QWaylandDecoration::update() +{ + m_isDirty = true; +} + +void QWaylandDecoration::paint(QPaintDevice *device) +{ + QRect surfaceRect(QPoint(), window()->frameGeometry().size()); + QRect clips[] = + { + QRect(0, 0, surfaceRect.width(), margins().top()), + QRect(0, surfaceRect.height() - margins().bottom(), surfaceRect.width(), margins().bottom()), + QRect(0, margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()), + QRect(surfaceRect.width() - margins().right(), margins().top(), margins().left(), surfaceRect.height() - margins().top() - margins().bottom()) + }; + + QRect top = clips[0]; + + QPainter p(device); + p.setRenderHint(QPainter::Antialiasing); + + // Title bar + QPoint gradCenter(top.center()+ QPoint(30, 60)); + QLinearGradient grad(top.topLeft(), top.bottomLeft()); + QColor base(backgroundColor()); + grad.setColorAt(0, base.lighter(100)); + grad.setColorAt(1, base.darker(180)); + QPainterPath roundedRect; + roundedRect.addRoundedRect(surfaceRect, 6, 6); + for (int i = 0; i < 4; ++i) { + p.save(); + p.setClipRect(clips[i]); + p.fillPath(roundedRect, grad); + p.restore(); + } + + // Window icon + QIcon icon = m_wayland_window->windowIcon(); + if (!icon.isNull()) { + QPixmap pixmap = icon.pixmap(QSize(128, 128)); + QPixmap scaled = pixmap.scaled(22, 22, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + QRectF iconRect(0, 0, 22, 22); + p.drawPixmap(iconRect.adjusted(margins().left() + BUTTON_SPACING, 4, + margins().left() + BUTTON_SPACING, 4), + scaled, iconRect); + } + + // Window title + QString windowTitleText = window()->title(); + if (!windowTitleText.isEmpty()) { + if (m_windowTitle.text() != windowTitleText) { + m_windowTitle.setText(windowTitleText); + m_windowTitle.prepare(); + } + + QRect titleBar = top; + titleBar.setLeft(m_margins.left() + BUTTON_SPACING + + (icon.isNull() ? 0 : 22 + BUTTON_SPACING)); + titleBar.setRight(minimizeButtonRect().left() - BUTTON_SPACING); + + p.save(); + p.setClipRect(titleBar); + p.setPen(m_foregroundColor); + QSizeF size = m_windowTitle.size(); + int dx = (top.width() - size.width()) /2; + int dy = (top.height()- size.height()) /2; + QFont font = p.font(); + font.setBold(true); + p.setFont(font); + QPoint windowTitlePoint(top.topLeft().x() + dx, + top.topLeft().y() + dy); + p.drawStaticText(windowTitlePoint,m_windowTitle); + p.restore(); + } + +#ifndef QT_NO_IMAGEFORMAT_XPM + p.save(); + + // Close button + QPixmap closePixmap(qt_close_xpm); + p.drawPixmap(closeButtonRect(), closePixmap, closePixmap.rect()); + + // Maximize button + QPixmap maximizePixmap(m_wayland_window->isMaximized() + ? qt_normalizeup_xpm : qt_maximize_xpm); + p.drawPixmap(maximizeButtonRect(), maximizePixmap, maximizePixmap.rect()); + + // Minimize button + QPixmap minimizePixmap(qt_minimize_xpm); + p.drawPixmap(minimizeButtonRect(), minimizePixmap, minimizePixmap.rect()); + + p.restore(); +#else + // We don't need antialiasing from now on + p.setRenderHint(QPainter::Antialiasing, false); + + QRectF rect; + + // Default pen + QPen pen(m_foregroundColor); + p.setPen(pen); + + // Close button + p.save(); + rect = closeButtonRect(); + p.drawRect(rect); + qreal crossSize = rect.height() / 2; + QPointF crossCenter(rect.center()); + QRectF crossRect(crossCenter.x() - crossSize / 2, crossCenter.y() - crossSize / 2, crossSize, crossSize); + pen.setWidth(2); + p.setPen(pen); + p.drawLine(crossRect.topLeft(), crossRect.bottomRight()); + p.drawLine(crossRect.bottomLeft(), crossRect.topRight()); + p.restore(); + + // Maximize button + p.save(); + p.drawRect(maximizeButtonRect()); + rect = maximizeButtonRect().adjusted(5, 5, -5, -5); + if (m_wayland_window->isMaximized()) { + QRectF rect1 = rect.adjusted(rect.width() / 3, 0, 0, -rect.height() / 3); + QRectF rect2 = rect.adjusted(0, rect.height() / 4, -rect.width() / 4, 0); + p.drawRect(rect1); + p.drawRect(rect2); + } else { + p.setPen(m_foregroundColor); + p.drawRect(rect); + p.drawLine(rect.left(), rect.top() + 1, rect.right(), rect.top() + 1); + } + p.restore(); + + // Minimize button + p.save(); + p.drawRect(minimizeButtonRect()); + rect = minimizeButtonRect().adjusted(5, 5, -5, -5); + pen.setWidth(2); + p.setPen(pen); + p.drawLine(rect.bottomLeft(), rect.bottomRight()); + p.restore(); +#endif +} + +bool QWaylandDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) + +{ + Q_UNUSED(global); + + // Figure out what area mouse is in + if (closeButtonRect().contains(local) && isLeftClicked(b)) { + QWindowSystemInterface::handleCloseEvent(m_window); + } else if (maximizeButtonRect().contains(local) && isLeftClicked(b)) { + m_window->setWindowState(m_wayland_window->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); + } else if (minimizeButtonRect().contains(local) && isLeftClicked(b)) { + m_window->setWindowState(Qt::WindowMinimized); + } else if (local.y() <= m_margins.top()) { + processMouseTop(inputDevice,local,b,mods); + } else if (local.y() > m_window->height() - m_margins.bottom() + m_margins.top()) { + processMouseBottom(inputDevice,local,b,mods); + } else if (local.x() <= m_margins.left()) { + processMouseLeft(inputDevice,local,b,mods); + } else if (local.x() > m_window->width() - m_margins.right() + m_margins.left()) { + processMouseRight(inputDevice,local,b,mods); + } else { + m_wayland_window->restoreMouseCursor(inputDevice); + m_mouseButtons = b; + return false; + } + + m_mouseButtons = b; + return true; +} + +bool QWaylandDecoration::inMouseButtonPressedState() const +{ + return m_mouseButtons & Qt::NoButton; +} + +void QWaylandDecoration::startResize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize resize, Qt::MouseButtons buttons) +{ + if (isLeftClicked(buttons)) { + m_wayland_window->shellSurface()->resize(inputDevice, resize); + inputDevice->removeMouseButtonFromState(Qt::LeftButton); + } +} + +void QWaylandDecoration::startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons) +{ + if (isLeftClicked(buttons)) { + m_wayland_window->shellSurface()->move(inputDevice); + inputDevice->removeMouseButtonFromState(Qt::LeftButton); + } +} + +void QWaylandDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(mods); + if (local.y() <= m_margins.bottom()) { + if (local.x() <= margins().left()) { + //top left bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_LEFT,b); + } else if (local.x() > m_window->width() - margins().right()) { + //top right bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP_RIGHT,b); + } else { + //top reszie bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SplitVCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_TOP,b); + } + } else { + m_wayland_window->restoreMouseCursor(inputDevice); + startMove(inputDevice,b); + } + +} + +void QWaylandDecoration::processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(mods); + if (local.x() <= margins().left()) { + //bottom left bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SizeBDiagCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT,b); + } else if (local.x() > m_window->width() - margins().right()) { + //bottom right bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SizeFDiagCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT,b); + } else { + //bottom bit + m_wayland_window->setMouseCursor(inputDevice, Qt::SplitVCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_BOTTOM,b); + } +} + +void QWaylandDecoration::processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(local); + Q_UNUSED(mods); + m_wayland_window->setMouseCursor(inputDevice, Qt::SplitHCursor); + startResize(inputDevice,WL_SHELL_SURFACE_RESIZE_LEFT,b); +} + +void QWaylandDecoration::processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(local); + Q_UNUSED(mods); + m_wayland_window->setMouseCursor(inputDevice, Qt::SplitHCursor); + startResize(inputDevice, WL_SHELL_SURFACE_RESIZE_RIGHT,b); +} + +bool QWaylandDecoration::isLeftClicked(Qt::MouseButtons newMouseButtonState) +{ + if ((!m_mouseButtons & Qt::LeftButton) && (newMouseButtonState & Qt::LeftButton)) + return true; + return false; +} + +bool QWaylandDecoration::isLeftReleased(Qt::MouseButtons newMouseButtonState) +{ + if ((m_mouseButtons & Qt::LeftButton) && !(newMouseButtonState & Qt::LeftButton)) + return true; + return false; +} + +QRectF QWaylandDecoration::closeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH - BUTTON_SPACING * 2, + (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +QRectF QWaylandDecoration::maximizeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 2 - BUTTON_SPACING * 3, + (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +QRectF QWaylandDecoration::minimizeButtonRect() const +{ + return QRectF(window()->frameGeometry().width() - BUTTON_WIDTH * 3 - BUTTON_SPACING * 4, + (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); +} + +void QWaylandDecoration::setForegroundColor(const QColor &c) +{ + m_foregroundColor = c; +} + +void QWaylandDecoration::setBackgroundColor(const QColor &c) +{ + m_backgroundColor = c; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddecoration.h b/src/client/qwaylanddecoration.h new file mode 100644 index 00000000..f9972358 --- /dev/null +++ b/src/client/qwaylanddecoration.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDECORATION_H +#define QWAYLANDDECORATION_H + +#include <QtCore/QMargins> +#include <QtCore/QPointF> +#include <QtGui/QGuiApplication> +#include <QtGui/QCursor> +#include <QtGui/QColor> +#include <QtGui/QStaticText> +#include <QtGui/QImage> +#include <QtWaylandClient/qwaylandclientexport.h> + +#include <wayland-client.h> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +class QWindow; +class QPaintDevice; +class QPainter; +class QEvent; +class QWaylandScreen; +class QWaylandWindow; +class QWaylandInputDevice; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDecoration +{ +public: + QWaylandDecoration(QWaylandWindow *window); + virtual ~QWaylandDecoration(); + + void update(); + bool isDirty() const; + + bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods); + bool inMouseButtonPressedState() const; + + void startResize(QWaylandInputDevice *inputDevice,enum wl_shell_surface_resize resize, Qt::MouseButtons buttons); + void startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons); + QMargins margins() const; + QWindow *window() const; + QWaylandWindow *waylandWindow() const; + const QImage &contentImage(); + + void setForegroundColor(const QColor &c); + inline QColor foregroundColor() const; + + void setBackgroundColor(const QColor &c); + inline QColor backgroundColor() const; + +protected: + void paint(QPaintDevice *device); + +private: + void processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseBottom(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseLeft(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + void processMouseRight(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b,Qt::KeyboardModifiers mods); + + bool isLeftClicked(Qt::MouseButtons newMouseButtonState); + bool isLeftReleased(Qt::MouseButtons newMouseButtonState); + + QRectF closeButtonRect() const; + QRectF maximizeButtonRect() const; + QRectF minimizeButtonRect() const; + + QWindow *m_window; + QWaylandWindow *m_wayland_window; + + bool m_isDirty; + QImage m_decorationContentImage; + + QMargins m_margins; + Qt::MouseButtons m_mouseButtons; + + QColor m_foregroundColor; + QColor m_backgroundColor; + QStaticText m_windowTitle; +}; + +inline bool QWaylandDecoration::isDirty() const +{ + return m_isDirty; +} + +inline QMargins QWaylandDecoration::margins() const +{ + return m_margins; +} + +inline QWindow *QWaylandDecoration::window() const +{ + return m_window; +} + +inline QWaylandWindow *QWaylandDecoration::waylandWindow() const +{ + return m_wayland_window; +} + +inline QColor QWaylandDecoration::foregroundColor() const +{ + return m_foregroundColor; +} + +inline QColor QWaylandDecoration::backgroundColor() const +{ + return m_backgroundColor; +} + +QT_END_NAMESPACE + +#endif // QWAYLANDDECORATION_H diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp new file mode 100644 index 00000000..d9a8b452 --- /dev/null +++ b/src/client/qwaylanddisplay.cpp @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** 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 "qwaylanddisplay.h" + +#include "qwaylandeventthread.h" +#include "qwaylandwindow.h" +#include "qwaylandscreen.h" +#include "qwaylandcursor.h" +#include "qwaylandinputdevice.h" +#include "qwaylandclipboard.h" +#include "qwaylanddatadevicemanager.h" + +#ifdef QT_WAYLAND_GL_SUPPORT +#include "qwaylandglintegration.h" +#endif + +#include "qwaylandwindowmanagerintegration.h" + +#include "qwaylandextendedoutput.h" +#include "qwaylandextendedsurface.h" +#include "qwaylandsubsurface.h" +#include "qwaylandtouch.h" +#include "qwaylandqtkey.h" + +#include <QtWaylandClient/private/qwayland-text.h> + +#include <QtCore/QAbstractEventDispatcher> +#include <QtGui/private/qguiapplication_p.h> + +#include <QtCore/QDebug> + +#include <errno.h> + +QT_BEGIN_NAMESPACE + +struct wl_surface *QWaylandDisplay::createSurface(void *handle) +{ + struct wl_surface *surface = mCompositor.create_surface(); + wl_surface_set_user_data(surface, handle); + return surface; +} + +#ifdef QT_WAYLAND_GL_SUPPORT +QWaylandGLIntegration * QWaylandDisplay::eglIntegration() +{ + return mEglIntegration; +} +#endif + +QWaylandWindowManagerIntegration *QWaylandDisplay::windowManagerIntegration() +{ + return mWindowManagerIntegration; +} + +QWaylandInputDevice *QWaylandDisplay::lastKeyboardFocusInputDevice() const +{ + return mLastKeyboardFocusInputDevice; +} + +void QWaylandDisplay::setLastKeyboardFocusInputDevice(QWaylandInputDevice *device) +{ + mLastKeyboardFocusInputDevice = device; +} + +static QWaylandDisplay *display = 0; + +QWaylandDisplay::QWaylandDisplay() + : mLastKeyboardFocusInputDevice(0) + , mDndSelectionHandler(0) + , mWindowExtension(0) + , mSubSurfaceExtension(0) + , mOutputExtension(0) + , mTouchExtension(0) + , mQtKeyExtension(0) + , mTextInputManager(0) +{ + display = this; + qRegisterMetaType<uint32_t>("uint32_t"); + + mEventThreadObject = new QWaylandEventThread(0); + mEventThread = new QThread(this); + mEventThreadObject->moveToThread(mEventThread); + mEventThread->start(); + + mEventThreadObject->displayConnect(); + mDisplay = mEventThreadObject->display(); //blocks until display is available + + //Create a new even queue for the QtGui thread + mEventQueue = wl_display_create_queue(mDisplay); + + struct ::wl_registry *registry = wl_display_get_registry(mDisplay); + wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue); + + init(registry); + + connect(mEventThreadObject, SIGNAL(newEventsRead()), this, SLOT(flushRequests())); + +#ifdef QT_WAYLAND_GL_SUPPORT + //mEglIntegration = QWaylandGLIntegration::createGLIntegration(this); +#endif + + mWindowManagerIntegration = new QWaylandWindowManagerIntegration(this); + + blockingReadEvents(); + +#ifdef QT_WAYLAND_GL_SUPPORT + mEglIntegration->initialize(); + + flushRequests(); + while (mEglIntegration->waitingForEvents()) + blockingReadEvents(); +#endif + + waitForScreens(); +} + +QWaylandDisplay::~QWaylandDisplay(void) +{ +#ifdef QT_WAYLAND_GL_SUPPORT + delete mEglIntegration; +#endif + mEventThread->quit(); + mEventThread->wait(); + delete mEventThreadObject; +} + +void QWaylandDisplay::flushRequests() +{ + if (wl_display_dispatch_queue_pending(mDisplay, mEventQueue) == -1 && errno == EPIPE) { + qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + ::exit(1); + } + wl_display_flush(mDisplay); +} + +void QWaylandDisplay::blockingReadEvents() +{ + if (wl_display_dispatch_queue(mDisplay, mEventQueue) == -1 && errno == EPIPE) { + qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + ::exit(1); + } +} + +QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const +{ + for (int i = 0; i < mScreens.size(); ++i) { + QWaylandScreen *screen = static_cast<QWaylandScreen *>(mScreens.at(i)); + if (screen->output() == output) + return screen; + } + return 0; +} + +void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data) +{ + Listener l = { listener, data }; + mRegistryListeners.append(l); +} + +void QWaylandDisplay::waitForScreens() +{ + flushRequests(); + + while (true) { + bool screensReady = !mScreens.isEmpty(); + + for (int ii = 0; screensReady && ii < mScreens.count(); ++ii) { + if (mScreens.at(ii)->geometry() == QRect(0, 0, 0, 0)) + screensReady = false; + } + + if (!screensReady) + blockingReadEvents(); + else + return; + } +} + +void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uint32_t version) +{ + Q_UNUSED(version); + + struct ::wl_registry *registry = object(); + + if (interface == "wl_output") { + mScreens.append(new QWaylandScreen(this, id)); + } else if (interface == "wl_compositor") { + mCompositor.init(registry, id); + } else if (interface == "wl_shm") { + mShm = static_cast<struct wl_shm *>(wl_registry_bind(registry, id, &wl_shm_interface,1)); + } else if (interface == "wl_shell"){ + mShell = new QtWayland::wl_shell(registry, id); + } else if (interface == "wl_seat") { + QWaylandInputDevice *inputDevice = new QWaylandInputDevice(this, id); + mInputDevices.append(inputDevice); + } else if (interface == "wl_data_device_manager") { + mDndSelectionHandler = new QWaylandDataDeviceManager(this, id); + } else if (interface == "qt_output_extension") { + mOutputExtension = new QtWayland::qt_output_extension(registry, id); + foreach (QPlatformScreen *screen, screens()) + static_cast<QWaylandScreen *>(screen)->createExtendedOutput(); + } else if (interface == "qt_surface_extension") { + mWindowExtension = new QtWayland::qt_surface_extension(registry, id); + } else if (interface == "qt_sub_surface_extension") { + mSubSurfaceExtension = new QtWayland::qt_sub_surface_extension(registry, id); + } else if (interface == "qt_touch_extension") { + mTouchExtension = new QWaylandTouchExtension(this, id); + } else if (interface == "qt_key_extension") { + mQtKeyExtension = new QWaylandQtKeyExtension(this, id); + } else if (interface == "wl_text_input_manager") { + mTextInputManager = new QtWayland::wl_text_input_manager(registry, id); + } + + foreach (Listener l, mRegistryListeners) + (*l.listener)(l.data, registry, id, interface, version); +} + +uint32_t QWaylandDisplay::currentTimeMillisec() +{ + //### we throw away the time information + struct timeval tv; + int ret = gettimeofday(&tv, 0); + if (ret == 0) + return tv.tv_sec*1000 + tv.tv_usec/1000; + return 0; +} + +void QWaylandDisplay::forceRoundTrip() +{ + wl_display_roundtrip(mDisplay); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddisplay.h b/src/client/qwaylanddisplay.h new file mode 100644 index 00000000..45104350 --- /dev/null +++ b/src/client/qwaylanddisplay.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDISPLAY_H +#define QWAYLANDDISPLAY_H + +#include <QtCore/QObject> +#include <QtCore/QRect> + +#include <QtCore/QWaitCondition> + +#include <wayland-client.h> +#include <QtWaylandClient/private/qwayland-wayland.h> + +#include <QtWaylandClient/qwaylandclientexport.h> + +struct wl_cursor_image; + +QT_BEGIN_NAMESPACE + +class QAbstractEventDispatcher; +class QWaylandInputDevice; +class QSocketNotifier; +class QWaylandBuffer; +class QPlatformScreen; +class QWaylandScreen; +class QWaylandGLIntegration; +class QWaylandWindowManagerIntegration; +class QWaylandDataDeviceManager; +class QWaylandTouchExtension; +class QWaylandQtKeyExtension; +class QWaylandWindow; +class QWaylandEventThread; + +namespace QtWayland { + class qt_output_extension; + class qt_shell; + class qt_sub_surface_extension; + class qt_surface_extension; + class wl_text_input_manager; +} + +typedef void (*RegistryListener)(void *data, + struct wl_registry *registry, + uint32_t id, + const QString &interface, + uint32_t version); + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland::wl_registry { + Q_OBJECT + +public: + QWaylandDisplay(void); + ~QWaylandDisplay(void); + + QList<QPlatformScreen *> screens() const { return mScreens; } + + QWaylandScreen *screenForOutput(struct wl_output *output) const; + + struct wl_surface *createSurface(void *handle); + +#ifdef QT_WAYLAND_GL_SUPPORT + QWaylandGLIntegration *eglIntegration(); +#endif + + QWaylandWindowManagerIntegration *windowManagerIntegration(); + + void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image); + + struct wl_display *wl_display() const { return mDisplay; } + struct wl_event_queue *wl_event_queue() const { return mEventQueue; } + struct ::wl_registry *wl_registry() { return object(); } + + const struct wl_compositor *wl_compositor() const { return mCompositor.object(); } + QtWayland::wl_compositor *compositor() { return &mCompositor; } + + QtWayland::wl_shell *shell() { return mShell; } + + QList<QWaylandInputDevice *> inputDevices() const { return mInputDevices; } + QWaylandInputDevice *defaultInputDevice() const; + QWaylandInputDevice *currentInputDevice() const { return defaultInputDevice(); } + + QWaylandInputDevice *lastKeyboardFocusInputDevice() const; + void setLastKeyboardFocusInputDevice(QWaylandInputDevice *device); + + QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler; } + + QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension; } + QtWayland::qt_sub_surface_extension *subSurfaceExtension() const { return mSubSurfaceExtension; } + QtWayland::qt_output_extension *outputExtension() const { return mOutputExtension; } + QWaylandTouchExtension *touchExtension() const { return mTouchExtension; } + QtWayland::wl_text_input_manager *textInputManager() const { return mTextInputManager; } + + /* wl_registry_add_listener does not add but rather sets a listener, so this function is used + * to enable many listeners at once. */ + void addRegistryListener(RegistryListener listener, void *data); + + struct wl_shm *shm() const { return mShm; } + + static uint32_t currentTimeMillisec(); + + void forceRoundTrip(); + +public slots: + void blockingReadEvents(); + void flushRequests(); + +private: + void waitForScreens(); + + struct Listener { + RegistryListener listener; + void *data; + }; + + struct wl_display *mDisplay; + struct wl_event_queue *mEventQueue; + QtWayland::wl_compositor mCompositor; + struct wl_shm *mShm; + QThread *mEventThread; + QWaylandEventThread *mEventThreadObject; + QtWayland::wl_shell *mShell; + QList<QPlatformScreen *> mScreens; + QList<QWaylandInputDevice *> mInputDevices; + QList<Listener> mRegistryListeners; + QWaylandInputDevice *mLastKeyboardFocusInputDevice; + QWaylandDataDeviceManager *mDndSelectionHandler; + QtWayland::qt_surface_extension *mWindowExtension; + QtWayland::qt_sub_surface_extension *mSubSurfaceExtension; + QtWayland::qt_output_extension *mOutputExtension; + QWaylandTouchExtension *mTouchExtension; + QWaylandQtKeyExtension *mQtKeyExtension; + QWaylandWindowManagerIntegration *mWindowManagerIntegration; + QtWayland::wl_text_input_manager *mTextInputManager; + + QSocketNotifier *mReadNotifier; + int mFd; + int mWritableNotificationFd; + bool mScreensInitialized; + + void registry_global(uint32_t id, const QString &interface, uint32_t version) Q_DECL_OVERRIDE; + +#ifdef QT_WAYLAND_GL_SUPPORT + QWaylandGLIntegration *mEglIntegration; +#endif + + static void shellHandleConfigure(void *data, struct wl_shell *shell, + uint32_t time, uint32_t edges, + struct wl_surface *surface, + int32_t width, int32_t height); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDISPLAY_H diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp new file mode 100644 index 00000000..635fd967 --- /dev/null +++ b/src/client/qwaylanddnd.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** 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 "qwaylanddnd.h" + +#include "qwaylanddatadevice.h" +#include "qwaylanddatadevicemanager.h" +#include "qwaylanddataoffer.h" +#include "qwaylandinputdevice.h" + +#include <QtGui/private/qshapedpixmapdndwindow_p.h> + +#include <QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandDrag::QWaylandDrag(QWaylandDisplay *display) + : m_display(display) +{ +} + +QWaylandDrag::~QWaylandDrag() +{ +} + +QMimeData * QWaylandDrag::platformDropData() +{ + if (drag()) + return drag()->mimeData(); + return 0; +} + +void QWaylandDrag::startDrag() +{ + if (!shapedPixmapWindow()) { + QBasicDrag::startDrag(); + QBasicDrag::cancel(); + } + + QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle()); + m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon); + QBasicDrag::startDrag(); +} + +void QWaylandDrag::cancel() +{ + QBasicDrag::cancel(); + + m_display->currentInputDevice()->dataDevice()->cancelDrag(); +} + +void QWaylandDrag::move(const QMouseEvent *me) +{ + Q_UNUSED(me); + // Do nothing +} + +void QWaylandDrag::drop(const QMouseEvent *me) +{ + Q_UNUSED(me); + // Do nothing +} + +void QWaylandDrag::endDrag() +{ + // Do nothing +} + +void QWaylandDrag::updateTarget(const QString &mimeType) +{ + setCanDrop(!mimeType.isEmpty()); + + if (canDrop()) { + updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); + } else { + updateCursor(Qt::IgnoreAction); + } +} + +void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response) +{ + setCanDrop(response.isAccepted()); + + if (canDrop()) { + updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers())); + } else { + updateCursor(Qt::IgnoreAction); + } +} + +void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response) +{ + setExecutedDropAction(response.acceptedAction()); + QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier); + eventFilter(shapedPixmapWindow(), &event); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylanddnd.h b/src/client/qwaylanddnd.h new file mode 100644 index 00000000..f125dd2b --- /dev/null +++ b/src/client/qwaylanddnd.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDDND_H +#define QWAYLANDDND_H + +#include <qpa/qplatformdrag.h> +#include <QtGui/private/qsimpledrag_p.h> + +#include <QtGui/QDrag> +#include <QtCore/QMimeData> +#include "qwaylanddisplay.h" + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_CLIENT_EXPORT QWaylandDrag : public QBasicDrag +{ +public: + QWaylandDrag(QWaylandDisplay *display); + ~QWaylandDrag(); + + QMimeData *platformDropData() Q_DECL_OVERRIDE; + + void updateTarget(const QString &mimeType); + void setResponse(const QPlatformDragQtResponse &response); + void finishDrag(const QPlatformDropQtResponse &response); + +protected: + void startDrag() Q_DECL_OVERRIDE; + void cancel() Q_DECL_OVERRIDE; + void move(const QMouseEvent *me) Q_DECL_OVERRIDE; + void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + void endDrag() Q_DECL_OVERRIDE; + + +private: + QWaylandDisplay *m_display; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDDND_H diff --git a/src/client/qwaylandeventthread.cpp b/src/client/qwaylandeventthread.cpp new file mode 100644 index 00000000..3392d36c --- /dev/null +++ b/src/client/qwaylandeventthread.cpp @@ -0,0 +1,63 @@ +#include "qwaylandeventthread.h" +#include <QtCore/QSocketNotifier> +#include <QCoreApplication> + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> + +QT_BEGIN_NAMESPACE + +QWaylandEventThread::QWaylandEventThread(QObject *parent) + : QObject(parent) + , m_display(0) + , m_fileDescriptor(-1) + , m_readNotifier(0) + , m_displayLock(new QMutex) +{ +} + +QWaylandEventThread::~QWaylandEventThread() +{ + delete m_displayLock; + wl_display_disconnect(m_display); +} + +void QWaylandEventThread::displayConnect() +{ + m_displayLock->lock(); + QMetaObject::invokeMethod(this, "waylandDisplayConnect", Qt::QueuedConnection); +} + +void QWaylandEventThread::readWaylandEvents() +{ + if (wl_display_dispatch(m_display) == -1 && errno == EPIPE) { + qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + ::exit(1); + } + emit newEventsRead(); +} + +void QWaylandEventThread::waylandDisplayConnect() +{ + m_display = wl_display_connect(NULL); + if (m_display == NULL) { + qErrnoWarning(errno, "Failed to create display"); + ::exit(1); + } + m_displayLock->unlock(); + + m_fileDescriptor = wl_display_get_fd(m_display); + + m_readNotifier = new QSocketNotifier(m_fileDescriptor, QSocketNotifier::Read, this); + connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readWaylandEvents())); +} + +wl_display *QWaylandEventThread::display() const +{ + QMutexLocker displayLock(m_displayLock); + return m_display; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandeventthread.h b/src/client/qwaylandeventthread.h new file mode 100644 index 00000000..ba7e33e0 --- /dev/null +++ b/src/client/qwaylandeventthread.h @@ -0,0 +1,46 @@ +#ifndef QWAYLANDEVENTTHREAD_H +#define QWAYLANDEVENTTHREAD_H + +#include <QObject> +#include <QMutex> +#include <wayland-client.h> + +#include <QtWaylandClient/qwaylandclientexport.h> + +QT_BEGIN_NAMESPACE + +class QSocketNotifier; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandEventThread : public QObject +{ + Q_OBJECT +public: + explicit QWaylandEventThread(QObject *parent = 0); + ~QWaylandEventThread(); + + void displayConnect(); + + wl_display *display() const; + +private slots: + void readWaylandEvents(); + + void waylandDisplayConnect(); + +signals: + void newEventsRead(); + +private: + + struct wl_display *m_display; + int m_fileDescriptor; + + QSocketNotifier *m_readNotifier; + + QMutex *m_displayLock; + +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDEVENTTHREAD_H diff --git a/src/client/qwaylandextendedoutput.cpp b/src/client/qwaylandextendedoutput.cpp new file mode 100644 index 00000000..d7c684be --- /dev/null +++ b/src/client/qwaylandextendedoutput.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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 "qwaylandextendedoutput.h" + +#include "qwaylandscreen.h" + +#include <qpa/qwindowsysteminterface.h> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandExtendedOutput::QWaylandExtendedOutput(QWaylandScreen *screen, ::qt_extended_output *extended_output) + : QtWayland::qt_extended_output(extended_output) + , m_screen(screen) + , m_orientation(m_screen->orientation()) +{ +} + +Qt::ScreenOrientation QWaylandExtendedOutput::currentOrientation() const +{ + return m_orientation; +} + +void QWaylandExtendedOutput::setOrientationUpdateMask(Qt::ScreenOrientations orientations) +{ + int mask = 0; + if (orientations & Qt::PortraitOrientation) + mask |= QT_EXTENDED_OUTPUT_ROTATION_PORTRAITORIENTATION; + if (orientations & Qt::LandscapeOrientation) + mask |= QT_EXTENDED_OUTPUT_ROTATION_LANDSCAPEORIENTATION; + if (orientations & Qt::InvertedPortraitOrientation) + mask |= QT_EXTENDED_OUTPUT_ROTATION_INVERTEDPORTRAITORIENTATION; + if (orientations & Qt::InvertedLandscapeOrientation) + mask |= QT_EXTENDED_OUTPUT_ROTATION_INVERTEDLANDSCAPEORIENTATION; + set_orientation_update_mask(mask); +} + +void QWaylandExtendedOutput::extended_output_set_screen_rotation(int32_t rotation) +{ + switch (rotation) { + case QT_EXTENDED_OUTPUT_ROTATION_PORTRAITORIENTATION: + m_orientation = Qt::PortraitOrientation; + break; + case QT_EXTENDED_OUTPUT_ROTATION_LANDSCAPEORIENTATION: + m_orientation = Qt::LandscapeOrientation; + break; + case QT_EXTENDED_OUTPUT_ROTATION_INVERTEDPORTRAITORIENTATION: + m_orientation = Qt::InvertedPortraitOrientation; + break; + case QT_EXTENDED_OUTPUT_ROTATION_INVERTEDLANDSCAPEORIENTATION: + m_orientation = Qt::InvertedLandscapeOrientation; + break; + default: + m_orientation = Qt::PortraitOrientation; + break; + } + QWindowSystemInterface::handleScreenOrientationChange(m_screen->screen(), m_orientation); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandextendedoutput.h b/src/client/qwaylandextendedoutput.h new file mode 100644 index 00000000..e311a9b4 --- /dev/null +++ b/src/client/qwaylandextendedoutput.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDEXTENDEDOUTPUT_H +#define QWAYLANDEXTENDEDOUTPUT_H + +#include "qwaylanddisplay.h" +#include <QtWaylandClient/private/qwayland-output-extension.h> + +QT_BEGIN_NAMESPACE + +class QWaylandExtendedOutput; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandExtendedOutput : public QtWayland::qt_extended_output +{ +public: + QWaylandExtendedOutput(QWaylandScreen *screen, struct ::qt_extended_output *extended_output); + + Qt::ScreenOrientation currentOrientation() const; + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + +private: + void extended_output_set_screen_rotation(int32_t rotation) Q_DECL_OVERRIDE; + + QWaylandScreen *m_screen; + Qt::ScreenOrientation m_orientation; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDEXTENDEDOUTPUT_H diff --git a/src/client/qwaylandextendedsurface.cpp b/src/client/qwaylandextendedsurface.cpp new file mode 100644 index 00000000..bfd2a1d0 --- /dev/null +++ b/src/client/qwaylandextendedsurface.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** 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 "qwaylandextendedsurface.h" + +#include "qwaylandwindow.h" + +#include "wayland-client.h" + +#include "qwaylanddisplay.h" + +#include "qwaylandnativeinterface.h" + +#include <QtGui/QGuiApplication> +#include <qpa/qplatformnativeinterface.h> +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +QWaylandExtendedSurface::QWaylandExtendedSurface(QWaylandWindow *window, struct ::qt_extended_surface *extended_surface) + : QtWayland::qt_extended_surface(extended_surface) + , m_window(window) +{ +} + +QWaylandExtendedSurface::~QWaylandExtendedSurface() +{ + qt_extended_surface_destroy(object()); +} + +void QWaylandExtendedSurface::updateGenericProperty(const QString &name, const QVariant &value) +{ + QByteArray byteValue; + QDataStream ds(&byteValue, QIODevice::WriteOnly); + ds << value; + + update_generic_property(name, byteValue); + + m_properties.insert(name, value); + QWaylandNativeInterface *nativeInterface = static_cast<QWaylandNativeInterface *>( + QGuiApplication::platformNativeInterface()); + nativeInterface->emitWindowPropertyChanged(m_window, name); +} + +static int32_t waylandRotationFromScreenOrientation(Qt::ScreenOrientation orientation) +{ + switch (orientation) { + case Qt::PortraitOrientation: return QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION; + case Qt::InvertedPortraitOrientation: return QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION; + case Qt::LandscapeOrientation: return QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION; + case Qt::InvertedLandscapeOrientation: return QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION; + default: return QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION; + } +} + +void QWaylandExtendedSurface::setContentOrientation(Qt::ScreenOrientation orientation) +{ + set_content_orientation(waylandRotationFromScreenOrientation(orientation)); +} + +QVariantMap QWaylandExtendedSurface::properties() const +{ + return m_properties; +} + +QVariant QWaylandExtendedSurface::property(const QString &name) +{ + return m_properties.value(name); +} + +QVariant QWaylandExtendedSurface::property(const QString &name, const QVariant &defaultValue) +{ + return m_properties.value(name,defaultValue); +} + +void QWaylandExtendedSurface::extended_surface_onscreen_visibility(int32_t visibility) +{ + m_window->window()->setVisibility(static_cast<QWindow::Visibility>(visibility)); +} + +void QWaylandExtendedSurface::extended_surface_set_generic_property(const QString &name, wl_array *value) +{ + QByteArray data = QByteArray::fromRawData(static_cast<char *>(value->data), value->size); + + QVariant variantValue; + QDataStream ds(data); + ds >> variantValue; + + m_properties.insert(name, variantValue); + + QWaylandNativeInterface *nativeInterface = static_cast<QWaylandNativeInterface *>( + QGuiApplication::platformNativeInterface()); + nativeInterface->emitWindowPropertyChanged(m_window, name); +} + +void QWaylandExtendedSurface::extended_surface_close() +{ + QWindowSystemInterface::handleCloseEvent(m_window->window()); +} + +Qt::WindowFlags QWaylandExtendedSurface::setWindowFlags(Qt::WindowFlags flags) +{ + uint wlFlags = 0; + + if (flags & Qt::WindowStaysOnTopHint) wlFlags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP; + if (flags & Qt::WindowOverridesSystemGestures) wlFlags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES; + if (flags & Qt::BypassWindowManagerHint) wlFlags |= QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER; + + set_window_flags(wlFlags); + + return flags & (Qt::WindowStaysOnTopHint | Qt::WindowOverridesSystemGestures | Qt::BypassWindowManagerHint); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandextendedsurface.h b/src/client/qwaylandextendedsurface.h new file mode 100644 index 00000000..8c054647 --- /dev/null +++ b/src/client/qwaylandextendedsurface.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDEXTENDEDSURFACE_H +#define QWAYLANDEXTENDEDSURFACE_H + +#include <QtCore/QString> +#include <QtCore/QVariant> + +#include <QtWaylandClient/qwaylandclientexport.h> + +#include <wayland-client.h> +#include <QtWaylandClient/private/qwayland-surface-extension.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandWindow; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandExtendedSurface : public QtWayland::qt_extended_surface +{ +public: + QWaylandExtendedSurface(QWaylandWindow *window, struct ::qt_extended_surface *extended_surface); + ~QWaylandExtendedSurface(); + + void setContentOrientation(Qt::ScreenOrientation orientation); + + void updateGenericProperty(const QString &name, const QVariant &value); + + QVariantMap properties() const; + QVariant property(const QString &name); + QVariant property(const QString &name, const QVariant &defaultValue); + + Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + +private: + void extended_surface_onscreen_visibility(int32_t visibility) Q_DECL_OVERRIDE; + void extended_surface_set_generic_property(const QString &name, wl_array *value) Q_DECL_OVERRIDE; + void extended_surface_close() Q_DECL_OVERRIDE; + + QWaylandWindow *m_window; + QVariantMap m_properties; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDEXTENDEDSURFACE_H diff --git a/src/client/qwaylandglintegration.cpp b/src/client/qwaylandglintegration.cpp new file mode 100644 index 00000000..bafb9944 --- /dev/null +++ b/src/client/qwaylandglintegration.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 "qwaylandglintegration.h" + +QT_BEGIN_NAMESPACE + +QWaylandGLIntegration::QWaylandGLIntegration() +{ + +} + +QWaylandGLIntegration::~QWaylandGLIntegration() +{ + +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandglintegration.h b/src/client/qwaylandglintegration.h new file mode 100644 index 00000000..7697d310 --- /dev/null +++ b/src/client/qwaylandglintegration.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDGLINTEGRATION_H +#define QWAYLANDGLINTEGRATION_H + +#include <QtCore/qglobal.h> +#include <QtWaylandClient/qwaylandclientexport.h> + +QT_BEGIN_NAMESPACE + +class QWaylandWindow; +class QWaylandDisplay; +class QWindow; + +class QPlatformOpenGLContext; +class QSurfaceFormat; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandGLIntegration +{ +public: + QWaylandGLIntegration(); + virtual ~QWaylandGLIntegration(); + + virtual void initialize() = 0; + virtual bool waitingForEvents() { return false; } + + virtual bool supportsThreadedOpenGL() const { return false; } + + virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; + + static QWaylandGLIntegration *createGLIntegration(QWaylandDisplay *waylandDisplay); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDGLINTEGRATION_H diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp new file mode 100644 index 00000000..f50581b3 --- /dev/null +++ b/src/client/qwaylandinputcontext.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandinputcontext.h" + +#include <QGuiApplication> +#include <QWindow> +#ifndef QT_NO_WAYLAND_XKB +#include <xkbcommon/xkbcommon.h> +#endif + +#include "qwaylanddisplay.h" +#include "qwaylandinputdevice.h" +#include "qwaylandwindow.h" + +QT_BEGIN_NAMESPACE + +static Qt::Key toQtKey(uint32_t sym) +{ +#ifndef QT_NO_WAYLAND_XKB + switch (static_cast<xkb_keysym_t>(sym)) { + case XKB_KEY_BackSpace: + return Qt::Key_Backspace; + case XKB_KEY_Return: + return Qt::Key_Return; + case XKB_KEY_Left: + return Qt::Key_Left; + case XKB_KEY_Up: + return Qt::Key_Up; + case XKB_KEY_Right: + return Qt::Key_Right; + case XKB_KEY_Down: + return Qt::Key_Down; + default: + return Qt::Key_unknown; + } +#else + return Qt::Key_unknown; +#endif +} + +static QEvent::Type toQEventType(uint32_t state) +{ + switch (static_cast<wl_keyboard_key_state>(state)) { + default: + case WL_KEYBOARD_KEY_STATE_PRESSED: + return QEvent::KeyPress; + case WL_KEYBOARD_KEY_STATE_RELEASED: + return QEvent::KeyRelease; + } +} + +QWaylandTextInput::QWaylandTextInput(struct ::wl_text_input *text_input) + : QtWayland::wl_text_input(text_input) + , m_commit() + , m_serial(0) + , m_resetSerial(0) +{ +} + +QString QWaylandTextInput::commitString() const +{ + return m_commit; +} + +void QWaylandTextInput::reset() +{ + wl_text_input::reset(); + updateState(); + m_resetSerial = m_serial; +} + +void QWaylandTextInput::updateState() +{ + if (!QGuiApplication::focusObject()) + return; + + QInputMethodQueryEvent event(Qt::ImQueryAll); + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); + + const QString &text = event.value(Qt::ImSurroundingText).toString(); + const int cursor = event.value(Qt::ImCursorPosition).toInt(); + const int anchor = event.value(Qt::ImAnchorPosition).toInt(); + + set_surrounding_text(text, text.leftRef(cursor).toUtf8().size(), text.leftRef(anchor).toUtf8().size()); + + commit_state(++m_serial); +} + +void QWaylandTextInput::text_input_commit_string(uint32_t serial, const QString &text) +{ + if (!QGuiApplication::focusObject()) + return; + + QInputMethodEvent event; + event.setCommitString(text); + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); +} + +void QWaylandTextInput::text_input_enter(wl_surface *) +{ + updateState(); + m_resetSerial = m_serial; +} + +void QWaylandTextInput::text_input_leave() +{ +} + +void QWaylandTextInput::text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) +{ + if (!QGuiApplication::focusObject()) + return; + + // TODO: Convert modifiers to Qt::KeyboardModifiers. + QKeyEvent event(toQEventType(state), toQtKey(sym), Qt::NoModifier); + QCoreApplication::sendEvent(qGuiApp->focusWindow(), &event); +} + +QWaylandInputContext::QWaylandInputContext(QWaylandDisplay *display) + : QPlatformInputContext() + , mDisplay(display) + , mTextInput() +{ +} + +bool QWaylandInputContext::isValid() const +{ + return mDisplay->textInputManager() != 0; +} + +void QWaylandInputContext::reset() +{ + if (!ensureTextInput()) + return; + + mTextInput->reset(); +} + +void QWaylandInputContext::commit() +{ + if (!ensureTextInput()) + return; + + if (!QGuiApplication::focusObject()) + return; + + QInputMethodEvent event; + event.setCommitString(mTextInput->commitString()); + QCoreApplication::sendEvent(QGuiApplication::focusObject(), &event); + + mTextInput->reset(); +} + +void QWaylandInputContext::update(Qt::InputMethodQueries queries) +{ + if (!ensureTextInput()) + return; + + mTextInput->updateState(); +} + +void QWaylandInputContext::invokeAction(QInputMethod::Action, int cursorPosition) +{ + if (!ensureTextInput()) + return; + + mTextInput->invoke_action(0, cursorPosition); // FIXME button, to UTF8 cursor position +} + +void QWaylandInputContext::showInputPanel() +{ + if (!ensureTextInput()) + return; + + mTextInput->show_input_panel(); +} + +void QWaylandInputContext::hideInputPanel() +{ + if (!ensureTextInput()) + return; + + mTextInput->hide_input_panel(); +} + +bool QWaylandInputContext::isInputPanelVisible() const +{ + return false; +} + +void QWaylandInputContext::setFocusObject(QObject *object) +{ + if (!ensureTextInput()) + return; + + if (!object) { + mTextInput->deactivate(mDisplay->defaultInputDevice()->wl_seat()); + return; + } + + QWindow *window = QGuiApplication::focusWindow(); + if (!window || !window->handle()) + return; + + struct ::wl_surface *surface = static_cast<QWaylandWindow *>(window->handle())->object(); + mTextInput->activate(mDisplay->defaultInputDevice()->wl_seat(), surface); +} + +bool QWaylandInputContext::ensureTextInput() +{ + if (mTextInput) + return true; + + if (!isValid()) + return false; + + mTextInput.reset(new QWaylandTextInput(mDisplay->textInputManager()->create_text_input())); + return true; +} + +QT_END_NAMESPACE + diff --git a/src/client/qwaylandinputcontext.h b/src/client/qwaylandinputcontext.h new file mode 100644 index 00000000..1f7e4e36 --- /dev/null +++ b/src/client/qwaylandinputcontext.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Compositor. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTCONTEXT_H +#define QWAYLANDINPUTCONTEXT_H + +#include <qpa/qplatforminputcontext.h> + +#include <QtWaylandClient/private/qwayland-text.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; + +class QWaylandTextInput : public QtWayland::wl_text_input +{ +public: + QWaylandTextInput(struct ::wl_text_input *text_input); + + QString commitString() const; + + void reset(); + void updateState(); + +protected: + void text_input_commit_string(uint32_t serial, const QString &text) Q_DECL_OVERRIDE; + void text_input_enter(wl_surface *surface) Q_DECL_OVERRIDE; + void text_input_leave() Q_DECL_OVERRIDE; + void text_input_keysym(uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers); + +private: + QString m_commit; + + uint32_t m_serial; + uint32_t m_resetSerial; +}; + +class QWaylandInputContext : public QPlatformInputContext +{ + Q_OBJECT +public: + explicit QWaylandInputContext(QWaylandDisplay *display); + + bool isValid() const Q_DECL_OVERRIDE; + + void reset() Q_DECL_OVERRIDE; + void commit() Q_DECL_OVERRIDE; + void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; + void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; + + void showInputPanel() Q_DECL_OVERRIDE; + void hideInputPanel() Q_DECL_OVERRIDE; + bool isInputPanelVisible() const Q_DECL_OVERRIDE; + + void setFocusObject(QObject *object) Q_DECL_OVERRIDE; + +private: + bool ensureTextInput(); + + QWaylandDisplay *mDisplay; + QScopedPointer<QWaylandTextInput> mTextInput; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTCONTEXT_H diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp new file mode 100644 index 00000000..b9338b4c --- /dev/null +++ b/src/client/qwaylandinputdevice.cpp @@ -0,0 +1,798 @@ +/**************************************************************************** +** +** 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 "qwaylandinputdevice.h" + +#include "qwaylandintegration.h" +#include "qwaylandwindow.h" +#include "qwaylandbuffer.h" +#include "qwaylanddatadevice.h" +#include "qwaylanddatadevicemanager.h" +#include "qwaylandtouch.h" +#include "qwaylandscreen.h" +#include "qwaylandcursor.h" + +#include <QtGui/private/qpixmap_raster_p.h> +#include <qpa/qplatformwindow.h> +#include <QDebug> + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include <wayland-cursor.h> + +#include <QtGui/QGuiApplication> + +#ifndef QT_NO_WAYLAND_XKB +#include <xkbcommon/xkbcommon.h> +#include <X11/keysym.h> +#endif + +QT_BEGIN_NAMESPACE + +QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, uint32_t id) + : QObject() + , QtWayland::wl_seat(display->wl_registry(), id) + , mQDisplay(display) + , mDisplay(display->wl_display()) + , mFocusCallback(0) + , mCaps(0) + , mDataDevice(0) + , mPointerFocus(0) + , mKeyboardFocus(0) + , mTouchFocus(0) + , mButtons(0) + , mTime(0) + , mSerial(0) + , mEnterSerial(0) + , mCursorSerial(0) + , mTouchDevice(0) + #ifndef QT_NO_WAYLAND_XKB + , mXkbContext(0) + , mXkbMap(0) + , mXkbState(0) + #endif +{ +#ifndef QT_NO_WAYLAND_XKB + xkb_rule_names names; + names.rules = strdup("evdev"); + names.model = strdup("pc105"); + names.layout = strdup("us"); + names.variant = strdup(""); + names.options = strdup(""); + + mXkbContext = xkb_context_new(xkb_context_flags(0)); + if (mXkbContext) { + mXkbMap = xkb_map_new_from_names(mXkbContext, &names, xkb_map_compile_flags(0)); + if (mXkbMap) { + mXkbState = xkb_state_new(mXkbMap); + } + } + + if (!mXkbContext || !mXkbMap || !mXkbState) + qWarning() << "xkb_map_new_from_names failed, no key input"; +#endif + + if (mQDisplay->dndSelectionHandler()) { + mDataDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this); + } + + connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); +} + +QWaylandInputDevice::~QWaylandInputDevice() +{ +#ifndef QT_NO_WAYLAND_XKB + if (mXkbState) + xkb_state_unref(mXkbState); + if (mXkbMap) + xkb_map_unref(mXkbMap); + if (mXkbContext) + xkb_context_unref(mXkbContext); +#endif +} + +void QWaylandInputDevice::seat_capabilities(uint32_t caps) +{ + mCaps = caps; + + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) + QtWayland::wl_keyboard::init(get_keyboard()); + + if (caps & WL_SEAT_CAPABILITY_POINTER) { + QtWayland::wl_pointer::init(get_pointer()); + pointerSurface = mQDisplay->createSurface(this); + } + + if (caps & WL_SEAT_CAPABILITY_TOUCH) { + QtWayland::wl_touch::init(get_touch()); + + if (!mTouchDevice) { + mTouchDevice = new QTouchDevice; + mTouchDevice->setType(QTouchDevice::TouchScreen); + mTouchDevice->setCapabilities(QTouchDevice::Position); + QWindowSystemInterface::registerTouchDevice(mTouchDevice); + } + } +} + +void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window) +{ + if (window == mPointerFocus) + mPointerFocus = 0; + if (window == mKeyboardFocus) { + mKeyboardFocus = 0; + mRepeatTimer.stop(); + } +} + +void QWaylandInputDevice::setDataDevice(QWaylandDataDevice *device) +{ + mDataDevice = device; +} + +QWaylandDataDevice *QWaylandInputDevice::dataDevice() const +{ + Q_ASSERT(mDataDevice); + return mDataDevice; +} + +void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) +{ + mButtons = mButtons & !button; +} + +QWaylandWindow *QWaylandInputDevice::pointerFocus() const +{ + return mPointerFocus; +} + +Qt::KeyboardModifiers QWaylandInputDevice::modifiers() const +{ + Qt::KeyboardModifiers ret = Qt::NoModifier; + +#ifndef QT_NO_WAYLAND_XKB + xkb_state_component cstate = static_cast<xkb_state_component>(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED); + + if (xkb_state_mod_name_is_active(mXkbState, "Shift", cstate)) + ret |= Qt::ShiftModifier; + if (xkb_state_mod_name_is_active(mXkbState, "Control", cstate)) + ret |= Qt::ControlModifier; + if (xkb_state_mod_name_is_active(mXkbState, "Alt", cstate)) + ret |= Qt::AltModifier; + if (xkb_state_mod_name_is_active(mXkbState, "Mod1", cstate)) + ret |= Qt::AltModifier; + if (xkb_state_mod_name_is_active(mXkbState, "Mod4", cstate)) + ret |= Qt::MetaModifier; +#endif + + return ret; +} + +void QWaylandInputDevice::setCursor(Qt::CursorShape newShape, QWaylandScreen *screen) +{ + struct wl_cursor_image *image = screen->waylandCursor()->cursorImage(newShape); + if (!image) { + return; + } + + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + setCursor(buffer, image); +} + +void QWaylandInputDevice::setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image) +{ + if (mCaps & WL_SEAT_CAPABILITY_POINTER) { + mCursorSerial = mEnterSerial; + /* Hide cursor */ + if (!buffer) + { + set_cursor(mEnterSerial, NULL, 0, 0); + return; + } + + set_cursor(mEnterSerial, pointerSurface, + image->hotspot_x, image->hotspot_y); + wl_surface_attach(pointerSurface, buffer, 0, 0); + wl_surface_damage(pointerSurface, 0, 0, image->width, image->height); + wl_surface_commit(pointerSurface); + } +} + +void QWaylandInputDevice::pointer_enter(uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) +{ + Q_UNUSED(sx); + Q_UNUSED(sy); + + if (!surface) + return; + + QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); + window->window()->setCursor(window->window()->cursor()); + + mPointerFocus = window; + + mTime = QWaylandDisplay::currentTimeMillisec(); + mSerial = serial; + mEnterSerial = serial; + + QWaylandWindow *grab = QWaylandWindow::mouseGrab(); + if (!grab) { + window->handleMouseEnter(this); + window->handleMouse(this, mTime, mSurfacePos, mGlobalPos, mButtons, Qt::NoModifier); + } +} + +void QWaylandInputDevice::pointer_leave(uint32_t time, struct wl_surface *surface) +{ + // The event may arrive after destroying the window, indicated by + // a null surface. + if (!surface) + return; + + if (!QWaylandWindow::mouseGrab()) { + QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); + window->handleMouseLeave(this); + } + mPointerFocus = 0; + mButtons = Qt::NoButton; + + mTime = time; +} + +void QWaylandInputDevice::pointer_motion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + Q_UNUSED(surface_x); + Q_UNUSED(surface_y); + + QWaylandWindow *window = mPointerFocus; + + if (window == NULL) { + // We destroyed the pointer focus surface, but the server + // didn't get the message yet. + return; + } + + QPointF pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); + QPointF delta = pos - pos.toPoint(); + QPointF global = window->window()->mapToGlobal(pos.toPoint()); + global += delta; + + mSurfacePos = pos; + mGlobalPos = global; + mTime = time; + + QWaylandWindow *grab = QWaylandWindow::mouseGrab(); + if (grab && grab != window) { + // We can't know the true position since we're getting events for another surface, + // so we just set it outside of the window boundaries. + pos = QPointF(-1, -1); + global = grab->window()->mapToGlobal(pos.toPoint()); + grab->handleMouse(this, time, pos, global, mButtons, Qt::NoModifier); + } else + window->handleMouse(this, time, mSurfacePos, mGlobalPos, mButtons, Qt::NoModifier); +} + +void QWaylandInputDevice::pointer_button(uint32_t serial, uint32_t time, + uint32_t button, uint32_t state) +{ + Q_UNUSED(serial); + QWaylandWindow *window = mPointerFocus; + Qt::MouseButton qt_button; + + // translate from kernel (input.h) 'button' to corresponding Qt:MouseButton. + // The range of mouse values is 0x110 <= mouse_button < 0x120, the first Joystick button. + switch (button) { + case 0x110: qt_button = Qt::LeftButton; break; // kernel BTN_LEFT + case 0x111: qt_button = Qt::RightButton; break; + case 0x112: qt_button = Qt::MiddleButton; break; + case 0x113: qt_button = Qt::ExtraButton1; break; // AKA Qt::BackButton + case 0x114: qt_button = Qt::ExtraButton2; break; // AKA Qt::ForwardButton + case 0x115: qt_button = Qt::ExtraButton3; break; // AKA Qt::TaskButton + case 0x116: qt_button = Qt::ExtraButton4; break; + case 0x117: qt_button = Qt::ExtraButton5; break; + case 0x118: qt_button = Qt::ExtraButton6; break; + case 0x119: qt_button = Qt::ExtraButton7; break; + case 0x11a: qt_button = Qt::ExtraButton8; break; + case 0x11b: qt_button = Qt::ExtraButton9; break; + case 0x11c: qt_button = Qt::ExtraButton10; break; + case 0x11d: qt_button = Qt::ExtraButton11; break; + case 0x11e: qt_button = Qt::ExtraButton12; break; + case 0x11f: qt_button = Qt::ExtraButton13; break; + default: return; // invalid button number (as far as Qt is concerned) + } + + if (state) + mButtons |= qt_button; + else + mButtons &= ~qt_button; + + mTime = time; + mSerial = serial; + + QWaylandWindow *grab = QWaylandWindow::mouseGrab(); + if (grab && grab != mPointerFocus) { + QPointF pos = QPointF(-1, -1); + QPointF global = grab->window()->mapToGlobal(pos.toPoint()); + grab->handleMouse(this, time, pos, global, mButtons, Qt::NoModifier); + } else if (window) + window->handleMouse(this, time, mSurfacePos, mGlobalPos, mButtons, Qt::NoModifier); +} + +void QWaylandInputDevice::pointer_axis(uint32_t time, uint32_t axis, int32_t value) +{ + QWaylandWindow *window = mPointerFocus; + QPoint pixelDelta; + QPoint angleDelta; + + //normalize value and inverse axis + int valueDelta = wl_fixed_to_int(value) * -12; + + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + pixelDelta = QPoint(); + angleDelta.setX(valueDelta); + } else { + pixelDelta = QPoint(); + angleDelta.setY(valueDelta); + } + + QWindowSystemInterface::handleWheelEvent(window->window(), + time, mSurfacePos, + mGlobalPos, pixelDelta, + angleDelta); +} + +#ifndef QT_NO_WAYLAND_XKB + +static const uint32_t KeyTbl[] = { + XK_Escape, Qt::Key_Escape, + XK_Tab, Qt::Key_Tab, + XK_ISO_Left_Tab, Qt::Key_Backtab, + XK_BackSpace, Qt::Key_Backspace, + XK_Return, Qt::Key_Return, + XK_Insert, Qt::Key_Insert, + XK_Delete, Qt::Key_Delete, + XK_Clear, Qt::Key_Delete, + XK_Pause, Qt::Key_Pause, + XK_Print, Qt::Key_Print, + + XK_Home, Qt::Key_Home, + XK_End, Qt::Key_End, + XK_Left, Qt::Key_Left, + XK_Up, Qt::Key_Up, + XK_Right, Qt::Key_Right, + XK_Down, Qt::Key_Down, + XK_Prior, Qt::Key_PageUp, + XK_Next, Qt::Key_PageDown, + + XK_Shift_L, Qt::Key_Shift, + XK_Shift_R, Qt::Key_Shift, + XK_Shift_Lock, Qt::Key_Shift, + XK_Control_L, Qt::Key_Control, + XK_Control_R, Qt::Key_Control, + XK_Meta_L, Qt::Key_Meta, + XK_Meta_R, Qt::Key_Meta, + XK_Alt_L, Qt::Key_Alt, + XK_Alt_R, Qt::Key_Alt, + XK_Caps_Lock, Qt::Key_CapsLock, + XK_Num_Lock, Qt::Key_NumLock, + XK_Scroll_Lock, Qt::Key_ScrollLock, + XK_Super_L, Qt::Key_Super_L, + XK_Super_R, Qt::Key_Super_R, + XK_Menu, Qt::Key_Menu, + XK_Hyper_L, Qt::Key_Hyper_L, + XK_Hyper_R, Qt::Key_Hyper_R, + XK_Help, Qt::Key_Help, + + XK_KP_Space, Qt::Key_Space, + XK_KP_Tab, Qt::Key_Tab, + XK_KP_Enter, Qt::Key_Enter, + XK_KP_Home, Qt::Key_Home, + XK_KP_Left, Qt::Key_Left, + XK_KP_Up, Qt::Key_Up, + XK_KP_Right, Qt::Key_Right, + XK_KP_Down, Qt::Key_Down, + XK_KP_Prior, Qt::Key_PageUp, + XK_KP_Next, Qt::Key_PageDown, + XK_KP_End, Qt::Key_End, + XK_KP_Begin, Qt::Key_Clear, + XK_KP_Insert, Qt::Key_Insert, + XK_KP_Delete, Qt::Key_Delete, + XK_KP_Equal, Qt::Key_Equal, + XK_KP_Multiply, Qt::Key_Asterisk, + XK_KP_Add, Qt::Key_Plus, + XK_KP_Separator, Qt::Key_Comma, + XK_KP_Subtract, Qt::Key_Minus, + XK_KP_Decimal, Qt::Key_Period, + XK_KP_Divide, Qt::Key_Slash, + + XK_ISO_Level3_Shift, Qt::Key_AltGr, + XK_Multi_key, Qt::Key_Multi_key, + XK_Codeinput, Qt::Key_Codeinput, + XK_SingleCandidate, Qt::Key_SingleCandidate, + XK_MultipleCandidate, Qt::Key_MultipleCandidate, + XK_PreviousCandidate, Qt::Key_PreviousCandidate, + + XK_Mode_switch, Qt::Key_Mode_switch, + XK_script_switch, Qt::Key_Mode_switch, + + 0, 0 +}; + +static int keysymToQtKey(xkb_keysym_t key) +{ + int code = 0; + int i = 0; + while (KeyTbl[i]) { + if (key == KeyTbl[i]) { + code = (int)KeyTbl[i+1]; + break; + } + i += 2; + } + + return code; +} + +static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) +{ + int code = 0; + + if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { + code = Qt::Key_F1 + (int(keysym) - XKB_KEY_F1); + } else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) { + if (keysym >= XKB_KEY_KP_0) { + // numeric keypad keys + code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0); + } else { + code = keysymToQtKey(keysym); + } + modifiers |= Qt::KeypadModifier; + } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f + && text.unicode()->unicode() != 0x7f + && !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_currency)) { + code = text.unicode()->toUpper().unicode(); + } else { + // any other keys + code = keysymToQtKey(keysym); + } + + return code; +} + +#endif // QT_NO_WAYLAND_XKB + +void QWaylandInputDevice::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) +{ +#ifndef QT_NO_WAYLAND_XKB + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + char *map_str = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + + mXkbMap = xkb_map_new_from_string(mXkbContext, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, (xkb_keymap_compile_flags)0); + munmap(map_str, size); + close(fd); + + mXkbState = xkb_state_new(mXkbMap); +#else + Q_UNUSED(format); + Q_UNUSED(fd); + Q_UNUSED(size); +#endif +} + +void QWaylandInputDevice::keyboard_enter(uint32_t time, struct wl_surface *surface, struct wl_array *keys) +{ + Q_UNUSED(time); + Q_UNUSED(keys); + + if (!surface) + return; + + + QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); + mKeyboardFocus = window; + + if (!mFocusCallback) { + mFocusCallback = wl_display_sync(mDisplay); + wl_callback_add_listener(mFocusCallback, &QWaylandInputDevice::callback, this); + } +} + +void QWaylandInputDevice::keyboard_leave(uint32_t time, struct wl_surface *surface) +{ + Q_UNUSED(time); + Q_UNUSED(surface); + + mKeyboardFocus = NULL; + + // Use a callback to set the focus because we may get a leave/enter pair, and + // the latter one would be lost in the QWindowSystemInterface queue, if + // we issue the handleWindowActivated() calls immediately. + if (!mFocusCallback) { + mFocusCallback = wl_display_sync(mDisplay); + wl_callback_add_listener(mFocusCallback, &QWaylandInputDevice::callback, this); + } + mRepeatTimer.stop(); +} + +const wl_callback_listener QWaylandInputDevice::callback = { + QWaylandInputDevice::focusCallback +}; + +void QWaylandInputDevice::focusCallback(void *data, struct wl_callback *callback, uint32_t time) +{ + Q_UNUSED(time); + Q_UNUSED(callback); + QWaylandInputDevice *self = static_cast<QWaylandInputDevice *>(data); + if (self->mFocusCallback) { + wl_callback_destroy(self->mFocusCallback); + self->mFocusCallback = 0; + } + + self->mQDisplay->setLastKeyboardFocusInputDevice(self->mKeyboardFocus ? self : 0); + QWindowSystemInterface::handleWindowActivated(self->mKeyboardFocus ? self->mKeyboardFocus->window() : 0); +} + +void QWaylandInputDevice::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + Q_UNUSED(serial); + QWaylandWindow *window = mKeyboardFocus; +#ifndef QT_NO_WAYLAND_XKB + if (!mXkbMap) + return; + + uint32_t code = key + 8; + bool isDown = state != 0; + const xkb_keysym_t *syms; + uint32_t numSyms = xkb_key_get_syms(mXkbState, code, &syms); + xkb_state_update_key(mXkbState, code, + isDown ? XKB_KEY_DOWN : XKB_KEY_UP); + QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; + + if (!window) { + // We destroyed the keyboard focus surface, but the server + // didn't get the message yet. + return; + } + + int qtkey = key + 8; // qt-compositor substracts 8 for some reason + QString text; + + if (numSyms == 1) { + xkb_keysym_t sym = syms[0]; + Qt::KeyboardModifiers modifiers = this->modifiers(); + + uint utf32 = xkb_keysym_to_utf32(sym); + text = QString::fromUcs4(&utf32, 1); + + qtkey = keysymToQtKey(sym, modifiers, text); + + QWindowSystemInterface::handleExtendedKeyEvent(window->window(), + time, type, qtkey, + modifiers, + code, 0, 0, text); + } +#else + // Generic fallback for single hard keys: Assume 'key' is a Qt key code. + if (window) { + QWindowSystemInterface::handleExtendedKeyEvent(window->window(), + time, type, + qtkey, + Qt::NoModifier, + code, 0, 0); + } +#endif + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + mRepeatKey = qtkey; + mRepeatCode = code; + mRepeatTime = time; + mRepeatText = text; + mRepeatTimer.setInterval(400); + mRepeatTimer.start(); + } else { + mRepeatTimer.stop(); + } +} + +void QWaylandInputDevice::repeatKey() +{ + mRepeatTimer.setInterval(25); + QWindowSystemInterface::handleExtendedKeyEvent(mKeyboardFocus->window(), + mRepeatTime, QEvent::KeyPress, mRepeatKey, + Qt::NoModifier, + mRepeatCode, 0, 0, mRepeatText); +} + +void QWaylandInputDevice::keyboard_modifiers(uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + Q_UNUSED(serial); +#ifndef QT_NO_WAYLAND_XKB + if (mXkbState) + xkb_state_update_mask(mXkbState, + mods_depressed, mods_latched, mods_locked, + 0, 0, group); +#else + Q_UNUSED(serial); + Q_UNUSED(mods_depressed); + Q_UNUSED(mods_latched); + Q_UNUSED(mods_locked); + Q_UNUSED(group); +#endif +} + +void QWaylandInputDevice::touch_down(uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + Q_UNUSED(serial); + Q_UNUSED(time); + mTouchFocus = QWaylandWindow::fromWlSurface(surface); + handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed); +} + +void QWaylandInputDevice::touch_up(uint32_t serial, uint32_t time, int32_t id) +{ + Q_UNUSED(serial); + Q_UNUSED(time); + mTouchFocus = 0; + handleTouchPoint(id, 0, 0, Qt::TouchPointReleased); +} + +void QWaylandInputDevice::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + Q_UNUSED(time); + handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointMoved); +} + +void QWaylandInputDevice::touch_cancel() +{ + mPrevTouchPoints.clear(); + mTouchPoints.clear(); + + QWaylandTouchExtension *touchExt = mQDisplay->touchExtension(); + if (touchExt) + touchExt->touchCanceled(); + + QWindowSystemInterface::handleTouchCancelEvent(0, mTouchDevice); +} + +void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state) +{ + QWindowSystemInterface::TouchPoint tp; + + // Find out the coordinates for Released events. + bool coordsOk = false; + if (state == Qt::TouchPointReleased) + for (int i = 0; i < mPrevTouchPoints.count(); ++i) + if (mPrevTouchPoints.at(i).id == id) { + tp.area = mPrevTouchPoints.at(i).area; + coordsOk = true; + break; + } + + if (!coordsOk) { + // x and y are surface relative. + // We need a global (screen) position. + QWaylandWindow *win = mTouchFocus; + + //is it possible that mTouchFocus is null; + if (!win) + win = mPointerFocus; + if (!win) + win = mKeyboardFocus; + if (!win || !win->window()) + return; + + tp.area = QRectF(0, 0, 8, 8); + QMargins margins = win->frameMargins(); + tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x+margins.left(), y+margins.top()))); + } + + tp.state = state; + tp.id = id; + tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; + mTouchPoints.append(tp); +} + +void QWaylandInputDevice::touch_frame() +{ + // Copy all points, that are in the previous but not in the current list, as stationary. + for (int i = 0; i < mPrevTouchPoints.count(); ++i) { + const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i)); + if (prevPoint.state == Qt::TouchPointReleased) + continue; + bool found = false; + for (int j = 0; j < mTouchPoints.count(); ++j) + if (mTouchPoints.at(j).id == prevPoint.id) { + found = true; + break; + } + if (!found) { + QWindowSystemInterface::TouchPoint p = prevPoint; + p.state = Qt::TouchPointStationary; + mTouchPoints.append(p); + } + } + + if (mTouchPoints.isEmpty()) { + mPrevTouchPoints.clear(); + return; + } + + QWindow *window = mTouchFocus ? mTouchFocus->window() : 0; + + QWindowSystemInterface::handleTouchEvent(window, mTouchDevice, mTouchPoints); + + bool allReleased = true; + for (int i = 0; i < mTouchPoints.count(); ++i) + if (mTouchPoints.at(i).state != Qt::TouchPointReleased) { + allReleased = false; + break; + } + + mPrevTouchPoints = mTouchPoints; + mTouchPoints.clear(); + + if (allReleased) { + QWindowSystemInterface::handleTouchEvent(window, mTouchDevice, mTouchPoints); + mPrevTouchPoints.clear(); + } +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandinputdevice.h b/src/client/qwaylandinputdevice.h new file mode 100644 index 00000000..625d773d --- /dev/null +++ b/src/client/qwaylandinputdevice.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDINPUTDEVICE_H +#define QWAYLANDINPUTDEVICE_H + +#include "qwaylandwindow.h" + +#include <QSocketNotifier> +#include <QObject> +#include <QTimer> +#include <qpa/qplatformintegration.h> +#include <qpa/qplatformscreen.h> +#include <qpa/qwindowsysteminterface.h> + +#include <wayland-client.h> + +#include <QtWaylandClient/private/qwayland-wayland.h> + +#ifndef QT_NO_WAYLAND_XKB +struct xkb_context; +struct xkb_keymap; +struct xkb_state; +#endif + +QT_BEGIN_NAMESPACE + +class QWaylandWindow; +class QWaylandDisplay; +class QWaylandDataDevice; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice + : public QObject + , public QtWayland::wl_pointer + , public QtWayland::wl_keyboard + , public QtWayland::wl_touch + , public QtWayland::wl_seat +{ + Q_OBJECT +public: + QWaylandInputDevice(QWaylandDisplay *display, uint32_t id); + ~QWaylandInputDevice(); + + uint32_t capabilities() const { return mCaps; } + + struct ::wl_seat *wl_seat() { return QtWayland::wl_seat::object(); } + + void setCursor(Qt::CursorShape cursor, QWaylandScreen *screen); + void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image); + void handleWindowDestroyed(QWaylandWindow *window); + + void setDataDevice(QWaylandDataDevice *device); + QWaylandDataDevice *dataDevice() const; + + void removeMouseButtonFromState(Qt::MouseButton button); + + QWaylandWindow *pointerFocus() const; + + Qt::KeyboardModifiers modifiers() const; + + uint32_t serial() const; + uint32_t cursorSerial() const { return mCursorSerial; } + +private slots: + void repeatKey(); + +private: + QWaylandDisplay *mQDisplay; + struct wl_display *mDisplay; + struct wl_callback *mFocusCallback; + + uint32_t mCaps; + + struct wl_surface *pointerSurface; + + QWaylandDataDevice *mDataDevice; + QWaylandWindow *mPointerFocus; + QWaylandWindow *mKeyboardFocus; + QWaylandWindow *mTouchFocus; + + Qt::MouseButtons mButtons; + QPointF mSurfacePos; + QPointF mGlobalPos; + uint32_t mTime; + uint32_t mSerial; + uint32_t mEnterSerial; + uint32_t mCursorSerial; + + void seat_capabilities(uint32_t caps) Q_DECL_OVERRIDE; + + void pointer_enter(uint32_t serial, struct wl_surface *surface, + wl_fixed_t sx, wl_fixed_t sy) Q_DECL_OVERRIDE; + void pointer_leave(uint32_t time, struct wl_surface *surface); + void pointer_motion(uint32_t time, + wl_fixed_t sx, wl_fixed_t sy) Q_DECL_OVERRIDE; + void pointer_button(uint32_t serial, uint32_t time, + uint32_t button, uint32_t state) Q_DECL_OVERRIDE; + void pointer_axis(uint32_t time, + uint32_t axis, + wl_fixed_t value) Q_DECL_OVERRIDE; + + void keyboard_keymap(uint32_t format, + int32_t fd, + uint32_t size) Q_DECL_OVERRIDE; + void keyboard_enter(uint32_t time, + struct wl_surface *surface, + struct wl_array *keys) Q_DECL_OVERRIDE; + void keyboard_leave(uint32_t time, + struct wl_surface *surface) Q_DECL_OVERRIDE; + void keyboard_key(uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) Q_DECL_OVERRIDE; + void keyboard_modifiers(uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) Q_DECL_OVERRIDE; + + void touch_down(uint32_t serial, + uint32_t time, + struct wl_surface *surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) Q_DECL_OVERRIDE; + void touch_up(uint32_t serial, + uint32_t time, + int32_t id) Q_DECL_OVERRIDE; + void touch_motion(uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) Q_DECL_OVERRIDE; + void touch_frame() Q_DECL_OVERRIDE; + void touch_cancel() Q_DECL_OVERRIDE; + + void handleTouchPoint(int id, double x, double y, Qt::TouchPointState state); + + static const wl_callback_listener callback; + static void focusCallback(void *data, struct wl_callback *callback, uint32_t time); + + QList<QWindowSystemInterface::TouchPoint> mTouchPoints; + QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints; + QTouchDevice *mTouchDevice; + +#ifndef QT_NO_WAYLAND_XKB + xkb_context *mXkbContext; + xkb_keymap *mXkbMap; + xkb_state *mXkbState; +#endif + + int mRepeatKey; + uint32_t mRepeatCode; + uint32_t mRepeatTime; + QString mRepeatText; + QTimer mRepeatTimer; + + friend class QWaylandTouchExtension; + friend class QWaylandQtKeyExtension; +}; + +inline uint32_t QWaylandInputDevice::serial() const +{ + return mSerial; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp new file mode 100644 index 00000000..9c02419b --- /dev/null +++ b/src/client/qwaylandintegration.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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 "qwaylandintegration.h" + +#include "qwaylanddisplay.h" +#include "qwaylandinputcontext.h" +#include "qwaylandshmbackingstore.h" +#include "qwaylandshmwindow.h" +#include "qwaylandnativeinterface.h" +#include "qwaylandclipboard.h" +#include "qwaylanddnd.h" +#include "qwaylandwindowmanagerintegration.h" + +#include "QtPlatformSupport/private/qgenericunixfontdatabase_p.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixthemes_p.h> + +#include <QtGui/private/qguiapplication_p.h> + +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformcursor.h> +#include <QtGui/QSurfaceFormat> +#include <QtGui/QOpenGLContext> + +#include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qplatformaccessibility.h> +#include <qpa/qplatforminputcontext.h> + +#ifdef QT_WAYLAND_GL_SUPPORT +#include "qwaylandglintegration.h" +#endif + + +QT_BEGIN_NAMESPACE + +class GenericWaylandTheme: public QGenericUnixTheme +{ +public: + static QStringList themeNames() + { + QStringList result; + + if (QGuiApplication::desktopSettingsAware()) { + const QByteArray desktopEnvironment = QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment(); + + // Ignore X11 desktop environments + if (!desktopEnvironment.isEmpty() && + desktopEnvironment != QByteArrayLiteral("UNKNOWN") && + desktopEnvironment != QByteArrayLiteral("KDE") && + desktopEnvironment != QByteArrayLiteral("GNOME") && + desktopEnvironment != QByteArrayLiteral("UNITY") && + desktopEnvironment != QByteArrayLiteral("MATE") && + desktopEnvironment != QByteArrayLiteral("XFCE") && + desktopEnvironment != QByteArrayLiteral("LXDE")) + result.push_back(desktopEnvironment.toLower()); + } + + if (result.isEmpty()) + result.push_back(QLatin1String(QGenericUnixTheme::name)); + + return result; + } +}; + +QWaylandIntegration::QWaylandIntegration() + : mFontDb(new QGenericUnixFontDatabase()) + , mNativeInterface(new QWaylandNativeInterface(this)) +#ifndef QT_NO_ACCESSIBILITY + , mAccessibility(new QPlatformAccessibility()) +#else + , mAccessibility(0) +#endif +{ + mDisplay = new QWaylandDisplay(); + mClipboard = new QWaylandClipboard(mDisplay); + mDrag = new QWaylandDrag(mDisplay); + + foreach (QPlatformScreen *screen, mDisplay->screens()) + screenAdded(screen); + + mInputContext.reset(new QWaylandInputContext(mDisplay)); +} + +QWaylandIntegration::~QWaylandIntegration() +{ + delete mDrag; + delete mClipboard; +#ifndef QT_NO_ACCESSIBILITY + delete mAccessibility; +#endif + delete mNativeInterface; + delete mDisplay; +} + +QPlatformNativeInterface * QWaylandIntegration::nativeInterface() const +{ + return mNativeInterface; +} + +bool QWaylandIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: +#ifdef QT_WAYLAND_GL_SUPPORT + return true; +#else + return false; +#endif + case ThreadedOpenGL: +#ifdef QT_WAYLAND_GL_SUPPORT + return mDisplay->eglIntegration()->supportsThreadedOpenGL(); +#else + return false; +#endif + case BufferQueueingOpenGL: + return true; + case MultipleWindows: + case NonFullScreenWindows: + return true; + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) const +{ +#ifdef QT_WAYLAND_GL_SUPPORT + if (window->surfaceType() == QWindow::OpenGLSurface) + return mDisplay->eglIntegration()->createEglWindow(window); +#endif + return new QWaylandShmWindow(window); +} + +QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ +#ifdef QT_WAYLAND_GL_SUPPORT + return mDisplay->eglIntegration()->createPlatformOpenGLContext(context->format(), context->shareHandle()); +#else + Q_UNUSED(context); + return 0; +#endif +} + +QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QWaylandShmBackingStore(window); +} + +QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const +{ + return createUnixEventDispatcher(); +} + +void QWaylandIntegration::initialize() +{ + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay, SLOT(flushRequests())); +} + +QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const +{ + return mFontDb; +} + +QPlatformClipboard *QWaylandIntegration::clipboard() const +{ + return mClipboard; +} + +QPlatformDrag *QWaylandIntegration::drag() const +{ + return mDrag; +} + +QPlatformInputContext *QWaylandIntegration::inputContext() const +{ + return mInputContext.data(); +} + +QVariant QWaylandIntegration::styleHint(StyleHint hint) const +{ + if (hint == ShowIsFullScreen && mDisplay->windowManagerIntegration()) + return mDisplay->windowManagerIntegration()->showIsFullScreen(); + + return QPlatformIntegration::styleHint(hint); +} + +QPlatformAccessibility *QWaylandIntegration::accessibility() const +{ + return mAccessibility; +} + +QPlatformServices *QWaylandIntegration::services() const +{ + return mDisplay->windowManagerIntegration(); +} + +QWaylandDisplay *QWaylandIntegration::display() const +{ + return mDisplay; +} + +QStringList QWaylandIntegration::themeNames() const +{ + return GenericWaylandTheme::themeNames(); +} + +QPlatformTheme *QWaylandIntegration::createPlatformTheme(const QString &name) const +{ + return GenericWaylandTheme::createUnixTheme(name); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandintegration.h b/src/client/qwaylandintegration.h new file mode 100644 index 00000000..8886c28d --- /dev/null +++ b/src/client/qwaylandintegration.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QPLATFORMINTEGRATION_WAYLAND_H +#define QPLATFORMINTEGRATION_WAYLAND_H + +#include <qpa/qplatformintegration.h> + +#include <QtWaylandClient/qwaylandclientexport.h> +QT_BEGIN_NAMESPACE + +class QWaylandBuffer; +class QWaylandDisplay; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandIntegration : public QPlatformIntegration +{ +public: + QWaylandIntegration(); + ~QWaylandIntegration(); + + bool hasCapability(QPlatformIntegration::Capability cap) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + + QAbstractEventDispatcher *createEventDispatcher() const; + void initialize(); + + QPlatformFontDatabase *fontDatabase() const; + + QPlatformNativeInterface *nativeInterface() const; + + QPlatformClipboard *clipboard() const; + + QPlatformDrag *drag() const; + + QPlatformInputContext *inputContext() const; + + QVariant styleHint(StyleHint hint) const; + + QPlatformAccessibility *accessibility() const; + + QPlatformServices *services() const; + + QWaylandDisplay *display() const; + + QStringList themeNames() const; + + QPlatformTheme *createPlatformTheme(const QString &name) const; + +private: + QPlatformFontDatabase *mFontDb; + QPlatformClipboard *mClipboard; + QPlatformDrag *mDrag; + QWaylandDisplay *mDisplay; + QPlatformNativeInterface *mNativeInterface; + QScopedPointer<QPlatformInputContext> mInputContext; + QPlatformAccessibility *mAccessibility; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp new file mode 100644 index 00000000..354e8dba --- /dev/null +++ b/src/client/qwaylandnativeinterface.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 "qwaylandnativeinterface.h" +#include "qwaylanddisplay.h" +#include "qwaylandwindow.h" +#include "qwaylandextendedsurface.h" +#include "qwaylandintegration.h" +#include "qwaylanddisplay.h" +#include "qwaylandwindowmanagerintegration.h" +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QScreen> + +QT_BEGIN_NAMESPACE + +QWaylandNativeInterface::QWaylandNativeInterface(QWaylandIntegration *integration) + : m_integration(integration) +{ +} + +void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + + if (lowerCaseResource == "display") + return m_integration->display()->wl_display(); + if (lowerCaseResource == "compositor") + return const_cast<wl_compositor *>(m_integration->display()->wl_compositor()); + + return 0; +} + +void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + + if (lowerCaseResource == "display") + return m_integration->display()->wl_display(); + if (lowerCaseResource == "compositor") + return const_cast<wl_compositor *>(m_integration->display()->wl_compositor()); + if (lowerCaseResource == "surface") { + return ((QWaylandWindow *) window->handle())->object(); + } + + return NULL; +} + +void *QWaylandNativeInterface::nativeResourceForScreen(const QByteArray &resourceString, QScreen *screen) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + + if (lowerCaseResource == "output") + return ((QWaylandScreen *) screen->handle())->output(); + + return NULL; +} + +QVariantMap QWaylandNativeInterface::windowProperties(QPlatformWindow *window) const +{ + QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(window); + if (QWaylandExtendedSurface *extendedWindow = waylandWindow->extendedWindow()) + return extendedWindow->properties(); + return QVariantMap(); +} + + +QVariant QWaylandNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const +{ + QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(window); + if (QWaylandExtendedSurface *extendedWindow = waylandWindow->extendedWindow()) + return extendedWindow->property(name); + return QVariant(); +} + +QVariant QWaylandNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const +{ + QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(window); + if (QWaylandExtendedSurface *extendedWindow = waylandWindow->extendedWindow()) { + return extendedWindow->property(name,defaultValue); + } + return defaultValue; +} + +void QWaylandNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) +{ + QWaylandWindow *wlWindow = static_cast<QWaylandWindow*>(window); + if (QWaylandExtendedSurface *extendedWindow = wlWindow->extendedWindow()) + extendedWindow->updateGenericProperty(name,value); +} + +void QWaylandNativeInterface::emitWindowPropertyChanged(QPlatformWindow *window, const QString &name) +{ + emit windowPropertyChanged(window,name); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandnativeinterface.h b/src/client/qwaylandnativeinterface.h new file mode 100644 index 00000000..c5f0fda7 --- /dev/null +++ b/src/client/qwaylandnativeinterface.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDNATIVEINTERFACE_H +#define QWAYLANDNATIVEINTERFACE_H + +#include "qwaylandscreen.h" +#include <QVariantMap> +#include <qpa/qplatformnativeinterface.h> + +QT_BEGIN_NAMESPACE + +class QWaylandIntegration; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandNativeInterface : public QPlatformNativeInterface +{ +public: + QWaylandNativeInterface(QWaylandIntegration *integration); + void *nativeResourceForIntegration(const QByteArray &resource); + void *nativeResourceForWindow(const QByteArray &resourceString, + QWindow *window); + void *nativeResourceForScreen(const QByteArray &resourceString, + QScreen *screen); + + QVariantMap windowProperties(QPlatformWindow *window) const; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); + + void emitWindowPropertyChanged(QPlatformWindow *window, const QString &name); +private: + static QWaylandScreen *qPlatformScreenForWindow(QWindow *window); + +private: + QWaylandIntegration *m_integration; + QHash<QPlatformWindow*, QVariantMap> m_windowProperties; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDNATIVEINTERFACE_H diff --git a/src/client/qwaylandqtkey.cpp b/src/client/qwaylandqtkey.cpp new file mode 100644 index 00000000..6cc4597d --- /dev/null +++ b/src/client/qwaylandqtkey.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 "qwaylandqtkey.h" +#include "qwaylandinputdevice.h" + +QT_BEGIN_NAMESPACE + +QWaylandQtKeyExtension::QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id) + : QtWayland::qt_key_extension(display->wl_registry(), id) + , m_display(display) +{ +} + +void QWaylandQtKeyExtension::key_extension_qtkey(struct wl_surface *surface, + uint32_t time, + uint32_t type, + uint32_t key, + uint32_t modifiers, + uint32_t nativeScanCode, + uint32_t nativeVirtualKey, + uint32_t nativeModifiers, + const QString &text, + uint32_t autorep, + uint32_t count) +{ + QList<QWaylandInputDevice *> inputDevices = m_display->inputDevices(); + if (!surface && inputDevices.isEmpty()) { + qWarning("qt_key_extension: handle_qtkey: No input device"); + return; + } + + QWaylandInputDevice *dev = inputDevices.first(); + QWaylandWindow *win = surface ? QWaylandWindow::fromWlSurface(surface) : dev->mKeyboardFocus; + + if (!win || !win->window()) { + qWarning("qt_key_extension: handle_qtkey: No keyboard focus"); + return; + } + + QWindow *window = win->window(); + QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::Type(type), key, Qt::KeyboardModifiers(modifiers), + nativeScanCode, nativeVirtualKey, nativeModifiers, text, + autorep, count); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandqtkey.h b/src/client/qwaylandqtkey.h new file mode 100644 index 00000000..0acc9e8a --- /dev/null +++ b/src/client/qwaylandqtkey.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDQTKEY_H +#define QWAYLANDQTKEY_H + +#include "qwaylanddisplay.h" +#include <qpa/qwindowsysteminterface.h> + +#include <QtWaylandClient/private/qwayland-qtkey-extension.h> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_CLIENT_EXPORT QWaylandQtKeyExtension : public QtWayland::qt_key_extension +{ +public: + QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id); + +private: + QWaylandDisplay *m_display; + + void key_extension_qtkey(struct wl_surface *surface, + uint32_t time, + uint32_t type, + uint32_t key, + uint32_t modifiers, + uint32_t nativeScanCode, + uint32_t nativeVirtualKey, + uint32_t nativeModifiers, + const QString &text, + uint32_t autorep, + uint32_t count) Q_DECL_OVERRIDE; + +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDQTKEY_H diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp new file mode 100644 index 00000000..cda94a7e --- /dev/null +++ b/src/client/qwaylandscreen.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** 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 "qwaylandscreen.h" + +#include "qwaylanddisplay.h" +#include "qwaylandcursor.h" +#include "qwaylandextendedoutput.h" + +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, uint32_t id) + : QtWayland::wl_output(waylandDisplay->wl_registry(), id) + , mWaylandDisplay(waylandDisplay) + , mExtendedOutput(0) + , mDepth(32) + , mRefreshRate(60000) + , mFormat(QImage::Format_ARGB32_Premultiplied) + , mOutputName(QStringLiteral("Screen%1").arg(id)) + , mWaylandCursor(new QWaylandCursor(this)) +{ + // handle case of output extension global being sent after outputs + createExtendedOutput(); +} + +QWaylandScreen::~QWaylandScreen() +{ + delete mWaylandCursor; +} + +QWaylandDisplay * QWaylandScreen::display() const +{ + return mWaylandDisplay; +} + +QRect QWaylandScreen::geometry() const +{ + return mGeometry; +} + +int QWaylandScreen::depth() const +{ + return mDepth; +} + +QImage::Format QWaylandScreen::format() const +{ + return mFormat; +} + +QDpi QWaylandScreen::logicalDpi() const +{ + static int force_dpi = !qgetenv("QT_WAYLAND_FORCE_DPI").isEmpty() ? qgetenv("QT_WAYLAND_FORCE_DPI").toInt() : -1; + if (force_dpi > 0) + return QDpi(force_dpi, force_dpi); + + return QPlatformScreen::logicalDpi(); +} + +void QWaylandScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) +{ + if (mExtendedOutput) + mExtendedOutput->setOrientationUpdateMask(mask); +} + +Qt::ScreenOrientation QWaylandScreen::orientation() const +{ + if (mExtendedOutput) + return mExtendedOutput->currentOrientation(); + return QPlatformScreen::orientation(); +} + +qreal QWaylandScreen::refreshRate() const +{ + return mRefreshRate / 1000.f; +} + +QPlatformCursor *QWaylandScreen::cursor() const +{ + return mWaylandCursor; +} + +QWaylandExtendedOutput *QWaylandScreen::extendedOutput() const +{ + return mExtendedOutput; +} + +void QWaylandScreen::createExtendedOutput() +{ + QtWayland::qt_output_extension *extension = mWaylandDisplay->outputExtension(); + if (!mExtendedOutput && extension) + mExtendedOutput = new QWaylandExtendedOutput(this, extension->get_extended_output(output())); +} + +QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window) +{ + QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window); + return static_cast<QWaylandScreen *>(platformScreen); +} + +void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refresh) +{ + if (!(flags & WL_OUTPUT_MODE_CURRENT)) + return; + + QSize size(width, height); + + if (size != mGeometry.size()) { + mGeometry.setSize(size); + QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), mGeometry); + } + + if (refresh != mRefreshRate) { + mRefreshRate = refresh; + QWindowSystemInterface::handleScreenRefreshRateChange(screen(), refreshRate()); + } +} + +void QWaylandScreen::output_geometry(int32_t x, int32_t y, + int32_t width, int32_t height, + int subpixel, + const QString &make, + const QString &model, + int32_t transform) +{ + Q_UNUSED(subpixel); + Q_UNUSED(make); + Q_UNUSED(transform); + + if (!model.isEmpty()) + mOutputName = model; + + QRect geom(x, y, width, height); + + if (mGeometry == geom) + return; + + mGeometry = geom; + QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), mGeometry); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandscreen.h b/src/client/qwaylandscreen.h new file mode 100644 index 00000000..15ae5189 --- /dev/null +++ b/src/client/qwaylandscreen.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDSCREEN_H +#define QWAYLANDSCREEN_H + +#include <qpa/qplatformscreen.h> +#include <QtWaylandClient/qwaylandclientexport.h> + +#include <QtWaylandClient/private/qwayland-wayland.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandCursor; +class QWaylandExtendedOutput; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandScreen : public QPlatformScreen, QtWayland::wl_output +{ +public: + QWaylandScreen(QWaylandDisplay *waylandDisplay, uint32_t id); + ~QWaylandScreen(); + + QWaylandDisplay *display() const; + + QRect geometry() const; + int depth() const; + QImage::Format format() const; + + QDpi logicalDpi() const Q_DECL_OVERRIDE; + + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + + Qt::ScreenOrientation orientation() const; + qreal refreshRate() const; + + QString name() const { return mOutputName; } + + QPlatformCursor *cursor() const; + QWaylandCursor *waylandCursor() const { return mWaylandCursor; }; + + ::wl_output *output() { return object(); } + + QWaylandExtendedOutput *extendedOutput() const; + void createExtendedOutput(); + + static QWaylandScreen *waylandScreenFromWindow(QWindow *window); + +private: + void output_mode(uint32_t flags, int width, int height, int refresh) Q_DECL_OVERRIDE; + void output_geometry(int32_t x, int32_t y, + int32_t width, int32_t height, + int subpixel, + const QString &make, + const QString &model, + int32_t transform) Q_DECL_OVERRIDE; + + QWaylandDisplay *mWaylandDisplay; + QWaylandExtendedOutput *mExtendedOutput; + QRect mGeometry; + int mDepth; + int mRefreshRate; + QImage::Format mFormat; + QSize mPhysicalSize; + QString mOutputName; + + QWaylandCursor *mWaylandCursor; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDSCREEN_H diff --git a/src/client/qwaylandshellsurface.cpp b/src/client/qwaylandshellsurface.cpp new file mode 100644 index 00000000..4c8ff1bc --- /dev/null +++ b/src/client/qwaylandshellsurface.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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 "qwaylandshellsurface.h" + +#include "qwaylanddisplay.h" +#include "qwaylandwindow.h" +#include "qwaylandinputdevice.h" +#include "qwaylanddecoration.h" +#include "qwaylandscreen.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandShellSurface::QWaylandShellSurface(struct ::wl_shell_surface *shell_surface, QWaylandWindow *window) + : QtWayland::wl_shell_surface(shell_surface) + , m_window(window) + , m_maximized(false) + , m_fullscreen(false) +{ +} + +QWaylandShellSurface::~QWaylandShellSurface() +{ + wl_shell_surface_destroy(object()); +} + +void QWaylandShellSurface::resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges) +{ + resize(inputDevice->wl_seat(), + inputDevice->serial(), + edges); +} + +void QWaylandShellSurface::move(QWaylandInputDevice *inputDevice) +{ + move(inputDevice->wl_seat(), + inputDevice->serial()); +} + +void QWaylandShellSurface::setMaximized() +{ + m_maximized = true; + m_size = m_window->window()->geometry().size(); + set_maximized(0); +} + +void QWaylandShellSurface::setFullscreen() +{ + m_fullscreen = true; + m_size = m_window->window()->geometry().size(); + set_fullscreen(WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, 0); +} + +void QWaylandShellSurface::setNormal() +{ + if (m_fullscreen || m_maximized) { + m_fullscreen = m_maximized = false; + setTopLevel(); + QMargins m = m_window->frameMargins(); + m_window->configure(0, m_size.width() + m.left() + m.right(), m_size.height() + m.top() + m.bottom()); + } +} + +void QWaylandShellSurface::setMinimized() +{ + // TODO: There's no wl_shell_surface API for this +} + +void QWaylandShellSurface::setTopLevel() +{ + set_toplevel(); +} + +void QWaylandShellSurface::updateTransientParent(QWindow *parent) +{ + QWaylandWindow *parent_wayland_window = static_cast<QWaylandWindow *>(parent->handle()); + if (!parent_wayland_window) + return; + + // set_transient expects a position relative to the parent + QPoint transientPos = m_window->geometry().topLeft(); // this is absolute + QWindow *parentWin = m_window->window()->transientParent(); + transientPos -= parentWin->geometry().topLeft(); + if (parent_wayland_window->decoration()) { + transientPos.setX(transientPos.x() + parent_wayland_window->decoration()->margins().left()); + transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top()); + } + + uint32_t flags = 0; + Qt::WindowFlags wf = m_window->window()->flags(); + if (wf.testFlag(Qt::ToolTip) + || wf.testFlag(Qt::WindowTransparentForInput)) + flags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE; + + set_transient(parent_wayland_window->object(), + transientPos.x(), + transientPos.y(), + flags); +} + +void QWaylandShellSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial) +{ + QWaylandWindow *parent_wayland_window = parent; + if (!parent_wayland_window) + return; + + // set_popup expects a position relative to the parent + QPoint transientPos = m_window->geometry().topLeft(); // this is absolute + transientPos -= parent_wayland_window->geometry().topLeft(); + if (parent_wayland_window->decoration()) { + transientPos.setX(transientPos.x() + parent_wayland_window->decoration()->margins().left()); + transientPos.setY(transientPos.y() + parent_wayland_window->decoration()->margins().top()); + } + + set_popup(device->wl_seat(), serial, parent_wayland_window->object(), + transientPos.x(), transientPos.y(), 0); +} + +void QWaylandShellSurface::shell_surface_ping(uint32_t serial) +{ + pong(serial); +} + +void QWaylandShellSurface::shell_surface_configure(uint32_t edges, + int32_t width, + int32_t height) +{ + m_window->configure(edges, width, height); +} + +void QWaylandShellSurface::shell_surface_popup_done() +{ + QCoreApplication::postEvent(m_window->window(), new QCloseEvent()); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandshellsurface.h b/src/client/qwaylandshellsurface.h new file mode 100644 index 00000000..25f70333 --- /dev/null +++ b/src/client/qwaylandshellsurface.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDSHELLSURFACE_H +#define QWAYLANDSHELLSURFACE_H + +#include <QtCore/QSize> + +#include <wayland-client.h> + +#include <QtWaylandClient/private/qwayland-wayland.h> +#include <QtWaylandClient/qwaylandclientexport.h> + +QT_BEGIN_NAMESPACE + +class QWaylandWindow; +class QWaylandInputDevice; +class QWindow; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandShellSurface : public QtWayland::wl_shell_surface +{ +public: + QWaylandShellSurface(struct ::wl_shell_surface *shell_surface, QWaylandWindow *window); + ~QWaylandShellSurface(); + + using QtWayland::wl_shell_surface::resize; + void resize(QWaylandInputDevice *inputDevice, enum wl_shell_surface_resize edges); + + using QtWayland::wl_shell_surface::move; + void move(QWaylandInputDevice *inputDevice); + +private: + void setMaximized(); + void setFullscreen(); + void setNormal(); + void setMinimized(); + + void setTopLevel(); + void updateTransientParent(QWindow *parent); + void setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial); + + QWaylandWindow *m_window; + bool m_maximized; + bool m_fullscreen; + QSize m_size; + + void shell_surface_ping(uint32_t serial) Q_DECL_OVERRIDE; + void shell_surface_configure(uint32_t edges, + int32_t width, + int32_t height) Q_DECL_OVERRIDE; + void shell_surface_popup_done() Q_DECL_OVERRIDE; + + friend class QWaylandWindow; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDSHELLSURFACE_H diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp new file mode 100644 index 00000000..00a4b13a --- /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 diff --git a/src/client/qwaylandshmbackingstore.h b/src/client/qwaylandshmbackingstore.h new file mode 100644 index 00000000..c7875f52 --- /dev/null +++ b/src/client/qwaylandshmbackingstore.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDSHMBACKINGSTORE_H +#define QWAYLANDSHMBACKINGSTORE_H + +#include "qwaylandbuffer.h" + +#include "qwaylanddecoration.h" +#include "qwaylandshmwindow.h" + +#include <qpa/qplatformbackingstore.h> +#include <QtGui/QImage> +#include <qpa/qplatformwindow.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer { +public: + QWaylandShmBuffer(QWaylandDisplay *display, + const QSize &size, QImage::Format format); + ~QWaylandShmBuffer(); + QSize size() const { return mImage.size(); } + QImage *image() { return &mImage; } + + QImage *imageInsideMargins(const QMargins &margins); +private: + QImage mImage; + struct wl_shm_pool *mShmPool; + QMargins mMargins; + QImage *mMarginsImage; +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingStore +{ +public: + QWaylandShmBackingStore(QWindow *window); + ~QWaylandShmBackingStore(); + + QPaintDevice *paintDevice(); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + void resize(const QSize &size, const QRegion &staticContents); + void resize(const QSize &size); + void beginPaint(const QRegion &); + void endPaint(); + + QWaylandDecoration *windowDecoration() const; + + QMargins windowDecorationMargins() const; + QImage *entireSurface() const; + void ensureSize(); + + QWaylandShmWindow *waylandWindow() const; + void iterateBuffer(); + +private: + void updateDecorations(); + + QWaylandDisplay *mDisplay; + QWaylandShmBuffer *mFrontBuffer; + QWaylandShmBuffer *mBackBuffer; + bool mFrontBufferIsDirty; + bool mPainting; + + QSize mRequestedSize; + Qt::WindowFlags mCurrentWindowFlags; + + static const struct wl_callback_listener frameCallbackListener; + static void done(void *data, + struct wl_callback *callback, + uint32_t time); + struct wl_callback *mFrameCallback; +}; + +inline QWaylandDecoration *QWaylandShmBackingStore::windowDecoration() const +{ + return waylandWindow()->decoration(); +} + +inline QMargins QWaylandShmBackingStore::windowDecorationMargins() const +{ + if (windowDecoration()) + return windowDecoration()->margins(); + return QMargins(); +} + +inline QWaylandShmWindow *QWaylandShmBackingStore::waylandWindow() const +{ + return static_cast<QWaylandShmWindow *>(window()->handle()); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/client/qwaylandshmwindow.cpp b/src/client/qwaylandshmwindow.cpp new file mode 100644 index 00000000..48a1bfd5 --- /dev/null +++ b/src/client/qwaylandshmwindow.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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 "qwaylandshmwindow.h" + +#include "qwaylandbuffer.h" + +#include <QtCore/QVector> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandShmWindow::QWaylandShmWindow(QWindow *window) + : QWaylandWindow(window) + , mBackingStore(0) +{ +} + +QWaylandShmWindow::~QWaylandShmWindow() +{ + +} + +QWaylandWindow::WindowType QWaylandShmWindow::windowType() const +{ + return QWaylandWindow::Shm; +} + +void QWaylandShmWindow::setBackingStore(QWaylandShmBackingStore *backingStore) +{ + mBackingStore = backingStore; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandshmwindow.h b/src/client/qwaylandshmwindow.h new file mode 100644 index 00000000..e443bb18 --- /dev/null +++ b/src/client/qwaylandshmwindow.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDSHMWINDOW_H +#define QWAYLANDSHMWINDOW_H + +#include "qwaylandwindow.h" +#include <QtGui/QRegion> + +QT_BEGIN_NAMESPACE + +class QWaylandShmBackingStore; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandShmWindow : public QWaylandWindow +{ +public: + QWaylandShmWindow(QWindow *window); + ~QWaylandShmWindow(); + + WindowType windowType() const; + QSurfaceFormat format() const { return QSurfaceFormat(); } + + void setBackingStore(QWaylandShmBackingStore *backingStore); + QWaylandShmBackingStore *backingStore() const; + +private: + QWaylandShmBackingStore *mBackingStore; +}; + +inline QWaylandShmBackingStore *QWaylandShmWindow::backingStore() const +{ + return mBackingStore; +} + +QT_END_NAMESPACE + +#endif // QWAYLANDSHMWINDOW_H diff --git a/src/client/qwaylandsubsurface.cpp b/src/client/qwaylandsubsurface.cpp new file mode 100644 index 00000000..0e9d575a --- /dev/null +++ b/src/client/qwaylandsubsurface.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 "qwaylandsubsurface.h" + +#include "qwaylandwindow.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandSubSurface::QWaylandSubSurface(QWaylandWindow *window, struct ::qt_sub_surface *sub_surface) + : QtWayland::qt_sub_surface(sub_surface) + , m_window(window) +{ +} + +void QWaylandSubSurface::setParent(const QWaylandWindow *parent) +{ + QWaylandSubSurface *parentSurface = parent ? parent->subSurfaceWindow() : 0; + if (parentSurface) { + int x = m_window->geometry().x() + parent->frameMargins().left(); + int y = m_window->geometry().y() + parent->frameMargins().top(); + parentSurface->attach_sub_surface(object(), x, y); + } +} + +static void setPositionToParent(QWaylandWindow *parentWaylandWindow) +{ + QObjectList children = parentWaylandWindow->window()->children(); + for (int i = 0; i < children.size(); i++) { + QWindow *childWindow = qobject_cast<QWindow *>(children.at(i)); + if (!childWindow) + continue; + + if (childWindow->handle()) { + QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(childWindow->handle()); + waylandWindow->subSurfaceWindow()->setParent(parentWaylandWindow); + setPositionToParent(waylandWindow); + } + } +} + +void QWaylandSubSurface::adjustPositionOfChildren() +{ + QWindow *window = m_window->window(); + if (window->parent()) { + qDebug() << "QWaylandSubSurface::adjustPositionOfChildren not called for toplevel window"; + } + setPositionToParent(m_window); +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandsubsurface.h b/src/client/qwaylandsubsurface.h new file mode 100644 index 00000000..97158b6a --- /dev/null +++ b/src/client/qwaylandsubsurface.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDSUBSURFACE_H +#define QWAYLANDSUBSURFACE_H + +#include <wayland-client.h> + +#include <QtCore/qglobal.h> + +#include <QtWaylandClient/qwaylandclientexport.h> + +#include <QtWaylandClient/private/qwayland-sub-surface-extension.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandWindow; +class QWaylandSubSurface; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandSubSurface : public QtWayland::qt_sub_surface +{ +public: + QWaylandSubSurface(QWaylandWindow *window, struct ::qt_sub_surface *sub_surface); + + void setParent(const QWaylandWindow *parent); + void adjustPositionOfChildren(); + +private: + QWaylandWindow *m_window; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDSUBSURFACE_H diff --git a/src/client/qwaylandtouch.cpp b/src/client/qwaylandtouch.cpp new file mode 100644 index 00000000..5835d9d3 --- /dev/null +++ b/src/client/qwaylandtouch.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** 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 "qwaylandtouch.h" +#include "qwaylandinputdevice.h" + +QT_BEGIN_NAMESPACE + +QWaylandTouchExtension::QWaylandTouchExtension(QWaylandDisplay *display, uint32_t id) + : QtWayland::qt_touch_extension(display->wl_registry(), id), + mDisplay(display), + mTouchDevice(0), + mPointsLeft(0), + mFlags(0), + mMouseSourceId(-1), + mInputDevice(0) +{ +} + +void QWaylandTouchExtension::registerDevice(int caps) +{ + mTouchDevice = new QTouchDevice; + mTouchDevice->setType(QTouchDevice::TouchScreen); + mTouchDevice->setCapabilities(QTouchDevice::Capabilities(caps)); + QWindowSystemInterface::registerTouchDevice(mTouchDevice); +} + +static inline qreal fromFixed(int f) +{ + return f / qreal(10000); +} + +void QWaylandTouchExtension::touch_extension_touch(uint32_t time, + uint32_t id, uint32_t state, int32_t x, int32_t y, + int32_t normalized_x, int32_t normalized_y, + int32_t width, int32_t height, uint32_t pressure, + int32_t velocity_x, int32_t velocity_y, + uint32_t flags, wl_array *rawdata) +{ + if (!mInputDevice) { + QList<QWaylandInputDevice *> inputDevices = mDisplay->inputDevices(); + if (inputDevices.isEmpty()) { + qWarning("qt_touch_extension: handle_touch: No input devices"); + return; + } + mInputDevice = inputDevices.first(); + } + QWaylandWindow *win = mInputDevice->mTouchFocus; + if (!win) + win = mInputDevice->mPointerFocus; + if (!win) + win = mInputDevice->mKeyboardFocus; + if (!win || !win->window()) { + qWarning("qt_touch_extension: handle_touch: No pointer focus"); + return; + } + mTargetWindow = win->window(); + + QWindowSystemInterface::TouchPoint tp; + tp.id = id; + tp.state = Qt::TouchPointState(int(state & 0xFFFF)); + int sentPointCount = state >> 16; + if (!mPointsLeft) { + Q_ASSERT(sentPointCount > 0); + mPointsLeft = sentPointCount; + } + tp.flags = QTouchEvent::TouchPoint::InfoFlags(int(flags & 0xFFFF)); + + if (!mTouchDevice) + registerDevice(flags >> 16); + + tp.area = QRectF(0, 0, fromFixed(width), fromFixed(height)); + // Got surface-relative coords but need a (virtual) screen position. + QPointF relPos = QPointF(fromFixed(x), fromFixed(y)); + QPointF delta = relPos - relPos.toPoint(); + tp.area.moveCenter(mTargetWindow->mapToGlobal(relPos.toPoint()) + delta); + + tp.normalPosition.setX(fromFixed(normalized_x)); + tp.normalPosition.setY(fromFixed(normalized_y)); + tp.pressure = pressure / 255.0; + tp.velocity.setX(fromFixed(velocity_x)); + tp.velocity.setY(fromFixed(velocity_y)); + + if (rawdata) { + const int rawPosCount = rawdata->size / sizeof(float) / 2; + float *p = static_cast<float *>(rawdata->data); + for (int i = 0; i < rawPosCount; ++i) { + float x = *p++; + float y = *p++; + tp.rawPositions.append(QPointF(x, y)); + } + } + + mTouchPoints.append(tp); + mTimestamp = time; + + if (!--mPointsLeft) + sendTouchEvent(); +} + +void QWaylandTouchExtension::sendTouchEvent() +{ + // Copy all points, that are in the previous but not in the current list, as stationary. + for (int i = 0; i < mPrevTouchPoints.count(); ++i) { + const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i)); + if (prevPoint.state == Qt::TouchPointReleased) + continue; + bool found = false; + for (int j = 0; j < mTouchPoints.count(); ++j) + if (mTouchPoints.at(j).id == prevPoint.id) { + found = true; + break; + } + if (!found) { + QWindowSystemInterface::TouchPoint p = prevPoint; + p.state = Qt::TouchPointStationary; + mTouchPoints.append(p); + } + } + + if (mTouchPoints.isEmpty()) { + mPrevTouchPoints.clear(); + return; + } + + QWindowSystemInterface::handleTouchEvent(mTargetWindow, mTimestamp, mTouchDevice, mTouchPoints); + + Qt::TouchPointStates states = 0; + for (int i = 0; i < mTouchPoints.count(); ++i) + states |= mTouchPoints.at(i).state; + + if (mFlags & QT_TOUCH_EXTENSION_FLAGS_MOUSE_FROM_TOUCH) { + if (states == Qt::TouchPointPressed) + mMouseSourceId = mTouchPoints.first().id; + for (int i = 0; i < mTouchPoints.count(); ++i) { + const QWindowSystemInterface::TouchPoint &tp(mTouchPoints.at(i)); + if (tp.id == mMouseSourceId) { + Qt::MouseButtons buttons = tp.state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton; + mLastMouseGlobal = tp.area.center(); + QPoint globalPoint = mLastMouseGlobal.toPoint(); + QPointF delta = mLastMouseGlobal - globalPoint; + mLastMouseLocal = mTargetWindow->mapFromGlobal(globalPoint) + delta; + QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal, buttons); + if (buttons == Qt::NoButton) + mMouseSourceId = -1; + break; + } + } + } + + mPrevTouchPoints = mTouchPoints; + mTouchPoints.clear(); + + if (states == Qt::TouchPointReleased) + mPrevTouchPoints.clear(); +} + +void QWaylandTouchExtension::touchCanceled() +{ + mTouchPoints.clear(); + mPrevTouchPoints.clear(); + if (mMouseSourceId != -1) + QWindowSystemInterface::handleMouseEvent(mTargetWindow, mTimestamp, mLastMouseLocal, mLastMouseGlobal, Qt::NoButton); +} + +void QWaylandTouchExtension::touch_extension_configure(uint32_t flags) +{ + mFlags = flags; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandtouch.h b/src/client/qwaylandtouch.h new file mode 100644 index 00000000..0d14330e --- /dev/null +++ b/src/client/qwaylandtouch.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDTOUCh_H +#define QWAYLANDTOUCH_H + +#include "qwaylanddisplay.h" +#include <qpa/qwindowsysteminterface.h> + +#include <QtWaylandClient/private/qwayland-touch-extension.h> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_CLIENT_EXPORT QWaylandTouchExtension : public QtWayland::qt_touch_extension +{ +public: + QWaylandTouchExtension(QWaylandDisplay *display, uint32_t id); + + void touchCanceled(); + +private: + void registerDevice(int caps); + + QWaylandDisplay *mDisplay; + + void touch_extension_touch(uint32_t time, + uint32_t id, + uint32_t state, + int32_t x, + int32_t y, + int32_t normalized_x, + int32_t normalized_y, + int32_t width, + int32_t height, + uint32_t pressure, + int32_t velocity_x, + int32_t velocity_y, + uint32_t flags, + struct wl_array *rawdata) Q_DECL_OVERRIDE; + void touch_extension_configure(uint32_t flags) Q_DECL_OVERRIDE; + + void sendTouchEvent(); + + QList<QWindowSystemInterface::TouchPoint> mTouchPoints; + QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints; + QTouchDevice *mTouchDevice; + uint32_t mTimestamp; + int mPointsLeft; + uint32_t mFlags; + int mMouseSourceId; + QPointF mLastMouseLocal; + QPointF mLastMouseGlobal; + QWindow *mTargetWindow; + QWaylandInputDevice *mInputDevice; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDTOUCH_H diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp new file mode 100644 index 00000000..b64d3e6a --- /dev/null +++ b/src/client/qwaylandwindow.cpp @@ -0,0 +1,608 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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 "qwaylandwindow.h" + +#include "qwaylandbuffer.h" +#include "qwaylanddisplay.h" +#include "qwaylandinputdevice.h" +#include "qwaylandscreen.h" +#include "qwaylandshellsurface.h" +#include "qwaylandextendedsurface.h" +#include "qwaylandsubsurface.h" +#include "qwaylanddecoration.h" +#include "qwaylandwindowmanagerintegration.h" + +#include <QtCore/QFileInfo> +#include <QtGui/QWindow> + +#include <QGuiApplication> +#include <qpa/qwindowsysteminterface.h> + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +QWaylandWindow *QWaylandWindow::mMouseGrab = 0; + +QWaylandWindow::QWaylandWindow(QWindow *window) + : QObject() + , QPlatformWindow(window) + , mScreen(QWaylandScreen::waylandScreenFromWindow(window)) + , mDisplay(mScreen->display()) + , mShellSurface(0) + , mExtendedWindow(0) + , mSubSurfaceWindow(0) + , mWindowDecoration(0) + , mMouseEventsInContentArea(false) + , mMousePressedInContentArea(Qt::NoButton) + , m_cursorShape(Qt::ArrowCursor) + , mBuffer(0) + , mWaitingForFrameSync(false) + , mFrameCallback(0) + , mRequestResizeSent(false) + , mCanResize(true) + , mSentInitialResize(false) + , mMouseDevice(0) + , mMouseSerial(0) + , mState(Qt::WindowNoState) +{ + init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this))); + + static WId id = 1; + mWindowId = id++; + + if (mDisplay->shell() && window->type() & Qt::Window && !(window->flags() & Qt::BypassWindowManagerHint)) + mShellSurface = new QWaylandShellSurface(mDisplay->shell()->get_shell_surface(object()), this); + if (mDisplay->windowExtension()) + mExtendedWindow = new QWaylandExtendedSurface(this, mDisplay->windowExtension()->get_extended_surface(object())); + if (mDisplay->subSurfaceExtension()) + mSubSurfaceWindow = new QWaylandSubSurface(this, mDisplay->subSurfaceExtension()->get_sub_surface_aware_surface(object())); + + if (mShellSurface) { + // Set initial surface title + mShellSurface->set_title(window->title()); + + // Set surface class to the .desktop file name (obtained from executable name) + QFileInfo exeFileInfo(qApp->applicationFilePath()); + QString className = exeFileInfo.baseName() + QLatin1String(".desktop"); + mShellSurface->set_class(className); + } + + if (QPlatformWindow::parent() && mSubSurfaceWindow) { + mSubSurfaceWindow->setParent(static_cast<const QWaylandWindow *>(QPlatformWindow::parent())); + } else if (window->transientParent() && mShellSurface) { + if (window->type() != Qt::Popup) { + mShellSurface->updateTransientParent(window->transientParent()); + } + } else if (mShellSurface) { + mShellSurface->setTopLevel(); + } + + setWindowFlags(window->flags()); + setGeometry(window->geometry()); + setWindowState(window->windowState()); +} + +QWaylandWindow::~QWaylandWindow() +{ + if (isInitialized()) { + delete mShellSurface; + delete mExtendedWindow; + destroy(); + } + if (mFrameCallback) + wl_callback_destroy(mFrameCallback); + + QList<QWaylandInputDevice *> inputDevices = mDisplay->inputDevices(); + for (int i = 0; i < inputDevices.size(); ++i) + inputDevices.at(i)->handleWindowDestroyed(this); + + const QWindow *parent = window(); + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->transientParent() == parent) + QWindowSystemInterface::handleCloseEvent(w); + } + + if (mMouseGrab == this) { + mMouseGrab = 0; + } +} + +QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface) +{ + return static_cast<QWaylandWindow *>(static_cast<QtWayland::wl_surface *>(wl_surface_get_user_data(surface))); +} + +WId QWaylandWindow::winId() const +{ + return mWindowId; +} + +void QWaylandWindow::setParent(const QPlatformWindow *parent) +{ + const QWaylandWindow *parentWaylandWindow = static_cast<const QWaylandWindow *>(parent); + if (subSurfaceWindow()) { + subSurfaceWindow()->setParent(parentWaylandWindow); + } +} + +void QWaylandWindow::setWindowTitle(const QString &title) +{ + if (mShellSurface) { + mShellSurface->set_title(title); + } + + if (mWindowDecoration && window()->isVisible()) + mWindowDecoration->update(); +} + +void QWaylandWindow::setWindowIcon(const QIcon &icon) +{ + mWindowIcon = icon; + + if (mWindowDecoration && window()->isVisible()) + mWindowDecoration->update(); +} + +void QWaylandWindow::setGeometry(const QRect &rect) +{ + QPlatformWindow::setGeometry(QRect(rect.x(), rect.y(), + qBound(window()->minimumWidth(), rect.width(), window()->maximumWidth()), + qBound(window()->minimumHeight(), rect.height(), window()->maximumHeight()))); + + if (shellSurface() && window()->transientParent() && window()->type() != Qt::Popup) + shellSurface()->updateTransientParent(window()->transientParent()); + + if (mWindowDecoration && window()->isVisible()) + mWindowDecoration->update(); + + if (mConfigure.isEmpty()) { + QWindowSystemInterface::handleGeometryChange(window(), geometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + } +} + +void QWaylandWindow::setVisible(bool visible) +{ + if (visible) { + if (mBuffer) + attach(mBuffer->buffer(), 0, 0); + + if (window()->type() == Qt::Popup && transientParent()) { + QWaylandWindow *parent = transientParent(); + mMouseDevice = parent->mMouseDevice; + mMouseSerial = parent->mMouseSerial; + + if (mMouseDevice) + mShellSurface->setPopup(transientParent(), mMouseDevice, mMouseSerial); + } + + if (!mSentInitialResize) { + QWindowSystemInterface::handleGeometryChange(window(), geometry()); + mSentInitialResize = true; + } + + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + // Don't flush the events here, or else the newly visible window may start drawing, but since + // there was no frame before it will be stuck at the waitForFrameSync() in + // QWaylandShmBackingStore::beginPaint(). + } else { + QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + attach(static_cast<QWaylandBuffer *>(0), 0, 0); + } + damage(QRect(QPoint(0,0),geometry().size())); + commit(); +} + + +void QWaylandWindow::raise() +{ + if (mExtendedWindow) + mExtendedWindow->raise(); +} + + +void QWaylandWindow::lower() +{ + if (mExtendedWindow) + mExtendedWindow->lower(); +} + +void QWaylandWindow::configure(uint32_t edges, int32_t width, int32_t height) +{ + QMutexLocker resizeLocker(&mResizeLock); + mConfigure.edges |= edges; + mConfigure.width = width; + mConfigure.height = height; + + if (!mRequestResizeSent && !mConfigure.isEmpty()) { + mRequestResizeSent= true; + QMetaObject::invokeMethod(this, "requestResize", Qt::QueuedConnection); + } +} + +void QWaylandWindow::doResize() +{ + if (mConfigure.isEmpty()) { + return; + } + + int widthWithoutMargins = qMax(mConfigure.width-(frameMargins().left() +frameMargins().right()),1); + int heightWithoutMargins = qMax(mConfigure.height-(frameMargins().top()+frameMargins().bottom()),1); + + widthWithoutMargins = qMax(widthWithoutMargins, window()->minimumSize().width()); + heightWithoutMargins = qMax(heightWithoutMargins, window()->minimumSize().height()); + QRect geometry = QRect(0,0, widthWithoutMargins, heightWithoutMargins); + + int x = 0; + int y = 0; + QSize size = this->geometry().size(); + if (mConfigure.edges & WL_SHELL_SURFACE_RESIZE_LEFT) { + x = size.width() - geometry.width(); + } + if (mConfigure.edges & WL_SHELL_SURFACE_RESIZE_TOP) { + y = size.height() - geometry.height(); + } + mOffset += QPoint(x, y); + + setGeometry(geometry); + + mConfigure.clear(); + QWindowSystemInterface::handleGeometryChange(window(), geometry); +} + +void QWaylandWindow::setCanResize(bool canResize) +{ + QMutexLocker lock(&mResizeLock); + mCanResize = canResize; + + if (canResize && !mConfigure.isEmpty()) { + doResize(); + QWindowSystemInterface::handleExposeEvent(window(), geometry()); + } +} + +void QWaylandWindow::requestResize() +{ + QMutexLocker lock(&mResizeLock); + + if (mCanResize) { + doResize(); + } + + mRequestResizeSent = false; + lock.unlock(); + QWindowSystemInterface::handleExposeEvent(window(), geometry()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) +{ + mBuffer = buffer; + + if (mBuffer) + attach(mBuffer->buffer(), x, y); + else + QtWayland::wl_surface::attach(0, 0, 0); +} + +void QWaylandWindow::attachOffset(QWaylandBuffer *buffer) +{ + attach(buffer, mOffset.x(), mOffset.y()); + mOffset = QPoint(); +} + +QWaylandBuffer *QWaylandWindow::attached() const +{ + return mBuffer; +} + +void QWaylandWindow::damage(const QRect &rect) +{ + //We have to do sync stuff before calling damage, or we might + //get a frame callback before we get the timestamp + if (!mWaitingForFrameSync) { + mFrameCallback = frame(); + wl_callback_add_listener(mFrameCallback,&QWaylandWindow::callbackListener,this); + mWaitingForFrameSync = true; + } + if (mBuffer) { + damage(rect.x(), rect.y(), rect.width(), rect.height()); + } +} + +const wl_callback_listener QWaylandWindow::callbackListener = { + QWaylandWindow::frameCallback +}; + +void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uint32_t time) +{ + Q_UNUSED(time); + QWaylandWindow *self = static_cast<QWaylandWindow*>(data); + if (callback != self->mFrameCallback) // might be a callback caused by the shm backingstore + return; + self->mWaitingForFrameSync = false; + if (self->mFrameCallback) { + wl_callback_destroy(self->mFrameCallback); + self->mFrameCallback = 0; + } +} + +QMutex QWaylandWindow::mFrameSyncMutex; + +void QWaylandWindow::waitForFrameSync() +{ + QMutexLocker locker(&mFrameSyncMutex); + if (!mWaitingForFrameSync) + return; + mDisplay->flushRequests(); + while (mWaitingForFrameSync) + mDisplay->blockingReadEvents(); +} + +QMargins QWaylandWindow::frameMargins() const +{ + if (mWindowDecoration) + return mWindowDecoration->margins(); + return QPlatformWindow::frameMargins(); +} + +QWaylandShellSurface *QWaylandWindow::shellSurface() const +{ + return mShellSurface; +} + +QWaylandExtendedSurface *QWaylandWindow::extendedWindow() const +{ + return mExtendedWindow; +} + +QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const +{ + return mSubSurfaceWindow; +} + +void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation) +{ + if (mExtendedWindow) + mExtendedWindow->setContentOrientation(orientation); +} + +void QWaylandWindow::setWindowState(Qt::WindowState state) +{ + if (mState == state) { + return; + } + + // As of february 2013 QWindow::setWindowState sets the new state value after + // QPlatformWindow::setWindowState returns, so we cannot rely on QWindow::windowState + // here. We use then this mState variable. + mState = state; + createDecoration(); + switch (state) { + case Qt::WindowFullScreen: + mShellSurface->setFullscreen(); + break; + case Qt::WindowMaximized: + mShellSurface->setMaximized(); + break; + case Qt::WindowMinimized: + mShellSurface->setMinimized(); + break; + default: + mShellSurface->setNormal(); + } + + QWindowSystemInterface::handleWindowStateChanged(window(), mState); + QWindowSystemInterface::flushWindowSystemEvents(); // Required for oldState to work on WindowStateChanged +} + +void QWaylandWindow::setWindowFlags(Qt::WindowFlags flags) +{ + if (mExtendedWindow) + mExtendedWindow->setWindowFlags(flags); +} + +bool QWaylandWindow::createDecoration() +{ + static bool disableWaylandDecorations = !qgetenv("QT_WAYLAND_DISABLE_WINDOWDECORATION").isEmpty(); + if (disableWaylandDecorations) + return false; + + bool decoration = false; + switch (window()->type()) { + case Qt::Window: + case Qt::Widget: + case Qt::Dialog: + case Qt::Tool: + case Qt::Drawer: + decoration = true; + break; + default: + break; + } + if (window()->flags() & Qt::FramelessWindowHint || isFullscreen()) + decoration = false; + if (window()->flags() & Qt::BypassWindowManagerHint) + decoration = false; + + if (decoration) { + if (!mWindowDecoration) + mWindowDecoration = new QWaylandDecoration(this); + } else { + delete mWindowDecoration; + mWindowDecoration = 0; + } + + return mWindowDecoration; +} + +QWaylandDecoration *QWaylandWindow::decoration() const +{ + return mWindowDecoration; +} + +void QWaylandWindow::setDecoration(QWaylandDecoration *decoration) +{ + mWindowDecoration = decoration; + if (subSurfaceWindow()) { + subSurfaceWindow()->adjustPositionOfChildren(); + } +} + +static QWindow *topLevelWindow(QWindow *window) +{ + while (QWindow *parent = window->parent()) + window = parent; + return window; +} + +QWaylandWindow *QWaylandWindow::transientParent() const +{ + if (window()->transientParent()) { + // Take the top level window here, since the transient parent may be a QWidgetWindow + // or some other window without a shell surface, which is then not able to get mouse + // events, nor set mMouseSerial and mMouseDevice. + return static_cast<QWaylandWindow *>(topLevelWindow(window()->transientParent())->handle()); + } + return 0; +} + +void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + if (b != Qt::NoButton) { + mMouseSerial = inputDevice->serial(); + mMouseDevice = inputDevice; + } + + if (mWindowDecoration) { + handleMouseEventWithDecoration(inputDevice, timestamp,local,global,b,mods); + return; + } + + QWindowSystemInterface::handleMouseEvent(window(),timestamp,local,global,b,mods); +} + +void QWaylandWindow::handleMouseEnter(QWaylandInputDevice *inputDevice) +{ + if (!mWindowDecoration) { + QWindowSystemInterface::handleEnterEvent(window()); + } + restoreMouseCursor(inputDevice); +} + +void QWaylandWindow::handleMouseLeave(QWaylandInputDevice *inputDevice) +{ + if (mWindowDecoration) { + if (mMouseEventsInContentArea) { + QWindowSystemInterface::handleLeaveEvent(window()); + } + } else { + QWindowSystemInterface::handleLeaveEvent(window()); + } + restoreMouseCursor(inputDevice); +} + +void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +{ + if (mWindowDecoration->handleMouse(inputDevice,local,global,b,mods)) + return; + + QMargins marg = frameMargins(); + QRect windowRect(0 + marg.left(), + 0 + marg.top(), + geometry().size().width() - marg.right(), + geometry().size().height() - marg.bottom()); + if (windowRect.contains(local.toPoint()) || mMousePressedInContentArea != Qt::NoButton) { + QPointF localTranslated = local; + QPointF globalTranslated = global; + localTranslated.setX(localTranslated.x() - marg.left()); + localTranslated.setY(localTranslated.y() - marg.top()); + globalTranslated.setX(globalTranslated.x() - marg.left()); + globalTranslated.setY(globalTranslated.y() - marg.top()); + if (!mMouseEventsInContentArea) { + restoreMouseCursor(inputDevice); + QWindowSystemInterface::handleEnterEvent(window()); + } + QWindowSystemInterface::handleMouseEvent(window(), timestamp, localTranslated, globalTranslated, b, mods); + mMouseEventsInContentArea = true; + mMousePressedInContentArea = b; + } else { + if (mMouseEventsInContentArea) { + QWindowSystemInterface::handleLeaveEvent(window()); + mMouseEventsInContentArea = false; + } + mWindowDecoration->handleMouse(inputDevice,local,global,b,mods); + } +} + +void QWaylandWindow::setMouseCursor(QWaylandInputDevice *device, Qt::CursorShape shape) +{ + if (m_cursorShape != shape || device->serial() > device->cursorSerial()) { + device->setCursor(shape, mScreen); + m_cursorShape = shape; + } +} + +void QWaylandWindow::restoreMouseCursor(QWaylandInputDevice *device) +{ + setMouseCursor(device, window()->cursor().shape()); +} + +void QWaylandWindow::requestActivateWindow() +{ + // no-op. Wayland does not have activation protocol, + // we rely on compositor setting keyboard focus based on window stacking. +} + +bool QWaylandWindow::setMouseGrabEnabled(bool grab) +{ + if (window()->type() != Qt::Popup) { + qWarning("This plugin supports grabbing the mouse only for popup windows"); + return false; + } + + mMouseGrab = grab ? this : 0; + return true; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandwindow.h b/src/client/qwaylandwindow.h new file mode 100644 index 00000000..c4d39180 --- /dev/null +++ b/src/client/qwaylandwindow.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDWINDOW_H +#define QWAYLANDWINDOW_H + +#include <QtCore/QWaitCondition> +#include <QtCore/QMutex> +#include <QtGui/QIcon> + +#include <qpa/qplatformwindow.h> + +#include "qwaylanddisplay.h" + +#include <QtWaylandClient/private/qwayland-wayland.h> + +struct wl_egl_window; + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandBuffer; +class QWaylandShellSurface; +class QWaylandExtendedSurface; +class QWaylandSubSurface; +class QWaylandDecoration; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandWindowConfigure +{ +public: + QWaylandWindowConfigure() + : width(0) + , height(0) + , edges(0) + { } + + void clear() + { width = height = edges = 0; } + + bool isEmpty() const + { return !height || !width; } + + int width; + int height; + uint32_t edges; +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow, public QtWayland::wl_surface +{ + Q_OBJECT +public: + enum WindowType { + Shm, + Egl + }; + + QWaylandWindow(QWindow *window); + ~QWaylandWindow(); + + virtual WindowType windowType() const = 0; + WId winId() const; + void setVisible(bool visible); + void setParent(const QPlatformWindow *parent); + + void setWindowTitle(const QString &title); + + inline QIcon windowIcon() const; + void setWindowIcon(const QIcon &icon); + + void setGeometry(const QRect &rect); + + void configure(uint32_t edges, int32_t width, int32_t height); + + using QtWayland::wl_surface::attach; + void attach(QWaylandBuffer *buffer, int x, int y); + void attachOffset(QWaylandBuffer *buffer); + QWaylandBuffer *attached() const; + QPoint attachOffset() const; + + using QtWayland::wl_surface::damage; + void damage(const QRect &rect); + + void waitForFrameSync(); + + QMargins frameMargins() const; + + static QWaylandWindow *fromWlSurface(::wl_surface *surface); + + QWaylandShellSurface *shellSurface() const; + QWaylandExtendedSurface *extendedWindow() const; + QWaylandSubSurface *subSurfaceWindow() const; + + void handleContentOrientationChange(Qt::ScreenOrientation orientation); + + void setWindowState(Qt::WindowState state); + void setWindowFlags(Qt::WindowFlags flags); + + void raise() Q_DECL_OVERRIDE; + void lower() Q_DECL_OVERRIDE; + + void requestActivateWindow() Q_DECL_OVERRIDE; + + QWaylandDecoration *decoration() const; + void setDecoration(QWaylandDecoration *decoration); + + + void handleMouse(QWaylandInputDevice *inputDevice, + ulong timestamp, + const QPointF & local, + const QPointF & global, + Qt::MouseButtons b, + Qt::KeyboardModifiers mods); + void handleMouseEnter(QWaylandInputDevice *inputDevice); + void handleMouseLeave(QWaylandInputDevice *inputDevice); + + bool createDecoration(); + + inline bool isMaximized() const { return mState == Qt::WindowMaximized; } + inline bool isFullscreen() const { return mState == Qt::WindowFullScreen; } + + void setMouseCursor(QWaylandInputDevice *device, Qt::CursorShape shape); + void restoreMouseCursor(QWaylandInputDevice *device); + + QWaylandWindow *transientParent() const; + + QMutex *resizeMutex() { return &mResizeLock; } + void doResize(); + void setCanResize(bool canResize); + + bool setMouseGrabEnabled(bool grab); + static QWaylandWindow *mouseGrab() { return mMouseGrab; } + +public slots: + void requestResize(); + +protected: + QWaylandScreen *mScreen; + QWaylandDisplay *mDisplay; + QWaylandShellSurface *mShellSurface; + QWaylandExtendedSurface *mExtendedWindow; + QWaylandSubSurface *mSubSurfaceWindow; + + QWaylandDecoration *mWindowDecoration; + bool mMouseEventsInContentArea; + Qt::MouseButtons mMousePressedInContentArea; + Qt::CursorShape m_cursorShape; + + QWaylandBuffer *mBuffer; + WId mWindowId; + bool mWaitingForFrameSync; + struct wl_callback *mFrameCallback; + QWaitCondition mFrameSyncWait; + + QMutex mResizeLock; + QWaylandWindowConfigure mConfigure; + bool mRequestResizeSent; + bool mCanResize; + + bool mSentInitialResize; + QPoint mOffset; + + QIcon mWindowIcon; + QWaylandInputDevice *mMouseDevice; + int mMouseSerial; + + Qt::WindowState mState; + +private: + void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, + ulong timestamp, + const QPointF & local, + const QPointF & global, + Qt::MouseButtons b, + Qt::KeyboardModifiers mods); + + static const wl_callback_listener callbackListener; + static void frameCallback(void *data, struct wl_callback *wl_callback, uint32_t time); + + static QMutex mFrameSyncMutex; + static QWaylandWindow *mMouseGrab; +}; + +inline QIcon QWaylandWindow::windowIcon() const +{ + return mWindowIcon; +} + +inline QPoint QWaylandWindow::attachOffset() const +{ + return mOffset; +} + +QT_END_NAMESPACE + +#endif // QWAYLANDWINDOW_H diff --git a/src/client/qwaylandwindowmanagerintegration.cpp b/src/client/qwaylandwindowmanagerintegration.cpp new file mode 100644 index 00000000..7543ba13 --- /dev/null +++ b/src/client/qwaylandwindowmanagerintegration.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 "qwaylandwindowmanagerintegration.h" +#include "qwaylandscreen.h" +#include "qwaylandwindow.h" + +#include <stdint.h> +#include <QtCore/QEvent> +#include <QtCore/QHash> +#include <QtCore/QUrl> +#include <qpa/qplatformnativeinterface.h> +#include <qpa/qplatformwindow.h> +#include <QtGui/QtEvents> +#include <QtGui/QGuiApplication> + +#include <QDebug> + +QT_BEGIN_NAMESPACE + +class QWaylandWindowManagerIntegrationPrivate { +public: + QWaylandWindowManagerIntegrationPrivate(QWaylandDisplay *waylandDisplay); + bool m_blockPropertyUpdates; + QWaylandDisplay *m_waylandDisplay; + QHash<QWindow*, QVariantMap> m_queuedProperties; + bool m_showIsFullScreen; +}; + +QWaylandWindowManagerIntegrationPrivate::QWaylandWindowManagerIntegrationPrivate(QWaylandDisplay *waylandDisplay) + : m_blockPropertyUpdates(false) + , m_waylandDisplay(waylandDisplay) + , m_showIsFullScreen(false) +{ + +} + +QWaylandWindowManagerIntegration::QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay) + : d_ptr(new QWaylandWindowManagerIntegrationPrivate(waylandDisplay)) +{ + waylandDisplay->addRegistryListener(&wlHandleListenerGlobal, this); +} + +QWaylandWindowManagerIntegration::~QWaylandWindowManagerIntegration() +{ + +} + +bool QWaylandWindowManagerIntegration::showIsFullScreen() const +{ + Q_D(const QWaylandWindowManagerIntegration); + return d->m_showIsFullScreen; +} + +void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(void *data, wl_registry *registry, uint32_t id, const QString &interface, uint32_t version) +{ + Q_UNUSED(version); + if (interface == "qt_windowmanager") + static_cast<QWaylandWindowManagerIntegration *>(data)->init(registry, id); +} + +void QWaylandWindowManagerIntegration::windowmanager_hints(int32_t showIsFullScreen) +{ + Q_D(QWaylandWindowManagerIntegration); + d->m_showIsFullScreen = showIsFullScreen; +} + +void QWaylandWindowManagerIntegration::windowmanager_quit() +{ + QGuiApplication::quit(); +} + +QByteArray QWaylandWindowManagerIntegration::desktopEnvironment() const +{ + const QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP"); + if (!xdgCurrentDesktop.isEmpty()) + return xdgCurrentDesktop.toUpper(); // KDE, GNOME, UNITY, LXDE, MATE, XFCE... + + // Classic fallbacks + if (!qEnvironmentVariableIsEmpty("KDE_FULL_SESSION")) + return QByteArrayLiteral("KDE"); + if (!qEnvironmentVariableIsEmpty("GNOME_DESKTOP_SESSION_ID")) + return QByteArrayLiteral("GNOME"); + + // Fallback to checking $DESKTOP_SESSION (unreliable) + const QByteArray desktopSession = qgetenv("DESKTOP_SESSION"); + if (desktopSession == "gnome") + return QByteArrayLiteral("GNOME"); + if (desktopSession == "xfce") + return QByteArrayLiteral("XFCE"); + + return QByteArrayLiteral("UNKNOWN"); +} + +void QWaylandWindowManagerIntegration::openUrl_helper(const QUrl &url) +{ + if (isInitialized()) { + QByteArray data = url.toString().toUtf8(); + + static const int chunkSize = 128; + while (!data.isEmpty()) { + QByteArray chunk = data.left(chunkSize); + data = data.mid(chunkSize); + open_url(!data.isEmpty(), QString::fromUtf8(chunk)); + } + } +} + +bool QWaylandWindowManagerIntegration::openUrl(const QUrl &url) +{ + openUrl_helper(url); + return true; +} + +bool QWaylandWindowManagerIntegration::openDocument(const QUrl &url) +{ + openUrl_helper(url); + return true; +} + +QT_END_NAMESPACE diff --git a/src/client/qwaylandwindowmanagerintegration.h b/src/client/qwaylandwindowmanagerintegration.h new file mode 100644 index 00000000..4506f06a --- /dev/null +++ b/src/client/qwaylandwindowmanagerintegration.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWAYLANDWINDOWMANAGERINTEGRATION_H +#define QWAYLANDWINDOWMANAGERINTEGRATION_H + +#include <QtCore/QObject> +#include <QtCore/QScopedPointer> + +#include "wayland-client.h" +#include "qwaylanddisplay.h" +#include <qpa/qplatformservices.h> + +#include "QtWaylandClient/private/qwayland-windowmanager.h" + +QT_BEGIN_NAMESPACE + +class QWaylandWindow; +class QWaylandWindowManagerIntegrationPrivate; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandWindowManagerIntegration : public QObject, public QPlatformServices, public QtWayland::qt_windowmanager +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandWindowManagerIntegration) +public: + explicit QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay); + virtual ~QWaylandWindowManagerIntegration(); + + QByteArray desktopEnvironment() const; + + bool openUrl(const QUrl &url); + bool openDocument(const QUrl &url); + + bool showIsFullScreen() const; + +private: + static void wlHandleListenerGlobal(void *data, wl_registry *registry, uint32_t id, + const QString &interface, uint32_t version); + + QScopedPointer<QWaylandWindowManagerIntegrationPrivate> d_ptr; + + void windowmanager_hints(int32_t showIsFullScreen) Q_DECL_OVERRIDE; + void windowmanager_quit() Q_DECL_OVERRIDE; + + void openUrl_helper(const QUrl &url); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDWINDOWMANAGERINTEGRATION_H |