diff --git a/liblatte2/commontools.cpp b/liblatte2/commontools.cpp index c97b56c0..21ebf4f8 100644 --- a/liblatte2/commontools.cpp +++ b/liblatte2/commontools.cpp @@ -1,74 +1,104 @@ /* * 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 "commontools.h" // Qt +#include +#include #include namespace Latte { float colorBrightness(QColor color) { return colorBrightness(color.red(), color.green(), color.blue()); } float colorBrightness(QRgb rgb) { return colorBrightness(qRed(rgb), qGreen(rgb), qBlue(rgb)); } float colorBrightness(float r, float g, float b) { float brightness = (r * 299 + g * 587 + b * 114) / 1000; return brightness; } float colorLumina(QRgb rgb) { float r = (float)(qRed(rgb)) / 255; float g = (float)(qGreen(rgb)) / 255; float b = (float)(qBlue(rgb)) / 255; return colorLumina(r, g, b); } float colorLumina(QColor color) { return colorLumina(color.redF(), color.greenF(), color.blueF()); } float colorLumina(float r, float g, float b) { // formula for luminance according to: // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef float rS = (r <= 0.03928 ? r / 12.92 : qPow(((r + 0.055) / 1.055), 2.4)); float gS = (g <= 0.03928 ? g / 12.92 : qPow(((g + 0.055) / 1.055), 2.4)); float bS = (b <= 0.03928 ? b / 12.92 : qPow(((b + 0.055) / 1.055), 2.4)); float luminosity = 0.2126 * rS + 0.7152 * gS + 0.0722 * bS; return luminosity; } +QString standardPath(QString subPath, bool localfirst) +{ + QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + + if (localfirst) { + foreach (auto pt, paths) { + QString ptF = pt + "/" +subPath; + if (QFileInfo(ptF).exists()) { + return ptF; + } + } + } else { + for (int i=paths.count()-1; i>=0; i--) { + QString ptF = paths[i] + "/" +subPath; + if (QFileInfo(ptF).exists()) { + return ptF; + } + } + } + + //! in any case that above fails + if (QFileInfo("/usr/share/"+subPath).exists()) { + return "/usr/share/"+subPath; + } + + return ""; +} + } diff --git a/liblatte2/commontools.h b/liblatte2/commontools.h index bb70e771..ee61f93f 100644 --- a/liblatte2/commontools.h +++ b/liblatte2/commontools.h @@ -1,34 +1,37 @@ /* * 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 . * */ // Qt #include namespace Latte { float colorBrightness(QColor color); float colorBrightness(QRgb rgb); float colorBrightness(float r, float g, float b); float colorLumina(QColor color); float colorLumina(QRgb rgb); float colorLumina(float r, float g, float b); +//! returns the standard path found that contains the subPath +//! local paths have higher priority by default +QString standardPath(QString subPath, bool localFirst = true); } diff --git a/liblatte2/plasma/extended/backgroundcache.cpp b/liblatte2/plasma/extended/backgroundcache.cpp index 6bb3cde7..87a539f5 100644 --- a/liblatte2/plasma/extended/backgroundcache.cpp +++ b/liblatte2/plasma/extended/backgroundcache.cpp @@ -1,463 +1,462 @@ /* * 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 "backgroundcache.h" // local #include "../../commontools.h" -#include "../../../app/importer.h" // Qt #include #include #include #include #include #include // Plasma #include // KDE #include #include #define MAXHASHSIZE 300 #define PLASMACONFIG "plasma-org.kde.plasma.desktop-appletsrc" #define DEFAULTWALLPAPER "wallpapers/Next/contents/images/1920x1080.png" namespace Latte{ namespace PlasmaExtended { BackgroundCache::BackgroundCache(QObject *parent) : QObject(parent), m_initialized(false), m_plasmaConfig(KSharedConfig::openConfig(PLASMACONFIG)) { const auto configFile = QStandardPaths::writableLocation( QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + PLASMACONFIG; - m_defaultWallpaperPath = Importer::standardPath(DEFAULTWALLPAPER); + m_defaultWallpaperPath = Latte::standardPath(DEFAULTWALLPAPER); qDebug() << "Default Wallpaper path ::: " << m_defaultWallpaperPath; KDirWatch::self()->addFile(configFile); connect(KDirWatch::self(), &KDirWatch::dirty, this, &BackgroundCache::settingsFileChanged); connect(KDirWatch::self(), &KDirWatch::created, this, &BackgroundCache::settingsFileChanged); if (!m_pool) { m_pool = new ScreenPool(this); } reload(); } BackgroundCache::~BackgroundCache() { if (m_pool) { m_pool->deleteLater(); } } BackgroundCache *BackgroundCache::self() { static BackgroundCache cache; return &cache; } void BackgroundCache::settingsFileChanged(const QString &file) { if (!file.endsWith(PLASMACONFIG)) { return; } if (m_initialized) { m_plasmaConfig->reparseConfiguration(); reload(); } } QString BackgroundCache::backgroundFromConfig(const KConfigGroup &config, QString wallpaperPlugin) const { auto wallpaperConfig = config.group("Wallpaper").group(wallpaperPlugin).group("General"); if (wallpaperConfig.hasKey("Image")) { // Trying for the wallpaper auto wallpaper = wallpaperConfig.readEntry("Image", QString()); if (!wallpaper.isEmpty()) { return wallpaper; } } if (wallpaperConfig.hasKey("Color")) { auto backgroundColor = wallpaperConfig.readEntry("Color", QColor(0, 0, 0)); return backgroundColor.name(); } return QString(); } bool BackgroundCache::isDesktopContainment(const KConfigGroup &containment) const { const auto type = containment.readEntry("plugin", QString()); if (type == "org.kde.desktopcontainment" || type == "org.kde.plasma.folder" ) { return true; } return false; } void BackgroundCache::reload() { // Traversing through all containments in search for // containments that define activities in plasma KConfigGroup plasmaConfigContainments = m_plasmaConfig->group("Containments"); //!activityId and screen names for which their background was updated QHash> updates; for (const auto &containmentId : plasmaConfigContainments.groupList()) { const auto containment = plasmaConfigContainments.group(containmentId); const auto wallpaperPlugin = containment.readEntry("wallpaperplugin", QString()); const auto lastScreen = containment.readEntry("lastScreen", 0); const auto activity = containment.readEntry("activityId", QString()); //! Ignore the containment if the activity is not defined or //! the containment is not a plasma desktop if (activity.isEmpty() || !isDesktopContainment(containment)) continue; const auto returnedBackground = backgroundFromConfig(containment, wallpaperPlugin); QString background = returnedBackground; if (background.startsWith("file://")) { background = returnedBackground.mid(7); } QString screenName = m_pool->connector(lastScreen); //! Take case of broadcasted backgrounds, when their plugin is changed they should be disabled if (pluginExistsFor(activity,screenName) && m_plugins[activity][screenName] != wallpaperPlugin && backgroundIsBroadcasted(activity, screenName)){ //! in such case the Desktop changed wallpaper plugin and the broadcasted wallpapers should be removed setBroadcastedBackgroundsEnabled(activity, screenName, false); } m_plugins[activity][screenName] = wallpaperPlugin; if (background.isEmpty() || backgroundIsBroadcasted(activity, screenName)) { continue; } if(!m_backgrounds.contains(activity) || !m_backgrounds[activity].contains(screenName) || m_backgrounds[activity][screenName] != background) { updates[activity].append(screenName); } m_backgrounds[activity][screenName] = background; } m_initialized = true; foreach (auto activity, updates.keys()) { foreach (auto screen, updates[activity]) { emit backgroundChanged(activity, screen); } } } QString BackgroundCache::background(QString activity, QString screen) { if (m_backgrounds.contains(activity) && m_backgrounds[activity].contains(screen)) { return m_backgrounds[activity][screen]; } else { return m_defaultWallpaperPath; } } bool BackgroundCache::busyFor(QString activity, QString screen, Plasma::Types::Location location) { QString assignedBackground = background(activity, screen); if (!assignedBackground.isEmpty()) { return busyForFile(assignedBackground, location); } return false; } float BackgroundCache::brightnessFor(QString activity, QString screen, Plasma::Types::Location location) { QString assignedBackground = background(activity, screen); if (!assignedBackground.isEmpty()) { return brightnessForFile(assignedBackground, location); } return -1000; } float BackgroundCache::brightnessFromArea(QImage &image, int firstRow, int firstColumn, int endRow, int endColumn) { float areaBrightness = -1000; if (image.format() != QImage::Format_Invalid) { for (int row = firstRow; row < endRow; ++row) { QRgb *line = (QRgb *)image.scanLine(row); for (int col = firstColumn; col < endColumn ; ++col) { QRgb pixelData = line[col]; float pixelBrightness = Latte::colorBrightness(pixelData); areaBrightness = (areaBrightness == -1000) ? pixelBrightness : (areaBrightness + pixelBrightness); } } float areaSize = (endRow - firstRow) * (endColumn - firstColumn); areaBrightness = areaBrightness / areaSize; } return areaBrightness; } bool BackgroundCache::areaIsBusy(float bright1, float bright2) { bool bright1IsLight = bright1>=123; bool bright2IsLight = bright2>=123; bool inBounds = bright1>=0 && bright2<=255 && bright2>=0 && bright2<=255; return !inBounds || bright1IsLight != bright2IsLight; } //! In order to calculate the brightness and busy hints for specific image //! the code is doing the following. It is not needed to calculate these values //! for the entire image that would also be cpu costly. The function takes //! the location of the area in the image for which we are interested. //! The area is splitted in ten different subareas and for each one its brightness //! is computed. The brightness average from these areas provides the entire //! area brightness. In order to indicate if this area is busy or not we //! compare the minimum and the maximum values of brightness from these //! subareas. If the difference it too big then the area is busy void BackgroundCache::updateImageCalculations(QString imageFile, Plasma::Types::Location location) { if (m_hintsCache.size() > MAXHASHSIZE) { cleanupHashes(); } //! if it is a local image QImage image(imageFile); if (image.format() != QImage::Format_Invalid) { float brightness{-1000}; float maxBrightness{0}; float minBrightness{255}; //! 24px. should be enough because the views are always snapped to edges int maskHeight = qMin(24,image.height()); // (0.08 * image.height()); int maskWidth = qMin(24,image.width()); //(0.05 * image.width()); bool vertical = image.width() > image.height() ? false : true; int imageLength = image.width() > image.height() ? image.width() : image.height(); int areas{qMin(10,imageLength)}; float factor = ((float)100/areas)/100; QList subBrightness; //! Iterating algorigthm int firstRow = 0; int firstColumn = 0; int endRow = 0; int endColumn = 0; //! horizontal mask calculations if (location == Plasma::Types::TopEdge) { firstRow = 0; endRow = maskHeight; } else if (location == Plasma::Types::BottomEdge) { firstRow = image.height() - maskHeight - 1; endRow = image.height() - 1; } if (!vertical) { for (int i=1; i<=areas; ++i) { float subFactor = ((float)i) * factor; firstColumn = endColumn+1; endColumn = (subFactor*imageLength) - 1; endColumn = qMin(endColumn, imageLength-1); int tempBrightness = brightnessFromArea(image, firstRow, firstColumn, endRow, endColumn); subBrightness.append(tempBrightness); if (tempBrightness > maxBrightness) { maxBrightness = tempBrightness; } if (tempBrightness < minBrightness) { minBrightness = tempBrightness; } } } //! vertical mask calculations if (location == Plasma::Types::LeftEdge) { firstColumn = 0; endColumn = maskWidth; } else if (location == Plasma::Types::RightEdge) { firstColumn = image.width() - 1 - maskWidth; endColumn = image.width() - 1; } if (vertical) { for (int i=1; i<=areas; ++i) { float subFactor = ((float)i) * factor; firstRow = endRow+1; endRow = (subFactor*imageLength) - 1; endRow = qMin(endRow, imageLength-1); int tempBrightness = brightnessFromArea(image, firstRow, firstColumn, endRow, endColumn); subBrightness.append(tempBrightness); if (tempBrightness > maxBrightness) { maxBrightness = tempBrightness; } if (tempBrightness < minBrightness) { minBrightness = tempBrightness; } } } //! compute total brightness for this area float subBrightnessSum = 0; for (int i=0; i(); } m_broadcasted[activity].append(screen); } else if (!enabled && backgroundIsBroadcasted(activity, screen)) { m_broadcasted[activity].removeAll(screen); if (m_broadcasted[activity].isEmpty()) { m_broadcasted.remove(activity); } reload(); } } bool BackgroundCache::backgroundIsBroadcasted(QString activity, QString screenName) { return m_broadcasted.contains(activity) && m_broadcasted[activity].contains(screenName); } bool BackgroundCache::pluginExistsFor(QString activity, QString screenName) { return m_plugins.contains(activity) && m_plugins[activity].contains(screenName); } } }