From 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 Mon Sep 17 00:00:00 2001 From: AlexanderCurl Date: Sat, 18 Apr 2026 17:46:06 +0100 Subject: Replaced file structures for themes in the correct format --- .../appIndicator.js | 1607 -------------------- 1 file changed, 1607 deletions(-) delete mode 100644 raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js (limited to 'raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js') diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js deleted file mode 100644 index 7efded2..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/appIndicator.js +++ /dev/null @@ -1,1607 +0,0 @@ -// 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 Clutter from 'gi://Clutter'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import GdkPixbuf from 'gi://GdkPixbuf'; -import Gio from 'gi://Gio'; -import St from 'gi://St'; - -import * as Params from 'resource:///org/gnome/shell/misc/params.js'; -import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; - -import * as DBusUtils from './dbusUtils.js'; -import * as IconCache from './iconCache.js'; -import * as Util from './util.js'; -import * as Interfaces from './interfaces.js'; -import * as PixmapsUtils from './pixmapsUtils.js'; -import * as PromiseUtils from './promiseUtils.js'; -import * as SettingsManager from './settingsManager.js'; -import {DBusProxy} from './dbusProxy.js'; - -Gio._promisify(Gio.File.prototype, 'read_async'); -Gio._promisify(GdkPixbuf.Pixbuf, 'get_file_info_async'); -Gio._promisify(GdkPixbuf.Pixbuf, 'new_from_stream_at_scale_async', - 'new_from_stream_finish'); -Gio._promisify(St.IconInfo.prototype, 'load_symbolic_async'); -Gio._promisify(Gio.DBusConnection.prototype, 'call'); - -const MAX_UPDATE_FREQUENCY = 30; // In ms -const FALLBACK_ICON_NAME = 'image-loading-symbolic'; -const PIXMAPS_FORMAT = imports.gi.Cogl.PixelFormat.ARGB_8888; - -export const SNICategory = Object.freeze({ - APPLICATION: 'ApplicationStatus', - COMMUNICATIONS: 'Communications', - SYSTEM: 'SystemServices', - HARDWARE: 'Hardware', -}); - -export const SNIStatus = Object.freeze({ - PASSIVE: 'Passive', - ACTIVE: 'Active', - NEEDS_ATTENTION: 'NeedsAttention', -}); - -const SNIconType = Object.freeze({ - NORMAL: 0, - ATTENTION: 1, - OVERLAY: 2, - - toPropertyName: (iconType, params = {isPixbuf: false}) => { - let propertyName = 'Icon'; - - if (iconType === SNIconType.OVERLAY) - propertyName = 'OverlayIcon'; - else if (iconType === SNIconType.ATTENTION) - propertyName = 'AttentionIcon'; - - return `${propertyName}${params.isPixbuf ? 'Pixmap' : 'Name'}`; - }, -}); - -export const AppIndicatorProxy = GObject.registerClass( -class AppIndicatorProxy extends DBusProxy { - static get interfaceInfo() { - if (!this._interfaceInfo) { - this._interfaceInfo = Gio.DBusInterfaceInfo.new_for_xml( - Interfaces.StatusNotifierItem); - } - return this._interfaceInfo; - } - - static get OPTIONAL_PROPERTIES() { - return [ - 'XAyatanaLabel', - 'XAyatanaLabelGuide', - 'XAyatanaOrderingIndex', - 'IconAccessibleDesc', - 'AttentionAccessibleDesc', - ]; - } - - static get TUPLE_TYPE() { - if (!this._tupleType) - this._tupleType = new GLib.VariantType('()'); - - return this._tupleType; - } - - static destroy() { - delete this._interfaceInfo; - delete this._tupleType; - } - - _init(busName, objectPath) { - const {interfaceInfo} = AppIndicatorProxy; - - super._init(busName, objectPath, interfaceInfo, - Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES); - - this.set_cached_property('Status', - new GLib.Variant('s', SNIStatus.PASSIVE)); - - - this._accumulatedProperties = new Set(); - this._cancellables = new Map(); - this._changedProperties = Object.create(null); - } - - async initAsync(cancellable) { - await super.initAsync(cancellable); - - this._setupProxyPropertyList(); - } - - destroy() { - const cachedProperties = this.get_cached_property_names(); - if (cachedProperties) { - cachedProperties.forEach(propertyName => - this.set_cached_property(propertyName, null)); - } - - super.destroy(); - } - - _onNameOwnerChanged() { - this._resetNeededProperties(); - - if (!this.gNameOwner) - this._cancelRefreshProperties(); - else - this._setupProxyPropertyList(); - } - - _setupProxyPropertyList() { - this._propertiesList = - (this.get_cached_property_names() || []).filter(p => - this.gInterfaceInfo.properties.some(pInfo => pInfo.name === p)); - - if (this._propertiesList.length) { - AppIndicatorProxy.OPTIONAL_PROPERTIES.forEach( - p => this._addExtraProperty(p)); - } - } - - _addExtraProperty(name) { - if (this._propertiesList.includes(name)) - return; - - if (!(name in this)) { - Object.defineProperty(this, name, { - configurable: false, - enumerable: true, - get: () => { - const v = this.get_cached_property(name); - return v ? v.deep_unpack() : null; - }, - }); - } - - this._propertiesList.push(name); - } - - _signalToPropertyName(signal) { - if (signal.startsWith('New')) - return signal.substr(3); - else if (signal.startsWith('XAyatanaNew')) - return `XAyatana${signal.substr(11)}`; - - return null; - } - - // The Author of the spec didn't like the PropertiesChanged signal, so he invented his own - async _refreshOwnProperties(prop) { - await Promise.all( - [prop, `${prop}Name`, `${prop}Pixmap`, `${prop}AccessibleDesc`].filter(p => - this._propertiesList.includes(p)).map(async p => { - try { - await this.refreshProperty(p, { - skipEqualityCheck: p.endsWith('Pixmap'), - }); - } catch (e) { - if (!AppIndicatorProxy.OPTIONAL_PROPERTIES.includes(p) || - !(e instanceof Gio.DBusError)) - logError(e); - } - })); - } - - _onSignal(sender, signal, ...args) { - this._onSignalAsync(sender, signal, ...args).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e, `Error while processing signal '${signal}'`); - }); - } - - async _onSignalAsync(_sender, signal, params) { - const property = this._signalToPropertyName(signal); - if (!property) - return; - - if (this.status === SNIStatus.PASSIVE && - ![...AppIndicator.NEEDED_PROPERTIES, 'Status'].includes(property)) { - this._accumulatedProperties.add(property); - return; - } - - const cancellable = this._cancellable; - - if (!params.get_type().equal(AppIndicatorProxy.TUPLE_TYPE)) { - // If the property includes arguments, we can just queue the signal emission - const [value] = params.unpack(); - try { - await this._queuePropertyUpdate(property, value); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - throw e; - } - - if (!this._accumulatedProperties.size) - return; - } else { - this._accumulatedProperties.add(property); - } - - if (this._signalsAccumulator) - return; - - this._signalsAccumulator = new PromiseUtils.TimeoutPromise( - MAX_UPDATE_FREQUENCY, GLib.PRIORITY_DEFAULT_IDLE, cancellable); - try { - await this._signalsAccumulator; - const refreshPropertiesPromises = - [...this._accumulatedProperties].map(p => - this._refreshOwnProperties(p)); - this._accumulatedProperties.clear(); - await Promise.all(refreshPropertiesPromises); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - throw e; - } finally { - delete this._signalsAccumulator; - } - } - - _resetNeededProperties() { - AppIndicator.NEEDED_PROPERTIES.forEach(p => - this.set_cached_property(p, null)); - } - - async refreshAllProperties() { - const cancellableName = 'org.freedesktop.DBus.Properties.GetAll'; - const cancellable = this._cancelRefreshProperties({ - propertyName: cancellableName, - addNew: true, - }); - - try { - const [valuesVariant] = (await this.getProperties( - cancellable)).deep_unpack(); - - this._cancellables.delete(cancellableName); - - await Promise.all( - Object.entries(valuesVariant).map(([propertyName, valueVariant]) => - this._queuePropertyUpdate(propertyName, valueVariant, { - skipEqualityCheck: true, - cancellable, - }))); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - // the property may not even exist, silently ignore it - Util.Logger.debug(`While refreshing all properties: ${e}`); - - this.get_cached_property_names().forEach(propertyName => - this.set_cached_property(propertyName, null)); - - this._cancellables.delete(cancellableName); - throw e; - } - } - } - - async refreshProperty(propertyName, params) { - params = Params.parse(params, { - skipEqualityCheck: false, - }); - - const cancellable = this._cancelRefreshProperties({ - propertyName, - addNew: true, - }); - - try { - const [valueVariant] = (await this.getProperty( - propertyName, cancellable)).deep_unpack(); - - this._cancellables.delete(propertyName); - await this._queuePropertyUpdate(propertyName, valueVariant, - Object.assign(params, {cancellable})); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - // the property may not even exist, silently ignore it - Util.Logger.debug(`Error when calling 'Get(${propertyName})' ` + - `in ${this.gName}, ${this.gObjectPath}, ` + - `org.freedesktop.DBus.Properties, ${this.gInterfaceName} ` + - `while refreshing property ${propertyName}: ${e}\n` + - `${e.stack}`); - this.set_cached_property(propertyName, null); - this._cancellables.delete(propertyName); - delete this._changedProperties[propertyName]; - throw e; - } - } - } - - async _queuePropertyUpdate(propertyName, value, params) { - params = Params.parse(params, { - skipEqualityCheck: false, - cancellable: null, - }); - - if (!params.skipEqualityCheck) { - const cachedProperty = this.get_cached_property(propertyName); - - if (value && cachedProperty && - value.equal(this.get_cached_property(propertyName))) - return; - } - - this.set_cached_property(propertyName, value); - - // synthesize a batched property changed event - this._changedProperties[propertyName] = value; - - if (!this._propertiesEmitTimeout || !this._propertiesEmitTimeout.pending()) { - if (!params.cancellable) { - params.cancellable = this._cancelRefreshProperties({ - propertyName, - addNew: true, - }); - } - this._propertiesEmitTimeout = new PromiseUtils.TimeoutPromise( - MAX_UPDATE_FREQUENCY * 2, GLib.PRIORITY_DEFAULT_IDLE, params.cancellable); - await this._propertiesEmitTimeout; - - if (Object.keys(this._changedProperties).length) { - this.emit('g-properties-changed', GLib.Variant.new('a{sv}', - this._changedProperties), []); - this._changedProperties = Object.create(null); - } - } - } - - _cancelRefreshProperties(params) { - params = Params.parse(params, { - propertyName: undefined, - addNew: false, - }); - - if (!this._cancellables.size && !params.addNew) - return null; - - if (params.propertyName !== undefined) { - let cancellable = this._cancellables.get(params.propertyName); - if (cancellable) { - cancellable.cancel(); - - if (!params.addNew) - this._cancellables.delete(params.propertyName); - } - - if (params.addNew) { - cancellable = new Util.CancellableChild(this._cancellable); - this._cancellables.set(params.propertyName, cancellable); - return cancellable; - } - } else { - this._cancellables.forEach(c => c.cancel()); - this._cancellables.clear(); - this._changedProperties = Object.create(null); - } - - return null; - } -}); - -/** - * the AppIndicator class serves as a generic container for indicator information and functions common - * for every displaying implementation (IndicatorMessageSource and IndicatorStatusIcon) - */ -export class AppIndicator extends Signals.EventEmitter { - static get NEEDED_PROPERTIES() { - return ['Id', 'Menu']; - } - - constructor(service, busName, object) { - super(); - - this.isReady = false; - this.busName = busName; - this._uniqueId = Util.indicatorId(service, busName, object); - - this._cancellable = new Gio.Cancellable(); - this._proxy = new AppIndicatorProxy(busName, object); - this._invalidatedPixmapsIcons = new Set(); - - this._setupProxy().catch(logError); - Util.connectSmart(this._proxy, 'g-properties-changed', this, this._onPropertiesChanged); - Util.connectSmart(this._proxy, 'notify::g-name-owner', this, this._nameOwnerChanged); - - if (this.uniqueId === service) { - this._nameWatcher = new Util.NameWatcher(service); - Util.connectSmart(this._nameWatcher, 'changed', this, this._nameOwnerChanged); - } - } - - async _setupProxy() { - const cancellable = this._cancellable; - - try { - await this._proxy.initAsync(cancellable); - this._checkIfReady(); - await this._checkNeededProperties(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - logError(e, `While initalizing proxy for ${this._uniqueId}`); - this.destroy(); - } - } - - // We try to lookup the activate method to see if the app supports it - try { - const introspectionVariant = await this._proxy.gConnection.call( - this._proxy.gNameOwner, this._proxy.gObjectPath, - 'org.freedesktop.DBus.Introspectable', 'Introspect', null, null, - Gio.DBusCallFlags.NONE, -1, cancellable); - const [introspectionXml] = introspectionVariant.deep_unpack(); - const nodeInfo = Gio.DBusNodeInfo.new_for_xml(introspectionXml); - const interfaceInfo = nodeInfo.lookup_interface(this._proxy.gInterfaceName); - this.supportsActivation = !!interfaceInfo.lookup_method('Activate'); - this._hasAyatanaSecondaryActivate = - !!interfaceInfo.lookup_method('XAyatanaSecondaryActivate'); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - Util.Logger.debug( - `${this.uniqueId}, check for Activation support: ${e.message}`); - } - } - - try { - this._commandLine = await DBusUtils.getProcessName(this.busName, - cancellable, GLib.PRIORITY_LOW); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - Util.Logger.debug( - `${this.uniqueId}, failed getting command line: ${e.message}`); - } - } - } - - _checkIfReady() { - const wasReady = this.isReady; - let isReady = false; - - if (this.hasNameOwner && this.id && this.menuPath) - isReady = true; - - this.isReady = isReady; - - if (this.isReady && !wasReady) { - if (this._delayCheck) { - this._delayCheck.cancel(); - delete this._delayCheck; - } - - this.emit('ready'); - return true; - } - - return false; - } - - async _checkNeededProperties() { - if (this.id && this.menuPath) - return true; - - const MAX_RETRIES = 3; - const cancellable = this._cancellable; - for (let checks = 0; checks < MAX_RETRIES; ++checks) { - this._delayCheck = new PromiseUtils.TimeoutSecondsPromise(1, - GLib.PRIORITY_DEFAULT_IDLE, cancellable); - // eslint-disable-next-line no-await-in-loop - await this._delayCheck; - - try { - // eslint-disable-next-line no-await-in-loop - await Promise.all(AppIndicator.NEEDED_PROPERTIES.map(p => - this._proxy.refreshProperty(p))); - } catch (e) { - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - throw e; - - if (checks < MAX_RETRIES - 1) - continue; - - throw e; - } - - if (this.id && this.menuPath) - break; - } - - return this.id && this.menuPath; - } - - async _nameOwnerChanged() { - if (!this.hasNameOwner) { - this._checkIfReady(); - } else { - try { - await this._checkNeededProperties(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - Util.Logger.warn(`${this.uniqueId}, Impossible to get basic properties: ${e}`); - this.checkAlive(); - } - } - } - - this.emit('name-owner-changed'); - } - - // public property getters - get title() { - return this._proxy.Title; - } - - get id() { - return this._proxy.Id; - } - - get uniqueId() { - return this._uniqueId; - } - - get status() { - return this._proxy.Status; - } - - get label() { - return this._proxy.XAyatanaLabel || null; - } - - get accessibleName() { - const accessibleDesc = this.status === SNIStatus.NEEDS_ATTENTION - ? this._proxy.AccessibleDesc : this._proxy.IconAccessibleDesc; - - return accessibleDesc || this.title; - } - - get menuPath() { - if (this._proxy.Menu === '/NO_DBUSMENU') - return null; - - return this._proxy.Menu; - } - - get attentionIcon() { - return { - theme: this._proxy.IconThemePath, - name: this._proxy.AttentionIconName, - pixmap: this._getPixmapProperty(SNIconType.ATTENTION), - }; - } - - get icon() { - return { - theme: this._proxy.IconThemePath, - name: this._proxy.IconName, - pixmap: this._getPixmapProperty(SNIconType.NORMAL), - }; - } - - get overlayIcon() { - return { - theme: this._proxy.IconThemePath, - name: this._proxy.OverlayIconName, - pixmap: this._getPixmapProperty(SNIconType.OVERLAY), - }; - } - - get hasOverlayIcon() { - const {name, pixmap} = this.overlayIcon; - - return name || (pixmap && pixmap.n_children()); - } - - get hasNameOwner() { - if (this._nameWatcher && !this._nameWatcher.nameOnBus) - return false; - return !!this._proxy.g_name_owner; - } - - get cancellable() { - return this._cancellable; - } - - async checkAlive() { - // Some applications (hey electron!) just remove the indicator object - // from bus after hiding it, without closing its bus name, so we are - // not able to understand whe they're gone. - // Thus we just kill it when an expected well-known method is failing. - if (this.status !== SNIStatus.PASSIVE && this._checkIfReady()) { - if (this._checkAliveTimeout) { - this._checkAliveTimeout.cancel(); - delete this._checkAliveTimeout; - } - return; - } - - if (this._checkAliveTimeout) - return; - - try { - const cancellable = this._cancellable; - this._checkAliveTimeout = new PromiseUtils.TimeoutSecondsPromise(10, - GLib.PRIORITY_DEFAULT_IDLE, cancellable); - Util.Logger.debug(`${this.uniqueId}: may not respond, checking...`); - await this._checkAliveTimeout; - - // We should call the Ping method instead but in some containers - // such as snaps that's not accessible, so let's just use our own - await this._proxy.getProperty('Status', cancellable); - } catch (e) { - if (e.matches(Gio.DBusError, Gio.DBusError.NAME_HAS_NO_OWNER) || - e.matches(Gio.DBusError, Gio.DBusError.SERVICE_UNKNOWN) || - e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_OBJECT) || - e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_INTERFACE) || - e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD) || - e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_PROPERTY)) { - Util.Logger.warn(`${this.uniqueId}: not on bus anymore, removing it`); - this.destroy(); - return; - } - - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } finally { - delete this._checkAliveTimeout; - } - } - - _onPropertiesChanged(_proxy, changed, _invalidated) { - const props = Object.keys(changed.unpack()); - const signalsToEmit = new Set(); - const checkIfReadyChanged = () => { - if (checkIfReadyChanged.value === undefined) - checkIfReadyChanged.value = this._checkIfReady(); - return checkIfReadyChanged.value; - }; - - props.forEach(property => { - // some property changes require updates on our part, - // a few need to be passed down to the displaying code - if (property === 'Id') - checkIfReadyChanged(); - - // all these can mean that the icon has to be changed - if (property.startsWith('Icon') || - property.startsWith('AttentionIcon')) - signalsToEmit.add('icon'); - - // same for overlays - if (property.startsWith('OverlayIcon')) - signalsToEmit.add('overlay-icon'); - - // this may make all of our icons invalid - if (property === 'IconThemePath') { - signalsToEmit.add('icon'); - signalsToEmit.add('overlay-icon'); - } - - // the label will be handled elsewhere - if (property === 'XAyatanaLabel') - signalsToEmit.add('label'); - - if (property === 'Menu') { - if (!checkIfReadyChanged() && this.isReady) - signalsToEmit.add('menu'); - } - - if (property === 'IconAccessibleDesc' || - property === 'AttentionAccessibleDesc' || - property === 'Title') - signalsToEmit.add('accessible-name'); - - // status updates may cause the indicator to be hidden - if (property === 'Status') { - signalsToEmit.add('icon'); - signalsToEmit.add('overlay-icon'); - signalsToEmit.add('status'); - signalsToEmit.add('accessible-name'); - } - }); - - signalsToEmit.forEach(s => this.emit(s)); - } - - reset() { - this.emit('reset'); - } - - destroy() { - this.emit('destroy'); - - this.disconnectAll(); - this._proxy.destroy(); - this._cancellable.cancel(); - this._invalidatedPixmapsIcons.clear(); - - if (this._nameWatcher) - this._nameWatcher.destroy(); - delete this._cancellable; - delete this._proxy; - delete this._nameWatcher; - } - - _getPixmapProperty(iconType) { - const propertyName = SNIconType.toPropertyName(iconType, - {isPixbuf: true}); - const pixmap = this._proxy.get_cached_property(propertyName); - const wasInvalidated = this._invalidatedPixmapsIcons.delete(iconType); - - if (!pixmap && wasInvalidated) { - this._proxy.refreshProperty(propertyName, { - skipEqualityCheck: true, - }).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - }); - } - - return pixmap; - } - - invalidatePixmapProperty(iconType) { - this._invalidatedPixmapsIcons.add(iconType); - this._proxy.set_cached_property( - SNIconType.toPropertyName(iconType, {isPixbuf: true}), null); - } - - _getActivationToken(timestamp) { - const launchContext = global.create_app_launch_context(timestamp, -1); - const fakeAppInfo = Gio.AppInfo.create_from_commandline( - this._commandLine || 'true', this.id, - Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION); - return [launchContext, launchContext.get_startup_notify_id(fakeAppInfo, [])]; - } - - async provideActivationToken(timestamp) { - if (this._hasProvideXdgActivationToken === false) - return; - - const [launchContext, activationToken] = this._getActivationToken(timestamp); - try { - await this._proxy.ProvideXdgActivationTokenAsync(activationToken, - this._cancellable); - this._hasProvideXdgActivationToken = true; - } catch (e) { - launchContext.launch_failed(activationToken); - - if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD)) - this._hasProvideXdgActivationToken = false; - else - Util.Logger.warn(`${this.id}, failed to provide activation token: ${e.message}`); - } - } - - async open(x, y, timestamp) { - const cancellable = this._cancellable; - // we can't use WindowID because we're not able to get the x11 window id from a MetaWindow - // nor can we call any X11 functions. Luckily, the Activate method usually works fine. - // parameters are "an hint to the item where to show eventual windows" [sic] - // ... and don't seem to have any effect. - - try { - await this.provideActivationToken(timestamp); - await this._proxy.ActivateAsync(x, y, cancellable); - this.supportsActivation = true; - } catch (e) { - if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD)) { - this.supportsActivation = false; - Util.Logger.warn(`${this.id}, does not support activation: ${e.message}`); - return; - } - - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - Util.Logger.critical(`${this.id}, failed to activate: ${e.message}`); - } - } - - async secondaryActivate(timestamp, x, y) { - const cancellable = this._cancellable; - - try { - await this.provideActivationToken(timestamp); - - if (this._hasAyatanaSecondaryActivate !== false) { - try { - await this._proxy.XAyatanaSecondaryActivateAsync(timestamp, cancellable); - this._hasAyatanaSecondaryActivate = true; - } catch (e) { - if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD)) - this._hasAyatanaSecondaryActivate = false; - else - throw e; - } - } - - if (!this._hasAyatanaSecondaryActivate) - await this._proxy.SecondaryActivateAsync(x, y, cancellable); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - Util.Logger.critical(`${this.id}, failed to secondary activate: ${e.message}`); - } - } - - async scroll(dx, dy) { - const cancellable = this._cancellable; - - try { - const actions = []; - - if (dx !== 0) { - actions.push(this._proxy.ScrollAsync(Math.floor(dx), - 'horizontal', cancellable)); - } - - if (dy !== 0) { - actions.push(this._proxy.ScrollAsync(Math.floor(dy), - 'vertical', cancellable)); - } - - await Promise.all(actions); - } catch (e) { - Util.Logger.critical(`${this.id}, failed to scroll: ${e.message}`); - } - } -} - -const StTextureCacheSkippingFileIcon = GObject.registerClass({ - Implements: [Gio.Icon], -}, class StTextureCacheSkippingFileIconImpl extends Gio.EmblemedIcon { - _init(params) { - // FIXME: We can't just inherit from Gio.FileIcon for some reason - super._init({gicon: new Gio.FileIcon(params)}); - } - - vfunc_to_tokens() { - // Disables the to_tokens() vfunc so that the icon to_string() - // method won't work and thus can't be kept forever around by - // StTextureCache, see the awesome debugging session in this thread: - // https://twitter.com/mild_sunrise/status/1458739604098621443 - // upstream bug is at: - // https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4944 - return [false, [], 0]; - } -}); - -export const IconActor = GObject.registerClass( -class AppIndicatorsIconActor extends St.Icon { - static get DEFAULT_STYLE() { - const settings = SettingsManager.getDefaultGSettings(); - if (!settings.get_boolean('compact-mode-enabled')) - return 'padding: 0'; - else - return 'padding: 0; margin: 0'; - } - - static get USER_WRITABLE_PATHS() { - if (!this._userWritablePaths) { - this._userWritablePaths = [ - GLib.get_user_cache_dir(), - GLib.get_user_data_dir(), - GLib.get_user_config_dir(), - GLib.get_user_runtime_dir(), - GLib.get_home_dir(), - GLib.get_tmp_dir(), - ]; - - this._userWritablePaths.push(Object.values(GLib.UserDirectory).slice( - 0, -1).map(dirId => GLib.get_user_special_dir(dirId))); - } - - return this._userWritablePaths; - } - - _init(indicator, iconSize) { - super._init({ - reactive: true, - style_class: 'system-status-icon', - fallbackIconName: FALLBACK_ICON_NAME, - }); - - this.name = this.constructor.name; - this.add_style_class_name('appindicator-icon'); - this.add_style_class_name('status-notifier-icon'); - this.set_style(AppIndicatorsIconActor.DEFAULT_STYLE); - - const themeContext = St.ThemeContext.get_for_stage(global.stage); - this.height = iconSize * themeContext.scale_factor; - - this._indicator = indicator; - this._customIcons = new Map(); - this._iconSize = iconSize; - this._iconCache = new IconCache.IconCache(); - this._cancellable = new Gio.Cancellable(); - this._loadingIcons = Object.create(null); - - Object.values(SNIconType).forEach(t => (this._loadingIcons[t] = new Map())); - - Util.connectSmart(this._indicator, 'icon', this, () => { - if (this.is_mapped()) - this._updateIcon(); - }); - Util.connectSmart(this._indicator, 'overlay-icon', this, () => { - if (this.is_mapped()) - this._updateIcon(); - }); - Util.connectSmart(this._indicator, 'reset', this, - () => this._invalidateIconWhenFullyReady()); - - const settings = SettingsManager.getDefaultGSettings(); - Util.connectSmart(settings, 'changed::icon-size', this, () => - this._updateWhenFullyReady()); - Util.connectSmart(settings, 'changed::custom-icons', this, () => { - this._updateCustomIcons(); - this._invalidateIconWhenFullyReady(); - }); - - if (GObject.signal_lookup('resource-scale-changed', this)) - this.connect('resource-scale-changed', () => this._invalidateIcon()); - else - this.connect('notify::resource-scale', () => this._invalidateIcon()); - - Util.connectSmart(themeContext, 'notify::scale-factor', this, tc => { - this._updateIconSize(); - this.height = this._iconSize * tc.scale_factor; - this.width = -1; - this._invalidateIcon(); - }); - - Util.connectSmart(Util.getDefaultTheme(), 'changed', this, - () => this._invalidateIconWhenFullyReady()); - - this.connect('notify::mapped', () => { - if (!this.is_mapped()) - this._updateWhenFullyReady(); - }); - - this._updateWhenFullyReady(); - - this.connect('destroy', () => { - this._iconCache.destroy(); - this._cancellable.cancel(); - this._cancellable = null; - this._indicator = null; - this._loadingIcons = null; - this._iconTheme = null; - }); - } - - get debugId() { - return this._indicator ? this._indicator.id : this.toString(); - } - - async _waitForFullyReady() { - const waitConditions = []; - - if (!this.is_mapped()) { - waitConditions.push(new PromiseUtils.SignalConnectionPromise( - this, 'notify::mapped', this._cancellable)); - } - - if (!this._indicator.isReady) { - waitConditions.push(new PromiseUtils.SignalConnectionPromise( - this._indicator, 'ready', this._cancellable)); - } - - if (!waitConditions.length) - return true; - - await Promise.all(waitConditions); - return this._waitForFullyReady(); - } - - async _updateWhenFullyReady() { - if (this._waitingReady) - return; - - try { - this._waitingReady = true; - await this._waitForFullyReady(); - - this._updateIconSize(); - this._updateIconClass(); - this._updateCustomIcons(); - this._invalidateIcon(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } finally { - delete this._waitingReady; - } - } - - _updateIconClass() { - if (!this._indicator) - return; - - this.add_style_class_name( - `appindicator-icon-${this._indicator.id.toLowerCase().replace(/_|\s/g, '-')}`); - } - - _cancelLoadingByType(iconType) { - this._loadingIcons[iconType].forEach(c => c.cancel()); - this._loadingIcons[iconType].clear(); - } - - _ensureNoIconIsLoading(iconType, id) { - if (this._loadingIcons[iconType].has(id)) { - Util.Logger.debug(`${this.debugId}, Icon ${id} Is still loading, ignoring the request`); - throw new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING, - 'Already in progress'); - } else if (this._loadingIcons[iconType].size > 0) { - throw new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS, - 'Another icon is already loading'); - } - } - - _getIconLoadingCancellable(iconType, loadingId) { - try { - this._ensureNoIconIsLoading(iconType, loadingId); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) - throw e; - this._cancelLoadingByType(iconType); - } - - const cancellable = new Util.CancellableChild(this._cancellable); - this._loadingIcons[iconType].set(loadingId, cancellable); - - return cancellable; - } - - _cleanupIconLoadingCancellable(iconType, loadingId) { - if (this._loadingIcons) - this._loadingIcons[iconType].delete(loadingId); - } - - _getResourceScale() { - // Remove this when we remove support for versions earlier than 3.38 - const resourceScale = this.get_resource_scale(); - if (Array.isArray(resourceScale)) - return resourceScale[0] ? resourceScale[1] : 1.0; - - return resourceScale; - } - - // Will look the icon up in the cache, if it's found - // it will return it. Otherwise, it will create it and cache it. - async _cacheOrCreateIconByName(iconType, iconSize, iconScaling, iconName, themePath) { - const id = `${iconType}:${iconName}@${iconSize * iconScaling}:${themePath || ''}`; - let gicon = this._iconCache.get(id); - - if (gicon) - return gicon; - - const iconData = this._getIconData(iconName, themePath, iconSize, iconScaling); - const loadingId = iconData.file ? iconData.file.get_path() : id; - - const cancellable = await this._getIconLoadingCancellable(iconType, id); - try { - gicon = await this._createIconByIconData(iconData, iconSize, - iconScaling, cancellable); - } finally { - this._cleanupIconLoadingCancellable(iconType, loadingId); - } - if (gicon) - gicon = this._iconCache.add(id, gicon); - return gicon; - } - - _getIconLookupFlags(themeNode) { - let lookupFlags = 0; - - if (!themeNode) - return lookupFlags; - - const lookupFlagsEnum = St.IconLookupFlags; - const iconStyle = themeNode.get_icon_style(); - if (iconStyle === St.IconStyle.REGULAR) - lookupFlags |= lookupFlagsEnum.FORCE_REGULAR; - else if (iconStyle === St.IconStyle.SYMBOLIC) - lookupFlags |= lookupFlagsEnum.FORCE_SYMBOLIC; - - if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) - lookupFlags |= lookupFlagsEnum.DIR_RTL; - else - lookupFlags |= lookupFlagsEnum.DIR_LTR; - - return lookupFlags; - } - - async _createIconByIconData(iconData, iconSize, iconScaling, cancellable) { - const {file, name} = iconData; - - if (!file && !name) { - if (this._createIconIdle) { - throw new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING, - 'Already in progress'); - } - - try { - this._createIconIdle = new PromiseUtils.IdlePromise(GLib.PRIORITY_DEFAULT_IDLE, - cancellable); - await this._createIconIdle; - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - throw e; - } finally { - delete this._createIconIdle; - } - return this.gicon; - } else if (this._createIconIdle) { - this._createIconIdle.cancel(); - delete this._createIconIdle; - } - - if (name) - return new Gio.ThemedIcon({name}); - - if (!file) - throw new Error('Neither file or name are set'); - - if (!this._isFileInWritableArea(file)) - return new Gio.FileIcon({file}); - - try { - const [format, width, height] = await GdkPixbuf.Pixbuf.get_file_info_async( - file.get_path(), cancellable); - - if (!format) { - Util.Logger.critical(`${this.debugId}, Invalid image format: ${file.get_path()}`); - return null; - } - - if (width >= height * 1.5) { - /* Hello indicator-multiload! */ - await this._loadCustomImage(file, - width, height, iconSize, iconScaling, cancellable); - return null; - } else { - /* We'll wrap the icon so that it won't be cached forever by the shell */ - return new StTextureCacheSkippingFileIcon({file}); - } - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - Util.Logger.warn( - `${this.debugId}, Impossible to read image info from ` + - `path '${file ? file.get_path() : null}' or name '${name}': ${e}`); - } - throw e; - } - } - - async _loadCustomImage(file, width, height, iconSize, iconScaling, cancellable) { - const textureCache = St.TextureCache.get_default(); - const customImage = textureCache.load_file_async(file, -1, - height, 1, iconScaling); - - const setCustomImageActor = imageActor => { - const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); - const {content} = imageActor; - imageActor.content = null; - imageActor.destroy(); - - this._setImageContent(content, - width * scaleFactor, height * scaleFactor); - }; - - if (customImage.content) { - setCustomImageActor(customImage); - return; - } - - const imageContentPromise = new PromiseUtils.SignalConnectionPromise( - customImage, 'notify::content', cancellable); - const waitPromise = new PromiseUtils.TimeoutSecondsPromise( - 1, GLib.PRIORITY_DEFAULT, cancellable); - - const racingPromises = [imageContentPromise, waitPromise]; - - try { - await Promise.race(racingPromises); - if (!waitPromise.resolved()) - setCustomImageActor(customImage); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - throw e; - } finally { - racingPromises.forEach(p => p.cancel()); - } - } - - _isFileInWritableArea(file) { - // No need to use IO here, we can just do some assumptions - // print('Writable paths', IconActor.USER_WRITABLE_PATHS) - const path = file.get_path(); - return IconActor.USER_WRITABLE_PATHS.some(writablePath => - path.startsWith(writablePath)); - } - - _createIconTheme(searchPath = []) { - const iconTheme = new St.IconTheme(); - iconTheme.set_search_path(searchPath); - - return iconTheme; - } - - _getIconData(name, themePath, size, scale) { - const emptyIconData = {iconInfo: null, file: null, name: null}; - - if (!name) { - delete this._iconTheme; - return emptyIconData; - } - - // HACK: icon is a path name. This is not specified by the API, - // but at least indicator-sensors uses it. - if (name[0] === '/') { - delete this._iconTheme; - - const file = Gio.File.new_for_path(name); - return {file, iconInfo: null, name: null}; - } - - if (name.includes('.')) { - const splits = name.split('.'); - - if (['svg', 'png'].includes(splits[splits.length - 1])) - name = splits.slice(0, -1).join(''); - } - - if (themePath && Util.getDefaultTheme().get_search_path().includes(themePath)) - themePath = null; - - if (themePath) { - // If a theme path is provided, we need to lookup the icon ourself - // as St won't be able to do it unless we mess with default theme - // that is something we prefer not to do, as it would imply lots of - // St.TextureCache cleanups. - - const newSearchPath = [themePath]; - if (!this._iconTheme) { - this._iconTheme = this._createIconTheme(newSearchPath); - } else { - const currentSearchPath = this._iconTheme.get_search_path(); - - if (!currentSearchPath.includes(newSearchPath)) - this._iconTheme.set_search_path(newSearchPath); - } - - // try to look up the icon in the icon theme - const iconInfo = this._iconTheme.lookup_icon_for_scale(`${name}`, - size, scale, this._getIconLookupFlags(this.get_theme_node()) | - St.IconLookupFlags.GENERIC_FALLBACK); - - if (iconInfo) { - return { - iconInfo, - file: Gio.File.new_for_path(iconInfo.get_filename()), - name: null, - }; - } - - const logger = this.gicon ? Util.Logger.debug : Util.Logger.warn; - logger(`${this.debugId}, Impossible to lookup icon ` + - `for '${name}' in ${themePath}`); - - return emptyIconData; - } - - delete this._iconTheme; - return {name, iconInfo: null, file: null}; - } - - _setImageContent(content, width, height) { - this.set({ - content, - width, - height, - contentGravity: Clutter.ContentGravity.RESIZE_ASPECT, - fallbackIconName: null, - }); - } - - async _createIconFromPixmap(iconType, iconSize, iconScaling, scaleFactor, pixmapsVariant) { - const {pixmapVariant, width, height, rowStride} = - PixmapsUtils.getBestPixmap(pixmapsVariant, iconSize * iconScaling); - - const id = `__PIXMAP_ICON_${width}x${height}`; - - const imageContent = new St.ImageContent({ - preferredWidth: width, - preferredHeight: height, - }); - - // Remove this dynamic check when we depend on GNOME 48. - const coglContext = []; - const mutterBackend = global.stage?.context?.get_backend?.(); - if (imageContent.set_bytes.length === 6 && mutterBackend?.get_cogl_context) - coglContext.push(mutterBackend.get_cogl_context()); - imageContent.set_bytes(...coglContext, pixmapVariant.get_data_as_bytes(), - PIXMAPS_FORMAT, width, height, rowStride); - - if (iconType !== SNIconType.OVERLAY && !this._indicator.hasOverlayIcon) { - const scaledSize = iconSize * scaleFactor; - this._setImageContent(imageContent, scaledSize, scaledSize); - return null; - } - - const cancellable = this._getIconLoadingCancellable(iconType, id); - try { - // FIXME: async API results in a gray icon for some reason - const [inputStream] = imageContent.load(iconSize, cancellable); - return await GdkPixbuf.Pixbuf.new_from_stream_at_scale_async( - inputStream, -1, iconSize * iconScaling, true, cancellable); - } catch (e) { - // the image data was probably bogus. We don't really know why, but it _does_ happen. - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - Util.Logger.warn(`${this.debugId}, Impossible to create image from data: ${e}`); - throw e; - } finally { - this._cleanupIconLoadingCancellable(iconType, id); - } - } - - // The icon cache Active flag will be set to true if the used gicon matches - // the cached one (as in some cases it may be equal, but not the same object). - // So when it's not need anymore we make sure to check the active state - // and set it to false so that it can be picked up by the garbage collector. - _setGicon(iconType, gicon) { - if (iconType !== SNIconType.OVERLAY) { - if (gicon) { - if (this.gicon === gicon || - (this.gicon && this.gicon.get_icon() === gicon)) - return; - - if (gicon instanceof Gio.EmblemedIcon) - this.gicon = gicon; - else - this.gicon = new Gio.EmblemedIcon({gicon}); - - this._iconCache.updateActive(SNIconType.NORMAL, gicon, - this.gicon.get_icon() === gicon); - } else { - this.gicon = null; - } - } else if (gicon) { - this._emblem = new Gio.Emblem({icon: gicon}); - this._iconCache.updateActive(iconType, gicon, true); - } else { - this._emblem = null; - } - - if (this.gicon) { - if (!this.gicon.get_emblems().some(e => e.equal(this._emblem))) { - this.gicon.clear_emblems(); - if (this._emblem) - this.gicon.add_emblem(this._emblem); - } - } - } - - async _updateIconByType(iconType, iconSize) { - let icon; - switch (iconType) { - case SNIconType.ATTENTION: - icon = this._indicator.attentionIcon; - break; - case SNIconType.NORMAL: - ({icon} = this._indicator); - break; - case SNIconType.OVERLAY: - icon = this._indicator.overlayIcon; - break; - } - - const {theme, name, pixmap} = icon; - const commonArgs = [theme, iconType, iconSize]; - - if (this._customIcons.size) { - let customIcon = this._customIcons.get(iconType); - if (!await this._createAndSetIcon(customIcon, null, ...commonArgs)) { - if (iconType !== SNIconType.OVERLAY) { - customIcon = this._customIcons.get(SNIconType.NORMAL); - await this._createAndSetIcon(customIcon, null, ...commonArgs); - } - } - } else { - await this._createAndSetIcon(name, pixmap, ...commonArgs); - } - } - - async _createAndSetIcon(name, pixmap, theme, iconType, iconSize) { - let gicon = null; - - try { - gicon = await this._createIcon(name, pixmap, theme, iconType, iconSize); - } catch (e) { - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED) || - e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING)) - return null; - - if (iconType === SNIconType.OVERLAY) { - logError(e, `${this.debugId} unable to update icon emblem`); - } else { - this.fallbackIconName = FALLBACK_ICON_NAME; - logError(e, `${this.debugId} unable to update icon`); - } - } - - try { - this._setGicon(iconType, gicon); - - if (pixmap && this.gicon) { - // The pixmap has been saved, we can free the variants memory - this._indicator.invalidatePixmapProperty(iconType); - } - - return gicon; - } catch (e) { - logError(e, 'Setting GIcon failed'); - return null; - } - } - - // updates the base icon - async _createIcon(name, pixmap, theme, iconType, iconSize) { - const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); - const resourceScale = this._getResourceScale(); - const iconScaling = Math.ceil(resourceScale * scaleFactor); - - // From now on we consider them the same thing, as one replaces the other - if (iconType === SNIconType.ATTENTION) - iconType = SNIconType.NORMAL; - - if (name) { - const gicon = await this._cacheOrCreateIconByName( - iconType, iconSize, iconScaling, name, theme); - if (gicon) - return gicon; - } - - if (pixmap && pixmap.n_children()) { - return this._createIconFromPixmap(iconType, - iconSize, iconScaling, scaleFactor, pixmap); - } - - return null; - } - - // updates the base icon - async _updateIcon() { - if (this._indicator.status === SNIStatus.PASSIVE) - return; - - if (this.gicon instanceof Gio.EmblemedIcon) { - const {gicon} = this.gicon; - this._iconCache.updateActive(SNIconType.NORMAL, gicon, false); - } - - // we might need to use the AttentionIcon*, which have precedence over the normal icons - const iconType = this._indicator.status === SNIStatus.NEEDS_ATTENTION - ? SNIconType.ATTENTION : SNIconType.NORMAL; - - try { - await this._updateIconByType(iconType, this._iconSize); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED) && - !e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING)) - logError(e, `${this.debugId}: Updating icon type ${iconType} failed`); - } - } - - async _updateOverlayIcon() { - if (this._indicator.status === SNIStatus.PASSIVE) - return; - - if (this._emblem) { - const {icon} = this._emblem; - this._iconCache.updateActive(SNIconType.OVERLAY, icon, false); - } - - // KDE hardcodes the overlay icon size to 10px (normal icon size 16px) - // we approximate that ratio for other sizes, too. - // our algorithms will always pick a smaller one instead of stretching it. - const iconSize = Math.floor(this._iconSize / 1.6); - - try { - await this._updateIconByType(SNIconType.OVERLAY, iconSize); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED) && - !e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING)) - logError(e, `${this.debugId}: Updating overlay icon failed`); - } - } - - async _invalidateIconWhenFullyReady() { - if (this._waitingInvalidation) - return; - - try { - this._waitingInvalidation = true; - await this._waitForFullyReady(); - this._invalidateIcon(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } finally { - delete this._waitingInvalidation; - } - } - - // called when the icon theme changes - _invalidateIcon() { - this._iconCache.clear(); - this._cancellable.cancel(); - this._cancellable = new Gio.Cancellable(); - Object.values(SNIconType).forEach(iconType => - this._loadingIcons[iconType].clear()); - - this._updateIcon().catch(e => logError(e)); - this._updateOverlayIcon().catch(e => logError(e)); - } - - _updateIconSize() { - const settings = SettingsManager.getDefaultGSettings(); - const sizeValue = settings.get_int('icon-size'); - - if (sizeValue > 0) { - if (!this._defaultIconSize) - this._defaultIconSize = this._iconSize; - - this._iconSize = sizeValue; - } else if (this._defaultIconSize) { - this._iconSize = this._defaultIconSize; - delete this._defaultIconSize; - } - - const themeIconSize = Math.round( - this.get_theme_node().get_length('icon-size')); - let iconStyle = AppIndicatorsIconActor.DEFAULT_STYLE; - - if (themeIconSize > 0) { - const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); - - if (themeIconSize / scaleFactor !== this._iconSize) { - iconStyle = `${AppIndicatorsIconActor.DEFAULT_STYLE};` + - 'icon-size: 0'; - } - } - - this.set_style(iconStyle); - this.set_icon_size(this._iconSize); - } - - _updateCustomIcons() { - const settings = SettingsManager.getDefaultGSettings(); - this._customIcons.clear(); - - settings.get_value('custom-icons').deep_unpack().forEach(customIcons => { - const [indicatorId, normalIcon, attentionIcon] = customIcons; - if (this._indicator.id === indicatorId) { - this._customIcons.set(SNIconType.NORMAL, normalIcon); - this._customIcons.set(SNIconType.ATTENTION, attentionIcon); - } - }); - } -}); -- cgit v1.3