From f213a7d54e3e9e67f8ad4dd5b3775e0c4469e81a Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Mon, 27 Jun 2016 11:17:57 +0200 Subject: [PATCH 1/4] Fix the key code of key events when control is pressed Change-Id: I51a57a32d8263e663a48dac15881d685359bc91d Reviewed-by: Jan Arne Petersen Reviewed-by: Pier Luigi Fiorini --- .../wayland/qwaylandinputcontext.cpp | 5 +-- .../platforms/wayland/qwaylandinputdevice.cpp | 3 +- .../platforms/wayland/shared/qwaylandxkb.cpp | 31 ++++++++----------- .../platforms/wayland/shared/qwaylandxkb_p.h | 5 +-- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp index 509965d2f1a..5a58d6d7509 100644 --- a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp @@ -335,8 +335,9 @@ 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); - const QString &text = QWaylandXkb::textFromKeysym(sym, qtModifiers); - int qtkey = QWaylandXkb::keysymToQtKey(sym, qtModifiers, text); + QString text; + int qtkey; + std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, qtModifiers); QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), time, type, qtkey, qtModifiers, text); diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 613d517a3f0..13ab5efe6bf 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -707,8 +707,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, Qt::KeyboardModifiers modifiers = mParent->modifiers(); - text = QWaylandXkb::textFromKeysym(sym, modifiers); - qtkey = QWaylandXkb::keysymToQtKey(sym, modifiers, text); + std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); #else diff --git a/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp b/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp index 499257009cf..2afdcce8a05 100644 --- a/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp +++ b/src/plugins/platforms/wayland/shared/qwaylandxkb.cpp @@ -293,8 +293,13 @@ static xkb_keysym_t toKeysymFromTable(uint32_t key) return 0; } -int QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text) +std::pair QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers) { + 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) { @@ -316,7 +321,13 @@ int QWaylandXkb::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modif code = lookupKeysym(keysym); } - return code; + // Map control + letter to proper text + if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { + utf32 &= ~0x60; + text = QString::fromUcs4(&utf32, 1); + } + + return { code, text }; } Qt::KeyboardModifiers QWaylandXkb::modifiers(struct xkb_state *state) @@ -342,22 +353,6 @@ QEvent::Type QWaylandXkb::toQtEventType(uint32_t state) return state != 0 ? QEvent::KeyPress : QEvent::KeyRelease; } -QString QWaylandXkb::textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers) -{ - uint utf32 = xkb_keysym_to_utf32(keysym); - - // Map control + letter to proper text - if (utf32 >= 'A' && utf32 <= '~' && (modifiers & Qt::ControlModifier)) { - utf32 &= ~0x60; - return QString::fromUcs4(&utf32, 1); - } - - if (utf32) - return QString::fromUcs4(&utf32, 1); - - return QString(); -} - QVector QWaylandXkb::toKeysym(QKeyEvent *event) { QVector keysyms; diff --git a/src/plugins/platforms/wayland/shared/qwaylandxkb_p.h b/src/plugins/platforms/wayland/shared/qwaylandxkb_p.h index 9b5c935a5b5..cdebf1b08b0 100644 --- a/src/plugins/platforms/wayland/shared/qwaylandxkb_p.h +++ b/src/plugins/platforms/wayland/shared/qwaylandxkb_p.h @@ -47,6 +47,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QKeyEvent; @@ -54,11 +56,10 @@ class QKeyEvent; class QWaylandXkb { public: - static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, const QString &text); + 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 QString textFromKeysym(uint32_t keysym, Qt::KeyboardModifiers modifiers); static QVector toKeysym(QKeyEvent *event); }; From d4d47f2a043f3e7548ba10c69fb54637511ba563 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 1 Jun 2016 16:23:23 +0200 Subject: [PATCH 2/4] Use xdg_shell configure events to determine active window According to the xdg_shell protocol, the compositor is allowed to set multiple active windows. Qt's model, however, allows only a single active window. In order to map between the models, a list of the compositor's active windows is kept in QWaylandDisplay in the order they were activated. Hence, the front of this list will always be the most recently activated window, and it will be mapped as Qt's active window. Previously keyboard focus was used to determine the active window, this method has been disabled for xdg_shell. Functionality for delaying the call to QWindowSystemInterface::handleWindowActivated has been moved from QWaylandInputDevice::Keyboard to QWaylandDisplay so the implementations can share the workaround. Task-number: QTBUG-53702 Change-Id: I878151f9c52ed09a8d6571c6208920436c3ca8fc Reviewed-by: Giulio Camuffo --- .../platforms/wayland/qwaylanddisplay.cpp | 69 +++++++++++++++++++ .../platforms/wayland/qwaylanddisplay_p.h | 13 ++++ .../platforms/wayland/qwaylandinputdevice.cpp | 34 +-------- .../platforms/wayland/qwaylandinputdevice_p.h | 4 -- .../platforms/wayland/qwaylandxdgsurface.cpp | 15 +++- .../platforms/wayland/qwaylandxdgsurface_p.h | 1 + 6 files changed, 100 insertions(+), 36 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 4358bf69f6c..f6d86bb39ed 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -130,6 +130,8 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) , mLastInputSerial(0) , mLastInputDevice(0) , mLastInputWindow(0) + , mLastKeyboardFocus(Q_NULLPTR) + , mSyncCallback(Q_NULLPTR) { qRegisterMetaType("uint32_t"); @@ -383,6 +385,73 @@ void QWaylandDisplay::setLastInputDevice(QWaylandInputDevice *device, uint32_t s mLastInputWindow = win; } +bool QWaylandDisplay::shellManagesActiveState() const +{ + //TODO: This should be part of a shell interface used by the shell protocol implementations + return mShellXdg; +} + +void QWaylandDisplay::handleWindowActivated(QWaylandWindow *window) +{ + if (mActiveWindows.contains(window)) + return; + + mActiveWindows.append(window); + requestWaylandSync(); +} + +void QWaylandDisplay::handleWindowDeactivated(QWaylandWindow *window) +{ + Q_ASSERT(!mActiveWindows.empty()); + + if (mActiveWindows.last() == window) + requestWaylandSync(); + + mActiveWindows.removeOne(window); +} + +void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice) +{ + QWaylandWindow *keyboardFocus = inputDevice->keyboardFocus(); + + if (!shellManagesActiveState() && mLastKeyboardFocus != keyboardFocus) { + if (keyboardFocus) + handleWindowActivated(keyboardFocus); + if (mLastKeyboardFocus) + handleWindowDeactivated(mLastKeyboardFocus); + } + mLastKeyboardFocus = inputDevice->keyboardFocus(); +} + +void QWaylandDisplay::handleWaylandSync() +{ + // This callback is used to set the window activation because we may get an activate/deactivate + // pair, and the latter one would be lost in the QWindowSystemInterface queue, if we issue the + // handleWindowActivated() calls immediately. + QWindow *activeWindow = mActiveWindows.empty() ? Q_NULLPTR : mActiveWindows.last()->window(); + if (activeWindow != QGuiApplication::focusWindow()) + QWindowSystemInterface::handleWindowActivated(activeWindow); +} + +const wl_callback_listener QWaylandDisplay::syncCallbackListener = { + [](void *data, struct wl_callback *callback, uint32_t time){ + Q_UNUSED(time); + wl_callback_destroy(callback); + QWaylandDisplay *display = static_cast(data); + display->mSyncCallback = Q_NULLPTR; + display->handleWaylandSync(); + } +}; + +void QWaylandDisplay::requestWaylandSync() +{ + if (mSyncCallback) + return; + + mSyncCallback = wl_display_sync(mDisplay); + wl_callback_add_listener(mSyncCallback, &syncCallbackListener, this); +} + } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h index adc012b53d8..237be5b783f 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -168,6 +169,11 @@ public: QWaylandWindow *lastInputWindow() const; void setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *window); + bool shellManagesActiveState() const; + void handleWindowActivated(QWaylandWindow *window); + void handleWindowDeactivated(QWaylandWindow *window); + void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice); + public slots: void blockingReadEvents(); void flushRequests(); @@ -177,6 +183,9 @@ private: void exitWithError(); void checkError() const; + void handleWaylandSync(); + void requestWaylandSync(); + struct Listener { RegistryListener listener; void *data; @@ -207,6 +216,10 @@ private: uint32_t mLastInputSerial; QWaylandInputDevice *mLastInputDevice; QPointer mLastInputWindow; + QWaylandWindow *mLastKeyboardFocus; + QVector mActiveWindows; + struct wl_callback *mSyncCallback; + static const wl_callback_listener syncCallbackListener; void registry_global(uint32_t id, const QString &interface, uint32_t version) Q_DECL_OVERRIDE; void registry_global_remove(uint32_t id) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index e2412eaa4a9..5eaed9ea151 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -69,7 +69,6 @@ QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) , mXkbMap(0) , mXkbState(0) #endif - , mFocusCallback(0) , mNativeModifiers(0) { connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); @@ -122,8 +121,6 @@ QWaylandInputDevice::Keyboard::~Keyboard() #endif if (mFocus) QWindowSystemInterface::handleWindowActivated(0); - if (mFocusCallback) - wl_callback_destroy(mFocusCallback); if (mParent->mVersion >= 3) wl_keyboard_release(object()); else @@ -591,10 +588,7 @@ void QWaylandInputDevice::Keyboard::keyboard_enter(uint32_t time, struct wl_surf QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); mFocus = window; - if (!mFocusCallback) { - mFocusCallback = wl_display_sync(mParent->mDisplay); - wl_callback_add_listener(mFocusCallback, &QWaylandInputDevice::Keyboard::callback, this); - } + mParent->mQDisplay->handleKeyboardFocusChanged(mParent); } void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surface *surface) @@ -609,33 +603,11 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf mFocus = NULL; - // Use a callback to set the focus because we may get a leave/enter pair, and - // the latter one would be lost in the QWindowSystemInterface queue, if - // we issue the handleWindowActivated() calls immediately. - if (!mFocusCallback) { - mFocusCallback = wl_display_sync(mParent->mDisplay); - wl_callback_add_listener(mFocusCallback, &QWaylandInputDevice::Keyboard::callback, this); - } + mParent->mQDisplay->handleKeyboardFocusChanged(mParent); + mRepeatTimer.stop(); } -const wl_callback_listener QWaylandInputDevice::Keyboard::callback = { - QWaylandInputDevice::Keyboard::focusCallback -}; - -void QWaylandInputDevice::Keyboard::focusCallback(void *data, struct wl_callback *callback, uint32_t time) -{ - Q_UNUSED(time); - Q_UNUSED(callback); - QWaylandInputDevice::Keyboard *self = static_cast(data); - if (self->mFocusCallback) { - wl_callback_destroy(self->mFocusCallback); - self->mFocusCallback = 0; - } - - QWindowSystemInterface::handleWindowActivated(self->mFocus ? self->mFocus->window() : 0); -} - void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { QWaylandWindow *window = mFocus; diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h index 1df90292b50..e38ad2f8415 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h @@ -185,7 +185,6 @@ public: xkb_keymap *mXkbMap; xkb_state *mXkbState; #endif - struct wl_callback *mFocusCallback; uint32_t mNativeModifiers; int mRepeatKey; @@ -197,9 +196,6 @@ public: #endif QTimer mRepeatTimer; - static const wl_callback_listener callback; - static void focusCallback(void *data, struct wl_callback *callback, uint32_t time); - Qt::KeyboardModifiers modifiers() const; private slots: diff --git a/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp b/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp index 8852d2dfb81..bbda03dc3cc 100644 --- a/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp @@ -52,6 +52,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(struct ::xdg_surface *xdg_surface, QWayla , m_maximized(false) , m_minimized(false) , m_fullscreen(false) + , m_active(false) , m_extendedWindow(Q_NULLPTR) { if (window->display()->windowExtension()) @@ -60,6 +61,9 @@ QWaylandXdgSurface::QWaylandXdgSurface(struct ::xdg_surface *xdg_surface, QWayla QWaylandXdgSurface::~QWaylandXdgSurface() { + if (m_active) + window()->display()->handleWindowDeactivated(m_window); + xdg_surface_destroy(object()); delete m_extendedWindow; } @@ -176,6 +180,7 @@ void QWaylandXdgSurface::xdg_surface_configure(int32_t width, int32_t height, st size_t numStates = states->size / sizeof(uint32_t); bool aboutToMaximize = false; bool aboutToFullScreen = false; + bool aboutToActivate = false; for (size_t i = 0; i < numStates; i++) { switch (state[i]) { @@ -189,13 +194,21 @@ void QWaylandXdgSurface::xdg_surface_configure(int32_t width, int32_t height, st m_normalSize = QSize(width, height); break; case XDG_SURFACE_STATE_ACTIVATED: - // TODO: here about the missing window activation + aboutToActivate = true; break; default: break; } } + if (!m_active && aboutToActivate) { + m_active = true; + window()->display()->handleWindowActivated(m_window); + } else if (m_active && !aboutToActivate) { + m_active = false; + window()->display()->handleWindowDeactivated(m_window); + } + if (!m_fullscreen && aboutToFullScreen) { if (!m_maximized) m_normalSize = m_window->window()->frameGeometry().size(); diff --git a/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h b/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h index d4380d25fbb..e367980b7fc 100644 --- a/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h +++ b/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h @@ -106,6 +106,7 @@ private: bool m_maximized; bool m_minimized; bool m_fullscreen; + bool m_active; QSize m_normalSize; QMargins m_margins; QWaylandExtendedSurface *m_extendedWindow; From f4c3ad57b7a23086e4db17ad823d83fc5be791c2 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 8 Jul 2016 14:46:34 +0200 Subject: [PATCH 3/4] Fix high-DPI scaling of window decorations for shared memory buffers Change-Id: I6833ab86ffdb4e37dad5108baddb7a54cfb5e9fa Reviewed-by: Giulio Camuffo --- .../wayland/qwaylandshmbackingstore.cpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index 3bbe24c318c..5c93d2ba3d2 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -301,29 +301,37 @@ void QWaylandShmBackingStore::updateDecorations() QPainter decorationPainter(entireSurface()); decorationPainter.setCompositionMode(QPainter::CompositionMode_Source); QImage sourceImage = windowDecoration()->contentImage(); - QRect target; + + qreal dp = sourceImage.devicePixelRatio(); + int dpWidth = int(sourceImage.width() / dp); + int dpHeight = int(sourceImage.height() / dp); + QMatrix sourceMatrix; + sourceMatrix.scale(dp, dp); + QRect target; // needs to be in device independent pixels + //Top target.setX(0); target.setY(0); - target.setWidth(sourceImage.width()); + target.setWidth(dpWidth); target.setHeight(windowDecorationMargins().top()); - decorationPainter.drawImage(target, sourceImage, target); + decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target)); //Left target.setWidth(windowDecorationMargins().left()); - target.setHeight(sourceImage.height()); - decorationPainter.drawImage(target, sourceImage, target); + target.setHeight(dpHeight); + decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target)); //Right - target.setX(sourceImage.width() - windowDecorationMargins().right()); - decorationPainter.drawImage(target, sourceImage, target); + target.setX(dpWidth - windowDecorationMargins().right()); + target.setWidth(windowDecorationMargins().right()); + decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target)); //Bottom target.setX(0); - target.setY(sourceImage.height() - windowDecorationMargins().bottom()); - target.setWidth(sourceImage.width()); + target.setY(dpHeight - windowDecorationMargins().bottom()); + target.setWidth(dpWidth); target.setHeight(windowDecorationMargins().bottom()); - decorationPainter.drawImage(target, sourceImage, target); + decorationPainter.drawImage(target, sourceImage, sourceMatrix.mapRect(target)); } QWaylandAbstractDecoration *QWaylandShmBackingStore::windowDecoration() const From 84aec97c835752d0243266e97e2093ce84d0a685 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Mon, 11 Jul 2016 11:38:50 +0200 Subject: [PATCH 4/4] Fix clang compilation errors Adds missing overrides and removes a private header generated by wayland-scanner from the public API. Change-Id: I53fc3f8bacca41821f0531aae02ca2a5da758e13 Reviewed-by: Giulio Camuffo --- .../platforms/wayland/global/qwaylandclientextension.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/wayland/global/qwaylandclientextension.h b/src/plugins/platforms/wayland/global/qwaylandclientextension.h index 9ff45ea00d0..afb3f868fba 100644 --- a/src/plugins/platforms/wayland/global/qwaylandclientextension.h +++ b/src/plugins/platforms/wayland/global/qwaylandclientextension.h @@ -39,7 +39,9 @@ #include #include -#include + +struct wl_registry; + QT_BEGIN_NAMESPACE namespace QtWaylandClient {