diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -20,6 +20,7 @@ #include "kwin_wayland_test.h" #include "platform.h" #include "cursor.h" +#include "effects.h" #include "shell_client.h" #include "screens.h" #include "wayland_server.h" @@ -32,13 +33,16 @@ #include #include #include +#include #include #include using namespace KWayland::Client; +Q_DECLARE_METATYPE(NET::WindowType); + namespace KWin { @@ -67,6 +71,11 @@ void testModifierScroll(); void testPopup(); void testScale(); + void testWindowType_data(); + void testWindowType(); + void testChangeWindowType_data(); + void testChangeWindowType(); + void testEffectWindow(); }; class HelperWindow : public QRasterWindow @@ -712,6 +721,98 @@ QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2)); } +void InternalWindowTest::testWindowType_data() +{ + QTest::addColumn("windowType"); + + QTest::newRow("normal") << NET::Normal; + QTest::newRow("desktop") << NET::Desktop; + QTest::newRow("Dock") << NET::Dock; + QTest::newRow("Toolbar") << NET::Toolbar; + QTest::newRow("Menu") << NET::Menu; + QTest::newRow("Dialog") << NET::Dialog; + QTest::newRow("Utility") << NET::Utility; + QTest::newRow("Splash") << NET::Splash; + QTest::newRow("DropdownMenu") << NET::DropdownMenu; + QTest::newRow("PopupMenu") << NET::PopupMenu; + QTest::newRow("Tooltip") << NET::Tooltip; + QTest::newRow("Notification") << NET::Notification; + QTest::newRow("ComboBox") << NET::ComboBox; + QTest::newRow("OnScreenDisplay") << NET::OnScreenDisplay; +} + +void InternalWindowTest::testWindowType() +{ + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + HelperWindow win; + win.setGeometry(0, 0, 100, 100); + QFETCH(NET::WindowType, windowType); + KWindowSystem::setType(win.winId(), windowType); + win.show(); + QVERIFY(clientAddedSpy.wait()); + QTRY_COMPARE(clientAddedSpy.count(), 1); + auto internalClient = clientAddedSpy.first().first().value(); + QVERIFY(internalClient); + QCOMPARE(internalClient->windowType(), windowType); +} + +void InternalWindowTest::testChangeWindowType_data() +{ + QTest::addColumn("windowType"); + + QTest::newRow("desktop") << NET::Desktop; + QTest::newRow("Dock") << NET::Dock; + QTest::newRow("Toolbar") << NET::Toolbar; + QTest::newRow("Menu") << NET::Menu; + QTest::newRow("Dialog") << NET::Dialog; + QTest::newRow("Utility") << NET::Utility; + QTest::newRow("Splash") << NET::Splash; + QTest::newRow("DropdownMenu") << NET::DropdownMenu; + QTest::newRow("PopupMenu") << NET::PopupMenu; + QTest::newRow("Tooltip") << NET::Tooltip; + QTest::newRow("Notification") << NET::Notification; + QTest::newRow("ComboBox") << NET::ComboBox; + QTest::newRow("OnScreenDisplay") << NET::OnScreenDisplay; +} + +void InternalWindowTest::testChangeWindowType() +{ + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + HelperWindow win; + win.setGeometry(0, 0, 100, 100); + win.show(); + QVERIFY(clientAddedSpy.wait()); + QTRY_COMPARE(clientAddedSpy.count(), 1); + auto internalClient = clientAddedSpy.first().first().value(); + QVERIFY(internalClient); + QCOMPARE(internalClient->windowType(), NET::Normal); + + QFETCH(NET::WindowType, windowType); + KWindowSystem::setType(win.winId(), windowType); + QTRY_COMPARE(internalClient->windowType(), windowType); + + KWindowSystem::setType(win.winId(), NET::Normal); + QTRY_COMPARE(internalClient->windowType(), NET::Normal); +} + +void InternalWindowTest::testEffectWindow() +{ + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + HelperWindow win; + win.setGeometry(0, 0, 100, 100); + win.show(); + QVERIFY(clientAddedSpy.wait()); + auto internalClient = clientAddedSpy.first().first().value(); + QVERIFY(internalClient); + QVERIFY(internalClient->effectWindow()); + QCOMPARE(internalClient->effectWindow()->internalWindow(), &win); + + QCOMPARE(effects->findWindow(&win), internalClient->effectWindow()); + QCOMPARE(effects->findWindow(&win)->internalWindow(), &win); +} } diff --git a/autotests/integration/shell_client_test.cpp b/autotests/integration/shell_client_test.cpp --- a/autotests/integration/shell_client_test.cpp +++ b/autotests/integration/shell_client_test.cpp @@ -184,6 +184,9 @@ QVERIFY(client->property("moveable").toBool()); QVERIFY(client->property("moveableAcrossScreens").toBool()); QVERIFY(client->property("resizeable").toBool()); + QCOMPARE(client->isInternal(), false); + QVERIFY(client->effectWindow()); + QVERIFY(!client->effectWindow()->internalWindow()); QCOMPARE(client->internalId().isNull(), false); const auto uuid = client->internalId(); QUuid deletedUuid; diff --git a/autotests/mock_effectshandler.h b/autotests/mock_effectshandler.h --- a/autotests/mock_effectshandler.h +++ b/autotests/mock_effectshandler.h @@ -134,6 +134,9 @@ KWin::EffectWindow *findWindow(KWayland::Server::SurfaceInterface *) const override { return nullptr; } + KWin::EffectWindow *findWindow(QWindow *w) const override { + return nullptr; + } void *getProxy(QString) override { return nullptr; } diff --git a/autotests/test_window_paint_data.cpp b/autotests/test_window_paint_data.cpp --- a/autotests/test_window_paint_data.cpp +++ b/autotests/test_window_paint_data.cpp @@ -59,6 +59,9 @@ void closeWindow() override; void referencePreviousWindowPixmap() override {} void unreferencePreviousWindowPixmap() override {} + QWindow *internalWindow() const override { + return nullptr; + } bool isDeleted() const override { return false; } diff --git a/effects.h b/effects.h --- a/effects.h +++ b/effects.h @@ -134,6 +134,7 @@ void stopMousePolling() override; EffectWindow* findWindow(WId id) const override; EffectWindow* findWindow(KWayland::Server::SurfaceInterface *surf) const override; + EffectWindow *findWindow(QWindow *w) const override; EffectWindowList stackingOrder() const override; void setElevatedWindow(KWin::EffectWindow* w, bool set) override; @@ -474,6 +475,8 @@ void referencePreviousWindowPixmap() override; void unreferencePreviousWindowPixmap() override; + QWindow *internalWindow() const override; + const Toplevel* window() const; Toplevel* window(); diff --git a/effects.cpp b/effects.cpp --- a/effects.cpp +++ b/effects.cpp @@ -1086,6 +1086,19 @@ return nullptr; } +EffectWindow *EffectsHandlerImpl::findWindow(QWindow *w) const +{ + if (waylandServer()) { + if (auto c = waylandServer()->findClient(w)) { + return c->effectWindow(); + } + } + if (auto u = Workspace::self()->findUnmanaged(w->winId())) { + return u->effectWindow(); + } + return nullptr; +} + EffectWindowList EffectsHandlerImpl::stackingOrder() const { @@ -1936,6 +1949,15 @@ return nullptr; } +QWindow *EffectWindowImpl::internalWindow() const +{ + auto client = qobject_cast(toplevel); + if (!client) { + return nullptr; + } + return client->internalWindow(); +} + template EffectWindowList getMainWindows(T *c) { diff --git a/effects/backgroundcontrast/contrast.h b/effects/backgroundcontrast/contrast.h --- a/effects/backgroundcontrast/contrast.h +++ b/effects/backgroundcontrast/contrast.h @@ -64,6 +64,8 @@ return 76; } + bool eventFilter(QObject *watched, QEvent *event) override; + public Q_SLOTS: void slotWindowAdded(KWin::EffectWindow *w); void slotWindowDeleted(KWin::EffectWindow *w); diff --git a/effects/backgroundcontrast/contrast.cpp b/effects/backgroundcontrast/contrast.cpp --- a/effects/backgroundcontrast/contrast.cpp +++ b/effects/backgroundcontrast/contrast.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -140,6 +141,27 @@ m_colorMatrices[w] = colorMatrix(surf->contrast()->contrast(), surf->contrast()->intensity(), surf->contrast()->saturation()); } + if (auto internal = w->internalWindow()) { + const auto property = internal->property("kwin_background_region"); + if (property.isValid()) { + region = property.value(); + bool ok = false; + qreal contrast = internal->property("kwin_background_contrast").toReal(&ok); + if (!ok) { + contrast = 1.0; + } + qreal intensity = internal->property("kwin_background_intensity").toReal(&ok); + if (!ok) { + intensity = 1.0; + } + qreal saturation = internal->property("kwin_background_saturation").toReal(&ok); + if (!ok) { + saturation = 1.0; + } + m_colorMatrices[w] = colorMatrix(contrast, intensity, saturation); + } + } + //!value.isNull() full window in X11 case, surf->contrast() //valid, full window in wayland case if (region.isEmpty() && (!value.isNull() || (surf && surf->contrast()))) { @@ -163,9 +185,31 @@ } }); } + + if (auto internal = w->internalWindow()) { + internal->installEventFilter(this); + } + updateContrastRegion(w); } +bool ContrastEffect::eventFilter(QObject *watched, QEvent *event) +{ + auto internal = qobject_cast(watched); + if (internal && event->type() == QEvent::DynamicPropertyChange) { + QDynamicPropertyChangeEvent *pe = static_cast(event); + if (pe->propertyName() == "kwin_background_region" || + pe->propertyName() == "kwin_background_contrast" || + pe->propertyName() == "kwin_background_intensity" || + pe->propertyName() == "kwin_background_saturation") { + if (auto w = effects->findWindow(internal)) { + updateContrastRegion(w); + } + } + } + return false; +} + void ContrastEffect::slotWindowDeleted(EffectWindow *w) { if (m_contrastChangedConnections.contains(w)) { diff --git a/effects/blur/blur.h b/effects/blur/blur.h --- a/effects/blur/blur.h +++ b/effects/blur/blur.h @@ -67,6 +67,8 @@ return 75; } + bool eventFilter(QObject *watched, QEvent *event) override; + public Q_SLOTS: void slotWindowAdded(KWin::EffectWindow *w); void slotWindowDeleted(KWin::EffectWindow *w); diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -29,6 +29,7 @@ #include #include // for QGuiApplication #include +#include #include // for ceil() #include @@ -272,6 +273,13 @@ region = surf->blur()->region(); } + if (auto internal = w->internalWindow()) { + const auto property = internal->property("kwin_blur"); + if (property.isValid()) { + region = property.value(); + } + } + //!value.isNull() full window in X11 case, surf->blur() //valid, full window in wayland case if (region.isEmpty() && (!value.isNull() || (surf && surf->blur()))) { @@ -294,6 +302,9 @@ } }); } + if (auto internal = w->internalWindow()) { + internal->installEventFilter(this); + } updateBlurRegion(w); } @@ -315,6 +326,20 @@ } } +bool BlurEffect::eventFilter(QObject *watched, QEvent *event) +{ + auto internal = qobject_cast(watched); + if (internal && event->type() == QEvent::DynamicPropertyChange) { + QDynamicPropertyChangeEvent *pe = static_cast(event); + if (pe->propertyName() == "kwin_blur") { + if (auto w = effects->findWindow(internal)) { + updateBlurRegion(w); + } + } + } + return false; +} + bool BlurEffect::enabledByDefault() { GLPlatform *gl = GLPlatform::instance(); diff --git a/effects/slidingpopups/slidingpopups.h b/effects/slidingpopups/slidingpopups.h --- a/effects/slidingpopups/slidingpopups.h +++ b/effects/slidingpopups/slidingpopups.h @@ -53,6 +53,8 @@ int slideInDuration() const; int slideOutDuration() const; + bool eventFilter(QObject *watched, QEvent *event) override; + private Q_SLOTS: void slotWindowAdded(EffectWindow *w); void slotWindowDeleted(EffectWindow *w); @@ -65,6 +67,7 @@ private: void setupAnimData(EffectWindow *w); + void setupInternalWindowSlide(EffectWindow *w); long m_atom; diff --git a/effects/slidingpopups/slidingpopups.cpp b/effects/slidingpopups/slidingpopups.cpp --- a/effects/slidingpopups/slidingpopups.cpp +++ b/effects/slidingpopups/slidingpopups.cpp @@ -24,11 +24,16 @@ #include #include +#include #include #include #include +#include + +Q_DECLARE_METATYPE(KWindowEffects::SlideFromLocation) + namespace KWin { @@ -200,6 +205,11 @@ }); } + if (auto internal = w->internalWindow()) { + internal->installEventFilter(this); + setupInternalWindowSlide(w); + } + slideIn(w); } @@ -377,6 +387,62 @@ } } +void SlidingPopupsEffect::setupInternalWindowSlide(EffectWindow *w) +{ + if (!w) { + return; + } + auto internal = w->internalWindow(); + if (!internal) { + return; + } + const QVariant slideProperty = internal->property("kwin_slide"); + if (!slideProperty.isValid()) { + return; + } + AnimationData &animData = m_animationsData[w]; + switch (slideProperty.value()) { + case KWindowEffects::BottomEdge: + animData.location = Location::Bottom; + break; + case KWindowEffects::TopEdge: + animData.location = Location::Top; + break; + case KWindowEffects::RightEdge: + animData.location = Location::Right; + break; + case KWindowEffects::LeftEdge: + animData.location = Location::Left; + break; + default: + return; + } + bool intOk = false; + animData.offset = internal->property("kwin_slide_offset").toInt(&intOk); + if (!intOk) { + animData.offset = -1; + } + animData.slideLength = 0; + animData.slideInDuration = m_slideInDuration; + animData.slideOutDuration = m_slideOutDuration; + + setupAnimData(w); +} + +bool SlidingPopupsEffect::eventFilter(QObject *watched, QEvent *event) +{ + auto internal = qobject_cast(watched); + if (internal && event->type() == QEvent::DynamicPropertyChange) { + QDynamicPropertyChangeEvent *pe = static_cast(event); + if (pe->propertyName() == "kwin_slide" || pe->propertyName() == "kwin_slide_offset") { + if (auto w = effects->findWindow(internal)) { + setupInternalWindowSlide(w); + } + } + } + return false; +} + void SlidingPopupsEffect::slideIn(EffectWindow *w) { if (effects->activeFullScreenEffect()) { diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -1078,6 +1078,16 @@ Q_SCRIPTABLE virtual KWin::EffectWindow* findWindow(WId id) const = 0; Q_SCRIPTABLE virtual KWin::EffectWindow* findWindow(KWayland::Server::SurfaceInterface *surf) const = 0; + /** + * Finds the EffectWindow for the internal window @p w. + * If there is no such window @c null is returned. + * + * On Wayland this returns the internal window. On X11 it returns an Unamanged with the + * window id matching that of the provided window @p w. + * + * @since 5.16 + **/ + Q_SCRIPTABLE virtual KWin::EffectWindow *findWindow(QWindow *w) const = 0; virtual EffectWindowList stackingOrder() const = 0; // window will be temporarily painted as if being at the top of the stack Q_SCRIPTABLE virtual void setElevatedWindow(KWin::EffectWindow* w, bool set) = 0; @@ -2041,6 +2051,14 @@ **/ Q_PROPERTY(bool popupWindow READ isPopupWindow CONSTANT) + /** + * KWin internal window. Specific to Wayland platform. + * + * If the EffectWindow does not reference an internal window, this property is @c null. + * @since 5.16 + **/ + Q_PROPERTY(QWindow *internalWindow READ internalWindow CONSTANT) + public: /** Flags explaining why painting should be disabled */ enum { @@ -2324,6 +2342,11 @@ **/ virtual bool isPopupWindow() const = 0; + /** + * @since 5.16 + **/ + virtual QWindow *internalWindow() const = 0; + /** * Can be used to by effects to store arbitrary data in the EffectWindow. * diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(idletime) add_subdirectory(platforms) add_subdirectory(scenes) +add_subdirectory(windowsystem) if(KWIN_BUILD_DECORATIONS) add_subdirectory(kdecorations) diff --git a/plugins/windowsystem/CMakeLists.txt b/plugins/windowsystem/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/CMakeLists.txt @@ -0,0 +1,19 @@ +set(kwindowsystem_plugin_SRCS + plugin.cpp + windoweffects.cpp + windowsystem.cpp +) + + +add_library(KF5WindowSystemKWinPrivatePlugin MODULE ${kwindowsystem_plugin_SRCS}) +set_target_properties(KF5WindowSystemKWinPrivatePlugin PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/kf5/org.kde.kwindowsystem.platforms/") +target_link_libraries(KF5WindowSystemKWinPrivatePlugin + kwin +) + +install( + TARGETS + KF5WindowSystemKWinPrivatePlugin + DESTINATION + ${PLUGIN_INSTALL_DIR}/kf5/org.kde.kwindowsystem.platforms/ +) diff --git a/plugins/windowsystem/kwindowsystem.json b/plugins/windowsystem/kwindowsystem.json new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/kwindowsystem.json @@ -0,0 +1,3 @@ +{ + "platforms": ["wayland-org.kde.kwin.qpa"] +} diff --git a/plugins/windowsystem/plugin.h b/plugins/windowsystem/plugin.h new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/plugin.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 . + */ +#pragma once + +#include + +class KWindowSystemKWinPlugin : public KWindowSystemPluginInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.kde.kwindowsystem.KWindowSystemPluginInterface" FILE "kwindowsystem.json") + Q_INTERFACES(KWindowSystemPluginInterface) + +public: + explicit KWindowSystemKWinPlugin(QObject *parent = nullptr); + ~KWindowSystemKWinPlugin() override; + + KWindowEffectsPrivate *createEffects() override; + KWindowSystemPrivate *createWindowSystem() override; +}; diff --git a/plugins/windowsystem/plugin.cpp b/plugins/windowsystem/plugin.cpp new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/plugin.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 "plugin.h" +#include "windowsystem.h" +#include "windoweffects.h" + +KWindowSystemKWinPlugin::KWindowSystemKWinPlugin(QObject *parent) + : KWindowSystemPluginInterface(parent) +{ +} + +KWindowSystemKWinPlugin::~KWindowSystemKWinPlugin() +{ +} + +KWindowEffectsPrivate *KWindowSystemKWinPlugin::createEffects() +{ + return new KWin::WindowEffects(); +} + +KWindowSystemPrivate *KWindowSystemKWinPlugin::createWindowSystem() +{ + return new KWin::WindowSystem(); +} diff --git a/plugins/windowsystem/windoweffects.h b/plugins/windowsystem/windoweffects.h new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/windoweffects.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 . + */ +#pragma once +#include + +namespace KWin +{ + +class WindowEffects : public QObject, public KWindowEffectsPrivate +{ +public: + WindowEffects(); + ~WindowEffects() override; + + bool isEffectAvailable(KWindowEffects::Effect effect) override; + void slideWindow(WId id, KWindowEffects::SlideFromLocation location, int offset) override; + void slideWindow(QWidget *widget, KWindowEffects::SlideFromLocation location) override; + QList windowSizes(const QList &ids) override; + void presentWindows(WId controller, const QList &ids) override; + void presentWindows(WId controller, int desktop = NET::OnAllDesktops) override; + void highlightWindows(WId controller, const QList &ids) override; + void enableBlurBehind(WId window, bool enable = true, const QRegion ®ion = QRegion()) override; + void enableBackgroundContrast(WId window, bool enable = true, qreal contrast = 1, qreal intensity = 1, qreal saturation = 1, const QRegion ®ion = QRegion()) override; + void markAsDashboard(WId window) override; +}; + +} diff --git a/plugins/windowsystem/windoweffects.cpp b/plugins/windowsystem/windoweffects.cpp new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/windoweffects.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 "windoweffects.h" +#include "effect_builtins.h" +#include "../../effects.h" + +#include +#include +#include + +Q_DECLARE_METATYPE(KWindowEffects::SlideFromLocation) + +namespace KWin +{ + +WindowEffects::WindowEffects() + : QObject(), + KWindowEffectsPrivate() +{ +} + +WindowEffects::~WindowEffects() +{} + +namespace +{ +QWindow *findWindow(WId win) +{ + const auto windows = qApp->allWindows(); + auto it = std::find_if(windows.begin(), windows.end(), [win] (QWindow *w) { return w->winId() == win; }); + if (it == windows.end()) { + return nullptr; + } + return *it; +} +} + +bool WindowEffects::isEffectAvailable(KWindowEffects::Effect effect) +{ + if (!effects) { + return false; + } + auto e = static_cast(effects); + switch (effect) { + case KWindowEffects::BackgroundContrast: + return e->isEffectLoaded(BuiltInEffects::nameForEffect(BuiltInEffect::Contrast)); + case KWindowEffects::BlurBehind: + return e->isEffectLoaded(BuiltInEffects::nameForEffect(BuiltInEffect::Blur)); + case KWindowEffects::Slide: + return e->isEffectLoaded(BuiltInEffects::nameForEffect(BuiltInEffect::SlidingPopups)); + default: + // plugin does not provide integration for other effects + return false; + } +} + +void WindowEffects::slideWindow(WId id, KWindowEffects::SlideFromLocation location, int offset) +{ + auto w = findWindow(id); + if (!w) { + return; + } + w->setProperty("kwin_slide", QVariant::fromValue(location)); + w->setProperty("kwin_slide_offset", offset); +} + +void WindowEffects::slideWindow(QWidget *widget, KWindowEffects::SlideFromLocation location) +{ + slideWindow(widget->winId(), location, 0); +} + +QList WindowEffects::windowSizes(const QList &ids) +{ + Q_UNUSED(ids) + return {}; +} + +void WindowEffects::presentWindows(WId controller, const QList &ids) +{ + Q_UNUSED(controller) + Q_UNUSED(ids) +} + +void WindowEffects::presentWindows(WId controller, int desktop) +{ + Q_UNUSED(controller) + Q_UNUSED(desktop) +} + +void WindowEffects::highlightWindows(WId controller, const QList &ids) +{ + Q_UNUSED(controller) + Q_UNUSED(ids) +} + +void WindowEffects::enableBlurBehind(WId window, bool enable, const QRegion ®ion) +{ + auto w = findWindow(window); + if (!w) { + return; + } + if (enable) { + w->setProperty("kwin_blur", region); + } else { + w->setProperty("kwin_blur", {}); + } +} + +void WindowEffects::enableBackgroundContrast(WId window, bool enable, qreal contrast, qreal intensity, qreal saturation, const QRegion ®ion) +{ + auto w = findWindow(window); + if (!w) { + return; + } + if (enable) { + w->setProperty("kwin_background_region", region); + w->setProperty("kwin_background_contrast", contrast); + w->setProperty("kwin_background_intensity", intensity); + w->setProperty("kwin_background_saturation", saturation); + } else { + w->setProperty("kwin_background_region", {}); + w->setProperty("kwin_background_contrast", {}); + w->setProperty("kwin_background_intensity", {}); + w->setProperty("kwin_background_saturation", {}); + } +} + +void WindowEffects::markAsDashboard(WId window) +{ + Q_UNUSED(window) +} + +} diff --git a/plugins/windowsystem/windowsystem.h b/plugins/windowsystem/windowsystem.h new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/windowsystem.h @@ -0,0 +1,85 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 . + */ +#pragma once + +#include + +#include + +namespace KWin +{ + +class WindowSystem : public QObject, public KWindowSystemPrivate +{ + Q_OBJECT +public: + WindowSystem(); + QList windows() override; + QList stackingOrder() override; + WId activeWindow() override; + void activateWindow(WId win, long time) override; + void forceActiveWindow(WId win, long time) override; + void demandAttention(WId win, bool set) override; + bool compositingActive() override; + int currentDesktop() override; + int numberOfDesktops() override; + void setCurrentDesktop(int desktop) override; + void setOnAllDesktops(WId win, bool b) override; + void setOnDesktop(WId win, int desktop) override; + void setOnActivities(WId win, const QStringList &activities) override; +#ifndef KWINDOWSYSTEM_NO_DEPRECATED + WId transientFor(WId window) override; + WId groupLeader(WId window) override; +#endif + QPixmap icon(WId win, int width, int height, bool scale, int flags) override; + void setIcons(WId win, const QPixmap &icon, const QPixmap &miniIcon) override; + void setType(WId win, NET::WindowType windowType) override; + void setState(WId win, NET::States state) override; + void clearState(WId win, NET::States state) override; + void minimizeWindow(WId win) override; + void unminimizeWindow(WId win) override; + void raiseWindow(WId win) override; + void lowerWindow(WId win) override; + bool icccmCompliantMappingState() override; + QRect workArea(int desktop) override; + QRect workArea(const QList &excludes, int desktop) override; + QString desktopName(int desktop) override; + void setDesktopName(int desktop, const QString &name) override; + bool showingDesktop() override; + void setShowingDesktop(bool showing) override; + void setUserTime(WId win, long time) override; + void setExtendedStrut(WId win, int left_width, int left_start, int left_end, + int right_width, int right_start, int right_end, int top_width, int top_start, int top_end, + int bottom_width, int bottom_start, int bottom_end) override; + void setStrut(WId win, int left, int right, int top, int bottom) override; + bool allowedActionsSupported() override; + QString readNameProperty(WId window, unsigned long atom) override; + void allowExternalProcessWindowActivation(int pid) override; + void setBlockingCompositing(WId window, bool active) override; + bool mapViewport() override; + int viewportToDesktop(const QPoint &pos) override; + int viewportWindowToDesktop(const QRect &r) override; + QPoint desktopToViewport(int desktop, bool absolute) override; + QPoint constrainViewportRelativePosition(const QPoint &pos) override; + + void connectNotify(const QMetaMethod &signal) override; +}; + +} diff --git a/plugins/windowsystem/windowsystem.cpp b/plugins/windowsystem/windowsystem.cpp new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/windowsystem.cpp @@ -0,0 +1,328 @@ +/* + * Copyright 2019 Martin Flöser + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 "windowsystem.h" + +#include + +#include +#include + +Q_DECLARE_METATYPE(NET::WindowType) + +namespace KWin +{ + +WindowSystem::WindowSystem() + : QObject() + , KWindowSystemPrivate() +{ +} + +void WindowSystem::activateWindow(WId win, long int time) +{ + Q_UNUSED(win) + Q_UNUSED(time) + // KWin cannot activate own windows +} + +void WindowSystem::forceActiveWindow(WId win, long int time) +{ + Q_UNUSED(win) + Q_UNUSED(time) + // KWin cannot activate own windows +} + +WId WindowSystem::activeWindow() +{ + // KWin internal should not use KWindowSystem to find active window + return 0; +} + +bool WindowSystem::allowedActionsSupported() +{ + return false; +} + +void WindowSystem::allowExternalProcessWindowActivation(int pid) +{ + Q_UNUSED(pid) +} + +bool WindowSystem::compositingActive() +{ + // wayland is always composited + return true; +} + +void WindowSystem::connectNotify(const QMetaMethod &signal) +{ + Q_UNUSED(signal) +} + +QPoint WindowSystem::constrainViewportRelativePosition(const QPoint &pos) +{ + Q_UNUSED(pos) + return QPoint(); +} + +int WindowSystem::currentDesktop() +{ + // KWin internal should not use KWindowSystem to find current desktop + return 0; +} + +void WindowSystem::demandAttention(WId win, bool set) +{ + Q_UNUSED(win) + Q_UNUSED(set) +} + +QString WindowSystem::desktopName(int desktop) +{ + Q_UNUSED(desktop) + return QString(); +} + +QPoint WindowSystem::desktopToViewport(int desktop, bool absolute) +{ + Q_UNUSED(desktop) + Q_UNUSED(absolute) + return QPoint(); +} + +#ifndef KWINDOWSYSTEM_NO_DEPRECATED +WId WindowSystem::groupLeader(WId window) +{ + Q_UNUSED(window) + return 0; +} +#endif + +bool WindowSystem::icccmCompliantMappingState() +{ + return false; +} + +QPixmap WindowSystem::icon(WId win, int width, int height, bool scale, int flags) +{ + Q_UNUSED(win) + Q_UNUSED(width) + Q_UNUSED(height) + Q_UNUSED(scale) + Q_UNUSED(flags) + return QPixmap(); +} + +void WindowSystem::lowerWindow(WId win) +{ + Q_UNUSED(win) +} + +bool WindowSystem::mapViewport() +{ + return false; +} + +void WindowSystem::minimizeWindow(WId win) +{ + Q_UNUSED(win) +} + +void WindowSystem::unminimizeWindow(WId win) +{ + Q_UNUSED(win) +} + +int WindowSystem::numberOfDesktops() +{ + // KWin internal should not use KWindowSystem to find number of desktops + return 1; +} + +void WindowSystem::raiseWindow(WId win) +{ + Q_UNUSED(win) +} + +QString WindowSystem::readNameProperty(WId window, long unsigned int atom) +{ + Q_UNUSED(window) + Q_UNUSED(atom) + return QString(); +} + +void WindowSystem::setBlockingCompositing(WId window, bool active) +{ + Q_UNUSED(window) + Q_UNUSED(active) +} + +void WindowSystem::setCurrentDesktop(int desktop) +{ + Q_UNUSED(desktop) + // KWin internal should not use KWindowSystem to set current desktop +} + +void WindowSystem::setDesktopName(int desktop, const QString &name) +{ + Q_UNUSED(desktop) + Q_UNUSED(name) + // KWin internal should not use KWindowSystem to set desktop name +} + +void WindowSystem::setExtendedStrut(WId win, int left_width, int left_start, int left_end, int right_width, int right_start, int right_end, int top_width, int top_start, int top_end, int bottom_width, int bottom_start, int bottom_end) +{ + Q_UNUSED(win) + Q_UNUSED(left_width) + Q_UNUSED(left_start) + Q_UNUSED(left_end) + Q_UNUSED(right_width) + Q_UNUSED(right_start) + Q_UNUSED(right_end) + Q_UNUSED(top_width) + Q_UNUSED(top_start) + Q_UNUSED(top_end) + Q_UNUSED(bottom_width) + Q_UNUSED(bottom_start) + Q_UNUSED(bottom_end) +} + +void WindowSystem::setStrut(WId win, int left, int right, int top, int bottom) +{ + Q_UNUSED(win) + Q_UNUSED(left) + Q_UNUSED(right) + Q_UNUSED(top) + Q_UNUSED(bottom) +} + +void WindowSystem::setIcons(WId win, const QPixmap &icon, const QPixmap &miniIcon) +{ + Q_UNUSED(win) + Q_UNUSED(icon) + Q_UNUSED(miniIcon) +} + +void WindowSystem::setOnActivities(WId win, const QStringList &activities) +{ + Q_UNUSED(win) + Q_UNUSED(activities) +} + +void WindowSystem::setOnAllDesktops(WId win, bool b) +{ + Q_UNUSED(win) + Q_UNUSED(b) +} + +void WindowSystem::setOnDesktop(WId win, int desktop) +{ + Q_UNUSED(win) + Q_UNUSED(desktop) +} + +void WindowSystem::setShowingDesktop(bool showing) +{ + Q_UNUSED(showing) + // KWin should not use KWindowSystem to set showing desktop state +} + +void WindowSystem::clearState(WId win, NET::States state) +{ + // KWin's windows don't support state + Q_UNUSED(win) + Q_UNUSED(state) +} + +void WindowSystem::setState(WId win, NET::States state) +{ + // KWin's windows don't support state + Q_UNUSED(win) + Q_UNUSED(state) +} + +void WindowSystem::setType(WId win, NET::WindowType windowType) +{ + const auto windows = qApp->allWindows(); + auto it = std::find_if(windows.begin(), windows.end(), [win] (QWindow *w) { return w->winId() == win; }); + if (it == windows.end()) { + return; + } + + (*it)->setProperty("kwin_windowType", QVariant::fromValue(windowType)); +} + +void WindowSystem::setUserTime(WId win, long int time) +{ + Q_UNUSED(win) + Q_UNUSED(time) +} + +bool WindowSystem::showingDesktop() +{ + // KWin should not use KWindowSystem for showing desktop state + return false; +} + +QList< WId > WindowSystem::stackingOrder() +{ + // KWin should not use KWindowSystem for stacking order + return {}; +} + +#ifndef KWINDOWSYSTEM_NO_DEPRECATED +WId WindowSystem::transientFor(WId window) +{ + Q_UNUSED(window) + return 0; +} +#endif + +int WindowSystem::viewportToDesktop(const QPoint &pos) +{ + Q_UNUSED(pos) + return 0; +} + +int WindowSystem::viewportWindowToDesktop(const QRect &r) +{ + Q_UNUSED(r) + return 0; +} + +QList< WId > WindowSystem::windows() +{ + return {}; +} + +QRect WindowSystem::workArea(const QList< WId > &excludes, int desktop) +{ + Q_UNUSED(excludes) + Q_UNUSED(desktop) + return {}; +} + +QRect WindowSystem::workArea(int desktop) +{ + Q_UNUSED(desktop) + return {}; +} + +} diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -60,6 +60,8 @@ #include #include +Q_DECLARE_METATYPE(NET::WindowType) + using namespace KWayland::Server; static const QByteArray s_skipClosePropertyName = QByteArrayLiteral("KWIN_SKIP_CLOSE_ANIMATION"); @@ -1143,11 +1145,9 @@ connect(m_internalWindow, &QWindow::destroyed, this, [this] { m_internalWindow = nullptr; }); connect(m_internalWindow, &QWindow::opacityChanged, this, &ShellClient::setOpacity); - // Try reading the window type from the QWindow. PlasmaCore.Dialog provides a dynamic type property - // let's check whether it exists, if it does it's our window type - const QVariant windowType = m_internalWindow->property("type"); + const QVariant windowType = m_internalWindow->property("kwin_windowType"); if (!windowType.isNull()) { - m_windowType = static_cast(windowType.toInt()); + m_windowType = windowType.value(); } setOpacity(m_internalWindow->opacity()); @@ -1505,6 +1505,10 @@ if (pe->propertyName() == s_skipClosePropertyName) { setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool()); } + if (pe->propertyName() == "kwin_windowType") { + m_windowType = m_internalWindow->property("kwin_windowType").value(); + workspace()->updateClientArea(); + } } return false; }