const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const Main = imports.ui.main; const Volume = imports.ui.status.volume; let volume_scroller = null; const VolumeScrollerIcons = [ 'audio-volume-muted-symbolic', 'audio-volume-low-symbolic', 'audio-volume-medium-symbolic', 'audio-volume-high-symbolic' ]; class VolumeScroller { constructor() { this.controller = Volume.getMixerControl(); this.panel = Main.panel; this.enabled = false; this.sink = null; this.volume_max = this.controller.get_vol_max_norm(); this.volume_step = 0.05 * this.volume_max; this.scroll_binding = null; this.sink_binding = null; } enable() { if (this.enabled) { this.disable(); } this.enabled = true; this.sink = this.controller.get_default_sink(); this.scroll_binding = this.panel.connect( 'scroll-event', (actor, event) => this._handle_scroll(actor, event)); this.sink_binding = this.controller.connect( 'default-sink-changed', (controller, id) => this._handle_sink_change(controller, id)); } disable() { if (this.enabled) { this.enabled = false; this.sink = null; this.panel.disconnect(this.scroll_binding); this.scroll_binding = null; this.controller.disconnect(this.sink_binding); this.sink_binding = null; } } _handle_scroll(actor, event) { let volume = this.sink.volume; switch (event.get_scroll_direction()) { case Clutter.ScrollDirection.UP: volume += this.volume_step; break; case Clutter.ScrollDirection.DOWN: volume -= this.volume_step; break; default: return Clutter.EVENT_PROPAGATE; } volume = Math.min(volume, this.volume_max); volume = Math.max(volume, 0); this.sink.volume = volume; this.sink.push_volume(); this._show_volume(volume); return Clutter.EVENT_STOP; } _handle_sink_change(controller, id) { this.sink = controller.lookup_stream_id(id); } _show_volume(volume) { const percentage = volume / this.volume_max; let n; if (volume === 0) { n = 0; } else { n = parseInt(3 * percentage + 1); n = Math.max(1, n); n = Math.min(3, n); } const monitor = -1; // Display volume window on all monitors. const icon = Gio.Icon.new_for_string(VolumeScrollerIcons[n]); const label = this.sink.get_port().human_port; Main.osdWindowManager.show(monitor, icon, label, percentage); } }; function enable() { volume_scroller = new VolumeScroller(); volume_scroller.enable(); } function disable() { if (volume_scroller !== null) { volume_scroller.disable(); volume_scroller = null; } }