status/volume: Port to quick settings

Thanks to the preparations and QuickSlider, this is again
straight-forward.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2393>
This commit is contained in:
Florian Müllner 2022-07-30 01:37:07 +02:00 committed by Marge Bot
parent 7bbd59838a
commit 62c62eced0
2 changed files with 49 additions and 91 deletions

View File

@ -378,15 +378,11 @@ class AggregateMenu extends PanelMenu.Button {
else else
this._network = null; this._network = null;
this._volume = new imports.ui.status.volume.Indicator();
this._system = new imports.ui.status.system.Indicator(); this._system = new imports.ui.status.system.Indicator();
if (this._network) if (this._network)
this._indicators.add_child(this._network); this._indicators.add_child(this._network);
this._indicators.add_child(this._volume);
this.menu.addMenuItem(this._volume.menu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
if (this._network) if (this._network)
this.menu.addMenuItem(this._network.menu); this.menu.addMenuItem(this._network.menu);
@ -414,6 +410,7 @@ class QuickSettings extends PanelMenu.Button {
else else
this._bluetooth = null; this._bluetooth = null;
this._volume = new imports.ui.status.volume.Indicator();
this._brightness = new imports.ui.status.brightness.Indicator(); this._brightness = new imports.ui.status.brightness.Indicator();
this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet(); this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet();
this._location = new imports.ui.status.location.Indicator(); this._location = new imports.ui.status.location.Indicator();
@ -437,9 +434,11 @@ class QuickSettings extends PanelMenu.Button {
this._indicators.add_child(this._bluetooth); this._indicators.add_child(this._bluetooth);
this._indicators.add_child(this._rfkill); this._indicators.add_child(this._rfkill);
this._indicators.add_child(this._autoRotate); this._indicators.add_child(this._autoRotate);
this._indicators.add_child(this._volume);
this._indicators.add_child(this._unsafeMode); this._indicators.add_child(this._unsafeMode);
this._indicators.add_child(this._power); this._indicators.add_child(this._power);
this._addItems(this._volume.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS);
this._addItems(this._brightness.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS); this._addItems(this._brightness.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS);
this._addItems(this._remoteAccess.quickSettingsItems); this._addItems(this._remoteAccess.quickSettingsItems);

View File

@ -1,13 +1,12 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Indicator */ /* exported Indicator */
const { Clutter, Gio, GLib, GObject, Gvc, St } = imports.gi; const {Clutter, Gio, GLib, GObject, Gvc} = imports.gi;
const Signals = imports.misc.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const Slider = imports.ui.slider;
const {QuickSlider, SystemIndicator} = imports.ui.quickSettings;
const ALLOW_AMPLIFIED_VOLUME_KEY = 'allow-volume-above-100-percent'; const ALLOW_AMPLIFIED_VOLUME_KEY = 'allow-volume-above-100-percent';
@ -27,30 +26,19 @@ function getMixerControl() {
return _mixerControl; return _mixerControl;
} }
var StreamSlider = class extends Signals.EventEmitter { const StreamSlider = GObject.registerClass({
constructor(control) { Signals: {
super(); 'stream-updated': {},
},
}, class StreamSlider extends QuickSlider {
_init(control) {
super._init();
this._control = control; this._control = control;
this.item = new PopupMenu.PopupMenuSection();
const sliderItem = new PopupMenu.PopupBaseMenuItem({activate: false});
this.item.addMenuItem(sliderItem);
const submenuItem = new PopupMenu.PopupSubMenuMenuItem('');
this.item.addMenuItem(submenuItem);
// HACK: Hide the submenu item, its menu is controlled from sliderItem
submenuItem.hide();
this.menu = submenuItem.menu;
this._inDrag = false; this._inDrag = false;
this._notifyVolumeChangeId = 0; this._notifyVolumeChangeId = 0;
this._slider = new Slider.Slider(0);
this._soundSettings = new Gio.Settings({ this._soundSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.sound', schema_id: 'org.gnome.desktop.sound',
}); });
@ -58,48 +46,20 @@ var StreamSlider = class extends Signals.EventEmitter {
() => this._amplifySettingsChanged()); () => this._amplifySettingsChanged());
this._amplifySettingsChanged(); this._amplifySettingsChanged();
this._sliderChangedId = this._slider.connect('notify::value', this._sliderChangedId = this.slider.connect('notify::value',
() => this._sliderChanged()); () => this._sliderChanged());
this._slider.connect('drag-begin', () => (this._inDrag = true)); this.slider.connect('drag-begin', () => (this._inDrag = true));
this._slider.connect('drag-end', () => { this.slider.connect('drag-end', () => {
this._inDrag = false; this._inDrag = false;
this._notifyVolumeChange(); this._notifyVolumeChange();
}); });
this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
sliderItem.add(this._icon);
sliderItem.add_child(this._slider);
sliderItem.connect('button-press-event',
(actor, event) => this._slider.startDragging(event));
sliderItem.connect('key-press-event',
(actor, event) => this._slider.emit('key-press-event', event));
sliderItem.connect('scroll-event',
(actor, event) => this._slider.emit('scroll-event', event));
this._menuButton = new St.Button({
child: new St.Icon({
iconName: 'pan-end-symbolic',
style_class: 'popup-menu-arrow',
}),
y_expand: true,
});
sliderItem.add_child(this._menuButton);
this._menuButton.connect('clicked', () => this.menu.toggle());
// In order to keep sliders aligned, do not hide
// the menu button, but make it fully transparent
this._menuButton.bind_property_full('reactive',
this._menuButton, 'opacity',
GObject.BindingFlags.DEFAULT,
(bind, source) => [true, source ? 255 : 0],
null);
this._deviceItems = new Map(); this._deviceItems = new Map();
this._deviceSection = new PopupMenu.PopupMenuSection(); this._deviceSection = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(this._deviceSection); this.menu.addMenuItem(this._deviceSection);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_('Sound Settings'), this.menu.addSettingsAction(_('Sound Settings'),
'gnome-sound-panel.desktop'); 'gnome-sound-panel.desktop');
@ -182,19 +142,15 @@ var StreamSlider = class extends Signals.EventEmitter {
} }
_sync() { _sync() {
this.item.actor.visible = this._shouldBeVisible(); this.visible = this._shouldBeVisible();
this._menuButton.reactive = this._deviceItems.size > 1; this.menuEnabled = this._deviceItems.size > 1;
}
scroll(event) {
return this._slider.scroll(event);
} }
_sliderChanged() { _sliderChanged() {
if (!this._stream) if (!this._stream)
return; return;
let value = this._slider.value; let value = this.slider.value;
let volume = value * this._control.get_vol_max_norm(); let volume = value * this._control.get_vol_max_norm();
let prevMuted = this._stream.is_muted; let prevMuted = this._stream.is_muted;
let prevVolume = this._stream.volume; let prevVolume = this._stream.volume;
@ -236,9 +192,9 @@ var StreamSlider = class extends Signals.EventEmitter {
} }
_changeSlider(value) { _changeSlider(value) {
this._slider.block_signal_handler(this._sliderChangedId); this.slider.block_signal_handler(this._sliderChangedId);
this._slider.value = value; this.slider.value = value;
this._slider.unblock_signal_handler(this._sliderChangedId); this.slider.unblock_signal_handler(this._sliderChangedId);
} }
_updateVolume() { _updateVolume() {
@ -251,7 +207,7 @@ var StreamSlider = class extends Signals.EventEmitter {
_amplifySettingsChanged() { _amplifySettingsChanged() {
this._allowAmplified = this._soundSettings.get_boolean(ALLOW_AMPLIFIED_VOLUME_KEY); this._allowAmplified = this._soundSettings.get_boolean(ALLOW_AMPLIFIED_VOLUME_KEY);
this._slider.maximum_value = this._allowAmplified this.slider.maximum_value = this._allowAmplified
? this.getMaxLevel() : 1; ? this.getMaxLevel() : 1;
if (this._stream) if (this._stream)
@ -287,13 +243,14 @@ var StreamSlider = class extends Signals.EventEmitter {
return maxVolume / this._control.get_vol_max_norm(); return maxVolume / this._control.get_vol_max_norm();
} }
}; });
var OutputStreamSlider = class extends StreamSlider { const OutputStreamSlider = GObject.registerClass(
constructor(control) { class OutputStreamSlider extends StreamSlider {
super(control); _init(control) {
super._init(control);
this._slider.accessible_name = _('Volume'); this.slider.accessible_name = _('Volume');
this._control.connectObject( this._control.connectObject(
'output-added', (c, id) => this._addDevice(id), 'output-added', (c, id) => this._addDevice(id),
@ -308,6 +265,8 @@ var OutputStreamSlider = class extends StreamSlider {
'audio-volume-high-symbolic', 'audio-volume-high-symbolic',
'audio-volume-overamplified-symbolic', 'audio-volume-overamplified-symbolic',
]; ];
this.menu.setHeader('audio-headphones-symbolic', _('Sound Output'));
} }
_connectStream(stream) { _connectStream(stream) {
@ -346,17 +305,18 @@ var OutputStreamSlider = class extends StreamSlider {
return; return;
this._hasHeadphones = hasHeadphones; this._hasHeadphones = hasHeadphones;
this._icon.icon_name = this._hasHeadphones this.iconName = this._hasHeadphones
? 'audio-headphones-symbolic' ? 'audio-headphones-symbolic'
: 'audio-speakers-symbolic'; : 'audio-speakers-symbolic';
} }
}; });
var InputStreamSlider = class extends StreamSlider { const InputStreamSlider = GObject.registerClass(
constructor(control) { class InputStreamSlider extends StreamSlider {
super(control); _init(control) {
super._init(control);
this._slider.accessible_name = _('Microphone'); this.slider.accessible_name = _('Microphone');
this._control.connectObject( this._control.connectObject(
'input-added', (c, id) => this._addDevice(id), 'input-added', (c, id) => this._addDevice(id),
@ -366,13 +326,15 @@ var InputStreamSlider = class extends StreamSlider {
'stream-removed', () => this._maybeShowInput(), 'stream-removed', () => this._maybeShowInput(),
this); this);
this._icon.icon_name = 'audio-input-microphone-symbolic'; this.iconName = 'audio-input-microphone-symbolic';
this._icons = [ this._icons = [
'microphone-sensitivity-muted-symbolic', 'microphone-sensitivity-muted-symbolic',
'microphone-sensitivity-low-symbolic', 'microphone-sensitivity-low-symbolic',
'microphone-sensitivity-medium-symbolic', 'microphone-sensitivity-medium-symbolic',
'microphone-sensitivity-high-symbolic', 'microphone-sensitivity-high-symbolic',
]; ];
this.menu.setHeader('audio-input-microphone-symbolic', _('Sound Input'));
} }
_connectStream(stream) { _connectStream(stream) {
@ -410,10 +372,10 @@ var InputStreamSlider = class extends StreamSlider {
_shouldBeVisible() { _shouldBeVisible() {
return super._shouldBeVisible() && this._showInput; return super._shouldBeVisible() && this._showInput;
} }
}; });
var Indicator = GObject.registerClass( var Indicator = GObject.registerClass(
class Indicator extends PanelMenu.SystemIndicator { class Indicator extends SystemIndicator {
_init() { _init() {
super._init(); super._init();
@ -428,8 +390,6 @@ class Indicator extends PanelMenu.SystemIndicator {
this._inputIndicator.connect('scroll-event', this._inputIndicator.connect('scroll-event',
(actor, event) => this._handleScrollEvent(this._input, event)); (actor, event) => this._handleScrollEvent(this._input, event));
const volumeMenu = new PopupMenu.PopupMenuSection();
this._control = getMixerControl(); this._control = getMixerControl();
this._control.connectObject( this._control.connectObject(
'state-changed', () => this._onControlStateChanged(), 'state-changed', () => this._onControlStateChanged(),
@ -445,7 +405,6 @@ class Indicator extends PanelMenu.SystemIndicator {
this._primaryIndicator.icon_name = icon; this._primaryIndicator.icon_name = icon;
this._primaryIndicator.visible = icon !== null; this._primaryIndicator.visible = icon !== null;
}); });
volumeMenu.addMenuItem(this._output.item);
this._input = new InputStreamSlider(this._control); this._input = new InputStreamSlider(this._control);
this._input.connect('stream-updated', () => { this._input.connect('stream-updated', () => {
@ -454,13 +413,13 @@ class Indicator extends PanelMenu.SystemIndicator {
if (icon) if (icon)
this._inputIndicator.icon_name = icon; this._inputIndicator.icon_name = icon;
}); });
volumeMenu.addMenuItem(this._input.item);
this._input.item.actor.bind_property('visible', this._input.bind_property('visible',
this._inputIndicator, 'visible', this._inputIndicator, 'visible',
GObject.BindingFlags.SYNC_CREATE); GObject.BindingFlags.SYNC_CREATE);
this.menu.addMenuItem(volumeMenu); this.quickSettingsItems.push(this._output);
this.quickSettingsItems.push(this._input);
this._onControlStateChanged(); this._onControlStateChanged();
} }
@ -483,8 +442,8 @@ class Indicator extends PanelMenu.SystemIndicator {
} }
_handleScrollEvent(item, event) { _handleScrollEvent(item, event) {
const result = item.scroll(event); const result = item.slider.scroll(event);
if (result === Clutter.EVENT_PROPAGATE || this.menu.actor.mapped) if (result === Clutter.EVENT_PROPAGATE || item.mapped)
return result; return result;
const gicon = new Gio.ThemedIcon({name: item.getIcon()}); const gicon = new Gio.ThemedIcon({name: item.getIcon()});