diff --git a/src/platformtheme/kwaylandintegration.cpp b/src/platformtheme/kwaylandintegration.cpp index 10da7e5..b3a20e3 100644 --- a/src/platformtheme/kwaylandintegration.cpp +++ b/src/platformtheme/kwaylandintegration.cpp @@ -1,149 +1,157 @@ /* This file is part of the KDE libraries * Copyright 2015 Martin Gräßlin * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kwaylandintegration.h" #include #include #include #include #include #include #include #include #include using namespace KWayland::Client; static const QByteArray s_schemePropertyName = QByteArrayLiteral("KDE_COLOR_SCHEME_PATH"); static const QByteArray s_blurBehindPropertyName = QByteArrayLiteral("ENABLE_BLUR_BEHIND_HINT"); KWaylandIntegration::KWaylandIntegration() : QObject() , m_decoration(Q_NULLPTR) { } KWaylandIntegration::~KWaylandIntegration() = default; void KWaylandIntegration::init() { auto connection = ConnectionThread::fromApplication(this); if (!connection) { return; } Registry *registry = new Registry(this); registry->create(connection); QObject::connect(registry, &Registry::interfacesAnnounced, this, [registry, this] { const auto interface = registry->interface(Registry::Interface::ServerSideDecorationManager); if (interface.name != 0) { m_decoration = registry->createServerSideDecorationManager(interface.name, interface.version, this); qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1"); QCoreApplication::instance()->installEventFilter(this); } } ); registry->setup(); connection->roundtrip(); } bool KWaylandIntegration::eventFilter(QObject *watched, QEvent *event) { if (!m_decoration) { return false; - } - if (event->type() == QEvent::PlatformSurface) { + } else if (event->type() == QEvent::Expose) { + auto ee = static_cast(event); + if (ee->region().isNull()) { + return false; + } QWindow *w = qobject_cast(watched); if (!w || w->parent()) { return false; } - if (auto e = dynamic_cast(event)) { - switch (e->surfaceEventType()) { - case QPlatformSurfaceEvent::SurfaceCreated: { - // set colorscheme hint - if (qApp->property(s_schemePropertyName.constData()).isValid()) { - installColorScheme(w); - } - const auto blurBehindProperty = w->property(s_blurBehindPropertyName.constData()); - if (blurBehindProperty.isValid()) { - KWindowEffects::enableBlurBehind(w->winId(), blurBehindProperty.toBool()); - } - // create deco - Surface *s = Surface::fromWindow(w); - if (!s) { - return false; - } - auto deco = m_decoration->create(s, w); - connect(deco, &ServerSideDecoration::modeChanged, w, - [deco, w] { - const auto flags = w->flags(); - const auto ourMode = (flags.testFlag(Qt::FramelessWindowHint) || flags.testFlag(Qt::Popup) || flags.testFlag(Qt::ToolTip)) ? ServerSideDecoration::Mode::None : ServerSideDecoration::Mode::Server; - if (deco->mode() != ourMode) { - deco->requestMode(ourMode); - } - } - ); - const auto flags = w->flags(); - const auto ourMode = (flags.testFlag(Qt::FramelessWindowHint) || flags.testFlag(Qt::Popup) || flags.testFlag(Qt::ToolTip)) ? ServerSideDecoration::Mode::None : ServerSideDecoration::Mode::Server; - if (deco->defaultMode() != ourMode) { - deco->requestMode(ourMode); - } - w->setProperty("org.kde.plasma.integration.waylandserverdecoration", QVariant::fromValue(deco)); - break; - } - case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: { - delete w->property("org.kde.plasma.integration.waylandserverdecoration").value(); - break; - } - default: - // nothing - break; - } + shellSurfaceCreated(w); + } else if (event->type() == QEvent::Hide) { + QWindow *w = qobject_cast(watched); + if (!w || w->parent()) { + return false; } - } - if (event->type() == QEvent::ApplicationPaletteChange) { + shellSurfaceDestroyed(w); + } else if (event->type() == QEvent::ApplicationPaletteChange) { const auto topLevelWindows = QGuiApplication::topLevelWindows(); for (QWindow *w : topLevelWindows) { installColorScheme(w); } } + return false; } +void KWaylandIntegration::shellSurfaceCreated(QWindow *w) +{ + // set colorscheme hint + if (qApp->property(s_schemePropertyName.constData()).isValid()) { + installColorScheme(w); + } + const auto blurBehindProperty = w->property(s_blurBehindPropertyName.constData()); + if (blurBehindProperty.isValid()) { + KWindowEffects::enableBlurBehind(w->winId(), blurBehindProperty.toBool()); + } + // create deco + Surface *s = Surface::fromWindow(w); + if (!s) { + return; + } + auto deco = m_decoration->create(s, w); + connect(deco, &ServerSideDecoration::modeChanged, w, + [deco, w] { + const auto flags = w->flags(); + const auto ourMode = (flags.testFlag(Qt::FramelessWindowHint) || flags.testFlag(Qt::Popup) || flags.testFlag(Qt::ToolTip)) ? ServerSideDecoration::Mode::None : ServerSideDecoration::Mode::Server; + if (deco->mode() != ourMode) { + deco->requestMode(ourMode); + } + } + ); + const auto flags = w->flags(); + const auto ourMode = (flags.testFlag(Qt::FramelessWindowHint) || flags.testFlag(Qt::Popup) || flags.testFlag(Qt::ToolTip)) ? ServerSideDecoration::Mode::None : ServerSideDecoration::Mode::Server; + if (deco->defaultMode() != ourMode) { + deco->requestMode(ourMode); + } + w->setProperty("org.kde.plasma.integration.waylandserverdecoration", QVariant::fromValue(deco)); +} + +void KWaylandIntegration::shellSurfaceDestroyed(QWindow *w) +{ + delete w->property("org.kde.plasma.integration.waylandserverdecoration").value(); + w->setProperty("org.kde.plasma.integration.waylandserverdecoration", 0); +} + void KWaylandIntegration::installColorScheme(QWindow *w) { if (QPlatformNativeInterface *native = qApp->platformNativeInterface()) { if (QPlatformWindow *pw = w->handle()) { native->setWindowProperty(pw, QString::fromUtf8(s_schemePropertyName), qApp->property(s_schemePropertyName.constData())); } } } void KWaylandIntegration::setWindowProperty(QWindow *window, const QByteArray &name, const QByteArray &value) { if (QPlatformNativeInterface *nativeInterface = qApp->platformNativeInterface()) { if (QPlatformWindow *platformWindow = window->handle()) { nativeInterface->setWindowProperty(platformWindow, QString::fromUtf8(name), QString::fromUtf8(value)); } } } + +#include "kwaylandintegration.moc" diff --git a/src/platformtheme/kwaylandintegration.h b/src/platformtheme/kwaylandintegration.h index 1ab11e7..46d8112 100644 --- a/src/platformtheme/kwaylandintegration.h +++ b/src/platformtheme/kwaylandintegration.h @@ -1,52 +1,55 @@ /* This file is part of the KDE libraries * Copyright 2015 Martin Gräßlin * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License or ( at * your option ) version 3 or, at the discretion of KDE e.V. ( which shall * act as a proxy as in section 14 of the GPLv3 ), any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KWAYLANDINTEGRATION_H #define KWAYLANDINTEGRATION_H #include class QWindow; namespace KWayland { namespace Client { class ServerSideDecorationManager; } } class KWaylandIntegration : public QObject { Q_OBJECT public: explicit KWaylandIntegration(); virtual ~KWaylandIntegration(); void init(); void setWindowProperty(QWindow *window, const QByteArray &name, const QByteArray &value); bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE; private: + void shellSurfaceCreated(QWindow *w); + void shellSurfaceDestroyed(QWindow *w); + void installColorScheme(QWindow *w); KWayland::Client::ServerSideDecorationManager *m_decoration; }; #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 87beb05..ed5f8a6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,2 +1,5 @@ add_executable(qfiledialogtest qfiledialogtest.cpp) target_link_libraries(qfiledialogtest Qt5::Core Qt5::Widgets) + +add_executable(windowdecotest windowdecotest.cpp) +target_link_libraries(windowdecotest Qt5::Core Qt5::Widgets) diff --git a/tests/windowdecotest.cpp b/tests/windowdecotest.cpp new file mode 100644 index 0000000..5d1253c --- /dev/null +++ b/tests/windowdecotest.cpp @@ -0,0 +1,71 @@ +/* This file is part of the KDE libraries + + Copyright 2017 David Edmundson + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +/* + * This class is for checking that wayland server side window decorations remain + * after a window is hidden and shown. + */ + +#include +#include +#include +#include +#include + +class ATestWindow: public QWidget +{ + Q_OBJECT +public: + ATestWindow(); + +private: + QPushButton *mBtn; + QWidget *m_area; +}; + +ATestWindow::ATestWindow() +{ + mBtn = new QPushButton(QStringLiteral("Hide and Show")); + + m_area = new QWidget; + m_area->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + connect(mBtn, &QPushButton::clicked, this, [this]() { + this->hide(); + QTimer::singleShot(1000, this, [this](){this->show();}); + }); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(mBtn); + setLayout(layout); +} + + + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + ATestWindow wnd; + wnd.show(); + + return app.exec(); +} + + +#include "windowdecotest.moc"