diff options
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/client.pro | 2 | ||||
-rw-r--r-- | src/client/configure.json | 12 | ||||
-rw-r--r-- | src/client/hardwareintegration/qwaylandserverbufferintegration_p.h | 3 | ||||
-rw-r--r-- | src/client/qwaylandcursor.cpp | 7 | ||||
-rw-r--r-- | src/client/qwaylandcursor_p.h | 2 | ||||
-rw-r--r-- | src/client/qwaylanddatadevice.cpp | 16 | ||||
-rw-r--r-- | src/client/qwaylanddisplay.cpp | 3 | ||||
-rw-r--r-- | src/client/qwaylanddisplay_p.h | 1 | ||||
-rw-r--r-- | src/client/qwaylandextendedsurface.cpp | 2 | ||||
-rw-r--r-- | src/client/qwaylandinputcontext.cpp | 8 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 462 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice_p.h | 87 | ||||
-rw-r--r-- | src/client/qwaylandnativeinterface.cpp | 2 | ||||
-rw-r--r-- | src/client/qwaylandqtkey.cpp | 6 | ||||
-rw-r--r-- | src/client/qwaylandscreen.cpp | 5 | ||||
-rw-r--r-- | src/client/qwaylandshmbackingstore.cpp | 13 | ||||
-rw-r--r-- | src/client/qwaylandsurface.cpp | 122 | ||||
-rw-r--r-- | src/client/qwaylandsurface_p.h | 97 | ||||
-rw-r--r-- | src/client/qwaylandtouch.cpp | 1 | ||||
-rw-r--r-- | src/client/qwaylandwindow.cpp | 170 | ||||
-rw-r--r-- | src/client/qwaylandwindow_p.h | 19 |
21 files changed, 792 insertions, 248 deletions
diff --git a/src/client/client.pro b/src/client/client.pro index db91bd691..ff9e845f1 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -46,6 +46,7 @@ SOURCES += qwaylandintegration.cpp \ qwaylandshellsurface.cpp \ qwaylandextendedsurface.cpp \ qwaylandsubsurface.cpp \ + qwaylandsurface.cpp \ qwaylandtouch.cpp \ qwaylandqtkey.cpp \ ../shared/qwaylandmimehelper.cpp \ @@ -70,6 +71,7 @@ HEADERS += qwaylandintegration_p.h \ qwaylandshellsurface_p.h \ qwaylandextendedsurface_p.h \ qwaylandsubsurface_p.h \ + qwaylandsurface_p.h \ qwaylandtouch_p.h \ qwaylandqtkey_p.h \ qwaylandabstractdecoration_p.h \ diff --git a/src/client/configure.json b/src/client/configure.json index 93c5d4e49..2ec87eb49 100644 --- a/src/client/configure.json +++ b/src/client/configure.json @@ -75,6 +75,11 @@ "type": "compile", "test": "dmabuf_server_buffer", "use": "egl" + }, + "vulkan-server-buffer": { + "label": "Vulkan Buffer Sharing", + "type": "compile", + "test": "vulkan_server_buffer" } }, @@ -153,6 +158,11 @@ "condition": "features.wayland-client && features.opengl && features.egl && tests.dmabuf-server-buffer", "output": [ "privateFeature" ] }, + "wayland-vulkan-server-buffer": { + "label": "Vulkan-based server buffer integration", + "condition": "features.wayland-client && features.opengl && features.egl && tests.vulkan-server-buffer", + "output": [ "privateFeature" ] + }, "wayland-shm-emulation-server-buffer": { "label": "Shm emulation server buffer integration", "condition": "features.wayland-client && features.opengl", @@ -179,6 +189,8 @@ "xcomposite-glx", "wayland-drm-egl-server-buffer", "wayland-libhybris-egl-server-buffer", + "wayland-dmabuf-server-buffer", + "wayland-vulkan-server-buffer", "wayland-shm-emulation-server-buffer" ] }, diff --git a/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h b/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h index 632429bef..6833efd0c 100644 --- a/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h +++ b/src/client/hardwareintegration/qwaylandserverbufferintegration_p.h @@ -70,7 +70,8 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandServerBuffer public: enum Format { RGBA32, - A8 + A8, + Custom }; QWaylandServerBuffer(); diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp index 8b2ed036d..165df7762 100644 --- a/src/client/qwaylandcursor.cpp +++ b/src/client/qwaylandcursor.cpp @@ -209,7 +209,7 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) return nullptr; } -struct wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape) +::wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation) { struct wl_cursor *waylandCursor = nullptr; @@ -227,8 +227,9 @@ struct wl_cursor_image *QWaylandCursorTheme::cursorImage(Qt::CursorShape shape) return nullptr; } - struct wl_cursor_image *image = waylandCursor->images[0]; - struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); + int frame = wl_cursor_frame(waylandCursor, millisecondsIntoAnimation); + ::wl_cursor_image *image = waylandCursor->images[frame]; + ::wl_buffer *buffer = wl_cursor_image_get_buffer(image); if (!buffer) { qCWarning(lcQpaWayland) << "Could not find buffer for cursor"; return nullptr; diff --git a/src/client/qwaylandcursor_p.h b/src/client/qwaylandcursor_p.h index 6c48fb628..a4605f3d2 100644 --- a/src/client/qwaylandcursor_p.h +++ b/src/client/qwaylandcursor_p.h @@ -75,7 +75,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandCursorTheme public: static QWaylandCursorTheme *create(QWaylandShm *shm, int size, const QString &themeName); ~QWaylandCursorTheme(); - struct wl_cursor_image *cursorImage(Qt::CursorShape shape); + ::wl_cursor_image *cursorImage(Qt::CursorShape shape, uint millisecondsIntoAnimation = 0); private: enum WaylandCursor { diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp index 300c9de0a..9dbef8d5b 100644 --- a/src/client/qwaylanddatadevice.cpp +++ b/src/client/qwaylanddatadevice.cpp @@ -47,6 +47,7 @@ #include "qwaylandinputdevice_p.h" #include "qwaylanddisplay_p.h" #include "qwaylandabstractdecoration_p.h" +#include "qwaylandsurface_p.h" #include <QtCore/QMimeData> #include <QtGui/QGuiApplication> @@ -107,11 +108,12 @@ void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon) m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData)); connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled); - QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus(); + auto *seat = m_display->currentInputDevice(); + auto *origin = seat->pointerFocus(); if (!origin) - origin = m_display->currentInputDevice()->touchFocus(); + origin = seat->touchFocus(); - start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial()); + start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial()); } void QWaylandDataDevice::cancelDrag() @@ -151,9 +153,13 @@ void QWaylandDataDevice::data_device_drop() void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id) { - m_enterSerial = serial; - m_dragWindow = QWaylandWindow::fromWlSurface(surface)->window(); + auto *dragWaylandWindow = QWaylandWindow::fromWlSurface(surface); + if (!dragWaylandWindow) + return; // Ignore foreign surfaces + + m_dragWindow = dragWaylandWindow->window(); m_dragPoint = calculateDragPosition(x, y, m_dragWindow); + m_enterSerial = serial; QMimeData *dragData = nullptr; Qt::DropActions supportedActions; diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 4a91c1c96..7c32b6bf5 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -41,6 +41,7 @@ #include "qwaylandintegration_p.h" #include "qwaylandwindow_p.h" +#include "qwaylandsurface_p.h" #include "qwaylandabstractdecoration_p.h" #include "qwaylandscreen_p.h" #include "qwaylandcursor_p.h" @@ -109,7 +110,7 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) return nullptr; } - return mSubCompositor->get_subsurface(window->object(), parent->object()); + return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface()); } QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 558d8d9b5..2c7ed3231 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -98,6 +98,7 @@ class QWaylandQtKeyExtension; class QWaylandWindow; class QWaylandIntegration; class QWaylandHardwareIntegration; +class QWaylandSurface; class QWaylandShellIntegration; class QWaylandCursor; class QWaylandCursorTheme; diff --git a/src/client/qwaylandextendedsurface.cpp b/src/client/qwaylandextendedsurface.cpp index c5db6d7ba..a7836e292 100644 --- a/src/client/qwaylandextendedsurface.cpp +++ b/src/client/qwaylandextendedsurface.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { QWaylandExtendedSurface::QWaylandExtendedSurface(QWaylandWindow *window) - : QtWayland::qt_extended_surface(window->display()->windowExtension()->get_extended_surface(window->object())) + : QtWayland::qt_extended_surface(window->display()->windowExtension()->get_extended_surface(window->wlSurface())) , m_window(window) { } diff --git a/src/client/qwaylandinputcontext.cpp b/src/client/qwaylandinputcontext.cpp index c6f287dda..1d34f06cc 100644 --- a/src/client/qwaylandinputcontext.cpp +++ b/src/client/qwaylandinputcontext.cpp @@ -119,7 +119,7 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla if (!QGuiApplication::focusWindow() || !QGuiApplication::focusWindow()->handle()) return; - struct ::wl_surface *surface = static_cast<QWaylandWindow *>(QGuiApplication::focusWindow()->handle())->object(); + auto *surface = static_cast<QWaylandWindow *>(QGuiApplication::focusWindow()->handle())->wlSurface(); if (!surface || (surface != m_surface)) return; @@ -428,7 +428,7 @@ static ::wl_surface *surfaceForWindow(QWindow *window) return nullptr; auto *waylandWindow = static_cast<QWaylandWindow *>(window->handle()); - return waylandWindow->wl_surface::object(); + return waylandWindow->wlSurface(); } void QWaylandInputContext::update(Qt::InputMethodQueries queries) @@ -534,7 +534,7 @@ void QWaylandInputContext::setFocusObject(QObject *) if (mCurrentWindow && mCurrentWindow->handle()) { if (mCurrentWindow.data() != window || !inputMethodAccepted()) { - struct ::wl_surface *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->object(); + auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface(); if (surface) textInput()->disable(surface); mCurrentWindow.clear(); @@ -543,7 +543,7 @@ void QWaylandInputContext::setFocusObject(QObject *) if (window && window->handle() && inputMethodAccepted()) { if (mCurrentWindow.data() != window) { - struct ::wl_surface *surface = static_cast<QWaylandWindow *>(window->handle())->object(); + auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface(); if (surface) { textInput()->enable(surface); mCurrentWindow = window; diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 39c02d962..f0fd99563 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -41,6 +41,7 @@ #include "qwaylandintegration_p.h" #include "qwaylandwindow_p.h" +#include "qwaylandsurface_p.h" #include "qwaylandbuffer_p.h" #if QT_CONFIG(wayland_datadevice) #include "qwaylanddatadevice_p.h" @@ -73,6 +74,8 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { +Q_LOGGING_CATEGORY(lcQpaWaylandInput, "qt.qpa.wayland.input"); + QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) : mParent(p) { @@ -147,25 +150,45 @@ QWaylandInputDevice::Pointer::~Pointer() wl_pointer_destroy(object()); } +QWaylandWindow *QWaylandInputDevice::Pointer::focusWindow() const +{ + return mFocus ? mFocus->waylandWindow() : nullptr; +} + #if QT_CONFIG(cursor) -class CursorSurface : public QObject, public QtWayland::wl_surface +class WlCallback : public QtWayland::wl_callback { +public: + explicit WlCallback(::wl_callback *callback, std::function<void(uint32_t)> fn, bool autoDelete = false) + : QtWayland::wl_callback(callback) + , m_fn(fn) + , m_autoDelete(autoDelete) + {} + ~WlCallback() override { wl_callback_destroy(object()); } + bool done() const { return m_done; } + void callback_done(uint32_t callback_data) override { + m_done = true; + m_fn(callback_data); + if (m_autoDelete) + delete this; + } +private: + bool m_done = false; + std::function<void(uint32_t)> m_fn; + bool m_autoDelete = false; +}; + +class CursorSurface : public QWaylandSurface { public: explicit CursorSurface(QWaylandInputDevice::Pointer *pointer, QWaylandDisplay *display) - : m_pointer(pointer) + : QWaylandSurface(display) + , m_pointer(pointer) { - init(display->createSurface(this)); //TODO: When we upgrade to libwayland 1.10, use wl_surface_get_version instead. m_version = display->compositorVersion(); - connect(qApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) { - int oldScale = outputScale(); - if (!m_screens.removeOne(static_cast<QWaylandScreen *>(screen->handle()))) - return; - - if (outputScale() != oldScale) - m_pointer->updateCursor(); - }); + connect(this, &QWaylandSurface::screensChanged, + m_pointer, &QWaylandInputDevice::Pointer::updateCursor); } void hide() @@ -177,7 +200,7 @@ public: } // Size and hotspot are in surface coordinates - void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale) + void update(wl_buffer *buffer, const QPoint &hotspot, const QSize &size, int bufferScale, bool animated = false) { // Calling code needs to ensure buffer scale is supported if != 1 Q_ASSERT(bufferScale == 1 || m_version >= 3); @@ -194,6 +217,13 @@ public: attach(buffer, 0, 0); damage(0, 0, size.width(), size.height()); + m_frameCallback.reset(); + if (animated) { + m_frameCallback.reset(new WlCallback(frame(), [this](uint32_t time){ + Q_UNUSED(time); + m_pointer->updateCursor(); + })); + } commit(); } @@ -205,38 +235,12 @@ public: return scale; } -protected: - void surface_enter(struct ::wl_output *output) override - { - int oldScale = outputScale(); - auto *screen = QWaylandScreen::fromWlOutput(output); - if (m_screens.contains(screen)) - return; - - m_screens.append(screen); - - if (outputScale() != oldScale) - m_pointer->updateCursor(); - } - - void surface_leave(struct ::wl_output *output) override - { - int oldScale = outputScale(); - auto *screen = QWaylandScreen::fromWlOutput(output); - - if (!m_screens.removeOne(screen)) - return; - - if (outputScale() != oldScale) - m_pointer->updateCursor(); - } - private: + QScopedPointer<WlCallback> m_frameCallback; QWaylandInputDevice::Pointer *m_pointer = nullptr; uint m_version = 0; uint m_setSerial = 0; QPoint m_hotspot; - QVector<QWaylandScreen *> m_screens; }; QString QWaylandInputDevice::Pointer::cursorThemeName() const @@ -311,12 +315,14 @@ void QWaylandInputDevice::Pointer::updateCursor() updateCursorTheme(); // Set from shape using theme - if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape)) { + uint time = seat()->mCursor.animationTimer.elapsed(); + if (struct ::wl_cursor_image *image = mCursor.theme->cursorImage(shape, time)) { struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); int bufferScale = mCursor.themeBufferScale; QPoint hotspot = QPoint(image->hotspot_x, image->hotspot_y) / bufferScale; QSize size = QSize(image->width, image->height) / bufferScale; - getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale); + bool animated = image->delay > 0; + getOrCreateCursorSurface()->update(buffer, hotspot, size, bufferScale, animated); return; } @@ -346,10 +352,10 @@ QWaylandInputDevice::Touch::~Touch() } QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id) - : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 4)) + : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 5)) , mQDisplay(display) , mDisplay(display->wl_display()) - , mVersion(qMin(version, 4)) + , mVersion(qMin(version, 5)) { #if QT_CONFIG(wayland_datadevice) if (mQDisplay->dndSelectionHandler()) { @@ -458,7 +464,7 @@ void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button) QWaylandWindow *QWaylandInputDevice::pointerFocus() const { - return mPointer ? mPointer->mFocus : nullptr; + return mPointer ? mPointer->focusWindow() : nullptr; } QWaylandWindow *QWaylandInputDevice::keyboardFocus() const @@ -517,6 +523,7 @@ void QWaylandInputDevice::setCursor(const QCursor *cursor, const QSharedPointer< mCursor.shape = cursor ? cursor->shape() : Qt::ArrowCursor; mCursor.hotspot = cursor ? cursor->hotSpot() : QPoint(); mCursor.fallbackOutputScale = fallbackOutputScale; + mCursor.animationTimer.start(); if (mCursor.shape == Qt::BitmapCursor) { mCursor.bitmapBuffer = cachedBuffer ? cachedBuffer : QWaylandCursor::cursorBitmapBuffer(mQDisplay, cursor); @@ -543,8 +550,9 @@ void QWaylandInputDevice::setCursor(const QCursor *cursor, const QSharedPointer< class EnterEvent : public QWaylandPointerEvent { public: - EnterEvent(const QPointF &l, const QPointF &g) - : QWaylandPointerEvent(QWaylandPointerEvent::Enter, 0, l, g, nullptr, Qt::NoModifier) + EnterEvent(QWaylandWindow *surface, const QPointF &local, const QPointF &global) + : QWaylandPointerEvent(QWaylandPointerEvent::Enter, Qt::NoScrollPhase, surface, 0, + local, global, nullptr, Qt::NoModifier) {} }; @@ -556,14 +564,17 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); + if (!window) + return; // Ignore foreign surfaces + if (mFocus) { qCWarning(lcQpaWayland) << "The compositor sent a wl_pointer.enter event before sending a" << "leave event first, this is not allowed by the wayland protocol" << "attempting to work around it by invalidating the current focus"; invalidateFocus(); } - mFocus = window; - connect(mFocus, &QWaylandWindow::wlSurfaceDestroyed, this, &Pointer::handleFocusDestroyed); + mFocus = window->waylandSurface(); + connect(mFocus, &QObject::destroyed, this, &Pointer::handleFocusDestroyed); mSurfacePos = QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy)); mGlobalPos = window->window()->mapToGlobal(mSurfacePos.toPoint()); @@ -577,12 +588,19 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf #endif QWaylandWindow *grab = QWaylandWindow::mouseGrab(); - if (!grab) { - EnterEvent evt(mSurfacePos, mGlobalPos); - window->handleMouse(mParent, evt); - } + if (!grab) + setFrameEvent(new EnterEvent(window, mSurfacePos, mGlobalPos)); } +class LeaveEvent : public QWaylandPointerEvent +{ +public: + LeaveEvent(QWaylandWindow *surface, const QPointF &localPos, const QPointF &globalPos) + : QWaylandPointerEvent(QWaylandPointerEvent::Leave, Qt::NoScrollPhase, surface, 0, + localPos, globalPos, nullptr, Qt::NoModifier) + {} +}; + void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surface *surface) { // The event may arrive after destroying the window, indicated by @@ -590,10 +608,12 @@ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surfac if (!surface) return; - if (!QWaylandWindow::mouseGrab()) { - QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); - window->handleMouseLeave(mParent); - } + auto *window = QWaylandWindow::fromWlSurface(surface); + if (!window) + return; // Ignore foreign surfaces + + if (!QWaylandWindow::mouseGrab()) + setFrameEvent(new LeaveEvent(window, mSurfacePos, mGlobalPos)); invalidateFocus(); mButtons = Qt::NoButton; @@ -604,15 +624,17 @@ void QWaylandInputDevice::Pointer::pointer_leave(uint32_t time, struct wl_surfac class MotionEvent : public QWaylandPointerEvent { public: - MotionEvent(ulong t, const QPointF &l, const QPointF &g, Qt::MouseButtons b, Qt::KeyboardModifiers m) - : QWaylandPointerEvent(QWaylandPointerEvent::Motion, t, l, g, b, m) + MotionEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos, + const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) + : QWaylandPointerEvent(QWaylandPointerEvent::Motion, Qt::NoScrollPhase, surface, + timestamp, localPos, globalPos, buttons, modifiers) { } }; void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - QWaylandWindow *window = mFocus; + QWaylandWindow *window = focusWindow(); if (!window) { // We destroyed the pointer focus surface, but the server didn't get the message yet... // or the server didn't send an enter event first. In either case, ignore the event. @@ -634,18 +656,37 @@ void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surf // so we just set it outside of the window boundaries. pos = QPointF(-1, -1); global = grab->window()->mapToGlobal(pos.toPoint()); - MotionEvent e(time, pos, global, mButtons, mParent->modifiers()); - grab->handleMouse(mParent, e); - } else { - MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers()); - window->handleMouse(mParent, e); + window = grab; } + setFrameEvent(new MotionEvent(window, time, pos, global, mButtons, mParent->modifiers())); } +class PressEvent : public QWaylandPointerEvent +{ +public: + PressEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos, + const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) + : QWaylandPointerEvent(QWaylandPointerEvent::Press, Qt::NoScrollPhase, surface, + timestamp, localPos, globalPos, buttons, modifiers) + { + } +}; + +class ReleaseEvent : public QWaylandPointerEvent +{ +public: + ReleaseEvent(QWaylandWindow *surface, ulong timestamp, const QPointF &localPos, + const QPointF &globalPos, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) + : QWaylandPointerEvent(QWaylandPointerEvent::Release, Qt::NoScrollPhase, surface, + timestamp, localPos, globalPos, buttons, modifiers) + { + } +}; + void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - QWaylandWindow *window = mFocus; + QWaylandWindow *window = focusWindow(); if (!window) { // We destroyed the pointer focus surface, but the server didn't get the message yet... // or the server didn't send an enter event first. In either case, ignore the event. @@ -687,20 +728,25 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time mParent->mQDisplay->setLastInputDevice(mParent, serial, window); QWaylandWindow *grab = QWaylandWindow::mouseGrab(); - if (grab && grab != mFocus) { - QPointF pos = QPointF(-1, -1); - QPointF global = grab->window()->mapToGlobal(pos.toPoint()); - MotionEvent e(time, pos, global, mButtons, mParent->modifiers()); - grab->handleMouse(mParent, e); - } else if (window) { - MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers()); - window->handleMouse(mParent, e); + + QPointF pos = mSurfacePos; + QPointF global = mGlobalPos; + if (grab && grab != focusWindow()) { + pos = QPointF(-1, -1); + global = grab->window()->mapToGlobal(pos.toPoint()); + + window = grab; } + + if (state) + setFrameEvent(new PressEvent(window, time, pos, global, mButtons, mParent->modifiers())); + else + setFrameEvent(new ReleaseEvent(window, time, pos, global, mButtons, mParent->modifiers())); } void QWaylandInputDevice::Pointer::invalidateFocus() { - disconnect(mFocus, &QWaylandWindow::wlSurfaceDestroyed, this, &Pointer::handleFocusDestroyed); + disconnect(mFocus, &QObject::destroyed, this, &Pointer::handleFocusDestroyed); mFocus = nullptr; mEnterSerial = 0; } @@ -708,45 +754,265 @@ void QWaylandInputDevice::Pointer::invalidateFocus() void QWaylandInputDevice::Pointer::releaseButtons() { mButtons = Qt::NoButton; - MotionEvent e(mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers()); - if (mFocus) - mFocus->handleMouse(mParent, e); + + if (auto *window = focusWindow()) { + MotionEvent e(focusWindow(), mParent->mTime, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers()); + window->handleMouse(mParent, e); + } } class WheelEvent : public QWaylandPointerEvent { public: - WheelEvent(ulong t, const QPointF &l, const QPointF &g, const QPoint &pd, const QPoint &ad, Qt::KeyboardModifiers m) - : QWaylandPointerEvent(QWaylandPointerEvent::Wheel, t, l, g, pd, ad, m) + WheelEvent(QWaylandWindow *surface, Qt::ScrollPhase phase, ulong timestamp, const QPointF &local, + const QPointF &global, const QPoint &pixelDelta, const QPoint &angleDelta, + Qt::MouseEventSource source, Qt::KeyboardModifiers modifiers) + : QWaylandPointerEvent(QWaylandPointerEvent::Wheel, phase, surface, timestamp, + local, global, pixelDelta, angleDelta, source, modifiers) { } }; void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, int32_t value) { - QWaylandWindow *window = mFocus; - if (!window) { + if (!focusWindow()) { // We destroyed the pointer focus surface, but the server didn't get the message yet... // or the server didn't send an enter event first. In either case, ignore the event. return; } - QPoint pixelDelta; - QPoint angleDelta; + // Get the delta and convert it into the expected range + switch (axis) { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + mFrameData.delta.ry() += wl_fixed_to_double(value); + qCDebug(lcQpaWaylandInput) << "wl_pointer.axis vertical:" << mFrameData.delta.y(); + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + mFrameData.delta.rx() += wl_fixed_to_double(value); + qCDebug(lcQpaWaylandInput) << "wl_pointer.axis horizontal:" << mFrameData.delta.x(); + break; + default: + //TODO: is this really needed? + qCWarning(lcQpaWaylandInput) << "wl_pointer.axis: Unknown axis:" << axis; + return; + } + + mParent->mTime = time; - //normalize value and inverse axis - int valueDelta = wl_fixed_to_int(value) * -12; + if (mParent->mVersion < WL_POINTER_FRAME_SINCE_VERSION) { + qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version"; + flushFrameEvent(); + } +} - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - pixelDelta = QPoint(); - angleDelta.setX(valueDelta); - } else { - pixelDelta = QPoint(); - angleDelta.setY(valueDelta); +void QWaylandInputDevice::Pointer::pointer_frame() +{ + flushFrameEvent(); +} + +void QWaylandInputDevice::Pointer::pointer_axis_source(uint32_t source) +{ + switch (source) { + case axis_source_wheel: + qCDebug(lcQpaWaylandInput) << "Axis source wheel"; + break; + case axis_source_finger: + qCDebug(lcQpaWaylandInput) << "Axis source finger"; + break; + case axis_source_continuous: + qCDebug(lcQpaWaylandInput) << "Axis source continuous"; + break; + } + mFrameData.axisSource = axis_source(source); +} + +void QWaylandInputDevice::Pointer::pointer_axis_stop(uint32_t time, uint32_t axis) +{ + if (!focusWindow()) + return; + + mParent->mTime = time; + switch (axis) { + case axis_vertical_scroll: + qCDebug(lcQpaWaylandInput) << "Received vertical wl_pointer.axis_stop"; + mFrameData.delta.setY(0); //TODO: what's the point of doing this? + break; + case axis_horizontal_scroll: + qCDebug(lcQpaWaylandInput) << "Received horizontal wl_pointer.axis_stop"; + mFrameData.delta.setX(0); + break; + default: + qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_stop: Unknown axis: " << axis + << "This is most likely a compositor bug"; + return; + } + + // May receive axis_stop for events we haven't sent a ScrollBegin for because + // most axis_sources do not mandate an axis_stop event to be sent. + if (!mScrollBeginSent) { + // TODO: For now, we just ignore these events, but we could perhaps take this as an + // indication that this compositor will in fact send axis_stop events for these sources + // and send a ScrollBegin the next time an axis_source event with this type is encountered. + return; + } + + QWaylandWindow *target = QWaylandWindow::mouseGrab(); + if (!target) + target = focusWindow(); + Qt::KeyboardModifiers mods = mParent->modifiers(); + WheelEvent wheelEvent(focusWindow(), Qt::ScrollEnd, mParent->mTime, mSurfacePos, mGlobalPos, + QPoint(), QPoint(), Qt::MouseEventNotSynthesized, mods); + target->handleMouse(mParent, wheelEvent); + mScrollBeginSent = false; + mScrollDeltaRemainder = QPointF(); +} + +void QWaylandInputDevice::Pointer::pointer_axis_discrete(uint32_t axis, int32_t value) +{ + if (!focusWindow()) + return; + + switch (axis) { + case axis_vertical_scroll: + qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete vertical:" << value; + mFrameData.discreteDelta.ry() += value; + break; + case axis_horizontal_scroll: + qCDebug(lcQpaWaylandInput) << "wl_pointer.axis_discrete horizontal:" << value; + mFrameData.discreteDelta.rx() += value; + break; + default: + //TODO: is this really needed? + qCWarning(lcQpaWaylandInput) << "wl_pointer.axis_discrete: Unknown axis:" << axis; + return; } +} - WheelEvent e(time, mSurfacePos, mGlobalPos, pixelDelta, angleDelta, mParent->modifiers()); - window->handleMouse(mParent, e); +void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event) +{ + qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type; + if (mFrameData.event && mFrameData.event->type != event->type) { + qCDebug(lcQpaWaylandInput) << "Flushing; previous was " << mFrameData.event->type; + flushFrameEvent(); + } + + mFrameData.event = event; + + if (mParent->mVersion < WL_POINTER_FRAME_SINCE_VERSION) { + qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version"; + flushFrameEvent(); + } +} + +void QWaylandInputDevice::Pointer::FrameData::resetScrollData() +{ + discreteDelta = QPoint(); + delta = QPointF(); + axisSource = axis_source_wheel; +} + +bool QWaylandInputDevice::Pointer::FrameData::hasPixelDelta() const +{ + switch (axisSource) { + case axis_source_wheel_tilt: // sideways tilt of the wheel + case axis_source_wheel: + // In the case of wheel events, a pixel delta doesn't really make sense, + // and will make Qt think this is a continuous scroll event when it isn't, + // so just ignore it. + return false; + case axis_source_finger: + case axis_source_continuous: + return !delta.isNull(); + } +} + +QPoint QWaylandInputDevice::Pointer::FrameData::pixelDeltaAndError(QPointF *accumulatedError) const +{ + if (!hasPixelDelta()) + return QPoint(); + + Q_ASSERT(accumulatedError); + // Add accumulated rounding error before rounding again + QPoint pixelDelta = (delta + *accumulatedError).toPoint(); + *accumulatedError += delta - pixelDelta; + Q_ASSERT(qAbs(accumulatedError->x()) < 1.0); + Q_ASSERT(qAbs(accumulatedError->y()) < 1.0); + return pixelDelta; +} + +QPoint QWaylandInputDevice::Pointer::FrameData::angleDelta() const +{ + if (discreteDelta.isNull()) { + // If we didn't get any discrete events, then we need to fall back to + // the continuous information. + return (delta * -12).toPoint(); //TODO: why multiply by 12? + } + + // The angle delta is in eights of degrees, and our docs says most mice have + // 1 click = 15 degrees. It's also in the opposite direction of surface space. + return -discreteDelta * 15 * 8; +} + +Qt::MouseEventSource QWaylandInputDevice::Pointer::FrameData::wheelEventSource() const +{ + switch (axisSource) { + case axis_source_wheel_tilt: // sideways tilt of the wheel + case axis_source_wheel: + return Qt::MouseEventNotSynthesized; + case axis_source_finger: + case axis_source_continuous: + default: // Whatever other sources might be added are probably not mouse wheels + return Qt::MouseEventSynthesizedBySystem; + } +} + +void QWaylandInputDevice::Pointer::flushScrollEvent() +{ + QPoint angleDelta = mFrameData.angleDelta(); + + // Angle delta is required for Qt wheel events, so don't try to send events if it's zero + if (!angleDelta.isNull()) { + QWaylandWindow *target = QWaylandWindow::mouseGrab(); + if (!target) + target = focusWindow(); + + if (isDefinitelyTerminated(mFrameData.axisSource) && !mScrollBeginSent) { + qCDebug(lcQpaWaylandInput) << "Flushing scroll event sending ScrollBegin"; + target->handleMouse(mParent, WheelEvent(focusWindow(), Qt::ScrollBegin, mParent->mTime, + mSurfacePos, mGlobalPos, QPoint(), QPoint(), + Qt::MouseEventNotSynthesized, + mParent->modifiers())); + mScrollBeginSent = true; + mScrollDeltaRemainder = QPointF(); + } + + Qt::ScrollPhase phase = mScrollBeginSent ? Qt::ScrollUpdate : Qt::NoScrollPhase; + QPoint pixelDelta = mFrameData.pixelDeltaAndError(&mScrollDeltaRemainder); + Qt::MouseEventSource source = mFrameData.wheelEventSource(); + + qCDebug(lcQpaWaylandInput) << "Flushing scroll event" << phase << pixelDelta << angleDelta; + target->handleMouse(mParent, WheelEvent(focusWindow(), phase, mParent->mTime, mSurfacePos, mGlobalPos, + pixelDelta, angleDelta, source, mParent->modifiers())); + } + + mFrameData.resetScrollData(); +} + +void QWaylandInputDevice::Pointer::flushFrameEvent() +{ + if (mFrameData.event) { + mFrameData.event->surface->handleMouse(mParent, *mFrameData.event); + delete mFrameData.event; + mFrameData.event = nullptr; + } + + //TODO: do modifiers get passed correctly here? + flushScrollEvent(); +} + +bool QWaylandInputDevice::Pointer::isDefinitelyTerminated(QtWayland::wl_pointer::axis_source source) const +{ + return source == axis_source_finger; } void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) @@ -913,7 +1179,7 @@ void QWaylandInputDevice::Keyboard::handleFocusDestroyed() // surface, so we still need to disconnect the signal auto *window = qobject_cast<QWaylandWindow *>(sender()); disconnect(window, &QWaylandWindow::wlSurfaceDestroyed, this, &Keyboard::handleFocusDestroyed); - Q_ASSERT(window->object() == mFocus); + Q_ASSERT(window->wlSurface() == mFocus); handleFocusLost(); } @@ -965,9 +1231,13 @@ void QWaylandInputDevice::Touch::touch_down(uint32_t serial, if (!surface) return; + auto *window = QWaylandWindow::fromWlSurface(surface); + if (!window) + return; // Ignore foreign surfaces + mParent->mTime = time; mParent->mSerial = serial; - mFocus = QWaylandWindow::fromWlSurface(surface); + mFocus = window; mParent->mQDisplay->setLastInputDevice(mParent, serial, mFocus); mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed); } @@ -1026,7 +1296,7 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch //is it possible that mTouchFocus is null; if (!win && mPointer) - win = mPointer->mFocus; + win = mPointer->focusWindow(); if (!win && mKeyboard) win = mKeyboard->focusWindow(); if (!win || !win->window()) diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 39ca9dca5..f44f1ab1f 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -69,7 +69,8 @@ #endif #include <QtCore/QDebug> -#include <QPointer> +#include <QtCore/QElapsedTimer> +#include <QtCore/QPointer> #if QT_CONFIG(cursor) struct wl_cursor_image; @@ -150,6 +151,7 @@ private: Qt::CursorShape shape = Qt::ArrowCursor; int fallbackOutputScale = 1; QPoint hotspot; + QElapsedTimer animationTimer; } mCursor; #endif @@ -256,6 +258,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, pub public: explicit Pointer(QWaylandInputDevice *seat); ~Pointer() override; + QWaylandWindow *focusWindow() const; #if QT_CONFIG(cursor) QString cursorThemeName() const; int cursorSize() const; // in surface coordinates @@ -277,6 +280,10 @@ protected: void pointer_axis(uint32_t time, uint32_t axis, wl_fixed_t value) override; + void pointer_axis_source(uint32_t source) override; + void pointer_axis_stop(uint32_t time, uint32_t axis) override; + void pointer_axis_discrete(uint32_t axis, int32_t value) override; + void pointer_frame() override; private slots: void handleFocusDestroyed() { invalidateFocus(); } @@ -288,7 +295,7 @@ public: void releaseButtons(); QWaylandInputDevice *mParent = nullptr; - QPointer<QWaylandWindow> mFocus; + QPointer<QWaylandSurface> mFocus; uint32_t mEnterSerial = 0; #if QT_CONFIG(cursor) struct { @@ -304,6 +311,30 @@ public: wl_buffer *mCursorBuffer = nullptr; Qt::CursorShape mCursorShape = Qt::BitmapCursor; #endif + + struct FrameData { + QWaylandPointerEvent *event = nullptr; + + QPointF delta; + QPoint discreteDelta; + axis_source axisSource = axis_source_wheel; + + void resetScrollData(); + bool hasPixelDelta() const; + QPoint pixelDeltaAndError(QPointF *accumulatedError) const; + QPoint pixelDelta() const { return hasPixelDelta() ? delta.toPoint() : QPoint(); } + QPoint angleDelta() const; + Qt::MouseEventSource wheelEventSource() const; + } mFrameData; + + bool mScrollBeginSent = false; + QPointF mScrollDeltaRemainder; + + void setFrameEvent(QWaylandPointerEvent *event); + void flushScrollEvent(); + void flushFrameEvent(); +private: //TODO: should other methods be private as well? + bool isDefinitelyTerminated(axis_source source) const; }; class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch @@ -339,38 +370,58 @@ public: class QWaylandPointerEvent { + Q_GADGET public: enum Type { Enter, + Leave, Motion, + Press, + Release, Wheel }; - inline QWaylandPointerEvent(Type t, ulong ts, const QPointF &l, const QPointF &g, Qt::MouseButtons b, Qt::KeyboardModifiers m) - : type(t) - , timestamp(ts) - , local(l) - , global(g) - , buttons(b) - , modifiers(m) + Q_ENUM(Type) + + inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface, + ulong timestamp, const QPointF &localPos, const QPointF &globalPos, + Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) + : type(type) + , phase(phase) + , timestamp(timestamp) + , local(localPos) + , global(globalPos) + , buttons(buttons) + , modifiers(modifiers) + , surface(surface) {} - inline QWaylandPointerEvent(Type t, ulong ts, const QPointF &l, const QPointF &g, const QPoint &pd, const QPoint &ad, Qt::KeyboardModifiers m) - : type(t) - , timestamp(ts) - , local(l) - , global(g) - , modifiers(m) - , pixelDelta(pd) - , angleDelta(ad) + inline QWaylandPointerEvent(Type type, Qt::ScrollPhase phase, QWaylandWindow *surface, + ulong timestamp, const QPointF &local, const QPointF &global, + const QPoint &pixelDelta, const QPoint &angleDelta, + Qt::MouseEventSource source, + Qt::KeyboardModifiers modifiers) + : type(type) + , phase(phase) + , timestamp(timestamp) + , local(local) + , global(global) + , modifiers(modifiers) + , pixelDelta(pixelDelta) + , angleDelta(angleDelta) + , source(source) + , surface(surface) {} Type type; - ulong timestamp; + Qt::ScrollPhase phase = Qt::NoScrollPhase; + ulong timestamp = 0; QPointF local; QPointF global; Qt::MouseButtons buttons; Qt::KeyboardModifiers modifiers; QPoint pixelDelta; QPoint angleDelta; + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + QWaylandWindow *surface = nullptr; }; } diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp index 76acb526b..cf227d489 100644 --- a/src/client/qwaylandnativeinterface.cpp +++ b/src/client/qwaylandnativeinterface.cpp @@ -89,7 +89,7 @@ void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourc return const_cast<wl_compositor *>(m_integration->display()->wl_compositor()); if (lowerCaseResource == "surface") { QWaylandWindow *w = static_cast<QWaylandWindow*>(window->handle()); - return w ? w->object() : nullptr; + return w ? w->wlSurface() : nullptr; } if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration()) diff --git a/src/client/qwaylandqtkey.cpp b/src/client/qwaylandqtkey.cpp index a60185bd6..192619738 100644 --- a/src/client/qwaylandqtkey.cpp +++ b/src/client/qwaylandqtkey.cpp @@ -70,7 +70,11 @@ void QWaylandQtKeyExtension::zqt_key_v1_key(struct wl_surface *surface, } QWaylandInputDevice *dev = inputDevices.first(); - QWaylandWindow *win = surface ? QWaylandWindow::fromWlSurface(surface) : dev->keyboardFocus(); + + auto *win = surface ? QWaylandWindow::fromWlSurface(surface) : nullptr; + + if (!win) + win = dev->keyboardFocus(); if (!win || !win->window()) { qWarning("qt_key_extension: handle_qtkey: No keyboard focus"); diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp index 5b04ae609..d116a807b 100644 --- a/src/client/qwaylandscreen.cpp +++ b/src/client/qwaylandscreen.cpp @@ -217,8 +217,9 @@ QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window) QWaylandScreen *QWaylandScreen::fromWlOutput(::wl_output *output) { - auto wlOutput = static_cast<QtWayland::wl_output *>(wl_output_get_user_data(output)); - return static_cast<QWaylandScreen *>(wlOutput); + if (auto *o = QtWayland::wl_output::fromObject(output)) + return static_cast<QWaylandScreen *>(o); + return nullptr; } void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refresh) diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp index 34044ec9b..c16d346eb 100644 --- a/src/client/qwaylandshmbackingstore.cpp +++ b/src/client/qwaylandshmbackingstore.cpp @@ -288,12 +288,15 @@ void QWaylandShmBackingStore::resize(const QSize &size) buffer = getBuffer(sizeWithMargins); } - qsizetype oldSize = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0; + qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0; + qsizetype newSizeInBytes = buffer->image()->sizeInBytes(); + // mBackBuffer may have been deleted here but if so it means its size was different so we wouldn't copy it anyway - if (mBackBuffer != buffer && oldSize == buffer->image()->sizeInBytes()) { - memcpy(buffer->image()->bits(), mBackBuffer->image()->constBits(), buffer->image()->sizeInBytes()); - } + if (mBackBuffer != buffer && oldSizeInBytes == newSizeInBytes) + memcpy(buffer->image()->bits(), mBackBuffer->image()->constBits(), newSizeInBytes); + mBackBuffer = buffer; + // ensure the new buffer is at the beginning of the list so next time getBuffer() will pick // it if possible if (mBuffers.first() != buffer) { @@ -301,7 +304,7 @@ void QWaylandShmBackingStore::resize(const QSize &size) mBuffers.prepend(buffer); } - if (windowDecoration() && window()->isVisible()) + if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes) windowDecoration()->update(); } diff --git a/src/client/qwaylandsurface.cpp b/src/client/qwaylandsurface.cpp new file mode 100644 index 000000000..c35f01b56 --- /dev/null +++ b/src/client/qwaylandsurface.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the config.tests 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 "qwaylandsurface_p.h" +#include "qwaylanddisplay_p.h" +#include "qwaylandscreen_p.h" + +#include <QtGui/QGuiApplication> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +QWaylandSurface::QWaylandSurface(QWaylandDisplay *display) + : wl_surface(display->createSurface(this)) +{ + connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandSurface::handleScreenRemoved); +} + +QWaylandSurface::~QWaylandSurface() +{ + destroy(); +} + +QWaylandScreen *QWaylandSurface::oldestEnteredScreen() +{ + return m_screens.value(0, nullptr); +} + +QWaylandSurface *QWaylandSurface::fromWlSurface(::wl_surface *surface) +{ + if (auto *s = QtWayland::wl_surface::fromObject(surface)) + return static_cast<QWaylandSurface *>(s); + return nullptr; +} + +void QWaylandSurface::handleScreenRemoved(QScreen *qScreen) +{ + auto *screen = static_cast<QWaylandScreen *>(qScreen->handle()); + if (m_screens.removeOne(screen)) + emit screensChanged(); +} + +void QWaylandSurface::surface_enter(wl_output *output) +{ + auto addedScreen = QWaylandScreen::fromWlOutput(output); + + if (!addedScreen) + return; + + if (m_screens.contains(addedScreen)) { + qCWarning(lcQpaWayland) + << "Ignoring unexpected wl_surface.enter received for output with id:" + << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) + << "screen name:" << addedScreen->name() << "screen model:" << addedScreen->model() + << "This is most likely a bug in the compositor."; + return; + } + + m_screens.append(addedScreen); + emit screensChanged(); +} + +void QWaylandSurface::surface_leave(wl_output *output) +{ + auto *removedScreen = QWaylandScreen::fromWlOutput(output); + + if (!removedScreen) + return; + + bool wasRemoved = m_screens.removeOne(removedScreen); + if (!wasRemoved) { + qCWarning(lcQpaWayland) + << "Ignoring unexpected wl_surface.leave received for output with id:" + << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) + << "screen name:" << removedScreen->name() + << "screen model:" << removedScreen->model() + << "This is most likely a bug in the compositor."; + return; + } + emit screensChanged(); +} + +} // namespace QtWaylandClient + +QT_END_NAMESPACE diff --git a/src/client/qwaylandsurface_p.h b/src/client/qwaylandsurface_p.h new file mode 100644 index 000000000..541010934 --- /dev/null +++ b/src/client/qwaylandsurface_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the config.tests 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 QWAYLANDSURFACE_P_H +#define QWAYLANDSURFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/QScreen> + +#include <QtWaylandClient/private/qwayland-wayland.h> + +QT_BEGIN_NAMESPACE + +namespace QtWaylandClient { + +class QWaylandScreen; +class QWaylandWindow; +class QWaylandDisplay; + +class QWaylandSurface : public QObject, public QtWayland::wl_surface +{ + Q_OBJECT +public: + explicit QWaylandSurface(QWaylandDisplay *display); + ~QWaylandSurface() override; + QWaylandScreen *oldestEnteredScreen(); + QWaylandWindow *waylandWindow() const { return m_window; } + + static QWaylandSurface *fromWlSurface(::wl_surface *surface); + +signals: + void screensChanged(); + +private slots: + void handleScreenRemoved(QScreen *qScreen); + +protected: + void surface_enter(struct ::wl_output *output) override; + void surface_leave(struct ::wl_output *output) override; + + QVector<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order. + QWaylandWindow *m_window = nullptr; + + friend class QWaylandWindow; // TODO: shouldn't need to be friends +}; + +} // namespace QtWaylandClient + +QT_END_NAMESPACE + +#endif // QWAYLANDSURFACE_P_H diff --git a/src/client/qwaylandtouch.cpp b/src/client/qwaylandtouch.cpp index 48c869a60..0394aef31 100644 --- a/src/client/qwaylandtouch.cpp +++ b/src/client/qwaylandtouch.cpp @@ -40,6 +40,7 @@ #include "qwaylandtouch_p.h" #include "qwaylandinputdevice_p.h" #include "qwaylanddisplay_p.h" +#include "qwaylandsurface_p.h" QT_BEGIN_NAMESPACE diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 4532bc236..9bc400f8a 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -41,6 +41,7 @@ #include "qwaylandbuffer_p.h" #include "qwaylanddisplay_p.h" +#include "qwaylandsurface_p.h" #include "qwaylandinputdevice_p.h" #include "qwaylandscreen_p.h" #include "qwaylandshellsurface_p.h" @@ -80,7 +81,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window) { static WId id = 1; mWindowId = id++; - connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandWindow::handleScreenRemoved); initializeWlSurface(); } @@ -90,7 +90,7 @@ QWaylandWindow::~QWaylandWindow() delete mWindowDecoration; - if (isInitialized()) + if (mSurface) reset(false); const QWindow *parent = window(); @@ -115,7 +115,7 @@ void QWaylandWindow::initWindow() if (window()->type() == Qt::Desktop) return; - if (!isInitialized()) { + if (!mSurface) { initializeWlSurface(); QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); QGuiApplication::sendEvent(window(), &e); @@ -181,7 +181,7 @@ void QWaylandWindow::initWindow() // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale() // to inform the compositor that high-resolution buffers will be provided. if (mDisplay->compositorVersion() >= 3) - set_buffer_scale(scale()); + mSurface->set_buffer_scale(scale()); if (QScreen *s = window()->screen()) setOrientationMask(s->orientationUpdateMask()); @@ -199,7 +199,11 @@ void QWaylandWindow::initWindow() void QWaylandWindow::initializeWlSurface() { - init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this))); + Q_ASSERT(!mSurface); + mSurface.reset(new QWaylandSurface(mDisplay)); + connect(mSurface.data(), &QWaylandSurface::screensChanged, + this, &QWaylandWindow::handleScreensChanged); + mSurface->m_window = this; } bool QWaylandWindow::shouldCreateShellSurface() const @@ -226,7 +230,7 @@ bool QWaylandWindow::shouldCreateSubSurface() const void QWaylandWindow::reset(bool sendDestroyEvent) { - if (isInitialized() && sendDestroyEvent) { + if (mSurface && sendDestroyEvent) { QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed); QGuiApplication::sendEvent(window(), &e); } @@ -234,11 +238,10 @@ void QWaylandWindow::reset(bool sendDestroyEvent) mShellSurface = nullptr; delete mSubSurfaceWindow; mSubSurfaceWindow = nullptr; - if (isInitialized()) { + if (mSurface) { emit wlSurfaceDestroyed(); - destroy(); + mSurface.reset(); } - mScreens.clear(); if (mFrameCallback) { wl_callback_destroy(mFrameCallback); @@ -251,7 +254,9 @@ void QWaylandWindow::reset(bool sendDestroyEvent) QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface) { - return static_cast<QWaylandWindow *>(static_cast<QtWayland::wl_surface *>(wl_surface_get_user_data(surface))); + if (auto *s = QWaylandSurface::fromWlSurface(surface)) + return s->m_window; + return nullptr; } WId QWaylandWindow::winId() const @@ -381,7 +386,12 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent) QWaylandScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const { - return mScreens.isEmpty() ? waylandScreen() : mScreens.first(); + if (mSurface) { + if (auto *screen = mSurface->oldestEnteredScreen()) + return screen; + } + + return waylandScreen(); } void QWaylandWindow::setVisible(bool visible) @@ -425,18 +435,18 @@ void QWaylandWindow::setMask(const QRegion &mask) mMask = mask; - if (!isInitialized()) + if (!mSurface) return; if (mMask.isEmpty()) { - set_input_region(nullptr); + mSurface->set_input_region(nullptr); } else { struct ::wl_region *region = mDisplay->createRegion(mMask); - set_input_region(region); + mSurface->set_input_region(region); wl_region_destroy(region); } - wl_surface::commit(); + mSurface->commit(); } void QWaylandWindow::applyConfigureWhenPossible() @@ -490,58 +500,6 @@ void QWaylandWindow::applyConfigure() QWindowSystemInterface::flushWindowSystemEvents(); } -void QWaylandWindow::surface_enter(wl_output *output) -{ - QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); - auto addedScreen = QWaylandScreen::fromWlOutput(output); - - if (mScreens.contains(addedScreen)) { - qCWarning(lcQpaWayland) - << "Ignoring unexpected wl_surface.enter received for output with id:" - << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) - << "screen name:" << addedScreen->name() << "screen model:" << addedScreen->model() - << "This is most likely a bug in the compositor."; - return; - } - - mScreens.append(addedScreen); - - QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); - if (oldScreen != newScreen) //currently this will only happen if the first wl_surface.enter is for a non-primary screen - handleScreenChanged(); -} - -void QWaylandWindow::surface_leave(wl_output *output) -{ - QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); - auto *removedScreen = QWaylandScreen::fromWlOutput(output); - bool wasRemoved = mScreens.removeOne(removedScreen); - if (!wasRemoved) { - qCWarning(lcQpaWayland) - << "Ignoring unexpected wl_surface.leave received for output with id:" - << wl_proxy_get_id(reinterpret_cast<wl_proxy *>(output)) - << "screen name:" << removedScreen->name() - << "screen model:" << removedScreen->model() - << "This is most likely a bug in the compositor."; - return; - } - - QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); - if (oldScreen != newScreen) - handleScreenChanged(); -} - -void QWaylandWindow::handleScreenRemoved(QScreen *qScreen) -{ - QWaylandScreen *oldScreen = calculateScreenFromSurfaceEvents(); - bool wasRemoved = mScreens.removeOne(static_cast<QWaylandScreen *>(qScreen->handle())); - if (wasRemoved) { - QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); - if (oldScreen != newScreen) - handleScreenChanged(); - } -} - void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) { Q_ASSERT(!buffer->committed()); @@ -549,9 +507,9 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) handleUpdate(); buffer->setBusy(); - QtWayland::wl_surface::attach(buffer->buffer(), x, y); + mSurface->attach(buffer->buffer(), x, y); } else { - QtWayland::wl_surface::attach(nullptr, 0, 0); + mSurface->attach(nullptr, 0, 0); } } @@ -563,7 +521,7 @@ void QWaylandWindow::attachOffset(QWaylandBuffer *buffer) void QWaylandWindow::damage(const QRect &rect) { - damage(rect.x(), rect.y(), rect.width(), rect.height()); + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height()); } void QWaylandWindow::safeCommit(QWaylandBuffer *buffer, const QRegion &damage) @@ -593,20 +551,20 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage) qCDebug(lcWaylandBackingstore) << "Buffer already committed, ignoring."; return; } - if (!isInitialized()) + if (!mSurface) return; attachOffset(buffer); for (const QRect &rect: damage) - wl_surface::damage(rect.x(), rect.y(), rect.width(), rect.height()); + mSurface->damage(rect.x(), rect.y(), rect.width(), rect.height()); Q_ASSERT(!buffer->committed()); buffer->setCommitted(); - wl_surface::commit(); + mSurface->commit(); } void QWaylandWindow::commit() { - wl_surface::commit(); + mSurface->commit(); } const wl_callback_listener QWaylandWindow::callbackListener = { @@ -691,6 +649,11 @@ QRect QWaylandWindow::windowContentGeometry() const return QRect(QPoint(), surfaceSize()); } +wl_surface *QWaylandWindow::wlSurface() +{ + return mSurface ? mSurface->object() : nullptr; +} + QWaylandShellSurface *QWaylandWindow::shellSurface() const { return mShellSurface; @@ -732,9 +695,9 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient default: Q_UNREACHABLE(); } - set_buffer_transform(transform); + mSurface->set_buffer_transform(transform); // set_buffer_transform is double buffered, we need to commit. - wl_surface::commit(); + mSurface->commit(); } void QWaylandWindow::setOrientationMask(Qt::ScreenOrientations mask) @@ -866,6 +829,18 @@ QWaylandWindow *QWaylandWindow::transientParent() const void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e) { + if (e.type == QWaylandPointerEvent::Leave) { + if (mWindowDecoration) { + if (mMouseEventsInContentArea) + QWindowSystemInterface::handleLeaveEvent(window()); + } else { + QWindowSystemInterface::handleLeaveEvent(window()); + } +#if QT_CONFIG(cursor) + restoreMouseCursor(inputDevice); +#endif + return; + } if (mWindowDecoration) { handleMouseEventWithDecoration(inputDevice, e); @@ -874,11 +849,15 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan case QWaylandPointerEvent::Enter: QWindowSystemInterface::handleEnterEvent(window(), e.local, e.global); break; + case QWaylandPointerEvent::Press: + case QWaylandPointerEvent::Release: case QWaylandPointerEvent::Motion: QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.modifiers); break; case QWaylandPointerEvent::Wheel: - QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global, e.pixelDelta, e.angleDelta, e.modifiers); + QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global, + e.pixelDelta, e.angleDelta, e.modifiers, + e.phase, e.source, false); break; } } @@ -892,20 +871,6 @@ void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylan #endif } -void QWaylandWindow::handleMouseLeave(QWaylandInputDevice *inputDevice) -{ - if (mWindowDecoration) { - if (mMouseEventsInContentArea) { - QWindowSystemInterface::handleLeaveEvent(window()); - } - } else { - QWindowSystemInterface::handleLeaveEvent(window()); - } -#if QT_CONFIG(cursor) - restoreMouseCursor(inputDevice); -#endif -} - bool QWaylandWindow::touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) { if (!mWindowDecoration) @@ -947,12 +912,18 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe case QWaylandPointerEvent::Enter: QWindowSystemInterface::handleEnterEvent(window(), localTranslated, globalTranslated); break; + case QWaylandPointerEvent::Press: + case QWaylandPointerEvent::Release: case QWaylandPointerEvent::Motion: QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, localTranslated, globalTranslated, e.buttons, e.modifiers); break; - case QWaylandPointerEvent::Wheel: - QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, localTranslated, globalTranslated, e.pixelDelta, e.angleDelta, e.modifiers); + case QWaylandPointerEvent::Wheel: { + QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, + localTranslated, globalTranslated, + e.pixelDelta, e.angleDelta, e.modifiers, + e.phase, e.source, false); break; + } } mMouseEventsInContentArea = true; @@ -965,16 +936,21 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe } } -void QWaylandWindow::handleScreenChanged() +void QWaylandWindow::handleScreensChanged() { QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents(); + + if (newScreen == mLastReportedScreen) + return; + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); + mLastReportedScreen = newScreen; int scale = newScreen->scale(); if (scale != mScale) { mScale = scale; - if (isInitialized() && mDisplay->compositorVersion() >= 3) - set_buffer_scale(mScale); + if (mSurface && mDisplay->compositorVersion() >= 3) + mSurface->set_buffer_scale(mScale); ensureSize(); } } @@ -1158,7 +1134,7 @@ void QWaylandWindow::handleUpdate() QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); } - mFrameCallback = frame(); + mFrameCallback = mSurface->frame(); wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); mWaitingForFrameCallback = true; mWaitingForUpdate = false; diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 8c1ebe167..5eadc02c8 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -79,8 +79,9 @@ class QWaylandInputDevice; class QWaylandScreen; class QWaylandShmBackingStore; class QWaylandPointerEvent; +class QWaylandSurface; -class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow, public QtWayland::wl_surface +class Q_WAYLAND_CLIENT_EXPORT QWaylandWindow : public QObject, public QPlatformWindow { Q_OBJECT public: @@ -108,12 +109,10 @@ public: void applyConfigureWhenPossible(); //rename to possible? - using QtWayland::wl_surface::attach; void attach(QWaylandBuffer *buffer, int x, int y); void attachOffset(QWaylandBuffer *buffer); QPoint attachOffset() const; - using QtWayland::wl_surface::damage; void damage(const QRect &rect); void safeCommit(QWaylandBuffer *buffer, const QRegion &damage); @@ -128,6 +127,8 @@ public: QSize surfaceSize() const; QRect windowContentGeometry() const; + QWaylandSurface *waylandSurface() const { return mSurface.data(); } + ::wl_surface *wlSurface(); static QWaylandWindow *fromWlSurface(::wl_surface *surface); QWaylandDisplay *display() const { return mDisplay; } @@ -157,7 +158,6 @@ public: QWaylandAbstractDecoration *decoration() const; void handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); - void handleMouseLeave(QWaylandInputDevice *inputDevice); bool touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods); @@ -206,11 +206,8 @@ signals: void wlSurfaceDestroyed(); protected: - void surface_enter(struct ::wl_output *output) override; - void surface_leave(struct ::wl_output *output) override; - - QVector<QWaylandScreen *> mScreens; //As seen by wl_surface.enter/leave events. Chronological order. QWaylandDisplay *mDisplay = nullptr; + QScopedPointer<QWaylandSurface> mSurface; QWaylandShellSurface *mShellSurface = nullptr; QWaylandSubSurface *mSubSurfaceWindow = nullptr; QVector<QWaylandSubSurface *> mChildren; @@ -241,6 +238,7 @@ protected: bool mSentInitialResize = false; QPoint mOffset; int mScale = 1; + QWaylandScreen *mLastReportedScreen = nullptr; QIcon mWindowIcon; @@ -252,9 +250,6 @@ protected: QWaylandBuffer *mQueuedBuffer = nullptr; QRegion mQueuedBufferDamage; -private slots: - void handleScreenRemoved(QScreen *qScreen); - private: void setGeometry_helper(const QRect &rect); void initWindow(); @@ -267,7 +262,7 @@ private: QWaylandScreen *calculateScreenFromSurfaceEvents() const; void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); - void handleScreenChanged(); + void handleScreensChanged(); QRect mLastExposeGeometry; |