diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2019-09-16 23:10:27 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2019-09-16 23:11:30 +0200 |
commit | b95e6e5babc5e70b25076aed8080ee37773000cb (patch) | |
tree | 21170a1e7062e61507104f9ed0f3be2ca9b6257b /src | |
parent | 3e9fe00c4e4ae4c096a960b4a3b432fca546007a (diff) | |
parent | fb1f6733b6d98d84f8abd89623c3878ed4a62573 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/qt6
Conflicts:
.qmake.conf
Change-Id: Ifb5723b11bf5fe5bb3583018f496beba17c6bf40
Diffstat (limited to 'src')
42 files changed, 1748 insertions, 205 deletions
diff --git a/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml b/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml new file mode 100644 index 000000000..9c06cdcba --- /dev/null +++ b/src/3rdparty/protocol/idle-inhibit-unstable-v1.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="idle_inhibit_unstable_v1"> + + <copyright> + Copyright © 2015 Samsung Electronics Co., Ltd + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="zwp_idle_inhibit_manager_v1" version="1"> + <description summary="control behavior when display idles"> + This interface permits inhibiting the idle behavior such as screen + blanking, locking, and screensaving. The client binds the idle manager + globally, then creates idle-inhibitor objects for each surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the idle inhibitor object"> + Destroy the inhibit manager. + </description> + </request> + + <request name="create_inhibitor"> + <description summary="create a new inhibitor object"> + Create a new inhibitor object associated with the given surface. + </description> + <arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/> + <arg name="surface" type="object" interface="wl_surface" + summary="the surface that inhibits the idle behavior"/> + </request> + + </interface> + + <interface name="zwp_idle_inhibitor_v1" version="1"> + <description summary="context object for inhibiting idle behavior"> + An idle inhibitor prevents the output that the associated surface is + visible on from being set to a state where it is not visually usable due + to lack of user interaction (e.g. blanked, dimmed, locked, set to power + save, etc.) Any screensaver processes are also blocked from displaying. + + If the surface is destroyed, unmapped, becomes occluded, loses + visibility, or otherwise becomes not visually relevant for the user, the + idle inhibitor will not be honored by the compositor; if the surface + subsequently regains visibility the inhibitor takes effect once again. + Likewise, the inhibitor isn't honored if the system was already idled at + the time the inhibitor was established, although if the system later + de-idles and re-idles the inhibitor will take effect. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the idle inhibitor object"> + Remove the inhibitor effect from the associated wl_surface. + </description> + </request> + + </interface> +</protocol> diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json index e6f90698b..c49ead4f3 100644 --- a/src/3rdparty/protocol/qt_attribution.json +++ b/src/3rdparty/protocol/qt_attribution.json @@ -127,8 +127,9 @@ Copyright (c) 2013 BMW Car IT GmbH" "Id": "wayland-xdg-output-protocol", "Name": "Wayland XDG Output Protocol", "QDocModule": "qtwaylandcompositor", - "QtUsage": "Used in the Qt Wayland platform plugin.", + "QtUsage": "Used in the Qt Wayland Compositor API, and the Qt Wayland platform plugin.", "Files": "xdg-output-unstable-v1.xml", + "Description": "The XDG Output protocol is an extended way to describe output regions under Wayland", "Homepage": "https://wayland.freedesktop.org", "Version": "unstable v1, version 2", diff --git a/src/client/client.pro b/src/client/client.pro index 4f4c58328..d0ae9009e 100644 --- a/src/client/client.pro +++ b/src/client/client.pro @@ -20,7 +20,7 @@ qtConfig(xkbcommon) { } qtHaveModule(linuxaccessibility_support_private): \ - QT += linuxaccessibility_support_private + QT_PRIVATE += linuxaccessibility_support_private QMAKE_USE += wayland-client diff --git a/src/client/qwaylandcursor.cpp b/src/client/qwaylandcursor.cpp index 165df7762..4356b23a0 100644 --- a/src/client/qwaylandcursor.cpp +++ b/src/client/qwaylandcursor.cpp @@ -48,6 +48,8 @@ #include <wayland-cursor.h> +#include <algorithm> + QT_BEGIN_NAMESPACE namespace QtWaylandClient { @@ -75,7 +77,10 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) if (struct wl_cursor *cursor = m_cursors.value(shape, nullptr)) return cursor; - static const QMultiMap<WaylandCursor, QByteArray>cursorNamesMap { + static Q_CONSTEXPR struct ShapeAndName { + WaylandCursor shape; + const char name[33]; + } cursorNamesMap[] = { {ArrowCursor, "left_ptr"}, {ArrowCursor, "default"}, {ArrowCursor, "top_left_arrow"}, @@ -193,9 +198,14 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) {ResizeSouthWestCursor, "bottom_left_corner"}, }; - QList<QByteArray> cursorNames = cursorNamesMap.values(shape); - for (auto &name : qAsConst(cursorNames)) { - if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, name.constData())) { + const auto byShape = [](ShapeAndName lhs, ShapeAndName rhs) { + return lhs.shape < rhs.shape; + }; + Q_ASSERT(std::is_sorted(std::begin(cursorNamesMap), std::end(cursorNamesMap), byShape)); + const auto p = std::equal_range(std::begin(cursorNamesMap), std::end(cursorNamesMap), + ShapeAndName{shape, ""}, byShape); + for (auto it = p.first; it != p.second; ++it) { + if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) { m_cursors.insert(shape, cursor); return cursor; } diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 19e36ccba..8aa0239d0 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -442,6 +442,21 @@ QWaylandInputDevice::Touch *QWaylandInputDevice::createTouch(QWaylandInputDevice return new Touch(device); } +QWaylandInputDevice::Keyboard *QWaylandInputDevice::keyboard() const +{ + return mKeyboard; +} + +QWaylandInputDevice::Pointer *QWaylandInputDevice::pointer() const +{ + return mPointer; +} + +QWaylandInputDevice::Touch *QWaylandInputDevice::touch() const +{ + return mTouch; +} + void QWaylandInputDevice::handleEndDrag() { if (mTouch) @@ -602,7 +617,7 @@ void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surf invalidateFocus(); } mFocus = window->waylandSurface(); - connect(mFocus, &QObject::destroyed, this, &Pointer::handleFocusDestroyed); + connect(mFocus.data(), &QObject::destroyed, this, &Pointer::handleFocusDestroyed); mSurfacePos = QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy)); mGlobalPos = window->window()->mapToGlobal(mSurfacePos.toPoint()); @@ -774,8 +789,10 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time void QWaylandInputDevice::Pointer::invalidateFocus() { - disconnect(mFocus, &QObject::destroyed, this, &Pointer::handleFocusDestroyed); - mFocus = nullptr; + if (mFocus) { + disconnect(mFocus.data(), &QObject::destroyed, this, &Pointer::handleFocusDestroyed); + mFocus = nullptr; + } mEnterSerial = 0; } diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 06ba5d566..4ac1dca35 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -148,6 +148,10 @@ public: virtual Pointer *createPointer(QWaylandInputDevice *device); virtual Touch *createTouch(QWaylandInputDevice *device); + Keyboard *keyboard() const; + Pointer *pointer() const; + Touch *touch() const; + private: QWaylandDisplay *mQDisplay = nullptr; struct wl_display *mDisplay = nullptr; @@ -248,6 +252,8 @@ public: Qt::KeyboardModifiers modifiers() const; + struct ::wl_keyboard *wl_keyboard() { return QtWayland::wl_keyboard::object(); } + private slots: void handleFocusDestroyed(); void handleFocusLost(); @@ -284,6 +290,8 @@ public: #endif QWaylandInputDevice *seat() const { return mParent; } + struct ::wl_pointer *wl_pointer() { return QtWayland::wl_pointer::object(); } + protected: void pointer_enter(uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy) override; @@ -377,6 +385,8 @@ public: bool allTouchPointsReleased(); void releasePoints(); + struct ::wl_touch *wl_touch() { return QtWayland::wl_touch::object(); } + QWaylandInputDevice *mParent = nullptr; QPointer<QWaylandWindow> mFocus; QList<QWindowSystemInterface::TouchPoint> mTouchPoints; diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp index 078e5be19..7f79d6b98 100644 --- a/src/client/qwaylandintegration.cpp +++ b/src/client/qwaylandintegration.cpp @@ -272,7 +272,7 @@ QPlatformAccessibility *QWaylandIntegration::accessibility() const { if (!mAccessibility) { #ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE - Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QXcbIntegration", + Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QWaylandIntegration", "Initializing accessibility without event-dispatcher!"); mAccessibility.reset(new QSpiAccessibleBridge()); #else diff --git a/src/client/qwaylandnativeinterface.cpp b/src/client/qwaylandnativeinterface.cpp index cf227d489..b4ecc0090 100644 --- a/src/client/qwaylandnativeinterface.cpp +++ b/src/client/qwaylandnativeinterface.cpp @@ -47,6 +47,7 @@ #include "qwaylanddisplay_p.h" #include "qwaylandwindowmanagerintegration_p.h" #include "qwaylandscreen_p.h" +#include "qwaylandinputdevice_p.h" #include <QtGui/private/qguiapplication_p.h> #include <QtGui/QScreen> #include <QtWaylandClient/private/qwaylandclientbufferintegration_p.h> @@ -76,6 +77,27 @@ void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &re if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration()) return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay); + if (lowerCaseResource == "wl_seat") + return m_integration->display()->defaultInputDevice()->wl_seat(); + if (lowerCaseResource == "wl_keyboard") { + auto *keyboard = m_integration->display()->defaultInputDevice()->keyboard(); + if (keyboard) + return keyboard->wl_keyboard(); + return nullptr; + } + if (lowerCaseResource == "wl_pointer") { + auto *pointer = m_integration->display()->defaultInputDevice()->pointer(); + if (pointer) + return pointer->wl_pointer(); + return nullptr; + } + if (lowerCaseResource == "wl_touch") { + auto *touch = m_integration->display()->defaultInputDevice()->touch(); + if (touch) + return touch->wl_touch(); + return nullptr; + } + return nullptr; } diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp index d768e7fc2..9b5971a21 100644 --- a/src/client/qwaylandshmbackingstore.cpp +++ b/src/client/qwaylandshmbackingstore.cpp @@ -249,7 +249,7 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size) if (b->size() == size) { return b; } else { - mBuffers.removeOne(b); + mBuffers.remove(b); if (mBackBuffer == b) mBackBuffer = nullptr; delete b; @@ -257,11 +257,11 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size) } } - static const int MAX_BUFFERS = 5; - if (mBuffers.count() < MAX_BUFFERS) { + static const size_t MAX_BUFFERS = 5; + if (mBuffers.size() < MAX_BUFFERS) { QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); QWaylandShmBuffer *b = new QWaylandShmBuffer(mDisplay, size, format, waylandWindow()->scale()); - mBuffers.prepend(b); + mBuffers.push_front(b); return b; } return nullptr; @@ -300,9 +300,9 @@ void QWaylandShmBackingStore::resize(const QSize &size) // ensure the new buffer is at the beginning of the list so next time getBuffer() will pick // it if possible - if (mBuffers.first() != buffer) { - mBuffers.removeOne(buffer); - mBuffers.prepend(buffer); + if (mBuffers.front() != buffer) { + mBuffers.remove(buffer); + mBuffers.push_front(buffer); } if (windowDecoration() && window()->isVisible() && oldSizeInBytes != newSizeInBytes) diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h index 88ecfc5ec..8a85cd7f3 100644 --- a/src/client/qwaylandshmbackingstore_p.h +++ b/src/client/qwaylandshmbackingstore_p.h @@ -57,7 +57,8 @@ #include <QtGui/QImage> #include <qpa/qplatformwindow.h> #include <QMutex> -#include <QLinkedList> + +#include <list> QT_BEGIN_NAMESPACE @@ -116,7 +117,7 @@ private: QWaylandShmBuffer *getBuffer(const QSize &size); QWaylandDisplay *mDisplay = nullptr; - QLinkedList<QWaylandShmBuffer *> mBuffers; + std::list<QWaylandShmBuffer *> mBuffers; QWaylandShmBuffer *mFrontBuffer = nullptr; QWaylandShmBuffer *mBackBuffer = nullptr; bool mPainting = false; diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 9a58ec39a..ce58003cc 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -249,6 +249,13 @@ void QWaylandWindow::reset(bool sendDestroyEvent) mFrameCallback = nullptr; } + int timerId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1); + if (timerId != -1) { + killTimer(timerId); + } + mWaitingForFrameCallback = false; + mFrameCallbackTimedOut = false; + mMask = QRegion(); mQueuedBuffer = nullptr; } @@ -343,7 +350,7 @@ void QWaylandWindow::setGeometry(const QRect &rect) mSentInitialResize = true; } QRect exposeGeometry(QPoint(), geometry().size()); - if (exposeGeometry != mLastExposeGeometry) + if (isExposed() && !mInResizeFromApplyConfigure && exposeGeometry != mLastExposeGeometry) sendExposeEvent(exposeGeometry); if (mShellSurface) @@ -358,7 +365,9 @@ void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, cons QRect geometry(windowGeometry().topLeft(), QSize(widthWithoutMargins, heightWithoutMargins)); mOffset += offset; + mInResizeFromApplyConfigure = true; setGeometry(geometry); + mInResizeFromApplyConfigure = false; } void QWaylandWindow::sendExposeEvent(const QRect &rect) @@ -573,29 +582,34 @@ const wl_callback_listener QWaylandWindow::callbackListener = { Q_UNUSED(callback); Q_UNUSED(time); auto *window = static_cast<QWaylandWindow*>(data); - if (window->thread() != QThread::currentThread()) - QMetaObject::invokeMethod(window, [=] { window->handleFrameCallback(); }, Qt::QueuedConnection); - else - window->handleFrameCallback(); + window->handleFrameCallback(); } }; void QWaylandWindow::handleFrameCallback() { - bool wasExposed = isExposed(); + // Stop the timer and stop waiting immediately + int timerId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1); + mWaitingForFrameCallback = false; - if (mFrameCallbackTimerId != -1) { - killTimer(mFrameCallbackTimerId); - mFrameCallbackTimerId = -1; - } + // The rest can wait until we can run it on the correct thread + auto doHandleExpose = [this, timerId]() { + if (timerId != -1) + killTimer(timerId); - mWaitingForFrameCallback = false; - mFrameCallbackTimedOut = false; + bool wasExposed = isExposed(); + mFrameCallbackTimedOut = false; + if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed? + sendExposeEvent(QRect(QPoint(), geometry().size())); + if (wasExposed && hasPendingUpdateRequest()) + deliverUpdateRequest(); + }; - if (!wasExposed && isExposed()) - sendExposeEvent(QRect(QPoint(), geometry().size())); - if (wasExposed && hasPendingUpdateRequest()) - deliverUpdateRequest(); + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, doHandleExpose); + } else { + doHandleExpose(); + } } QMutex QWaylandWindow::mFrameSyncMutex; @@ -617,11 +631,11 @@ bool QWaylandWindow::waitForFrameSync(int timeout) } // Stop current frame timer if any, can't use killTimer directly, because we might be on a diffent thread - if (mFrameCallbackTimerId != -1) { - int id = mFrameCallbackTimerId; - mFrameCallbackTimerId = -1; - QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); - } + // Ordered semantics is needed to avoid stopping the timer twice and not miss it when it's + // started by other writes + int fcbId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1); + if (fcbId != -1) + QMetaObject::invokeMethod(this, [this, fcbId] { killTimer(fcbId); }, Qt::QueuedConnection); return !mWaitingForFrameCallback; } @@ -1077,9 +1091,9 @@ void QWaylandWindow::timerEvent(QTimerEvent *event) } } - if (event->timerId() == mFrameCallbackTimerId) { - killTimer(mFrameCallbackTimerId); - mFrameCallbackTimerId = -1; + + if (mFrameCallbackTimerId.testAndSetOrdered(event->timerId(), -1)) { + killTimer(event->timerId()); qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; mFrameCallbackTimedOut = true; mWaitingForUpdate = false; @@ -1132,7 +1146,7 @@ void QWaylandWindow::handleUpdate() // ignore it if it times out before it's cleaned up by the invokeMethod call. int id = mFallbackUpdateTimerId; mFallbackUpdateTimerId = -1; - QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); + QMetaObject::invokeMethod(this, [this, id] { killTimer(id); }, Qt::QueuedConnection); } mFrameCallback = mSurface->frame(); @@ -1141,14 +1155,12 @@ void QWaylandWindow::handleUpdate() mWaitingForUpdate = false; // Stop current frame timer if any, can't use killTimer directly, see comment above. - if (mFrameCallbackTimerId != -1) { - int id = mFrameCallbackTimerId; - mFrameCallbackTimerId = -1; - QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); - } + int fcbId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1); + if (fcbId != -1) + QMetaObject::invokeMethod(this, [this, fcbId] { killTimer(fcbId); }, Qt::QueuedConnection); // Start a timer for handling the case when the compositor stops sending frame callbacks. - QMetaObject::invokeMethod(this, [=] { // Again; can't do it directly + QMetaObject::invokeMethod(this, [this] { // Again; can't do it directly if (mWaitingForFrameCallback) mFrameCallbackTimerId = startTimer(100); }, Qt::QueuedConnection); diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 5eadc02c8..8d8565d77 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -219,7 +219,7 @@ protected: WId mWindowId; bool mWaitingForFrameCallback = false; bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out - int mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback + QAtomicInt mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback struct ::wl_callback *mFrameCallback = nullptr; struct ::wl_event_queue *mFrameQueue = nullptr; QWaitCondition mFrameSyncWait; @@ -264,6 +264,7 @@ private: void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); void handleScreensChanged(); + bool mInResizeFromApplyConfigure = false; QRect mLastExposeGeometry; static const wl_callback_listener callbackListener; diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 2d10c6384..e2d617c37 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -302,7 +302,7 @@ void QWaylandCompositorPrivate::addPolishObject(QObject *object) if (initialized) { QCoreApplication::postEvent(object, new QEvent(QEvent::Polish)); } else { - polish_objects.append(object); + polish_objects.push_back(object); } } diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h index 2c9624216..2437533dd 100644 --- a/src/compositor/compositor_api/qwaylandcompositor_p.h +++ b/src/compositor/compositor_api/qwaylandcompositor_p.h @@ -60,6 +60,8 @@ #include <QtWaylandCompositor/private/qwayland-server-wayland.h> +#include <vector> + #if QT_CONFIG(xkbcommon) #include <QtXkbCommonSupport/private/qxkbcommon_p.h> #endif @@ -175,7 +177,7 @@ protected: bool retainSelection = false; bool preInitialized = false; bool initialized = false; - QList<QPointer<QObject> > polish_objects; + std::vector<QPointer<QObject> > polish_objects; #if QT_CONFIG(xkbcommon) QXkbCommon::ScopedXKBContext mXkbContext; diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index 452be4363..c5ec008d7 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -366,6 +366,13 @@ void QWaylandKeyboardPrivate::createXKBKeymap() QByteArray variant = keymap->variant().toLocal8Bit(); QByteArray options = keymap->options().toLocal8Bit(); + if (!layout.isEmpty() && !layout.contains("us")) { + // This is needed for shortucts like "ctrl+c" to function even when + // user has selected only non-latin keyboard layouts, e.g. 'ru'. + layout.append(",us"); + variant.append(","); + } + struct xkb_rule_names rule_names = { rules.constData(), model.constData(), diff --git a/src/compositor/compositor_api/qwaylandoutput.cpp b/src/compositor/compositor_api/qwaylandoutput.cpp index 7a02d4caa..601f692af 100644 --- a/src/compositor/compositor_api/qwaylandoutput.cpp +++ b/src/compositor/compositor_api/qwaylandoutput.cpp @@ -48,6 +48,7 @@ #include <QtWaylandCompositor/private/qwaylandcompositor_p.h> #include <QtWaylandCompositor/private/qwaylandview_p.h> #include <QtWaylandCompositor/private/qwaylandutils_p.h> +#include <QtWaylandCompositor/private/qwaylandxdgoutputv1_p.h> #include <QtCore/QCoreApplication> #include <QtCore/QtMath> @@ -162,6 +163,9 @@ void QWaylandOutputPrivate::sendGeometryInfo() if (resource->version() >= 2) send_done(resource->handle); } + + if (xdgOutput) + QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone(); } void QWaylandOutputPrivate::sendMode(const Resource *resource, const QWaylandOutputMode &mode) @@ -185,6 +189,9 @@ void QWaylandOutputPrivate::sendModesInfo() if (resource->version() >= 2) send_done(resource->handle); } + + if (xdgOutput) + QWaylandXdgOutputV1Private::get(xdgOutput)->sendDone(); } void QWaylandOutputPrivate::handleWindowPixelSizeChanged() @@ -840,6 +847,9 @@ void QWaylandOutput::setScaleFactor(int scale) } Q_EMIT scaleFactorChanged(); + + if (d->xdgOutput) + QWaylandXdgOutputV1Private::get(d->xdgOutput)->sendDone(); } /*! diff --git a/src/compositor/compositor_api/qwaylandoutput_p.h b/src/compositor/compositor_api/qwaylandoutput_p.h index 4badd3797..58188ac38 100644 --- a/src/compositor/compositor_api/qwaylandoutput_p.h +++ b/src/compositor/compositor_api/qwaylandoutput_p.h @@ -57,6 +57,7 @@ #include <QtWaylandCompositor/QWaylandOutput> #include <QtWaylandCompositor/QWaylandClient> #include <QtWaylandCompositor/QWaylandSurface> +#include <QtWaylandCompositor/QWaylandXdgOutputV1> #include <QtWaylandCompositor/private/qwayland-server-wayland.h> @@ -110,6 +111,8 @@ public: void handleWindowPixelSizeChanged(); + QPointer<QWaylandXdgOutputV1> xdgOutput; + protected: void output_bind_resource(Resource *resource) override; @@ -137,6 +140,8 @@ private: Q_DECLARE_PUBLIC(QWaylandOutput) Q_DISABLE_COPY(QWaylandOutputPrivate) + + friend class QWaylandXdgOutputManagerV1Private; }; diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 996177be4..ee15a0871 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -610,13 +610,17 @@ void QWaylandQuickItem::wheelEvent(QWheelEvent *event) { Q_D(QWaylandQuickItem); if (d->shouldSendInputEvents()) { - if (!inputRegionContains(event->pos())) { + if (!inputRegionContains(event->position())) { event->ignore(); return; } QWaylandSeat *seat = compositor()->seatFor(event); - seat->sendMouseWheelEvent(event->orientation(), event->delta()); + // TODO: fix this to send a single event, when diagonal scrolling is supported + if (event->angleDelta().x() != 0) + seat->sendMouseWheelEvent(Qt::Horizontal, event->angleDelta().x()); + if (event->angleDelta().y() != 0) + seat->sendMouseWheelEvent(Qt::Vertical, event->angleDelta().y()); } else { event->ignore(); } @@ -1324,7 +1328,7 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat if (d->view->isBufferLocked() && !bufferHasContent && d->paintEnabled) return oldNode; - if (!bufferHasContent || !d->paintEnabled) { + if (!bufferHasContent || !d->paintEnabled || !surface()) { delete oldNode; return nullptr; } diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 433b53228..2265b41c0 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -764,6 +764,29 @@ bool QWaylandSurface::isCursorSurface() const return d->isCursorSurface; } +/*! + * \qmlproperty bool QtWaylandCompositor::WaylandSurface::inhibitsIdle + * + * This property holds whether this surface is intended to inhibit the idle + * behavior of the compositor such as screen blanking, locking and screen saving. + * + * \sa IdleInhibitManagerV1 + */ + +/*! + * \property QWaylandSurface::inhibitsIdle + * + * This property holds whether this surface is intended to inhibit the idle + * behavior of the compositor such as screen blanking, locking and screen saving. + * + * \sa QWaylandIdleInhibitManagerV1 + */ +bool QWaylandSurface::inhibitsIdle() const +{ + Q_D(const QWaylandSurface); + return !d->idleInhibitors.isEmpty(); +} + #if QT_CONFIG(im) QWaylandInputMethodControl *QWaylandSurface::inputMethodControl() const { diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index 667f911c3..f8cdc4434 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -92,6 +92,7 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandSurface : public QWaylandObject Q_PROPERTY(QWaylandSurface::Origin origin READ origin NOTIFY originChanged) Q_PROPERTY(bool hasContent READ hasContent NOTIFY hasContentChanged) Q_PROPERTY(bool cursorSurface READ isCursorSurface WRITE markAsCursorSurface NOTIFY cursorSurfaceChanged) + Q_PROPERTY(bool inhibitsIdle READ inhibitsIdle NOTIFY inhibitsIdleChanged REVISION 14) public: enum Origin { @@ -148,6 +149,8 @@ public: void markAsCursorSurface(bool cursorSurface); bool isCursorSurface() const; + bool inhibitsIdle() const; + #if QT_CONFIG(im) QWaylandInputMethodControl *inputMethodControl() const; #endif @@ -181,6 +184,7 @@ Q_SIGNALS: void subsurfacePlaceBelow(QWaylandSurface *sibling); void dragStarted(QWaylandDrag *drag); void cursorSurfaceChanged(); + void inhibitsIdleChanged(); void configure(bool hasBuffer); void redraw(); diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 1637d8704..97cb19d9b 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -74,6 +74,7 @@ #include <QtWaylandCompositor/private/qwayland-server-wayland.h> #include <QtWaylandCompositor/private/qwaylandviewporter_p.h> +#include <QtWaylandCompositor/private/qwaylandidleinhibitv1_p.h> QT_BEGIN_NAMESPACE @@ -167,6 +168,8 @@ public: //member variables QList<QPointer<QWaylandSurface>> subsurfaceChildren; + QVector<QWaylandIdleInhibitManagerV1Private::Inhibitor *> idleInhibitors; + QRegion inputRegion; QRegion opaqueRegion; diff --git a/src/compositor/doc/qtwaylandcompositor.qdocconf b/src/compositor/doc/qtwaylandcompositor.qdocconf index 4fa9f394d..45928b640 100644 --- a/src/compositor/doc/qtwaylandcompositor.qdocconf +++ b/src/compositor/doc/qtwaylandcompositor.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtwayland.qdocconf) project = QtWaylandCompositor description = Qt Wayland Compositor Reference Documentation diff --git a/src/compositor/extensions/extensions.pri b/src/compositor/extensions/extensions.pri index 027ea114b..61ab043ea 100644 --- a/src/compositor/extensions/extensions.pri +++ b/src/compositor/extensions/extensions.pri @@ -14,7 +14,9 @@ WAYLANDSERVERSOURCES += \ ../3rdparty/protocol/xdg-shell-unstable-v6.xml \ ../3rdparty/protocol/xdg-shell.xml \ ../3rdparty/protocol/xdg-decoration-unstable-v1.xml \ + ../3rdparty/protocol/xdg-output-unstable-v1.xml \ ../3rdparty/protocol/ivi-application.xml \ + ../3rdparty/protocol/idle-inhibit-unstable-v1.xml \ HEADERS += \ extensions/qwlqttouch_p.h \ @@ -41,7 +43,11 @@ HEADERS += \ extensions/qwaylandxdgshell_p.h \ extensions/qwaylandxdgdecorationv1.h \ extensions/qwaylandxdgdecorationv1_p.h \ + extensions/qwaylandxdgoutputv1.h \ + extensions/qwaylandxdgoutputv1_p.h \ extensions/qwaylandshellsurface.h \ + extensions/qwaylandidleinhibitv1.h \ + extensions/qwaylandidleinhibitv1_p.h \ extensions/qwaylandiviapplication.h \ extensions/qwaylandiviapplication_p.h \ extensions/qwaylandivisurface.h \ @@ -61,7 +67,9 @@ SOURCES += \ extensions/qwaylandxdgshellv6.cpp \ extensions/qwaylandxdgshell.cpp \ extensions/qwaylandxdgdecorationv1.cpp \ + extensions/qwaylandxdgoutputv1.cpp \ extensions/qwaylandshellsurface.cpp \ + extensions/qwaylandidleinhibitv1.cpp \ extensions/qwaylandiviapplication.cpp \ extensions/qwaylandivisurface.cpp \ @@ -72,6 +80,7 @@ qtHaveModule(quick) { extensions/qwaylandquickshellsurfaceitem_p.h \ extensions/qwaylandivisurfaceintegration_p.h \ extensions/qwaylandwlshellintegration_p.h \ + extensions/qwaylandquickxdgoutputv1.h \ extensions/qwaylandxdgshellv5integration_p.h \ extensions/qwaylandxdgshellv6integration_p.h \ extensions/qwaylandxdgshellintegration_p.h \ @@ -81,6 +90,7 @@ qtHaveModule(quick) { extensions/qwaylandquickshellsurfaceitem.cpp \ extensions/qwaylandivisurfaceintegration.cpp \ extensions/qwaylandwlshellintegration.cpp \ + extensions/qwaylandquickxdgoutputv1.cpp \ extensions/qwaylandxdgshellv5integration.cpp \ extensions/qwaylandxdgshellv6integration.cpp \ extensions/qwaylandxdgshellintegration.cpp \ diff --git a/src/compositor/extensions/qwaylandidleinhibitv1.cpp b/src/compositor/extensions/qwaylandidleinhibitv1.cpp new file mode 100644 index 000000000..b97f58130 --- /dev/null +++ b/src/compositor/extensions/qwaylandidleinhibitv1.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWaylandCompositor/QWaylandCompositor> +#include <QtWaylandCompositor/private/qwaylandsurface_p.h> + +#include "qwaylandidleinhibitv1_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWaylandIdleInhibitManagerV1 + \inmodule QtWaylandCompositor + \since 5.14 + \brief Provides an extension that allows to inhibit the idle behavior of the compositor + \sa QWaylandSurface::inhibitsIdle + + The QWaylandIdleInhibitV1 extension provides a way for a client to inhibit the idle behavior of + the compositor when a specific surface is visually relevant to the user. + + QWaylandIdleInhibitManagerV1 corresponds to the Wayland interface, \c zwp_idle_inhibit_manager_v1. + + Inhibited surfaces have the QWaylandSurface::inhibitsIdle property set to \c true. +*/ + +/*! + \qmltype IdleInhibitManagerV1 + \inqmlmodule QtWayland.Compositor + \since 5.14 + \brief Provides an extension that allows to inhibit the idle behavior of the compositor + \sa WaylandSurface::inhibitsIdle + + The IdleInhibitManagerV1 extension provides a way for a client to inhibit the idle behavior of + the compositor when a specific surface is visually relevant to the user. + + IdleInhibitManagerV1 corresponds to the Wayland interface, \c zwp_idle_inhibit_manager_v1. + + To provide the functionality of the extension in a compositor, create an instance of the + IdleInhibitManagerV1 component and add it to the list of extensions supported by the compositor: + + \qml \QtMinorVersion + import QtWayland.Compositor 1.\1 + + WaylandCompositor { + IdleInhibitManagerV1 { + // ... + } + } + \endqml + + Inhibited surfaces have the WaylandSurface::inhibitsIdle property set to \c true. +*/ + +/*! + Constructs a QWaylandIdleInhibitManagerV1 object. +*/ +QWaylandIdleInhibitManagerV1::QWaylandIdleInhibitManagerV1() + : QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1>(*new QWaylandIdleInhibitManagerV1Private()) +{ +} + +/*! + Constructs a QWaylandIdleInhibitManagerV1 object for the provided \a compositor. +*/ +QWaylandIdleInhibitManagerV1::QWaylandIdleInhibitManagerV1(QWaylandCompositor *compositor) + : QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1>(compositor, *new QWaylandIdleInhibitManagerV1Private()) +{ +} + +/*! + Destructs a QWaylandIdleInhibitManagerV1 object. +*/ +QWaylandIdleInhibitManagerV1::~QWaylandIdleInhibitManagerV1() = default; + +/*! + Initializes the extension. +*/ +void QWaylandIdleInhibitManagerV1::initialize() +{ + Q_D(QWaylandIdleInhibitManagerV1); + + QWaylandCompositorExtensionTemplate::initialize(); + QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); + if (!compositor) { + qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandIdleInhibitManagerV1"; + return; + } + d->init(compositor->display(), d->interfaceVersion()); +} + +/*! + Returns the Wayland interface for the QWaylandIdleInhibitManagerV1. +*/ +const wl_interface *QWaylandIdleInhibitManagerV1::interface() +{ + return QWaylandIdleInhibitManagerV1Private::interface(); +} + + +void QWaylandIdleInhibitManagerV1Private::zwp_idle_inhibit_manager_v1_create_inhibitor(Resource *resource, uint id, wl_resource *surfaceResource) +{ + auto *surface = QWaylandSurface::fromResource(surfaceResource); + if (!surface) { + qCWarning(qLcWaylandCompositor) << "Couldn't find surface requested for creating an inhibitor"; + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid wl_surface@%d", wl_resource_get_id(surfaceResource)); + return; + } + + auto *surfacePrivate = QWaylandSurfacePrivate::get(surface); + if (!surfacePrivate) { + wl_resource_post_no_memory(resource->handle); + return; + } + + auto *inhibitor = new Inhibitor(surface, resource->client(), id, resource->version()); + if (!inhibitor) { + wl_resource_post_no_memory(resource->handle); + return; + } + surfacePrivate->idleInhibitors.append(inhibitor); + + if (surfacePrivate->idleInhibitors.size() == 1) + Q_EMIT surface->inhibitsIdleChanged(); +} + + +QWaylandIdleInhibitManagerV1Private::Inhibitor::Inhibitor(QWaylandSurface *surface, + wl_client *client, + quint32 id, quint32 version) + : QtWaylandServer::zwp_idle_inhibitor_v1(client, id, qMin<quint32>(version, interfaceVersion())) + , m_surface(surface) +{ + Q_ASSERT(surface); +} + +void QWaylandIdleInhibitManagerV1Private::Inhibitor::zwp_idle_inhibitor_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource); + delete this; +} + +void QWaylandIdleInhibitManagerV1Private::Inhibitor::zwp_idle_inhibitor_v1_destroy(Resource *resource) +{ + if (m_surface) { + auto *surfacePrivate = QWaylandSurfacePrivate::get(m_surface.data()); + Q_ASSERT(surfacePrivate->idleInhibitors.contains(this)); + surfacePrivate->idleInhibitors.removeOne(this); + + if (surfacePrivate->idleInhibitors.isEmpty()) + Q_EMIT m_surface.data()->inhibitsIdleChanged(); + } + + wl_resource_destroy(resource->handle); +} + +QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandidleinhibitv1.h b/src/compositor/extensions/qwaylandidleinhibitv1.h new file mode 100644 index 000000000..53c09d084 --- /dev/null +++ b/src/compositor/extensions/qwaylandidleinhibitv1.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDIDLEINHIBITV1_H +#define QWAYLANDIDLEINHIBITV1_H + +#include <QtWaylandCompositor/QWaylandCompositorExtension> + +QT_BEGIN_NAMESPACE + +class QWaylandIdleInhibitManagerV1Private; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandIdleInhibitManagerV1 : public QWaylandCompositorExtensionTemplate<QWaylandIdleInhibitManagerV1> +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandIdleInhibitManagerV1) +public: + QWaylandIdleInhibitManagerV1(); + explicit QWaylandIdleInhibitManagerV1(QWaylandCompositor *compositor); + ~QWaylandIdleInhibitManagerV1(); + + void initialize() override; + + static const struct wl_interface *interface(); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDIDLEINHIBITV1_H diff --git a/src/compositor/extensions/qwaylandidleinhibitv1_p.h b/src/compositor/extensions/qwaylandidleinhibitv1_p.h new file mode 100644 index 000000000..380551804 --- /dev/null +++ b/src/compositor/extensions/qwaylandidleinhibitv1_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDIDLEINHIBITV1_P_H +#define QWAYLANDIDLEINHIBITV1_P_H + +#include <QtWaylandCompositor/QWaylandSurface> +#include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1> +#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h> +#include <QtWaylandCompositor/private/qwayland-server-idle-inhibit-unstable-v1.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. +// + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandIdleInhibitManagerV1Private + : public QWaylandCompositorExtensionPrivate + , public QtWaylandServer::zwp_idle_inhibit_manager_v1 +{ + Q_DECLARE_PUBLIC(QWaylandIdleInhibitManagerV1) +public: + explicit QWaylandIdleInhibitManagerV1Private() = default; + + class Q_WAYLAND_COMPOSITOR_EXPORT Inhibitor + : public QtWaylandServer::zwp_idle_inhibitor_v1 + { + public: + explicit Inhibitor(QWaylandSurface *surface, wl_client *client, quint32 id, quint32 version); + + protected: + void zwp_idle_inhibitor_v1_destroy_resource(Resource *resource) override; + void zwp_idle_inhibitor_v1_destroy(Resource *resource) override; + + private: + QPointer<QWaylandSurface> m_surface; + }; + + static QWaylandIdleInhibitManagerV1Private *get(QWaylandIdleInhibitManagerV1 *manager) { return manager ? manager->d_func() : nullptr; } + +protected: + void zwp_idle_inhibit_manager_v1_create_inhibitor(Resource *resource, uint32_t id, wl_resource *surfaceResource) override; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDIDLEINHIBITV1_P_H diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp new file mode 100644 index 000000000..eb6717a78 --- /dev/null +++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QWaylandCompositor> +#include <QWaylandOutput> + +#include "qwaylandquickxdgoutputv1.h" +#include "qwaylandxdgoutputv1_p.h" + +QWaylandQuickXdgOutputV1::QWaylandQuickXdgOutputV1() + : QWaylandXdgOutputV1() +{ +} + +void QWaylandQuickXdgOutputV1::componentComplete() +{ + // Try to find the manager from the compositor extensions + if (!manager()) { + for (auto *p = parent(); p != nullptr; p = p->parent()) { + if (auto *c = qobject_cast<QWaylandCompositor *>(p)) { + for (auto *extension : c->extensions()) { + if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(extension)) { + QWaylandXdgOutputV1Private::get(this)->setManager(m); + break; + } + } + } + } + } + + // Try to find the output from the parents + if (!output()) { + for (auto *p = parent(); p != nullptr; p = p->parent()) { + if (auto *o = qobject_cast<QWaylandOutput *>(p)) { + QWaylandXdgOutputV1Private::get(this)->setOutput(o); + break; + } + } + } +} diff --git a/src/compositor/extensions/qwaylandquickxdgoutputv1.h b/src/compositor/extensions/qwaylandquickxdgoutputv1.h new file mode 100644 index 000000000..c8b16ab8e --- /dev/null +++ b/src/compositor/extensions/qwaylandquickxdgoutputv1.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDQUICKXDGOUTPUT_V1 +#define QWAYLANDQUICKXDGOUTPUT_V1 + +#include <QtQml/QQmlListProperty> +#include <QtQml/QQmlParserStatus> +#include <QtWaylandCompositor/QWaylandXdgOutputV1> + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandQuickXdgOutputV1 + : public QWaylandXdgOutputV1 + , public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) +public: + explicit QWaylandQuickXdgOutputV1(); + +protected: + void classBegin() override {} + void componentComplete() override; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDQUICKXDGOUTPUT_V1 diff --git a/src/compositor/extensions/qwaylandwlscaler_p.h b/src/compositor/extensions/qwaylandwlscaler_p.h index d3c2edd76..10a66f884 100644 --- a/src/compositor/extensions/qwaylandwlscaler_p.h +++ b/src/compositor/extensions/qwaylandwlscaler_p.h @@ -55,6 +55,7 @@ QT_BEGIN_NAMESPACE +#if QT_DEPRECATED_SINCE(5, 13) class QWaylandSurface; class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandWlScalerPrivate @@ -87,6 +88,7 @@ private: QPointer<QWaylandSurface> m_surface = nullptr; }; }; +#endif QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.cpp b/src/compositor/extensions/qwaylandxdgoutputv1.cpp new file mode 100644 index 000000000..2ab26c162 --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QWaylandCompositor> + +#include "qwaylandxdgoutputv1_p.h" +#include "qwaylandoutput_p.h" + +#include <wayland-server.h> + +QT_BEGIN_NAMESPACE + +/*! + * \qmltype XdgOutputManagerV1 + * \inqmlmodule QtWayland.Compositor + * \since 5.14 + * \brief Provides an extension for describing outputs in a desktop oriented fashion + * + * The XdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way + * that is more in line with the concept of an output on desktop oriented systems. + * + * Some information may not make sense in other applications such as IVI systems. + * + * Typically the global compositor space on a desktop system is made of a + * contiguous or overlapping set of rectangular regions. + * + * XdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1. + * + * To provide the functionality of the extension in a compositor, create an instance of the + * XdgOutputManagerV1 component and add it to the list of extensions supported by the compositor, + * and associated each XdgOutputV1 with its WaylandOutput: + * + * \qml \QtMinorVersion + * import QtWayland.Compositor 1.\1 + * + * WaylandCompositor { + * XdgOutputManagerV1 { + * WaylandOutput { + * id: output1 + * + * position: Qt.point(0, 0) + * window: Window {} + * + * XdgOutputV1 { + * name: "WL-1" + * logicalPosition: output1.position + * logicalSize: Qt.size(output1.geometry.width / output1.scaleFactor, + * output1.geometry.height / output1.scaleFactor) + * } + * } + * + * WaylandOutput { + * id: output2 + * + * position: Qt.point(800, 0) + * window: Window {} + * + * XdgOutputV1 { + * name: "WL-2" + * logicalPosition: output2.position + * logicalSize: Qt.size(output2.geometry.width / output2.scaleFactor, + * output2.geometry.height / output2.scaleFactor) + * } + * } + * } + * } + * \endqml + */ + +/*! + * \class QWaylandXdgOutputManagerV1 + * \inmodule QtWaylandCompositor + * \since 5.14 + * \brief Provides an extension for describing outputs in a desktop oriented fashion + * + * The QWaylandXdgOutputManagerV1 extension provides a way for a compositor to describe outputs in a way + * that is more in line with the concept of an output on desktop oriented systems. + * + * Some information may not make sense in other applications such as IVI systems. + * + * QWaylandXdgOutputManagerV1 corresponds to the Wayland interface, \c zxdg_output_manager_v1. + */ + +/*! + * Constructs a QWaylandXdgOutputManagerV1 object. + */ +QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1() + : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(*new QWaylandXdgOutputManagerV1Private()) +{ +} + +/*! + * Constructs a QWaylandXdgOutputManagerV1 object for the provided \a compositor. + */ +QWaylandXdgOutputManagerV1::QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor) + : QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1>(compositor, *new QWaylandXdgOutputManagerV1Private()) +{ +} + +// QWaylandXdgOutputManagerV1Private + +/*! + * Initializes the extension. + */ +void QWaylandXdgOutputManagerV1::initialize() +{ + Q_D(QWaylandXdgOutputManagerV1); + + QWaylandCompositorExtensionTemplate::initialize(); + QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); + if (!compositor) { + qCWarning(qLcWaylandCompositor) << "Failed to find QWaylandCompositor when initializing QWaylandXdgOutputManagerV1"; + return; + } + d->init(compositor->display(), d->interfaceVersion()); +} + +/*! + * Returns the Wayland interface for QWaylandXdgOutputManagerV1. + */ +const wl_interface *QWaylandXdgOutputManagerV1::interface() +{ + return QWaylandXdgOutputManagerV1Private::interface(); +} + +// QWaylandXdgOutputManagerV1Private + +void QWaylandXdgOutputManagerV1Private::registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput) +{ + if (!xdgOutputs.contains(output)) { + xdgOutputs[output] = xdgOutput; + QWaylandOutputPrivate::get(output)->xdgOutput = xdgOutput; + } +} + +void QWaylandXdgOutputManagerV1Private::unregisterXdgOutput(QWaylandOutput *output) +{ + xdgOutputs.remove(output); +} + +void QWaylandXdgOutputManagerV1Private::zxdg_output_manager_v1_get_xdg_output(Resource *resource, + uint32_t id, + wl_resource *outputResource) +{ + Q_Q(QWaylandXdgOutputManagerV1); + + // Verify if the associated output exist + auto *output = QWaylandOutput::fromResource(outputResource); + if (!output) { + qCWarning(qLcWaylandCompositor, + "The client is requesting a QWaylandXdgOutputV1 for a " + "QWaylandOutput that doesn't exist"); + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "output not found"); + return; + } + + // Do we have a QWaylandXdgOutputV1 for this output? + if (!xdgOutputs.contains(output)) { + qCWarning(qLcWaylandCompositor, + "The client is requesting a QWaylandXdgOutputV1 that the compositor " + "didn't create before"); + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, + "compositor didn't create a QWaylandXdgOutputV1 for this zxdg_output_v1 object"); + return; + } + + // Bind QWaylandXdgOutputV1 and initialize + auto *xdgOutput = xdgOutputs[output]; + auto *xdgOutputPrivate = QWaylandXdgOutputV1Private::get(xdgOutput); + Q_ASSERT(xdgOutputPrivate); + xdgOutputPrivate->setManager(q); + xdgOutputPrivate->setOutput(output); + xdgOutputPrivate->add(resource->client(), id, qMin(resource->version(), QWaylandXdgOutputV1Private::interfaceVersion())); +} + +// QWaylandXdgOutputV1 + +QWaylandXdgOutputV1::QWaylandXdgOutputV1() + : QObject(*new QWaylandXdgOutputV1Private) +{ +} + +QWaylandXdgOutputV1::QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager) + : QObject(*new QWaylandXdgOutputV1Private) +{ + Q_D(QWaylandXdgOutputV1); + + // Set members before emitting changed signals so that handlers will + // see both already set and not nullptr, avoiding potential crashes + d->manager = manager; + d->output = output; + + QWaylandXdgOutputManagerV1Private::get(d->manager)->registerXdgOutput(output, this); + + emit managerChanged(); + emit outputChanged(); +} + +QWaylandXdgOutputV1::~QWaylandXdgOutputV1() +{ + Q_D(QWaylandXdgOutputV1); + + if (d->manager) + QWaylandXdgOutputManagerV1Private::get(d->manager)->unregisterXdgOutput(d->output); +} + +/*! + * \qmlproperty XdgOutputManagerV1 QtWaylandCompositor::XdgOutputV1::manager + * \readonly + * + * This property holds the object that manages this XdgOutputV1. + */ +/*! + * \property QWaylandXdgOutputV1::manager + * \readonly + * + * This property holds the object that manages this QWaylandXdgOutputV1. + */ +QWaylandXdgOutputManagerV1 *QWaylandXdgOutputV1::manager() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->manager; +} + +/*! + * \qmlproperty WaylandOutput QtWaylandCompositor::XdgOutputV1::output + * \readonly + * + * This property holds the WaylandOutput associated with this XdgOutputV1. + */ +/*! + * \property QWaylandXdgOutputV1::output + * \readonly + * + * This property holds the QWaylandOutput associated with this QWaylandXdgOutputV1. + */ +QWaylandOutput *QWaylandXdgOutputV1::output() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->output; +} + +/*! + * \qmlproperty string QtWaylandCompositor::XdgOutputV1::name + * + * This property holds the name of this output. + * + * The naming convention is compositor defined, but limited to alphanumeric + * characters and dashes ("-"). Each name is unique and will also remain + * consistent across sessions with the same hardware and software configuration. + * + * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc... + * However don't assume the name reflects the underlying technology. + * + * Changing this property after initialization doesn't take effect. + */ +/*! + * \property QWaylandXdgOutputV1::name + * + * This property holds the name of this output. + * + * The naming convention is compositor defined, but limited to alphanumeric + * characters and dashes ("-"). Each name is unique and will also remain + * consistent across sessions with the same hardware and software configuration. + * + * Examples of names include "HDMI-A-1", "WL-1", "X11-1" etc... + * However don't assume the name reflects the underlying technology. + * + * Changing this property after initialization doesn't take effect. + */ +QString QWaylandXdgOutputV1::name() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->name; +} + +void QWaylandXdgOutputV1::setName(const QString &name) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->name == name) + return; + + // Can't change after clients bound to xdg-output + if (d->initialized) { + qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::name cannot be changed after initialization"); + return; + } + + d->name = name; + emit nameChanged(); +} + +/*! + * \qmlproperty string QtWaylandCompositor::XdgOutputV1::description + * + * This property holds the description of this output. + * + * No convention is defined for the description. + * + * Changing this property after initialization doesn't take effect. + */ +/*! + * \property QWaylandXdgOutputV1::description + * + * This property holds the description of this output. + * + * No convention is defined for the description. + * + * Changing this property after initialization doesn't take effect. + */ +QString QWaylandXdgOutputV1::description() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->description; +} + +void QWaylandXdgOutputV1::setDescription(const QString &description) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->description == description) + return; + + // Can't change after clients bound to xdg-output + if (d->initialized) { + qCWarning(qLcWaylandCompositor, "QWaylandXdgOutputV1::description cannot be changed after initialization"); + return; + } + + d->description = description; + emit descriptionChanged(); +} + +/*! + * \qmlproperty point QtWaylandCompositor::XdgOutputV1::logicalPosition + * + * This property holds the coordinates of the output within the global compositor space. + * + * The default value is 0,0. + */ +/*! + * \property QWaylandXdgOutputV1::logicalPosition + * + * This property holds the coordinates of the output within the global compositor space. + * + * The default value is 0,0. + */ +QPoint QWaylandXdgOutputV1::logicalPosition() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->logicalPos; +} + +void QWaylandXdgOutputV1::setLogicalPosition(const QPoint &position) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->logicalPos == position) + return; + + d->logicalPos = position; + if (d->initialized) { + d->sendLogicalPosition(position); + d->sendDone(); + } + emit logicalPositionChanged(); + emit logicalGeometryChanged(); +} + +/*! + * \qmlproperty size QtWaylandCompositor::XdgOutputV1::logicalSize + * + * This property holds the size of the output in the global compositor space. + * + * The default value is -1,-1 which is invalid. + * + * Please remember that this is the logical size, not the physical size. + * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2: + * \list + * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160. + * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080. + * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620. + * \endlist + */ +/*! + * \property QWaylandXdgOutputV1::logicalSize + * + * This property holds the size of the output in the global compositor space. + * + * The default value is -1,-1 which is invalid. + * + * Please remember that this is the logical size, not the physical size. + * For example, for a WaylandOutput mode 3840x2160 and a scale factor 2: + * \list + * \li A compositor not scaling the surface buffers, will report a logical size of 3840x2160. + * \li A compositor automatically scaling the surface buffers, will report a logical size of 1920x1080. + * \li A compositor using a fractional scale of 1.5, will report a logical size of 2560x1620. + * \endlist + */ +QSize QWaylandXdgOutputV1::logicalSize() const +{ + Q_D(const QWaylandXdgOutputV1); + return d->logicalSize; +} + +void QWaylandXdgOutputV1::setLogicalSize(const QSize &size) +{ + Q_D(QWaylandXdgOutputV1); + + if (d->logicalSize == size) + return; + + d->logicalSize = size; + if (d->initialized) { + d->sendLogicalSize(size); + d->sendDone(); + } + emit logicalSizeChanged(); + emit logicalGeometryChanged(); +} + +/*! + * \qmlproperty rect QtWaylandCompositor::XdgOutputV1::logicalGeometry + * \readonly + * + * This property holds the position and size of the output in the global compositor space. + * It's the combination of the logical position and logical size. + * + * \sa XdgOutputV1::logicalPosition + * \sa XdgOutputV1::logicalSize + */ +/*! + * \property QWaylandXdgOutputV1::logicalGeometry + * \readonly + * + * This property holds the position and size of the output in the global compositor space. + * It's the combination of the logical position and logical size. + * + * \sa QWaylandXdgOutputV1::logicalPosition + * \sa QWaylandXdgOutputV1::logicalSize + */ +QRect QWaylandXdgOutputV1::logicalGeometry() const +{ + Q_D(const QWaylandXdgOutputV1); + return QRect(d->logicalPos, d->logicalSize); +} + +// QWaylandXdgOutputV1Private + +void QWaylandXdgOutputV1Private::sendLogicalPosition(const QPoint &position) +{ + const auto values = resourceMap().values(); + for (auto *resource : values) + send_logical_position(resource->handle, position.x(), position.y()); + needToSendDone = true; +} + +void QWaylandXdgOutputV1Private::sendLogicalSize(const QSize &size) +{ + const auto values = resourceMap().values(); + for (auto *resource : values) + send_logical_size(resource->handle, size.width(), size.height()); + needToSendDone = true; +} + +void QWaylandXdgOutputV1Private::sendDone() +{ + if (needToSendDone) { + const auto values = resourceMap().values(); + for (auto *resource : values) { + if (resource->version() < 3) + send_done(resource->handle); + } + needToSendDone = false; + } +} + +void QWaylandXdgOutputV1Private::setManager(QWaylandXdgOutputManagerV1 *_manager) +{ + Q_Q(QWaylandXdgOutputV1); + + if (!_manager) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a null QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p", this); + return; + } + + if (manager == _manager) + return; + + if (manager) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a different QWaylandXdgOutputManagerV1 to QWaylandXdgOutputV1 %p " + "after initialization", this); + return; + } + + manager = _manager; + emit q->managerChanged(); +} + +void QWaylandXdgOutputV1Private::setOutput(QWaylandOutput *_output) +{ + Q_Q(QWaylandXdgOutputV1); + + if (!_output) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a null QWaylandOutput to QWaylandXdgOutputV1 %p", this); + return; + } + + if (output == _output) + return; + + if (output) { + qCWarning(qLcWaylandCompositor, + "Cannot associate a different QWaylandOutput to QWaylandXdgOutputV1 %p " + "after initialization", this); + return; + } + + // Assign output above manager, to make both values valid in handlers + output = _output; + + if (!manager) { + // Try to find the manager from the output parents + for (auto *p = output->parent(); p != nullptr; p = p->parent()) { + if (auto *m = qobject_cast<QWaylandXdgOutputManagerV1 *>(p)) { + manager = m; + emit q->managerChanged(); + break; + } + } + } + + emit q->outputChanged(); + + // Register the output + if (manager) + QWaylandXdgOutputManagerV1Private::get(manager)->registerXdgOutput(output, q); +} + +void QWaylandXdgOutputV1Private::zxdg_output_v1_bind_resource(Resource *resource) +{ + send_logical_position(resource->handle, logicalPos.x(), logicalPos.y()); + send_logical_size(resource->handle, logicalSize.width(), logicalSize.height()); + if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) + send_name(resource->handle, name); + if (resource->version() >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION) + send_description(resource->handle, description); + send_done(resource->handle); + + initialized = true; +} + +void QWaylandXdgOutputV1Private::zxdg_output_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +QT_END_NAMESPACE diff --git a/src/compositor/extensions/qwaylandxdgoutputv1.h b/src/compositor/extensions/qwaylandxdgoutputv1.h new file mode 100644 index 000000000..c5f03758a --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDXDGOUTPUTV1_H +#define QWAYLANDXDGOUTPUTV1_H + +#include <QRect> +#include <QWaylandCompositorExtension> +#include <QtWaylandCompositor/qwaylandquickchildren.h> + +QT_BEGIN_NAMESPACE + +class QWaylandOutput; + +class QWaylandXdgOutputManagerV1Private; +class QWaylandXdgOutputV1Private; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1 + : public QWaylandCompositorExtensionTemplate<QWaylandXdgOutputManagerV1> +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandXdgOutputManagerV1) +public: + explicit QWaylandXdgOutputManagerV1(); + QWaylandXdgOutputManagerV1(QWaylandCompositor *compositor); + + void initialize() override; + + static const wl_interface *interface(); +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1 : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandXdgOutputV1) + Q_WAYLAND_COMPOSITOR_DECLARE_QUICK_CHILDREN(QWaylandXdgOutputV1) + Q_PROPERTY(QWaylandXdgOutputManagerV1 *manager READ manager NOTIFY managerChanged) + Q_PROPERTY(QWaylandOutput *output READ output NOTIFY outputChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged) + Q_PROPERTY(QPoint logicalPosition READ logicalPosition WRITE setLogicalPosition NOTIFY logicalPositionChanged) + Q_PROPERTY(QSize logicalSize READ logicalSize WRITE setLogicalSize NOTIFY logicalSizeChanged) + Q_PROPERTY(QRect logicalGeometry READ logicalGeometry NOTIFY logicalGeometryChanged) +public: + QWaylandXdgOutputV1(); + QWaylandXdgOutputV1(QWaylandOutput *output, QWaylandXdgOutputManagerV1 *manager); + ~QWaylandXdgOutputV1() override; + + QWaylandXdgOutputManagerV1 *manager() const; + QWaylandOutput *output() const; + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &name); + + QPoint logicalPosition() const; + void setLogicalPosition(const QPoint &position); + + QSize logicalSize() const; + void setLogicalSize(const QSize &size); + + QRect logicalGeometry() const; + +Q_SIGNALS: + void managerChanged(); + void outputChanged(); + void logicalPositionChanged(); + void logicalSizeChanged(); + void logicalGeometryChanged(); + void nameChanged(); + void descriptionChanged(); +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDXDGOUTPUTV1_H diff --git a/src/compositor/extensions/qwaylandxdgoutputv1_p.h b/src/compositor/extensions/qwaylandxdgoutputv1_p.h new file mode 100644 index 000000000..2e8a6fff9 --- /dev/null +++ b/src/compositor/extensions/qwaylandxdgoutputv1_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWaylandCompositor module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDXDGOUTPUTV1_P_H +#define QWAYLANDXDGOUTPUTV1_P_H + +#include <QWaylandOutput> +#include <QWaylandXdgOutputV1> +#include <QtWaylandCompositor/private/qwaylandcompositorextension_p.h> +#include <QtWaylandCompositor/private/qwayland-server-xdg-output-unstable-v1.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. +// + +QT_BEGIN_NAMESPACE + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputManagerV1Private + : public QWaylandCompositorExtensionPrivate + , public QtWaylandServer::zxdg_output_manager_v1 +{ + Q_DECLARE_PUBLIC(QWaylandXdgOutputManagerV1) +public: + explicit QWaylandXdgOutputManagerV1Private() = default; + + void registerXdgOutput(QWaylandOutput *output, QWaylandXdgOutputV1 *xdgOutput); + void unregisterXdgOutput(QWaylandOutput *output); + + static QWaylandXdgOutputManagerV1Private *get(QWaylandXdgOutputManagerV1 *manager) { return manager ? manager->d_func() : nullptr; } + +protected: + void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, + wl_resource *outputResource) override; + +private: + QHash<QWaylandOutput *, QWaylandXdgOutputV1 *> xdgOutputs; +}; + +class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandXdgOutputV1Private + : public QObjectPrivate + , public QtWaylandServer::zxdg_output_v1 +{ + Q_DECLARE_PUBLIC(QWaylandXdgOutputV1) +public: + explicit QWaylandXdgOutputV1Private() = default; + + void sendLogicalPosition(const QPoint &position); + void sendLogicalSize(const QSize &size); + void sendDone(); + + void setManager(QWaylandXdgOutputManagerV1 *manager); + void setOutput(QWaylandOutput *output); + + static QWaylandXdgOutputV1Private *get(QWaylandXdgOutputV1 *xdgOutput) { return xdgOutput ? xdgOutput->d_func() : nullptr; } + + bool initialized = false; + QWaylandOutput *output = nullptr; + QWaylandXdgOutputManagerV1 *manager = nullptr; + QPoint logicalPos; + QSize logicalSize; + QString name; + QString description; + bool needToSendDone = false; + +protected: + void zxdg_output_v1_bind_resource(Resource *resource) override; + void zxdg_output_v1_destroy(Resource *resource) override; +}; + +QT_END_NAMESPACE + +#endif // QWAYLANDXDGOUTPUTV1_P_H diff --git a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp index cb1ee3da0..ef6b26483 100644 --- a/src/compositor/wayland_wrapper/qwlclientbuffer.cpp +++ b/src/compositor/wayland_wrapper/qwlclientbuffer.cpp @@ -81,7 +81,7 @@ void ClientBuffer::setDestroyed() m_committed = false; m_buffer = nullptr; - if (!m_refCount) + if (!m_refCount.loadAcquire()) delete this; } diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp index 7514929de..23b24101d 100644 --- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp @@ -259,22 +259,25 @@ bool LinuxDmabufClientBufferIntegration::initYuvTexture(LinuxDmabufWlBuffer *dma LinuxDmabufClientBufferIntegration::LinuxDmabufClientBufferIntegration() { - m_yuvFormats.insert(DRM_FORMAT_YUYV, - YuvFormatConversion { - .inputPlanes = 1, - .outputPlanes = 2, - .plane = {{ - .format = DRM_FORMAT_GR88, - .widthDivisor = 1, - .heightDivisor = 1, - .planeIndex = 0 - }, { - .format = DRM_FORMAT_ARGB8888, - .widthDivisor = 2, - .heightDivisor = 1, - .planeIndex = 0 - }} - }); + YuvPlaneConversion firstPlane; + firstPlane.format = DRM_FORMAT_GR88; + firstPlane.widthDivisor = 1; + firstPlane.heightDivisor = 1; + firstPlane.planeIndex = 0; + + YuvPlaneConversion secondPlane; + secondPlane.format = DRM_FORMAT_ARGB8888; + secondPlane.widthDivisor = 2; + secondPlane.heightDivisor = 1; + secondPlane.planeIndex = 0; + + YuvFormatConversion formatConversion; + formatConversion.inputPlanes = 1; + formatConversion.outputPlanes = 2; + formatConversion.plane[0] = firstPlane; + formatConversion.plane[1] = secondPlane; + + m_yuvFormats.insert(DRM_FORMAT_YUYV, formatConversion); } LinuxDmabufClientBufferIntegration::~LinuxDmabufClientBufferIntegration() diff --git a/src/imports/compositor/qwaylandquickcompositorplugin.cpp b/src/imports/compositor/qwaylandquickcompositorplugin.cpp index 93bab1790..7b4d2b5e8 100644 --- a/src/imports/compositor/qwaylandquickcompositorplugin.cpp +++ b/src/imports/compositor/qwaylandquickcompositorplugin.cpp @@ -66,6 +66,8 @@ #include <QtWaylandCompositor/QWaylandXdgShellV6> #include <QtWaylandCompositor/QWaylandXdgShell> #include <QtWaylandCompositor/QWaylandXdgDecorationManagerV1> +#include <QtWaylandCompositor/QWaylandIdleInhibitManagerV1> +#include <QtWaylandCompositor/QWaylandQuickXdgOutputV1> #include <QtWaylandCompositor/QWaylandIviApplication> #include <QtWaylandCompositor/QWaylandIviSurface> @@ -76,13 +78,17 @@ QT_BEGIN_NAMESPACE Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CONTAINER_CLASS(QWaylandQuickCompositor) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandQtWindowManager) +Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandIdleInhibitManagerV1) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandIviApplication) +#if QT_DEPRECATED_SINCE(5, 13) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandWlScaler) +#endif Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandWlShell) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV5) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShellV6) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgShell) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgDecorationManagerV1) +Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandXdgOutputManagerV1) Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(QWaylandTextInputManager) class QmlUrlResolver @@ -184,7 +190,14 @@ public: qmlRegisterType<QWaylandXdgDecorationManagerV1QuickExtension>(uri, 1, 3, "XdgDecorationManagerV1"); +#if QT_DEPRECATED_SINCE(5, 13) qmlRegisterType<QWaylandWlScalerQuickExtension>(uri, 1, 13, "WlScaler"); +#endif + + qmlRegisterType<QWaylandIdleInhibitManagerV1QuickExtension>(uri, 1, 14, "IdleInhibitManagerV1"); + + qmlRegisterType<QWaylandXdgOutputManagerV1QuickExtension>(uri, 1, 14, "XdgOutputManagerV1"); + qmlRegisterType<QWaylandQuickXdgOutputV1>(uri, 1, 14, "XdgOutputV1"); } }; //![class decl] diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 4ff506c61..7452a9283 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,10 +1,10 @@ TEMPLATE = subdirs -qtHaveModule(quick): { +qtHaveModule(quick):qtHaveModule(waylandcompositor) { SUBDIRS += \ compositor - qtConfig(opengl): { + qtConfig(opengl):qtHaveModule(waylandclient) { SUBDIRS += \ texture-sharing \ texture-sharing-extension diff --git a/src/plugins/hardwareintegration/hardwareintegration.pro b/src/plugins/hardwareintegration/hardwareintegration.pro index cb7a4b263..12658adff 100644 --- a/src/plugins/hardwareintegration/hardwareintegration.pro +++ b/src/plugins/hardwareintegration/hardwareintegration.pro @@ -1,4 +1,4 @@ TEMPLATE=subdirs -SUBDIRS += client +qtHaveModule(waylandclient): SUBDIRS += client qtHaveModule(waylandcompositor): SUBDIRS += compositor diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 9b66b851e..e121d92d3 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,6 +1,11 @@ TEMPLATE=subdirs + +qtHaveModule(waylandclient) { + SUBDIRS += \ + platforms \ + decorations \ + shellintegration +} + SUBDIRS += \ - platforms \ - hardwareintegration \ - decorations \ - shellintegration + hardwareintegration diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp index 9309faccd..ea725ac31 100644 --- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp +++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.cpp @@ -48,6 +48,8 @@ #include "qwaylandivisurface_p.h" +#include <mutex> + #include <unistd.h> QT_BEGIN_NAMESPACE @@ -95,7 +97,7 @@ uint32_t QWaylandIviShellIntegration::getNextUniqueSurfaceId() { const uint32_t PID_MAX_EXPONENTIATION = 22; // 22 bit shift operation const uint32_t ID_LIMIT = 1 << (32 - PID_MAX_EXPONENTIATION); // 10 bit is unique id - QMutexLocker locker(&m_mutex); + const std::lock_guard<QRecursiveMutex> locker(m_mutex); if (m_lastSurfaceId == 0) { QByteArray env = qgetenv("QT_IVI_SURFACE_ID"); diff --git a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h index fc16d2f64..13282e438 100644 --- a/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h +++ b/src/plugins/shellintegration/ivi-shell/qwaylandivishellintegration.h @@ -71,7 +71,7 @@ private: uint32_t m_lastSurfaceId = 0; uint32_t m_surfaceNumber = 0; bool m_useEnvSurfaceId = false; - QMutex m_mutex{QMutex::Recursive}; + QRecursiveMutex m_mutex; }; } diff --git a/src/qtwaylandscanner/qtwaylandscanner.cpp b/src/qtwaylandscanner/qtwaylandscanner.cpp index 02bb5701c..9691b857f 100644 --- a/src/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/qtwaylandscanner/qtwaylandscanner.cpp @@ -40,7 +40,8 @@ #include <QCoreApplication> #include <QFile> #include <QXmlStreamReader> -#include <QtCore/QList> + +#include <vector> class Scanner { @@ -63,7 +64,7 @@ private: struct WaylandEnum { QByteArray name; - QList<WaylandEnumEntry> entries; + std::vector<WaylandEnumEntry> entries; }; struct WaylandArgument { @@ -78,16 +79,16 @@ private: bool request; QByteArray name; QByteArray type; - QList<WaylandArgument> arguments; + std::vector<WaylandArgument> arguments; }; struct WaylandInterface { QByteArray name; int version; - QList<WaylandEnum> enums; - QList<WaylandEvent> events; - QList<WaylandEvent> requests; + std::vector<WaylandEnum> enums; + std::vector<WaylandEvent> events; + std::vector<WaylandEvent> requests; }; bool isServerSide(); @@ -101,11 +102,11 @@ private: Scanner::WaylandInterface readInterface(QXmlStreamReader &xml); QByteArray waylandToCType(const QByteArray &waylandType, const QByteArray &interface); QByteArray waylandToQtType(const QByteArray &waylandType, const QByteArray &interface, bool cStyleArray); - const Scanner::WaylandArgument *newIdArgument(const QList<WaylandArgument> &arguments); + const Scanner::WaylandArgument *newIdArgument(const std::vector<WaylandArgument> &arguments); void printEvent(const WaylandEvent &e, bool omitNames = false, bool withResource = false); void printEventHandlerSignature(const WaylandEvent &e, const char *interfaceName, bool deepIndent = true); - void printEnums(const QList<WaylandEnum> &enums); + void printEnums(const std::vector<WaylandEnum> &enums); QByteArray stripInterfaceName(const QByteArray &name); bool ignoreInterface(const QByteArray &name); @@ -189,19 +190,22 @@ bool Scanner::boolValue(const QXmlStreamReader &xml, const char *name) Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request) { - WaylandEvent event; - event.request = request; - event.name = byteArrayValue(xml, "name"); - event.type = byteArrayValue(xml, "type"); + WaylandEvent event = { + .request = request, + .name = byteArrayValue(xml, "name"), + .type = byteArrayValue(xml, "type"), + .arguments = {}, + }; while (xml.readNextStartElement()) { if (xml.name() == "arg") { - WaylandArgument argument; - argument.name = byteArrayValue(xml, "name"); - argument.type = byteArrayValue(xml, "type"); - argument.interface = byteArrayValue(xml, "interface"); - argument.summary = byteArrayValue(xml, "summary"); - argument.allowNull = boolValue(xml, "allowNull"); - event.arguments << argument; + WaylandArgument argument = { + .name = byteArrayValue(xml, "name"), + .type = byteArrayValue(xml, "type"), + .interface = byteArrayValue(xml, "interface"), + .summary = byteArrayValue(xml, "summary"), + .allowNull = boolValue(xml, "allowNull"), + }; + event.arguments.push_back(std::move(argument)); } xml.skipCurrentElement(); @@ -211,16 +215,19 @@ Scanner::WaylandEvent Scanner::readEvent(QXmlStreamReader &xml, bool request) Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml) { - WaylandEnum result; - result.name = byteArrayValue(xml, "name"); + WaylandEnum result = { + .name = byteArrayValue(xml, "name"), + .entries = {}, + }; while (xml.readNextStartElement()) { if (xml.name() == "entry") { - WaylandEnumEntry entry; - entry.name = byteArrayValue(xml, "name"); - entry.value = byteArrayValue(xml, "value"); - entry.summary = byteArrayValue(xml, "summary"); - result.entries << entry; + WaylandEnumEntry entry = { + .name = byteArrayValue(xml, "name"), + .value = byteArrayValue(xml, "value"), + .summary = byteArrayValue(xml, "summary"), + }; + result.entries.push_back(std::move(entry)); } xml.skipCurrentElement(); @@ -231,17 +238,21 @@ Scanner::WaylandEnum Scanner::readEnum(QXmlStreamReader &xml) Scanner::WaylandInterface Scanner::readInterface(QXmlStreamReader &xml) { - WaylandInterface interface; - interface.name = byteArrayValue(xml, "name"); - interface.version = intValue(xml, "version", 1); + WaylandInterface interface = { + .name = byteArrayValue(xml, "name"), + .version = intValue(xml, "version", 1), + .enums = {}, + .events = {}, + .requests = {}, + }; while (xml.readNextStartElement()) { if (xml.name() == "event") - interface.events << readEvent(xml, false); + interface.events.push_back(readEvent(xml, false)); else if (xml.name() == "request") - interface.requests << readEvent(xml, true); + interface.requests.push_back(readEvent(xml, true)); else if (xml.name() == "enum") - interface.enums << readEnum(xml); + interface.enums.push_back(readEnum(xml)); else xml.skipCurrentElement(); } @@ -283,11 +294,11 @@ QByteArray Scanner::waylandToQtType(const QByteArray &waylandType, const QByteAr return waylandToCType(waylandType, interface); } -const Scanner::WaylandArgument *Scanner::newIdArgument(const QList<WaylandArgument> &arguments) +const Scanner::WaylandArgument *Scanner::newIdArgument(const std::vector<WaylandArgument> &arguments) { - for (int i = 0; i < arguments.size(); ++i) { - if (arguments.at(i).type == "new_id") - return &arguments.at(i); + for (const WaylandArgument &a : arguments) { + if (a.type == "new_id") + return &a; } return nullptr; } @@ -305,8 +316,7 @@ void Scanner::printEvent(const WaylandEvent &e, bool omitNames, bool withResourc needsComma = true; } } - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { bool isNewId = a.type == "new_id"; if (isNewId && !isServerSide() && (a.interface.isEmpty() != e.request)) continue; @@ -346,9 +356,8 @@ void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *inte printf(" %svoid *data,\n", indent); printf(" %sstruct ::%s *object", indent, interfaceName); } - for (int i = 0; i < e.arguments.size(); ++i) { + for (const WaylandArgument &a : e.arguments) { printf(",\n"); - const WaylandArgument &a = e.arguments.at(i); bool isNewId = a.type == "new_id"; if (isServerSide() && isNewId) { printf(" %suint32_t %s", indent, a.name.constData()); @@ -360,17 +369,13 @@ void Scanner::printEventHandlerSignature(const WaylandEvent &e, const char *inte printf(")"); } -void Scanner::printEnums(const QList<WaylandEnum> &enums) +void Scanner::printEnums(const std::vector<WaylandEnum> &enums) { - for (int i = 0; i < enums.size(); ++i) { + for (const WaylandEnum &e : enums) { printf("\n"); - const WaylandEnum &e = enums.at(i); printf(" enum %s {\n", e.name.constData()); - for (int i = 0; i < e.entries.size(); ++i) { - const WaylandEnumEntry &entry = e.entries.at(i); - printf(" %s_%s = %s", e.name.constData(), entry.name.constData(), entry.value.constData()); - if (i < e.entries.size() - 1) - printf(","); + for (const WaylandEnumEntry &entry : e.entries) { + printf(" %s_%s = %s,", e.name.constData(), entry.name.constData(), entry.value.constData()); if (!entry.summary.isNull()) printf(" // %s", entry.summary.constData()); printf("\n"); @@ -424,11 +429,11 @@ bool Scanner::process() //QByteArray preProcessorProtocolName = QByteArray(m_protocolName).replace('-', '_').toUpper(); QByteArray preProcessorProtocolName = QByteArray(m_protocolName).toUpper(); - QList<WaylandInterface> interfaces; + std::vector<WaylandInterface> interfaces; while (m_xml->readNextStartElement()) { if (m_xml->name() == "interface") - interfaces << readInterface(*m_xml); + interfaces.push_back(readInterface(*m_xml)); else m_xml->skipCurrentElement(); } @@ -478,12 +483,16 @@ bool Scanner::process() printf("\n"); printf("namespace QtWaylandServer {\n"); - for (int j = 0; j < interfaces.size(); ++j) { - const WaylandInterface &interface = interfaces.at(j); + bool needsNewLine = false; + for (const WaylandInterface &interface : interfaces) { if (ignoreInterface(interface.name)) continue; + if (needsNewLine) + printf("\n"); + needsNewLine = true; + const char *interfaceName = interface.name.constData(); QByteArray stripped = stripInterfaceName(interface.name); @@ -538,7 +547,7 @@ bool Scanner::process() printEnums(interface.enums); - bool hasEvents = !interface.events.isEmpty(); + bool hasEvents = !interface.events.empty(); if (hasEvents) { printf("\n"); @@ -559,7 +568,7 @@ bool Scanner::process() printf(" virtual void %s_bind_resource(Resource *resource);\n", interfaceNameStripped); printf(" virtual void %s_destroy_resource(Resource *resource);\n", interfaceNameStripped); - bool hasRequests = !interface.requests.isEmpty(); + bool hasRequests = !interface.requests.empty(); if (hasRequests) { printf("\n"); @@ -584,8 +593,7 @@ bool Scanner::process() printf(" static const struct ::%s_interface m_%s_interface;\n", interfaceName, interfaceName); printf("\n"); - for (int i = 0; i < interface.requests.size(); ++i) { - const WaylandEvent &e = interface.requests.at(i); + for (const WaylandEvent &e : interface.requests) { printf(" static void "); printEventHandlerSignature(e, interfaceName); @@ -603,9 +611,6 @@ bool Scanner::process() printf(" };\n"); printf(" DisplayDestroyedListener m_displayDestroyedListener;\n"); printf(" };\n"); - - if (j < interfaces.size() - 1) - printf("\n"); } printf("}\n"); @@ -629,8 +634,7 @@ bool Scanner::process() printf("namespace QtWaylandServer {\n"); bool needsNewLine = false; - for (int j = 0; j < interfaces.size(); ++j) { - const WaylandInterface &interface = interfaces.at(j); + for (const WaylandInterface &interface : interfaces) { if (ignoreInterface(interface.name)) continue; @@ -778,7 +782,7 @@ bool Scanner::process() printf(" }\n"); printf("\n"); - bool hasRequests = !interface.requests.isEmpty(); + bool hasRequests = !interface.requests.empty(); QByteArray interfaceMember = hasRequests ? "&m_" + interface.name + "_interface" : QByteArray("nullptr"); @@ -816,11 +820,12 @@ bool Scanner::process() if (hasRequests) { printf("\n"); printf(" const struct ::%s_interface %s::m_%s_interface = {", interfaceName, interfaceName, interfaceName); - for (int i = 0; i < interface.requests.size(); ++i) { - if (i > 0) + bool needsComma = false; + for (const WaylandEvent &e : interface.requests) { + if (needsComma) printf(","); + needsComma = true; printf("\n"); - const WaylandEvent &e = interface.requests.at(i); printf(" %s::handle_%s", interfaceName, e.name.constData()); } printf("\n"); @@ -836,11 +841,10 @@ bool Scanner::process() } printf("\n"); - for (int i = 0; i < interface.requests.size(); ++i) { + for (const WaylandEvent &e : interface.requests) { printf("\n"); printf(" void %s::", interfaceName); - const WaylandEvent &e = interface.requests.at(i); printEventHandlerSignature(e, interfaceName, false); printf("\n"); @@ -849,9 +853,8 @@ bool Scanner::process() printf(" Resource *r = Resource::fromResource(resource);\n"); printf(" static_cast<%s *>(r->%s_object)->%s_%s(\n", interfaceName, interfaceNameStripped, interfaceNameStripped, e.name.constData()); printf(" r"); - for (int i = 0; i < e.arguments.size(); ++i) { + for (const WaylandArgument &a : e.arguments) { printf(",\n"); - const WaylandArgument &a = e.arguments.at(i); QByteArray cType = waylandToCType(a.type, a.interface); QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); const char *argumentName = a.name.constData(); @@ -865,17 +868,15 @@ bool Scanner::process() } } - for (int i = 0; i < interface.events.size(); ++i) { + for (const WaylandEvent &e : interface.events) { printf("\n"); - const WaylandEvent &e = interface.events.at(i); printf(" void %s::send_", interfaceName); printEvent(e); printf("\n"); printf(" {\n"); printf(" send_%s(\n", e.name.constData()); printf(" m_resource->handle"); - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { printf(",\n"); printf(" %s", a.name.constData()); } @@ -888,8 +889,7 @@ bool Scanner::process() printf("\n"); printf(" {\n"); - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { if (a.type != "array") continue; QByteArray array = a.name + "_data"; @@ -905,8 +905,7 @@ bool Scanner::process() printf(" %s_send_%s(\n", interfaceName, e.name.constData()); printf(" resource"); - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { printf(",\n"); QByteArray cType = waylandToCType(a.type, a.interface); QByteArray qtType = waylandToQtType(a.type, a.interface, e.request); @@ -962,12 +961,17 @@ bool Scanner::process() } printf("\n"); printf("namespace QtWayland {\n"); - for (int j = 0; j < interfaces.size(); ++j) { - const WaylandInterface &interface = interfaces.at(j); + + bool needsNewLine = false; + for (const WaylandInterface &interface : interfaces) { if (ignoreInterface(interface.name)) continue; + if (needsNewLine) + printf("\n"); + needsNewLine = true; + const char *interfaceName = interface.name.constData(); QByteArray stripped = stripInterfaceName(interface.name); @@ -994,7 +998,7 @@ bool Scanner::process() printEnums(interface.enums); - if (!interface.requests.isEmpty()) { + if (!interface.requests.empty()) { printf("\n"); for (const WaylandEvent &e : interface.requests) { const WaylandArgument *new_id = newIdArgument(e.arguments); @@ -1011,7 +1015,7 @@ bool Scanner::process() } } - bool hasEvents = !interface.events.isEmpty(); + bool hasEvents = !interface.events.empty(); if (hasEvents) { printf("\n"); @@ -1028,8 +1032,7 @@ bool Scanner::process() if (hasEvents) { printf(" void init_listener();\n"); printf(" static const struct %s_listener m_%s_listener;\n", interfaceName, interfaceName); - for (int i = 0; i < interface.events.size(); ++i) { - const WaylandEvent &e = interface.events.at(i); + for (const WaylandEvent &e : interface.events) { printf(" static void "); printEventHandlerSignature(e, interfaceName); @@ -1038,9 +1041,6 @@ bool Scanner::process() } printf(" struct ::%s *m_%s;\n", interfaceName, interfaceName); printf(" };\n"); - - if (j < interfaces.size() - 1) - printf("\n"); } printf("}\n"); printf("\n"); @@ -1077,18 +1077,23 @@ bool Scanner::process() printf("#endif\n"); printf("}\n"); printf("\n"); - for (int j = 0; j < interfaces.size(); ++j) { - const WaylandInterface &interface = interfaces.at(j); + + bool needsNewLine = false; + for (const WaylandInterface &interface : interfaces) { if (ignoreInterface(interface.name)) continue; + if (needsNewLine) + printf("\n"); + needsNewLine = true; + const char *interfaceName = interface.name.constData(); QByteArray stripped = stripInterfaceName(interface.name); const char *interfaceNameStripped = stripped.constData(); - bool hasEvents = !interface.events.isEmpty(); + bool hasEvents = !interface.events.empty(); printf(" %s::%s(struct ::wl_registry *registry, int id, int version)\n", interfaceName, interfaceName); printf(" {\n"); @@ -1152,9 +1157,8 @@ bool Scanner::process() printf(" return &::%s_interface;\n", interfaceName); printf(" }\n"); - for (int i = 0; i < interface.requests.size(); ++i) { + for (const WaylandEvent &e : interface.requests) { printf("\n"); - const WaylandEvent &e = interface.requests.at(i); const WaylandArgument *new_id = newIdArgument(e.arguments); QByteArray new_id_str = "void "; if (new_id) { @@ -1167,8 +1171,7 @@ bool Scanner::process() printEvent(e); printf("\n"); printf(" {\n"); - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { if (a.type != "array") continue; QByteArray array = a.name + "_data"; @@ -1180,12 +1183,11 @@ bool Scanner::process() printf(" %s.alloc = 0;\n", arrayName); printf("\n"); } - int actualArgumentCount = new_id ? e.arguments.size() - 1 : e.arguments.size(); + int actualArgumentCount = new_id ? int(e.arguments.size()) - 1 : int(e.arguments.size()); printf(" %s%s_%s(\n", new_id ? "return " : "", interfaceName, e.name.constData()); printf(" m_%s%s", interfaceName, actualArgumentCount > 0 ? "," : ""); bool needsComma = false; - for (int i = 0; i < e.arguments.size(); ++i) { - const WaylandArgument &a = e.arguments.at(i); + for (const WaylandArgument &a : e.arguments) { bool isNewId = a.type == "new_id"; if (isNewId && !a.interface.isEmpty()) continue; @@ -1215,8 +1217,7 @@ bool Scanner::process() if (hasEvents) { printf("\n"); - for (int i = 0; i < interface.events.size(); ++i) { - const WaylandEvent &e = interface.events.at(i); + for (const WaylandEvent &e : interface.events) { printf(" void %s::%s_", interfaceName, interfaceNameStripped); printEvent(e, true); printf("\n"); @@ -1229,17 +1230,17 @@ bool Scanner::process() printf(" {\n"); printf(" Q_UNUSED(object);\n"); printf(" static_cast<%s *>(data)->%s_%s(", interfaceName, interfaceNameStripped, e.name.constData()); - for (int i = 0; i < e.arguments.size(); ++i) { + bool needsComma = false; + for (const WaylandArgument &a : e.arguments) { + if (needsComma) + printf(","); + needsComma = true; printf("\n"); - const WaylandArgument &a = e.arguments.at(i); const char *argumentName = a.name.constData(); if (a.type == "string") printf(" QString::fromUtf8(%s)", argumentName); else printf(" %s", argumentName); - - if (i < e.arguments.size() - 1) - printf(","); } printf(");\n"); @@ -1247,9 +1248,8 @@ bool Scanner::process() printf("\n"); } printf(" const struct %s_listener %s::m_%s_listener = {\n", interfaceName, interfaceName, interfaceName); - for (int i = 0; i < interface.events.size(); ++i) { - const WaylandEvent &e = interface.events.at(i); - printf(" %s::handle_%s%s\n", interfaceName, e.name.constData(), i < interface.events.size() - 1 ? "," : ""); + for (const WaylandEvent &e : interface.events) { + printf(" %s::handle_%s,\n", interfaceName, e.name.constData()); } printf(" };\n"); printf("\n"); @@ -1259,9 +1259,6 @@ bool Scanner::process() printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName); printf(" }\n"); } - - if (j < interfaces.size() - 1) - printf("\n"); } printf("}\n"); printf("\n"); diff --git a/src/src.pro b/src/src.pro index d4244de33..3d68c69fb 100644 --- a/src/src.pro +++ b/src/src.pro @@ -3,21 +3,22 @@ include($$OUT_PWD/client/qtwaylandclient-config.pri) include($$OUT_PWD/compositor/qtwaylandcompositor-config.pri) QT_FOR_CONFIG += waylandclient-private waylandcompositor-private -qtConfig(wayland-client) { +qtConfig(wayland-client)|qtConfig(wayland-server) { sub_qtwaylandscanner.subdir = qtwaylandscanner sub_qtwaylandscanner.target = sub-qtwaylandscanner SUBDIRS += sub_qtwaylandscanner - sub_client.subdir = client - sub_client.depends = sub-qtwaylandscanner - sub_client.target = sub-client - SUBDIRS += sub_client + qtConfig(wayland-client) { + sub_client.subdir = client + sub_client.depends = sub-qtwaylandscanner + sub_client.target = sub-client + SUBDIRS += sub_client + } sub_plugins.subdir = plugins - sub_plugins.depends += sub-qtwaylandscanner sub-client - qtConfig(wayland-server) { - sub_plugins.depends += sub-compositor - } + sub_plugins.depends += sub-qtwaylandscanner + qtConfig(wayland-client):sub_plugins.depends += sub-client + qtConfig(wayland-server):sub_plugins.depends += sub-compositor sub_plugins.target = sub-plugins SUBDIRS += sub_plugins @@ -26,10 +27,11 @@ qtConfig(wayland-client) { sub_compositor.depends = sub-qtwaylandscanner sub_compositor.target = sub-compositor SUBDIRS += sub_compositor - - sub_imports.subdir = imports - sub_imports.depends += sub-compositor sub-client - sub_imports.target = sub-imports - SUBDIRS += sub_imports } + + sub_imports.subdir = imports + qtConfig(wayland-client):sub_imports.depends += sub-client + qtConfig(wayland-server):sub_imports.depends += sub-compositor + sub_imports.target = sub-imports + SUBDIRS += sub_imports } |