import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; import * as QuickSettings from 'resource:///org/gnome/shell/ui/quickSettings.js'; import { Extension } from "resource:///org/gnome/shell/extensions/extension.js"; import { getDefault } from "resource:///org/gnome/shell/misc/systemActions.js"; import GObject from "gi://GObject"; //import import { LogWarning, Log } from './utils.js'; import { BootLoaders, Bootloader } from "./bootloader.js"; const RebootQuickMenu = GObject.registerClass( class RebootQuickMenu extends QuickSettings.QuickMenuToggle { _init(extension) { const init_params = { iconName: 'system-reboot-symbolic', toggleMode: false }; init_params.title = "Reboot Into"; super._init(init_params); // Set toggle to be unchecked this.checked = false; // Open menu and set toggle check to true this.clickedID = this.connect("clicked", () => { this.menu.open(); this.checked = true; }); // Connect 'menu-closed' to update checked state this.menuClosedID = this.menu.connect("menu-closed", () => { this.checked = false; }); // Add boot options to menu try { this.createBootMenu(extension); } catch (e) { LogWarning(e); } } cleanConns() { // Disconnect all connections this.disconnect(this.openStateID); this.disconnect(this.clickedID); } async createBootMenu(extension) { // Get boot options const type = await Bootloader.GetUseableType(extension); const header_title = `Boot Options - ${type}`; // Set Menu Header this.menu.setHeader('system-reboot-symbolic', header_title, 'Reboot into the selected entry'); const loader = await Bootloader.GetUseable(type); if (loader === undefined) { // Set Menu Header this.menu.setHeader('system-reboot-symbolic', 'Error', 'The selected boot loader cannot be found...'); // Add reload option, to refresh extension menu without reloading GNOME or the extension this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addAction('Reload', () => { this.menu.removeAll(); this.createBootMenu(); }); // Add button to open settings this.menu.addAction('Settings', () => { extension.openPreferences(); }); return; } loader.GetBootOptions().then(([bootOps, defaultOpt]) => { if (bootOps !== undefined) { this._itemsSection = new PopupMenu.PopupMenuSection(); for (let [title, id] of bootOps) { Log(`${title} - ${id}`); this._itemsSection.addAction(String(title), () => { // Set boot option loader.SetBootOption(String(id)).then(result => { if (result) { // On success trigger restart dialog new getDefault().activateRestart(); } }); }, (title === defaultOpt || id === defaultOpt)? "pan-end-symbolic" : undefined); } this.menu.addMenuItem(this._itemsSection); } // Add reload option, to refresh extension menu without reloading GNOME or the extension this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addAction('Reload', () => { this.menu.removeAll(); this.createBootMenu(); }); // Add button to open settings this.menu.addAction('Settings', () => { extension.openPreferences(); }); loader.CanQuickReboot().then(async result => { if (!result) return; if (!await loader.QuickRebootEnabled()) { this.menu.addAction('Enable Quick Reboot', async () => { await loader.EnableQuickReboot(extension); this.menu.removeAll(); this.createBootMenu(); }); } else { this.menu.addAction('Disable Quick Reboot', async () => { await loader.DisableQuickReboot(); this.menu.removeAll(); this.createBootMenu(); }); } }); }).catch((error) => { LogWarning(error); // Only do this if the current bootloader is grub if (type === BootLoaders.GRUB) { // Only add this if all fails, giving user option to make the config readable this.menu.addMenuItem(new PopupSeparatorMenuItem()); this.menu.addAction('Fix Grub.conf Perms', async () => { await loader.SetReadable(); this.menu.removeAll(); this.createBootMenu(extension); }); } }) } }); export default class CustomReboot extends Extension { enable() { // Add items to QuickSettingsMenu this._indicator = new QuickSettings.SystemIndicator(); this.menu = new RebootQuickMenu(this); this._indicator.quickSettingsItems.push(this.menu); Main.panel.statusArea.quickSettings.addExternalIndicator(this._indicator, 1); } disable() { this.menu.cleanConns(); this.menu = null; this._indicator.quickSettingsItems.forEach(item => { item.destroy(); }); this._indicator.destroy(); this._indicator = null; } }