[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kwin] /: [wayland] Add a QPA plugin for kwin_wayland
From:       Martin_Gräßlin <mgraesslin () kde ! org>
Date:       2015-08-25 12:41:16
Message-ID: E1ZUDXQ-0003D6-Tb () scm ! kde ! org
[Download RAW message or body]

Git commit 26b3569a0b4f5b298141d2b3bb3d9f8a3176eedd by Martin Gräßlin.
Committed on 25/08/2015 at 12:33.
Pushed by graesslin into branch 'master'.

[wayland] Add a QPA plugin for kwin_wayland

This introduces an own QPA plugin for KWin. QtWayland's plugin is not
a good solution for KWin as QtWayland is meant for Wayland clients and
not for a Wayland server. Given that it makes more sense to have a very
minimal QPA plugin which supports the use cases we actually have.

With our own QPA plugin we should be able to improve the following
areas:
* no need to create Wayland server before QApplication
* Qt::BypassWindowManagerHint can be supported
* no workaround for creating OpenGL context in main thread
* sharing OpenGL context with Qt
* OpenGL context for Qt on libhybris backend

The plugin supports so far the following features:
* creating a QPlatformWindow using KWayland::Client (ShellSurface)
* creating a QPlatformBackingStore using a ShmPool
* creating a QPlatformOpenGLContext with Wayland::EGL
* or creating a QPlatformOpenGLContext which shares with KWin's scene
* creating a QPlatformScreen for each KWayland::Client::Output
* QPlatformNativeInterface compatible to QtWayland

M  +15   -0    CMakeLists.txt
A  +50   -0    cmake/modules/FindFontconfig.cmake
A  +121  -0    cmake/modules/FindQt5PlatformSupport.cmake
M  +1    -0    plugins/CMakeLists.txt
A  +32   -0    plugins/qpa/CMakeLists.txt
A  +186  -0    plugins/qpa/abstractplatformcontext.cpp     [License: GPL (v2)]
A  +68   -0    plugins/qpa/abstractplatformcontext.h     [License: GPL (v2)]
A  +116  -0    plugins/qpa/backingstore.cpp     [License: GPL (v2)]
A  +60   -0    plugins/qpa/backingstore.h     [License: GPL (v2)]
A  +256  -0    plugins/qpa/integration.cpp     [License: GPL (v2)]
A  +82   -0    plugins/qpa/integration.h     [License: GPL (v2)]
A  +3    -0    plugins/qpa/kwin.json
A  +47   -0    plugins/qpa/main.cpp     [License: GPL (v2)]
A  +77   -0    plugins/qpa/nativeinterface.cpp     [License: GPL (v2)]
A  +46   -0    plugins/qpa/nativeinterface.h     [License: GPL (v2)]
A  +77   -0    plugins/qpa/platformcontextwayland.cpp     [License: GPL (v2)]
A  +49   -0    plugins/qpa/platformcontextwayland.h     [License: GPL (v2)]
A  +59   -0    plugins/qpa/screen.cpp     [License: GPL (v2)]
A  +56   -0    plugins/qpa/screen.h     [License: GPL (v2)]
A  +92   -0    plugins/qpa/sharingplatformcontext.cpp     [License: GPL (v2)]
A  +51   -0    plugins/qpa/sharingplatformcontext.h     [License: GPL (v2)]
A  +153  -0    plugins/qpa/window.cpp     [License: GPL (v2)]
A  +95   -0    plugins/qpa/window.h     [License: GPL (v2)]

http://commits.kde.org/kwin/26b3569a0b4f5b298141d2b3bb3d9f8a3176eedd

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5687720..7acd53c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -211,6 +211,21 @@ set_package_properties(X11_XCB PROPERTIES
                        PURPOSE "Required for building X11 windowed backend of \
kwin_wayland"  TYPE OPTIONAL)
 
+# dependencies for QPA plugin
+find_package(Qt5PlatformSupport REQUIRED)
+find_package(Freetype REQUIRED)
+set_package_properties(Freetype PROPERTIES DESCRIPTION "A font rendering engine"
+                       URL "http://www.freetype.org"
+                       TYPE REQUIRED
+                       PURPOSE "Needed for KWin's QPA plugin."
+                      )
+find_package(Fontconfig REQUIRED)
+set_package_properties(Fontconfig PROPERTIES DESCRIPTION "Font access configuration \
library" +                       URL \
"http://www.freedesktop.org/wiki/Software/fontconfig" +                       TYPE \
REQUIRED +                       PURPOSE "Needed for KWin's QPA plugin."
+                      )
+
 ########### configure tests ###############
 include(CMakeDependentOption)
 
diff --git a/cmake/modules/FindFontconfig.cmake b/cmake/modules/FindFontconfig.cmake
new file mode 100644
index 0000000..d95e46b
--- /dev/null
+++ b/cmake/modules/FindFontconfig.cmake
@@ -0,0 +1,50 @@
+# - Try to find the  Fontconfig
+# Once done this will define
+#
+#  FONTCONFIG_FOUND - system has Fontconfig
+#  FONTCONFIG_INCLUDE_DIR - The include directory to use for the fontconfig headers
+#  FONTCONFIG_LIBRARIES - Link these to use FONTCONFIG
+#  FONTCONFIG_DEFINITIONS - Compiler switches required for using FONTCONFIG
+
+# Copyright (c) 2006,2007 Laurent Montel, <montel@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+if (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)
+
+  # in cache already
+  set(FONTCONFIG_FOUND TRUE)
+
+else (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)
+
+  if (NOT WIN32)
+    # use pkg-config to get the directories and then use these values
+    # in the FIND_PATH() and FIND_LIBRARY() calls
+    find_package(PkgConfig)
+    pkg_check_modules(PC_FONTCONFIG QUIET fontconfig)
+
+    set(FONTCONFIG_DEFINITIONS ${PC_FONTCONFIG_CFLAGS_OTHER})
+  endif (NOT WIN32)
+
+  find_path(FONTCONFIG_INCLUDE_DIR fontconfig/fontconfig.h
+    PATHS
+    ${PC_FONTCONFIG_INCLUDEDIR}
+    ${PC_FONTCONFIG_INCLUDE_DIRS}
+    /usr/X11/include
+  )
+
+  find_library(FONTCONFIG_LIBRARIES NAMES fontconfig
+    PATHS
+    ${PC_FONTCONFIG_LIBDIR}
+    ${PC_FONTCONFIG_LIBRARY_DIRS}
+  )
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Fontconfig DEFAULT_MSG FONTCONFIG_LIBRARIES \
FONTCONFIG_INCLUDE_DIR ) +
+  mark_as_advanced(FONTCONFIG_LIBRARIES FONTCONFIG_INCLUDE_DIR)
+
+endif (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR)
+
diff --git a/cmake/modules/FindQt5PlatformSupport.cmake \
b/cmake/modules/FindQt5PlatformSupport.cmake new file mode 100644
index 0000000..e762596
--- /dev/null
+++ b/cmake/modules/FindQt5PlatformSupport.cmake
@@ -0,0 +1,121 @@
+#.rst:
+# FindQt5PlatformSupport
+# -------
+#
+# Try to find Qt5PlatformSupport on a Unix system.
+#
+# This will define the following variables:
+#
+# ``Qt5PlatformSupport_FOUND``
+#     True if (the requested version of) Qt5PlatformSupport is available
+# ``Qt5PlatformSupport_VERSION``
+#     The version of Qt5PlatformSupport
+# ``Qt5PlatformSupport_LIBRARIES``
+#     This can be passed to target_link_libraries() instead of the \
``Qt5PlatformSupport::Qt5PlatformSupport`` +#     target
+# ``Qt5PlatformSupport_INCLUDE_DIRS``
+#     This should be passed to target_include_directories() if the target is not
+#     used for linking
+# ``Qt5PlatformSupport_DEFINITIONS``
+#     This should be passed to target_compile_options() if the target is not
+#     used for linking
+#
+# If ``Qt5PlatformSupport_FOUND`` is TRUE, it will also define the following \
imported target: +#
+# ``Qt5PlatformSupport::Qt5PlatformSupport``
+#     The Qt5PlatformSupport library
+#
+# In general we recommend using the imported target, as it is easier to use.
+# Bear in mind, however, that if the target is in the link interface of an
+# exported library, it must be made available by the package config file.
+
+#=============================================================================
+# Copyright 2014 Alex Merry <alex.merry@kde.org>
+# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+if(CMAKE_VERSION VERSION_LESS 2.8.12)
+    message(FATAL_ERROR "CMake 2.8.12 is required by FindQt5PlatformSupport.cmake")
+endif()
+if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
+    message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use \
FindQt5PlatformSupport.cmake") +endif()
+
+# Use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+find_package(PkgConfig)
+pkg_check_modules(PKG_Qt5PlatformSupport QUIET Qt5PlatformSupport)
+
+set(Qt5PlatformSupport_DEFINITIONS ${PKG_Qt5PlatformSupport_CFLAGS_OTHER})
+set(Qt5PlatformSupport_VERSION ${PKG_Qt5PlatformSupport_VERSION})
+
+find_path(Qt5PlatformSupport_INCLUDE_DIR
+    NAMES
+        QtPlatformSupport/private/qfontconfigdatabase_p.h
+    HINTS
+        ${PKG_Qt5PlatformSupport_INCLUDE_DIRS}/QtPlatformSupport/${PKG_Qt5PlatformSupport_VERSION}/
 +)
+find_library(Qt5PlatformSupport_LIBRARY
+    NAMES
+        Qt5PlatformSupport
+    HINTS
+        ${PKG_Qt5PlatformSupport_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Qt5PlatformSupport
+    FOUND_VAR
+        Qt5PlatformSupport_FOUND
+    REQUIRED_VARS
+        Qt5PlatformSupport_LIBRARY
+        Qt5PlatformSupport_INCLUDE_DIR
+    VERSION_VAR
+        Qt5PlatformSupport_VERSION
+)
+
+if(Qt5PlatformSupport_FOUND AND NOT TARGET Qt5PlatformSupport::Qt5PlatformSupport)
+    add_library(Qt5PlatformSupport::Qt5PlatformSupport UNKNOWN IMPORTED)
+    set_target_properties(Qt5PlatformSupport::Qt5PlatformSupport PROPERTIES
+        IMPORTED_LOCATION "${Qt5PlatformSupport_LIBRARY}"
+        INTERFACE_COMPILE_OPTIONS "${Qt5PlatformSupport_DEFINITIONS}"
+        INTERFACE_INCLUDE_DIRECTORIES "${Qt5PlatformSupport_INCLUDE_DIR}"
+    )
+endif()
+
+mark_as_advanced(Qt5PlatformSupport_LIBRARY Qt5PlatformSupport_INCLUDE_DIR)
+
+# compatibility variables
+set(Qt5PlatformSupport_LIBRARIES ${Qt5PlatformSupport_LIBRARY})
+set(Qt5PlatformSupport_INCLUDE_DIRS ${Qt5PlatformSupport_INCLUDE_DIR})
+set(Qt5PlatformSupport_VERSION_STRING ${Qt5PlatformSupport_VERSION})
+
+
+include(FeatureSummary)
+set_package_properties(Qt5PlatformSupport PROPERTIES
+    URL "http://www.qt.io"
+    DESCRIPTION "Qt PlatformSupport module."
+)
+
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 2ed788e..74fc189 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(kglobalaccel)
+add_subdirectory(qpa)
diff --git a/plugins/qpa/CMakeLists.txt b/plugins/qpa/CMakeLists.txt
new file mode 100644
index 0000000..296aa47
--- /dev/null
+++ b/plugins/qpa/CMakeLists.txt
@@ -0,0 +1,32 @@
+include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS})
+include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
+add_definitions(-DQ_FONTCONFIGDATABASE)
+
+set(QPA_SOURCES
+    abstractplatformcontext.cpp
+    backingstore.cpp
+    integration.cpp
+    main.cpp
+    nativeinterface.cpp
+    platformcontextwayland.cpp
+    screen.cpp
+    sharingplatformcontext.cpp
+    window.cpp
+)
+
+add_library(KWinQpaPlugin MODULE ${QPA_SOURCES})
+target_link_libraries(KWinQpaPlugin
+    kwin
+    KF5::WaylandClient
+    Wayland::Egl
+    Qt5PlatformSupport::Qt5PlatformSupport
+    ${FONTCONFIG_LIBRARIES}
+    ${FREETYPE_LIBRARIES}
+)
+
+install(
+    TARGETS
+        KWinQpaPlugin
+    DESTINATION
+        ${PLUGIN_INSTALL_DIR}/platforms/
+)
diff --git a/plugins/qpa/abstractplatformcontext.cpp \
b/plugins/qpa/abstractplatformcontext.cpp new file mode 100644
index 0000000..386edea
--- /dev/null
+++ b/plugins/qpa/abstractplatformcontext.cpp
@@ -0,0 +1,186 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "abstractplatformcontext.h"
+#include "integration.h"
+
+namespace KWin
+{
+
+namespace QPA
+{
+
+static EGLConfig configFromGLFormat(EGLDisplay dpy, const QSurfaceFormat &format)
+{
+#define SIZE( __buffer__ ) format.__buffer__##BufferSize() > 0 ? \
format.__buffer__##BufferSize() : 0 +    // not setting samples as QtQuick doesn't \
need it +    const EGLint config_attribs[] = {
+        EGL_SURFACE_TYPE,         EGL_WINDOW_BIT,
+        EGL_RED_SIZE,             SIZE(red),
+        EGL_GREEN_SIZE,           SIZE(green),
+        EGL_BLUE_SIZE,            SIZE(blue),
+        EGL_ALPHA_SIZE,           SIZE(alpha),
+        EGL_DEPTH_SIZE,           SIZE(depth),
+        EGL_STENCIL_SIZE,         SIZE(stencil),
+#ifdef KWIN_HAVE_OPENGLES
+        EGL_RENDERABLE_TYPE,      EGL_OPENGL_ES2_BIT,
+#else
+        EGL_RENDERABLE_TYPE,      EGL_OPENGL_BIT,
+#endif
+        EGL_NONE,
+    };
+#undef SIZE
+
+    EGLint count;
+    EGLConfig configs[1024];
+    if (eglChooseConfig(dpy, config_attribs, configs, 1, &count) == EGL_FALSE) {
+        return 0;
+    }
+    if (count != 1) {
+        return 0;
+    }
+    return configs[0];
+}
+
+static QSurfaceFormat formatFromConfig(EGLDisplay dpy, EGLConfig config)
+{
+    QSurfaceFormat format;
+    EGLint value = 0;
+#define HELPER(__egl__, __qt__) \
+    eglGetConfigAttrib(dpy, config, EGL_##__egl__, &value); \
+    format.set##__qt__(value); \
+    value = 0;
+
+#define BUFFER_HELPER(__eglColor__, __color__) \
+    HELPER(__eglColor__##_SIZE, __color__##BufferSize)
+
+    BUFFER_HELPER(RED, Red)
+    BUFFER_HELPER(GREEN, Green)
+    BUFFER_HELPER(BLUE, Blue)
+    BUFFER_HELPER(ALPHA, Alpha)
+    BUFFER_HELPER(STENCIL, Stencil)
+    BUFFER_HELPER(DEPTH, Depth)
+#undef BUFFER_HELPER
+    HELPER(SAMPLES, Samples)
+#undef HELPER
+#ifdef KWIN_HAVE_OPENGLES
+    format.setRenderableType(QSurfaceFormat::OpenGLES);
+#else
+    format.setRenderableType(QSurfaceFormat::OpenGL);
+#endif
+    format.setStereo(false);
+
+    return format;
+}
+
+AbstractPlatformContext::AbstractPlatformContext(QOpenGLContext *context, \
Integration *integration, EGLDisplay display) +    : QPlatformOpenGLContext()
+    , m_integration(integration)
+    , m_eglDisplay(display)
+    , m_config(configFromGLFormat(m_eglDisplay, context->format()))
+    , m_format(formatFromConfig(m_eglDisplay, m_config))
+{
+}
+
+AbstractPlatformContext::~AbstractPlatformContext()
+{
+    if (m_context != EGL_NO_CONTEXT) {
+        eglDestroyContext(m_eglDisplay, m_context);
+    }
+}
+
+void AbstractPlatformContext::doneCurrent()
+{
+    eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+QSurfaceFormat AbstractPlatformContext::format() const
+{
+    return m_format;
+}
+
+QFunctionPointer AbstractPlatformContext::getProcAddress(const QByteArray &procName)
+{
+    return eglGetProcAddress(procName.constData());
+}
+
+bool AbstractPlatformContext::isValid() const
+{
+    return m_context != EGL_NO_CONTEXT;
+}
+
+bool AbstractPlatformContext::bindApi()
+{
+#ifdef KWIN_HAVE_OPENGLES
+    if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
+        return false;
+    }
+#else
+    if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
+        return false;
+    }
+#endif
+    return true;
+}
+
+void AbstractPlatformContext::createContext(EGLContext shareContext)
+{
+    EGLContext context = EGL_NO_CONTEXT;
+#ifdef KWIN_HAVE_OPENGLES
+    const EGLint context_attribs[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    context = eglCreateContext(eglDisplay(), config(), shareContext, \
context_attribs); +#else
+    const EGLint context_attribs_31_core[] = {
+        EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(),
+        EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(),
+        EGL_CONTEXT_FLAGS_KHR,         \
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, +        \
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() == \
QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : \
EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, +        EGL_NONE
+    };
+
+    const EGLint context_attribs_legacy[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    const char* eglExtensionsCString = eglQueryString(eglDisplay(), EGL_EXTENSIONS);
+    const QList<QByteArray> extensions = \
QByteArray::fromRawData(eglExtensionsCString, qstrlen(eglExtensionsCString)).split(' \
'); +
+    // Try to create a 3.1 core context
+    if (m_format.majorVersion() >= 3 &&  \
extensions.contains(QByteArrayLiteral("EGL_KHR_create_context"))) { +        context \
= eglCreateContext(eglDisplay(), config(), shareContext, context_attribs_31_core); +  \
} +
+    if (context == EGL_NO_CONTEXT) {
+        context = eglCreateContext(eglDisplay(), config(), shareContext, \
context_attribs_legacy); +    }
+#endif
+
+    if (context == EGL_NO_CONTEXT) {
+        return;
+    }
+    m_context = context;
+}
+
+}
+}
diff --git a/plugins/qpa/abstractplatformcontext.h \
b/plugins/qpa/abstractplatformcontext.h new file mode 100644
index 0000000..0eb474e
--- /dev/null
+++ b/plugins/qpa/abstractplatformcontext.h
@@ -0,0 +1,68 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H
+#define KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H
+
+#include <epoxy/egl.h>
+#include <fixx11h.h>
+#include <qpa/qplatformopenglcontext.h>
+
+namespace KWin
+{
+namespace QPA
+{
+class Integration;
+
+class AbstractPlatformContext : public QPlatformOpenGLContext
+{
+public:
+    explicit AbstractPlatformContext(QOpenGLContext *context, Integration \
*integration, EGLDisplay display); +    virtual ~AbstractPlatformContext();
+
+    void doneCurrent() override;
+    QSurfaceFormat format() const override;
+    bool isValid() const override;
+    QFunctionPointer getProcAddress(const QByteArray &procName) override;
+
+protected:
+    EGLDisplay eglDisplay() const {
+        return m_eglDisplay;
+    }
+    EGLConfig config() const {
+        return m_config;
+    }
+    bool bindApi();
+    EGLContext context() const {
+        return m_context;
+    }
+    void createContext(EGLContext shareContext = EGL_NO_CONTEXT);
+
+private:
+    Integration *m_integration;
+    EGLDisplay m_eglDisplay;
+    EGLConfig m_config;
+    EGLContext m_context = EGL_NO_CONTEXT;
+    QSurfaceFormat m_format;
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/backingstore.cpp b/plugins/qpa/backingstore.cpp
new file mode 100644
index 0000000..78160f0
--- /dev/null
+++ b/plugins/qpa/backingstore.cpp
@@ -0,0 +1,116 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "window.h"
+#include "backingstore.h"
+#include "../../wayland_server.h"
+
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/buffer.h>
+#include <KWayland/Client/shm_pool.h>
+#include <KWayland/Client/surface.h>
+
+namespace KWin
+{
+namespace QPA
+{
+
+BackingStore::BackingStore(QWindow *w, KWayland::Client::ShmPool *shm)
+    : QPlatformBackingStore(w)
+    , m_shm(shm)
+    , m_backBuffer(QSize(), QImage::Format_ARGB32_Premultiplied)
+{
+    QObject::connect(m_shm, &KWayland::Client::ShmPool::poolResized,
+        [this] {
+            if (!m_buffer) {
+                return;
+            }
+            auto b = m_buffer.toStrongRef();
+            if (!b->isUsed()){
+                return;
+            }
+            const QSize size = m_backBuffer.size();
+            m_backBuffer = QImage(b->address(), size.width(), size.height(), \
QImage::Format_ARGB32_Premultiplied); +        }
+    );
+}
+
+BackingStore::~BackingStore() = default;
+
+QPaintDevice *BackingStore::paintDevice()
+{
+    return &m_backBuffer;
+}
+
+void BackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+    Q_UNUSED(staticContents)
+    m_size = size;
+    if (!m_buffer) {
+        return;
+    }
+    m_buffer.toStrongRef()->setUsed(false);
+    m_buffer.clear();
+}
+
+void BackingStore::flush(QWindow *window, const QRegion &region, const QPoint \
&offset) +{
+    Q_UNUSED(region)
+    Q_UNUSED(offset)
+    auto s = static_cast<Window *>(window->handle())->surface();
+    s->attachBuffer(m_buffer);
+    // TODO: proper damage region
+    s->damage(QRect(QPoint(0, 0), m_backBuffer.size()));
+    s->commit(KWayland::Client::Surface::CommitFlag::None);
+    waylandServer()->internalClientConection()->flush();
+    waylandServer()->dispatch();
+}
+
+void BackingStore::beginPaint(const QRegion&)
+{
+    if (m_buffer) {
+        auto b = m_buffer.toStrongRef();
+        if (b->isReleased()) {
+            // we can re-use this buffer
+            b->setReleased(false);
+            return;
+        } else {
+            // buffer is still in use, get a new one
+            b->setUsed(false);
+        }
+    }
+    auto oldBuffer = m_buffer.toStrongRef();
+    m_buffer.clear();
+    m_buffer = m_shm->getBuffer(m_size, m_size.width() * 4);
+    if (!m_buffer) {
+        m_backBuffer = QImage();
+        return;
+    }
+    auto b = m_buffer.toStrongRef();
+    b->setUsed(true);
+    m_backBuffer = QImage(b->address(), m_size.width(), m_size.height(), \
QImage::Format_ARGB32_Premultiplied); +    if (oldBuffer) {
+        b->copy(oldBuffer->address());
+    } else {
+        m_backBuffer.fill(Qt::transparent);
+    }
+}
+
+}
+}
diff --git a/plugins/qpa/backingstore.h b/plugins/qpa/backingstore.h
new file mode 100644
index 0000000..0e00de6
--- /dev/null
+++ b/plugins/qpa/backingstore.h
@@ -0,0 +1,60 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_BACKINGSTORE_H
+#define KWIN_QPA_BACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+
+namespace KWayland
+{
+namespace Client
+{
+class Buffer;
+class ShmPool;
+}
+}
+
+namespace KWin
+{
+namespace QPA
+{
+
+class BackingStore : public QPlatformBackingStore
+{
+public:
+    explicit BackingStore(QWindow *w, KWayland::Client::ShmPool *shm);
+    virtual ~BackingStore();
+
+    QPaintDevice *paintDevice() override;
+    void flush(QWindow *window, const QRegion &region, const QPoint &offset) \
override; +    void resize(const QSize &size, const QRegion &staticContents) \
override; +    void beginPaint(const QRegion &) override;
+
+private:
+    KWayland::Client::ShmPool *m_shm;
+    QWeakPointer<KWayland::Client::Buffer> m_buffer;
+    QImage m_backBuffer;
+    QSize m_size;
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/integration.cpp b/plugins/qpa/integration.cpp
new file mode 100644
index 0000000..41b7733
--- /dev/null
+++ b/plugins/qpa/integration.cpp
@@ -0,0 +1,256 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#define WL_EGL_PLATFORM 1
+#include "integration.h"
+#include "abstract_backend.h"
+#include "backingstore.h"
+#include "nativeinterface.h"
+#include "platformcontextwayland.h"
+#include "screen.h"
+#include "sharingplatformcontext.h"
+#include "window.h"
+#include "../../main.h"
+#include "../../wayland_server.h"
+
+#include <KWayland/Client/compositor.h>
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/output.h>
+#include <KWayland/Client/registry.h>
+#include <KWayland/Client/shell.h>
+#include <KWayland/Server/clientconnection.h>
+
+#include <QCoreApplication>
+#include <QtConcurrentRun>
+
+#include <qpa/qplatformwindow.h>
+#include <QtCore/private/qeventdispatcher_unix_p.h>
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#include <QtPlatformSupport/private/qgenericunixthemes_p.h>
+
+namespace KWin
+{
+
+namespace QPA
+{
+
+Integration::Integration()
+    : QObject()
+    , QPlatformIntegration()
+    , m_fontDb(new QGenericUnixFontDatabase())
+    , m_nativeInterface(new NativeInterface(this))
+{
+}
+
+Integration::~Integration() = default;
+
+bool Integration::hasCapability(Capability cap) const
+{
+    switch (cap) {
+    case ThreadedPixmaps:
+        return true;
+    case OpenGL:
+        return true;
+    case ThreadedOpenGL:
+        return false;
+    case BufferQueueingOpenGL:
+        return false;
+    case MultipleWindows:
+    case NonFullScreenWindows:
+        return true;
+    case RasterGLSurface:
+        return false;
+    default:
+        return QPlatformIntegration::hasCapability(cap);
+    }
+}
+
+void Integration::initialize()
+{
+    // TODO: start initialize Wayland once the internal Wayland connection is \
created +    connect(kwinApp(), &Application::screensCreated, this, \
&Integration::initializeWayland, Qt::QueuedConnection); +    \
QPlatformIntegration::initialize(); +}
+
+QAbstractEventDispatcher *Integration::createEventDispatcher() const
+{
+    // TODO: add our own event dispatcher
+    return new QEventDispatcherUNIX;
+}
+
+QPlatformBackingStore *Integration::createPlatformBackingStore(QWindow *window) \
const +{
+    auto registry = waylandServer()->internalClientRegistry();
+    const auto shm = \
registry->interface(KWayland::Client::Registry::Interface::Shm); +    if (shm.name == \
0u) { +        return nullptr;
+    }
+    return new BackingStore(window, registry->createShmPool(shm.name, shm.version, \
window)); +}
+
+QPlatformWindow *Integration::createPlatformWindow(QWindow *window) const
+{
+    auto c = compositor();
+    auto s = shell();
+    if (!s || !c) {
+        return new QPlatformWindow(window);
+    } else {
+        // don't set window as parent, cause infinite recursion in \
PlasmaQuick::Dialog +        auto surface = c->createSurface();
+        return new Window(window, surface, s->createSurface(surface), this);
+    }
+}
+
+QPlatformFontDatabase *Integration::fontDatabase() const
+{
+    return m_fontDb;
+}
+
+QPlatformTheme *Integration::createPlatformTheme(const QString &name) const
+{
+    return QGenericUnixTheme::createUnixTheme(name);
+}
+
+QStringList Integration::themeNames() const
+{
+    if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
+        return QStringList({QStringLiteral("kde")});
+    }
+    return QStringList({QLatin1String(QGenericUnixTheme::name)});
+}
+
+QPlatformNativeInterface *Integration::nativeInterface() const
+{
+    return m_nativeInterface;
+}
+
+QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext \
*context) const +{
+    if (waylandServer()->backend()->supportsQpaContext()) {
+        return new SharingPlatformContext(context, const_cast<Integration*>(this));
+    }
+    if (m_eglDisplay == EGL_NO_DISPLAY) {
+        const_cast<Integration*>(this)->initEgl();
+    }
+    if (m_eglDisplay == EGL_NO_DISPLAY) {
+        return nullptr;
+    }
+    return new PlatformContextWayland(context, const_cast<Integration*>(this));
+}
+
+void Integration::initializeWayland()
+{
+    if (m_registry) {
+        return;
+    }
+    using namespace KWayland::Client;
+    auto setupRegistry = [this] {
+        m_registry = waylandServer()->internalClientRegistry();
+        connect(m_registry, &Registry::outputAnnounced, this, \
&Integration::createWaylandOutput); +        const auto outputs = \
m_registry->interfaces(Registry::Interface::Output); +        for (const auto &o : \
outputs) { +            createWaylandOutput(o.name, o.version);
+        }
+    };
+    if (waylandServer()->internalClientRegistry()) {
+        setupRegistry();
+    } else {
+        connect(waylandServer()->internalClientConection(), \
&ConnectionThread::connected, this, setupRegistry, Qt::QueuedConnection); +    }
+}
+
+void Integration::createWaylandOutput(quint32 name, quint32 version)
+{
+    using namespace KWayland::Client;
+    auto o = m_registry->createOutput(name, version, this);
+    connect(o, &Output::changed, this,
+        [this, o] {
+            disconnect(o, &Output::changed, nullptr, nullptr);
+            // TODO: handle screen removal
+            screenAdded(new Screen(o));
+        }
+    );
+    waylandServer()->internalClientConection()->flush();
+}
+
+KWayland::Client::Compositor *Integration::compositor() const
+{
+    if (!m_compositor) {
+        using namespace KWayland::Client;
+        auto registry = waylandServer()->internalClientRegistry();
+        const auto c = registry->interface(Registry::Interface::Compositor);
+        if (c.name != 0u) {
+            const_cast<Integration*>(this)->m_compositor = \
registry->createCompositor(c.name, c.version); +        }
+    }
+    return m_compositor;
+}
+
+KWayland::Client::Shell *Integration::shell() const
+{
+    if (!m_shell) {
+        using namespace KWayland::Client;
+        auto registry = waylandServer()->internalClientRegistry();
+        const auto s = registry->interface(Registry::Interface::Shell);
+        if (s.name != 0u) {
+            const_cast<Integration*>(this)->m_shell = registry->createShell(s.name, \
s.version); +        }
+    }
+    return m_shell;
+}
+
+EGLDisplay Integration::eglDisplay() const
+{
+    return m_eglDisplay;
+}
+
+void Integration::initEgl()
+{
+    Q_ASSERT(m_eglDisplay == EGL_NO_DISPLAY);
+    // This variant uses Wayland as the EGL platform
+    qputenv("EGL_PLATFORM", "wayland");
+    m_eglDisplay = eglGetDisplay(waylandServer()->internalClientConection()->display());
 +    if (m_eglDisplay == EGL_NO_DISPLAY) {
+        return;
+    }
+    // call eglInitialize in a thread to not block
+    QFuture<bool> future = QtConcurrent::run([this] () -> bool {
+        EGLint major, minor;
+        if (eglInitialize(m_eglDisplay, &major, &minor) == EGL_FALSE) {
+            return false;
+        }
+        EGLint error = eglGetError();
+        if (error != EGL_SUCCESS) {
+            return false;
+        }
+        return true;
+    });
+    // TODO: make this better
+    while (!future.isFinished()) {
+        waylandServer()->internalClientConection()->flush();
+        QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
+    }
+    if (!future.result()) {
+        eglTerminate(m_eglDisplay);
+        m_eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+}
+}
diff --git a/plugins/qpa/integration.h b/plugins/qpa/integration.h
new file mode 100644
index 0000000..6bf6b22
--- /dev/null
+++ b/plugins/qpa/integration.h
@@ -0,0 +1,82 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_INTEGRATION_H
+#define KWIN_QPA_INTEGRATION_H
+
+#include <epoxy/egl.h>
+#include <fixx11h.h>
+#include <qpa/qplatformintegration.h>
+#include <QObject>
+
+namespace KWayland
+{
+namespace Client
+{
+class Registry;
+class Compositor;
+class Shell;
+}
+}
+
+namespace KWin
+{
+namespace QPA
+{
+
+class Integration : public QObject, public QPlatformIntegration
+{
+    Q_OBJECT
+public:
+    explicit Integration();
+    virtual ~Integration();
+
+    bool hasCapability(Capability cap) const override;
+    QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+    QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const \
override; +    QAbstractEventDispatcher *createEventDispatcher() const override;
+    QPlatformFontDatabase *fontDatabase() const override;
+    QStringList themeNames() const override;
+    QPlatformTheme *createPlatformTheme(const QString &name) const override;
+    QPlatformNativeInterface *nativeInterface() const override;
+    QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) \
const override; +
+    void initialize() override;
+
+    KWayland::Client::Compositor *compositor() const;
+    EGLDisplay eglDisplay() const;
+
+private:
+    void initializeWayland();
+    void createWaylandOutput(quint32 name, quint32 version);
+    void initEgl();
+    KWayland::Client::Shell *shell() const;
+
+    QPlatformFontDatabase *m_fontDb;
+    QPlatformNativeInterface *m_nativeInterface;
+    KWayland::Client::Registry *m_registry = nullptr;
+    KWayland::Client::Compositor *m_compositor = nullptr;
+    KWayland::Client::Shell *m_shell = nullptr;
+    EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/kwin.json b/plugins/qpa/kwin.json
new file mode 100644
index 0000000..d820f2a
--- /dev/null
+++ b/plugins/qpa/kwin.json
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "wayland-org.kde.kwin.qpa" ]
+}
diff --git a/plugins/qpa/main.cpp b/plugins/qpa/main.cpp
new file mode 100644
index 0000000..970d71f
--- /dev/null
+++ b/plugins/qpa/main.cpp
@@ -0,0 +1,47 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "integration.h"
+#include <qpa/qplatformintegrationplugin.h>
+
+#include <QCoreApplication>
+
+class KWinIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID \
"org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "kwin.json") \
+public: +    QPlatformIntegration *create(const QString &system, const QStringList \
&paramList) override; +};
+
+QPlatformIntegration *KWinIntegrationPlugin::create(const QString &system, const \
QStringList &paramList) +{
+    Q_UNUSED(paramList)
+    if (!QCoreApplication::applicationFilePath().endsWith(QLatin1Literal("kwin_wayland"))) \
{ +        // Not KWin
+        return nullptr;
+    }
+    if (system.compare(QLatin1String("wayland-org.kde.kwin.qpa"), \
Qt::CaseInsensitive) == 0) { +        // create our integration
+        return new KWin::QPA::Integration;
+    }
+    return nullptr;
+}
+
+#include "main.moc"
diff --git a/plugins/qpa/nativeinterface.cpp b/plugins/qpa/nativeinterface.cpp
new file mode 100644
index 0000000..1895725
--- /dev/null
+++ b/plugins/qpa/nativeinterface.cpp
@@ -0,0 +1,77 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "nativeinterface.h"
+#include "integration.h"
+#include "window.h"
+#include "../../wayland_server.h"
+
+#include <QWindow>
+
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/compositor.h>
+#include <KWayland/Client/surface.h>
+
+namespace KWin
+{
+namespace QPA
+{
+
+static const QByteArray s_displayKey = QByteArrayLiteral("display");
+static const QByteArray s_wlDisplayKey = QByteArrayLiteral("wl_display");
+static const QByteArray s_compositorKey = QByteArrayLiteral("compositor");
+static const QByteArray s_surfaceKey = QByteArrayLiteral("surface");
+
+NativeInterface::NativeInterface(Integration *integration)
+    : QPlatformNativeInterface()
+    , m_integration(integration)
+{
+}
+
+void *NativeInterface::nativeResourceForIntegration(const QByteArray &resource)
+{
+    const QByteArray r = resource.toLower();
+    if (r == s_displayKey || r == s_wlDisplayKey) {
+        return waylandServer()->internalClientConection()->display();
+    }
+    if (r == s_compositorKey) {
+        return static_cast<wl_compositor*>(*m_integration->compositor());
+    }
+    return nullptr;
+}
+
+void *NativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow \
*window) +{
+    const QByteArray r = resource.toLower();
+    if (r == s_displayKey || r == s_wlDisplayKey) {
+        return waylandServer()->internalClientConection()->display();
+    }
+    if (r == s_compositorKey) {
+        return static_cast<wl_compositor*>(*m_integration->compositor());
+    }
+    if (r == s_surfaceKey && window) {
+        if (auto handle = window->handle()) {
+            return static_cast<wl_surface*>(*static_cast<Window*>(handle)->surface());
 +        }
+    }
+    return nullptr;
+}
+
+}
+}
diff --git a/plugins/qpa/nativeinterface.h b/plugins/qpa/nativeinterface.h
new file mode 100644
index 0000000..b36ee1b
--- /dev/null
+++ b/plugins/qpa/nativeinterface.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_NATIVEINTERFACE_H
+#define KWIN_QPA_NATIVEINTERFACE_H
+
+#include <qpa/qplatformnativeinterface.h>
+
+namespace KWin
+{
+namespace QPA
+{
+
+class Integration;
+
+class NativeInterface : public QPlatformNativeInterface
+{
+public:
+    explicit NativeInterface(Integration *integration);
+    void *nativeResourceForIntegration(const QByteArray &resource) override;
+    void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) \
override; +
+private:
+    Integration *m_integration;
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/platformcontextwayland.cpp \
b/plugins/qpa/platformcontextwayland.cpp new file mode 100644
index 0000000..aacad70
--- /dev/null
+++ b/plugins/qpa/platformcontextwayland.cpp
@@ -0,0 +1,77 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "platformcontextwayland.h"
+#include "integration.h"
+#include "window.h"
+
+namespace KWin
+{
+
+namespace QPA
+{
+
+PlatformContextWayland::PlatformContextWayland(QOpenGLContext *context, Integration \
*integration) +    : AbstractPlatformContext(context, integration, \
integration->eglDisplay()) +{
+    create();
+}
+
+bool PlatformContextWayland::makeCurrent(QPlatformSurface *surface)
+{
+    Window *window = static_cast<Window*>(surface);
+    EGLSurface s = window->eglSurface();
+    if (s == EGL_NO_SURFACE) {
+        window->createEglSurface(eglDisplay(), config());
+        s = window->eglSurface();
+        if (s == EGL_NO_SURFACE) {
+            return false;
+        }
+    }
+    return eglMakeCurrent(eglDisplay(), s, s, context());
+}
+
+bool PlatformContextWayland::isSharing() const
+{
+    return false;
+}
+
+void PlatformContextWayland::swapBuffers(QPlatformSurface *surface)
+{
+    Window *window = static_cast<Window*>(surface);
+    EGLSurface s = window->eglSurface();
+    if (s == EGL_NO_SURFACE) {
+        return;
+    }
+    eglSwapBuffers(eglDisplay(), s);
+}
+
+void PlatformContextWayland::create()
+{
+    if (config() == 0) {
+        return;
+    }
+    if (!bindApi()) {
+        return;
+    }
+    createContext();
+}
+
+}
+}
diff --git a/plugins/qpa/platformcontextwayland.h \
b/plugins/qpa/platformcontextwayland.h new file mode 100644
index 0000000..fbf7c21
--- /dev/null
+++ b/plugins/qpa/platformcontextwayland.h
@@ -0,0 +1,49 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_PLATFORMCONTEXTWAYLAND_H
+#define KWIN_QPA_PLATFORMCONTEXTWAYLAND_H
+
+#include "abstractplatformcontext.h"
+
+namespace KWin
+{
+namespace QPA
+{
+class Integration;
+
+class PlatformContextWayland : public AbstractPlatformContext
+{
+public:
+    explicit PlatformContextWayland(QOpenGLContext *context, Integration \
*integration); +
+    void swapBuffers(QPlatformSurface *surface) override;
+
+    bool makeCurrent(QPlatformSurface *surface) override;
+
+    bool isSharing() const override;
+
+private:
+    void create();
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/screen.cpp b/plugins/qpa/screen.cpp
new file mode 100644
index 0000000..1c33a84
--- /dev/null
+++ b/plugins/qpa/screen.cpp
@@ -0,0 +1,59 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "screen.h"
+
+#include <KWayland/Client/output.h>
+
+namespace KWin
+{
+namespace QPA
+{
+
+Screen::Screen(KWayland::Client::Output *o)
+    : QPlatformScreen()
+    , m_output(o)
+{
+    // TODO: connect to resolution changes
+}
+
+Screen::~Screen() = default;
+
+int Screen::depth() const
+{
+    return 32;
+}
+
+QImage::Format Screen::format() const
+{
+    return QImage::Format_ARGB32_Premultiplied;
+}
+
+QRect Screen::geometry() const
+{
+    return m_output->geometry();
+}
+
+QSizeF Screen::physicalSize() const
+{
+    return m_output->physicalSize();
+}
+
+}
+}
diff --git a/plugins/qpa/screen.h b/plugins/qpa/screen.h
new file mode 100644
index 0000000..5d445b7
--- /dev/null
+++ b/plugins/qpa/screen.h
@@ -0,0 +1,56 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_SCREEN_H
+#define KWIN_QPA_SCREEN_H
+
+#include <qpa/qplatformscreen.h>
+
+namespace KWayland
+{
+namespace Client
+{
+class Output;
+}
+}
+
+namespace KWin
+{
+namespace QPA
+{
+
+class Screen : public QPlatformScreen
+{
+public:
+    explicit Screen(KWayland::Client::Output *o);
+    virtual ~Screen();
+
+    QRect geometry() const override;
+    int depth() const override;
+    QImage::Format format() const override;
+    QSizeF physicalSize() const override;
+
+private:
+    KWayland::Client::Output *m_output;
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/sharingplatformcontext.cpp \
b/plugins/qpa/sharingplatformcontext.cpp new file mode 100644
index 0000000..4531499
--- /dev/null
+++ b/plugins/qpa/sharingplatformcontext.cpp
@@ -0,0 +1,92 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "sharingplatformcontext.h"
+#include "integration.h"
+#include "window.h"
+#include "../../abstract_backend.h"
+#include "../../wayland_server.h"
+#include "../../shell_client.h"
+
+#include <QOpenGLFramebufferObject>
+
+namespace KWin
+{
+
+namespace QPA
+{
+
+SharingPlatformContext::SharingPlatformContext(QOpenGLContext *context, Integration \
*integration) +    : AbstractPlatformContext(context, integration, \
waylandServer()->backend()->sceneEglDisplay()) +{
+    create();
+}
+
+bool SharingPlatformContext::makeCurrent(QPlatformSurface *surface)
+{
+    Window *window = static_cast<Window*>(surface);
+    if (eglMakeCurrent(eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, context())) {
+        window->bindContentFBO();
+        return true;
+    }
+    return false;
+}
+
+bool SharingPlatformContext::isSharing() const
+{
+    return false;
+}
+
+void SharingPlatformContext::swapBuffers(QPlatformSurface *surface)
+{
+    Window *window = static_cast<Window*>(surface);
+    auto c = window->shellClient();
+    if (!c) {
+        return;
+    }
+    makeCurrent(surface);
+    glFlush();
+    c->setInternalFramebufferObject(window->swapFBO());
+    window->bindContentFBO();
+}
+
+GLuint SharingPlatformContext::defaultFramebufferObject(QPlatformSurface *surface) \
const +{
+    if (Window *window = dynamic_cast<Window*>(surface)) {
+        const auto &fbo = window->contentFBO();
+        if (!fbo.isNull()) {
+            return fbo->handle();
+        }
+    }
+    return 0;
+}
+
+void SharingPlatformContext::create()
+{
+    if (config() == 0) {
+        return;
+    }
+    if (!bindApi()) {
+        return;
+    }
+    createContext(waylandServer()->backend()->sceneEglContext());
+}
+
+}
+}
diff --git a/plugins/qpa/sharingplatformcontext.h \
b/plugins/qpa/sharingplatformcontext.h new file mode 100644
index 0000000..9042d1c
--- /dev/null
+++ b/plugins/qpa/sharingplatformcontext.h
@@ -0,0 +1,51 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_SHARINGPLATFORMCONTEXT_H
+#define KWIN_QPA_SHARINGPLATFORMCONTEXT_H
+
+#include "abstractplatformcontext.h"
+
+namespace KWin
+{
+namespace QPA
+{
+class Integration;
+
+class SharingPlatformContext : public AbstractPlatformContext
+{
+public:
+    explicit SharingPlatformContext(QOpenGLContext *context, Integration \
*integration); +
+    void swapBuffers(QPlatformSurface *surface) override;
+
+    GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
+
+    bool makeCurrent(QPlatformSurface *surface) override;
+
+    bool isSharing() const override;
+
+private:
+    void create();
+};
+
+}
+}
+
+#endif
diff --git a/plugins/qpa/window.cpp b/plugins/qpa/window.cpp
new file mode 100644
index 0000000..5944a4e
--- /dev/null
+++ b/plugins/qpa/window.cpp
@@ -0,0 +1,153 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#define WL_EGL_PLATFORM 1
+#include "integration.h"
+#include "window.h"
+#include "../../shell_client.h"
+#include "../../wayland_server.h"
+
+#include <QOpenGLFramebufferObject>
+
+#include <KWayland/Client/buffer.h>
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/shell.h>
+#include <KWayland/Client/surface.h>
+
+namespace KWin
+{
+namespace QPA
+{
+static quint32 s_windowId = 0;
+
+Window::Window(QWindow *window, KWayland::Client::Surface *surface, \
KWayland::Client::ShellSurface *shellSurface, const Integration *integration) +    : \
QPlatformWindow(window) +    , m_surface(surface)
+    , m_shellSurface(shellSurface)
+    , m_windowId(++s_windowId)
+    , m_integration(integration)
+{
+    waylandServer()->internalClientConection()->flush();
+}
+
+Window::~Window()
+{
+    unmap();
+    if (m_eglSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(m_integration->eglDisplay(), m_eglSurface);
+    }
+    if (m_eglWaylandWindow) {
+        wl_egl_window_destroy(m_eglWaylandWindow);
+    }
+    delete m_shellSurface;
+    delete m_surface;
+    waylandServer()->internalClientConection()->flush();
+}
+
+WId Window::winId() const
+{
+    return m_windowId;
+}
+
+void Window::setVisible(bool visible)
+{
+    if (!visible) {
+        unmap();
+    }
+    QPlatformWindow::setVisible(visible);
+}
+
+void Window::setGeometry(const QRect &rect)
+{
+    const QRect &oldRect = geometry();
+    QPlatformWindow::setGeometry(rect);
+    if (rect.x() != oldRect.x()) {
+        emit window()->xChanged(rect.x());
+    }
+    if (rect.y() != oldRect.y()) {
+        emit window()->yChanged(rect.y());
+    }
+    if (rect.width() != oldRect.width()) {
+        emit window()->widthChanged(rect.width());
+    }
+    if (rect.height() != oldRect.height()) {
+        emit window()->heightChanged(rect.height());
+    }
+    if (m_contentFBO) {
+        if (m_contentFBO->width() != geometry().width() || m_contentFBO->height() != \
geometry().height()) { +            m_resized = true;
+        }
+    }
+    if (m_eglWaylandWindow) {
+        wl_egl_window_resize(m_eglWaylandWindow, geometry().width(), \
geometry().height(), 0, 0); +    }
+}
+
+void Window::unmap()
+{
+    if (m_shellClient) {
+        m_shellClient->setInternalFramebufferObject(QSharedPointer<QOpenGLFramebufferObject>());
 +    }
+    m_surface->attachBuffer(KWayland::Client::Buffer::Ptr());
+    m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
+    waylandServer()->internalClientConection()->flush();
+}
+
+void Window::createEglSurface(EGLDisplay dpy, EGLConfig config)
+{
+    const QSize size = window()->size();
+    m_eglWaylandWindow = wl_egl_window_create(*m_surface, size.width(), \
size.height()); +    if (!m_eglWaylandWindow) {
+        return;
+    }
+    m_eglSurface = eglCreateWindowSurface(dpy, config, m_eglWaylandWindow, nullptr);
+}
+
+void Window::bindContentFBO()
+{
+    if (m_resized || !m_contentFBO) {
+        createFBO();
+    }
+    m_contentFBO->bind();
+}
+
+QSharedPointer<QOpenGLFramebufferObject> Window::swapFBO()
+{
+    auto fbo = m_contentFBO;
+    m_contentFBO.clear();
+    return fbo;
+}
+
+void Window::createFBO()
+{
+    const QRect &r = geometry();
+    m_contentFBO.reset(new QOpenGLFramebufferObject(r.width(), r.height(), \
QOpenGLFramebufferObject::CombinedDepthStencil)); +    m_resized = false;
+}
+
+ShellClient *Window::shellClient()
+{
+    if (!m_shellClient) {
+        m_shellClient = waylandServer()->findClient(window());
+    }
+    return m_shellClient;
+}
+
+}
+}
diff --git a/plugins/qpa/window.h b/plugins/qpa/window.h
new file mode 100644
index 0000000..091b5bd
--- /dev/null
+++ b/plugins/qpa/window.h
@@ -0,0 +1,95 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef KWIN_QPA_WINDOW_H
+#define KWIN_QPA_WINDOW_H
+
+#include <epoxy/egl.h>
+#include <fixx11h.h>
+#include <qpa/qplatformwindow.h>
+// wayland
+#include <wayland-egl.h>
+
+class QOpenGLFramebufferObject;
+
+struct wl_egl_window;
+
+namespace KWayland
+{
+namespace Client
+{
+class Surface;
+class ShellSurface;
+}
+}
+
+namespace KWin
+{
+
+class ShellClient;
+
+namespace QPA
+{
+
+class Integration;
+
+class Window : public QPlatformWindow
+{
+public:
+    explicit Window(QWindow *window, KWayland::Client::Surface *surface, \
KWayland::Client::ShellSurface *shellSurface, const Integration *integration); +    \
virtual ~Window(); +
+    void setVisible(bool visible) override;
+    void setGeometry(const QRect &rect) override;
+    WId winId() const override;
+
+    KWayland::Client::Surface *surface() const {
+        return m_surface;
+    }
+    EGLSurface eglSurface() const {
+        return m_eglSurface;
+    }
+    void createEglSurface(EGLDisplay dpy, EGLConfig config);
+
+    void bindContentFBO();
+    const QSharedPointer<QOpenGLFramebufferObject> &contentFBO() const {
+        return m_contentFBO;
+    }
+    QSharedPointer<QOpenGLFramebufferObject> swapFBO();
+    ShellClient *shellClient();
+
+private:
+    void unmap();
+    void createFBO();
+
+    KWayland::Client::Surface *m_surface;
+    KWayland::Client::ShellSurface *m_shellSurface;
+    EGLSurface m_eglSurface = EGL_NO_SURFACE;
+    QSharedPointer<QOpenGLFramebufferObject> m_contentFBO;
+    bool m_resized = false;
+    ShellClient *m_shellClient = nullptr;
+    wl_egl_window *m_eglWaylandWindow = nullptr;
+    quint32 m_windowId;
+    const Integration *m_integration;
+};
+
+}
+}
+
+#endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic