summaryrefslogtreecommitdiff
path: root/extension.js
diff options
context:
space:
mode:
Diffstat (limited to 'extension.js')
-rw-r--r--extension.js246
1 files changed, 104 insertions, 142 deletions
diff --git a/extension.js b/extension.js
index 403d956..b08d77b 100644
--- a/extension.js
+++ b/extension.js
@@ -15,219 +15,181 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const Main = imports.ui.main;
-const GnomeBluetooth = imports.gi.GnomeBluetooth;
-const PopupMenu = imports.ui.popupMenu;
-const Util = imports.misc.util;
const GLib = imports.gi.GLib;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
-const Convenience = Me.imports.convenience;
-
-class BluetoothDevice {
- constructor(model, device) {
- this._name = model.get_value(device, GnomeBluetooth.Column.NAME);
- this._isConnected = model.get_value(device, GnomeBluetooth.Column.CONNECTED);
- this._isPaired = model.get_value(device, GnomeBluetooth.Column.PAIRED);
- this._mac = model.get_value(device, GnomeBluetooth.Column.ADDRESS);
- }
-
- get name() {
- return this._name;
- }
-
- get isConnected() {
- return this._isConnected;
- }
-
- get isPaired() {
- return this._isPaired;
- }
-
- get mac() {
- return this._mac;
- }
-
- get item() {
- if (!this._item)
- this._buildMenuItem();
-
- return this._item;
- }
-
- _buildMenuItem() {
- this._item = new PopupMenu.PopupSwitchMenuItem(this.name, this.isConnected);
- this._item.isDeviceSwitcher = true;
- this._item.connect('toggled', (item, state) => {
- if (state)
- this._connect();
- else
- this._disconnect();
- });
- }
-
- _disconnect() {
- this._call_bluetoothctl(`disconnect ${this.mac}`)
- }
-
- _connect() {
- this._call_bluetoothctl(`connect ${this.mac}`)
- }
+const UiExtension = Me.imports.ui;
+const Bluetooth = Me.imports.bluetooth;
+const Utils = Me.imports.utils;
+const Settings = Me.imports.settings.Settings;
- _call_bluetoothctl(command) {
- let btctl_command = `echo -e "${command}\\n" | bluetoothctl`;
- Util.spawn(['/usr/bin/env', 'bash', '-c', btctl_command]);
- }
-}
class BluetoothQuickConnect {
constructor(bluetooth, settings) {
+ this._logger = new Utils.Logger(settings);
+ this._logger.info('Initializing extension');
this._menu = bluetooth._item.menu;
this._proxy = bluetooth._proxy;
- this._settings = settings;
+ this._controller = new Bluetooth.BluetoothController();
+ this._settings = settings
- this._signals = [];
+ this._items = {};
}
enable() {
- this._loadBluetoothModel();
+ this._logger.info('Enabling extension');
+ this._controller.enable();
+ this._refresh();
+ this._connectControllerSignals();
+ this._connectIdleMonitor();
+ this._connectMenuSignals();
+ }
+
+ _connectMenuSignals() {
this._connectSignal(this._menu, 'open-state-changed', (menu, isOpen) => {
- if (isOpen && this._autoPowerOnEnabled())
+ this._logger.info(`Menu toggled: ${isOpen}`);
+ if (isOpen)
+ this._disconnectIdleMonitor()
+ else
+ this._connectIdleMonitor();
+
+ if (isOpen && this._settings.isAutoPowerOnEnabled() && this._proxy.BluetoothAirplaneMode) {
+ this._logger.info('Disabling airplane mode');
this._proxy.BluetoothAirplaneMode = false;
+ }
});
-
- this._connectSignal(this._model, 'row-changed', () => this._sync());
- this._connectSignal(this._model, 'row-deleted', () => this._sync());
- this._connectSignal(this._model, 'row-inserted', () => this._sync());
-
- this._idleMonitor();
- if (!this._proxy.BluetoothAirplaneMode) {
- this._sync();
- }
}
disable() {
+ this._logger.info('Disabling extension');
this._destroy();
}
test() {
try {
+ this._logger.info('Testing bluetoothctl');
GLib.spawn_command_line_sync("bluetoothctl --version");
- } catch(error) {
- Main.notifyError(`Bluetooth quick connect: error trying to execute "bluetoothctl"`);
+ this._logger.info('Test succeeded');
+ } catch (error) {
+ Main.notifyError(_('Bluetooth quick connect'), _(`Error trying to execute "bluetoothctl"`));
+ this._logger.info('Test failed');
}
}
- _idleMonitor() {
- this._idleMonitorId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, this._autoPowerOffCheckingInterval() * 1000, () => {
- if (this._autoPowerOffEnabled() && this._getConnectedDevices().length === 0)
- this._proxy.BluetoothAirplaneMode = true;
+ _connectControllerSignals() {
+ this._logger.info('Connecting bluetooth controller signals');
- return true;
+ this._connectSignal(this._controller, 'device-inserted', (ctrl, device) => {
+ this._logger.info(`Device inserted event: ${device.name}`);
+ this._addMenuItem(device);
+ });
+ this._connectSignal(this._controller, 'device-changed', (ctrl, device) => {
+ this._logger.info(`Device changed event: ${device.name}`);
+ if (device.isDefault)
+ this._refresh();
+ else
+ this._syncMenuItem(device);
+ });
+ this._connectSignal(this._controller, 'device-deleted', () => {
+ this._logger.info(`Device deleted event`);
+ this._refresh();
});
- }
- _connectSignal(subject, signal_name, method) {
- let signal_id = subject.connect(signal_name, method);
- this._signals.push({
- subject: subject,
- signal_id: signal_id
+ this._connectSignal(Main.sessionMode, 'updated', () => {
+ this._refresh()
});
}
- _loadBluetoothModel() {
- this._client = new GnomeBluetooth.Client();
- this._model = this._client.get_model();
+ _syncMenuItem(device) {
+ this._logger.info(`Synchronizing device menu item: ${device.name}`);
+ let item = this._items[device.mac] || this._addMenuItem(device);
+ item.sync(device);
}
- _getDefaultAdapter() {
- let [ret, iter] = this._model.get_iter_first();
- while (ret) {
- let isDefault = this._model.get_value(iter, GnomeBluetooth.Column.DEFAULT);
- let isPowered = this._model.get_value(iter, GnomeBluetooth.Column.POWERED);
- if (isDefault && isPowered)
- return iter;
- ret = this._model.iter_next(iter);
- }
- return null;
+ _addMenuItem(device) {
+ this._logger.info(`Adding device menu item: ${device.name}`);
+ let menuItem = new UiExtension.PopupBluetoothDeviceMenuItem(
+ device,
+ {
+ showRefreshButton: this._settings.isShowRefreshButtonEnabled(),
+ closeMenuOnAction: !this._settings.isKeepMenuOnToggleEnabled()
+ }
+ );
+ this._items[device.mac] = menuItem;
+ this._menu.addMenuItem(menuItem, 1);
+
+ return menuItem;
}
- _getDevices() {
- let adapter = this._getDefaultAdapter();
- if (!adapter)
- return [];
+ _connectIdleMonitor() {
+ if (this._idleMonitorId) return;
- let devices = [];
+ this._logger.info('Connecting idle monitor');
- let [ret, iter] = this._model.iter_children(adapter);
- while (ret) {
- devices.push(new BluetoothDevice(this._model, iter));
- ret = this._model.iter_next(iter);
- }
+ this._idleMonitorId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, this._settings.autoPowerOffCheckingInterval() * 1000, () => {
+ if (this._settings.isAutoPowerOffEnabled() && this._controller.getConnectedDevices().length === 0)
+ this._proxy.BluetoothAirplaneMode = true;
- return devices;
+ return true;
+ });
}
- _getPairedDevices() {
- return this._getDevices().filter((device) => {
- return device.isPaired || device.isConnected;
- });
+ _disconnectIdleMonitor() {
+ if (!this._idleMonitorId) return;
+
+ this._logger.info('Disconnecting idle monitor');
+
+ GLib.Source.remove(this._idleMonitorId);
+ this._idleMonitorId = null;
}
- _getConnectedDevices() {
- return this._getDevices().filter((device) => {
- return device.isConnected;
+ _connectSignal(subject, signal_name, method) {
+ let signal_id = subject.connect(signal_name, method);
+ this._signals.push({
+ subject: subject,
+ signal_id: signal_id
});
}
- _sync() {
+ _refresh() {
this._removeDevicesFromMenu();
this._addDevicesToMenu();
+
+ this._logger.info('Refreshing devices list');
}
_addDevicesToMenu() {
- this._getPairedDevices().forEach((device) => {
- this._menu.addMenuItem(device.item, 1);
+ this._controller.getDevices().forEach((device) => {
+ this._addMenuItem(device);
});
}
_removeDevicesFromMenu() {
- this._menu._getMenuItems().forEach((item) => {
- if (item.isDeviceSwitcher) {
- item.destroy();
- }
+ Object.values(this._items).forEach((item) => {
+ item.destroy();
});
+
+ this._items = {};
}
_destroy() {
- this._signals.forEach((signal) => {
- signal.subject.disconnect(signal.signal_id);
- });
- this._signals = [];
+ this._disconnectSignals();
this._removeDevicesFromMenu();
-
- if (this._idleMonitorId)
- GLib.Source.remove(this._idleMonitorId);
- }
-
- _autoPowerOnEnabled() {
- return this._settings.get_boolean('bluetooth-auto-power-on');
+ this._disconnectIdleMonitor();
+ if (this._controller)
+ this._controller.destroy();
}
+}
- _autoPowerOffEnabled() {
- return this._settings.get_boolean('bluetooth-auto-power-off');
- }
+Utils.addSignalsHelperMethods(BluetoothQuickConnect.prototype);
- _autoPowerOffCheckingInterval() {
- return this._settings.get_int('bluetooth-auto-power-off-interval');
- }
-}
let bluetoothQuickConnect = null;
function init() {
let bluetooth = Main.panel.statusArea.aggregateMenu._bluetooth;
- let settings = Convenience.getSettings();
+ let settings = new Settings();
bluetoothQuickConnect = new BluetoothQuickConnect(bluetooth, settings);
}