Migrating to gnome 45 - import errors (original) (raw)
February 13, 2024, 10:03am 1
SyntaxError: ambiguous indirect export: GObject @ file:///home/bernhard/.local/share/gnome-shell/extensions/audio-switcher@ahoi.io/extension.js:1:9
import { GObject } from 'gi://GObject';
import { PopupMenu } from 'resource:///org/gnome/shell/ui/popupMenu.js';
import { Extension as GExtension } from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const AudioOutputSubMenu = GObject.registerClass({
GTypeName: 'ASAudioOutputSubMenu',
}, class AudioOutputSubMenu extends PopupMenu.PopupSubMenuMenuItem {
_init() {
super._init('Audio Output: Connecting...', true);
this._control = Main.panel.statusArea.aggregateMenu._volume._control;
this._controlSignal = this._control.connect('default-sink-changed', () => {
this._updateDefaultSink();
});
this._updateDefaultSink();
this.menu.connect('open-state-changed', (menu, isOpen) => {
if (isOpen)
this._updateSinkList();
});
//Unless there is at least one item here, no 'open' will be emitted...
let item = new PopupMenu.PopupMenuItem('Connecting...');
this.menu.addMenuItem(item);
}
_updateDefaultSink() {
let defsink = this._control.get_default_sink();
//Unfortunately, Gvc neglects some pulse-devices, such as all "Monitor of ..."
if (defsink == null)
this.label.set_text("Other");
else
this.label.set_text(defsink.get_description());
}
_updateSinkList() {
this.menu.removeAll();
let defsink = this._control.get_default_sink();
let sinklist = this._control.get_sinks();
let control = this._control;
let item;
for (let i=0; i<sinklist.length; i++) {
let sink = sinklist[i];
if (sink === defsink)
continue;
item = new PopupMenu.PopupMenuItem(sink.get_description());
item.connect('activate', () => {
control.set_default_sink(sink);
});
this.menu.addMenuItem(item);
}
if (sinklist.length == 0 ||
(sinklist.length == 1 && sinklist[0] === defsink)) {
item = new PopupMenu.PopupMenuItem("No more Devices");
this.menu.addMenuItem(item);
}
}
destroy() {
this._control.disconnect(this._controlSignal);
super.destroy();
}
});
const AudioInputSubMenu = GObject.registerClass({
GTypeName: 'ASAudioInputSubMenu',
}, class AudioInputSubMenu extends PopupMenu.PopupSubMenuMenuItem {
_init() {
super._init('Audio Input: Connecting...', true);
this._control = Main.panel.statusArea.aggregateMenu._volume._control;
this._controlSignal = this._control.connect('default-source-changed', () => {
this._updateDefaultSource();
});
this._updateDefaultSource();
this.menu.connect('open-state-changed', (menu, isOpen) => {
if (isOpen)
this._updateSourceList();
});
//Unless there is at least one item here, no 'open' will be emitted...
let item = new PopupMenu.PopupMenuItem('Connecting...');
this.menu.addMenuItem(item);
}
_updateDefaultSource() {
let defsource = this._control.get_default_source();
//Unfortunately, Gvc neglects some pulse-devices, such as all "Monitor of ..."
if (defsource == null)
this.label.set_text("Other");
else
this.label.set_text(defsource.get_description());
}
_updateSourceList() {
this.menu.removeAll();
let defsource = this._control.get_default_source();
let sourcelist = this._control.get_sources();
let control = this._control;
let item;
for (var i = 0; i < sourcelist.length; i++) {
let source = sourcelist[i];
if (source === defsource) {
continue;
}
item = new PopupMenu.PopupMenuItem(source.get_description());
item.connect('activate', () => {
control.set_default_source(source);
});
this.menu.addMenuItem(item);
}
if (sourcelist.length == 0 ||
(sourcelist.length == 1 && sourcelist[0] === defsource)) {
item = new PopupMenu.PopupMenuItem("No more Devices");
this.menu.addMenuItem(item);
}
}
destroy() {
this._control.disconnect(this._controlSignal);
super.destroy();
}
});
export default class AudioSwitcherExtension extends GExtension {
constructor(metadata) {
super(metadata)
this.audioOutputSubMenu = null;
this.audioInputSubMenu = null;
this.savedUpdateVisibility = null;
}
enable() {
if ((audioInputSubMenu != null) || (audioOutputSubMenu != null))
return;
this.audioInputSubMenu = new AudioInputSubMenu();
this.audioOutputSubMenu = new AudioOutputSubMenu();
//Try to add the switchers right below the sliders...
let volMen = Main.panel.statusArea.aggregateMenu._volume._volumeMenu;
let items = volMen._getMenuItems();
let i = 0;
let addedInput, addedOutput = false;
while (i < items.length){
if (items[i] === volMen._output.item){
volMen.addMenuItem(audioOutputSubMenu, i+1);
addedOutput = true;
} else if (items[i] === volMen._input.item){
volMen.addMenuItem(audioInputSubMenu, i+2);
addedInput = true;
}
if (addedOutput && addedInput){
break;
}
i++;
}
//Make input-slider allways visible.
this.savedUpdateVisibility = Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility = function () {};
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input.item.actor.visible = true;
}
disable() {
this.audioInputSubMenu.destroy();
this.audioInputSubMenu = null;
this.audioOutputSubMenu.destroy();
this.audioOutputSubMenu = null;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility = savedUpdateVisibility;
this.savedUpdateVisibility = null;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility();
}
}
The full plugin can be found GitHub - drahnr/audio-switcher: Easily switch between your audio inputs/outputs from the system menu in GNOME 42
Note that i.e. caffeine
does the same GObject
import and works.
Port Extensions to GNOME Shell 45 | GNOME JavaScript doesn’t help much.
I’d appreciate any help!
jrahmatzadeh (Javad Rahmatzadeh) February 13, 2024, 10:23am 2
You need to drop those {}
in line 1 and 2:
import GObject from 'gi://GObject';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
drahnr February 15, 2024, 2:39pm 3
Hey, yes, that got me one step further.
Note that Anatomy of an Extension | GNOME JavaScript appears to suggest to do what I had initially, so if you could sheld some light on why it doesn’t work, that’d be much appreciated.
The next error message is
TypeError: Extension is not a constructor
get from
import GObject from 'gi://GObject';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
import * as Extension from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const AudioOutputSubMenu = GObject.registerClass({
GTypeName: 'ASAudioOutputSubMenu',
}, class AudioOutputSubMenu extends PopupMenu.PopupSubMenuMenuItem {
_init() {
super._init('Audio Output: Connecting...', true);
this._control = Main.panel.statusArea.aggregateMenu._volume._control;
this._controlSignal = this._control.connect('default-sink-changed', () => {
this._updateDefaultSink();
});
this._updateDefaultSink();
this.menu.connect('open-state-changed', (menu, isOpen) => {
if (isOpen)
this._updateSinkList();
});
//Unless there is at least one item here, no 'open' will be emitted...
let item = new PopupMenu.PopupMenuItem('Connecting...');
this.menu.addMenuItem(item);
}
_updateDefaultSink() {
let defsink = this._control.get_default_sink();
//Unfortunately, Gvc neglects some pulse-devices, such as all "Monitor of ..."
if (defsink == null)
this.label.set_text("Other");
else
this.label.set_text(defsink.get_description());
}
_updateSinkList() {
this.menu.removeAll();
let defsink = this._control.get_default_sink();
let sinklist = this._control.get_sinks();
let control = this._control;
let item;
for (let i=0; i<sinklist.length; i++) {
let sink = sinklist[i];
if (sink === defsink)
continue;
item = new PopupMenu.PopupMenuItem(sink.get_description());
item.connect('activate', () => {
control.set_default_sink(sink);
});
this.menu.addMenuItem(item);
}
if (sinklist.length == 0 ||
(sinklist.length == 1 && sinklist[0] === defsink)) {
item = new PopupMenu.PopupMenuItem("No more Devices");
this.menu.addMenuItem(item);
}
}
destroy() {
this._control.disconnect(this._controlSignal);
super.destroy();
}
});
const AudioInputSubMenu = GObject.registerClass({
GTypeName: 'ASAudioInputSubMenu',
}, class AudioInputSubMenu extends PopupMenu.PopupSubMenuMenuItem {
_init() {
super._init('Audio Input: Connecting...', true);
this._control = Main.panel.statusArea.aggregateMenu._volume._control;
this._controlSignal = this._control.connect('default-source-changed', () => {
this._updateDefaultSource();
});
this._updateDefaultSource();
this.menu.connect('open-state-changed', (menu, isOpen) => {
if (isOpen)
this._updateSourceList();
});
//Unless there is at least one item here, no 'open' will be emitted...
let item = new PopupMenu.PopupMenuItem('Connecting...');
this.menu.addMenuItem(item);
}
_updateDefaultSource() {
let defsource = this._control.get_default_source();
//Unfortunately, Gvc neglects some pulse-devices, such as all "Monitor of ..."
if (defsource == null)
this.label.set_text("Other");
else
this.label.set_text(defsource.get_description());
}
_updateSourceList() {
this.menu.removeAll();
let defsource = this._control.get_default_source();
let sourcelist = this._control.get_sources();
let control = this._control;
let item;
for (var i = 0; i < sourcelist.length; i++) {
let source = sourcelist[i];
if (source === defsource) {
continue;
}
item = new PopupMenu.PopupMenuItem(source.get_description());
item.connect('activate', () => {
control.set_default_source(source);
});
this.menu.addMenuItem(item);
}
if (sourcelist.length == 0 ||
(sourcelist.length == 1 && sourcelist[0] === defsource)) {
item = new PopupMenu.PopupMenuItem("No more Devices");
this.menu.addMenuItem(item);
}
}
destroy() {
this._control.disconnect(this._controlSignal);
super.destroy();
}
});
export default class AudioSwitcherExtension extends Extension {
audioOutputSubMenu = null;
audioInputSubMenu = null;
savedUpdateVisibility = null;
// constructor(metadata) {
// super(metadata)
//
// this.audioOutputSubMenu = null;
// this.audioInputSubMenu = null;
// this.savedUpdateVisibility = null;
// }
enable() {
if ((this.audioInputSubMenu != null) || (this.audioOutputSubMenu != null))
return;
this.audioInputSubMenu = new AudioInputSubMenu();
this.audioOutputSubMenu = new AudioOutputSubMenu();
//Try to add the switchers right below the sliders...
let volMen = Main.panel.statusArea.aggregateMenu._volume._volumeMenu;
let items = volMen._getMenuItems();
let i = 0;
let addedInput, addedOutput = false;
while (i < items.length){
if (items[i] === volMen._output.item){
volMen.addMenuItem(audioOutputSubMenu, i+1);
addedOutput = true;
} else if (items[i] === volMen._input.item){
volMen.addMenuItem(audioInputSubMenu, i+2);
addedInput = true;
}
if (addedOutput && addedInput){
break;
}
i++;
}
//Make input-slider allways visible.
this.savedUpdateVisibility = Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility = function () {};
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input.item.actor.visible = true;
}
disable() {
this.audioInputSubMenu.destroy();
this.audioInputSubMenu = null;
this.audioOutputSubMenu.destroy();
this.audioOutputSubMenu = null;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility = savedUpdateVisibility;
this.savedUpdateVisibility = null;
Main.panel.statusArea.aggregateMenu._volume._volumeMenu._input._updateVisibility();
}
}
regardless if I comment constructor(metdata) {..}
or not. Could you shed some light on that too.
Thank you very much for your time and help!
jrahmatzadeh (Javad Rahmatzadeh) February 15, 2024, 3:58pm 4
As I mentioned before, that change is only related to the line 1 and 2 in your first code.
drahnr February 15, 2024, 4:51pm 5
That doesn’t work, if I only apply your suggested changes to line 1 and 2, I get:
SyntaxError: ambiguous indirect export: default @ file:///home/bernhard/.local/share/gnome-shell/extensions/audio-switcher@ahoi.io/extension.js:3:7
Edith: tried again, now the only thing left to figure is how to replace the removed aggregate member on the panel.
Thanks again!
system (system) Closed March 16, 2024, 4:52pm 6
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.