diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,14 +5,16 @@ find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${ECM_MODULE_PATH}) -find_package(Qt5 REQUIRED NO_MODULE COMPONENTS DBus) +find_package(Qt5 REQUIRED NO_MODULE COMPONENTS DBus Svg) find_package(KF5CoreAddons REQUIRED) find_package(KF5Config REQUIRED) find_package(KF5ConfigWidgets REQUIRED) find_package(KF5GuiAddons REQUIRED) find_package(KF5IconThemes REQUIRED) find_package(KF5DBusAddons REQUIRED) +find_package(KF5Service REQUIRED) find_package(PkgConfig REQUIRED) +find_package(KDecoration2 REQUIRED) find_package(GSettingSchemas REQUIRED) find_package(XSettingsd) diff --git a/kded/CMakeLists.txt b/kded/CMakeLists.txt --- a/kded/CMakeLists.txt +++ b/kded/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(kwin_bridge) + set(kscreen_daemon_SRCS gtkconfig.cpp configeditor.cpp @@ -19,15 +21,18 @@ ) target_link_libraries(gtkconfig + PRIVATE + KWinBridge PUBLIC Qt5::DBus + Qt5::Svg KF5::CoreAddons KF5::ConfigCore KF5::ConfigWidgets KF5::DBusAddons KF5::IconThemes - PkgConfig::GTK+3 KF5::GuiAddons + PkgConfig::GTK+3 PkgConfig::GIO PkgConfig::GObject ) diff --git a/kded/configeditor.h b/kded/configeditor.h --- a/kded/configeditor.h +++ b/kded/configeditor.h @@ -35,16 +35,21 @@ void setGtk3ConfigValueSettingsIni(const QString ¶mName, const QVariant ¶mValue); void setGtk3ConfigValueXSettingsd(const QString ¶mName, const QVariant ¶mValue); + void setClientSideDecorations(const QStringList &windowDecorationsButtonsImages); void setGtk3Colors(const QMap &colorsDefinitions); QString gtk2ConfigValue(const QString& paramName); QString gtk3ConfigValueSettingsIni(const QString& paramName); void removeLegacyGtk2Strings(); + + void saveWindowDecorationsToAssets(const QStringList &windowDecorationsButtonsImages); + void modifyWindowDecorationsCssFile(); + void addGtkModule(const QString &moduleName); - void addImportStatementToGtkCssUserFile(); + void addImportStatementsToGtkCssUserFile(); void modifyColorsCssFile(const QMap &colorsDefinitions); void replaceValueInGtkrcContents(QString >krcContents, const QString ¶mName, const QVariant ¶mValue); diff --git a/kded/configeditor.cpp b/kded/configeditor.cpp --- a/kded/configeditor.cpp +++ b/kded/configeditor.cpp @@ -75,14 +75,14 @@ void ConfigEditor::setGtk3ConfigValueXSettingsd(const QString ¶mName, const QVariant ¶mValue) { QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); - + QDir xsettingsdPath = configLocation + QStringLiteral("/xsettingsd"); if (!xsettingsdPath.exists()) { xsettingsdPath.mkpath(QStringLiteral(".")); } - + QString xSettingsdConfigPath = xsettingsdPath.path() + QStringLiteral("/xsettingsd.conf"); - + QFile xSettingsdConfig(xSettingsdConfigPath); QString xSettingsdConfigContents = readFileContents(xSettingsdConfig); replaceValueInXSettingsdContents(xSettingsdConfigContents, paramName, paramValue); @@ -107,9 +107,16 @@ reloadGtk2Apps(); } +void ConfigEditor::setClientSideDecorations(const QStringList &windowDecorationsButtonsImages) +{ + saveWindowDecorationsToAssets(windowDecorationsButtonsImages); + addImportStatementsToGtkCssUserFile(); +// modifyWindowDecorationsCssFile(); +} + void ConfigEditor::setGtk3Colors(const QMap &colorsDefinitions) { - addImportStatementToGtkCssUserFile(); + addImportStatementsToGtkCssUserFile(); modifyColorsCssFile(colorsDefinitions); addGtkModule(QStringLiteral("colorreload-gtk-module")); } @@ -172,6 +179,34 @@ reloadGtk2Apps(); } +void ConfigEditor::saveWindowDecorationsToAssets(const QStringList &windowDecorationsButtonsImages) +{ + QDir assetsFolder {QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/gtk-3.0/assets")}; + + if (!assetsFolder.exists()) { + assetsFolder.mkpath(QStringLiteral(".")); + } + + for (const auto &buttonImagePath : windowDecorationsButtonsImages) { + const QString destination = assetsFolder.path() + '/' + QFileInfo(buttonImagePath).fileName(); + QFile(destination).remove(); + QFile(buttonImagePath).rename(buttonImagePath, destination); + } +} + +void ConfigEditor::modifyWindowDecorationsCssFile() +{ + QString windowDecorationsCssPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/gtk-3.0/windowDecorations.css"); + QFile windowDecorationsCss(windowDecorationsCssPath); + + if (windowDecorationsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QTextStream colorsCssStream(&windowDecorationsCss); + + // TODO: Write appropriate css + + } +} + void ConfigEditor::addGtkModule(const QString& moduleName) { const QString currentModulesString = gtk3ConfigValueSettingsIni(QStringLiteral("gtk-modules")); @@ -187,18 +222,24 @@ } } -void ConfigEditor::addImportStatementToGtkCssUserFile() +void ConfigEditor::addImportStatementsToGtkCssUserFile() { QString gtkCssPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/gtk-3.0/gtk.css"); QFile gtkCss(gtkCssPath); if (gtkCss.open(QIODevice::ReadWrite)) { QByteArray gtkCssContents = gtkCss.readAll(); - static const QByteArray importStatement = QByteArrayLiteral("@import 'colors.css';"); - if (!gtkCssContents.contains(importStatement)) { - QTextStream gtkCssStream(>kCss); - gtkCssStream << importStatement; + static const QVector importStatements { + QByteArrayLiteral("\n@import 'colors.css';"), + QByteArrayLiteral("\n@import 'windowDecorations.css';"), + }; + + for (const auto &statement : importStatements) { + if (!gtkCssContents.contains(statement.trimmed())) { + QTextStream gtkCssStream(>kCss); + gtkCssStream << statement; + } } } } diff --git a/kded/configvalueprovider.h b/kded/configvalueprovider.h --- a/kded/configvalueprovider.h +++ b/kded/configvalueprovider.h @@ -39,12 +39,14 @@ bool scrollbarBehavior() const; bool preferDarkTheme() const; QString windowDecorationsButtonsOrder() const; + QStringList windowDecorationsButtonsImages() const; bool enableAnimations() const; QMap colors() const; private: QString fontStyleHelper(const QFont &font) const; QString windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const; + QString currentWindowDecorationPluginPath() const; KSharedConfigPtr kdeglobalsConfig; KSharedConfigPtr inputConfig; diff --git a/kded/configvalueprovider.cpp b/kded/configvalueprovider.cpp --- a/kded/configvalueprovider.cpp +++ b/kded/configvalueprovider.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -33,6 +35,7 @@ #include +#include "dummydecorationbridge.h" #include "configvalueprovider.h" ConfigValueProvider::ConfigValueProvider() : @@ -174,6 +177,49 @@ return windowBackgroundGray < 192; } +QStringList ConfigValueProvider::windowDecorationsButtonsImages() const +{ + static const QVector buttonTypes { + QStringLiteral("close"), + QStringLiteral("maximize"), + QStringLiteral("maximized"), + QStringLiteral("minimize"), + }; + + static const QVector buttonStates { + QStringLiteral("normal"), + QStringLiteral("active"), // aka pressed + QStringLiteral("hover"), + }; + + KConfigGroup decorationGroup = kwinConfig->group(QStringLiteral("org.kde.kdecoration2")); + const QString themeName = decorationGroup.readEntry(QStringLiteral("theme"), QStringLiteral("Breeze")); + + KDecoration2::DummyDecorationBridge kwinBridge {themeName}; + QStringList decorationsImages {}; + + for (const auto &buttonType : buttonTypes) { + for (const auto &buttonState : buttonStates) { + QSvgGenerator svgGenerator {}; + + const QString fileDirPath = QDir::tempPath() + QStringLiteral("/plasma-csd-generator"); + QDir(fileDirPath).mkpath(QStringLiteral(".")); + QString filePath = QStringLiteral("%1/%2-%3.svg").arg(fileDirPath, buttonType, buttonState); + + svgGenerator.setFileName(filePath); + svgGenerator.setViewBox(QRect{0, 0, 17, 17}); + + QPainter painter {&svgGenerator}; + kwinBridge.paintButton(painter, buttonType, buttonState); + painter.end(); + + decorationsImages.append(filePath); + } + } + + return decorationsImages; +} + QString ConfigValueProvider::windowDecorationsButtonsOrder() const { KConfigGroup configGroup = kwinConfig->group(QStringLiteral("org.kde.kdecoration2")); diff --git a/kded/gtkconfig.h b/kded/gtkconfig.h --- a/kded/gtkconfig.h +++ b/kded/gtkconfig.h @@ -45,6 +45,7 @@ void setToolbarStyle() const; void setScrollbarBehavior() const; void setDarkThemePreference() const; + void setWindowDecorationsAppearance() const; void setWindowDecorationsButtonsOrder() const; void setEnableAnimations() const; void setColors() const; diff --git a/kded/gtkconfig.cpp b/kded/gtkconfig.cpp --- a/kded/gtkconfig.cpp +++ b/kded/gtkconfig.cpp @@ -160,6 +160,12 @@ ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-application-prefer-dark-theme"), preferDarkTheme); } +void GtkConfig::setWindowDecorationsAppearance() const +{ + const auto windowDecorationsButtonsImages = configValueProvider->windowDecorationsButtonsImages(); + ConfigEditor::setClientSideDecorations(windowDecorationsButtonsImages); +} + void GtkConfig::setWindowDecorationsButtonsOrder() const { const QString windowDecorationsButtonOrder = configValueProvider->windowDecorationsButtonsOrder(); @@ -193,6 +199,7 @@ setToolbarStyle(); setScrollbarBehavior(); setDarkThemePreference(); + setWindowDecorationsAppearance(); setWindowDecorationsButtonsOrder(); setEnableAnimations(); setColors(); @@ -234,9 +241,14 @@ void GtkConfig::onKWinSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const { - if (group.name() == QStringLiteral("org.kde.kdecoration2") - && (names.contains("ButtonsOnRight") || names.contains("ButtonsOnLeft"))) { - setWindowDecorationsButtonsOrder(); + if (group.name() == QStringLiteral("org.kde.kdecoration2")) { + if (names.contains(QByteArrayLiteral("ButtonsOnRight")) + || names.contains(QByteArrayLiteral("ButtonsOnLeft"))) { + setWindowDecorationsButtonsOrder(); + } + if (names.contains(QByteArrayLiteral("theme"))) { + setWindowDecorationsAppearance(); + } } } diff --git a/kded/kwin_bridge/CMakeLists.txt b/kded/kwin_bridge/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(KWinBridge STATIC + dummydecoratedclient.cpp + dummydecorationbridge.cpp + dummydecorationsettings.cpp + decorationpalette.cpp +) + +target_link_libraries(KWinBridge + PUBLIC + KDecoration2::KDecoration + PRIVATE + KDecoration2::KDecoration2Private + KF5::Service + KF5::ConfigWidgets +) diff --git a/kded/kwin_bridge/decorationpalette.h b/kded/kwin_bridge/decorationpalette.h new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/decorationpalette.h @@ -0,0 +1,70 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2014 Martin Gräßlin +Copyright 2014 Hugo Pereira Da Costa +Copyright 2015 Mika Allan Rauhala + +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_DECORATION_PALETTE_H +#define KWIN_DECORATION_PALETTE_H + +#include +#include +#include + +namespace KWin +{ +namespace Decoration +{ + +class DecorationPalette : public QObject +{ + Q_OBJECT +public: + DecorationPalette(const QString &colorScheme); + + bool isValid() const; + + QColor color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const; + QPalette palette() const; + +Q_SIGNALS: + void changed(); +private: + void update(); + + QString m_colorScheme; + QFileSystemWatcher m_watcher; + + QPalette m_palette; + + QColor m_activeTitleBarColor; + QColor m_inactiveTitleBarColor; + + QColor m_activeFrameColor; + QColor m_inactiveFrameColor; + + QColor m_activeForegroundColor; + QColor m_inactiveForegroundColor; + QColor m_warningForegroundColor; +}; + +} +} + +#endif diff --git a/kded/kwin_bridge/decorationpalette.cpp b/kded/kwin_bridge/decorationpalette.cpp new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/decorationpalette.cpp @@ -0,0 +1,137 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2014 Martin Gräßlin +Copyright 2014 Hugo Pereira Da Costa +Copyright 2015 Mika Allan Rauhala + +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 "decorationpalette.h" + +#include +#include +#include + +#include +#include +#include + +namespace KWin +{ +namespace Decoration +{ + +DecorationPalette::DecorationPalette(const QString &colorScheme) + : m_colorScheme(QFileInfo(colorScheme).isAbsolute() + ? colorScheme + : QStandardPaths::locate(QStandardPaths::GenericConfigLocation, colorScheme)) +{ + if (!m_colorScheme.startsWith(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)) && colorScheme == QStringLiteral("kdeglobals")) { + // kdeglobals doesn't exist so create it. This is needed to monitor it using QFileSystemWatcher. + auto config = KSharedConfig::openConfig(colorScheme, KConfig::SimpleConfig); + KConfigGroup wmConfig(config, QStringLiteral("WM")); + wmConfig.writeEntry("FakeEntryToKeepThisGroup", true); + config->sync(); + + m_colorScheme = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, colorScheme); + } + m_watcher.addPath(m_colorScheme); + connect(&m_watcher, &QFileSystemWatcher::fileChanged, [this]() { + m_watcher.addPath(m_colorScheme); + update(); + emit changed(); + }); + + update(); +} + +bool DecorationPalette::isValid() const +{ + return m_activeTitleBarColor.isValid(); +} + +QColor DecorationPalette::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const +{ + using KDecoration2::ColorRole; + using KDecoration2::ColorGroup; + + switch (role) { + case ColorRole::Frame: + switch (group) { + case ColorGroup::Active: + return m_activeFrameColor; + case ColorGroup::Inactive: + return m_inactiveFrameColor; + default: + return QColor(); + } + case ColorRole::TitleBar: + switch (group) { + case ColorGroup::Active: + return m_activeTitleBarColor; + case ColorGroup::Inactive: + return m_inactiveTitleBarColor; + default: + return QColor(); + } + case ColorRole::Foreground: + switch (group) { + case ColorGroup::Active: + return m_activeForegroundColor; + case ColorGroup::Inactive: + return m_inactiveForegroundColor; + case ColorGroup::Warning: + return m_warningForegroundColor; + default: + return QColor(); + } + default: + return QColor(); + } +} + +QPalette DecorationPalette::palette() const +{ + return m_palette; +} + +void DecorationPalette::update() +{ + auto config = KSharedConfig::openConfig(m_colorScheme, KConfig::SimpleConfig); + KConfigGroup wmConfig(config, QStringLiteral("WM")); + + if (!wmConfig.exists() && !m_colorScheme.endsWith(QStringLiteral("/kdeglobals"))) { +// qCWarning(KWIN_DECORATIONS) << "Invalid color scheme" << m_colorScheme << "lacks WM group"; + return; + } + + m_palette = KColorScheme::createApplicationPalette(config); + + m_activeFrameColor = wmConfig.readEntry("frame", m_palette.color(QPalette::Active, QPalette::Window)); + m_inactiveFrameColor = wmConfig.readEntry("inactiveFrame", m_activeFrameColor); + m_activeTitleBarColor = wmConfig.readEntry("activeBackground", m_palette.color(QPalette::Active, QPalette::Highlight)); + m_inactiveTitleBarColor = wmConfig.readEntry("inactiveBackground", m_inactiveFrameColor); + m_activeForegroundColor = wmConfig.readEntry("activeForeground", m_palette.color(QPalette::Active, QPalette::HighlightedText)); + m_inactiveForegroundColor = wmConfig.readEntry("inactiveForeground", m_activeForegroundColor.darker()); + + KConfigGroup windowColorsConfig(config, QStringLiteral("Colors:Window")); + m_warningForegroundColor = windowColorsConfig.readEntry("ForegroundNegative", QColor(237, 21, 2)); + +} + +} +} diff --git a/kded/kwin_bridge/dummydecoratedclient.h b/kded/kwin_bridge/dummydecoratedclient.h new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/dummydecoratedclient.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 Mikhail Zolotukhin + * + * 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 + +#include "decorationpalette.h" + +namespace KDecoration2 { + +class DummyDecoratedClient : public QObject, public DecoratedClientPrivate { + Q_OBJECT +public: + DummyDecoratedClient(DecoratedClient *client, Decoration *decoration); + + bool isActive() const override; + QString caption() const override; + int desktop() const override; + bool isOnAllDesktops() const override; + bool isShaded() const override; + QIcon icon() const override; + bool isMaximized() const override; + bool isMaximizedHorizontally() const override; + bool isMaximizedVertically() const override; + bool isKeepAbove() const override; + bool isKeepBelow() const override; + + bool isCloseable() const override; + bool isMaximizeable() const override; + bool isMinimizeable() const override; + bool providesContextHelp() const override; + bool isModal() const override; + bool isShadeable() const override; + bool isMoveable() const override; + bool isResizeable() const override; + + WId windowId() const override; + WId decorationId() const override; + + int width() const override; + int height() const override; + QSize size() const override; + QPalette palette() const override; + QColor color(ColorGroup group, ColorRole role) const override; + Qt::Edges adjacentScreenEdges() const override; + + void requestShowToolTip(const QString &text) override; + + void requestHideToolTip() override; + void requestClose() override; + void requestToggleMaximization(Qt::MouseButtons buttons) override; + void requestMinimize() override; + void requestContextHelp() override; + void requestToggleOnAllDesktops() override; + void requestToggleShade() override; + void requestToggleKeepAbove() override; + void requestToggleKeepBelow() override; + void requestShowWindowMenu() override; + + void setMaximized(bool maximized); + +private: + KWin::Decoration::DecorationPalette m_pallete; + bool m_maximized; +}; + +} diff --git a/kded/kwin_bridge/dummydecoratedclient.cpp b/kded/kwin_bridge/dummydecoratedclient.cpp new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/dummydecoratedclient.cpp @@ -0,0 +1,220 @@ +/* + * Copyright 2020 Mikhail Zolotukhin + * + * 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 "dummydecoratedclient.h" + +namespace KDecoration2 { + +DummyDecoratedClient::DummyDecoratedClient(DecoratedClient *client, Decoration *decoration) + : DecoratedClientPrivate(client, decoration) + , m_pallete(QStringLiteral("kdeglobals")) + , m_maximized() +{ + +} + +bool DummyDecoratedClient::isActive() const +{ + return true; +} + +QString DummyDecoratedClient::caption() const +{ + return {}; +} + +int DummyDecoratedClient::desktop() const +{ + return 0; +} + +bool DummyDecoratedClient::isOnAllDesktops() const +{ + return true; +} + +bool DummyDecoratedClient::isShaded() const +{ + return true; +} + +QIcon DummyDecoratedClient::icon() const +{ + return {}; +} + +bool DummyDecoratedClient::isMaximized() const +{ + return m_maximized; +} + +bool DummyDecoratedClient::isMaximizedHorizontally() const +{ + return m_maximized; +} + +bool DummyDecoratedClient::isMaximizedVertically() const +{ + return m_maximized; +} + +bool DummyDecoratedClient::isKeepAbove() const +{ + return true; +} + +bool DummyDecoratedClient::isKeepBelow() const +{ + return true; +} + +bool DummyDecoratedClient::isCloseable() const +{ + return true; +} + +bool DummyDecoratedClient::isMaximizeable() const +{ + return true; +} + +bool DummyDecoratedClient::isMinimizeable() const +{ + return true; +} + +bool DummyDecoratedClient::providesContextHelp() const +{ + return true; +} + +bool DummyDecoratedClient::isModal() const +{ + return true; +} + +bool DummyDecoratedClient::isShadeable() const +{ + return true; +} + +bool DummyDecoratedClient::isMoveable() const +{ + return true; +} + +bool DummyDecoratedClient::isResizeable() const +{ + return true; +} + +WId DummyDecoratedClient::windowId() const +{ + return {}; +} + +WId DummyDecoratedClient::decorationId() const +{ + return {}; +} + +int DummyDecoratedClient::width() const +{ + return {}; +} + +int DummyDecoratedClient::height() const +{ + return {}; +} + +QSize DummyDecoratedClient::size() const +{ + return {}; +} + +QPalette DummyDecoratedClient::palette() const +{ + return m_pallete.palette(); +} + +QColor DummyDecoratedClient::color(ColorGroup group, ColorRole role) const +{ + return m_pallete.color(group, role); +} + +Qt::Edges DummyDecoratedClient::adjacentScreenEdges() const +{ + return {}; +} + +void DummyDecoratedClient::requestShowToolTip(const QString &text) +{ + Q_UNUSED(text) +} + +void DummyDecoratedClient::requestHideToolTip() +{ +} + +void DummyDecoratedClient::requestClose() +{ +} + +void DummyDecoratedClient::requestToggleMaximization(Qt::MouseButtons buttons) +{ + Q_UNUSED(buttons) + m_maximized = !m_maximized; +} + +void DummyDecoratedClient::requestMinimize() +{ +} + +void DummyDecoratedClient::requestContextHelp() +{ +} + +void DummyDecoratedClient::requestToggleOnAllDesktops() +{ +} + +void DummyDecoratedClient::requestToggleShade() +{ +} + +void DummyDecoratedClient::requestToggleKeepAbove() +{ +} + +void DummyDecoratedClient::requestToggleKeepBelow() +{ +} + +void DummyDecoratedClient::requestShowWindowMenu() +{ +} + +void DummyDecoratedClient::setMaximized(bool maximized) +{ + m_maximized = maximized; +} + +} diff --git a/kded/kwin_bridge/dummydecorationbridge.h b/kded/kwin_bridge/dummydecorationbridge.h new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/dummydecorationbridge.h @@ -0,0 +1,64 @@ +/* + * Copyright 2020 Mikhail Zolotukhin + * + * 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 +#include + +class KPluginFactory; + +namespace KDecoration2 +{ + +class DecorationSettings; +class DecoratedClientPrivate; +class DecorationSettingsPrivate; + +class DummyDecorationBridge : public DecorationBridge +{ + Q_OBJECT +public: + DummyDecorationBridge(const QString &decorationTheme, QObject *parent = nullptr); + ~DummyDecorationBridge() override = default; + + std::unique_ptr settings(KDecoration2::DecorationSettings *parent) override; + void update(KDecoration2::Decoration *decoration, const QRect &geometry) override; + std::unique_ptr createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) override; + + void paintButton(QPainter &painter, const QString &buttonType, const QString &buttonState); + +private: + QString windowDecorationPluginPath(const QString &decorationTheme) const; + + void passMouseHoverEventToButton(KDecoration2::DecorationButton *button) const; + void passMousePressEventToButton(KDecoration2::DecorationButton *button) const; + + KDecoration2::DecorationButtonType strToButtonType(const QString &type) const; + + KPluginFactory *m_factory; + KDecoration2::Decoration *m_decoration; + KDecoration2::DecoratedClientPrivate *m_client; +}; + +} + + diff --git a/kded/kwin_bridge/dummydecorationbridge.cpp b/kded/kwin_bridge/dummydecorationbridge.cpp new file mode 100644 --- /dev/null +++ b/kded/kwin_bridge/dummydecorationbridge.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2020 Mikhail Zolotukhin + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dummydecorationbridge.h" +#include "dummydecorationsettings.h" +#include "dummydecoratedclient.h" + +namespace KDecoration2 +{ + +DummyDecorationBridge::DummyDecorationBridge(const QString &decorationTheme, QObject *parent) + : DecorationBridge(parent) + , m_factory() + , m_decoration() + , m_client() +{ + const QString pluginPath = windowDecorationPluginPath(decorationTheme); + KPluginLoader loader {pluginPath}; + m_factory = loader.factory(); + + QVariantMap args({ {QStringLiteral("bridge"), QVariant::fromValue(this)} }); + m_decoration = m_factory->create(m_factory, QVariantList({args})); + + auto decorationSettings = QSharedPointer::create(this); + m_decoration->setSettings(decorationSettings); + m_decoration->init(); +} + +std::unique_ptr< KDecoration2::DecorationSettingsPrivate > DummyDecorationBridge::settings(KDecoration2::DecorationSettings *parent) +{ + return std::unique_ptr(new DummyDecorationSettings(parent)); +} + +void DummyDecorationBridge::update(KDecoration2::Decoration *decoration, const QRect &geometry) +{ + Q_UNUSED(decoration) + Q_UNUSED(geometry) +} + +std::unique_ptr< KDecoration2::DecoratedClientPrivate > DummyDecorationBridge::createClient(KDecoration2::DecoratedClient *client, KDecoration2::Decoration *decoration) +{ + auto ptr = std::unique_ptr(new DummyDecoratedClient(client, decoration)); + m_client = ptr.get(); + return ptr; +} + +void DummyDecorationBridge::paintButton(QPainter &painter, const QString &buttonType, const QString &buttonState) +{ + std::unique_ptr button {m_factory->create( + QStringLiteral("button"), + m_decoration, + QVariantList({ + QVariant::fromValue(strToButtonType(buttonType)), + QVariant::fromValue(m_decoration) + }) + )}; + + if (button == nullptr) { + return; + } + + if (buttonType == QStringLiteral("maximized")) { + // Different decorations use different ways to know if the windows is maximized + // For example Breeze uses 'checked' property, but Oxygen uses client's 'isMaximized' method + button->setChecked(true); + if (m_client) { + dynamic_cast(m_client)->setMaximized(true); + } + } + + if (buttonState == QStringLiteral("active")) { + passMousePressEventToButton(button.get()); + } else if (buttonState == QStringLiteral("hover")) { + passMouseHoverEventToButton(button.get()); + } + + button->paint(&painter, {0, 0, 20, 20}); +} + +QString DummyDecorationBridge::windowDecorationPluginPath(const QString &decorationTheme) const +{ + const auto decorationPlugins = KPluginLoader::findPlugins(QStringLiteral("org.kde.kdecoration2")); + + QString defaultPluginPath; + + for (const auto &pluginMetaData : decorationPlugins) { + if (pluginMetaData.name() == QStringLiteral("Breeze")) { + defaultPluginPath = pluginMetaData.fileName(); + } + + if (pluginMetaData.name() == decorationTheme) { + return pluginMetaData.fileName(); + } + } + return defaultPluginPath; +} + +void DummyDecorationBridge::passMouseHoverEventToButton(KDecoration2::DecorationButton *button) const +{ + QHoverEvent event { + QEvent::HoverEnter, {5, 5}, {4, 4}, Qt::NoModifier + }; + QCoreApplication::instance()->sendEvent(button, &event); +} + +void DummyDecorationBridge::passMousePressEventToButton(KDecoration2::DecorationButton *button) const +{ + QMouseEvent event { + QEvent::MouseButtonPress, + {5, 5}, + Qt::LeftButton, + Qt::LeftButton, + Qt::NoModifier + }; + QCoreApplication::instance()->sendEvent(button, &event); +} + +KDecoration2::DecorationButtonType DummyDecorationBridge::strToButtonType(const QString &type) const +{ + if (type == QStringLiteral("minimize")) { + return KDecoration2::DecorationButtonType::Minimize; + } else if (type == QStringLiteral("close")) { + return KDecoration2::DecorationButtonType::Close; + } else { + return KDecoration2::DecorationButtonType::Maximize; + } +} + +} diff --git a/kded/configvalueprovider.h b/kded/kwin_bridge/dummydecorationsettings.h copy from kded/configvalueprovider.h copy to kded/kwin_bridge/dummydecorationsettings.h --- a/kded/configvalueprovider.h +++ b/kded/kwin_bridge/dummydecorationsettings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Mikhail Zolotukhin + * Copyright 2020 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,33 +20,25 @@ #pragma once -#include +#include +#include -class QString; -class QFont; +namespace KDecoration2 { -class ConfigValueProvider +class DummyDecorationSettings : public KDecoration2::DecorationSettingsPrivate { public: - ConfigValueProvider(); - - QString fontName() const; - QString iconThemeName() const; - QString cursorThemeName() const; - bool iconsOnButtons() const; - bool iconsInMenus() const; - int toolbarStyle() const; - bool scrollbarBehavior() const; - bool preferDarkTheme() const; - QString windowDecorationsButtonsOrder() const; - bool enableAnimations() const; - QMap colors() const; - -private: - QString fontStyleHelper(const QFont &font) const; - QString windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const; - - KSharedConfigPtr kdeglobalsConfig; - KSharedConfigPtr inputConfig; - KSharedConfigPtr kwinConfig; + explicit DummyDecorationSettings(DecorationSettings *parent); + + virtual bool isOnAllDesktopsAvailable() const override; + virtual bool isAlphaChannelSupported() const override; + virtual bool isCloseOnDoubleClickOnMenu() const override; + virtual QVector decorationButtonsLeft() const override; + virtual QVector decorationButtonsRight() const override; + virtual BorderSize borderSize() const override; }; + +} + + + diff --git a/kded/configvalueprovider.h b/kded/kwin_bridge/dummydecorationsettings.cpp copy from kded/configvalueprovider.h copy to kded/kwin_bridge/dummydecorationsettings.cpp --- a/kded/configvalueprovider.h +++ b/kded/kwin_bridge/dummydecorationsettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Mikhail Zolotukhin + * Copyright 2020 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,36 +17,44 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "dummydecorationsettings.h" -#pragma once +namespace KDecoration2 +{ + +DummyDecorationSettings::DummyDecorationSettings(DecorationSettings *parent) + : DecorationSettingsPrivate(parent) +{} + +bool DummyDecorationSettings::isOnAllDesktopsAvailable() const +{ + return false; +} + +bool DummyDecorationSettings::isAlphaChannelSupported() const +{ + return true; +} -#include +bool DummyDecorationSettings::isCloseOnDoubleClickOnMenu() const +{ + return false; +} + +QVector DummyDecorationSettings::decorationButtonsLeft() const +{ + return {}; +} -class QString; -class QFont; +QVector DummyDecorationSettings::decorationButtonsRight() const +{ + return {}; +} -class ConfigValueProvider +BorderSize DummyDecorationSettings::borderSize() const { -public: - ConfigValueProvider(); - - QString fontName() const; - QString iconThemeName() const; - QString cursorThemeName() const; - bool iconsOnButtons() const; - bool iconsInMenus() const; - int toolbarStyle() const; - bool scrollbarBehavior() const; - bool preferDarkTheme() const; - QString windowDecorationsButtonsOrder() const; - bool enableAnimations() const; - QMap colors() const; - -private: - QString fontStyleHelper(const QFont &font) const; - QString windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const; - - KSharedConfigPtr kdeglobalsConfig; - KSharedConfigPtr inputConfig; - KSharedConfigPtr kwinConfig; -}; + return BorderSize::None; +} + + +}