[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
This commit is contained in:
Martin Gräßlin 2015-08-14 16:52:40 +02:00
parent 79317717c8
commit 26b3569a0b
23 changed files with 1792 additions and 0 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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."
)

View file

@ -1 +1,2 @@
add_subdirectory(kglobalaccel)
add_subdirectory(qpa)

View file

@ -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/
)

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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);
}
}
}
}

View file

@ -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

256
plugins/qpa/integration.cpp Normal file
View file

@ -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;
}
}
}
}

82
plugins/qpa/integration.h Normal file
View file

@ -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

3
plugins/qpa/kwin.json Normal file
View file

@ -0,0 +1,3 @@
{
"Keys": [ "wayland-org.kde.kwin.qpa" ]
}

47
plugins/qpa/main.cpp Normal file
View file

@ -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"

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -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

59
plugins/qpa/screen.cpp Normal file
View file

@ -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();
}
}
}

56
plugins/qpa/screen.h Normal file
View file

@ -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

View file

@ -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());
}
}
}

View file

@ -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

153
plugins/qpa/window.cpp Normal file
View file

@ -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;
}
}
}

95
plugins/qpa/window.h Normal file
View file

@ -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