gnome-shell/js/ui/audioDeviceSelection.js
Zander Brown 350cd296fa js: Stop using ClutterContainer API
These have been long deprecated over in clutter, and (via several
vtables) simply forward the call to the equivalent ClutterActor methods

Save ourselves the hassle and just use ClutterActor methods directly

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3010>
2023-11-10 20:19:13 +00:00

215 lines
6.3 KiB
JavaScript

import Clutter from 'gi://Clutter';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Meta from 'gi://Meta';
import Shell from 'gi://Shell';
import St from 'gi://St';
import * as Dialog from './dialog.js';
import * as ModalDialog from './modalDialog.js';
import * as Main from './main.js';
import {loadInterfaceXML} from '../misc/fileUtils.js';
const AudioDevice = {
HEADPHONES: 1 << 0,
HEADSET: 1 << 1,
MICROPHONE: 1 << 2,
};
const AudioDeviceSelectionIface = loadInterfaceXML('org.gnome.Shell.AudioDeviceSelection');
const AudioDeviceSelectionDialog = GObject.registerClass({
Signals: {'device-selected': {param_types: [GObject.TYPE_UINT]}},
}, class AudioDeviceSelectionDialog extends ModalDialog.ModalDialog {
_init(devices) {
super._init({styleClass: 'audio-device-selection-dialog'});
this._deviceItems = {};
this._buildLayout();
if (devices & AudioDevice.HEADPHONES)
this._addDevice(AudioDevice.HEADPHONES);
if (devices & AudioDevice.HEADSET)
this._addDevice(AudioDevice.HEADSET);
if (devices & AudioDevice.MICROPHONE)
this._addDevice(AudioDevice.MICROPHONE);
if (this._selectionBox.get_n_children() < 2)
throw new Error('Too few devices for a selection');
}
_buildLayout() {
let content = new Dialog.MessageDialogContent({
title: _('Select Audio Device'),
});
this._selectionBox = new St.BoxLayout({
style_class: 'audio-selection-box',
x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
});
content.add_child(this._selectionBox);
this.contentLayout.add_child(content);
if (Main.sessionMode.allowSettings) {
this.addButton({
action: this._openSettings.bind(this),
label: _('Sound Settings'),
});
}
this.addButton({
action: () => this.close(),
label: _('Cancel'),
key: Clutter.KEY_Escape,
});
}
_getDeviceLabel(device) {
switch (device) {
case AudioDevice.HEADPHONES:
return _('Headphones');
case AudioDevice.HEADSET:
return _('Headset');
case AudioDevice.MICROPHONE:
return _('Microphone');
default:
return null;
}
}
_getDeviceIcon(device) {
switch (device) {
case AudioDevice.HEADPHONES:
return 'audio-headphones-symbolic';
case AudioDevice.HEADSET:
return 'audio-headset-symbolic';
case AudioDevice.MICROPHONE:
return 'audio-input-microphone-symbolic';
default:
return null;
}
}
_addDevice(device) {
const box = new St.BoxLayout({
style_class: 'audio-selection-device-box',
vertical: true,
});
box.connect('notify::height', () => {
const laters = global.compositor.get_laters();
laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
box.width = box.height;
return GLib.SOURCE_REMOVE;
});
});
const icon = new St.Icon({
style_class: 'audio-selection-device-icon',
icon_name: this._getDeviceIcon(device),
});
box.add_child(icon);
const label = new St.Label({
style_class: 'audio-selection-device-label',
text: this._getDeviceLabel(device),
x_align: Clutter.ActorAlign.CENTER,
});
box.add_child(label);
const button = new St.Button({
style_class: 'audio-selection-device',
can_focus: true,
child: box,
});
this._selectionBox.add_child(button);
button.connect('clicked', () => {
this.emit('device-selected', device);
this.close();
Main.overview.hide();
});
}
_openSettings() {
let desktopFile = 'gnome-sound-panel.desktop';
let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
if (!app) {
log(`Settings panel for desktop file ${desktopFile} could not be loaded!`);
return;
}
this.close();
Main.overview.hide();
app.activate();
}
});
export class AudioDeviceSelectionDBus {
constructor() {
this._audioSelectionDialog = null;
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AudioDeviceSelectionIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/AudioDeviceSelection');
Gio.DBus.session.own_name('org.gnome.Shell.AudioDeviceSelection', Gio.BusNameOwnerFlags.REPLACE, null, null);
}
_onDialogClosed() {
this._audioSelectionDialog = null;
}
_onDeviceSelected(dialog, device) {
let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info();
const deviceName = Object.keys(AudioDevice)
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase();
connection.emit_signal(
this._audioSelectionDialog._sender,
this._dbusImpl.get_object_path(),
info ? info.name : null,
'DeviceSelected',
GLib.Variant.new('(s)', [deviceName]));
}
OpenAsync(params, invocation) {
if (this._audioSelectionDialog) {
invocation.return_value(null);
return;
}
let [deviceNames] = params;
let devices = 0;
deviceNames.forEach(n => (devices |= AudioDevice[n.toUpperCase()]));
let dialog;
try {
dialog = new AudioDeviceSelectionDialog(devices);
} catch (e) {
invocation.return_value(null);
return;
}
dialog._sender = invocation.get_sender();
dialog.connect('closed', this._onDialogClosed.bind(this));
dialog.connect('device-selected',
this._onDeviceSelected.bind(this));
dialog.open();
this._audioSelectionDialog = dialog;
invocation.return_value(null);
}
CloseAsync(params, invocation) {
if (this._audioSelectionDialog &&
this._audioSelectionDialog._sender === invocation.get_sender())
this._audioSelectionDialog.close();
invocation.return_value(null);
}
}