Merge "Merge remote-tracking branch 'origin/dev' into wip/qt6"
This commit is contained in:
commit
95ce296968
83
src/3rdparty/wayland/protocols/idle-inhibit-unstable-v1.xml
vendored
Normal file
83
src/3rdparty/wayland/protocols/idle-inhibit-unstable-v1.xml
vendored
Normal file
@ -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>
|
@ -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",
|
||||
|
@ -20,7 +20,7 @@ qtConfig(xkbcommon) {
|
||||
}
|
||||
|
||||
qtHaveModule(linuxaccessibility_support_private): \
|
||||
QT += linuxaccessibility_support_private
|
||||
QT_PRIVATE += linuxaccessibility_support_private
|
||||
|
||||
QMAKE_USE += wayland-client
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
if (mFrameCallbackTimerId != -1) {
|
||||
killTimer(mFrameCallbackTimerId);
|
||||
mFrameCallbackTimerId = -1;
|
||||
}
|
||||
|
||||
// Stop the timer and stop waiting immediately
|
||||
int timerId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1);
|
||||
mWaitingForFrameCallback = false;
|
||||
mFrameCallbackTimedOut = false;
|
||||
|
||||
if (!wasExposed && isExposed())
|
||||
sendExposeEvent(QRect(QPoint(), geometry().size()));
|
||||
if (wasExposed && hasPendingUpdateRequest())
|
||||
deliverUpdateRequest();
|
||||
// The rest can wait until we can run it on the correct thread
|
||||
auto doHandleExpose = [this, timerId]() {
|
||||
if (timerId != -1)
|
||||
killTimer(timerId);
|
||||
|
||||
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 (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);
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -66,7 +66,7 @@ void tst_datadevicev1::initTestCase()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(pointer());
|
||||
QCOMPOSITOR_TRY_VERIFY(!pointer()->resourceMap().empty());
|
||||
QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 4);
|
||||
QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 5);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(keyboard());
|
||||
|
||||
@ -104,8 +104,11 @@ void tst_datadevicev1::pasteAscii()
|
||||
keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
|
||||
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client);
|
||||
pointer()->sendButton(client, BTN_LEFT, 1);
|
||||
pointer()->sendFrame(client);
|
||||
pointer()->sendButton(client, BTN_LEFT, 0);
|
||||
pointer()->sendFrame(client);
|
||||
});
|
||||
QTRY_COMPARE(window.m_text, "normal ascii");
|
||||
}
|
||||
@ -139,8 +142,11 @@ void tst_datadevicev1::pasteUtf8()
|
||||
keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
|
||||
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client);
|
||||
pointer()->sendButton(client, BTN_LEFT, 1);
|
||||
pointer()->sendFrame(client);
|
||||
pointer()->sendButton(client, BTN_LEFT, 0);
|
||||
pointer()->sendFrame(client);
|
||||
});
|
||||
QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
include (../shared/shared.pri)
|
||||
|
||||
QT += waylandcompositor
|
||||
|
||||
TARGET = tst_inputcontext
|
||||
SOURCES += tst_inputcontext.cpp
|
||||
|
@ -196,8 +196,11 @@ void tst_output::removePrimaryScreen()
|
||||
exec([&] {
|
||||
auto *surface = xdgToplevel()->surface();
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_LEFT, 1);
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_LEFT, 0);
|
||||
pointer()->sendFrame(client());
|
||||
});
|
||||
|
||||
// Wait to make sure mouse events dont't cause a crash now that the screen has changed
|
||||
|
@ -268,7 +268,7 @@ void tst_primaryselectionv1::initTestCase()
|
||||
{
|
||||
QCOMPOSITOR_TRY_VERIFY(pointer());
|
||||
QCOMPOSITOR_TRY_VERIFY(!pointer()->resourceMap().empty());
|
||||
QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 4);
|
||||
QCOMPOSITOR_TRY_COMPARE(pointer()->resourceMap().first()->version(), 5);
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(keyboard());
|
||||
}
|
||||
@ -329,8 +329,11 @@ void tst_primaryselectionv1::pasteAscii()
|
||||
device->sendSelection(offer);
|
||||
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_MIDDLE, 1);
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_MIDDLE, 0);
|
||||
pointer()->sendFrame(client());
|
||||
});
|
||||
QTRY_COMPARE(window.m_formats, QStringList{"text/plain"});
|
||||
QTRY_COMPARE(window.m_text, "normal ascii");
|
||||
@ -372,8 +375,11 @@ void tst_primaryselectionv1::pasteUtf8()
|
||||
device->sendSelection(offer);
|
||||
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_MIDDLE, 1);
|
||||
pointer()->sendFrame(client());
|
||||
pointer()->sendButton(client(), BTN_MIDDLE, 0);
|
||||
pointer()->sendFrame(client());
|
||||
});
|
||||
QTRY_COMPARE(window.m_formats, QStringList({"text/plain", "text/plain;charset=utf-8"}));
|
||||
QTRY_COMPARE(window.m_text, "face with tears of joy: 😂");
|
||||
@ -428,8 +434,11 @@ void tst_primaryselectionv1::copy()
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
keyboard()->sendEnter(surface); // Need to set keyboard focus according to protocol
|
||||
pointer()->sendEnter(surface, {32, 32});
|
||||
pointer()->sendFrame(client());
|
||||
mouseSerials << pointer()->sendButton(client(), BTN_MIDDLE, 1);
|
||||
pointer()->sendFrame(client());
|
||||
mouseSerials << pointer()->sendButton(client(), BTN_MIDDLE, 0);
|
||||
pointer()->sendFrame(client());
|
||||
});
|
||||
QCOMPOSITOR_TRY_VERIFY(primarySelectionDevice()->m_selectionSource);
|
||||
QCOMPOSITOR_TRY_VERIFY(mouseSerials.contains(primarySelectionDevice()->m_serial));
|
||||
|
@ -212,22 +212,20 @@ void tst_seatv4::simpleAxis_data()
|
||||
{
|
||||
QTest::addColumn<uint>("axis");
|
||||
QTest::addColumn<qreal>("value");
|
||||
QTest::addColumn<Qt::Orientation>("orientation");
|
||||
QTest::addColumn<QPoint>("angleDelta");
|
||||
|
||||
// Directions in regular windows/linux terms (no "natural" scrolling)
|
||||
QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << Qt::Vertical << QPoint{0, -12};
|
||||
QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << Qt::Vertical << QPoint{0, 12};
|
||||
QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << Qt::Horizontal << QPoint{-12, 0};
|
||||
QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << Qt::Horizontal << QPoint{12, 0};
|
||||
QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << Qt::Vertical << QPoint{0, 120};
|
||||
QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12};
|
||||
QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12};
|
||||
QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0};
|
||||
QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0};
|
||||
QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120};
|
||||
}
|
||||
|
||||
void tst_seatv4::simpleAxis()
|
||||
{
|
||||
QFETCH(uint, axis);
|
||||
QFETCH(qreal, value);
|
||||
QFETCH(Qt::Orientation, orientation);
|
||||
QFETCH(QPoint, angleDelta);
|
||||
|
||||
class WheelWindow : QRasterWindow {
|
||||
@ -256,27 +254,18 @@ void tst_seatv4::simpleAxis()
|
||||
// We didn't press any buttons
|
||||
QCOMPARE(event->buttons(), Qt::NoButton);
|
||||
|
||||
if (event->orientation() == Qt::Horizontal)
|
||||
QCOMPARE(event->delta(), event->angleDelta().x());
|
||||
else
|
||||
QCOMPARE(event->delta(), event->angleDelta().y());
|
||||
|
||||
// There has been no information about what created the event.
|
||||
// Documentation says not synthesized is appropriate in such cases
|
||||
QCOMPARE(event->source(), Qt::MouseEventNotSynthesized);
|
||||
|
||||
m_events.append(Event(event->pixelDelta(), event->angleDelta(), event->orientation()));
|
||||
m_events.append(Event{event->pixelDelta(), event->angleDelta()});
|
||||
}
|
||||
struct Event // Because I didn't find a convenient way to copy it entirely
|
||||
{
|
||||
// TODO: Constructors can be removed when we start supporting brace-initializers
|
||||
Event() = default;
|
||||
Event(const QPoint &pixelDelta, const QPoint &angleDelta, Qt::Orientation orientation)
|
||||
: pixelDelta(pixelDelta), angleDelta(angleDelta), orientation(orientation)
|
||||
{}
|
||||
|
||||
const QPoint pixelDelta;
|
||||
const QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
const Qt::Orientation orientation{};
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
};
|
||||
@ -299,7 +288,6 @@ void tst_seatv4::simpleAxis()
|
||||
QTRY_COMPARE(window.m_events.size(), 1);
|
||||
auto event = window.m_events.takeFirst();
|
||||
QCOMPARE(event.angleDelta, angleDelta);
|
||||
QCOMPARE(event.orientation, orientation);
|
||||
}
|
||||
|
||||
void tst_seatv4::invalidPointerEvents()
|
||||
|
@ -41,18 +41,11 @@ public:
|
||||
|
||||
removeAll<Seat>();
|
||||
|
||||
uint capabilities = MockCompositor::Seat::capability_pointer;
|
||||
uint capabilities = MockCompositor::Seat::capability_pointer | MockCompositor::Seat::capability_touch;
|
||||
int version = 5;
|
||||
add<Seat>(capabilities, version);
|
||||
});
|
||||
}
|
||||
|
||||
Pointer *pointer()
|
||||
{
|
||||
auto *seat = get<Seat>();
|
||||
Q_ASSERT(seat);
|
||||
return seat->m_pointer;
|
||||
}
|
||||
};
|
||||
|
||||
class tst_seatv5 : public QObject, private SeatV5Compositor
|
||||
@ -61,6 +54,8 @@ class tst_seatv5 : public QObject, private SeatV5Compositor
|
||||
private slots:
|
||||
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
|
||||
void bindsToSeat();
|
||||
|
||||
// Pointer tests
|
||||
void createsPointer();
|
||||
void setsCursorOnEnter();
|
||||
void usesEnterSerial();
|
||||
@ -69,6 +64,10 @@ private slots:
|
||||
void fingerScroll();
|
||||
void fingerScrollSlow();
|
||||
void wheelDiscreteScroll();
|
||||
|
||||
// Touch tests
|
||||
void createsTouch();
|
||||
void singleTap();
|
||||
};
|
||||
|
||||
void tst_seatv5::bindsToSeat()
|
||||
@ -128,12 +127,8 @@ public:
|
||||
QRasterWindow::wheelEvent(event);
|
||||
// qDebug() << event << "angleDelta" << event->angleDelta() << "pixelDelta" << event->pixelDelta();
|
||||
|
||||
if (event->phase() == Qt::ScrollUpdate || event->phase() == Qt::NoScrollPhase) {
|
||||
// Angle delta should always be provided (says docs, but QPA sends compatibility events
|
||||
// for Qt4 with zero angleDelta, and with a delta)
|
||||
QVERIFY(!event->angleDelta().isNull() || event->delta());
|
||||
} else {
|
||||
// Shouldn't have deltas in the other phases
|
||||
if (event->phase() != Qt::ScrollUpdate && event->phase() != Qt::NoScrollPhase) {
|
||||
// Shouldn't have deltas in the these phases
|
||||
QCOMPARE(event->angleDelta(), QPoint(0, 0));
|
||||
QCOMPARE(event->pixelDelta(), QPoint(0, 0));
|
||||
}
|
||||
@ -145,13 +140,6 @@ public:
|
||||
// We didn't press any buttons
|
||||
QCOMPARE(event->buttons(), Qt::NoButton);
|
||||
|
||||
if (!event->angleDelta().isNull()) {
|
||||
if (event->orientation() == Qt::Horizontal)
|
||||
QCOMPARE(event->delta(), event->angleDelta().x());
|
||||
else
|
||||
QCOMPARE(event->delta(), event->angleDelta().y());
|
||||
}
|
||||
|
||||
m_events.append(Event{event});
|
||||
}
|
||||
struct Event // Because I didn't find a convenient way to copy it entirely
|
||||
@ -161,14 +149,12 @@ public:
|
||||
: phase(event->phase())
|
||||
, pixelDelta(event->pixelDelta())
|
||||
, angleDelta(event->angleDelta())
|
||||
, orientation(event->orientation())
|
||||
, source(event->source())
|
||||
{
|
||||
}
|
||||
const Qt::ScrollPhase phase{};
|
||||
const QPoint pixelDelta;
|
||||
const QPoint angleDelta; // eights of a degree, positive is upwards, left
|
||||
const Qt::Orientation orientation{};
|
||||
const Qt::MouseEventSource source{};
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
@ -178,22 +164,20 @@ void tst_seatv5::simpleAxis_data()
|
||||
{
|
||||
QTest::addColumn<uint>("axis");
|
||||
QTest::addColumn<qreal>("value");
|
||||
QTest::addColumn<Qt::Orientation>("orientation");
|
||||
QTest::addColumn<QPoint>("angleDelta");
|
||||
|
||||
// Directions in regular windows/linux terms (no "natural" scrolling)
|
||||
QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << Qt::Vertical << QPoint{0, -12};
|
||||
QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << Qt::Vertical << QPoint{0, 12};
|
||||
QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << Qt::Horizontal << QPoint{-12, 0};
|
||||
QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << Qt::Horizontal << QPoint{12, 0};
|
||||
QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << Qt::Vertical << QPoint{0, 120};
|
||||
QTest::newRow("down") << uint(Pointer::axis_vertical_scroll) << 1.0 << QPoint{0, -12};
|
||||
QTest::newRow("up") << uint(Pointer::axis_vertical_scroll) << -1.0 << QPoint{0, 12};
|
||||
QTest::newRow("left") << uint(Pointer::axis_horizontal_scroll) << 1.0 << QPoint{-12, 0};
|
||||
QTest::newRow("right") << uint(Pointer::axis_horizontal_scroll) << -1.0 << QPoint{12, 0};
|
||||
QTest::newRow("up big") << uint(Pointer::axis_vertical_scroll) << -10.0 << QPoint{0, 120};
|
||||
}
|
||||
|
||||
void tst_seatv5::simpleAxis()
|
||||
{
|
||||
QFETCH(uint, axis);
|
||||
QFETCH(qreal, value);
|
||||
QFETCH(Qt::Orientation, orientation);
|
||||
QFETCH(QPoint, angleDelta);
|
||||
|
||||
WheelWindow window;
|
||||
@ -220,7 +204,6 @@ void tst_seatv5::simpleAxis()
|
||||
// There has been no information about what created the event.
|
||||
// Documentation says not synthesized is appropriate in such cases
|
||||
QCOMPARE(e.source, Qt::MouseEventNotSynthesized);
|
||||
QCOMPARE(e.orientation, orientation);
|
||||
QCOMPARE(e.angleDelta, angleDelta);
|
||||
}
|
||||
|
||||
@ -263,7 +246,7 @@ void tst_seatv5::fingerScroll()
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.phase, Qt::ScrollUpdate);
|
||||
QCOMPARE(e.orientation, Qt::Vertical);
|
||||
QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
|
||||
// QCOMPARE(e.angleDelta, angleDelta); // TODO: what should this be?
|
||||
QCOMPARE(e.pixelDelta, QPoint(0, 10));
|
||||
QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // A finger is not a wheel
|
||||
@ -281,7 +264,7 @@ void tst_seatv5::fingerScroll()
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.phase, Qt::ScrollUpdate);
|
||||
QCOMPARE(e.orientation, Qt::Horizontal);
|
||||
QVERIFY(qAbs(e.angleDelta.x()) > qAbs(e.angleDelta.y())); // Horizontal scroll
|
||||
QCOMPARE(e.pixelDelta, QPoint(10, 0));
|
||||
QCOMPARE(e.source, Qt::MouseEventSynthesizedBySystem); // A finger is not a wheel
|
||||
}
|
||||
@ -373,7 +356,7 @@ void tst_seatv5::wheelDiscreteScroll()
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.phase, Qt::NoScrollPhase);
|
||||
QCOMPARE(e.orientation, Qt::Vertical);
|
||||
QVERIFY(qAbs(e.angleDelta.x()) <= qAbs(e.angleDelta.y())); // Vertical scroll
|
||||
// According to the docs the angle delta is in eights of a degree and most mice have
|
||||
// 1 click = 15 degrees. The angle delta should therefore be:
|
||||
// 15 degrees / (1/8 eights per degrees) = 120 eights of degrees.
|
||||
@ -383,5 +366,70 @@ void tst_seatv5::wheelDiscreteScroll()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_seatv5::createsTouch()
|
||||
{
|
||||
QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().size(), 1);
|
||||
QCOMPOSITOR_TRY_COMPARE(touch()->resourceMap().first()->version(), 5);
|
||||
}
|
||||
|
||||
class TouchWindow : public QRasterWindow {
|
||||
public:
|
||||
TouchWindow()
|
||||
{
|
||||
resize(64, 64);
|
||||
show();
|
||||
}
|
||||
void touchEvent(QTouchEvent *event) override
|
||||
{
|
||||
QRasterWindow::touchEvent(event);
|
||||
m_events.append(Event{event});
|
||||
}
|
||||
struct Event // Because I didn't find a convenient way to copy it entirely
|
||||
{
|
||||
explicit Event() = default;
|
||||
explicit Event(const QTouchEvent *event)
|
||||
: type(event->type())
|
||||
, touchPointStates(event->touchPointStates())
|
||||
, touchPoints(event->touchPoints())
|
||||
{
|
||||
}
|
||||
const QEvent::Type type{};
|
||||
const Qt::TouchPointStates touchPointStates{};
|
||||
const QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
};
|
||||
QVector<Event> m_events;
|
||||
};
|
||||
|
||||
void tst_seatv5::singleTap()
|
||||
{
|
||||
TouchWindow window;
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
exec([=] {
|
||||
auto *t = touch();
|
||||
auto *c = client();
|
||||
t->sendDown(xdgToplevel()->surface(), {32, 32}, 1);
|
||||
t->sendFrame(c);
|
||||
t->sendUp(c, 1);
|
||||
t->sendFrame(c);
|
||||
});
|
||||
|
||||
QTRY_VERIFY(!window.m_events.empty());
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.type, QEvent::TouchBegin);
|
||||
QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointPressed);
|
||||
QCOMPARE(e.touchPoints.length(), 1);
|
||||
QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
|
||||
}
|
||||
{
|
||||
auto e = window.m_events.takeFirst();
|
||||
QCOMPARE(e.type, QEvent::TouchEnd);
|
||||
QCOMPARE(e.touchPointStates, Qt::TouchPointState::TouchPointReleased);
|
||||
QCOMPARE(e.touchPoints.length(), 1);
|
||||
QCOMPARE(e.touchPoints.first().pos(), QPointF(32-window.frameMargins().left(), 32-window.frameMargins().top()));
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_seatv5)
|
||||
#include "tst_seatv5.moc"
|
||||
|
@ -191,12 +191,15 @@ Seat::~Seat()
|
||||
{
|
||||
qDeleteAll(m_oldPointers);
|
||||
delete m_pointer;
|
||||
|
||||
qDeleteAll(m_oldTouchs);
|
||||
delete m_touch;
|
||||
|
||||
qDeleteAll(m_oldKeyboards);
|
||||
delete m_keyboard;
|
||||
}
|
||||
|
||||
void Seat::setCapabilities(uint capabilities) {
|
||||
// TODO: Add support for touch
|
||||
Q_ASSERT(~capabilities & capability_touch);
|
||||
|
||||
m_capabilities = capabilities;
|
||||
|
||||
if (m_capabilities & capability_pointer) {
|
||||
@ -207,6 +210,14 @@ void Seat::setCapabilities(uint capabilities) {
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
if (m_capabilities & capability_touch) {
|
||||
if (!m_touch)
|
||||
m_touch = (new Touch(this));
|
||||
} else if (m_touch) {
|
||||
m_oldTouchs << m_touch;
|
||||
m_touch = nullptr;
|
||||
}
|
||||
|
||||
if (m_capabilities & capability_keyboard) {
|
||||
if (!m_keyboard)
|
||||
m_keyboard = (new Keyboard(this));
|
||||
@ -234,9 +245,24 @@ void Seat::seat_get_pointer(Resource *resource, uint32_t id)
|
||||
m_pointer->add(resource->client(), id, resource->version());
|
||||
}
|
||||
|
||||
void Seat::seat_get_touch(QtWaylandServer::wl_seat::Resource *resource, uint32_t id)
|
||||
{
|
||||
if (~m_capabilities & capability_touch) {
|
||||
qWarning() << "Client requested a wl_touch without the capability being available."
|
||||
<< "This Could be a race condition when hotunplugging,"
|
||||
<< "but is most likely a client error";
|
||||
Touch *touch = new Touch(this);
|
||||
touch->add(resource->client(), id, resource->version());
|
||||
// TODO: mark as destroyed
|
||||
m_oldTouchs << touch;
|
||||
return;
|
||||
}
|
||||
m_touch->add(resource->client(), id, resource->version());
|
||||
}
|
||||
|
||||
void Seat::seat_get_keyboard(QtWaylandServer::wl_seat::Resource *resource, uint32_t id)
|
||||
{
|
||||
if (~m_capabilities & capability_pointer) {
|
||||
if (~m_capabilities & capability_keyboard) {
|
||||
qWarning() << "Client requested a wl_keyboard without the capability being available."
|
||||
<< "This Could be a race condition when hotunplugging,"
|
||||
<< "but is most likely a client error";
|
||||
@ -371,6 +397,40 @@ void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resourc
|
||||
emit setCursor(serial);
|
||||
}
|
||||
|
||||
uint Touch::sendDown(Surface *surface, const QPointF &position, int id)
|
||||
{
|
||||
wl_fixed_t x = wl_fixed_from_double(position.x());
|
||||
wl_fixed_t y = wl_fixed_from_double(position.y());
|
||||
uint serial = m_seat->m_compositor->nextSerial();
|
||||
auto time = m_seat->m_compositor->currentTimeMilliseconds();
|
||||
wl_client *client = surface->resource()->client();
|
||||
|
||||
const auto touchResources = resourceMap().values(client);
|
||||
for (auto *r : touchResources)
|
||||
wl_touch::send_down(r->handle, serial, time, surface->resource()->handle, id, x, y);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
uint Touch::sendUp(wl_client *client, int id)
|
||||
{
|
||||
uint serial = m_seat->m_compositor->nextSerial();
|
||||
auto time = m_seat->m_compositor->currentTimeMilliseconds();
|
||||
|
||||
const auto touchResources = resourceMap().values(client);
|
||||
for (auto *r : touchResources)
|
||||
wl_touch::send_up(r->handle, serial, time, id);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
void Touch::sendFrame(wl_client *client)
|
||||
{
|
||||
const auto touchResources = resourceMap().values(client);
|
||||
for (auto *r : touchResources)
|
||||
send_frame(r->handle);
|
||||
}
|
||||
|
||||
uint Keyboard::sendEnter(Surface *surface)
|
||||
{
|
||||
auto serial = m_seat->m_compositor->nextSerial();
|
||||
|
@ -38,6 +38,7 @@ namespace MockCompositor {
|
||||
class WlCompositor;
|
||||
class Output;
|
||||
class Pointer;
|
||||
class Touch;
|
||||
class Keyboard;
|
||||
class CursorRole;
|
||||
class ShmPool;
|
||||
@ -236,7 +237,7 @@ class Seat : public Global, public QtWaylandServer::wl_seat
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard, int version = 4);
|
||||
explicit Seat(CoreCompositor *compositor, uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch, int version = 5);
|
||||
~Seat() override;
|
||||
void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead
|
||||
void send_capabilities(uint capabilities) = delete; // Use wrapper instead
|
||||
@ -247,6 +248,9 @@ public:
|
||||
Pointer* m_pointer = nullptr;
|
||||
QVector<Pointer *> m_oldPointers;
|
||||
|
||||
Touch* m_touch = nullptr;
|
||||
QVector<Touch *> m_oldTouchs;
|
||||
|
||||
Keyboard* m_keyboard = nullptr;
|
||||
QVector<Keyboard *> m_oldKeyboards;
|
||||
|
||||
@ -259,8 +263,8 @@ protected:
|
||||
}
|
||||
|
||||
void seat_get_pointer(Resource *resource, uint32_t id) override;
|
||||
void seat_get_touch(Resource *resource, uint32_t id) override;
|
||||
void seat_get_keyboard(Resource *resource, uint32_t id) override;
|
||||
// void seat_get_touch(Resource *resource, uint32_t id) override;
|
||||
|
||||
// void seat_release(Resource *resource) override;
|
||||
};
|
||||
@ -307,6 +311,18 @@ public:
|
||||
Surface *m_surface = nullptr;
|
||||
};
|
||||
|
||||
class Touch : public QObject, public QtWaylandServer::wl_touch
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Touch(Seat *seat) : m_seat(seat) {}
|
||||
uint sendDown(Surface *surface, const QPointF &position, int id);
|
||||
uint sendUp(wl_client *client, int id);
|
||||
void sendFrame(wl_client *client);
|
||||
|
||||
Seat *m_seat = nullptr;
|
||||
};
|
||||
|
||||
class Keyboard : public QObject, public QtWaylandServer::wl_keyboard
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -41,7 +41,7 @@ DefaultCompositor::DefaultCompositor()
|
||||
add<SubCompositor>();
|
||||
auto *output = add<Output>();
|
||||
output->m_data.physicalSize = output->m_data.mode.physicalSizeForDpi(96);
|
||||
add<Seat>(Seat::capability_pointer | Seat::capability_keyboard);
|
||||
add<Seat>(Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch);
|
||||
add<XdgWmBase>();
|
||||
add<Shm>();
|
||||
// TODO: other shells, viewporter, xdgoutput etc
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
XdgToplevel *xdgToplevel(int i = 0) { return get<XdgWmBase>()->toplevel(i); }
|
||||
XdgPopup *xdgPopup(int i = 0) { return get<XdgWmBase>()->popup(i); }
|
||||
Pointer *pointer() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_pointer; }
|
||||
Touch *touch() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_touch; }
|
||||
Surface *cursorSurface() { auto *p = pointer(); return p ? p->cursorSurface() : nullptr; }
|
||||
Keyboard *keyboard() { auto *seat = get<Seat>(); Q_ASSERT(seat); return seat->m_keyboard; }
|
||||
uint sendXdgShellPing();
|
||||
|
@ -214,12 +214,13 @@ void tst_xdgshell::popup()
|
||||
uint clickSerial = exec([=] {
|
||||
auto *surface = xdgToplevel()->surface();
|
||||
auto *p = pointer();
|
||||
auto *c = client();
|
||||
p->sendEnter(surface, {100, 100});
|
||||
// p->sendFrame(); //TODO: uncomment when we support seat v5
|
||||
p->sendFrame(c);
|
||||
uint serial = p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
|
||||
return serial;
|
||||
// p->sendFrame(); //TODO: uncomment when we support seat v5
|
||||
p->sendFrame(c);
|
||||
});
|
||||
|
||||
QTRY_VERIFY(window.m_popup);
|
||||
@ -298,13 +299,14 @@ void tst_xdgshell::tooltipOnPopup()
|
||||
exec([=] {
|
||||
auto *surface = xdgToplevel()->surface();
|
||||
auto *p = pointer();
|
||||
auto *c = client();
|
||||
p->sendEnter(surface, {100, 100});
|
||||
// p->sendFrame(); //TODO: uncomment when we support seat v5
|
||||
p->sendFrame(c);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
p->sendLeave(surface);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
|
||||
@ -315,11 +317,12 @@ void tst_xdgshell::tooltipOnPopup()
|
||||
exec([=] {
|
||||
auto *surface = xdgPopup()->surface();
|
||||
auto *p = pointer();
|
||||
auto *c = client();
|
||||
p->sendEnter(surface, {100, 100});
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup(1));
|
||||
@ -380,13 +383,14 @@ void tst_xdgshell::switchPopups()
|
||||
exec([=] {
|
||||
auto *surface = xdgToplevel()->surface();
|
||||
auto *p = pointer();
|
||||
auto *c = client();
|
||||
p->sendEnter(surface, {100, 100});
|
||||
// p->sendFrame(); //TODO: uncomment when we support seat v5
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
|
||||
p->sendFrame(c);
|
||||
p->sendLeave(surface);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
});
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgPopup());
|
||||
@ -399,11 +403,12 @@ void tst_xdgshell::switchPopups()
|
||||
exec([=] {
|
||||
auto *surface = xdgToplevel()->surface();
|
||||
auto *p = pointer();
|
||||
auto *c = client();
|
||||
p->sendEnter(surface, {100, 100});
|
||||
// p->sendFrame();
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(client(), BTN_LEFT, Pointer::button_state_released);
|
||||
// p->sendFrame();
|
||||
p->sendFrame(c);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_pressed);
|
||||
p->sendButton(c, BTN_LEFT, Pointer::button_state_released);
|
||||
p->sendFrame(c);
|
||||
});
|
||||
|
||||
// The client will now hide one popup and then show another
|
||||
@ -476,10 +481,14 @@ void tst_xdgshell::windowGeometry()
|
||||
|
||||
exec([=] { xdgToplevel()->sendCompleteConfigure(); });
|
||||
|
||||
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), window.frameGeometry().size()));
|
||||
QSize marginsSize;
|
||||
marginsSize.setWidth(window.frameMargins().left() + window.frameMargins().right());
|
||||
marginsSize.setHeight(window.frameMargins().top() + window.frameMargins().bottom());
|
||||
|
||||
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), QSize(400, 320) + marginsSize));
|
||||
|
||||
window.resize(800, 600);
|
||||
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), window.frameGeometry().size()));
|
||||
QCOMPOSITOR_TRY_COMPARE(xdgSurface()->m_committed.windowGeometry, QRect(QPoint(0, 0), QSize(800, 600) + marginsSize));
|
||||
}
|
||||
|
||||
void tst_xdgshell::foreignSurface()
|
||||
|
Loading…
x
Reference in New Issue
Block a user