summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz
RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js')
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js941
1 files changed, 0 insertions, 941 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js b/raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js
deleted file mode 100644
index 8476964..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/burn-my-windows@schneegans.github.com/prefs.js
+++ /dev/null
@@ -1,941 +0,0 @@
-//////////////////////////////////////////////////////////////////////////////////////////
-// ) ( //
-// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
-// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
-// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
-// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
-// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
-// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
-// |__/ //
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// SPDX-FileCopyrightText: Simon Schneegans <code@simonschneegans.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-'use strict';
-
-import Gio from 'gi://Gio';
-import Gtk from 'gi://Gtk';
-import GLib from 'gi://GLib';
-import Gdk from 'gi://Gdk';
-import Adw from 'gi://Adw';
-
-import * as utils from './src/utils.js';
-import {ProfileManager} from './src/ProfileManager.js';
-
-import Apparition from './src/effects/Apparition.js';
-import AuraGlow from './src/effects/AuraGlow.js';
-import BrokenGlass from './src/effects/BrokenGlass.js';
-import Doom from './src/effects/Doom.js';
-import EnergizeA from './src/effects/EnergizeA.js';
-import EnergizeB from './src/effects/EnergizeB.js';
-import Fire from './src/effects/Fire.js';
-import Focus from './src/effects/Focus.js';
-import Glide from './src/effects/Glide.js';
-import Glitch from './src/effects/Glitch.js';
-import Hexagon from './src/effects/Hexagon.js';
-import Incinerate from './src/effects/Incinerate.js';
-import Matrix from './src/effects/Matrix.js';
-import Mushroom from './src/effects/Mushroom.js';
-import PaintBrush from './src/effects/PaintBrush.js';
-import Pixelate from './src/effects/Pixelate.js';
-import PixelWheel from './src/effects/PixelWheel.js';
-import PixelWipe from './src/effects/PixelWipe.js';
-import Portal from './src/effects/Portal.js';
-import RGBWarp from './src/effects/RGBWarp.js';
-import SnapOfDisintegration from './src/effects/SnapOfDisintegration.js';
-import TeamRocket from './src/effects/TeamRocket.js';
-import TRexAttack from './src/effects/TRexAttack.js';
-import TVEffect from './src/effects/TVEffect.js';
-import TVGlitch from './src/effects/TVGlitch.js';
-import Wisps from './src/effects/Wisps.js';
-
-
-import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
-
-// Currently, the extension supports only one set of UI files. In the past, there were
-// three different sets for GTK3, GTK4, and Adwaita. This method returns the name of the
-// current UI directory. It's still here since it might be useful in the future.
-function getUIDir() {
- return 'adw';
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// The preferences dialog is organized in pages, each of which is loaded from a //
-// separate ui file. There's one page with general options, all other paged are loaded //
-// from the respective effects. //
-//////////////////////////////////////////////////////////////////////////////////////////
-
-export default class BurnMyWindowsPreferences extends ExtensionPreferences {
-
- // ------------------------------------------------------------ constructor / destructor
-
- fillPreferencesWindow(window) {
- window.set_default_size(650, 750);
-
- // New effects must be registered here and in extension.js.
- this._ALL_EFFECTS = [
- Apparition, AuraGlow, BrokenGlass,
- Doom, EnergizeA, EnergizeB,
- Fire, Focus, Glide,
- Glitch, Hexagon, Incinerate,
- Matrix, Mushroom, PaintBrush,
- Pixelate, PixelWheel, PixelWipe,
- Portal, RGBWarp, SnapOfDisintegration,
- TeamRocket, TRexAttack, TVEffect,
- TVGlitch, Wisps,
- ];
-
-
- // Load all of our resources.
- this._resources =
- Gio.Resource.load(this.path + '/resources/burn-my-windows.gresource');
- Gio.resources_register(this._resources);
-
- // Make sure custom icons are found.
- Gtk.IconTheme.get_for_display(Gdk.Display.get_default()).add_resource_path('/img');
-
- // Load the general user interface files.
- this._builder = new Gtk.Builder();
- this._builder.add_from_resource(`/ui/common/menus.ui`);
- this._builder.add_from_resource(`/ui/${getUIDir()}/prefs.ui`);
-
-
- // Store a reference to the general settings object.
- this._settings = this.getSettings();
-
- // This tracks all available effect profiles.
- this._profileManager = new ProfileManager(this.metadata);
-
- // This is used to track all connections to properties of the current effect profile.
- // Whenever the current effect profile changes, all connections are disconnected.
- this._profileConnections = [];
-
- // Load the current effect profile. If there is none, we create a default profile.
- this._settings.connect('changed::active-profile', () => {
- this._loadActiveProfile();
- });
-
- // Check whether the power profiles daemon is available - if not, we hide the
- // corresponding settings row.
- let hasPowerProfiles = false;
- try {
- const PowerProfilesProxy = Gio.DBusProxy.makeProxyWrapper(
- utils.getStringResource('/interfaces/net.hadess.PowerProfiles.xml'));
- let powerProfilesProxy = new PowerProfilesProxy(
- Gio.DBus.system, 'net.hadess.PowerProfiles', '/net/hadess/PowerProfiles');
-
- hasPowerProfiles = powerProfilesProxy.get_name_owner() != null;
- } catch (e) {
- // Maybe the service is masked...
- }
-
-
- let powerProfileRow = this._builder.get_object('profile-power-profile');
- powerProfileRow.set_visible(hasPowerProfiles);
-
- // Wire up the window picker of the profile editor. Whenever the app-chooser button is
- // clicked, we call a method of the extension which will initiate the window picking.
- this._builder.get_object('profile-choose-app-button').connect('clicked', () => {
- Gio.DBus.session.call('org.gnome.Shell',
- '/org/gnome/shell/extensions/BurnMyWindows',
- 'org.gnome.shell.extensions.BurnMyWindows', 'PickWindow',
- null, null, Gio.DBusCallFlags.NO_AUTO_START, -1, null, null);
- });
-
- // If the window picking was successful, this D-Bus signal will be emitted. If a
- // window was picked, we add it to the list of window name.
- this._dbusConnection = Gio.DBus.session.signal_subscribe(
- 'org.gnome.Shell', 'org.gnome.shell.extensions.BurnMyWindows', 'WindowPicked',
- '/org/gnome/shell/extensions/BurnMyWindows', null, Gio.DBusSignalFlags.NONE,
- (conn, sender, obj_path, iface, signal, params) => {
- const val = params.get_child_value(0).get_string()[0];
- if (val != 'window-not-found') {
- const entry = this._builder.get_object('profile-app');
-
- // Split the current value at each |, trim spaces, and remove empty components.
- let apps = entry.text.split('|').map(item => item.trim()).filter(v => v != '');
-
- // If the list is empty, we simply use the name of the picked window.
- if (apps.length == 0) {
- entry.text = val;
- } else {
-
- // Else we append the new application name, remove any duplicates, and sort
- // the resulting list alphabetically.
- apps.push(val);
- apps = [...new Set(apps)].sort();
- entry.text = apps.join(' | ');
- }
- }
- });
-
-
- // This is our top-level widget which we will return later.
- this._widget = this._builder.get_object('general-prefs');
-
- // Add the functionality to the choose-all and choose-none buttons.
- this._builder.get_object('choose-all-effects-button').connect('clicked', () => {
- this._ALL_EFFECTS.forEach(effect => {
- this.getProfileSettings().set_boolean(`${effect.getNick()}-enable-effect`, true);
- });
- });
-
- this._builder.get_object('choose-no-effects-button').connect('clicked', () => {
- this._ALL_EFFECTS.forEach(effect => {
- this.getProfileSettings().set_boolean(`${effect.getNick()}-enable-effect`, false);
- });
- });
-
- // search for effect feature
- this._searchEntry = this._builder.get_object('search_entry');
- this._searchEntry.connect('search-changed', () => {
- const query = this._searchEntry.get_text().toLowerCase();
-
- // If only one effect is left, we will expand it automatically.
- let lastRow = null;
- let numRows = 0;
-
- this._effectRows.forEach(row => {
- row.set_expanded(false);
-
- if (query === '') {
- row.show(); // Show all effects if query is empty
- } else {
- // Show or hide each effect based on query match
- const showEffect = row.name.toLowerCase().includes(query);
-
- if (showEffect) {
- row.show();
- lastRow = row;
- numRows++;
- } else {
- row.hide();
- }
- }
- });
-
- // If only one effect is left, we expand it automatically.
- if (numRows === 1) {
- lastRow.set_expanded(true);
- }
- });
-
- // Then add a preferences group for the effect expander rows.
- const group = this._builder.get_object('effects-group');
-
- // This stores all expander rows for the effects. We use this to implement the
- // accordion-like behavior of the effect settings.
- this._effectRows = [];
-
- // Now add all the rows.
- this._ALL_EFFECTS.forEach(effect => {
- const [minMajor, minMinor] = effect.getMinShellVersion();
- if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
-
- const uiFile = `/ui/${getUIDir()}/${effect.getNick()}.ui`;
-
- // Is there a better way to test for the existence of a resource file?
- let hasPrefs = false;
- try {
- Gio.resources_get_info(uiFile, 0);
- hasPrefs = true;
- } catch (e) {
- // Nothing todo, there
- }
-
- // Add the settings page to the builder.
- if (hasPrefs) {
- this._builder.add_from_resource(uiFile);
- }
-
- // The preview button.
- let previewButton = Gtk.Button.new_from_icon_name('bmw-preview-symbolic');
- previewButton.get_style_context().add_class('circular');
- previewButton.get_style_context().add_class('flat');
- previewButton.set_tooltip_text(_('Preview this effect'));
- previewButton.set_valign(Gtk.Align.CENTER);
- previewButton.connect('clicked', () => {
- this._previewEffect(effect);
- });
-
- // The toggle button for enabling and disabling the effect.
- const button = Gtk.Switch.new();
- button.set_valign(Gtk.Align.CENTER);
- this._builder.expose_object(`${effect.getNick()}-enable-effect`, button);
-
- let row;
- if (hasPrefs) {
-
- // Add the effect's preferences (if any).
- row = this._builder.get_object(`${effect.getNick()}-prefs`);
- } else {
- row = Adw.ActionRow.new();
- }
-
- // On older versions of Adw (e.g. on GNOME Shell <43), the set_use_markup() does
- // not yet exist.
- if (row.set_use_markup) {
- row.set_title('<b>' + effect.getLabel() + '</b>');
- row.set_use_markup(true);
- } else {
- row.set_title(effect.getLabel());
- }
-
- // this is the fix for the merge issue when an effect doesn't have a discription
- row.name = effect.getLabel();
-
-
- // Un-expand any previously expanded effect row. This way we ensure that there
- // is only one expanded row at any time.
- if (hasPrefs) {
- row.connect('notify::expanded', currentRow => {
- if (currentRow.get_expanded()) {
- this._effectRows.forEach(row => {
- if (row != currentRow) {
- row.set_expanded(false);
- }
- });
- }
- });
- this._effectRows.push(row);
- row.add_action(button);
- } else {
- row.add_suffix(button);
- }
-
- row.add_prefix(previewButton);
-
- group.add(row);
- }
- });
-
-
- // Some things can only be done once the widget is shown as we do not have access to
- // the toplevel widget before.
- this._widget.connect('realize', (widget) => {
- const window = widget.get_root();
-
- // Show the version number in the title bar.
- window.set_title(`Burn-My-Windows ${this.metadata.version}`);
-
- this._loadActiveProfile();
- this._updateProfileMenu();
-
- // Show an Adw.Toast or a Gtk.InfoBar whenever Burn-My-Windows was updated. We use a
- // small timeout so that it is not shown instantaneously.
- const lastVersion = this._settings.get_int('last-prefs-version');
- if (lastVersion < this.metadata.version) {
- this._showUpdateInfoTimeout =
- GLib.timeout_add(GLib.PRIORITY_DEFAULT, 2000, () => {
- this._showUpdateInfoTimeout = 0;
-
- const toast = Adw.Toast.new(_('Burn-My-Windows has been updated!'));
- toast.set_button_label(_('View Changelog'));
- toast.set_action_name('prefs.changelog');
- toast.set_timeout(0);
-
- toast.connect(
- 'dismissed',
- () => this._settings.set_int('last-prefs-version', this.metadata.version));
-
- window.add_toast(toast);
-
- return false;
- });
- }
-
- // Count the number of times the user has opened the preferences window. Every now
- // and then, we show a dialog asking the user to support the extension. We connect
- // to the notify::visible signal to ensure that the dialog can be a modal dialog.
- window.connect('notify::visible', (window) => {
- // Do not show the dialog when the window is hidden.
- if (!window.get_visible()) {
- return;
- }
-
- // Do not show the dialog when the user has disabled it.
- if (!this._settings.get_boolean('show-support-dialog')) {
- return;
- }
-
- const count = this._settings.get_int('prefs-open-count') + 1;
- this._settings.set_int('prefs-open-count', count);
-
- // Show the dialog every 10th time.
- if (count % 10 == 0) {
- const dialog = this._createMessageDialog(
- '❤️ Do you love Burn-My-Windows?',
- `Even the smallest donation can have a big impact! If just one of ten Burn-My-Windows users donated $1 per month, I could dedicate myself to creating awesome open-source projects full-time!
-
-Ko-fi: <a href='https://ko-fi.com/schneegans'>https://ko-fi.com/schneegans</a>
-GitHub: <a href='https://github.com/sponsors/schneegans'>https://github.com/sponsors/schneegans</a>`,
- window, [
- {
- label: 'Do not show this again!',
- destructive: true,
- default: false,
- action: () => {
- this._settings.set_boolean('show-support-dialog', false);
- }
- },
- {
- label: 'Remind me later.',
- destructive: false,
- default: true,
- }
- ]);
-
- dialog.show();
- }
- });
-
- // Populate the menu with actions.
- const group = Gio.SimpleActionGroup.new();
- window.insert_action_group('prefs', group);
-
- // Add the main menu to the title bar.
- {
- // Add the menu button to the title bar.
- const menu = this._builder.get_object('menu-button');
-
- // Starting with GNOME Shell 42, we have to hack our way through the widget tree
- // of the Adw.PreferencesWindow...
- const header = this._findWidgetByType(window.get_content(), Adw.HeaderBar);
- header.pack_start(menu);
- header.set_title_widget(this._builder.get_object('profile-button'));
-
- // GNOME Shell extensions are forced to use a AdwPreferencesWindow. This already
- // includes a Gtk.ScrolledWindow as well as an Adw.Clamp. For the profile
- // editing, we want to use an Adw.Flap which reveals itself from the top. This
- // needs to be inserted in the widget hierarchy above the Adw.Clamp, else it
- // would look ugly. Therefore, we fiddle around with the internal widgets...
- const flap = this._builder.get_object('profile-editor-flap');
- const clamp = this._findWidgetByType(window.get_content(), Adw.Clamp);
- const viewport = clamp.get_parent();
- viewport.get_parent().set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
- viewport.set_child(flap);
-
- const scrolledWindow = Gtk.ScrolledWindow.new();
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- scrolledWindow.set_propagate_natural_height(true);
- scrolledWindow.set_vexpand(true);
- scrolledWindow.set_child(clamp);
-
- flap.set_content(scrolledWindow);
-
- const addURIAction = (name, uri) => {
- const action = Gio.SimpleAction.new(name, null);
- action.connect('activate', () => Gtk.show_uri(null, uri, Gdk.CURRENT_TIME));
- group.add_action(action);
- };
-
- // clang-format off
- addURIAction('homepage', 'https://github.com/Schneegans/Burn-My-Windows');
- addURIAction('bugs', 'https://github.com/Schneegans/Burn-My-Windows/issues');
- addURIAction('new-effect', 'https://github.com/Schneegans/Burn-My-Windows/blob/main/docs/how-to-create-new-effects.md');
- addURIAction('translate', 'https://hosted.weblate.org/engage/burn-my-windows/');
- addURIAction('donate-kofi', 'https://ko-fi.com/schneegans');
- addURIAction('donate-github', 'https://github.com/sponsors/Schneegans');
- addURIAction('donate-paypal', 'https://www.paypal.me/simonschneegans');
- addURIAction('donate-crypto', 'https://schneegans.cb.id');
- addURIAction('show-sponsors', 'https://schneegans.github.io/sponsors');
- addURIAction('wallpapers', 'https://github.com/Schneegans/ai-wallpapers');
- addURIAction('profile-dir', `file://${GLib.get_user_config_dir()}/burn-my-windows/profiles`);
- // clang-format on
-
- // The changelog action is a bit different, as it may get activated when the
- // view-changelog button is pressed which is shown in an Adw.Toast or a
- // Gtk.InfoBar whenever Burn-My-Windows gets updated. To ensure that the
- // notification is shown only once, we have to store the current version of
- // Burn-My-Windows in the settings.
- const changelogAction = Gio.SimpleAction.new('changelog', null);
- changelogAction.connect('activate', () => {
- Gtk.show_uri(
- null,
- 'https://github.com/Schneegans/Burn-My-Windows/blob/main/docs/changelog.md',
- Gdk.CURRENT_TIME);
- this._settings.set_int('last-prefs-version', this.metadata.version)
- });
- group.add_action(changelogAction);
-
- // Add the about dialog.
- const aboutAction = Gio.SimpleAction.new('about', null);
- aboutAction.connect('activate', () => {
- // The JSON report format from weblate is a bit weird. Here we extract all
- // unique names from the translation report.
- const translators = new Set();
- this._getJSONResource('/credits/translators.json').forEach(i => {
- for (const j of Object.values(i)) {
- j.forEach(k => translators.add(k.full_name));
- }
- });
-
- const dialog = new Adw.AboutWindow({transient_for: window, modal: true});
- dialog.set_application_icon('burn-my-windows-symbolic');
- dialog.set_application_name('Burn-My-Windows');
- dialog.set_version(`${this.metadata.version}`);
- dialog.set_developer_name('Simon Schneegans');
- dialog.set_issue_url('https://github.com/Schneegans/Burn-My-Windows/issues');
- dialog.set_translator_credits([...translators].join('\n'));
- dialog.set_copyright('© 2023 Simon Schneegans');
- dialog.set_website('https://github.com/Schneegans/Burn-My-Windows');
- dialog.set_license_type(Gtk.License.GPL_3_0);
-
- dialog.show();
- });
-
- group.add_action(aboutAction);
- }
-
- // Setup all the profile-related actions.
- {
- // Allow switching the current profile.
- const activeProfileAction = this._settings.create_action('active-profile');
- group.add_action(activeProfileAction);
-
- // This action creates a new profile and makes it the active one.
- const newProfileAction = Gio.SimpleAction.new('profile-new', null);
- newProfileAction.connect('activate', () => {
- const profile = this._profileManager.createProfile();
- this._settings.set_string('active-profile', profile.path);
-
- // Start editing the profile.
- this._builder.get_object('edit-profile-button').active = true;
-
- // The number of profiles has changed, so we have to update the profile
- // selection menu.
- this._updateProfileMenu();
- });
- group.add_action(newProfileAction);
-
- // This action shows a confirmation dialog. Upon user approval, the currently
- // active profile is deleted. We use the more beautiful Adw.MessageDialog if it is
- // available (usually on GNOME 43 and beyond).
- const deleteProfileDialog = this._createMessageDialog(
- _('Delete this Profile?'),
- _('The current effect profile with all its effect settings will be permanently lost.'),
- window, [
- {
- label: _('Cancel'),
- destructive: false,
- default: true,
- },
- {
- label: _('Delete'),
- destructive: true,
- default: false,
- action: () => {
- // Stop editing the current profile.
- this._builder.get_object('edit-profile-button').active = false;
-
- // Delete the currently active profile.
- this._profileManager.deleteProfile(this._activeProfile.path);
-
- // Select another one.
- this._settings.set_string('active-profile',
- this._profileManager.getProfiles()[0].path);
-
- // The number of profiles has changed, so we have to update the profile
- // selection menu.
- this._updateProfileMenu();
- }
- }
- ]);
-
- // This action deletes the currently active profile.
- const deleteProfileAction = Gio.SimpleAction.new('profile-delete', null);
- deleteProfileAction.connect('activate', () => {
- deleteProfileDialog.show();
- });
- group.add_action(deleteProfileAction);
- }
- });
-
- // As we do not have something like a destructor, we just listen for the destroy
- // signal of our main widget.
- this._widget.connect('destroy', () => {
- // Unregister our resources.
- Gio.resources_unregister(this._resources);
-
- // Disconnect from the window-picker API.
- Gio.DBus.session.signal_unsubscribe(this._dbusConnection);
-
- // If the settings dialog got closed too quickly, this may not have been shown.
- if (this._showUpdateInfoTimeout > 0) {
- GLib.source_remove(this._showUpdateInfoTimeout);
- }
- });
-
- window.add(this._widget);
- }
-
- // -------------------------------------------------------------------- public interface
-
- // Returns the internally used Gtk.Builder. Effects can use this to modify the UI of the
- // preferences dialog.
- getBuilder() {
- return this._builder;
- }
-
- // Returns a Gio.Settings object for the current effect profile.
- getProfileSettings() {
- return this._activeProfile.settings;
- }
-
- // Connects an Adw.ComboRow (or anything else which has an 'selected' property) to a
- // settings key. It also binds the corresponding reset button.
- bindComboRow(settingsKey) {
- this._bind(settingsKey, 'selected');
- }
-
- // Connects a Gtk.ComboBox (or anything else which has an 'active' property) to a
- // settings key. It also binds the corresponding reset button.
- bindComboBox(settingsKey) {
- this._bind(settingsKey, 'active');
- }
-
- // Connects a Gtk.Entry (or anything else which has an 'text' property) to a
- // settings key. It also binds the corresponding reset button.
- bindEntry(settingsKey) {
- this._bind(settingsKey, 'text');
- }
-
- // Connects a Gtk.Adjustment (or anything else which has a 'value' property) to a
- // settings key. It also binds the corresponding reset button.
- bindAdjustment(settingsKey) {
- this._bind(settingsKey, 'value');
- }
-
- // Connects a Gtk.Switch (or anything else which has an 'active' property) to a settings
- // key. It also binds the corresponding reset button.
- bindSwitch(settingsKey) {
- this._bind(settingsKey, 'active');
- }
-
- // Colors are stored as strings like 'rgb(1, 0.5, 0)'. As Gio.Settings.bind_with_mapping
- // is not available yet, we need to do the color conversion manually. It also binds the
- // corresponding reset button.
- bindColorButton(settingsKey) {
-
- const button = this._builder.get_object(settingsKey);
-
- if (button) {
-
- // Update the settings when the color is modified.
- if (!button._isConnected) {
- button.connect('color-set', () => {
- this.getProfileSettings().set_string(settingsKey,
- button.get_rgba().to_string());
- });
-
- button._isConnected = true;
- }
-
- // Update the button state when the settings change.
- const settingSignalHandler = () => {
- const rgba = new Gdk.RGBA();
- rgba.parse(this.getProfileSettings().get_string(settingsKey));
- button.rgba = rgba;
- };
-
- this._connectProfileSetting('changed::' + settingsKey, settingSignalHandler);
-
- // Initialize the button with the state in the settings.
- settingSignalHandler();
- }
-
- this._bindResetButton(settingsKey);
- }
-
- // ----------------------------------------------------------------------- private stuff
-
- // This loads all settings from the profile given in the settings key 'active-profile'.
- _loadActiveProfile() {
-
- // Disconnect any connection to the previously active profile.
- this._disconnectProfileSettings();
-
- // Find the active profile in the list of all profiles.
- const allProfiles = this._profileManager.getProfiles();
- const path = this._settings.get_string('active-profile');
- this._activeProfile = allProfiles.find(p => p.path == path);
-
- // If, for whatever reason, it is not found, select the first one. Setting the
- // settings key will trigger this method again.
- if (!this._activeProfile) {
- this._activeProfile = allProfiles[0];
- this._settings.set_string('active-profile', this._activeProfile.path);
- return;
- }
-
- // Connect all profile options.
- const updateProfileButtonMenuIfChanged = (settingsKey) => {
- this._connectProfileSetting('changed::' + settingsKey, () => {
- this._updateProfileButton();
- this._updateProfileMenu();
- });
- };
-
- updateProfileButtonMenuIfChanged('profile-app');
- updateProfileButtonMenuIfChanged('profile-animation-type');
- updateProfileButtonMenuIfChanged('profile-window-type');
- updateProfileButtonMenuIfChanged('profile-color-scheme');
- updateProfileButtonMenuIfChanged('profile-power-mode');
- updateProfileButtonMenuIfChanged('profile-power-profile');
- updateProfileButtonMenuIfChanged('profile-high-priority');
-
- this.bindEntry('profile-app');
- this.bindComboRow('profile-animation-type');
- this.bindComboRow('profile-window-type');
- this.bindComboRow('profile-color-scheme');
- this.bindComboRow('profile-power-mode');
- this.bindComboRow('profile-power-profile');
- this.bindSwitch('profile-high-priority');
-
- // Connect all effect settings.
- this._ALL_EFFECTS.forEach(effect => {
- const [minMajor, minMinor] = effect.getMinShellVersion();
- if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
- this.bindSwitch(`${effect.getNick()}-enable-effect`);
- effect.bindPreferences(this);
- }
- });
-
- // Update the label in the profile-select button.
- this._updateProfileButton();
- }
-
- // This updates the label of the profile-selection button according to the currently
- // active profile. It's called whenever the active profile is changed or whenever a
- // configuration option of the profile is changed.
- _updateProfileButton() {
- this._builder.get_object('choose-profile-button').label =
- this._getProfileName(this.getProfileSettings());
- }
-
- // This updates the list of available profiles in the dropdown of the profile-selection
- // button. It's called whenever one of the configuration option of the currently active
- // profile is changed, or whenever a profile is added / removed.
- _updateProfileMenu() {
-
- // First, clear the menu section.
- const profileSection = this._builder.get_object('profile-section');
- profileSection.remove_all();
-
- // Then add an entry for each available profile.
- this._profileManager.getProfiles().forEach(profile => {
- const label = this._getProfileName(profile.settings);
- const item = Gio.MenuItem.new(label, 'prefs.active-profile');
- item.set_action_and_target_value('prefs.active-profile',
- GLib.Variant.new_string(profile.path));
- profileSection.append_item(item);
- });
- }
-
- // Profiles are named according to their configuration. This method returns a localized
- // string describing the settings of the profile.
- _getProfileName(settings) {
- let items = [];
-
- // If an app is configured, use it as first component for the profile's name.
- const app = settings.get_string('profile-app');
- if (app != '') {
- items.push(app);
- }
-
- // Now add components to the name for each non-default profile option. Make sure that
- // these are the same strings as used in the UI files!
- const addComponent = (settingsKey, options) => {
- const option = settings.get_int(settingsKey);
- if (option > 0) {
- items.push(options[option - 1]);
- }
- };
-
- // clang-format off
- addComponent('profile-animation-type', [_('Opening Windows'),
- _('Closing Windows')]);
- addComponent('profile-window-type', [_('Normal Windows'),
- _('Dialog Windows')]);
- addComponent('profile-color-scheme', [_('Default Color Scheme'),
- _('Dark Color Scheme')]);
- addComponent('profile-power-mode', [_('On Battery'),
- _('Plugged In')]);
- addComponent('profile-power-profile', [_('Power-Saver Mode'),
- _('Balanced Mode'),
- _('Performance Mode'),
- _('Power Saver or Balanced'),
- _('Balanced or Performance')]);
- // clang-format on
-
- // If the profile is a high-priority profile, also add this..
- if (settings.get_boolean('profile-high-priority')) {
- items.push(_('High Priority'));
- }
-
- let name = '';
-
- if (items.length == 0) {
- name = _('Standard Profile');
- } else {
- name = items.join(' · ');
- }
-
- return name;
- }
-
- // This wrapper connects a given callback to a profile settings key. Use this instead of
- // the direct connect() call on the profile settings to make sure that the callback is
- // disconnected when the active profile changes.
- _connectProfileSetting(key, callback) {
- this._profileConnections.push(this.getProfileSettings().connect(key, callback));
- }
-
- // This is called whenever the currently edited effect profile changes. It unbinds all
- // callbacks bound with the above method before.
- _disconnectProfileSettings() {
- this._profileConnections.forEach(c => this.getProfileSettings().disconnect(c));
- this._profileConnections = [];
- }
-
- // Searches for a reset button for the given settings key and make it reset the settings
- // key when clicked.
- _bindResetButton(settingsKey) {
- const resetButton = this._builder.get_object('reset-' + settingsKey);
- if (resetButton && !resetButton._isConnected) {
- resetButton.connect('clicked', () => {
- this.getProfileSettings().reset(settingsKey);
- });
- resetButton._isConnected = true;
- }
- }
-
- // Connects any widget's property to a settings key. The widget must have the same ID as
- // the settings key. It also binds the corresponding reset button.
- _bind(settingsKey, property) {
- const object = this._builder.get_object(settingsKey);
-
- if (object) {
- // Unbind any previous binding (potentially to a previously edited profile).
- Gio.Settings.unbind(object, property);
- this.getProfileSettings().bind(settingsKey, object, property,
- Gio.SettingsBindFlags.DEFAULT);
- }
-
- this._bindResetButton(settingsKey);
- }
-
- // Reads the contents of a JSON file contained in the global resources archive. The data
- // is parsed and returned as a JavaScript object / array.
- _getJSONResource(path) {
- return JSON.parse(utils.getStringResource(path));
- }
-
- // This traverses the widget tree below the given parent recursively and returns the
- // first widget of the given type.
- _findWidgetByType(parent, type) {
- for (const child of [...parent]) {
- if (child instanceof type) return child;
-
- const match = this._findWidgetByType(child, type);
- if (match) return match;
- }
-
- return null;
- }
-
- // Opens a modal window using the given effect.
- _previewEffect(effect) {
-
- // Set the to-be-previewed effect.
- this._settings.set_string('preview-effect', effect.getNick());
-
- // Make sure that the window.show() firther below "sees" this change.
- Gio.Settings.sync();
-
- // Create the preview-window.
- const window = new Gtk.Window({
- // Translators: %s will be replaced by the effect's name.
- title: _('Preview for %s').replace('%s', effect.getLabel()),
- default_width: 800,
- default_height: 450,
- modal: true,
- transient_for: this._widget.get_root()
- });
-
- // Add a header bar to the window.
- const header = Gtk.HeaderBar.new();
- window.set_titlebar(header);
-
- const box = new Gtk.Box({
- orientation: Gtk.Orientation.VERTICAL,
- valign: Gtk.Align.CENTER,
- spacing: 10,
- margin_start: 50,
- margin_end: 50
- });
-
- const label = Gtk.Label.new(_('Close this Window to Preview the Effect!'));
- label.wrap = true;
- label.justify = Gtk.Justification.CENTER;
- label.get_style_context().add_class('large-title');
-
- const image = new Gtk.Image({
- icon_name: 'burn-my-windows-symbolic',
- pixel_size: 128,
- });
-
- box.append(image);
- box.append(label);
-
- window.set_child(box);
- window.show();
- }
-
- // Helper function to show a message dialog. The dialog is modal and has a title, a
- // message and a list of buttons. Each button is an object with a label, a default flag
- // and a destructive flag. Each button object can also have an "action" callback that is
- // called when the button is clicked.
- // This method works on GTK3, GTK4, and libadwaita.
- _createMessageDialog(title, message, window, buttons) {
- let dialog = new Adw.MessageDialog({
- heading: title,
- body: message,
- body_use_markup: true,
- modal: true,
- });
-
- buttons.forEach((button, i) => {
- const response = i.toString();
- dialog.add_response(response, button.label);
-
- if (button.default) {
- dialog.set_default_response(response);
- dialog.set_close_response(response);
- }
-
- if (button.destructive) {
- dialog.set_response_appearance(response, Adw.ResponseAppearance.DESTRUCTIVE);
- }
- });
-
- dialog.set_hide_on_close(true);
- dialog.set_transient_for(window);
-
- // If the dialog is closed or a button is clicked, we hide the dialog and call the
- // button's action callback if it exists.
- dialog.connect('response', (dialog, response) => {
- const i = parseInt(response);
-
- const button = buttons[i];
- if (button && button.action) {
- button.action();
- }
-
- dialog.hide();
- });
-
- return dialog;
- }
-}