diff --git a/schemas/net.evermiss.mymindstorm.volume-mixer.gschema.xml b/schemas/net.evermiss.mymindstorm.volume-mixer.gschema.xml
index 7a88ae6..49b8b63 100644
--- a/schemas/net.evermiss.mymindstorm.volume-mixer.gschema.xml
+++ b/schemas/net.evermiss.mymindstorm.volume-mixer.gschema.xml
@@ -10,6 +10,9 @@
true
+
+ false
+
diff --git a/src/applicationStreamSlider.js b/src/applicationStreamSlider.js
index 2e34c29..4e26467 100644
--- a/src/applicationStreamSlider.js
+++ b/src/applicationStreamSlider.js
@@ -6,31 +6,36 @@ const { BoxLayout, Label } = imports.gi.St;
const Volume = imports.ui.status.volume;
export class ApplicationStreamSlider extends Volume.StreamSlider {
- constructor(stream, opts) {
- super(Volume.getMixerControl());
+ constructor(stream, opts) {
+ super(Volume.getMixerControl());
- this.stream = stream;
+ this.stream = stream;
- if (opts.showIcon) {
- this._icon.icon_name = stream.get_icon_name();
- }
+ if (opts.showIcon) {
+ this._icon.icon_name = stream.get_icon_name();
+ }
- let name = stream.get_name();
- let description = stream.get_description();
+ let name = stream.get_name();
+ let description = stream.get_description();
- if (name || description) {
- this._vbox = new BoxLayout()
- this._vbox.vertical = true;
+ if (name || description) {
+ this._vbox = new BoxLayout()
+ this._vbox.vertical = true;
- this._label = new Label();
- this._label.text = name && opts.showDesc ? `${name} - ${description}` : (name || description);
- this._vbox.add(this._label);
+ this._label = new Label();
+ this._label.text = name && opts.showDesc ? `${name} - ${description}` : (name || description);
+ this._vbox.add(this._label);
- this.item.remove_child(this._slider);
- this._vbox.add(this._slider);
- this._slider.set_height(32);
+ this.item.remove_child(this._slider);
+ this._vbox.add(this._slider);
+ this._slider.set_height(32);
- this.item.actor.add(this._vbox);
+ this.item.actor.add(this._vbox);
+ }
+ }
+
+ destroy() {
+ this._disconnectStream(this._stream);
+ this._stream = null;
}
- }
};
diff --git a/src/volumeMixerPopupMenu.js b/src/volumeMixerPopupMenu.js
index 8d0d0b7..0a66bf3 100644
--- a/src/volumeMixerPopupMenu.js
+++ b/src/volumeMixerPopupMenu.js
@@ -15,18 +15,8 @@ const Me = ExtensionUtils.getCurrentExtension();
export class VolumeMixerPopupMenu extends PopupMenu.PopupMenuSection {
constructor() {
super();
- this._applicationStreams = {};
-
- // The PopupSeparatorMenuItem needs something above and below it or it won't display
- this._hiddenItem = new PopupMenu.PopupBaseMenuItem();
- this._hiddenItem.set_height(0)
- this.addMenuItem(this._hiddenItem);
-
- this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
- this._control = Volume.getMixerControl();
- this._streamAddedEventId = this._control.connect("stream-added", this._streamAdded.bind(this));
- this._streamRemovedEventId = this._control.connect("stream-removed", this._streamRemoved.bind(this));
+ this._applicationStreams = {};
let gschema = SettingsSchemaSource.new_from_directory(
Me.dir.get_child('schemas').get_path(),
@@ -38,11 +28,56 @@ export class VolumeMixerPopupMenu extends PopupMenu.PopupMenuSection {
settings_schema: gschema.lookup('net.evermiss.mymindstorm.volume-mixer', true)
});
+ this._block = null;
+ this._blockMenu = null;
+ this._dummyStream = null;
+
+ this._control = Volume.getMixerControl();
+ this._streamAddedEventId = this._control.connect("stream-added", this._streamAdded.bind(this));
+ this._streamRemovedEventId = this._control.connect("stream-removed", this._streamRemoved.bind(this));
+
this._settingsChangedId = this.settings.connect('changed', () => this._updateStreams());
this._updateStreams();
}
+ _addDummyIfNoStreams() {
+ if (this._dummyStream) {
+ return;
+ }
+
+ if (this._getStreamCount() !== 0) {
+ return;
+ }
+
+ this._dummyStream = new PopupMenu.PopupMenuItem("There are currently no audio streams", {
+ activate: false,
+ reactive: false
+ });
+ this._blockMenu.addMenuItem(this._dummyStream);
+ }
+
+ _createMenu() {
+ if (this._old_menu) {
+ this._block = new PopupMenu.PopupMenuSection();
+ this._blockMenu = this._block;
+
+ // The PopupSeparatorMenuItem needs something above and below it or it won't display
+ this._hiddenItem = new PopupMenu.PopupBaseMenuItem();
+ this._hiddenItem.set_height(0)
+ this._block.addMenuItem(this._hiddenItem);
+
+ this._block.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+ } else {
+ this._block = new PopupMenu.PopupSubMenuMenuItem('Volume Mixer', true);
+ this._block.icon.icon_name = 'audio-volume-high-symbolic';
+ this._blockMenu = this._block.menu;
+ }
+
+ this.addMenuItem(this._block);
+ }
+
_streamAdded(control, id) {
if (id in this._applicationStreams) {
return;
@@ -65,36 +100,70 @@ export class VolumeMixerPopupMenu extends PopupMenu.PopupMenuSection {
}
this._applicationStreams[id] = new ApplicationStreamSlider(stream, { showDesc: this._showStreamDesc, showIcon: this._showStreamIcon });
- this.addMenuItem(this._applicationStreams[id].item);
+
+ if (this._dummyStream) {
+ this._dummyStream.destroy();
+ this._dummyStream = null;
+ }
+
+ this._blockMenu.addMenuItem(this._applicationStreams[id].item);
}
_streamRemoved(_control, id) {
if (id in this._applicationStreams) {
this._applicationStreams[id].item.destroy();
delete this._applicationStreams[id];
+
+ if (!this._old_menu) {
+ this._addDummyIfNoStreams();
+ }
}
}
_updateStreams() {
for (const id in this._applicationStreams) {
this._applicationStreams[id].item.destroy();
+ this._applicationStreams[id].destroy();
delete this._applicationStreams[id];
}
+ if (this._block) {
+ this._block.destroy();
+ this._block = null;
+ this._blockMenu = null;
+ }
+
+ this._dummyStream = null;
+
this._filteredApps = this.settings.get_strv("filtered-apps");
this._filterMode = this.settings.get_string("filter-mode");
this._showStreamDesc = this.settings.get_boolean("show-description");
this._showStreamIcon = this.settings.get_boolean("show-icon");
+ this._old_menu = this.settings.get_boolean("old-menu");
+
+ this._createMenu();
for (const stream of this._control.get_streams()) {
this._streamAdded(this._control, stream.get_id())
}
+
+ if (!this._old_menu) {
+ this._addDummyIfNoStreams();
+ }
+ }
+
+ _getStreamCount() {
+ return Object.keys(this._applicationStreams).length;
}
destroy() {
this._control.disconnect(this._streamAddedEventId);
this._control.disconnect(this._streamRemovedEventId);
this.settings.disconnect(this._settingsChangedId);
+ if (this._dummyStream) {
+ this._dummyStream.destroy();
+ }
+ this._block.destroy();
super.destroy();
}
};
diff --git a/src/volumeMixerPrefsPage.js b/src/volumeMixerPrefsPage.js
index ac018d0..ee5f451 100644
--- a/src/volumeMixerPrefsPage.js
+++ b/src/volumeMixerPrefsPage.js
@@ -60,6 +60,30 @@ export const VolumeMixerPrefsPage = GObject.registerClass({
showIconRow.add_suffix(showIconToggle);
showIconRow.activatable_widget = showIconToggle;
+ // old-menu
+ const oldMenuRow = new Adw.ActionRow({
+ title: 'Show In Old Way',
+ subtitle: 'Will show all controlls in menu instead of using Volume Mixer Sub Menu. '
+ + '\x0ABeaware that if there are too many audio sources, this option will '
+ + 'overflow the menu'
+ });
+ generalGroup.add(oldMenuRow);
+
+ const oldMenuToggle = new Gtk.Switch({
+ active: this.settings.get_boolean('old-menu'),
+ valign: Gtk.Align.CENTER
+ });
+
+ this.settings.bind(
+ 'old-menu',
+ oldMenuToggle,
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT
+ );
+
+ oldMenuRow.add_suffix(oldMenuToggle);
+ oldMenuRow.activatable_widget = oldMenuToggle;
+
// Application filter settings group
const filterGroup = new Adw.PreferencesGroup({
title: 'Application Filtering',