diff options
Diffstat (limited to 'js/ui/inhibitShortcutsDialog.js')
-rw-r--r-- | js/ui/inhibitShortcutsDialog.js | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/js/ui/inhibitShortcutsDialog.js b/js/ui/inhibitShortcutsDialog.js new file mode 100644 index 0000000..d16c55a --- /dev/null +++ b/js/ui/inhibitShortcutsDialog.js @@ -0,0 +1,163 @@ +/* exported InhibitShortcutsDialog */ +const { Clutter, Gio, GLib, 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 = ['gnome-control-center.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(); + } + + _saveToPermissionStore(grant) { + if (!this._shouldUsePermStore() || this._permStore == null) + return; + + let permissions = {}; + permissions[this._app.get_id()] = [grant]; + let data = GLib.Variant.new('av', {}); + + this._permStore.SetRemote(APP_PERMISSIONS_TABLE, + true, + APP_PERMISSIONS_ID, + permissions, + data, + (result, error) => { + if (error != null) + log(error.message); + }); + } + + _buildLayout() { + let name = this._app ? 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((proxy, error) => { + if (error) { + log(error.message); + this._dialog.open(); + return; + } + + this._permStore.LookupRemote(APP_PERMISSIONS_TABLE, + APP_PERMISSIONS_ID, + (res, err) => { + if (err) { + this._dialog.open(); + log(err.message); + return; + } + + let [permissions] = res; + if (permissions[appId] === undefined) // Not found + this._dialog.open(); + else if (permissions[appId] == GRANTED) + this._emitResponse(DialogResponse.ALLOW); + else + this._emitResponse(DialogResponse.DENY); + }); + }); + } + + vfunc_hide() { + this._dialog.close(); + } +}); |