dbusServices/extensions: Only allow one dialog at a time

Showing multiple preference dialogs at the same time (for instance
by repeated `gnome-extensions prefs` calls) may or may not work as
expected, depending on whether any of the dialogs is modal or not
(read: opened via the Extensions app).

The easiest way to address this is to disallow more than a single
dialog at the time. It's arguably also the more predictable behavior,
and means extensions don't have to deal with inconsistent state
caused by multiple dialogs.

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4564

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2013>
(cherry picked from commit b93342f72e)
This commit is contained in:
Florian Müllner 2021-10-26 19:40:08 +02:00
parent 1297d8dc30
commit b6b9e755c7

View File

@ -116,30 +116,37 @@ var ExtensionsService = class extends ServiceImplementation {
if (this._handleError(invocation, error)) if (this._handleError(invocation, error))
return; return;
if (this._prefsDialog) {
this._handleError(invocation,
new Error('Already showing a prefs dialog'));
return;
}
const [serialized] = res; const [serialized] = res;
const extension = ExtensionUtils.deserializeExtension(serialized); const extension = ExtensionUtils.deserializeExtension(serialized);
const window = new ExtensionPrefsDialog(extension); this._prefsDialog = new ExtensionPrefsDialog(extension);
window.connect('realize', () => { this._prefsDialog.connect('realize', () => {
let externalWindow = null; let externalWindow = null;
if (parentWindow) if (parentWindow)
externalWindow = Shew.ExternalWindow.new_from_handle(parentWindow); externalWindow = Shew.ExternalWindow.new_from_handle(parentWindow);
if (externalWindow) if (externalWindow)
externalWindow.set_parent_of(window.get_surface()); externalWindow.set_parent_of(this._prefsDialog.get_surface());
}); });
if (options.modal) if (options.modal)
window.modal = options.modal.get_boolean(); this._prefsDialog.modal = options.modal.get_boolean();
window.connect('close-request', () => { this._prefsDialog.connect('close-request', () => {
delete this._prefsDialog;
this.release(); this.release();
return false; return false;
}); });
this.hold(); this.hold();
window.show(); this._prefsDialog.show();
invocation.return_value(null); invocation.return_value(null);
}); });