diff --git a/src/plugins/platforms/wayland/global/qwaylandclientextension.h b/src/plugins/platforms/wayland/global/qwaylandclientextension.h index a39f32b7f29..d1610c271e3 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 { diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 9ed76d2ce1f..7b3ff7bbba7 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -137,6 +137,8 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) , mLastInputSerial(0) , mLastInputDevice(0) , mLastInputWindow(0) + , mLastKeyboardFocus(Q_NULLPTR) + , mSyncCallback(Q_NULLPTR) { qRegisterMetaType("uint32_t"); @@ -393,6 +395,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 1c0b46bfb3c..b040d69a017 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h @@ -54,6 +54,7 @@ #include #include #include +#include #include @@ -174,6 +175,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(); @@ -183,6 +189,9 @@ private: void exitWithError(); void checkError() const; + void handleWaylandSync(); + void requestWaylandSync(); + struct Listener { RegistryListener listener; void *data; @@ -213,6 +222,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/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..f490f07ffe5 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -78,7 +78,6 @@ QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) , mXkbMap(0) , mXkbState(0) #endif - , mFocusCallback(0) , mNativeModifiers(0) { connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); @@ -131,8 +130,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 @@ -614,10 +611,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) @@ -632,33 +626,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); -} - 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) @@ -707,8 +679,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/qwaylandinputdevice_p.h b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h index 3954328f1b5..ea685223d8d 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice_p.h +++ b/src/plugins/platforms/wayland/qwaylandinputdevice_p.h @@ -197,7 +197,6 @@ public: xkb_keymap *mXkbMap; xkb_state *mXkbState; #endif - struct wl_callback *mFocusCallback; uint32_t mNativeModifiers; int mRepeatKey; @@ -209,9 +208,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/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index ea1fe7baa97..13f823edf81 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -308,29 +308,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 diff --git a/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp b/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp index 69532b5145b..93263e0aa4e 100644 --- a/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandxdgsurface.cpp @@ -58,6 +58,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()) @@ -66,6 +67,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; } @@ -182,6 +186,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]) { @@ -195,13 +200,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 24eb86519cf..e98aa41e938 100644 --- a/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h +++ b/src/plugins/platforms/wayland/qwaylandxdgsurface_p.h @@ -112,6 +112,7 @@ private: bool m_maximized; bool m_minimized; bool m_fullscreen; + bool m_active; QSize m_normalSize; QMargins m_margins; QWaylandExtendedSurface *m_extendedWindow; 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); };