[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 ®ion, 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 ®ion, 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 \
¶mList) override; +};
+
+QPlatformIntegration *KWinIntegrationPlugin::create(const QString &system, \
const QStringList ¶mList) +{
+ 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