Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Port extension to GNOME 45 #3

Merged
merged 2 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-FileCopyrightText: 2018 Claudio André <claudioandre.br@gmail.com>
env:
es2021: true
extends: 'eslint:recommended'
extends: "eslint:recommended"
plugins:
- jsdoc
rules:
Expand Down Expand Up @@ -58,11 +58,11 @@ rules:
- error
- 4
- ignoredNodes:
# Allow not indenting the body of GObject.registerClass, since in the
# future it's intended to be a decorator
- 'CallExpression[callee.object.name=GObject][callee.property.name=registerClass] > ClassExpression:first-child'
# Allow not indenting the body of GObject.registerClass, since in the
# future it's intended to be a decorator
- "CallExpression[callee.object.name=GObject][callee.property.name=registerClass] > ClassExpression:first-child"
# Allow dedenting chained member expressions
MemberExpression: 'off'
MemberExpression: "off"
jsdoc/check-alignment: error
jsdoc/check-param-names: error
jsdoc/check-tag-names: error
Expand Down Expand Up @@ -115,7 +115,7 @@ rules:
no-implicit-coercion:
- error
- allow:
- '!!'
- "!!"
no-invalid-this: error
no-iterator: error
no-label-var: error
Expand All @@ -126,7 +126,7 @@ rules:
no-new-wrappers: error
no-octal-escape: error
no-proto: error
no-prototype-builtins: 'off'
no-prototype-builtins: "off"
no-restricted-globals: [error, window]
no-restricted-properties:
- error
Expand Down Expand Up @@ -265,3 +265,4 @@ globals:
clearInterval: readonly
parserOptions:
ecmaVersion: 2022
sourceType: module
227 changes: 80 additions & 147 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,169 +20,118 @@

'use strict';

const {Gio, GLib, GObject} = imports.gi;
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Main = imports.ui.main;
const QuickSettings = imports.ui.quickSettings;

const _ = ExtensionUtils.gettext;
import {Extension, gettext as _} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as QuickSettings from 'resource:///org/gnome/shell/ui/quickSettings.js';

// This is the live instance of the Quick Settings menu
const QuickSettingsMenu = imports.ui.main.panel.statusArea.quickSettings;

const KMonadToggle = GObject.registerClass(
class FeatureToggle extends QuickSettings.QuickToggle {
_init() {
super._init({
title: _('KMonad'),
gicon: getIcon(),
toggleMode: true,
});

// NOTE: In GNOME 44, the `label` property must be set after
// construction. The newer `title` property can be set at construction.
this.label = _('KMonad');

this._settings = ExtensionUtils.getSettings();
class FeatureToggle extends QuickSettings.QuickToggle {
_init(extensionObject, icon) {
super._init({
title: _('KMonad'),
gicon: icon,
toggleMode: true,
});

this._settings.bind(
'kmonad-running',
this,
'checked',
Gio.SettingsBindFlags.DEFAULT
);
}
}
this._settings = extensionObject.getSettings();
this._settings.bind(
'kmonad-running',
this,
'checked',
Gio.SettingsBindFlags.DEFAULT
);
}
}
);

const KMonadIndicator = GObject.registerClass(
class FeatureIndicator extends QuickSettings.SystemIndicator {
_init() {
super._init();

// Create the icon for the indicator
this._indicator = this._addIndicator();
this._indicator.gicon = getIcon();

// Showing the indicator when the feature is enabled
this._settings = ExtensionUtils.getSettings();

this._settings.bind(
'kmonad-running',
this._indicator,
'visible',
Gio.SettingsBindFlags.DEFAULT
);

// Create the toggle and associate it with the indicator, being sure to
// destroy it along with the indicator
this.quickSettingsItems.push(new KMonadToggle());

this.connect('destroy', () => {
this.quickSettingsItems.forEach(item => item.destroy());
});

// Add the indicator to the panel and the toggle to the menu
QuickSettingsMenu._indicators.insert_child_at_index(this, 0);
addQuickSettingsItems(this.quickSettingsItems);
}
}
);

/**
* Returns the KMonad symbolic icon
*/
function getIcon() {
return Gio.icon_new_for_string(
GLib.build_filenamev([Me.path, 'icons', 'kmonad-symbolic.svg'])
);
}

/**
* Adds the items to the Quick Settings menu above the Background Apps menu
*
* @param {Array} items - The items to add
*/
function addQuickSettingsItems(items) {
// Add the items with the built-in function
QuickSettingsMenu._addItems(items);

// Ensure the tile(s) are above the background apps menu
for (const item of items) {
QuickSettingsMenu.menu._grid.set_child_below_sibling(
item,
QuickSettingsMenu._backgroundApps.quickSettingsItems[0]
class FeatureIndicator extends QuickSettings.SystemIndicator {
_init(extensionObject, icon) {
super._init();

// Create the icon for the indicator
this._indicator = this._addIndicator();
this._indicator.gicon = icon;

// Showing the indicator when the feature is enabled
this._settings = extensionObject.getSettings();
this._settings.bind(
'kmonad-running',
this._indicator,
'visible',
Gio.SettingsBindFlags.DEFAULT
);
}
}
);

class Extension {
constructor(uuid) {
this._uuid = uuid;

this._indicator = null;

this._settings = ExtensionUtils.getSettings();
this._cancellable = new Gio.Cancellable();

export default class KMonadToggleExtension extends Extension {
enable() {
this._settings = this.getSettings();
// Watch for changes to a specific setting
this._settings.connect('changed::kmonad-running', (settings, key) => {
this._handlerId = this._settings.connect('changed::kmonad-running', async (settings, key) => {
const isEnabled = settings.get_boolean(key);
if (isEnabled)
this.startKmonad();
else
if (isEnabled) {
this._cancellable = new Gio.Cancellable();
await this.startKmonad();
} else if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
});
}

/**
* This function is called when your extension is enabled, which could be
* done in GNOME Extensions, when you log in or when the screen is unlocked.
*
* This is when you should setup any UI for your extension, change existing
* widgets, connect signals or modify GNOME Shell's behaviour.
*/
enable() {
this._indicator = new KMonadIndicator(this, this.getIcon());
this._indicator.quickSettingsItems.push(new KMonadToggle(this, this.getIcon()));
Main.panel.statusArea.quickSettings.addExternalIndicator(this._indicator);

this._settings.set_boolean('kmonad-running', false);
this._indicator = new KMonadIndicator();
if (this._settings.get_boolean('autostart-kmonad'))
this._settings.set_boolean('kmonad-running', true);
}

/**
* This function is called when your extension is uninstalled, disabled in
* GNOME Extensions, when you log out or when the screen locks.
*
* Anything you created, modified or setup in enable() MUST be undone here.
* Not doing so is the most common reason extensions are rejected in review!
*/
disable() {
this._indicator.destroy();
this._indicator = null;
this._cancellable.cancel();
if (this._indicator) {
this._indicator.quickSettingsItems.forEach(item => item.destroy());
this._indicator.destroy();
this._indicator = null;
}
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
if (this._handlerId) {
this._settings.disconnect(this._handlerId);
this._handlerId = null;
}
}

/**
* Starts the kmonad process
*/
startKmonad() {
this._cancellable.cancel();
this._cancellable.reset();
async startKmonad() {
const command = GLib.shell_parse_argv(
this._settings.get_string('kmonad-command')
)[1];
execCommunicate(command, null, this._cancellable)
.catch(e => {
if (!this._cancellable.is_cancelled()) {
logError(e);
Main.notifyError(_('KMonad failed'), e.message.trim());
}
})
.then(() => {
this._settings.set_boolean('kmonad-running', false);
});
try {
await execCommunicate(command, null, this._cancellable);
} catch (e) {
if (this._cancellable?.is_cancelled() === false)
Main.notifyError(_('KMonad failed'), e.message.trim());
} finally {
this._settings.set_boolean('kmonad-running', false);
}
}

getIcon() {
return Gio.icon_new_for_string(
GLib.build_filenamev([this.path, 'icons', 'kmonad-symbolic.svg'])
);
}
}

Expand Down Expand Up @@ -238,19 +187,3 @@ function execCommunicate(argv, input = null, cancellable = null) {
});
});
}

/**
* This function is called once when your extension is loaded, not enabled. This
* is a good time to setup translations or anything else you only do once.
*
* You MUST NOT make any changes to GNOME Shell, connect any signals or add any
* MainLoop sources here.
*
* @param {ExtensionMeta} meta - An extension meta object, described below.
* @returns {object} an object with enable() and disable() methods
*/
function init(meta) {
ExtensionUtils.initTranslations();

return new Extension(meta.uuid);
}
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "KMonad Toggle",
"description": "Control KMonad directly from GNOME Shell!\n\nThis extension allows you to:\n • Autostart KMonad on login\n • Quickly check if KMonad is running from the top bar\n • Toggle KMonad on or off with a quick setting\n • Easily configure the KMonad launch command\n\nNote: This extension does not manage the KMonad installation. See the installation guide and FAQ in the KMonad repo for instructions on how to set it up. https://github.com/kmonad/kmonad",
"uuid": "kmonad-toggle@jurf.github.io",
"shell-version": ["44"],
"shell-version": ["45"],
"settings-schema": "org.gnome.shell.extensions.kmonad-toggle",
"gettext-domain": "kmonad-toggle",
"url": "https://github.com/jurf/gnome-kmonad-toggle",
Expand Down
Loading