summaryrefslogtreecommitdiffstats
path: root/js/ui/inhibitShortcutsDialog.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/ui/inhibitShortcutsDialog.js')
-rw-r--r--js/ui/inhibitShortcutsDialog.js160
1 files changed, 160 insertions, 0 deletions
diff --git a/js/ui/inhibitShortcutsDialog.js b/js/ui/inhibitShortcutsDialog.js
new file mode 100644
index 0000000..7c3d159
--- /dev/null
+++ b/js/ui/inhibitShortcutsDialog.js
@@ -0,0 +1,160 @@
+/* exported InhibitShortcutsDialog */
+const {Clutter, Gio, GObject, Gtk, Meta, Pango, Shell, St} = imports.gi;
+
+const Dialog = imports.ui.dialog;
+const ModalDialog = imports.ui.modalDialog;
+const PermissionStore = imports.misc.permissionStore;
+
+const WAYLAND_KEYBINDINGS_SCHEMA = 'org.gnome.mutter.wayland.keybindings';
+
+const APP_ALLOWLIST = ['org.gnome.Settings.desktop'];
+const APP_PERMISSIONS_TABLE = 'gnome';
+const APP_PERMISSIONS_ID = 'shortcuts-inhibitor';
+const GRANTED = 'GRANTED';
+const DENIED = 'DENIED';
+
+var DialogResponse = Meta.InhibitShortcutsDialogResponse;
+
+var InhibitShortcutsDialog = GObject.registerClass({
+ Implements: [Meta.InhibitShortcutsDialog],
+ Properties: {
+ 'window': GObject.ParamSpec.override('window', Meta.InhibitShortcutsDialog),
+ },
+}, class InhibitShortcutsDialog extends GObject.Object {
+ _init(window) {
+ super._init();
+ this._window = window;
+
+ this._dialog = new ModalDialog.ModalDialog();
+ this._buildLayout();
+ }
+
+ get window() {
+ return this._window;
+ }
+
+ set window(window) {
+ this._window = window;
+ }
+
+ get _app() {
+ let windowTracker = Shell.WindowTracker.get_default();
+ return windowTracker.get_window_app(this._window);
+ }
+
+ _getRestoreAccel() {
+ let settings = new Gio.Settings({ schema_id: WAYLAND_KEYBINDINGS_SCHEMA });
+ let accel = settings.get_strv('restore-shortcuts')[0] || '';
+ return Gtk.accelerator_get_label.apply(null,
+ Gtk.accelerator_parse(accel));
+ }
+
+ _shouldUsePermStore() {
+ return this._app && !this._app.is_window_backed();
+ }
+
+ async _saveToPermissionStore(grant) {
+ if (!this._shouldUsePermStore() || this._permStore == null)
+ return;
+
+ try {
+ await this._permStore.SetPermissionAsync(APP_PERMISSIONS_TABLE,
+ true,
+ APP_PERMISSIONS_ID,
+ this._app.get_id(),
+ [grant]);
+ } catch (error) {
+ log(error.message);
+ }
+ }
+
+ _buildLayout() {
+ const name = this._app?.get_name() ?? this._window.title;
+
+ let content = new Dialog.MessageDialogContent({
+ title: _('Allow inhibiting shortcuts'),
+ description: name
+ /* Translators: %s is an application name like "Settings" */
+ ? _('The application %s wants to inhibit shortcuts').format(name)
+ : _('An application wants to inhibit shortcuts'),
+ });
+
+ let restoreAccel = this._getRestoreAccel();
+ if (restoreAccel) {
+ let restoreLabel = new St.Label({
+ /* Translators: %s is a keyboard shortcut like "Super+x" */
+ text: _('You can restore shortcuts by pressing %s.').format(restoreAccel),
+ style_class: 'message-dialog-description',
+ });
+ restoreLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+ restoreLabel.clutter_text.line_wrap = true;
+ content.add_child(restoreLabel);
+ }
+
+ this._dialog.contentLayout.add_child(content);
+
+ this._dialog.addButton({
+ label: _('Deny'),
+ action: () => {
+ this._saveToPermissionStore(DENIED);
+ this._emitResponse(DialogResponse.DENY);
+ },
+ key: Clutter.KEY_Escape,
+ });
+
+ this._dialog.addButton({
+ label: _('Allow'),
+ action: () => {
+ this._saveToPermissionStore(GRANTED);
+ this._emitResponse(DialogResponse.ALLOW);
+ },
+ default: true,
+ });
+ }
+
+ _emitResponse(response) {
+ this.emit('response', response);
+ this._dialog.close();
+ }
+
+ vfunc_show() {
+ if (this._app && APP_ALLOWLIST.includes(this._app.get_id())) {
+ this._emitResponse(DialogResponse.ALLOW);
+ return;
+ }
+
+ if (!this._shouldUsePermStore()) {
+ this._dialog.open();
+ return;
+ }
+
+ /* Check with the permission store */
+ let appId = this._app.get_id();
+ this._permStore = new PermissionStore.PermissionStore(async (proxy, error) => {
+ if (error) {
+ log(error.message);
+ this._dialog.open();
+ return;
+ }
+
+ try {
+ const [permissions] = await this._permStore.LookupAsync(
+ APP_PERMISSIONS_TABLE, APP_PERMISSIONS_ID);
+
+ if (permissions[appId] === undefined) // Not found
+ this._dialog.open();
+ else if (permissions[appId][0] === GRANTED)
+ this._emitResponse(DialogResponse.ALLOW);
+ else
+ this._emitResponse(DialogResponse.DENY);
+ } catch (err) {
+ this._dialog.open();
+ log(err.message);
+ }
+ });
+ }
+
+ vfunc_hide() {
+ this._dialog.close();
+ }
+});