Version 14
[AdvancedVolumeMixer.git] / mixer.js
blobcb83a566db524529f22423754b0ec8716e9f0537
1 // extension.js
2 // vi: et sw=2
3 //
4 // Advanced Volume Mixer
5 // Control programs' volume from gnome volume mixer applet.
6 //
7 // Author: Harry Karvonen <harry.karvonen@gmail.com>
8 //
10 const Clutter = imports.gi.Clutter;
11 const Lang = imports.lang;
12 const Gvc = imports.gi.Gvc;
13 const St = imports.gi.St;
15 const Main = imports.ui.main;
16 const PopupMenu = imports.ui.popupMenu;
18 const Volume = imports.ui.status.volume;
20 const AVM = imports.misc.extensionUtils.getCurrentExtension();
21 const Widget = AVM.imports.widget;
22 const Settings = AVM.imports.settings;
23 const Panel = AVM.imports.panel;
25 const AdvancedVolumeMixer = new Lang.Class({
26 Name: "AdvancedVolumeMixer",
27 Extends: PopupMenu.PopupMenuSection,
29 _init: function() {
30 this.parent();
32 this._control = Volume.getMixerControl();
33 this._sinks = {};
34 this._outputs = {};
35 this._settings = Settings.gsettings;
37 this._control.connect(
38 "state-changed",
39 Lang.bind(this, this._onControlStateChanged)
41 this._control.connect(
42 "default-sink-changed",
43 Lang.bind(this, this._readOutput));
44 this._control.connect(
45 "default-source-changed",
46 Lang.bind(this, this._readInput)
48 this._control.connect(
49 "stream-added",
50 Lang.bind(this, this._streamAdded)
52 this._control.connect(
53 "stream-removed",
54 Lang.bind(this, this._streamRemoved)
57 this._output = new Widget.AdvOutputStreamSlider(
58 this._control,
59 this._settings.get_enum("output-type") == 0
62 this._output.connect('stream-updated', Lang.bind(this, function() {
63 this.emit('icon-changed');
64 }));
65 this._output.item.actor.connect(
66 'button-press-event',
67 Lang.bind(this, function(actor, event) {
68 if (event.get_button() == 2) {
69 actor.stream.change_is_muted(!actor.stream.is_muted);
70 return true;
73 ));
75 this._input = new Volume.InputStreamSlider(this._control);
76 this._separator = new PopupMenu.PopupSeparatorMenuItem();
78 this.addMenuItem(this._output.item);
79 this.addMenuItem(this._input.item);
80 this.addMenuItem(this._separator);
82 this._onControlStateChanged();
85 scroll: function(event) {
86 this._output.scroll(event);
89 outputHasHeadphones: function() {
90 return this._output._hasHeadphones;
93 separatorLastItem: function(last) {
94 if (this._separator) {
95 this._separator.destroy();
98 if (last) {
99 this._separator = null;
100 } else {
101 this._separator = new PopupMenu.PopupSeparatorMenuItem();
102 this.addMenuItem(this._separator, 2);
106 _streamAdded: function(control, id) {
107 if (id in this._sinks) {
108 return;
111 if (id in this._outputs) {
112 return;
115 let stream = control.lookup_stream_id(id);
117 if (stream["is-event-stream"]) {
118 // Do nothing
119 } else if (stream instanceof Gvc.MixerSinkInput) {
120 let s = new Widget.AppOutputStreamSlider(this._control);
121 s.stream = stream;
122 this._sinks[id] = s;
123 this.addMenuItem(s.item);
124 s.item.actor.connect(
125 "button-press-event",
126 function (actor, event) {
127 if (event.get_button() == 2) {
128 actor.stream.change_is_muted(!actor.stream.is_muted);
132 } else if (stream instanceof Gvc.MixerSink) {
133 let s = new Widget.AppOutputStreamSlider(this._control, false, function (st) { return st.get_description(); });
134 s.stream = stream;
135 s.item.setOrnament(this._output.stream.id == s.stream.id);
136 this._outputs[id] = s;
137 this._output.item.menu.addMenuItem(s.item);
138 s.item.actor.connect(
139 "button-press-event",
140 function (actor, event) {
141 if (event.get_button() == 1) {
142 control.set_default_sink(actor.stream);
143 } else if (event.get_button() == 2) {
144 actor.stream.change_is_muted(!actor.stream.is_muted);
151 _streamRemoved: function(control, id) {
152 if (id in this._sinks) {
153 this._sinks[id].item.destroy();
154 delete this._sinks[id];
155 } else if (id in this._outputs) {
156 this._outputs[id].item.destroy();
157 delete this._outputs[id];
161 _onControlStateChanged: function() {
162 if (this._control.get_state() == Gvc.MixerControlState.READY) {
163 this._readInput();
164 this._readOutput();
166 let streams = this._control.get_streams();
167 for (let i = 0; i < streams.length; i++) {
168 this._streamAdded(this._control, streams[i].id);
172 this.emit('icon-changed');
175 _readOutput: function() {
176 this._output.stream = this._control.get_default_sink();
178 for (let output in this._outputs) {
179 this._outputs[output].item.setOrnament(this._output.stream.id == output);
183 _readInput: function() {
184 this._input.stream = this._control.get_default_source();
187 getIcon: function() {
188 return this._output.getIcon();