2012-01-10 15:37:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 09:53:00 +00:00
|
|
|
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import Gcr from 'gi://Gcr';
|
|
|
|
import Gio from 'gi://Gio';
|
|
|
|
import GObject from 'gi://GObject';
|
|
|
|
import Pango from 'gi://Pango';
|
|
|
|
import Shell from 'gi://Shell';
|
|
|
|
import St from 'gi://St';
|
|
|
|
|
|
|
|
import * as Dialog from '../dialog.js';
|
|
|
|
import * as ModalDialog from '../modalDialog.js';
|
|
|
|
import * as ShellEntry from '../shellEntry.js';
|
|
|
|
import * as CheckBox from '../checkBox.js';
|
|
|
|
import {wiggle} from '../misc/animationUtils.js';
|
|
|
|
|
|
|
|
const KeyringDialog = GObject.registerClass(
|
2019-05-23 20:45:44 +00:00
|
|
|
class KeyringDialog extends ModalDialog.ModalDialog {
|
|
|
|
_init() {
|
|
|
|
super._init({ styleClass: 'prompt-dialog' });
|
2012-01-10 15:37:26 +00:00
|
|
|
|
|
|
|
this.prompt = new Shell.KeyringPrompt();
|
2017-12-02 00:27:35 +00:00
|
|
|
this.prompt.connect('show-password', this._onShowPassword.bind(this));
|
|
|
|
this.prompt.connect('show-confirm', this._onShowConfirm.bind(this));
|
|
|
|
this.prompt.connect('prompt-close', this._onHidePrompt.bind(this));
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
let content = new Dialog.MessageDialogContent();
|
2017-07-15 04:03:55 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
this.prompt.bind_property('message',
|
|
|
|
content, 'title', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('description',
|
|
|
|
content, 'description', GObject.BindingFlags.SYNC_CREATE);
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
let passwordBox = new St.BoxLayout({
|
|
|
|
style_class: 'prompt-dialog-password-layout',
|
|
|
|
vertical: true,
|
2019-10-21 18:44:00 +00:00
|
|
|
});
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
this._passwordEntry = new St.PasswordEntry({
|
|
|
|
style_class: 'prompt-dialog-password-entry',
|
|
|
|
can_focus: true,
|
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
ShellEntry.addContextMenu(this._passwordEntry);
|
|
|
|
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
|
|
|
|
this.prompt.bind_property('password-visible',
|
|
|
|
this._passwordEntry, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
passwordBox.add_child(this._passwordEntry);
|
|
|
|
|
|
|
|
this._confirmEntry = new St.PasswordEntry({
|
|
|
|
style_class: 'prompt-dialog-password-entry',
|
|
|
|
can_focus: true,
|
|
|
|
x_align: Clutter.ActorAlign.CENTER,
|
|
|
|
});
|
|
|
|
ShellEntry.addContextMenu(this._confirmEntry);
|
|
|
|
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
|
|
|
|
this.prompt.bind_property('confirm-visible',
|
|
|
|
this._confirmEntry, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
passwordBox.add_child(this._confirmEntry);
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
this.prompt.set_password_actor(this._passwordEntry.clutter_text);
|
|
|
|
this.prompt.set_confirm_actor(this._confirmEntry.clutter_text);
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
let warningBox = new St.BoxLayout({ vertical: true });
|
2019-12-17 20:03:45 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
let capsLockWarning = new ShellEntry.CapsLockWarning();
|
2020-01-30 10:27:25 +00:00
|
|
|
let syncCapsLockWarningVisibility = () => {
|
|
|
|
capsLockWarning.visible =
|
|
|
|
this.prompt.password_visible || this.prompt.confirm_visible;
|
|
|
|
};
|
|
|
|
this.prompt.connect('notify::password-visible', syncCapsLockWarningVisibility);
|
|
|
|
this.prompt.connect('notify::confirm-visible', syncCapsLockWarningVisibility);
|
2020-01-20 16:40:25 +00:00
|
|
|
warningBox.add_child(capsLockWarning);
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
2012-01-10 15:37:26 +00:00
|
|
|
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
|
|
warning.clutter_text.line_wrap = true;
|
2020-01-20 16:40:25 +00:00
|
|
|
this.prompt.bind_property('warning',
|
|
|
|
warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.connect('notify::warning-visible', () => {
|
|
|
|
warning.opacity = this.prompt.warning_visible ? 255 : 0;
|
|
|
|
});
|
2020-01-20 16:42:09 +00:00
|
|
|
this.prompt.connect('notify::warning', () => {
|
2021-10-30 22:09:39 +00:00
|
|
|
if (this._passwordEntry && this.prompt.warning !== '')
|
2023-07-10 04:58:21 +00:00
|
|
|
wiggle(this._passwordEntry);
|
2020-01-20 16:42:09 +00:00
|
|
|
});
|
2020-01-20 16:40:25 +00:00
|
|
|
warningBox.add_child(warning);
|
|
|
|
|
|
|
|
passwordBox.add_child(warningBox);
|
|
|
|
content.add_child(passwordBox);
|
|
|
|
|
|
|
|
this._choice = new CheckBox.CheckBox();
|
|
|
|
this.prompt.bind_property('choice-label', this._choice.getLabelActor(),
|
|
|
|
'text', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('choice-chosen', this._choice,
|
|
|
|
'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
|
|
|
this.prompt.bind_property('choice-visible', this._choice,
|
|
|
|
'visible', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
content.add_child(this._choice);
|
|
|
|
|
|
|
|
this.contentLayout.add_child(content);
|
|
|
|
|
|
|
|
this._cancelButton = this.addButton({
|
|
|
|
label: '',
|
|
|
|
action: this._onCancelButton.bind(this),
|
|
|
|
key: Clutter.KEY_Escape,
|
|
|
|
});
|
|
|
|
this._continueButton = this.addButton({
|
|
|
|
label: '',
|
|
|
|
action: this._onContinueButton.bind(this),
|
|
|
|
default: true,
|
|
|
|
});
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2020-01-20 16:40:25 +00:00
|
|
|
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateSensitivity(sensitive) {
|
2020-03-18 21:20:33 +00:00
|
|
|
if (this._passwordEntry)
|
2013-04-17 10:02:12 +00:00
|
|
|
this._passwordEntry.reactive = sensitive;
|
|
|
|
|
2020-03-18 21:20:33 +00:00
|
|
|
if (this._confirmEntry)
|
2013-04-17 10:02:12 +00:00
|
|
|
this._confirmEntry.reactive = sensitive;
|
2012-12-21 16:07:56 +00:00
|
|
|
|
2012-12-30 17:05:24 +00:00
|
|
|
this._continueButton.can_focus = sensitive;
|
|
|
|
this._continueButton.reactive = sensitive;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-12-21 16:07:56 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_ensureOpen() {
|
2012-01-10 15:37:26 +00:00
|
|
|
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
|
|
|
// already open - it just returns true without side-effects
|
|
|
|
if (this.open())
|
2019-01-29 19:36:54 +00:00
|
|
|
return true;
|
2012-01-10 15:37:26 +00:00
|
|
|
|
|
|
|
// The above fail if e.g. unable to get input grab
|
|
|
|
//
|
|
|
|
// In an ideal world this wouldn't happen (because the
|
|
|
|
// Shell is in complete control of the session) but that's
|
|
|
|
// just not how things work right now.
|
|
|
|
|
|
|
|
log('keyringPrompt: Failed to show modal dialog.' +
|
|
|
|
' Dismissing prompt request');
|
2019-01-29 01:18:52 +00:00
|
|
|
this.prompt.cancel();
|
2012-01-10 15:37:26 +00:00
|
|
|
return false;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_onShowPassword() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._ensureOpen();
|
2012-12-28 08:20:18 +00:00
|
|
|
this._updateSensitivity(true);
|
2020-01-20 16:40:25 +00:00
|
|
|
this._passwordEntry.text = '';
|
2012-01-10 15:37:26 +00:00
|
|
|
this._passwordEntry.grab_key_focus();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_onShowConfirm() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._ensureOpen();
|
2012-12-28 08:20:18 +00:00
|
|
|
this._updateSensitivity(true);
|
2020-01-20 16:40:25 +00:00
|
|
|
this._confirmEntry.text = '';
|
2012-01-10 15:37:26 +00:00
|
|
|
this._continueButton.grab_key_focus();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_onHidePrompt() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this.close();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onPasswordActivate() {
|
2012-12-28 08:20:18 +00:00
|
|
|
if (this.prompt.confirm_visible)
|
2012-01-10 15:37:26 +00:00
|
|
|
this._confirmEntry.grab_key_focus();
|
2012-12-28 08:20:18 +00:00
|
|
|
else
|
2012-01-10 15:37:26 +00:00
|
|
|
this._onContinueButton();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onConfirmActivate() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._onContinueButton();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onContinueButton() {
|
2012-12-21 16:07:56 +00:00
|
|
|
this._updateSensitivity(false);
|
2012-09-03 01:23:50 +00:00
|
|
|
this.prompt.complete();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onCancelButton() {
|
2012-09-03 01:23:50 +00:00
|
|
|
this.prompt.cancel();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2019-05-23 20:45:44 +00:00
|
|
|
});
|
2013-09-18 15:53:26 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
class KeyringDummyDialog {
|
2017-10-31 01:19:44 +00:00
|
|
|
constructor() {
|
2013-09-18 15:53:26 +00:00
|
|
|
this.prompt = new Shell.KeyringPrompt();
|
2017-12-02 00:27:35 +00:00
|
|
|
this.prompt.connect('show-password', this._cancelPrompt.bind(this));
|
|
|
|
this.prompt.connect('show-confirm', this._cancelPrompt.bind(this));
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-09-18 15:53:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_cancelPrompt() {
|
2013-09-18 15:53:26 +00:00
|
|
|
this.prompt.cancel();
|
|
|
|
}
|
2023-07-10 09:53:00 +00:00
|
|
|
}
|
2012-09-03 01:23:50 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
const KeyringPrompter = GObject.registerClass(
|
2019-05-28 21:07:51 +00:00
|
|
|
class KeyringPrompter extends Gcr.SystemPrompter {
|
|
|
|
_init() {
|
|
|
|
super._init();
|
|
|
|
this.connect('new-prompt', () => {
|
2019-08-19 19:33:15 +00:00
|
|
|
let dialog = this._enabled
|
|
|
|
? new KeyringDialog()
|
|
|
|
: new KeyringDummyDialog();
|
2017-10-31 00:38:18 +00:00
|
|
|
this._currentPrompt = dialog.prompt;
|
|
|
|
return this._currentPrompt;
|
|
|
|
});
|
2012-09-03 01:23:50 +00:00
|
|
|
this._dbusId = null;
|
2013-09-18 15:53:26 +00:00
|
|
|
this._registered = false;
|
|
|
|
this._enabled = false;
|
2013-09-27 14:04:25 +00:00
|
|
|
this._currentPrompt = null;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-09-03 01:23:50 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
enable() {
|
2013-09-18 15:53:26 +00:00
|
|
|
if (!this._registered) {
|
2019-05-28 21:07:51 +00:00
|
|
|
this.register(Gio.DBus.session);
|
2013-09-18 15:53:26 +00:00
|
|
|
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
|
|
|
|
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
|
|
|
|
this._registered = true;
|
|
|
|
}
|
|
|
|
this._enabled = true;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-09-03 01:23:50 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
disable() {
|
2013-09-18 15:53:26 +00:00
|
|
|
this._enabled = false;
|
2013-09-27 14:04:25 +00:00
|
|
|
|
2019-05-28 21:07:51 +00:00
|
|
|
if (this.prompting)
|
2013-09-27 14:04:25 +00:00
|
|
|
this._currentPrompt.cancel();
|
|
|
|
this._currentPrompt = null;
|
2012-09-03 01:23:50 +00:00
|
|
|
}
|
2019-05-28 21:07:51 +00:00
|
|
|
});
|
2012-09-03 01:23:50 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export {KeyringPrompter as Component};
|