From 5405de120bba480f780e37e90fbd7c2ff1308b01 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 1 Nov 2018 13:48:52 +0100 Subject: Client: Don't be exposed if we want to create a sub or shell surface Because some shells don't allow attaching buffers before configure, we need to not be exposed until we know that we don't want a shell surface. Change-Id: Ida7101a99f953d02cf6401e4ea8d28cfabd6e102 Reviewed-by: Giulio Camuffo Reviewed-by: David Edmundson --- src/client/qwaylanddisplay.cpp | 13 ++++++------- src/client/qwaylanddisplay_p.h | 6 +++--- src/client/qwaylandwindow.cpp | 18 +++++++++++++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index a2957e0dd..f2bd3160a 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -88,13 +88,6 @@ struct wl_surface *QWaylandDisplay::createSurface(void *handle) return surface; } -QWaylandShellSurface *QWaylandDisplay::createShellSurface(QWaylandWindow *window) -{ - if (!mWaylandIntegration->shellIntegration()) - return nullptr; - return mWaylandIntegration->shellIntegration()->createShellSurface(window); -} - struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) { struct ::wl_region *region = mCompositor.create_region(); @@ -108,12 +101,18 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) ::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent) { if (!mSubCompositor) { + qCWarning(lcQpaWayland) << "Can't create subsurface, not supported by the compositor."; return nullptr; } return mSubCompositor->get_subsurface(window->object(), parent->object()); } +QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const +{ + return mWaylandIntegration->shellIntegration(); +} + QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const { return mWaylandIntegration->clientBufferIntegration(); diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 43ccc0a96..fe1d7874e 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -94,7 +94,7 @@ class QWaylandQtKeyExtension; class QWaylandWindow; class QWaylandIntegration; class QWaylandHardwareIntegration; -class QWaylandShellSurface; +class QWaylandShellIntegration; class QWaylandCursorTheme; typedef void (*RegistryListener)(void *data, @@ -115,13 +115,13 @@ public: QWaylandScreen *screenForOutput(struct wl_output *output) const; struct wl_surface *createSurface(void *handle); - QWaylandShellSurface *createShellSurface(QWaylandWindow *window); struct ::wl_region *createRegion(const QRegion &qregion); struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent); + QWaylandShellIntegration *shellIntegration() const; QWaylandClientBufferIntegration *clientBufferIntegration() const; - QWaylandWindowManagerIntegration *windowManagerIntegration() const; + #if QT_CONFIG(cursor) void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image, qreal dpr); void setCursor(const QSharedPointer &buffer, const QPoint &hotSpot, qreal dpr); diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index c46c49813..79639cba0 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -50,6 +50,7 @@ #include "qwaylandnativeinterface_p.h" #include "qwaylanddecorationfactory_p.h" #include "qwaylandshmbackingstore_p.h" +#include "qwaylandshellintegration_p.h" #if QT_CONFIG(wayland_datadevice) #include "qwaylanddatadevice_p.h" @@ -138,8 +139,9 @@ void QWaylandWindow::initWindow() } } else if (shouldCreateShellSurface()) { Q_ASSERT(!mShellSurface); + Q_ASSERT(mDisplay->shellIntegration()); - mShellSurface = mDisplay->createShellSurface(this); + mShellSurface = mDisplay->shellIntegration()->createShellSurface(this); if (mShellSurface) { // Set initial surface title setWindowTitle(window()->title()); @@ -211,6 +213,9 @@ void QWaylandWindow::initializeWlSurface() bool QWaylandWindow::shouldCreateShellSurface() const { + if (!mDisplay->shellIntegration()) + return false; + if (shouldCreateSubSurface()) return false; @@ -958,9 +963,16 @@ void QWaylandWindow::unfocus() bool QWaylandWindow::isExposed() const { + if (!window()->isVisible()) + return false; + if (mShellSurface) - return window()->isVisible() && mShellSurface->isExposed(); - return QPlatformWindow::isExposed(); + return mShellSurface->isExposed(); + + if (mSubSurfaceWindow) + return mSubSurfaceWindow->parent()->isExposed(); + + return !(shouldCreateShellSurface() || shouldCreateSubSurface()); } bool QWaylandWindow::isActive() const -- cgit v1.2.3 From e70a8070ea1e7903221fb980ddf3c23f3e9b0836 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Mon, 1 Apr 2019 13:35:30 +0300 Subject: Add changes file for Qt 5.12.3 + 7206b4e8b6e10f5623b19ca132f538066c96aab5 Fix the build with -no-gui + 489fedaa320a4941a9fc6a17df1a791c93270bb8 Compositor: Call eglUnbindWaylandDisplayWL when destroying the compositor + 3200e86cefd9a83cea45c7cab589bfbf1ff63f4f Client: Fix incorrect damage region for window decorations + 7a0956a89a559e5a73a659fcc08001cefa01d9bd Bump version Change-Id: I770edad3ca0728ce18a14a02284231fe14c8e68c Reviewed-by: Johan Helsing Reviewed-by: Jani Heikkinen --- dist/changes-5.12.3 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 dist/changes-5.12.3 diff --git a/dist/changes-5.12.3 b/dist/changes-5.12.3 new file mode 100644 index 000000000..da95edbb1 --- /dev/null +++ b/dist/changes-5.12.3 @@ -0,0 +1,33 @@ +Qt 5.12.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Compositor * +**************************************************************************** + + - Fixed a slightly unusual cleanup order that would lead to crashes in some + graphics drivers. + +**************************************************************************** +* QPA plugin * +**************************************************************************** + + - Fixed a bug where the window decoration's damaged area didn't cover the + entire decoration. This meant some compositors would not redraw those + areas. -- cgit v1.2.3 From 5ef85a13da557e81a598f9a867817dfcba25ef98 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 11 Apr 2019 03:58:06 +0100 Subject: Client: Avoid shadowing QPlatformWindow::windowGeometry windowGeometry is an existing method in QPlatformWindow with an entirely different meaning to the newly added QWaylandWindow::windowGeometry. This led to the existing call in resizeFromApplyConfigure calling the wrong method. Change-Id: Ib344cf09178e77e5b4d5427325d840346663ec9d Reviewed-by: Johan Helsing --- src/client/qwaylandwindow.cpp | 6 +++--- src/client/qwaylandwindow_p.h | 2 +- src/plugins/decorations/bradient/main.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 20a671c6c..2a0867765 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -334,7 +334,7 @@ void QWaylandWindow::setGeometry(const QRect &rect) sendExposeEvent(exposeGeometry); if (mShellSurface) - mShellSurface->setWindowGeometry(windowGeometry()); + mShellSurface->setWindowGeometry(windowContentGeometry()); } void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset) @@ -655,7 +655,7 @@ QSize QWaylandWindow::surfaceSize() const * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates) * topLeft is where the shadow stops and the decorations border start. */ -QRect QWaylandWindow::windowGeometry() const +QRect QWaylandWindow::windowContentGeometry() const { return QRect(QPoint(), surfaceSize()); } @@ -854,7 +854,7 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan #if QT_CONFIG(cursor) if (e.type == QWaylandPointerEvent::Enter) { - QRect contentGeometry = windowGeometry().marginsRemoved(frameMargins()); + QRect contentGeometry = windowContentGeometry().marginsRemoved(frameMargins()); if (contentGeometry.contains(e.local.toPoint())) restoreMouseCursor(inputDevice); } diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 8999682d9..7ab0ca74e 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -126,7 +126,7 @@ public: QMargins frameMargins() const override; QSize surfaceSize() const; - QRect windowGeometry() const; + QRect windowContentGeometry() const; static QWaylandWindow *fromWlSurface(::wl_surface *surface); diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp index 96ad261b2..e8e35775e 100644 --- a/src/plugins/decorations/bradient/main.cpp +++ b/src/plugins/decorations/bradient/main.cpp @@ -109,21 +109,21 @@ QWaylandBradientDecoration::QWaylandBradientDecoration() QRectF QWaylandBradientDecoration::closeButtonRect() const { - const int windowRight = waylandWindow()->windowGeometry().right() + 1; + const int windowRight = waylandWindow()->windowContentGeometry().right() + 1; return QRectF(windowRight - BUTTON_WIDTH - BUTTON_SPACING * 0 - BUTTONS_RIGHT_MARGIN, (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); } QRectF QWaylandBradientDecoration::maximizeButtonRect() const { - const int windowRight = waylandWindow()->windowGeometry().right() + 1; + const int windowRight = waylandWindow()->windowContentGeometry().right() + 1; return QRectF(windowRight - BUTTON_WIDTH * 2 - BUTTON_SPACING * 1 - BUTTONS_RIGHT_MARGIN, (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); } QRectF QWaylandBradientDecoration::minimizeButtonRect() const { - const int windowRight = waylandWindow()->windowGeometry().right() + 1; + const int windowRight = waylandWindow()->windowContentGeometry().right() + 1; return QRectF(windowRight - BUTTON_WIDTH * 3 - BUTTON_SPACING * 2 - BUTTONS_RIGHT_MARGIN, (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); } @@ -136,7 +136,7 @@ QMargins QWaylandBradientDecoration::margins() const void QWaylandBradientDecoration::paint(QPaintDevice *device) { bool active = window()->handle()->isActive(); - QRect wg = waylandWindow()->windowGeometry(); + QRect wg = waylandWindow()->windowContentGeometry(); QRect clips[] = { QRect(wg.left(), wg.top(), wg.width(), margins().top()), @@ -267,7 +267,7 @@ bool QWaylandBradientDecoration::handleMouse(QWaylandInputDevice *inputDevice, c Q_UNUSED(global); // Figure out what area mouse is in - QRect wg = waylandWindow()->windowGeometry(); + QRect wg = waylandWindow()->windowContentGeometry(); if (local.y() <= wg.top() + margins().top()) { processMouseTop(inputDevice,local,b,mods); } else if (local.y() > wg.bottom() - margins().bottom()) { @@ -312,7 +312,7 @@ bool QWaylandBradientDecoration::handleTouch(QWaylandInputDevice *inputDevice, c void QWaylandBradientDecoration::processMouseTop(QWaylandInputDevice *inputDevice, const QPointF &local, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { - QRect wg = waylandWindow()->windowGeometry(); + QRect wg = waylandWindow()->windowContentGeometry(); Q_UNUSED(mods); if (local.y() <= wg.top() + margins().bottom()) { if (local.x() <= margins().left()) { -- cgit v1.2.3 From 0b51286635ca3f724df94dd4d5268c950505f6ec Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 11 Apr 2019 13:43:07 +0200 Subject: Fix incorrect path to wl-eglstream-controller.xml Change-Id: I1d4bceeb87b7e95b7b4b9c9885e06052bd7536e9 Reviewed-by: Paul Olav Tvete --- src/3rdparty/protocol/qt_attribution.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json index 7881e6b0d..051bd3f95 100644 --- a/src/3rdparty/protocol/qt_attribution.json +++ b/src/3rdparty/protocol/qt_attribution.json @@ -110,7 +110,7 @@ Copyright © 2015, 2016 Jan Arne Petersen" "Name": "Wayland EGLStream Controller Protocol", "QDocModule": "qtwaylandcompositor", "QtUsage": "Used in the Qt Wayland Compositor", - "Files": "wayland-eglstream-controller.xml", + "Files": "wl-eglstream-controller.xml", "Description": "Allows clients to request that the compositor creates its EGLStream.", "Homepage": "https://github.com/NVIDIA/egl-wayland", -- cgit v1.2.3 From 3f40adc92f5eefed7860a09ddbbc1eae07ba1de6 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 10 Apr 2019 12:47:40 +0200 Subject: tst_xdgshell::showMinimized: Really make sure the window was created The surface(), may be a leftover cursor surface from earlier tests. Check for an xdgSurface instead, as those are verified to be cleaned up between tests. Change-Id: I6a2b402130814e896d335787fcb90fd8d57cafb7 Reviewed-by: Paul Olav Tvete --- tests/auto/client/xdgshell/tst_xdgshell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp index 6efffc8a4..dc463e38f 100644 --- a/tests/auto/client/xdgshell/tst_xdgshell.cpp +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp @@ -62,7 +62,7 @@ void tst_xdgshell::showMinimized() // Make sure the window on the compositor side is/was created here, and not after the test // finishes, as that may mess up for later tests. - QCOMPOSITOR_TRY_VERIFY(surface()); + QCOMPOSITOR_TRY_VERIFY(xdgSurface()); QVERIFY(!window.isExposed()); } -- cgit v1.2.3 From 1b773df93f5bccb6b616d2a228cb15cffe8e32d5 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 10 Apr 2019 12:44:06 +0200 Subject: Client tests: Fix tst_xdgShell::pongs when run as the only test The shell integration is initialized lazily, so it's not possible to send ping events to the client before the first window has been initialized. This adds a simple window to the pong test. Change-Id: I13b4a9cb802b7abe18bfc23cf8c75eb873ded3ca Reviewed-by: Paul Olav Tvete --- tests/auto/client/xdgshell/tst_xdgshell.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/auto/client/xdgshell/tst_xdgshell.cpp b/tests/auto/client/xdgshell/tst_xdgshell.cpp index dc463e38f..9b18abdc3 100644 --- a/tests/auto/client/xdgshell/tst_xdgshell.cpp +++ b/tests/auto/client/xdgshell/tst_xdgshell.cpp @@ -423,9 +423,16 @@ void tst_xdgshell::switchPopups() void tst_xdgshell::pongs() { - QSignalSpy pongSpy(exec([=] { return get(); }), &XdgWmBase::pong); + // Create and show a window to trigger shell integration initialzation, + // otherwise we don't have anything to send ping events to. + QRasterWindow window; + window.resize(200, 200); + window.show(); + // Verify that the client has bound to the global QCOMPOSITOR_TRY_COMPARE(get()->resourceMap().size(), 1); + + QSignalSpy pongSpy(exec([=] { return get(); }), &XdgWmBase::pong); const uint serial = exec([=] { return nextSerial(); }); exec([=] { auto *base = get(); -- cgit v1.2.3 From 3aedd01271dc4f4a13103d632df224971ab2b6df Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 13 Dec 2018 12:14:59 +0100 Subject: client: rework input method handling The existing solution was parsing compose tables on startup, it is better to lazy initialize the compose table/state on a first key press, instead of doing it on an application startup. This logic is inside of the compose input plugin. The existing code did not utilize correctly how Qt handles complex text input. It used libxkbcommon-compose APIs to compose user input and then passed the same input again to QPlatformInputContext (from QWaylandInputDevice::Keyboard::sendKey), which was erroneous. This also means that code was forcing "xkb compose", and did not respect QT_IM_MODULE at client-side. From commit that added compose key handling (57c4af2b18c0fb1d266b245a107fa6cb876b9d9e): "We should expand on it in the future to handle things like resetting the compose state on text field switching". This is now handled by properly utilizing Qt IM framework. Converted QWaylandInputDevice::Keyboard::sendKey into a class member function to avoid adding one more arg (mXkbContext) to the already long argument list. That whole function should be simplified, but that is out-of-scope for this patch. The reworked code uses qxkbcommon support library to reduce code duplication between platforms and to unify behavior. Some users might mistakenly think that this patch introduces a regression with Qt on KDE, but it is actually a KWin/Wayland compositor bug: https://bugs.kde.org/show_bug.cgi?id=405388 The work around on KDE is to use QT_IM_MODULE at client-side to select input method, as KWin compositor over the wire supports only the qtvirtualkeyboard module. Setting this envvar is not someting out of the ordinary for users on Linux. Input method handling at compositor-side is new feature and clearly not very well supported yet. Task-number: QTBUG-65503 Change-Id: Ie511d950396fa2fb6cbe6672996cee9791f3ab11 Reviewed-by: Johan Helsing --- examples/wayland/pure-qml/qml/main.qml | 2 +- src/client/client.pro | 5 +- src/client/qwaylanddisplay.cpp | 12 +- src/client/qwaylanddisplay_p.h | 8 + src/client/qwaylandinputdevice.cpp | 85 ++-------- src/client/qwaylandinputdevice_p.h | 16 +- src/client/qwaylandintegration.cpp | 56 +++++-- src/client/qwaylandintegration_p.h | 2 + tests/auto/client/client.pro | 2 + tests/auto/client/inputcontext/inputcontext.pro | 6 + .../auto/client/inputcontext/tst_inputcontext.cpp | 184 +++++++++++++++++++++ tests/auto/client/shared/shared.pri | 9 +- tests/auto/client/shared/textinput.cpp | 45 +++++ tests/auto/client/shared/textinput.h | 51 ++++++ 14 files changed, 378 insertions(+), 105 deletions(-) create mode 100644 tests/auto/client/inputcontext/inputcontext.pro create mode 100644 tests/auto/client/inputcontext/tst_inputcontext.cpp create mode 100644 tests/auto/client/shared/textinput.cpp create mode 100644 tests/auto/client/shared/textinput.h diff --git a/examples/wayland/pure-qml/qml/main.qml b/examples/wayland/pure-qml/qml/main.qml index 69be7cf10..483de7514 100644 --- a/examples/wayland/pure-qml/qml/main.qml +++ b/examples/wayland/pure-qml/qml/main.qml @@ -72,6 +72,6 @@ WaylandCompositor { onWlShellSurfaceCreated: screen.handleShellSurface(shellSurface) } - // Extension for Virtual keyboard support + // Extension for Input Method (QT_IM_MODULE) support at compositor-side TextInputManager {} } diff --git a/src/client/client.pro b/src/client/client.pro index 38d0ac3e1..9f7d979dc 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -15,8 +15,9 @@ use_gold_linker: CONFIG += no_linker_version_script CONFIG -= precompile_header CONFIG += link_pkgconfig wayland-scanner -qtConfig(xkbcommon): \ - QMAKE_USE_PRIVATE += xkbcommon +qtConfig(xkbcommon) { + QT_PRIVATE += xkbcommon_support-private +} qtHaveModule(linuxaccessibility_support_private): \ QT += linuxaccessibility_support_private diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 5b1b9bffb..22a79124d 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -266,11 +266,11 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("zqt_key_v1")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); - } else if (interface == QStringLiteral("zwp_text_input_manager_v2")) { + } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) { mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1)); - foreach (QWaylandInputDevice *inputDevice, mInputDevices) { + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat()))); - } + mWaylandIntegration->reconfigureInputContext(); } else if (interface == QStringLiteral("qt_hardware_integration")) { bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION"); if (!disableHardwareIntegration) { @@ -306,6 +306,12 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) } } } + if (global.interface == QStringLiteral("zwp_text_input_manager_v2")) { + mTextInputManager.reset(); + for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices)) + inputDevice->setTextInput(nullptr); + mWaylandIntegration->reconfigureInputContext(); + } mGlobals.removeAt(i); break; } diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 4a98b935b..836ee0f9a 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -63,6 +63,8 @@ #include #include +#include + struct wl_cursor_image; QT_BEGIN_NAMESPACE @@ -144,6 +146,7 @@ public: QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } QtWayland::zxdg_output_manager_v1 *xdgOutputManager() const { return mXdgOutputManager.data(); } + bool usingInputContextFromCompositor() const { return mUsingInputContextFromCompositor; } struct RegistryGlobal { uint32_t id; @@ -237,8 +240,13 @@ private: struct wl_callback *mSyncCallback = nullptr; static const wl_callback_listener syncCallbackListener; + bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); + bool mUsingInputContextFromCompositor = false; + void registry_global(uint32_t id, const QString &interface, uint32_t version) override; void registry_global_remove(uint32_t id) override; + + friend class QWaylandIntegration; }; } diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 2ae2caca2..f31ab2745 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -71,7 +71,7 @@ #include #if QT_CONFIG(xkbcommon) -#include +#include #endif QT_BEGIN_NAMESPACE @@ -110,7 +110,7 @@ bool QWaylandInputDevice::Keyboard::createDefaultKeyMap() qWarning() << "xkb_map_new_from_names failed, no key input"; return false; } - createComposeState(); + return true; } @@ -123,41 +123,11 @@ void QWaylandInputDevice::Keyboard::releaseKeyMap() if (mXkbContext) xkb_context_unref(mXkbContext); } - -void QWaylandInputDevice::Keyboard::createComposeState() -{ - static const char *locale = nullptr; - if (!locale) { - locale = getenv("LC_ALL"); - if (!locale) - locale = getenv("LC_CTYPE"); - if (!locale) - locale = getenv("LANG"); - if (!locale) - locale = "C"; - } - - mXkbComposeTable = xkb_compose_table_new_from_locale(mXkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); - if (mXkbComposeTable) - mXkbComposeState = xkb_compose_state_new(mXkbComposeTable, XKB_COMPOSE_STATE_NO_FLAGS); -} - -void QWaylandInputDevice::Keyboard::releaseComposeState() -{ - if (mXkbComposeState) - xkb_compose_state_unref(mXkbComposeState); - if (mXkbComposeTable) - xkb_compose_table_unref(mXkbComposeTable); - mXkbComposeState = nullptr; - mXkbComposeTable = nullptr; -} - #endif QWaylandInputDevice::Keyboard::~Keyboard() { #if QT_CONFIG(xkbcommon) - releaseComposeState(); releaseKeyMap(); #endif if (mFocus) @@ -396,9 +366,9 @@ QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, } #endif - if (mQDisplay->textInputManager()) { - mTextInput = new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat())); - } + if (mQDisplay->textInputManager()) + mTextInput.reset(new QWaylandTextInput(mQDisplay, mQDisplay->textInputManager()->get_text_input(wl_seat()))); + } QWaylandInputDevice::~QWaylandInputDevice() @@ -481,12 +451,12 @@ QWaylandDataDevice *QWaylandInputDevice::dataDevice() const void QWaylandInputDevice::setTextInput(QWaylandTextInput *textInput) { - mTextInput = textInput; + mTextInput.reset(textInput); } QWaylandTextInput *QWaylandInputDevice::textInput() const { - return mTextInput; + return mTextInput.data(); } void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) @@ -793,7 +763,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, // Release the old keymap resources in the case they were already created in // the key event or when the compositor issues a new map - releaseComposeState(); releaseKeyMap(); mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -802,8 +771,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, close(fd); mXkbState = xkb_state_new(mXkbMap); - createComposeState(); - #else Q_UNUSED(format); Q_UNUSED(fd); @@ -852,16 +819,17 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf handleFocusLost(); } -static void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text = QString(), bool autorep = false, ushort count = 1) +void QWaylandInputDevice::Keyboard::sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, + Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString& text, bool autorep, ushort count) { QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); bool filtered = false; - if (inputContext) { - QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, - text, autorep, count); + if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) { + QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, + nativeModifiers, text, autorep, count); event.setTimestamp(timestamp); filtered = inputContext->filterEvent(&event); } @@ -896,37 +864,12 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, return; } - QString composedText; xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code); - if (mXkbComposeState) { - if (isDown) - xkb_compose_state_feed(mXkbComposeState, sym); - xkb_compose_status status = xkb_compose_state_get_status(mXkbComposeState); - - switch (status) { - case XKB_COMPOSE_COMPOSED: { - int size = xkb_compose_state_get_utf8(mXkbComposeState, nullptr, 0); - QVarLengthArray buffer(size + 1); - xkb_compose_state_get_utf8(mXkbComposeState, buffer.data(), buffer.size()); - composedText = QString::fromUtf8(buffer.constData()); - sym = xkb_compose_state_get_one_sym(mXkbComposeState); - xkb_compose_state_reset(mXkbComposeState); - } break; - case XKB_COMPOSE_COMPOSING: - case XKB_COMPOSE_CANCELLED: - return; - case XKB_COMPOSE_NOTHING: - break; - } - } Qt::KeyboardModifiers modifiers = mParent->modifiers(); std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); - if (!composedText.isNull()) - text = composedText; - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); #else // Generic fallback for single hard keys: Assume 'key' is a Qt key code. diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 50b1af385..4149e5005 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -75,11 +76,6 @@ struct wl_cursor_image; #endif -#if QT_CONFIG(xkbcommon) -struct xkb_compose_state; -struct xkb_compose_table; -#endif - QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -164,7 +160,7 @@ private: Pointer *mPointer = nullptr; Touch *mTouch = nullptr; - QWaylandTextInput *mTextInput = nullptr; + QScopedPointer mTextInput; uint32_t mTime = 0; uint32_t mSerial = 0; @@ -217,8 +213,6 @@ public: xkb_context *mXkbContext = nullptr; xkb_keymap *mXkbMap = nullptr; xkb_state *mXkbState = nullptr; - xkb_compose_table *mXkbComposeTable = nullptr; - xkb_compose_state *mXkbComposeState = nullptr; #endif uint32_t mNativeModifiers = 0; @@ -244,10 +238,10 @@ private: #if QT_CONFIG(xkbcommon) bool createDefaultKeyMap(); void releaseKeyMap(); - void createComposeState(); - void releaseComposeState(); #endif - + void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString& text = QString(), bool autorep = false, ushort count = 1); }; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index 45957629f..8bfe3b6fc 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -90,6 +90,10 @@ #include #endif +#if QT_CONFIG(xkbcommon) +#include +#endif + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -146,20 +150,8 @@ QWaylandIntegration::QWaylandIntegration() #if QT_CONFIG(draganddrop) mDrag.reset(new QWaylandDrag(mDisplay.data())); #endif - QString icStr = QPlatformInputContextFactory::requested(); - if (!icStr.isNull()) { - mInputContext.reset(QPlatformInputContextFactory::create(icStr)); - } else { - //try to use the input context using the wl_text_input interface - QPlatformInputContext *ctx = new QWaylandInputContext(mDisplay.data()); - mInputContext.reset(ctx); - - //use the traditional way for on screen keyboards for now - if (!mInputContext.data()->isValid()) { - ctx = QPlatformInputContextFactory::create(); - mInputContext.reset(ctx); - } - } + + reconfigureInputContext(); } QWaylandIntegration::~QWaylandIntegration() @@ -462,6 +454,42 @@ void QWaylandIntegration::initializeInputDeviceIntegration() } } +void QWaylandIntegration::reconfigureInputContext() +{ + if (!mDisplay) { + // This function can be called from QWaylandDisplay::registry_global() when we + // are in process of constructing QWaylandDisplay. Configuring input context + // in that case is done by calling reconfigureInputContext() from QWaylandIntegration + // constructor, after QWaylandDisplay has been constructed. + return; + } + + const QString &requested = QPlatformInputContextFactory::requested(); + if (requested == QLatin1String("qtvirtualkeyboard")) + qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side," + " use QT_IM_MODULE=qtvirtualkeyboard at compositor-side."; + + if (requested.isNull()) + mInputContext.reset(new QWaylandInputContext(mDisplay.data())); + else + mInputContext.reset(QPlatformInputContextFactory::create(requested)); + + const QString defaultInputContext(QStringLiteral("compose")); + if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext) + mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); + +#if QT_CONFIG(xkbcommon) + QXkbCommon::setXkbContext(mInputContext.data(), xkb_context_new(XKB_CONTEXT_NO_FLAGS)); +#endif + + // Even if compositor-side input context handling has been requested, we fallback to + // client-side handling if compositor does not provide the text-input extension. This + // is why we need to check here which input context actually is being used. + mDisplay->mUsingInputContextFromCompositor = qobject_cast(mInputContext.data()); + + qCDebug(lcQpaWayland) << "using input method:" << inputContext()->metaObject()->className(); +} + QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName) { if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) { diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index 944f635bb..5e6f16d09 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -116,6 +116,8 @@ public: virtual QWaylandServerBufferIntegration *serverBufferIntegration() const; virtual QWaylandShellIntegration *shellIntegration() const; + void reconfigureInputContext(); + private: // NOTE: mDisplay *must* be destructed after mDrag and mClientBufferIntegration // and mShellIntegration. diff --git a/tests/auto/client/client.pro b/tests/auto/client/client.pro index e99db20ba..051cb4e3d 100644 --- a/tests/auto/client/client.pro +++ b/tests/auto/client/client.pro @@ -12,3 +12,5 @@ SUBDIRS += \ xdgoutput \ xdgshell \ xdgshellv6 + +qtConfig(im): SUBDIRS += inputcontext diff --git a/tests/auto/client/inputcontext/inputcontext.pro b/tests/auto/client/inputcontext/inputcontext.pro new file mode 100644 index 000000000..4419b3e77 --- /dev/null +++ b/tests/auto/client/inputcontext/inputcontext.pro @@ -0,0 +1,6 @@ +include (../shared/shared.pri) + +QT += waylandcompositor + +TARGET = tst_inputcontext +SOURCES += tst_inputcontext.cpp diff --git a/tests/auto/client/inputcontext/tst_inputcontext.cpp b/tests/auto/client/inputcontext/tst_inputcontext.cpp new file mode 100644 index 000000000..b1a5a7f17 --- /dev/null +++ b/tests/auto/client/inputcontext/tst_inputcontext.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mockcompositor.h" +#include "textinput.h" + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace MockCompositor; + +class tst_inputcontext : public QObject, private DefaultCompositor +{ + Q_OBJECT +private slots: + void initTestCase(); + void selectingInputContext_data(); + void selectingInputContext(); + void inputContextReconfigurationWhenTogglingTextInputExtension(); + +private: + QByteArray inputContextName() const; + void ensureTextInputPresentOnCompositor(); + void ensureTextInputNotPresentOnCompositor(); + + QByteArray mComposeModule = QByteArray("QComposeInputContext"); // default input context + QByteArray mIbusModule = QByteArray("QIBusPlatformInputContext"); + QByteArray mWaylandModule = QByteArray("QtWaylandClient::QWaylandInputContext"); + + TextInputManager *mTextInputManager = nullptr; +}; + +void tst_inputcontext::initTestCase() +{ + // Verify that plugins are present and valid + QPlatformInputContext *context = QPlatformInputContextFactory::create(QStringLiteral("compose")); + QVERIFY(context && context->isValid()); + + context = QPlatformInputContextFactory::create(QStringLiteral("ibus")); + // The ibus plugin depends on properly configured system services, if plugin is not valid + // verify that wayland qpa plugin properly fallbacks to default input context. + if (!context || !context->isValid()) + mIbusModule = mComposeModule; +} + +QByteArray tst_inputcontext::inputContextName() const +{ + QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); + if (platformIntegration->inputContext()) + return platformIntegration->inputContext()->metaObject()->className(); + + return QByteArray(""); +} + +void tst_inputcontext::ensureTextInputPresentOnCompositor() +{ + exec([&] { + QVector extensions = getAll(); + if (extensions.length() > 1) + QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned"); + if (extensions.length() == 0) + add(); + }); +} + +void tst_inputcontext::ensureTextInputNotPresentOnCompositor() +{ + exec([&] { + QVector extensions = getAll(); + if (extensions.length() > 1) + QFAIL("TextInputManager is a singleton, hence there should not be more then one object returned"); + if (extensions.length() == 1) + remove(extensions.first()); + }); +} + +void tst_inputcontext::selectingInputContext_data() +{ + QTest::addColumn("requestedModule"); + QTest::addColumn("expectedModule"); + + // Test compositor without Text Input extension + QTest::newRow("ibus") << QByteArray("ibus") << mIbusModule; + QTest::newRow("compose") << QByteArray("compose") << mComposeModule; + QTest::newRow("empty") << QByteArray("") << mComposeModule; + QTest::newRow("null") << QByteArray() << mComposeModule; + QTest::newRow("fake") << QByteArray("fake") << mComposeModule; + + // Test compositor with Text Input extension + QTest::newRow("ibus:text-input") << QByteArray("ibus") << mIbusModule; + QTest::newRow("compose:text-input") << QByteArray("compose") << mComposeModule; + QTest::newRow("empty:text-input") << QByteArray("") << mComposeModule; + QTest::newRow("null:text-input") << QByteArray() << mWaylandModule; + QTest::newRow("fake:text-input") << QByteArray("fake") << mComposeModule; +} + +void tst_inputcontext::selectingInputContext() +{ + QFETCH(QByteArray, requestedModule); + QFETCH(QByteArray, expectedModule); + + if (requestedModule.isNull()) + qunsetenv("QT_IM_MODULE"); + else + qputenv("QT_IM_MODULE", requestedModule); + + const bool withTextInputAtCompositorSide = QByteArray(QTest::currentDataTag()).endsWith(":text-input"); + + if (withTextInputAtCompositorSide) + ensureTextInputPresentOnCompositor(); + else + ensureTextInputNotPresentOnCompositor(); + + int argc = 0; + QGuiApplication app(argc, nullptr); // loads the platform plugin + + QCOMPARE(inputContextName(), expectedModule); +} + +void tst_inputcontext::inputContextReconfigurationWhenTogglingTextInputExtension() +{ + qunsetenv("QT_IM_MODULE"); + + ensureTextInputPresentOnCompositor(); + int argc = 0; + QGuiApplication app(argc, nullptr); // loads the platform plugin + QCOMPARE(inputContextName(), mWaylandModule); + + // remove text input extension after the platform plugin has been loaded + ensureTextInputNotPresentOnCompositor(); + // QTRY_* because we need to spin the event loop for wayland QPA plugin + // to handle registry_global_remove() + QTRY_COMPARE(inputContextName(), mComposeModule); + + // add text input extension after the platform plugin has been loaded + ensureTextInputPresentOnCompositor(); + // QTRY_* because we need to spin the event loop for wayland QPA plugin + // to handle registry_global() + QTRY_COMPARE(inputContextName(), mWaylandModule); +} + +int main(int argc, char *argv[]) +{ + qputenv("XDG_RUNTIME_DIR", "."); + qputenv("QT_QPA_PLATFORM", "wayland"); + + tst_inputcontext tc; + QTEST_SET_MAIN_SOURCE_PATH + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_inputcontext.moc" diff --git a/tests/auto/client/shared/shared.pri b/tests/auto/client/shared/shared.pri index 303e13046..c86183b3d 100644 --- a/tests/auto/client/shared/shared.pri +++ b/tests/auto/client/shared/shared.pri @@ -4,7 +4,8 @@ QMAKE_USE += wayland-server WAYLANDSERVERSOURCES += \ $$PWD/../../../../src/3rdparty/protocol/wayland.xml \ - $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml + $$PWD/../../../../src/3rdparty/protocol/xdg-shell.xml \ + $$PWD/../../../../src/3rdparty/protocol/text-input-unstable-v2.xml INCLUDEPATH += ../shared @@ -13,11 +14,13 @@ HEADERS += \ $$PWD/coreprotocol.h \ $$PWD/datadevice.h \ $$PWD/mockcompositor.h \ - $$PWD/xdgshell.h + $$PWD/xdgshell.h \ + $$PWD/textinput.h SOURCES += \ $$PWD/corecompositor.cpp \ $$PWD/coreprotocol.cpp \ $$PWD/datadevice.cpp \ $$PWD/mockcompositor.cpp \ - $$PWD/xdgshell.cpp + $$PWD/xdgshell.cpp \ + $$PWD/textinput.cpp diff --git a/tests/auto/client/shared/textinput.cpp b/tests/auto/client/shared/textinput.cpp new file mode 100644 index 000000000..f9fd287bb --- /dev/null +++ b/tests/auto/client/shared/textinput.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "textinput.h" + +namespace MockCompositor { + +TextInputManager::TextInputManager(CoreCompositor *compositor) +{ + init(compositor->m_display, 1); +} + +void TextInputManager::zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, wl_resource *seatResource) +{ + Q_UNUSED(resource); + Q_UNUSED(id); + Q_UNUSED(seatResource); +} + +} // namespace MockCompositor diff --git a/tests/auto/client/shared/textinput.h b/tests/auto/client/shared/textinput.h new file mode 100644 index 000000000..85072e74b --- /dev/null +++ b/tests/auto/client/shared/textinput.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOCKCOMPOSITOR_TEXTINPUT_H +#define MOCKCOMPOSITOR_TEXTINPUT_H + +#include "coreprotocol.h" +#include + +#include + +namespace MockCompositor { + +class TextInputManager : public Global, public QtWaylandServer::zwp_text_input_manager_v2 +{ + Q_OBJECT +public: + TextInputManager(CoreCompositor *compositor); + +protected: + void zwp_text_input_manager_v2_get_text_input(Resource *resource, uint32_t id, struct ::wl_resource *seatResource) override; +}; + +} // namespace MockCompositor + +#endif // MOCKCOMPOSITOR_TEXTINPUT_H -- cgit v1.2.3 From 4de344decf7db4d7703575a78d6013a5c776bf1e Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 13 Dec 2018 22:04:18 +0100 Subject: client: rework xkb context/keymap/state handling - Use smart pointers from xkbcommon_support-private. - Remove needless strdup() calls. - Don't recreate context. And move it into qwaylanddisplay so it can be shared in future between several keyboards. It contains things like a logging level and include paths. Change-Id: I5d1f667e710046e6b62aa2caf82fdb2decc24520 Reviewed-by: Johan Helsing --- src/client/client.pro | 2 +- src/client/qwaylanddisplay.cpp | 6 +++ src/client/qwaylanddisplay_p.h | 12 ++++++ src/client/qwaylandinputdevice.cpp | 78 ++++++++++++++------------------------ src/client/qwaylandinputdevice_p.h | 21 +++++----- src/client/qwaylandintegration.cpp | 2 +- 6 files changed, 57 insertions(+), 64 deletions(-) diff --git a/src/client/client.pro b/src/client/client.pro index 9f7d979dc..81152f756 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -16,7 +16,7 @@ CONFIG -= precompile_header CONFIG += link_pkgconfig wayland-scanner qtConfig(xkbcommon) { - QT_PRIVATE += xkbcommon_support-private + QT_FOR_PRIVATE += xkbcommon_support-private } qtHaveModule(linuxaccessibility_support_private): \ diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 22a79124d..e96e52fe4 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -142,6 +142,12 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) mWindowManagerIntegration.reset(new QWaylandWindowManagerIntegration(this)); +#if QT_CONFIG(xkbcommon) + mXkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS)); + if (!mXkbContext) + qCWarning(lcQpaWayland, "failed to create xkb context"); +#endif + forceRoundTrip(); } diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 836ee0f9a..3ced2d9e3 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -65,6 +65,10 @@ #include +#if QT_CONFIG(xkbcommon) +#include +#endif + struct wl_cursor_image; QT_BEGIN_NAMESPACE @@ -111,6 +115,10 @@ public: QWaylandDisplay(QWaylandIntegration *waylandIntegration); ~QWaylandDisplay(void) override; +#if QT_CONFIG(xkbcommon) + struct xkb_context *xkbContext() const { return mXkbContext.get(); } +#endif + QList screens() const { return mScreens; } QWaylandScreen *screenForOutput(struct wl_output *output) const; @@ -246,6 +254,10 @@ private: void registry_global(uint32_t id, const QString &interface, uint32_t version) override; void registry_global_remove(uint32_t id) override; +#if QT_CONFIG(xkbcommon) + QXkbCommon::ScopedXKBContext mXkbContext; +#endif + friend class QWaylandIntegration; }; diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index f31ab2745..572ce1e50 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -70,10 +70,6 @@ #include -#if QT_CONFIG(xkbcommon) -#include -#endif - QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -85,51 +81,34 @@ QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) } #if QT_CONFIG(xkbcommon) -bool QWaylandInputDevice::Keyboard::createDefaultKeyMap() +bool QWaylandInputDevice::Keyboard::createDefaultKeymap() { - if (mXkbContext && mXkbMap && mXkbState) { - return true; - } + struct xkb_context *ctx = mParent->mQDisplay->xkbContext(); + if (!ctx) + return false; - 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); - } - } + struct xkb_rule_names names; + names.rules = "evdev"; + names.model = "pc105"; + names.layout = "us"; + names.variant = ""; + names.options = ""; - if (!mXkbContext || !mXkbMap || !mXkbState) { - qWarning() << "xkb_map_new_from_names failed, no key input"; + mXkbKeymap.reset(xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS)); + if (mXkbKeymap) + mXkbState.reset(xkb_state_new(mXkbKeymap.get())); + + if (!mXkbKeymap || !mXkbState) { + qCWarning(lcQpaWayland, "failed to create default keymap"); return false; } return true; } - -void QWaylandInputDevice::Keyboard::releaseKeyMap() -{ - if (mXkbState) - xkb_state_unref(mXkbState); - if (mXkbMap) - xkb_map_unref(mXkbMap); - if (mXkbContext) - xkb_context_unref(mXkbContext); -} #endif QWaylandInputDevice::Keyboard::~Keyboard() { -#if QT_CONFIG(xkbcommon) - releaseKeyMap(); -#endif if (mFocus) QWindowSystemInterface::handleWindowActivated(nullptr); if (mParent->mVersion >= 3) @@ -501,7 +480,7 @@ Qt::KeyboardModifiers QWaylandInputDevice::Keyboard::modifiers() const if (!mXkbState) return ret; - ret = QWaylandXkb::modifiers(mXkbState); + ret = QWaylandXkb::modifiers(mXkbState.get()); #endif return ret; @@ -761,16 +740,16 @@ 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_NO_FLAGS); - mXkbMap = xkb_map_new_from_string(mXkbContext, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + mXkbKeymap.reset(xkb_keymap_new_from_string(mParent->mQDisplay->xkbContext(), map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS)); munmap(map_str, size); close(fd); - mXkbState = xkb_state_new(mXkbMap); + if (mXkbKeymap) + mXkbState.reset(xkb_state_new(mXkbKeymap.get())); + else + mXkbState.reset(nullptr); #else Q_UNUSED(format); Q_UNUSED(fd); @@ -860,11 +839,10 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, mParent->mQDisplay->setLastInputDevice(mParent, serial, window); #if QT_CONFIG(xkbcommon) - if (!createDefaultKeyMap()) { + if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap()) return; - } - xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, code); + xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code); Qt::KeyboardModifiers modifiers = mParent->modifiers(); @@ -878,7 +856,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, if (state == WL_KEYBOARD_KEY_STATE_PRESSED #if QT_CONFIG(xkbcommon) - && xkb_keymap_key_repeats(mXkbMap, code) + && xkb_keymap_key_repeats(mXkbKeymap.get(), code) #endif ) { mRepeatKey = qtkey; @@ -952,7 +930,7 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial, Q_UNUSED(serial); #if QT_CONFIG(xkbcommon) if (mXkbState) - xkb_state_update_mask(mXkbState, + xkb_state_update_mask(mXkbState.get(), mods_depressed, mods_latched, mods_locked, 0, 0, group); mNativeModifiers = mods_depressed | mods_latched | mods_locked; diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 4149e5005..98e60286e 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -65,8 +65,7 @@ #include #if QT_CONFIG(xkbcommon) -#include -#include +#include #endif #include @@ -209,11 +208,7 @@ public: QWaylandInputDevice *mParent = nullptr; ::wl_surface *mFocus = nullptr; -#if QT_CONFIG(xkbcommon) - xkb_context *mXkbContext = nullptr; - xkb_keymap *mXkbMap = nullptr; - xkb_state *mXkbState = nullptr; -#endif + uint32_t mNativeModifiers = 0; int mRepeatKey; @@ -222,9 +217,6 @@ public: int mRepeatRate = 25; int mRepeatDelay = 400; QString mRepeatText; -#if QT_CONFIG(xkbcommon) - xkb_keysym_t mRepeatSym; -#endif QTimer mRepeatTimer; Qt::KeyboardModifiers modifiers() const; @@ -236,12 +228,17 @@ private slots: private: #if QT_CONFIG(xkbcommon) - bool createDefaultKeyMap(); - void releaseKeyMap(); + bool createDefaultKeymap(); #endif void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text = QString(), bool autorep = false, ushort count = 1); + +#if QT_CONFIG(xkbcommon) + xkb_keysym_t mRepeatSym = XKB_KEY_NoSymbol; + QXkbCommon::ScopedXKBKeymap mXkbKeymap; + QXkbCommon::ScopedXKBState mXkbState; +#endif }; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index 8bfe3b6fc..3a389d9ec 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -479,7 +479,7 @@ void QWaylandIntegration::reconfigureInputContext() mInputContext.reset(QPlatformInputContextFactory::create(defaultInputContext)); #if QT_CONFIG(xkbcommon) - QXkbCommon::setXkbContext(mInputContext.data(), xkb_context_new(XKB_CONTEXT_NO_FLAGS)); + QXkbCommon::setXkbContext(mInputContext.data(), mDisplay->xkbContext()); #endif // Even if compositor-side input context handling has been requested, we fallback to -- cgit v1.2.3 From 60dc973ab2c9227e2b6161a8b61a8c129e8b8cbc Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 14 Dec 2018 12:14:42 +0100 Subject: compositor: rework xkb context/keymap/state handling - Use smart pointers from xkbcommon_support-private. - Avoid unnecessary strdup()/free() calls. - Don't recreate context. And move it into qwaylandcompositor so it can be shared between seats. It contains things like a logging level and include paths. Change-Id: Ibea29f2874cc147a8e08f15192831fa42ca58f48 Reviewed-by: Johan Helsing --- src/compositor/compositor.pro | 4 + .../compositor_api/qwaylandcompositor.cpp | 8 ++ .../compositor_api/qwaylandcompositor_p.h | 12 +++ src/compositor/compositor_api/qwaylandkeyboard.cpp | 85 ++++++++++------------ src/compositor/compositor_api/qwaylandkeyboard_p.h | 11 ++- 5 files changed, 68 insertions(+), 52 deletions(-) diff --git a/src/compositor/compositor.pro b/src/compositor/compositor.pro index 47be591d7..b887cf281 100644 --- a/src/compositor/compositor.pro +++ b/src/compositor/compositor.pro @@ -3,6 +3,10 @@ MODULE = waylandcompositor QT = core gui-private +qtConfig(xkbcommon) { + QT_FOR_PRIVATE += xkbcommon_support-private +} + qtHaveModule(quick): QT += quick CONFIG -= precompile_header diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index e95e9a72e..856417fb4 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -172,6 +172,14 @@ QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *composi timer.start(); QWindowSystemInterfacePrivate::installWindowSystemEventHandler(eventHandler.data()); + +#if QT_CONFIG(xkbcommon) + mXkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS)); + if (!mXkbContext) { + qWarning("Failed to create a XKB context: keymap will not be supported"); + return; + } +#endif } void QWaylandCompositorPrivate::init() diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h index d91977def..2c9624216 100644 --- a/src/compositor/compositor_api/qwaylandcompositor_p.h +++ b/src/compositor/compositor_api/qwaylandcompositor_p.h @@ -60,6 +60,10 @@ #include +#if QT_CONFIG(xkbcommon) +#include +#endif + QT_BEGIN_NAMESPACE namespace QtWayland { @@ -81,6 +85,10 @@ public: QWaylandCompositorPrivate(QWaylandCompositor *compositor); ~QWaylandCompositorPrivate() override; +#if QT_CONFIG(xkbcommon) + struct xkb_context *xkbContext() const { return mXkbContext.get(); } +#endif + void preInit(); void init(); @@ -169,6 +177,10 @@ protected: bool initialized = false; QList > polish_objects; +#if QT_CONFIG(xkbcommon) + QXkbCommon::ScopedXKBContext mXkbContext; +#endif + Q_DECLARE_PUBLIC(QWaylandCompositor) Q_DISABLE_COPY(QWaylandCompositorPrivate) }; diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index 5f3bd3d4b..c92d00ebe 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -67,12 +67,11 @@ QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandSeat *seat) QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate() { #if QT_CONFIG(xkbcommon) - if (xkb_context) { + if (xkbContext()) { if (keymap_area) munmap(keymap_area, keymap_size); - close(keymap_fd); - xkb_context_unref(xkb_context); - xkb_state_unref(xkb_state); + if (keymap_fd >= 0) + close(keymap_fd); } #endif } @@ -137,7 +136,7 @@ void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *reso send_repeat_info(resource->handle, repeatRate, repeatDelay); #if QT_CONFIG(xkbcommon) - if (xkb_context) { + if (xkbContext()) { send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size); } else @@ -203,7 +202,7 @@ void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable() if (!scanCodesByQtKey.isEmpty() || !xkbState()) return; - if (xkb_keymap *keymap = xkb_state_get_keymap(xkb_state)) { + if (xkb_keymap *keymap = xkb_state_get_keymap(xkbState())) { xkb_keymap_key_for_each(keymap, [](xkb_keymap *keymap, xkb_keycode_t keycode, void *d){ auto *scanCodesByQtKey = static_cast*>(d); uint numLayouts = xkb_keymap_num_layouts_for_key(keymap, keycode); @@ -226,15 +225,15 @@ void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable() void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) { #if QT_CONFIG(xkbcommon) - if (!xkb_context) + if (!xkbContext()) return; - xkb_state_update_key(xkb_state, code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); + xkb_state_update_key(xkbState(), 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); + uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_DEPRESSED); + uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_LATCHED); + uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_LOCKED); + uint32_t group = xkb_state_serialize_group(xkbState(), (xkb_state_component)XKB_STATE_EFFECTIVE); if (this->modsDepressed == modsDepressed && this->modsLatched == modsLatched @@ -266,7 +265,7 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap() pendingKeymap = false; #if QT_CONFIG(xkbcommon) - if (!xkb_context) + if (!xkbContext()) return; createXKBKeymap(); @@ -274,7 +273,7 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap() 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); + xkb_state_update_mask(xkbState(), 0, modsLatched, modsLocked, 0, 0, 0); if (focusResource) send_modifiers(focusResource->handle, compositor()->nextSerial(), @@ -316,18 +315,6 @@ static int createAnonymousFile(size_t size) return fd; } -void QWaylandKeyboardPrivate::initXKB() -{ - xkb_context = xkb_context_new(static_cast(0)); - if (!xkb_context) { - qWarning("Failed to create a XKB context: keymap will not be supported"); - return; - } - - createXKBKeymap(); -} - - void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap) { char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); @@ -356,9 +343,9 @@ void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap) strcpy(keymap_area, keymap_str); free(keymap_str); - if (xkb_state) - xkb_state_unref(xkb_state); - xkb_state = xkb_state_new(keymap); + mXkbState.reset(xkb_state_new(keymap)); + if (!mXkbState) + qWarning("Failed to create XKB state"); } uint QWaylandKeyboardPrivate::toWaylandXkbV1Key(const uint nativeScanCode) @@ -370,32 +357,34 @@ uint QWaylandKeyboardPrivate::toWaylandXkbV1Key(const uint nativeScanCode) void QWaylandKeyboardPrivate::createXKBKeymap() { - if (!xkb_context) + if (!xkbContext()) return; - auto keymap = seat->keymap(); - 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 *xkbKeymap = xkb_keymap_new_from_names(xkb_context, &rule_names, static_cast(0)); - + QWaylandKeymap *keymap = seat->keymap(); + QByteArray rules = keymap->rules().toLocal8Bit(); + QByteArray model = keymap->model().toLocal8Bit(); + QByteArray layout = keymap->layout().toLocal8Bit(); + QByteArray variant = keymap->variant().toLocal8Bit(); + QByteArray options = keymap->options().toLocal8Bit(); + + struct xkb_rule_names rule_names = { + rules.constData(), + model.constData(), + layout.constData(), + variant.constData(), + options.constData() + }; + + QXkbCommon::ScopedXKBKeymap xkbKeymap(xkb_keymap_new_from_names(xkbContext(), &rule_names, + XKB_KEYMAP_COMPILE_NO_FLAGS)); if (xkbKeymap) { scanCodesByQtKey.clear(); - createXKBState(xkbKeymap); - xkb_keymap_unref(xkbKeymap); + createXKBState(xkbKeymap.get()); } else { qWarning("Failed to load the '%s' XKB keymap.", qPrintable(keymap->layout())); } - - 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 +#endif // QT_CONFIG(xkbcommon) void QWaylandKeyboardPrivate::sendRepeatInfo() { @@ -430,7 +419,7 @@ QWaylandKeyboard::QWaylandKeyboard(QWaylandSeat *seat, QObject *parent) connect(keymap, &QWaylandKeymap::rulesChanged, this, &QWaylandKeyboard::updateKeymap); connect(keymap, &QWaylandKeymap::modelChanged, this, &QWaylandKeyboard::updateKeymap); #if QT_CONFIG(xkbcommon) - d->initXKB(); + d->createXKBKeymap(); #endif } diff --git a/src/compositor/compositor_api/qwaylandkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h index 87e89e85e..c4d29c2d6 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard_p.h +++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h @@ -51,6 +51,7 @@ // // We mean it. // +#include #include #include @@ -64,6 +65,7 @@ #if QT_CONFIG(xkbcommon) #include +#include #endif @@ -87,7 +89,10 @@ public: uint32_t mods_latched, uint32_t mods_locked, uint32_t group); #if QT_CONFIG(xkbcommon) - struct xkb_state *xkbState() const { return xkb_state; } + struct xkb_state *xkbState() const { return mXkbState.get(); } + struct xkb_context *xkbContext() const { + return QWaylandCompositorPrivate::get(seat->compositor())->xkbContext(); + } uint32_t xkbModsMask() const { return modsDepressed | modsLatched | modsLocked; } void maybeUpdateXkbScanCodeTable(); #endif @@ -107,7 +112,6 @@ protected: private: #if QT_CONFIG(xkbcommon) - void initXKB(); void createXKBKeymap(); void createXKBState(xkb_keymap *keymap); #endif @@ -134,8 +138,7 @@ private: char *keymap_area = nullptr; using ScanCodeKey = std::pair; // group/layout and QtKey QMap scanCodesByQtKey; - struct xkb_context *xkb_context = nullptr; - struct xkb_state *xkb_state = nullptr; + QXkbCommon::ScopedXKBState mXkbState; #endif quint32 repeatRate = 40; -- cgit v1.2.3 From 458bc86f82f8fa6cfd659950549d1d2b36e5e40d Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 14 Dec 2018 17:14:06 +0100 Subject: xkbcommon: replace deprecated APIs See xkbcommon/xkbcommon-compat.h Change-Id: I2a70e14481db227fc0be657fbcf4f6550d62e7e8 Reviewed-by: Johan Helsing --- src/compositor/compositor_api/qwaylandkeyboard.cpp | 8 ++++---- src/shared/qwaylandxkb.cpp | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index c92d00ebe..e84eed64a 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -230,10 +230,10 @@ void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) xkb_state_update_key(xkbState(), code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); - uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_DEPRESSED); - uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_LATCHED); - uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), (xkb_state_component)XKB_STATE_LOCKED); - uint32_t group = xkb_state_serialize_group(xkbState(), (xkb_state_component)XKB_STATE_EFFECTIVE); + uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_DEPRESSED); + uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LATCHED); + uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LOCKED); + uint32_t group = xkb_state_serialize_layout(xkbState(), XKB_STATE_LAYOUT_EFFECTIVE); if (this->modsDepressed == modsDepressed && this->modsLatched == modsLatched diff --git a/src/shared/qwaylandxkb.cpp b/src/shared/qwaylandxkb.cpp index 3cfc4b074..6a81e9fd4 100644 --- a/src/shared/qwaylandxkb.cpp +++ b/src/shared/qwaylandxkb.cpp @@ -342,15 +342,13 @@ Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state) #if QT_CONFIG(xkbcommon) Qt::KeyboardModifiers modifiers = Qt::NoModifier; - xkb_state_component cstate = static_cast(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED | XKB_STATE_LOCKED); - - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, cstate)) + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE)) modifiers |= Qt::ShiftModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, cstate)) + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) modifiers |= Qt::ControlModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, cstate)) + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE)) modifiers |= Qt::AltModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, cstate)) + if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE)) modifiers |= Qt::MetaModifier; return modifiers; -- cgit v1.2.3 From 35880c7e1021a379e3cdd4005edd53472b63856c Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 16 Jan 2019 14:42:50 +0100 Subject: rework key handling - Document the magical 8 keycode offset in QKeyEvent::nativeScanCode() - Check if we are working with the expected keymap format. - Rename sendKey() to handleKey() as that is typical naming convention for events that are passed to QWindowSystemInterface. - WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP is in the bundled xml so use it in send_keymap() - Rename toWaylandXkbV1Key() to toWaylandKey() as previous name was incorrect. - Remove "Generic fallback" in keyboard_key() as it was non-functional, you can't expect any useful output when mapping scan code directly to Qt::Key. It was not working in 5.9 (did not check beyond that) and no one has complained. It is safe to assume that the fallback code path is dead and can be dropped. To use HW keyboard with wayland, you need to build with libxkbcommon. We require this on XCB since Qt 5.1.0, so it is not an unreasonable requirement for Wayland. - Cleanup auto-repeat key handling. - Cleanup "#if QT_CONFIG(xkbcommon)" checks. Change-Id: Ie9fcc628621487fb58bc55dd595bf0d51eedfc92 Reviewed-by: Johan Helsing --- src/client/qwaylandinputdevice.cpp | 127 ++++++++++----------- src/client/qwaylandinputdevice_p.h | 26 +++-- src/compositor/compositor_api/qwaylandkeyboard.cpp | 40 ++++--- src/compositor/compositor_api/qwaylandkeyboard_p.h | 2 +- 4 files changed, 100 insertions(+), 95 deletions(-) diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 572ce1e50..166be1934 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -77,7 +77,20 @@ namespace QtWaylandClient { QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) : mParent(p) { - connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); + mRepeatTimer.callOnTimeout([&]() { + if (!focusWindow()) { + // We destroyed the keyboard focus surface, but the server didn't get the message yet... + // or the server didn't send an enter event first. + return; + } + mRepeatTimer.setInterval(mRepeatRate); + handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, mRepeatKey.modifiers, + mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers, + mRepeatKey.text, true); + handleKey(mRepeatKey.time, QEvent::KeyPress, mRepeatKey.key, mRepeatKey.modifiers, + mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers, + mRepeatKey.text, true); + }); } #if QT_CONFIG(xkbcommon) @@ -728,8 +741,10 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) { + mKeymapFormat = format; #if QT_CONFIG(xkbcommon) if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + qCWarning(lcQpaWayland) << "unknown keymap format:" << format; close(fd); return; } @@ -751,7 +766,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, else mXkbState.reset(nullptr); #else - Q_UNUSED(format); Q_UNUSED(fd); Q_UNUSED(size); #endif @@ -798,29 +812,34 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf handleFocusLost(); } -void QWaylandInputDevice::Keyboard::sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, - Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, - quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text, bool autorep, ushort count) +void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type, int key, + Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString &text, bool autorepeat, ushort count) { QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); bool filtered = false; if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) { QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, - nativeModifiers, text, autorep, count); + nativeModifiers, text, autorepeat, count); event.setTimestamp(timestamp); filtered = inputContext->filterEvent(&event); } if (!filtered) { - QWindowSystemInterface::handleExtendedKeyEvent(tlw, timestamp, type, key, modifiers, - nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); + QWindowSystemInterface::handleExtendedKeyEvent(focusWindow()->window(), timestamp, type, key, modifiers, + nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count); } } void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + if (mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 && mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) { + qCWarning(lcQpaWayland) << Q_FUNC_INFO << "unknown keymap format:" << mKeymapFormat; + return; + } + auto *window = focusWindow(); if (!window) { // We destroyed the keyboard focus surface, but the server didn't get the message yet... @@ -828,76 +847,53 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, return; } - uint32_t code = key + 8; - bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED; - QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; - QString text; - int qtkey = key + 8; // qt-compositor substracts 8 for some reason mParent->mSerial = serial; + const bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED; if (isDown) mParent->mQDisplay->setLastInputDevice(mParent, serial, window); + if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { #if QT_CONFIG(xkbcommon) - if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap()) - return; - - xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code); - - Qt::KeyboardModifiers modifiers = mParent->modifiers(); + if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap()) + return; - std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); + auto code = key + 8; // map to wl_keyboard::keymap_format::keymap_format_xkb_v1 - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); -#else - // Generic fallback for single hard keys: Assume 'key' is a Qt key code. - sendKey(window->window(), time, type, qtkey, Qt::NoModifier, code, 0, 0); -#endif + xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code); - if (state == WL_KEYBOARD_KEY_STATE_PRESSED -#if QT_CONFIG(xkbcommon) - && xkb_keymap_key_repeats(mXkbKeymap.get(), code) -#endif - ) { - mRepeatKey = qtkey; - mRepeatCode = code; - mRepeatTime = time; - mRepeatText = text; -#if QT_CONFIG(xkbcommon) - mRepeatSym = sym; -#endif - mRepeatTimer.setInterval(mRepeatDelay); - mRepeatTimer.start(); - } else if (mRepeatCode == code) { - mRepeatTimer.stop(); - } -} + Qt::KeyboardModifiers modifiers = mParent->modifiers(); -void QWaylandInputDevice::Keyboard::repeatKey() -{ - auto *window = focusWindow(); - if (!window) { - // We destroyed the keyboard focus surface, but the server didn't get the message yet... - // or the server didn't send an enter event first. - return; - } + int qtkey = 0; + QString text; + std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); - mRepeatTimer.setInterval(mRepeatRate); - sendKey(window->window(), mRepeatTime, QEvent::KeyRelease, mRepeatKey, modifiers(), mRepeatCode, -#if QT_CONFIG(xkbcommon) - mRepeatSym, mNativeModifiers, -#else - 0, 0, -#endif - mRepeatText, true); + QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; + handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); - sendKey(window->window(), mRepeatTime, QEvent::KeyPress, mRepeatKey, modifiers(), mRepeatCode, -#if QT_CONFIG(xkbcommon) - mRepeatSym, mNativeModifiers, + if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code)) { + mRepeatKey.key = qtkey; + mRepeatKey.code = code; + mRepeatKey.time = time; + mRepeatKey.text = text; + mRepeatKey.modifiers = modifiers; + mRepeatKey.nativeModifiers = mNativeModifiers; + mRepeatKey.nativeVirtualKey = sym; + mRepeatTimer.setInterval(mRepeatDelay); + mRepeatTimer.start(); + } else if (mRepeatKey.code == code) { + mRepeatTimer.stop(); + } #else - 0, 0, + Q_UNUSED(time); + Q_UNUSED(key); + qCWarning(lcQpaWayland, "xkbcommon not available on this build, not performing key mapping"); + return; #endif - mRepeatText, true); + } else if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) { + // raw scan code + return; + } } void QWaylandInputDevice::Keyboard::handleFocusDestroyed() @@ -935,7 +931,6 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial, 0, 0, group); mNativeModifiers = mods_depressed | mods_latched | mods_locked; #else - Q_UNUSED(serial); Q_UNUSED(mods_depressed); Q_UNUSED(mods_latched); Q_UNUSED(mods_locked); diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 98e60286e..2dc3ddc27 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -211,18 +211,25 @@ public: uint32_t mNativeModifiers = 0; - int mRepeatKey; - uint32_t mRepeatCode; - uint32_t mRepeatTime; + struct repeatKey { + int key; + uint32_t code; + uint32_t time; + QString text; + Qt::KeyboardModifiers modifiers; + uint32_t nativeVirtualKey; + uint32_t nativeModifiers; + } mRepeatKey; + + QTimer mRepeatTimer; int mRepeatRate = 25; int mRepeatDelay = 400; - QString mRepeatText; - QTimer mRepeatTimer; + + uint32_t mKeymapFormat = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1; Qt::KeyboardModifiers modifiers() const; private slots: - void repeatKey(); void handleFocusDestroyed(); void handleFocusLost(); @@ -230,12 +237,11 @@ private: #if QT_CONFIG(xkbcommon) bool createDefaultKeymap(); #endif - void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text = QString(), bool autorep = false, ushort count = 1); + void handleKey(ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString &text, bool autorepeat = false, ushort count = 1); #if QT_CONFIG(xkbcommon) - xkb_keysym_t mRepeatSym = XKB_KEY_NoSymbol; QXkbCommon::ScopedXKBKeymap mXkbKeymap; QXkbCommon::ScopedXKBState mXkbState; #endif diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index e84eed64a..f66fe3263 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -143,7 +143,7 @@ void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *reso #endif { int null_fd = open("/dev/null", O_RDONLY); - send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, + send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, null_fd, 0); close(null_fd); } @@ -163,11 +163,8 @@ void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource) void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state) { -#if QT_CONFIG(xkbcommon) - uint key = toWaylandXkbV1Key(code); -#else - uint key = code; -#endif + uint key = toWaylandKey(code); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { keys << key; } else { @@ -179,11 +176,7 @@ void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state) { uint32_t time = compositor()->currentTimeMsecs(); uint32_t serial = compositor()->nextSerial(); -#if QT_CONFIG(xkbcommon) - uint key = toWaylandXkbV1Key(code); -#else - uint key = code; -#endif + uint key = toWaylandKey(code); if (focusResource) send_key(focusResource->handle, serial, time, key, state); } @@ -284,6 +277,24 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap() #endif } +uint QWaylandKeyboardPrivate::toWaylandKey(const uint nativeScanCode) +{ +#if QT_CONFIG(xkbcommon) + // In all current XKB keymaps there's a constant offset of 8 (for historical + // reasons) from hardware/evdev scancodes to XKB keycodes. On X11, we pass + // XKB keycodes (as sent by X server) via QKeyEvent::nativeScanCode. eglfs+evdev + // adds 8 for consistency, see qtbase/05c07c7636012ebb4131ca099ca4ea093af76410. + // eglfs+libinput also adds 8, for the same reason. Wayland protocol uses + // hardware/evdev scancodes, thus we need to minus 8 before sending the event + // out. + const uint offset = 8; + Q_ASSERT(nativeScanCode >= offset); + return nativeScanCode - offset; +#else + return nativeScanCode; +#endif +} + #if QT_CONFIG(xkbcommon) static int createAnonymousFile(size_t size) { @@ -348,13 +359,6 @@ void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap) qWarning("Failed to create XKB state"); } -uint QWaylandKeyboardPrivate::toWaylandXkbV1Key(const uint nativeScanCode) -{ - const uint offset = 8; - Q_ASSERT(nativeScanCode >= offset); - return nativeScanCode - offset; -} - void QWaylandKeyboardPrivate::createXKBKeymap() { if (!xkbContext()) diff --git a/src/compositor/compositor_api/qwaylandkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h index c4d29c2d6..fb3f5fe34 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard_p.h +++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h @@ -115,7 +115,7 @@ private: void createXKBKeymap(); void createXKBState(xkb_keymap *keymap); #endif - static uint toWaylandXkbV1Key(const uint nativeScanCode); + static uint toWaylandKey(const uint nativeScanCode); void sendRepeatInfo(); -- cgit v1.2.3 From c53bcc3b2ec04db86f77e9b3d0d18cef2c6932a0 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 10 Apr 2019 13:03:20 +0200 Subject: Compositor: Fix compilation problems for qwaylandshell.h d65783c broke compilation for code that includes qwaylandshell.h, but not qwaylandshell_p.h, because QWaylandShellPrivate is an incomplete type and we don't know that it's convertible to QWaylandCompositorExtensionPrivate by just looking at the public header. And we can't move the QWaylandShellTemplate constructors to the cpp file because it's a template class. Change-Id: Ia2d093de74429ace33d08b91743cbc8b7e7befa8 Reviewed-by: Paul Olav Tvete --- src/compositor/extensions/qwaylandshell.cpp | 20 ++++++++++++++++++++ src/compositor/extensions/qwaylandshell.h | 8 ++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/compositor/extensions/qwaylandshell.cpp b/src/compositor/extensions/qwaylandshell.cpp index 12479186b..bb3b4675c 100644 --- a/src/compositor/extensions/qwaylandshell.cpp +++ b/src/compositor/extensions/qwaylandshell.cpp @@ -92,4 +92,24 @@ void QWaylandShell::setFocusPolicy(QWaylandShell::FocusPolicy focusPolicy) emit focusPolicyChanged(); } +QWaylandShell::QWaylandShell(QWaylandShellPrivate &dd) + : QWaylandCompositorExtension(dd) +{ +} + +QWaylandShell::QWaylandShell(QWaylandObject *container, QWaylandShellPrivate &dd) + : QWaylandCompositorExtension(container, dd) +{ +} + +QWaylandShell::QWaylandShell(QWaylandCompositorExtensionPrivate &dd) + : QWaylandShell(static_cast(dd)) +{ +} + +QWaylandShell::QWaylandShell(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd) + : QWaylandShell(container, static_cast(dd)) +{ +} + QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandshell.h b/src/compositor/extensions/qwaylandshell.h index 9241b8662..6f494be55 100644 --- a/src/compositor/extensions/qwaylandshell.h +++ b/src/compositor/extensions/qwaylandshell.h @@ -68,8 +68,12 @@ Q_SIGNALS: void focusPolicyChanged(); protected: - QWaylandShell(QWaylandCompositorExtensionPrivate &dd) : QWaylandCompositorExtension(dd) {} - QWaylandShell(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd) : QWaylandCompositorExtension(container, dd) {} + explicit QWaylandShell(QWaylandShellPrivate &dd); + explicit QWaylandShell(QWaylandObject *container, QWaylandShellPrivate &dd); + + //Qt 6: remove + Q_DECL_DEPRECATED QWaylandShell(QWaylandCompositorExtensionPrivate &dd); + Q_DECL_DEPRECATED QWaylandShell(QWaylandObject *container, QWaylandCompositorExtensionPrivate &dd); }; template -- cgit v1.2.3 From 821cd2eae36ddbd9642208ad75a669c8c15f1b5f Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Tue, 23 Apr 2019 09:43:23 +0200 Subject: Compositor: Add qwaylandoutput_p.h to headers Fixes: QTBUG-75329 Change-Id: Ifdd93e28ebf971ab10f7d051c2da56d115f2068b Reviewed-by: Pier Luigi Fiorini --- src/compositor/compositor_api/compositor_api.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 3df061459..8dbe12ac1 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -17,6 +17,7 @@ HEADERS += \ compositor_api/qwaylandtouch.h \ compositor_api/qwaylandtouch_p.h \ compositor_api/qwaylandoutput.h \ + compositor_api/qwaylandoutput_p.h \ compositor_api/qwaylandoutputmode.h \ compositor_api/qwaylandoutputmode_p.h \ compositor_api/qwaylandbufferref.h \ -- cgit v1.2.3 From 85bb158ddf08aca4d76c13c6a9fcd2637d84d3ea Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 28 Jan 2019 09:48:26 +0100 Subject: Client: Full implementation for frame callbacks (second try) The Wayland plugin now takes full control over delivering update request and implement frame callbacks for both egl and shm. [ChangeLog][QPA plugin] The non-blocking version of eglSwapBuffers is now used, if supported. This fixed a bug where minimized windows would block the event loop. [ChangeLog][QPA plugin] Windows that don't get frame callbacks from the compositor within 100 ms are now set as not exposed. This should stop most clients from rendering unnecessary frames to minimized or hidden windows. Also, when we relied on the QPA version of requestUpdate, we would sometimes deliver one update request while we were waiting for a frame callback. When we implement the fallback timer ourselves we can make sure we only deliver the fallback if there are no pending frame callbacks. QtQuick and other applications often depend on blocking swapBuffers to throttle animations. If the context's surface format has a non-zero swapInterval, try to emulate a blocking swap. Fixes: QTBUG-69077 Change-Id: I3c6964f31a16e9aff70b8ec3c5340e640a30fef2 Reviewed-by: Paul Olav Tvete --- src/client/qwaylanddisplay.cpp | 38 ++++- src/client/qwaylanddisplay_p.h | 3 + src/client/qwaylandwindow.cpp | 180 +++++++++++++++++---- src/client/qwaylandwindow_p.h | 17 +- .../client/wayland-egl/qwaylandglcontext.cpp | 25 ++- .../qwaylandxcompositeeglcontext.cpp | 2 +- .../qwaylandxcompositeglxcontext.cpp | 2 +- 7 files changed, 218 insertions(+), 49 deletions(-) diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index f2bd3160a..82003a308 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -68,6 +68,8 @@ #include +#include + #include #include @@ -190,7 +192,6 @@ void QWaylandDisplay::flushRequests() wl_display_flush(mDisplay); } - void QWaylandDisplay::blockingReadEvents() { if (wl_display_dispatch(mDisplay) < 0) { @@ -204,6 +205,41 @@ void QWaylandDisplay::exitWithError() ::exit(1); } +wl_event_queue *QWaylandDisplay::createEventQueue() +{ + return wl_display_create_queue(mDisplay); +} + +void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function condition, int timeout) +{ + if (!condition()) + return; + + QElapsedTimer timer; + timer.start(); + struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN); + while (timeout == -1 || timer.elapsed() < timeout) { + while (wl_display_prepare_read_queue(mDisplay, queue) != 0) + wl_display_dispatch_queue_pending(mDisplay, queue); + + wl_display_flush(mDisplay); + + const int remaining = qMax(timeout - timer.elapsed(), 0ll); + const int pollTimeout = timeout == -1 ? -1 : remaining; + if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0) + wl_display_read_events(mDisplay); + else + wl_display_cancel_read(mDisplay); + + if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0) { + checkError(); + exitWithError(); + } + if (!condition()) + break; + } +} + QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const { for (int i = 0; i < mScreens.size(); ++i) { diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index fe1d7874e..6bf6abd5d 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -182,6 +182,9 @@ public: void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice); void handleWindowDestroyed(QWaylandWindow *window); + wl_event_queue *createEventQueue(); + void dispatchQueueWhile(wl_event_queue *queue, std::function condition, int timeout = -1); + public slots: void blockingReadEvents(); void flushRequests(); diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 79639cba0..58e0fc585 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -67,6 +67,7 @@ #include #include +#include #include @@ -81,6 +82,7 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr; QWaylandWindow::QWaylandWindow(QWindow *window) : QPlatformWindow(window) , mDisplay(waylandScreen()->display()) + , mFrameQueue(mDisplay->createEventQueue()) , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP")) { static WId id = 1; @@ -363,6 +365,8 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect) { if (!(mShellSurface && mShellSurface->handleExpose(rect))) QWindowSystemInterface::handleExposeEvent(window(), rect); + else + qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending"; mLastExposeGeometry = rect; } @@ -542,18 +546,11 @@ void QWaylandWindow::handleScreenRemoved(QScreen *qScreen) void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) { Q_ASSERT(!buffer->committed()); - if (mFrameCallback) { - wl_callback_destroy(mFrameCallback); - mFrameCallback = nullptr; - } - if (buffer) { - mFrameCallback = frame(); - wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); - mWaitingForFrameSync = true; + handleUpdate(); buffer->setBusy(); - attach(buffer->buffer(), x, y); + QtWayland::wl_surface::attach(buffer->buffer(), x, y); } else { QtWayland::wl_surface::attach(nullptr, 0, 0); } @@ -609,32 +606,61 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage) } const wl_callback_listener QWaylandWindow::callbackListener = { - QWaylandWindow::frameCallback + [](void *data, wl_callback *callback, uint32_t time) { + Q_UNUSED(callback); + Q_UNUSED(time); + auto *window = static_cast(data); + if (window->thread() != QThread::currentThread()) + QMetaObject::invokeMethod(window, [=] { window->handleFrameCallback(); }, Qt::QueuedConnection); + else + window->handleFrameCallback(); + } }; -void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uint32_t time) +void QWaylandWindow::handleFrameCallback() { - Q_UNUSED(time); - Q_UNUSED(callback); - QWaylandWindow *self = static_cast(data); + bool wasExposed = isExposed(); - self->mWaitingForFrameSync = false; - if (self->mUpdateRequested) { - self->mUpdateRequested = false; - self->deliverUpdateRequest(); + if (mFrameCallbackTimerId != -1) { + killTimer(mFrameCallbackTimerId); + mFrameCallbackTimerId = -1; } + + mWaitingForFrameCallback = false; + mFrameCallbackTimedOut = false; + + if (!wasExposed && isExposed()) + sendExposeEvent(QRect(QPoint(), geometry().size())); + if (wasExposed && hasPendingUpdateRequest()) + deliverUpdateRequest(); } QMutex QWaylandWindow::mFrameSyncMutex; -void QWaylandWindow::waitForFrameSync() +bool QWaylandWindow::waitForFrameSync(int timeout) { QMutexLocker locker(&mFrameSyncMutex); - if (!mWaitingForFrameSync) - return; - mDisplay->flushRequests(); - while (mWaitingForFrameSync) - mDisplay->blockingReadEvents(); + if (!mWaitingForFrameCallback) + return true; + + wl_proxy_set_queue(reinterpret_cast(mFrameCallback), mFrameQueue); + mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout); + + if (mWaitingForFrameCallback) { + qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; + mFrameCallbackTimedOut = true; + mWaitingForUpdate = false; + sendExposeEvent(QRect()); + } + + // Stop current frame timer if any, can't use killTimer directly, because we might be on a diffent thread + if (mFrameCallbackTimerId != -1) { + int id = mFrameCallbackTimerId; + mFrameCallbackTimerId = -1; + QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); + } + + return !mWaitingForFrameCallback; } QMargins QWaylandWindow::frameMargins() const @@ -966,6 +992,9 @@ bool QWaylandWindow::isExposed() const if (!window()->isVisible()) return false; + if (mFrameCallbackTimedOut) + return false; + if (mShellSurface) return mShellSurface->isExposed(); @@ -1041,12 +1070,107 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa return m_properties.value(name, defaultValue); } +void QWaylandWindow::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == mFallbackUpdateTimerId) { + killTimer(mFallbackUpdateTimerId); + mFallbackUpdateTimerId = -1; + qCDebug(lcWaylandBackingstore) << "mFallbackUpdateTimer timed out"; + + if (!isExposed()) { + qCDebug(lcWaylandBackingstore) << "Fallback update timer: Window not exposed," + << "not delivering update request."; + return; + } + + if (mWaitingForUpdate && hasPendingUpdateRequest() && !mWaitingForFrameCallback) { + qCWarning(lcWaylandBackingstore) << "Delivering update request through fallback timer," + << "may not be in sync with display"; + deliverUpdateRequest(); + } + } + + if (event->timerId() == mFrameCallbackTimerId) { + killTimer(mFrameCallbackTimerId); + mFrameCallbackTimerId = -1; + qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; + mFrameCallbackTimedOut = true; + mWaitingForUpdate = false; + sendExposeEvent(QRect()); + } +} + void QWaylandWindow::requestUpdate() { - if (!mWaitingForFrameSync) - QPlatformWindow::requestUpdate(); - else - mUpdateRequested = true; + Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA + + // If we have a frame callback all is good and will be taken care of there + if (mWaitingForFrameCallback) + return; + + // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet + if (mWaitingForUpdate) { + // Ideally, we should just have returned here, but we're not guaranteed that the client + // will actually update, so start this timer to deliver another request update after a while + // *IF* the client doesn't update. + int fallbackTimeout = 100; + mFallbackUpdateTimerId = startTimer(fallbackTimeout); + return; + } + + // Some applications (such as Qt Quick) depend on updates being delivered asynchronously, + // so use invokeMethod to delay the delivery a bit. + QMetaObject::invokeMethod(this, [this] { + // Things might have changed in the meantime + if (hasPendingUpdateRequest() && !mWaitingForUpdate && !mWaitingForFrameCallback) + deliverUpdateRequest(); + }, Qt::QueuedConnection); +} + +// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly +// with eglSwapBuffers) to know when it's time to commit the next one. +// Can be called from the render thread (without locking anything) so make sure to not make races in this method. +void QWaylandWindow::handleUpdate() +{ + // TODO: Should sync subsurfaces avoid requesting frame callbacks? + + if (mFrameCallback) { + wl_callback_destroy(mFrameCallback); + mFrameCallback = nullptr; + } + + if (mFallbackUpdateTimerId != -1) { + // Ideally, we would stop the fallback timer here, but since we're on another thread, + // it's not allowed. Instead we set mFallbackUpdateTimer to -1 here, so we'll just + // ignore it if it times out before it's cleaned up by the invokeMethod call. + int id = mFallbackUpdateTimerId; + mFallbackUpdateTimerId = -1; + QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); + } + + mFrameCallback = frame(); + wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); + mWaitingForFrameCallback = true; + mWaitingForUpdate = false; + + // Stop current frame timer if any, can't use killTimer directly, see comment above. + if (mFrameCallbackTimerId != -1) { + int id = mFrameCallbackTimerId; + mFrameCallbackTimerId = -1; + QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); + } + + // Start a timer for handling the case when the compositor stops sending frame callbacks. + QMetaObject::invokeMethod(this, [=] { // Again; can't do it directly + if (mWaitingForFrameCallback) + mFrameCallbackTimerId = startTimer(100); + }, Qt::QueuedConnection); +} + +void QWaylandWindow::deliverUpdateRequest() +{ + mWaitingForUpdate = true; + QPlatformWindow::deliverUpdateRequest(); } void QWaylandWindow::addAttachOffset(const QPoint point) diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 56ebd3cc6..c47123dc9 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -120,7 +120,7 @@ public: void handleExpose(const QRegion ®ion); void commit(QWaylandBuffer *buffer, const QRegion &damage); - void waitForFrameSync(); + bool waitForFrameSync(int timeout); QMargins frameMargins() const override; @@ -191,7 +191,10 @@ public: bool startSystemMove(const QPoint &pos) override; + void timerEvent(QTimerEvent *event) override; void requestUpdate() override; + void handleUpdate(); + void deliverUpdateRequest() override; public slots: void applyConfigure(); @@ -211,10 +214,17 @@ protected: Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton; WId mWindowId; - bool mWaitingForFrameSync = false; + bool mWaitingForFrameCallback = false; + bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out + int mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback struct ::wl_callback *mFrameCallback = nullptr; + struct ::wl_event_queue *mFrameQueue = nullptr; QWaitCondition mFrameSyncWait; + // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer + bool mWaitingForUpdate = false; + int mFallbackUpdateTimerId = -1; // Started when waiting for app to commit + QMutex mResizeLock; bool mWaitingToApplyConfigure = false; bool mCanResize = true; @@ -253,11 +263,10 @@ private: void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); void handleScreenChanged(); - bool mUpdateRequested = false; QRect mLastExposeGeometry; static const wl_callback_listener callbackListener; - static void frameCallback(void *data, struct wl_callback *wl_callback, uint32_t time); + void handleFrameCallback(); static QMutex mFrameSyncMutex; static QWaylandWindow *mMouseGrab; diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp index c9bd83752..6b9776e9c 100644 --- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp +++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp @@ -316,7 +316,9 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis mSupportNonBlockingSwap = false; } if (!mSupportNonBlockingSwap) { - qWarning() << "Non-blocking swap buffers not supported. Subsurface rendering can be affected."; + qWarning(lcQpaWayland) << "Non-blocking swap buffers not supported." + << "Subsurface rendering can be affected." + << "It may also cause the event loop to freeze in some situations"; } updateGLFormat(); @@ -556,20 +558,15 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface) m_blitter->blit(window); } - - QWaylandSubSurface *sub = window->subSurfaceWindow(); - if (sub) { - QMutexLocker l(sub->syncMutex()); - - int si = (sub->isSync() && mSupportNonBlockingSwap) ? 0 : m_format.swapInterval(); - - eglSwapInterval(m_eglDisplay, si); - eglSwapBuffers(m_eglDisplay, eglSurface); - } else { - eglSwapInterval(m_eglDisplay, m_format.swapInterval()); - eglSwapBuffers(m_eglDisplay, eglSurface); + int swapInterval = mSupportNonBlockingSwap ? 0 : m_format.swapInterval(); + eglSwapInterval(m_eglDisplay, swapInterval); + if (swapInterval == 0 && m_format.swapInterval() > 0) { + // Emulating a blocking swap + glFlush(); // Flush before waiting so we can swap more quickly when the frame event arrives + window->waitForFrameSync(100); } - + window->handleUpdate(); + eglSwapBuffers(m_eglDisplay, eglSurface); window->setCanResize(true); } diff --git a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp index c07ad5342..a6fead95c 100644 --- a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp +++ b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp @@ -65,7 +65,7 @@ void QWaylandXCompositeEGLContext::swapBuffers(QPlatformSurface *surface) QSize size = w->geometry().size(); w->commit(w->buffer(), QRegion(0, 0, size.width(), size.height())); - w->waitForFrameSync(); + w->waitForFrameSync(100); } EGLSurface QWaylandXCompositeEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) diff --git a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp index 33ae2e038..351887416 100644 --- a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp +++ b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp @@ -93,7 +93,7 @@ void QWaylandXCompositeGLXContext::swapBuffers(QPlatformSurface *surface) glXSwapBuffers(m_display, w->xWindow()); w->commit(w->buffer(), QRegion(0, 0, size.width(), size.height())); - w->waitForFrameSync(); + w->waitForFrameSync(100); } QFunctionPointer QWaylandXCompositeGLXContext::getProcAddress(const char *procName) -- cgit v1.2.3 From 23453c30084d09d7325e113bbc3d0637c51cb3e7 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Fri, 14 Dec 2018 21:07:08 +0100 Subject: drop qwaylandxkb and share the logic with X11 QtWayland can benefit from sharing code with X11. This will fix issues that have been reported and fixed on XCB a long time ago. Task-number: QTBUG-65503 Fixes: QTBUG-71301 Fixes: QTBUG-66497 Change-Id: I09cbf8e1c9cf29e8d7f46b97bc2f11d6e91b61a5 Reviewed-by: Johan Helsing --- src/client/client.pro | 2 - src/client/qwaylandinputcontext.cpp | 15 +- src/client/qwaylandinputdevice.cpp | 10 +- .../compositor_api/qwaylandcompositor.cpp | 11 +- src/compositor/compositor_api/qwaylandkeyboard.cpp | 3 +- src/compositor/extensions/qwaylandtextinput.cpp | 11 +- src/compositor/wayland_wrapper/wayland_wrapper.pri | 6 +- src/shared/qwaylandxkb.cpp | 393 --------------------- src/shared/qwaylandxkb_p.h | 73 ---- 9 files changed, 32 insertions(+), 492 deletions(-) delete mode 100644 src/shared/qwaylandxkb.cpp delete mode 100644 src/shared/qwaylandxkb_p.h diff --git a/src/client/client.pro b/src/client/client.pro index 81152f756..db91bd691 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -49,7 +49,6 @@ SOURCES += qwaylandintegration.cpp \ qwaylandtouch.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ - ../shared/qwaylandxkb.cpp \ ../shared/qwaylandinputmethodeventbuilder.cpp \ qwaylandabstractdecoration.cpp \ qwaylanddecorationfactory.cpp \ @@ -83,7 +82,6 @@ HEADERS += qwaylandintegration_p.h \ qtwaylandclientglobal_p.h \ ../shared/qwaylandinputmethodeventbuilder_p.h \ ../shared/qwaylandmimehelper_p.h \ - ../shared/qwaylandxkb_p.h \ ../shared/qwaylandsharedmemoryformathelper_p.h \ qtConfig(clipboard) { diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp index e85faaf8e..c6f287dda 100644 --- a/src/client/qwaylandinputcontext.cpp +++ b/src/client/qwaylandinputcontext.cpp @@ -50,7 +50,6 @@ #include "qwaylandinputdevice_p.h" #include "qwaylandinputmethodeventbuilder_p.h" #include "qwaylandwindow_p.h" -#include "qwaylandxkb_p.h" QT_BEGIN_NAMESPACE @@ -315,6 +314,7 @@ void QWaylandTextInput::zwp_text_input_v2_delete_surrounding_text(uint32_t befor void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) { +#if QT_CONFIG(xkbcommon) if (m_resetCallback) { qCDebug(qLcQpaInputMethods()) << "discard keysym: reset not confirmed"; return; @@ -325,13 +325,18 @@ void QWaylandTextInput::zwp_text_input_v2_keysym(uint32_t time, uint32_t sym, ui Qt::KeyboardModifiers qtModifiers = modifiersToQtModifiers(modifiers); - QEvent::Type type = QWaylandXkb::toQtEventType(state); - QString text; - int qtkey; - std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, qtModifiers); + QEvent::Type type = state == WL_KEYBOARD_KEY_STATE_PRESSED ? QEvent::KeyPress : QEvent::KeyRelease; + QString text = QXkbCommon::lookupStringNoKeysymTransformations(sym); + int qtkey = QXkbCommon::keysymToQtKey(sym, qtModifiers); QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), time, type, qtkey, qtModifiers, text); +#else + Q_UNUSED(time); + Q_UNUSED(sym); + Q_UNUSED(state); + Q_UNUSED(modifiers); +#endif } void QWaylandTextInput::zwp_text_input_v2_language(const QString &language) diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 166be1934..17c408a3d 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -51,7 +51,6 @@ #include "qwaylandcursor_p.h" #include "qwaylanddisplay_p.h" #include "qwaylandshmbackingstore_p.h" -#include "../shared/qwaylandxkb_p.h" #include "qwaylandinputcontext_p.h" #include @@ -493,7 +492,7 @@ Qt::KeyboardModifiers QWaylandInputDevice::Keyboard::modifiers() const if (!mXkbState) return ret; - ret = QWaylandXkb::modifiers(mXkbState.get()); + ret = QXkbCommon::modifiers(mXkbState.get()); #endif return ret; @@ -758,6 +757,8 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, mXkbKeymap.reset(xkb_keymap_new_from_string(mParent->mQDisplay->xkbContext(), map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS)); + QXkbCommon::verifyHasLatinLayout(mXkbKeymap.get()); + munmap(map_str, size); close(fd); @@ -864,9 +865,8 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, Qt::KeyboardModifiers modifiers = mParent->modifiers(); - int qtkey = 0; - QString text; - std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); + int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, mXkbState.get(), code); + QString text = QXkbCommon::lookupString(mXkbState.get(), code); QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 856417fb4..8ff9e0905 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -72,7 +72,6 @@ #include "extensions/qwaylandqtwindowmanager.h" -#include "qwaylandxkb_p.h" #include "qwaylandsharedmemoryformathelper_p.h" #include @@ -129,12 +128,12 @@ public: bool isDown = ke->keyType == QEvent::KeyPress; #if QT_CONFIG(xkbcommon) - QString text; - Qt::KeyboardModifiers modifiers = QWaylandXkb::modifiers(keyb->xkbState()); + xkb_state *xkbState = keyb->xkbState(); + Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(xkbState); - const xkb_keysym_t sym = xkb_state_key_get_one_sym(keyb->xkbState(), code); - int qtkey; - std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); + const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code); + int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code); + QString text = QXkbCommon::lookupString(xkbState, code); ke->key = qtkey; ke->modifiers = modifiers; diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index f66fe3263..ffe536ce3 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -54,7 +54,6 @@ #if QT_CONFIG(xkbcommon) #include #include -#include #endif QT_BEGIN_NAMESPACE @@ -206,7 +205,7 @@ void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable() continue; Qt::KeyboardModifiers mods = {}; - int qtKey = QWaylandXkb::keysymToQtKey(syms[0], mods).first; + int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods); if (qtKey != 0) scanCodesByQtKey->insert({layout, qtKey}, keycode); } diff --git a/src/compositor/extensions/qwaylandtextinput.cpp b/src/compositor/extensions/qwaylandtextinput.cpp index 6cf33d18d..f60a32a14 100644 --- a/src/compositor/extensions/qwaylandtextinput.cpp +++ b/src/compositor/extensions/qwaylandtextinput.cpp @@ -45,12 +45,15 @@ #include "qwaylandsurface.h" #include "qwaylandview.h" -#include "qwaylandxkb_p.h" #include "qwaylandinputmethodeventbuilder_p.h" #include #include +#if QT_CONFIG(xkbcommon) +#include +#endif + QT_BEGIN_NAMESPACE QWaylandTextInputClientState::QWaylandTextInputClientState() @@ -203,11 +206,15 @@ void QWaylandTextInputPrivate::sendKeyEvent(QKeyEvent *event) // TODO add support for modifiers - foreach (xkb_keysym_t keysym, QWaylandXkb::toKeysym(event)) { +#if QT_CONFIG(xkbcommon) + for (xkb_keysym_t keysym : QXkbCommon::toKeysym(event)) { send_keysym(focusResource->handle, event->timestamp(), keysym, event->type() == QEvent::KeyPress ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, 0); } +#else + Q_UNUSED(event); +#endif } void QWaylandTextInputPrivate::sendInputPanelState() diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index b0c8371f4..08dd38e82 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -5,14 +5,12 @@ WAYLANDSERVERSOURCES += \ HEADERS += \ wayland_wrapper/qwlbuffermanager_p.h \ wayland_wrapper/qwlclientbuffer_p.h \ - wayland_wrapper/qwlregion_p.h \ - ../shared/qwaylandxkb_p.h \ + wayland_wrapper/qwlregion_p.h SOURCES += \ wayland_wrapper/qwlbuffermanager.cpp \ wayland_wrapper/qwlclientbuffer.cpp \ - wayland_wrapper/qwlregion.cpp \ - ../shared/qwaylandxkb.cpp \ + wayland_wrapper/qwlregion.cpp qtConfig(wayland-datadevice) { HEADERS += \ diff --git a/src/shared/qwaylandxkb.cpp b/src/shared/qwaylandxkb.cpp deleted file mode 100644 index 6a81e9fd4..000000000 --- a/src/shared/qwaylandxkb.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Jolla 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwaylandxkb_p.h" - -#include -#include - -#if QT_CONFIG(xkbcommon) -#include -#endif - -QT_BEGIN_NAMESPACE - -#if QT_CONFIG(xkbcommon) -static const uint32_t KeyTbl[] = { - XKB_KEY_Escape, Qt::Key_Escape, - XKB_KEY_Tab, Qt::Key_Tab, - XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab, - XKB_KEY_BackSpace, Qt::Key_Backspace, - XKB_KEY_Return, Qt::Key_Return, - XKB_KEY_Insert, Qt::Key_Insert, - XKB_KEY_Delete, Qt::Key_Delete, - XKB_KEY_Clear, Qt::Key_Delete, - XKB_KEY_Pause, Qt::Key_Pause, - XKB_KEY_Print, Qt::Key_Print, - - XKB_KEY_Home, Qt::Key_Home, - XKB_KEY_End, Qt::Key_End, - XKB_KEY_Left, Qt::Key_Left, - XKB_KEY_Up, Qt::Key_Up, - XKB_KEY_Right, Qt::Key_Right, - XKB_KEY_Down, Qt::Key_Down, - XKB_KEY_Prior, Qt::Key_PageUp, - XKB_KEY_Next, Qt::Key_PageDown, - - XKB_KEY_Shift_L, Qt::Key_Shift, - XKB_KEY_Shift_R, Qt::Key_Shift, - XKB_KEY_Shift_Lock, Qt::Key_Shift, - XKB_KEY_Control_L, Qt::Key_Control, - XKB_KEY_Control_R, Qt::Key_Control, - XKB_KEY_Meta_L, Qt::Key_Meta, - XKB_KEY_Meta_R, Qt::Key_Meta, - XKB_KEY_Alt_L, Qt::Key_Alt, - XKB_KEY_Alt_R, Qt::Key_Alt, - XKB_KEY_Caps_Lock, Qt::Key_CapsLock, - XKB_KEY_Num_Lock, Qt::Key_NumLock, - XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock, - XKB_KEY_Super_L, Qt::Key_Super_L, - XKB_KEY_Super_R, Qt::Key_Super_R, - XKB_KEY_Menu, Qt::Key_Menu, - XKB_KEY_Hyper_L, Qt::Key_Hyper_L, - XKB_KEY_Hyper_R, Qt::Key_Hyper_R, - XKB_KEY_Help, Qt::Key_Help, - - XKB_KEY_KP_Space, Qt::Key_Space, - XKB_KEY_KP_Tab, Qt::Key_Tab, - XKB_KEY_KP_Enter, Qt::Key_Enter, - XKB_KEY_KP_Home, Qt::Key_Home, - XKB_KEY_KP_Left, Qt::Key_Left, - XKB_KEY_KP_Up, Qt::Key_Up, - XKB_KEY_KP_Right, Qt::Key_Right, - XKB_KEY_KP_Down, Qt::Key_Down, - XKB_KEY_KP_Prior, Qt::Key_PageUp, - XKB_KEY_KP_Next, Qt::Key_PageDown, - XKB_KEY_KP_End, Qt::Key_End, - XKB_KEY_KP_Begin, Qt::Key_Clear, - XKB_KEY_KP_Insert, Qt::Key_Insert, - XKB_KEY_KP_Delete, Qt::Key_Delete, - XKB_KEY_KP_Equal, Qt::Key_Equal, - XKB_KEY_KP_Multiply, Qt::Key_Asterisk, - XKB_KEY_KP_Add, Qt::Key_Plus, - XKB_KEY_KP_Separator, Qt::Key_Comma, - XKB_KEY_KP_Subtract, Qt::Key_Minus, - XKB_KEY_KP_Decimal, Qt::Key_Period, - XKB_KEY_KP_Divide, Qt::Key_Slash, - - XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr, - XKB_KEY_Multi_key, Qt::Key_Multi_key, - XKB_KEY_Codeinput, Qt::Key_Codeinput, - XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate, - XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate, - XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate, - - XKB_KEY_Mode_switch, Qt::Key_Mode_switch, - XKB_KEY_script_switch, Qt::Key_Mode_switch, - - XKB_KEY_XF86Back, Qt::Key_Back, - XKB_KEY_XF86Forward, Qt::Key_Forward, - XKB_KEY_XF86Stop, Qt::Key_Stop, - XKB_KEY_XF86Refresh, Qt::Key_Refresh, - XKB_KEY_XF86Favorites, Qt::Key_Favorites, - XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia, - XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl, - XKB_KEY_XF86HomePage, Qt::Key_HomePage, - XKB_KEY_XF86Search, Qt::Key_Search, - XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown, - XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute, - XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp, - XKB_KEY_XF86AudioPlay, Qt::Key_MediaTogglePlayPause, - XKB_KEY_XF86AudioStop, Qt::Key_MediaStop, - XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious, - XKB_KEY_XF86AudioNext, Qt::Key_MediaNext, - XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord, - XKB_KEY_XF86AudioPause, Qt::Key_MediaPause, - XKB_KEY_XF86Mail, Qt::Key_LaunchMail, - XKB_KEY_XF86Calculator, Qt::Key_Calculator, - XKB_KEY_XF86Memo, Qt::Key_Memo, - XKB_KEY_XF86ToDoList, Qt::Key_ToDoList, - XKB_KEY_XF86Calendar, Qt::Key_Calendar, - XKB_KEY_XF86PowerDown, Qt::Key_PowerDown, - XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust, - XKB_KEY_XF86Standby, Qt::Key_Standby, - XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp, - XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown, - XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff, - XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp, - XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown, - XKB_KEY_XF86PowerOff, Qt::Key_PowerOff, - XKB_KEY_XF86WakeUp, Qt::Key_WakeUp, - XKB_KEY_XF86Eject, Qt::Key_Eject, - XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver, - XKB_KEY_XF86WWW, Qt::Key_WWW, - XKB_KEY_XF86Sleep, Qt::Key_Sleep, - XKB_KEY_XF86LightBulb, Qt::Key_LightBulb, - XKB_KEY_XF86Shop, Qt::Key_Shop, - XKB_KEY_XF86History, Qt::Key_History, - XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite, - XKB_KEY_XF86HotLinks, Qt::Key_HotLinks, - XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust, - XKB_KEY_XF86Finance, Qt::Key_Finance, - XKB_KEY_XF86Community, Qt::Key_Community, - XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind, - XKB_KEY_XF86BackForward, Qt::Key_BackForward, - XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft, - XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight, - XKB_KEY_XF86Book, Qt::Key_Book, - XKB_KEY_XF86CD, Qt::Key_CD, - XKB_KEY_XF86Calculater, Qt::Key_Calculator, - XKB_KEY_XF86Clear, Qt::Key_Clear, - XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab, - XKB_KEY_XF86Close, Qt::Key_Close, - XKB_KEY_XF86Copy, Qt::Key_Copy, - XKB_KEY_XF86Cut, Qt::Key_Cut, - XKB_KEY_XF86Display, Qt::Key_Display, - XKB_KEY_XF86DOS, Qt::Key_DOS, - XKB_KEY_XF86Documents, Qt::Key_Documents, - XKB_KEY_XF86Excel, Qt::Key_Excel, - XKB_KEY_XF86Explorer, Qt::Key_Explorer, - XKB_KEY_XF86Game, Qt::Key_Game, - XKB_KEY_XF86Go, Qt::Key_Go, - XKB_KEY_XF86iTouch, Qt::Key_iTouch, - XKB_KEY_XF86LogOff, Qt::Key_LogOff, - XKB_KEY_XF86Market, Qt::Key_Market, - XKB_KEY_XF86Meeting, Qt::Key_Meeting, - XKB_KEY_XF86MenuKB, Qt::Key_MenuKB, - XKB_KEY_XF86MenuPB, Qt::Key_MenuPB, - XKB_KEY_XF86MySites, Qt::Key_MySites, - XKB_KEY_XF86New, Qt::Key_New, - XKB_KEY_XF86News, Qt::Key_News, - XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome, - XKB_KEY_XF86Open, Qt::Key_Open, - XKB_KEY_XF86Option, Qt::Key_Option, - XKB_KEY_XF86Paste, Qt::Key_Paste, - XKB_KEY_XF86Phone, Qt::Key_Phone, - XKB_KEY_XF86Reply, Qt::Key_Reply, - XKB_KEY_XF86Reload, Qt::Key_Reload, - XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows, - XKB_KEY_XF86RotationPB, Qt::Key_RotationPB, - XKB_KEY_XF86RotationKB, Qt::Key_RotationKB, - XKB_KEY_XF86Save, Qt::Key_Save, - XKB_KEY_XF86Send, Qt::Key_Send, - XKB_KEY_XF86Spell, Qt::Key_Spell, - XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen, - XKB_KEY_XF86Support, Qt::Key_Support, - XKB_KEY_XF86TaskPane, Qt::Key_TaskPane, - XKB_KEY_XF86Terminal, Qt::Key_Terminal, - XKB_KEY_XF86Tools, Qt::Key_Tools, - XKB_KEY_XF86Travel, Qt::Key_Travel, - XKB_KEY_XF86Video, Qt::Key_Video, - XKB_KEY_XF86Word, Qt::Key_Word, - XKB_KEY_XF86Xfer, Qt::Key_Xfer, - XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn, - XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut, - XKB_KEY_XF86Away, Qt::Key_Away, - XKB_KEY_XF86Messenger, Qt::Key_Messenger, - XKB_KEY_XF86WebCam, Qt::Key_WebCam, - XKB_KEY_XF86MailForward, Qt::Key_MailForward, - XKB_KEY_XF86Pictures, Qt::Key_Pictures, - XKB_KEY_XF86Music, Qt::Key_Music, - XKB_KEY_XF86Battery, Qt::Key_Battery, - XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth, - XKB_KEY_XF86WLAN, Qt::Key_WLAN, - XKB_KEY_XF86UWB, Qt::Key_UWB, - XKB_KEY_XF86AudioForward, Qt::Key_AudioForward, - XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat, - XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay, - XKB_KEY_XF86Subtitle, Qt::Key_Subtitle, - XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack, - XKB_KEY_XF86Time, Qt::Key_Time, - XKB_KEY_XF86Select, Qt::Key_Select, - XKB_KEY_XF86View, Qt::Key_View, - XKB_KEY_XF86TopMenu, Qt::Key_TopMenu, - XKB_KEY_XF86Red, Qt::Key_Red, - XKB_KEY_XF86Green, Qt::Key_Green, - XKB_KEY_XF86Yellow, Qt::Key_Yellow, - XKB_KEY_XF86Blue, Qt::Key_Blue, - XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth, - XKB_KEY_XF86Suspend, Qt::Key_Suspend, - XKB_KEY_XF86Hibernate, Qt::Key_Hibernate, - XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle, - XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn, - XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff, - XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute, - XKB_KEY_XF86Launch0, Qt::Key_Launch0, - XKB_KEY_XF86Launch1, Qt::Key_Launch1, - XKB_KEY_XF86Launch2, Qt::Key_Launch2, - XKB_KEY_XF86Launch3, Qt::Key_Launch3, - XKB_KEY_XF86Launch4, Qt::Key_Launch4, - XKB_KEY_XF86Launch5, Qt::Key_Launch5, - XKB_KEY_XF86Launch6, Qt::Key_Launch6, - XKB_KEY_XF86Launch7, Qt::Key_Launch7, - XKB_KEY_XF86Launch8, Qt::Key_Launch8, - XKB_KEY_XF86Launch9, Qt::Key_Launch9, - XKB_KEY_XF86LaunchA, Qt::Key_LaunchA, - XKB_KEY_XF86LaunchB, Qt::Key_LaunchB, - XKB_KEY_XF86LaunchC, Qt::Key_LaunchC, - XKB_KEY_XF86LaunchD, Qt::Key_LaunchD, - XKB_KEY_XF86LaunchE, Qt::Key_LaunchE, - XKB_KEY_XF86LaunchF, Qt::Key_LaunchF, - - 0, 0 -}; - -static int lookupKeysym(xkb_keysym_t key) -{ - int code = 0; - int i = 0; - while (KeyTbl[i]) { - if (key == KeyTbl[i]) { - code = (int)KeyTbl[i+1]; - break; - } - i += 2; - } - - return code; -} - -static xkb_keysym_t toKeysymFromTable(uint32_t key) -{ - for (int i = 0; KeyTbl[i]; i += 2) { - if (key == KeyTbl[i + 1]) - return KeyTbl[i]; - } - - return 0; -} -#endif - -std::pair QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers) -{ -#if QT_CONFIG(xkbcommon) - QString text; - uint utf32 = xkb_keysym_to_utf32(keysym); - if (utf32) - text = QString::fromUcs4(&utf32, 1); - - int code = 0; - - if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) { - code = Qt::Key_F1 + (int(keysym) - XKB_KEY_F1); - } else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) { - if (keysym >= XKB_KEY_KP_0) { - // numeric keypad keys - code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0); - } else { - code = lookupKeysym(keysym); - } - modifiers |= Qt::KeypadModifier; - } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f - && text.unicode()->unicode() != 0x7f - && !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_currency)) { - code = text.unicode()->toUpper().unicode(); - } else { - // any other keys - code = lookupKeysym(keysym); - } - - // Map control + letter to proper text - if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { - utf32 &= ~0x60; - text = QString::fromUcs4(&utf32, 1); - } - - return { code, text }; -#else - Q_UNUSED(modifiers) - return { keysym, "" }; -#endif -} - -Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state) -{ -#if QT_CONFIG(xkbcommon) - Qt::KeyboardModifiers modifiers = Qt::NoModifier; - - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_EFFECTIVE)) - modifiers |= Qt::ShiftModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE)) - modifiers |= Qt::ControlModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE)) - modifiers |= Qt::AltModifier; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE)) - modifiers |= Qt::MetaModifier; - - return modifiers; -#else - Q_UNUSED(state) - return Qt::NoModifier; -#endif -} - -QEvent::Type QWaylandXkb::toQtEventType(uint32_t state) -{ - return state != 0 ? QEvent::KeyPress : QEvent::KeyRelease; -} - -QVector QWaylandXkb::toKeysym(QKeyEvent *event) -{ -#if QT_CONFIG(xkbcommon) - QVector keysyms; - if (event->key() >= Qt::Key_F1 && event->key() <= Qt::Key_F35) { - keysyms.append(XKB_KEY_F1 + (event->key() - Qt::Key_F1)); - } else if (event->modifiers() & Qt::KeypadModifier) { - if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) - keysyms.append(XKB_KEY_KP_0 + (event->key() - Qt::Key_0)); - else - keysyms.append(toKeysymFromTable(event->key())); - } else if (!event->text().isEmpty()) { - // From libxkbcommon keysym-utf.c: - // "We allow to represent any UCS character in the range U-00000000 to - // U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff." - foreach (uint utf32, event->text().toUcs4()) { - keysyms.append(utf32 | 0x01000000); - } - } else { - keysyms.append(toKeysymFromTable(event->key())); - } - return keysyms; -#else - return QVector() << event->nativeScanCode(); -#endif -} - -QT_END_NAMESPACE diff --git a/src/shared/qwaylandxkb_p.h b/src/shared/qwaylandxkb_p.h deleted file mode 100644 index 4820d94be..000000000 --- a/src/shared/qwaylandxkb_p.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Jolla 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWAYLANDXKB_H -#define QWAYLANDXKB_H - -#include -#include -#include - -#if QT_CONFIG(xkbcommon) -#include -#else -typedef quint32 xkb_keysym_t; -struct xkb_state; -#endif - -#include - -QT_BEGIN_NAMESPACE - -class QKeyEvent; - -class QWaylandXkb -{ -public: - static std::pair keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers); - static Qt::KeyboardModifiers modifiers(struct xkb_state *state); - - static QEvent::Type toQtEventType(uint32_t state); - static QVector toKeysym(QKeyEvent *event); -}; - -QT_END_NAMESPACE - -#endif -- cgit v1.2.3 From f533c767b2b5955ae8f242da7c8c11ad18ba0181 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 24 Jan 2019 13:49:10 +0100 Subject: remove useless indirection The function name also was not the best :) Change-Id: Iee853a77ac0ad210f2dff70b55df2ba534fd355b Reviewed-by: Johan Helsing --- src/compositor/compositor_api/qwaylandkeyboard.cpp | 13 ++++--------- src/compositor/compositor_api/qwaylandkeyboard_p.h | 2 -- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index ffe536ce3..2302c0b6a 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -180,14 +180,6 @@ void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state) send_key(focusResource->handle, 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); - } -} - #if QT_CONFIG(xkbcommon) void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable() { @@ -238,7 +230,10 @@ void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state) this->modsLocked = modsLocked; this->group = group; - modifiers(compositor()->nextSerial(), modsDepressed, modsLatched, modsLocked, group); + if (focusResource) { + send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed, + modsLatched, modsLocked, group); + } #else Q_UNUSED(code); Q_UNUSED(state); diff --git a/src/compositor/compositor_api/qwaylandkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h index fb3f5fe34..4dfe0035e 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard_p.h +++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h @@ -85,8 +85,6 @@ public: QWaylandCompositor *compositor() const { return seat->compositor(); } void focused(QWaylandSurface* surface); - void modifiers(uint32_t serial, uint32_t mods_depressed, - uint32_t mods_latched, uint32_t mods_locked, uint32_t group); #if QT_CONFIG(xkbcommon) struct xkb_state *xkbState() const { return mXkbState.get(); } -- cgit v1.2.3 From 16e34eed8b58fe837167af00582cec48cb59484d Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 28 Feb 2019 13:59:19 +0100 Subject: Doc: Fix minor link issues Change-Id: I42bca2a6d5a687217c3dde9bd80394bc95e361f8 Reviewed-by: Johan Helsing --- src/compositor/compositor_api/qwaylandquickitem.cpp | 1 - src/compositor/compositor_api/qwaylandsurface.cpp | 4 +--- src/compositor/extensions/qwaylandshellsurface.cpp | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 69c0a31a3..7b0d5c5d5 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -833,7 +833,6 @@ void QWaylandQuickItem::setOutput(QWaylandOutput *output) * * The default is false. */ - /*! * \property QWaylandQuickItem::bufferLocked * diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index cd78166dc..c79787e6e 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -450,9 +450,7 @@ QWaylandClient *QWaylandSurface::client() const } /*! - * \property QWaylandSurface::waylandClient - * - * This property holds the \c wl_client using this QWaylandSurface. + * Holds the \c wl_client using this QWaylandSurface. */ ::wl_client *QWaylandSurface::waylandClient() const { diff --git a/src/compositor/extensions/qwaylandshellsurface.cpp b/src/compositor/extensions/qwaylandshellsurface.cpp index 3cfe44895..cb6d03646 100644 --- a/src/compositor/extensions/qwaylandshellsurface.cpp +++ b/src/compositor/extensions/qwaylandshellsurface.cpp @@ -87,7 +87,7 @@ */ /*! - * \property QWaylandWlShellSurface::windowType + * \property QWaylandShellSurface::windowType * * This property holds the window type of the QWaylandShellSurface. */ -- cgit v1.2.3 From 1beb8bda6fcaf1698c1e43f8df2d623d8ea46614 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 23 Apr 2019 09:53:32 +0200 Subject: Remove wayland-egl as dependency of linux-dmabuf-unstable-v1 Fixes Project ERROR: Library 'wayland-egl' is not defined. in linux-dmabuf-unstable-v1.pri Change-Id: I8a618c7cfb61340ea21535757daacb9141863f72 Reviewed-by: Johan Helsing --- .../compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri index 77f6d9410..a7630040e 100644 --- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri +++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linux-dmabuf-unstable-v1.pri @@ -1,6 +1,6 @@ INCLUDEPATH += $$PWD -QMAKE_USE_PRIVATE += egl wayland-server wayland-egl +QMAKE_USE_PRIVATE += egl wayland-server CONFIG += wayland-scanner WAYLANDSERVERSOURCES += $$PWD/../../../3rdparty/protocol/linux-dmabuf-unstable-v1.xml -- cgit v1.2.3 From 9ff83e63ddb23de7deb7a866269733739151ae2f Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 17 Apr 2019 11:43:33 +0200 Subject: Remove tst_WaylandCompositor::keyboardGrab from blacklist It's not clear to me why it was failing in CI on Ubuntu 14.04 back in 2015. I can't get it to fail on my machine, and the linked logs in the bug report are no longer available. Let's try to remove the blacklist and fix it if it starts failing again. Fixes: QTBUG-45108 Change-Id: I7a73bdbcee2e544480af71db135ecd73122f747c Reviewed-by: Gatis Paeglis --- tests/auto/compositor/compositor/BLACKLIST | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 tests/auto/compositor/compositor/BLACKLIST diff --git a/tests/auto/compositor/compositor/BLACKLIST b/tests/auto/compositor/compositor/BLACKLIST deleted file mode 100644 index df4672be3..000000000 --- a/tests/auto/compositor/compositor/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[keyboardGrab] -ubuntu-14.04 -- cgit v1.2.3 From 475910a75a5cd3332fe2f0e5740c4c3c2c0b8987 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 16 Jan 2019 10:36:52 +0100 Subject: Client: Fix reverse screen order [ChangeLog][QPA plugin] Fixed a bug where QGuiApplication::screens() and primaryScreen() would return initial screens in the reverse order they were added by the compositor. QGuiApplication::primaryScreen() will now return the first output added by the compositor. Calling forceRoundTrip in registry_global() meant it would call itself recursively if there were additional wl_output events in the queue. This in turn meant the screens got added in the reverse order. Instead we now add the screen to a list of not yet initialized screens and add it properly when we've received the required done events (wl_output and possibly zdg_output_v1). This also has the added benefit of wl_output hot plugging not calling forceRoundTrip(). Fixes: QTBUG-72828 Change-Id: I35c6959d6c219f65fd19d571a25b5a6cdb3f741b Reviewed-by: Gatis Paeglis --- src/client/qwaylanddisplay.cpp | 30 +++++++++++++++---- src/client/qwaylanddisplay_p.h | 2 ++ src/client/qwaylandscreen.cpp | 52 ++++++++++++++++++++++++++++++--- src/client/qwaylandscreen_p.h | 7 +++++ tests/auto/client/output/tst_output.cpp | 3 -- 5 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 43401325a..eccc382bd 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -148,6 +148,11 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) #endif forceRoundTrip(); + + if (!mWaitingScreens.isEmpty()) { + // Give wl_output.done and zxdg_output_v1.done events a chance to arrive + forceRoundTrip(); + } } QWaylandDisplay::~QWaylandDisplay(void) @@ -162,6 +167,7 @@ QWaylandDisplay::~QWaylandDisplay(void) QWindowSystemInterface::handleScreenRemoved(screen); } mScreens.clear(); + qDeleteAll(mWaitingScreens); #if QT_CONFIG(wayland_datadevice) delete mDndSelectionHandler.take(); @@ -222,6 +228,14 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const return nullptr; } +void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen) +{ + if (!mWaitingScreens.removeOne(screen)) + return; + mScreens.append(screen); + QWindowSystemInterface::handleScreenAdded(screen); +} + void QWaylandDisplay::waitForScreens() { flushRequests(); @@ -246,11 +260,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin struct ::wl_registry *registry = object(); if (interface == QStringLiteral("wl_output")) { - QWaylandScreen *screen = new QWaylandScreen(this, version, id); - mScreens.append(screen); - // We need to get the output events before creating surfaces - forceRoundTrip(); - QWindowSystemInterface::handleScreenAdded(screen); + mWaitingScreens << new QWaylandScreen(this, version, id); } else if (interface == QStringLiteral("wl_compositor")) { mCompositorVersion = qMin((int)version, 3); mCompositor.init(registry, id, mCompositorVersion); @@ -286,7 +296,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin } } else if (interface == QLatin1String("zxdg_output_manager_v1")) { mXdgOutputManager.reset(new QtWayland::zxdg_output_manager_v1(registry, id, qMin(2, int(version)))); - for (auto *screen : qAsConst(mScreens)) + for (auto *screen : qAsConst(mWaitingScreens)) screen->initXdgOutput(xdgOutputManager()); forceRoundTrip(); } @@ -303,6 +313,14 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) RegistryGlobal &global = mGlobals[i]; if (global.id == id) { if (global.interface == QStringLiteral("wl_output")) { + for (auto *screen : mWaitingScreens) { + if (screen->outputId() == id) { + mWaitingScreens.removeOne(screen); + delete screen; + break; + } + } + foreach (QWaylandScreen *screen, mScreens) { if (screen->outputId() == id) { mScreens.removeOne(screen); diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 2d5832d8d..f4b3c26c5 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -122,6 +122,7 @@ public: QList screens() const { return mScreens; } QWaylandScreen *screenForOutput(struct wl_output *output) const; + void handleScreenInitialized(QWaylandScreen *screen); struct wl_surface *createSurface(void *handle); struct ::wl_region *createRegion(const QRegion &qregion); @@ -216,6 +217,7 @@ private: struct wl_display *mDisplay = nullptr; QtWayland::wl_compositor mCompositor; QScopedPointer mShm; + QList mWaitingScreens; QList mScreens; QList mInputDevices; QList mRegistryListeners; diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp index b2e3ce819..5b04ae609 100644 --- a/src/client/qwaylandscreen.cpp +++ b/src/client/qwaylandscreen.cpp @@ -40,6 +40,7 @@ #include "qwaylandscreen_p.h" #include "qwaylanddisplay_p.h" +#include "qwaylandintegration_p.h" #include "qwaylandcursor_p.h" #include "qwaylandwindow_p.h" @@ -60,6 +61,14 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin { if (auto *xdgOutputManager = waylandDisplay->xdgOutputManager()) initXdgOutput(xdgOutputManager); + + if (version < WL_OUTPUT_DONE_SINCE_VERSION) { + qCWarning(lcQpaWayland) << "wl_output done event not supported by compositor," + << "QScreen may not work correctly"; + mWaylandDisplay->forceRoundTrip(); // Give the compositor a chance to send geometry etc. + mOutputDone = true; // Fake the done event + maybeInitialize(); + } } QWaylandScreen::~QWaylandScreen() @@ -68,6 +77,24 @@ QWaylandScreen::~QWaylandScreen() zxdg_output_v1::destroy(); } +void QWaylandScreen::maybeInitialize() +{ + Q_ASSERT(!mInitialized); + + if (!mOutputDone) + return; + + if (mWaylandDisplay->xdgOutputManager() && !mXdgOutputDone) + return; + + mInitialized = true; + mWaylandDisplay->handleScreenInitialized(this); + + updateOutputProperties(); + if (zxdg_output_v1::isInitialized()) + updateXdgOutputProperties(); +} + void QWaylandScreen::initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager) { Q_ASSERT(xdgOutputManager); @@ -232,10 +259,15 @@ void QWaylandScreen::output_scale(int32_t factor) void QWaylandScreen::output_done() { - // the done event is sent after all the geometry and the mode events are sent, - // and the last mode event to be sent is the active one, so we can trust the - // values of mGeometry and mRefreshRate here + mOutputDone = true; + if (mInitialized) + updateOutputProperties(); + else + maybeInitialize(); +} +void QWaylandScreen::updateOutputProperties() +{ if (mTransform >= 0) { bool isPortrait = mGeometry.height() > mGeometry.width(); switch (mTransform) { @@ -262,7 +294,9 @@ void QWaylandScreen::output_done() QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); mTransform = -1; } + QWindowSystemInterface::handleScreenRefreshRateChange(screen(), refreshRate()); + if (!zxdg_output_v1::isInitialized()) QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry()); } @@ -280,7 +314,11 @@ void QWaylandScreen::zxdg_output_v1_logical_size(int32_t width, int32_t height) void QWaylandScreen::zxdg_output_v1_done() { - QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry()); + mXdgOutputDone = true; + if (mInitialized) + updateXdgOutputProperties(); + else + maybeInitialize(); } void QWaylandScreen::zxdg_output_v1_name(const QString &name) @@ -288,6 +326,12 @@ void QWaylandScreen::zxdg_output_v1_name(const QString &name) mOutputName = name; } +void QWaylandScreen::updateXdgOutputProperties() +{ + Q_ASSERT(zxdg_output_v1::isInitialized()); + QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), geometry()); +} + } // namespace QtWaylandClient QT_END_NAMESPACE diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h index 4ef58c0c1..e9e07d9cd 100644 --- a/src/client/qwaylandscreen_p.h +++ b/src/client/qwaylandscreen_p.h @@ -71,6 +71,8 @@ public: QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id); ~QWaylandScreen() override; + void maybeInitialize(); + void initXdgOutput(QtWayland::zxdg_output_manager_v1 *xdgOutputManager); QWaylandDisplay *display() const; @@ -116,12 +118,14 @@ private: int32_t transform) override; void output_scale(int32_t factor) override; void output_done() override; + void updateOutputProperties(); // XdgOutput void zxdg_output_v1_logical_position(int32_t x, int32_t y) override; void zxdg_output_v1_logical_size(int32_t width, int32_t height) override; void zxdg_output_v1_done() override; void zxdg_output_v1_name(const QString &name) override; + void updateXdgOutputProperties(); int m_outputId; QWaylandDisplay *mWaylandDisplay = nullptr; @@ -137,6 +141,9 @@ private: QSize mPhysicalSize; QString mOutputName; Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; + bool mOutputDone = false; + bool mXdgOutputDone = false; + bool mInitialized = false; #if QT_CONFIG(cursor) QScopedPointer mWaylandCursor; diff --git a/tests/auto/client/output/tst_output.cpp b/tests/auto/client/output/tst_output.cpp index 451679481..2d2c8efd6 100644 --- a/tests/auto/client/output/tst_output.cpp +++ b/tests/auto/client/output/tst_output.cpp @@ -215,10 +215,7 @@ void tst_output::screenOrder() QTRY_COMPARE(QGuiApplication::screens().size(), 3); const auto screens = QGuiApplication::screens(); - QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue); QCOMPARE(screens[1]->model(), "Screen 1"); - - QEXPECT_FAIL(nullptr, "TODO: fix screen order", Continue); QCOMPARE(screens[2]->model(), "Screen 2"); exec([=] { -- cgit v1.2.3 From c1b65146f6b9ad98edea424742f7594712758377 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 25 Apr 2019 16:21:51 +0200 Subject: Docs: Fix incorrect version for module import This fixes an issue with the XdgShell documentation where the import statement at the top was too low (1.1 instead of 1.3) Later we should make it automatically follow the Qt minor version (see QTBUG-74042). Fixes: QTBUG-73256 Change-Id: Ib280998fe9c65168854e517b8555c5cd9b17cdd7 Reviewed-by: Paul Olav Tvete --- src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc index 1dadb7102..454fc3711 100644 --- a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc +++ b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \qmlmodule QtWayland.Compositor 1.1 + \qmlmodule QtWayland.Compositor 1.3 \title Qt Wayland Compositor QML Types \ingroup qmlmodules \brief Provides QML types for writing custom Wayland display servers. @@ -38,7 +38,7 @@ import statement: \code - import QtWayland.Compositor 1.1 + import QtWayland.Compositor 1.3 \endcode To link against the module, add this line to your \l qmake \c .pro file: -- cgit v1.2.3 From 8b69d52db792c3910be53321df44b5c57baa694c Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 17 Apr 2019 12:51:56 +0200 Subject: Make QtWayland.Compositor available under 1.QT_MINOR_VERSION It was already available under 1.13, but this ensures it will stay available for future minor versions of Qt and also use the latest minor version in the examples. Fixes: QTBUG-74042 Change-Id: I4a6a4f762ed0af565af32931971a1df7f33a3ba1 Reviewed-by: Paul Olav Tvete --- src/compositor/compositor_api/qwaylandquickcompositor.cpp | 6 +++--- src/compositor/extensions/qwaylandiviapplication.cpp | 7 ++++--- src/compositor/extensions/qwaylandwlscaler.cpp | 6 +++--- src/compositor/extensions/qwaylandwlshell.cpp | 7 ++++--- src/compositor/extensions/qwaylandxdgdecorationv1.cpp | 6 +++--- src/compositor/extensions/qwaylandxdgshell.cpp | 7 ++++--- src/compositor/extensions/qwaylandxdgshellv5.cpp | 8 +++++--- src/compositor/extensions/qwaylandxdgshellv6.cpp | 7 ++++--- src/imports/compositor/qwaylandquickcompositorplugin.cpp | 4 ++++ 9 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp index 426008a60..14b592efb 100644 --- a/src/compositor/compositor_api/qwaylandquickcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp @@ -90,15 +90,15 @@ QWaylandQuickCompositor::QWaylandQuickCompositor(QObject *parent) * For instance, the following code would allow the clients to request \c wl_shell * surfaces in the compositor using the \c wl_shell interface. * - * \code - * import QtWayland.Compositor 1.0 + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * WlShell { * // ... * } * } - * \endcode + * \endqml */ void QWaylandQuickCompositor::create() diff --git a/src/compositor/extensions/qwaylandiviapplication.cpp b/src/compositor/extensions/qwaylandiviapplication.cpp index 36690341f..a2e9842db 100644 --- a/src/compositor/extensions/qwaylandiviapplication.cpp +++ b/src/compositor/extensions/qwaylandiviapplication.cpp @@ -62,8 +62,9 @@ QT_BEGIN_NAMESPACE * To provide the functionality of the shell extension in a compositor, create * an instance of the IviApplication component and add it to the list of extensions * supported by the compositor: - * \code - * import QtWayland.Compositor 1.0 + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * IviApplication { @@ -74,7 +75,7 @@ QT_BEGIN_NAMESPACE * } * } * } - * \endcode + * \endqml */ /*! diff --git a/src/compositor/extensions/qwaylandwlscaler.cpp b/src/compositor/extensions/qwaylandwlscaler.cpp index e097ea3c5..5c8e4b270 100644 --- a/src/compositor/extensions/qwaylandwlscaler.cpp +++ b/src/compositor/extensions/qwaylandwlscaler.cpp @@ -61,14 +61,14 @@ QT_BEGIN_NAMESPACE To provide the functionality of the extension in a compositor, create an instance of the WlScaler component and add it to the list of extensions supported by the compositor: - \code - import QtWayland.Compositor 1.13 + \qml \QtMinorVersion + import QtWayland.Compositor 1.\1 WaylandCompositor { // ... WlScaler {} } - \endcode + \endqml \deprecated */ diff --git a/src/compositor/extensions/qwaylandwlshell.cpp b/src/compositor/extensions/qwaylandwlshell.cpp index 3f6734632..9871a8a5a 100644 --- a/src/compositor/extensions/qwaylandwlshell.cpp +++ b/src/compositor/extensions/qwaylandwlshell.cpp @@ -267,15 +267,16 @@ void QWaylandWlShellSurfacePrivate::shell_surface_set_class(Resource *resource, * To provide the functionality of the shell extension in a compositor, create * an instance of the WlShell component and add it to the list of extensions * supported by the compositor: - * \code - * import QtWayland.Compositor 1.0 + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * WlShell { * // ... * } * } - * \endcode + * \endqml */ /*! diff --git a/src/compositor/extensions/qwaylandxdgdecorationv1.cpp b/src/compositor/extensions/qwaylandxdgdecorationv1.cpp index 89c56acd9..2d283ddf9 100644 --- a/src/compositor/extensions/qwaylandxdgdecorationv1.cpp +++ b/src/compositor/extensions/qwaylandxdgdecorationv1.cpp @@ -59,8 +59,8 @@ QT_BEGIN_NAMESPACE To provide the functionality of the extension in a compositor, create an instance of the XdgDecorationManagerV1 component and add it to the list of extensions supported by the compositor: - \code - import QtWayland.Compositor 1.3 + \qml \QtMinorVersion + import QtWayland.Compositor 1.\1 WaylandCompositor { // Xdg decoration manager assumes xdg-shell is being used @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE preferredMode: XdgToplevel.ServerSideDecoration } } - \endcode + \endqml \sa XdgToplevel::decorationMode */ diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp index 560f95acd..eb7b958b4 100644 --- a/src/compositor/extensions/qwaylandxdgshell.cpp +++ b/src/compositor/extensions/qwaylandxdgshell.cpp @@ -154,15 +154,16 @@ void QWaylandXdgShellPrivate::xdg_wm_base_pong(Resource *resource, uint32_t seri * To provide the functionality of the shell extension in a compositor, create * an instance of the XdgShell component and add it to the list of extensions * supported by the compositor: - * \code - * import QtWayland.Compositor 1.3 + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * XdgShell { * // ... * } * } - * \endcode + * \endqml */ /*! diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp index 9e157a8a3..0628f55e7 100644 --- a/src/compositor/extensions/qwaylandxdgshellv5.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp @@ -513,15 +513,17 @@ void QWaylandXdgPopupV5Private::xdg_popup_destroy(Resource *resource) * * To provide the functionality of the shell extension in a compositor, create * an instance of the XdgShellV5 component and add it as a child of the - * compositor: \code - * import QtWayland.Compositor 1.0 + * compositor: + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * XdgShellV5 { * // ... * } * } - * \endcode + * \endqml * * \deprecated */ diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp index d69ed6ca9..f971fe5b4 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp @@ -159,15 +159,16 @@ void QWaylandXdgShellV6Private::zxdg_shell_v6_pong(Resource *resource, uint32_t * To provide the functionality of the shell extension in a compositor, create * an instance of the XdgShellV6 component and add it to the list of extensions * supported by the compositor: - * \code - * import QtWayland.Compositor 1.1 + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 * * WaylandCompositor { * XdgShellV6 { * // ... * } * } - * \endcode + * \endqml */ /*! diff --git a/src/imports/compositor/qwaylandquickcompositorplugin.cpp b/src/imports/compositor/qwaylandquickcompositorplugin.cpp index df7536ed1..c7553d932 100644 --- a/src/imports/compositor/qwaylandquickcompositorplugin.cpp +++ b/src/imports/compositor/qwaylandquickcompositorplugin.cpp @@ -130,6 +130,10 @@ public: static void defineModule(const char *uri) { + // This is needed so to guarantee that the import is available with the current + // Qt minor version even if no new types have been added since the last release. + qmlRegisterModule(uri, 1, QT_VERSION_MINOR); + qmlRegisterType(uri, 1, 0, "WaylandCompositor"); qmlRegisterType(uri, 1, 0, "WaylandQuickItem"); qmlRegisterType(uri, 1, 13, "WaylandQuickItem"); -- cgit v1.2.3 From 812ca6b0cf31ac424bb23a63a47a4771c9b71fc1 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sun, 10 Feb 2019 14:22:59 +0100 Subject: client: reimplement QPlatformIntegration::possibleKeys() This is required to trigger more complex shortcut sequences. For example, with 'us' keyboard layout to enter '%' or '+' you have to press 'Shift' button. Previosly the following shortcuts could not be triggered: 'Shift' + '5' '%' 'Ctrl' + '+' 'Ctrl' + 'Shift' + '=' The same function also ensures that these shortcuts work with non-latin keyboard layouts. Change-Id: Id50c7bb28cf76b9f7a861ced7894b2cacae6ed65 Reviewed-by: David Edmundson Reviewed-by: Gatis Paeglis Reviewed-by: Johan Helsing --- src/client/qwaylandinputdevice.cpp | 11 +++++++++++ src/client/qwaylandinputdevice_p.h | 3 +++ src/client/qwaylandintegration.cpp | 7 +++++++ src/client/qwaylandintegration_p.h | 2 ++ 4 files changed, 23 insertions(+) diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 17c408a3d..39c02d962 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -476,6 +476,17 @@ QPointF QWaylandInputDevice::pointerSurfacePosition() const return mPointer ? mPointer->mSurfacePos : QPointF(); } +QList QWaylandInputDevice::possibleKeys(const QKeyEvent *event) const +{ +#if QT_CONFIG(xkbcommon) + if (mKeyboard && mKeyboard->mXkbState) + return QXkbCommon::possibleKeys(mKeyboard->mXkbState.get(), event); +#else + Q_UNUSED(event); +#endif + return {}; +} + Qt::KeyboardModifiers QWaylandInputDevice::modifiers() const { if (!mKeyboard) diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 2dc3ddc27..39ca9dca5 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -124,6 +124,8 @@ public: QWaylandWindow *keyboardFocus() const; QWaylandWindow *touchFocus() const; + QList possibleKeys(const QKeyEvent *event) const; + QPointF pointerSurfacePosition() const; Qt::KeyboardModifiers modifiers() const; @@ -245,6 +247,7 @@ private: QXkbCommon::ScopedXKBKeymap mXkbKeymap; QXkbCommon::ScopedXKBState mXkbState; #endif + friend class QWaylandInputDevice; }; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index 3a389d9ec..ea2b50b4a 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -293,6 +293,13 @@ QWaylandDisplay *QWaylandIntegration::display() const return mDisplay.data(); } +QList QWaylandIntegration::possibleKeys(const QKeyEvent *event) const +{ + if (auto *seat = mDisplay->currentInputDevice()) + return seat->possibleKeys(event); + return {}; +} + QStringList QWaylandIntegration::themeNames() const { return GenericWaylandTheme::themeNames(); diff --git a/src/client/qwaylandintegration_p.h b/src/client/qwaylandintegration_p.h index 5e6f16d09..3aef2c4d9 100644 --- a/src/client/qwaylandintegration_p.h +++ b/src/client/qwaylandintegration_p.h @@ -106,6 +106,8 @@ public: QWaylandDisplay *display() const; + QList possibleKeys(const QKeyEvent *event) const override; + QStringList themeNames() const override; QPlatformTheme *createPlatformTheme(const QString &name) const override; -- cgit v1.2.3 From a658a10f6a42e67bd762f87851c23cc1c1e3b141 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 6 May 2019 13:24:09 +0200 Subject: Make QML module documentation follow Qt minor version In 8b69d52d I forgot to also check for import statements in the .qdoc files. Task-number: QTBUG-74042 Change-Id: I385bbab50b3ffdee174f0542b3692d21ef57e08f Reviewed-by: Paul Olav Tvete --- src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc index 454fc3711..a89e07d78 100644 --- a/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc +++ b/src/compositor/doc/src/qtwaylandcompositor-qmltypes.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \qmlmodule QtWayland.Compositor 1.3 + \qmlmodule QtWayland.Compositor 1.\QtMinorVersion \title Qt Wayland Compositor QML Types \ingroup qmlmodules \brief Provides QML types for writing custom Wayland display servers. @@ -37,15 +37,15 @@ The QML types can be imported into your application using the following import statement: - \code - import QtWayland.Compositor 1.3 + \qml \QtMinorVersion + import QtWayland.Compositor 1.\1 \endcode To link against the module, add this line to your \l qmake \c .pro file: \code QT += waylandcompositor - \endcode + \endqml For more information about using these types in your application, see the \l{Qt Wayland Compositor} documentation. -- cgit v1.2.3