4 // Advanced Volume Mixer
5 // Control programs' volume from gnome volume mixer applet.
7 // Author: Harry Karvonen <harry.karvonen@gmail.com>
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,
32 this._control = Volume.getMixerControl();
35 this._settings = Settings.gsettings;
37 this._control.connect(
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(
50 Lang.bind(this, this._streamAdded)
52 this._control.connect(
54 Lang.bind(this, this._streamRemoved)
57 this._output = new Widget.AdvOutputStreamSlider(
59 this._settings.get_enum("output-type") == 0
62 this._output.connect('stream-updated', Lang.bind(this, function() {
63 this.emit('icon-changed');
65 this._output.item.actor.connect(
67 Lang.bind(this, function(actor, event) {
68 if (event.get_button() == 2) {
69 actor.stream.change_is_muted(!actor.stream.is_muted);
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();
83 log("AdvVolumeMixer init");
86 scroll: function(event) {
87 this._output.scroll(event);
90 outputHasHeadphones: function() {
91 return this._output._hasHeadphones;
94 separatorLastItem: function(last) {
95 log("separatorLastItem");
98 this._separator.destroy();
99 this._separator = new PopupMenu.PopupSeparatorMenuItem();
102 this.addMenuItem(this._separator, 999);
104 this.addMenuItem(this._separator, 2);
108 _streamAdded: function(control, id) {
109 if (id in this._sinks) {
113 if (id in this._outputs) {
117 let stream = control.lookup_stream_id(id);
119 if (stream["is-event-stream"]) {
121 } else if (stream instanceof Gvc.MixerSinkInput) {
122 let s = new Widget.AppOutputStreamSlider(this._control);
125 this.addMenuItem(s.item);
126 s.item.actor.connect(
127 "button-press-event",
128 function (actor, event) {
129 if (event.get_button() == 2) {
130 actor.stream.change_is_muted(!actor.stream.is_muted);
134 } else if (stream instanceof Gvc.MixerSink) {
135 let s = new Widget.AppOutputStreamSlider(this._control);
137 s.item.setOrnament(this._output.stream.id == s.stream.id);
138 this._outputs[id] = s;
139 this._output.item.menu.addMenuItem(s.item);
140 s.item.actor.connect(
141 "button-press-event",
142 function (actor, event) {
143 if (event.get_button() == 1) {
144 control.set_default_sink(actor.stream);
145 } else if (event.get_button() == 2) {
146 actor.stream.change_is_muted(!actor.stream.is_muted);
153 _streamRemoved: function(control, id) {
154 if (id in this._sinks) {
155 this._sinks[id].item.destroy();
156 delete this._sinks[id];
157 } else if (id in this._outputs) {
158 this._outputs[id].item.destroy();
159 delete this._outputs[id];
163 _onControlStateChanged: function() {
164 if (this._control.get_state() == Gvc.MixerControlState.READY) {
168 let streams = this._control.get_streams();
169 for (let i = 0; i < streams.length; i++) {
170 this._streamAdded(this._control, streams[i].id);
174 this.emit('icon-changed');
177 _readOutput: function() {
178 this._output.stream = this._control.get_default_sink();
180 for (let output in this._outputs) {
181 this._outputs[output].item.setOrnament(this._output.stream.id == output);
185 _readInput: function() {
186 this._input.stream = this._control.get_default_source();
189 getIcon: function() {
190 return this._output.getIcon();