linux-presets/gui/gnome/autocustom-gnome-macos/res/extensions/desktop-cube@schneegans.git.../prefs.js

208 lines
8.6 KiB
JavaScript
Executable File

//////////////////////////////////////////////////////////////////////////////////////////
// ,-. ,--. ,-. , , ,---. ,-. ;-. ,-. . . ,-. ,--. //
// | \ | ( ` | / | / \ | ) / | | | ) | //
// | | |- `-. |< | | | |-' | | | |-< |- //
// | / | . ) | \ | \ / | \ | | | ) | //
// `-' `--' `-' ' ` ' `-' ' `-' `--` `-' `--' //
//////////////////////////////////////////////////////////////////////////////////////////
// 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 Gdk from 'gi://Gdk';
import Adw from 'gi://Adw';
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js';
import {registerImageChooserButton} from './src/ImageChooserButton.js';
//////////////////////////////////////////////////////////////////////////////////////////
// For now, the preferences dialog of this extension is very simple. In the future, if //
// we might consider to improve its layout... //
//////////////////////////////////////////////////////////////////////////////////////////
export default class DesktopCubePreferences extends ExtensionPreferences {
// -------------------------------------------------------------------- public interface
// This function is called when the preferences window is created. We create a new
// instance of the PreferencesDialog class each time this method is called. This way we
// can actually open multiple settings windows and interact with all of them properly.
fillPreferencesWindow(window) {
// Load all of our resources.
this._resources = Gio.Resource.load(this.path + '/resources/desktop-cube.gresource');
Gio.resources_register(this._resources);
// Register our custom widgets.
registerImageChooserButton();
// Load the user interface file.
this._builder = new Gtk.Builder();
this._builder.add_from_resource(`/ui/settings.ui`);
// Make sure custom icons are found.
Gtk.IconTheme.get_for_display(Gdk.Display.get_default()).add_resource_path('/img');
// These are our top-level preferences pages which we will return later.
this._pages = [
this._builder.get_object('general-page'), this._builder.get_object('desktop-page'),
this._builder.get_object('overview-page')
];
// Store a reference to the settings object.
this._settings = this.getSettings();
// Bind all properties.
this._bindAdjustment('workpace-separation');
this._bindAdjustment('horizontal-stretch');
this._bindAdjustment('window-parallax');
this._bindImageChooserButton('background-panorama');
this._bindSwitch('last-first-gap');
this._bindSwitch('enable-desktop-dragging');
this._bindSwitch('enable-panel-dragging');
this._bindSwitch('enable-desktop-edge-switch');
this._bindSwitch('enable-overview-edge-switch');
this._bindSwitch('enable-overview-dragging');
this._bindSwitch('do-explode');
this._bindSwitch('per-monitor-perspective');
this._bindAdjustment('active-workpace-opacity');
this._bindAdjustment('inactive-workpace-opacity');
this._bindAdjustment('edge-switch-pressure');
this._bindAdjustment('mouse-rotation-speed');
// Inject the video link.
const label = this._builder.get_object('central-perspective-row');
label.subtitle = label.subtitle.replace(
'%s', '<a href="https://youtu.be/dpYyn1BXGjU">https://youtu.be/dpYyn1BXGjU</a>');
// Add a menu to the title bar of the preferences dialog.
this._pages[0].connect('realize', (widget) => {
const window = widget.get_root();
// Add the menu to the header bar.
const menu = this._builder.get_object('menu-button');
const header = this._findWidgetByType(window.get_content(), Adw.HeaderBar);
header.pack_start(menu);
// Populate the actions.
const group = Gio.SimpleActionGroup.new();
const addAction = (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
addAction('homepage', 'https://github.com/Schneegans/Desktop-Cube');
addAction('changelog', 'https://github.com/Schneegans/Desktop-Cube/blob/main/docs/changelog.md');
addAction('translate', 'https://hosted.weblate.org/engage/desktop-cube/');
addAction('bugs', 'https://github.com/Schneegans/Desktop-Cube/issues');
addAction('donate-kofi', 'https://ko-fi.com/schneegans');
addAction('donate-github', 'https://github.com/sponsors/Schneegans');
addAction('donate-paypal', 'https://www.paypal.me/simonschneegans');
addAction('show-sponsors', 'https://schneegans.github.io/sponsors');
// clang-format on
// 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[1]));
}
});
const dialog = new Adw.AboutWindow({transient_for: window, modal: true});
dialog.set_application_icon('desktop-cube-symbolic');
dialog.set_application_name('Desktop Cube');
dialog.set_version(`${this.metadata.version}`);
dialog.set_developer_name('Simon Schneegans');
dialog.set_issue_url('https://github.com/Schneegans/Desktop-Cube/issues');
dialog.set_translator_credits([...translators].join('\n'));
dialog.set_copyright('© 2023 Simon Schneegans');
dialog.set_website('https://github.com/Schneegans/Desktop-Cube');
dialog.set_license_type(Gtk.License.GPL_3_0);
dialog.show();
});
group.add_action(aboutAction);
window.insert_action_group('prefs', group);
});
window.set_search_enabled(true);
this._pages.forEach(page => {
window.add(page);
});
// As we do not have something like a destructor, we just listen for the destroy
// signal of our general page.
this._pages[0].connect('destroy', () => {
// Unregister our resources.
Gio.resources_unregister(this._resources);
});
}
// ----------------------------------------------------------------------- private stuff
// Connects a DesktopCubeImageChooserButton (or anything else which has a 'file'
// property) to a settings key. It also binds the corresponding reset button.
_bindImageChooserButton(settingsKey) {
this._bind(settingsKey, 'file');
}
// 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');
}
// 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) {
this._settings.bind(settingsKey, this._builder.get_object(settingsKey), property,
Gio.SettingsBindFlags.DEFAULT);
const resetButton = this._builder.get_object('reset-' + settingsKey);
resetButton.connect('clicked', () => {
this._settings.reset(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) {
const data = Gio.resources_lookup_data(path, 0);
const string = new TextDecoder().decode(data.get_data());
return JSON.parse(string);
}
// 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;
}
}