summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js
diff options
context:
space:
mode:
authornippy <you@example.com>2026-04-18 13:49:56 +0200
committernippy <you@example.com>2026-04-18 13:49:56 +0200
commit5d94c0a7d44a2255b81815a52a7056a94a39842d (patch)
tree759bdea9645c6a62f9e1e4c001f7d81cccd120d2 /raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js
parente79cdf210b267f21a186255ce1a4d50029439d54 (diff)
downloadRaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.tar.gz
RaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.zip
update Raveos themes
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js')
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js179
1 files changed, 179 insertions, 0 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js
new file mode 100644
index 0000000..3610184
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js
@@ -0,0 +1,179 @@
+// This file is part of the AppIndicator/KStatusNotifierItem GNOME Shell extension
+//
+// This program 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.
+//
+// This program 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, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import GLib from 'gi://GLib';
+import Gio from 'gi://Gio';
+
+import * as PromiseUtils from './promiseUtils.js';
+import * as Util from './util.js';
+
+// The icon cache caches icon objects in case they're reused shortly aftwerwards.
+// This is necessary for some indicators like skype which rapidly switch between serveral icons.
+// Without caching, the garbage collection would never be able to handle the amount of new icon data.
+// If the lifetime of an icon is over, the cache will destroy the icon. (!)
+// The presence of active icons will extend the lifetime.
+
+const GC_INTERVAL = 100; // seconds
+const LIFETIME_TIMESPAN = 120; // seconds
+
+// how to use: see IconCache.add, IconCache.get
+export class IconCache {
+ constructor() {
+ this._cache = new Map();
+ this._activeIcons = Object.create(null);
+ this._lifetime = new Map(); // we don't want to attach lifetime to the object
+ }
+
+ add(id, icon) {
+ if (!(icon instanceof Gio.Icon)) {
+ Util.Logger.critical('IconCache: Only Gio.Icons are supported');
+ return null;
+ }
+
+ if (!id) {
+ Util.Logger.critical('IconCache: Invalid ID provided');
+ return null;
+ }
+
+ const oldIcon = this._cache.get(id);
+ if (!oldIcon || !oldIcon.equal(icon)) {
+ Util.Logger.debug(`IconCache: adding ${id}: ${icon}`);
+ this._cache.set(id, icon);
+ } else {
+ icon = oldIcon;
+ }
+
+ this._renewLifetime(id);
+ this._checkGC();
+
+ return icon;
+ }
+
+ updateActive(iconType, gicon, isActive) {
+ if (!gicon)
+ return;
+
+ const previousActive = this._activeIcons[iconType];
+
+ if (isActive && [...this._cache.values()].some(icon => icon === gicon))
+ this._activeIcons[iconType] = gicon;
+ else if (previousActive === gicon)
+ delete this._activeIcons[iconType];
+ else
+ return;
+
+ if (previousActive) {
+ this._cache.forEach((icon, id) => {
+ if (icon === previousActive)
+ this._renewLifetime(id);
+ });
+ }
+ }
+
+ _remove(id) {
+ Util.Logger.debug(`IconCache: removing ${id}`);
+
+ this._cache.delete(id);
+ this._lifetime.delete(id);
+ }
+
+ _renewLifetime(id) {
+ this._lifetime.set(id, new Date().getTime() + LIFETIME_TIMESPAN * 1000);
+ }
+
+ forceDestroy(id) {
+ const gicon = this._cache.has(id);
+ if (gicon) {
+ Object.keys(this._activeIcons).forEach(iconType =>
+ this.updateActive(iconType, gicon, false));
+ this._remove(id);
+ this._checkGC();
+ }
+ }
+
+ // marks all the icons as removable, if something doesn't claim them before
+ weakClear() {
+ this._activeIcons = Object.create(null);
+ this._checkGC();
+ }
+
+ // removes everything from the cache
+ clear() {
+ this._activeIcons = Object.create(null);
+ this._cache.forEach((_icon, id) => this._remove(id));
+ this._checkGC();
+ }
+
+ // returns an object from the cache, or null if it can't be found.
+ get(id) {
+ const icon = this._cache.get(id);
+ if (icon) {
+ Util.Logger.debug(`IconCache: retrieving ${id}: ${icon}`);
+ this._renewLifetime(id);
+ return icon;
+ }
+
+ return null;
+ }
+
+ async _checkGC() {
+ const cacheIsEmpty = this._cache.size === 0;
+
+ if (!cacheIsEmpty && !this._gcTimeout) {
+ Util.Logger.debug('IconCache: garbage collector started');
+ let anyUnusedInCache = false;
+ this._gcTimeout = new PromiseUtils.TimeoutSecondsPromise(GC_INTERVAL,
+ GLib.PRIORITY_LOW);
+ try {
+ await this._gcTimeout;
+ anyUnusedInCache = this._gc();
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ logError(e, 'IconCache: garbage collector');
+ } finally {
+ delete this._gcTimeout;
+ }
+
+ if (anyUnusedInCache)
+ this._checkGC();
+ } else if (cacheIsEmpty && this._gcTimeout) {
+ Util.Logger.debug('IconCache: garbage collector stopped');
+ this._gcTimeout.cancel();
+ }
+ }
+
+ _gc() {
+ const time = new Date().getTime();
+ let anyUnused = false;
+
+ this._cache.forEach((icon, id) => {
+ if (Object.values(this._activeIcons).includes(icon)) {
+ Util.Logger.debug(`IconCache: ${id} is in use.`);
+ } else if (this._lifetime.get(id) < time) {
+ this._remove(id);
+ } else {
+ anyUnused = true;
+ Util.Logger.debug(`IconCache: ${id} survived this round.`);
+ }
+ });
+
+ return anyUnused;
+ }
+
+ destroy() {
+ this.clear();
+ }
+}