209 lines
8.4 KiB
JavaScript
209 lines
8.4 KiB
JavaScript
|
/* extension.js
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
*/
|
||
|
|
||
|
import Clutter from 'gi://Clutter';
|
||
|
|
||
|
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||
|
import { MediaSection } from 'resource:///org/gnome/shell/ui/mpris.js';
|
||
|
|
||
|
import { LibPanel, Panel } from './libs/libpanel/main.js';
|
||
|
import { ApplicationsMixer, waitProperty } from './libs/widgets.js';
|
||
|
|
||
|
const DateMenu = Main.panel.statusArea.dateMenu;
|
||
|
const QuickSettings = Main.panel.statusArea.quickSettings;
|
||
|
|
||
|
const CalendarMessageList = DateMenu._messageList;
|
||
|
const MediaSection_DateMenu = CalendarMessageList._mediaSection;
|
||
|
|
||
|
const SystemItem = QuickSettings._system._systemItem;
|
||
|
// _volumeOutput is always defined here because `./libs/widgets.js` wait on it
|
||
|
const OutputVolumeSlider = QuickSettings._volumeOutput._output;
|
||
|
|
||
|
export default class QSAP extends Extension {
|
||
|
async enable() {
|
||
|
this.InputVolumeIndicator = await waitProperty(QuickSettings, '_volumeInput');
|
||
|
this.InputVolumeSlider = this.InputVolumeIndicator._input;
|
||
|
|
||
|
this.settings = this.getSettings();
|
||
|
|
||
|
this._scasis_callback = this.settings.connect(
|
||
|
'changed::always-show-input-slider',
|
||
|
() => this._set_always_show_input(this.settings.get_boolean('always-show-input-slider'))
|
||
|
);
|
||
|
this.settings.emit('changed::always-show-input-slider', 'always-show-input-slider');
|
||
|
|
||
|
this._master_volumes = [];
|
||
|
this._sc_callback = this.settings.connect('changed', () => this._refresh_panel());
|
||
|
this._refresh_panel();
|
||
|
}
|
||
|
|
||
|
disable() {
|
||
|
this.settings.disconnect(this._scasis_callback);
|
||
|
this.settings.disconnect(this._sc_callback);
|
||
|
for (const id of waitProperty.idle_ids) {
|
||
|
GLib.Source.remove(id);
|
||
|
}
|
||
|
waitProperty.idle_ids = null;
|
||
|
|
||
|
this._set_always_show_input(false);
|
||
|
this._cleanup_panel();
|
||
|
|
||
|
this.settings = null;
|
||
|
}
|
||
|
|
||
|
_refresh_panel() {
|
||
|
this._cleanup_panel();
|
||
|
|
||
|
const move_master_volume = this.settings.get_boolean('move-master-volume');
|
||
|
const media_control_action = this.settings.get_string('media-control');
|
||
|
const create_mixer_sliders = this.settings.get_boolean('create-mixer-sliders');
|
||
|
const merge_panel = this.settings.get_boolean('merge-panel');
|
||
|
const panel_position = this.settings.get_string("panel-position");
|
||
|
const widgets_ordering = this.settings.get_strv('ordering');
|
||
|
|
||
|
const filter_mode = this.settings.get_string('filter-mode');
|
||
|
const filters = this.settings.get_strv('filters');
|
||
|
|
||
|
if (move_master_volume || media_control_action !== 'none' || create_mixer_sliders) {
|
||
|
LibPanel.enable();
|
||
|
|
||
|
this._panel = LibPanel.main_panel;
|
||
|
let index = -1;
|
||
|
|
||
|
if (!merge_panel) {
|
||
|
this._panel = new Panel('main');
|
||
|
// Since the panel contains no element that have a minimal width (like QuickToggle)
|
||
|
// we need to force it to take the same with as a normal panel
|
||
|
this._panel.add_constraint(new Clutter.BindConstraint({
|
||
|
coordinate: Clutter.BindCoordinate.WIDTH,
|
||
|
source: LibPanel.main_panel,
|
||
|
}));
|
||
|
|
||
|
LibPanel.addPanel(this._panel);
|
||
|
|
||
|
}
|
||
|
if (merge_panel && panel_position === 'top') {
|
||
|
widgets_ordering.reverse();
|
||
|
index = this._panel.getItems().indexOf(SystemItem) + 2;
|
||
|
}
|
||
|
|
||
|
for (const widget of widgets_ordering) {
|
||
|
if (widget === 'volume-output' && move_master_volume) {
|
||
|
this._move_slider(index, OutputVolumeSlider);
|
||
|
} else if (widget === 'volume-input' && move_master_volume) {
|
||
|
this._move_slider(index, this.InputVolumeSlider);
|
||
|
} else if (widget === 'media' && media_control_action === 'move') {
|
||
|
this._move_media_controls(index);
|
||
|
} else if (widget === 'media' && media_control_action === 'duplicate') {
|
||
|
this._create_media_controls(index);
|
||
|
} else if (widget === 'mixer' && create_mixer_sliders) {
|
||
|
this._create_app_mixer(index, filter_mode, filters);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_cleanup_panel() {
|
||
|
if (!this._panel) return;
|
||
|
|
||
|
if (this._applications_mixer) {
|
||
|
this._applications_mixer.destroy();
|
||
|
this._applications_mixer = null;
|
||
|
}
|
||
|
|
||
|
if (this._media_section) {
|
||
|
this._panel.removeItem(this._media_section);
|
||
|
this._media_section = null;
|
||
|
}
|
||
|
if (MediaSection_DateMenu.has_style_class_name('QSAP-media-section')) {
|
||
|
this._panel.removeItem(MediaSection_DateMenu);
|
||
|
CalendarMessageList._sectionList.insert_child_at_index(MediaSection_DateMenu, 0);
|
||
|
MediaSection_DateMenu.remove_style_class_name('QSAP-media-section');
|
||
|
}
|
||
|
|
||
|
this._master_volumes.reverse();
|
||
|
for (const [slider, index] of this._master_volumes) {
|
||
|
this._panel.removeItem(slider);
|
||
|
LibPanel.main_panel.addItem(slider, 2);
|
||
|
LibPanel.main_panel._grid.set_child_at_index(slider, index);
|
||
|
}
|
||
|
this._master_volumes = [];
|
||
|
|
||
|
if (this._panel !== LibPanel.main_panel) {
|
||
|
LibPanel.removePanel(this._panel); // prevent the panel's position being forgotten
|
||
|
this._panel.destroy();
|
||
|
};
|
||
|
this._panel = null;
|
||
|
|
||
|
LibPanel.disable();
|
||
|
}
|
||
|
|
||
|
_move_slider(index, slider) {
|
||
|
const old_index = slider.get_parent().get_children().indexOf(slider);
|
||
|
|
||
|
LibPanel.main_panel.removeItem(slider);
|
||
|
this._panel.addItem(slider, 2);
|
||
|
this._panel._grid.set_child_at_index(slider, index);
|
||
|
|
||
|
this._master_volumes.push([slider, old_index]);
|
||
|
}
|
||
|
|
||
|
_move_media_controls(index) {
|
||
|
CalendarMessageList._sectionList.remove_child(MediaSection_DateMenu);
|
||
|
|
||
|
this._panel.addItem(MediaSection_DateMenu, 2);
|
||
|
this._panel._grid.set_child_at_index(MediaSection_DateMenu, index);
|
||
|
|
||
|
MediaSection_DateMenu.add_style_class_name('QSAP-media-section');
|
||
|
}
|
||
|
|
||
|
_create_media_controls(index) {
|
||
|
this._media_section = new MediaSection();
|
||
|
this._media_section.add_style_class_name('QSAP-media-section');
|
||
|
|
||
|
this._panel.addItem(this._media_section, 2);
|
||
|
this._panel._grid.set_child_at_index(this._media_section, index);
|
||
|
}
|
||
|
|
||
|
_create_app_mixer(index, filter_mode, filters) {
|
||
|
this._applications_mixer = new ApplicationsMixer(this._panel, index, filter_mode, filters);
|
||
|
}
|
||
|
|
||
|
_set_always_show_input(enabled) {
|
||
|
if (enabled) {
|
||
|
this._ivssa_callback = this.InputVolumeSlider._control.connect('stream-added', () => {
|
||
|
this.InputVolumeSlider.visible = true;
|
||
|
this.InputVolumeIndicator.visible = this.InputVolumeSlider._shouldBeVisible();
|
||
|
});
|
||
|
this._ivssr_callback = this.InputVolumeSlider._control.connect('stream-removed', () => {
|
||
|
this.InputVolumeSlider.visible = true;
|
||
|
this.InputVolumeIndicator.visible = this.InputVolumeSlider._shouldBeVisible();
|
||
|
});
|
||
|
this.InputVolumeSlider.visible = true;
|
||
|
this.InputVolumeIndicator.visible = this.InputVolumeSlider._shouldBeVisible();
|
||
|
} else {
|
||
|
if (this._ivssr_callback) this.InputVolumeSlider._control.disconnect(this._ivssr_callback);
|
||
|
if (this._ivssa_callback) this.InputVolumeSlider._control.disconnect(this._ivssa_callback);
|
||
|
this._ivssr_callback = null;
|
||
|
this._ivssa_callback = null;
|
||
|
this.InputVolumeSlider.visible = this.InputVolumeSlider._shouldBeVisible();
|
||
|
this.InputVolumeIndicator.visible = this.InputVolumeSlider._shouldBeVisible();
|
||
|
}
|
||
|
}
|
||
|
}
|