Merge remote-tracking branch 'origin/5.12' into 5.13

Change-Id: I5d587b79b96d2b44f1975419a658c259c63fa30d
This commit is contained in:
Qt Forward Merge Bot 2019-09-08 11:32:16 +02:00
commit 7a7c60d4b6
7 changed files with 77 additions and 72 deletions

View File

@ -102,19 +102,22 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
return m_dragOffer.data(); 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);
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus(); QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
if (!origin) if (!origin)
origin = m_display->currentInputDevice()->touchFocus(); origin = m_display->currentInputDevice()->touchFocus();
if (origin) if (!origin) {
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
else
qCDebug(lcQpaWayland) << "Couldn't start a drag because the origin window could not be found."; 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->object(), icon->object(), m_display->currentInputDevice()->serial());
return true;
} }
void QWaylandDataDevice::cancelDrag() void QWaylandDataDevice::cancelDrag()

View File

@ -89,7 +89,7 @@ public:
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
QWaylandDataOffer *dragOffer() const; QWaylandDataOffer *dragOffer() const;
void startDrag(QMimeData *mimeData, QWaylandWindow *icon); bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
void cancelDrag(); void cancelDrag();
#endif #endif

View File

@ -66,8 +66,13 @@ void QWaylandDrag::startDrag()
{ {
QBasicDrag::startDrag(); QBasicDrag::startDrag();
QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle()); QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon); if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
icon->addAttachOffset(-drag()->hotSpot()); 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() void QWaylandDrag::cancel()

View File

@ -994,16 +994,21 @@ void QWaylandInputDevice::Touch::touch_up(uint32_t serial, uint32_t time, int32_
{ {
Q_UNUSED(serial); Q_UNUSED(serial);
Q_UNUSED(time); Q_UNUSED(time);
mFocus = nullptr;
mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased); mParent->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
// As of Weston 1.5.90 there is no touch_frame after the last touch_up 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 // (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 // touch_frame. This cannot hurt since it is safe to call the touch_frame
// handler multiple times when there are no points left. // handler multiple times when there are no points left.
if (allTouchPointsReleased()) // 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(); touch_frame();
} }
}
void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
{ {
@ -1013,8 +1018,7 @@ void QWaylandInputDevice::Touch::touch_motion(uint32_t time, int32_t id, wl_fixe
void QWaylandInputDevice::Touch::touch_cancel() void QWaylandInputDevice::Touch::touch_cancel()
{ {
mPrevTouchPoints.clear(); mPendingTouchPoints.clear();
mTouchPoints.clear();
QWaylandTouchExtension *touchExt = mParent->mQDisplay->touchExtension(); QWaylandTouchExtension *touchExt = mParent->mQDisplay->touchExtension();
if (touchExt) if (touchExt)
@ -1025,19 +1029,16 @@ void QWaylandInputDevice::Touch::touch_cancel()
void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state) void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state)
{ {
QWindowSystemInterface::TouchPoint tp; auto end = mTouch->mPendingTouchPoints.end();
auto it = std::find_if(mTouch->mPendingTouchPoints.begin(), end, [id](auto tp){ return tp.id == id; });
// Find out the coordinates for Released events. if (it == end) {
bool coordsOk = false; it = mTouch->mPendingTouchPoints.insert(end, QWindowSystemInterface::TouchPoint());
if (state == Qt::TouchPointReleased) it->id = id;
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;
} }
QWindowSystemInterface::TouchPoint &tp = *it;
if (!coordsOk) { // Only moved and pressed needs to update/set position
if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed) {
// x and y are surface relative. // x and y are surface relative.
// We need a global (screen) position. // We need a global (screen) position.
QWaylandWindow *win = mTouch->mFocus; QWaylandWindow *win = mTouch->mFocus;
@ -1056,59 +1057,37 @@ void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::Touch
} }
tp.state = state; tp.state = state;
tp.id = id;
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
mTouch->mTouchPoints.append(tp);
} }
bool QWaylandInputDevice::Touch::allTouchPointsReleased() bool QWaylandInputDevice::Touch::allTouchPointsReleased()
{ {
for (int i = 0; i < mTouchPoints.count(); ++i) for (const auto &tp : qAsConst(mPendingTouchPoints)) {
if (mTouchPoints.at(i).state != Qt::TouchPointReleased) if (tp.state != Qt::TouchPointReleased)
return false; return false;
}
return true; return true;
} }
void QWaylandInputDevice::Touch::releasePoints() void QWaylandInputDevice::Touch::releasePoints()
{ {
Q_FOREACH (const QWindowSystemInterface::TouchPoint &previousPoint, mPrevTouchPoints) { if (mPendingTouchPoints.empty())
QWindowSystemInterface::TouchPoint tp = previousPoint; return;
for (QWindowSystemInterface::TouchPoint &tp : mPendingTouchPoints)
tp.state = Qt::TouchPointReleased; tp.state = Qt::TouchPointReleased;
mTouchPoints.append(tp);
}
touch_frame(); touch_frame();
} }
void QWaylandInputDevice::Touch::touch_frame() void QWaylandInputDevice::Touch::touch_frame()
{ {
// Copy all points, that are in the previous but not in the current list, as stationary. // TODO: early return if no events?
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;
}
QWindow *window = mFocus ? mFocus->window() : nullptr; QWindow *window = mFocus ? mFocus->window() : nullptr;
if (mFocus) { 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 // 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. // in mind. Now we need to adjust again to get the correct local pos back.
QMargins margins = window->frameMargins(); QMargins margins = window->frameMargins();
@ -1117,14 +1096,21 @@ void QWaylandInputDevice::Touch::touch_frame()
if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers())) if (mFocus->touchDragDecoration(mParent, localPos, tp.area.center(), tp.state, mParent->modifiers()))
return; return;
} }
QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mTouchPoints);
if (allTouchPointsReleased()) QWindowSystemInterface::handleTouchEvent(window, mParent->mTouchDevice, mPendingTouchPoints);
mPrevTouchPoints.clear();
else // Prepare state for next frame
mPrevTouchPoints = mTouchPoints; 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();
} }
} }

View File

@ -333,8 +333,7 @@ public:
QWaylandInputDevice *mParent = nullptr; QWaylandInputDevice *mParent = nullptr;
QPointer<QWaylandWindow> mFocus; QPointer<QWaylandWindow> mFocus;
QList<QWindowSystemInterface::TouchPoint> mTouchPoints; QList<QWindowSystemInterface::TouchPoint> mPendingTouchPoints;
QList<QWindowSystemInterface::TouchPoint> mPrevTouchPoints;
}; };
class QWaylandPointerEvent class QWaylandPointerEvent

View File

@ -200,7 +200,10 @@ void QWaylandWindow::initWindow()
void QWaylandWindow::initializeWlSurface() void QWaylandWindow::initializeWlSurface()
{ {
Q_ASSERT(!isInitialized()); Q_ASSERT(!isInitialized());
{
QWriteLocker lock(&mSurfaceLock);
init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this))); init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
}
emit wlSurfaceCreated(); emit wlSurfaceCreated();
} }
@ -238,6 +241,7 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
mSubSurfaceWindow = nullptr; mSubSurfaceWindow = nullptr;
if (isInitialized()) { if (isInitialized()) {
emit wlSurfaceDestroyed(); emit wlSurfaceDestroyed();
QWriteLocker lock(&mSurfaceLock);
destroy(); destroy();
} }
mScreens.clear(); mScreens.clear();
@ -659,10 +663,11 @@ QMutex QWaylandWindow::mFrameSyncMutex;
bool QWaylandWindow::waitForFrameSync(int timeout) bool QWaylandWindow::waitForFrameSync(int timeout)
{ {
QMutexLocker locker(&mFrameSyncMutex);
if (!mWaitingForFrameCallback) if (!mWaitingForFrameCallback)
return true; return true;
QMutexLocker locker(&mFrameSyncMutex);
wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue); wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue);
mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout); mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout);
@ -1159,6 +1164,9 @@ void QWaylandWindow::requestUpdate()
void QWaylandWindow::handleUpdate() void QWaylandWindow::handleUpdate()
{ {
// TODO: Should sync subsurfaces avoid requesting frame callbacks? // TODO: Should sync subsurfaces avoid requesting frame callbacks?
QReadLocker lock(&mSurfaceLock);
if (!isInitialized())
return;
if (mFrameCallback) { if (mFrameCallback) {
wl_callback_destroy(mFrameCallback); wl_callback_destroy(mFrameCallback);

View File

@ -53,6 +53,8 @@
#include <QtCore/QWaitCondition> #include <QtCore/QWaitCondition>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtCore/QReadWriteLock>
#include <QtGui/QIcon> #include <QtGui/QIcon>
#include <QtCore/QVariant> #include <QtCore/QVariant>
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
@ -279,6 +281,8 @@ private:
static QMutex mFrameSyncMutex; static QMutex mFrameSyncMutex;
static QWaylandWindow *mMouseGrab; static QWaylandWindow *mMouseGrab;
QReadWriteLock mSurfaceLock;
friend class QWaylandSubSurface; friend class QWaylandSubSurface;
}; };