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();
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();
99 this._separator
= null;
101 this._separator
= new PopupMenu
.PopupSeparatorMenuItem();
102 this.addMenuItem(this._separator
, 2);
106 _streamAdded: function(control
, id
) {
107 if (id
in this._sinks
) {
111 if (id
in this._outputs
) {
115 let stream
= control
.lookup_stream_id(id
);
117 if (stream
["is-event-stream"]) {
119 } else if (stream
instanceof Gvc
.MixerSinkInput
) {
120 let s
= new Widget
.AppOutputStreamSlider(this._control
);
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(); });
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
) {
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();