diff options
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com')
51 files changed, 0 insertions, 5856 deletions
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); - } - }); - } -}); diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js deleted file mode 100644 index 52c812d..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js +++ /dev/null @@ -1,990 +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 PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; -import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; - -import * as DBusInterfaces from './interfaces.js'; -import * as PromiseUtils from './promiseUtils.js'; -import * as Util from './util.js'; -import {DBusProxy} from './dbusProxy.js'; - -Gio._promisify(GdkPixbuf.Pixbuf, 'new_from_stream_async'); - -// //////////////////////////////////////////////////////////////////////// -// PART ONE: "ViewModel" backend implementation. -// Both code and design are inspired by libdbusmenu -// //////////////////////////////////////////////////////////////////////// - -/** - * Saves menu property values and handles type checking and defaults - */ -export class PropertyStore { - constructor(initialProperties) { - this._props = new Map(); - - if (initialProperties) { - for (const [prop, value] of Object.entries(initialProperties)) - this.set(prop, value); - } - } - - set(name, value) { - if (name in PropertyStore.MandatedTypes && value && - !value.is_of_type(PropertyStore.MandatedTypes[name])) - Util.Logger.warn(`Cannot set property ${name}: type mismatch!`); - else if (value) - this._props.set(name, value); - else - this._props.delete(name); - } - - get(name) { - const prop = this._props.get(name); - if (prop) - return prop; - else if (name in PropertyStore.DefaultValues) - return PropertyStore.DefaultValues[name]; - else - return null; - } -} - -// we list all the properties we know and use here, so we won' have to deal with unexpected type mismatches -PropertyStore.MandatedTypes = { - 'visible': GLib.VariantType.new('b'), - 'enabled': GLib.VariantType.new('b'), - 'label': GLib.VariantType.new('s'), - 'type': GLib.VariantType.new('s'), - 'children-display': GLib.VariantType.new('s'), - 'icon-name': GLib.VariantType.new('s'), - 'icon-data': GLib.VariantType.new('ay'), - 'toggle-type': GLib.VariantType.new('s'), - 'toggle-state': GLib.VariantType.new('i'), -}; - -PropertyStore.DefaultValues = { - 'visible': GLib.Variant.new_boolean(true), - 'enabled': GLib.Variant.new_boolean(true), - 'label': GLib.Variant.new_string(''), - 'type': GLib.Variant.new_string('standard'), - // elements not in here must return null -}; - -/** - * Represents a single menu item - */ -export class DbusMenuItem extends Signals.EventEmitter { - // will steal the properties object - constructor(client, id, properties, childrenIds) { - super(); - - this._client = client; - this._id = id; - this._propStore = new PropertyStore(properties); - this._children_ids = childrenIds; - } - - propertyGet(propName) { - const prop = this.propertyGetVariant(propName); - return prop ? prop.get_string()[0] : null; - } - - propertyGetVariant(propName) { - return this._propStore.get(propName); - } - - propertyGetBool(propName) { - const prop = this.propertyGetVariant(propName); - return prop ? prop.get_boolean() : false; - } - - propertyGetInt(propName) { - const prop = this.propertyGetVariant(propName); - return prop ? prop.get_int32() : 0; - } - - propertySet(prop, value) { - this._propStore.set(prop, value); - - this.emit('property-changed', prop, this.propertyGetVariant(prop)); - } - - resetProperties() { - Object.entries(PropertyStore.DefaultValues).forEach(([prop, value]) => - this.propertySet(prop, value)); - } - - getChildrenIds() { - return this._children_ids.concat(); // clone it! - } - - addChild(pos, childId) { - this._children_ids.splice(pos, 0, childId); - this.emit('child-added', this._client.getItem(childId), pos); - } - - removeChild(childId) { - // find it - let pos = -1; - for (let i = 0; i < this._children_ids.length; ++i) { - if (this._children_ids[i] === childId) { - pos = i; - break; - } - } - - if (pos < 0) { - Util.Logger.critical("Trying to remove child which doesn't exist"); - } else { - this._children_ids.splice(pos, 1); - this.emit('child-removed', this._client.getItem(childId)); - } - } - - moveChild(childId, newPos) { - // find the old position - let oldPos = -1; - for (let i = 0; i < this._children_ids.length; ++i) { - if (this._children_ids[i] === childId) { - oldPos = i; - break; - } - } - - if (oldPos < 0) { - Util.Logger.critical("tried to move child which wasn't in the list"); - return; - } - - if (oldPos !== newPos) { - this._children_ids.splice(oldPos, 1); - this._children_ids.splice(newPos, 0, childId); - this.emit('child-moved', oldPos, newPos, this._client.getItem(childId)); - } - } - - getChildren() { - return this._children_ids.map(el => this._client.getItem(el)); - } - - hasChildren() { - return this._children_ids.length > 0; - } - - handleEvent(event, data, timestamp) { - if (!data) - data = GLib.Variant.new_int32(0); - - return this._client.sendEvent(this._id, event, data, timestamp); - } - - getId() { - return this._id; - } - - sendAboutToShow() { - this._client.sendAboutToShow(this._id); - } -} - - -/** - * The client does the heavy lifting of actually reading layouts and distributing events - */ - -export const DBusClient = GObject.registerClass({ - Signals: {'ready-changed': {}}, -}, class AppIndicatorsDBusClient extends DBusProxy { - static get interfaceInfo() { - if (!this._interfaceInfo) { - this._interfaceInfo = Gio.DBusInterfaceInfo.new_for_xml( - DBusInterfaces.DBusMenu); - } - return this._interfaceInfo; - } - - static get baseItems() { - if (!this._baseItems) { - this._baseItems = { - 'children-display': GLib.Variant.new_string('submenu'), - }; - } - return this._baseItems; - } - - static destroy() { - delete this._interfaceInfo; - } - - _init(busName, objectPath) { - const {interfaceInfo} = AppIndicatorsDBusClient; - - super._init(busName, objectPath, interfaceInfo, - Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES); - - this._items = new Map(); - this._items.set(0, new DbusMenuItem(this, 0, DBusClient.baseItems, [])); - this._flagItemsUpdateRequired = false; - - // will be set to true if a layout update is needed once active - this._flagLayoutUpdateRequired = false; - - // property requests are queued - this._propertiesRequestedFor = new Set(/* ids */); - - this._layoutUpdated = false; - this._active = false; - } - - async initAsync(cancellable) { - await super.initAsync(cancellable); - - this._requestLayoutUpdate(); - } - - _onNameOwnerChanged() { - if (this.isReady) - this._requestLayoutUpdate(); - } - - get isReady() { - return this._layoutUpdated && !!this.gNameOwner; - } - - get cancellable() { - return this._cancellable; - } - - getRoot() { - return this._items.get(0); - } - - _requestLayoutUpdate() { - const cancellable = new Util.CancellableChild(this._cancellable); - this._beginLayoutUpdate(cancellable); - } - - async _requestProperties(propertyId, cancellable) { - this._propertiesRequestedFor.add(propertyId); - - if (this._propertiesRequest && this._propertiesRequest.pending()) - return; - - // if we don't have any requests queued, we'll need to add one - this._propertiesRequest = new PromiseUtils.IdlePromise( - GLib.PRIORITY_DEFAULT_IDLE, cancellable); - await this._propertiesRequest; - - const requestedProperties = Array.from(this._propertiesRequestedFor); - this._propertiesRequestedFor.clear(); - const [result] = await this.GetGroupPropertiesAsync(requestedProperties, - [], cancellable); - - result.forEach(([id, properties]) => { - const item = this._items.get(id); - if (!item) - return; - - item.resetProperties(); - - for (const [prop, value] of Object.entries(properties)) - item.propertySet(prop, value); - }); - } - - // Traverses the list of cached menu items and removes everyone that is not in the list - // so we don't keep alive unused items - _gcItems() { - const tag = new Date().getTime(); - - const toTraverse = [0]; - while (toTraverse.length > 0) { - const item = this.getItem(toTraverse.shift()); - item._dbusClientGcTag = tag; - Array.prototype.push.apply(toTraverse, item.getChildrenIds()); - } - - this._items.forEach((i, id) => { - if (i._dbusClientGcTag !== tag) - this._items.delete(id); - }); - } - - // the original implementation will only request partial layouts if somehow possible - // we try to save us from multiple kinds of race conditions by always requesting a full layout - _beginLayoutUpdate(cancellable) { - this._layoutUpdateUpdateAsync(cancellable).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - }); - } - - // the original implementation will only request partial layouts if somehow possible - // we try to save us from multiple kinds of race conditions by always requesting a full layout - async _layoutUpdateUpdateAsync(cancellable) { - // we only read the type property, because if the type changes after reading all properties, - // the view would have to replace the item completely which we try to avoid - if (this._layoutUpdateCancellable) - this._layoutUpdateCancellable.cancel(); - - this._layoutUpdateCancellable = cancellable; - - try { - const [revision_, root] = await this.GetLayoutAsync(0, -1, - ['type', 'children-display'], cancellable); - - this._updateLayoutState(true); - this._doLayoutUpdate(root, cancellable); - this._gcItems(); - this._flagLayoutUpdateRequired = false; - this._flagItemsUpdateRequired = false; - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - this._updateLayoutState(false); - throw e; - } finally { - if (this._layoutUpdateCancellable === cancellable) - this._layoutUpdateCancellable = null; - } - } - - _updateLayoutState(state) { - const wasReady = this.isReady; - this._layoutUpdated = state; - if (this.isReady !== wasReady) - this.emit('ready-changed'); - } - - _doLayoutUpdate(item, cancellable) { - const [id, properties, children] = item; - - const childrenUnpacked = children.map(c => c.deep_unpack()); - const childrenIds = childrenUnpacked.map(([c]) => c); - - // make sure all our children exist - childrenUnpacked.forEach(c => this._doLayoutUpdate(c, cancellable)); - - // make sure we exist - const menuItem = this._items.get(id); - - if (menuItem) { - // we do, update our properties if necessary - for (const [prop, value] of Object.entries(properties)) - menuItem.propertySet(prop, value); - - // make sure our children are all at the right place, and exist - const oldChildrenIds = menuItem.getChildrenIds(); - for (let i = 0; i < childrenIds.length; ++i) { - // try to recycle an old child - let oldChild = -1; - for (let j = 0; j < oldChildrenIds.length; ++j) { - if (oldChildrenIds[j] === childrenIds[i]) { - [oldChild] = oldChildrenIds.splice(j, 1); - break; - } - } - - if (oldChild < 0) { - // no old child found, so create a new one! - menuItem.addChild(i, childrenIds[i]); - } else { - // old child found, reuse it! - menuItem.moveChild(childrenIds[i], i); - } - } - - // remove any old children that weren't reused - oldChildrenIds.forEach(c => menuItem.removeChild(c)); - - if (!this._flagItemsUpdateRequired) - return id; - } - - // we don't, so let's create us - let newMenuItem = menuItem; - - if (!newMenuItem) { - newMenuItem = new DbusMenuItem(this, id, properties, childrenIds); - this._items.set(id, newMenuItem); - } - - this._requestProperties(id, cancellable).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - Util.Logger.warn(`Could not get menu properties menu proxy: ${e}`); - }); - - return id; - } - - async _doPropertiesUpdateAsync(cancellable) { - if (this._propertiesUpdateCancellable) - this._propertiesUpdateCancellable.cancel(); - - this._propertiesUpdateCancellable = cancellable; - - try { - const requests = []; - - this._items.forEach((_, id) => - requests.push(this._requestProperties(id, cancellable))); - - await Promise.all(requests); - } finally { - if (this._propertiesUpdateCancellable === cancellable) - this._propertiesUpdateCancellable = null; - } - } - - _doPropertiesUpdate() { - const cancellable = new Util.CancellableChild(this._cancellable); - this._doPropertiesUpdateAsync(cancellable).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - Util.Logger.warn(`Could not get menu properties menu proxy: ${e}`); - }); - } - - - set active(active) { - const wasActive = this._active; - this._active = active; - - if (active && wasActive !== active) { - if (this._flagLayoutUpdateRequired) { - this._requestLayoutUpdate(); - } else if (this._flagItemsUpdateRequired) { - this._doPropertiesUpdate(); - this._flagItemsUpdateRequired = false; - } - } - } - - _onSignal(_sender, signal, params) { - if (signal === 'LayoutUpdated') { - if (!this._active && this.getRoot()?.hasChildren()) { - this._flagLayoutUpdateRequired = true; - return; - } - - this._requestLayoutUpdate(); - } else if (signal === 'ItemsPropertiesUpdated') { - if (!this._active && this.getRoot()?.hasChildren()) { - this._flagItemsUpdateRequired = true; - return; - } - - this._onPropertiesUpdated(params.deep_unpack()); - } - } - - getItem(id) { - const item = this._items.get(id); - if (!item) - Util.Logger.warn(`trying to retrieve item for non-existing id ${id} !?`); - return item || null; - } - - // we don't need to cache and burst-send that since it will not happen that frequently - async sendAboutToShow(id) { - if (this._hasAboutToShow === false) - return; - - /* Some indicators (you, dropbox!) don't use the right signature - * and don't return a boolean, so we need to support both cases */ - try { - const ret = await this.gConnection.call(this.gName, this.gObjectPath, - this.gInterfaceName, 'AboutToShow', new GLib.Variant('(i)', [id]), - null, Gio.DBusCallFlags.NONE, -1, this._cancellable); - - if ((ret.is_of_type(new GLib.VariantType('(b)')) && - ret.get_child_value(0).get_boolean()) || - ret.is_of_type(new GLib.VariantType('()'))) - this._requestLayoutUpdate(); - } catch (e) { - Util.Logger.debug('Error when calling \'AboutToShow()\' in ' + - `${this.gName}, ${this.gObjectPath}, ${this.gInterfaceName}`); - if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD) || - e.matches(Gio.DBusError, Gio.DBusError.FAILED)) { - this._hasAboutToShow = false; - return; - } - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } - } - - async sendEvent(id, event, params, timestamp) { - if (!this.gNameOwner) - return; - - try { - await this.EventAsync(id, event, params, timestamp, this._cancellable); - } catch (e) { - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - return; - - throw e; - } - } - - _onPropertiesUpdated([changed, removed]) { - changed.forEach(([id, props]) => { - const item = this._items.get(id); - if (!item) - return; - - for (const [prop, value] of Object.entries(props)) - item.propertySet(prop, value); - }); - removed.forEach(([id, propNames]) => { - const item = this._items.get(id); - if (!item) - return; - - propNames.forEach(propName => item.propertySet(propName, null)); - }); - } -}); - -// //////////////////////////////////////////////////////////////////////// -// PART TWO: "View" frontend implementation. -// //////////////////////////////////////////////////////////////////////// - -// https://bugzilla.gnome.org/show_bug.cgi?id=731514 -// GNOME 3.10 and 3.12 can't open a nested submenu. -// Patches have been written, but it's not clear when (if?) they will be applied. -// We also don't know whether they will be backported to 3.10, so we will work around -// it in the meantime. Offending versions can be clearly identified: -const NEED_NESTED_SUBMENU_FIX = '_setOpenedSubMenu' in PopupMenu.PopupMenu.prototype; - -/** - * Creates new wrapper menu items and injects methods for managing them at runtime. - * - * Many functions in this object will be bound to the created item and executed as event - * handlers, so any `this` will refer to a menu item create in createItem - */ -const MenuItemFactory = { - createItem(client, dbusItem) { - // first, decide whether it's a submenu or not - let shellItem; - if (dbusItem.propertyGet('children-display') === 'submenu') - shellItem = new PopupMenu.PopupSubMenuMenuItem('FIXME'); - else if (dbusItem.propertyGet('type') === 'separator') - shellItem = new PopupMenu.PopupSeparatorMenuItem(''); - else - shellItem = new PopupMenu.PopupMenuItem('FIXME'); - - shellItem._dbusItem = dbusItem; - shellItem._dbusClient = client; - - if (shellItem instanceof PopupMenu.PopupMenuItem) { - shellItem._icon = new St.Icon({ - style_class: 'popup-menu-icon', - xAlign: Clutter.ActorAlign.END, - }); - shellItem.add_child(shellItem._icon); - shellItem.label.x_expand = true; - } - - // initialize our state - MenuItemFactory._updateLabel.call(shellItem); - MenuItemFactory._updateOrnament.call(shellItem); - MenuItemFactory._updateImage.call(shellItem); - MenuItemFactory._updateVisible.call(shellItem); - MenuItemFactory._updateSensitive.call(shellItem); - - // initially create children - if (shellItem instanceof PopupMenu.PopupSubMenuMenuItem) { - dbusItem.getChildren().forEach(c => - shellItem.menu.addMenuItem(MenuItemFactory.createItem(client, c))); - } - - // now, connect various events - Util.connectSmart(dbusItem, 'property-changed', - shellItem, MenuItemFactory._onPropertyChanged); - Util.connectSmart(dbusItem, 'child-added', - shellItem, MenuItemFactory._onChildAdded); - Util.connectSmart(dbusItem, 'child-removed', - shellItem, MenuItemFactory._onChildRemoved); - Util.connectSmart(dbusItem, 'child-moved', - shellItem, MenuItemFactory._onChildMoved); - Util.connectSmart(shellItem, 'activate', - shellItem, MenuItemFactory._onActivate); - - shellItem.connect('destroy', () => { - shellItem._dbusItemCancellable?.cancel(); - shellItem._dbusItemCancellable = null; - shellItem._dbusItem = null; - shellItem._dbusClient = null; - shellItem._icon = null; - }); - - if (shellItem.menu) { - Util.connectSmart(shellItem.menu, 'open-state-changed', - shellItem, MenuItemFactory._onOpenStateChanged); - } - - return shellItem; - }, - - _onOpenStateChanged(menu, open) { - if (open) { - if (NEED_NESTED_SUBMENU_FIX) { - // close our own submenus - if (menu._openedSubMenu) - menu._openedSubMenu.close(false); - - // register ourselves and close sibling submenus - if (menu._parent._openedSubMenu && menu._parent._openedSubMenu !== menu) - menu._parent._openedSubMenu.close(true); - - menu._parent._openedSubMenu = menu; - } - - this._dbusItem.handleEvent('opened', null, 0).catch(logError); - this._dbusItem.sendAboutToShow(); - } else { - if (NEED_NESTED_SUBMENU_FIX) { - // close our own submenus - if (menu._openedSubMenu) - menu._openedSubMenu.close(false); - } - - this._dbusItem.handleEvent('closed', null, 0).catch(logError); - } - }, - - _onActivate(_item, event) { - const timestamp = event.get_time(); - if (timestamp && this._dbusClient.indicator) - this._dbusClient.indicator.provideActivationToken(timestamp); - - this._dbusItem.handleEvent('clicked', GLib.Variant.new('i', 0), - timestamp).catch(logError); - }, - - _onPropertyChanged(dbusItem, prop, _value) { - if (prop === 'toggle-type' || prop === 'toggle-state') - MenuItemFactory._updateOrnament.call(this); - else if (prop === 'label') - MenuItemFactory._updateLabel.call(this); - else if (prop === 'enabled') - MenuItemFactory._updateSensitive.call(this); - else if (prop === 'visible') - MenuItemFactory._updateVisible.call(this); - else if (prop === 'icon-name' || prop === 'icon-data') - MenuItemFactory._updateImage.call(this); - else if (prop === 'type' || prop === 'children-display') - MenuItemFactory._replaceSelf.call(this); - else - Util.Logger.debug(`Unhandled property change: ${prop}`); - }, - - _onChildAdded(dbusItem, child, position) { - if (!(this instanceof PopupMenu.PopupSubMenuMenuItem)) { - Util.Logger.warn('Tried to add a child to non-submenu item. Better recreate it as whole'); - MenuItemFactory._replaceSelf.call(this); - } else { - this.menu.addMenuItem(MenuItemFactory.createItem(this._dbusClient, child), position); - } - }, - - _onChildRemoved(dbusItem, child) { - if (!(this instanceof PopupMenu.PopupSubMenuMenuItem)) { - Util.Logger.warn('Tried to remove a child from non-submenu item. Better recreate it as whole'); - MenuItemFactory._replaceSelf.call(this); - } else { - // find it! - this.menu._getMenuItems().forEach(item => { - if (item._dbusItem === child) - item.destroy(); - }); - } - }, - - _onChildMoved(dbusItem, child, oldpos, newpos) { - if (!(this instanceof PopupMenu.PopupSubMenuMenuItem)) { - Util.Logger.warn('Tried to move a child in non-submenu item. Better recreate it as whole'); - MenuItemFactory._replaceSelf.call(this); - } else { - MenuUtils.moveItemInMenu(this.menu, child, newpos); - } - }, - - _updateLabel() { - const label = this._dbusItem.propertyGet('label').replace(/_([^_])/, '$1'); - - if (this.label) // especially on GS3.8, the separator item might not even have a hidden label - this.label.set_text(label); - }, - - _updateOrnament() { - if (!this.setOrnament) - return; // separators and alike might not have gotten the polyfill - - if (this._dbusItem.propertyGet('toggle-type') === 'checkmark' && - this._dbusItem.propertyGetInt('toggle-state')) - this.setOrnament(PopupMenu.Ornament.CHECK); - else if (this._dbusItem.propertyGet('toggle-type') === 'radio' && - this._dbusItem.propertyGetInt('toggle-state')) - this.setOrnament(PopupMenu.Ornament.DOT); - else - this.setOrnament(PopupMenu.Ornament.NONE); - }, - - async _updateImage() { - if (!this._icon) - return; // might be missing on submenus / separators - - const iconName = this._dbusItem.propertyGet('icon-name'); - const iconData = this._dbusItem.propertyGetVariant('icon-data'); - if (iconName) { - this._icon.icon_name = iconName; - } else if (iconData) { - try { - if (!this._dbusItemCancellable) { - this._dbusItemCancellable = new Util.CancellableChild( - this._dbusClient.cancellable); - } - - const inputStream = Gio.MemoryInputStream.new_from_bytes( - iconData.get_data_as_bytes()); - this._icon.gicon = await GdkPixbuf.Pixbuf.new_from_stream_async( - inputStream, this._dbusItemCancellable); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } - } - }, - - _updateVisible() { - this.visible = this._dbusItem.propertyGetBool('visible'); - }, - - _updateSensitive() { - this.setSensitive(this._dbusItem.propertyGetBool('enabled')); - }, - - _replaceSelf(newSelf) { - // create our new self if needed - if (!newSelf) - newSelf = MenuItemFactory.createItem(this._dbusClient, this._dbusItem); - - // first, we need to find our old position - let pos = -1; - const family = this._parent._getMenuItems(); - for (let i = 0; i < family.length; ++i) { - if (family[i] === this) - pos = i; - } - - if (pos < 0) - throw new Error("DBusMenu: can't replace non existing menu item"); - - - // add our new self while we're still alive - this._parent.addMenuItem(newSelf, pos); - - // now destroy our old self - this.destroy(); - }, -}; - -/** - * Utility functions not necessarily belonging into the item factory - */ -const MenuUtils = { - moveItemInMenu(menu, dbusItem, newpos) { - // HACK: we're really getting into the internals of the PopupMenu implementation - - // First, find our wrapper. Children tend to lie. We do not trust the old positioning. - const family = menu._getMenuItems(); - for (let i = 0; i < family.length; ++i) { - if (family[i]._dbusItem === dbusItem) { - // now, remove it - menu.box.remove_child(family[i]); - - // and add it again somewhere else - if (newpos < family.length && family[newpos] !== family[i]) - menu.box.insert_child_below(family[i], family[newpos]); - else - menu.box.add(family[i]); - - // skip the rest - return; - } - } - }, -}; - - -/** - * Processes DBus events, creates the menu items and handles the actions - * - * Something like a mini-god-object - */ -export class Client extends Signals.EventEmitter { - constructor(busName, path, indicator) { - super(); - - this._busName = busName; - this._busPath = path; - this._client = new DBusClient(busName, path); - this._rootMenu = null; // the shell menu - this._rootItem = null; // the DbusMenuItem for the root - this.indicator = indicator; - this.cancellable = new Util.CancellableChild(this.indicator.cancellable); - - this._client.initAsync(this.cancellable).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - }); - - Util.connectSmart(this._client, 'ready-changed', this, - () => this.emit('ready-changed')); - } - - get isReady() { - return this._client.isReady; - } - - // this will attach the client to an already existing menu that will be used as the root menu. - // it will also connect the client to be automatically destroyed when the menu dies. - attachToMenu(menu) { - this._rootMenu = menu; - this._rootItem = this._client.getRoot(); - this._itemsBeingAdded = new Set(); - - // cleanup: remove existing children (just in case) - this._rootMenu.removeAll(); - - if (NEED_NESTED_SUBMENU_FIX) - menu._setOpenedSubMenu = this._setOpenedSubmenu.bind(this); - - // connect handlers - Util.connectSmart(menu, 'open-state-changed', this, this._onMenuOpenStateChanged); - Util.connectSmart(menu, 'destroy', this, this.destroy); - - Util.connectSmart(this._rootItem, 'child-added', this, this._onRootChildAdded); - Util.connectSmart(this._rootItem, 'child-removed', this, this._onRootChildRemoved); - Util.connectSmart(this._rootItem, 'child-moved', this, this._onRootChildMoved); - - // Dropbox requires us to call AboutToShow(0) first - this._rootItem.sendAboutToShow(); - - // fill the menu for the first time - const children = this._rootItem.getChildren(); - children.forEach(child => - this._onRootChildAdded(this._rootItem, child)); - } - - _setOpenedSubmenu(submenu) { - if (!submenu) - return; - - if (submenu._parent !== this._rootMenu) - return; - - if (submenu === this._openedSubMenu) - return; - - if (this._openedSubMenu && this._openedSubMenu.isOpen) - this._openedSubMenu.close(true); - - this._openedSubMenu = submenu; - } - - _onRootChildAdded(dbusItem, child, position) { - // Menu additions can be expensive, so let's do it in different chunks - const basePriority = this.isOpen ? GLib.PRIORITY_DEFAULT : GLib.PRIORITY_LOW; - const idlePromise = new PromiseUtils.IdlePromise( - basePriority + this._itemsBeingAdded.size, this.cancellable); - this._itemsBeingAdded.add(child); - - idlePromise.then(() => { - if (!this._itemsBeingAdded.has(child)) - return; - - this._rootMenu.addMenuItem( - MenuItemFactory.createItem(this, child), position); - }).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - }).finally(() => this._itemsBeingAdded.delete(child)); - } - - _onRootChildRemoved(dbusItem, child) { - // children like to play hide and seek - // but we know how to find it for sure! - const item = this._rootMenu._getMenuItems().find(it => - it._dbusItem === child); - - if (item) - item.destroy(); - else - this._itemsBeingAdded.delete(child); - } - - _onRootChildMoved(dbusItem, child, oldpos, newpos) { - MenuUtils.moveItemInMenu(this._rootMenu, dbusItem, newpos); - } - - _onMenuOpenStateChanged(menu, state) { - if (!this._rootItem) - return; - - this._client.active = state; - - if (state) { - if (this._openedSubMenu && this._openedSubMenu.isOpen) - this._openedSubMenu.close(); - - this._rootItem.handleEvent('opened', null, 0).catch(logError); - this._rootItem.sendAboutToShow(); - } else { - this._rootItem.handleEvent('closed', null, 0).catch(e => { - if (e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_OBJECT)) { - // The menu hay have been removed at this point, thus do not - // spam the users about this if it happens. - return; - } - - logError(e); - }); - } - } - - destroy() { - this.emit('destroy'); - - if (this._client) - this._client.destroy(); - - this._client = null; - this._rootItem = null; - this._rootMenu = null; - this.indicator = null; - this._itemsBeingAdded = null; - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusProxy.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusProxy.js deleted file mode 100644 index 047f2d2..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusProxy.js +++ /dev/null @@ -1,108 +0,0 @@ -import Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; - -import {CancellableChild, Logger} from './util.js'; - -Gio._promisify(Gio.DBusProxy.prototype, 'init_async'); - -export const DBusProxy = GObject.registerClass({ - Signals: {'destroy': {}}, -}, class DBusProxy extends Gio.DBusProxy { - static get TUPLE_VARIANT_TYPE() { - if (!this._tupleVariantType) - this._tupleVariantType = new GLib.VariantType('(v)'); - - return this._tupleVariantType; - } - - static destroy() { - delete this._tupleType; - } - - _init(busName, objectPath, interfaceInfo, flags = Gio.DBusProxyFlags.NONE) { - if (interfaceInfo.signals.length) - Logger.warn('Avoid exposing signals to gjs!'); - - super._init({ - gConnection: Gio.DBus.session, - gInterfaceName: interfaceInfo.name, - gInterfaceInfo: interfaceInfo, - gName: busName, - gObjectPath: objectPath, - gFlags: flags, - }); - - this._signalIds = []; - - if (!(flags & Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS)) { - this._signalIds.push(this.connect('g-signal', - (_proxy, ...args) => this._onSignal(...args))); - } - - this._signalIds.push(this.connect('notify::g-name-owner', () => { - if (!this.gNameOwner) { - this._cancellable.cancel(); - this._cancellable = new Gio.Cancellable(); - } - this._onNameOwnerChanged(); - })); - } - - async initAsync(cancellable) { - cancellable = new CancellableChild(cancellable); - await this.init_async(GLib.PRIORITY_DEFAULT, cancellable); - this._cancellable = cancellable; - - this.gInterfaceInfo.methods.map(m => m.name).forEach(method => - this._ensureAsyncMethod(method)); - } - - destroy() { - this.emit('destroy'); - - this._signalIds.forEach(id => this.disconnect(id)); - - if (this._cancellable) - this._cancellable.cancel(); - } - - // This can be removed when we will have GNOME 43 as minimum version - _ensureAsyncMethod(method) { - if (this[`${method}Async`]) - return; - - if (!this[`${method}Remote`]) - throw new Error(`Missing remote method '${method}'`); - - this[`${method}Async`] = function (...args) { - return new Promise((resolve, reject) => { - this[`${method}Remote`](...args, (ret, e) => { - if (e) - reject(e); - else - resolve(ret); - }); - }); - }; - } - - _onSignal() { - } - - getProperty(propertyName, cancellable) { - return this.gConnection.call(this.gName, - this.gObjectPath, 'org.freedesktop.DBus.Properties', 'Get', - GLib.Variant.new('(ss)', [this.gInterfaceName, propertyName]), - DBusProxy.TUPLE_VARIANT_TYPE, Gio.DBusCallFlags.NONE, -1, - cancellable); - } - - getProperties(cancellable) { - return this.gConnection.call(this.gName, - this.gObjectPath, 'org.freedesktop.DBus.Properties', 'GetAll', - GLib.Variant.new('(s)', [this.gInterfaceName]), - GLib.VariantType.new('(a{sv})'), Gio.DBusCallFlags.NONE, -1, - cancellable); - } -}); diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusUtils.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusUtils.js deleted file mode 100644 index d4d7a96..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/dbusUtils.js +++ /dev/null @@ -1,121 +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 Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; - -import {Logger} from './logger.js'; - -export const BUS_ADDRESS_REGEX = /([a-zA-Z0-9._-]+\.[a-zA-Z0-9.-]+)|(:[0-9]+\.[0-9]+)$/; - -Gio._promisify(Gio.DBusConnection.prototype, 'call'); - -export async function getUniqueBusName(bus, name, cancellable) { - if (name[0] === ':') - return name; - - if (!bus) - bus = Gio.DBus.session; - - const variantName = new GLib.Variant('(s)', [name]); - const [unique] = (await bus.call('org.freedesktop.DBus', '/', 'org.freedesktop.DBus', - 'GetNameOwner', variantName, new GLib.VariantType('(s)'), - Gio.DBusCallFlags.NONE, -1, cancellable)).deep_unpack(); - - return unique; -} - -export async function getBusNames(bus, cancellable) { - if (!bus) - bus = Gio.DBus.session; - - const [names] = (await bus.call('org.freedesktop.DBus', '/', 'org.freedesktop.DBus', - 'ListNames', null, new GLib.VariantType('(as)'), Gio.DBusCallFlags.NONE, - -1, cancellable)).deep_unpack(); - - const uniqueNames = new Map(); - const requests = names.map(name => getUniqueBusName(bus, name, cancellable)); - const results = await Promise.allSettled(requests); - - for (let i = 0; i < results.length; i++) { - const result = results[i]; - if (result.status === 'fulfilled') { - let namesForBus = uniqueNames.get(result.value); - if (!namesForBus) { - namesForBus = new Set(); - uniqueNames.set(result.value, namesForBus); - } - if (result.value !== names[i]) - namesForBus.add(names[i]); - } else if (!result.reason.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - Logger.debug(`Impossible to get the unique name of ${names[i]}: ${result.reason}`); - } - } - - return uniqueNames; -} - -async function getProcessId(connectionName, cancellable = null, bus = Gio.DBus.session) { - const res = await bus.call('org.freedesktop.DBus', '/', - 'org.freedesktop.DBus', 'GetConnectionUnixProcessID', - new GLib.Variant('(s)', [connectionName]), - new GLib.VariantType('(u)'), - Gio.DBusCallFlags.NONE, - -1, - cancellable); - const [pid] = res.deepUnpack(); - return pid; -} - -export async function getProcessName(connectionName, cancellable = null, - priority = GLib.PRIORITY_DEFAULT, bus = Gio.DBus.session) { - const pid = await getProcessId(connectionName, cancellable, bus); - const cmdFile = Gio.File.new_for_path(`/proc/${pid}/cmdline`); - const inputStream = await cmdFile.read_async(priority, cancellable); - const bytes = await inputStream.read_bytes_async(2048, priority, cancellable); - const textDecoder = new TextDecoder(); - return textDecoder.decode(bytes.toArray().map(v => !v ? 0x20 : v)); -} - -export async function* introspectBusObject(bus, name, cancellable, - interfaces = undefined, path = undefined) { - if (!path) - path = '/'; - - const [introspection] = (await bus.call(name, path, 'org.freedesktop.DBus.Introspectable', - 'Introspect', null, new GLib.VariantType('(s)'), Gio.DBusCallFlags.NONE, - 5000, cancellable)).deep_unpack(); - - const nodeInfo = Gio.DBusNodeInfo.new_for_xml(introspection); - - if (!interfaces || dbusNodeImplementsInterfaces(nodeInfo, interfaces)) - yield {nodeInfo, path}; - - if (path === '/') - path = ''; - - for (const subNodeInfo of nodeInfo.nodes) { - const subPath = `${path}/${subNodeInfo.path}`; - yield* introspectBusObject(bus, name, cancellable, interfaces, subPath); - } -} - -function dbusNodeImplementsInterfaces(nodeInfo, interfaces) { - if (!(nodeInfo instanceof Gio.DBusNodeInfo) || !Array.isArray(interfaces)) - return false; - - return interfaces.some(iface => nodeInfo.lookup_interface(iface)); -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/extension.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/extension.js deleted file mode 100644 index 6321077..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/extension.js +++ /dev/null @@ -1,90 +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 * as Extension from 'resource:///org/gnome/shell/extensions/extension.js'; - -import * as StatusNotifierWatcher from './statusNotifierWatcher.js'; -import * as Interfaces from './interfaces.js'; -import * as TrayIconsManager from './trayIconsManager.js'; -import * as Util from './util.js'; -import {Logger} from './logger.js'; -import {SettingsManager} from './settingsManager.js'; - -export default class AppIndicatorExtension extends Extension.Extension { - constructor(...args) { - super(...args); - - Logger.init(this); - Interfaces.initialize(this); - - this._isEnabled = false; - this._statusNotifierWatcher = null; - this._watchDog = new Util.NameWatcher(StatusNotifierWatcher.WATCHER_BUS_NAME); - this._watchDog.connect('vanished', () => this._maybeEnableAfterNameAvailable()); - - // HACK: we want to leave the watchdog alive when disabling the extension, - // but if we are being reloaded, we destroy it since it could be considered - // a leak and spams our log, too. - /* eslint-disable no-undef */ - if (typeof global['--appindicator-extension-on-reload'] === 'function') - global['--appindicator-extension-on-reload'](); - - global['--appindicator-extension-on-reload'] = () => { - Logger.debug('Reload detected, destroying old watchdog'); - this._watchDog.destroy(); - this._watchDog = null; - }; - /* eslint-enable no-undef */ - } - - enable() { - this._isEnabled = true; - SettingsManager.initialize(this); - Util.tryCleanupOldIndicators(); - this._maybeEnableAfterNameAvailable(); - TrayIconsManager.TrayIconsManager.initialize(); - } - - disable() { - this._isEnabled = false; - TrayIconsManager.TrayIconsManager.destroy(); - - if (this._statusNotifierWatcher !== null) { - this._statusNotifierWatcher.destroy(); - this._statusNotifierWatcher = null; - } - - SettingsManager.destroy(); - } - - // FIXME: when entering/leaving the lock screen, the extension might be - // enabled/disabled rapidly. - // This will create very bad side effects in case we were not done unowning - // the name while trying to own it again. Since g_bus_unown_name doesn't - // fire any callback when it's done, we need to monitor the bus manually - // to find out when the name vanished so we can reclaim it again. - _maybeEnableAfterNameAvailable() { - // by the time we get called whe might not be enabled - if (!this._isEnabled || this._statusNotifierWatcher) - return; - - if (this._watchDog.nameAcquired && this._watchDog.nameOnBus) - return; - - this._statusNotifierWatcher = new StatusNotifierWatcher.StatusNotifierWatcher( - this, this._watchDog); - } -} 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 deleted file mode 100644 index 3610184..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconCache.js +++ /dev/null @@ -1,179 +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 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(); - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconTheme.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconTheme.js deleted file mode 100644 index cdd6540..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/iconTheme.js +++ /dev/null @@ -1,12 +0,0 @@ -let _defaultTheme; -export function getDefaultTheme() { - if (_defaultTheme) - return _defaultTheme; - - _defaultTheme = new St.IconTheme(); - return _defaultTheme; -} - -export function destroyDefaultTheme() { - _defaultTheme = null; -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/custom-icons-symbolic.svg b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/custom-icons-symbolic.svg deleted file mode 100644 index bfc3698..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/custom-icons-symbolic.svg +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - viewBox="0 0 16 16" - version="1.1" - id="svg2" - sodipodi:docname="custom-icons-symbolic.svg" - inkscape:version="1.4 (1:1.4+202410161351+e7c3feb100)" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns="http://www.w3.org/2000/svg" - xmlns:svg="http://www.w3.org/2000/svg"> - <defs - id="defs2" /> - <sodipodi:namedview - id="namedview2" - pagecolor="#ffffff" - bordercolor="#000000" - borderopacity="0.25" - inkscape:showpageshadow="2" - inkscape:pageopacity="0.0" - inkscape:pagecheckerboard="0" - inkscape:deskcolor="#d1d1d1" - inkscape:zoom="31.404053" - inkscape:cx="7.4671891" - inkscape:cy="8.9001252" - inkscape:window-width="1860" - inkscape:window-height="1011" - inkscape:window-x="0" - inkscape:window-y="0" - inkscape:window-maximized="1" - inkscape:current-layer="svg2" /> - <g - fill="#222222" - id="g3" - transform="translate(-0.16009403)"> - <path - d="m 5.207031,1.292969 c -0.390625,-0.390625 -1.023437,-0.390625 -1.414062,0 l -2.5,2.5 c -0.390625,0.390625 -0.390625,1.023437 0,1.414062 l 2.5,2.5 c 0.390625,0.390625 1.023437,0.390625 1.414062,0 l 2.496094,-2.5 c 0.390625,-0.390625 0.390625,-1.023437 0,-1.414062 z m 0,0" - id="path1-3" /> - <path - d="m 10,12 c 0,1.65625 -1.34375,3 -3,3 -1.660156,0 -3,-1.34375 -3,-3 0,-1.65625 1.339844,-3 3,-3 1.65625,0 3,1.34375 3,3 z m 0,0" - id="path2-6" /> - <path - d="M 11.945312,2.003906 C 11.605469,2.019531 11.300781,2.207031 11.132812,2.5 L 8.8125,6.5 C 8.425781,7.164062 8.90625,8 9.675781,8 h 4.644531 c 0.769532,0 1.25,-0.835938 0.863282,-1.5 l -2.320313,-4 C 12.675781,2.171875 12.320312,1.980469 11.945312,2.003906 Z m 0,0" - id="path3" /> - </g> -</svg> diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/general-preferences-symbolic.svg b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/general-preferences-symbolic.svg deleted file mode 100644 index 6334430..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/icons/hicolor/scalable/actions/general-preferences-symbolic.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M12.5 2A2.5 2.5 0 0 0 10 4.5 2.5 2.5 0 0 0 12.5 7 2.5 2.5 0 0 0 15 4.5 2.5 2.5 0 0 0 12.5 2zm0 1A1.5 1.5 0 0 1 14 4.5 1.5 1.5 0 0 1 12.5 6 1.5 1.5 0 0 1 11 4.5 1.5 1.5 0 0 1 12.5 3zm-9 5A2.5 2.5 0 0 0 1 10.5 2.5 2.5 0 0 0 3.5 13a2.5 2.5 0 0 0 2.443-2H15v-1H5.95A2.5 2.5 0 0 0 3.5 8zm0 1A1.5 1.5 0 0 1 5 10.5 1.5 1.5 0 0 1 3.5 12 1.5 1.5 0 0 1 2 10.5 1.5 1.5 0 0 1 3.5 9z" style="fill:gray;stroke-width:.70228"/><path d="M-9 4h8v1h-8z" style="fill:gray;fill-opacity:1;stroke-width:1.05153;opacity:.5" transform="scale(-1 1)"/></svg>
\ No newline at end of file diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js deleted file mode 100644 index 533789e..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/indicatorStatusIcon.js +++ /dev/null @@ -1,613 +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 Gio from 'gi://Gio'; -import GObject from 'gi://GObject'; -import St from 'gi://St'; - -import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Panel from 'resource:///org/gnome/shell/ui/panel.js'; -import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js'; - -import * as AppIndicator from './appIndicator.js'; -import * as PromiseUtils from './promiseUtils.js'; -import * as SettingsManager from './settingsManager.js'; -import * as Util from './util.js'; -import * as DBusMenu from './dbusMenu.js'; - -const DEFAULT_ICON_SIZE = Panel.PANEL_ICON_SIZE || 16; - -export function addIconToPanel(statusIcon) { - if (!(statusIcon instanceof BaseStatusIcon)) - throw TypeError(`Unexpected icon type: ${statusIcon}`); - - const settings = SettingsManager.getDefaultGSettings(); - const indicatorId = `appindicator-${statusIcon.uniqueId}`; - - const currentIcon = Main.panel.statusArea[indicatorId]; - if (currentIcon) { - if (currentIcon !== statusIcon) - currentIcon.destroy(); - - Main.panel.statusArea[indicatorId] = null; - } - - Main.panel.addToStatusArea(indicatorId, statusIcon, 1, - settings.get_string('tray-pos')); - - Util.connectSmart(settings, 'changed::tray-pos', statusIcon, () => - addIconToPanel(statusIcon)); -} - -export function getTrayIcons() { - return Object.values(Main.panel.statusArea).filter( - i => i instanceof IndicatorStatusTrayIcon); -} - -export function getAppIndicatorIcons() { - return Object.values(Main.panel.statusArea).filter( - i => i instanceof IndicatorStatusIcon); -} - -export const BaseStatusIcon = GObject.registerClass( -class IndicatorBaseStatusIcon extends PanelMenu.Button { - _init(menuAlignment, nameText, iconActor, dontCreateMenu) { - super._init(menuAlignment, nameText, dontCreateMenu); - - const settings = SettingsManager.getDefaultGSettings(); - Util.connectSmart(settings, 'changed::icon-opacity', this, this._updateOpacity); - this.connect('notify::hover', () => this._onHoverChanged()); - - if (!super._onDestroy) - this.connect('destroy', () => this._onDestroy()); - - this._box = new St.BoxLayout({style_class: 'panel-status-indicators-box'}); - this.add_child(this._box); - - this._setIconActor(iconActor); - this._showIfReady(); - - this.set_style(IndicatorBaseStatusIcon.DEFAULT_STYLE); - } - - _setIconActor(icon) { - if (!(icon instanceof Clutter.Actor)) - throw new Error(`${icon} is not a valid actor`); - - if (this._icon && this._icon !== icon) - this._icon.destroy(); - - this._icon = icon; - this._updateEffects(); - this._monitorIconEffects(); - - if (this._icon) { - this._box.add_child(this._icon); - const id = this._icon.connect('destroy', () => { - this._icon.disconnect(id); - this._icon = null; - this._monitorIconEffects(); - }); - } - } - - _onDestroy() { - if (this._icon) - this._icon.destroy(); - - if (super._onDestroy) - super._onDestroy(); - } - - isReady() { - throw new GObject.NotImplementedError('isReady() in %s'.format(this.constructor.name)); - } - - get icon() { - return this._icon; - } - - get uniqueId() { - throw new GObject.NotImplementedError('uniqueId in %s'.format(this.constructor.name)); - } - - _showIfReady() { - this.visible = this.isReady(); - } - - _onHoverChanged() { - if (this.hover) { - this.opacity = 255; - if (this._icon) - this._icon.remove_effect_by_name('desaturate'); - } else { - this._updateEffects(); - } - } - - _updateOpacity() { - const settings = SettingsManager.getDefaultGSettings(); - const userValue = settings.get_user_value('icon-opacity'); - if (userValue) - this.opacity = userValue.unpack(); - else - this.opacity = 255; - } - - _updateEffects() { - this._updateOpacity(); - - if (this._icon) { - this._updateSaturation(); - this._updateBrightnessContrast(); - } - } - - _monitorIconEffects() { - const settings = SettingsManager.getDefaultGSettings(); - const monitoring = !!this._iconSaturationIds; - - if (!this._icon && monitoring) { - Util.disconnectSmart(settings, this, this._iconSaturationIds); - delete this._iconSaturationIds; - - Util.disconnectSmart(settings, this, this._iconBrightnessIds); - delete this._iconBrightnessIds; - - Util.disconnectSmart(settings, this, this._iconContrastIds); - delete this._iconContrastIds; - - Util.disconnectSmart(settings, this, this._compactModeEnabledIds); - delete this._compactModeEnabledIds; - } else if (this._icon && !monitoring) { - this._iconSaturationIds = - Util.connectSmart(settings, 'changed::icon-saturation', this, - this._updateSaturation); - this._iconBrightnessIds = - Util.connectSmart(settings, 'changed::icon-brightness', this, - this._updateBrightnessContrast); - this._iconContrastIds = - Util.connectSmart(settings, 'changed::icon-contrast', this, - this._updateBrightnessContrast); - this._compactModeEnabledIds = - Util.connectSmart(settings, 'changed::compact-mode-enabled', this, - this._updateCompactMode); - } - } - - static get DEFAULT_STYLE() { - const settings = SettingsManager.getDefaultGSettings(); - if (!settings.get_boolean('compact-mode-enabled')) - return null; // drop to default -natural-hpadding. - - return '-natural-hpadding: 10px'; - } - - _updateCompactMode() { - this._icon.set_style(AppIndicator.IconActor.DEFAULT_STYLE); - this.set_style(IndicatorBaseStatusIcon.DEFAULT_STYLE); - } - - _updateSaturation() { - const settings = SettingsManager.getDefaultGSettings(); - const desaturationValue = settings.get_double('icon-saturation'); - let desaturateEffect = this._icon.get_effect('desaturate'); - - if (desaturationValue > 0) { - if (!desaturateEffect) { - desaturateEffect = new Clutter.DesaturateEffect(); - this._icon.add_effect_with_name('desaturate', desaturateEffect); - } - desaturateEffect.set_factor(desaturationValue); - } else if (desaturateEffect) { - this._icon.remove_effect(desaturateEffect); - } - } - - _updateBrightnessContrast() { - const settings = SettingsManager.getDefaultGSettings(); - const brightnessValue = settings.get_double('icon-brightness'); - const contrastValue = settings.get_double('icon-contrast'); - let brightnessContrastEffect = this._icon.get_effect('brightness-contrast'); - - if (brightnessValue !== 0 | contrastValue !== 0) { - if (!brightnessContrastEffect) { - brightnessContrastEffect = new Clutter.BrightnessContrastEffect(); - this._icon.add_effect_with_name('brightness-contrast', brightnessContrastEffect); - } - brightnessContrastEffect.set_brightness(brightnessValue); - brightnessContrastEffect.set_contrast(contrastValue); - } else if (brightnessContrastEffect) { - this._icon.remove_effect(brightnessContrastEffect); - } - } -}); - -/* - * IndicatorStatusIcon implements an icon in the system status area - */ -export const IndicatorStatusIcon = GObject.registerClass( -class IndicatorStatusIcon extends BaseStatusIcon { - _init(indicator) { - super._init(0.5, indicator.accessibleName, - new AppIndicator.IconActor(indicator, DEFAULT_ICON_SIZE)); - - // Disable upstream's click gesture and fall back to vfunc_button_press_event etc. - this._clickGesture?.set_enabled(false); - - this._indicator = indicator; - - this._lastClickTime = -1; - this._lastClickX = -1; - this._lastClickY = -1; - - this._box.add_style_class_name('appindicator-box'); - - Util.connectSmart(this._indicator, 'ready', this, this._showIfReady); - Util.connectSmart(this._indicator, 'menu', this, this._updateMenu); - Util.connectSmart(this._indicator, 'label', this, this._updateLabel); - Util.connectSmart(this._indicator, 'status', this, this._updateStatus); - Util.connectSmart(this._indicator, 'reset', this, () => { - this._updateStatus(); - this._updateLabel(); - }); - Util.connectSmart(this._indicator, 'accessible-name', this, () => - this.set_accessible_name(this._indicator.accessibleName)); - Util.connectSmart(this._indicator, 'destroy', this, () => this.destroy()); - - this.connect('notify::visible', () => this._updateMenu()); - - this._showIfReady(); - } - - _onDestroy() { - if (this._menuClient) { - this._menuClient.disconnect(this._menuReadyId); - this._menuClient.destroy(); - this._menuClient = null; - } - - super._onDestroy(); - } - - get uniqueId() { - return this._indicator.uniqueId; - } - - isReady() { - return this._indicator && this._indicator.isReady; - } - - _updateLabel() { - const {label} = this._indicator; - if (label) { - if (!this._label || !this._labelBin) { - this._labelBin = new St.Bin({ - yAlign: Clutter.ActorAlign.CENTER, - }); - this._label = new St.Label(); - Util.addActor(this._labelBin, this._label); - Util.addActor(this._box, this._labelBin); - } - this._label.set_text(label); - if (!this._box.contains(this._labelBin)) - Util.addActor(this._box, this._labelBin); // FIXME: why is it suddenly necessary? - } else if (this._label) { - this._labelBin.destroy_all_children(); - Util.removeActor(this._box, this._labelBin); - this._labelBin.destroy(); - delete this._labelBin; - delete this._label; - } - } - - _updateStatus() { - const wasVisible = this.visible; - this.visible = this._indicator.status !== AppIndicator.SNIStatus.PASSIVE; - - if (this.visible !== wasVisible) - this._indicator.checkAlive().catch(logError); - } - - _updateMenu() { - if (this._menuClient) { - this._menuClient.disconnect(this._menuReadyId); - this._menuClient.destroy(); - this._menuClient = null; - this.menu.removeAll(); - } - - if (this.visible && this._indicator.menuPath) { - this._menuClient = new DBusMenu.Client(this._indicator.busName, - this._indicator.menuPath, this._indicator); - - if (this._menuClient.isReady) - this._menuClient.attachToMenu(this.menu); - - this._menuReadyId = this._menuClient.connect('ready-changed', () => { - if (this._menuClient.isReady) - this._menuClient.attachToMenu(this.menu); - else - this._updateMenu(); - }); - } - } - - _showIfReady() { - if (!this.isReady()) - return; - - this._updateLabel(); - this._updateStatus(); - this._updateMenu(); - } - - _updateClickCount(event) { - const [x, y] = event.get_coords(); - const time = event.get_time(); - const {doubleClickDistance, doubleClickTime} = - Clutter.Settings.get_default(); - - if (time > (this._lastClickTime + doubleClickTime) || - (Math.abs(x - this._lastClickX) > doubleClickDistance) || - (Math.abs(y - this._lastClickY) > doubleClickDistance)) - this._clickCount = 0; - - this._lastClickTime = time; - this._lastClickX = x; - this._lastClickY = y; - - this._clickCount = (this._clickCount % 2) + 1; - - return this._clickCount; - } - - _maybeHandleDoubleClick(event) { - if (this._indicator.supportsActivation === false) - return Clutter.EVENT_PROPAGATE; - - if (event.get_button() !== Clutter.BUTTON_PRIMARY) - return Clutter.EVENT_PROPAGATE; - - if (this._updateClickCount(event) === 2) { - this._indicator.open(...event.get_coords(), event.get_time()); - return Clutter.EVENT_STOP; - } - - return Clutter.EVENT_PROPAGATE; - } - - async _waitForDoubleClick() { - const {doubleClickTime} = Clutter.Settings.get_default(); - this._waitDoubleClickPromise = new PromiseUtils.TimeoutPromise( - doubleClickTime); - - try { - await this._waitDoubleClickPromise; - this.menu.toggle(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - throw e; - } finally { - delete this._waitDoubleClickPromise; - } - } - - vfunc_event(event) { - if (this.menu.numMenuItems && event.type() === Clutter.EventType.TOUCH_BEGIN) - this.menu.toggle(); - - return Clutter.EVENT_PROPAGATE; - } - - vfunc_button_press_event(event) { - if (this._waitDoubleClickPromise) - this._waitDoubleClickPromise.cancel(); - - // if middle mouse button clicked send SecondaryActivate dbus event and do not show appindicator menu - if (event.get_button() === Clutter.BUTTON_MIDDLE) { - if (Main.panel.menuManager.activeMenu) - Main.panel.menuManager._closeMenu(true, Main.panel.menuManager.activeMenu); - this._indicator.secondaryActivate(event.get_time(), ...event.get_coords()); - return Clutter.EVENT_STOP; - } - - if (event.get_button() === Clutter.BUTTON_SECONDARY) { - this.menu.toggle(); - return Clutter.EVENT_PROPAGATE; - } - - const doubleClickHandled = this._maybeHandleDoubleClick(event); - if (doubleClickHandled === Clutter.EVENT_PROPAGATE && - event.get_button() === Clutter.BUTTON_PRIMARY && - this.menu.numMenuItems) { - if (this._indicator.supportsActivation !== false) - this._waitForDoubleClick().catch(logError); - else - this.menu.toggle(); - } - - return Clutter.EVENT_PROPAGATE; - } - - vfunc_scroll_event(event) { - // Since Clutter 1.10, clutter will always send a smooth scrolling event - // with explicit deltas, no matter what input device is used - // In fact, for every scroll there will be a smooth and non-smooth scroll - // event, and we can choose which one we interpret. - if (event.get_scroll_direction() === Clutter.ScrollDirection.SMOOTH) { - const [dx, dy] = event.get_scroll_delta(); - - this._indicator.scroll(dx, dy); - return Clutter.EVENT_STOP; - } - - return Clutter.EVENT_PROPAGATE; - } -}); - -export const IndicatorStatusTrayIcon = GObject.registerClass( -class IndicatorTrayIcon extends BaseStatusIcon { - _init(icon) { - super._init(0.5, icon.wm_class, icon, {dontCreateMenu: true}); - Util.Logger.debug(`Adding legacy tray icon ${this.uniqueId}`); - this._box.add_style_class_name('appindicator-trayicons-box'); - this.add_style_class_name('appindicator-icon'); - this.add_style_class_name('tray-icon'); - - this.connect('button-press-event', (_actor, _event) => { - this.add_style_pseudo_class('active'); - return Clutter.EVENT_PROPAGATE; - }); - this.connect('button-release-event', (_actor, event) => { - this._icon.click(event); - this.remove_style_pseudo_class('active'); - return Clutter.EVENT_PROPAGATE; - }); - this.connect('key-press-event', (_actor, event) => { - this.add_style_pseudo_class('active'); - this._icon.click(event); - return Clutter.EVENT_PROPAGATE; - }); - this.connect('key-release-event', (_actor, event) => { - this._icon.click(event); - this.remove_style_pseudo_class('active'); - return Clutter.EVENT_PROPAGATE; - }); - - Util.connectSmart(this._icon, 'destroy', this, () => { - icon.clear_effects(); - this.destroy(); - }); - - const settings = SettingsManager.getDefaultGSettings(); - Util.connectSmart(settings, 'changed::icon-size', this, this._updateIconSize); - - const themeContext = St.ThemeContext.get_for_stage(global.stage); - Util.connectSmart(themeContext, 'notify::scale-factor', this, () => - this._updateIconSize()); - - this._updateIconSize(); - } - - _onDestroy() { - Util.Logger.debug(`Destroying legacy tray icon ${this.uniqueId}`); - - if (this._waitDoubleClickPromise) - this._waitDoubleClickPromise.cancel(); - - super._onDestroy(); - } - - isReady() { - return !!this._icon; - } - - get uniqueId() { - return `legacy:${this._icon.wm_class}:${this._icon.pid}`; - } - - vfunc_navigate_focus(from, direction) { - this.grab_key_focus(); - return super.vfunc_navigate_focus(from, direction); - } - - _getSimulatedButtonEvent(touchEvent) { - const event = Clutter.Event.new(Clutter.EventType.BUTTON_RELEASE); - event.set_button(1); - event.set_time(touchEvent.get_time()); - event.set_flags(touchEvent.get_flags()); - event.set_stage(global.stage); - event.set_source(touchEvent.get_source()); - event.set_coords(...touchEvent.get_coords()); - event.set_state(touchEvent.get_state()); - return event; - } - - vfunc_touch_event(event) { - // Under X11 we rely on emulated pointer events - const isWayland = typeof imports.gi.Meta.is_wayland_compositor === 'function' - ? imports.gi.Meta.is_wayland_compositor() - : global.display?.is_wayland_compositor?.() ?? true; - if (!isWayland) - return Clutter.EVENT_PROPAGATE; - - const slot = event.get_event_sequence().get_slot(); - - if (!this._touchPressSlot && - event.get_type() === Clutter.EventType.TOUCH_BEGIN) { - this.add_style_pseudo_class('active'); - this._touchButtonEvent = this._getSimulatedButtonEvent(event); - this._touchPressSlot = slot; - this._touchDelayPromise = new PromiseUtils.TimeoutPromise( - AppDisplay.MENU_POPUP_TIMEOUT); - this._touchDelayPromise.then(() => { - delete this._touchDelayPromise; - delete this._touchPressSlot; - this._touchButtonEvent.set_button(3); - this._icon.click(this._touchButtonEvent); - this.remove_style_pseudo_class('active'); - }); - } else if (event.get_type() === Clutter.EventType.TOUCH_END && - this._touchPressSlot === slot) { - delete this._touchPressSlot; - delete this._touchButtonEvent; - if (this._touchDelayPromise) { - this._touchDelayPromise.cancel(); - delete this._touchDelayPromise; - } - - this._icon.click(this._getSimulatedButtonEvent(event)); - this.remove_style_pseudo_class('active'); - } else if (event.get_type() === Clutter.EventType.TOUCH_UPDATE && - this._touchPressSlot === slot) { - this.add_style_pseudo_class('active'); - this._touchButtonEvent = this._getSimulatedButtonEvent(event); - } - - return Clutter.EVENT_PROPAGATE; - } - - vfunc_leave_event(event) { - this.remove_style_pseudo_class('active'); - - if (this._touchDelayPromise) { - this._touchDelayPromise.cancel(); - delete this._touchDelayPromise; - } - - return super.vfunc_leave_event(event); - } - - _updateIconSize() { - const settings = SettingsManager.getDefaultGSettings(); - const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); - let iconSize = settings.get_int('icon-size'); - - if (iconSize <= 0) - iconSize = DEFAULT_ICON_SIZE; - - this.height = -1; - this._icon.set({ - width: iconSize * scaleFactor, - height: iconSize * scaleFactor, - xAlign: Clutter.ActorAlign.CENTER, - yAlign: Clutter.ActorAlign.CENTER, - }); - } -}); diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/DBusMenu.xml b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/DBusMenu.xml deleted file mode 100644 index e98e04e..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/DBusMenu.xml +++ /dev/null @@ -1,66 +0,0 @@ -<interface name="com.canonical.dbusmenu"> - <!-- Properties --> - <property name="Version" type="u" access="read" /> - <property name="TextDirection" type="s" access="read" /> - <property name="Status" type="s" access="read" /> - <property name="IconThemePath" type="as" access="read" /> - - <!-- Functions --> - <method name="GetLayout"> - <arg type="i" name="parentId" direction="in" /> - <arg type="i" name="recursionDepth" direction="in" /> - <arg type="as" name="propertyNames" direction="in" /> - <arg type="u" name="revision" direction="out" /> - <arg type="(ia{sv}av)" name="layout" direction="out" /> - </method> - - <method name="GetGroupProperties"> - <arg type="ai" name="ids" direction="in" /> - <arg type="as" name="propertyNames" direction="in" /> - <arg type="a(ia{sv})" name="properties" direction="out" /> - </method> - - <method name="GetProperty"> - <arg type="i" name="id" direction="in" /> - <arg type="s" name="name" direction="in" /> - <arg type="v" name="value" direction="out" /> - </method> - - <method name="Event"> - <arg type="i" name="id" direction="in" /> - <arg type="s" name="eventId" direction="in" /> - <arg type="v" name="data" direction="in" /> - <arg type="u" name="timestamp" direction="in" /> - </method> - - <method name="EventGroup"> - <arg type="a(isvu)" name="events" direction="in" /> - <arg type="ai" name="idErrors" direction="out" /> - </method> - - <method name="AboutToShow"> - <arg type="i" name="id" direction="in" /> - <arg type="b" name="needUpdate" direction="out" /> - </method> - - <method name="AboutToShowGroup"> - <arg type="ai" name="ids" direction="in" /> - <arg type="ai" name="updatesNeeded" direction="out" /> - <arg type="ai" name="idErrors" direction="out" /> - </method> - - <!-- Signals - <signal name="ItemsPropertiesUpdated"> - <arg type="a(ia{sv})" name="updatedProps" direction="out" /> - <arg type="a(ias)" name="removedProps" direction="out" /> - </signal> - <signal name="LayoutUpdated"> - <arg type="u" name="revision" direction="out" /> - <arg type="i" name="parent" direction="out" /> - </signal> - <signal name="ItemActivationRequested"> - <arg type="i" name="id" direction="out" /> - <arg type="u" name="timestamp" direction="out" /> - </signal> - --> -</interface> diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierItem.xml b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierItem.xml deleted file mode 100644 index 8c36294..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierItem.xml +++ /dev/null @@ -1,130 +0,0 @@ -<!-- Based on: - https://invent.kde.org/frameworks/knotifications/-/blob/master/src/org.kde.StatusNotifierItem.xml ---> - -<interface name="org.kde.StatusNotifierItem"> - - <property name="Category" type="s" access="read"/> - <property name="Id" type="s" access="read"/> - <property name="Title" type="s" access="read"/> - <property name="Status" type="s" access="read"/> - <property name="WindowId" type="i" access="read"/> - - <!-- An additional path to add to the theme search path to find the icons specified above. --> - <property name="IconThemePath" type="s" access="read"/> - <property name="Menu" type="o" access="read"/> - <property name="ItemIsMenu" type="b" access="read"/> - - - <!-- main icon --> - <!-- names are preferred over pixmaps --> - <property name="IconName" type="s" access="read"/> - - <!--struct containing width, height and image data--> - <property name="IconPixmap" type="a(iiay)" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> - </property> - - <property name="OverlayIconName" type="s" access="read"/> - - <property name="OverlayIconPixmap" type="a(iiay)" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> - </property> - - - <!-- Requesting attention icon --> - <property name="AttentionIconName" type="s" access="read"/> - - <!--same definition as image--> - <property name="AttentionIconPixmap" type="a(iiay)" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusImageVector"/> - </property> - - <property name="AttentionMovieName" type="s" access="read"/> - - - - <!-- tooltip data --> - - <!--(iiay) is an image--> - <!-- We disable this as we don't support tooltip, so no need to go through it - <property name="ToolTip" type="(sa(iiay)ss)" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName" value="KDbusToolTipStruct"/> - </property> - --> - - <!-- interaction: the systemtray wants the application to do something --> - <method name="ContextMenu"> - <!-- we're passing the coordinates of the icon, so the app knows where to put the popup window --> - <arg name="x" type="i" direction="in"/> - <arg name="y" type="i" direction="in"/> - </method> - - <method name="Activate"> - <arg name="x" type="i" direction="in"/> - <arg name="y" type="i" direction="in"/> - </method> - - <method name="ProvideXdgActivationToken"> - <arg name="token" type="s" direction="in"/> - </method> - - <method name="SecondaryActivate"> - <arg name="x" type="i" direction="in"/> - <arg name="y" type="i" direction="in"/> - </method> - - <method name="XAyatanaSecondaryActivate"> - <arg name="timestamp" type="u" direction="in"/> - </method> - - <method name="Scroll"> - <arg name="delta" type="i" direction="in"/> - <arg name="orientation" type="s" direction="in"/> - </method> - - <!-- Signals: the client wants to change something in the status - <signal name="NewTitle"> - </signal> - - <signal name="NewIcon"> - </signal> - - <signal name="NewAttentionIcon"> - </signal> - - <signal name="NewOverlayIcon"> - </signal> - --> - <!-- We disable this as we don't support tooltip, so no need to go through it - <signal name="NewToolTip"> - </signal> - --> - - <!-- - <signal name="NewStatus"> - <arg name="status" type="s"/> - </signal> - --> - - - <!-- The following items are not supported by specs, but widely used - <signal name="NewIconThemePath"> - <arg type="s" name="icon_theme_path" direction="out" /> - </signal> - - <signal name="NewMenu"></signal> - --> - - <!-- ayatana labels --> - <!-- These are commented out because GDBusProxy would otherwise require them, - but they are not available for KDE indicators - --> - <!--<signal name="XAyatanaNewLabel"> - <arg type="s" name="label" direction="out" /> - <arg type="s" name="guide" direction="out" /> - </signal> - <property name="XAyatanaLabel" type="s" access="read" /> - <property name="XAyatanaLabelGuide" type="s" access="read" />--> - -</interface> diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierWatcher.xml b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierWatcher.xml deleted file mode 100644 index e450d04..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces-xml/StatusNotifierWatcher.xml +++ /dev/null @@ -1,38 +0,0 @@ -<interface name="org.kde.StatusNotifierWatcher"> - - <!-- methods --> - <method name="RegisterStatusNotifierItem"> - <arg name="service" type="s" direction="in"/> - </method> - - <method name="RegisterStatusNotifierHost"> - <arg name="service" type="s" direction="in"/> - </method> - - - <!-- properties --> - - <property name="RegisteredStatusNotifierItems" type="as" access="read"> - <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QStringList"/> - </property> - - <property name="IsStatusNotifierHostRegistered" type="b" access="read"/> - - <property name="ProtocolVersion" type="i" access="read"/> - - - <!-- signals --> - <signal name="StatusNotifierItemRegistered"> - <arg type="s"/> - </signal> - - <signal name="StatusNotifierItemUnregistered"> - <arg type="s"/> - </signal> - - <signal name="StatusNotifierHostRegistered"> - </signal> - - <signal name="StatusNotifierHostUnregistered"> - </signal> -</interface> diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces.js deleted file mode 100644 index 0a97907..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/interfaces.js +++ /dev/null @@ -1,52 +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. - -export let StatusNotifierItem = null; -export let StatusNotifierWatcher = null; -export let DBusMenu = null; - -// loads a xml file into an in-memory string -function loadInterfaceXml(extension, filename) { - const interfacesDir = extension.dir.get_child('interfaces-xml'); - const file = interfacesDir.get_child(filename); - const [result, contents] = imports.gi.GLib.file_get_contents(file.get_path()); - - if (result) { - // HACK: The "" + trick is important as hell because file_get_contents returns - // an object (WTF?) but Gio.makeProxyWrapper requires `typeof() === "string"` - // Otherwise, it will try to check `instanceof XML` and fail miserably because there - // is no `XML` on very recent SpiderMonkey releases (or, if SpiderMonkey is old enough, - // will spit out a TypeError soon). - let nodeContents = contents; - if (contents instanceof Uint8Array) - nodeContents = imports.byteArray.toString(contents); - return `<node>${nodeContents}</node>`; - } else { - throw new Error(`AppIndicatorSupport: Could not load file: ${filename}`); - } -} - -export function initialize(extension) { - StatusNotifierItem = loadInterfaceXml(extension, 'StatusNotifierItem.xml'); - StatusNotifierWatcher = loadInterfaceXml(extension, 'StatusNotifierWatcher.xml'); - DBusMenu = loadInterfaceXml(extension, 'DBusMenu.xml'); -} - -export function destroy() { - StatusNotifierItem = null; - StatusNotifierWatcher = null; - DBusMenu = null; -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ar/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ar/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 6c73616..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ar/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/bg/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/bg/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 2289e6d..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/bg/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 4cedb41..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/cs/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/de/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/de/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 6edb419..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/de/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/fr/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/fr/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index ba0d667..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/fr/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index ffbe4ed..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/hu/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/it/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/it/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 8b4b367..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/it/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ja/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ja/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index d22309b..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ja/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ka/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ka/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 0773c28..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ka/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ko/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ko/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 6d33af8..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ko/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/nl/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/nl/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 9d81088..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/nl/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/oc/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/oc/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index fe31bca..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/oc/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pl/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pl/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 4536d6e..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pl/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pt_BR/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pt_BR/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 0bb1b44..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/pt_BR/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ru/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ru/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index b4dfbe5..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ru/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sk/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sk/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 060d9c3..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sk/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index a7770c5..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr@latin/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr@latin/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index af2179f..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/sr@latin/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ta/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ta/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 9b6e5a6..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/ta/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/tr/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/tr/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index d31e5f2..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/tr/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index 88c7fbc..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/uk/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_CN/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_CN/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index df28844..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_CN/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo Binary files differdeleted file mode 100644 index f66fd67..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/locale/zh_TW/LC_MESSAGES/AppIndicatorExtension.mo +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/logger.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/logger.js deleted file mode 100644 index 3c60400..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/logger.js +++ /dev/null @@ -1,105 +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 GLib from 'gi://GLib'; - -/** - * Helper class for logging stuff - */ -export class Logger { - static _logStructured(logLevel, message, extraFields = {}) { - if (!Object.values(GLib.LogLevelFlags).includes(logLevel)) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_WARNING, - 'logLevel is not a valid GLib.LogLevelFlags'); - return; - } - - if (!Logger._levels.includes(logLevel)) - return; - - let fields = { - 'SYSLOG_IDENTIFIER': Logger._uuid, - 'MESSAGE': `${message}`, - }; - - let thisFile = null; - const {stack} = new Error(); - for (let stackLine of stack.split('\n')) { - stackLine = stackLine.replace('resource:///org/gnome/Shell/', ''); - const [code, line] = stackLine.split(':'); - const [func, file] = code.split(/@(.+)/); - - if (!thisFile || thisFile === file) { - thisFile = file; - continue; - } - - fields = Object.assign(fields, { - 'CODE_FILE': file || '', - 'CODE_LINE': line || '', - 'CODE_FUNC': func || '', - }); - - break; - } - - GLib.log_structured(Logger._domain, logLevel, Object.assign(fields, extraFields)); - } - - static init(extension) { - if (Logger._domain) - return; - - const allLevels = Object.values(GLib.LogLevelFlags); - const domains = GLib.getenv('G_MESSAGES_DEBUG'); - const {name: domain} = extension.metadata; - Logger._uuid = extension.metadata.uuid; - Logger._domain = domain.replaceAll(' ', '-'); - - if (domains === 'all' || (domains && domains.split(' ').includes(Logger._domain))) { - Logger._levels = allLevels; - } else { - Logger._levels = allLevels.filter( - l => l <= GLib.LogLevelFlags.LEVEL_WARNING); - } - } - - static destroy() { - delete Logger._domain; - delete Logger._uuid; - delete Logger._levels; - } - - static debug(message) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_DEBUG, message); - } - - static message(message) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_MESSAGE, message); - } - - static warn(message) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_WARNING, message); - } - - static error(message) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_ERROR, message); - } - - static critical(message) { - Logger._logStructured(GLib.LogLevelFlags.LEVEL_CRITICAL, message); - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/metadata.json b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/metadata.json deleted file mode 100644 index 96e3e2d..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/metadata.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Adds AppIndicator, KStatusNotifierItem and legacy Tray icons support to the Shell", - "gettext-domain": "AppIndicatorExtension", - "name": "AppIndicator and KStatusNotifierItem Support", - "settings-schema": "org.gnome.shell.extensions.appindicator", - "shell-version": [ - "45", - "46", - "47", - "48", - "49", - "50" - ], - "url": "https://github.com/ubuntu/gnome-shell-extension-appindicator", - "uuid": "appindicatorsupport@rgcjonas.gmail.com", - "version": 64 -}
\ No newline at end of file diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/pixmapsUtils.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/pixmapsUtils.js deleted file mode 100644 index ce4c3f3..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/pixmapsUtils.js +++ /dev/null @@ -1,68 +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. - -export function argbToRgba(src) { - const dest = new Uint8Array(src.length); - - for (let j = 0; j < src.length; j += 4) { - const srcAlpha = src[j]; - - dest[j] = src[j + 1]; /* red */ - dest[j + 1] = src[j + 2]; /* green */ - dest[j + 2] = src[j + 3]; /* blue */ - dest[j + 3] = srcAlpha; /* alpha */ - } - - return dest; -} - -export function getBestPixmap(pixmapsVariant, preferredSize) { - if (!pixmapsVariant) - throw new TypeError('null pixmapsVariant'); - - const pixmapsVariantsArray = new Array(pixmapsVariant.n_children()); - if (!pixmapsVariantsArray.length) - throw TypeError('Empty Icon found'); - - for (let i = 0; i < pixmapsVariantsArray.length; ++i) - pixmapsVariantsArray[i] = pixmapsVariant.get_child_value(i); - - const pixmapsSizedArray = pixmapsVariantsArray.map((pixmapVariant, index) => ({ - width: pixmapVariant.get_child_value(0).unpack(), - height: pixmapVariant.get_child_value(1).unpack(), - index, - })); - - const sortedIconPixmapArray = pixmapsSizedArray.sort( - ({width: widthA, height: heightA}, {width: widthB, height: heightB}) => { - const areaA = widthA * heightA; - const areaB = widthB * heightB; - - return areaA - areaB; - }); - - // we prefer any pixmap that is equal or bigger than our requested size - const qualifiedIconPixmapArray = sortedIconPixmapArray.filter(({width, height}) => - width >= preferredSize && height >= preferredSize); - - const {width, height, index} = qualifiedIconPixmapArray.length > 0 - ? qualifiedIconPixmapArray[0] : sortedIconPixmapArray.pop(); - - const pixmapVariant = pixmapsVariantsArray[index].get_child_value(2); - const rowStride = width * 4; // hopefully this is correct - - return {pixmapVariant, width, height, rowStride}; -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/customIconPage.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/customIconPage.js deleted file mode 100644 index b132562..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/customIconPage.js +++ /dev/null @@ -1,240 +0,0 @@ -/* exported GeneralPage*/ - -import Adw from 'gi://Adw'; -import Gtk from 'gi://Gtk'; -import GObject from 'gi://GObject'; -import Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import {gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; - -const IconData = GObject.registerClass({ - GTypeName: 'IconData', - Properties: { - 'id': GObject.ParamSpec.string( - 'id', - 'Id', - 'A read and write string property', - GObject.ParamFlags.READWRITE, - '' - ), - 'name': GObject.ParamSpec.string( - 'name', - 'Name', - 'A read and write string property', - GObject.ParamFlags.READWRITE, - '' - ), - 'at-name': GObject.ParamSpec.string( - 'at-name', - 'At Name', - 'A read and write string property', - GObject.ParamFlags.READWRITE, - '' - ), - - }, -}, class IconData extends GObject.Object { - constructor(props = {}) { - super(props); - } - - get id() { - if (this._id === 'undefined') - this._id = null; - return this._id; - } - - set id(value) { - if (this.id === value) - return; - - this._id = value; - this.notify('id'); - } - - get name() { - if (this._name === 'undefined') - this._name = null; - return this._name; - } - - set name(value) { - if (this.name === value) - return; - - this._name = value; - this.notify('name'); - } - - get atName() { - if (this._atName === 'undefined') - this._atName = null; - return this._atName; - } - - set atName(value) { - if (this.atName === value) - return; - - this._atName = value; - this.notify('at-name'); - } -}); - -export var CustomIconPage = GObject.registerClass( -class AppIndicatorCustomIconPage extends Adw.PreferencesPage { - _init(settings, settingsKey) { - super._init({ - title: _('Custom Icons'), - icon_name: 'custom-icons-symbolic', - name: 'Custom Icons Page', - }); - this._settings = settings; - this._settingsKey = settingsKey; - - this.group = new Adw.PreferencesGroup(); - - this.container = new Gtk.Box({ - halign: Gtk.Align.FILL, - hexpand: true, - orientation: Gtk.Orientation.VERTICAL, - }); - - this.listStore = new Gio.ListStore({ - item_type: IconData, - }); - - const initList = this._settings.get_value(this._settingsKey.CUSTOM_ICONS).deep_unpack(); - initList.forEach(pair => { - let data = new IconData({ - id: pair[0], - name: pair[1], - atName: pair[2], - }); - this.listStore.append(data); - }); - - this.listStore.append(new IconData({id: '', name: '', atName: ''})); - - this.selectionModel = new Gtk.SingleSelection({ - model: this.listStore, - }); - - this.columnView = new Gtk.ColumnView({ - hexpand: true, - model: this.selectionModel, - reorderable: false, - }); - - const columnTitles = [ - _('Indicator ID'), - _('Icon Name'), - _('Attention Icon Name'), - ]; - const indicatorIdColumn = new Gtk.ColumnViewColumn({ - title: columnTitles[0], - expand: true, - }); - const iconNameColumn = new Gtk.ColumnViewColumn({ - title: columnTitles[1], - expand: true, - }); - const attentionIconNameColumn = new Gtk.ColumnViewColumn({ - title: columnTitles[2], - expand: true, - }); - - - const factoryId = new Gtk.SignalListItemFactory(); - factoryId.connect('setup', (_widget, item) => { - const label = new Gtk.EditableLabel({text: ''}); - item.set_child(label); - }); - factoryId.connect('bind', (_widget, item) => { - const label = item.get_child(); - const data = item.get_item(); - label.set_text(data.id); - label.bind_property('text', data, 'id', GObject.BindingFlags.SYNC_CREATE); - label.connect('changed', () => this._autoSave(item)); - }); - - const factoryName = new Gtk.SignalListItemFactory(); - factoryName.connect('setup', (_widget, item) => { - const label = new Gtk.EditableLabel({text: ''}); - item.set_child(label); - }); - factoryName.connect('bind', (_widget, item) => { - const label = item.get_child(); - const data = item.get_item(); - label.set_text(data.name); - label.bind_property('text', data, 'name', GObject.BindingFlags.SYNC_CREATE); - label.connect('changed', () => this._autoSave(item)); - }); - - const factoryItName = new Gtk.SignalListItemFactory(); - factoryItName.connect('setup', (_widget, item) => { - const label = new Gtk.EditableLabel({text: ''}); - item.set_child(label); - }); - factoryItName.connect('bind', (_widget, item) => { - const label = item.get_child(); - const data = item.get_item(); - label.set_text(data.atName); - label.bind_property('text', data, 'at-name', GObject.BindingFlags.SYNC_CREATE); - label.connect('changed', () => this._autoSave(item)); - }); - - indicatorIdColumn.set_factory(factoryId); - iconNameColumn.set_factory(factoryName); - attentionIconNameColumn.set_factory(factoryItName); - - this.columnView.append_column(indicatorIdColumn); - this.columnView.append_column(iconNameColumn); - this.columnView.append_column(attentionIconNameColumn); - - this.container.append(this.columnView); - - this.group.add(this.container); - this.add(this.group); - } - - _autoSave(item) { - const storeLength = this.listStore.get_n_items(); - const newStore = []; - - for (let i = 0; i < storeLength; i++) { - const currentItem = this.listStore.get_item(i); - const id = currentItem.id; - const name = currentItem.name; - const atName = currentItem.atName; - if (id && name) - newStore.push([id, name, atName || '']); - } - - this._settings.set_value(this._settingsKey.CUSTOM_ICONS, - new GLib.Variant('a(sss)', newStore)); - - const id = item.get_item().id; - const name = item.get_item().name; - - /* dynamic new entry*/ - if (storeLength === 1 && (id || name)) - this.listStore.append(new IconData({id: '', name: '', atName: ''})); - - if (storeLength > 1) { - if ((id || name) && item.get_position() >= storeLength - 1) - this.listStore.append(new IconData({id: '', name: '', atName: ''})); - } - } - - _autoDelete(item) { - const storeLength = this.listStore.get_n_items(); - const id = item.get_item().id; - const name = item.get_item().name; - if (storeLength > 1 && !id && !name && - item.get_position() < storeLength - 1) - this.listStore.remove(item.get_position()); - } -}); - - diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/generalPage.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/generalPage.js deleted file mode 100644 index 7a2575b..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/preferences/generalPage.js +++ /dev/null @@ -1,159 +0,0 @@ -/* exported GeneralPage*/ - -import Adw from 'gi://Adw'; -import Gtk from 'gi://Gtk'; -import GObject from 'gi://GObject'; -import {gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; - - -export var GeneralPage = GObject.registerClass( -class AppIndicatorGeneralPage extends Adw.PreferencesPage { - _init(settings, settingsKey) { - super._init({ - title: _('General'), - icon_name: 'general-preferences-symbolic', - name: 'General Page', - }); - - this._settings = settings; - this._settingsKey = settingsKey; - - this.group = new Adw.PreferencesGroup(); // no title since only single group - - const legacyTraySwitch = new Adw.SwitchRow({ - title: _('Enable Legacy Tray Icons support'), - subtitle: _('Add X11 legacy tray icons to the panel area'), - active: this._settings.get_boolean(this._settingsKey.LEGACY_TRAY_ENABLED), - }); - - legacyTraySwitch.connect('notify::active', widget => - this._settings.set_boolean( - this._settingsKey.LEGACY_TRAY_ENABLED, - widget.get_active() - ) - ); - - this.group.add(legacyTraySwitch); - - const compactModeSwitch = new Adw.SwitchRow({ - title: _('Compact Mode'), - subtitle: _('Puts tray indicators closer together'), - active: this._settings.get_boolean(this._settingsKey.COMPACT_MODE_ENABLED), - }); - - compactModeSwitch.connect('notify::active', widget => - this._settings.set_boolean( - this._settingsKey.COMPACT_MODE_ENABLED, - widget.get_active() - ) - ); - - this.group.add(compactModeSwitch); - - this._createSpinRow({ - title: _('Opacity'), - settingsKey: this._settingsKey.ICON_OPACITY, - from: 0, - to: 255, - step: 1, - round: true, - }); - - this._createSpinRow({ - title: _('Desaturation'), - settingsKey: this._settingsKey.ICON_SATURATION, - from: 0.0, - to: 1.0, - step: 0.1, - }); - - this._createSpinRow({ - title: _('Brightness'), - settingsKey: this._settingsKey.ICON_BRIGHTNESS, - from: -1.0, - to: 1.0, - step: 0.1, - }); - - this._createSpinRow({ - title: _('Contrast'), - settingsKey: this._settingsKey.ICON_CONTRAST, - from: -1.0, - to: 1.0, - step: 0.1, - }); - - this._createSpinRow({ - title: _('Icon Size'), - settingsKey: this._settingsKey.ICON_SIZE, - from: 0, - to: 96, - step: 2, - round: true, - }); - - const alignmentList = new Gtk.StringList(); - const comboItems = [ - {pos: 'center', label: _('Center')}, - {pos: 'left', label: _('Left')}, - {pos: 'right', label: _('Right')}, - ]; - - comboItems.forEach(item => alignmentList.append(item.label)); - - const combo = new Adw.ComboRow({ - title: _('Tray Horizontal Alignment'), - model: alignmentList, - }); - const trayPos = this._settings.get_string(this._settingsKey.TRAY_POS); - combo.set_selected(comboItems.findIndex(item => trayPos === item.pos)); - - combo.connect('notify::selected', widget => this._settings.set_string( - this._settingsKey.TRAY_POS, comboItems[widget.get_selected()].pos)); - - this.group.add(combo); - this.add(this.group); - } - - _createSpinRow(args) { - let title = args.title || 'Default Title'; - let subtitle = args.subtitle || null; - let settingsKey = args.settingsKey || ''; - let from = args.from || 0; - let to = args.to || 100; - let step = args.step || 1; - let round = args.round || false; - - let spin = Adw.SpinRow.new_with_range(from, to, step); - spin.title = title; - if (subtitle !== null) - spin.subtitle = subtitle; - - if (round) - spin.set_value(this._settings.get_int(settingsKey)); - else - spin.set_value(this._settings.get_int(settingsKey)); - - - spin.connect('input', widget => { - if (round) - this._settings.set_int(settingsKey, parseInt(widget.get_value(), 10)); - else - this._settings.set_double(settingsKey, widget.get_value()); - - return false; - }); - spin.connect('output', widget => { - if (round) - this._settings.set_int(settingsKey, parseInt(widget.get_value(), 10)); - else - this._settings.set_double(settingsKey, widget.get_value()); - - return false; - }); - - this.group.add(spin); - } -}); - - diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/prefs.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/prefs.js deleted file mode 100644 index 344ba0a..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/prefs.js +++ /dev/null @@ -1,45 +0,0 @@ -// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- - -/* exported init, buildPrefsWidget */ - -import Gtk from 'gi://Gtk'; // will be removed -import Gdk from 'gi://Gdk'; -import * as GeneralPreferences from './preferences/generalPage.js'; -import * as CustomIconPreferences from './preferences/customIconPage.js'; - -import { - ExtensionPreferences, - gettext as _ -} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; - -const SettingsKey = { - LEGACY_TRAY_ENABLED: 'legacy-tray-enabled', - COMPACT_MODE_ENABLED: 'compact-mode-enabled', - ICON_SIZE: 'icon-size', - ICON_OPACITY: 'icon-opacity', - ICON_SATURATION: 'icon-saturation', - ICON_BRIGHTNESS: 'icon-brightness', - ICON_CONTRAST: 'icon-contrast', - TRAY_POS: 'tray-pos', - CUSTOM_ICONS: 'custom-icons', -}; - -export default class DockPreferences extends ExtensionPreferences { - fillPreferencesWindow(window) { - const iconTheme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()); - if (!iconTheme.get_search_path().includes(`${this.path}/icons`)) - iconTheme.add_search_path(`${this.path}/icons`); - - - const settings = this.getSettings(); - const generalPage = new GeneralPreferences.GeneralPage(settings, SettingsKey); - const customIconPage = new CustomIconPreferences.CustomIconPage(settings, SettingsKey); - - window.add(generalPage); - window.add(customIconPage); - - window.connect('close-request', () => { - window.destroy(); - }); - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/promiseUtils.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/promiseUtils.js deleted file mode 100644 index 2749b03..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/promiseUtils.js +++ /dev/null @@ -1,324 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -import Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Meta from 'gi://GdkPixbuf'; - -import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; - -export class CancellablePromise extends Promise { - constructor(executor, cancellable) { - if (!(executor instanceof Function)) - throw TypeError('executor is not a function'); - - if (cancellable && !(cancellable instanceof Gio.Cancellable)) - throw TypeError('cancellable parameter is not a Gio.Cancellable'); - - let rejector; - let resolver; - super((resolve, reject) => { - resolver = resolve; - rejector = reject; - }); - - const {stack: promiseStack} = new Error(); - this._promiseStack = promiseStack; - - this._resolver = (...args) => { - resolver(...args); - this._resolved = true; - this._cleanup(); - }; - this._rejector = (...args) => { - rejector(...args); - this._rejected = true; - this._cleanup(); - }; - - if (!cancellable) { - executor(this._resolver, this._rejector); - return; - } - - this._cancellable = cancellable; - this._cancelled = cancellable.is_cancelled(); - if (this._cancelled) { - this._rejector(new GLib.Error(Gio.IOErrorEnum, - Gio.IOErrorEnum.CANCELLED, 'Promise cancelled')); - return; - } - - this._cancellationId = cancellable.connect(() => { - const id = this._cancellationId; - this._cancellationId = 0; - GLib.idle_add(GLib.PRIORITY_DEFAULT, () => cancellable.disconnect(id)); - this.cancel(); - }); - - executor(this._resolver, this._rejector); - } - - _cleanup() { - if (this._cancellationId) - this._cancellable.disconnect(this._cancellationId); - } - - get cancellable() { - return this._chainRoot._cancellable || null; - } - - get _chainRoot() { - return this._root ? this._root : this; - } - - then(...args) { - const ret = super.then(...args); - - /* Every time we call then() on this promise we'd get a new - * CancellablePromise however that won't have the properties that the - * root one has set, and then it won't be possible to cancel a promise - * chain from the last one. - * To allow this we keep track of the root promise, make sure that - * the same method on the root object is called during cancellation - * or any destruction method if you want this to work. */ - if (ret instanceof CancellablePromise) - ret._root = this._chainRoot; - - return ret; - } - - resolved() { - return !!this._chainRoot._resolved; - } - - rejected() { - return !!this._chainRoot._rejected; - } - - cancelled() { - return !!this._chainRoot._cancelled; - } - - pending() { - return !this.resolved() && !this.rejected(); - } - - cancel() { - if (this._root) { - this._root.cancel(); - return this; - } - - if (!this.pending()) - return this; - - this._cancelled = true; - const error = new GLib.Error(Gio.IOErrorEnum, - Gio.IOErrorEnum.CANCELLED, 'Promise cancelled'); - error.stack += `## Promise created at:\n${this._promiseStack}`; - this._rejector(error); - - return this; - } -} - -export class SignalConnectionPromise extends CancellablePromise { - constructor(object, signal, cancellable) { - if (arguments.length === 1 && object instanceof Function) { - super(object); - return; - } - - if (!(object.connect instanceof Function)) - throw new TypeError('Not a valid object'); - - if (object instanceof GObject.Object && - !GObject.signal_lookup(signal.split(':')[0], object.constructor.$gtype)) - throw new TypeError(`Signal ${signal} not found on object ${object}`); - - let id; - let destroyId; - super(resolve => { - let connectSignal; - if (object instanceof GObject.Object) - connectSignal = (sig, cb) => GObject.signal_connect(object, sig, cb); - else - connectSignal = (sig, cb) => object.connect(sig, cb); - - id = connectSignal(signal, (_obj, ...args) => { - if (!args.length) - resolve(); - else - resolve(args.length === 1 ? args[0] : args); - }); - - if (signal !== 'destroy' && - (!(object instanceof GObject.Object) || - GObject.signal_lookup('destroy', object.constructor.$gtype))) - destroyId = connectSignal('destroy', () => this.cancel()); - }, cancellable); - - this._object = object; - this._id = id; - this._destroyId = destroyId; - } - - _cleanup() { - if (this._id) { - let disconnectSignal; - - if (this._object instanceof GObject.Object) - disconnectSignal = id => GObject.signal_handler_disconnect(this._object, id); - else - disconnectSignal = id => this._object.disconnect(id); - - disconnectSignal(this._id); - if (this._destroyId) { - disconnectSignal(this._destroyId); - this._destroyId = 0; - } - this._object = null; - this._id = 0; - } - - super._cleanup(); - } - - get object() { - return this._chainRoot._object; - } -} - -export class GSourcePromise extends CancellablePromise { - constructor(gsource, priority, cancellable) { - if (arguments.length === 1 && gsource instanceof Function) { - super(gsource); - return; - } - - if (gsource.constructor.$gtype !== GLib.Source.$gtype) - throw new TypeError(`gsource ${gsource} is not of type GLib.Source`); - - if (priority === undefined) - priority = GLib.PRIORITY_DEFAULT; - else if (!Number.isInteger(priority)) - throw TypeError('Invalid priority'); - - super(resolve => { - gsource.set_priority(priority); - gsource.set_callback(() => { - resolve(); - return GLib.SOURCE_REMOVE; - }); - gsource.attach(null); - }, cancellable); - - this._gsource = gsource; - this._gsource.set_name(`[gnome-shell] ${this.constructor.name} ${ - new Error().stack.split('\n').filter(line => - !line.match(/misc\/promiseUtils\.js/))[0]}`); - - if (this.rejected()) - this._gsource.destroy(); - } - - get gsource() { - return this._chainRoot._gsource; - } - - _cleanup() { - if (this._gsource) { - this._gsource.destroy(); - this._gsource = null; - } - super._cleanup(); - } -} - -export class IdlePromise extends GSourcePromise { - constructor(priority, cancellable) { - if (arguments.length === 1 && priority instanceof Function) { - super(priority); - return; - } - - if (priority === undefined) - priority = GLib.PRIORITY_DEFAULT_IDLE; - - super(GLib.idle_source_new(), priority, cancellable); - } -} - -export class TimeoutPromise extends GSourcePromise { - constructor(interval, priority, cancellable) { - if (arguments.length === 1 && interval instanceof Function) { - super(interval); - return; - } - - if (!Number.isInteger(interval) || interval < 0) - throw TypeError('Invalid interval'); - - super(GLib.timeout_source_new(interval), priority, cancellable); - } -} - -export class TimeoutSecondsPromise extends GSourcePromise { - constructor(interval, priority, cancellable) { - if (arguments.length === 1 && interval instanceof Function) { - super(interval); - return; - } - - if (!Number.isInteger(interval) || interval < 0) - throw TypeError('Invalid interval'); - - super(GLib.timeout_source_new_seconds(interval), priority, cancellable); - } -} - -export class MetaLaterPromise extends CancellablePromise { - constructor(laterType, cancellable) { - if (arguments.length === 1 && laterType instanceof Function) { - super(laterType); - return; - } - - if (laterType && laterType.constructor.$gtype !== Meta.LaterType.$gtype) - throw new TypeError(`laterType ${laterType} is not of type Meta.LaterType`); - else if (!laterType) - laterType = Meta.LaterType.BEFORE_REDRAW; - - let id; - super(resolve => { - id = Meta.later_add(laterType, () => { - this.remove(); - resolve(); - return GLib.SOURCE_REMOVE; - }); - }, cancellable); - - this._id = id; - } - - _cleanup() { - if (this._id) { - Meta.later_remove(this._id); - this._id = 0; - } - super._cleanup(); - } -} - -export function _promisifySignals(proto) { - if (proto.connect_once) - return; - - proto.connect_once = function (signal, cancellable) { - return new SignalConnectionPromise(this, signal, cancellable); - }; -} - -_promisifySignals(GObject.Object.prototype); -_promisifySignals(Signals.EventEmitter.prototype); diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/gschemas.compiled b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/gschemas.compiled Binary files differdeleted file mode 100644 index 1a6beff..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/gschemas.compiled +++ /dev/null diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/org.gnome.shell.extensions.appindicator.gschema.xml b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/org.gnome.shell.extensions.appindicator.gschema.xml deleted file mode 100644 index c303489..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/schemas/org.gnome.shell.extensions.appindicator.gschema.xml +++ /dev/null @@ -1,49 +0,0 @@ -<schemalist gettext-domain="AppIndicatorExtension"> - <schema id="org.gnome.shell.extensions.appindicator" path="/org/gnome/shell/extensions/appindicator/"> - <key name="legacy-tray-enabled" type="b"> - <default>true</default> - <summary>Enable legacy tray icons support</summary> - </key> - <key name="icon-saturation" type="d"> - <default>0.0</default> - <summary>Saturation</summary> - </key> - <key name="icon-brightness" type="d"> - <default>0.0</default> - <summary>Brightness</summary> - </key> - <key name="icon-contrast" type="d"> - <default>0.0</default> - <summary>Contrast</summary> - </key> - <key name="icon-opacity" type="i"> - <default>240</default> - <summary>Opacity</summary> - </key> - <key name="icon-size" type="i"> - <default>0</default> - <summary>Icon size</summary> - <description>Icon size in pixel</description> - </key> - <key name="compact-mode-enabled" type="b"> - <default>true</default> - <summary>Compact Mode</summary> - <description>Reduces the Spacing Between Indicators</description> - </key> - <key name="tray-pos" type="s"> - <default>"right"</default> - <summary>Position in tray</summary> - <description>Set where the Icon tray should appear in Gnome tray</description> - </key> - <key name="tray-order" type="i"> - <default>1</default> - <summary>Order in tray</summary> - <description>Set where the Icon tray should appear among other trays</description> - </key> - <key name="custom-icons" type="a(sss)"> - <default>[]</default> - <summary>Custom icons</summary> - <description>Replace any icons with custom icons from themes</description> - </key> - </schema> -</schemalist> diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/settingsManager.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/settingsManager.js deleted file mode 100644 index 6d943b9..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/settingsManager.js +++ /dev/null @@ -1,55 +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. - -let settingsManager; - -export class SettingsManager { - static initialize(extension) { - SettingsManager._settingsManager = new SettingsManager(extension); - } - - static destroy() { - SettingsManager._settingsManager.destroy(); - SettingsManager._settingsManager = null; - } - - static getDefault() { - return this._settingsManager; - } - - get gsettings() { - return this._gsettings; - } - - constructor(extension) { - if (settingsManager) - throw new Error('SettingsManager is already constructed'); - - this._gsettings = extension.getSettings(); - } - - destroy() { - this._gsettings = null; - } -} - -export function getDefault() { - return SettingsManager.getDefault(); -} - -export function getDefaultGSettings() { - return SettingsManager.getDefault().gsettings; -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/statusNotifierWatcher.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/statusNotifierWatcher.js deleted file mode 100644 index 2c5e54f..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/statusNotifierWatcher.js +++ /dev/null @@ -1,320 +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 Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; - -import * as AppIndicator from './appIndicator.js'; -import * as IndicatorStatusIcon from './indicatorStatusIcon.js'; -import * as Interfaces from './interfaces.js'; -import * as PromiseUtils from './promiseUtils.js'; -import * as Util from './util.js'; -import * as DBusUtils from './dbusUtils.js'; -import * as DBusMenu from './dbusMenu.js'; - -import {DBusProxy} from './dbusProxy.js'; - -Gio._promisify(Gio.Subprocess.prototype, 'wait_async'); -Gio._promisify(Gio.Subprocess.prototype, 'communicate_async'); -Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async', 'read_line_finish_utf8'); - - -// TODO: replace with org.freedesktop and /org/freedesktop when approved -const KDE_PREFIX = 'org.kde'; - -export const WATCHER_BUS_NAME = `${KDE_PREFIX}.StatusNotifierWatcher`; -const WATCHER_OBJECT = '/StatusNotifierWatcher'; - -const DEFAULT_ITEM_OBJECT_PATH = '/StatusNotifierItem'; - -/* - * The StatusNotifierWatcher class implements the StatusNotifierWatcher dbus object - */ -export class StatusNotifierWatcher { - constructor(extension, watchDog) { - this._watchDog = watchDog; - this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(Interfaces.StatusNotifierWatcher, this); - try { - this._dbusImpl.export(Gio.DBus.session, WATCHER_OBJECT); - } catch (e) { - Util.Logger.warn(`Failed to export ${WATCHER_OBJECT}`); - logError(e); - } - this._cancellable = new Gio.Cancellable(); - this._everAcquiredName = false; - this._ownName = Gio.DBus.session.own_name(WATCHER_BUS_NAME, - Gio.BusNameOwnerFlags.NONE, - this._acquiredName.bind(this), - this._lostName.bind(this)); - this._items = new Map(); - - try { - this._dbusImpl.emit_signal('StatusNotifierHostRegistered', null); - } catch (e) { - Util.Logger.warn(`Failed to notify registered host ${WATCHER_OBJECT}`); - } - - this._seekStatusNotifierItems(extension).catch(e => { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e, 'Looking for StatusNotifierItem\'s'); - }); - } - - _acquiredName() { - this._everAcquiredName = true; - this._watchDog.nameAcquired = true; - } - - _lostName() { - if (this._everAcquiredName) - Util.Logger.debug(`Lost name${WATCHER_BUS_NAME}`); - else - Util.Logger.warn(`Failed to acquire ${WATCHER_BUS_NAME}`); - this._watchDog.nameAcquired = false; - } - - async _registerItem(service, busName, objPath) { - const id = Util.indicatorId(service, busName, objPath); - - if (this._items.has(id)) { - Util.Logger.warn(`Item ${id} is already registered`); - return; - } - - Util.Logger.debug(`Registering StatusNotifierItem ${id}`); - - try { - const indicator = new AppIndicator.AppIndicator(service, busName, objPath); - this._items.set(id, indicator); - indicator.connect('destroy', () => this._onIndicatorDestroyed(indicator)); - - indicator.connect('name-owner-changed', async () => { - if (!indicator.hasNameOwner) { - try { - await new PromiseUtils.TimeoutPromise(500, - GLib.PRIORITY_DEFAULT, this._cancellable); - if (this._items.has(id) && !indicator.hasNameOwner) - indicator.destroy(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } - } - }); - - // if the desktop is not ready delay the icon creation and signal emissions - await Util.waitForStartupCompletion(indicator.cancellable); - const statusIcon = new IndicatorStatusIcon.IndicatorStatusIcon(indicator); - IndicatorStatusIcon.addIconToPanel(statusIcon); - - this._dbusImpl.emit_signal('StatusNotifierItemRegistered', - GLib.Variant.new('(s)', [indicator.uniqueId])); - this._dbusImpl.emit_property_changed('RegisteredStatusNotifierItems', - GLib.Variant.new('as', this.RegisteredStatusNotifierItems)); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - throw e; - } - } - - async _ensureItemRegistered(service, busName, objPath) { - const id = Util.indicatorId(service, busName, objPath); - const item = this._items.get(id); - - if (item) { - // delete the old one and add the new indicator - Util.Logger.debug(`Attempting to re-register ${id}; resetting instead`); - item.reset(); - return; - } - - await this._registerItem(service, busName, objPath); - } - - async _seekStatusNotifierItems(extension) { - // Some indicators (*coff*, dropbox, *coff*) do not re-register again - // when the plugin is enabled/disabled, thus we need to manually look - // for the objects in the session bus that implements the - // StatusNotifierItem interface... However let's do it after a low - // priority timeout, and using an external process so that it won't - // affect startup or memory (as it seems that gjs is not great at - // handling the memory of the bus analyzer async code). - const cancellable = this._cancellable; - await new PromiseUtils.TimeoutSecondsPromise(2, GLib.PRIORITY_LOW, cancellable); - const busAnalyzer = GLib.build_filenamev([ - extension.path, 'tools', 'busAnalyzer.js', - ]); - - const subProcess = Gio.Subprocess.new(['gjs', '-m', busAnalyzer], - Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE); - - const stdOut = subProcess.get_stdout_pipe(); - const dataInputStream = new Gio.DataInputStream({base_stream: stdOut}); - const textDecoder = new TextDecoder(); - - while (true) { - // eslint-disable-next-line no-await-in-loop - const [line] = await dataInputStream.read_line_async(GLib.PRIORITY_DEFAULT, - cancellable); - if (!line) - break; - - try { - const {services, name, path} = JSON.parse(textDecoder.decode(line)); - const ids = [null, ...services].map(s => Util.indicatorId(s, name, path)); - - if (ids.every(id => !this._items.has(id))) { - const service = services.find(s => - s && s.startsWith('org.kde.StatusNotifierItem')) || services[0]; - const id = Util.indicatorId( - path === DEFAULT_ITEM_OBJECT_PATH ? service : null, - name, path); - Util.Logger.warn(`Using Brute-force mode for StatusNotifierItem ${id}`); - // eslint-disable-next-line no-await-in-loop - await this._registerItem(service, name, path); - } - } catch (e) { - logError(e); - } - } - - const [, stdErr] = await subProcess.communicate_async(null, cancellable); - await subProcess.wait_async(cancellable); - - if (subProcess.get_exit_status() !== 0) { - const errorLines = textDecoder.decode(stdErr.toArray()).split('\n'); - const error = new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED, - errorLines[0]); - error.stack = `${errorLines.slice(3).join('\n')}${error.stack}`; - throw error; - } - } - - async RegisterStatusNotifierItemAsync(params, invocation) { - // it would be too easy if all application behaved the same - // instead, ayatana patched gnome apps to send a path - // while kde apps send a bus name - const [service] = params; - let busName, objPath; - - if (service.charAt(0) === '/') { // looks like a path - busName = invocation.get_sender(); - objPath = service; - } else if (service.match(DBusUtils.BUS_ADDRESS_REGEX)) { - try { - busName = await DBusUtils.getUniqueBusName(invocation.get_connection(), - service, this._cancellable); - } catch (e) { - logError(e); - } - objPath = DEFAULT_ITEM_OBJECT_PATH; - } - - if (!busName || !objPath) { - const error = `Impossible to register an indicator for parameters '${ - service.toString()}'`; - Util.Logger.warn(error); - - invocation.return_dbus_error('org.gnome.gjs.JSError.ValueError', - error); - return; - } - - try { - await this._ensureItemRegistered(service, busName, objPath); - invocation.return_value(null); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - invocation.return_dbus_error('org.gnome.gjs.JSError.ValueError', - e.message); - } - } - - _onIndicatorDestroyed(indicator) { - const {uniqueId} = indicator; - this._items.delete(uniqueId); - - try { - this._dbusImpl.emit_signal('StatusNotifierItemUnregistered', - GLib.Variant.new('(s)', [uniqueId])); - this._dbusImpl.emit_property_changed('RegisteredStatusNotifierItems', - GLib.Variant.new('as', this.RegisteredStatusNotifierItems)); - } catch (e) { - Util.Logger.warn(`Failed to emit signals: ${e}`); - } - } - - RegisterStatusNotifierHostAsync(_service, invocation) { - invocation.return_error_literal( - Gio.DBusError, - Gio.DBusError.NOT_SUPPORTED, - 'Registering additional notification hosts is not supported'); - } - - IsNotificationHostRegistered() { - return true; - } - - get RegisteredStatusNotifierItems() { - return Array.from(this._items.values()).map(i => i.uniqueId); - } - - get IsStatusNotifierHostRegistered() { - return true; - } - - get ProtocolVersion() { - return 0; - } - - destroy() { - if (this._isDestroyed) - return; - - // this doesn't do any sync operation and doesn't allow us to hook up - // the event of being finished which results in our unholy debounce hack - // (see extension.js) - this._items.forEach(indicator => indicator.destroy()); - this._cancellable.cancel(); - - try { - this._dbusImpl.emit_signal('StatusNotifierHostUnregistered', null); - } catch (e) { - Util.Logger.warn(`Failed to emit uinregistered signal: ${e}`); - } - - Gio.DBus.session.unown_name(this._ownName); - - try { - this._dbusImpl.unexport(); - } catch (e) { - Util.Logger.warn(`Failed to unexport watcher object: ${e}`); - } - - DBusMenu.DBusClient.destroy(); - AppIndicator.AppIndicatorProxy.destroy(); - DBusProxy.destroy(); - Util.destroyDefaultTheme(); - - this._dbusImpl.run_dispose(); - delete this._dbusImpl; - - delete this._items; - this._isDestroyed = true; - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/tools/busAnalyzer.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/tools/busAnalyzer.js deleted file mode 100644 index 969f4e6..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/tools/busAnalyzer.js +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env gjs -m - -import GLib from 'gi://GLib'; -import Gio from 'gi://Gio'; -import GioUnix from 'gi://GioUnix'; - -import * as DBusUtils from '../dbusUtils.js'; - -async function seekStatusNotifierItems() { - // Some indicators (*coff*, dropbox, *coff*) do not re-register again - // when the plugin is enabled/disabled, thus we need to manually look - // for the objects in the session bus that implements the StatusNotifierItem - // interface... - const cancellable = null; - const bus = Gio.DBus.session; - const uniqueNames = await DBusUtils.getBusNames(bus, cancellable); - - const stdErrOutputStream = new GioUnix.OutputStream({fd: 1, closeFd: true}); - const introspectName = async name => { - const nodes = DBusUtils.introspectBusObject(bus, name, cancellable, - ['org.kde.StatusNotifierItem']); - const services = [...uniqueNames.get(name)]; - - for await (const node of nodes) { - const {path} = node; - stdErrOutputStream.write(`${JSON.stringify({services, name, path})}\n`, - cancellable); - } - }; - await Promise.allSettled([...uniqueNames.keys()].map(n => introspectName(n))); -} - -function main(_argv) { - const loop = new GLib.MainLoop(null, false); - - let exitCode = 0; - seekStatusNotifierItems().catch(e => { - logError(e); - exitCode = 1; - }).finally(() => loop.quit()); - loop.run(); - - return exitCode; -} - -imports.system.exit(main(ARGV)); diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js deleted file mode 100644 index 6ec7ccd..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/trayIconsManager.js +++ /dev/null @@ -1,103 +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 Shell from 'gi://Shell'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; - -import * as IndicatorStatusIcon from './indicatorStatusIcon.js'; -import * as Util from './util.js'; -import * as SettingsManager from './settingsManager.js'; - -let trayIconsManager; - -export class TrayIconsManager extends Signals.EventEmitter { - static initialize() { - if (!trayIconsManager) - trayIconsManager = new TrayIconsManager(); - return trayIconsManager; - } - - static destroy() { - trayIconsManager.destroy(); - } - - constructor() { - super(); - - if (trayIconsManager) - throw new Error('TrayIconsManager is already constructed'); - - this._changedId = SettingsManager.getDefaultGSettings().connect( - 'changed::legacy-tray-enabled', () => this._toggle()); - - this._toggle(); - } - - _toggle() { - if (SettingsManager.getDefaultGSettings().get_boolean('legacy-tray-enabled')) - this._enable(); - else - this._disable(); - } - - _getPanelBgColor() { - return Main.panel?.get_parent() - ? Main.panel.get_theme_node()?.get_background_color() : null; - } - - _enable() { - if (this._tray) - return; - - this._tray = new Shell.TrayManager({bgColor: this._getPanelBgColor()}); - Util.connectSmart(this._tray, 'tray-icon-added', this, this.onTrayIconAdded); - Util.connectSmart(this._tray, 'tray-icon-removed', this, this.onTrayIconRemoved); - - this._tray.manage_screen(Main.panel); - } - - _disable() { - if (!this._tray) - return; - - IndicatorStatusIcon.getTrayIcons().forEach(i => i.destroy()); - this._tray.unmanage_screen(); - this._tray = null; - } - - onTrayIconAdded(_tray, icon) { - const trayIcon = new IndicatorStatusIcon.IndicatorStatusTrayIcon(icon); - IndicatorStatusIcon.addIconToPanel(trayIcon); - } - - onTrayIconRemoved(_tray, icon) { - try { - const [trayIcon] = IndicatorStatusIcon.getTrayIcons().filter(i => i.icon === icon); - trayIcon.destroy(); - } catch (e) { - Util.Logger.warning(`No icon container found for ${icon.title} (${icon})`); - } - } - - destroy() { - this.emit('destroy'); - SettingsManager.getDefaultGSettings().disconnect(this._changedId); - this._disable(); - trayIconsManager = null; - } -} diff --git a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/util.js b/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/util.js deleted file mode 100644 index 7ec25b5..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/appindicatorsupport@rgcjonas.gmail.com/util.js +++ /dev/null @@ -1,271 +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 Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import St from 'gi://St'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Config from 'resource:///org/gnome/shell/misc/config.js'; -import * as Signals from 'resource:///org/gnome/shell/misc/signals.js'; - -import {Logger} from './logger.js'; -import {BaseStatusIcon} from './indicatorStatusIcon.js'; -import {BUS_ADDRESS_REGEX} from './dbusUtils.js'; - -Gio._promisify(Gio._LocalFilePrototype, 'read'); -Gio._promisify(Gio.InputStream.prototype, 'read_bytes_async'); - -export function indicatorId(service, busName, objectPath) { - if (service !== busName && service?.match(BUS_ADDRESS_REGEX)) - return service; - - return `${busName}@${objectPath}`; -} - - -export class NameWatcher extends Signals.EventEmitter { - constructor(name) { - super(); - - this._watcherId = Gio.DBus.session.watch_name(name, - Gio.BusNameWatcherFlags.NONE, () => { - this._nameOnBus = true; - Logger.debug(`Name ${name} appeared`); - this.emit('changed'); - this.emit('appeared'); - }, () => { - this._nameOnBus = false; - Logger.debug(`Name ${name} vanished`); - this.emit('changed'); - this.emit('vanished'); - }); - } - - destroy() { - this.emit('destroy'); - - Gio.DBus.session.unwatch_name(this._watcherId); - delete this._watcherId; - } - - get nameOnBus() { - return !!this._nameOnBus; - } -} - -function connectSmart3A(src, signal, handler) { - const id = src.connect(signal, handler); - let destroyId = 0; - - if (src.connect && (!(src instanceof GObject.Object) || GObject.signal_lookup('destroy', src))) { - destroyId = src.connect('destroy', () => { - src.disconnect(id); - src.disconnect(destroyId); - }); - } - - return [id, destroyId]; -} - -function connectSmart4A(src, signal, target, method) { - if (typeof method !== 'function') - throw new TypeError('Unsupported function'); - - method = method.bind(target); - const signalId = src.connect(signal, method); - const onDestroy = () => { - src.disconnect(signalId); - if (srcDestroyId) - src.disconnect(srcDestroyId); - if (tgtDestroyId) - target.disconnect(tgtDestroyId); - }; - - // GObject classes might or might not have a destroy signal - // JS Classes will not complain when connecting to non-existent signals - const srcDestroyId = src.connect && (!(src instanceof GObject.Object) || - GObject.signal_lookup('destroy', src)) ? src.connect('destroy', onDestroy) : 0; - const tgtDestroyId = target.connect && (!(target instanceof GObject.Object) || - GObject.signal_lookup('destroy', target)) ? target.connect('destroy', onDestroy) : 0; - - return [signalId, srcDestroyId, tgtDestroyId]; -} - -// eslint-disable-next-line valid-jsdoc -/** - * Connect signals to slots, and remove the connection when either source or - * target are destroyed - * - * Usage: - * Util.connectSmart(srcOb, 'signal', tgtObj, 'handler') - * or - * Util.connectSmart(srcOb, 'signal', () => { ... }) - */ -export function connectSmart(...args) { - if (arguments.length === 4) - return connectSmart4A(...args); - else - return connectSmart3A(...args); -} - -function disconnectSmart3A(src, signalIds) { - const [id, destroyId] = signalIds; - src.disconnect(id); - - if (destroyId) - src.disconnect(destroyId); -} - -function disconnectSmart4A(src, tgt, signalIds) { - const [signalId, srcDestroyId, tgtDestroyId] = signalIds; - - disconnectSmart3A(src, [signalId, srcDestroyId]); - - if (tgtDestroyId) - tgt.disconnect(tgtDestroyId); -} - -export function disconnectSmart(...args) { - if (arguments.length === 2) - return disconnectSmart3A(...args); - else if (arguments.length === 3) - return disconnectSmart4A(...args); - - throw new TypeError('Unexpected number of arguments'); -} - -let _defaultTheme; -export function getDefaultTheme() { - if (_defaultTheme) - return _defaultTheme; - - _defaultTheme = new St.IconTheme(); - return _defaultTheme; -} - -export function destroyDefaultTheme() { - _defaultTheme = null; -} - -// eslint-disable-next-line valid-jsdoc -/** - * Helper function to wait for the system startup to be completed. - * Adding widgets before the desktop is ready to accept them can result in errors. - */ -export async function waitForStartupCompletion(cancellable) { - if (Main.layoutManager._startingUp) - await Main.layoutManager.connect_once('startup-complete', cancellable); -} - -export {Logger}; - -export function versionCheck(required) { - const current = Config.PACKAGE_VERSION; - const currentArray = current.split('.'); - const [major] = currentArray; - return major >= required; -} - -export function tryCleanupOldIndicators() { - const indicatorType = BaseStatusIcon; - const indicators = Object.values(Main.panel.statusArea).filter(i => i instanceof indicatorType); - - try { - const panelBoxes = [ - Main.panel._leftBox, Main.panel._centerBox, Main.panel._rightBox, - ]; - - panelBoxes.forEach(box => - indicators.push(...box.get_children().filter(i => i instanceof indicatorType))); - } catch (e) { - logError(e); - } - - new Set(indicators).forEach(i => i.destroy()); -} - -export function addActor(obj, actor) { - if (obj.add_actor) - obj.add_actor(actor); - else - obj.add_child(actor); -} - -export function removeActor(obj, actor) { - if (obj.remove_actor) - obj.remove_actor(actor); - else - obj.remove_child(actor); -} - -export const CancellableChild = GObject.registerClass({ - Properties: { - 'parent': GObject.ParamSpec.object( - 'parent', 'parent', 'parent', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, - Gio.Cancellable.$gtype), - }, -}, -class CancellableChild extends Gio.Cancellable { - _init(parent) { - if (parent && !(parent instanceof Gio.Cancellable)) - throw TypeError('Not a valid cancellable'); - - super._init({parent}); - - if (parent) { - if (parent.is_cancelled()) { - this.cancel(); - return; - } - - this._connectToParent(); - } - } - - _connectToParent() { - this._connectId = this.parent.connect(() => { - this._realCancel(); - - if (this._disconnectIdle) - return; - - this._disconnectIdle = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - delete this._disconnectIdle; - this._disconnectFromParent(); - return GLib.SOURCE_REMOVE; - }); - }); - } - - _disconnectFromParent() { - if (this._connectId && !this._disconnectIdle) { - this.parent.disconnect(this._connectId); - delete this._connectId; - } - } - - _realCancel() { - Gio.Cancellable.prototype.cancel.call(this); - } - - cancel() { - this._disconnectFromParent(); - this._realCancel(); - } -}); |