Replaced title with PopupSwitchMenuItem.
[AdvancedVolumeMixer.git] / extension.js
blob256886bae34b649783f0eeca982724cb036da385
1 // extension.js
2 // vi: et sw=2
3 //
4 // Advanced Volume Mixer
5 // Control programs' volume from gnome volume mixer applet.
6 //
7 // Idea from: https://extensions.gnome.org/extension/142/output-device-chooser-on-volume-menu/
8 //
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;
22 let advMixer;
25 function AdvMixer(mixer) {
26   this._init(mixer);
30 AdvMixer.prototype = {
31   _init: function(mixer) {
32     this._mixer = mixer;
33     this._control = mixer._control;
34     this._items = {};
36     this._streamAddedId = this._control.connect(
37       "stream-added",
38       Lang.bind(this, this._streamAdded)
39     );
40     this._streamRemovedId = this._control.connect(
41       "stream-removed",
42       Lang.bind(this, this._streamRemoved)
43     );
44   },
47   _streamAdded: function(control, id) {
48     if (id in this._items) {
49       return;
50     }
52     let stream = control.lookup_stream_id(id);
54     if (stream["is-event-stream"]) {
55       // Do nothing
56     } else if (stream instanceof Gvc.MixerSinkInput) {
57       let item = new PopupMenu.PopupSliderMenuItem(
58         stream.volume / this._control.get_vol_max_norm()
59       );
60       let title = new PopupMenu.PopupSwitchMenuItem(
61         stream.name,
62         !stream.is_muted,
63         {activate: false}
64       );
66       this._items[id] = [item, title];
68       item.connect(
69         "value-changed",
70         Lang.bind(this, this._sliderValueChanged, stream.id)
71       );
73       title.actor.connect(
74         "button-release-event",
75         Lang.bind(this, this._titleToggleState, stream.id)
76       );
78       title.actor.connect(
79         "key-press-event",
80         Lang.bind(this, this._titleToggleState, stream.id)
81       );
83       //title.connect(
84       //  "toggled",
85       //  Lang.bind(this, this._titleToggled, stream.id)
86       //);
88       stream.connect(
89         "notify::volume",
90         Lang.bind(this, this._notifyVolume, stream.id)
91       );
93       stream.connect(
94         "notify::is-muted",
95         Lang.bind(this, this._notifyIsMuted, stream.id)
96       );
98       this._mixer.menu.addMenuItem(item, 3);
99       this._mixer.menu.addMenuItem(title, 3);
101       title.actor.show();
102       item.actor.show();
103     }
104   },
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];
111     }
112   },
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();
120   },
122   _titleToggled: function(title, value, id) {
123     let stream = this._control.lookup_stream_id(id);
125     stream.change_is_muted(!value);
127     return false;
128   },
130   _titleToggleState: function(title, event, id) {
131     //if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
132     //} else
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) {
137         return false;
138       }
139     }
141     let stream = this._control.lookup_stream_id(id);
143     stream.change_is_muted(!stream.is_muted);
145     return true;
146   },
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());
152   },
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);
158   },
160   destroy: function() {
161     this._control.disconnect(this._streamAddedId);
162     this._control.disconnect(this._streamRemovedId);
163     this.emit("destroy");
164   }
168 Signals.addSignalMethods(AdvMixer.prototype);
171 function main() {
172   init();
173   enable();
177 function init() {
181 function enable() {
182   if (Main.panel._statusArea['volume'] && !advMixer) {
183     advMixer = new AdvMixer(Main.panel._statusArea["volume"]);
184   }
188 function disable() {
189   if (advMixer) {
190     advMixer.destroy();
191     advMixer = null;
192   }