diff --git a/extension.js b/extension.js
index d34bdac..1137148 100644
--- a/extension.js
+++ b/extension.js
@@ -30,6 +30,7 @@ try {
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
+const migrate = Me.imports.src.migrate;
const utils = Me.imports.src.utils;
const ProfileManager = Me.imports.src.ProfileManager.ProfileManager;
const WindowPicker = Me.imports.src.WindowPicker.WindowPicker;
@@ -82,6 +83,20 @@ class Extension {
// Store a reference to the settings object.
this._settings = ExtensionUtils.getSettings();
+ // Now we check whether the extension settings need to be migrated from a previous
+ // version. If this is the case, we defer the profile loading until this is finished.
+ const lastVersion = this._settings.get_int('last-extension-version');
+ if (lastVersion < Me.metadata.version) {
+ if (lastVersion <= 26) {
+ migrate.fromVersion26().then(() => {
+ this._loadProfiles();
+ this._settings.set_int('last-extension-version', Me.metadata.version);
+ });
+ }
+ } else {
+ this._loadProfiles();
+ }
+
// We reload all effect profiles whenever the currently edited profile in the
// preferences dialog changes. This is most likely a bit too often, but it will also
// happen whenever a new profile is created and whenever an old profile is deleted.
@@ -89,8 +104,6 @@ class Extension {
this._loadProfiles();
});
- this._loadProfiles();
-
// This is used to get the desktop's color scheme.
this._shellSettings = new Gio.Settings({schema: 'org.gnome.desktop.interface'});
diff --git a/prefs.js b/prefs.js
index d87f323..5b079f9 100644
--- a/prefs.js
+++ b/prefs.js
@@ -28,7 +28,6 @@ const _ = imports.gettext.domain('burn-my-windows').gettext;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
-const migrate = Me.imports.src.migrate;
const utils = Me.imports.src.utils;
const ProfileManager = Me.imports.src.ProfileManager.ProfileManager;
@@ -68,8 +67,6 @@ var PreferencesDialog = class PreferencesDialog {
new Me.imports.src.effects.Wisps.Wisps(),
];
- migrate.migrate();
-
// Load all of our resources.
this._resources = Gio.Resource.load(Me.path + '/resources/burn-my-windows.gresource');
Gio.resources_register(this._resources);
@@ -358,7 +355,7 @@ var PreferencesDialog = class PreferencesDialog {
// 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-version');
+ const lastVersion = this._settings.get_int('last-prefs-version');
if (lastVersion < Me.metadata.version) {
this._showUpdateInfoTimeout =
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 2000, () => {
@@ -372,13 +369,13 @@ var PreferencesDialog = class PreferencesDialog {
toast.connect(
'dismissed',
- () => this._settings.set_int('last-version', Me.metadata.version));
+ () => this._settings.set_int('last-prefs-version', Me.metadata.version));
window.add_toast(toast);
} else {
const infoBar = this._builder.get_object('update-info');
infoBar.connect('response', i => {
- this._settings.set_int('last-version', Me.metadata.version);
+ this._settings.set_int('last-prefs-version', Me.metadata.version);
i.set_revealed(false);
});
infoBar.set_revealed(true);
@@ -459,7 +456,7 @@ var PreferencesDialog = class PreferencesDialog {
null,
'https://github.com/Schneegans/Burn-My-Windows/blob/main/docs/changelog.md',
Gdk.CURRENT_TIME);
- this._settings.set_int('last-version', Me.metadata.version)
+ this._settings.set_int('last-prefs-version', Me.metadata.version)
});
group.add_action(changelogAction);
diff --git a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
index 8739d9c..50fd50e 100644
--- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
@@ -31,10 +31,16 @@ SPDX-License-Identifier: CC0-1.0
If set to true, all animations will show only one still frame to allow for continuous integration tests.
-
+
0
- Last Version
- Used to check whether the extension got updated.
+ Last Prefs Version
+ Used to check whether the extension got updated from the preferences dialog.
+
+
+
+ 0
+ Last Extension Version
+ Used to check whether the extension got updated from the extension side.
diff --git a/src/ProfileManager.js b/src/ProfileManager.js
index c655e27..4d1c81e 100644
--- a/src/ProfileManager.js
+++ b/src/ProfileManager.js
@@ -56,15 +56,17 @@ var ProfileManager = class {
return this._profiles;
}
- // This will create a new profile with all values initialized to their defaults. The
- // method will return an effect profile object (as described above). We will use the
- // current system time in microseconds as profile name. This ensures that they are
- // always sorted according to their creation date.
- createProfile() {
+ // This will create a new profile. If no content is given, all values will be
+ // initialized to their defaults. The method will return an effect profile object (as
+ // described above). We will use the current system time in microseconds as profile
+ // name. This ensures that they are always sorted according to their creation date.
+ createProfile(content = '') {
const path = `${GLib.get_user_config_dir()}/burn-my-windows/profiles/${
GLib.get_real_time()}.conf`;
const file = Gio.File.new_for_path(path);
file.create(Gio.FileCreateFlags.NONE, null);
+ file.replace_contents(content, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION,
+ null);
const profile = {'path': path, 'settings': this._getProfileSettings(path)};
diff --git a/src/migrate.js b/src/migrate.js
index 382b535..7ae8788 100644
--- a/src/migrate.js
+++ b/src/migrate.js
@@ -16,27 +16,35 @@
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
+const ProfileManager = Me.imports.src.ProfileManager.ProfileManager;
const utils = Me.imports.src.utils;
-function migrate() {
- utils.executeCommand(['dconf', 'dump', '/org/gnome/shell/extensions/burn-my-windows/'])
+// Migrating from pre-27 versions is pretty involved. Before, all settings were stored in
+// the standard Gio.Settings backend. Now, there are effect profiles. Depending on the
+// settings one or two profiles may be required.
+async function fromVersion26() {
+ return utils
+ .executeCommand(['dconf', 'dump', '/org/gnome/shell/extensions/burn-my-windows/'])
.catch(r => utils.debug('Failed to get old settings for effect migration: ' + r))
.then(r => {
- utils.debug('Starting Burn-My-Windows profile migration!');
+ utils.debug('Starting Burn-My-Windows profile migration (old version <= 26)!');
- // The default value of this is false, so not-present is equal to false.
+ // We use this to write the new profiles.
+ const profileManager = new ProfileManager();
+
+ // The default value of this was false, so not-present is equal to false.
const destroyDialogs = r.includes('destroy-dialogs=true');
if (!destroyDialogs) {
utils.debug('Only normal windows will be burned by the new profile(s).');
}
- // The default value of this is false, so not-present is equal to false.
+ // The default value of this was false, so not-present is equal to false.
const disableOnBattery = r.includes('disable-on-battery=true');
if (disableOnBattery) {
utils.debug('The new profile(s) will not be active on battery.');
}
- // The default value of this is false, so not-present is equal to false.
+ // The default value of this was false, so not-present is equal to false.
const disableOnPowerSave = r.includes('disable-on-power-save=true');
if (disableOnPowerSave) {
utils.debug('The new profile(s) will not be active in power-save mode.');
@@ -45,7 +53,8 @@ function migrate() {
// Remove some unnecessary lines.
r = r.replace(/^active-profile=.*\n?/gm, '');
r = r.replace(/^test-mode=.*\n?/gm, '');
- r = r.replace(/^last-version=.*\n?/gm, '');
+ r = r.replace(/^last-extension-version=.*\n?/gm, '');
+ r = r.replace(/^last-prefs-version=.*\n?/gm, '');
r = r.replace(/^destroy-dialogs=.*\n?/gm, '');
r = r.replace(/^disable-on-battery=.*\n?/gm, '');
r = r.replace(/^disable-on-power-save=.*\n?/gm, '');
@@ -53,15 +62,14 @@ function migrate() {
r = r.replace('[/]\n', '');
r = r.trim();
- // There were some inconsistencies in the key names.
+ // There were some inconsistencies in the key names. The update fixes them.
r.replace('flame-', 'fire-');
r.replace('claw-', 'trex-');
- let lines = r.split('\n');
-
// Find all effects which were used for openeing and closing. This first extracts
// all lines which end in "-open-effect=true" and then remove this suffix from the
// lines. This leaves only the effect nicks.
+ let lines = r.split('\n');
let openEffects = lines.filter(l => l.includes('-open-effect=true'))
.map(l => l.replace('-open-effect=true', ''));
let closeEffects = lines.filter(l => l.includes('-close-effect=true'))
@@ -73,11 +81,13 @@ function migrate() {
closeEffects.push('fire');
}
+ // Print all effects we've found.
utils.debug('Enabled open effects: ' + openEffects);
utils.debug('Enabled close effects: ' + closeEffects);
- // If the same effects were used for opening and closing windows, only one profile
- // is required. Else we have to create two new profiles.
+ // If the same effects were used for opening and closing windows or there is either
+ // no opening or no closing animation configured, only one profile is required. Else
+ // we have to create two new profiles.
const numProfiles = openEffects.join() == closeEffects.join() ? 1 : 2;
if (numProfiles == 1) {
utils.debug('Only one profile is required.');
@@ -89,69 +99,121 @@ function migrate() {
utils.debug('Two profiles are required.');
}
- const profile =
+ // Remove all open / close lines.
+ const profileLines =
lines.filter(l => !l.includes('-close-effect=') && !l.includes('-open-effect='));
- profile.unshift('[burn-my-windows-profile]');
+ // Add the header.
+ profileLines.unshift('[burn-my-windows-profile]');
+
+ // Push the line which makes the profile only apply to normal windows.
if (!destroyDialogs) {
- profile.push('profile-window-type=1');
+ profileLines.push('profile-window-type=1');
}
+ // Push the line which makes the profile only active when plugged in.
if (disableOnBattery) {
- profile.push('profile-power-mode=2');
+ profileLines.push('profile-power-mode=2');
}
+ // Push the line which makes the profile only active when on balanced or performance
+ // mode.
if (disableOnPowerSave) {
- profile.push('profile-power-profile=5');
+ profileLines.push('profile-power-profile=5');
}
+ // Now comes a bit of code repetition, but it is more readable this way.
if (numProfiles == 1) {
- openEffects.forEach(e => profile.push(e + '-enable-effect=true'));
+
+ // Add all relevant effects.
+ openEffects.forEach(e => profileLines.push(e + '-enable-effect=true'));
+
+ // The fire effect is enabled per default, so we have to explicitly disable it if
+ // not required.
if (!openEffects.includes('fire')) {
- profile.push('fire-enable-effect=false');
+ profileLines.push('fire-enable-effect=false');
}
+ // Print and save the new profile.
+ const profile = profileLines.join('\n');
+
utils.debug('The new profile:');
- utils.debug(profile.join('\n'));
+ utils.debug(profile);
+
+ profileManager.createProfile(profile);
} else if (closeEffects.length == 0) {
- profile.push('profile-animation-type=1')
- openEffects.forEach(e => profile.push(e + '-enable-effect=true'));
+ // This profile is only for window openeing.
+ profileLines.push('profile-animation-type=1')
+
+ // Add all relevant effects.
+ openEffects.forEach(e => profileLines.push(e + '-enable-effect=true'));
+
+ // The fire effect is enabled per default, so we have to explicitly disable it if
+ // not required.
if (!openEffects.includes('fire')) {
- profile.push('fire-enable-effect=false');
+ profileLines.push('fire-enable-effect=false');
}
+ // Print and save the new profile.
+ const profile = profileLines.join('\n');
+
utils.debug('The new window-open profile:');
- utils.debug(profile.join('\n'));
+ utils.debug(profile);
+
+ profileManager.createProfile(profile);
} else if (openEffects.length == 0) {
- profile.push('profile-animation-type=2')
- closeEffects.forEach(e => profile.push(e + '-enable-effect=true'));
+ // This profile is only for window closing.
+ profileLines.push('profile-animation-type=2')
+
+ // Add all relevant effects.
+ closeEffects.forEach(e => profileLines.push(e + '-enable-effect=true'));
+
+ // The fire effect is enabled per default, so we have to explicitly disable it if
+ // not required.
if (!closeEffects.includes('fire')) {
- profile.push('fire-enable-effect=false');
+ profileLines.push('fire-enable-effect=false');
}
+ // Print and save the new profile.
+ const profile = profileLines.join('\n');
+
utils.debug('The new window-close profile:');
- utils.debug(profile.join('\n'));
+ utils.debug(profile);
+
+ profileManager.createProfile(profile);
+
} else {
- const openProfile = [...profile, 'profile-animation-type=1'];
- const closeProfile = [...profile, 'profile-animation-type=2'];
+ const openProfileLines = [...profile, 'profile-animation-type=1'];
+ const closeProfileLines = [...profile, 'profile-animation-type=2'];
- openEffects.forEach(e => openProfile.push(e + '-enable-effect=true'));
- closeEffects.forEach(e => closeProfile.push(e + '-enable-effect=true'));
+ // Add all relevant effects.
+ openEffects.forEach(e => openProfileLines.push(e + '-enable-effect=true'));
+ closeEffects.forEach(e => closeProfileLines.push(e + '-enable-effect=true'));
+
+ // The fire effect is enabled per default, so we have to explicitly disable it if
+ // not required.
if (!closeEffects.includes('fire')) {
- closeProfile.push('fire-enable-effect=false');
+ closeProfileLines.push('fire-enable-effect=false');
}
+ // Print and save the new profiles.
+ const openProfile = openProfileLines.join('\n');
+ const closeProfile = closeProfileLines.join('\n');
+
utils.debug('The new open-window profile:');
- utils.debug(openProfile.join('\n'));
+ utils.debug(openProfile);
utils.debug('The new close-window profile:');
- utils.debug(closeProfile.join('\n'));
+ utils.debug(closeProfile);
+
+ profileManager.createProfile(openProfile);
+ profileManager.createProfile(closeProfile);
}
})
- .catch(r => utils.debug('Failed migrate settings: ' + r));
+ .catch(r => utils.debug('Failed to migrate settings: ' + r));
}
\ No newline at end of file