diff options
-rw-r--r-- | src/compositor/compositor_api/compositor_api.pri | 1 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandcompositor.cpp | 4 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandinput.cpp | 1 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard.cpp | 340 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard.h | 2 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard_p.h (renamed from src/compositor/wayland_wrapper/qwlkeyboard_p.h) | 68 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwldatadevice.cpp | 1 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlinputmethod.cpp | 3 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/qwlkeyboard.cpp | 384 | ||||
-rw-r--r-- | src/compositor/wayland_wrapper/wayland_wrapper.pri | 2 |
10 files changed, 351 insertions, 455 deletions
diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 6b9b76241..ee07ff737 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -9,6 +9,7 @@ HEADERS += \ compositor_api/qwaylandinput.h \ compositor_api/qwaylandinput_p.h \ compositor_api/qwaylandkeyboard.h \ + compositor_api/qwaylandkeyboard_p.h \ compositor_api/qwaylandpointer.h \ compositor_api/qwaylandpointer_p.h \ compositor_api/qwaylandtouch.h \ diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 14aabac6f..f66ebd3f1 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -44,11 +44,11 @@ #include <QtCompositor/qwaylandview.h> #include <QtCompositor/qwaylandclient.h> #include <QtCompositor/qwaylandkeyboard.h> -#include <QtCompositor/private/qwlkeyboard_p.h> #include <QtCompositor/qwaylandpointer.h> #include <QtCompositor/qwaylandtouch.h> -#include "qwaylandsurface_p.h" +#include <QtCompositor/private/qwaylandkeyboard_p.h> +#include <QtCompositor/private/qwaylandsurface_p.h> #include "wayland_wrapper/qwldatadevice_p.h" #include "wayland_wrapper/qwldatadevicemanager_p.h" diff --git a/src/compositor/compositor_api/qwaylandinput.cpp b/src/compositor/compositor_api/qwaylandinput.cpp index 3c81ed6cd..c1a9a9149 100644 --- a/src/compositor/compositor_api/qwaylandinput.cpp +++ b/src/compositor/compositor_api/qwaylandinput.cpp @@ -37,7 +37,6 @@ #include "qwaylandinput.h" #include "qwaylandinput_p.h" -#include "qwlkeyboard_p.h" #include "qwaylandcompositor.h" #include "qwaylandview.h" #include <QtCompositor/QWaylandDrag> diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index 7d62f3898..383c97b00 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -36,12 +36,300 @@ ****************************************************************************/ #include "qwaylandkeyboard.h" -#include "qwlkeyboard_p.h" +#include "qwaylandkeyboard_p.h" +#include <QtCompositor/QWaylandCompositor> #include <QtCompositor/QWaylandInputDevice> #include <QtCompositor/QWaylandClient> +#include <QtCompositor/private/qwlshellsurface_p.h> + +#include <QtCore/QFile> +#include <QtCore/QStandardPaths> + +#include <fcntl.h> +#include <unistd.h> +#ifndef QT_NO_WAYLAND_XKB +#include <sys/mman.h> +#include <sys/types.h> +#endif + + QT_BEGIN_NAMESPACE +QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandInputDevice *seat) + : QtWaylandServer::wl_keyboard() + , seat(seat) + , grab(this) + , focus() + , focusResource() + , keys() + , modsDepressed() + , modsLatched() + , modsLocked() + , group() + , pendingKeymap(false) +#ifndef QT_NO_WAYLAND_XKB + , xkb_state(0) +#endif +{ +#ifndef QT_NO_WAYLAND_XKB + initXKB(); +#endif +} + +QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate() +{ +#ifndef QT_NO_WAYLAND_XKB + if (xkb_context) { + if (keymap_area) + munmap(keymap_area, keymap_size); + close(keymap_fd); + xkb_context_unref(xkb_context); + xkb_state_unref(xkb_state); + } +#endif +} + +QWaylandKeyboardPrivate *QWaylandKeyboardPrivate::get(QWaylandKeyboard *keyboard) +{ + return keyboard->d_func(); +} + +void QWaylandKeyboardPrivate::focused(QWaylandSurface *surface) +{ + if (surface && surface->isCursorSurface()) + surface = Q_NULLPTR; + if (focusResource && focus != surface) { + uint32_t serial = compositor()->nextSerial(); + send_leave(focusResource->handle, serial, focus->resource()); + focusDestroyListener.reset(); + } + + Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0; + + if (resource && (focus != surface || focusResource != resource)) { + uint32_t serial = compositor()->nextSerial(); + send_modifiers(resource->handle, serial, modsDepressed, modsLatched, modsLocked, group); + send_enter(resource->handle, serial, surface->resource(), QByteArray::fromRawData((char *)keys.data(), keys.size() * sizeof(uint32_t))); + focusDestroyListener.listenForDestruction(surface->resource()); + } + + focusResource = resource; + focus = surface; + Q_EMIT q_func()->focusChanged(focus); +} + + +void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource) +{ +#ifndef QT_NO_WAYLAND_XKB + if (xkb_context) { + send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, + keymap_fd, keymap_size); + return; + } +#endif + int null_fd = open("/dev/null", O_RDONLY); + send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, + null_fd, 0); + close(null_fd); +} + +void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource) +{ + if (focusResource == resource) + focusResource = 0; +} + +void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void QWaylandKeyboardPrivate::key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + if (focusResource) { + send_key(focusResource->handle, serial, time, key, state); + } +} + +void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state) +{ + uint key = code - 8; + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + keys << key; + } else { + for (int i = 0; i < keys.size(); ++i) { + if (keys.at(i) == key) { + keys.remove(i); + } + } + } +} + +void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state) +{ + uint32_t time = compositor()->currentTimeMsecs(); + uint32_t serial = compositor()->nextSerial(); + uint key = code - 8; + grab->key(serial, time, key, state); +} + +void QWaylandKeyboardPrivate::modifiers(uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, uint32_t group) +{ + if (focusResource) { + send_modifiers(focusResource->handle, serial, mods_depressed, mods_latched, mods_locked, group); + } +} + +void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) +{ +#ifndef QT_NO_WAYLAND_XKB + if (!xkb_context) + return; + + xkb_state_update_key(xkb_state, code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); + + uint32_t modsDepressed = xkb_state_serialize_mods(xkb_state, (xkb_state_component)XKB_STATE_DEPRESSED); + uint32_t modsLatched = xkb_state_serialize_mods(xkb_state, (xkb_state_component)XKB_STATE_LATCHED); + uint32_t modsLocked = xkb_state_serialize_mods(xkb_state, (xkb_state_component)XKB_STATE_LOCKED); + uint32_t group = xkb_state_serialize_group(xkb_state, (xkb_state_component)XKB_STATE_EFFECTIVE); + + if (modsDepressed == modsDepressed + && modsLatched == modsLatched + && modsLocked == modsLocked + && group == group) + return; + + modsDepressed = modsDepressed; + modsLatched = modsLatched; + modsLocked = modsLocked; + group = group; + + grab->modifiers(compositor()->nextSerial(), modsDepressed, modsLatched, modsLocked, group); +#else + Q_UNUSED(code); + Q_UNUSED(state); +#endif +} + +void QWaylandKeyboardPrivate::updateKeymap() +{ + // There must be no keys pressed when changing the keymap, + // see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html + if (!pendingKeymap || !keys.isEmpty()) + return; + + pendingKeymap = false; +#ifndef QT_NO_WAYLAND_XKB + if (!xkb_context) + return; + + createXKBKeymap(); + foreach (Resource *res, resourceMap()) { + send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size); + } + + xkb_state_update_mask(xkb_state, 0, modsLatched, modsLocked, 0, 0, 0); + if (focusResource) + send_modifiers(focusResource->handle, + compositor()->nextSerial(), + modsDepressed, + modsLatched, + modsLocked, + group); +#endif +} + +#ifndef QT_NO_WAYLAND_XKB +static int createAnonymousFile(size_t size) +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); + if (path.isEmpty()) + return -1; + + QByteArray name = QFile::encodeName(path + QStringLiteral("/qtwayland-XXXXXX")); + + int fd = mkstemp(name.data()); + if (fd < 0) + return -1; + + long flags = fcntl(fd, F_GETFD); + if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + close(fd); + fd = -1; + } + unlink(name.constData()); + + if (fd < 0) + return -1; + + if (ftruncate(fd, size) < 0) { + close(fd); + return -1; + } + + return fd; +} + +void QWaylandKeyboardPrivate::initXKB() +{ + xkb_context = xkb_context_new(static_cast<xkb_context_flags>(0)); + if (!xkb_context) { + qWarning("Failed to create a XKB context: keymap will not be supported"); + return; + } + + createXKBKeymap(); +} + +void QWaylandKeyboardPrivate::createXKBKeymap() +{ + if (!xkb_context) + return; + + if (xkb_state) + xkb_state_unref(xkb_state); + + struct xkb_rule_names rule_names = { strdup(qPrintable(keymap.rules())), + strdup(qPrintable(keymap.model())), + strdup(qPrintable(keymap.layout())), + strdup(qPrintable(keymap.variant())), + strdup(qPrintable(keymap.options())) }; + struct xkb_keymap *keymap = xkb_keymap_new_from_names(xkb_context, &rule_names, static_cast<xkb_keymap_compile_flags>(0)); + + char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); + if (!keymap_str) + qFatal("Failed to compile global XKB keymap"); + + keymap_size = strlen(keymap_str) + 1; + keymap_fd = createAnonymousFile(keymap_size); + if (keymap_fd < 0) + qFatal("Failed to create anonymous file of size %lu", static_cast<unsigned long>(keymap_size)); + + keymap_area = static_cast<char *>(mmap(0, keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymap_fd, 0)); + if (keymap_area == MAP_FAILED) { + close(keymap_fd); + qFatal("Failed to map shared memory segment"); + } + + strcpy(keymap_area, keymap_str); + free(keymap_str); + + xkb_state = xkb_state_new(keymap); + + xkb_keymap_unref(keymap); + + free((char *)rule_names.rules); + free((char *)rule_names.model); + free((char *)rule_names.layout); + free((char *)rule_names.variant); + free((char *)rule_names.options); +} +#endif + + QWaylandKeyboardGrabber::~QWaylandKeyboardGrabber() { } @@ -50,37 +338,37 @@ QWaylandKeyboard::QWaylandKeyboard(QWaylandInputDevice *seat, QObject *parent) : QObject(* new QWaylandKeyboardPrivate(seat), parent) { Q_D(QWaylandKeyboard); - connect(&d->m_focusDestroyListener, &QWaylandDestroyListener::fired, this, &QWaylandKeyboard::focusDestroyed); + connect(&d->focusDestroyListener, &QWaylandDestroyListener::fired, this, &QWaylandKeyboard::focusDestroyed); } QWaylandInputDevice *QWaylandKeyboard::inputDevice() const { Q_D(const QWaylandKeyboard); - return d->m_seat; + return d->seat; } QWaylandCompositor *QWaylandKeyboard::compositor() const { Q_D(const QWaylandKeyboard); - return d->m_seat->compositor(); + return d->seat->compositor(); } void QWaylandKeyboard::focusDestroyed(void *data) { Q_UNUSED(data); Q_D(QWaylandKeyboard); - d->m_focusDestroyListener.reset(); + d->focusDestroyListener.reset(); - d->m_focus = 0; - d->m_focusResource = 0; + d->focus = 0; + d->focusResource = 0; } QWaylandClient *QWaylandKeyboard::focusClient() const { Q_D(const QWaylandKeyboard); - if (!d->focusResource()) + if (!d->focusResource) return Q_NULLPTR; - return QWaylandClient::fromWlClient(compositor(), d->focusResource()->client()); + return QWaylandClient::fromWlClient(compositor(), d->focusResource->client()); } void QWaylandKeyboard::sendKeyModifiers(QWaylandClient *client, uint serial) @@ -88,54 +376,70 @@ void QWaylandKeyboard::sendKeyModifiers(QWaylandClient *client, uint serial) Q_D(QWaylandKeyboard); QtWaylandServer::wl_keyboard::Resource *resource = d->resourceMap().value(client->client()); if (resource) - d->sendKeyModifiers(resource, serial); + d->send_modifiers(resource->handle, serial, d->modsDepressed, d->modsLatched, d->modsLocked, d->group); } + void QWaylandKeyboard::sendKeyPressEvent(uint code) { Q_D(QWaylandKeyboard); - d->sendKeyPressEvent(code); + d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED); } void QWaylandKeyboard::sendKeyReleaseEvent(uint code) { Q_D(QWaylandKeyboard); - d->sendKeyReleaseEvent(code); + d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED); } QWaylandSurface *QWaylandKeyboard::focus() const { Q_D(const QWaylandKeyboard); - return d->focus(); + return d->focus; } bool QWaylandKeyboard::setFocus(QWaylandSurface *surface) { Q_D(QWaylandKeyboard); - return d->setFocus(surface); + QtWayland::ShellSurface *shellsurface = QtWayland::ShellSurface::findIn(surface); + if (shellsurface && shellsurface->isTransientInactive()) + return false; + d->grab->focused(surface); + return true; } void QWaylandKeyboard::setKeymap(const QWaylandKeymap &keymap) { Q_D(QWaylandKeyboard); - d->setKeymap(keymap); + d->keymap = keymap; + + // If there is no key currently pressed, update right away the keymap + // Otherwise, delay the update when keys are released + // see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html + if (d->keys.isEmpty()) { + d->updateKeymap(); + } else { + d->pendingKeymap = true; + } } void QWaylandKeyboard::startGrab(QWaylandKeyboardGrabber *grab) { Q_D(QWaylandKeyboard); - d->startGrab(grab); + d->grab = grab; + d->grab->keyboard = this; + d->grab->focused(d->focus); } void QWaylandKeyboard::endGrab() { Q_D(QWaylandKeyboard); - d->endGrab(); + d->grab = d; } QWaylandKeyboardGrabber *QWaylandKeyboard::currentGrab() const { Q_D(const QWaylandKeyboard); - return d->currentGrab(); + return d->grab; } void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id) diff --git a/src/compositor/compositor_api/qwaylandkeyboard.h b/src/compositor/compositor_api/qwaylandkeyboard.h index c43c1851c..c95634ed9 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.h +++ b/src/compositor/compositor_api/qwaylandkeyboard.h @@ -57,7 +57,7 @@ public: virtual void modifiers(uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) = 0; - QWaylandKeyboard *m_keyboard; + QWaylandKeyboard *keyboard; }; class Q_COMPOSITOR_EXPORT QWaylandKeymap diff --git a/src/compositor/wayland_wrapper/qwlkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h index bcd0bab69..498a967b0 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard_p.h +++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h @@ -55,15 +55,6 @@ QT_BEGIN_NAMESPACE -namespace QtWayland { - -class Compositor; -class InputDevice; -class Surface; -class Keyboard; - -} - class Q_COMPOSITOR_EXPORT QWaylandKeyboardPrivate : public QObjectPrivate , public QtWaylandServer::wl_keyboard , public QWaylandKeyboardGrabber @@ -71,35 +62,23 @@ class Q_COMPOSITOR_EXPORT QWaylandKeyboardPrivate : public QObjectPrivate public: Q_DECLARE_PUBLIC(QWaylandKeyboard) + static QWaylandKeyboardPrivate *get(QWaylandKeyboard *keyboard); + QWaylandKeyboardPrivate(QWaylandInputDevice *seat); ~QWaylandKeyboardPrivate(); - QWaylandCompositor *compositor() const { return m_seat->compositor(); } - bool setFocus(QWaylandSurface *surface); - void setKeymap(const QWaylandKeymap &keymap); - - void sendKeyModifiers(Resource *resource, uint32_t serial); - void sendKeyPressEvent(uint code); - void sendKeyReleaseEvent(uint code); - - QWaylandSurface *focus() const; - Resource *focusResource() const { return m_focusResource; } + QWaylandCompositor *compositor() const { return seat->compositor(); } void focused(QWaylandSurface* surface); void key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state); void modifiers(uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); - void startGrab(QWaylandKeyboardGrabber *grab); - void endGrab(); - QWaylandKeyboardGrabber *currentGrab() const; - - static QWaylandKeyboardPrivate *get(QWaylandKeyboard *keyboard); - #ifndef QT_NO_WAYLAND_XKB - struct xkb_state *xkbState() const { return m_state; } - uint32_t xkbModsMask() const { return m_modsDepressed | m_modsLatched | m_modsLocked; } + struct xkb_state *xkbState() const { return xkb_state; } + uint32_t xkbModsMask() const { return modsDepressed | modsLatched | modsLocked; } #endif + void keyEvent(uint code, uint32_t state); void sendKeyEvent(uint code, uint32_t state); void updateModifierState(uint code, uint32_t state); @@ -111,33 +90,32 @@ protected: void keyboard_release(Resource *resource) Q_DECL_OVERRIDE; private: - #ifndef QT_NO_WAYLAND_XKB void initXKB(); void createXKBKeymap(); #endif - QWaylandInputDevice *m_seat; + QWaylandInputDevice *seat; - QWaylandKeyboardGrabber* m_grab; - QWaylandSurface *m_focus; - Resource *m_focusResource; - QWaylandDestroyListener m_focusDestroyListener; + QWaylandKeyboardGrabber* grab; + QWaylandSurface *focus; + Resource *focusResource; + QWaylandDestroyListener focusDestroyListener; - QVector<uint32_t> m_keys; - uint32_t m_modsDepressed; - uint32_t m_modsLatched; - uint32_t m_modsLocked; - uint32_t m_group; + QVector<uint32_t> keys; + uint32_t modsDepressed; + uint32_t modsLatched; + uint32_t modsLocked; + uint32_t group; - QWaylandKeymap m_keymap; - bool m_pendingKeymap; + QWaylandKeymap keymap; + bool pendingKeymap; #ifndef QT_NO_WAYLAND_XKB - size_t m_keymap_size; - int m_keymap_fd; - char *m_keymap_area; - struct xkb_context *m_context; - struct xkb_state *m_state; + size_t keymap_size; + int keymap_fd; + char *keymap_area; + struct xkb_context *xkb_context; + struct xkb_state *xkb_state; #endif }; diff --git a/src/compositor/wayland_wrapper/qwldatadevice.cpp b/src/compositor/wayland_wrapper/qwldatadevice.cpp index 7a375b628..b2eb25684 100644 --- a/src/compositor/wayland_wrapper/qwldatadevice.cpp +++ b/src/compositor/wayland_wrapper/qwldatadevice.cpp @@ -38,7 +38,6 @@ #include "qwldatasource_p.h" #include "qwldataoffer_p.h" -#include "qwlkeyboard_p.h" #include "qwaylandsurface_p.h" #include "qwltouch_p.h" #include "qwldatadevicemanager_p.h" diff --git a/src/compositor/wayland_wrapper/qwlinputmethod.cpp b/src/compositor/wayland_wrapper/qwlinputmethod.cpp index 106cb40a7..febb47a1e 100644 --- a/src/compositor/wayland_wrapper/qwlinputmethod.cpp +++ b/src/compositor/wayland_wrapper/qwlinputmethod.cpp @@ -37,9 +37,10 @@ #include "qwlinputmethod_p.h" #include <QtCompositor/QWaylandCompositor> +#include <QtCompositor/QWaylandKeyboard> +#include <QtCompositor/QWaylandInputDevice> #include "qwlinputmethodcontext_p.h" #include "qwlinputpanel_p.h" -#include "qwlkeyboard_p.h" #include "qwltextinput_p.h" QT_BEGIN_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlkeyboard.cpp b/src/compositor/wayland_wrapper/qwlkeyboard.cpp deleted file mode 100644 index 4977ce014..000000000 --- a/src/compositor/wayland_wrapper/qwlkeyboard.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2013 Klarälvdalens Datakonsult AB (KDAB). -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later 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 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwlkeyboard_p.h" -#include "qwlshellsurface_p.h" - -#include <QFile> -#include <QStandardPaths> - -#include <QtCompositor/QWaylandClient> -#include <QtCompositor/QWaylandCompositor> - -#include <fcntl.h> -#include <unistd.h> -#ifndef QT_NO_WAYLAND_XKB -#include <sys/mman.h> -#include <sys/types.h> -#endif - -QT_BEGIN_NAMESPACE - -QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandInputDevice *seat) - : QtWaylandServer::wl_keyboard() - , m_seat(seat) - , m_grab(this) - , m_focus() - , m_focusResource() - , m_keys() - , m_modsDepressed() - , m_modsLatched() - , m_modsLocked() - , m_group() - , m_pendingKeymap(false) -#ifndef QT_NO_WAYLAND_XKB - , m_state(0) -#endif -{ -#ifndef QT_NO_WAYLAND_XKB - initXKB(); -#endif -} - -QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate() -{ -#ifndef QT_NO_WAYLAND_XKB - if (m_context) { - if (m_keymap_area) - munmap(m_keymap_area, m_keymap_size); - close(m_keymap_fd); - xkb_context_unref(m_context); - xkb_state_unref(m_state); - } -#endif -} - -void QWaylandKeyboardPrivate::startGrab(QWaylandKeyboardGrabber *grab) -{ - Q_Q(QWaylandKeyboard); - m_grab = grab; - m_grab->m_keyboard = q; - m_grab->focused(m_focus); -} - -void QWaylandKeyboardPrivate::endGrab() -{ - m_grab = this; -} - -QWaylandKeyboardGrabber *QWaylandKeyboardPrivate::currentGrab() const -{ - return m_grab; -} - -QWaylandKeyboardPrivate *QWaylandKeyboardPrivate::get(QWaylandKeyboard *keyboard) -{ - return keyboard->d_func(); -} - -void QWaylandKeyboardPrivate::focused(QWaylandSurface *surface) -{ - if (surface && surface->isCursorSurface()) - surface = Q_NULLPTR; - if (m_focusResource && m_focus != surface) { - uint32_t serial = compositor()->nextSerial(); - send_leave(m_focusResource->handle, serial, m_focus->resource()); - m_focusDestroyListener.reset(); - } - - Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0; - - if (resource && (m_focus != surface || m_focusResource != resource)) { - uint32_t serial = compositor()->nextSerial(); - send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); - send_enter(resource->handle, serial, surface->resource(), QByteArray::fromRawData((char *)m_keys.data(), m_keys.size() * sizeof(uint32_t))); - m_focusDestroyListener.listenForDestruction(surface->resource()); - } - - m_focusResource = resource; - m_focus = surface; - Q_EMIT q_func()->focusChanged(m_focus); -} - -bool QWaylandKeyboardPrivate::setFocus(QWaylandSurface* surface) -{ - QtWayland::ShellSurface *shellsurface = QtWayland::ShellSurface::findIn(surface); - if (shellsurface && shellsurface->isTransientInactive()) - return false; - m_grab->focused(surface); - return true; -} - -void QWaylandKeyboardPrivate::setKeymap(const QWaylandKeymap &keymap) -{ - m_keymap = keymap; - - // If there is no key currently pressed, update right away the keymap - // Otherwise, delay the update when keys are released - // see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html - if (m_keys.isEmpty()) { - updateKeymap(); - } else { - m_pendingKeymap = true; - } -} - -void QWaylandKeyboardPrivate::sendKeyModifiers(wl_keyboard::Resource *resource, uint32_t serial) -{ - send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); -} - -void QWaylandKeyboardPrivate::sendKeyPressEvent(uint code) -{ - sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED); -} - -void QWaylandKeyboardPrivate::sendKeyReleaseEvent(uint code) -{ - sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED); -} - -QWaylandSurface *QWaylandKeyboardPrivate::focus() const -{ - return m_focus; -} - -void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource) -{ -#ifndef QT_NO_WAYLAND_XKB - if (m_context) { - send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, - m_keymap_fd, m_keymap_size); - return; - } -#endif - int null_fd = open("/dev/null", O_RDONLY); - send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, - null_fd, 0); - close(null_fd); -} - -void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource) -{ - if (m_focusResource == resource) - m_focusResource = 0; -} - -void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource) -{ - wl_resource_destroy(resource->handle); -} - -void QWaylandKeyboardPrivate::key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) -{ - if (m_focusResource) { - send_key(m_focusResource->handle, serial, time, key, state); - } -} - -void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state) -{ - uint key = code - 8; - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - m_keys << key; - } else { - for (int i = 0; i < m_keys.size(); ++i) { - if (m_keys.at(i) == key) { - m_keys.remove(i); - } - } - } -} - -void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state) -{ - uint32_t time = compositor()->currentTimeMsecs(); - uint32_t serial = compositor()->nextSerial(); - uint key = code - 8; - m_grab->key(serial, time, key, state); -} - -void QWaylandKeyboardPrivate::modifiers(uint32_t serial, uint32_t mods_depressed, - uint32_t mods_latched, uint32_t mods_locked, uint32_t group) -{ - if (m_focusResource) { - send_modifiers(m_focusResource->handle, serial, mods_depressed, mods_latched, mods_locked, group); - } -} - -void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) -{ -#ifndef QT_NO_WAYLAND_XKB - if (!m_context) - return; - - xkb_state_update_key(m_state, code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); - - uint32_t modsDepressed = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_DEPRESSED); - uint32_t modsLatched = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LATCHED); - uint32_t modsLocked = xkb_state_serialize_mods(m_state, (xkb_state_component)XKB_STATE_LOCKED); - uint32_t group = xkb_state_serialize_group(m_state, (xkb_state_component)XKB_STATE_EFFECTIVE); - - if (modsDepressed == m_modsDepressed - && modsLatched == m_modsLatched - && modsLocked == m_modsLocked - && group == m_group) - return; - - m_modsDepressed = modsDepressed; - m_modsLatched = modsLatched; - m_modsLocked = modsLocked; - m_group = group; - - m_grab->modifiers(compositor()->nextSerial(), m_modsDepressed, m_modsLatched, m_modsLocked, m_group); -#else - Q_UNUSED(code); - Q_UNUSED(state); -#endif -} - -void QWaylandKeyboardPrivate::updateKeymap() -{ - // There must be no keys pressed when changing the keymap, - // see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html - if (!m_pendingKeymap || !m_keys.isEmpty()) - return; - - m_pendingKeymap = false; -#ifndef QT_NO_WAYLAND_XKB - if (!m_context) - return; - - createXKBKeymap(); - foreach (Resource *res, resourceMap()) { - send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, m_keymap_fd, m_keymap_size); - } - - xkb_state_update_mask(m_state, 0, m_modsLatched, m_modsLocked, 0, 0, 0); - if (m_focusResource) - sendKeyModifiers(m_focusResource, compositor()->nextSerial()); -#endif -} - -#ifndef QT_NO_WAYLAND_XKB -static int createAnonymousFile(size_t size) -{ - QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - if (path.isEmpty()) - return -1; - - QByteArray name = QFile::encodeName(path + QStringLiteral("/qtwayland-XXXXXX")); - - int fd = mkstemp(name.data()); - if (fd < 0) - return -1; - - long flags = fcntl(fd, F_GETFD); - if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - close(fd); - fd = -1; - } - unlink(name.constData()); - - if (fd < 0) - return -1; - - if (ftruncate(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} - -void QWaylandKeyboardPrivate::initXKB() -{ - m_context = xkb_context_new(static_cast<xkb_context_flags>(0)); - if (!m_context) { - qWarning("Failed to create a XKB context: keymap will not be supported"); - return; - } - - createXKBKeymap(); -} - -void QWaylandKeyboardPrivate::createXKBKeymap() -{ - if (!m_context) - return; - - if (m_state) - xkb_state_unref(m_state); - - struct xkb_rule_names rule_names = { strdup(qPrintable(m_keymap.rules())), - strdup(qPrintable(m_keymap.model())), - strdup(qPrintable(m_keymap.layout())), - strdup(qPrintable(m_keymap.variant())), - strdup(qPrintable(m_keymap.options())) }; - struct xkb_keymap *keymap = xkb_keymap_new_from_names(m_context, &rule_names, static_cast<xkb_keymap_compile_flags>(0)); - - char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); - if (!keymap_str) - qFatal("Failed to compile global XKB keymap"); - - m_keymap_size = strlen(keymap_str) + 1; - m_keymap_fd = createAnonymousFile(m_keymap_size); - if (m_keymap_fd < 0) - qFatal("Failed to create anonymous file of size %lu", static_cast<unsigned long>(m_keymap_size)); - - m_keymap_area = static_cast<char *>(mmap(0, m_keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_keymap_fd, 0)); - if (m_keymap_area == MAP_FAILED) { - close(m_keymap_fd); - qFatal("Failed to map shared memory segment"); - } - - strcpy(m_keymap_area, keymap_str); - free(keymap_str); - - m_state = xkb_state_new(keymap); - - xkb_keymap_unref(keymap); - - free((char *)rule_names.rules); - free((char *)rule_names.model); - free((char *)rule_names.layout); - free((char *)rule_names.variant); - free((char *)rule_names.options); -} -#endif - -QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index 3ffc7148e..6355bbb2c 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -11,7 +11,6 @@ HEADERS += \ wayland_wrapper/qwldatasource_p.h \ wayland_wrapper/qwlinputmethod_p.h \ wayland_wrapper/qwlinputmethodcontext_p.h \ - wayland_wrapper/qwlkeyboard_p.h \ wayland_wrapper/qwlregion_p.h \ wayland_wrapper/qwlsurfacebuffer_p.h \ wayland_wrapper/qwltouch_p.h \ @@ -24,7 +23,6 @@ SOURCES += \ wayland_wrapper/qwldatasource.cpp \ wayland_wrapper/qwlinputmethod.cpp \ wayland_wrapper/qwlinputmethodcontext.cpp \ - wayland_wrapper/qwlkeyboard.cpp \ wayland_wrapper/qwlregion.cpp \ wayland_wrapper/qwlsurfacebuffer.cpp \ wayland_wrapper/qwltouch.cpp \ |