d3d165243c
Clutter originally cluttered its namespace with key symbols, before prefixing all symbols with KEY. We still use the unprefixed symbols occasionally, replace them so mutter can drop the deprecated symbols. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/808
770 lines
28 KiB
JavaScript
770 lines
28 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||
/* exported ShellMountOperation, GnomeShellMountOpHandler */
|
||
|
||
const { Clutter, Gio, GLib, GObject, Pango, Shell, St } = imports.gi;
|
||
|
||
const Animation = imports.ui.animation;
|
||
const CheckBox = imports.ui.checkBox;
|
||
const Dialog = imports.ui.dialog;
|
||
const Main = imports.ui.main;
|
||
const MessageTray = imports.ui.messageTray;
|
||
const ModalDialog = imports.ui.modalDialog;
|
||
const Params = imports.misc.params;
|
||
const ShellEntry = imports.ui.shellEntry;
|
||
|
||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||
|
||
var LIST_ITEM_ICON_SIZE = 48;
|
||
var WORK_SPINNER_ICON_SIZE = 16;
|
||
|
||
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
|
||
|
||
/* ------ Common Utils ------- */
|
||
function _setButtonsForChoices(dialog, choices) {
|
||
let buttons = [];
|
||
|
||
for (let idx = 0; idx < choices.length; idx++) {
|
||
let button = idx;
|
||
buttons.unshift({
|
||
label: choices[idx],
|
||
action: () => dialog.emit('response', button),
|
||
});
|
||
}
|
||
|
||
dialog.setButtons(buttons);
|
||
}
|
||
|
||
function _setLabelsForMessage(content, message) {
|
||
let labels = message.split('\n');
|
||
|
||
content.title = labels.shift();
|
||
content.body = labels.join('\n');
|
||
}
|
||
|
||
/* -------------------------------------------------------- */
|
||
|
||
var ListItem = GObject.registerClass({
|
||
Signals: { 'activate': {} }
|
||
}, class ListItem extends St.Button {
|
||
_init(app) {
|
||
let layout = new St.BoxLayout({ vertical: false });
|
||
super._init({
|
||
style_class: 'mount-dialog-app-list-item',
|
||
can_focus: true,
|
||
child: layout,
|
||
reactive: true,
|
||
});
|
||
|
||
this._app = app;
|
||
|
||
this._icon = this._app.create_icon_texture(LIST_ITEM_ICON_SIZE);
|
||
|
||
let iconBin = new St.Bin({ style_class: 'mount-dialog-app-list-item-icon',
|
||
child: this._icon });
|
||
layout.add(iconBin);
|
||
|
||
this._nameLabel = new St.Label({
|
||
text: this._app.get_name(),
|
||
style_class: 'mount-dialog-app-list-item-name',
|
||
y_align: Clutter.ActorAlign.CENTER,
|
||
});
|
||
let labelBin = new St.Bin({ child: this._nameLabel });
|
||
layout.add(labelBin);
|
||
}
|
||
|
||
vfunc_clicked() {
|
||
this.emit('activate');
|
||
this._app.activate();
|
||
}
|
||
});
|
||
|
||
var ShellMountOperation = class {
|
||
constructor(source, params) {
|
||
params = Params.parse(params, { existingDialog: null });
|
||
|
||
this._dialog = null;
|
||
this._dialogId = 0;
|
||
this._existingDialog = params.existingDialog;
|
||
this._processesDialog = null;
|
||
|
||
this.mountOp = new Shell.MountOperation();
|
||
|
||
this.mountOp.connect('ask-question',
|
||
this._onAskQuestion.bind(this));
|
||
this.mountOp.connect('ask-password',
|
||
this._onAskPassword.bind(this));
|
||
this.mountOp.connect('show-processes-2',
|
||
this._onShowProcesses2.bind(this));
|
||
this.mountOp.connect('aborted',
|
||
this.close.bind(this));
|
||
this.mountOp.connect('show-unmount-progress',
|
||
this._onShowUnmountProgress.bind(this));
|
||
|
||
this._gicon = source.get_icon();
|
||
}
|
||
|
||
_closeExistingDialog() {
|
||
if (!this._existingDialog)
|
||
return;
|
||
|
||
this._existingDialog.close();
|
||
this._existingDialog = null;
|
||
}
|
||
|
||
_onAskQuestion(op, message, choices) {
|
||
this._closeExistingDialog();
|
||
this._dialog = new ShellMountQuestionDialog(this._gicon);
|
||
|
||
this._dialogId = this._dialog.connect('response',
|
||
(object, choice) => {
|
||
this.mountOp.set_choice(choice);
|
||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||
|
||
this.close();
|
||
});
|
||
|
||
this._dialog.update(message, choices);
|
||
this._dialog.open();
|
||
}
|
||
|
||
_onAskPassword(op, message, defaultUser, defaultDomain, flags) {
|
||
if (this._existingDialog) {
|
||
this._dialog = this._existingDialog;
|
||
this._dialog.reaskPassword();
|
||
} else {
|
||
this._dialog = new ShellMountPasswordDialog(message, this._gicon, flags);
|
||
}
|
||
|
||
this._dialogId = this._dialog.connect('response',
|
||
(object, choice, password, remember, hiddenVolume, systemVolume, pim) => {
|
||
if (choice == -1) {
|
||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||
} else {
|
||
if (remember)
|
||
this.mountOp.set_password_save(Gio.PasswordSave.PERMANENTLY);
|
||
else
|
||
this.mountOp.set_password_save(Gio.PasswordSave.NEVER);
|
||
|
||
this.mountOp.set_password(password);
|
||
this.mountOp.set_is_tcrypt_hidden_volume(hiddenVolume);
|
||
this.mountOp.set_is_tcrypt_system_volume(systemVolume);
|
||
this.mountOp.set_pim(pim);
|
||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||
}
|
||
});
|
||
this._dialog.open();
|
||
}
|
||
|
||
close(_op) {
|
||
this._closeExistingDialog();
|
||
this._processesDialog = null;
|
||
|
||
if (this._dialog) {
|
||
this._dialog.close();
|
||
this._dialog = null;
|
||
}
|
||
|
||
if (this._notifier) {
|
||
this._notifier.done();
|
||
this._notifier = null;
|
||
}
|
||
}
|
||
|
||
_onShowProcesses2(op) {
|
||
this._closeExistingDialog();
|
||
|
||
let processes = op.get_show_processes_pids();
|
||
let choices = op.get_show_processes_choices();
|
||
let message = op.get_show_processes_message();
|
||
|
||
if (!this._processesDialog) {
|
||
this._processesDialog = new ShellProcessesDialog(this._gicon);
|
||
this._dialog = this._processesDialog;
|
||
|
||
this._dialogId = this._processesDialog.connect('response',
|
||
(object, choice) => {
|
||
if (choice == -1) {
|
||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||
} else {
|
||
this.mountOp.set_choice(choice);
|
||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||
}
|
||
|
||
this.close();
|
||
});
|
||
this._processesDialog.open();
|
||
}
|
||
|
||
this._processesDialog.update(message, processes, choices);
|
||
}
|
||
|
||
_onShowUnmountProgress(op, message, timeLeft, bytesLeft) {
|
||
if (!this._notifier)
|
||
this._notifier = new ShellUnmountNotifier();
|
||
|
||
if (bytesLeft == 0)
|
||
this._notifier.done(message);
|
||
else
|
||
this._notifier.show(message);
|
||
}
|
||
|
||
borrowDialog() {
|
||
if (this._dialogId != 0) {
|
||
this._dialog.disconnect(this._dialogId);
|
||
this._dialogId = 0;
|
||
}
|
||
|
||
return this._dialog;
|
||
}
|
||
};
|
||
|
||
var ShellUnmountNotifier = GObject.registerClass(
|
||
class ShellUnmountNotifier extends MessageTray.Source {
|
||
_init() {
|
||
super._init('', 'media-removable');
|
||
|
||
this._notification = null;
|
||
Main.messageTray.add(this);
|
||
}
|
||
|
||
show(message) {
|
||
let [header, text] = message.split('\n', 2);
|
||
|
||
if (!this._notification) {
|
||
this._notification = new MessageTray.Notification(this, header, text);
|
||
this._notification.setTransient(true);
|
||
this._notification.setUrgency(MessageTray.Urgency.CRITICAL);
|
||
} else {
|
||
this._notification.update(header, text);
|
||
}
|
||
|
||
this.showNotification(this._notification);
|
||
}
|
||
|
||
done(message) {
|
||
if (this._notification) {
|
||
this._notification.destroy();
|
||
this._notification = null;
|
||
}
|
||
|
||
if (message) {
|
||
let notification = new MessageTray.Notification(this, message, null);
|
||
notification.setTransient(true);
|
||
|
||
this.showNotification(notification);
|
||
}
|
||
}
|
||
});
|
||
|
||
var ShellMountQuestionDialog = GObject.registerClass({
|
||
Signals: { 'response': { param_types: [GObject.TYPE_INT] } }
|
||
}, class ShellMountQuestionDialog extends ModalDialog.ModalDialog {
|
||
_init(icon) {
|
||
super._init({ styleClass: 'mount-dialog' });
|
||
|
||
this._content = new Dialog.MessageDialogContent({ icon });
|
||
this.contentLayout.add_child(this._content);
|
||
}
|
||
|
||
update(message, choices) {
|
||
_setLabelsForMessage(this._content, message);
|
||
_setButtonsForChoices(this, choices);
|
||
}
|
||
});
|
||
|
||
var ShellMountPasswordDialog = GObject.registerClass({
|
||
Signals: { 'response': { param_types: [GObject.TYPE_INT,
|
||
GObject.TYPE_STRING,
|
||
GObject.TYPE_BOOLEAN,
|
||
GObject.TYPE_BOOLEAN,
|
||
GObject.TYPE_BOOLEAN,
|
||
GObject.TYPE_UINT] } }
|
||
}, class ShellMountPasswordDialog extends ModalDialog.ModalDialog {
|
||
_init(message, icon, flags) {
|
||
let strings = message.split('\n');
|
||
let title = strings.shift() || null;
|
||
let body = strings.shift() || null;
|
||
super._init({ styleClass: 'prompt-dialog' });
|
||
|
||
let disksApp = Shell.AppSystem.get_default().lookup_app('org.gnome.DiskUtility.desktop');
|
||
|
||
let content = new Dialog.MessageDialogContent({ icon, title, body });
|
||
this.contentLayout.add_actor(content);
|
||
content._body.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||
|
||
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||
let grid = new St.Widget({ style_class: 'prompt-dialog-grid',
|
||
layout_manager: layout });
|
||
layout.hookup_style(grid);
|
||
let rtl = grid.get_text_direction() === Clutter.TextDirection.RTL;
|
||
|
||
if (flags & Gio.AskPasswordFlags.TCRYPT) {
|
||
this._keyfilesLabel = new St.Label({
|
||
style_class: 'prompt-dialog-keyfiles-label',
|
||
visible: false,
|
||
y_align: Clutter.ActorAlign.CENTER,
|
||
});
|
||
|
||
this._hiddenVolume = new CheckBox.CheckBox(_("Hidden Volume"));
|
||
content.messageBox.add(this._hiddenVolume);
|
||
|
||
this._systemVolume = new CheckBox.CheckBox(_("Windows System Volume"));
|
||
content.messageBox.add(this._systemVolume);
|
||
|
||
this._keyfilesCheckbox = new CheckBox.CheckBox(_("Uses Keyfiles"));
|
||
this._keyfilesCheckbox.connect("clicked", this._onKeyfilesCheckboxClicked.bind(this));
|
||
content.messageBox.add(this._keyfilesCheckbox);
|
||
|
||
this._keyfilesLabel.clutter_text.set_markup(
|
||
/* Translators: %s is the Disks application */
|
||
_("To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.").format(disksApp.get_name())
|
||
);
|
||
this._keyfilesLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||
this._keyfilesLabel.clutter_text.line_wrap = true;
|
||
content.messageBox.add_child(this._keyfilesLabel);
|
||
|
||
this._pimLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||
text: _("PIM Number"),
|
||
y_align: Clutter.ActorAlign.CENTER });
|
||
this._pimEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||
can_focus: true,
|
||
x_expand: true });
|
||
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||
this._pimEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||
ShellEntry.addContextMenu(this._pimEntry, { isPassword: true });
|
||
|
||
if (rtl) {
|
||
layout.attach(this._pimEntry, 0, 0, 1, 1);
|
||
layout.attach(this._pimLabel, 1, 0, 1, 1);
|
||
} else {
|
||
layout.attach(this._pimLabel, 0, 0, 1, 1);
|
||
layout.attach(this._pimEntry, 1, 0, 1, 1);
|
||
}
|
||
|
||
this._pimErrorMessageLabel = new St.Label({ style_class: 'prompt-dialog-password-entry',
|
||
text: _("The PIM must be a number or empty."),
|
||
visible: false });
|
||
layout.attach(this._pimErrorMessageLabel, 0, 2, 2, 1);
|
||
} else {
|
||
this._hiddenVolume = null;
|
||
this._systemVolume = null;
|
||
this._pimEntry = null;
|
||
this._pimErrorMessageLabel = null;
|
||
}
|
||
|
||
this._passwordLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||
text: _("Password"),
|
||
y_align: Clutter.ActorAlign.CENTER });
|
||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||
can_focus: true,
|
||
x_expand: true });
|
||
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||
this.setInitialKeyFocus(this._passwordEntry);
|
||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
|
||
this._passwordEntry.secondary_icon = this._workSpinner;
|
||
|
||
if (rtl) {
|
||
layout.attach(this._passwordEntry, 0, 1, 1, 1);
|
||
layout.attach(this._passwordLabel, 1, 1, 1, 1);
|
||
} else {
|
||
layout.attach(this._passwordLabel, 0, 1, 1, 1);
|
||
layout.attach(this._passwordEntry, 1, 1, 1, 1);
|
||
}
|
||
|
||
content.messageBox.add(grid);
|
||
|
||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
|
||
text: _("Sorry, that didn’t work. Please try again.") });
|
||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||
this._errorMessageLabel.hide();
|
||
content.messageBox.add(this._errorMessageLabel);
|
||
|
||
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
||
this._rememberChoice = new CheckBox.CheckBox(_("Remember Password"));
|
||
this._rememberChoice.checked =
|
||
global.settings.get_boolean(REMEMBER_MOUNT_PASSWORD_KEY);
|
||
content.messageBox.add(this._rememberChoice);
|
||
} else {
|
||
this._rememberChoice = null;
|
||
}
|
||
|
||
this._defaultButtons = [{
|
||
label: _("Cancel"),
|
||
action: this._onCancelButton.bind(this),
|
||
key: Clutter.KEY_Escape,
|
||
}, {
|
||
label: _("Unlock"),
|
||
action: this._onUnlockButton.bind(this),
|
||
default: true,
|
||
}];
|
||
|
||
this._usesKeyfilesButtons = [{
|
||
label: _("Cancel"),
|
||
action: this._onCancelButton.bind(this),
|
||
key: Clutter.KEY_Escape,
|
||
}, {
|
||
/* Translators: %s is the Disks application */
|
||
label: _("Open %s").format(disksApp.get_name()),
|
||
action: this._onOpenDisksButton.bind(this),
|
||
default: true,
|
||
}];
|
||
|
||
this.setButtons(this._defaultButtons);
|
||
}
|
||
|
||
reaskPassword() {
|
||
this._passwordEntry.set_text('');
|
||
this._errorMessageLabel.show();
|
||
this._workSpinner.stop();
|
||
}
|
||
|
||
_onCancelButton() {
|
||
this.emit('response', -1, '', false, false, false, 0);
|
||
}
|
||
|
||
_onUnlockButton() {
|
||
this._onEntryActivate();
|
||
}
|
||
|
||
_onEntryActivate() {
|
||
let pim = 0;
|
||
if (this._pimEntry !== null)
|
||
pim = this._pimEntry.get_text();
|
||
if (isNaN(pim)) {
|
||
this._pimEntry.set_text('');
|
||
this._pimErrorMessageLabel.show();
|
||
return;
|
||
} else if (this._pimErrorMessageLabel !== null) {
|
||
this._pimErrorMessageLabel.hide();
|
||
}
|
||
|
||
global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
|
||
this._rememberChoice && this._rememberChoice.checked);
|
||
|
||
this._workSpinner.play();
|
||
this.emit('response', 1,
|
||
this._passwordEntry.get_text(),
|
||
this._rememberChoice &&
|
||
this._rememberChoice.checked,
|
||
this._hiddenVolume &&
|
||
this._hiddenVolume.checked,
|
||
this._systemVolume &&
|
||
this._systemVolume.checked,
|
||
parseInt(pim));
|
||
}
|
||
|
||
_onKeyfilesCheckboxClicked() {
|
||
let useKeyfiles = this._keyfilesCheckbox.checked;
|
||
this._passwordEntry.reactive = !useKeyfiles;
|
||
this._passwordEntry.can_focus = !useKeyfiles;
|
||
this._passwordEntry.clutter_text.editable = !useKeyfiles;
|
||
this._passwordEntry.clutter_text.selectable = !useKeyfiles;
|
||
this._pimEntry.reactive = !useKeyfiles;
|
||
this._pimEntry.can_focus = !useKeyfiles;
|
||
this._pimEntry.clutter_text.editable = !useKeyfiles;
|
||
this._pimEntry.clutter_text.selectable = !useKeyfiles;
|
||
this._rememberChoice.reactive = !useKeyfiles;
|
||
this._rememberChoice.can_focus = !useKeyfiles;
|
||
this._keyfilesLabel.visible = useKeyfiles;
|
||
this.setButtons(useKeyfiles ? this._usesKeyfilesButtons : this._defaultButtons);
|
||
}
|
||
|
||
_onOpenDisksButton() {
|
||
let app = Shell.AppSystem.get_default().lookup_app('org.gnome.DiskUtility.desktop');
|
||
if (app)
|
||
app.activate();
|
||
else
|
||
Main.notifyError(
|
||
/* Translators: %s is the Disks application */
|
||
_("Unable to start %s").format(app.get_name()),
|
||
/* Translators: %s is the Disks application */
|
||
_("Couldn’t find the %s application").format(app.get_name())
|
||
);
|
||
this._onCancelButton();
|
||
}
|
||
});
|
||
|
||
var ShellProcessesDialog = GObject.registerClass({
|
||
Signals: { 'response': { param_types: [GObject.TYPE_INT] } }
|
||
}, class ShellProcessesDialog extends ModalDialog.ModalDialog {
|
||
_init(icon) {
|
||
super._init({ styleClass: 'mount-dialog' });
|
||
|
||
this._content = new Dialog.MessageDialogContent({ icon });
|
||
this.contentLayout.add_child(this._content);
|
||
|
||
let scrollView = new St.ScrollView({
|
||
style_class: 'mount-dialog-app-list',
|
||
x_expand: true,
|
||
y_expand: true,
|
||
});
|
||
scrollView.set_policy(St.PolicyType.NEVER,
|
||
St.PolicyType.AUTOMATIC);
|
||
this.contentLayout.add_child(scrollView);
|
||
scrollView.hide();
|
||
|
||
this._applicationList = new St.BoxLayout({ vertical: true });
|
||
scrollView.add_actor(this._applicationList);
|
||
|
||
this._applicationList.connect('actor-added', () => {
|
||
if (this._applicationList.get_n_children() == 1)
|
||
scrollView.show();
|
||
});
|
||
|
||
this._applicationList.connect('actor-removed', () => {
|
||
if (this._applicationList.get_n_children() == 0)
|
||
scrollView.hide();
|
||
});
|
||
}
|
||
|
||
_setAppsForPids(pids) {
|
||
// remove all the items
|
||
this._applicationList.destroy_all_children();
|
||
|
||
pids.forEach(pid => {
|
||
let tracker = Shell.WindowTracker.get_default();
|
||
let app = tracker.get_app_from_pid(pid);
|
||
|
||
if (!app)
|
||
return;
|
||
|
||
let item = new ListItem(app);
|
||
this._applicationList.add_child(item);
|
||
|
||
item.connect('activate', () => {
|
||
// use -1 to indicate Cancel
|
||
this.emit('response', -1);
|
||
});
|
||
});
|
||
}
|
||
|
||
update(message, processes, choices) {
|
||
this._setAppsForPids(processes);
|
||
_setLabelsForMessage(this._content, message);
|
||
_setButtonsForChoices(this, choices);
|
||
}
|
||
});
|
||
|
||
const GnomeShellMountOpIface = loadInterfaceXML('org.Gtk.MountOperationHandler');
|
||
|
||
var ShellMountOperationType = {
|
||
NONE: 0,
|
||
ASK_PASSWORD: 1,
|
||
ASK_QUESTION: 2,
|
||
SHOW_PROCESSES: 3
|
||
};
|
||
|
||
var GnomeShellMountOpHandler = class {
|
||
constructor() {
|
||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellMountOpIface, this);
|
||
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
|
||
Gio.bus_own_name_on_connection(Gio.DBus.session, 'org.gtk.MountOperationHandler',
|
||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||
|
||
this._dialog = null;
|
||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||
|
||
this._ensureEmptyRequest();
|
||
}
|
||
|
||
_ensureEmptyRequest() {
|
||
this._currentId = null;
|
||
this._currentInvocation = null;
|
||
this._currentType = ShellMountOperationType.NONE;
|
||
}
|
||
|
||
_clearCurrentRequest(response, details) {
|
||
if (this._currentInvocation) {
|
||
this._currentInvocation.return_value(
|
||
GLib.Variant.new('(ua{sv})', [response, details]));
|
||
}
|
||
|
||
this._ensureEmptyRequest();
|
||
}
|
||
|
||
_setCurrentRequest(invocation, id, type) {
|
||
let oldId = this._currentId;
|
||
let oldType = this._currentType;
|
||
let requestId = `${id}@${invocation.get_sender()}`;
|
||
|
||
this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
|
||
|
||
this._currentInvocation = invocation;
|
||
this._currentId = requestId;
|
||
this._currentType = type;
|
||
|
||
if (this._dialog && (oldId == requestId) && (oldType == type))
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
_closeDialog() {
|
||
if (this._dialog) {
|
||
this._dialog.close();
|
||
this._dialog = null;
|
||
}
|
||
}
|
||
|
||
_createGIcon(iconName) {
|
||
let realIconName = iconName ? iconName : 'drive-harddisk';
|
||
return new Gio.ThemedIcon({ name: realIconName,
|
||
use_default_fallbacks: true });
|
||
}
|
||
|
||
/**
|
||
* AskPassword:
|
||
* @id: an opaque ID identifying the object for which the operation is requested
|
||
* The ID must be unique in the context of the calling process.
|
||
* @message: the message to display
|
||
* @icon_name: the name of an icon to display
|
||
* @default_user: the default username for display
|
||
* @default_domain: the default domain for display
|
||
* @flags: a set of GAskPasswordFlags
|
||
* @response: a GMountOperationResult
|
||
* @response_details: a dictionary containing the response details as
|
||
* entered by the user. The dictionary MAY contain the following properties:
|
||
* - "password" -> (s): a password to be used to complete the mount operation
|
||
* - "password_save" -> (u): a GPasswordSave
|
||
*
|
||
* The dialog will stay visible until clients call the Close() method, or
|
||
* another dialog becomes visible.
|
||
* Calling AskPassword again for the same id will have the effect to clear
|
||
* the existing dialog and update it with a message indicating the previous
|
||
* attempt went wrong.
|
||
*/
|
||
AskPasswordAsync(params, invocation) {
|
||
let [id, message, iconName, defaultUser_, defaultDomain_, flags] = params;
|
||
|
||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_PASSWORD)) {
|
||
this._dialog.reaskPassword();
|
||
return;
|
||
}
|
||
|
||
this._closeDialog();
|
||
|
||
this._dialog = new ShellMountPasswordDialog(message, this._createGIcon(iconName), flags);
|
||
this._dialog.connect('response',
|
||
(object, choice, password, remember, hiddenVolume, systemVolume, pim) => {
|
||
let details = {};
|
||
let response;
|
||
|
||
if (choice == -1) {
|
||
response = Gio.MountOperationResult.ABORTED;
|
||
} else {
|
||
response = Gio.MountOperationResult.HANDLED;
|
||
|
||
let passSave = remember ? Gio.PasswordSave.PERMANENTLY : Gio.PasswordSave.NEVER;
|
||
details['password_save'] = GLib.Variant.new('u', passSave);
|
||
details['password'] = GLib.Variant.new('s', password);
|
||
details['hidden_volume'] = GLib.Variant.new('b', hiddenVolume);
|
||
details['system_volume'] = GLib.Variant.new('b', systemVolume);
|
||
details['pim'] = GLib.Variant.new('u', pim);
|
||
}
|
||
|
||
this._clearCurrentRequest(response, details);
|
||
});
|
||
this._dialog.open();
|
||
}
|
||
|
||
/**
|
||
* AskQuestion:
|
||
* @id: an opaque ID identifying the object for which the operation is requested
|
||
* The ID must be unique in the context of the calling process.
|
||
* @message: the message to display
|
||
* @icon_name: the name of an icon to display
|
||
* @choices: an array of choice strings
|
||
* GetResponse:
|
||
* @response: a GMountOperationResult
|
||
* @response_details: a dictionary containing the response details as
|
||
* entered by the user. The dictionary MAY contain the following properties:
|
||
* - "choice" -> (i): the chosen answer among the array of strings passed in
|
||
*
|
||
* The dialog will stay visible until clients call the Close() method, or
|
||
* another dialog becomes visible.
|
||
* Calling AskQuestion again for the same id will have the effect to clear
|
||
* update the dialog with the new question.
|
||
*/
|
||
AskQuestionAsync(params, invocation) {
|
||
let [id, message, iconName, choices] = params;
|
||
|
||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_QUESTION)) {
|
||
this._dialog.update(message, choices);
|
||
return;
|
||
}
|
||
|
||
this._closeDialog();
|
||
|
||
this._dialog = new ShellMountQuestionDialog(this._createGIcon(iconName), message);
|
||
this._dialog.connect('response', (object, choice) => {
|
||
this._clearCurrentRequest(Gio.MountOperationResult.HANDLED,
|
||
{ choice: GLib.Variant.new('i', choice) });
|
||
});
|
||
|
||
this._dialog.update(message, choices);
|
||
this._dialog.open();
|
||
}
|
||
|
||
/**
|
||
* ShowProcesses:
|
||
* @id: an opaque ID identifying the object for which the operation is requested
|
||
* The ID must be unique in the context of the calling process.
|
||
* @message: the message to display
|
||
* @icon_name: the name of an icon to display
|
||
* @application_pids: the PIDs of the applications to display
|
||
* @choices: an array of choice strings
|
||
* @response: a GMountOperationResult
|
||
* @response_details: a dictionary containing the response details as
|
||
* entered by the user. The dictionary MAY contain the following properties:
|
||
* - "choice" -> (i): the chosen answer among the array of strings passed in
|
||
*
|
||
* The dialog will stay visible until clients call the Close() method, or
|
||
* another dialog becomes visible.
|
||
* Calling ShowProcesses again for the same id will have the effect to clear
|
||
* the existing dialog and update it with the new message and the new list
|
||
* of processes.
|
||
*/
|
||
ShowProcessesAsync(params, invocation) {
|
||
let [id, message, iconName, applicationPids, choices] = params;
|
||
|
||
if (this._setCurrentRequest(invocation, id, ShellMountOperationType.SHOW_PROCESSES)) {
|
||
this._dialog.update(message, applicationPids, choices);
|
||
return;
|
||
}
|
||
|
||
this._closeDialog();
|
||
|
||
this._dialog = new ShellProcessesDialog(this._createGIcon(iconName));
|
||
this._dialog.connect('response', (object, choice) => {
|
||
let response;
|
||
let details = {};
|
||
|
||
if (choice == -1) {
|
||
response = Gio.MountOperationResult.ABORTED;
|
||
} else {
|
||
response = Gio.MountOperationResult.HANDLED;
|
||
details['choice'] = GLib.Variant.new('i', choice);
|
||
}
|
||
|
||
this._clearCurrentRequest(response, details);
|
||
});
|
||
|
||
this._dialog.update(message, applicationPids, choices);
|
||
this._dialog.open();
|
||
}
|
||
|
||
/**
|
||
* Close:
|
||
*
|
||
* Closes a dialog previously opened by AskPassword, AskQuestion or ShowProcesses.
|
||
* If no dialog is open, does nothing.
|
||
*/
|
||
Close(_params, _invocation) {
|
||
this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
|
||
this._closeDialog();
|
||
}
|
||
};
|