Add a new lock screen menu to combine volume network and power
The design has a combined volume-network-power indicator in the lock screen, which when opened shows a volume slider. Implement it by abstracting the volume menu into a PopupMenuSection, and by creating three StIcons bound to the real ones. https://bugzilla.gnome.org/show_bug.cgi?id=682540
This commit is contained in:
parent
41dc9e0894
commit
c1de2788b1
@ -85,6 +85,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/shellDBus.js \
|
ui/shellDBus.js \
|
||||||
ui/status/accessibility.js \
|
ui/status/accessibility.js \
|
||||||
ui/status/keyboard.js \
|
ui/status/keyboard.js \
|
||||||
|
ui/status/lockScreenMenu.js \
|
||||||
ui/status/network.js \
|
ui/status/network.js \
|
||||||
ui/status/power.js \
|
ui/status/power.js \
|
||||||
ui/status/volume.js \
|
ui/status/volume.js \
|
||||||
|
@ -908,7 +908,7 @@ const Panel = new Lang.Class({
|
|||||||
reactive: true });
|
reactive: true });
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this._statusArea = {};
|
this.statusArea = {};
|
||||||
|
|
||||||
Main.overview.connect('shown', Lang.bind(this, function () {
|
Main.overview.connect('shown', Lang.bind(this, function () {
|
||||||
this.actor.add_style_class_name('in-overview');
|
this.actor.add_style_class_name('in-overview');
|
||||||
@ -1126,7 +1126,7 @@ const Panel = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addToStatusArea: function(role, indicator, position) {
|
addToStatusArea: function(role, indicator, position) {
|
||||||
if (this._statusArea[role])
|
if (this.statusArea[role])
|
||||||
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
||||||
|
|
||||||
if (!(indicator instanceof PanelMenu.Button))
|
if (!(indicator instanceof PanelMenu.Button))
|
||||||
@ -1138,9 +1138,9 @@ const Panel = new Lang.Class({
|
|||||||
if (indicator.menu)
|
if (indicator.menu)
|
||||||
this._menus.addMenu(indicator.menu);
|
this._menus.addMenu(indicator.menu);
|
||||||
|
|
||||||
this._statusArea[role] = indicator;
|
this.statusArea[role] = indicator;
|
||||||
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
||||||
delete this._statusArea[role];
|
delete this.statusArea[role];
|
||||||
emitter.disconnect(destroyId);
|
emitter.disconnect(destroyId);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1155,7 +1155,7 @@ const Panel = new Lang.Class({
|
|||||||
if (this._dateMenu)
|
if (this._dateMenu)
|
||||||
this._dateMenu.setLockedState(locked);
|
this._dateMenu.setLockedState(locked);
|
||||||
|
|
||||||
for (let id in this._statusArea)
|
for (let id in this.statusArea)
|
||||||
this._statusArea[id].setLockedState(locked);
|
this.statusArea[id].setLockedState(locked);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -236,6 +236,7 @@ const SystemStatusButton = new Lang.Class({
|
|||||||
this._box = new St.BoxLayout({ style_class: 'panel-status-button-box' });
|
this._box = new St.BoxLayout({ style_class: 'panel-status-button-box' });
|
||||||
this.actor.add_actor(this._box);
|
this.actor.add_actor(this._box);
|
||||||
|
|
||||||
|
if (iconName)
|
||||||
this.setIcon(iconName);
|
this.setIcon(iconName);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
|||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
'battery': imports.ui.status.power.Indicator,
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||||
'userMenu': imports.ui.userMenu.UserMenuButton
|
'userMenu': imports.ui.userMenu.UserMenuButton
|
||||||
};
|
};
|
||||||
@ -44,12 +45,13 @@ const _modes = {
|
|||||||
statusArea: {
|
statusArea: {
|
||||||
order: [
|
order: [
|
||||||
'a11y', 'display', 'keyboard',
|
'a11y', 'display', 'keyboard',
|
||||||
'volume', 'battery', 'powerMenu'
|
'volume', 'battery', 'lockScreen', 'powerMenu'
|
||||||
],
|
],
|
||||||
implementation: {
|
implementation: {
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
'battery': imports.ui.status.power.Indicator,
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||||
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
||||||
}
|
}
|
||||||
@ -68,12 +70,13 @@ const _modes = {
|
|||||||
extraStylesheet: null,
|
extraStylesheet: null,
|
||||||
statusArea: {
|
statusArea: {
|
||||||
order: [
|
order: [
|
||||||
'a11y', 'keyboard', 'volume'
|
'a11y', 'keyboard', 'volume', 'lockScreen',
|
||||||
],
|
],
|
||||||
implementation: {
|
implementation: {
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
||||||
'volume': imports.ui.status.volume.Indicator
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
|
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -92,7 +95,7 @@ const _modes = {
|
|||||||
statusArea: {
|
statusArea: {
|
||||||
order: [
|
order: [
|
||||||
'input-method', 'a11y', 'keyboard', 'volume', 'bluetooth',
|
'input-method', 'a11y', 'keyboard', 'volume', 'bluetooth',
|
||||||
'network', 'battery', 'userMenu'
|
'network', 'battery', 'lockScreen', 'userMenu'
|
||||||
],
|
],
|
||||||
implementation: STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION
|
implementation: STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION
|
||||||
}
|
}
|
||||||
|
62
js/ui/status/lockScreenMenu.js
Normal file
62
js/ui/status/lockScreenMenu.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
const VolumeMenu = imports.ui.status.volume;
|
||||||
|
|
||||||
|
const Indicator = new Lang.Class({
|
||||||
|
Name: 'LockScreenMenuIndicator',
|
||||||
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent(null, _("Volume, network, battery"));
|
||||||
|
this.actor.hide();
|
||||||
|
|
||||||
|
this._volume = Main.panel.statusArea.volume;
|
||||||
|
if (this._volume) {
|
||||||
|
this._volumeIcon = this.addIcon(null);
|
||||||
|
this._volume.mainIcon.bind_property('gicon', this._volumeIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._volume.mainIcon.bind_property('visible', this._volumeIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
this._volumeControl = VolumeMenu.getMixerControl();
|
||||||
|
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
|
||||||
|
this.menu.addMenuItem(this._volumeMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._network = Main.panel.statusArea.network;
|
||||||
|
if (this._network) {
|
||||||
|
this._networkIcon = this.addIcon(null);
|
||||||
|
this._network.mainIcon.bind_property('gicon', this._networkIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._network.mainIcon.bind_property('visible', this._networkIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
this._networkSecondaryIcon = this.addIcon(null);
|
||||||
|
this._network.secondaryIcon.bind_property('gicon', this._networkSecondaryIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._network.secondaryIcon.bind_property('visible', this._networkSecondaryIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._battery = Main.panel.statusArea.battery;
|
||||||
|
if (this._battery) {
|
||||||
|
this._batteryIcon = this.addIcon(null);
|
||||||
|
this._battery.mainIcon.bind_property('gicon', this._batteryIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
this.actor.visible = locked;
|
||||||
|
}
|
||||||
|
});
|
@ -1570,9 +1570,10 @@ const NMApplet = new Lang.Class({
|
|||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('network-offline', _('Network'));
|
this.parent('network-offline', _('Network'));
|
||||||
|
|
||||||
this._secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn' }));
|
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn' }));
|
||||||
this._secondaryIcon.hide();
|
this.secondaryIcon.hide();
|
||||||
|
|
||||||
|
this._isLocked = false;
|
||||||
this._client = NMClient.Client.new();
|
this._client = NMClient.Client.new();
|
||||||
|
|
||||||
this._statusSection = new PopupMenu.PopupMenuSection();
|
this._statusSection = new PopupMenu.PopupMenuSection();
|
||||||
@ -1681,12 +1682,8 @@ const NMApplet = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
setLockedState: function(locked) {
|
||||||
// FIXME: more design discussion is needed before we can
|
this._isLocked = locked;
|
||||||
// expose part of this menu
|
this._syncNMState();
|
||||||
|
|
||||||
if (locked)
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.reactive = !locked;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ensureSource: function() {
|
_ensureSource: function() {
|
||||||
@ -2074,13 +2071,8 @@ const NMApplet = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_syncNMState: function() {
|
_syncNMState: function() {
|
||||||
if (!this._client.manager_running) {
|
this.mainIcon.visible = this._client.manager_running;
|
||||||
log('NetworkManager is not running, hiding...');
|
this.actor.visible = this.mainIcon.visible && !this._isLocked;
|
||||||
this.menu.close();
|
|
||||||
this.actor.hide();
|
|
||||||
return;
|
|
||||||
} else
|
|
||||||
this.actor.show();
|
|
||||||
|
|
||||||
if (!this._client.networking_enabled) {
|
if (!this._client.networking_enabled) {
|
||||||
this.setIcon('network-offline');
|
this.setIcon('network-offline');
|
||||||
@ -2192,14 +2184,14 @@ const NMApplet = new Lang.Class({
|
|||||||
// only show a separate icon when we're using a wireless/3g connection
|
// only show a separate icon when we're using a wireless/3g connection
|
||||||
if (mc._section == NMConnectionCategory.WIRELESS ||
|
if (mc._section == NMConnectionCategory.WIRELESS ||
|
||||||
mc._section == NMConnectionCategory.WWAN) {
|
mc._section == NMConnectionCategory.WWAN) {
|
||||||
this._secondaryIcon.icon_name = vpnIconName;
|
this.secondaryIcon.icon_name = vpnIconName;
|
||||||
this._secondaryIcon.visible = true;
|
this.secondaryIcon.show();
|
||||||
} else {
|
} else {
|
||||||
this.setIcon(vpnIconName);
|
this.setIcon(vpnIconName);
|
||||||
this._secondaryIcon.visible = false;
|
this.secondaryIcon.hide();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._secondaryIcon.visible = false;
|
this.secondaryIcon.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup stale signal connections
|
// cleanup stale signal connections
|
||||||
|
@ -56,6 +56,7 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||||
|
|
||||||
|
this._isLocked = false;
|
||||||
this._deviceItems = [ ];
|
this._deviceItems = [ ];
|
||||||
this._hasPrimary = false;
|
this._hasPrimary = false;
|
||||||
this._primaryDeviceId = null;
|
this._primaryDeviceId = null;
|
||||||
@ -77,9 +78,8 @@ const Indicator = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
setLockedState: function(locked) {
|
||||||
if (locked)
|
this._isLocked = locked;
|
||||||
this.menu.close();
|
this._syncIcon();
|
||||||
this.actor.reactive = !locked;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_readPrimaryDevice: function() {
|
_readPrimaryDevice: function() {
|
||||||
@ -150,16 +150,20 @@ const Indicator = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_devicesChanged: function() {
|
_syncIcon: function() {
|
||||||
let icon = this._proxy.Icon;
|
let icon = this._proxy.Icon;
|
||||||
if (icon) {
|
let hasIcon = (icon != null);
|
||||||
|
|
||||||
|
if (hasIcon) {
|
||||||
let gicon = Gio.icon_new_for_string(icon);
|
let gicon = Gio.icon_new_for_string(icon);
|
||||||
this.setGIcon(gicon);
|
this.setGIcon(gicon);
|
||||||
this.actor.show();
|
|
||||||
} else {
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.hide();
|
|
||||||
}
|
}
|
||||||
|
this.mainIcon.visible = hasIcon;
|
||||||
|
this.actor.visible = hasIcon && !this._isLocked;
|
||||||
|
},
|
||||||
|
|
||||||
|
_devicesChanged: function() {
|
||||||
|
this._syncIcon();
|
||||||
this._readPrimaryDevice();
|
this._readPrimaryDevice();
|
||||||
this._readOtherDevices();
|
this._readOtherDevices();
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,27 @@ const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
|||||||
|
|
||||||
const VOLUME_NOTIFY_ID = 1;
|
const VOLUME_NOTIFY_ID = 1;
|
||||||
|
|
||||||
const Indicator = new Lang.Class({
|
// Each Gvc.MixerControl is a connection to PulseAudio,
|
||||||
Name: 'VolumeIndicator',
|
// so it's better to make it a singleton
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
let _mixerControl;
|
||||||
|
function getMixerControl() {
|
||||||
|
if (_mixerControl)
|
||||||
|
return _mixerControl;
|
||||||
|
|
||||||
_init: function() {
|
_mixerControl = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
||||||
this.parent('audio-volume-muted', _("Volume"));
|
_mixerControl.open();
|
||||||
|
|
||||||
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
return _mixerControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VolumeMenu = new Lang.Class({
|
||||||
|
Name: 'VolumeMenu',
|
||||||
|
Extends: PopupMenu.PopupMenuSection,
|
||||||
|
|
||||||
|
_init: function(control) {
|
||||||
|
this.parent();
|
||||||
|
|
||||||
|
this._control = control;
|
||||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||||
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
||||||
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
||||||
@ -35,10 +48,10 @@ const Indicator = new Lang.Class({
|
|||||||
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
||||||
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.menu.addMenuItem(this._outputTitle);
|
this.addMenuItem(this._outputTitle);
|
||||||
this.menu.addMenuItem(this._outputSlider);
|
this.addMenuItem(this._outputSlider);
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
|
||||||
this._input = null;
|
this._input = null;
|
||||||
this._inputVolumeId = 0;
|
this._inputVolumeId = 0;
|
||||||
@ -47,22 +60,11 @@ const Indicator = new Lang.Class({
|
|||||||
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
||||||
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.menu.addMenuItem(this._inputTitle);
|
this.addMenuItem(this._inputTitle);
|
||||||
this.menu.addMenuItem(this._inputSlider);
|
this.addMenuItem(this._inputSlider);
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
|
||||||
|
|
||||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
|
||||||
this._control.open();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
scroll: function(direction) {
|
||||||
this.menu.setSettingsVisibility(!locked);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onScrollEvent: function(actor, event) {
|
|
||||||
let direction = event.get_scroll_direction();
|
|
||||||
let currentVolume = this._output.volume;
|
let currentVolume = this._output.volume;
|
||||||
|
|
||||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||||
@ -88,9 +90,8 @@ const Indicator = new Lang.Class({
|
|||||||
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
||||||
this._readOutput();
|
this._readOutput();
|
||||||
this._readInput();
|
this._readInput();
|
||||||
this.actor.show();
|
|
||||||
} else {
|
} else {
|
||||||
this.actor.hide();
|
this.emit('icon-changed', null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -109,7 +110,7 @@ const Indicator = new Lang.Class({
|
|||||||
this._volumeChanged (null, null, '_output');
|
this._volumeChanged (null, null, '_output');
|
||||||
} else {
|
} else {
|
||||||
this._outputSlider.setValue(0);
|
this._outputSlider.setValue(0);
|
||||||
this.setIcon('audio-volume-muted-symbolic');
|
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -196,15 +197,55 @@ const Indicator = new Lang.Class({
|
|||||||
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
||||||
if (property == '_output') {
|
if (property == '_output') {
|
||||||
if (muted)
|
if (muted)
|
||||||
this.setIcon('audio-volume-muted');
|
this.emit('icon-changed', 'audio-volume-muted');
|
||||||
else
|
else
|
||||||
this.setIcon(this._volumeToIcon(this._output.volume));
|
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_volumeChanged: function(object, param_spec, property) {
|
_volumeChanged: function(object, param_spec, property) {
|
||||||
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
||||||
if (property == '_output' && !this._output.is_muted)
|
if (property == '_output' && !this._output.is_muted)
|
||||||
this.setIcon(this._volumeToIcon(this._output.volume));
|
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Indicator = new Lang.Class({
|
||||||
|
Name: 'VolumeIndicator',
|
||||||
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent('audio-volume-muted', _("Volume"));
|
||||||
|
|
||||||
|
this._isLocked = false;
|
||||||
|
|
||||||
|
this._control = getMixerControl();
|
||||||
|
this._volumeMenu = new VolumeMenu(this._control);
|
||||||
|
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
|
||||||
|
this._hasPulseAudio = (icon != null);
|
||||||
|
this.setIcon(icon);
|
||||||
|
this._syncVisibility();
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.menu.addMenuItem(this._volumeMenu);
|
||||||
|
|
||||||
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
||||||
|
|
||||||
|
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||||
|
},
|
||||||
|
|
||||||
|
setLockedState: function(locked) {
|
||||||
|
this._isLocked = locked;
|
||||||
|
this._syncVisibility();
|
||||||
|
},
|
||||||
|
|
||||||
|
_syncVisibility: function() {
|
||||||
|
this.actor.visible = this._hasPulseAudio && !this._isLocked;
|
||||||
|
this.mainIcon.visible = this._hasPulseAudio;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onScrollEvent: function(actor, event) {
|
||||||
|
this._volumeMenu.scroll(event.get_scroll_direction());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user