This file is indexed.

/usr/share/gnome-shell/extensions/bettervolume@tudmotu.com/extension.js is in gnome-shell-extension-better-volume 0.0-git20161106.ff67408-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/**
 * Better Volume Indicator
 *
 * This simple extension implements two things:
 *     1. When scrolling on the volume indicator, the volume slider/menu appears to
 *         display current level.
 *     2. Middle/scroll clicking on the indicator, output is muted.
 *
 */
const Clutter = imports.gi.Clutter;
const Mainloop = imports.mainloop;

const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const VolumeMenu = imports.ui.status.volume.VolumeMenu;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const prettyPrint = Convenience.dbPrintObj;

const POPUP_TIMEOUT_SECS = 1;
const VOLUME_MUTE_ICON = 'audio-volume-muted-symbolic';
let onlyVolumeMenuShown = false;
let volumeIndicator;
let aggregateMenu;
let _onAggregateMenuClickEventId;
let _onAggregateMenuEnterEventId;
let _onAggregateMenuLeaveEventId;
let _onVolumeIndicatorScrollEventId;
let _onVolumeIndicatorClickEventId;

let popupTimeout = null;
let availableMenus = [];
function _onVolumeIndicatorScroll(indicators, e) {
    let menu = aggregateMenu.menu;

    // Only if menu is not already open (and not due to our request)
    if (menu.actor.visible && popupTimeout === null)
        return;

    // We need to remove the previous timeout if the user scrolled again since
    // it means they are not ready yet for us to hide the menu
    if (popupTimeout !== null) _removeTimeout();

    // Set a timeout for the menu to close (we don't want it staying open forever)
    _setTimeout();

    // We want to hide all menus which are not the volume menu
    _setMenusVisibility(false);

    // Open the aggregateMenu so we can see some volume
    aggregateMenu.menu.open();
}

function _onVolumeIndicatorScrollTimeout () {
    // When time is up, we close the menu
    aggregateMenu.menu.close();

    // Re-show the aggegate menu entries
    _setMenusVisibility(true);

    _removeTimeout();
}

function _onAggregateMenuClick (actor, e) {
    // Make sure menus are displayed
    _setMenusVisibility(true);

    // We want to see if the popup is already displayed, and if so, kill its
    // timeout, so it won't suddenly disappear on us
    // If it's not open, we don't won't to do anything
    if (popupTimeout !== null) {
        _removeTimeout();

        // Make sure the menu is open
        // This is kinda hacky - since the aggregateMenu toggles its own
        // visibility, we want to reverse the effect. It's a dirty trick but I
        // could not figure out a better way to overcome its self-toggling
        aggregateMenu.menu.toggle();
    }
}

function _onAggregateMenuEnter () {
    _removeTimeout();
}

function _onAggregateMenuLeave () {
    // When mouse leaves, set a new timeout only if menu was shown due to
    // volume-scrolling (meaning - this extension caused the menu to appear, and
    // not, say, a click on the aggregate-menu by the user)
    if (onlyVolumeMenuShown) _setTimeout();
}

let _previousVolumeValue, _previousVolumeIcon;
function _onVolumeIndicatorClick (actor, e) {
    // When middle-clicking on the indicator we want to toggle mute
    if (e.get_button() === Clutter.BUTTON_MIDDLE) {
        let sliderActor = volumeIndicator._volumeMenu._output._slider; // hummm.. hack?
        let currentValue = sliderActor._getCurrentValue(); // starting to look like a hack
        let currentIcon = volumeIndicator._primaryIndicator.icon_name;

        if (currentValue === 0 && _previousVolumeValue) {
            // this is definitely a hack
            sliderActor.setValue(_previousVolumeValue);
            sliderActor.emit('value-changed', _previousVolumeValue); // mimic slider behvaiour so volume will actually change
            volumeIndicator._primaryIndicator.icon_name = _previousVolumeIcon;
        }
        else {
            // a dirty dirty hack
            sliderActor.setValue(0);
            sliderActor.emit('value-changed', 0); // like above
            volumeIndicator._primaryIndicator.icon_name = VOLUME_MUTE_ICON;
            _previousVolumeValue = currentValue;
            _previousVolumeIcon = currentIcon;
        }

        aggregateMenu.menu.toggle(); // again with that previous hack
    }
}

function _setTimeout () {
    popupTimeout = Mainloop.timeout_add_seconds(POPUP_TIMEOUT_SECS, _onVolumeIndicatorScrollTimeout);
}

function _removeTimeout () {
    if (popupTimeout !== null)
        Mainloop.source_remove(popupTimeout);
    popupTimeout = null;
}

function _setMenusVisibility (visibility) {
    // Find the menus inside the aggregateMenu (I couldn't find a better
    // way for finding the menus except finding their indicators. seems to work
    // though)
    for (let k in aggregateMenu) {
        let entry = aggregateMenu[k];
        if (entry instanceof PanelMenu.SystemIndicator) {
            if (entry !== volumeIndicator) {
                entry.menu.actor.visible = visibility;
            }
        }
    }

    // Hide inner menus inside the volume section
    volumeIndicator.menu._getMenuItems().forEach(function (item, i) {
        if ( !(item instanceof VolumeMenu) ) {
            item.actor.visible = visibility;
        }
    });

    // Mark volume menu visibility accordingly
    onlyVolumeMenuShown = !visibility;
}

function init() {

}

function enable() {
    aggregateMenu = Main.panel.statusArea.aggregateMenu;

    if (aggregateMenu.hasOwnProperty('_volume') && aggregateMenu._volume instanceof PanelMenu.SystemIndicator) {
        volumeIndicator = aggregateMenu._volume;
        _onVolumeIndicatorScrollEventId = volumeIndicator.indicators.connect('scroll-event', _onVolumeIndicatorScroll);
        _onVolumeIndicatorClickEventId = volumeIndicator.indicators.connect('button-press-event', _onVolumeIndicatorClick);
        _onAggregateMenuEnterEventId = aggregateMenu.menu.actor.connect('enter-event', _onAggregateMenuEnter);
        _onAggregateMenuLeaveEventId = aggregateMenu.menu.actor.connect('leave-event', _onAggregateMenuLeave);
        _onAggregateMenuClickEventId = aggregateMenu.actor.connect('button-press-event', _onAggregateMenuClick);
    }
}

function disable() {
    // We need to verify we still have connections and disconnect them
    if (_onVolumeIndicatorScrollEventId)
        volumeIndicator.indicators.disconnect(_onVolumeIndicatorScrollEventId);

    if (_onVolumeIndicatorClickEventId)
        volumeIndicator.indicators.disconnect(_onVolumeIndicatorClickEventId);

    if (_onAggregateMenuEnterEventId)
        aggregateMenu.menu.actor.disconnect(_onAggregateMenuEnterEventId);

    if (_onAggregateMenuLeaveEventId)
        aggregateMenu.menu.actor.disconnect(_onAggregateMenuLeaveEventId);

    if (_onAggregateMenuClickEventId)
        aggregateMenu.actor.disconnect(_onAggregateMenuClickEventId);
}