diff --git a/CMakeLists.txt b/CMakeLists.txt index 063b8ba315..3e68b00647 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ set(kwin_KDEINIT_SRCS scripting/screenedgeitem.cpp decorations/decoratedclient.cpp decorations/decorationbridge.cpp + decorations/decorationpalette.cpp decorations/settings.cpp decorations/decorationrenderer.cpp ) diff --git a/client.cpp b/client.cpp index b6af2faf61..8bf10e8058 100644 --- a/client.cpp +++ b/client.cpp @@ -79,6 +79,9 @@ const long ClientWinMask = XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; +QHash> Client::s_palettes; +std::shared_ptr Client::s_defaultPalette; + // Creating a client: // - only by calling Workspace::createClient() // - it creates a new client and calls manage() for it @@ -138,7 +141,7 @@ Client::Client() , needsXWindowMove(false) , m_decoInputExtent() , m_focusOutTimer(nullptr) - , m_palette(QApplication::palette()) + , m_colorScheme(QStringLiteral("kdeglobals")) , m_clientSideDecorated(false) { // TODO: Do all as initialization @@ -2257,15 +2260,43 @@ void Client::readColorScheme(Xcb::StringProperty &property) { QString path = QString::fromUtf8(property); path = rules()->checkDecoColor(path); - QPalette p = m_palette; - if (!path.isEmpty()) { - p = KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path)); - } else { - p = QApplication::palette(); + + if (path.isEmpty()) { + path = QStringLiteral("kdeglobals"); } - if (p != m_palette) { - m_palette = p; - emit paletteChanged(m_palette); + + if (!m_palette || m_colorScheme != path) { + m_colorScheme = path; + + if (m_palette) { + disconnect(m_palette.get(), &Decoration::DecorationPalette::changed, this, &Client::handlePaletteChange); + } + + auto it = s_palettes.find(m_colorScheme); + + if (it == s_palettes.end() || it->expired()) { + m_palette = std::make_shared(m_colorScheme); + if (m_palette->isValid()) { + s_palettes[m_colorScheme] = m_palette; + } else { + if (!s_defaultPalette) { + s_defaultPalette = std::make_shared(QStringLiteral("kdeglobals")); + s_palettes[QStringLiteral("kdeglobals")] = s_defaultPalette; + } + + m_palette = s_defaultPalette; + } + + if (m_colorScheme == QStringLiteral("kdeglobals")) { + s_defaultPalette = m_palette; + } + } else { + m_palette = it->lock(); + } + + connect(m_palette.get(), &Decoration::DecorationPalette::changed, this, &Client::handlePaletteChange); + + emit paletteChanged(palette()); triggerDecorationRepaint(); } } @@ -2276,6 +2307,12 @@ void Client::updateColorScheme() readColorScheme(property); } +void Client::handlePaletteChange() +{ + emit paletteChanged(palette()); + triggerDecorationRepaint(); +} + bool Client::isClient() const { return true; diff --git a/client.h b/client.h index 6b947fed2d..b574aa26ab 100644 --- a/client.h +++ b/client.h @@ -28,6 +28,7 @@ along with this program. If not, see . #include "tabgroup.h" #include "toplevel.h" #include "xcbutils.h" +#include "decorations/decorationpalette.h" // Qt #include #include @@ -671,6 +672,7 @@ public: void cancelFocusOutTimer(); QPalette palette() const; + const Decoration::DecorationPalette *decorationPalette() const; /** * Restores the Client after it had been hidden due to show on screen edge functionality. @@ -881,6 +883,8 @@ private: **/ void updateShowOnScreenEdge(); + void handlePaletteChange(); + Xcb::Window m_client; Xcb::Window m_wrapper; Xcb::Window m_frame; @@ -1025,7 +1029,11 @@ private: QTimer *m_focusOutTimer; - QPalette m_palette; + QString m_colorScheme; + std::shared_ptr m_palette; + static QHash> s_palettes; + static std::shared_ptr s_defaultPalette; + QList m_connections; bool m_clientSideDecorated; }; @@ -1278,7 +1286,12 @@ inline bool Client::hiddenPreview() const inline QPalette Client::palette() const { - return m_palette; + return m_palette->palette(); +} + +inline const Decoration::DecorationPalette *Client::decorationPalette() const +{ + return m_palette.get(); } template diff --git a/decorations/decoratedclient.cpp b/decorations/decoratedclient.cpp index a30e6fe8b4..83b7ea175d 100644 --- a/decorations/decoratedclient.cpp +++ b/decorations/decoratedclient.cpp @@ -166,6 +166,16 @@ DELEGATE(requestClose, closeWindow) #undef DELEGATE +QColor DecoratedClientImpl::color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const +{ + auto dp = m_client->decorationPalette(); + if (dp) { + return dp->color(group, role); + } + + return QColor(); +} + void DecoratedClientImpl::requestShowWindowMenu() { // TODO: add rect to requestShowWindowMenu diff --git a/decorations/decoratedclient.h b/decorations/decoratedclient.h index 898c9c58dd..cb585cfe28 100644 --- a/decorations/decoratedclient.h +++ b/decorations/decoratedclient.h @@ -61,6 +61,7 @@ public: bool isShadeable() const override; bool isShaded() const override; QPalette palette() const override; + QColor color(KDecoration2::ColorGroup group, KDecoration2::ColorRole role) const override; bool providesContextHelp() const override; int width() const override; WId windowId() const override; diff --git a/decorations/decorationpalette.cpp b/decorations/decorationpalette.cpp new file mode 100644 index 0000000000..de7e560c50 --- /dev/null +++ b/decorations/decorationpalette.cpp @@ -0,0 +1,129 @@ +/******************************************************************** + 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 +#include + +namespace KWin +{ +namespace Decoration +{ + +DecorationPalette::DecorationPalette(const QString &colorScheme) + : m_colorScheme(QFileInfo(colorScheme).isAbsolute() + ? 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()) { + qWarning() << "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::Background)); + 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.dark()); + + KConfigGroup windowColorsConfig(config, QStringLiteral("Colors:Window")); + m_warningForegroundColor = windowColorsConfig.readEntry("ForegroundNegative", QColor(237, 21, 2)); + +} + +} +} diff --git a/decorations/decorationpalette.h b/decorations/decorationpalette.h new file mode 100644 index 0000000000..f652c4e33a --- /dev/null +++ b/decorations/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/kcmkwin/kwindecoration/declarative-plugin/CMakeLists.txt b/kcmkwin/kwindecoration/declarative-plugin/CMakeLists.txt index 22512a0cb5..701057fa30 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/CMakeLists.txt +++ b/kcmkwin/kwindecoration/declarative-plugin/CMakeLists.txt @@ -6,6 +6,7 @@ set(plugin_SRCS previewsettings.cpp plugin.cpp buttonsmodel.cpp + ../../../decorations/decorationpalette.cpp ) add_library(kdecorationprivatedeclarative SHARED ${plugin_SRCS}) diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp index 3bcddefd2f..146915f533 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp +++ b/kcmkwin/kwindecoration/declarative-plugin/previewclient.cpp @@ -41,6 +41,7 @@ PreviewClient::PreviewClient(DecoratedClient *c, Decoration *decoration) , m_colorSchemeIndex(0) , m_icon(QIcon::fromTheme(QStringLiteral("start-here-kde"))) , m_iconName(m_icon.name()) + , m_palette(QStringLiteral("kdeglobals")) , m_active(true) , m_closeable(true) , m_keepBelow(false) @@ -107,14 +108,9 @@ PreviewClient::PreviewClient(DecoratedClient *c, Decoration *decoration) emit onAllDesktopsChanged(isOnAllDesktops()); } ); - connect(this, &PreviewClient::colorSchemeIndexChanged, this, - [this]() { - const QModelIndex index = m_colorSchemeManager->model()->index(m_colorSchemeIndex, 0); - qDebug() << "Scheme: " << index.data(Qt::UserRole).toString(); - m_palette = KColorScheme::createApplicationPalette(KSharedConfig::openConfig(index.data(Qt::UserRole).toString())); - emit paletteChanged(m_palette); - } - ); + connect(&m_palette, &KWin::Decoration::DecorationPalette::changed, [this]() { + emit paletteChanged(m_palette.palette()); + }); auto emitEdgesChanged = [this, c]() { c->adjacentScreenEdgesChanged(adjacentScreenEdges()); }; @@ -268,7 +264,12 @@ WId PreviewClient::windowId() const QPalette PreviewClient::palette() const { - return m_palette; + return m_palette.palette(); +} + +QColor PreviewClient::color(ColorGroup group, ColorRole role) const +{ + return m_palette.color(group, role); } QAbstractItemModel *PreviewClient::colorSchemeModel() const @@ -453,14 +454,5 @@ SETTER2(setProvidesContextHelp, providesContextHelp) #undef SETTER2 #undef SETTER -bool PreviewClient::eventFilter(QObject *watched, QEvent *e) -{ - if (e->type() == QEvent::ApplicationPaletteChange) { - m_palette = QPalette(); - emit paletteChanged(m_palette); - } - return false; -} - } // namespace Preview } // namespace KDecoration2 diff --git a/kcmkwin/kwindecoration/declarative-plugin/previewclient.h b/kcmkwin/kwindecoration/declarative-plugin/previewclient.h index c55a3b7bb8..806a4fbd3f 100644 --- a/kcmkwin/kwindecoration/declarative-plugin/previewclient.h +++ b/kcmkwin/kwindecoration/declarative-plugin/previewclient.h @@ -20,6 +20,8 @@ #ifndef KDECOARTIONS_PREVIEW_CLIENT_H #define KDECOARTIONS_PREVIEW_CLIENT_H +#include "../../../decorations/decorationpalette.h" + #include #include #include @@ -92,6 +94,7 @@ public: int width() const override; int height() const override; QPalette palette() const override; + QColor color(ColorGroup group, ColorRole role) const override; Qt::Edges adjacentScreenEdges() const override; void requestClose() override; @@ -142,8 +145,6 @@ public: void setBordersRightEdge(bool enabled); void setBordersBottomEdge(bool enabled); - bool eventFilter(QObject *watched, QEvent *e) override; - Q_SIGNALS: void captionChanged(const QString &); void iconChanged(const QIcon &); @@ -184,7 +185,7 @@ private: QString m_caption; QIcon m_icon; QString m_iconName; - QPalette m_palette; + KWin::Decoration::DecorationPalette m_palette; bool m_active; bool m_closeable; bool m_keepBelow; diff --git a/manage.cpp b/manage.cpp index 8b1a2ee9cc..c8e74cb84d 100644 --- a/manage.cpp +++ b/manage.cpp @@ -377,6 +377,8 @@ bool Client::manage(xcb_window_t w, bool isMapped) } } + readColorScheme(colorSchemeCookie); + updateDecoration(false); // Also gravitates // TODO: Is CentralGravity right here, when resizing is done after gravitating? plainResize(rules()->checkSize(sizeForClientSize(geom.size()), !isMapped)); @@ -641,7 +643,6 @@ bool Client::manage(xcb_window_t w, bool isMapped) updateWindowRules(Rules::All); // Was blocked while !isManaged() setBlockingCompositing(info->isBlockingCompositing()); - readColorScheme(colorSchemeCookie); readShowOnScreenEdge(showOnScreenEdgeCookie); // TODO: there's a small problem here - isManaged() depends on the mapping state,