2012-01-10 15:37:26 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
|
|
|
|
const Lang = imports.lang;
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const St = imports.gi.St;
|
|
|
|
const Pango = imports.gi.Pango;
|
|
|
|
const Gio = imports.gi.Gio;
|
|
|
|
const GObject = imports.gi.GObject;
|
|
|
|
const Gcr = imports.gi.Gcr;
|
|
|
|
|
2015-07-29 11:45:11 +00:00
|
|
|
const Animation = imports.ui.animation;
|
2017-07-15 04:03:55 +00:00
|
|
|
const Dialog = imports.ui.dialog;
|
2012-01-10 15:37:26 +00:00
|
|
|
const ModalDialog = imports.ui.modalDialog;
|
|
|
|
const ShellEntry = imports.ui.shellEntry;
|
|
|
|
const CheckBox = imports.ui.checkBox;
|
2015-07-29 11:45:11 +00:00
|
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var WORK_SPINNER_ICON_SIZE = 16;
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2017-07-18 17:41:25 +00:00
|
|
|
var KeyringDialog = new Lang.Class({
|
2012-01-10 15:37:26 +00:00
|
|
|
Name: 'KeyringDialog',
|
|
|
|
Extends: ModalDialog.ModalDialog,
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this.parent({ styleClass: 'prompt-dialog' });
|
|
|
|
|
|
|
|
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
|
|
|
|
2017-07-15 04:03:55 +00:00
|
|
|
let icon = new Gio.ThemedIcon({ name: 'dialog-password-symbolic' });
|
|
|
|
this._content = new Dialog.MessageDialogContent({ icon });
|
|
|
|
this.contentLayout.add(this._content);
|
|
|
|
|
|
|
|
// FIXME: Why does this break now?
|
|
|
|
/*
|
|
|
|
this.prompt.bind_property('message', this._content, 'title', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('description', this._content, 'body', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
*/
|
|
|
|
this.prompt.connect('notify::message', () => {
|
|
|
|
this._content.title = this.prompt.message;
|
|
|
|
});
|
|
|
|
this._content.title = this.prompt.message;
|
|
|
|
|
|
|
|
this.prompt.connect('notify::description', () => {
|
|
|
|
this._content.body = this.prompt.description;
|
|
|
|
});
|
|
|
|
this._content.body = this.prompt.description;
|
2012-01-10 15:37:26 +00:00
|
|
|
|
2015-07-29 11:45:11 +00:00
|
|
|
this._workSpinner = null;
|
2012-01-10 15:37:26 +00:00
|
|
|
this._controlTable = null;
|
|
|
|
|
2012-12-21 16:04:57 +00:00
|
|
|
this._cancelButton = this.addButton({ label: '',
|
2017-12-02 00:27:35 +00:00
|
|
|
action: this._onCancelButton.bind(this),
|
2015-07-29 11:45:11 +00:00
|
|
|
key: Clutter.Escape });
|
2012-12-21 16:04:57 +00:00
|
|
|
this._continueButton = this.addButton({ label: '',
|
2017-12-02 00:27:35 +00:00
|
|
|
action: this._onContinueButton.bind(this),
|
2015-07-29 11:45:11 +00:00
|
|
|
default: true });
|
2012-01-10 15:37:26 +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 00:03:21 +00:00
|
|
|
_setWorking(working) {
|
2015-07-29 11:45:11 +00:00
|
|
|
if (!this._workSpinner)
|
|
|
|
return;
|
|
|
|
|
2018-11-28 16:34:48 +00:00
|
|
|
if (working)
|
2015-07-29 11:45:11 +00:00
|
|
|
this._workSpinner.play();
|
2018-11-28 16:34:48 +00:00
|
|
|
else
|
|
|
|
this._workSpinner.stop();
|
2015-07-29 11:45:11 +00:00
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_buildControlTable() {
|
2013-11-19 14:07:58 +00:00
|
|
|
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
2013-07-09 01:02:58 +00:00
|
|
|
let table = new St.Widget({ style_class: 'keyring-dialog-control-table',
|
|
|
|
layout_manager: layout });
|
|
|
|
layout.hookup_style(table);
|
2014-09-12 10:27:14 +00:00
|
|
|
let rtl = table.get_text_direction() == Clutter.TextDirection.RTL;
|
2012-01-10 15:37:26 +00:00
|
|
|
let row = 0;
|
|
|
|
|
|
|
|
if (this.prompt.password_visible) {
|
2013-11-19 14:07:58 +00:00
|
|
|
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER });
|
2012-01-10 15:37:26 +00:00
|
|
|
label.set_text(_("Password:"));
|
2013-09-18 19:39:23 +00:00
|
|
|
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
2012-01-10 15:37:26 +00:00
|
|
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
|
|
|
text: '',
|
2013-11-19 14:07:58 +00:00
|
|
|
can_focus: true,
|
|
|
|
x_expand: true });
|
2012-01-10 15:37:26 +00:00
|
|
|
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
|
|
|
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
2017-12-02 00:27:35 +00:00
|
|
|
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
|
2014-09-12 10:27:14 +00:00
|
|
|
|
2018-11-28 16:34:48 +00:00
|
|
|
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
|
2015-07-29 11:45:11 +00:00
|
|
|
|
2014-09-12 10:27:14 +00:00
|
|
|
if (rtl) {
|
2015-07-29 11:45:11 +00:00
|
|
|
layout.attach(this._workSpinner.actor, 0, row, 1, 1);
|
|
|
|
layout.attach(this._passwordEntry, 1, row, 1, 1);
|
|
|
|
layout.attach(label, 2, row, 1, 1);
|
2014-09-12 10:27:14 +00:00
|
|
|
} else {
|
|
|
|
layout.attach(label, 0, row, 1, 1);
|
|
|
|
layout.attach(this._passwordEntry, 1, row, 1, 1);
|
2015-07-29 11:45:11 +00:00
|
|
|
layout.attach(this._workSpinner.actor, 2, row, 1, 1);
|
2014-09-12 10:27:14 +00:00
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
row++;
|
|
|
|
} else {
|
2015-07-29 11:45:11 +00:00
|
|
|
this._workSpinner = null;
|
2012-01-10 15:37:26 +00:00
|
|
|
this._passwordEntry = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.prompt.confirm_visible) {
|
2013-11-19 14:07:58 +00:00
|
|
|
var label = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
|
|
|
x_align: Clutter.ActorAlign.START,
|
|
|
|
y_align: Clutter.ActorAlign.CENTER }));
|
2012-01-10 15:37:26 +00:00
|
|
|
label.set_text(_("Type again:"));
|
|
|
|
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
|
|
|
text: '',
|
2013-11-19 14:07:58 +00:00
|
|
|
can_focus: true,
|
|
|
|
x_expand: true });
|
2012-01-10 15:37:26 +00:00
|
|
|
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
|
|
|
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
2017-12-02 00:27:35 +00:00
|
|
|
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
|
2014-09-12 10:27:14 +00:00
|
|
|
if (rtl) {
|
|
|
|
layout.attach(this._confirmEntry, 0, row, 1, 1);
|
|
|
|
layout.attach(label, 1, row, 1, 1);
|
|
|
|
} else {
|
|
|
|
layout.attach(label, 0, row, 1, 1);
|
|
|
|
layout.attach(this._confirmEntry, 1, row, 1, 1);
|
|
|
|
}
|
2012-01-10 15:37:26 +00:00
|
|
|
row++;
|
|
|
|
} else {
|
|
|
|
this._confirmEntry = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
|
|
|
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
|
|
|
|
|
|
|
if (this.prompt.choice_visible) {
|
|
|
|
let choice = new CheckBox.CheckBox();
|
|
|
|
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
2014-09-12 10:27:14 +00:00
|
|
|
layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
|
2012-01-10 15:37:26 +00:00
|
|
|
row++;
|
|
|
|
}
|
|
|
|
|
2013-11-19 14:07:58 +00:00
|
|
|
let warning = new St.Label({ style_class: 'prompt-dialog-error-label',
|
|
|
|
x_align: Clutter.ActorAlign.START });
|
2012-01-10 15:37:26 +00:00
|
|
|
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
|
|
|
warning.clutter_text.line_wrap = true;
|
2014-09-12 10:27:14 +00:00
|
|
|
layout.attach(warning, rtl ? 0 : 1, row, 1, 1);
|
2012-01-10 15:37:26 +00:00
|
|
|
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
|
|
|
|
|
|
|
if (this._controlTable) {
|
|
|
|
this._controlTable.destroy_all_children();
|
|
|
|
this._controlTable.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
this._controlTable = table;
|
2017-07-15 04:03:55 +00:00
|
|
|
this._content.messageBox.add(table, { x_fill: true, y_fill: true });
|
2012-01-10 15:37:26 +00:00
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateSensitivity(sensitive) {
|
2013-04-17 10:02:12 +00:00
|
|
|
if (this._passwordEntry) {
|
|
|
|
this._passwordEntry.reactive = sensitive;
|
|
|
|
this._passwordEntry.clutter_text.editable = sensitive;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._confirmEntry) {
|
|
|
|
this._confirmEntry.reactive = sensitive;
|
|
|
|
this._confirmEntry.clutter_text.editable = 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;
|
2015-07-29 11:45:11 +00:00
|
|
|
this._setWorking(!sensitive);
|
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())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// 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');
|
|
|
|
this.prompt.cancel()
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onShowPassword(prompt) {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._buildControlTable();
|
|
|
|
this._ensureOpen();
|
2012-12-28 08:20:18 +00:00
|
|
|
this._updateSensitivity(true);
|
2012-01-10 15:37:26 +00:00
|
|
|
this._passwordEntry.grab_key_focus();
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onShowConfirm(prompt) {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._buildControlTable();
|
|
|
|
this._ensureOpen();
|
2012-12-28 08:20:18 +00:00
|
|
|
this._updateSensitivity(true);
|
2012-01-10 15:37:26 +00:00
|
|
|
this._continueButton.grab_key_focus();
|
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onHidePrompt(prompt) {
|
2012-01-10 15:37:26 +00:00
|
|
|
this.close();
|
|
|
|
},
|
|
|
|
|
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 00:03:21 +00:00
|
|
|
_onConfirmActivate() {
|
2012-01-10 15:37:26 +00:00
|
|
|
this._onContinueButton();
|
|
|
|
},
|
|
|
|
|
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();
|
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();
|
2012-01-10 15:37:26 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-07-18 17:41:25 +00:00
|
|
|
var KeyringDummyDialog = new Lang.Class({
|
2013-09-18 15:53:26 +00:00
|
|
|
Name: 'KeyringDummyDialog',
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
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));
|
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();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-07-18 17:41:25 +00:00
|
|
|
var KeyringPrompter = new Lang.Class({
|
2012-09-03 01:23:50 +00:00
|
|
|
Name: 'KeyringPrompter',
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2012-09-03 01:23:50 +00:00
|
|
|
this._prompter = new Gcr.SystemPrompter();
|
2017-10-31 00:38:18 +00:00
|
|
|
this._prompter.connect('new-prompt', () => {
|
|
|
|
let dialog = this._enabled ? new KeyringDialog()
|
|
|
|
: new KeyringDummyDialog();
|
|
|
|
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;
|
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) {
|
|
|
|
this._prompter.register(Gio.DBus.session);
|
|
|
|
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
|
|
|
|
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
|
|
|
|
this._registered = true;
|
|
|
|
}
|
|
|
|
this._enabled = true;
|
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
|
|
|
|
|
|
|
if (this._prompter.prompting)
|
|
|
|
this._currentPrompt.cancel();
|
|
|
|
this._currentPrompt = null;
|
2012-09-03 01:23:50 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var Component = KeyringPrompter;
|