Skip to content

Commit c4d402f

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 5c2c2de commit c4d402f

File tree

1 file changed

+73
-46
lines changed

1 file changed

+73
-46
lines changed

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

Lines changed: 73 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,73 @@ 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+
const overridden = this._overriddenValues.get(key);
48+
if (overridden !== undefined) {
49+
if (overridden?.is_of_type(expectedType) !== false)
50+
return overridden;
51+
52+
logError(new Error(),
53+
'Overriden value is of an invalid type: ' +
54+
`${expectedType} vs ${overridden?.get_type()}`);
55+
}
56+
57+
return this._originalSettingsRead.call(this._backend,
58+
key, expectedType, defaultValue);
59+
});
60+
}
61+
62+
_getSettingPath(schema, key) {
63+
return `/${schema.replaceAll('.', '/')}/${key}`;
64+
}
65+
66+
add(schema, key, value) {
67+
const path = this._getSettingPath(schema, key);
68+
this._overriddenValues.set(path, value);
69+
this._backend.changed(path, this);
70+
}
71+
72+
remove(schema, key) {
73+
const path = this._getSettingPath(schema, key);
74+
this._overriddenValues.delete(path);
75+
this._backend.changed(path, this);
76+
77+
if (!this._overriddenValues.size)
78+
this._clear();
79+
}
80+
81+
_clear() {
82+
if (this._originalSettingsRead) {
83+
Util.overrideVFunc(this._backend.constructor.prototype,
84+
'read', this._originalSettingsRead);
85+
this._originalSettingsRead = null;
86+
}
87+
88+
this._overriddenValues?.forEach((_value, key) =>
89+
this._backend.changed(key, this));
90+
this._overriddenValues = null;
91+
}
92+
93+
destroy() {
94+
this._clear();
95+
}
96+
}
97+
3998
function init() {
4099
ExtensionUtils.initTranslations(Me.metadata.uuid);
41100
}
42101

43102
function enable() {
44103
this._settings = Me.imports.src.common.Settings;
45104
this._settings.initialize();
105+
this._settingsOverrider = new SettingsOverrider();
46106

47107
this._twm = Me.imports.src.extension.tilingWindowManager.TilingWindowManager;
48108
this._twm.initialize();
@@ -62,45 +122,34 @@ function enable() {
62122
this._altTabOverride = new AltTabOverride();
63123

64124
// 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-
}
125+
this._settingsOverrider.add('org.gnome.mutter', 'edge-tiling',
126+
new GLib.Variant('b', false));
74127

75128
// Disable native keybindings for Super+Up/Down/Left/Right
76129
this._gnomeMutterKeybindings = ExtensionUtils.getSettings('org.gnome.mutter.keybindings');
77130
this._gnomeDesktopKeybindings = ExtensionUtils.getSettings('org.gnome.desktop.wm.keybindings');
78-
this._nativeKeybindings = [];
79131
const sc = Me.imports.src.common.Shortcuts;
132+
const emptyStrvVariant = new GLib.Variant('as', []);
80133

81134
if (this._gnomeDesktopKeybindings.get_strv('maximize').includes('<Super>Up') &&
82135
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]);
136+
this._settingsOverrider.add(this._gnomeDesktopKeybindings.schemaId,
137+
'maximize', emptyStrvVariant);
86138
}
87139
if (this._gnomeDesktopKeybindings.get_strv('unmaximize').includes('<Super>Down') &&
88140
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]);
141+
this._settingsOverrider.add(this._gnomeDesktopKeybindings.schemaId,
142+
'unmaximize', emptyStrvVariant);
92143
}
93144
if (this._gnomeMutterKeybindings.get_strv('toggle-tiled-left').includes('<Super>Left') &&
94145
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]);
146+
this._settingsOverrider.add(this._gnomeMutterKeybindings.schemaId,
147+
'toggle-tiled-left', emptyStrvVariant);
98148
}
99149
if (this._gnomeMutterKeybindings.get_strv('toggle-tiled-right').includes('<Super>Right') &&
100150
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]);
151+
this._settingsOverrider.add(this._gnomeMutterKeybindings.schemaId,
152+
'toggle-tiled-right', emptyStrvVariant);
104153
}
105154

106155
// Include tiled windows when dragging from the top panel.
@@ -134,6 +183,8 @@ function disable() {
134183
// them after the session is unlocked again.
135184
_saveBeforeSessionLock();
136185

186+
this._settingsOverrider.destroy();
187+
this._settingsOverrider = null;
137188
this._moveHandler.destroy();
138189
this._moveHandler = null;
139190
this._resizeHandler.destroy();
@@ -154,30 +205,6 @@ function disable() {
154205
this._settings.destroy();
155206
this._settings = null;
156207

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 = [];
181208
this._gnomeMutterKeybindings = null;
182209
this._gnomeDesktopKeybindings = null;
183210

0 commit comments

Comments
 (0)