Allow client side input device customization

Introduces QWaylandInputDeviceIntegration plugins to allow customization
of input device related behavior. The plugin can be activated via the
environment variable QT_WAYLAND_INPUTDEVICE_INTEGRATION

Change-Id: If5629737752afacb29161f51c1b7c6e171fb2758
Reviewed-by: Mikko Levonmaa <mikko.levonmaa@lge.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Reviewed-by: Giulio Camuffo <giulio.camuffo@jollamobile.com>
This commit is contained in:
Mikko Levonmaa 2014-09-18 12:32:57 +03:00
parent 03c1b4d4ca
commit 5ec3eacefe
12 changed files with 659 additions and 183 deletions

View File

@ -3,7 +3,9 @@ QT += core-private gui-private
QT_FOR_PRIVATE += platformsupport-private
MODULE=waylandclient
MODULE_PLUGIN_TYPES = wayland-graphics-integration-client
MODULE_PLUGIN_TYPES = \
wayland-graphics-integration-client \
wayland-inputdevice-integration
load(qt_module)
@ -108,3 +110,4 @@ HEADERS += qwaylandintegration_p.h \
include(hardwareintegration/hardwareintegration.pri)
include(shellintegration/shellintegration.pri)
include(inputdeviceintegration/inputdeviceintegration.pri)

View File

@ -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

View File

@ -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, uint32_t id) = 0;
};
QT_END_NAMESPACE
#endif // QWAYLANDINPUTDEVICEINTEGRATION_H

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 &paramList) = 0;
};
QT_END_NAMESPACE
#endif // QWAYLANDINPUTDEVICEINTEGRATIONPLUGIN_H

View File

@ -241,7 +241,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, id);
QWaylandInputDevice *inputDevice = mWaylandIntegration->createInputDevice(this, id);
mInputDevices.append(inputDevice);
} else if (interface == QStringLiteral("wl_data_device_manager")) {
mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));

View File

@ -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)
{
#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("");
, mFocusCallback(0)
, mNativeModifiers(0)
{
connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey()));
}
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);
}
#ifndef QT_NO_WAYLAND_XKB
bool QWaylandInputDevice::Keyboard::createDefaultKeyMap()
{
if (mXkbContext && mXkbMap && mXkbState) {
return true;
}
xkb_rule_names names;
names.rules = strdup("evdev");
names.model = strdup("pc105");
names.layout = strdup("us");
names.variant = strdup("");
names.options = strdup("");
mXkbContext = xkb_context_new(xkb_context_flags(0));
if (mXkbContext) {
mXkbMap = xkb_map_new_from_names(mXkbContext, &names, xkb_map_compile_flags(0));
if (mXkbMap) {
mXkbState = xkb_state_new(mXkbMap);
}
if (!mXkbContext || !mXkbMap || !mXkbState)
qWarning() << "xkb_map_new_from_names failed, no key input";
#endif
}
~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());
}
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;
if (!mXkbContext || !mXkbMap || !mXkbState) {
qWarning() << "xkb_map_new_from_names failed, no key input";
return false;
}
return true;
}
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
static const wl_callback_listener callback;
static void focusCallback(void *data, struct wl_callback *callback, uint32_t time);
};
class QWaylandInputDevice::Pointer : public QtWayland::wl_pointer
void QWaylandInputDevice::Keyboard::releaseKeyMap()
{
public:
Pointer(QWaylandInputDevice *p)
: mParent(p)
, mFocus(0)
, mEnterSerial(0)
, mCursorSerial(0)
, mButtons(0)
{
}
~Pointer()
{
wl_pointer_destroy(object());
}
if (mXkbState)
xkb_state_unref(mXkbState);
if (mXkbMap)
xkb_map_unref(mXkbMap);
if (mXkbContext)
xkb_context_unref(mXkbContext);
}
#endif
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 QWaylandInputDevice::Touch : public QtWayland::wl_touch
QWaylandInputDevice::Keyboard::~Keyboard()
{
public:
Touch(QWaylandInputDevice *p)
: mParent(p)
, mFocus(0)
{
}
~Touch()
{
wl_touch_destroy(object());
}
#ifndef QT_NO_WAYLAND_XKB
releaseKeyMap();
#endif
wl_keyboard_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;
void QWaylandInputDevice::Keyboard::stopRepeat()
{
mRepeatTimer.stop();
}
bool allTouchPointsReleased();
QWaylandInputDevice::Pointer::Pointer(QWaylandInputDevice *p)
: mParent(p)
, mFocus(0)
, mEnterSerial(0)
, mCursorSerial(0)
, mButtons(0)
{
}
QWaylandInputDevice *mParent;
QWaylandWindow *mFocus;
QList<QWindowSystemInterface::TouchPoint> mTouchPoints;
QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints;
};
QWaylandInputDevice::Pointer::~Pointer()
{
wl_pointer_destroy(object());
}
QWaylandInputDevice::Touch::Touch(QWaylandInputDevice *p)
: mParent(p)
, mFocus(0)
{
}
QWaylandInputDevice::Touch::~Touch()
{
wl_touch_destroy(object());
}
QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, uint32_t id)
: QObject()
@ -246,7 +175,6 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, uint32_t id)
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,26 +760,26 @@ 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::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,

View File

@ -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, 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

View File

@ -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);
@ -361,4 +367,30 @@ void QWaylandIntegration::initializeShellIntegration()
}
}
QWaylandInputDevice *QWaylandIntegration::createInputDevice(QWaylandDisplay *display, uint32_t id)
{
if (mInputDeviceIntegration) {
return mInputDeviceIntegration->createInputDevice(display, id);
}
return new QWaylandInputDevice(display, 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

View File

@ -52,6 +52,8 @@ class QWaylandDisplay;
class QWaylandClientBufferIntegration;
class QWaylandServerBufferIntegration;
class QWaylandShellIntegration;
class QWaylandInputDeviceIntegration;
class QWaylandInputDevice;
class Q_WAYLAND_CLIENT_EXPORT QWaylandIntegration : public QPlatformIntegration
{
@ -89,17 +91,24 @@ public:
QPlatformTheme *createPlatformTheme(const QString &name) const;
QWaylandInputDevice *createInputDevice(QWaylandDisplay *display, 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;