diff options
43 files changed, 1483 insertions, 265 deletions
diff --git a/.qmake.conf b/.qmake.conf index e28797de2..a98bcf66b 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,3 @@ load(qt_build_config) -MODULE_VERSION = 5.4.0 +MODULE_VERSION = 5.5.0 diff --git a/src/client/client.pro b/src/client/client.pro index a8a1136ea..ef3cff054 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -3,7 +3,10 @@ QT += core-private gui-private QT_FOR_PRIVATE += platformsupport-private MODULE=waylandclient -MODULE_PLUGIN_TYPES = wayland-graphics-integration-client wayland-decoration-client +MODULE_PLUGIN_TYPES = \ + wayland-graphics-integration-client \ + wayland-inputdevice-integration \ + wayland-decoration-client load(qt_module) @@ -112,3 +115,4 @@ HEADERS += qwaylandintegration_p.h \ include(hardwareintegration/hardwareintegration.pri) include(shellintegration/shellintegration.pri) +include(inputdeviceintegration/inputdeviceintegration.pri) diff --git a/src/client/inputdeviceintegration/inputdeviceintegration.pri b/src/client/inputdeviceintegration/inputdeviceintegration.pri new file mode 100644 index 000000000..f16dfc3c9 --- /dev/null +++ b/src/client/inputdeviceintegration/inputdeviceintegration.pri @@ -0,0 +1,11 @@ +INCLUDEPATH += $$PWD + +SOURCES += \ + $$PWD/qwaylandinputdeviceintegrationplugin.cpp \ + $$PWD/qwaylandinputdeviceintegrationfactory.cpp + +HEADERS += \ + $$PWD/qwaylandinputdeviceintegration_p.h \ + $$PWD/qwaylandinputdeviceintegrationplugin_p.h \ + $$PWD/qwaylandinputdeviceintegrationfactory_p.h + diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegration_p.h b/src/client/inputdeviceintegration/qwaylandinputdeviceintegration_p.h new file mode 100644 index 000000000..5fa187e69 --- /dev/null +++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegration_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd +** 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 QWAYLANDINPUTDEVICEINTEGRATION_H +#define QWAYLANDINPUTDEVICEINTEGRATION_H + +#include <QtCore/qglobal.h> +#include <QtWaylandClient/private/qwaylandclientexport_p.h> + +QT_BEGIN_NAMESPACE + +class QWaylandDisplay; +class QWaylandInputDevice; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDeviceIntegration +{ +public: + QWaylandInputDeviceIntegration() {} + virtual ~QWaylandInputDeviceIntegration() {} + + virtual QWaylandInputDevice *createInputDevice(QWaylandDisplay *d, int version, uint32_t id) = 0; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTDEVICEINTEGRATION_H diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp new file mode 100644 index 000000000..58a82fb2c --- /dev/null +++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 "qwaylandinputdeviceintegrationfactory_p.h" +#include "qwaylandinputdeviceintegrationplugin_p.h" +#include "qwaylandinputdeviceintegration_p.h" +#include <QtCore/private/qfactoryloader_p.h> +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_LIBRARY +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QWaylandInputDeviceIntegrationFactoryInterface_iid, QLatin1String("/wayland-inputdevice-integration"), Qt::CaseInsensitive)) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, + (QWaylandInputDeviceIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive)) +#endif + +QStringList QWaylandInputDeviceIntegrationFactory::keys(const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + QStringList list; + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + list = directLoader()->keyMap().values(); + if (!list.isEmpty()) { + const QString postFix = QStringLiteral(" (from ") + + QDir::toNativeSeparators(pluginPath) + + QLatin1Char(')'); + const QStringList::iterator end = list.end(); + for (QStringList::iterator it = list.begin(); it != end; ++it) + (*it).append(postFix); + } + } + list.append(loader()->keyMap().values()); + return list; +#else + return QStringList(); +#endif +} + +QWaylandInputDeviceIntegration *QWaylandInputDeviceIntegrationFactory::create(const QString &name, const QStringList &args, const QString &pluginPath) +{ +#ifndef QT_NO_LIBRARY + // Try loading the plugin from platformPluginPath first: + if (!pluginPath.isEmpty()) { + QCoreApplication::addLibraryPath(pluginPath); + if (QWaylandInputDeviceIntegration *ret = qLoadPlugin1<QWaylandInputDeviceIntegration, QWaylandInputDeviceIntegrationPlugin>(directLoader(), name, args)) + return ret; + } + if (QWaylandInputDeviceIntegration *ret = qLoadPlugin1<QWaylandInputDeviceIntegration, QWaylandInputDeviceIntegrationPlugin>(loader(), name, args)) + return ret; +#endif + return Q_NULLPTR; +} + +QT_END_NAMESPACE diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory_p.h b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory_p.h new file mode 100644 index 000000000..13cddc24f --- /dev/null +++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationfactory_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 QWAYLANDINPUTDEVICEINTEGRATIONFACTORY_H +#define QWAYLANDINPUTDEVICEINTEGRATIONFACTORY_H + +#include <QtWaylandClient/private/qwaylandclientexport_p.h> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QWaylandInputDeviceIntegration; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDeviceIntegrationFactory +{ +public: + static QStringList keys(const QString &pluginPath = QString()); + static QWaylandInputDeviceIntegration *create(const QString &name, const QStringList &args, const QString &pluginPath = QString()); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTDEVICENTEGRATIONFACTORY_H diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin.cpp b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin.cpp new file mode 100644 index 000000000..71a933254 --- /dev/null +++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 "qwaylandinputdeviceintegrationplugin_p.h" + +QT_BEGIN_NAMESPACE + +QWaylandInputDeviceIntegrationPlugin::QWaylandInputDeviceIntegrationPlugin(QObject *parent) + : QObject(parent) +{ +} + +QWaylandInputDeviceIntegrationPlugin::~QWaylandInputDeviceIntegrationPlugin() +{ +} + +QT_END_NAMESPACE diff --git a/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin_p.h b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin_p.h new file mode 100644 index 000000000..a0a062f4c --- /dev/null +++ b/src/client/inputdeviceintegration/qwaylandinputdeviceintegrationplugin_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 QWAYLANDINPUTDEVICEINTEGRATIONPLUGIN_H +#define QWAYLANDINPUTDEVICEINTEGRATIONPLUGIN_H + +#include <QtWaylandClient/private/qwaylandclientexport_p.h> + +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QWaylandInputDeviceIntegration; + +#define QWaylandInputDeviceIntegrationFactoryInterface_iid "org.qt-project.Qt.WaylandClient.QWaylandInputDeviceIntegrationFactoryInterface.5.3" + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDeviceIntegrationPlugin : public QObject +{ + Q_OBJECT +public: + explicit QWaylandInputDeviceIntegrationPlugin(QObject *parent = 0); + ~QWaylandInputDeviceIntegrationPlugin(); + + virtual QWaylandInputDeviceIntegration *create(const QString &key, const QStringList ¶mList) = 0; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDINPUTDEVICEINTEGRATIONPLUGIN_H diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index fda2c204e..023050326 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -97,6 +97,16 @@ QWaylandShellSurface *QWaylandDisplay::createShellSurface(QWaylandWindow *window return Q_NULLPTR; } +struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) +{ + struct ::wl_region *region = mCompositor.create_region(); + + Q_FOREACH (const QRect &rect, qregion.rects()) + wl_region_add(region, rect.x(), rect.y(), rect.width(), rect.height()); + + return region; +} + QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const { return mWaylandIntegration->clientBufferIntegration(); @@ -242,7 +252,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin } else if (interface == QStringLiteral("wl_shell")){ mShell.reset(new QtWayland::wl_shell(registry, id, 1)); } else if (interface == QStringLiteral("wl_seat")) { - QWaylandInputDevice *inputDevice = new QWaylandInputDevice(this, version, id); + QWaylandInputDevice *inputDevice = mWaylandIntegration->createInputDevice(this, version, id); mInputDevices.append(inputDevice); } else if (interface == QStringLiteral("wl_data_device_manager")) { mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id)); diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 8d1d26bba..2f12ee7f9 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -103,6 +103,7 @@ public: struct wl_surface *createSurface(void *handle); QWaylandShellSurface *createShellSurface(QWaylandWindow *window); + struct ::wl_region *createRegion(const QRegion &qregion); QWaylandClientBufferIntegration *clientBufferIntegration() const; diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 39d1705c0..43c5807d4 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -63,170 +63,99 @@ #include <QtGui/QGuiApplication> -#ifndef QT_NO_WAYLAND_XKB -#include <xkbcommon/xkbcommon.h> -#include <xkbcommon/xkbcommon-keysyms.h> -#endif - QT_BEGIN_NAMESPACE -class QWaylandInputDevice::Keyboard : public QtWayland::wl_keyboard -{ -public: - Keyboard(QWaylandInputDevice *p) - : mParent(p) - , mFocus(0) +QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) + : mParent(p) + , mFocus(0) #ifndef QT_NO_WAYLAND_XKB - , mXkbContext(0) - , mXkbMap(0) - , mXkbState(0) + , mXkbContext(0) + , mXkbMap(0) + , mXkbState(0) #endif - , mFocusCallback(0) - , mNativeModifiers(0) - { + , mFocusCallback(0) + , mNativeModifiers(0) +{ + connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); +} + #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); - } - } +bool QWaylandInputDevice::Keyboard::createDefaultKeyMap() +{ + if (mXkbContext && mXkbMap && mXkbState) { + return true; + } - if (!mXkbContext || !mXkbMap || !mXkbState) - qWarning() << "xkb_map_new_from_names failed, no key input"; -#endif + 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); + } } - ~Keyboard() - { -#ifndef QT_NO_WAYLAND_XKB - if (mXkbState) - xkb_state_unref(mXkbState); - if (mXkbMap) - xkb_map_unref(mXkbMap); - if (mXkbContext) - xkb_context_unref(mXkbContext); -#endif - wl_keyboard_destroy(object()); + + if (!mXkbContext || !mXkbMap || !mXkbState) { + qWarning() << "xkb_map_new_from_names failed, no key input"; + return false; } + return true; +} - 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; - - QWaylandInputDevice *mParent; - QWaylandWindow *mFocus; -#ifndef QT_NO_WAYLAND_XKB - xkb_context *mXkbContext; - xkb_keymap *mXkbMap; - xkb_state *mXkbState; +void QWaylandInputDevice::Keyboard::releaseKeyMap() +{ + if (mXkbState) + xkb_state_unref(mXkbState); + if (mXkbMap) + xkb_map_unref(mXkbMap); + if (mXkbContext) + xkb_context_unref(mXkbContext); +} #endif - struct wl_callback *mFocusCallback; - uint32_t mNativeModifiers; - int mRepeatKey; - uint32_t mRepeatCode; - uint32_t mRepeatTime; - QString mRepeatText; +QWaylandInputDevice::Keyboard::~Keyboard() +{ #ifndef QT_NO_WAYLAND_XKB - xkb_keysym_t mRepeatSym; + releaseKeyMap(); #endif + wl_keyboard_destroy(object()); +} - static const wl_callback_listener callback; - static void focusCallback(void *data, struct wl_callback *callback, uint32_t time); -}; +void QWaylandInputDevice::Keyboard::stopRepeat() +{ + mRepeatTimer.stop(); +} -class QWaylandInputDevice::Pointer : public QtWayland::wl_pointer +QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *p) + : mParent(p) + , mFocus(0) + , mEnterSerial(0) + , mCursorSerial(0) + , mButtons(0) { -public: - Pointer(QWaylandInputDevice *p) - : mParent(p) - , mFocus(0) - , mEnterSerial(0) - , mCursorSerial(0) - , mButtons(0) - { - } - ~Pointer() - { - wl_pointer_destroy(object()); - } +} - 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; - - QWaylandInputDevice *mParent; - QWaylandWindow *mFocus; - uint32_t mEnterSerial; - uint32_t mCursorSerial; - QPointF mSurfacePos; - QPointF mGlobalPos; - Qt::MouseButtons mButtons; -}; +QWaylandInputDevice::Pointer::~Pointer() +{ + wl_pointer_destroy(object()); +} -class QWaylandInputDevice::Touch : public QtWayland::wl_touch +QWaylandInputDevice::Touch::Touch(QWaylandInputDevice *p) + : mParent(p) + , mFocus(0) { -public: - Touch(QWaylandInputDevice *p) - : mParent(p) - , mFocus(0) - { - } - ~Touch() - { - wl_touch_destroy(object()); - } +} - 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; - - bool allTouchPointsReleased(); - - QWaylandInputDevice *mParent; - QWaylandWindow *mFocus; - QList<QWindowSystemInterface::TouchPoint> mTouchPoints; - QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints; -}; +QWaylandInputDevice::Touch::~Touch() +{ + wl_touch_destroy(object()); +} QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id) : QObject() @@ -246,7 +175,6 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, mDataDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this); } - connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); } QWaylandInputDevice::~QWaylandInputDevice() @@ -261,16 +189,15 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps) mCaps = caps; if (caps & WL_SEAT_CAPABILITY_KEYBOARD && !mKeyboard) { - mKeyboard = new Keyboard(this); + mKeyboard = createKeyboard(this); mKeyboard->init(get_keyboard()); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && mKeyboard) { delete mKeyboard; mKeyboard = 0; - mRepeatTimer.stop(); } if (caps & WL_SEAT_CAPABILITY_POINTER && !mPointer) { - mPointer = new Pointer(this); + mPointer = createPointer(this); mPointer->init(get_pointer()); pointerSurface = mQDisplay->createSurface(this); } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && mPointer) { @@ -279,7 +206,7 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps) } if (caps & WL_SEAT_CAPABILITY_TOUCH && !mTouch) { - mTouch = new Touch(this); + mTouch = createTouch(this); mTouch->init(get_touch()); if (!mTouchDevice) { @@ -294,13 +221,28 @@ void QWaylandInputDevice::seat_capabilities(uint32_t caps) } } +QWaylandInputDevice::Keyboard *QWaylandInputDevice::createKeyboard(QWaylandInputDevice *device) +{ + return new Keyboard(device); +} + +QWaylandInputDevice::Pointer *QWaylandInputDevice::createPointer(QWaylandInputDevice *device) +{ + return new Pointer(device); +} + +QWaylandInputDevice::Touch *QWaylandInputDevice::createTouch(QWaylandInputDevice *device) +{ + return new Touch(device); +} + void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window) { if (mPointer && window == mPointer->mFocus) mPointer->mFocus = 0; if (mKeyboard && window == mKeyboard->mFocus) { mKeyboard->mFocus = 0; - mRepeatTimer.stop(); + mKeyboard->stopRepeat(); } } @@ -341,20 +283,25 @@ Qt::KeyboardModifiers QWaylandInputDevice::modifiers() const if (!mKeyboard) return Qt::NoModifier; + return mKeyboard->modifiers(); +} + +Qt::KeyboardModifiers QWaylandInputDevice::Keyboard::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(mKeyboard->mXkbState, "Shift", cstate)) + if (xkb_state_mod_name_is_active(mXkbState, "Shift", cstate)) ret |= Qt::ShiftModifier; - if (xkb_state_mod_name_is_active(mKeyboard->mXkbState, "Control", cstate)) + if (xkb_state_mod_name_is_active(mXkbState, "Control", cstate)) ret |= Qt::ControlModifier; - if (xkb_state_mod_name_is_active(mKeyboard->mXkbState, "Alt", cstate)) + if (xkb_state_mod_name_is_active(mXkbState, "Alt", cstate)) ret |= Qt::AltModifier; - if (xkb_state_mod_name_is_active(mKeyboard->mXkbState, "Mod1", cstate)) + if (xkb_state_mod_name_is_active(mXkbState, "Mod1", cstate)) ret |= Qt::AltModifier; - if (xkb_state_mod_name_is_active(mKeyboard->mXkbState, "Mod4", cstate)) + if (xkb_state_mod_name_is_active(mXkbState, "Mod4", cstate)) ret |= Qt::MetaModifier; #endif @@ -682,6 +629,11 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, return; } + // Release the old keymap resources in the case they were already created in + // the key event or when the compositor issues a new map + releaseKeyMap(); + + mXkbContext = xkb_context_new(xkb_context_flags(0)); 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); @@ -731,7 +683,7 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf mFocusCallback = wl_display_sync(mParent->mDisplay); wl_callback_add_listener(mFocusCallback, &QWaylandInputDevice::Keyboard::callback, this); } - mParent->mRepeatTimer.stop(); + mRepeatTimer.stop(); } const wl_callback_listener QWaylandInputDevice::Keyboard::callback = { @@ -769,8 +721,9 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, } #ifndef QT_NO_WAYLAND_XKB - if (!mXkbMap) + if (!createDefaultKeyMap()) { return; + } const xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code); xkb_state_update_key(mXkbState, code, isDown ? XKB_KEY_DOWN : XKB_KEY_UP); @@ -807,38 +760,37 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, #ifndef QT_NO_WAYLAND_XKB mRepeatSym = sym; #endif - mParent->mRepeatTimer.setInterval(400); - mParent->mRepeatTimer.start(); + mRepeatTimer.setInterval(400); + mRepeatTimer.start(); } else if (mRepeatCode == code) { - mParent->mRepeatTimer.stop(); + mRepeatTimer.stop(); } } -void QWaylandInputDevice::repeatKey() +void QWaylandInputDevice::Keyboard::repeatKey() { mRepeatTimer.setInterval(25); - - QWindowSystemInterface::handleExtendedKeyEvent(mKeyboard->mFocus->window(), - mKeyboard->mRepeatTime, QEvent::KeyRelease, mKeyboard->mRepeatKey, + QWindowSystemInterface::handleExtendedKeyEvent(mFocus->window(), + mRepeatTime, QEvent::KeyRelease, mRepeatKey, modifiers(), - mKeyboard->mRepeatCode, + mRepeatCode, #ifndef QT_NO_WAYLAND_XKB - mKeyboard->mRepeatSym, mKeyboard->mNativeModifiers, + mRepeatSym, mNativeModifiers, #else 0, 0, #endif - mKeyboard->mRepeatText, true); + mRepeatText, true); - QWindowSystemInterface::handleExtendedKeyEvent(mKeyboard->mFocus->window(), - mKeyboard->mRepeatTime, QEvent::KeyPress, mKeyboard->mRepeatKey, + QWindowSystemInterface::handleExtendedKeyEvent(mFocus->window(), + mRepeatTime, QEvent::KeyPress, mRepeatKey, modifiers(), - mKeyboard->mRepeatCode, + mRepeatCode, #ifndef QT_NO_WAYLAND_XKB - mKeyboard->mRepeatSym, mKeyboard->mNativeModifiers, + mRepeatSym, mNativeModifiers, #else 0, 0, #endif - mKeyboard->mRepeatText, true); + mRepeatText, true); } void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial, diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 630640f87..f1c264545 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -56,15 +56,17 @@ #include <QtWaylandClient/private/qwayland-wayland.h> #ifndef QT_NO_WAYLAND_XKB -struct xkb_context; -struct xkb_keymap; -struct xkb_state; +#include <xkbcommon/xkbcommon.h> +#include <xkbcommon/xkbcommon-keysyms.h> #endif +#include <QtCore/QDebug> + struct wl_cursor_image; QT_BEGIN_NAMESPACE + class QWaylandWindow; class QWaylandDisplay; class QWaylandDataDevice; @@ -75,6 +77,10 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice { Q_OBJECT public: + class Keyboard; + class Pointer; + class Touch; + QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id); ~QWaylandInputDevice(); @@ -100,14 +106,11 @@ public: uint32_t serial() const; uint32_t cursorSerial() const; -private slots: - void repeatKey(); + virtual Keyboard *createKeyboard(QWaylandInputDevice *device); + virtual Pointer *createPointer(QWaylandInputDevice *device); + virtual Touch *createTouch(QWaylandInputDevice *device); private: - class Keyboard; - class Pointer; - class Touch; - QWaylandDisplay *mQDisplay; struct wl_display *mDisplay; @@ -123,7 +126,6 @@ private: uint32_t mTime; uint32_t mSerial; - QTimer mRepeatTimer; void seat_capabilities(uint32_t caps) Q_DECL_OVERRIDE; void handleTouchPoint(int id, double x, double y, Qt::TouchPointState state); @@ -139,6 +141,127 @@ inline uint32_t QWaylandInputDevice::serial() const return mSerial; } + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Keyboard : public QObject, public QtWayland::wl_keyboard +{ + Q_OBJECT + +public: + Keyboard(QWaylandInputDevice *p); + virtual ~Keyboard(); + + void stopRepeat(); + + 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; + + QWaylandInputDevice *mParent; + QWaylandWindow *mFocus; +#ifndef QT_NO_WAYLAND_XKB + xkb_context *mXkbContext; + xkb_keymap *mXkbMap; + xkb_state *mXkbState; +#endif + struct wl_callback *mFocusCallback; + uint32_t mNativeModifiers; + + int mRepeatKey; + uint32_t mRepeatCode; + uint32_t mRepeatTime; + QString mRepeatText; +#ifndef QT_NO_WAYLAND_XKB + xkb_keysym_t mRepeatSym; +#endif + QTimer mRepeatTimer; + + static const wl_callback_listener callback; + static void focusCallback(void *data, struct wl_callback *callback, uint32_t time); + + Qt::KeyboardModifiers modifiers() const; + +private slots: + void repeatKey(); + +private: +#ifndef QT_NO_WAYLAND_XKB + bool createDefaultKeyMap(); + void releaseKeyMap(); +#endif + +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QtWayland::wl_pointer +{ + +public: + Pointer(QWaylandInputDevice *p); + virtual ~Pointer(); + + 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; + + QWaylandInputDevice *mParent; + QWaylandWindow *mFocus; + uint32_t mEnterSerial; + uint32_t mCursorSerial; + QPointF mSurfacePos; + QPointF mGlobalPos; + Qt::MouseButtons mButtons; +}; + +class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch +{ +public: + Touch(QWaylandInputDevice *p); + virtual ~Touch(); + + 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; + + bool allTouchPointsReleased(); + + QWaylandInputDevice *mParent; + QWaylandWindow *mFocus; + QList<QWindowSystemInterface::TouchPoint> mTouchPoints; + QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints; +}; + + + QT_END_NAMESPACE #endif diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index aa5a1cea8..27613eef7 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -43,6 +43,7 @@ #include "qwaylanddisplay_p.h" #include "qwaylandshmwindow_p.h" +#include "qwaylandinputdevice_p.h" #include "qwaylandinputcontext_p.h" #include "qwaylandshmbackingstore_p.h" #include "qwaylandnativeinterface_p.h" @@ -76,6 +77,9 @@ #include "qwaylandshellintegration_p.h" #include "qwaylandshellintegrationfactory_p.h" +#include "qwaylandinputdeviceintegration_p.h" +#include "qwaylandinputdeviceintegrationfactory_p.h" + QT_BEGIN_NAMESPACE class GenericWaylandTheme: public QGenericUnixTheme @@ -113,6 +117,7 @@ public: QWaylandIntegration::QWaylandIntegration() : mClientBufferIntegration(0) , mShellIntegration(Q_NULLPTR) + , mInputDeviceIntegration(Q_NULLPTR) , mFontDb(new QGenericUnixFontDatabase()) , mNativeInterface(new QWaylandNativeInterface(this)) #ifndef QT_NO_ACCESSIBILITY @@ -124,6 +129,7 @@ QWaylandIntegration::QWaylandIntegration() , mServerBufferIntegrationInitialized(false) , mShellIntegrationInitialized(false) { + initializeInputDeviceIntegration(); mDisplay = new QWaylandDisplay(this); mClipboard = new QWaylandClipboard(mDisplay); mDrag = new QWaylandDrag(mDisplay); @@ -363,4 +369,30 @@ void QWaylandIntegration::initializeShellIntegration() } } +QWaylandInputDevice *QWaylandIntegration::createInputDevice(QWaylandDisplay *display, int version, uint32_t id) +{ + if (mInputDeviceIntegration) { + return mInputDeviceIntegration->createInputDevice(display, version, id); + } + return new QWaylandInputDevice(display, version, id); +} + +void QWaylandIntegration::initializeInputDeviceIntegration() +{ + QByteArray integrationName = qgetenv("QT_WAYLAND_INPUTDEVICE_INTEGRATION"); + QString targetKey = QString::fromLocal8Bit(integrationName); + + if (targetKey.isEmpty()) { + return; + } + + QStringList keys = QWaylandInputDeviceIntegrationFactory::keys(); + if (keys.contains(targetKey)) { + mInputDeviceIntegration = QWaylandInputDeviceIntegrationFactory::create(targetKey, QStringList()); + qDebug("Using the '%s' input device integration", qPrintable(targetKey)); + } else { + qWarning("Wayland inputdevice integration '%s' not found, using default", qPrintable(targetKey)); + } +} + QT_END_NAMESPACE diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index 699702482..c0909418e 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -52,6 +52,8 @@ class QWaylandDisplay; class QWaylandClientBufferIntegration; class QWaylandServerBufferIntegration; class QWaylandShellIntegration; +class QWaylandInputDeviceIntegration; +class QWaylandInputDevice; class Q_WAYLAND_CLIENT_EXPORT QWaylandIntegration : public QPlatformIntegration { @@ -91,17 +93,24 @@ public: QPlatformTheme *createPlatformTheme(const QString &name) const; + QWaylandInputDevice *createInputDevice(QWaylandDisplay *display, int version, uint32_t id); + virtual QWaylandClientBufferIntegration *clientBufferIntegration() const; virtual QWaylandServerBufferIntegration *serverBufferIntegration() const; virtual QWaylandShellIntegration *shellIntegration() const; + protected: QWaylandClientBufferIntegration *mClientBufferIntegration; QWaylandServerBufferIntegration *mServerBufferIntegration; QWaylandShellIntegration *mShellIntegration; + QWaylandInputDeviceIntegration *mInputDeviceIntegration; + private: void initializeClientBufferIntegration(); void initializeServerBufferIntegration(); void initializeShellIntegration(); + void initializeInputDeviceIntegration(); + QPlatformFontDatabase *mFontDb; QPlatformClipboard *mClipboard; QPlatformDrag *mDrag; diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 6c4a339f1..9f7bdda1f 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -91,6 +91,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window) , mMouseDevice(0) , mMouseSerial(0) , mState(Qt::WindowNoState) + , mMask() , mBackingStore(Q_NULLPTR) { init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this))); @@ -128,6 +129,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window) setOrientationMask(window->screen()->orientationUpdateMask()); setWindowFlags(window->flags()); setGeometry_helper(window->geometry()); + setMask(window->mask()); setWindowStateInternal(window->windowState()); handleContentOrientationChange(window->contentOrientation()); } @@ -271,6 +273,24 @@ void QWaylandWindow::lower() mShellSurface->lower(); } +void QWaylandWindow::setMask(const QRegion &mask) +{ + if (mMask == mask) + return; + + mMask = mask; + + if (mMask.isEmpty()) { + set_input_region(0); + } else { + struct ::wl_region *region = mDisplay->createRegion(mMask); + set_input_region(region); + wl_region_destroy(region); + } + + commit(); +} + void QWaylandWindow::configure(uint32_t edges, int32_t width, int32_t height) { QMutexLocker resizeLocker(&mResizeLock); diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 6c32bc3ef..0c55cd88d 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -140,6 +140,8 @@ public: void raise() Q_DECL_OVERRIDE; void lower() Q_DECL_OVERRIDE; + void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; + void requestActivateWindow() Q_DECL_OVERRIDE; bool isExposed() const Q_DECL_OVERRIDE; void unfocus(); @@ -224,6 +226,7 @@ protected: int mMouseSerial; Qt::WindowState mState; + QRegion mMask; QWaylandShmBackingStore *mBackingStore; diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 2ef7231bf..bc46def80 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -2,6 +2,8 @@ INCLUDEPATH += compositor_api HEADERS += \ compositor_api/qwaylandcompositor.h \ + compositor_api/qwaylandcompositor_p.h \ + compositor_api/qwaylandclient.h \ compositor_api/qwaylandsurface.h \ compositor_api/qwaylandsurface_p.h \ compositor_api/qwaylandinput.h \ @@ -14,6 +16,7 @@ HEADERS += \ SOURCES += \ compositor_api/qwaylandcompositor.cpp \ + compositor_api/qwaylandclient.cpp \ compositor_api/qwaylandsurface.cpp \ compositor_api/qwaylandinput.cpp \ compositor_api/qwaylandinputpanel.cpp \ diff --git a/src/compositor/compositor_api/qwaylandclient.cpp b/src/compositor/compositor_api/qwaylandclient.cpp new file mode 100644 index 000000000..e5567584e --- /dev/null +++ b/src/compositor/compositor_api/qwaylandclient.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** 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 <private/qobject_p.h> + +#include "wayland_wrapper/qwlcompositor_p.h" +#include "qwaylandcompositor.h" +#include "qwaylandclient.h" + +#include <wayland-server.h> +#include <wayland-util.h> + +QT_BEGIN_NAMESPACE + +class QWaylandClientPrivate : public QObjectPrivate +{ +public: + QWaylandClientPrivate(wl_client *_client) + : client(_client) + { + // Save client credentials + wl_client_get_credentials(client, &pid, &uid, &gid); + } + + ~QWaylandClientPrivate() + { + } + + static void client_destroy_callback(wl_listener *listener, void *data) + { + Q_UNUSED(data); + + QWaylandClient *client = reinterpret_cast<Listener *>(listener)->parent; + Q_ASSERT(client != 0); + QtWayland::Compositor::instance()->m_clients.removeOne(client); + delete client; + } + + wl_client *client; + + uid_t uid; + gid_t gid; + pid_t pid; + + struct Listener { + wl_listener listener; + QWaylandClient *parent; + }; + Listener listener; +}; + +QWaylandClient::QWaylandClient(wl_client *client) + : QObject(*new QWaylandClientPrivate(client)) +{ + Q_D(QWaylandClient); + + // Destroy wrapper when the client goes away + d->listener.parent = this; + d->listener.listener.notify = QWaylandClientPrivate::client_destroy_callback; + wl_client_add_destroy_listener(client, &d->listener.listener); +} + +QWaylandClient::~QWaylandClient() +{ + Q_D(QWaylandClient); + + // Remove listener from signal + wl_list_remove(&d->listener.listener.link); +} + +QWaylandClient *QWaylandClient::fromWlClient(wl_client *wlClient) +{ + if (!wlClient) + return 0; + + QWaylandClient *client = Q_NULLPTR; + + wl_listener *l = wl_client_get_destroy_listener(wlClient, + QWaylandClientPrivate::client_destroy_callback); + if (l) + client = reinterpret_cast<QWaylandClientPrivate::Listener *>( + wl_container_of(l, (QWaylandClientPrivate::Listener *)0, listener))->parent; + + if (!client) { + // The original idea was to create QWaylandClient instances when + // a client bound wl_compositor, but it's legal for a client to + // bind several times resulting in multiple QWaylandClient + // instances for the same wl_client therefore we create it from + // here on demand + client = new QWaylandClient(wlClient); + QtWayland::Compositor::instance()->m_clients.append(client); + } + + return client; +} + +wl_client *QWaylandClient::client() const +{ + Q_D(const QWaylandClient); + + return d->client; +} + +qint64 QWaylandClient::userId() const +{ + Q_D(const QWaylandClient); + + return d->uid; +} + +qint64 QWaylandClient::groupId() const +{ + Q_D(const QWaylandClient); + + return d->gid; +} + +qint64 QWaylandClient::processId() const +{ + Q_D(const QWaylandClient); + + return d->pid; +} + +void QWaylandClient::kill(int sig) +{ + Q_D(QWaylandClient); + + ::kill(d->pid, sig); +} + +void QWaylandClient::close() +{ + QtWayland::Compositor::instance()->waylandCompositor()->destroyClient(this); +} + +QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandclient.h b/src/compositor/compositor_api/qwaylandclient.h new file mode 100644 index 000000000..ba6e3e274 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandclient.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** 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 QWAYLANDCLIENT_H +#define QWAYLANDCLIENT_H + +#include <QtCompositor/qwaylandexport.h> + +#include <QObject> + +#include <signal.h> + +struct wl_client; + +QT_BEGIN_NAMESPACE + +class QWaylandClientPrivate; + +class Q_COMPOSITOR_EXPORT QWaylandClient : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandClient) + + Q_PROPERTY(qint64 userId READ userId CONSTANT) + Q_PROPERTY(qint64 groupId READ groupId CONSTANT) + Q_PROPERTY(qint64 processId READ processId CONSTANT) +public: + ~QWaylandClient(); + + static QWaylandClient *fromWlClient(wl_client *wlClient); + + wl_client *client() const; + + qint64 userId() const; + qint64 groupId() const; + + qint64 processId() const; + + Q_INVOKABLE void kill(int sig = SIGTERM); + +public Q_SLOTS: + void close(); + +private: + explicit QWaylandClient(wl_client *client); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDCLIENT_H diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 3248e4b1c..25ceb6e85 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -114,21 +114,19 @@ void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface) destroyClient(surface->client()); } -void QWaylandCompositor::destroyClient(WaylandClient *client) +void QWaylandCompositor::destroyClient(QWaylandClient *client) { m_compositor->destroyClient(client); } -QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(WaylandClient* c) const +QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* client) const { - wl_client *client = static_cast<wl_client *>(c); - QList<QtWayland::Surface *> surfaces = m_compositor->surfaces(); QList<QWaylandSurface *> result; for (int i = 0; i < surfaces.count(); ++i) { - if (surfaces.at(i)->resource()->client() == client) { + if (surfaces.at(i)->waylandSurface()->client() == client) { result.append(surfaces.at(i)->waylandSurface()); } } @@ -181,7 +179,7 @@ QPointF QWaylandCompositor::mapToView(QWaylandSurfaceView *surface, const QPoint The default implementation simply forwards the request to QDesktopServices::openUrl(). */ -bool QWaylandCompositor::openUrl(WaylandClient *client, const QUrl &url) +bool QWaylandCompositor::openUrl(QWaylandClient *client, const QUrl &url) { Q_UNUSED(client); return QDesktopServices::openUrl(url); @@ -299,4 +297,9 @@ QWaylandSurfaceView *QWaylandCompositor::createView(QWaylandSurface *surface) return new QWaylandSurfaceView(surface); } +QWaylandInputDevice *QWaylandCompositor::inputDeviceFor(QInputEvent *inputEvent) +{ + return m_compositor->inputDeviceFor(inputEvent); +} + QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h index 740f2553d..2c73a1d3e 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.h +++ b/src/compositor/compositor_api/qwaylandcompositor.h @@ -51,9 +51,12 @@ struct wl_display; QT_BEGIN_NAMESPACE +class QInputEvent; + class QMimeData; class QUrl; class QOpenGLContext; +class QWaylandClient; class QWaylandSurface; class QWaylandInputDevice; class QWaylandInputPanel; @@ -94,9 +97,9 @@ public: void sendFrameCallbacks(QList<QWaylandSurface *> visibleSurfaces); void destroyClientForSurface(QWaylandSurface *surface); - void destroyClient(WaylandClient *client); + void destroyClient(QWaylandClient *client); - QList<QWaylandSurface *> surfacesForClient(WaylandClient* client) const; + QList<QWaylandSurface *> surfacesForClient(QWaylandClient* client) const; QList<QWaylandSurface *> surfaces() const; QWindow *window()const; @@ -107,7 +110,7 @@ public: virtual QWaylandSurfaceView *pickView(const QPointF &globalPosition) const; virtual QPointF mapToView(QWaylandSurfaceView *view, const QPointF &surfacePosition) const; - virtual bool openUrl(WaylandClient *client, const QUrl &url); + virtual bool openUrl(QWaylandClient *client, const QUrl &url); QtWayland::Compositor *handle() const; @@ -148,6 +151,8 @@ public: virtual QWaylandSurfaceView *createView(QWaylandSurface *surface); + QWaylandInputDevice *inputDeviceFor(QInputEvent *inputEvent); + protected: QWaylandCompositor(QWindow *window, const char *socketName, QtWayland::Compositor *dptr); virtual void retainedSelectionReceived(QMimeData *mimeData); diff --git a/src/compositor/compositor_api/qwaylandinput.cpp b/src/compositor/compositor_api/qwaylandinput.cpp index 97bbb23b3..76e365fb5 100644 --- a/src/compositor/compositor_api/qwaylandinput.cpp +++ b/src/compositor/compositor_api/qwaylandinput.cpp @@ -183,4 +183,10 @@ QWaylandInputDevice::CapabilityFlags QWaylandInputDevice::capabilities() return d->capabilities(); } +bool QWaylandInputDevice::isOwner(QInputEvent *inputEvent) +{ + Q_UNUSED(inputEvent); + return true; +} + QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandinput.h b/src/compositor/compositor_api/qwaylandinput.h index 2c0b9ee7c..209228b97 100644 --- a/src/compositor/compositor_api/qwaylandinput.h +++ b/src/compositor/compositor_api/qwaylandinput.h @@ -54,6 +54,7 @@ class QWaylandSurface; class QKeyEvent; class QTouchEvent; class QWaylandSurfaceView; +class QInputEvent; namespace QtWayland { class InputDevice; @@ -125,6 +126,8 @@ public: QWaylandInputDevice::CapabilityFlags capabilities(); + virtual bool isOwner(QInputEvent *inputEvent); + private: QtWayland::InputDevice *d; Q_DISABLE_COPY(QWaylandInputDevice) diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp index ae472f219..1333100c6 100644 --- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp @@ -43,6 +43,7 @@ #include <QtCompositor/private/qwlcompositor_p.h> +#include "qwaylandclient.h" #include "qwaylandquickcompositor.h" #include "qwaylandquicksurface.h" #include "qwaylandsurfaceitem.h" @@ -84,6 +85,7 @@ QWaylandQuickCompositor::QWaylandQuickCompositor(QQuickWindow *window, const cha qmlRegisterUncreatableType<QWaylandSurfaceItem>("QtCompositor", 1, 0, "WaylandSurfaceItem", QObject::tr("Cannot create instance of WaylandSurfaceItem")); qmlRegisterUncreatableType<QWaylandQuickSurface>("QtCompositor", 1, 0, "WaylandQuickSurface", QObject::tr("Cannot create instance of WaylandQuickSurface")); + qmlRegisterUncreatableType<QWaylandClient>("QtCompositor", 1, 0, "WaylandClient", QObject::tr("Cannot create instance of WaylandClient")); } QWaylandQuickCompositorPrivate *QWaylandQuickCompositor::d_ptr() diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 205cea7a3..b5c38d88e 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -52,6 +53,7 @@ #include "wayland_wrapper/qwldatadevicemanager_p.h" #include "qwaylandcompositor.h" +#include "qwaylandclient.h" #include "qwaylandsurface_p.h" #include "qwaylandbufferref.h" #include "qwaylandsurfaceinterface.h" @@ -61,10 +63,11 @@ QT_BEGIN_NAMESPACE -QWaylandSurfacePrivate::QWaylandSurfacePrivate(wl_client *client, quint32 id, int version, QWaylandCompositor *compositor, QWaylandSurface *surface) - : QtWayland::Surface(client, id, version, compositor, surface) +QWaylandSurfacePrivate::QWaylandSurfacePrivate(wl_client *wlClient, quint32 id, int version, QWaylandCompositor *compositor, QWaylandSurface *surface) + : QtWayland::Surface(wlClient, id, version, compositor, surface) , closing(false) , refCount(1) + , client(QWaylandClient::fromWlClient(wlClient)) , windowType(QWaylandSurface::WindowType::None) {} @@ -89,10 +92,13 @@ QWaylandSurface::~QWaylandSurface() delete d->m_attacher; } -WaylandClient *QWaylandSurface::client() const +QWaylandClient *QWaylandSurface::client() const { Q_D(const QWaylandSurface); - return d->resource()->client(); + + if (!d->compositor()->clients().contains(d->client)) + return Q_NULLPTR; + return d->client; } QWaylandSurface *QWaylandSurface::parentSurface() const @@ -210,18 +216,6 @@ QtWayland::Surface * QWaylandSurface::handle() return d; } -qint64 QWaylandSurface::processId() const -{ - Q_D(const QWaylandSurface); - if (d->isDestroyed()) - return -1; - - struct wl_client *client = static_cast<struct wl_client *>(this->client()); - pid_t pid; - wl_client_get_credentials(client,&pid, 0,0); - return pid; -} - QVariantMap QWaylandSurface::windowProperties() const { Q_D(const QWaylandSurface); @@ -319,6 +313,12 @@ bool QWaylandSurface::transientInactive() const return d->transientInactive(); } +bool QWaylandSurface::inputRegionContains(const QPoint &p) const +{ + Q_D(const QWaylandSurface); + return d->inputRegion().contains(p); +} + void QWaylandSurface::destroy() { Q_D(QWaylandSurface); diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index 7c7ec4d76..4b802d778 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -54,6 +55,7 @@ struct wl_resource; QT_BEGIN_NAMESPACE class QTouchEvent; +class QWaylandClient; class QWaylandSurfacePrivate; class QWaylandCompositor; class QWaylandBufferRef; @@ -82,6 +84,7 @@ class Q_COMPOSITOR_EXPORT QWaylandSurface : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QWaylandSurface) + Q_PROPERTY(QWaylandClient *client READ client CONSTANT) Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) Q_PROPERTY(QWaylandSurface::WindowFlags windowFlags READ windowFlags NOTIFY windowFlagsChanged) Q_PROPERTY(QWaylandSurface::WindowType windowType READ windowType NOTIFY windowTypeChanged) @@ -120,7 +123,7 @@ public: QWaylandSurface(wl_client *client, quint32 id, int version, QWaylandCompositor *compositor); virtual ~QWaylandSurface(); - WaylandClient *client() const; + QWaylandClient *client() const; QWaylandSurface *parentSurface() const; QLinkedList<QWaylandSurface *> subSurfaces() const; @@ -153,7 +156,6 @@ public: QtWayland::Surface *handle(); - qint64 processId() const; QByteArray authenticationToken() const; QVariantMap windowProperties() const; void setWindowProperty(const QString &name, const QVariant &value); @@ -168,6 +170,8 @@ public: bool transientInactive() const; + bool inputRegionContains(const QPoint &p) const; + Q_INVOKABLE void destroy(); Q_INVOKABLE void destroySurface(); Q_INVOKABLE void ping(); diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 5e2188883..2e6f75a64 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> ** Contact: http://www.qt-project.org/legal ** @@ -58,13 +59,16 @@ class Q_COMPOSITOR_EXPORT QWaylandSurfacePrivate : public QObjectPrivate, public { Q_DECLARE_PUBLIC(QWaylandSurface) public: - QWaylandSurfacePrivate(wl_client *client, quint32 id, int version, QWaylandCompositor *compositor, QWaylandSurface *surface); + QWaylandSurfacePrivate(wl_client *wlClient, quint32 id, int version, QWaylandCompositor *compositor, QWaylandSurface *surface); void setType(QWaylandSurface::WindowType type); void setTitle(const QString &title); void setClassName(const QString &className); bool closing; int refCount; + + QWaylandClient *client; + QWaylandSurface::WindowType windowType; QList<QWaylandSurfaceView *> views; QList<QWaylandSurfaceInterface *> interfaces; diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp index cf9880b58..79afa3786 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp @@ -144,7 +144,12 @@ void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event) if (!surface()) return; - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + if (!surface()->inputRegionContains(event->pos())) { + event->ignore(); + return; + } + + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); if (inputDevice->mouseFocus() != this) inputDevice->setMouseFocus(this, event->localPos(), event->windowPos()); inputDevice->sendMousePressEvent(event->button(), event->localPos(), event->windowPos()); @@ -153,7 +158,7 @@ void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event) void QWaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseMoveEvent(this, event->localPos(), event->windowPos()); } } @@ -161,7 +166,7 @@ void QWaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event) void QWaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseReleaseEvent(event->button(), event->localPos(), event->windowPos()); } } @@ -169,7 +174,7 @@ void QWaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event) void QWaylandSurfaceItem::hoverEnterEvent(QHoverEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseMoveEvent(this, event->pos()); } } @@ -177,7 +182,7 @@ void QWaylandSurfaceItem::hoverEnterEvent(QHoverEvent *event) void QWaylandSurfaceItem::hoverMoveEvent(QHoverEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseMoveEvent(this, event->pos()); } } @@ -185,7 +190,7 @@ void QWaylandSurfaceItem::hoverMoveEvent(QHoverEvent *event) void QWaylandSurfaceItem::hoverLeaveEvent(QHoverEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseMoveEvent(this, event->pos()); } } @@ -193,7 +198,12 @@ void QWaylandSurfaceItem::hoverLeaveEvent(QHoverEvent *event) void QWaylandSurfaceItem::wheelEvent(QWheelEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + if (!surface()->inputRegionContains(event->pos())) { + event->ignore(); + return; + } + + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendMouseWheelEvent(event->orientation(), event->delta()); } } @@ -201,7 +211,7 @@ void QWaylandSurfaceItem::wheelEvent(QWheelEvent *event) void QWaylandSurfaceItem::keyPressEvent(QKeyEvent *event) { if (surface()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendFullKeyEvent(event); } } @@ -209,7 +219,7 @@ void QWaylandSurfaceItem::keyPressEvent(QKeyEvent *event) void QWaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event) { if (surface() && hasFocus()) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); inputDevice->sendFullKeyEvent(event); } } @@ -217,13 +227,20 @@ void QWaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event) void QWaylandSurfaceItem::touchEvent(QTouchEvent *event) { if (m_touchEventsEnabled) { - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); + QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event); + + QPoint pointPos; + const QList<QTouchEvent::TouchPoint> &points = event->touchPoints(); + if (!points.isEmpty()) + pointPos = points.at(0).pos().toPoint(); + + if (event->type() == QEvent::TouchBegin && !surface()->inputRegionContains(pointPos)) { + event->ignore(); + return; + } + event->accept(); if (inputDevice->mouseFocus() != this) { - QPoint pointPos; - QList<QTouchEvent::TouchPoint> points = event->touchPoints(); - if (!points.isEmpty()) - pointPos = points.at(0).pos().toPoint(); inputDevice->setMouseFocus(this, pointPos, pointPos); } inputDevice->sendFullTouchEvent(event); @@ -232,15 +249,18 @@ void QWaylandSurfaceItem::touchEvent(QTouchEvent *event) } } -void QWaylandSurfaceItem::takeFocus() +void QWaylandSurfaceItem::takeFocus(QWaylandInputDevice *device) { setFocus(true); if (!surface()) return; - QWaylandInputDevice *inputDevice = compositor()->defaultInputDevice(); - inputDevice->setKeyboardFocus(surface()); + QWaylandInputDevice *target = device; + if (!target) { + target = compositor()->defaultInputDevice(); + } + target->setKeyboardFocus(surface()); } void QWaylandSurfaceItem::surfaceMapped() diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.h b/src/compositor/compositor_api/qwaylandsurfaceitem.h index 58dc4d871..fb70705b2 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.h +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.h @@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE class QWaylandSurfaceTextureProvider; class QMutex; +class QWaylandInputDevice; class Q_COMPOSITOR_EXPORT QWaylandSurfaceItem : public QQuickItem, public QWaylandSurfaceView { @@ -101,7 +102,7 @@ protected: void touchEvent(QTouchEvent *event); public slots: - void takeFocus(); + virtual void takeFocus(QWaylandInputDevice *device = 0); void setPaintEnabled(bool paintEnabled); private slots: diff --git a/src/compositor/global/qwaylandexport.h b/src/compositor/global/qwaylandexport.h index 45ddc159d..2812d433d 100644 --- a/src/compositor/global/qwaylandexport.h +++ b/src/compositor/global/qwaylandexport.h @@ -55,8 +55,6 @@ QT_BEGIN_NAMESPACE # endif #endif -typedef void WaylandClient; - QT_END_NAMESPACE #endif //WAYLANDEXPORT_H diff --git a/src/compositor/wayland_wrapper/qwlcompositor.cpp b/src/compositor/wayland_wrapper/qwlcompositor.cpp index faf32dc57..91fd1818a 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor.cpp +++ b/src/compositor/wayland_wrapper/qwlcompositor.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -44,6 +45,7 @@ #include "qwldisplay_p.h" #include "qwloutput_p.h" #include "qwlsurface_p.h" +#include "qwaylandclient.h" #include "qwaylandcompositor.h" #include "qwldatadevicemanager_p.h" #include "qwldatadevice_p.h" @@ -107,7 +109,6 @@ Compositor *Compositor::instance() Compositor::Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::ExtensionFlags extensions) : m_extensions(extensions) , m_display(new Display) - , m_default_input_device(0) , m_current_frame(0) , m_last_queued_buf(-1) , m_qt_compositor(qt_compositor) @@ -163,6 +164,7 @@ void Compositor::init() connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processWaylandEvents())); qRegisterMetaType<SurfaceBuffer*>("SurfaceBuffer*"); + qRegisterMetaType<QWaylandClient*>("WaylandClient*"); qRegisterMetaType<QWaylandSurface*>("WaylandSurface*"); qRegisterMetaType<QWaylandSurfaceView*>("WaylandSurfaceView*"); //initialize distancefieldglyphcache here @@ -176,6 +178,8 @@ Compositor::~Compositor() { if (!m_destroyed_surfaces.isEmpty()) qWarning("QWaylandCompositor::cleanupGraphicsResources() must be called manually"); + qDeleteAll(m_clients); + delete m_outputExtension; delete m_surfaceExtension; @@ -183,6 +187,7 @@ Compositor::~Compositor() delete m_touchExtension; delete m_qtkeyExtension; + removeInputDevice(m_default_wayland_input_device); delete m_default_wayland_input_device; delete m_data_device_manager; @@ -221,6 +226,16 @@ void Compositor::destroySurface(Surface *surface) m_destroyed_surfaces << surface->waylandSurface(); } +void Compositor::resetInputDevice(Surface *surface) +{ + foreach (QWaylandInputDevice *dev, m_inputDevices) { + if (dev->keyboardFocus() == surface->waylandSurface()) + dev->setKeyboardFocus(0); + if (dev->mouseFocus() && dev->mouseFocus()->surface() == surface->waylandSurface()) + dev->setMouseFocus(0, QPointF(), QPointF()); + } +} + void Compositor::cleanupGraphicsResources() { qDeleteAll(m_destroyed_surfaces); @@ -241,16 +256,15 @@ void Compositor::compositor_create_region(Resource *resource, uint32_t id) new Region(resource->client(), id); } -void Compositor::destroyClient(WaylandClient *c) +void Compositor::destroyClient(QWaylandClient *client) { - wl_client *client = static_cast<wl_client *>(c); if (!client) return; if (m_windowManagerIntegration) - m_windowManagerIntegration->sendQuitMessage(client); + m_windowManagerIntegration->sendQuitMessage(client->client()); - wl_client_destroy(client); + wl_client_destroy(client->client()); } QWindow *Compositor::window() const @@ -319,18 +333,12 @@ void Compositor::initializeExtensions() void Compositor::initializeDefaultInputDevice() { m_default_wayland_input_device = new QWaylandInputDevice(m_qt_compositor); - m_default_input_device = m_default_wayland_input_device->handle(); + registerInputDevice(m_default_wayland_input_device); } -QList<struct wl_client *> Compositor::clients() const +QList<QWaylandClient *> Compositor::clients() const { - QList<struct wl_client *> list; - foreach (Surface *surface, m_surfaces) { - struct wl_client *client = surface->resource()->client(); - if (!list.contains(client)) - list.append(client); - } - return list; + return m_clients; } void Compositor::setScreenOrientation(Qt::ScreenOrientation orientation) @@ -383,7 +391,8 @@ QWaylandCompositor::ExtensionFlags Compositor::extensions() const InputDevice* Compositor::defaultInputDevice() { - return m_default_input_device; + // The list gets prepended so that default is the last element + return m_inputDevices.last()->handle(); } QList<QtWayland::Surface *> Compositor::surfacesForClient(wl_client *client) @@ -501,6 +510,32 @@ void Compositor::loadServerBufferIntegration() } } +void Compositor::registerInputDevice(QWaylandInputDevice *device) +{ + // The devices get prepended as the first input device that gets added + // is assumed to be the default and it will claim to accept all the input + // events if asked + m_inputDevices.prepend(device); +} + +void Compositor::removeInputDevice(QWaylandInputDevice *device) +{ + m_inputDevices.removeOne(device); +} + +QWaylandInputDevice *Compositor::inputDeviceFor(QInputEvent *inputEvent) +{ + QWaylandInputDevice *dev = NULL; + for (int i = 0; i < m_inputDevices.size(); i++) { + QWaylandInputDevice *candidate = m_inputDevices.at(i); + if (candidate->isOwner(inputEvent)) { + dev = candidate; + break; + } + } + return dev; +} + } // namespace Wayland QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlcompositor_p.h b/src/compositor/wayland_wrapper/qwlcompositor_p.h index 599f79b6d..9c3a0f9de 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor_p.h +++ b/src/compositor/wayland_wrapper/qwlcompositor_p.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -56,6 +57,10 @@ QT_BEGIN_NAMESPACE +class QWaylandClient; +class QWaylandClientPrivate; +class QInputEvent; + class QWaylandCompositor; class QWaylandInputDevice; class WindowManagerServerIntegration; @@ -93,11 +98,16 @@ public: void sendFrameCallbacks(QList<QWaylandSurface *> visibleSurfaces); void frameFinished(Surface *surface = 0); - InputDevice *defaultInputDevice(); //we just have 1 default device for now (since QPA doesn't give us anything else) + InputDevice *defaultInputDevice(); + + void registerInputDevice(QWaylandInputDevice *device); + QList<QWaylandInputDevice *> inputDevices() const { return m_inputDevices; } + QWaylandInputDevice *inputDeviceFor(QInputEvent *inputEvent); + void removeInputDevice(QWaylandInputDevice *device); void destroySurface(Surface *surface); - void destroyClient(WaylandClient *client); + void destroyClient(QWaylandClient *client); uint currentTimeMsecs() const; @@ -119,7 +129,7 @@ public: static Compositor *instance(); - QList<struct wl_client *> clients() const; + QList<QWaylandClient *> clients() const; WindowManagerServerIntegration *windowManagerIntegration() const { return m_windowManagerIntegration; } @@ -153,6 +163,8 @@ public: void feedRetainedSelectionData(QMimeData *data); static void bindGlobal(wl_client *client, void *data, uint32_t version, uint32_t id); + void resetInputDevice(Surface *surface); + public slots: void cleanupGraphicsResources(); @@ -173,7 +185,8 @@ protected: /* Input */ QWaylandInputDevice *m_default_wayland_input_device; - InputDevice *m_default_input_device; + + QList<QWaylandInputDevice *> m_inputDevices; /* Output */ //make this a list of the available screens @@ -193,6 +206,7 @@ protected: QWaylandCompositor *m_qt_compositor; Qt::ScreenOrientation m_orientation; + QList<QWaylandClient *> m_clients; #ifdef QT_COMPOSITOR_WAYLAND_GL QScopedPointer<HardwareIntegration> m_hw_integration; @@ -218,6 +232,8 @@ protected: bool m_retainSelection; friend class QT_PREPEND_NAMESPACE(QWaylandCompositor); + friend class QT_PREPEND_NAMESPACE(QWaylandClient); + friend class QT_PREPEND_NAMESPACE(QWaylandClientPrivate); }; } diff --git a/src/compositor/wayland_wrapper/qwlsurface.cpp b/src/compositor/wayland_wrapper/qwlsurface.cpp index 5cd8bb506..ee8197013 100644 --- a/src/compositor/wayland_wrapper/qwlsurface.cpp +++ b/src/compositor/wayland_wrapper/qwlsurface.cpp @@ -104,6 +104,11 @@ public: bool canSend; }; +static QRegion infiniteRegion() { + return QRegion(QRect(QPoint(std::numeric_limits<int>::min(), std::numeric_limits<int>::min()), + QPoint(std::numeric_limits<int>::max(), std::numeric_limits<int>::max()))); +} + Surface::Surface(struct wl_client *client, uint32_t id, int version, QWaylandCompositor *compositor, QWaylandSurface *surface) : QtWaylandServer::wl_surface(client, id, version) , m_compositor(compositor->handle()) @@ -114,6 +119,7 @@ Surface::Surface(struct wl_client *client, uint32_t id, int version, QWaylandCom , m_extendedSurface(0) , m_subSurface(0) , m_inputPanelSurface(0) + , m_inputRegion(infiniteRegion()) , m_transientParent(0) , m_transientInactive(false) , m_transientOffset(QPointF(0, 0)) @@ -124,6 +130,7 @@ Surface::Surface(struct wl_client *client, uint32_t id, int version, QWaylandCom { m_pending.buffer = 0; m_pending.newlyAttached = false; + m_pending.inputRegion = infiniteRegion(); } Surface::~Surface() @@ -190,7 +197,6 @@ void Surface::setSize(const QSize &size) { if (size != m_size) { m_opaqueRegion = QRegion(); - m_inputRegion = QRegion(QRect(QPoint(), size)); m_size = size; m_waylandSurface->sizeChanged(); } @@ -288,11 +294,7 @@ void Surface::setBackBuffer(SurfaceBuffer *buffer) m_damage = m_damage.intersected(QRect(QPoint(), m_size)); emit m_waylandSurface->damaged(m_damage); } else { - InputDevice *inputDevice = m_compositor->defaultInputDevice(); - if (inputDevice->keyboardFocus() == this) - inputDevice->setKeyboardFocus(0); - if (inputDevice->mouseFocus() && inputDevice->mouseFocus()->surface() == waylandSurface()) - inputDevice->setMouseFocus(0, QPointF(), QPointF()); + m_compositor->resetInputDevice(this); } m_damage = QRegion(); } @@ -379,7 +381,11 @@ void Surface::surface_set_opaque_region(Resource *, struct wl_resource *region) void Surface::surface_set_input_region(Resource *, struct wl_resource *region) { - m_inputRegion = region ? Region::fromResource(region)->region() : QRegion(QRect(QPoint(), size())); + if (region) { + m_pending.inputRegion = Region::fromResource(region)->region(); + } else { + m_pending.inputRegion = infiniteRegion(); + } } void Surface::surface_commit(Resource *) @@ -406,6 +412,8 @@ void Surface::surface_commit(Resource *) m_frameCallbacks << m_pendingFrameCallbacks; m_pendingFrameCallbacks.clear(); + m_inputRegion = m_pending.inputRegion.intersected(QRect(QPoint(), m_size)); + emit m_waylandSurface->redraw(); } diff --git a/src/compositor/wayland_wrapper/qwlsurface_p.h b/src/compositor/wayland_wrapper/qwlsurface_p.h index 5a3c4be3d..bbab57a4d 100644 --- a/src/compositor/wayland_wrapper/qwlsurface_p.h +++ b/src/compositor/wayland_wrapper/qwlsurface_p.h @@ -171,6 +171,7 @@ protected: QRegion damage; QPoint offset; bool newlyAttached; + QRegion inputRegion; } m_pending; QPoint m_lastLocalMousePos; diff --git a/src/compositor/windowmanagerprotocol/waylandwindowmanagerintegration.cpp b/src/compositor/windowmanagerprotocol/waylandwindowmanagerintegration.cpp index 5387854a4..150a04e5b 100644 --- a/src/compositor/windowmanagerprotocol/waylandwindowmanagerintegration.cpp +++ b/src/compositor/windowmanagerprotocol/waylandwindowmanagerintegration.cpp @@ -43,6 +43,7 @@ #include <wayland_wrapper/qwldisplay_p.h> #include <wayland_wrapper/qwlcompositor_p.h> +#include <compositor_api/qwaylandclient.h> #include <compositor_api/qwaylandcompositor.h> #include <wayland-server.h> @@ -104,7 +105,7 @@ void WindowManagerServerIntegration::windowmanager_open_url(Resource *resource, m_urls.insert(resource, url); else { m_urls.remove(resource); - m_compositor->openUrl(resource->client(), QUrl(url)); + m_compositor->openUrl(QWaylandClient::fromWlClient(resource->client()), QUrl(url)); } } diff --git a/tests/auto/compositor/compositor.pro b/tests/auto/compositor/compositor.pro index d173d2ed6..035beeb41 100644 --- a/tests/auto/compositor/compositor.pro +++ b/tests/auto/compositor/compositor.pro @@ -24,7 +24,11 @@ SOURCES += tst_compositor.cpp \ testcompositor.cpp \ testkeyboardgrabber.cpp \ mockclient.cpp \ + mockseat.cpp \ + testinputdevice.cpp HEADERS += testcompositor.h \ testkeyboardgrabber.h \ mockclient.h \ + mockseat.h \ + testinputdevice.h diff --git a/tests/auto/compositor/mockclient.cpp b/tests/auto/compositor/mockclient.cpp index 9bbe56519..8f2bbbc6d 100644 --- a/tests/auto/compositor/mockclient.cpp +++ b/tests/auto/compositor/mockclient.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "mockclient.h" +#include "mockseat.h" #include <QElapsedTimer> #include <QSocketNotifier> @@ -145,6 +146,9 @@ void MockClient::handleGlobal(uint32_t id, const QByteArray &interface) shm = static_cast<wl_shm *>(wl_registry_bind(registry, id, &wl_shm_interface, 1)); } else if (interface == "wl_shell") { wlshell = static_cast<wl_shell *>(wl_registry_bind(registry, id, &wl_shell_interface, 1)); + } else if (interface == "wl_seat") { + wl_seat *s = static_cast<wl_seat *>(wl_registry_bind(registry, id, &wl_seat_interface, 1)); + m_seats << new MockSeat(s); } } diff --git a/tests/auto/compositor/mockclient.h b/tests/auto/compositor/mockclient.h index de1084ab9..04c5dc831 100644 --- a/tests/auto/compositor/mockclient.h +++ b/tests/auto/compositor/mockclient.h @@ -44,6 +44,9 @@ #include <QObject> #include <QImage> #include <QRect> +#include <QList> + +class MockSeat; class ShmBuffer { @@ -74,6 +77,8 @@ public: wl_registry *registry; wl_shell *wlshell; + QList<MockSeat *> m_seats; + QRect geometry; int fd; diff --git a/tests/auto/compositor/mockseat.cpp b/tests/auto/compositor/mockseat.cpp new file mode 100644 index 000000000..ff6e449dd --- /dev/null +++ b/tests/auto/compositor/mockseat.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd., author: <mikko.levonmaa@lge.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite 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 "mockseat.h" + +MockSeat::MockSeat(wl_seat *seat) + : m_seat(seat) +{ + // Bind to the keyboard interface so that the compositor has + // the right resource associations + m_keyboard = wl_seat_get_keyboard(seat); +} + +MockSeat::~MockSeat() +{ + wl_keyboard_destroy(m_keyboard); + wl_seat_destroy(m_seat); +} diff --git a/tests/auto/compositor/mockseat.h b/tests/auto/compositor/mockseat.h new file mode 100644 index 000000000..19b777619 --- /dev/null +++ b/tests/auto/compositor/mockseat.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics Ltd., author: <mikko.levonmaa@lge.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite 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 MOCKSEAT +#define MOCKSEAT + +#include <QObject> +#include <wayland-client.h> + +class MockSeat : public QObject +{ + Q_OBJECT + +public: + MockSeat(wl_seat *seat); + ~MockSeat(); + + wl_seat *m_seat; + wl_keyboard *m_keyboard; +}; +#endif diff --git a/tests/auto/compositor/testinputdevice.cpp b/tests/auto/compositor/testinputdevice.cpp new file mode 100644 index 000000000..627578514 --- /dev/null +++ b/tests/auto/compositor/testinputdevice.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite 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 "testinputdevice.h" + +#include <QMouseEvent> + +TestInputDevice::TestInputDevice(QWaylandCompositor *compositor, QWaylandInputDevice::CapabilityFlags caps) + : QWaylandInputDevice(compositor, caps) +{ + m_queryCount = 0; +} + +TestInputDevice::~TestInputDevice() +{ +} + +bool TestInputDevice::isOwner(QInputEvent *event) +{ + m_queryCount++; + QMouseEvent *me = dynamic_cast<QMouseEvent *>(event); + return m_events.contains(me); +} + +QList<QMouseEvent *> TestInputDevice::createMouseEvents(int count) +{ + for (int i = 0; i < count; i++) { + m_events.append(new QMouseEvent(QEvent::MouseMove, QPointF(10 + i, 10 + i), Qt::NoButton, Qt::NoButton, Qt::NoModifier)); + } + return m_events; +} + diff --git a/tests/auto/compositor/testinputdevice.h b/tests/auto/compositor/testinputdevice.h new file mode 100644 index 000000000..cc930843a --- /dev/null +++ b/tests/auto/compositor/testinputdevice.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 LG Electronics, Inc., author: <mikko.levonmaa@lge.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite 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> +#include <QList> + +class QInputEvent; +class QMouseEvent; + +class TestInputDevice : public QWaylandInputDevice +{ + +public: + + TestInputDevice(QWaylandCompositor *compositor, QWaylandInputDevice::CapabilityFlags caps); + ~TestInputDevice(); + + bool isOwner(QInputEvent *event); + + QList<QMouseEvent *> createMouseEvents(int count); + + int queryCount() { return m_queryCount; } + +private: + int m_queryCount; + QList<QMouseEvent *> m_events; +}; diff --git a/tests/auto/compositor/tst_compositor.cpp b/tests/auto/compositor/tst_compositor.cpp index e97d3b16d..2e404a79d 100644 --- a/tests/auto/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/tst_compositor.cpp @@ -45,6 +45,8 @@ #include "QtCompositor/private/qwlkeyboard_p.h" #include "QtCompositor/private/qwlinputdevice_p.h" +#include "QtCompositor/private/qwlcompositor_p.h" +#include "testinputdevice.h" #include "qwaylandbufferref.h" @@ -64,6 +66,8 @@ public: private slots: void inputDeviceCapabilities(); void keyboardGrab(); + void inputDeviceCreation(); + void inputDeviceKeyboardFocus(); void singleClient(); void multipleClients(); void geometry(); @@ -83,10 +87,11 @@ void tst_WaylandCompositor::singleClient() wl_surface *sb = client.createSurface(); QTRY_COMPARE(compositor.surfaces.size(), 2); - WaylandClient *ca = compositor.surfaces.at(0)->client(); - WaylandClient *cb = compositor.surfaces.at(1)->client(); + QWaylandClient *ca = compositor.surfaces.at(0)->client(); + QWaylandClient *cb = compositor.surfaces.at(1)->client(); QCOMPARE(ca, cb); + QVERIFY(ca != 0); QList<QWaylandSurface *> surfaces = compositor.surfacesForClient(ca); QCOMPARE(surfaces.size(), 2); @@ -114,13 +119,14 @@ void tst_WaylandCompositor::multipleClients() QTRY_COMPARE(compositor.surfaces.size(), 3); - WaylandClient *ca = compositor.surfaces.at(0)->client(); - WaylandClient *cb = compositor.surfaces.at(1)->client(); - WaylandClient *cc = compositor.surfaces.at(2)->client(); + QWaylandClient *ca = compositor.surfaces.at(0)->client(); + QWaylandClient *cb = compositor.surfaces.at(1)->client(); + QWaylandClient *cc = compositor.surfaces.at(2)->client(); QVERIFY(ca != cb); QVERIFY(ca != cc); QVERIFY(cb != cc); + QVERIFY(ca != 0); QCOMPARE(compositor.surfacesForClient(ca).size(), 1); QCOMPARE(compositor.surfacesForClient(ca).at(0), compositor.surfaces.at(0)); @@ -321,5 +327,74 @@ void tst_WaylandCompositor::inputDeviceCapabilities() QTRY_COMPARE(k, dev.keyboardDevice()); } +void tst_WaylandCompositor::inputDeviceCreation() +{ + TestCompositor compositor; + TestInputDevice dev1(&compositor, QWaylandInputDevice::Pointer | QWaylandInputDevice::Keyboard); + TestInputDevice dev2(&compositor, QWaylandInputDevice::Pointer | QWaylandInputDevice::Keyboard); + + compositor.handle()->registerInputDevice(&dev1); + compositor.handle()->registerInputDevice(&dev2); + + // The compositor will create the default input device + QTRY_COMPARE(compositor.handle()->inputDevices().count(), 3); + // Test the order + QTRY_COMPARE(compositor.handle()->inputDevices().at(0), &dev2); + QTRY_COMPARE(compositor.handle()->inputDevices().at(1), &dev1); + QTRY_COMPARE(compositor.handle()->inputDevices().at(2), compositor.defaultInputDevice()); + + QList<QMouseEvent *> allEvents; + allEvents += dev1.createMouseEvents(2); + allEvents += dev2.createMouseEvents(5); + foreach (QMouseEvent *me, allEvents) { + compositor.inputDeviceFor(me); + } + + // The first input device will only get called exatly the number of times it has created + // the events + QTRY_COMPARE(dev1.queryCount(), 2); + // The second will get called the total number of times as it sits as the first item in + // the registered input devices list + QTRY_COMPARE(dev2.queryCount(), 7); +} + +void tst_WaylandCompositor::inputDeviceKeyboardFocus() +{ + TestCompositor compositor; + + + TestInputDevice dev1(&compositor, QWaylandInputDevice::Keyboard); + TestInputDevice dev2(&compositor, QWaylandInputDevice::Keyboard); + + compositor.handle()->registerInputDevice(&dev1); + compositor.handle()->registerInputDevice(&dev2); + + // Create client after all the input devices have been set up as the mock client + // does not dynamically listen to new seats + MockClient client; + wl_surface *surface = client.createSurface(); + QTRY_COMPARE(compositor.surfaces.size(), 1); + + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + QList<QWaylandInputDevice *> devices = compositor.handle()->inputDevices(); + foreach (QWaylandInputDevice *dev, devices) { + dev->setKeyboardFocus(waylandSurface); + } + QTRY_COMPARE(compositor.defaultInputDevice()->keyboardFocus(), waylandSurface); + QTRY_COMPARE(dev1.keyboardFocus(), waylandSurface); + QTRY_COMPARE(dev2.keyboardFocus(), waylandSurface); + + wl_surface_destroy(surface); + QTRY_VERIFY(compositor.surfaces.size() == 0); + // This will normally be called for example in the quick compositor + // but here call it manually to get rid of the surface and have it reset + // the focus + compositor.handle()->cleanupGraphicsResources(); + + QTRY_VERIFY(!compositor.defaultInputDevice()->keyboardFocus()); + QTRY_VERIFY(!dev1.keyboardFocus()); + QTRY_VERIFY(!dev2.keyboardFocus()); +} + #include <tst_compositor.moc> QTEST_MAIN(tst_WaylandCompositor); |