summaryrefslogtreecommitdiff
path: root/raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js')
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js346
1 files changed, 346 insertions, 0 deletions
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js b/raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js
new file mode 100644
index 0000000..898b047
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/unity-like-appswitcher-reforged@gabeszm/utils.js
@@ -0,0 +1,346 @@
+import Gdk from "gi://Gdk";
+import GdkPixbuf from "gi://GdkPixbuf";
+import Gio from "gi://Gio";
+import Gtk from "gi://Gtk";
+import St from "gi://St";
+import GLib from "gi://GLib";
+
+let iconCacheMap = new Map();
+const MAX_CACHED_ITEMS = 1000;
+const BATCH_SIZE_TO_DELETE = 50;
+const DOMINANT_COLOR_ICON_SIZE = 64;
+
+function debugLog(msg) {
+ try {
+ let f = Gio.File.new_for_path('/tmp/color_log.txt');
+ let out = f.append_to(Gio.FileCreateFlags.NONE, null);
+ out.write_all(new Date().toISOString() + " - " + msg + "\n", null);
+ out.close(null);
+ } catch (e) { }
+}
+
+function findFallbackIconPath(iconName) {
+ if (!iconName) return null;
+ if (GLib.file_test(iconName, GLib.FileTest.EXISTS)) return iconName;
+
+ const sizes = ['128x128', '256x256', '512x512', '64x64', 'scalable', '48x48'];
+
+ let currentTheme = 'Adwaita';
+ try {
+ const settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
+ if (settings.get_string('icon-theme')) {
+ currentTheme = settings.get_string('icon-theme');
+ }
+ } catch (e) {
+ debugLog("Failed to get active icon theme setting: " + e);
+ }
+
+ // Tegyük a hicolort az első helyre, a jelenleg aktív témát a másodikra, aztán a többi népszerű.
+ // A Set-tel kiszűrjük az esetleges ismétlődéseket.
+ const themes = [...new Set(['hicolor', currentTheme, 'locolor', 'Yaru', 'Pop', 'Adwaita', 'MoreWaita', 'Papirus', 'Tela'])];
+ const bases = [
+ GLib.get_home_dir() + '/.local/share/icons',
+ GLib.get_home_dir() + '/.local/share/flatpak/exports/share/icons',
+ '/var/lib/flatpak/exports/share/icons',
+ '/var/lib/snapd/desktop/icons',
+ '/usr/share/icons',
+ '/usr/local/share/icons'
+ ];
+ const formats = ['.svg', '.png', '.xpm'];
+
+ for (const base of bases) {
+ for (const theme of themes) {
+ for (const size of sizes) {
+ for (const format of formats) {
+ let path = `${base}/${theme}/${size}/apps/${iconName}${format}`;
+ if (GLib.file_test(path, GLib.FileTest.EXISTS)) return path;
+ }
+ }
+ }
+ }
+
+ // Check pixmaps
+ for (const format of formats) {
+ let path = `/usr/share/pixmaps/${iconName}${format}`;
+ if (GLib.file_test(path, GLib.FileTest.EXISTS)) return path;
+ }
+
+ return null;
+}
+
+export class DominantColorExtractor {
+ constructor(app) {
+ this._app = app;
+ }
+
+ _getIconPixBuf() {
+ debugLog("--- START Extracting for app: " + (this._app ? this._app.get_id() : "undefined") + " ---");
+ if (!this._app) {
+ debugLog("Error: _app is null or undefined");
+ return null;
+ }
+
+ const gicon = this._app.get_icon();
+ if (!gicon) {
+ debugLog("Fail: get_icon() returned null");
+ return null;
+ }
+
+ debugLog("Got gicon of type: " + gicon.constructor.name);
+
+ // Try to load via Gio.FileIcon directly
+ if (gicon instanceof Gio.FileIcon) {
+ try {
+ debugLog("gicon is Gio.FileIcon. Getting file path...");
+ const path = gicon.get_file().get_path();
+ debugLog("File path: " + path);
+ if (path) {
+ return GdkPixbuf.Pixbuf.new_from_file(path);
+ }
+ } catch (e) {
+ debugLog("Exception in Gio.FileIcon lookup: " + e);
+ }
+ }
+
+ // Try fallback manual lookup
+ if (gicon instanceof Gio.ThemedIcon) {
+ try {
+ debugLog("Attempting manual fallback search for ThemedIcon...");
+ const names = gicon.get_names();
+ for (const name of names) {
+ let path = findFallbackIconPath(name);
+ if (path) {
+ debugLog("Manual fallback found file: " + path);
+ return GdkPixbuf.Pixbuf.new_from_file(path);
+ }
+ }
+ } catch (e) {
+ debugLog("Exception in manual fallback: " + e);
+ }
+ }
+
+ // Try St.TextureCache as a last resort
+ try {
+ debugLog("Attempting St.TextureCache lookup...");
+ let textureCache = St.TextureCache.get_default();
+ let themeContext = St.ThemeContext.get_for_stage(global.stage);
+ let iconSize = 64 * themeContext.scale_factor;
+
+ let iconTexture = textureCache.load_gicon(null, gicon, iconSize);
+ if (iconTexture) {
+ debugLog("Found texture in cache, but cannot easily convert to Pixbuf in this context. Fallback to default.");
+ }
+ } catch (e) {
+ debugLog("St.TextureCache lookup failed: " + e);
+ }
+
+ debugLog("--- FAIL: Exhausted all methods to get icon pixbuf ---");
+ return null;
+ }
+
+ _getColorPalette() {
+ debugLog("--- START _getColorPalette ---");
+ const appId = this._app ? this._app.get_id() : null;
+ debugLog("App ID: " + appId);
+
+ if (appId && iconCacheMap.has(appId)) {
+ debugLog("Returning cached color for: " + appId);
+ return iconCacheMap.get(appId);
+ }
+
+ debugLog("Cache miss, calling _getIconPixBuf()");
+ const pixBuf = this._getIconPixBuf();
+ if (!pixBuf) {
+ debugLog("FAIL: pixBuf is null, cannot extract color.");
+ return null;
+ }
+
+ try {
+ const width = pixBuf.get_width();
+ const height = pixBuf.get_height();
+ const rowstride = pixBuf.get_rowstride();
+ const nChannels = pixBuf.get_n_channels();
+ const hasAlpha = pixBuf.get_has_alpha();
+
+ debugLog(`PixBuf info: ${width}x${height}, rowstride: ${rowstride}, channels: ${nChannels}, alpha: ${hasAlpha}`);
+
+ const pixels = pixBuf.get_pixels();
+ if (!pixels) {
+ debugLog("FAIL: pixBuf.get_pixels() returned null or undefined");
+ return null;
+ }
+
+ let total = 0, rTotal = 0, gTotal = 0, bTotal = 0;
+ const step = Math.max(1, Math.floor(width / 32));
+ debugLog("Calculated step for sampling: " + step);
+
+ let sampledCount = 0;
+ for (let y = 0; y < height; y += step) {
+ for (let x = 0; x < width; x += step) {
+ const offset = y * rowstride + x * nChannels;
+ const r = pixels[offset];
+ const g = pixels[offset + 1];
+ const b = pixels[offset + 2];
+ const a = hasAlpha ? pixels[offset + 3] : 255;
+
+ if (a < 128) continue;
+
+ const max = Math.max(r, g, b);
+ const min = Math.min(r, g, b);
+ const saturation = (max - min) / (max || 1);
+ const relevance = a * (saturation * saturation + 0.1);
+
+ rTotal += r * relevance;
+ gTotal += g * relevance;
+ bTotal += b * relevance;
+ total += relevance;
+ sampledCount++;
+ }
+ }
+
+ debugLog(`Sampling complete. Sampled pixels: ${sampledCount}. Total accumulator: ${total}`);
+
+ if (total === 0) {
+ debugLog("FAIL: Valid pixel total is 0. Returning null.");
+ return null;
+ }
+
+ let r = rTotal / total;
+ let g = gTotal / total;
+ let b = bTotal / total;
+ debugLog(`Averaged RGB: Math.round(${r}), Math.round(${g}), Math.round(${b})`);
+
+ let hsv = ColorUtils.RGBtoHSV(r, g, b);
+ debugLog(`HSV before normalize: h:${hsv.h.toFixed(2)}, s:${hsv.s.toFixed(2)}, v:${hsv.v.toFixed(2)}`);
+
+ if (hsv.s < 0.2) hsv.s = 0.35;
+ hsv.v = Math.max(0.6, Math.min(hsv.v, 0.9));
+
+ debugLog(`HSV after normalize: h:${hsv.h.toFixed(2)}, s:${hsv.s.toFixed(2)}, v:${hsv.v.toFixed(2)}`);
+
+ const rgb = ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v);
+
+ const backgroundColor = {
+ lighter: ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0.5),
+ original: ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0),
+ darker: ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, -0.5),
+ baseRgb: rgb
+ };
+
+ debugLog(`Generated Palette: original=${backgroundColor.original}, lighter=${backgroundColor.lighter}, darker=${backgroundColor.darker}`);
+
+ if (iconCacheMap.size >= MAX_CACHED_ITEMS) {
+ debugLog("Cache full, clearing batch.");
+ const keys = Array.from(iconCacheMap.keys());
+ for (let i = 0; i < BATCH_SIZE_TO_DELETE; i++) {
+ iconCacheMap.delete(keys[i]);
+ }
+ }
+
+ if (appId) {
+ iconCacheMap.set(appId, backgroundColor);
+ debugLog("Added to cache for appId: " + appId);
+ }
+
+ debugLog("--- SUCCESS: Color extraction finished ---");
+ return backgroundColor;
+
+ } catch (e) {
+ debugLog("Exception during pixel processing: " + e);
+ return null;
+ }
+ }
+}
+
+export class ColorUtils {
+ static ColorLuminance(r, g, b, dlum) {
+ let rgbString = '#';
+ rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r * (1 + dlum), 0), 255)), 2);
+ rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g * (1 + dlum), 0), 255)), 2);
+ rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b * (1 + dlum), 0), 255)), 2);
+ return rgbString;
+ }
+
+ static _decimalToHex(d, padding) {
+ let hex = d.toString(16);
+ while (hex.length < padding)
+ hex = '0' + hex;
+ return hex;
+ }
+
+ static _hexToRgb(h) {
+ return {
+ r: parseInt(h.substr(1, 2), 16),
+ g: parseInt(h.substr(3, 2), 16),
+ b: parseInt(h.substr(5, 2), 16)
+ }
+ }
+
+ static HSVtoRGB(h, s, v) {
+ if (arguments.length === 1) {
+ s = h.s;
+ v = h.v;
+ h = h.h;
+ }
+
+ let r, g, b;
+ let c = v * s;
+ let h1 = h * 6;
+ let x = c * (1 - Math.abs(h1 % 2 - 1));
+ let m = v - c;
+
+ if (h1 <= 1)
+ r = c + m, g = x + m, b = m;
+ else if (h1 <= 2)
+ r = x + m, g = c + m, b = m;
+ else if (h1 <= 3)
+ r = m, g = c + m, b = x + m;
+ else if (h1 <= 4)
+ r = m, g = x + m, b = c + m;
+ else if (h1 <= 5)
+ r = x + m, g = m, b = c + m;
+ else
+ r = c + m, g = m, b = x + m;
+
+ return {
+ r: Math.round(r * 255),
+ g: Math.round(g * 255),
+ b: Math.round(b * 255)
+ };
+ }
+
+ static RGBtoHSV(r, g, b) {
+ if (arguments.length === 1) {
+ r = r.r;
+ g = r.g;
+ b = r.b;
+ }
+
+ let h, s, v;
+ let M = Math.max(r, g, b);
+ let m = Math.min(r, g, b);
+ let c = M - m;
+
+ if (c == 0)
+ h = 0;
+ else if (M == r)
+ h = ((g - b) / c) % 6;
+ else if (M == g)
+ h = (b - r) / c + 2;
+ else
+ h = (r - g) / c + 4;
+
+ h = h / 6;
+ v = M / 255;
+ if (M !== 0)
+ s = c / M;
+ else
+ s = 0;
+
+ return {
+ h: h,
+ s: s,
+ v: v
+ };
+ }
+}