Skip to content

Commit de07e66

Browse files
committed
extension: Perform runtime-only settings overriding
The extension is overriding the user settings by writing on them, sadly this implies various issues because even if we reset them on extension unloading, a shell crash or mis-behavior could always lead to affect user settings. To prevent this, we can temporary override Settings backend read vfunc so that the values we want to override won't ever be written to user db and so there will be no risk of leaving them in a dirty state. Sadly, this requires fixes to gjs: https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/831
1 parent b4acb5b commit de07e66

File tree

1 file changed

+74
-46
lines changed

1 file changed

+74
-46
lines changed

tiling-assistant@leleat-on-github/extension.js

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,74 @@ const { Rect, Util } = Me.imports.src.extension.utility;
3636
* => resizeHandler.js (when resizing a window)
3737
*/
3838

39+
class SettingsOverrider {
40+
constructor() {
41+
this._backend = Gio.SettingsBackend.get_default();
42+
this._overriddenValues = new Map();
43+
44+
this._originalSettingsRead = Util.overrideVFunc(
45+
this._backend.constructor.prototype, 'read',
46+
(key, expectedType, defaultValue) => {
47+
print('Getting', key, expectedType, defaultValue)
48+
const overridden = this._overriddenValues.get(key);
49+
if (overridden !== undefined) {
50+
if (overridden?.is_of_type(expectedType) !== false)
51+
return overridden;
52+
53+
logError(new Error(),
54+
'Overriden value is of an invalid type: ' +
55+
`${expectedType} vs ${overridden?.get_type()}`);
56+
}
57+
58+
return this._originalSettingsRead.call(this._backend,
59+
key, expectedType, defaultValue);
60+
});
61+
}
62+
63+
_getSettingPath(schema, key) {
64+
return `/${schema.replaceAll('.', '/')}/${key}`;
65+
}
66+
67+
add(schema, key, value) {
68+
const path = this._getSettingPath(schema, key);
69+
this._overriddenValues.set(path, value);
70+
this._backend.changed(path, this);
71+
}
72+
73+
remove(schema, key) {
74+
const path = this._getSettingPath(schema, key);
75+
this._overriddenValues.delete(path);
76+
this._backend.changed(path, this);
77+
78+
if (!this._overriddenValues.size)
79+
this._clear();
80+
}
81+
82+
_clear() {
83+
if (this._originalSettingsRead) {
84+
Util.overrideVFunc(this._backend.constructor.prototype,
85+
'read', this._originalSettingsRead);
86+
this._originalSettingsRead = null;
87+
}
88+
89+
this._overriddenValues?.forEach((_value, key) =>
90+
this._backend.changed(key, this));
91+
this._overriddenValues = null;
92+
}
93+
94+
destroy() {
95+
this._clear();
96+
}
97+
}
98+
3999
function init() {
40100
ExtensionUtils.initTranslations(Me.metadata.uuid);
41101
}
42102

43103
function enable() {
44104
this._settings = Me.imports.src.common.Settings;
45105
this._settings.initialize();
106+
this._settingsOverrider = new SettingsOverrider();
46107

47108
this._twm = Me.imports.src.extension.tilingWindowManager.TilingWindowManager;
48109
this._twm.initialize();
@@ -62,45 +123,34 @@ function enable() {
62123
this._altTabOverride = new AltTabOverride();
63124

64125
// Disable native tiling.
65-
this._gnomeMutterSettings = ExtensionUtils.getSettings('org.gnome.mutter');
66-
this._gnomeMutterEdgeTilingUserValue = this._gnomeMutterSettings.get_user_value('edge-tiling');
67-
this._gnomeMutterSettings.set_boolean('edge-tiling', false);
68-
69-
if (Gio.SettingsSchemaSource.get_default().lookup('org.gnome.shell.overrides', true)) {
70-
this._gnomeShellSettings = ExtensionUtils.getSettings('org.gnome.shell.overrides');
71-
this._gnomeShellEdgeTilingUserValue = this._gnomeShellSettings.get_user_value('edge-tiling');
72-
this._gnomeShellSettings.set_boolean('edge-tiling', false);
73-
}
126+
this._settingsOverrider.add('org.gnome.mutter', 'edge-tiling',
127+
new GLib.Variant('b', false));
74128

75129
// Disable native keybindings for Super+Up/Down/Left/Right
76130
this._gnomeMutterKeybindings = ExtensionUtils.getSettings('org.gnome.mutter.keybindings');
77131
this._gnomeDesktopKeybindings = ExtensionUtils.getSettings('org.gnome.desktop.wm.keybindings');
78-
this._nativeKeybindings = [];
79132
const sc = Me.imports.src.common.Shortcuts;
133+
const emptyStrvVariant = new GLib.Variant('as', []);
80134

81135
if (this._gnomeDesktopKeybindings.get_strv('maximize').includes('<Super>Up') &&
82136
this._settings.getStrv(sc.MAXIMIZE).includes('<Super>Up')) {
83-
const userValue = this._gnomeDesktopKeybindings.get_value('maximize');
84-
this._gnomeDesktopKeybindings.set_strv('maximize', []);
85-
this._nativeKeybindings.push([this._gnomeDesktopKeybindings, 'maximize', userValue]);
137+
this._settingsOverrider.add(this._gnomeDesktopKeybindings.schemaId,
138+
'maximize', emptyStrvVariant);
86139
}
87140
if (this._gnomeDesktopKeybindings.get_strv('unmaximize').includes('<Super>Down') &&
88141
this._settings.getStrv(sc.RESTORE_WINDOW).includes('<Super>Down')) {
89-
const userValue = this._gnomeDesktopKeybindings.get_value('unmaximize');
90-
this._gnomeDesktopKeybindings.set_strv('unmaximize', []);
91-
this._nativeKeybindings.push([this._gnomeDesktopKeybindings, 'unmaximize', userValue]);
142+
this._settingsOverrider.add(this._gnomeDesktopKeybindings.schemaId,
143+
'unmaximize', emptyStrvVariant);
92144
}
93145
if (this._gnomeMutterKeybindings.get_strv('toggle-tiled-left').includes('<Super>Left') &&
94146
this._settings.getStrv(sc.LEFT).includes('<Super>Left')) {
95-
const userValue = this._gnomeMutterKeybindings.get_value('toggle-tiled-left');
96-
this._gnomeMutterKeybindings.set_strv('toggle-tiled-left', []);
97-
this._nativeKeybindings.push([this._gnomeMutterKeybindings, 'toggle-tiled-left', userValue]);
147+
this._settingsOverrider.add(this._gnomeMutterKeybindings.schemaId,
148+
'toggle-tiled-left', emptyStrvVariant);
98149
}
99150
if (this._gnomeMutterKeybindings.get_strv('toggle-tiled-right').includes('<Super>Right') &&
100151
this._settings.getStrv(sc.RIGHT).includes('<Super>Right')) {
101-
const userValue = this._gnomeMutterKeybindings.get_value('toggle-tiled-right');
102-
this._gnomeMutterKeybindings.set_strv('toggle-tiled-right', []);
103-
this._nativeKeybindings.push([this._gnomeMutterKeybindings, 'toggle-tiled-right', userValue]);
152+
this._settingsOverrider.add(this._gnomeMutterKeybindings.schemaId,
153+
'toggle-tiled-right', emptyStrvVariant);
104154
}
105155

106156
// Include tiled windows when dragging from the top panel.
@@ -134,6 +184,8 @@ function disable() {
134184
// them after the session is unlocked again.
135185
_saveBeforeSessionLock();
136186

187+
this._settingsOverrider.destroy();
188+
this._settingsOverrider = null;
137189
this._moveHandler.destroy();
138190
this._moveHandler = null;
139191
this._resizeHandler.destroy();
@@ -154,30 +206,6 @@ function disable() {
154206
this._settings.destroy();
155207
this._settings = null;
156208

157-
const restoreSetting = (gsettings, key, oldValue) => {
158-
if (gsettings) {
159-
if (oldValue)
160-
gsettings.set_value(key, oldValue);
161-
else
162-
gsettings.reset(key);
163-
}
164-
};
165-
166-
// Re-enable native tiling.
167-
restoreSetting(this._gnomeMutterSettings,
168-
'edge-tiling', this._gnomeMutterEdgeTilingUserValue);
169-
this._gnomeMutterEdgeTilingUserValue = null;
170-
this._gnomeMutterSettings = null;
171-
172-
restoreSetting(this._gnomeShellSettings,
173-
'edge-tiling', this._gnomeShellEdgeTilingUserValue);
174-
this._gnomeShellEdgeTilingUserValue = null;
175-
this._gnomeShellSettings = null;
176-
177-
// Restore native keybindings for Super+Up/Down/Left/Right
178-
this._nativeKeybindings.forEach(([kbSetting, kbName, kbOldValue]) =>
179-
restoreSetting(kbSetting, kbName, kbOldValue));
180-
this._nativeKeybindings = [];
181209
this._gnomeMutterKeybindings = null;
182210
this._gnomeDesktopKeybindings = null;
183211

0 commit comments

Comments
 (0)