4 // Advanced Volume Mixer
5 // Control programs' volume from gnome volume mixer applet.
7 // Idea from: https://extensions.gnome.org/extension/142/output-device-chooser-on-volume-menu/
9 // Author: Harry Karvonen <harry.karvonen@gmail.com>
12 const Clutter = imports.gi.Clutter;
13 const Lang = imports.lang;
14 const Gvc = imports.gi.Gvc;
15 const Signals = imports.signals;
17 const Main = imports.ui.main;
18 const PopupMenu = imports.ui.popupMenu;
20 const PA_INVALID_INDEX = 0xffffffff;
25 function AdvMixer(mixer) {
30 AdvMixer.prototype = {
31 _init: function(mixer) {
33 this._control = mixer._control;
36 this._streamAddedId = this._control.connect(
38 Lang.bind(this, this._streamAdded)
40 this._streamRemovedId = this._control.connect(
42 Lang.bind(this, this._streamRemoved)
47 _streamAdded: function(control, id) {
48 if (id in this._items) {
52 let stream = control.lookup_stream_id(id);
54 if (stream["is-event-stream"]) {
56 } else if (stream instanceof Gvc.MixerSinkInput) {
57 let item = new PopupMenu.PopupSliderMenuItem(
58 stream.volume / this._control.get_vol_max_norm()
60 let title = new PopupMenu.PopupSwitchMenuItem(
66 this._items[id] = [item, title];
70 Lang.bind(this, this._sliderValueChanged, stream.id)
74 "button-release-event",
75 Lang.bind(this, this._titleToggleState, stream.id)
80 Lang.bind(this, this._titleToggleState, stream.id)
85 // Lang.bind(this, this._titleToggled, stream.id)
90 Lang.bind(this, this._notifyVolume, stream.id)
95 Lang.bind(this, this._notifyIsMuted, stream.id)
98 this._mixer.menu.addMenuItem(item, 3);
99 this._mixer.menu.addMenuItem(title, 3);
106 _streamRemoved: function(control, id) {
107 if (id in this._items) {
108 this._items[id][0].destroy();
109 this._items[id][1].destroy();
110 delete this._items[id];
114 _sliderValueChanged: function(slider, value, id) {
115 let stream = this._control.lookup_stream_id(id);
116 let volume = value * this._control.get_vol_max_norm();
118 stream.volume = volume;
119 stream.push_volume();
122 _titleToggled: function(title, value, id) {
123 let stream = this._control.lookup_stream_id(id);
125 stream.change_is_muted(!value);
130 _titleToggleState: function(title, event, id) {
131 //if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
133 if (event.type() == Clutter.EventType.KEY_PRESS) {
134 let symbol = event.get_key_symbol();
136 if (symbol != Clutter.KEY_space && symbol != Clutter.KEY_Return) {
141 let stream = this._control.lookup_stream_id(id);
143 stream.change_is_muted(!stream.is_muted);
148 _notifyVolume: function(object, param_spec, id) {
149 let stream = this._control.lookup_stream_id(id);
151 this._items[id][0].setValue(stream.volume / this._control.get_vol_max_norm());
154 _notifyIsMuted: function(object, param_spec, id) {
155 let stream = this._control.lookup_stream_id(id);
157 this._items[id][1].setToggleState(!stream.is_muted);
160 destroy: function() {
161 this._control.disconnect(this._streamAddedId);
162 this._control.disconnect(this._streamRemovedId);
163 this.emit("destroy");
168 Signals.addSignalMethods(AdvMixer.prototype);
182 if (Main.panel._statusArea['volume'] && !advMixer) {
183 advMixer = new AdvMixer(Main.panel._statusArea["volume"]);