From 937b62ea9a1cd32474855c1241d1dd95f91c0a6e Mon Sep 17 00:00:00 2001
From: Kaosu <kaosuran@protonmail.com>
Date: Sun, 16 Feb 2025 14:21:08 +0100
Subject: [PATCH 1/4] add SNI custom icon manager

---
 include/modules/sni/icon_manager.hpp | 43 ++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 include/modules/sni/icon_manager.hpp

diff --git a/include/modules/sni/icon_manager.hpp b/include/modules/sni/icon_manager.hpp
new file mode 100644
index 000000000..614d42d9e
--- /dev/null
+++ b/include/modules/sni/icon_manager.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <json/json.h>
+#include <spdlog/spdlog.h>
+
+#include <string>
+#include <unordered_map>
+
+class IconManager {
+ public:
+  static IconManager& instance() {
+    static IconManager instance;
+    return instance;
+  }
+
+  void setIconsConfig(const Json::Value& icons_config) {
+    if (icons_config.isObject()) {
+      for (const auto& key : icons_config.getMemberNames()) {
+        std::string app_name = key;
+        const Json::Value& icon_value = icons_config[key];
+
+        if (icon_value.isString()) {
+          std::string icon_path = icon_value.asString();
+          icons_map_[app_name] = icon_path;
+        }
+      }
+    } else {
+      spdlog::warn("Invalid icon config format.");
+    }
+  }
+
+  std::string getIconForApp(const std::string& app_name) const {
+    auto it = icons_map_.find(app_name);
+    if (it != icons_map_.end()) {
+      return it->second;
+    }
+    return "";
+  }
+
+ private:
+  IconManager() = default;
+  std::unordered_map<std::string, std::string> icons_map_;
+};

From 78d5c3ef3a3bd78b92eaae2a67cb624d65ab3bf5 Mon Sep 17 00:00:00 2001
From: Kaosu <kaosuran@protonmail.com>
Date: Sun, 16 Feb 2025 14:21:34 +0100
Subject: [PATCH 2/4] init custom icons from config per tray

---
 src/modules/sni/tray.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp
index a2c56808b..abd23ebd7 100644
--- a/src/modules/sni/tray.cpp
+++ b/src/modules/sni/tray.cpp
@@ -1,4 +1,5 @@
 #include "modules/sni/tray.hpp"
+#include "modules/sni/icon_manager.hpp"
 
 #include <spdlog/spdlog.h>
 
@@ -20,6 +21,9 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
     box_.set_spacing(config_["spacing"].asUInt());
   }
   nb_hosts_ += 1;
+  if (config_["icons"].isObject()) {
+    IconManager::instance().setIconsConfig(config_["icons"]);
+  }
   dp.emit();
 }
 

From d1998de47a0e51688d29f8d08e1b1477315ccbbd Mon Sep 17 00:00:00 2001
From: Kaosu <kaosuran@protonmail.com>
Date: Sun, 16 Feb 2025 14:22:10 +0100
Subject: [PATCH 3/4] add setCustomIcon and try to apply such when ID is known

---
 include/modules/sni/item.hpp |  1 +
 src/modules/sni/item.cpp     | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/include/modules/sni/item.hpp b/include/modules/sni/item.hpp
index ebc08d45f..c5e86d37b 100644
--- a/include/modules/sni/item.hpp
+++ b/include/modules/sni/item.hpp
@@ -62,6 +62,7 @@ class Item : public sigc::trackable {
   void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
   void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
   void setStatus(const Glib::ustring& value);
+  void setCustomIcon(const std::string& id);
   void getUpdatedProperties();
   void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
   void onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
diff --git a/src/modules/sni/item.cpp b/src/modules/sni/item.cpp
index b3e848853..978e8b073 100644
--- a/src/modules/sni/item.cpp
+++ b/src/modules/sni/item.cpp
@@ -1,4 +1,5 @@
 #include "modules/sni/item.hpp"
+#include "modules/sni/icon_manager.hpp"
 
 #include <gdkmm/general.h>
 #include <glibmm/main.h>
@@ -7,6 +8,7 @@
 
 #include <fstream>
 #include <map>
+#include <filesystem>
 
 #include "gdk/gdk.h"
 #include "util/format.hpp"
@@ -138,6 +140,7 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
       category = get_variant<std::string>(value);
     } else if (name == "Id") {
       id = get_variant<std::string>(value);
+      setCustomIcon(id);
     } else if (name == "Title") {
       title = get_variant<std::string>(value);
       if (tooltip.text.empty()) {
@@ -199,6 +202,19 @@ void Item::setStatus(const Glib::ustring& value) {
   style->add_class(lower);
 }
 
+void Item::setCustomIcon(const std::string& id) {
+  std::string custom_icon = IconManager::instance().getIconForApp(id);
+  if (!custom_icon.empty()) {
+    if (std::filesystem::exists(custom_icon)) {
+        Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
+        icon_name = ""; // icon_name has priority over pixmap
+        icon_pixmap = custom_pixbuf;
+    } else { // if file doesn't exist it's most likely an icon_name
+      icon_name = custom_icon;
+    }
+  }
+}
+
 void Item::getUpdatedProperties() {
   auto params = Glib::VariantContainerBase::create_tuple(
       {Glib::Variant<Glib::ustring>::create(SNI_INTERFACE_NAME)});

From ddf5b3e07b4b5c9484f7bb5ca81e90973e5ade27 Mon Sep 17 00:00:00 2001
From: Kaosu <kaosuran@protonmail.com>
Date: Sun, 16 Feb 2025 14:30:08 +0100
Subject: [PATCH 4/4] add tray icons docs

---
 man/waybar-tray.5.scd  | 6 +++++-
 resources/config.jsonc | 6 +++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/man/waybar-tray.5.scd b/man/waybar-tray.5.scd
index 381d593da..dec5347fa 100644
--- a/man/waybar-tray.5.scd
+++ b/man/waybar-tray.5.scd
@@ -47,7 +47,11 @@ Addressed by *tray*
 ```
 "tray": {
 	"icon-size": 21,
-	"spacing": 10
+	"spacing": 10,
+  "icons": {
+    "blueman": "bluetooth",
+    "TelegramDesktop": "$HOME/.local/share/icons/hicolor/16x16/apps/telegram.png"
+  }
 }
 
 ```
diff --git a/resources/config.jsonc b/resources/config.jsonc
index 6ac1aa506..67d5ff5b9 100644
--- a/resources/config.jsonc
+++ b/resources/config.jsonc
@@ -104,7 +104,11 @@
     },
     "tray": {
         // "icon-size": 21,
-        "spacing": 10
+        "spacing": 10,
+        // "icons": {
+        //   "blueman": "bluetooth",
+        //   "TelegramDesktop": "$HOME/.local/share/icons/hicolor/16x16/apps/telegram.png"
+        // }
     },
     "clock": {
         // "timezone": "America/New_York",