Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: I1fdf822938737aebe0c13a2eba9e478ba8f8ba14
This commit is contained in:
commit
0d39c32532
@ -140,7 +140,7 @@
|
||||
},
|
||||
"xcomposite-egl": {
|
||||
"label": "XComposite EGL",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && features.xlib && libs.xcomposite",
|
||||
"condition": "features.wayland-client && features.opengl && features.egl && features.xlib && libs.xcomposite && features.egl_x11",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"xcomposite-glx": {
|
||||
|
@ -342,7 +342,7 @@ void QWaylandXdgSurfaceV6::requestWindowStates(Qt::WindowStates states)
|
||||
if (m_toplevel)
|
||||
m_toplevel->requestWindowStates(states);
|
||||
else
|
||||
qCWarning(lcQpaWayland) << "Non-toplevel surfaces can't request window states";
|
||||
qCDebug(lcQpaWayland) << "Ignoring window states requested by non-toplevel.";
|
||||
}
|
||||
|
||||
void QWaylandXdgSurfaceV6::setToplevel()
|
||||
|
@ -377,7 +377,7 @@ void QWaylandXdgSurface::requestWindowStates(Qt::WindowStates states)
|
||||
if (m_toplevel)
|
||||
m_toplevel->requestWindowStates(states);
|
||||
else
|
||||
qCWarning(lcQpaWayland) << "Non-toplevel surfaces can't request window states";
|
||||
qCDebug(lcQpaWayland) << "Ignoring window states requested by non-toplevel zxdg_surface_v6.";
|
||||
}
|
||||
|
||||
void QWaylandXdgSurface::setToplevel()
|
||||
|
@ -103,20 +103,23 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
|
||||
return m_dragOffer.data();
|
||||
}
|
||||
|
||||
void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
||||
bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
||||
{
|
||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
||||
|
||||
auto *seat = m_display->currentInputDevice();
|
||||
auto *origin = seat->pointerFocus();
|
||||
if (!origin)
|
||||
origin = seat->touchFocus();
|
||||
|
||||
if (origin)
|
||||
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
|
||||
else
|
||||
if (!origin) {
|
||||
qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
||||
|
||||
start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
|
||||
return true;
|
||||
}
|
||||
|
||||
void QWaylandDataDevice::cancelDrag()
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
QWaylandDataOffer *dragOffer() const;
|
||||
void startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
||||
bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
|
||||
void cancelDrag();
|
||||
#endif
|
||||
|
||||
|
@ -66,8 +66,13 @@ void QWaylandDrag::startDrag()
|
||||
{
|
||||
QBasicDrag::startDrag();
|
||||
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
|
||||
m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon);
|
||||
icon->addAttachOffset(-drag()->hotSpot());
|
||||
if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
|
||||
icon->addAttachOffset(-drag()->hotSpot());
|
||||
} else {
|
||||
// Cancelling immediately does not work, since the event loop for QDrag::exec is started
|
||||
// after this function returns.
|
||||
QMetaObject::invokeMethod(this, [this](){ cancelDrag(); }, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandDrag::cancel()
|
||||
|
@ -119,7 +119,8 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla
|
||||
if (!QGuiApplication::focusWindow() || !QGuiApplication::focusWindow()->handle())
|
||||
return;
|
||||
|
||||
auto *surface = static_cast<QWaylandWindow *>(QGuiApplication::focusWindow()->handle())->wlSurface();
|
||||
auto *window = static_cast<QWaylandWindow *>(QGuiApplication::focusWindow()->handle());
|
||||
auto *surface = window->wlSurface();
|
||||
if (!surface || (surface != m_surface))
|
||||
return;
|
||||
|
||||
@ -157,8 +158,10 @@ void QWaylandTextInput::updateState(Qt::InputMethodQueries queries, uint32_t fla
|
||||
|
||||
if (queries & Qt::ImCursorRectangle) {
|
||||
const QRect &cRect = event.value(Qt::ImCursorRectangle).toRect();
|
||||
const QRect &tRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect);
|
||||
set_cursor_rectangle(tRect.x(), tRect.y(), tRect.width(), tRect.height());
|
||||
const QRect &windowRect = QGuiApplication::inputMethod()->inputItemTransform().mapRect(cRect);
|
||||
const QMargins margins = window->frameMargins();
|
||||
const QRect &surfaceRect = windowRect.translated(margins.left(), margins.top());
|
||||
set_cursor_rectangle(surfaceRect.x(), surfaceRect.y(), surfaceRect.width(), surfaceRect.height());
|
||||
}
|
||||
|
||||
if (queries & Qt::ImPreferredLanguage) {
|
||||
|
@ -1200,7 +1200,7 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
|
||||
QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
|
||||
handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text);
|
||||
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code)) {
|
||||
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code) && mRepeatRate > 0) {
|
||||
mRepeatKey.key = qtkey;
|
||||
mRepeatKey.code = code;
|
||||
mRepeatKey.time = time;
|
||||
@ -1295,34 +1295,40 @@ void QWaylandInputDevice::Touch::touch_down(uint32_t serial,
|
||||
mParent->mSerial = serial;
|
||||
mFocus = window;
|
||||
mParent->mQDisplay->setLastInputDevice(mParent, serial, mFocus);
|
||||
mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed);
|
||||
QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y));
|
||||
mParent->handleTouchPoint(id, Qt::TouchPointPressed, position);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_t id)
|
||||
{
|
||||
Q_UNUSED(serial);
|
||||
Q_UNUSED(time);
|
||||
mFocus = nullptr;
|
||||
mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
|
||||
mParent->handleTouchPoint(id, Qt::TouchPointReleased);
|
||||
|
||||
// As of Weston 1.5.90 there is no touch_frame after the last touch_up
|
||||
// (i.e. when the last finger is released). To accommodate for this, issue a
|
||||
// touch_frame. This cannot hurt since it is safe to call the touch_frame
|
||||
// handler multiple times when there are no points left.
|
||||
if (allTouchPointsReleased())
|
||||
if (allTouchPointsReleased()) {
|
||||
mFocus = nullptr;
|
||||
|
||||
// As of Weston 7.0.0 there is no touch_frame after the last touch_up
|
||||
// (i.e. when the last finger is released). To accommodate for this, issue a
|
||||
// touch_frame. This cannot hurt since it is safe to call the touch_frame
|
||||
// handler multiple times when there are no points left.
|
||||
// See: https://gitlab.freedesktop.org/wayland/weston/issues/44
|
||||
// TODO: change logging category to lcQpaWaylandInput in newer versions.
|
||||
qCDebug(lcQpaWayland, "Generating fake frame event to work around Weston bug");
|
||||
touch_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
Q_UNUSED(time);
|
||||
mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointMoved);
|
||||
QPointF position(wl_fixed_to_double(x), wl_fixed_to_double(y));
|
||||
mParent->handleTouchPoint(id, Qt::TouchPointMoved, position);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Touch::touch_cancel()
|
||||
{
|
||||
mPrevTouchPoints.clear();
|
||||
mTouchPoints.clear();
|
||||
mPendingTouchPoints.clear();
|
||||
|
||||
QWaylandTouchExtension *touchExt = mParent->mQDisplay->touchExtension();
|
||||
if (touchExt)
|
||||
@ -1331,22 +1337,18 @@ void QWaylandInputDevice::Touch::touch_cancel()
|
||||
QWindowSystemInterface::handleTouchCancelEvent(nullptr, mParent->mTouchDevice);
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state)
|
||||
void QWaylandInputDevice::handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition)
|
||||
{
|
||||
QWindowSystemInterface::TouchPoint tp;
|
||||
auto end = mTouch->mPendingTouchPoints.end();
|
||||
auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](auto tp){ return tp.id == id; });
|
||||
if (it == end) {
|
||||
it = mTouch->mPendingTouchPoints.insert(end, QWindowSystemInterface::TouchPoint());
|
||||
it->id = id;
|
||||
}
|
||||
QWindowSystemInterface::TouchPoint &tp = *it;
|
||||
|
||||
// Find out the coordinates for Released events.
|
||||
bool coordsOk = false;
|
||||
if (state == Qt::TouchPointReleased)
|
||||
for (int i = 0; i < mTouch->mPrevTouchPoints.count(); ++i)
|
||||
if (mTouch->mPrevTouchPoints.at(i).id == id) {
|
||||
tp.area = mTouch->mPrevTouchPoints.at(i).area;
|
||||
coordsOk = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!coordsOk) {
|
||||
// x and y are surface relative.
|
||||
// Only moved and pressed needs to update/set position
|
||||
if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed) {
|
||||
// We need a global (screen) position.
|
||||
QWaylandWindow *win = mTouch->mFocus;
|
||||
|
||||
@ -1360,63 +1362,46 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch
|
||||
|
||||
tp.area = QRectF(0, 0, 8, 8);
|
||||
QMargins margins = win->frameMargins();
|
||||
tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x - margins.left(), y - margins.top())));
|
||||
QPointF localPosition = surfacePosition - QPointF(margins.left(), margins.top());
|
||||
// TODO: This doesn't account for high dpi scaling for the delta, but at least it matches
|
||||
// what we have for mouse input.
|
||||
QPointF delta = localPosition - localPosition.toPoint();
|
||||
QPointF globalPosition = win->window()->mapToGlobal(localPosition.toPoint()) + delta;
|
||||
tp.area.moveCenter(globalPosition);
|
||||
}
|
||||
|
||||
tp.state = state;
|
||||
tp.id = id;
|
||||
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
|
||||
mTouch->mTouchPoints.append(tp);
|
||||
}
|
||||
|
||||
bool QWaylandInputDevice::Touch::allTouchPointsReleased()
|
||||
{
|
||||
for (int i = 0; i < mTouchPoints.count(); ++i)
|
||||
if (mTouchPoints.at(i).state != Qt::TouchPointReleased)
|
||||
for (const auto &tp : qAsConst(mPendingTouchPoints)) {
|
||||
if (tp.state != Qt::TouchPointReleased)
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Touch::releasePoints()
|
||||
{
|
||||
for (const QWindowSystemInterface::TouchPoint &previousPoint : qAsConst(mPrevTouchPoints)) {
|
||||
QWindowSystemInterface::TouchPoint tp = previousPoint;
|
||||
if (mPendingTouchPoints.empty())
|
||||
return;
|
||||
|
||||
for (QWindowSystemInterface::TouchPoint &tp : mPendingTouchPoints)
|
||||
tp.state = Qt::TouchPointReleased;
|
||||
mTouchPoints.append(tp);
|
||||
}
|
||||
|
||||
touch_frame();
|
||||
}
|
||||
|
||||
void QWaylandInputDevice::Touch::touch_frame()
|
||||
{
|
||||
// Copy all points, that are in the previous but not in the current list, as stationary.
|
||||
for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
|
||||
const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
|
||||
if (prevPoint.state == Qt::TouchPointReleased)
|
||||
continue;
|
||||
bool found = false;
|
||||
for (int j = 0; j < mTouchPoints.count(); ++j)
|
||||
if (mTouchPoints.at(j).id == prevPoint.id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
QWindowSystemInterface::TouchPoint p = prevPoint;
|
||||
p.state = Qt::TouchPointStationary;
|
||||
mTouchPoints.append(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (mTouchPoints.isEmpty()) {
|
||||
mPrevTouchPoints.clear();
|
||||
return;
|
||||
}
|
||||
// TODO: early return if no events?
|
||||
|
||||
QWindow *window = mFocus ? mFocus->window() : nullptr;
|
||||
|
||||
if (mFocus) {
|
||||
const QWindowSystemInterface::TouchPoint &tp = mTouchPoints.last();
|
||||
const QWindowSystemInterface::TouchPoint &tp = mPendingTouchPoints.last();
|
||||
// When the touch event is received, the global pos is calculated with the margins
|
||||
// in mind. Now we need to adjust again to get the correct local pos back.
|
||||
QMargins margins = window->frameMargins();
|
||||
@ -1425,14 +1410,21 @@ void QWaylandInputDevice::Touch::touch_frame()
|
||||
if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers()))
|
||||
return;
|
||||
}
|
||||
QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mTouchPoints);
|
||||
|
||||
if (allTouchPointsReleased())
|
||||
mPrevTouchPoints.clear();
|
||||
else
|
||||
mPrevTouchPoints = mTouchPoints;
|
||||
QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mPendingTouchPoints);
|
||||
|
||||
// Prepare state for next frame
|
||||
const auto prevTouchPoints = mPendingTouchPoints;
|
||||
mPendingTouchPoints.clear();
|
||||
for (const auto &prevPoint: prevTouchPoints) {
|
||||
// All non-released touch points should be part of the next touch event
|
||||
if (prevPoint.state != Qt::TouchPointReleased) {
|
||||
QWindowSystemInterface::TouchPoint tp = prevPoint;
|
||||
tp.state = Qt::TouchPointStationary; // ... as stationary (unless proven otherwise)
|
||||
mPendingTouchPoints.append(tp);
|
||||
}
|
||||
}
|
||||
|
||||
mTouchPoints.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ private:
|
||||
uint32_t mSerial = 0;
|
||||
|
||||
void seat_capabilities(uint32_t caps) override;
|
||||
void handleTouchPoint(int id, double x, double y, Qt::TouchPointState state);
|
||||
void handleTouchPoint(int id, Qt::TouchPointState state, const QPointF &surfacePosition = QPoint());
|
||||
|
||||
QTouchDevice *mTouchDevice = nullptr;
|
||||
|
||||
@ -389,8 +389,7 @@ public:
|
||||
|
||||
QWaylandInputDevice *mParent = nullptr;
|
||||
QPointer<QWaylandWindow> mFocus;
|
||||
QList<QWindowSystemInterface::TouchPoint> mTouchPoints;
|
||||
QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints;
|
||||
QList<QWindowSystemInterface::TouchPoint> mPendingTouchPoints;
|
||||
};
|
||||
|
||||
class QWaylandPointerEvent
|
||||
|
@ -201,10 +201,13 @@ void QWaylandWindow::initWindow()
|
||||
void QWaylandWindow::initializeWlSurface()
|
||||
{
|
||||
Q_ASSERT(!mSurface);
|
||||
mSurface.reset(new QWaylandSurface(mDisplay));
|
||||
connect(mSurface.data(), &QWaylandSurface::screensChanged,
|
||||
this, &QWaylandWindow::handleScreensChanged);
|
||||
mSurface->m_window = this;
|
||||
{
|
||||
QWriteLocker lock(&mSurfaceLock);
|
||||
mSurface.reset(new QWaylandSurface(mDisplay));
|
||||
connect(mSurface.data(), &QWaylandSurface::screensChanged,
|
||||
this, &QWaylandWindow::handleScreensChanged);
|
||||
mSurface->m_window = this;
|
||||
}
|
||||
emit wlSurfaceCreated();
|
||||
}
|
||||
|
||||
@ -242,6 +245,7 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
|
||||
mSubSurfaceWindow = nullptr;
|
||||
if (mSurface) {
|
||||
emit wlSurfaceDestroyed();
|
||||
QWriteLocker lock(&mSurfaceLock);
|
||||
mSurface.reset();
|
||||
}
|
||||
|
||||
@ -617,10 +621,11 @@ QMutex QWaylandWindow::mFrameSyncMutex;
|
||||
|
||||
bool QWaylandWindow::waitForFrameSync(int timeout)
|
||||
{
|
||||
QMutexLocker locker(&mFrameSyncMutex);
|
||||
if (!mWaitingForFrameCallback)
|
||||
return true;
|
||||
|
||||
QMutexLocker locker(&mFrameSyncMutex);
|
||||
|
||||
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue);
|
||||
mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout);
|
||||
|
||||
@ -1135,6 +1140,9 @@ void QWaylandWindow::requestUpdate()
|
||||
void QWaylandWindow::handleUpdate()
|
||||
{
|
||||
// TODO: Should sync subsurfaces avoid requesting frame callbacks?
|
||||
QReadLocker lock(&mSurfaceLock);
|
||||
if (!mSurface)
|
||||
return;
|
||||
|
||||
if (mFrameCallback) {
|
||||
wl_callback_destroy(mFrameCallback);
|
||||
|
@ -53,6 +53,8 @@
|
||||
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
|
||||
#include <QtGui/QIcon>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
@ -274,6 +276,8 @@ private:
|
||||
static QMutex mFrameSyncMutex;
|
||||
static QWaylandWindow *mMouseGrab;
|
||||
|
||||
QReadWriteLock mSurfaceLock;
|
||||
|
||||
friend class QWaylandSubSurface;
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@ SUBDIRS += \
|
||||
seatv5 \
|
||||
surface \
|
||||
wl_connect \
|
||||
xdgdecorationv1 \
|
||||
xdgoutput \
|
||||
xdgshell \
|
||||
xdgshellv6
|
||||
|
@ -30,9 +30,8 @@
|
||||
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
|
||||
//TODO: move?
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QDrag>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
@ -60,6 +59,7 @@ private slots:
|
||||
void pasteUtf8();
|
||||
void destroysPreviousSelection();
|
||||
void destroysSelectionWithSurface();
|
||||
void dragWithoutFocus();
|
||||
};
|
||||
|
||||
void tst_datadevicev1::initTestCase()
|
||||
@ -215,5 +215,22 @@ void tst_datadevicev1::destroysSelectionWithSurface()
|
||||
QCOMPOSITOR_TRY_COMPARE(dataDevice()->m_sentSelectionOffers.size(), 0);
|
||||
}
|
||||
|
||||
// The application should not crash if it attempts to start a drag operation
|
||||
// when it doesn't have input focus (QTBUG-76368)
|
||||
void tst_datadevicev1::dragWithoutFocus()
|
||||
{
|
||||
QRasterWindow window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
auto *mimeData = new QMimeData;
|
||||
const QByteArray data("testData");
|
||||
mimeData->setData("text/plain", data);
|
||||
QDrag drag(&window);
|
||||
drag.setMimeData(mimeData);
|
||||
drag.exec();
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_datadevicev1)
|
||||
#include "tst_datadevicev1.moc"
|
||||
|
@ -72,6 +72,7 @@ private slots:
|
||||
void usesEnterSerial();
|
||||
void focusDestruction();
|
||||
void mousePress();
|
||||
void mousePressFloat();
|
||||
void simpleAxis_data();
|
||||
void simpleAxis();
|
||||
void invalidPointerEvents();
|
||||
@ -208,6 +209,30 @@ void tst_seatv4::mousePress()
|
||||
QTRY_VERIFY(window.m_pressed);
|
||||
}
|
||||
|
||||
void tst_seatv4::mousePressFloat()
|
||||
{
|
||||
class Window : public QRasterWindow {
|
||||
public:
|
||||
void mousePressEvent(QMouseEvent *e) override { m_position = e->localPos(); }
|
||||
QPointF m_position;
|
||||
};
|
||||
|
||||
Window window;
|
||||
window.resize(64, 64);
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
exec([&] {
|
||||
auto *surface = xdgSurface()->m_surface;
|
||||
pointer()->sendEnter(surface, {32.75, 32.25});
|
||||
pointer()->sendButton(client(), BTN_LEFT, 1);
|
||||
pointer()->sendButton(client(), BTN_LEFT, 0);
|
||||
});
|
||||
QMargins m = window.frameMargins();
|
||||
QPointF pressedPosition(32.75 -m.left(), 32.25 - m.top());
|
||||
QTRY_COMPARE(window.m_position, pressedPosition);
|
||||
}
|
||||
|
||||
void tst_seatv4::simpleAxis_data()
|
||||
{
|
||||
QTest::addColumn<uint>("axis");
|
||||
|
@ -68,6 +68,7 @@ private slots:
|
||||
// Touch tests
|
||||
void createsTouch();
|
||||
void singleTap();
|
||||
void singleTapFloat();
|
||||
};
|
||||
|
||||
void tst_seatv5::bindsToSeat()
|
||||
@ -431,5 +432,36 @@ void tst_seatv5::singleTap()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_seatv5::singleTapFloat()
|
||||
{
|
||||
TouchWindow window;
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgSurface() && xdgSurface()->m_committedConfigureSerial);
|
||||
|
||||
exec([=] {
|
||||
auto *t = touch();
|
||||
auto *c = client();
|
||||
t->sendDown(xdgToplevel()->surface(), {32.75, 32.25}, 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.75-window.frameMargins().left(), 32.25-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.75-window.frameMargins().left(), 32.25-window.frameMargins().top()));
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_seatv5)
|
||||
#include "tst_seatv5.moc"
|
||||
|
186
tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
Normal file
186
tests/auto/wayland/xdgdecorationv1/tst_xdgdecorationv1.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mockcompositor.h"
|
||||
|
||||
#include <qwayland-server-xdg-decoration-unstable-v1.h>
|
||||
|
||||
#include <QtGui/QRasterWindow>
|
||||
#include <QtGui/QOpenGLWindow>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/private/qcore_unix_p.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
using namespace MockCompositor;
|
||||
|
||||
constexpr int xdgDecorationVersion = 1; // protocol VERSION, not the name suffix (_v1)
|
||||
|
||||
class XdgDecorationManagerV1;
|
||||
class XdgToplevelDecorationV1 : public QObject, public QtWaylandServer::zxdg_toplevel_decoration_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgToplevelDecorationV1(XdgDecorationManagerV1 *manager, XdgToplevel *toplevel, int id, int version)
|
||||
: zxdg_toplevel_decoration_v1(toplevel->resource()->client(), id, version)
|
||||
, m_manager(manager)
|
||||
, m_toplevel(toplevel)
|
||||
{
|
||||
}
|
||||
void sendConfigure(mode mode)
|
||||
{
|
||||
if (!m_configureSent) {
|
||||
// Attaching buffers before the configure is a protocol error
|
||||
QVERIFY(!m_toplevel->surface()->m_pending.buffer);
|
||||
QVERIFY(!m_toplevel->surface()->m_committed.buffer);
|
||||
}
|
||||
send_configure(mode);
|
||||
m_configureSent = true;
|
||||
}
|
||||
void zxdg_toplevel_decoration_v1_destroy(Resource *resource) override
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
void zxdg_toplevel_decoration_v1_destroy_resource(Resource *resource) override;
|
||||
void zxdg_toplevel_decoration_v1_set_mode(Resource *resource, uint32_t mode) override
|
||||
{
|
||||
Q_UNUSED(resource);
|
||||
m_unsetModeRequested = false;
|
||||
m_requestedMode = XdgToplevelDecorationV1::mode(mode);
|
||||
}
|
||||
void zxdg_toplevel_decoration_v1_unset_mode(Resource *resource) override
|
||||
{
|
||||
Q_UNUSED(resource);
|
||||
m_unsetModeRequested = true;
|
||||
m_requestedMode = mode(0);
|
||||
}
|
||||
XdgDecorationManagerV1 *m_manager = nullptr;
|
||||
XdgToplevel *m_toplevel = nullptr;
|
||||
mode m_requestedMode = mode(0);
|
||||
bool m_unsetModeRequested = false;
|
||||
bool m_configureSent = false;
|
||||
};
|
||||
|
||||
class XdgDecorationManagerV1 : public Global, public QtWaylandServer::zxdg_decoration_manager_v1
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgDecorationManagerV1(CoreCompositor *compositor, int version = 1)
|
||||
: QtWaylandServer::zxdg_decoration_manager_v1(compositor->m_display, version)
|
||||
, m_version(version)
|
||||
{}
|
||||
bool isClean() override { return m_decorations.empty(); }
|
||||
XdgToplevelDecorationV1 *decorationFor(XdgToplevel *toplevel)
|
||||
{
|
||||
return m_decorations.value(toplevel, nullptr);
|
||||
}
|
||||
|
||||
int m_version = 1; // TODO: Remove on libwayland upgrade
|
||||
QMap<XdgToplevel *, XdgToplevelDecorationV1 *> m_decorations;
|
||||
|
||||
protected:
|
||||
void zxdg_decoration_manager_v1_destroy(Resource *resource) override
|
||||
{
|
||||
//TODO: Should the decorations be destroyed at this point?
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void zxdg_decoration_manager_v1_get_toplevel_decoration(Resource *resource, uint32_t id, ::wl_resource *toplevelResource) override
|
||||
{
|
||||
auto *toplevel = fromResource<XdgToplevel>(toplevelResource);
|
||||
QVERIFY(toplevel);
|
||||
QVERIFY(!decorationFor(toplevel));
|
||||
|
||||
// Attaching buffers before the configure is a protocol error
|
||||
QVERIFY(!toplevel->surface()->m_pending.buffer);
|
||||
QVERIFY(!toplevel->surface()->m_committed.buffer);
|
||||
|
||||
m_decorations[toplevel] = new XdgToplevelDecorationV1(this, toplevel, id, resource->version());
|
||||
}
|
||||
};
|
||||
|
||||
void XdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_destroy_resource(QtWaylandServer::zxdg_toplevel_decoration_v1::Resource *resource)
|
||||
{
|
||||
Q_UNUSED(resource);
|
||||
int removed = m_manager->m_decorations.remove(m_toplevel);
|
||||
Q_ASSERT(removed == 1);
|
||||
delete this;
|
||||
}
|
||||
|
||||
class XdgDecorationCompositor : public DefaultCompositor {
|
||||
public:
|
||||
explicit XdgDecorationCompositor()
|
||||
{
|
||||
exec([this] {
|
||||
m_config.autoConfigure = true;
|
||||
add<XdgDecorationManagerV1>(xdgDecorationVersion);
|
||||
});
|
||||
}
|
||||
XdgToplevelDecorationV1 *toplevelDecoration(int i = 0) {
|
||||
return get<XdgDecorationManagerV1>()->decorationFor(xdgToplevel(i));
|
||||
}
|
||||
};
|
||||
|
||||
class tst_xdgdecorationv1 : public QObject, private XdgDecorationCompositor
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanup() { QTRY_VERIFY2(isClean(), qPrintable(dirtyMessage())); }
|
||||
void clientSidePreferredByCompositor();
|
||||
};
|
||||
|
||||
void tst_xdgdecorationv1::initTestCase()
|
||||
{
|
||||
if (qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_WINDOWDECORATION"))
|
||||
QSKIP("This test doesn't make sense when QT_WAYLAND_DISABLE_WINDOWDECORATION is set in the environment");
|
||||
}
|
||||
|
||||
void tst_xdgdecorationv1::clientSidePreferredByCompositor()
|
||||
{
|
||||
QRasterWindow window;
|
||||
window.show();
|
||||
QCOMPOSITOR_TRY_COMPARE(get<XdgDecorationManagerV1>()->resourceMap().size(), 1);
|
||||
QCOMPOSITOR_TRY_COMPARE(get<XdgDecorationManagerV1>()->resourceMap().first()->version(), xdgDecorationVersion);
|
||||
QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()); // The client creates a toplevel object
|
||||
|
||||
// Check that we don't assume decorations before the server has configured them
|
||||
QVERIFY(window.frameMargins().isNull());
|
||||
|
||||
QCOMPOSITOR_TRY_VERIFY(xdgToplevel());
|
||||
QCOMPOSITOR_TRY_VERIFY(toplevelDecoration()->m_unsetModeRequested);
|
||||
QVERIFY(window.frameMargins().isNull()); // We're still waiting for a configure
|
||||
exec([=] {
|
||||
toplevelDecoration()->sendConfigure(XdgToplevelDecorationV1::mode_client_side);
|
||||
xdgToplevel()->sendCompleteConfigure();
|
||||
});
|
||||
QTRY_VERIFY(!window.frameMargins().isNull());
|
||||
}
|
||||
|
||||
QCOMPOSITOR_TEST_MAIN(tst_xdgdecorationv1)
|
||||
#include "tst_xdgdecorationv1.moc"
|
7
tests/auto/wayland/xdgdecorationv1/xdgdecorationv1.pro
Normal file
7
tests/auto/wayland/xdgdecorationv1/xdgdecorationv1.pro
Normal file
@ -0,0 +1,7 @@
|
||||
include (../shared/shared.pri)
|
||||
|
||||
WAYLANDSERVERSOURCES += \
|
||||
$$PWD/../../../../src/3rdparty/protocol/xdg-decoration-unstable-v1.xml
|
||||
|
||||
TARGET = tst_xdgdecorationv1
|
||||
SOURCES += tst_xdgdecorationv1.cpp
|
Loading…
x
Reference in New Issue
Block a user