summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-08-27 22:55:17 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-08-27 22:55:17 +1000
commit258feae3d7e3da2e2f7c59fe00cbb7d839dce904 (patch)
tree7073dab2466dc791d851beca96a737914c4f0384
parentplugin: make thread safe (diff)
downloadcaelestia-shell-258feae3d7e3da2e2f7c59fe00cbb7d839dce904.tar.gz
caelestia-shell-258feae3d7e3da2e2f7c59fe00cbb7d839dce904.tar.bz2
caelestia-shell-258feae3d7e3da2e2f7c59fe00cbb7d839dce904.zip
plugin: add getDominantColour
Replaces wack canvas stuff for ColouredIcon
-rw-r--r--components/effects/ColouredIcon.qml63
-rw-r--r--plugin/src/Caelestia/cutils.cpp71
-rw-r--r--plugin/src/Caelestia/cutils.hpp3
3 files changed, 79 insertions, 58 deletions
diff --git a/components/effects/ColouredIcon.qml b/components/effects/ColouredIcon.qml
index 8ba6c5d..a858c25 100644
--- a/components/effects/ColouredIcon.qml
+++ b/components/effects/ColouredIcon.qml
@@ -1,5 +1,6 @@
pragma ComponentBehavior: Bound
+import Caelestia
import Quickshell.Widgets
import QtQuick
@@ -7,77 +8,23 @@ IconImage {
id: root
required property color colour
- property color sourceColour
- property url lastSource
+ property color dominantColour
asynchronous: true
layer.enabled: true
layer.effect: Colouriser {
- sourceColor: root.sourceColour
+ sourceColor: root.dominantColour
colorizationColor: root.colour
}
layer.onEnabledChanged: {
if (layer.enabled)
- canvas.requestPaint();
+ CUtils.getDominantColour(this);
}
onStatusChanged: {
if (layer.enabled && status === Image.Ready)
- canvas.requestPaint();
- }
-
- Canvas {
- id: canvas
-
- property int retryCount
-
- implicitWidth: 32
- implicitHeight: 32
- visible: false
-
- onPaint: {
- if (!root.layer.enabled)
- return;
-
- const ctx = getContext("2d");
- ctx.reset();
- ctx.drawImage(root.backer, 0, 0, width, height);
-
- const colours = {} as Object;
- const data = ctx.getImageData(0, 0, width, height).data;
-
- for (let i = 0; i < data.length; i += 4) {
- if (data[i + 3] === 0)
- continue;
-
- const c = `${data[i]},${data[i + 1]},${data[i + 2]}`;
- if (colours.hasOwnProperty(c))
- colours[c]++;
- else
- colours[c] = 1;
- }
-
- // Canvas is empty, try again next frame
- if (retryCount < 5 && !Object.keys(colours).length) {
- retryCount++;
- Qt.callLater(() => requestPaint());
- return;
- }
-
- let max = 0;
- let maxColour = "0,0,0";
- for (const [colour, occurences] of Object.entries(colours)) {
- if (occurences > max) {
- max = occurences;
- maxColour = colour;
- }
- }
-
- const [r, g, b] = maxColour.split(",");
- root.sourceColour = Qt.rgba(r / 255, g / 255, b / 255, 1);
- retryCount = 0;
- }
+ CUtils.getDominantColour(this);
}
}
diff --git a/plugin/src/Caelestia/cutils.cpp b/plugin/src/Caelestia/cutils.cpp
index dfe5ee8..30f38dd 100644
--- a/plugin/src/Caelestia/cutils.cpp
+++ b/plugin/src/Caelestia/cutils.cpp
@@ -90,3 +90,74 @@ bool CUtils::copyFile(const QUrl& source, const QUrl& target, bool overwrite) co
return QFile::copy(source.toLocalFile(), target.toLocalFile());
}
+
+void CUtils::getDominantColour(QQuickItem* item) const {
+ this->getDominantColour(item, 128, 128);
+}
+
+void CUtils::getDominantColour(QQuickItem* item, int width, int height) const {
+ if (!item) {
+ qWarning() << "CUtils::getDominantColour: an item is required";
+ return;
+ }
+
+ if (!item->window()) {
+ // Fail silently to avoid warning
+ return;
+ }
+
+ QSharedPointer<QQuickItemGrabResult> grabResult = item->grabToImage(QSize(width, height));
+
+ QObject::connect(grabResult.data(), &QQuickItemGrabResult::ready, this,
+ [grabResult, item, this]() {
+ QImage image = grabResult->image();
+
+ if (image.format() != QImage::Format_ARGB32) {
+ image = image.convertToFormat(QImage::Format_ARGB32);
+ }
+
+ std::unordered_map<uint32_t, int> colours;
+ const uchar* data = image.bits();
+ int width = image.width();
+ int height = image.height();
+ int bytesPerLine = image.bytesPerLine();
+
+ for (int y = 0; y < height; ++y) {
+ const uchar* line = data + y * bytesPerLine;
+ for (int x = 0; x < width; ++x) {
+ const uchar* pixel = line + x * 4;
+ uchar r = pixel[0];
+ uchar g = pixel[1];
+ uchar b = pixel[2];
+ uchar a = pixel[3];
+
+ if (a == 0) {
+ continue;
+ }
+
+ r &= 0xF8;
+ g &= 0xF8;
+ b &= 0xF8;
+
+ uint32_t colour = (r << 16) | (g << 8) | b;
+ ++colours[colour];
+ }
+ }
+
+ uint32_t dominantColour = 0;
+ int maxCount = 0;
+ for (const auto& [colour, count] : colours) {
+ if (count > maxCount) {
+ dominantColour = colour;
+ maxCount = count;
+ }
+ }
+
+ const QColor colour = QColor((0xFF << 24) | dominantColour);
+
+ QMetaObject::invokeMethod(item, [item, colour]() {
+ item->setProperty("dominantColour", colour);
+ }, Qt::QueuedConnection);
+ }
+ );
+}
diff --git a/plugin/src/Caelestia/cutils.hpp b/plugin/src/Caelestia/cutils.hpp
index c796e8b..36120f4 100644
--- a/plugin/src/Caelestia/cutils.hpp
+++ b/plugin/src/Caelestia/cutils.hpp
@@ -19,4 +19,7 @@ public:
Q_INVOKABLE bool copyFile(const QUrl& source, const QUrl& target) const;
Q_INVOKABLE bool copyFile(const QUrl& source, const QUrl& target, bool overwrite) const;
+
+ Q_INVOKABLE void getDominantColour(QQuickItem* item) const;
+ Q_INVOKABLE void getDominantColour(QQuickItem* item, int width, int height) const;
};