/* extension.js * * 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, see . * * SPDX-License-Identifier: GPL-2.0-or-later */ /* exported init */ const GETTEXT_DOMAIN = 'my-indicator-extension'; const { GObject, St } = imports.gi; const GLib = imports.gi.GLib; const ByteArray = imports.byteArray; const ExtensionUtils = imports.misc.extensionUtils; const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; const _ = ExtensionUtils.gettext; allowedRateElements = []; const Indicator = GObject.registerClass( class Indicator extends PanelMenu.Button { _init() { super._init(0.0, _('My Shiny Indicator')); this.add_child(new St.Icon({ icon_name: 'face-smile-symbolic', style_class: 'system-status-icon', })); let sampleRate = getForcedSampleRate(); let allowedRates = getAllowedSampleRates(); allowedRateElements = []; for (let i = 0; i < allowedRates.length; i++) { let allowedRate = new PopupMenu.PopupMenuItem(_("Sample Rate: " + allowedRates[i])); if (allowedRates[i] == sampleRate) { allowedRate.setOrnament(PopupMenu.Ornament.DOT); } allowedRate.connect('activate', () => { console.log("set sample rate " + allowedRates[i]); for (let k = 0; k < allowedRateElements.length; k++) { allowedRateElements[k].setOrnament(PopupMenu.Ornament.NONE); } setSampleRate(allowedRates[i]); // sanity check sample rate let forcedRate = getForcedSampleRate(); if (forcedRate == allowedRates[i]) { allowedRate.setOrnament(PopupMenu.Ornament.DOT); } }); this.menu.addMenuItem(allowedRate); allowedRateElements.push(allowedRate); } } }); class Extension { constructor(uuid) { this._uuid = uuid; ExtensionUtils.initTranslations(GETTEXT_DOMAIN); } enable() { this._indicator = new Indicator(); Main.panel.addToStatusArea(this._uuid, this._indicator); } disable() { this._indicator.destroy(); this._indicator = null; } } function init(meta) { return new Extension(meta.uuid); } function setSampleRate(sampleRate) { spawnCommandLine("pw-metadata -n settings 0 clock.force-rate " + sampleRate); spawnCommandLine("pw-metadata -n settings 0 clock.rate " + sampleRate); } function getForcedSampleRate() { let res = spawnCommandLine("pw-metadata -n settings"); let lines = res.split(/\r?\n/); for (let i = 0; i < lines.length; i++) { if (lines[i].includes('clock.force-rate')) { console.log("found current force rate setting"); let phrases = lines[i].split(" "); for (let j = 0; j < phrases.length; j++) { if (phrases[j].includes("value")) { let value = phrases[j].slice(7, -1); console.log("with current value " + value); if (value) { return value; } } } } } return getCurrentSampleRate(lines); } function getCurrentSampleRate(lines) { for (let i = 0; i < lines.length; i++) { if (lines[i].includes('clock.rate')) { let phrases = lines[i].split(" "); for (let j = 0; j < phrases.length; j++) { if (phrases[j].includes("value")) { return phrases[j].slice(7, -1); } } } } return "not found"; } function getAllowedSampleRates() { let res = spawnCommandLine("pw-metadata -n settings"); let lines = res.split(/\r?\n/); for (let i = 0; i < lines.length; i++) { if (lines[i].includes('clock.allowed-rates')) { let valueIndex = lines[i].indexOf("value"); if (valueIndex !== -1) { return lines[i].slice(valueIndex + 9, -11).replaceAll(",", "").split(" "); } } } return "not found"; } // Runs @command_line in the background, handling any errors that // occur when trying to parse or start the program. function spawnCommandLine(command_line) { try { let [, stdout, stderr, status] = GLib.spawn_command_line_sync(command_line); if (status !== 0) { if (stderr instanceof Uint8Array) stderr = ByteArray.toString(stderr); throw new Error(stderr); } if (stdout instanceof Uint8Array) stdout = ByteArray.toString(stdout); // Now were done blocking the main loop, phewf! return stdout; } catch (e) { throw new Error(e); } }