From f08e1ecdc88e9373a31c1505d5db7f905431c644 Mon Sep 17 00:00:00 2001
From: Paul Olav Tvete <paul.tvete@theqtcompany.com>
Date: Fri, 7 Aug 2015 14:28:14 +0200
Subject: [PATCH] Add Mir client platform plugin

Contributed by Canonical, Ltd.

Change-Id: I77752a1fd56641342be6c84e01b013d3df36ad73
Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
---
 config.tests/qpa/mirclient/mirclient.cpp      |  47 ++
 config.tests/qpa/mirclient/mirclient.pro      |   4 +
 configure                                     |  34 +-
 .../platforms/mirclient/mirclient.json        |   3 +
 src/plugins/platforms/mirclient/mirclient.pro |  47 ++
 .../mirclient/qmirclientbackingstore.cpp      | 146 +++++
 .../mirclient/qmirclientbackingstore.h        |  70 +++
 .../mirclient/qmirclientclipboard.cpp         | 305 ++++++++++
 .../platforms/mirclient/qmirclientclipboard.h |  88 +++
 .../mirclient/qmirclientglcontext.cpp         | 156 ++++++
 .../platforms/mirclient/qmirclientglcontext.h |  66 +++
 .../platforms/mirclient/qmirclientinput.cpp   | 520 ++++++++++++++++++
 .../platforms/mirclient/qmirclientinput.h     |  78 +++
 .../mirclient/qmirclientintegration.cpp       | 264 +++++++++
 .../mirclient/qmirclientintegration.h         |  99 ++++
 .../platforms/mirclient/qmirclientlogging.h   |  60 ++
 .../mirclient/qmirclientnativeinterface.cpp   | 134 +++++
 .../mirclient/qmirclientnativeinterface.h     |  66 +++
 .../qmirclientorientationchangeevent_p.h      |  66 +++
 .../mirclient/qmirclientplatformservices.cpp  |  72 +++
 .../mirclient/qmirclientplatformservices.h    |  54 ++
 .../platforms/mirclient/qmirclientplugin.cpp  |  61 ++
 .../platforms/mirclient/qmirclientplugin.h    |  53 ++
 .../platforms/mirclient/qmirclientscreen.cpp  | 296 ++++++++++
 .../platforms/mirclient/qmirclientscreen.h    |  84 +++
 .../platforms/mirclient/qmirclienttheme.cpp   |  64 +++
 .../platforms/mirclient/qmirclienttheme.h     |  54 ++
 .../platforms/mirclient/qmirclientwindow.cpp  | 452 +++++++++++++++
 .../platforms/mirclient/qmirclientwindow.h    |  80 +++
 src/plugins/platforms/platforms.pro           |   2 +
 30 files changed, 3523 insertions(+), 2 deletions(-)
 create mode 100644 config.tests/qpa/mirclient/mirclient.cpp
 create mode 100644 config.tests/qpa/mirclient/mirclient.pro
 create mode 100644 src/plugins/platforms/mirclient/mirclient.json
 create mode 100644 src/plugins/platforms/mirclient/mirclient.pro
 create mode 100644 src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientbackingstore.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientclipboard.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientclipboard.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientglcontext.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientglcontext.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientinput.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientinput.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientintegration.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientintegration.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientlogging.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientnativeinterface.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientplatformservices.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientplatformservices.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientplugin.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientplugin.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientscreen.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientscreen.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclienttheme.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclienttheme.h
 create mode 100644 src/plugins/platforms/mirclient/qmirclientwindow.cpp
 create mode 100644 src/plugins/platforms/mirclient/qmirclientwindow.h

diff --git a/config.tests/qpa/mirclient/mirclient.cpp b/config.tests/qpa/mirclient/mirclient.cpp
new file mode 100644
index 00000000000..c7148e82f9c
--- /dev/null
+++ b/config.tests/qpa/mirclient/mirclient.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <mir_toolkit/mir_client_library.h>
+#include <ubuntu/application/lifecycle_delegate.h>
+#include <EGL/egl.h>
+
+static void surfaceCreateCallback(MirSurface*, void*)
+{
+}
+
+
+int main(int, char **)
+{
+    u_application_lifecycle_delegate_new();
+    mir_surface_create(0, surfaceCreateCallback, 0);
+}
diff --git a/config.tests/qpa/mirclient/mirclient.pro b/config.tests/qpa/mirclient/mirclient.pro
new file mode 100644
index 00000000000..b397c2d08a9
--- /dev/null
+++ b/config.tests/qpa/mirclient/mirclient.pro
@@ -0,0 +1,4 @@
+SOURCES = mirclient.cpp
+CONFIG += link_pkgconfig
+PKGCONFIG += egl mirclient ubuntu-platform-api
+CONFIG -= qt
diff --git a/configure b/configure
index ed352d4c95b..9aac48e15c2 100755
--- a/configure
+++ b/configure
@@ -689,6 +689,7 @@ CFG_EGLFS_VIV=no
 CFG_DIRECTFB=auto
 CFG_LINUXFB=auto
 CFG_KMS=auto
+CFG_MIRCLIENT=auto
 CFG_LIBUDEV=auto
 CFG_LIBINPUT=auto
 CFG_OBSOLETE_WAYLAND=no
@@ -1850,6 +1851,13 @@ while [ "$#" -gt 0 ]; do
             UNKNOWN_OPT=yes
         fi
         ;;
+    mirclient)
+        if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then
+            CFG_MIRCLIENT="$VAL"
+        else
+            UNKNOWN_OPT=yes
+        fi
+        ;;
     libudev)
         if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then
             CFG_LIBUDEV="$VAL"
@@ -2650,6 +2658,9 @@ Additional options:
     -no-kms ............ Do not compile KMS support.
  *  -kms ............... Compile KMS support (Requires EGL).
 
+ *  -no-mirclient....... Do not compile Mir client support.
+    -mirclient.......... Compile Mir client support.
+
     -qpa <name> ......... Sets the default QPA platform (e.g xcb, cocoa, windows).
 
     -xplatform target ... The target platform when cross-compiling.
@@ -5269,6 +5280,7 @@ ORIG_CFG_EGLFS="$CFG_EGLFS"
 ORIG_CFG_DIRECTFB="$CFG_DIRECTFB"
 ORIG_CFG_LINUXFB="$CFG_LINUXFB"
 ORIG_CFG_KMS="$CFG_KMS"
+ORIG_CFG_MIRCLIENT="$CFG_MIRCLIENT"
 
 if [ "$CFG_LIBUDEV" != "no" ]; then
     if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists libudev 2>/dev/null; then
@@ -5551,6 +5563,20 @@ if [ "$CFG_KMS" != "no" ]; then
     fi
 fi
 
+if [ "$CFG_MIRCLIENT" != "no" ]; then
+    if compileTest qpa/mirclient "Mir client"; then
+        CFG_MIRCLIENT=yes
+    elif [ "$CFG_MIRCLIENT" = "yes" ]; then
+        echo " Mir client support cannot be enabled due to functionality tests!"
+        echo " Turn on verbose messaging (-v) to $0 to see the final report."
+        echo " If you believe this message is in error you may use the continue"
+        echo " switch (-continue) to $0 to continue."
+        exit 101
+    else
+        CFG_MIRCLIENT=no
+    fi
+fi
+
 # Detect libxkbcommon
 MIN_REQ_XKBCOMMON="0.4.1"
 # currently only xcb platform plugin supports building xkbcommon
@@ -5721,11 +5747,14 @@ fi
 if [ "$CFG_KMS" = "yes" ]; then
     QT_CONFIG="$QT_CONFIG kms"
 fi
+if [ "$CFG_MIRCLIENT" = "yes" ]; then
+    QT_CONFIG="$QT_CONFIG mirclient"
+fi
 
 if [ "$XPLATFORM_MAC" = "no" ] && [ "$XPLATFORM_MINGW" = "no" ] && [ "$XPLATFORM_QNX" = "no" ] && [ "$XPLATFORM_ANDROID" = "no" ] && [ "$XPLATFORM_HAIKU" = "no" ]; then
-    if [ "$CFG_XCB" = "no" ] && [ "$CFG_EGLFS" = "no" ] && [ "$CFG_DIRECTFB" = "no" ] && [ "$CFG_LINUXFB" = "no" ] && [ "$CFG_KMS" = "no" ]; then
+    if [ "$CFG_XCB" = "no" ] && [ "$CFG_EGLFS" = "no" ] && [ "$CFG_DIRECTFB" = "no" ] && [ "$CFG_LINUXFB" = "no" ] && [ "$CFG_KMS" = "no" ]  && [ "$CFG_MIRCLIENT" = "no" ]; then
         if [ "$QPA_PLATFORM_GUARD" = "yes" ] &&
-            ( [ "$ORIG_CFG_XCB" = "auto" ] || [ "$ORIG_CFG_EGLFS" = "auto" ] || [ "$ORIG_CFG_DIRECTFB" = "auto" ] || [ "$ORIG_CFG_LINUXFB" = "auto" ] || [ "$ORIG_CFG_KMS" = "auto" ] ); then
+            ( [ "$ORIG_CFG_XCB" = "auto" ] || [ "$ORIG_CFG_EGLFS" = "auto" ] || [ "$ORIG_CFG_DIRECTFB" = "auto" ] || [ "$ORIG_CFG_LINUXFB" = "auto" ] || [ "$ORIG_CFG_KMS" = "auto" ]  || [ "$ORIG_CFG_MIRCLIENT" = "auto" ] ); then
         echo "No QPA platform plugin enabled!"
         echo " If you really want to build without a QPA platform plugin you must pass"
         echo " -no-qpa-platform-guard to configure. Doing this will"
@@ -7142,6 +7171,7 @@ report_support "      EGLFS Mali ........." "$CFG_EGLFS_MALI"
 report_support "      EGLFS Raspberry Pi ." "$CFG_EGLFS_BRCM"
 report_support "      EGLFS X11 .........." "$CFG_EGL_X"
 report_support "    LinuxFB .............." "$CFG_LINUXFB"
+report_support "    Mir client............" "$CFG_MIRCLIENT"
 report_support "    XCB .................." "$CFG_XCB" system "system library" qt "bundled copy"
 if [ "$CFG_XCB" != "no" ]; then
     report_support "      EGL on X ..........." "$CFG_EGL_X"
diff --git a/src/plugins/platforms/mirclient/mirclient.json b/src/plugins/platforms/mirclient/mirclient.json
new file mode 100644
index 00000000000..c31558a2f1d
--- /dev/null
+++ b/src/plugins/platforms/mirclient/mirclient.json
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "mirclient" ]
+}
diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro
new file mode 100644
index 00000000000..033ce579b92
--- /dev/null
+++ b/src/plugins/platforms/mirclient/mirclient.pro
@@ -0,0 +1,47 @@
+TARGET = mirclient
+TEMPLATE = lib
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = MirServerIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private dbus
+
+CONFIG += qpa/genericunixfontdatabase
+
+DEFINES += MESA_EGL_NO_X11_HEADERS
+# CONFIG += c++11 # only enables C++0x
+QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
+QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined
+
+CONFIG += link_pkgconfig
+PKGCONFIG += egl mirclient ubuntu-platform-api
+
+SOURCES = \
+    qmirclientbackingstore.cpp \
+    qmirclientclipboard.cpp \
+    qmirclientglcontext.cpp \
+    qmirclientinput.cpp \
+    qmirclientintegration.cpp \
+    qmirclientnativeinterface.cpp \
+    qmirclientplatformservices.cpp \
+    qmirclientplugin.cpp \
+    qmirclientscreen.cpp \
+    qmirclienttheme.cpp \
+    qmirclientwindow.cpp
+
+HEADERS = \
+    qmirclientbackingstore.h \
+    qmirclientclipboard.h \
+    qmirclientglcontext.h \
+    qmirclientinput.h \
+    qmirclientintegration.h \
+    qmirclientlogging.h \
+    qmirclientnativeinterface.h \
+    qmirclientorientationchangeevent_p.h \
+    qmirclientplatformservices.h \
+    qmirclientplugin.h \
+    qmirclientscreen.h \
+    qmirclienttheme.h \
+    qmirclientwindow.h
diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
new file mode 100644
index 00000000000..daa0b229ec7
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientbackingstore.h"
+#include "qmirclientlogging.h"
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QMatrix4x4>
+#include <QtGui/private/qopengltextureblitter_p.h>
+#include <QtGui/qopenglfunctions.h>
+
+QMirClientBackingStore::QMirClientBackingStore(QWindow* window)
+    : QPlatformBackingStore(window)
+    , mContext(new QOpenGLContext)
+    , mTexture(new QOpenGLTexture(QOpenGLTexture::Target2D))
+    , mBlitter(new QOpenGLTextureBlitter)
+{
+    mContext->setFormat(window->requestedFormat());
+    mContext->setScreen(window->screen());
+    mContext->create();
+
+    window->setSurfaceType(QSurface::OpenGLSurface);
+}
+
+QMirClientBackingStore::~QMirClientBackingStore()
+{
+}
+
+void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset)
+{
+    Q_UNUSED(region);
+    Q_UNUSED(offset);
+    mContext->makeCurrent(window);
+    glViewport(0, 0, window->width(), window->height());
+
+    updateTexture();
+
+    if (!mBlitter->isCreated())
+        mBlitter->create();
+
+    mBlitter->bind();
+    mBlitter->setSwizzleRB(true);
+    mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft);
+    mBlitter->release();
+
+    mContext->swapBuffers(window);
+}
+
+void QMirClientBackingStore::updateTexture()
+{
+    if (mDirty.isNull())
+        return;
+
+    if (!mTexture->isCreated()) {
+        mTexture->setMinificationFilter(QOpenGLTexture::Nearest);
+        mTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
+        mTexture->setWrapMode(QOpenGLTexture::ClampToEdge);
+        mTexture->setData(mImage, QOpenGLTexture::DontGenerateMipMaps);
+        mTexture->create();
+    }
+    mTexture->bind();
+
+    QRegion fixed;
+    QRect imageRect = mImage.rect();
+
+    Q_FOREACH (const QRect &rect, mDirty.rects()) {
+        // intersect with image rect to be sure
+        QRect r = imageRect & rect;
+
+        // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
+        if (r.width() >= imageRect.width() / 2) {
+            r.setX(0);
+            r.setWidth(imageRect.width());
+        }
+
+        fixed |= r;
+    }
+
+    Q_FOREACH (const QRect &rect, fixed.rects()) {
+        // if the sub-rect is full-width we can pass the image data directly to
+        // OpenGL instead of copying, since there is no gap between scanlines
+        if (rect.width() == imageRect.width()) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+                            mImage.constScanLine(rect.y()));
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+                            mImage.copy(rect).constBits());
+        }
+    }
+    /* End of code taken from QEGLPlatformBackingStore */
+
+    mDirty = QRegion();
+}
+
+
+void QMirClientBackingStore::beginPaint(const QRegion& region)
+{
+    mDirty |= region;
+}
+
+void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)
+{
+    mImage = QImage(size, QImage::Format_RGB32);
+
+    if (mTexture->isCreated())
+        mTexture->destroy();
+}
+
+QPaintDevice* QMirClientBackingStore::paintDevice()
+{
+    return &mImage;
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h
new file mode 100644
index 00000000000..22b8bf9bc51
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTBACKINGSTORE_H
+#define QMIRCLIENTBACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+
+class QOpenGLContext;
+class QOpenGLTexture;
+class QOpenGLTextureBlitter;
+
+class QMirClientBackingStore : public QPlatformBackingStore
+{
+public:
+    QMirClientBackingStore(QWindow* window);
+    virtual ~QMirClientBackingStore();
+
+    // QPlatformBackingStore methods.
+    void beginPaint(const QRegion&) override;
+    void flush(QWindow* window, const QRegion& region, const QPoint& offset) override;
+    void resize(const QSize& size, const QRegion& staticContents) override;
+    QPaintDevice* paintDevice() override;
+
+protected:
+    void updateTexture();
+
+private:
+    QScopedPointer<QOpenGLContext> mContext;
+    QScopedPointer<QOpenGLTexture> mTexture;
+    QScopedPointer<QOpenGLTextureBlitter> mBlitter;
+    QImage mImage;
+    QRegion mDirty;
+};
+
+#endif // QMIRCLIENTBACKINGSTORE_H
diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp
new file mode 100644
index 00000000000..aa2ddf21037
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientclipboard.h"
+
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QDBusInterface>
+#include <QDBusPendingCallWatcher>
+#include <QDBusPendingReply>
+
+// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API
+//     which makes it impossible to have non-Qt applications communicate with Qt
+//     applications through the clipboard API. The solution would be to have
+//     Ubuntu Platform define the data format or propose an API that supports
+//     embedding different mime types in the clipboard.
+
+// Data format:
+//   number of mime types      (sizeof(int))
+//   data layout               ((4 * sizeof(int)) * number of mime types)
+//     mime type string offset (sizeof(int))
+//     mime type string size   (sizeof(int))
+//     data offset             (sizeof(int))
+//     data size               (sizeof(int))
+//   data                      (n bytes)
+
+namespace {
+
+const int maxFormatsCount = 16;
+const int maxBufferSize = 4 * 1024 * 1024;  // 4 Mb
+
+}
+
+QMirClientClipboard::QMirClientClipboard()
+    : mMimeData(new QMimeData)
+    , mIsOutdated(true)
+    , mUpdatesDisabled(false)
+    , mDBusSetupDone(false)
+{
+}
+
+QMirClientClipboard::~QMirClientClipboard()
+{
+    delete mMimeData;
+}
+
+void QMirClientClipboard::requestDBusClipboardContents()
+{
+    if (!mDBusSetupDone) {
+        setupDBus();
+    }
+
+    if (!mPendingGetContentsCall.isNull())
+        return;
+
+    QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("GetContents");
+
+    mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
+
+    QObject::connect(mPendingGetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
+                     this, SLOT(onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*)));
+}
+
+void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call)
+{
+    Q_ASSERT(call == mPendingGetContentsCall.data());
+
+    QDBusPendingReply<QByteArray> reply = *call;
+    if (reply.isError()) {
+        qCritical("QMirClientClipboard - Failed to get system clipboard contents via D-Bus. %s, %s",
+                qPrintable(reply.error().name()), qPrintable(reply.error().message()));
+        // TODO: Might try again later a number of times...
+    } else {
+        QByteArray serializedMimeData = reply.argumentAt<0>();
+        updateMimeData(serializedMimeData);
+    }
+    call->deleteLater();
+}
+
+void QMirClientClipboard::onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher *call)
+{
+    QDBusPendingReply<void> reply = *call;
+    if (reply.isError()) {
+        qCritical("QMirClientClipboard - Failed to set the system clipboard contents via D-Bus. %s, %s",
+                qPrintable(reply.error().name()), qPrintable(reply.error().message()));
+        // TODO: Might try again later a number of times...
+    }
+    call->deleteLater();
+}
+
+void QMirClientClipboard::updateMimeData(const QByteArray &serializedMimeData)
+{
+    if (mUpdatesDisabled)
+        return;
+
+    QMimeData *newMimeData = deserializeMimeData(serializedMimeData);
+    if (newMimeData) {
+        delete mMimeData;
+        mMimeData = newMimeData;
+        mIsOutdated = false;
+        emitChanged(QClipboard::Clipboard);
+    } else {
+        qWarning("QMirClientClipboard - Got invalid serialized mime data. Ignoring it.");
+    }
+}
+
+void QMirClientClipboard::setupDBus()
+{
+    QDBusConnection dbusConnection = QDBusConnection::sessionBus();
+
+    bool ok = dbusConnection.connect(
+            "com.canonical.QtMir",
+            "/com/canonical/QtMir/Clipboard",
+            "com.canonical.QtMir.Clipboard",
+            "ContentsChanged",
+            this, SLOT(updateMimeData(QByteArray)));
+    if (!ok) {
+        qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard.");
+    }
+
+    mDBusClipboard = new QDBusInterface("com.canonical.QtMir",
+            "/com/canonical/QtMir/Clipboard",
+            "com.canonical.QtMir.Clipboard",
+            dbusConnection);
+
+    mDBusSetupDone = true;
+}
+
+QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const
+{
+    const QStringList formats = mimeData->formats();
+    const int formatCount = qMin(formats.size(), maxFormatsCount);
+    const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int));
+    int bufferSize = headerSize;
+
+    for (int i = 0; i < formatCount; i++)
+        bufferSize += formats[i].size() + mimeData->data(formats[i]).size();
+
+    QByteArray serializedMimeData;
+    if (bufferSize <= maxBufferSize) {
+        // Serialize data.
+        serializedMimeData.resize(bufferSize);
+        {
+            char *buffer = serializedMimeData.data();
+            int* header = reinterpret_cast<int*>(serializedMimeData.data());
+            int offset = headerSize;
+            header[0] = formatCount;
+            for (int i = 0; i < formatCount; i++) {
+                const int formatOffset = offset;
+                const int formatSize = formats[i].size();
+                const int dataOffset = offset + formatSize;
+                const int dataSize = mimeData->data(formats[i]).size();
+                memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize);
+                memcpy(&buffer[dataOffset], mimeData->data(formats[i]).data(), dataSize);
+                header[i*4+1] = formatOffset;
+                header[i*4+2] = formatSize;
+                header[i*4+3] = dataOffset;
+                header[i*4+4] = dataSize;
+                offset += formatSize + dataSize;
+            }
+        }
+    } else {
+        qWarning("QMirClientClipboard: Not sending contents (%d bytes) to the global clipboard as it's"
+                " bigger than the maximum allowed size of %d bytes", bufferSize, maxBufferSize);
+    }
+
+    return serializedMimeData;
+}
+
+QMimeData *QMirClientClipboard::deserializeMimeData(const QByteArray &serializedMimeData) const
+{
+    if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) {
+        // Data is invalid
+        return nullptr;
+    }
+
+    QMimeData *mimeData = new QMimeData;
+
+    const char* const buffer = serializedMimeData.constData();
+    const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData());
+
+    const int count = qMin(header[0], maxFormatsCount);
+
+    for (int i = 0; i < count; i++) {
+        const int formatOffset = header[i*4+1];
+        const int formatSize = header[i*4+2];
+        const int dataOffset = header[i*4+3];
+        const int dataSize = header[i*4+4];
+
+        if (formatOffset + formatSize <= serializedMimeData.size()
+                && dataOffset + dataSize <= serializedMimeData.size()) {
+
+            QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize);
+            QByteArray mimeDataBytes(&buffer[dataOffset], dataSize);
+
+            mimeData->setData(mimeType, mimeDataBytes);
+        }
+    }
+
+    return mimeData;
+}
+
+QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode)
+{
+    if (mode != QClipboard::Clipboard)
+        return nullptr;
+
+    if (mIsOutdated && mPendingGetContentsCall.isNull()) {
+        requestDBusClipboardContents();
+    }
+
+    // Return whatever we have at the moment instead of blocking until we have something.
+    //
+    // This might be called during app startup just for the sake of checking if some
+    // "Paste" UI control should be enabled or not.
+    // We will emit QClipboard::changed() once we finally have something.
+    return mMimeData;
+}
+
+void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
+{
+    if (mode != QClipboard::Clipboard)
+        return;
+
+    if (!mPendingGetContentsCall.isNull()) {
+        // Ignore whatever comes from the system clipboard as we are going to change it anyway
+        QObject::disconnect(mPendingGetContentsCall.data(), 0, this, 0);
+        mUpdatesDisabled = true;
+        mPendingGetContentsCall->waitForFinished();
+        mUpdatesDisabled = false;
+        delete mPendingGetContentsCall.data();
+    }
+
+    QByteArray serializedMimeData = serializeMimeData(mimeData);
+    if (!serializedMimeData.isEmpty()) {
+        setDBusClipboardContents(serializedMimeData);
+    }
+
+    mMimeData = mimeData;
+    emitChanged(QClipboard::Clipboard);
+}
+
+bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const
+{
+    return mode == QClipboard::Clipboard;
+}
+
+bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
+{
+    Q_UNUSED(mode);
+    return false;
+}
+
+void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents)
+{
+    if (!mPendingSetContentsCall.isNull()) {
+        // Ignore any previous set call as we are going to overwrite it anyway
+        QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0);
+        mUpdatesDisabled = true;
+        mPendingSetContentsCall->waitForFinished();
+        mUpdatesDisabled = false;
+        delete mPendingSetContentsCall.data();
+    }
+
+    QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("SetContents", clipboardContents);
+
+    mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
+
+    QObject::connect(mPendingSetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)),
+                     this, SLOT(onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*)));
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h
new file mode 100644
index 00000000000..d3d3d400d2d
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientclipboard.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTCLIPBOARD_H
+#define QMIRCLIENTCLIPBOARD_H
+
+#include <qpa/qplatformclipboard.h>
+
+#include <QMimeData>
+#include <QPointer>
+class QDBusInterface;
+class QDBusPendingCallWatcher;
+
+class QMirClientClipboard : public QObject, public QPlatformClipboard
+{
+    Q_OBJECT
+public:
+    QMirClientClipboard();
+    virtual ~QMirClientClipboard();
+
+    // QPlatformClipboard methods.
+    QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
+    void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override;
+    bool supportsMode(QClipboard::Mode mode) const override;
+    bool ownsMode(QClipboard::Mode mode) const override;
+
+    void requestDBusClipboardContents();
+
+private Q_SLOTS:
+    void onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*);
+    void onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*);
+    void updateMimeData(const QByteArray &serializedMimeData);
+
+private:
+    void setupDBus();
+
+    QByteArray serializeMimeData(QMimeData *mimeData) const;
+    QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) const;
+
+    void setDBusClipboardContents(const QByteArray &clipboardContents);
+
+    QMimeData *mMimeData;
+    bool mIsOutdated;
+
+    QPointer<QDBusInterface> mDBusClipboard;
+
+    QPointer<QDBusPendingCallWatcher> mPendingGetContentsCall;
+    QPointer<QDBusPendingCallWatcher> mPendingSetContentsCall;
+
+    bool mUpdatesDisabled;
+    bool mDBusSetupDone;
+};
+
+#endif // QMIRCLIENTCLIPBOARD_H
diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp
new file mode 100644
index 00000000000..bfba5051e55
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientglcontext.h"
+#include "qmirclientwindow.h"
+#include "qmirclientlogging.h"
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+
+#if !defined(QT_NO_DEBUG)
+static void printOpenGLESConfig() {
+  static bool once = true;
+  if (once) {
+    const char* string = (const char*) glGetString(GL_VENDOR);
+    LOG("OpenGL ES vendor: %s", string);
+    string = (const char*) glGetString(GL_RENDERER);
+    LOG("OpenGL ES renderer: %s", string);
+    string = (const char*) glGetString(GL_VERSION);
+    LOG("OpenGL ES version: %s", string);
+    string = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
+    LOG("OpenGL ES Shading Language version: %s", string);
+    string = (const char*) glGetString(GL_EXTENSIONS);
+    LOG("OpenGL ES extensions: %s", string);
+    once = false;
+  }
+}
+#endif
+
+static EGLenum api_in_use()
+{
+#ifdef QTUBUNTU_USE_OPENGL
+    return EGL_OPENGL_API;
+#else
+    return EGL_OPENGL_ES_API;
+#endif
+}
+
+QMirClientOpenGLContext::QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share)
+{
+    ASSERT(screen != NULL);
+    mEglDisplay = screen->eglDisplay();
+    mScreen = screen;
+
+    // Create an OpenGL ES 2 context.
+    QVector<EGLint> attribs;
+    attribs.append(EGL_CONTEXT_CLIENT_VERSION);
+    attribs.append(2);
+    attribs.append(EGL_NONE);
+    ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
+
+    mEglContext = eglCreateContext(mEglDisplay, screen->eglConfig(), share ? share->eglContext() : EGL_NO_CONTEXT,
+                                   attribs.constData());
+    DASSERT(mEglContext != EGL_NO_CONTEXT);
+}
+
+QMirClientOpenGLContext::~QMirClientOpenGLContext()
+{
+    ASSERT(eglDestroyContext(mEglDisplay, mEglContext) == EGL_TRUE);
+}
+
+bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface)
+{
+    DASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+    EGLSurface eglSurface = static_cast<QMirClientWindow*>(surface)->eglSurface();
+#if defined(QT_NO_DEBUG)
+    eglBindAPI(api_in_use());
+    eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
+#else
+    ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
+    ASSERT(eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext) == EGL_TRUE);
+    printOpenGLESConfig();
+#endif
+    return true;
+}
+
+void QMirClientOpenGLContext::doneCurrent()
+{
+#if defined(QT_NO_DEBUG)
+    eglBindAPI(api_in_use());
+    eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+#else
+    ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
+    ASSERT(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE);
+#endif
+}
+
+void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface)
+{
+    QMirClientWindow *ubuntuWindow = static_cast<QMirClientWindow*>(surface);
+
+    EGLSurface eglSurface = ubuntuWindow->eglSurface();
+#if defined(QT_NO_DEBUG)
+    eglBindAPI(api_in_use());
+    eglSwapBuffers(mEglDisplay, eglSurface);
+#else
+    ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
+    ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE);
+#endif
+
+    // "Technique" copied from mir, in examples/eglapp.c around line 96
+    EGLint newBufferWidth = -1;
+    EGLint newBufferHeight = -1;
+    /*
+     * Querying the surface (actually the current buffer) dimensions here is
+     * the only truly safe way to be sure that the dimensions we think we
+     * have are those of the buffer being rendered to. But this should be
+     * improved in future; https://bugs.launchpad.net/mir/+bug/1194384
+     */
+    eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &newBufferWidth);
+    eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &newBufferHeight);
+
+    ubuntuWindow->onBuffersSwapped_threadSafe(newBufferWidth, newBufferHeight);
+}
+
+void (*QMirClientOpenGLContext::getProcAddress(const QByteArray& procName)) ()
+{
+#if defined(QT_NO_DEBUG)
+    eglBindAPI(api_in_use());
+#else
+    ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
+#endif
+    return eglGetProcAddress(procName.constData());
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h
new file mode 100644
index 00000000000..cc402982597
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientglcontext.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTGLCONTEXT_H
+#define QMIRCLIENTGLCONTEXT_H
+
+#include <qpa/qplatformopenglcontext.h>
+#include "qmirclientscreen.h"
+
+class QMirClientOpenGLContext : public QPlatformOpenGLContext
+{
+public:
+    QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share);
+    virtual ~QMirClientOpenGLContext();
+
+    // QPlatformOpenGLContext methods.
+    QSurfaceFormat format() const override { return mScreen->surfaceFormat(); }
+    void swapBuffers(QPlatformSurface* surface) override;
+    bool makeCurrent(QPlatformSurface* surface) override;
+    void doneCurrent() override;
+    bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; }
+    void (*getProcAddress(const QByteArray& procName)) ();
+
+    EGLContext eglContext() const { return mEglContext; }
+
+private:
+    QMirClientScreen* mScreen;
+    EGLContext mEglContext;
+    EGLDisplay mEglDisplay;
+};
+
+#endif // QMIRCLIENTGLCONTEXT_H
diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp
new file mode 100644
index 00000000000..56bc21f420d
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientinput.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** Copyright (C) 2014-2015 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+// Local
+#include "qmirclientinput.h"
+#include "qmirclientintegration.h"
+#include "qmirclientnativeinterface.h"
+#include "qmirclientscreen.h"
+#include "qmirclientwindow.h"
+#include "qmirclientlogging.h"
+#include "qmirclientorientationchangeevent_p.h"
+
+// Qt
+#if !defined(QT_NO_DEBUG)
+#include <QtCore/QThread>
+#endif
+#include <QtCore/qglobal.h>
+#include <QtCore/QCoreApplication>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatforminputcontext.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-keysyms.h>
+
+#include <mir_toolkit/mir_client_library.h>
+
+#define LOG_EVENTS 0
+
+// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
+static const uint32_t KeyTable[] = {
+    XKB_KEY_Escape,                  Qt::Key_Escape,
+    XKB_KEY_Tab,                     Qt::Key_Tab,
+    XKB_KEY_ISO_Left_Tab,            Qt::Key_Backtab,
+    XKB_KEY_BackSpace,               Qt::Key_Backspace,
+    XKB_KEY_Return,                  Qt::Key_Return,
+    XKB_KEY_Insert,                  Qt::Key_Insert,
+    XKB_KEY_Delete,                  Qt::Key_Delete,
+    XKB_KEY_Clear,                   Qt::Key_Delete,
+    XKB_KEY_Pause,                   Qt::Key_Pause,
+    XKB_KEY_Print,                   Qt::Key_Print,
+
+    XKB_KEY_Home,                    Qt::Key_Home,
+    XKB_KEY_End,                     Qt::Key_End,
+    XKB_KEY_Left,                    Qt::Key_Left,
+    XKB_KEY_Up,                      Qt::Key_Up,
+    XKB_KEY_Right,                   Qt::Key_Right,
+    XKB_KEY_Down,                    Qt::Key_Down,
+    XKB_KEY_Prior,                   Qt::Key_PageUp,
+    XKB_KEY_Next,                    Qt::Key_PageDown,
+
+    XKB_KEY_Shift_L,                 Qt::Key_Shift,
+    XKB_KEY_Shift_R,                 Qt::Key_Shift,
+    XKB_KEY_Shift_Lock,              Qt::Key_Shift,
+    XKB_KEY_Control_L,               Qt::Key_Control,
+    XKB_KEY_Control_R,               Qt::Key_Control,
+    XKB_KEY_Meta_L,                  Qt::Key_Meta,
+    XKB_KEY_Meta_R,                  Qt::Key_Meta,
+    XKB_KEY_Alt_L,                   Qt::Key_Alt,
+    XKB_KEY_Alt_R,                   Qt::Key_Alt,
+    XKB_KEY_Caps_Lock,               Qt::Key_CapsLock,
+    XKB_KEY_Num_Lock,                Qt::Key_NumLock,
+    XKB_KEY_Scroll_Lock,             Qt::Key_ScrollLock,
+    XKB_KEY_Super_L,                 Qt::Key_Super_L,
+    XKB_KEY_Super_R,                 Qt::Key_Super_R,
+    XKB_KEY_Menu,                    Qt::Key_Menu,
+    XKB_KEY_Hyper_L,                 Qt::Key_Hyper_L,
+    XKB_KEY_Hyper_R,                 Qt::Key_Hyper_R,
+    XKB_KEY_Help,                    Qt::Key_Help,
+
+    XKB_KEY_KP_Space,                Qt::Key_Space,
+    XKB_KEY_KP_Tab,                  Qt::Key_Tab,
+    XKB_KEY_KP_Enter,                Qt::Key_Enter,
+    XKB_KEY_KP_Home,                 Qt::Key_Home,
+    XKB_KEY_KP_Left,                 Qt::Key_Left,
+    XKB_KEY_KP_Up,                   Qt::Key_Up,
+    XKB_KEY_KP_Right,                Qt::Key_Right,
+    XKB_KEY_KP_Down,                 Qt::Key_Down,
+    XKB_KEY_KP_Prior,                Qt::Key_PageUp,
+    XKB_KEY_KP_Next,                 Qt::Key_PageDown,
+    XKB_KEY_KP_End,                  Qt::Key_End,
+    XKB_KEY_KP_Begin,                Qt::Key_Clear,
+    XKB_KEY_KP_Insert,               Qt::Key_Insert,
+    XKB_KEY_KP_Delete,               Qt::Key_Delete,
+    XKB_KEY_KP_Equal,                Qt::Key_Equal,
+    XKB_KEY_KP_Multiply,             Qt::Key_Asterisk,
+    XKB_KEY_KP_Add,                  Qt::Key_Plus,
+    XKB_KEY_KP_Separator,            Qt::Key_Comma,
+    XKB_KEY_KP_Subtract,             Qt::Key_Minus,
+    XKB_KEY_KP_Decimal,              Qt::Key_Period,
+    XKB_KEY_KP_Divide,               Qt::Key_Slash,
+
+    XKB_KEY_ISO_Level3_Shift,        Qt::Key_AltGr,
+    XKB_KEY_Multi_key,               Qt::Key_Multi_key,
+    XKB_KEY_Codeinput,               Qt::Key_Codeinput,
+    XKB_KEY_SingleCandidate,         Qt::Key_SingleCandidate,
+    XKB_KEY_MultipleCandidate,       Qt::Key_MultipleCandidate,
+    XKB_KEY_PreviousCandidate,       Qt::Key_PreviousCandidate,
+
+    XKB_KEY_Mode_switch,             Qt::Key_Mode_switch,
+    XKB_KEY_script_switch,           Qt::Key_Mode_switch,
+    XKB_KEY_XF86AudioRaiseVolume,    Qt::Key_VolumeUp,
+    XKB_KEY_XF86AudioLowerVolume,    Qt::Key_VolumeDown,
+    XKB_KEY_XF86PowerOff,            Qt::Key_PowerOff,
+    XKB_KEY_XF86PowerDown,           Qt::Key_PowerDown,
+
+    0,                          0
+};
+
+class QMirClientEvent : public QEvent
+{
+public:
+    QMirClientEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type)
+        : QEvent(type), window(window) {
+        nativeEvent = mir_event_ref(event);
+    }
+    ~QMirClientEvent()
+    {
+        mir_event_unref(nativeEvent);
+    }
+
+    QPointer<QMirClientWindow> window;
+    const MirEvent *nativeEvent;
+};
+
+QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration)
+    : QObject(nullptr)
+    , mIntegration(integration)
+    , mEventFilterType(static_cast<QMirClientNativeInterface*>(
+        integration->nativeInterface())->genericEventFilterType())
+    , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
+{
+    // Initialize touch device.
+    mTouchDevice = new QTouchDevice;
+    mTouchDevice->setType(QTouchDevice::TouchScreen);
+    mTouchDevice->setCapabilities(
+            QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
+            QTouchDevice::NormalizedPosition);
+    QWindowSystemInterface::registerTouchDevice(mTouchDevice);
+}
+
+QMirClientInput::~QMirClientInput()
+{
+  // Qt will take care of deleting mTouchDevice.
+}
+
+#if (LOG_EVENTS != 0)
+static const char* nativeEventTypeToStr(MirEventType t)
+{
+    switch (t)
+    {
+    case mir_event_type_key:
+        return "mir_event_type_key";
+    case mir_event_type_motion:
+        return "mir_event_type_motion";
+    case mir_event_type_surface:
+        return "mir_event_type_surface";
+    case mir_event_type_resize:
+        return "mir_event_type_resize";
+    case mir_event_type_prompt_session_state_change:
+        return "mir_event_type_prompt_session_state_change";
+    case mir_event_type_orientation:
+        return "mir_event_type_orientation";
+    case mir_event_type_close_surface:
+        return "mir_event_type_close_surface";
+    case mir_event_type_input:
+        return "mir_event_type_input";
+    default:
+        DLOG("Invalid event type %d", t);
+        return "invalid";
+    }
+}
+#endif // LOG_EVENTS != 0
+
+void QMirClientInput::customEvent(QEvent* event)
+{
+    DASSERT(QThread::currentThread() == thread());
+    QMirClientEvent* ubuntuEvent = static_cast<QMirClientEvent*>(event);
+    const MirEvent *nativeEvent = ubuntuEvent->nativeEvent;
+
+    if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) {
+        qWarning() << "Attempted to deliver an event to a non-existent window, ignoring.";
+        return;
+    }
+
+    // Event filtering.
+    long result;
+    if (QWindowSystemInterface::handleNativeEvent(
+            ubuntuEvent->window->window(), mEventFilterType,
+            const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) {
+        DLOG("event filtered out by native interface");
+        return;
+    }
+
+    #if (LOG_EVENTS != 0)
+    LOG("QMirClientInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
+    #endif
+
+    // Event dispatching.
+    switch (mir_event_get_type(nativeEvent))
+    {
+    case mir_event_type_input:
+        dispatchInputEvent(ubuntuEvent->window->window(), mir_event_get_input_event(nativeEvent));
+        break;
+    case mir_event_type_resize:
+    {
+        Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen());
+
+        auto resizeEvent = mir_event_get_resize_event(nativeEvent);
+
+        mIntegration->screen()->handleWindowSurfaceResize(
+                mir_resize_event_get_width(resizeEvent),
+                mir_resize_event_get_height(resizeEvent));
+
+        ubuntuEvent->window->handleSurfaceResize(mir_resize_event_get_width(resizeEvent),
+            mir_resize_event_get_height(resizeEvent));
+        break;
+    }
+    case mir_event_type_surface:
+    {
+        auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
+        if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
+            ubuntuEvent->window->handleSurfaceFocusChange(mir_surface_event_get_attribute_value(surfaceEvent) ==
+                mir_surface_focused);
+        }
+        break;
+    }
+    case mir_event_type_orientation:
+        dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));
+        break;
+    case mir_event_type_close_surface:
+        QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window());
+        break;
+    default:
+        DLOG("unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent)));
+    }
+}
+
+void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent *event)
+{
+    QWindow *window = platformWindow->window();
+
+    QCoreApplication::postEvent(this, new QMirClientEvent(
+            platformWindow, event, mEventType));
+
+    if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) {
+        QCoreApplication::postEvent(this, new QMirClientEvent(
+                    static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()),
+                    event, mEventType));
+    }
+}
+
+void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *ev)
+{
+    switch (mir_input_event_get_type(ev))
+    {
+    case mir_input_event_type_key:
+        dispatchKeyEvent(window, ev);
+        break;
+    case mir_input_event_type_touch:
+        dispatchTouchEvent(window, ev);
+        break;
+    case mir_input_event_type_pointer:
+        dispatchPointerEvent(window, ev);
+        break;
+    default:
+        break;
+    }
+}
+
+void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *ev)
+{
+    const MirTouchEvent *tev = mir_input_event_get_touch_event(ev);
+
+    // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
+    //     needs to be fixed as soon as the compat input lib adds query support.
+    const float kMaxPressure = 1.28;
+    const QRect kWindowGeometry = window->geometry();
+    QList<QWindowSystemInterface::TouchPoint> touchPoints;
+
+
+    // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
+    //       as Qt::TouchPointMoved
+    const unsigned int kPointerCount = mir_touch_event_point_count(tev);
+    for (unsigned int i = 0; i < kPointerCount; ++i) {
+        QWindowSystemInterface::TouchPoint touchPoint;
+
+        const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x();
+        const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere
+        const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
+        const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
+        const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
+        touchPoint.id = mir_touch_event_id(tev, i);
+        touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
+        touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);
+        touchPoint.pressure = kP / kMaxPressure;
+
+        MirTouchAction touch_action = mir_touch_event_action(tev, i);
+        switch (touch_action)
+        {
+        case mir_touch_action_down:
+            touchPoint.state = Qt::TouchPointPressed;
+            break;
+        case mir_touch_action_up:
+            touchPoint.state = Qt::TouchPointReleased;
+            break;
+        case mir_touch_action_change:
+        default:
+            touchPoint.state = Qt::TouchPointMoved;
+        }
+
+        touchPoints.append(touchPoint);
+    }
+
+    ulong timestamp = mir_input_event_get_event_time(ev) / 1000000;
+    QWindowSystemInterface::handleTouchEvent(window, timestamp,
+            mTouchDevice, touchPoints);
+}
+
+static uint32_t translateKeysym(uint32_t sym, char *string, size_t size)
+{
+    Q_UNUSED(size);
+    string[0] = '\0';
+
+    if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35)
+        return Qt::Key_F1 + (int(sym) - XKB_KEY_F1);
+
+    for (int i = 0; KeyTable[i]; i += 2) {
+        if (sym == KeyTable[i])
+            return KeyTable[i + 1];
+    }
+
+    string[0] = sym;
+    string[1] = '\0';
+    return toupper(sym);
+}
+
+namespace
+{
+Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers)
+{
+    Qt::KeyboardModifiers q_modifiers = Qt::NoModifier;
+    if (modifiers & mir_input_event_modifier_shift) {
+        q_modifiers |= Qt::ShiftModifier;
+    }
+    if (modifiers & mir_input_event_modifier_ctrl) {
+        q_modifiers |= Qt::ControlModifier;
+    }
+    if (modifiers & mir_input_event_modifier_alt) {
+        q_modifiers |= Qt::AltModifier;
+    }
+    if (modifiers & mir_input_event_modifier_meta) {
+        q_modifiers |= Qt::MetaModifier;
+    }
+    return q_modifiers;
+}
+}
+
+void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *event)
+{
+    const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event);
+
+    ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
+    xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event);
+
+    // Key modifier and unicode index mapping.
+    auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event));
+
+    MirKeyboardAction action = mir_keyboard_event_action(key_event);
+    QEvent::Type keyType = action == mir_keyboard_action_up
+        ? QEvent::KeyRelease : QEvent::KeyPress;
+
+    char s[2];
+    int sym = translateKeysym(xk_sym, s, sizeof(s));
+    QString text = QString::fromLatin1(s);
+
+    bool is_auto_rep = action == mir_keyboard_action_repeat;
+
+    QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
+    if (context) {
+        QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep);
+        qKeyEvent.setTimestamp(timestamp);
+        if (context->filterEvent(&qKeyEvent)) {
+            DLOG("key event filtered out by input context");
+            return;
+        }
+    }
+
+    QWindowSystemInterface::handleKeyEvent(window, timestamp, keyType, sym, modifiers, text, is_auto_rep);
+}
+
+namespace
+{
+Qt::MouseButtons extract_buttons(const MirPointerEvent *pev)
+{
+    Qt::MouseButtons buttons = Qt::NoButton;
+    if (mir_pointer_event_button_state(pev, mir_pointer_button_primary))
+        buttons |= Qt::LeftButton;
+    if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary))
+        buttons |= Qt::RightButton;
+    if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary))
+        buttons |= Qt::MidButton;
+
+    // TODO: Should mir back and forward buttons exist?
+    // should they be Qt::X button 1 and 2?
+    return buttons;
+}
+}
+
+void QMirClientInput::dispatchPointerEvent(QWindow *window, const MirInputEvent *ev)
+{
+    auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
+
+    auto pev = mir_input_event_get_pointer_event(ev);
+    auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
+    auto buttons = extract_buttons(pev);
+
+    auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
+                               mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
+
+    QWindowSystemInterface::handleMouseEvent(window, timestamp, local_point, local_point /* Should we omit global point instead? */,
+                                             buttons, modifiers);
+}
+
+#if (LOG_EVENTS != 0)
+static const char* nativeOrientationDirectionToStr(MirOrientation orientation)
+{
+    switch (orientation) {
+    case mir_orientation_normal:
+        return "Normal";
+        break;
+    case mir_orientation_left:
+        return "Left";
+        break;
+    case mir_orientation_inverted:
+        return "Inverted";
+        break;
+    case mir_orientation_right:
+        return "Right";
+        break;
+    default:
+        return "INVALID!";
+    }
+}
+#endif
+
+void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event)
+{
+    MirOrientation mir_orientation = mir_orientation_event_get_direction(event);
+    #if (LOG_EVENTS != 0)
+    // Orientation event logging.
+    LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation));
+    #endif
+
+    if (!window->screen()) {
+        DLOG("Window has no associated screen, dropping orientation event");
+        return;
+    }
+
+    OrientationChangeEvent::Orientation orientation;
+    switch (mir_orientation) {
+    case mir_orientation_normal:
+        orientation = OrientationChangeEvent::TopUp;
+        break;
+    case mir_orientation_left:
+        orientation = OrientationChangeEvent::LeftUp;
+        break;
+    case mir_orientation_inverted:
+        orientation = OrientationChangeEvent::TopDown;
+        break;
+    case mir_orientation_right:
+        orientation = OrientationChangeEvent::RightUp;
+        break;
+    default:
+        DLOG("No such orientation %d", mir_orientation);
+        return;
+    }
+
+    // Dispatch orientation event to [Platform]Screen, as that is where Qt reads it. Screen will handle
+    // notifying Qt of the actual orientation change - done to prevent multiple Windows each creating
+    // an identical orientation change event and passing it directly to Qt.
+    // [Platform]Screen can also factor in the native orientation.
+    QCoreApplication::postEvent(static_cast<QMirClientScreen*>(window->screen()->handle()),
+                                new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));
+}
+
diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h
new file mode 100644
index 00000000000..c987d18c129
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientinput.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2014-2015 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTINPUT_H
+#define QMIRCLIENTINPUT_H
+
+// Qt
+#include <qpa/qwindowsysteminterface.h>
+
+#include <mir_toolkit/mir_client_library.h>
+
+class QMirClientClientIntegration;
+class QMirClientWindow;
+
+class QMirClientInput : public QObject
+{
+    Q_OBJECT
+
+public:
+    QMirClientInput(QMirClientClientIntegration* integration);
+    virtual ~QMirClientInput();
+
+    // QObject methods.
+    void customEvent(QEvent* event) override;
+
+    void postEvent(QMirClientWindow* window, const MirEvent *event);
+    QMirClientClientIntegration* integration() const { return mIntegration; }
+
+protected:
+    void dispatchKeyEvent(QWindow *window, const MirInputEvent *event);
+    void dispatchPointerEvent(QWindow *window, const MirInputEvent *event);
+    void dispatchTouchEvent(QWindow *window, const MirInputEvent *event);
+    void dispatchInputEvent(QWindow *window, const MirInputEvent *event);
+
+    void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
+
+private:
+    QMirClientClientIntegration* mIntegration;
+    QTouchDevice* mTouchDevice;
+    const QByteArray mEventFilterType;
+    const QEvent::Type mEventType;
+};
+
+#endif // QMIRCLIENTINPUT_H
diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp
new file mode 100644
index 00000000000..a234f4eac6b
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2014-2015 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+// Qt
+#include <QGuiApplication>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qplatforminputcontext.h>
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QOpenGLContext>
+
+// Local
+#include "qmirclientbackingstore.h"
+#include "qmirclientclipboard.h"
+#include "qmirclientglcontext.h"
+#include "qmirclientinput.h"
+#include "qmirclientintegration.h"
+#include "qmirclientlogging.h"
+#include "qmirclientnativeinterface.h"
+#include "qmirclientscreen.h"
+#include "qmirclienttheme.h"
+#include "qmirclientwindow.h"
+
+// platform-api
+#include <ubuntu/application/lifecycle_delegate.h>
+#include <ubuntu/application/id.h>
+#include <ubuntu/application/options.h>
+
+static void resumedCallback(const UApplicationOptions *options, void* context)
+{
+    Q_UNUSED(options)
+    Q_UNUSED(context)
+    DASSERT(context != NULL);
+    QCoreApplication::postEvent(QCoreApplication::instance(),
+                                new QEvent(QEvent::ApplicationActivate));
+}
+
+static void aboutToStopCallback(UApplicationArchive *archive, void* context)
+{
+    Q_UNUSED(archive)
+    DASSERT(context != NULL);
+    QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context);
+    integration->inputContext()->hideInputPanel();
+    QCoreApplication::postEvent(QCoreApplication::instance(),
+                                new QEvent(QEvent::ApplicationDeactivate));
+}
+
+QMirClientClientIntegration::QMirClientClientIntegration()
+    : QPlatformIntegration()
+    , mNativeInterface(new QMirClientNativeInterface)
+    , mFontDb(new QGenericUnixFontDatabase)
+    , mServices(new QMirClientPlatformServices)
+    , mClipboard(new QMirClientClipboard)
+    , mScaleFactor(1.0)
+{
+    setupOptions();
+    setupDescription();
+
+    // Create new application instance
+    mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions);
+
+    if (mInstance == nullptr)
+        qFatal("QMirClientClientIntegration: connection to Mir server failed. Check that a Mir server is\n"
+               "running, and the correct socket is being used and is accessible. The shell may have\n"
+               "rejected the incoming connection, so check its log file");
+
+    // Create default screen.
+    mScreen = new QMirClientScreen(u_application_instance_get_mir_connection(mInstance));
+    screenAdded(mScreen);
+
+    // Initialize input.
+    if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) {
+        mInput = new QMirClientInput(this);
+        mInputContext = QPlatformInputContextFactory::create();
+    } else {
+        mInput = nullptr;
+        mInputContext = nullptr;
+    }
+
+    // compute the scale factor
+    const int defaultGridUnit = 8;
+    int gridUnit = defaultGridUnit;
+    QByteArray gridUnitString = qgetenv("GRID_UNIT_PX");
+    if (!gridUnitString.isEmpty()) {
+        bool ok;
+        gridUnit = gridUnitString.toInt(&ok);
+        if (!ok) {
+            gridUnit = defaultGridUnit;
+        }
+    }
+    mScaleFactor = static_cast<qreal>(gridUnit) / defaultGridUnit;
+}
+
+QMirClientClientIntegration::~QMirClientClientIntegration()
+{
+    delete mInput;
+    delete mInputContext;
+    delete mScreen;
+    delete mServices;
+}
+
+QPlatformServices *QMirClientClientIntegration::services() const
+{
+    return mServices;
+}
+
+void QMirClientClientIntegration::setupOptions()
+{
+    QStringList args = QCoreApplication::arguments();
+    int argc = args.size() + 1;
+    char **argv = new char*[argc];
+    for (int i = 0; i < argc - 1; i++)
+        argv[i] = qstrdup(args.at(i).toLocal8Bit());
+    argv[argc - 1] = nullptr;
+
+    mOptions = u_application_options_new_from_cmd_line(argc - 1, argv);
+
+    for (int i = 0; i < argc; i++)
+        delete [] argv[i];
+    delete [] argv;
+}
+
+void QMirClientClientIntegration::setupDescription()
+{
+    mDesc = u_application_description_new();
+    UApplicationId* id = u_application_id_new_from_stringn("QtUbuntu", 8);
+    u_application_description_set_application_id(mDesc, id);
+
+    UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new();
+    u_application_lifecycle_delegate_set_application_resumed_cb(delegate, &resumedCallback);
+    u_application_lifecycle_delegate_set_application_about_to_stop_cb(delegate, &aboutToStopCallback);
+    u_application_lifecycle_delegate_set_context(delegate, this);
+    u_application_description_set_application_lifecycle_delegate(mDesc, delegate);
+}
+
+QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const
+{
+    return const_cast<QMirClientClientIntegration*>(this)->createPlatformWindow(window);
+}
+
+QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window)
+{
+    QPlatformWindow* platformWindow = new QMirClientWindow(
+            window, mClipboard, static_cast<QMirClientScreen*>(mScreen), mInput, u_application_instance_get_mir_connection(mInstance));
+    platformWindow->requestActivateWindow();
+    return platformWindow;
+}
+
+bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+    switch (cap) {
+    case ThreadedPixmaps:
+        return true;
+        break;
+
+    case OpenGL:
+        return true;
+        break;
+
+    case ThreadedOpenGL:
+        if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
+            return true;
+        } else {
+            DLOG("ubuntumirclient: disabled threaded OpenGL");
+            return false;
+        }
+        break;
+
+    default:
+        return QPlatformIntegration::hasCapability(cap);
+    }
+}
+
+QAbstractEventDispatcher *QMirClientClientIntegration::createEventDispatcher() const
+{
+    return createUnixEventDispatcher();
+}
+
+QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(QWindow* window) const
+{
+    return new QMirClientBackingStore(window);
+}
+
+QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
+        QOpenGLContext* context) const
+{
+    return const_cast<QMirClientClientIntegration*>(this)->createPlatformOpenGLContext(context);
+}
+
+QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
+        QOpenGLContext* context)
+{
+    return new QMirClientOpenGLContext(static_cast<QMirClientScreen*>(context->screen()->handle()),
+                                   static_cast<QMirClientOpenGLContext*>(context->shareHandle()));
+}
+
+QStringList QMirClientClientIntegration::themeNames() const
+{
+    return QStringList(QMirClientTheme::name);
+}
+
+QPlatformTheme* QMirClientClientIntegration::createPlatformTheme(const QString& name) const
+{
+    Q_UNUSED(name);
+    return new QMirClientTheme;
+}
+
+QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const
+{
+    switch (hint) {
+        case QPlatformIntegration::StartDragDistance: {
+            // default is 10 pixels (see QPlatformTheme::defaultThemeHint)
+            return 10.0 * mScaleFactor;
+        }
+        case QPlatformIntegration::PasswordMaskDelay: {
+            // return time in milliseconds - 1 second
+            return QVariant(1000);
+        }
+        default:
+            break;
+    }
+    return QPlatformIntegration::styleHint(hint);
+}
+
+QPlatformClipboard* QMirClientClientIntegration::clipboard() const
+{
+    return mClipboard.data();
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h
new file mode 100644
index 00000000000..29602096914
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientintegration.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTINTEGRATION_H
+#define QMIRCLIENTINTEGRATION_H
+
+#include <qpa/qplatformintegration.h>
+#include <QSharedPointer>
+
+#include "qmirclientplatformservices.h"
+
+// platform-api
+#include <ubuntu/application/description.h>
+#include <ubuntu/application/instance.h>
+
+class QMirClientClipboard;
+class QMirClientInput;
+class QMirClientScreen;
+
+class QMirClientClientIntegration : public QPlatformIntegration {
+public:
+    QMirClientClientIntegration();
+    virtual ~QMirClientClientIntegration();
+
+    // QPlatformIntegration methods.
+    bool hasCapability(QPlatformIntegration::Capability cap) const override;
+    QAbstractEventDispatcher *createEventDispatcher() const override;
+    QPlatformNativeInterface* nativeInterface() const override { return mNativeInterface; }
+    QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override;
+    QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override;
+    QPlatformFontDatabase* fontDatabase() const override { return mFontDb; }
+    QStringList themeNames() const override;
+    QPlatformTheme* createPlatformTheme(const QString& name) const override;
+    QVariant styleHint(StyleHint hint) const override;
+    QPlatformServices *services() const override;
+    QPlatformWindow* createPlatformWindow(QWindow* window) const override;
+    QPlatformInputContext* inputContext() const override { return mInputContext; }
+    QPlatformClipboard* clipboard() const override;
+
+    QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);
+    QPlatformWindow* createPlatformWindow(QWindow* window);
+    QMirClientScreen* screen() const { return mScreen; }
+
+private:
+    void setupOptions();
+    void setupDescription();
+
+    QPlatformNativeInterface* mNativeInterface;
+    QPlatformFontDatabase* mFontDb;
+
+    QMirClientPlatformServices* mServices;
+
+    QMirClientScreen* mScreen;
+    QMirClientInput* mInput;
+    QPlatformInputContext* mInputContext;
+    QSharedPointer<QMirClientClipboard> mClipboard;
+    qreal mScaleFactor;
+
+    // Platform API stuff
+    UApplicationOptions* mOptions;
+    UApplicationDescription* mDesc;
+    UApplicationInstance* mInstance;
+};
+
+#endif // QMIRCLIENTINTEGRATION_H
diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h
new file mode 100644
index 00000000000..80914d28b9e
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientlogging.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTLOGGING_H
+#define QMIRCLIENTLOGGING_H
+
+// Logging and assertion macros.
+#define LOG(...) qDebug(__VA_ARGS__)
+#define LOG_IF(cond,...) do { if (cond) qDebug(__VA_ARGS__); } while (0)
+#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
+#define NOT_REACHED() qt_assert("Not reached!",__FILE__,__LINE__)
+
+// Logging and assertion macros are compiled out for release builds.
+#if !defined(QT_NO_DEBUG)
+#define DLOG(...) LOG(__VA_ARGS__)
+#define DLOG_IF(cond,...) LOG_IF((cond), __VA_ARGS__)
+#define DASSERT(cond) ASSERT((cond))
+#define DNOT_REACHED() NOT_REACHED()
+#else
+#define DLOG(...) qt_noop()
+#define DLOG_IF(cond,...) qt_noop()
+#define DASSERT(cond) qt_noop()
+#define DNOT_REACHED() qt_noop()
+#endif
+
+#endif  // QMIRCLIENTLOGGING_H
diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
new file mode 100644
index 00000000000..a0bb932df3c
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+// Qt
+#include <private/qguiapplication_p.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qscreen.h>
+#include <QtCore/QMap>
+
+// Local
+#include "qmirclientnativeinterface.h"
+#include "qmirclientscreen.h"
+#include "qmirclientglcontext.h"
+
+class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
+{
+public:
+    QMirClientResourceMap()
+        : QMap<QByteArray, QMirClientNativeInterface::ResourceType>() {
+        insert("egldisplay", QMirClientNativeInterface::EglDisplay);
+        insert("eglcontext", QMirClientNativeInterface::EglContext);
+        insert("nativeorientation", QMirClientNativeInterface::NativeOrientation);
+        insert("display", QMirClientNativeInterface::Display);
+    }
+};
+
+Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap)
+
+QMirClientNativeInterface::QMirClientNativeInterface()
+    : mGenericEventFilterType(QByteArrayLiteral("Event"))
+    , mNativeOrientation(nullptr)
+{
+}
+
+QMirClientNativeInterface::~QMirClientNativeInterface()
+{
+    delete mNativeOrientation;
+    mNativeOrientation = nullptr;
+}
+
+void* QMirClientNativeInterface::nativeResourceForContext(
+    const QByteArray& resourceString, QOpenGLContext* context)
+{
+    if (!context)
+        return nullptr;
+
+    const QByteArray kLowerCaseResource = resourceString.toLower();
+
+    if (!ubuntuResourceMap()->contains(kLowerCaseResource))
+        return nullptr;
+
+    const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
+
+    if (kResourceType == QMirClientNativeInterface::EglContext)
+        return static_cast<QMirClientOpenGLContext*>(context->handle())->eglContext();
+    else
+        return nullptr;
+}
+
+void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resourceString, QWindow* window)
+{
+    const QByteArray kLowerCaseResource = resourceString.toLower();
+    if (!ubuntuResourceMap()->contains(kLowerCaseResource))
+        return NULL;
+    const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
+    if (kResourceType == QMirClientNativeInterface::EglDisplay) {
+        if (window) {
+            return static_cast<QMirClientScreen*>(window->screen()->handle())->eglDisplay();
+        } else {
+            return static_cast<QMirClientScreen*>(
+                    QGuiApplication::primaryScreen()->handle())->eglDisplay();
+        }
+    } else if (kResourceType == QMirClientNativeInterface::NativeOrientation) {
+        // Return the device's native screen orientation.
+        if (window) {
+            QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle());
+            mNativeOrientation = new Qt::ScreenOrientation(ubuntuScreen->nativeOrientation());
+        } else {
+            QPlatformScreen *platformScreen = QGuiApplication::primaryScreen()->handle();
+            mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation());
+        }
+        return mNativeOrientation;
+    } else {
+        return NULL;
+    }
+}
+
+void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resourceString, QScreen* screen)
+{
+    const QByteArray kLowerCaseResource = resourceString.toLower();
+    if (!ubuntuResourceMap()->contains(kLowerCaseResource))
+        return NULL;
+    const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
+    if (kResourceType == QMirClientNativeInterface::Display) {
+        if (!screen)
+            screen = QGuiApplication::primaryScreen();
+        return static_cast<QMirClientScreen*>(screen->handle())->eglNativeDisplay();
+    } else
+        return NULL;
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h
new file mode 100644
index 00000000000..84f03bb915c
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTNATIVEINTERFACE_H
+#define QMIRCLIENTNATIVEINTERFACE_H
+
+#include <qpa/qplatformnativeinterface.h>
+
+class QMirClientNativeInterface : public QPlatformNativeInterface {
+public:
+    enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display };
+
+    QMirClientNativeInterface();
+    ~QMirClientNativeInterface();
+
+    // QPlatformNativeInterface methods.
+    void* nativeResourceForContext(const QByteArray& resourceString,
+                                   QOpenGLContext* context) override;
+    void* nativeResourceForWindow(const QByteArray& resourceString,
+                                  QWindow* window) override;
+    void* nativeResourceForScreen(const QByteArray& resourceString,
+                                  QScreen* screen) override;
+
+    // New methods.
+    const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
+
+private:
+    const QByteArray mGenericEventFilterType;
+    Qt::ScreenOrientation* mNativeOrientation;
+};
+
+#endif // QMIRCLIENTNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h
new file mode 100644
index 00000000000..24d7307faaa
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTORIENTATIONCHANGEEVENT_P_H
+#define QMIRCLIENTORIENTATIONCHANGEEVENT_P_H
+
+#include <QEvent>
+#include "qmirclientlogging.h"
+
+class OrientationChangeEvent : public QEvent {
+public:
+    enum Orientation {
+        Undefined = 0,
+        TopUp,
+        TopDown,
+        LeftUp,
+        RightUp,
+        FaceUp,
+        FaceDown
+    };
+
+    OrientationChangeEvent(QEvent::Type type, Orientation orientation)
+        : QEvent(type)
+        , mOrientation(orientation)
+    {
+    }
+
+    static const QEvent::Type mType;
+    Orientation mOrientation;
+};
+
+#endif // QMIRCLIENTORIENTATIONCHANGEEVENT_P_H
diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp
new file mode 100644
index 00000000000..d0260c79d36
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientplatformservices.h"
+
+#include <QUrl>
+
+#include <ubuntu/application/url_dispatcher/service.h>
+#include <ubuntu/application/url_dispatcher/session.h>
+
+bool QMirClientPlatformServices::openUrl(const QUrl &url)
+{
+    return callDispatcher(url);
+}
+
+bool QMirClientPlatformServices::openDocument(const QUrl &url)
+{
+    return callDispatcher(url);
+}
+
+bool QMirClientPlatformServices::callDispatcher(const QUrl &url)
+{
+    UAUrlDispatcherSession* session = ua_url_dispatcher_session();
+    if (!session)
+        return false;
+
+    ua_url_dispatcher_session_open(session, url.toEncoded().constData(), NULL, NULL);
+
+    free(session);
+
+    // We are returning true here because the other option
+    // is spawning a nested event loop and wait for the
+    // callback. But there is no guarantee on how fast
+    // the callback is going to be so we prefer to avoid the
+    // nested event loop. Long term plan is improve Qt API
+    // to support an async openUrl
+    return true;
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.h b/src/plugins/platforms/mirclient/qmirclientplatformservices.h
new file mode 100644
index 00000000000..64a0432d06d
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientplatformservices.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTPLATFORMSERVICES_H
+#define QMIRCLIENTPLATFORMSERVICES_H
+
+#include <qpa/qplatformservices.h>
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+class QMirClientPlatformServices : public QPlatformServices {
+public:
+    bool openUrl(const QUrl &url) override;
+    bool openDocument(const QUrl &url) override;
+
+private:
+    bool callDispatcher(const QUrl &url);
+};
+
+#endif // QMIRCLIENTPLATFORMSERVICES_H
diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp
new file mode 100644
index 00000000000..43d913f8d2e
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientplugin.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientplugin.h"
+#include "qmirclientintegration.h"
+
+QStringList QMirClientIntegrationPlugin::keys() const
+{
+    QStringList list;
+    list << "mirclient";
+    return list;
+}
+
+QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system,
+                                                               const QStringList &)
+{
+    if (system.toLower() == "mirclient") {
+#ifdef PLATFORM_API_TOUCH
+        setenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient", 1);
+#else
+        setenv("UBUNTU_PLATFORM_API_BACKEND", "desktop_mirclient", 1);
+#endif
+        return new QMirClientClientIntegration;
+    } else {
+        return 0;
+    }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h
new file mode 100644
index 00000000000..a6f1a1081a9
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientplugin.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTPLUGIN_H
+#define QMIRCLIENTPLUGIN_H
+
+#include <qpa/qplatformintegrationplugin.h>
+
+class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json")
+
+public:
+    QStringList keys() const;
+    QPlatformIntegration* create(const QString&, const QStringList&);
+};
+
+#endif // QMIRCLIENTPLUGIN_H
diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp
new file mode 100644
index 00000000000..5c4b1cd0d62
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientscreen.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <mir_toolkit/mir_client_library.h>
+
+// Qt
+#include <QCoreApplication>
+#include <QtCore/qmath.h>
+#include <QScreen>
+#include <QThread>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+
+// local
+#include "qmirclientscreen.h"
+#include "qmirclientlogging.h"
+#include "qmirclientorientationchangeevent_p.h"
+
+#include "memory"
+
+static const int kSwapInterval = 1;
+
+#if !defined(QT_NO_DEBUG)
+
+static const char *orientationToStr(Qt::ScreenOrientation orientation) {
+    switch (orientation) {
+        case Qt::PrimaryOrientation:
+            return "primary";
+        case Qt::PortraitOrientation:
+            return "portrait";
+        case Qt::LandscapeOrientation:
+            return "landscape";
+        case Qt::InvertedPortraitOrientation:
+            return "inverted portrait";
+        case Qt::InvertedLandscapeOrientation:
+            return "inverted landscape";
+        default:
+            return "INVALID!";
+    }
+}
+
+static void printEglConfig(EGLDisplay display, EGLConfig config) {
+  DASSERT(display != EGL_NO_DISPLAY);
+  DASSERT(config != nullptr);
+  static const struct { const EGLint attrib; const char* name; } kAttribs[] = {
+    { EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" },
+    { EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" },
+    { EGL_BLUE_SIZE, "EGL_BLUE_SIZE" },
+    { EGL_GREEN_SIZE, "EGL_GREEN_SIZE" },
+    { EGL_RED_SIZE, "EGL_RED_SIZE" },
+    { EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" },
+    { EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" },
+    { EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT" },
+    { EGL_CONFIG_ID, "EGL_CONFIG_ID" },
+    { EGL_LEVEL, "EGL_LEVEL" },
+    { EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT" },
+    { EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS" },
+    { EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH" },
+    { EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" },
+    { EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" },
+    { EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" },
+    { EGL_SAMPLES, "EGL_SAMPLES" },
+    { EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS" },
+    { EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE" },
+    { EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE" },
+    { EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE" },
+    { EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE" },
+    { EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE" },
+    { EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB" },
+    { EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA" },
+    { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
+    { EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" },
+    { -1, NULL }
+  };
+  const char* string = eglQueryString(display, EGL_VENDOR);
+  LOG("EGL vendor: %s", string);
+  string = eglQueryString(display, EGL_VERSION);
+  LOG("EGL version: %s", string);
+  string = eglQueryString(display, EGL_EXTENSIONS);
+  LOG("EGL extensions: %s", string);
+  LOG("EGL configuration attibutes:");
+  for (int index = 0; kAttribs[index].attrib != -1; index++) {
+    EGLint value;
+    if (eglGetConfigAttrib(display, config, kAttribs[index].attrib, &value))
+      LOG("  %s: %d", kAttribs[index].name, static_cast<int>(value));
+  }
+}
+#endif
+
+
+const QEvent::Type OrientationChangeEvent::mType =
+        static_cast<QEvent::Type>(QEvent::registerEventType());
+
+static const MirDisplayOutput *find_active_output(
+    const MirDisplayConfiguration *conf)
+{
+    const MirDisplayOutput *output = NULL;
+    for (uint32_t d = 0; d < conf->num_outputs; d++)
+    {
+        const MirDisplayOutput *out = conf->outputs + d;
+
+        if (out->used &&
+            out->connected &&
+            out->num_modes &&
+            out->current_mode < out->num_modes)
+        {
+            output = out;
+            break;
+        }
+    }
+
+    return output;
+}
+
+QMirClientScreen::QMirClientScreen(MirConnection *connection)
+    : mFormat(QImage::Format_RGB32)
+    , mDepth(32)
+    , mSurfaceFormat()
+    , mEglDisplay(EGL_NO_DISPLAY)
+    , mEglConfig(nullptr)
+{
+    // Initialize EGL.
+    ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE);
+
+    mEglNativeDisplay = mir_connection_get_egl_native_display(connection);
+    ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
+    ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
+
+    // Configure EGL buffers format.
+    mSurfaceFormat.setRedBufferSize(8);
+    mSurfaceFormat.setGreenBufferSize(8);
+    mSurfaceFormat.setBlueBufferSize(8);
+    mSurfaceFormat.setAlphaBufferSize(8);
+    mSurfaceFormat.setDepthBufferSize(24);
+    mSurfaceFormat.setStencilBufferSize(8);
+    if (!qEnvironmentVariableIsEmpty("QTUBUNTU_MULTISAMPLE")) {
+        mSurfaceFormat.setSamples(4);
+        DLOG("ubuntumirclient: setting MSAA to 4 samples");
+    }
+#ifdef QTUBUNTU_USE_OPENGL
+    mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGL);
+#else
+    mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+#endif
+    mEglConfig = q_configFromGLFormat(mEglDisplay, mSurfaceFormat, true);
+
+    #if !defined(QT_NO_DEBUG)
+    printEglConfig(mEglDisplay, mEglConfig);
+    #endif
+
+    // Set vblank swap interval.
+    int swapInterval = kSwapInterval;
+    QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL");
+    if (!swapIntervalString.isEmpty()) {
+        bool ok;
+        swapInterval = swapIntervalString.toInt(&ok);
+        if (!ok)
+            swapInterval = kSwapInterval;
+    }
+    DLOG("ubuntumirclient: setting swap interval to %d", swapInterval);
+    eglSwapInterval(mEglDisplay, swapInterval);
+
+    // Get screen resolution.
+    auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
+    using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
+    configUp displayConfig(mir_connection_create_display_config(connection), configDeleter);
+    ASSERT(displayConfig != nullptr);
+
+    auto const displayOutput = find_active_output(displayConfig.get());
+    ASSERT(displayOutput != nullptr);
+
+    const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode];
+    const int kScreenWidth = mode->horizontal_resolution;
+    const int kScreenHeight = mode->vertical_resolution;
+    DASSERT(kScreenWidth > 0 && kScreenHeight > 0);
+
+    DLOG("ubuntumirclient: screen resolution: %dx%d", kScreenWidth, kScreenHeight);
+
+    mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight);
+
+    DLOG("QQMirClientScreen::QQMirClientScreen (this=%p)", this);
+
+    // Set the default orientation based on the initial screen dimmensions.
+    mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
+
+    // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
+    mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
+}
+
+QMirClientScreen::~QMirClientScreen()
+{
+    eglTerminate(mEglDisplay);
+}
+
+void QMirClientScreen::customEvent(QEvent* event) {
+    DASSERT(QThread::currentThread() == thread());
+
+    OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event);
+    switch (oReadingEvent->mOrientation) {
+        case OrientationChangeEvent::LeftUp: {
+            mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ?
+                        Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation;
+            break;
+        }
+        case OrientationChangeEvent::TopUp: {
+            mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ?
+                        Qt::LandscapeOrientation : Qt::PortraitOrientation;
+            break;
+        }
+        case OrientationChangeEvent::RightUp: {
+            mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ?
+                        Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation;
+            break;
+        }
+        case OrientationChangeEvent::TopDown: {
+            mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ?
+                        Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation;
+            break;
+        }
+        default: {
+            DLOG("QMirClientScreen::customEvent - Unknown orientation.");
+            return;
+        }
+    }
+
+    // Raise the event signal so that client apps know the orientation changed
+    DLOG("QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation));
+    QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
+}
+
+void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeight)
+{
+    if ((windowWidth > windowHeight && mGeometry.width() < mGeometry.height())
+     || (windowWidth < windowHeight && mGeometry.width() > mGeometry.height())) {
+
+        // The window aspect ratio differ's from the screen one. This means that
+        // unity8 has rotated the window in its scene.
+        // As there's no way to express window rotation in Qt's API, we have
+        // Flip QScreen's dimensions so that orientation properties match
+        // (primaryOrientation particularly).
+        // FIXME: This assumes a phone scenario. Won't work, or make sense,
+        //        on the desktop
+
+        QRect currGeometry = mGeometry;
+        mGeometry.setWidth(currGeometry.height());
+        mGeometry.setHeight(currGeometry.width());
+
+        DLOG("QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)",
+            mGeometry.width(), mGeometry.height());
+        QWindowSystemInterface::handleScreenGeometryChange(screen(),
+                                                           mGeometry /* newGeometry */,
+                                                           mGeometry /* newAvailableGeometry */);
+
+        if (mGeometry.width() < mGeometry.height()) {
+            mCurrentOrientation = Qt::PortraitOrientation;
+        } else {
+            mCurrentOrientation = Qt::LandscapeOrientation;
+        }
+        DLOG("QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation));
+        QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
+    }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h
new file mode 100644
index 00000000000..5d9325354f7
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientscreen.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTSCREEN_H
+#define QMIRCLIENTSCREEN_H
+
+#include <qpa/qplatformscreen.h>
+#include <QSurfaceFormat>
+#include <EGL/egl.h>
+
+struct MirConnection;
+
+class QMirClientScreen : public QObject, public QPlatformScreen
+{
+    Q_OBJECT
+public:
+    QMirClientScreen(MirConnection *connection);
+    virtual ~QMirClientScreen();
+
+    // QPlatformScreen methods.
+    QImage::Format format() const override { return mFormat; }
+    int depth() const override { return mDepth; }
+    QRect geometry() const override { return mGeometry; }
+    QRect availableGeometry() const override { return mGeometry; }
+    Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }
+    Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }
+
+    // New methods.
+    QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; }
+    EGLDisplay eglDisplay() const { return mEglDisplay; }
+    EGLConfig eglConfig() const { return mEglConfig; }
+    EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
+    void handleWindowSurfaceResize(int width, int height);
+
+    // QObject methods.
+    void customEvent(QEvent* event);
+
+private:
+    QRect mGeometry;
+    Qt::ScreenOrientation mNativeOrientation;
+    Qt::ScreenOrientation mCurrentOrientation;
+    QImage::Format mFormat;
+    int mDepth;
+    QSurfaceFormat mSurfaceFormat;
+    EGLDisplay mEglDisplay;
+    EGLConfig mEglConfig;
+    EGLNativeDisplayType mEglNativeDisplay;
+};
+
+#endif // QMIRCLIENTSCREEN_H
diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.cpp b/src/plugins/platforms/mirclient/qmirclienttheme.cpp
new file mode 100644
index 00000000000..c15da239455
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclienttheme.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclienttheme.h"
+
+#include <QtCore/QVariant>
+
+const char *QMirClientTheme::name = "ubuntu";
+
+QMirClientTheme::QMirClientTheme()
+{
+}
+
+QMirClientTheme::~QMirClientTheme()
+{
+}
+
+QVariant QMirClientTheme::themeHint(ThemeHint hint) const
+{
+    if (hint == QPlatformTheme::SystemIconThemeName) {
+        QByteArray iconTheme = qgetenv("QTUBUNTU_ICON_THEME");
+        if (iconTheme.isEmpty()) {
+            return QVariant(QStringLiteral("ubuntu-mobile"));
+        } else {
+            return QVariant(QString(iconTheme));
+        }
+    } else {
+        return QGenericUnixTheme::themeHint(hint);
+    }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.h b/src/plugins/platforms/mirclient/qmirclienttheme.h
new file mode 100644
index 00000000000..8f330395a0b
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclienttheme.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTTHEME_H
+#define QMIRCLIENTTHEME_H
+
+#include <QtPlatformSupport/private/qgenericunixthemes_p.h>
+
+class QMirClientTheme : public QGenericUnixTheme
+{
+public:
+    static const char* name;
+    QMirClientTheme();
+    virtual ~QMirClientTheme();
+
+    // From QPlatformTheme
+    QVariant themeHint(ThemeHint hint) const override;
+};
+
+#endif // QMIRCLIENTTHEME_H
diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp
new file mode 100644
index 00000000000..f3fd1e756d4
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2014-2015 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+// Local
+#include "qmirclientclipboard.h"
+#include "qmirclientinput.h"
+#include "qmirclientwindow.h"
+#include "qmirclientscreen.h"
+#include "qmirclientlogging.h"
+
+// Qt
+#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QMutex>
+#include <QMutexLocker>
+#include <QSize>
+#include <QtMath>
+
+// Platform API
+#include <ubuntu/application/instance.h>
+
+#include <EGL/egl.h>
+
+#define IS_OPAQUE_FLAG 1
+
+namespace
+{
+MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
+{
+    switch (state) {
+    case Qt::WindowNoState:
+        return mir_surface_state_restored;
+
+    case Qt::WindowFullScreen:
+        return mir_surface_state_fullscreen;
+
+    case Qt::WindowMaximized:
+        return mir_surface_state_maximized;
+
+    case Qt::WindowMinimized:
+        return mir_surface_state_minimized;
+
+    default:
+        LOG("Unexpected Qt::WindowState: %d", state);
+        return mir_surface_state_restored;
+    }
+}
+
+#if !defined(QT_NO_DEBUG)
+const char *qtWindowStateToStr(Qt::WindowState state)
+{
+    switch (state) {
+    case Qt::WindowNoState:
+        return "NoState";
+
+    case Qt::WindowFullScreen:
+        return "FullScreen";
+
+    case Qt::WindowMaximized:
+        return "Maximized";
+
+    case Qt::WindowMinimized:
+        return "Minimized";
+
+    default:
+        return "!?";
+    }
+}
+#endif
+
+} // anonymous namespace
+
+class QMirClientWindowPrivate
+{
+public:
+    void createEGLSurface(EGLNativeWindowType nativeWindow);
+    void destroyEGLSurface();
+    int panelHeight();
+
+    QMirClientScreen* screen;
+    EGLSurface eglSurface;
+    WId id;
+    QMirClientInput* input;
+    Qt::WindowState state;
+    MirConnection *connection;
+    MirSurface* surface;
+    QSize bufferSize;
+    QMutex mutex;
+    QSharedPointer<QMirClientClipboard> clipboard;
+};
+
+static void eventCallback(MirSurface* surface, const MirEvent *event, void* context)
+{
+    (void) surface;
+    DASSERT(context != NULL);
+    QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context);
+    platformWindow->priv()->input->postEvent(platformWindow, event);
+}
+
+static void surfaceCreateCallback(MirSurface* surface, void* context)
+{
+    DASSERT(context != NULL);
+    QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context);
+    platformWindow->priv()->surface = surface;
+
+    mir_surface_set_event_handler(surface, eventCallback, context);
+}
+
+QMirClientWindow::QMirClientWindow(QWindow* w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen* screen,
+                           QMirClientInput* input, MirConnection* connection)
+    : QObject(nullptr), QPlatformWindow(w)
+{
+    DASSERT(screen != NULL);
+
+    d = new QMirClientWindowPrivate;
+    d->screen = screen;
+    d->eglSurface = EGL_NO_SURFACE;
+    d->input = input;
+    d->state = window()->windowState();
+    d->connection = connection;
+    d->clipboard = clipboard;
+
+    static int id = 1;
+    d->id = id++;
+
+    // Use client geometry if set explicitly, use available screen geometry otherwise.
+    QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ?
+        window()->geometry() : screen->availableGeometry());
+    createWindow();
+    DLOG("QMirClientWindow::QMirClientWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input);
+}
+
+QMirClientWindow::~QMirClientWindow()
+{
+    DLOG("QMirClientWindow::~QMirClientWindow");
+    d->destroyEGLSurface();
+
+    mir_surface_release_sync(d->surface);
+
+    delete d;
+}
+
+void QMirClientWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow)
+{
+  DLOG("QMirClientWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)",
+          this, reinterpret_cast<void*>(nativeWindow));
+
+  eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(),
+          nativeWindow, nullptr);
+
+  DASSERT(eglSurface != EGL_NO_SURFACE);
+}
+
+void QMirClientWindowPrivate::destroyEGLSurface()
+{
+    DLOG("QMirClientWindowPrivate::destroyEGLSurface (this=%p)", this);
+    if (eglSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(screen->eglDisplay(), eglSurface);
+        eglSurface = EGL_NO_SURFACE;
+    }
+}
+
+// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
+// we need to guess the panel height (3GU + 2DP)
+int QMirClientWindowPrivate::panelHeight()
+{
+    const int defaultGridUnit = 8;
+    int gridUnit = defaultGridUnit;
+    QByteArray gridUnitString = qgetenv("GRID_UNIT_PX");
+    if (!gridUnitString.isEmpty()) {
+        bool ok;
+        gridUnit = gridUnitString.toInt(&ok);
+        if (!ok) {
+            gridUnit = defaultGridUnit;
+        }
+    }
+    qreal densityPixelRatio = static_cast<qreal>(gridUnit) / defaultGridUnit;
+    return gridUnit * 3 + qFloor(densityPixelRatio) * 2;
+}
+
+namespace
+{
+static MirPixelFormat
+mir_choose_default_pixel_format(MirConnection *connection)
+{
+    MirPixelFormat format[mir_pixel_formats];
+    unsigned int nformats;
+
+    mir_connection_get_available_surface_formats(connection,
+        format, mir_pixel_formats, &nformats);
+
+    return format[0];
+}
+}
+
+void QMirClientWindow::createWindow()
+{
+    DLOG("QMirClientWindow::createWindow (this=%p)", this);
+
+    // FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update
+    const int SCREEN_KEYBOARD_ROLE = 7;
+    // Get surface role and flags.
+    QVariant roleVariant = window()->property("role");
+    int role = roleVariant.isValid() ? roleVariant.toUInt() : 1;  // 1 is the default role for apps.
+    QVariant opaqueVariant = window()->property("opaque");
+    uint flags = opaqueVariant.isValid() ?
+        opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0;
+
+    // FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for
+    //     performance reasons.
+    flags |= static_cast<uint>(IS_OPAQUE_FLAG);
+
+    const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title
+    const int panelHeight = d->panelHeight();
+
+#if !defined(QT_NO_DEBUG)
+    LOG("panelHeight: '%d'", panelHeight);
+    LOG("role: '%d'", role);
+    LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque");
+    LOG("title: '%s'", title.constData());
+#endif
+
+    // Get surface geometry.
+    QRect geometry;
+    if (d->state == Qt::WindowFullScreen) {
+        printf("QMirClientWindow - fullscreen geometry\n");
+        geometry = screen()->geometry();
+    } else if (d->state == Qt::WindowMaximized) {
+        printf("QMirClientWindow - maximized geometry\n");
+        geometry = screen()->availableGeometry();
+        /*
+         * FIXME: Autopilot relies on being able to convert coordinates relative of the window
+         * into absolute screen coordinates. Mir does not allow this, see bug lp:1346633
+         * Until there's a correct way to perform this transformation agreed, this horrible hack
+         * guesses the transformation heuristically.
+         *
+         * Assumption: this method only used on phone devices!
+         */
+        geometry.setY(panelHeight);
+    } else {
+        printf("QMirClientWindow - regular geometry\n");
+        geometry = this->geometry();
+        geometry.setY(panelHeight);
+    }
+
+    DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n",
+            geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data());
+
+    MirSurfaceSpec *spec;
+    if (role == SCREEN_KEYBOARD_ROLE)
+    {
+        spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(),
+            geometry.height(), mir_choose_default_pixel_format(d->connection));
+    }
+    else
+    {
+        spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(),
+            geometry.height(), mir_choose_default_pixel_format(d->connection));
+    }
+    mir_surface_spec_set_name(spec, title.data());
+
+    // Create platform window
+    mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this));
+    mir_surface_spec_release(spec);
+
+    DASSERT(d->surface != NULL);
+    d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface)));
+
+    if (d->state == Qt::WindowFullScreen) {
+    // TODO: We could set this on creation once surface spec supports it (mps already up)
+        mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen));
+    }
+
+    // Window manager can give us a final size different from what we asked for
+    // so let's check what we ended up getting
+    {
+        MirSurfaceParameters parameters;
+        mir_surface_get_parameters(d->surface, &parameters);
+
+        geometry.setWidth(parameters.width);
+        geometry.setHeight(parameters.height);
+    }
+
+    DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)",
+            geometry.width(), geometry.height());
+
+    // Assume that the buffer size matches the surface size at creation time
+    d->bufferSize = geometry.size();
+
+    // Tell Qt about the geometry.
+    QWindowSystemInterface::handleGeometryChange(window(), geometry);
+    QPlatformWindow::setGeometry(geometry);
+}
+
+void QMirClientWindow::moveResize(const QRect& rect)
+{
+    (void) rect;
+    // TODO: Not yet supported by mir.
+}
+
+void QMirClientWindow::handleSurfaceResize(int width, int height)
+{
+    QMutexLocker(&d->mutex);
+    LOG("QMirClientWindow::handleSurfaceResize(width=%d, height=%d)", width, height);
+
+    // The current buffer size hasn't actually changed. so just render on it and swap
+    // buffers in the hope that the next buffer will match the surface size advertised
+    // in this event.
+    // But since this event is processed by a thread different from the one that swaps
+    // buffers, you can never know if this information is already outdated as there's
+    // no synchronicity whatsoever between the processing of resize events and the
+    // consumption of buffers.
+    if (d->bufferSize.width() != width || d->bufferSize.height() != height) {
+        QWindowSystemInterface::handleExposeEvent(window(), geometry());
+        QWindowSystemInterface::flushWindowSystemEvents();
+    }
+}
+
+void QMirClientWindow::handleSurfaceFocusChange(bool focused)
+{
+    LOG("QMirClientWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false");
+    QWindow *activatedWindow = focused ? window() : nullptr;
+
+    // System clipboard contents might have changed while this window was unfocused and wihtout
+    // this process getting notified about it because it might have been suspended (due to
+    // application lifecycle policies), thus unable to listen to any changes notified through
+    // D-Bus.
+    // Therefore let's ensure we are up to date with the system clipboard now that we are getting
+    // focused again.
+    if (focused) {
+        d->clipboard->requestDBusClipboardContents();
+    }
+
+    QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason);
+}
+
+void QMirClientWindow::setWindowState(Qt::WindowState state)
+{
+    QMutexLocker(&d->mutex);
+    DLOG("QMirClientWindow::setWindowState (this=%p, %s)", this,  qtWindowStateToStr(state));
+
+    if (state == d->state)
+        return;
+
+    // TODO: Perhaps we should check if the states are applied?
+    mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state)));
+    d->state = state;
+}
+
+void QMirClientWindow::setGeometry(const QRect& rect)
+{
+    DLOG("QMirClientWindow::setGeometry (this=%p)", this);
+
+    bool doMoveResize;
+
+    {
+        QMutexLocker(&d->mutex);
+        QPlatformWindow::setGeometry(rect);
+        doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized;
+    }
+
+    if (doMoveResize) {
+        moveResize(rect);
+    }
+}
+
+void QMirClientWindow::setVisible(bool visible)
+{
+    QMutexLocker(&d->mutex);
+    DLOG("QMirClientWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false");
+
+    if (visible) {
+        mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state)));
+
+        QWindowSystemInterface::handleExposeEvent(window(), QRect());
+        QWindowSystemInterface::flushWindowSystemEvents();
+    } else {
+        // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
+        //       Will have to change qtmir and unity8 for that.
+        mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized));
+    }
+}
+
+void* QMirClientWindow::eglSurface() const
+{
+    return d->eglSurface;
+}
+
+WId QMirClientWindow::winId() const
+{
+    return d->id;
+}
+
+void QMirClientWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight)
+{
+    QMutexLocker(&d->mutex);
+
+    bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0;
+
+    if (sizeKnown && (d->bufferSize.width() != newBufferWidth ||
+                d->bufferSize.height() != newBufferHeight)) {
+
+        DLOG("QMirClientWindow::onBuffersSwapped_threadSafe - buffer size changed from (%d,%d) to (%d,%d)",
+                d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight);
+
+        d->bufferSize.rwidth() = newBufferWidth;
+        d->bufferSize.rheight() = newBufferHeight;
+
+        QRect newGeometry;
+
+        newGeometry = geometry();
+        newGeometry.setWidth(d->bufferSize.width());
+        newGeometry.setHeight(d->bufferSize.height());
+
+        QPlatformWindow::setGeometry(newGeometry);
+        QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect());
+    }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h
new file mode 100644
index 00000000000..f342669544e
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientwindow.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2014-2015 Canonical, Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTWINDOW_H
+#define QMIRCLIENTWINDOW_H
+
+#include <qpa/qplatformwindow.h>
+#include <QSharedPointer>
+
+#include <mir_toolkit/mir_client_library.h>
+
+class QMirClientClipboard;
+class QMirClientInput;
+class QMirClientScreen;
+class QMirClientWindowPrivate;
+
+class QMirClientWindow : public QObject, public QPlatformWindow
+{
+    Q_OBJECT
+public:
+    QMirClientWindow(QWindow *w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen *screen,
+                 QMirClientInput *input, MirConnection *mir_connection);
+    virtual ~QMirClientWindow();
+
+    // QPlatformWindow methods.
+    WId winId() const override;
+    void setGeometry(const QRect&) override;
+    void setWindowState(Qt::WindowState state) override;
+    void setVisible(bool visible) override;
+
+    // New methods.
+    void* eglSurface() const;
+    void handleSurfaceResize(int width, int height);
+    void handleSurfaceFocusChange(bool focused);
+    void onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight);
+
+    QMirClientWindowPrivate* priv() { return d; }
+
+private:
+    void createWindow();
+    void moveResize(const QRect& rect);
+
+    QMirClientWindowPrivate *d;
+};
+
+#endif // QMIRCLIENTWINDOW_H
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index 22d443733ef..43bb04e3184 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -40,3 +40,5 @@ contains(QT_CONFIG, linuxfb): SUBDIRS += linuxfb
 haiku {
     SUBDIRS += haiku
 }
+
+contains(QT_CONFIG, mirclient): SUBDIRS += mirclient
-- 
GitLab