summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545
diff options
context:
space:
mode:
authornippy <you@example.com>2026-04-18 13:49:56 +0200
committernippy <you@example.com>2026-04-18 13:49:56 +0200
commit5d94c0a7d44a2255b81815a52a7056a94a39842d (patch)
tree759bdea9645c6a62f9e1e4c001f7d81cccd120d2 /raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545
parente79cdf210b267f21a186255ce1a4d50029439d54 (diff)
downloadRaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.tar.gz
RaveOS-PKGBUILD-5d94c0a7d44a2255b81815a52a7056a94a39842d.zip
update Raveos themes
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545')
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/42_custom_reboot11
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/bootloader.js36
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/efibootmgr.js101
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/extension.js170
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/grub.js205
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/metadata.json17
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/prefs.js101
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/gschemas.compiledbin0 -> 413 bytes
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/org.gnome.extensions.customreboot.gschema.xml15
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/systemdBoot.js121
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/utils.js89
11 files changed, 866 insertions, 0 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/42_custom_reboot b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/42_custom_reboot
new file mode 100644
index 0000000..638d768
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/42_custom_reboot
@@ -0,0 +1,11 @@
+#! /bin/sh
+# This script allows the extension to skip grub's timeout when rebooting
+
+set -e
+
+cat << EOF
+if [ ! -z "\${boot_once}" ] ; then
+ set timeout_style=hidden
+ set timeout=0
+fi
+EOF \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/bootloader.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/bootloader.js
new file mode 100644
index 0000000..5913d9c
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/bootloader.js
@@ -0,0 +1,36 @@
+import { EFIBootManager } from "./efibootmgr.js";
+import { SystemdBoot } from './systemdBoot.js';
+import { Grub } from './grub.js';
+
+export const BootLoaders = {
+ EFI: "EFI Boot Manager",
+ GRUB: "Grub",
+ SYSD: "Systemd Boot",
+ UNKNOWN: "Unknown Boot Loader"
+}
+
+export class Bootloader {
+ /**
+ * Gets the first available boot loader type on the current system
+ * @returns BootLoaders type. Can be "EFI", "SYSD", "GRUB", or "UNKNOWN"
+ */
+ static async GetUseableType(extension) {
+ const settings = extension.getSettings('org.gnome.shell.extensions.customreboot');
+
+ if (await EFIBootManager.IsUseable() && settings.get_boolean('use-efibootmgr')) return BootLoaders.EFI;
+ if (await Grub.IsUseable() && settings.get_boolean('use-grub')) return BootLoaders.GRUB;
+ if (await SystemdBoot.IsUseable() && settings.get_boolean('use-systemd-boot')) return BootLoaders.SYSD;
+ return BootLoaders.UNKNOWN;
+ }
+
+ /**
+ * Gets a instance of the provided boot loader
+ * @returns A boot loader if one is found otherwise undefined
+ */
+ static async GetUseable(type) {
+ if (type === BootLoaders.EFI) return EFIBootManager;
+ if (type === BootLoaders.SYSD) return SystemdBoot;
+ if (type === BootLoaders.GRUB) return Grub;
+ return undefined;
+ }
+} \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/efibootmgr.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/efibootmgr.js
new file mode 100644
index 0000000..f34cec0
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/efibootmgr.js
@@ -0,0 +1,101 @@
+import Gio from "gi://Gio";
+import { ExecCommand, Log, LogWarning } from './utils.js';
+
+/**
+ * Represents efibootmgr
+ */
+export class EFIBootManager {
+ /**
+ * Get's all available boot options
+ * @returns {[Map, string]} Map(title, id), defaultOption
+ */
+ static async GetBootOptions() {
+ const [status, stdout, stderr] = await ExecCommand(['efibootmgr'],);
+ const lines = stdout.split("\n");
+
+ let boot_first = "0000";
+
+ const boot_options = new Map();
+
+ for (let l = 0; l < lines.length; l++) {
+ const line = lines[l];
+ if (line.startsWith("BootOrder:")) {
+ boot_first = line.split(" ")[1].split(",")[0];
+ continue;
+ }
+
+ const regex = /(Boot[0-9]{4})/;
+ const vLine = regex.exec(line)
+ if (vLine && vLine.length) {
+ const option = line.replace("Boot", "").split("*");
+ const title = option[1];
+ if (title.includes("HD") || title.includes("RC")) {
+ const trimed_title = title.replace(/(?<=[\S\s]*)(HD|RC)([\s\S()]*|$)/, "").trim();
+ boot_options.set(trimed_title, option[0].trim());
+ }
+ else {
+ boot_options.set(option[1].trim(), option[0].trim());
+ }
+ }
+ }
+
+ return [boot_options, boot_first];
+ }
+
+ /**
+ * Set's the next boot option
+ * @param {string} id
+ * @returns True if the boot option was set, otherwise false
+ */
+ static async SetBootOption(id) {
+ if (!this.IsUseable()) return false;
+ const [status, stdout, stderr] = await ExecCommand(['/usr/bin/pkexec', 'efibootmgr', '-n', id],);
+ if (status === 0) {
+ Log(`Set boot option to ${id}`);
+ return true;
+ }
+ LogWarning("Unable to set boot option using efibootmgr");
+ return false;
+ }
+
+ /**
+ * Can we use this bootloader?
+ * @returns True if useable otherwise false
+ */
+ static async IsUseable() {
+ return await this.GetBinary() !== "";
+ }
+
+ /**
+ * Get's efibootmgr binary path
+ * @returns A string containing the location of the binary, if none is found returns a blank string
+ */
+ static async GetBinary() {
+ let paths = ["/usr/bin/efibootmgr", "/usr/sbin/efibootmgr"];
+
+ let file;
+
+ for (let i = 0; i < paths.length; i++) {
+ file = Gio.file_new_for_path(paths[i]);
+ if (file.query_exists(null)) {
+ return paths[i];
+ }
+ }
+
+ return "";
+ }
+
+ /**
+ * This boot loader cannot be quick rebooted
+ */
+ static async CanQuickReboot() {
+ return false;
+ }
+
+ /**
+ * This boot loader cannot be quick rebooted
+ */
+ static async QuickRebootEnabled() {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/extension.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/extension.js
new file mode 100644
index 0000000..035e019
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/extension.js
@@ -0,0 +1,170 @@
+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;
+ }
+}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/grub.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/grub.js
new file mode 100644
index 0000000..6d67ff0
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/grub.js
@@ -0,0 +1,205 @@
+import Gio from "gi://Gio";
+import { ExecCommand, Log, LogWarning } from './utils.js';
+
+/**
+ * Represents grub
+ */
+export class Grub {
+ /**
+ * Get's all available boot options
+ * @returns {[Map, string]} Map(title, id), defaultOption
+ */
+ static async GetBootOptions() {
+ try {
+ let cfgpath = await this.GetConfig();
+ if (cfgpath == "") {
+ throw new String("Failed to find grub config");
+ }
+
+ let bootOptions = new Map();
+
+ let defualtEn = "";
+
+ let file = Gio.file_new_for_path(cfgpath);
+ let [suc, content] = file.load_contents(null);
+ if (!suc) {
+ throw new String("Failed to load grub config");
+ }
+
+ let lines;
+ if (content instanceof Uint8Array) {
+ lines = new TextDecoder().decode(content);
+ }
+ else {
+ lines = content.toString();
+ }
+
+ let entryRx = /^menuentry ['"]([^'"]+)/;
+ let defaultRx = /(?<=set default=\")([A-Za-z- ()/0-9]*)(?=\")/
+ lines.split('\n').forEach(l => {
+ let res = entryRx.exec(l);
+ if (res && res.length) {
+ bootOptions.set(res[1], res[1]);
+ }
+ let def = defaultRx.exec(l);
+ if (def && def.length) {
+ defualtEn = def[0];
+ }
+ });
+
+ bootOptions.forEach((v, k) => {
+ Log(`${k} = ${v}`);
+ });
+
+ if (defualtEn == "") defualtEn = bootOptions.keys().next().value;
+
+ return [bootOptions, defualtEn];
+
+ } catch (e) {
+ LogWarning(e);
+ return undefined;
+ }
+ }
+
+ /**
+ * Set's the next boot option
+ * @param {string} id
+ * @returns True if the boot option was set, otherwise false
+ */
+ static async SetBootOption(id) {
+ try {
+ let [status, stdout, stderr] = await ExecCommand(
+ ['/usr/bin/pkexec', '/usr/sbin/grub-reboot', id],
+ );
+ Log(`Set boot option to ${id}: ${status}\n${stdout}\n${stderr}`);
+ return true;
+ } catch (e) {
+ LogWarning(e);
+ return false;
+ }
+ }
+
+ /**
+ * Can we use this bootloader?
+ * @returns True if useable otherwise false
+ */
+ static async IsUseable() {
+ return await this.GetConfig() !== "";
+ }
+
+ /**
+ * Get's grub config file
+ * @returns A string containing the location of the config file, if none is found returns a blank string
+ */
+ static async GetConfig() {
+ let paths = ["/boot/grub/grub.cfg", "/boot/grub2/grub.cfg"];
+
+ let file;
+
+ for (let i = 0; i < paths.length; i++) {
+ file = Gio.file_new_for_path(paths[i]);
+ if (file.query_exists(null)) {
+ return paths[i];
+ }
+ }
+
+ return "";
+ }
+
+ /**
+ * Copies a custom grub script to allow the extension to quickly reboot into another OS
+ * If anyone reads this: Idk how to combine these into one pkexec call, if you do please leave a commit fixing it
+ */
+ static async EnableQuickReboot(ext) {
+ try {
+ let [status, stdout, stderr] = await ExecCommand([
+ 'pkexec',
+ 'sh',
+ '-c',
+ `/usr/bin/cp ${ext.lookupByUUID('customreboot@nova1545').path()}/42_custom_reboot /etc/grub.d/42_custom_reboot && /usr/bin/chmod 755 /etc/grub.d/42_custom_reboot && /usr/sbin/update-grub`
+ ]);
+
+ if (status !== 0) {
+ return false;
+ }
+
+ return true;
+ }
+ catch (e) {
+ LogWarning(e);
+ return false;
+ }
+ }
+
+
+ /**
+ * Removes the script used to allow the extension to quickly reboot into another OS without waiting for grub's timeout
+ * If anyone reads this: Idk how to combine these into one pkexec call, if you do please leave a commit fixing it
+ */
+ static async DisableQuickReboot() {
+ try {
+
+ let [status, stdout, stderr] = await ExecCommand([
+ 'pkexec',
+ 'sh',
+ '-c',
+ '/usr/bin/rm /etc/grub.d/42_custom_reboot && /usr/sbin/update-grub'
+ ]);
+
+ if (status !== 0) {
+ return false;
+ }
+
+ return true;
+ }
+ catch (e) {
+ LogWarning(e);
+ return false;
+ }
+ }
+
+
+ /**
+ * This boot loader can be quick rebooted
+ */
+ static async CanQuickReboot() {
+ return true;
+ }
+
+ /**
+ * Checks if /etc/grub.d/42_custom_reboot exists
+ */
+ static async QuickRebootEnabled() {
+ try {
+ let [status, stdout, stderr] = await ExecCommand(['/usr/bin/cat', '/etc/grub.d/42_custom_reboot'],);
+ if (status !== 0) {
+ LogWarning(`/etc/grub.d/42_custom_reboot not found`);
+ return false;
+ }
+ Log(`/etc/grub.d/42_custom_reboot found`);
+
+ return true;
+ }
+ catch (e) {
+ LogWarning(e);
+ return false;
+ }
+ }
+
+ static async SetReadable() {
+ try {
+ const config = GetConfig();
+ let [status, stdout, stderr] = await ExecCommand(['/usr/bin/pkexec', '/usr/bin/chmod', '644', config],);
+ if (status !== 0) {
+ Log(`Failed to make ${config} readable`);
+ return false;
+ }
+ Log(`Made ${config} readable`);
+ return true;
+ }
+ catch (e) {
+ Log(e);
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/metadata.json b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/metadata.json
new file mode 100644
index 0000000..8cea11c
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/metadata.json
@@ -0,0 +1,17 @@
+{
+ "_generated": "Generated by SweetTooth, do not edit",
+ "description": "Reboot into another OS directly from GNOME.\nA expansion of https://github.com/docquantum/gnome-shell-extension-customreboot",
+ "name": "Custom Reboot",
+ "original-author": "Nova1545",
+ "shell-version": [
+ "45",
+ "46",
+ "47",
+ "48",
+ "49",
+ "50"
+ ],
+ "url": "https://github.com/Nova1545/gnome-shell-extension-customreboot",
+ "uuid": "customreboot@nova1545",
+ "version": 11
+}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/prefs.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/prefs.js
new file mode 100644
index 0000000..f93539a
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/prefs.js
@@ -0,0 +1,101 @@
+'use strict';
+
+import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
+
+
+import Gio from "gi://Gio";
+import Adw from "gi://Adw";
+import Gtk from "gi://Gtk";
+import { EFIBootManager } from './efibootmgr.js';
+import { Grub } from './grub.js';
+import { SystemdBoot } from './systemdBoot.js';
+
+export default class MyExtensionPreferences extends ExtensionPreferences {
+ fillPreferencesWindow(window) {
+ const settings = this.getSettings('org.gnome.shell.extensions.customreboot');
+
+ // Create a preferences page and group
+ const page = new Adw.PreferencesPage();
+ const group = new Adw.PreferencesGroup();
+ page.add(group);
+
+ // Create row for efibootmgr
+ const efi = new Adw.ActionRow({ title: 'Use EFI Boot Manager (efibootmgr)' });
+
+ // Create row for grub
+ const grub = new Adw.ActionRow({ title: 'Use Grub'});
+
+ // Create row for systemd-boot
+ const sysd = new Adw.ActionRow({ title: 'Use Systemd Boot'});
+
+ // Add rows
+ group.add(efi);
+ group.add(grub);
+ group.add(sysd);
+
+ // Create switch for efibootmgr
+ const efi_switch = new Gtk.Switch({
+ active: settings.get_boolean('use-efibootmgr'),
+ valign: Gtk.Align.CENTER,
+ });
+
+ // Create switch for grub
+ const grub_switch = new Gtk.Switch({
+ active: settings.get_boolean('use-grub'),
+ valign: Gtk.Align.CENTER,
+ });
+
+ // Create switch for systemd-boot
+ const sysd_switch = new Gtk.Switch({
+ active: settings.get_boolean('use-systemd-boot'),
+ valign: Gtk.Align.CENTER,
+ });
+
+ // Bind settings for efibootmgr
+ settings.bind(
+ 'use-efibootmgr',
+ efi_switch,
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT
+ );
+
+ // Bind settings for grub
+ settings.bind(
+ 'use-grub',
+ grub_switch,
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT
+ );
+
+ // Bind settings for systemd-boot
+ settings.bind(
+ 'use-systemd-boot',
+ sysd_switch,
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT
+ );
+
+ // Add the switch for efibootmgr
+ efi.add_suffix(efi_switch);
+ efi.activatable_widget = efi_switch;
+
+ // Add the switch for grub
+ grub.add_suffix(grub_switch);
+ grub.activatable_widget = grub_switch;
+
+ // Add the switch for systemd-boot
+ sysd.add_suffix(sysd_switch);
+ sysd.activatable_widget = sysd_switch;
+
+ // Add our page to the window
+ window.add(page);
+
+ (async () => {
+ // Disable/enable switches in accordance to them being usable
+
+ efi_switch.set_sensitive(await EFIBootManager.IsUseable());
+ grub_switch.set_sensitive(await Grub.IsUseable());
+ sysd_switch.set_sensitive(await SystemdBoot.IsUseable());
+ })();
+ }
+} \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/gschemas.compiled b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/gschemas.compiled
new file mode 100644
index 0000000..cdce7f0
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/gschemas.compiled
Binary files differ
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/org.gnome.extensions.customreboot.gschema.xml b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/org.gnome.extensions.customreboot.gschema.xml
new file mode 100644
index 0000000..f56ca42
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/schemas/org.gnome.extensions.customreboot.gschema.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+ <schema id="org.gnome.shell.extensions.customreboot" path="/org/gnome/shell/extensions/customreboot/">
+ <!-- See also: https://docs.gtk.org/glib/gvariant-format-strings.html -->
+ <key name="use-efibootmgr" type="b">
+ <default>true</default>
+ </key>
+ <key name="use-grub" type="b">
+ <default>false</default>
+ </key>
+ <key name="use-systemd-boot" type="b">
+ <default>false</default>
+ </key>
+ </schema>
+</schemalist> \ No newline at end of file
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/systemdBoot.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/systemdBoot.js
new file mode 100644
index 0000000..51d4e6e
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/systemdBoot.js
@@ -0,0 +1,121 @@
+import Gio from "gi://Gio";
+import { ExecCommand, Log, LogWarning } from './utils.js';
+
+/**
+ * Represents Systemdboot
+ */
+export class SystemdBoot {
+ /**
+ * Get's all available boot options
+ * @returns {[Map, string]} Map(title, id), defaultOption
+ */
+ static async GetBootOptions() {
+ let bootctl = await this.GetBinary();
+ if (bootctl == "") {
+ Log(`Failed to find bootctl binary`);
+ return undefined;
+ }
+
+ try {
+ let [status, stdout, stderr] = await ExecCommand([bootctl, "list"]);
+ if (status !== 0)
+ throw new Error(`Failed to get list from bootctl: ${status}\n${stdout}\n${stderr}`);
+ Log(`bootctl list: ${status}\n${stdout}\n${stderr}`);
+ let lines = String(stdout).split('\n');
+ let titleRx = /(?<=title:\s+).+/;
+ let idRx = /(?<=id:\s+).+/;
+ let defaultRx = /\(default\)/;
+ let titles = [];
+ let ids = []
+ let defaultOpt;
+ lines.forEach(l => {
+ let title = titleRx.exec(l);
+ let id = idRx.exec(l);
+ if (title && title.length) {
+ titles.push(String(title));
+ } else if (id && id.length) {
+ ids.push(String(id));
+ }
+ });
+ if (titles.length !== ids.length)
+ throw new Error("Number of titles and ids do not match!");
+ let bootOptions = new Map();
+ for (let i = 0; i < titles.length; i++) {
+ bootOptions.set(titles[i], ids[i])
+ }
+
+ bootOptions.forEach((id, title) => {
+ Log(`${id} = ${title}`);
+
+ let defaultRes = defaultRx.exec(title);
+
+ if (defaultRes) {
+ defaultOpt = title;
+ }
+ })
+
+ return [bootOptions, bootOptions.get(defaultOpt)];
+ } catch (e) {
+ LogWarning(e);
+ return undefined;
+ }
+ }
+
+ /**
+ * Set's the next boot option
+ * @param {string} id
+ * @returns True if the boot option was set, otherwise false
+ */
+ static async SetBootOption(id) {
+ if (!this.IsUseable()) return false;
+ const [status, stdout, stderr] = await ExecCommand(['/usr/bin/pkexec', '/usr/bin/bootctl', 'set-oneshot', id],);
+ if (status === 0) {
+ Log(`Set boot option to ${id}`);
+ return true;
+ }
+ LogWarning("Unable to set boot option using bootctl");
+ return false;
+ }
+
+
+ /**
+ * Can we use this bootloader?
+ * @returns True if useable otherwise false
+ */
+ static async IsUseable() {
+ return await this.GetBinary() !== "";
+ }
+
+ /**
+ * Get's bootctl binary path
+ * @returns A string containing the location of the binary, if none is found returns a blank string
+ */
+ static async GetBinary() {
+ let paths = ["/usr/sbin/bootctl", "/usr/bin/bootctl"];
+
+ let file;
+
+ for (let i = 0; i < paths.length; i++) {
+ file = Gio.file_new_for_path(paths[i]);
+ if (file.query_exists(null)) {
+ return paths[i];
+ }
+ }
+
+ return "";
+ }
+
+ /**
+ * This boot loader cannot be quick rebooted
+ */
+ static async CanQuickReboot() {
+ return false;
+ }
+
+ /**
+ * This boot loader cannot be quick rebooted
+ */
+ static async QuickRebootEnabled() {
+ return false;
+ }
+}
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/utils.js b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/utils.js
new file mode 100644
index 0000000..1c7514a
--- /dev/null
+++ b/raveos-theme/gnome/theme-data/extensions/installed/customreboot@nova1545/utils.js
@@ -0,0 +1,89 @@
+/* utils.js
+ *
+ * Copyright (C) 2020
+ * Daniel Shchur (DocQuantum) <shchurgood@gmail.com>
+ *
+ * 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 3 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-3.0-or-later
+*/
+
+import Gio from "gi://Gio";
+
+
+var DEBUG = false;
+
+/**
+ * @param {String[]} argv
+ * @param {String} input
+ * @param {Gio.Cancellable} cancellable
+ * @returns {Promise} Function execution
+ * => @returns {[int, String, String]} [StatusCode, STDOUT, STDERR]
+ *
+ * Executes a command asynchronously.
+ */
+export async function ExecCommand(argv, input = null, cancellable = null) {
+ let flags = Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE;
+
+ if (input !== null)
+ flags |= Gio.SubprocessFlags.STDIN_PIPE;
+
+ let proc = new Gio.Subprocess({
+ argv: argv,
+ flags: flags
+ });
+ proc.init(cancellable);
+ return new Promise((resolve,reject) => {
+ proc.communicate_utf8_async(input, cancellable, (proc, res) => {
+ try {
+ resolve([(function() {
+ if(!proc.get_if_exited())
+ throw new Error("Subprocess failed to exit in time!");
+ return proc.get_exit_status()
+ })()].concat(proc.communicate_utf8_finish(res).slice(1)));
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+}
+
+/**
+ * @param {bool} value
+ *
+ * Set's whether to debug or to not.
+ */
+export function SetDebug(value){
+ DEBUG = value;
+}
+
+/**
+ * @param {string} msg
+ *
+ * Logs general messages if debug is set to true.
+ */
+export function Log(msg) {
+ if(DEBUG)
+ console.log(`CustomReboot NOTE: ${msg}`);
+}
+
+/**
+ * @param {string} msg
+ *
+ * Logs warning messages if debug is set to true.
+ */
+export function LogWarning(msg) {
+ if(DEBUG)
+ console.warn(`CustomReboot WARN: ${msg}`);
+} \ No newline at end of file