diff --git a/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h b/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h index 7d79f326330..bbe42eb261f 100644 --- a/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h +++ b/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h @@ -62,7 +62,10 @@ public: virtual void initialize(QWaylandDisplay *display) = 0; + virtual bool isValid() const { return true; } + virtual bool supportsThreadedOpenGL() const { return false; } + virtual bool supportsWindowDecoration() const { return false; } virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; diff --git a/src/plugins/platforms/wayland/hardwareintegration/qwaylandhardwareintegration.cpp b/src/plugins/platforms/wayland/hardwareintegration/qwaylandhardwareintegration.cpp index a7269ce9e54..469f80360f3 100644 --- a/src/plugins/platforms/wayland/hardwareintegration/qwaylandhardwareintegration.cpp +++ b/src/plugins/platforms/wayland/hardwareintegration/qwaylandhardwareintegration.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE QWaylandHardwareIntegration::QWaylandHardwareIntegration(struct ::wl_registry *registry, int id) - : qt_hardware_integration(registry, id) + : qt_hardware_integration(registry, id, 1) { } diff --git a/src/plugins/platforms/wayland/qwaylanddatadevice.cpp b/src/plugins/platforms/wayland/qwaylanddatadevice.cpp index 8f690aae0fc..74f879f972d 100644 --- a/src/plugins/platforms/wayland/qwaylanddatadevice.cpp +++ b/src/plugins/platforms/wayland/qwaylanddatadevice.cpp @@ -77,6 +77,11 @@ QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const return m_selectionOffer.data(); } +void QWaylandDataDevice::invalidateSelectionOffer() +{ + m_selectionOffer.reset(); +} + QWaylandDataSource *QWaylandDataDevice::selectionSource() const { return m_selectionSource.data(); diff --git a/src/plugins/platforms/wayland/qwaylanddatadevice_p.h b/src/plugins/platforms/wayland/qwaylanddatadevice_p.h index f5fad17723f..dae91290ebf 100644 --- a/src/plugins/platforms/wayland/qwaylanddatadevice_p.h +++ b/src/plugins/platforms/wayland/qwaylanddatadevice_p.h @@ -65,6 +65,7 @@ public: ~QWaylandDataDevice(); QWaylandDataOffer *selectionOffer() const; + void invalidateSelectionOffer(); QWaylandDataSource *selectionSource() const; void setSelectionSource(QWaylandDataSource *source); diff --git a/src/plugins/platforms/wayland/qwaylanddatadevicemanager.cpp b/src/plugins/platforms/wayland/qwaylanddatadevicemanager.cpp index 1aef773490f..ea578ff7b1d 100644 --- a/src/plugins/platforms/wayland/qwaylanddatadevicemanager.cpp +++ b/src/plugins/platforms/wayland/qwaylanddatadevicemanager.cpp @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id) - : wl_data_device_manager(display->wl_registry(), id) + : wl_data_device_manager(display->wl_registry(), id, 1) , m_display(display) { // Create transfer devices for all input devices. diff --git a/src/plugins/platforms/wayland/qwaylanddataoffer.cpp b/src/plugins/platforms/wayland/qwaylanddataoffer.cpp index d1c85c7a40e..4ad73dc7e77 100644 --- a/src/plugins/platforms/wayland/qwaylanddataoffer.cpp +++ b/src/plugins/platforms/wayland/qwaylanddataoffer.cpp @@ -94,30 +94,18 @@ QWaylandMimeData::~QWaylandMimeData() void QWaylandMimeData::appendFormat(const QString &mimeType) { - if (m_types.contains(mimeType)) - close(m_types.take(mimeType)); // Unconsumed data + m_types << mimeType; m_data.remove(mimeType); // Clear previous contents - - int pipefd[2]; - if (::pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) { - qWarning("QWaylandMimeData: pipe2() failed"); - return; - } - - m_dataOffer->receive(mimeType, pipefd[1]); - m_display->forceRoundTrip(); - close(pipefd[1]); - m_types.insert(mimeType, pipefd[0]); } bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const { - return m_types.contains(mimeType) || m_data.contains(mimeType); + return m_types.contains(mimeType); } QStringList QWaylandMimeData::formats_sys() const { - return m_types.keys() << m_data.keys(); + return m_types; } QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const @@ -130,14 +118,24 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T if (!m_types.contains(mimeType)) return QVariant(); + int pipefd[2]; + if (::pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) { + qWarning("QWaylandMimeData: pipe2() failed"); + return QVariant(); + } + + m_dataOffer->receive(mimeType, pipefd[1]); + m_display->flushRequests(); + + close(pipefd[1]); + QByteArray content; - int fd = m_types.take(mimeType); - if (readData(fd, content) != 0) { + if (readData(pipefd[0], content) != 0) { qWarning("QWaylandDataOffer: error reading data for mimeType %s", qPrintable(mimeType)); content = QByteArray(); } - close(fd); + close(pipefd[0]); m_data.insert(mimeType, content); return content; } diff --git a/src/plugins/platforms/wayland/qwaylanddataoffer_p.h b/src/plugins/platforms/wayland/qwaylanddataoffer_p.h index a21e18bdc8d..12fc0a22f60 100644 --- a/src/plugins/platforms/wayland/qwaylanddataoffer_p.h +++ b/src/plugins/platforms/wayland/qwaylanddataoffer_p.h @@ -87,7 +87,7 @@ private: mutable QWaylandDataOffer *m_dataOffer; QWaylandDisplay *m_display; - mutable QHash m_types; + mutable QStringList m_types; mutable QHash m_data; }; diff --git a/src/plugins/platforms/wayland/qwaylanddecoration.cpp b/src/plugins/platforms/wayland/qwaylanddecoration.cpp index 8e7d03143a1..ed4978725a4 100644 --- a/src/plugins/platforms/wayland/qwaylanddecoration.cpp +++ b/src/plugins/platforms/wayland/qwaylanddecoration.cpp @@ -186,7 +186,7 @@ void QWaylandDecoration::paint(QPaintDevice *device) // Title bar QPoint gradCenter(top.center()+ QPoint(30, 60)); QLinearGradient grad(top.topLeft(), top.bottomLeft()); - QColor base(backgroundColor()); + QColor base(m_backgroundColor); grad.setColorAt(0, base.lighter(100)); grad.setColorAt(1, base.darker(180)); QPainterPath roundedRect; @@ -335,6 +335,28 @@ bool QWaylandDecoration::handleMouse(QWaylandInputDevice *inputDevice, const QPo return true; } +bool QWaylandDecoration::handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) +{ + Q_UNUSED(inputDevice); + Q_UNUSED(global); + Q_UNUSED(mods); + bool handled = state == Qt::TouchPointPressed; + if (handled) { + if (closeButtonRect().contains(local)) + QWindowSystemInterface::handleCloseEvent(m_window); + else if (maximizeButtonRect().contains(local)) + m_window->setWindowState(m_wayland_window->isMaximized() ? Qt::WindowNoState : Qt::WindowMaximized); + else if (minimizeButtonRect().contains(local)) + m_window->setWindowState(Qt::WindowMinimized); + else if (local.y() <= m_margins.top()) + m_wayland_window->shellSurface()->move(inputDevice); + else + handled = false; + } + + return handled; +} + bool QWaylandDecoration::inMouseButtonPressedState() const { return m_mouseButtons & Qt::NoButton; @@ -446,14 +468,4 @@ QRectF QWaylandDecoration::minimizeButtonRect() const (m_margins.top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); } -void QWaylandDecoration::setForegroundColor(const QColor &c) -{ - m_foregroundColor = c; -} - -void QWaylandDecoration::setBackgroundColor(const QColor &c) -{ - m_backgroundColor = c; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylanddecoration_p.h b/src/plugins/platforms/wayland/qwaylanddecoration_p.h index 3f53721f75d..c240b9c9d45 100644 --- a/src/plugins/platforms/wayland/qwaylanddecoration_p.h +++ b/src/plugins/platforms/wayland/qwaylanddecoration_p.h @@ -75,6 +75,7 @@ public: bool isDirty() const; bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods); + bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods); bool inMouseButtonPressedState() const; void startResize(QWaylandInputDevice *inputDevice,enum wl_shell_surface_resize resize, Qt::MouseButtons buttons); @@ -84,12 +85,6 @@ public: QWaylandWindow *waylandWindow() const; const QImage &contentImage(); - void setForegroundColor(const QColor &c); - inline QColor foregroundColor() const; - - void setBackgroundColor(const QColor &c); - inline QColor backgroundColor() const; - protected: void paint(QPaintDevice *device); @@ -140,16 +135,6 @@ inline QWaylandWindow *QWaylandDecoration::waylandWindow() const return m_wayland_window; } -inline QColor QWaylandDecoration::foregroundColor() const -{ - return m_foregroundColor; -} - -inline QColor QWaylandDecoration::backgroundColor() const -{ - return m_backgroundColor; -} - QT_END_NAMESPACE #endif // QWAYLANDDECORATION_H diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 4475356b0af..edaac8fed79 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -56,6 +56,7 @@ #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandshellintegration_p.h" +#include "qwaylandclientbufferintegration_p.h" #include "qwaylandextendedoutput_p.h" #include "qwaylandextendedsurface_p.h" @@ -126,8 +127,6 @@ void QWaylandDisplay::setLastKeyboardFocusInputDevice(QWaylandInputDevice *devic mLastKeyboardFocusInputDevice = device; } -static QWaylandDisplay *display = 0; - QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) : mWaylandIntegration(waylandIntegration) , mLastKeyboardFocusInputDevice(0) @@ -140,7 +139,6 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) , mTextInputManager(0) , mHardwareIntegration(0) { - display = this; qRegisterMetaType("uint32_t"); mEventThreadObject = new QWaylandEventThread(0); @@ -169,6 +167,8 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) QWaylandDisplay::~QWaylandDisplay(void) { + qDeleteAll(mScreens); + mScreens.clear(); delete mDndSelectionHandler.take(); mEventThread->quit(); mEventThread->wait(); @@ -177,20 +177,17 @@ QWaylandDisplay::~QWaylandDisplay(void) void QWaylandDisplay::flushRequests() { - if (wl_display_dispatch_queue_pending(mDisplay, mEventQueue) == -1 && (errno == EPIPE || errno == ECONNRESET)) { - qWarning("The Wayland connection broke. Did the Wayland compositor die?"); - ::exit(1); - } + if (wl_display_dispatch_queue_pending(mDisplay, mEventQueue) < 0) + mEventThreadObject->checkErrorAndExit(); + wl_display_flush(mDisplay); } void QWaylandDisplay::blockingReadEvents() { - if (wl_display_dispatch_queue(mDisplay, mEventQueue) == -1 && (errno == EPIPE || errno == ECONNRESET)) { - qWarning("The Wayland connection broke. Did the Wayland compositor die?"); - ::exit(1); - } + if (wl_display_dispatch_queue(mDisplay, mEventQueue) < 0) + mEventThreadObject->checkErrorAndExit(); } QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const @@ -229,37 +226,39 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin struct ::wl_registry *registry = object(); if (interface == QStringLiteral("wl_output")) { - mScreens.append(new QWaylandScreen(this, id)); + QWaylandScreen *screen = new QWaylandScreen(this, id); + mScreens.append(screen); // We need to get the output events before creating surfaces forceRoundTrip(); + mWaylandIntegration->screenAdded(screen); } else if (interface == QStringLiteral("wl_compositor")) { - mCompositor.init(registry, id); + mCompositor.init(registry, id, 3); } else if (interface == QStringLiteral("wl_shm")) { mShm = static_cast(wl_registry_bind(registry, id, &wl_shm_interface,1)); } else if (interface == QStringLiteral("xdg_shell") && qEnvironmentVariableIsSet("QT_WAYLAND_USE_XDG_SHELL")) { mShellXdg.reset(new QWaylandXdgShell(registry,id)); } else if (interface == QStringLiteral("wl_shell")){ - mShell.reset(new QtWayland::wl_shell(registry, id)); + mShell.reset(new QtWayland::wl_shell(registry, id, 1)); } else if (interface == QStringLiteral("wl_seat")) { QWaylandInputDevice *inputDevice = new QWaylandInputDevice(this, id); mInputDevices.append(inputDevice); } else if (interface == QStringLiteral("wl_data_device_manager")) { mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id)); } else if (interface == QStringLiteral("qt_output_extension")) { - mOutputExtension.reset(new QtWayland::qt_output_extension(registry, id)); + mOutputExtension.reset(new QtWayland::qt_output_extension(registry, id, 1)); foreach (QPlatformScreen *screen, screens()) static_cast(screen)->createExtendedOutput(); } else if (interface == QStringLiteral("qt_surface_extension")) { - mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id)); + mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1)); } else if (interface == QStringLiteral("qt_sub_surface_extension")) { - mSubSurfaceExtension.reset(new QtWayland::qt_sub_surface_extension(registry, id)); + mSubSurfaceExtension.reset(new QtWayland::qt_sub_surface_extension(registry, id, 1)); } else if (interface == QStringLiteral("qt_touch_extension")) { mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("qt_key_extension")) { mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id)); } else if (interface == QStringLiteral("wl_text_input_manager")) { - mTextInputManager.reset(new QtWayland::wl_text_input_manager(registry, id)); + mTextInputManager.reset(new QtWayland::wl_text_input_manager(registry, id, 1)); } else if (interface == QStringLiteral("qt_hardware_integration")) { mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id)); // make a roundtrip here since we need to receive the events sent by @@ -276,7 +275,17 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin void QWaylandDisplay::registry_global_remove(uint32_t id) { for (int i = 0, ie = mGlobals.count(); i != ie; ++i) { - if (mGlobals[i].id == id) { + RegistryGlobal &global = mGlobals[i]; + if (global.id == id) { + if (global.interface == QStringLiteral("wl_output")) { + foreach (QWaylandScreen *screen, mScreens) { + if (screen->outputId() == id) { + delete screen; + mScreens.removeOne(screen); + break; + } + } + } mGlobals.removeAt(i); break; } @@ -337,4 +346,16 @@ QtWayland::xdg_shell *QWaylandDisplay::shellXdg() return mShellXdg.data(); } +bool QWaylandDisplay::supportsWindowDecoration() const +{ + static bool disabled = qgetenv("QT_WAYLAND_DISABLE_WINDOWDECORATION").toInt(); + // Stop early when disabled via the environment. Do not try to load the integration in + // order to play nice with SHM-only, buffer integration-less systems. + if (disabled) + return false; + + static bool integrationSupport = clientBufferIntegration() && clientBufferIntegration()->supportsWindowDecoration(); + return integrationSupport; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h index ade8475e7d9..05bd7f15a76 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h @@ -97,7 +97,7 @@ public: QWaylandDisplay(QWaylandIntegration *waylandIntegration); ~QWaylandDisplay(void); - QList screens() const { return mScreens; } + QList screens() const { return mScreens; } QWaylandScreen *screenForOutput(struct wl_output *output) const; @@ -157,6 +157,8 @@ public: void forceRoundTrip(); + bool supportsWindowDecoration() const; + public slots: void blockingReadEvents(); void flushRequests(); @@ -177,7 +179,7 @@ private: QWaylandEventThread *mEventThreadObject; QScopedPointer mShell; QScopedPointer mShellXdg; - QList mScreens; + QList mScreens; QList mInputDevices; QList mRegistryListeners; QWaylandIntegration *mWaylandIntegration; diff --git a/src/plugins/platforms/wayland/qwaylandeventthread.cpp b/src/plugins/platforms/wayland/qwaylandeventthread.cpp index c6ac42bba8f..b7266765e61 100644 --- a/src/plugins/platforms/wayland/qwaylandeventthread.cpp +++ b/src/plugins/platforms/wayland/qwaylandeventthread.cpp @@ -71,12 +71,25 @@ void QWaylandEventThread::displayConnect() QMetaObject::invokeMethod(this, "waylandDisplayConnect", Qt::QueuedConnection); } +// ### be careful what you do, this function may also be called from other +// threads to clean up & exit. +void QWaylandEventThread::checkErrorAndExit() +{ + int ecode = wl_display_get_error(m_display); + if ((ecode == EPIPE || ecode == ECONNRESET)) { + // special case this to provide a nicer error + qWarning("The Wayland connection broke. Did the Wayland compositor die?"); + } else { + qErrnoWarning(ecode, "The Wayland connection experienced a fatal error"); + } + ::exit(1); +} + void QWaylandEventThread::readWaylandEvents() { - if (wl_display_dispatch(m_display) == -1 && (errno == EPIPE || errno == ECONNRESET)) { - qWarning("The Wayland connection broke. Did the Wayland compositor die?"); - ::exit(1); - } + if (wl_display_dispatch(m_display) < 0) + checkErrorAndExit(); + emit newEventsRead(); } diff --git a/src/plugins/platforms/wayland/qwaylandeventthread_p.h b/src/plugins/platforms/wayland/qwaylandeventthread_p.h index 0d2758c4c67..d51d627b962 100644 --- a/src/plugins/platforms/wayland/qwaylandeventthread_p.h +++ b/src/plugins/platforms/wayland/qwaylandeventthread_p.h @@ -63,6 +63,8 @@ public: wl_display *display() const; + void checkErrorAndExit(); + private slots: void readWaylandEvents(); diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 145ef608d28..5198a9e31ea 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -220,6 +220,8 @@ public: void touch_frame() Q_DECL_OVERRIDE; void touch_cancel() Q_DECL_OVERRIDE; + bool allTouchPointsReleased(); + QWaylandInputDevice *mParent; QWaylandWindow *mFocus; QList mTouchPoints; @@ -228,7 +230,7 @@ public: QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, uint32_t id) : QObject() - , QtWayland::wl_seat(display->wl_registry(), id) + , QtWayland::wl_seat(display->wl_registry(), id, 2) , mQDisplay(display) , mDisplay(display->wl_display()) , mCaps(0) @@ -715,6 +717,11 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf Q_UNUSED(time); Q_UNUSED(surface); + if (surface) { + QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface); + window->unfocus(); + } + mFocus = NULL; // Use a callback to set the focus because we may get a leave/enter pair, and @@ -851,8 +858,8 @@ void QWaylandInputDevice::Touch::touch_down(uint32_t serial, wl_fixed_t x, wl_fixed_t y) { - Q_UNUSED(serial); - Q_UNUSED(time); + mParent->mTime = time; + mParent->mSerial = serial; mFocus = QWaylandWindow::fromWlSurface(surface); mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed); } @@ -863,6 +870,13 @@ void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_ Q_UNUSED(time); mFocus = 0; mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased); + + // As of Weston 1.5.90 there is no touch_frame after the last touch_up + // (i.e. when the last finger is released). To accommodate for this, issue a + // touch_frame. This cannot hurt since it is safe to call the touch_frame + // handler multiple times when there are no points left. + if (allTouchPointsReleased()) + touch_frame(); } void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) @@ -912,7 +926,7 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch tp.area = QRectF(0, 0, 8, 8); QMargins margins = win->frameMargins(); - tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x+margins.left(), y+margins.top()))); + tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x - margins.left(), y - margins.top()))); } tp.state = state; @@ -921,6 +935,15 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch mTouch->mTouchPoints.append(tp); } +bool QWaylandInputDevice::Touch::allTouchPointsReleased() +{ + for (int i = 0; i < mTouchPoints.count(); ++i) + if (mTouchPoints.at(i).state != Qt::TouchPointReleased) + return false; + + return true; +} + void QWaylandInputDevice::Touch::touch_frame() { // Copy all points, that are in the previous but not in the current list, as stationary. @@ -948,22 +971,24 @@ void QWaylandInputDevice::Touch::touch_frame() QWindow *window = mFocus ? mFocus->window() : 0; + if (mFocus) { + const QWindowSystemInterface::TouchPoint &tp = mTouchPoints.last(); + // When the touch event is received, the global pos is calculated with the margins + // in mind. Now we need to adjust again to get the correct local pos back. + QMargins margins = window->frameMargins(); + QPoint p = tp.area.center().toPoint(); + QPointF localPos(window->mapFromGlobal(QPoint(p.x() + margins.left(), p.y() + margins.top()))); + if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers())) + return; + } QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mTouchPoints); - bool allReleased = true; - for (int i = 0; i < mTouchPoints.count(); ++i) - if (mTouchPoints.at(i).state != Qt::TouchPointReleased) { - allReleased = false; - break; - } - - mPrevTouchPoints = mTouchPoints; - mTouchPoints.clear(); - - if (allReleased) { - QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mTouchPoints); + if (allTouchPointsReleased()) mPrevTouchPoints.clear(); - } + else + mPrevTouchPoints = mTouchPoints; + + mTouchPoints.clear(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 88eeed842ad..d9bf82e4f98 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -42,13 +42,14 @@ #include "qwaylandintegration_p.h" #include "qwaylanddisplay_p.h" +#include "qwaylandshmwindow_p.h" #include "qwaylandinputcontext_p.h" #include "qwaylandshmbackingstore_p.h" -#include "qwaylandshmwindow_p.h" #include "qwaylandnativeinterface_p.h" #include "qwaylandclipboard_p.h" #include "qwaylanddnd_p.h" #include "qwaylandwindowmanagerintegration_p.h" +#include "qwaylandscreen_p.h" #include "QtPlatformSupport/private/qgenericunixfontdatabase_p.h" #include @@ -127,9 +128,6 @@ QWaylandIntegration::QWaylandIntegration() mClipboard = new QWaylandClipboard(mDisplay); mDrag = new QWaylandDrag(mDisplay); - foreach (QPlatformScreen *screen, mDisplay->screens()) - screenAdded(screen); - mInputContext.reset(new QWaylandInputContext(mDisplay)); } @@ -162,14 +160,18 @@ bool QWaylandIntegration::hasCapability(QPlatformIntegration::Capability cap) co case MultipleWindows: case NonFullScreenWindows: return true; + case RasterGLSurface: + return true; default: return QPlatformIntegration::hasCapability(cap); } } QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) const { - if (window->surfaceType() == QWindow::OpenGLSurface && mDisplay->clientBufferIntegration()) + if ((window->surfaceType() == QWindow::OpenGLSurface || window->surfaceType() == QWindow::RasterGLSurface) + && mDisplay->clientBufferIntegration()) return mDisplay->clientBufferIntegration()->createEglWindow(window); + return new QWaylandShmWindow(window); } @@ -255,7 +257,7 @@ QWaylandClientBufferIntegration *QWaylandIntegration::clientBufferIntegration() if (!mClientBufferIntegrationInitialized) const_cast(this)->initializeClientBufferIntegration(); - return mClientBufferIntegration; + return mClientBufferIntegration && mClientBufferIntegration->isValid() ? mClientBufferIntegration : 0; } QWaylandServerBufferIntegration *QWaylandIntegration::serverBufferIntegration() const @@ -291,7 +293,7 @@ void QWaylandIntegration::initializeClientBufferIntegration() } if (targetKey.isEmpty()) { - qWarning("Failed to determin what client buffer integration to use"); + qWarning("Failed to determine what client buffer integration to use"); return; } diff --git a/src/plugins/platforms/wayland/qwaylandintegration_p.h b/src/plugins/platforms/wayland/qwaylandintegration_p.h index 025e0b4df61..bbe98285389 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration_p.h +++ b/src/plugins/platforms/wayland/qwaylandintegration_p.h @@ -110,6 +110,8 @@ private: bool mClientBufferIntegrationInitialized; bool mServerBufferIntegrationInitialized; bool mShellIntegrationInitialized; + + friend class QWaylandDisplay; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandnativeinterface_p.h b/src/plugins/platforms/wayland/qwaylandnativeinterface_p.h index 536cbe8dd53..6c0be2d3c8d 100644 --- a/src/plugins/platforms/wayland/qwaylandnativeinterface_p.h +++ b/src/plugins/platforms/wayland/qwaylandnativeinterface_p.h @@ -68,8 +68,6 @@ public: void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); void emitWindowPropertyChanged(QPlatformWindow *window, const QString &name); -private: - static QWaylandScreen *qPlatformScreenForWindow(QWindow *window); private: QWaylandIntegration *m_integration; diff --git a/src/plugins/platforms/wayland/qwaylandqtkey.cpp b/src/plugins/platforms/wayland/qwaylandqtkey.cpp index 197914b0b9c..16562357f00 100644 --- a/src/plugins/platforms/wayland/qwaylandqtkey.cpp +++ b/src/plugins/platforms/wayland/qwaylandqtkey.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE QWaylandQtKeyExtension::QWaylandQtKeyExtension(QWaylandDisplay *display, uint32_t id) - : QtWayland::qt_key_extension(display->wl_registry(), id) + : QtWayland::qt_key_extension(display->wl_registry(), id, 2) , m_display(display) { } diff --git a/src/plugins/platforms/wayland/qwaylandscreen.cpp b/src/plugins/platforms/wayland/qwaylandscreen.cpp index 3432f247595..88667ae0d4f 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen.cpp +++ b/src/plugins/platforms/wayland/qwaylandscreen.cpp @@ -54,7 +54,9 @@ QT_BEGIN_NAMESPACE QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, uint32_t id) - : QtWayland::wl_output(waylandDisplay->wl_registry(), id) + : QPlatformScreen() + , QtWayland::wl_output(waylandDisplay->wl_registry(), id, 2) + , m_outputId(id) , mWaylandDisplay(waylandDisplay) , mExtendedOutput(0) , mDepth(32) @@ -93,6 +95,14 @@ QImage::Format QWaylandScreen::format() const return mFormat; } +QSizeF QWaylandScreen::physicalSize() const +{ + if (mPhysicalSize.isEmpty()) + return QPlatformScreen::physicalSize(); + else + return mPhysicalSize; +} + QDpi QWaylandScreen::logicalDpi() const { static int force_dpi = !qgetenv("QT_WAYLAND_FORCE_DPI").isEmpty() ? qgetenv("QT_WAYLAND_FORCE_DPI").toInt() : -1; @@ -151,16 +161,11 @@ void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refr QSize size(width, height); - if (size != mGeometry.size()) { + if (size != mGeometry.size()) mGeometry.setSize(size); - QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry); - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), mGeometry); - } - if (refresh != mRefreshRate) { + if (refresh != mRefreshRate) mRefreshRate = refresh; - QWindowSystemInterface::handleScreenRefreshRateChange(screen(), refreshRate()); - } } void QWaylandScreen::output_geometry(int32_t x, int32_t y, @@ -200,14 +205,17 @@ void QWaylandScreen::output_geometry(int32_t x, int32_t y, if (!model.isEmpty()) mOutputName = model; - QRect geom(x, y, width, height); + mPhysicalSize = QSize(width, height); + mGeometry.moveTopLeft(QPoint(x, y)); +} - if (mGeometry == geom) - return; - - mGeometry = geom; - QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry); - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), mGeometry); +void QWaylandScreen::output_done() +{ + // the done event is sent after all the geometry and the mode events are sent, + // and the last mode event to be sent is the active one, so we can trust the + // values of mGeometry and mRefreshRate here + QWindowSystemInterface::handleScreenGeometryChange(screen(), mGeometry, mGeometry); + QWindowSystemInterface::handleScreenRefreshRateChange(screen(), refreshRate()); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandscreen_p.h b/src/plugins/platforms/wayland/qwaylandscreen_p.h index 5d06227a5d3..866ac26ea2c 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen_p.h +++ b/src/plugins/platforms/wayland/qwaylandscreen_p.h @@ -65,6 +65,8 @@ public: int depth() const; QImage::Format format() const; + QSizeF physicalSize() const Q_DECL_OVERRIDE; + QDpi logicalDpi() const Q_DECL_OVERRIDE; void setOrientationUpdateMask(Qt::ScreenOrientations mask); @@ -77,6 +79,7 @@ public: QPlatformCursor *cursor() const; QWaylandCursor *waylandCursor() const { return mWaylandCursor; }; + uint32_t outputId() const { return m_outputId; } ::wl_output *output() { return object(); } QWaylandExtendedOutput *extendedOutput() const; @@ -92,7 +95,9 @@ private: const QString &make, const QString &model, int32_t transform) Q_DECL_OVERRIDE; + void output_done() Q_DECL_OVERRIDE; + int m_outputId; QWaylandDisplay *mWaylandDisplay; QWaylandExtendedOutput *mExtendedOutput; QRect mGeometry; diff --git a/src/plugins/platforms/wayland/qwaylandshellsurface.cpp b/src/plugins/platforms/wayland/qwaylandshellsurface.cpp index d68ae1b5d16..a3855dac0d6 100644 --- a/src/plugins/platforms/wayland/qwaylandshellsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandshellsurface.cpp @@ -50,6 +50,7 @@ QWaylandShellSurface::QWaylandShellSurface(QWaylandWindow *window) void QWaylandShellSurface::setWindowFlags(Qt::WindowFlags flags) { + Q_UNUSED(flags); } void QWaylandShellSurface::sendProperty(const QString &name, const QVariant &value) diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index 0677ed0d398..14e1285d37b 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -39,14 +39,12 @@ ** ****************************************************************************/ #include "qwaylandshmbackingstore_p.h" - -#include - +#include "qwaylandwindow_p.h" #include "qwaylanddisplay_p.h" -#include "qwaylandshmwindow_p.h" #include "qwaylandscreen_p.h" #include "qwaylanddecoration_p.h" +#include #include #include @@ -156,9 +154,7 @@ QWaylandShmBackingStore::~QWaylandShmBackingStore() QPaintDevice *QWaylandShmBackingStore::paintDevice() { - if (!windowDecoration()) - return mBackBuffer->image(); - return mBackBuffer->imageInsideMargins(windowDecorationMargins()); + return contentSurface(); } void QWaylandShmBackingStore::beginPaint(const QRegion &) @@ -166,13 +162,11 @@ void QWaylandShmBackingStore::beginPaint(const QRegion &) mPainting = true; ensureSize(); - if (waylandWindow()->attached() && mBackBuffer == waylandWindow()->attached() && mFrameCallback) { - QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); - Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); - waylandWindow->waitForFrameSync(); - } + QWaylandWindow *window = waylandWindow(); + if (window->attached() && mBackBuffer == window->attached() && mFrameCallback) + window->waitForFrameSync(); - waylandWindow()->setCanResize(false); + window->setCanResize(false); } void QWaylandShmBackingStore::endPaint() @@ -190,9 +184,15 @@ void QWaylandShmBackingStore::ensureSize() void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { + // Invoked when the window is of type RasterSurface or when the window is + // RasterGLSurface and there are no child widgets requiring OpenGL composition. + + // For the case of RasterGLSurface + having to compose, the composeAndFlush() is + // called instead. The default implementation from QPlatformBackingStore is sufficient + // however so no need to reimplement that. + Q_UNUSED(window); Q_UNUSED(offset); - Q_ASSERT(waylandWindow()->windowType() == QWaylandWindow::Shm); if (windowDecoration() && windowDecoration()->isDirty()) updateDecorations(); @@ -260,6 +260,11 @@ QImage *QWaylandShmBackingStore::entireSurface() const return mBackBuffer->image(); } +QImage *QWaylandShmBackingStore::contentSurface() const +{ + return windowDecoration() ? mBackBuffer->imageInsideMargins(windowDecorationMargins()) : mBackBuffer->image(); +} + void QWaylandShmBackingStore::updateDecorations() { QPainter decorationPainter(entireSurface()); @@ -302,11 +307,19 @@ QMargins QWaylandShmBackingStore::windowDecorationMargins() const return QMargins(); } -QWaylandShmWindow *QWaylandShmBackingStore::waylandWindow() const +QWaylandWindow *QWaylandShmBackingStore::waylandWindow() const { - return static_cast(window()->handle()); + return static_cast(window()->handle()); } +QImage QWaylandShmBackingStore::toImage() const +{ + // Invoked from QPlatformBackingStore::composeAndFlush() that is called + // instead of flush() for widgets that have renderToTexture children + // (QOpenGLWidget, QQuickWidget). + + return *contentSurface(); +} void QWaylandShmBackingStore::done(void *data, wl_callback *callback, uint32_t time) { @@ -315,7 +328,7 @@ void QWaylandShmBackingStore::done(void *data, wl_callback *callback, uint32_t t static_cast(data); if (callback != self->mFrameCallback) // others, like QWaylandWindow, may trigger callbacks too return; - QWaylandShmWindow *window = self->waylandWindow(); + QWaylandWindow *window = self->waylandWindow(); wl_callback_destroy(self->mFrameCallback); self->mFrameCallback = 0; diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h index 6097b5282c8..33f363f6873 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QWaylandDisplay; class QWaylandDecoration; -class QWaylandShmWindow; +class QWaylandWindow; class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer { public: @@ -87,11 +87,14 @@ public: QMargins windowDecorationMargins() const; QImage *entireSurface() const; + QImage *contentSurface() const; void ensureSize(); - QWaylandShmWindow *waylandWindow() const; + QWaylandWindow *waylandWindow() const; void iterateBuffer(); + QImage toImage() const Q_DECL_OVERRIDE; + private: void updateDecorations(); diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp index de87682ce70..431ed2fdb97 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp @@ -51,13 +51,11 @@ QT_BEGIN_NAMESPACE QWaylandShmWindow::QWaylandShmWindow(QWindow *window) : QWaylandWindow(window) - , mBackingStore(0) { } QWaylandShmWindow::~QWaylandShmWindow() { - } QWaylandWindow::WindowType QWaylandShmWindow::windowType() const @@ -65,9 +63,4 @@ QWaylandWindow::WindowType QWaylandShmWindow::windowType() const return QWaylandWindow::Shm; } -void QWaylandShmWindow::setBackingStore(QWaylandShmBackingStore *backingStore) -{ - mBackingStore = backingStore; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow_p.h b/src/plugins/platforms/wayland/qwaylandshmwindow_p.h index 83479f31303..47ee742699d 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandshmwindow_p.h @@ -47,8 +47,6 @@ QT_BEGIN_NAMESPACE -class QWaylandShmBackingStore; - class Q_WAYLAND_CLIENT_EXPORT QWaylandShmWindow : public QWaylandWindow { public: @@ -57,19 +55,8 @@ public: WindowType windowType() const; QSurfaceFormat format() const { return QSurfaceFormat(); } - - void setBackingStore(QWaylandShmBackingStore *backingStore); - QWaylandShmBackingStore *backingStore() const; - -private: - QWaylandShmBackingStore *mBackingStore; }; -inline QWaylandShmBackingStore *QWaylandShmWindow::backingStore() const -{ - return mBackingStore; -} - QT_END_NAMESPACE #endif // QWAYLANDSHMWINDOW_H diff --git a/src/plugins/platforms/wayland/qwaylandtouch.cpp b/src/plugins/platforms/wayland/qwaylandtouch.cpp index 71cc1c3cc98..3dabd1ea504 100644 --- a/src/plugins/platforms/wayland/qwaylandtouch.cpp +++ b/src/plugins/platforms/wayland/qwaylandtouch.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE QWaylandTouchExtension::QWaylandTouchExtension(QWaylandDisplay *display, uint32_t id) - : QtWayland::qt_touch_extension(display->wl_registry(), id), + : QtWayland::qt_touch_extension(display->wl_registry(), id, 1), mDisplay(display), mTouchDevice(0), mPointsLeft(0), diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 11d29045535..ec00d1af614 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -42,6 +42,7 @@ #include "qwaylandwindow_p.h" #include "qwaylandbuffer_p.h" +#include "qwaylanddatadevice_p.h" #include "qwaylanddisplay_p.h" #include "qwaylandinputdevice_p.h" #include "qwaylandscreen_p.h" @@ -132,6 +133,8 @@ QWaylandWindow::QWaylandWindow(QWindow *window) QWaylandWindow::~QWaylandWindow() { + delete mWindowDecoration; + if (isInitialized()) { delete mShellSurface; destroy(); @@ -458,6 +461,8 @@ void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orient case Qt::InvertedPortraitOrientation: transform = isPortrait ? WL_OUTPUT_TRANSFORM_180 : WL_OUTPUT_TRANSFORM_270; break; + default: + Q_UNREACHABLE(); } set_buffer_transform(transform); // set_buffer_transform is double buffered, we need to commit. @@ -498,8 +503,7 @@ bool QWaylandWindow::createDecoration() } } - static bool disableWaylandDecorations = !qgetenv("QT_WAYLAND_DISABLE_WINDOWDECORATION").isEmpty(); - if (disableWaylandDecorations) + if (!mDisplay->supportsWindowDecoration()) return false; bool decoration = false; @@ -596,6 +600,13 @@ void QWaylandWindow::handleMouseLeave(QWaylandInputDevice *inputDevice) restoreMouseCursor(inputDevice); } +bool QWaylandWindow::touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) +{ + if (!mWindowDecoration) + return false; + return mWindowDecoration->handleTouch(inputDevice, local, global, state, mods); +} + void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) { if (mWindowDecoration->handleMouse(inputDevice,local,global,b,mods)) @@ -648,6 +659,14 @@ void QWaylandWindow::requestActivateWindow() // we rely on compositor setting keyboard focus based on window stacking. } +void QWaylandWindow::unfocus() +{ + QWaylandInputDevice *inputDevice = mDisplay->currentInputDevice(); + if (inputDevice && inputDevice->dataDevice()) { + inputDevice->dataDevice()->invalidateSelectionOffer(); + } +} + bool QWaylandWindow::isExposed() const { if (mShellSurface) @@ -677,18 +696,21 @@ bool QWaylandWindow::setWindowStateInternal(Qt::WindowState state) // here. We use then this mState variable. mState = state; createDecoration(); - switch (state) { - case Qt::WindowFullScreen: - mShellSurface->setFullscreen(); - break; - case Qt::WindowMaximized: - mShellSurface->setMaximized(); - break; - case Qt::WindowMinimized: - mShellSurface->setMinimized(); - break; - default: - mShellSurface->setNormal(); + + if (mShellSurface) { + switch (state) { + case Qt::WindowFullScreen: + mShellSurface->setFullscreen(); + break; + case Qt::WindowMaximized: + mShellSurface->setMaximized(); + break; + case Qt::WindowMinimized: + mShellSurface->setMinimized(); + break; + default: + mShellSurface->setNormal(); + } } QWindowSystemInterface::handleWindowStateChanged(window(), mState); diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h index 85e9f429ee1..7da43c7b95f 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h @@ -63,6 +63,7 @@ class QWaylandSubSurface; class QWaylandDecoration; class QWaylandInputDevice; class QWaylandScreen; +class QWaylandShmBackingStore; class Q_WAYLAND_CLIENT_EXPORT QWaylandWindowConfigure { @@ -143,6 +144,7 @@ public: void requestActivateWindow() Q_DECL_OVERRIDE; bool isExposed() const Q_DECL_OVERRIDE; + void unfocus(); QWaylandDecoration *decoration() const; void setDecoration(QWaylandDecoration *decoration); @@ -157,6 +159,9 @@ public: void handleMouseEnter(QWaylandInputDevice *inputDevice); void handleMouseLeave(QWaylandInputDevice *inputDevice); + bool touchDragDecoration(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, + Qt::TouchPointState state, Qt::KeyboardModifiers mods); + bool createDecoration(); inline bool isMaximized() const { return mState == Qt::WindowMaximized; } @@ -181,6 +186,12 @@ public: QVariant property(const QString &name); QVariant property(const QString &name, const QVariant &defaultValue); + void setBackingStore(QWaylandShmBackingStore *backingStore) { mBackingStore = backingStore; } + QWaylandShmBackingStore *backingStore() const { return mBackingStore; } + + bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } + void propagateSizeHints() Q_DECL_OVERRIDE { } + public slots: void requestResize(); @@ -219,6 +230,8 @@ protected: Qt::WindowState mState; QRegion mMask; + QWaylandShmBackingStore *mBackingStore; + private: bool setWindowStateInternal(Qt::WindowState flags); void setGeometry_helper(const QRect &rect); diff --git a/src/plugins/platforms/wayland/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/qwaylandwindowmanagerintegration.cpp index c2e0153a55a..174ef93a548 100644 --- a/src/plugins/platforms/wayland/qwaylandwindowmanagerintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindowmanagerintegration.cpp @@ -95,7 +95,7 @@ void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(void *data, wl_reg { Q_UNUSED(version); if (interface == QStringLiteral("qt_windowmanager")) - static_cast(data)->init(registry, id); + static_cast(data)->init(registry, id, 1); } void QWaylandWindowManagerIntegration::windowmanager_hints(int32_t showIsFullScreen) diff --git a/src/plugins/platforms/wayland/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/qwaylandxdgshell.cpp index eb9f91c435f..8a96a0304b7 100644 --- a/src/plugins/platforms/wayland/qwaylandxdgshell.cpp +++ b/src/plugins/platforms/wayland/qwaylandxdgshell.cpp @@ -57,7 +57,7 @@ QWaylandXdgShell::QWaylandXdgShell(struct ::xdg_shell *shell) } QWaylandXdgShell::QWaylandXdgShell(struct ::wl_registry *registry, uint32_t id) - : QtWayland::xdg_shell(registry, id) + : QtWayland::xdg_shell(registry, id, 1) { use_unstable_version(QtWayland::xdg_shell::version_current); } diff --git a/src/tools/qtwaylandscanner/qtwaylandscanner.cpp b/src/tools/qtwaylandscanner/qtwaylandscanner.cpp index 475b9fec2c4..c99bf2b4815 100644 --- a/src/tools/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/tools/qtwaylandscanner/qtwaylandscanner.cpp @@ -822,13 +822,13 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf(" class %s %s\n {\n", clientExport.constData(), interfaceName); printf(" public:\n"); - printf(" %s(struct ::wl_registry *registry, int id);\n", interfaceName); + printf(" %s(struct ::wl_registry *registry, int id, int version);\n", interfaceName); printf(" %s(struct ::%s *object);\n", interfaceName, interfaceName); printf(" %s();\n", interfaceName); printf("\n"); printf(" virtual ~%s();\n", interfaceName); printf("\n"); - printf(" void init(struct ::wl_registry *registry, int id);\n"); + printf(" void init(struct ::wl_registry *registry, int id, int version);\n"); printf(" void init(struct ::%s *object);\n", interfaceName); printf("\n"); printf(" struct ::%s *object() { return m_%s; }\n", interfaceName, interfaceName); @@ -908,9 +908,9 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr bool hasEvents = !interface.events.isEmpty(); - printf(" %s::%s(struct ::wl_registry *registry, int id)\n", interfaceName, interfaceName); + printf(" %s::%s(struct ::wl_registry *registry, int id, int version)\n", interfaceName, interfaceName); printf(" {\n"); - printf(" init(registry, id);\n"); + printf(" init(registry, id, version);\n"); printf(" }\n"); printf("\n"); @@ -933,9 +933,9 @@ void process(QXmlStreamReader &xml, const QByteArray &headerPath, const QByteArr printf(" }\n"); printf("\n"); - printf(" void %s::init(struct ::wl_registry *registry, int id)\n", interfaceName); + printf(" void %s::init(struct ::wl_registry *registry, int id, int version)\n", interfaceName); printf(" {\n"); - printf(" m_%s = static_cast(wl_registry_bind(registry, id, &%s_interface, %s_interface.version));\n", interfaceName, interfaceName, interfaceName, interfaceName); + printf(" m_%s = static_cast(wl_registry_bind(registry, id, &%s_interface, version));\n", interfaceName, interfaceName, interfaceName); if (hasEvents) printf(" init_listener();\n"); printf(" }\n"); diff --git a/tests/auto/wayland/mockcompositor.cpp b/tests/auto/wayland/mockcompositor.cpp index bb4f10fd942..cb0e6576e90 100644 --- a/tests/auto/wayland/mockcompositor.cpp +++ b/tests/auto/wayland/mockcompositor.cpp @@ -135,8 +135,13 @@ QSharedPointer MockCompositor::surface() QSharedPointer result; lock(); QVector surfaces = m_compositor->surfaces(); - if (!surfaces.isEmpty()) - result = surfaces.first()->mockSurface(); + foreach (Impl::Surface *surface, surfaces) { + // we don't want to mistake the cursor surface for a window surface + if (surface->isMapped()) { + result = surface->mockSurface(); + break; + } + } unlock(); return result; } @@ -189,11 +194,6 @@ void *MockCompositor::run(void *data) return 0; } -void MockCompositor::discardSurfaces() -{ - m_compositor->discardSurfaces(); -} - namespace Impl { Compositor::Compositor() @@ -209,6 +209,8 @@ Compositor::Compositor() wl_display_add_global(m_display, &wl_compositor_interface, this, bindCompositor); + m_data_device_manager.reset(new DataDeviceManager(this, m_display)); + wl_display_init_shm(m_display); m_seat.reset(new Seat(this, m_display)); @@ -298,10 +300,5 @@ void Compositor::removeSurface(Surface *surface) m_pointer->setFocus(0, QPoint()); } -void Compositor::discardSurfaces() -{ - m_surfaces.clear(); -} - } diff --git a/tests/auto/wayland/mockcompositor.h b/tests/auto/wayland/mockcompositor.h index 68e55d3562c..03d3a96a354 100644 --- a/tests/auto/wayland/mockcompositor.h +++ b/tests/auto/wayland/mockcompositor.h @@ -61,6 +61,7 @@ typedef void (**Implementation)(void); class Keyboard; class Pointer; class Seat; +class DataDeviceManager; class Surface; class Compositor @@ -81,7 +82,6 @@ public: void addSurface(Surface *surface); void removeSurface(Surface *surface); - void discardSurfaces(); static void setKeyboardFocus(void *data, const QList ¶meters); static void sendMousePress(void *data, const QList ¶meters); @@ -112,6 +112,7 @@ private: QScopedPointer m_seat; Pointer *m_pointer; Keyboard *m_keyboard; + QScopedPointer m_data_device_manager; QVector m_surfaces; }; @@ -155,7 +156,6 @@ public: void sendKeyRelease(const QSharedPointer &surface, uint code); QSharedPointer surface(); - void discardSurfaces(); void lock(); void unlock(); diff --git a/tests/auto/wayland/mockinput.cpp b/tests/auto/wayland/mockinput.cpp index 7dbb735ed22..fbe44de41cd 100644 --- a/tests/auto/wayland/mockinput.cpp +++ b/tests/auto/wayland/mockinput.cpp @@ -130,6 +130,8 @@ void Seat::seat_get_pointer(Resource *resource, uint32_t id) Keyboard::Keyboard(Compositor *compositor) : wl_keyboard() , m_compositor(compositor) + , m_focusResource(Q_NULLPTR) + , m_focus(Q_NULLPTR) { } @@ -174,6 +176,8 @@ void Keyboard::keyboard_destroy_resource(wl_keyboard::Resource *resource) Pointer::Pointer(Compositor *compositor) : wl_pointer() , m_compositor(compositor) + , m_focusResource(Q_NULLPTR) + , m_focus(Q_NULLPTR) { } @@ -223,4 +227,35 @@ void Pointer::pointer_destroy_resource(wl_pointer::Resource *resource) m_focusResource = 0; } +DataDevice::DataDevice(Compositor *compositor) + : wl_data_device() + , m_compositor(compositor) +{ + +} + +DataDevice::~DataDevice() +{ + +} + +DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display) + : wl_data_device_manager(display) + , m_compositor(compositor) +{ + +} + +DataDeviceManager::~DataDeviceManager() +{ + +} + +void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) +{ + if (!m_data_device) + m_data_device.reset(new DataDevice(m_compositor)); + m_data_device->add(resource->client(), id); +} + } diff --git a/tests/auto/wayland/mockinput.h b/tests/auto/wayland/mockinput.h index 128758cad93..16b19b4fb2a 100644 --- a/tests/auto/wayland/mockinput.h +++ b/tests/auto/wayland/mockinput.h @@ -120,6 +120,31 @@ private: Surface *m_focus; }; +class DataDevice : public QtWaylandServer::wl_data_device +{ +public: + DataDevice(Compositor *compositor); + ~DataDevice(); + +private: + Compositor *m_compositor; +}; + +class DataDeviceManager : public QtWaylandServer::wl_data_device_manager +{ +public: + DataDeviceManager(Compositor *compositor, struct ::wl_display *display); + ~DataDeviceManager(); + +protected: + void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE; + +private: + Compositor *m_compositor; + + QScopedPointer m_data_device; +}; + } #endif // MOCKINPUT_H diff --git a/tests/auto/wayland/mockshell.cpp b/tests/auto/wayland/mockshell.cpp index 0d841f64c24..2a5969f70de 100644 --- a/tests/auto/wayland/mockshell.cpp +++ b/tests/auto/wayland/mockshell.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "mockcompositor.h" +#include "mocksurface.h" namespace Impl { @@ -173,6 +174,8 @@ static void get_shell_surface(wl_client *client, wl_resource *compositorResource Q_UNUSED(compositorResource); wl_client_add_object(client, &wl_shell_surface_interface, &shellSurfaceInterface, id, surfaceResource->data); + Surface *surf = Surface::fromResource(surfaceResource); + surf->map(); } void Compositor::bindShell(wl_client *client, void *compositorData, uint32_t version, uint32_t id) diff --git a/tests/auto/wayland/mocksurface.cpp b/tests/auto/wayland/mocksurface.cpp index d5e0367a080..2e4c2bc73a4 100644 --- a/tests/auto/wayland/mocksurface.cpp +++ b/tests/auto/wayland/mocksurface.cpp @@ -46,10 +46,11 @@ namespace Impl { Surface::Surface(wl_client *client, uint32_t id, Compositor *compositor) : QtWaylandServer::wl_surface(client, id) + , m_buffer(Q_NULLPTR) , m_compositor(compositor) , m_mockSurface(new MockSurface(this)) + , m_mapped(false) { - wl_list_init(&m_frameCallbackList); } Surface::~Surface() @@ -57,6 +58,21 @@ Surface::~Surface() m_mockSurface->m_surface = 0; } +void Surface::map() +{ + m_mapped = true; +} + +bool Surface::isMapped() const +{ + return m_mapped; +} + +Surface *Surface::fromResource(struct ::wl_resource *resource) +{ + return static_cast(Resource::fromResource(resource)->surface_object); +} + void Surface::surface_destroy_resource(Resource *) { compositor()->removeSurface(this); @@ -88,47 +104,44 @@ void Surface::surface_damage(Resource *resource, Q_UNUSED(y); Q_UNUSED(width); Q_UNUSED(height); - - if (!m_buffer) - return; - -#if WAYLAND_VERSION_CHECK(1, 2, 0) - struct ::wl_shm_buffer *shm_buffer = wl_shm_buffer_get(m_buffer); -#else - struct ::wl_buffer *shm_buffer = 0; - if (wl_buffer_is_shm(static_cast(m_buffer->data))) - shm_buffer = static_cast(m_buffer->data); -#endif - - if (shm_buffer) { - int stride = wl_shm_buffer_get_stride(shm_buffer); - uint format = wl_shm_buffer_get_format(shm_buffer); - Q_UNUSED(format); - void *data = wl_shm_buffer_get_data(shm_buffer); - const uchar *char_data = static_cast(data); - QImage img(char_data, wl_shm_buffer_get_width(shm_buffer), wl_shm_buffer_get_height(shm_buffer), stride, QImage::Format_ARGB32_Premultiplied); - m_mockSurface->image = img; - } - - wl_resource *frameCallback; - wl_list_for_each(frameCallback, &m_frameCallbackList, link) { - wl_callback_send_done(frameCallback, m_compositor->time()); - wl_resource_destroy(frameCallback); - } - - wl_list_init(&m_frameCallbackList); } void Surface::surface_frame(Resource *resource, uint32_t callback) { wl_resource *frameCallback = wl_client_add_object(resource->client(), &wl_callback_interface, 0, callback, this); - wl_list_insert(&m_frameCallbackList, &frameCallback->link); + m_frameCallbackList << frameCallback; } void Surface::surface_commit(Resource *resource) { Q_UNUSED(resource); + + if (m_buffer) { +#if WAYLAND_VERSION_CHECK(1, 2, 0) + struct ::wl_shm_buffer *shm_buffer = wl_shm_buffer_get(m_buffer); +#else + struct ::wl_buffer *shm_buffer = 0; + if (wl_buffer_is_shm(static_cast(m_buffer->data))) + shm_buffer = static_cast(m_buffer->data); +#endif + + if (shm_buffer) { + int stride = wl_shm_buffer_get_stride(shm_buffer); + uint format = wl_shm_buffer_get_format(shm_buffer); + Q_UNUSED(format); + void *data = wl_shm_buffer_get_data(shm_buffer); + const uchar *char_data = static_cast(data); + QImage img(char_data, wl_shm_buffer_get_width(shm_buffer), wl_shm_buffer_get_height(shm_buffer), stride, QImage::Format_ARGB32_Premultiplied); + m_mockSurface->image = img; + } + } + + foreach (wl_resource *frameCallback, m_frameCallbackList) { + wl_callback_send_done(frameCallback, m_compositor->time()); + wl_resource_destroy(frameCallback); + } + m_frameCallbackList.clear(); } } diff --git a/tests/auto/wayland/mocksurface.h b/tests/auto/wayland/mocksurface.h index 49260f51b38..f2a2f4eb355 100644 --- a/tests/auto/wayland/mocksurface.h +++ b/tests/auto/wayland/mocksurface.h @@ -54,6 +54,9 @@ public: ~Surface(); Compositor *compositor() const { return m_compositor; } + static Surface *fromResource(struct ::wl_resource *resource); + void map(); + bool isMapped() const; QSharedPointer mockSurface() const { return m_mockSurface; } @@ -74,8 +77,8 @@ private: Compositor *m_compositor; QSharedPointer m_mockSurface; - - wl_list m_frameCallbackList; + QList m_frameCallbackList; + bool m_mapped; }; } diff --git a/tests/auto/wayland/tst_client.cpp b/tests/auto/wayland/tst_client.cpp index 9c3138bcb09..113f9d9a850 100644 --- a/tests/auto/wayland/tst_client.cpp +++ b/tests/auto/wayland/tst_client.cpp @@ -149,11 +149,7 @@ private: void tst_WaylandClient::screen() { - QCoreApplication::processEvents(QEventLoop::AllEvents); - QTRY_COMPARE(QGuiApplication::primaryScreen()->size(), screenSize); - // discard the cursor surface created by the QWaylandInputDevice - compositor->discardSurfaces(); } void tst_WaylandClient::createDestroyWindow() @@ -252,6 +248,11 @@ int main(int argc, char **argv) setenv("XDG_RUNTIME_DIR", ".", 1); setenv("QT_QPA_PLATFORM", "wayland", 1); // force QGuiApplication to use wayland plugin + // wayland-egl hangs in the test setup when we try to initialize. Until it gets + // figured out, avoid clientBufferIntegration() from being called in + // QWaylandWindow::createDecorations(). + setenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1", 1); + MockCompositor compositor; compositor.setOutputGeometry(QRect(QPoint(), screenSize));