diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b82bde63c..d7172ca54 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -18,6 +18,7 @@ set(lattedock-app_SRCS importer.cpp infoview.cpp launcherssignals.cpp + schemecolors.cpp layoutsDelegates/checkboxdelegate.cpp layoutsDelegates/colorcmbboxdelegate.cpp layoutsDelegates/colorcmbboxitemdelegate.cpp diff --git a/app/abstractwindowinterface.cpp b/app/abstractwindowinterface.cpp index d0cdf34a8..4f8f8b7c5 100644 --- a/app/abstractwindowinterface.cpp +++ b/app/abstractwindowinterface.cpp @@ -32,10 +32,24 @@ namespace Latte { AbstractWindowInterface::AbstractWindowInterface(QObject *parent) : QObject(parent) { + QString defaultSchemePath = SchemeColors::possibleSchemeFile("kdeglobals"); + SchemeColors *dScheme = new SchemeColors(this, defaultSchemePath); + + m_schemes["kdeglobals"] = dScheme; + m_schemes[defaultSchemePath] = dScheme; + + connect(this, &AbstractWindowInterface::windowRemoved, this, [&](WindowId wid) { + m_windowScheme.remove(wid); + }); } AbstractWindowInterface::~AbstractWindowInterface() { + m_windowScheme.clear(); + //! it is just a reference to a real scheme file + m_schemes.take("kdeglobals"); + qDeleteAll(m_schemes); + m_schemes.clear(); } void AbstractWindowInterface::addDock(WindowId wid) @@ -51,5 +65,40 @@ void AbstractWindowInterface::removeDock(WindowId wid) m_docks.erase(it); } + +//! Scheme support for windows +SchemeColors *AbstractWindowInterface::schemeForWindow(WindowId wid) +{ + if (!m_windowScheme.contains(wid)) { + return m_schemes["kdeglobals"]; + } else { + return m_schemes[m_windowScheme[wid]]; + } + + return nullptr; +} + +void AbstractWindowInterface::setColorSchemeForWindow(WindowId wid, QString scheme) +{ + if (scheme == "kdeglobals" && !m_windowScheme.contains(wid)) { + //default scheme does not have to be set + return; + } + + if (scheme == "kdeglobals") { + //! a window that previously had an explicit set scheme now is set back to default scheme + m_windowScheme.remove(wid); + } else { + QString schemeFile = SchemeColors::possibleSchemeFile(scheme); + + if (!m_schemes.contains(schemeFile)) { + //! when this scheme file has not been loaded yet + m_schemes[schemeFile] = new SchemeColors(this, schemeFile); + } + + m_windowScheme[wid] = schemeFile; + } +} + } diff --git a/app/abstractwindowinterface.h b/app/abstractwindowinterface.h index 1fbadae61..998c704c2 100644 --- a/app/abstractwindowinterface.h +++ b/app/abstractwindowinterface.h @@ -21,6 +21,7 @@ #ifndef ABSTRACTWINDOWINTERFACE_H #define ABSTRACTWINDOWINTERFACE_H +#include "schemecolors.h" #include "windowinfowrap.h" #include "../liblattedock/dock.h" #include "../liblattedock/extras.h" @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +85,9 @@ public: void addDock(WindowId wid); void removeDock(WindowId wid); + SchemeColors *schemeForWindow(WindowId wId); + void setColorSchemeForWindow(WindowId wId, QString scheme); + signals: void activeWindowChanged(WindowId wid); void windowChanged(WindowId winfo); @@ -95,6 +100,14 @@ protected: std::list m_windows; std::list m_docks; QPointer m_activities; + +private: + //! scheme file and its loaded colors + QMap m_schemes; + + //! window id and its corresponding scheme file + QMap m_windowScheme; + }; // namespace alias diff --git a/app/dbus/org.kde.LatteDock.xml b/app/dbus/org.kde.LatteDock.xml index fac1b171c..f7dff0483 100644 --- a/app/dbus/org.kde.LatteDock.xml +++ b/app/dbus/org.kde.LatteDock.xml @@ -7,6 +7,9 @@ + + + diff --git a/app/dock/visibilitymanager.cpp b/app/dock/visibilitymanager.cpp index 995bc0381..75d420d6d 100644 --- a/app/dock/visibilitymanager.cpp +++ b/app/dock/visibilitymanager.cpp @@ -777,6 +777,17 @@ void VisibilityManagerPrivate::setExistsWindowSnapped(bool windowSnapped) emit q->existsWindowSnappedChanged(); } +void VisibilityManagerPrivate::setTouchingWindowScheme(SchemeColors *scheme) +{ + if (touchingScheme == scheme) { + return; + } + + touchingScheme = scheme; + + emit q->touchingWindowSchemeChanged(); +} + void VisibilityManagerPrivate::updateAvailableScreenGeometry() { if (!view || !view->containment()) { @@ -854,6 +865,8 @@ void VisibilityManagerPrivate::updateDynamicBackgroundWindowFlags() //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! maybe a garbage collector here is a good idea!!! bool existsFaultyWindow{false}; + WindowId maxWinId; + WindowId snapWinId; for (const auto &winfo : windows) { if (winfo.isValid() && !winfo.isMinimized() && wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { @@ -861,6 +874,7 @@ void VisibilityManagerPrivate::updateDynamicBackgroundWindowFlags() //! updated implementation to identify the screen that the maximized window is present //! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700 foundMaximized = true; + maxWinId = winfo.wid(); } bool touchingPanelEdge{false}; @@ -883,6 +897,7 @@ void VisibilityManagerPrivate::updateDynamicBackgroundWindowFlags() if (((winfo.isActive() || winfo.isKeepAbove()) && touchingPanelEdge) || (!winfo.isActive() && snappedWindowsGeometries.contains(winfo.geometry()))) { foundSnap = true; + snapWinId = winfo.wid(); } } @@ -906,6 +921,17 @@ void VisibilityManagerPrivate::updateDynamicBackgroundWindowFlags() setExistsWindowMaximized(foundMaximized); setExistsWindowSnapped(foundSnap); + + //! update color scheme for touching window + + if (foundSnap) { + //! first the snap one because that would mean it is active + setTouchingWindowScheme(wm->schemeForWindow(snapWinId)); + } else if (foundMaximized) { + setTouchingWindowScheme(wm->schemeForWindow(maxWinId)); + } else { + setTouchingWindowScheme(nullptr); + } } //! KWin Edges Support functions @@ -1109,6 +1135,11 @@ bool VisibilityManager::existsWindowSnapped() const return d->windowIsSnappedFlag; } +SchemeColors *VisibilityManager::touchingWindowScheme() const +{ + return d->touchingScheme; +} + //! KWin Edges Support functions bool VisibilityManager::enableKWinEdges() const { diff --git a/app/dock/visibilitymanager.h b/app/dock/visibilitymanager.h index 26c3ca8d3..456cabc14 100644 --- a/app/dock/visibilitymanager.h +++ b/app/dock/visibilitymanager.h @@ -22,6 +22,8 @@ #define VISIBILITYMANAGER_H #include "../plasmaquick/containmentview.h" +#include "../schemecolors.h" +#include "../windowinfowrap.h" #include "../../liblattedock/dock.h" #include @@ -48,6 +50,7 @@ class VisibilityManager : public QObject Q_PROPERTY(bool enabledDynamicBackground READ enabledDynamicBackground WRITE setEnabledDynamicBackground NOTIFY enabledDynamicBackgroundChanged) Q_PROPERTY(bool existsWindowMaximized READ existsWindowMaximized NOTIFY existsWindowMaximizedChanged) Q_PROPERTY(bool existsWindowSnapped READ existsWindowSnapped NOTIFY existsWindowSnappedChanged) + Q_PROPERTY(SchemeColors *touchingWindowScheme READ touchingWindowScheme NOTIFY touchingWindowSchemeChanged) //! KWin Edges Support Options Q_PROPERTY(bool enableKWinEdges READ enableKWinEdges WRITE setEnableKWinEdges NOTIFY enableKWinEdgesChanged) @@ -93,6 +96,8 @@ public: bool existsWindowMaximized() const; bool existsWindowSnapped() const; + SchemeColors *touchingWindowScheme() const; + //! KWin Edges Support functions bool enableKWinEdges() const; void setEnableKWinEdges(bool enable); @@ -111,6 +116,7 @@ signals: void containsMouseChanged(); void timerShowChanged(); void timerHideChanged(); + void touchingWindowSchemeChanged(); //! Dynamic Background signals (from options) void enabledDynamicBackgroundChanged(); diff --git a/app/dock/visibilitymanager_p.h b/app/dock/visibilitymanager_p.h index 39e591020..4efc18fa2 100644 --- a/app/dock/visibilitymanager_p.h +++ b/app/dock/visibilitymanager_p.h @@ -1,8 +1,9 @@ #ifndef VISIBILITYMANAGERPRIVATE_H #define VISIBILITYMANAGERPRIVATE_H -#include "../windowinfowrap.h" #include "../abstractwindowinterface.h" +#include "../schemecolors.h" +#include "../windowinfowrap.h" #include "../../liblattedock/dock.h" #include @@ -55,6 +56,7 @@ public: void setEnabledDynamicBackground(bool active); void setExistsWindowMaximized(bool windowMaximized); void setExistsWindowSnapped(bool windowSnapped); + void setTouchingWindowScheme(SchemeColors *scheme); void updateAvailableScreenGeometry(); void updateDynamicBackgroundWindowFlags(); @@ -112,6 +114,8 @@ public: QList snappedWindowsGeometries; std::array connectionsDynBackground; WindowId lastActiveWindowWid; + SchemeColors *touchingScheme{nullptr}; + //! KWin Edges bool enableKWinEdgesFromUser{true}; diff --git a/app/dockcorona.cpp b/app/dockcorona.cpp index 82c1722ad..bee457e1d 100644 --- a/app/dockcorona.cpp +++ b/app/dockcorona.cpp @@ -866,6 +866,15 @@ void DockCorona::activateLauncherMenu() m_globalShortcuts->activateLauncherMenu(); } +void DockCorona::windowColorScheme(QString windowIdAndScheme) +{ + int firstSlash = windowIdAndScheme.indexOf("-"); + QString windowIdStr = windowIdAndScheme.mid(0,firstSlash); + QString schemeStr = windowIdAndScheme.mid(firstSlash+1); + + m_wm->setColorSchemeForWindow(windowIdStr, schemeStr); +} + //! update badge for specific dock item void DockCorona::updateDockItemBadge(QString identifier, QString value) { diff --git a/app/dockcorona.h b/app/dockcorona.h index 7b4f0d4ff..8309a8109 100644 --- a/app/dockcorona.h +++ b/app/dockcorona.h @@ -113,6 +113,8 @@ public: public slots: void aboutApplication(); void activateLauncherMenu(); + //! they are separated with a "-" character + void windowColorScheme(QString windowIdAndScheme); void loadDefaultLayout() override; void updateDockItemBadge(QString identifier, QString value); void unload(); diff --git a/app/schemecolors.cpp b/app/schemecolors.cpp new file mode 100644 index 000000000..37e8f0ae8 --- /dev/null +++ b/app/schemecolors.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2018 Michail Vourlakos + * + * This file is part of Latte-Dock + * + * Latte-Dock 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. + * + * Latte-Dock 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 "schemecolors.h" + +#include +#include +#include + +#include +#include + +namespace Latte { + +SchemeColors::SchemeColors(QObject *parent, QString scheme) : + QObject(parent) +{ + QString pSchemeFile = possibleSchemeFile(scheme); + + if (QFileInfo(pSchemeFile).exists()) { + m_schemeFile = pSchemeFile; + m_schemeName = scheme; + } + + updateScheme(); +} + +SchemeColors::~SchemeColors() +{ +/// +} + +QColor SchemeColors::backgroundColor() const +{ + return subgroup() == Active ? m_activeBackgroundColor : m_inactiveBackgroundColor; +} + +QColor SchemeColors::foregroundColor() const +{ + return subgroup() == Active ? m_activeForegroundColor : m_inactiveForegroundColor; +} + +QString SchemeColors::schemeName() +{ + return m_schemeName; +} + +QString SchemeColors::schemeFile() +{ + return m_schemeFile; +} + +SchemeColors::ColorsSubgroup SchemeColors::subgroup() const +{ + return m_subgroup; +} + +void SchemeColors::setSubgroup(ColorsSubgroup subgroup) +{ + if (m_subgroup == subgroup) { + return; + } + + m_subgroup = subgroup; + emit colorsChanged(); +} + + +QString SchemeColors::possibleSchemeFile(QString scheme) +{ + if (scheme.startsWith("/") && scheme.endsWith(".colors") && QFileInfo(scheme).exists()) { + return scheme; + } + + QString tempScheme = scheme; + + if (scheme == "kdeglobals") { + QString settingsFile = QDir::homePath() + "/.config/kdeglobals"; + + if (QFileInfo(settingsFile).exists()) { + KSharedConfigPtr filePtr = KSharedConfig::openConfig(settingsFile); + KConfigGroup generalGroup = KConfigGroup(filePtr, "General"); + tempScheme = generalGroup.readEntry("ColorScheme", ""); + } + } + + //! remove all whitespaces and "-" from scheme in order to access correctly its file + QString schemeNameSimplified = tempScheme.simplified().remove(" ").remove("-"); + + QString localSchemePath = QDir::homePath() + "/.local/share/color-schemes/" + schemeNameSimplified + ".colors"; + QString globalSchemePath = "/usr/share/color-schemes/" + schemeNameSimplified + ".colors"; + + if (QFileInfo(localSchemePath).exists()) { + return localSchemePath; + } else if (QFileInfo(globalSchemePath).exists()) { + return globalSchemePath; + } + + return ""; +} + +void SchemeColors::updateScheme() +{ + if (m_schemeFile.isEmpty() || !QFileInfo(m_schemeFile).exists()) { + return; + } + + KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_schemeFile); + KConfigGroup wmGroup = KConfigGroup(filePtr, "WM"); + + m_activeBackgroundColor = wmGroup.readEntry("activeBackground", QColor()); + m_activeForegroundColor = wmGroup.readEntry("activeForeground", QColor()); + + m_inactiveBackgroundColor = wmGroup.readEntry("inactiveBackground", QColor()); + m_inactiveForegroundColor = wmGroup.readEntry("inactiveForeground", QColor()); + + emit colorsChanged(); +} + +} diff --git a/app/schemecolors.h b/app/schemecolors.h new file mode 100644 index 000000000..1d065a6d5 --- /dev/null +++ b/app/schemecolors.h @@ -0,0 +1,78 @@ +/* + * Copyright 2018 Michail Vourlakos + * + * This file is part of Latte-Dock + * + * Latte-Dock 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. + * + * Latte-Dock 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 SCHEMECOLORS_H +#define SCHEMECOLORS_H + +#include +#include + +namespace Latte { + +class SchemeColors: public QObject +{ + Q_OBJECT + Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY colorsChanged) + Q_PROPERTY(QColor foregroundColor READ foregroundColor NOTIFY colorsChanged) + +public: + enum ColorsSubgroup + { + Active = 0, + Inactive = 1 + }; + Q_ENUM(ColorsSubgroup); + + SchemeColors(QObject *parent, QString scheme); + ~SchemeColors() override; + + QString schemeName(); + QString schemeFile(); + + QColor backgroundColor() const; + QColor foregroundColor() const; + + SchemeColors::ColorsSubgroup subgroup() const; + void setSubgroup(SchemeColors::ColorsSubgroup subgroup); + + static QString possibleSchemeFile(QString scheme); + +signals: + void colorsChanged(); + +private slots: + void updateScheme(); + +private: + QString m_schemeName; + QString m_schemeFile; + + QColor m_activeBackgroundColor; + QColor m_activeForegroundColor; + + QColor m_inactiveBackgroundColor; + QColor m_inactiveForegroundColor; + + ColorsSubgroup m_subgroup{SchemeColors::Active}; +}; + +} + +#endif diff --git a/containment/package/contents/ui/PanelBox.qml b/containment/package/contents/ui/PanelBox.qml index 183db2a30..5e418b468 100644 --- a/containment/package/contents/ui/PanelBox.qml +++ b/containment/package/contents/ui/PanelBox.qml @@ -473,6 +473,15 @@ Item{ } } + Rectangle { + anchors.fill: solidBackground + opacity: showColoredPanel ? solidBackground.opacity : 0 + color: showColoredPanel ? dock.visibility.touchingWindowScheme.backgroundColor : "#00000000" + + readonly property bool showColoredPanel: dock && dock.visibility && (dock.visibility.existsWindowMaximized || dock.visibility.existsWindowSnapped) + && !hasExpandedApplet + } + PlasmaCore.FrameSvgItem{ id: hiddenPanelBackground imagePath: "widgets/panel-background" diff --git a/containment/package/contents/ui/main.qml b/containment/package/contents/ui/main.qml index f5bc13e66..97ac42486 100644 --- a/containment/package/contents/ui/main.qml +++ b/containment/package/contents/ui/main.qml @@ -1736,10 +1736,17 @@ DragDrop.DropArea { Loader{ id: colorizerLoader - active: forceColorizer + active: forceColorizer || forceSolidnessAndColorize anchors.fill: layoutsContainer z: layoutsContainer.z + 1 + readonly property bool forceSolidness: (root.solidPanel && !plasmoid.configuration.solidBackgroundForMaximized) || root.forceSolidPanel + || !Latte.WindowSystem.compositingActive + readonly property bool forceSolidnessAndColorize: forceSolidness && dock && dock.visibility + && (dock.visibility.existsWindowMaximized || dock.visibility.existsWindowSnapped) + && !root.hasExpandedApplet + + // formula for luminance according to: // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef property real textColorRs: { @@ -1801,7 +1808,7 @@ DragDrop.DropArea { readonly property real themeTextColorLuma: 0.2126*textColorRs + 0.7152*textColorGs + 0.0722*textColorBs readonly property color minimizedDotColor: themeTextColorLuma > 0.6 ? Qt.darker(theme.textColor, 1.7) : Qt.lighter(theme.textColor, 7) - property bool isShown: active && !forceSolidPanel + property bool isShown: active && (!forceSolidPanel || forceSolidnessAndColorize) //! when forceSemiTransparentPanel is enabled because of snapped or maximized etc. windows //! then the colorizer could be enabled for low panel transparency levels (<40%) && (!userShowPanelBackground || !forceSemiTransparentPanel || (forceSemiTransparentPanel && root.panelTransparency<40)) @@ -1815,6 +1822,10 @@ DragDrop.DropArea { property color themeDarkColor: themeBackgroundColorLuma > themeTextColorLuma ? theme.textColor : theme.backgroundColor property color applyColor: { + if (forceSolidnessAndColorize && dock.visibility.touchingWindowScheme) { + return dock.visibility.touchingWindowScheme.foregroundColor; + } + if (currentBackgroundLuminas>=0) { var textAbs = Math.abs(themeTextColorLuma - currentBackgroundLuminas); var backAbs = Math.abs(themeBackgroundColorLuma - currentBackgroundLuminas);