Git commit 26b3569a0b4f5b298141d2b3bb3d9f8a3176eedd by Martin Gr=C3=A4=C3= =9Flin. 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 (v= 2)] 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 e= ngine" + 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 conf= iguration library" + URL "http://www.freedesktop.org/wiki/Software/fontc= onfig" + TYPE REQUIRED + PURPOSE "Needed for KWin's QPA plugin." + ) + ########### configure tests ############### include(CMakeDependentOption) = diff --git a/cmake/modules/FindFontconfig.cmake b/cmake/modules/FindFontcon= fig.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 fontconfi= g headers +# FONTCONFIG_LIBRARIES - Link these to use FONTCONFIG +# FONTCONFIG_DEFINITIONS - Compiler switches required for using FONTCONFIG + +# Copyright (c) 2006,2007 Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD lice= nse. +# 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_LIBR= ARIES 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/Fin= dQt5PlatformSupport.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 ``Qt5Pl= atformSupport::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 n= ot +# used for linking +# +# If ``Qt5PlatformSupport_FOUND`` is TRUE, it will also define the followi= ng imported target: +# +# ``Qt5PlatformSupport::Qt5PlatformSupport`` +# The Qt5PlatformSupport library +# +# In general we recommend using the imported target, as it is easier to us= e. +# 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. + +#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D +# Copyright 2014 Alex Merry +# Copyright 2014 Martin Gr=C3=A4=C3=9Flin +# +# 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. +#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "CMake 2.8.12 is required by FindQt5PlatformSuppor= t.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_Qt5= PlatformSupport_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::Qt5Platform= Support) + 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/abstract= platformcontext.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#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[] =3D { + 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) =3D=3D EG= L_FALSE) { + return 0; + } + if (count !=3D 1) { + return 0; + } + return configs[0]; +} + +static QSurfaceFormat formatFromConfig(EGLDisplay dpy, EGLConfig config) +{ + QSurfaceFormat format; + EGLint value =3D 0; +#define HELPER(__egl__, __qt__) \ + eglGetConfigAttrib(dpy, config, EGL_##__egl__, &value); \ + format.set##__qt__(value); \ + value =3D 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 !=3D EGL_NO_CONTEXT) { + eglDestroyContext(m_eglDisplay, m_context); + } +} + +void AbstractPlatformContext::doneCurrent() +{ + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CO= NTEXT); +} + +QSurfaceFormat AbstractPlatformContext::format() const +{ + return m_format; +} + +QFunctionPointer AbstractPlatformContext::getProcAddress(const QByteArray = &procName) +{ + return eglGetProcAddress(procName.constData()); +} + +bool AbstractPlatformContext::isValid() const +{ + return m_context !=3D EGL_NO_CONTEXT; +} + +bool AbstractPlatformContext::bindApi() +{ +#ifdef KWIN_HAVE_OPENGLES + if (eglBindAPI(EGL_OPENGL_ES_API) =3D=3D EGL_FALSE) { + return false; + } +#else + if (eglBindAPI(EGL_OPENGL_API) =3D=3D EGL_FALSE) { + return false; + } +#endif + return true; +} + +void AbstractPlatformContext::createContext(EGLContext shareContext) +{ + EGLContext context =3D EGL_NO_CONTEXT; +#ifdef KWIN_HAVE_OPENGLES + const EGLint context_attribs[] =3D { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + context =3D eglCreateContext(eglDisplay(), config(), shareContext, con= text_attribs); +#else + const EGLint context_attribs_31_core[] =3D { + EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(), + EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(), + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIB= LE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() =3D=3D QSu= rfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CO= NTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, + EGL_NONE + }; + + const EGLint context_attribs_legacy[] =3D { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + const char* eglExtensionsCString =3D eglQueryString(eglDisplay(), EGL_= EXTENSIONS); + const QList extensions =3D QByteArray::fromRawData(eglExte= nsionsCString, qstrlen(eglExtensionsCString)).split(' '); + + // Try to create a 3.1 core context + if (m_format.majorVersion() >=3D 3 && extensions.contains(QByteArrayL= iteral("EGL_KHR_create_context"))) { + context =3D eglCreateContext(eglDisplay(), config(), shareContext,= context_attribs_31_core); + } + + if (context =3D=3D EGL_NO_CONTEXT) { + context =3D eglCreateContext(eglDisplay(), config(), shareContext,= context_attribs_legacy); + } +#endif + + if (context =3D=3D EGL_NO_CONTEXT) { + return; + } + m_context =3D context; +} + +} +} diff --git a/plugins/qpa/abstractplatformcontext.h b/plugins/qpa/abstractpl= atformcontext.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H +#define KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H + +#include +#include +#include + +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 =3D EGL_NO_CONTEXT); + +private: + Integration *m_integration; + EGLDisplay m_eglDisplay; + EGLConfig m_config; + EGLContext m_context =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "window.h" +#include "backingstore.h" +#include "../../wayland_server.h" + +#include +#include +#include +#include + +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 =3D m_buffer.toStrongRef(); + if (!b->isUsed()){ + return; + } + const QSize size =3D m_backBuffer.size(); + m_backBuffer =3D QImage(b->address(), size.width(), size.heigh= t(), QImage::Format_ARGB32_Premultiplied); + } + ); +} + +BackingStore::~BackingStore() =3D default; + +QPaintDevice *BackingStore::paintDevice() +{ + return &m_backBuffer; +} + +void BackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents) + m_size =3D size; + if (!m_buffer) { + return; + } + m_buffer.toStrongRef()->setUsed(false); + m_buffer.clear(); +} + +void BackingStore::flush(QWindow *window, const QRegion ®ion, const QPo= int &offset) +{ + Q_UNUSED(region) + Q_UNUSED(offset) + auto s =3D static_cast(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 =3D 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 =3D m_buffer.toStrongRef(); + m_buffer.clear(); + m_buffer =3D m_shm->getBuffer(m_size, m_size.width() * 4); + if (!m_buffer) { + m_backBuffer =3D QImage(); + return; + } + auto b =3D m_buffer.toStrongRef(); + b->setUsed(true); + m_backBuffer =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_BACKINGSTORE_H +#define KWIN_QPA_BACKINGSTORE_H + +#include + +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 &offse= t) override; + void resize(const QSize &size, const QRegion &staticContents) override; + void beginPaint(const QRegion &) override; + +private: + KWayland::Client::ShmPool *m_shm; + QWeakPointer 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace KWin +{ + +namespace QPA +{ + +Integration::Integration() + : QObject() + , QPlatformIntegration() + , m_fontDb(new QGenericUnixFontDatabase()) + , m_nativeInterface(new NativeInterface(this)) +{ +} + +Integration::~Integration() =3D 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::i= nitializeWayland, Qt::QueuedConnection); + QPlatformIntegration::initialize(); +} + +QAbstractEventDispatcher *Integration::createEventDispatcher() const +{ + // TODO: add our own event dispatcher + return new QEventDispatcherUNIX; +} + +QPlatformBackingStore *Integration::createPlatformBackingStore(QWindow *wi= ndow) const +{ + auto registry =3D waylandServer()->internalClientRegistry(); + const auto shm =3D registry->interface(KWayland::Client::Registry::Int= erface::Shm); + if (shm.name =3D=3D 0u) { + return nullptr; + } + return new BackingStore(window, registry->createShmPool(shm.name, shm.= version, window)); +} + +QPlatformWindow *Integration::createPlatformWindow(QWindow *window) const +{ + auto c =3D compositor(); + auto s =3D shell(); + if (!s || !c) { + return new QPlatformWindow(window); + } else { + // don't set window as parent, cause infinite recursion in PlasmaQ= uick::Dialog + auto surface =3D 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(QOpenGLCo= ntext *context) const +{ + if (waylandServer()->backend()->supportsQpaContext()) { + return new SharingPlatformContext(context, const_cast(this)); + } + if (m_eglDisplay =3D=3D EGL_NO_DISPLAY) { + const_cast(this)->initEgl(); + } + if (m_eglDisplay =3D=3D EGL_NO_DISPLAY) { + return nullptr; + } + return new PlatformContextWayland(context, const_cast(th= is)); +} + +void Integration::initializeWayland() +{ + if (m_registry) { + return; + } + using namespace KWayland::Client; + auto setupRegistry =3D [this] { + m_registry =3D waylandServer()->internalClientRegistry(); + connect(m_registry, &Registry::outputAnnounced, this, &Integration= ::createWaylandOutput); + const auto outputs =3D m_registry->interfaces(Registry::Interface:= :Output); + for (const auto &o : outputs) { + createWaylandOutput(o.name, o.version); + } + }; + if (waylandServer()->internalClientRegistry()) { + setupRegistry(); + } else { + connect(waylandServer()->internalClientConection(), &ConnectionThr= ead::connected, this, setupRegistry, Qt::QueuedConnection); + } +} + +void Integration::createWaylandOutput(quint32 name, quint32 version) +{ + using namespace KWayland::Client; + auto o =3D 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 =3D waylandServer()->internalClientRegistry(); + const auto c =3D registry->interface(Registry::Interface::Composit= or); + if (c.name !=3D 0u) { + const_cast(this)->m_compositor =3D registry->cre= ateCompositor(c.name, c.version); + } + } + return m_compositor; +} + +KWayland::Client::Shell *Integration::shell() const +{ + if (!m_shell) { + using namespace KWayland::Client; + auto registry =3D waylandServer()->internalClientRegistry(); + const auto s =3D registry->interface(Registry::Interface::Shell); + if (s.name !=3D 0u) { + const_cast(this)->m_shell =3D registry->createSh= ell(s.name, s.version); + } + } + return m_shell; +} + +EGLDisplay Integration::eglDisplay() const +{ + return m_eglDisplay; +} + +void Integration::initEgl() +{ + Q_ASSERT(m_eglDisplay =3D=3D EGL_NO_DISPLAY); + // This variant uses Wayland as the EGL platform + qputenv("EGL_PLATFORM", "wayland"); + m_eglDisplay =3D eglGetDisplay(waylandServer()->internalClientConectio= n()->display()); + if (m_eglDisplay =3D=3D EGL_NO_DISPLAY) { + return; + } + // call eglInitialize in a thread to not block + QFuture future =3D QtConcurrent::run([this] () -> bool { + EGLint major, minor; + if (eglInitialize(m_eglDisplay, &major, &minor) =3D=3D EGL_FALSE) { + return false; + } + EGLint error =3D eglGetError(); + if (error !=3D 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 =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_INTEGRATION_H +#define KWIN_QPA_INTEGRATION_H + +#include +#include +#include +#include + +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) con= st override; + QAbstractEventDispatcher *createEventDispatcher() const override; + QPlatformFontDatabase *fontDatabase() const override; + QStringList themeNames() const override; + QPlatformTheme *createPlatformTheme(const QString &name) const overrid= e; + QPlatformNativeInterface *nativeInterface() const override; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *co= ntext) 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 =3D nullptr; + KWayland::Client::Compositor *m_compositor =3D nullptr; + KWayland::Client::Shell *m_shell =3D nullptr; + EGLDisplay m_eglDisplay =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "integration.h" +#include + +#include + +class KWinIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFacto= ryInterface.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::Case= Insensitive) =3D=3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "nativeinterface.h" +#include "integration.h" +#include "window.h" +#include "../../wayland_server.h" + +#include + +#include +#include +#include + +namespace KWin +{ +namespace QPA +{ + +static const QByteArray s_displayKey =3D QByteArrayLiteral("display"); +static const QByteArray s_wlDisplayKey =3D QByteArrayLiteral("wl_display"); +static const QByteArray s_compositorKey =3D QByteArrayLiteral("compositor"= ); +static const QByteArray s_surfaceKey =3D QByteArrayLiteral("surface"); + +NativeInterface::NativeInterface(Integration *integration) + : QPlatformNativeInterface() + , m_integration(integration) +{ +} + +void *NativeInterface::nativeResourceForIntegration(const QByteArray &reso= urce) +{ + const QByteArray r =3D resource.toLower(); + if (r =3D=3D s_displayKey || r =3D=3D s_wlDisplayKey) { + return waylandServer()->internalClientConection()->display(); + } + if (r =3D=3D s_compositorKey) { + return static_cast(*m_integration->compositor()); + } + return nullptr; +} + +void *NativeInterface::nativeResourceForWindow(const QByteArray &resource,= QWindow *window) +{ + const QByteArray r =3D resource.toLower(); + if (r =3D=3D s_displayKey || r =3D=3D s_wlDisplayKey) { + return waylandServer()->internalClientConection()->display(); + } + if (r =3D=3D s_compositorKey) { + return static_cast(*m_integration->compositor()); + } + if (r =3D=3D s_surfaceKey && window) { + if (auto handle =3D window->handle()) { + return static_cast(*static_cast(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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_NATIVEINTERFACE_H +#define KWIN_QPA_NATIVEINTERFACE_H + +#include + +namespace KWin +{ +namespace QPA +{ + +class Integration; + +class NativeInterface : public QPlatformNativeInterface +{ +public: + explicit NativeInterface(Integration *integration); + void *nativeResourceForIntegration(const QByteArray &resource) overrid= e; + void *nativeResourceForWindow(const QByteArray &resourceString, QWindo= w *window) override; + +private: + Integration *m_integration; +}; + +} +} + +#endif diff --git a/plugins/qpa/platformcontextwayland.cpp b/plugins/qpa/platformc= ontextwayland.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "platformcontextwayland.h" +#include "integration.h" +#include "window.h" + +namespace KWin +{ + +namespace QPA +{ + +PlatformContextWayland::PlatformContextWayland(QOpenGLContext *context, In= tegration *integration) + : AbstractPlatformContext(context, integration, integration->eglDispla= y()) +{ + create(); +} + +bool PlatformContextWayland::makeCurrent(QPlatformSurface *surface) +{ + Window *window =3D static_cast(surface); + EGLSurface s =3D window->eglSurface(); + if (s =3D=3D EGL_NO_SURFACE) { + window->createEglSurface(eglDisplay(), config()); + s =3D window->eglSurface(); + if (s =3D=3D EGL_NO_SURFACE) { + return false; + } + } + return eglMakeCurrent(eglDisplay(), s, s, context()); +} + +bool PlatformContextWayland::isSharing() const +{ + return false; +} + +void PlatformContextWayland::swapBuffers(QPlatformSurface *surface) +{ + Window *window =3D static_cast(surface); + EGLSurface s =3D window->eglSurface(); + if (s =3D=3D EGL_NO_SURFACE) { + return; + } + eglSwapBuffers(eglDisplay(), s); +} + +void PlatformContextWayland::create() +{ + if (config() =3D=3D 0) { + return; + } + if (!bindApi()) { + return; + } + createContext(); +} + +} +} diff --git a/plugins/qpa/platformcontextwayland.h b/plugins/qpa/platformcon= textwayland.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "screen.h" + +#include + +namespace KWin +{ +namespace QPA +{ + +Screen::Screen(KWayland::Client::Output *o) + : QPlatformScreen() + , m_output(o) +{ + // TODO: connect to resolution changes +} + +Screen::~Screen() =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_SCREEN_H +#define KWIN_QPA_SCREEN_H + +#include + +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/sharingpl= atformcontext.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#include "sharingplatformcontext.h" +#include "integration.h" +#include "window.h" +#include "../../abstract_backend.h" +#include "../../wayland_server.h" +#include "../../shell_client.h" + +#include + +namespace KWin +{ + +namespace QPA +{ + +SharingPlatformContext::SharingPlatformContext(QOpenGLContext *context, In= tegration *integration) + : AbstractPlatformContext(context, integration, waylandServer()->backe= nd()->sceneEglDisplay()) +{ + create(); +} + +bool SharingPlatformContext::makeCurrent(QPlatformSurface *surface) +{ + Window *window =3D static_cast(surface); + if (eglMakeCurrent(eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, conte= xt())) { + window->bindContentFBO(); + return true; + } + return false; +} + +bool SharingPlatformContext::isSharing() const +{ + return false; +} + +void SharingPlatformContext::swapBuffers(QPlatformSurface *surface) +{ + Window *window =3D static_cast(surface); + auto c =3D window->shellClient(); + if (!c) { + return; + } + makeCurrent(surface); + glFlush(); + c->setInternalFramebufferObject(window->swapFBO()); + window->bindContentFBO(); +} + +GLuint SharingPlatformContext::defaultFramebufferObject(QPlatformSurface *= surface) const +{ + if (Window *window =3D dynamic_cast(surface)) { + const auto &fbo =3D window->contentFBO(); + if (!fbo.isNull()) { + return fbo->handle(); + } + } + return 0; +} + +void SharingPlatformContext::create() +{ + if (config() =3D=3D 0) { + return; + } + if (!bindApi()) { + return; + } + createContext(waylandServer()->backend()->sceneEglContext()); +} + +} +} diff --git a/plugins/qpa/sharingplatformcontext.h b/plugins/qpa/sharingplat= formcontext.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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#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 overr= ide; + + 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#define WL_EGL_PLATFORM 1 +#include "integration.h" +#include "window.h" +#include "../../shell_client.h" +#include "../../wayland_server.h" + +#include + +#include +#include +#include +#include + +namespace KWin +{ +namespace QPA +{ +static quint32 s_windowId =3D 0; + +Window::Window(QWindow *window, KWayland::Client::Surface *surface, KWayla= nd::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 !=3D 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 =3D geometry(); + QPlatformWindow::setGeometry(rect); + if (rect.x() !=3D oldRect.x()) { + emit window()->xChanged(rect.x()); + } + if (rect.y() !=3D oldRect.y()) { + emit window()->yChanged(rect.y()); + } + if (rect.width() !=3D oldRect.width()) { + emit window()->widthChanged(rect.width()); + } + if (rect.height() !=3D oldRect.height()) { + emit window()->heightChanged(rect.height()); + } + if (m_contentFBO) { + if (m_contentFBO->width() !=3D geometry().width() || m_contentFBO-= >height() !=3D geometry().height()) { + m_resized =3D true; + } + } + if (m_eglWaylandWindow) { + wl_egl_window_resize(m_eglWaylandWindow, geometry().width(), geome= try().height(), 0, 0); + } +} + +void Window::unmap() +{ + if (m_shellClient) { + m_shellClient->setInternalFramebufferObject(QSharedPointer()); + } + 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 =3D window()->size(); + m_eglWaylandWindow =3D wl_egl_window_create(*m_surface, size.width(), = size.height()); + if (!m_eglWaylandWindow) { + return; + } + m_eglSurface =3D eglCreateWindowSurface(dpy, config, m_eglWaylandWindo= w, nullptr); +} + +void Window::bindContentFBO() +{ + if (m_resized || !m_contentFBO) { + createFBO(); + } + m_contentFBO->bind(); +} + +QSharedPointer Window::swapFBO() +{ + auto fbo =3D m_contentFBO; + m_contentFBO.clear(); + return fbo; +} + +void Window::createFBO() +{ + const QRect &r =3D geometry(); + m_contentFBO.reset(new QOpenGLFramebufferObject(r.width(), r.height(),= QOpenGLFramebufferObject::CombinedDepthStencil)); + m_resized =3D false; +} + +ShellClient *Window::shellClient() +{ + if (!m_shellClient) { + m_shellClient =3D 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=C3=A4=C3=9Flin + +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 . +*********************************************************************/ +#ifndef KWIN_QPA_WINDOW_H +#define KWIN_QPA_WINDOW_H + +#include +#include +#include +// wayland +#include + +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, K= Wayland::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 &contentFBO() const { + return m_contentFBO; + } + QSharedPointer swapFBO(); + ShellClient *shellClient(); + +private: + void unmap(); + void createFBO(); + + KWayland::Client::Surface *m_surface; + KWayland::Client::ShellSurface *m_shellSurface; + EGLSurface m_eglSurface =3D EGL_NO_SURFACE; + QSharedPointer m_contentFBO; + bool m_resized =3D false; + ShellClient *m_shellClient =3D nullptr; + wl_egl_window *m_eglWaylandWindow =3D nullptr; + quint32 m_windowId; + const Integration *m_integration; +}; + +} +} + +#endif