diff --git a/src/client/qwaylandclipboard.cpp b/src/client/qwaylandclipboard.cpp
index 226a374abfac569eb37227be560b74fd7d860807..3e25875f04d1425779bfe6fbf401d59dc64c2553 100644
--- a/src/client/qwaylandclipboard.cpp
+++ b/src/client/qwaylandclipboard.cpp
@@ -88,6 +88,10 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
     if (!inputDevice || !inputDevice->dataDevice())
         return;
 
+    static const QString plain = QStringLiteral("text/plain");
+    static const QString utf8 = QStringLiteral("text/plain;charset=utf-8");
+    if (data && data->hasFormat(plain) && !data->hasFormat(utf8))
+        data->setData(utf8, data->data(plain));
     inputDevice->dataDevice()->setSelectionSource(data ? new QWaylandDataSource(mDisplay->dndSelectionHandler(), data) : 0);
 
     emitChanged(mode);
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
index 10bf2f1e1ba927604326181195ebfb69e5f667e3..7b69ce6ce904d5c05bf87a05b12e9369eeb3d729 100644
--- a/src/client/qwaylanddataoffer.cpp
+++ b/src/client/qwaylanddataoffer.cpp
@@ -53,6 +53,11 @@ QT_BEGIN_NAMESPACE
 
 namespace QtWaylandClient {
 
+static QString utf8Text()
+{
+    return QStringLiteral("text/plain;charset=utf-8");
+}
+
 QWaylandDataOffer::QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer)
     : QtWayland::wl_data_offer(offer)
     , m_mimeData(new QWaylandMimeData(this, display))
@@ -102,7 +107,13 @@ void QWaylandMimeData::appendFormat(const QString &mimeType)
 
 bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
 {
-    return m_types.contains(mimeType);
+    if (m_types.contains(mimeType))
+        return true;
+
+    if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
+        return true;
+
+    return false;
 }
 
 QStringList QWaylandMimeData::formats_sys() const
@@ -117,8 +128,14 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
     if (m_data.contains(mimeType))
         return m_data.value(mimeType);
 
-    if (!m_types.contains(mimeType))
-        return QVariant();
+    QString mime = mimeType;
+
+    if (!m_types.contains(mimeType)) {
+        if (mimeType == QStringLiteral("text/plain") && m_types.contains(utf8Text()))
+            mime = utf8Text();
+        else
+            return QVariant();
+    }
 
     int pipefd[2];
     if (::pipe2(pipefd, O_CLOEXEC|O_NONBLOCK) == -1) {
@@ -126,7 +143,7 @@ QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::T
         return QVariant();
     }
 
-    m_dataOffer->receive(mimeType, pipefd[1]);
+    m_dataOffer->receive(mime, pipefd[1]);
     m_display->flushRequests();
 
     close(pipefd[1]);
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index ea7fe1a6a8b4f7eadfb823de62bd3bc8b01349b4..1284d39a168f3b2eb1476cf71a7b82c6019f05ab 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -140,6 +140,9 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
     , mQtKeyExtension(0)
     , mTextInputManager(0)
     , mHardwareIntegration(0)
+    , mLastInputSerial(0)
+    , mLastInputDevice(0)
+    , mLastInputWindow(0)
 {
     qRegisterMetaType<uint32_t>("uint32_t");
 
@@ -373,6 +376,11 @@ bool QWaylandDisplay::supportsWindowDecoration() const
     return integrationSupport;
 }
 
+void QWaylandDisplay::setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *win)
+{
+    mLastInputDevice = device;
+    mLastInputSerial = serial;
+    mLastInputWindow = win;
 }
 
 QT_END_NAMESPACE
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 9d4413f6fe64c05760d13f189095790e795dd122..394fd427017d118e5c0813934b7a771f7c91520c 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -163,6 +163,11 @@ public:
 
     bool supportsWindowDecoration() const;
 
+    uint32_t lastInputSerial() const { return mLastInputSerial; }
+    QWaylandInputDevice *lastInputDevice() const { return mLastInputDevice; }
+    QWaylandWindow *lastInputWindow() const { return mLastInputWindow; }
+    void setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *window);
+
 public slots:
     void blockingReadEvents();
     void flushRequests();
@@ -204,6 +209,9 @@ private:
     bool mScreensInitialized;
     QList<RegistryGlobal> mGlobals;
     int mCompositorVersion;
+    uint32_t mLastInputSerial;
+    QWaylandInputDevice *mLastInputDevice;
+    QWaylandWindow *mLastInputWindow;
 
     void registry_global(uint32_t id, const QString &interface, uint32_t version) Q_DECL_OVERRIDE;
     void registry_global_remove(uint32_t id) Q_DECL_OVERRIDE;
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
index 514383d300addbf251c704f0d641c739a3e677a3..85deaf27f0f68d34db8a3e2c0be81a4901b07a9b 100644
--- a/src/client/qwaylanddnd.cpp
+++ b/src/client/qwaylanddnd.cpp
@@ -73,13 +73,20 @@ QMimeData * QWaylandDrag::platformDropData()
 
 void QWaylandDrag::startDrag()
 {
+    bool cancel = false;
     if (!shapedPixmapWindow()) {
         QBasicDrag::startDrag();
-        QBasicDrag::cancel();
+        // Don't call cancel() here, since that will hide 'shapedPixmapWindow()', and
+        // QWaylandWindow::setVisible(false) will flush the window system queue,
+        // ending up trying to render the window, which doesn't have a role yet,
+        // and so blocking waiting for a frame callback.
+        cancel = true;
     }
 
     QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
     m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon);
+    if (cancel)
+        QBasicDrag::cancel();
     QBasicDrag::startDrag();
 }
 
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp
index db43e525b2bd87cd305fc9ab024103d1ed25c520..63bbeb14acb288bc891953f4160ef2ec8e54be8d 100644
--- a/src/client/qwaylandinputdevice.cpp
+++ b/src/client/qwaylandinputdevice.cpp
@@ -439,10 +439,10 @@ void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surf
         // so we just set it outside of the window boundaries.
         pos = QPointF(-1, -1);
         global = grab->window()->mapToGlobal(pos.toPoint());
-        MotionEvent e(time, pos, global, mButtons, Qt::NoModifier);
+        MotionEvent e(time, pos, global, mButtons, mParent->modifiers());
         grab->handleMouse(mParent, e);
     } else {
-        MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, Qt::NoModifier);
+        MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
         window->handleMouse(mParent, e);
     }
 }
@@ -450,7 +450,6 @@ void QWaylandInputDevice::Pointer::pointer_motion(uint32_t time, wl_fixed_t surf
 void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time,
                                                   uint32_t button, uint32_t state)
 {
-    Q_UNUSED(serial);
     QWaylandWindow *window = mFocus;
     Qt::MouseButton qt_button;
 
@@ -483,15 +482,17 @@ void QWaylandInputDevice::Pointer::pointer_button(uint32_t serial, uint32_t time
 
     mParent->mTime = time;
     mParent->mSerial = serial;
+    if (state)
+        mParent->mQDisplay->setLastInputDevice(mParent, serial, window);
 
     QWaylandWindow *grab = QWaylandWindow::mouseGrab();
     if (grab && grab != mFocus) {
         QPointF pos = QPointF(-1, -1);
         QPointF global = grab->window()->mapToGlobal(pos.toPoint());
-        MotionEvent e(time, pos, global, mButtons, Qt::NoModifier);
+        MotionEvent e(time, pos, global, mButtons, mParent->modifiers());
         grab->handleMouse(mParent, e);
     } else if (window) {
-        MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, Qt::NoModifier);
+        MotionEvent e(time, mSurfacePos, mGlobalPos, mButtons, mParent->modifiers());
         window->handleMouse(mParent, e);
     }
 }
@@ -736,13 +737,13 @@ void QWaylandInputDevice::Keyboard::focusCallback(void *data, struct wl_callback
 
 void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
 {
-    Q_UNUSED(serial);
     QWaylandWindow *window = mFocus;
     uint32_t code = key + 8;
     bool isDown = state != 0;
     QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
     QString text;
     int qtkey = key + 8;  // qt-compositor substracts 8 for some reason
+    mParent->mSerial = serial;
 
     if (!window) {
         // We destroyed the keyboard focus surface, but the server
@@ -750,6 +751,9 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
         return;
     }
 
+    if (isDown)
+        mParent->mQDisplay->setLastInputDevice(mParent, serial, window);
+
 #ifndef QT_NO_WAYLAND_XKB
     if (!createDefaultKeyMap()) {
         return;
@@ -761,7 +765,8 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time,
     Qt::KeyboardModifiers modifiers = mParent->modifiers();
 
     uint utf32 = xkb_keysym_to_utf32(sym);
-    text = QString::fromUcs4(&utf32, 1);
+    if (utf32)
+        text = QString::fromUcs4(&utf32, 1);
 
     qtkey = keysymToQtKey(sym, modifiers, text);
 
@@ -855,6 +860,7 @@ void QWaylandInputDevice::Touch::touch_down(uint32_t serial,
     mParent->mTime = time;
     mParent->mSerial = serial;
     mFocus = QWaylandWindow::fromWlSurface(surface);
+    mParent->mQDisplay->setLastInputDevice(mParent, serial, mFocus);
     mParent->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed);
 }
 
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
index a1aff8d1cf57e8654991eb9ffc68f76b9f7f93ac..56885531cef86708bb0429b9889e4fd6b2657d34 100644
--- a/src/client/qwaylandscreen.cpp
+++ b/src/client/qwaylandscreen.cpp
@@ -118,6 +118,14 @@ QDpi QWaylandScreen::logicalDpi() const
     return QPlatformScreen::logicalDpi();
 }
 
+QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
+{
+    QList<QPlatformScreen *> list;
+    foreach (QWaylandScreen *screen, mWaylandDisplay->screens())
+        list << screen;
+    return list;
+}
+
 void QWaylandScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
 {
     foreach (QWindow *window, QGuiApplication::allWindows()) {
diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
index c337d9be3c14375cea744a33ac5ea90aeb2e291e..b1b4a73f7b3b609fac1c127bf3923996b80a2e35 100644
--- a/src/client/qwaylandscreen_p.h
+++ b/src/client/qwaylandscreen_p.h
@@ -70,6 +70,7 @@ public:
     QSizeF physicalSize() const Q_DECL_OVERRIDE;
 
     QDpi logicalDpi() const Q_DECL_OVERRIDE;
+    QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE;
 
     void setOrientationUpdateMask(Qt::ScreenOrientations mask);
 
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index cf4e0e67218290e81a9b3cf0046edef9be407db2..b01e1f108722aae499bf7daa9e517290330a8278 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -90,8 +90,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
     , mResizeDirty(false)
     , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
     , mSentInitialResize(false)
-    , mMouseDevice(0)
-    , mMouseSerial(0)
     , mState(Qt::WindowNoState)
     , mMask()
     , mBackingStore(Q_NULLPTR)
@@ -218,7 +216,7 @@ void QWaylandWindow::setGeometry(const QRect &rect)
 {
     setGeometry_helper(rect);
 
-    if (window()->isVisible()) {
+    if (window()->isVisible() && rect.isValid()) {
         if (mWindowDecoration)
             mWindowDecoration->update();
 
@@ -236,14 +234,17 @@ void QWaylandWindow::setGeometry(const QRect &rect)
 void QWaylandWindow::setVisible(bool visible)
 {
     if (visible) {
-        if (window()->type() == Qt::Popup && transientParent()) {
+        if (window()->type() == Qt::Popup) {
             QWaylandWindow *parent = transientParent();
-            mMouseDevice = parent->mMouseDevice;
-            mMouseSerial = parent->mMouseSerial;
-
-            QWaylandWlShellSurface *wlshellSurface = dynamic_cast<QWaylandWlShellSurface*>(mShellSurface);
-            if (mMouseDevice && wlshellSurface) {
-                wlshellSurface->setPopup(transientParent(), mMouseDevice, mMouseSerial);
+            if (!parent) {
+                // Try with the current focus window. It should be the right one and anyway
+                // better than having no parent at all.
+                parent = mDisplay->lastInputWindow();
+            }
+            if (parent) {
+                QWaylandWlShellSurface *wlshellSurface = dynamic_cast<QWaylandWlShellSurface*>(mShellSurface);
+                if (wlshellSurface)
+                    wlshellSurface->setPopup(parent, mDisplay->lastInputDevice(), mDisplay->lastInputSerial());
             }
         }
 
@@ -364,7 +365,7 @@ void QWaylandWindow::requestResize()
 {
     QMutexLocker lock(&mResizeLock);
 
-    if (mCanResize) {
+    if (mCanResize || !mSentInitialResize) {
         doResize();
     }
 
@@ -599,7 +600,7 @@ QWaylandWindow *QWaylandWindow::transientParent() const
     if (window()->transientParent()) {
         // Take the top level window here, since the transient parent may be a QWidgetWindow
         // or some other window without a shell surface, which is then not able to get mouse
-        // events, nor set mMouseSerial and mMouseDevice.
+        // events.
         return static_cast<QWaylandWindow *>(topLevelWindow(window()->transientParent())->handle());
     }
     return 0;
@@ -607,10 +608,6 @@ QWaylandWindow *QWaylandWindow::transientParent() const
 
 void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e)
 {
-    if (e.buttons != Qt::NoButton) {
-        mMouseSerial = inputDevice->serial();
-        mMouseDevice = inputDevice;
-    }
 
     if (mWindowDecoration) {
         handleMouseEventWithDecoration(inputDevice, e);
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index de59e4e20b6b1d44dc60ee1e58d0ac8cd8bfc6f2..21d4886ccf14fb3ccafc85703f1a77d28fb48e1c 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -222,8 +222,6 @@ protected:
     QPoint mOffset;
 
     QIcon mWindowIcon;
-    QWaylandInputDevice *mMouseDevice;
-    int mMouseSerial;
 
     Qt::WindowState mState;
     QRegion mMask;
diff --git a/src/client/qwaylandwlshellsurface.cpp b/src/client/qwaylandwlshellsurface.cpp
index 550e6caebb15febda395a1f84bf3d012c4757c7d..0f249e36e8833a589aa7365b412911308d41a556 100644
--- a/src/client/qwaylandwlshellsurface.cpp
+++ b/src/client/qwaylandwlshellsurface.cpp
@@ -189,8 +189,14 @@ void QWaylandWlShellSurface::updateTransientParent(QWindow *parent)
 void QWaylandWlShellSurface::setPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial)
 {
     QWaylandWindow *parent_wayland_window = parent;
-    if (!parent_wayland_window)
+    if (!parent_wayland_window) {
+        qWarning("setPopup called without parent window");
+        return;
+    }
+    if (!device) {
+        qWarning("setPopup called without input device");
         return;
+    }
 
     // set_popup expects a position relative to the parent
     QPoint transientPos = m_window->geometry().topLeft(); // this is absolute
diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp
index 8a0d6bd28071892f9737a25736b12486c9b93f17..972a9d34ac571cff2d024687d6d1b5d0cd2a47a4 100644
--- a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp
+++ b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp
@@ -229,6 +229,12 @@ void QWaylandSurfaceItem::touchEvent(QTouchEvent *event)
     if (m_touchEventsEnabled) {
         QWaylandInputDevice *inputDevice = compositor()->inputDeviceFor(event);
 
+        if (event->type() == QEvent::TouchBegin) {
+            QQuickItem *grabber = window()->mouseGrabberItem();
+            if (grabber != this)
+                grabMouse();
+        }
+
         QPoint pointPos;
         const QList<QTouchEvent::TouchPoint> &points = event->touchPoints();
         if (!points.isEmpty())
@@ -249,6 +255,14 @@ void QWaylandSurfaceItem::touchEvent(QTouchEvent *event)
     }
 }
 
+void QWaylandSurfaceItem::mouseUngrabEvent()
+{
+    if (surface()) {
+        QTouchEvent e(QEvent::TouchCancel);
+        touchEvent(&e);
+    }
+}
+
 void QWaylandSurfaceItem::takeFocus(QWaylandInputDevice *device)
 {
     setFocus(true);
diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.h b/src/compositor/compositor_api/qwaylandsurfaceitem.h
index 2573fba3ee2f53e5e32033728226f8f5dd5a9780..2bf822f54036f1178173cbd900a2cf744f64b015 100644
--- a/src/compositor/compositor_api/qwaylandsurfaceitem.h
+++ b/src/compositor/compositor_api/qwaylandsurfaceitem.h
@@ -101,6 +101,7 @@ protected:
     void keyReleaseEvent(QKeyEvent *event);
 
     void touchEvent(QTouchEvent *event);
+    void mouseUngrabEvent() Q_DECL_OVERRIDE;
 
 public slots:
     virtual void takeFocus(QWaylandInputDevice *device = 0);
diff --git a/src/compositor/compositor_api/qwaylandsurfaceview.cpp b/src/compositor/compositor_api/qwaylandsurfaceview.cpp
index e6fd905870b6d52fb1ba351fbe204429116bd158..664ab98059ae7ce8f778f6f139738f9188cb6fff 100644
--- a/src/compositor/compositor_api/qwaylandsurfaceview.cpp
+++ b/src/compositor/compositor_api/qwaylandsurfaceview.cpp
@@ -42,6 +42,8 @@
 #include "qwaylandsurfaceview.h"
 #include "qwaylandsurface.h"
 #include "qwaylandsurface_p.h"
+#include "qwaylandcompositor.h"
+#include "qwaylandinput.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -65,6 +67,10 @@ QWaylandSurfaceView::QWaylandSurfaceView(QWaylandSurface *surf)
 QWaylandSurfaceView::~QWaylandSurfaceView()
 {
     if (d->surface) {
+        QWaylandInputDevice *i = d->surface->compositor()->defaultInputDevice();
+        if (i->mouseFocus() == this)
+            i->setMouseFocus(nullptr, QPointF());
+
         d->surface->destroy();
         d->surface->d_func()->views.removeOne(this);
     }