8423ba44fe
These traditionally got the various ClutterEvent subtype structs as their argument, so it was not allowed to use ClutterEvent generic getter methods in these vfuncs. These methods used direct access to struct fields instead. This got spoiled with the move to make ClutterEvent opaque types, since these are no longer public structs so GNOME Shell most silently failed to fetch the expected values from event fields. But since they are not ClutterEvents either, the getters could not be used on them. Mutter is changing so that these vmethods all contain an alias to the one and only Clutter.Event type, thus lifting those barriers, and making it possible to use the ClutterEvent methods in these vfuncs. Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2950 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2872>
757 lines
26 KiB
JavaScript
757 lines
26 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||
|
||
import Clutter from 'gi://Clutter';
|
||
import Gio from 'gi://Gio';
|
||
import GLib from 'gi://GLib';
|
||
import GObject from 'gi://GObject';
|
||
import Pango from 'gi://Pango';
|
||
import Shell from 'gi://Shell';
|
||
import St from 'gi://St';
|
||
|
||
import * as Animation from './animation.js';
|
||
import * as CheckBox from './checkBox.js';
|
||
import * as Dialog from './dialog.js';
|
||
import * as Main from './main.js';
|
||
import * as MessageTray from './messageTray.js';
|
||
import * as ModalDialog from './modalDialog.js';
|
||
import * as Params from '../misc/params.js';
|
||
import * as ShellEntry from './shellEntry.js';
|
||
|
||
import {loadInterfaceXML} from '../misc/fileUtils.js';
|
||
import {wiggle} from '../misc/animationUtils.js';
|
||
|
||
const LIST_ITEM_ICON_SIZE = 48;
|
||
const WORK_SPINNER_ICON_SIZE = 16;
|
||
|
||
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
|
||
|
||
/* ------ Common Utils ------- */
|
||
function _setButtonsForChoices(dialog, oldChoices, choices) {
|
||
let buttons = [];
|
||
let buttonsChanged = oldChoices.length !== choices.length;
|
||
|
||
for (let idx = 0; idx < choices.length; idx++) {
|
||
let button = idx;
|
||
|
||
buttonsChanged ||= oldChoices[idx] !== choices[idx];
|
||
|
||
buttons.unshift({
|
||
label: choices[idx],
|
||
action: () => dialog.emit('response', button),
|
||
});
|
||
}
|
||
|
||
if (buttonsChanged)
|
||
dialog.setButtons(buttons);
|
||
}
|
||
|
||
function _setLabelsForMessage(content, message) {
|
||
let labels = message.split('\n');
|
||
|
||
content.title = labels.shift();
|
||
content.description = labels.join('\n');
|
||
}
|
||
|
||
/* -------------------------------------------------------- */
|
||
|
||
export class ShellMountOperation {
|
||
constructor(source, params) {
|
||
params = Params.parse(params, { existingDialog: null });
|
||
|
||
this._dialog = null;
|
||
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));
|
||
}
|
||
|
||
_closeExistingDialog() {
|
||
if (!this._existingDialog)
|
||
return;
|
||
|
||
this._existingDialog.close();
|
||
this._existingDialog = null;
|
||
}
|
||
|
||
_onAskQuestion(op, message, choices) {
|
||
this._closeExistingDialog();
|
||
this._dialog = new ShellMountQuestionDialog();
|
||
|
||
this._dialog.connectObject('response',
|
||
(object, choice) => {
|
||
this.mountOp.set_choice(choice);
|
||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||
|
||
this.close();
|
||
}, this);
|
||
|
||
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, flags);
|
||
}
|
||
|
||
this._dialog.connectObject('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);
|
||
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._dialog = this._processesDialog;
|
||
|
||
this._processesDialog.connectObject('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);
|
||
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() {
|
||
this._dialog?.disconnectObject(this);
|
||
return this._dialog;
|
||
}
|
||
}
|
||
|
||
const 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);
|
||
}
|
||
}
|
||
});
|
||
|
||
const ShellMountQuestionDialog = GObject.registerClass({
|
||
Signals: { 'response': { param_types: [GObject.TYPE_INT] } },
|
||
}, class ShellMountQuestionDialog extends ModalDialog.ModalDialog {
|
||
_init() {
|
||
super._init({ styleClass: 'mount-question-dialog' });
|
||
|
||
this._oldChoices = [];
|
||
|
||
this._content = new Dialog.MessageDialogContent();
|
||
this.contentLayout.add_child(this._content);
|
||
}
|
||
|
||
vfunc_key_release_event(event) {
|
||
if (event.get_key_symbol() === Clutter.KEY_Escape) {
|
||
this.emit('response', -1);
|
||
return Clutter.EVENT_STOP;
|
||
}
|
||
|
||
return Clutter.EVENT_PROPAGATE;
|
||
}
|
||
|
||
update(message, choices) {
|
||
_setLabelsForMessage(this._content, message);
|
||
_setButtonsForChoices(this, this._oldChoices, choices);
|
||
this._oldChoices = choices;
|
||
}
|
||
});
|
||
|
||
const 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, flags) {
|
||
let strings = message.split('\n');
|
||
let title = strings.shift() || null;
|
||
let description = 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({ title, description });
|
||
|
||
let passwordGridLayout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||
let passwordGrid = new St.Widget({
|
||
style_class: 'prompt-dialog-password-grid',
|
||
layout_manager: passwordGridLayout,
|
||
});
|
||
passwordGridLayout.hookup_style(passwordGrid);
|
||
|
||
let rtl = passwordGrid.get_text_direction() === Clutter.TextDirection.RTL;
|
||
let curGridRow = 0;
|
||
|
||
if (flags & Gio.AskPasswordFlags.TCRYPT) {
|
||
this._hiddenVolume = new CheckBox.CheckBox(_('Hidden Volume'));
|
||
content.add_child(this._hiddenVolume);
|
||
|
||
this._systemVolume = new CheckBox.CheckBox(_('Windows System Volume'));
|
||
content.add_child(this._systemVolume);
|
||
|
||
this._keyfilesCheckbox = new CheckBox.CheckBox(_('Uses Keyfiles'));
|
||
this._keyfilesCheckbox.connect('clicked', this._onKeyfilesCheckboxClicked.bind(this));
|
||
content.add_child(this._keyfilesCheckbox);
|
||
|
||
this._keyfilesLabel = new St.Label({visible: false});
|
||
if (disksApp) {
|
||
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()));
|
||
} else {
|
||
this._keyfilesLabel.clutter_text.set_markup(
|
||
_('You need an external utility like <i>Disks</i> to unlock a volume that uses keyfiles.'));
|
||
}
|
||
this._keyfilesLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||
this._keyfilesLabel.clutter_text.line_wrap = true;
|
||
content.add_child(this._keyfilesLabel);
|
||
|
||
this._pimEntry = new St.PasswordEntry({
|
||
style_class: 'prompt-dialog-password-entry',
|
||
hint_text: _('PIM Number'),
|
||
can_focus: true,
|
||
x_expand: true,
|
||
});
|
||
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||
ShellEntry.addContextMenu(this._pimEntry);
|
||
|
||
if (rtl)
|
||
passwordGridLayout.attach(this._pimEntry, 1, curGridRow, 1, 1);
|
||
else
|
||
passwordGridLayout.attach(this._pimEntry, 0, curGridRow, 1, 1);
|
||
curGridRow += 1;
|
||
} else {
|
||
this._hiddenVolume = null;
|
||
this._systemVolume = null;
|
||
this._pimEntry = null;
|
||
}
|
||
|
||
this._passwordEntry = new St.PasswordEntry({
|
||
style_class: 'prompt-dialog-password-entry',
|
||
hint_text: _('Password'),
|
||
can_focus: true,
|
||
x_expand: true,
|
||
});
|
||
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||
this.setInitialKeyFocus(this._passwordEntry);
|
||
ShellEntry.addContextMenu(this._passwordEntry);
|
||
|
||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
|
||
animate: true,
|
||
});
|
||
|
||
if (rtl) {
|
||
passwordGridLayout.attach(this._workSpinner, 0, curGridRow, 1, 1);
|
||
passwordGridLayout.attach(this._passwordEntry, 1, curGridRow, 1, 1);
|
||
} else {
|
||
passwordGridLayout.attach(this._passwordEntry, 0, curGridRow, 1, 1);
|
||
passwordGridLayout.attach(this._workSpinner, 1, curGridRow, 1, 1);
|
||
}
|
||
curGridRow += 1;
|
||
|
||
let warningBox = new St.BoxLayout({ vertical: true });
|
||
|
||
let capsLockWarning = new ShellEntry.CapsLockWarning();
|
||
warningBox.add_child(capsLockWarning);
|
||
|
||
this._errorMessageLabel = new St.Label({
|
||
style_class: 'prompt-dialog-error-label',
|
||
opacity: 0,
|
||
});
|
||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||
warningBox.add_child(this._errorMessageLabel);
|
||
|
||
passwordGridLayout.attach(warningBox, 0, curGridRow, 2, 1);
|
||
|
||
content.add_child(passwordGrid);
|
||
|
||
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.add_child(this._rememberChoice);
|
||
} else {
|
||
this._rememberChoice = null;
|
||
}
|
||
|
||
this.contentLayout.add_child(content);
|
||
|
||
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,
|
||
}];
|
||
|
||
if (disksApp) {
|
||
this._usesKeyfilesButtons.push({
|
||
/* Translators: %s is the Disks application */
|
||
label: _('Open %s').format(disksApp.get_name()),
|
||
action: () => {
|
||
disksApp.activate();
|
||
this._onCancelButton();
|
||
},
|
||
default: true,
|
||
});
|
||
}
|
||
|
||
this.setButtons(this._defaultButtons);
|
||
}
|
||
|
||
reaskPassword() {
|
||
this._workSpinner.stop();
|
||
this._passwordEntry.set_text('');
|
||
this._errorMessageLabel.text = _('Sorry, that didn’t work. Please try again.');
|
||
this._errorMessageLabel.opacity = 255;
|
||
|
||
wiggle(this._passwordEntry);
|
||
}
|
||
|
||
_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._errorMessageLabel.text = _('The PIM must be a number or empty.');
|
||
this._errorMessageLabel.opacity = 255;
|
||
return;
|
||
}
|
||
|
||
this._errorMessageLabel.opacity = 0;
|
||
}
|
||
|
||
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._pimEntry.reactive = !useKeyfiles;
|
||
this._pimEntry.can_focus = !useKeyfiles;
|
||
this._rememberChoice.reactive = !useKeyfiles;
|
||
this._rememberChoice.can_focus = !useKeyfiles;
|
||
this._keyfilesLabel.visible = useKeyfiles;
|
||
this.setButtons(useKeyfiles ? this._usesKeyfilesButtons : this._defaultButtons);
|
||
}
|
||
});
|
||
|
||
const ShellProcessesDialog = GObject.registerClass({
|
||
Signals: { 'response': { param_types: [GObject.TYPE_INT] } },
|
||
}, class ShellProcessesDialog extends ModalDialog.ModalDialog {
|
||
_init() {
|
||
super._init({ styleClass: 'processes-dialog' });
|
||
|
||
this._oldChoices = [];
|
||
|
||
this._content = new Dialog.MessageDialogContent();
|
||
this.contentLayout.add_child(this._content);
|
||
|
||
this._applicationSection = new Dialog.ListSection();
|
||
this._applicationSection.hide();
|
||
this.contentLayout.add_child(this._applicationSection);
|
||
}
|
||
|
||
vfunc_key_release_event(event) {
|
||
if (event.get_key_symbol() === Clutter.KEY_Escape) {
|
||
this.emit('response', -1);
|
||
return Clutter.EVENT_STOP;
|
||
}
|
||
|
||
return Clutter.EVENT_PROPAGATE;
|
||
}
|
||
|
||
_setAppsForPids(pids) {
|
||
// remove all the items
|
||
this._applicationSection.list.destroy_all_children();
|
||
|
||
pids.forEach(pid => {
|
||
let tracker = Shell.WindowTracker.get_default();
|
||
let app = tracker.get_app_from_pid(pid);
|
||
|
||
if (!app)
|
||
return;
|
||
|
||
let listItem = new Dialog.ListSectionItem({
|
||
icon_actor: app.create_icon_texture(LIST_ITEM_ICON_SIZE),
|
||
title: app.get_name(),
|
||
});
|
||
this._applicationSection.list.add_child(listItem);
|
||
});
|
||
|
||
this._applicationSection.visible =
|
||
this._applicationSection.list.get_n_children() > 0;
|
||
}
|
||
|
||
update(message, processes, choices) {
|
||
this._setAppsForPids(processes);
|
||
_setLabelsForMessage(this._content, message);
|
||
_setButtonsForChoices(this, this._oldChoices, choices);
|
||
this._oldChoices = choices;
|
||
}
|
||
});
|
||
|
||
const GnomeShellMountOpIface = loadInterfaceXML('org.Gtk.MountOperationHandler');
|
||
|
||
/** @enum {number} */
|
||
const ShellMountOperationType = {
|
||
NONE: 0,
|
||
ASK_PASSWORD: 1,
|
||
ASK_QUESTION: 2,
|
||
SHOW_PROCESSES: 3,
|
||
};
|
||
|
||
export class GnomeShellMountOpHandler {
|
||
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._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;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* AskPassword:
|
||
* @param {Array} params
|
||
* {string} id: an opaque ID identifying the object for which
|
||
* the operation is requested
|
||
* {string} message: the message to display
|
||
* {string} icon_name: the name of an icon to display
|
||
* {string} default_user: the default username for display
|
||
* {string} default_domain: the default domain for display
|
||
* {Gio.AskPasswordFlags} flags: a set of GAskPasswordFlags
|
||
* {Gio.MountOperationResults} response: a GMountOperationResult
|
||
* {Object} response_details: a dictionary containing 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
|
||
* @param {Gio.DBusMethodInvocation} invocation
|
||
* The ID must be unique in the context of the calling process.
|
||
*
|
||
* 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, 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:
|
||
* @param {Array} params - params
|
||
* {string} 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.
|
||
* {string} message: the message to display
|
||
* {string} icon_name: the name of an icon to display
|
||
* {string[]} choices: an array of choice strings
|
||
* @param {Gio.DBusMethodInvocation} invocation - invocation
|
||
*
|
||
* 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(message);
|
||
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, choices);
|
||
this._dialog.open();
|
||
}
|
||
|
||
/**
|
||
* ShowProcesses:
|
||
* @param {Array} params - params
|
||
* {string} 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.
|
||
* {string} message: the message to display
|
||
* {string} icon_name: the name of an icon to display
|
||
* {number[]} application_pids: the PIDs of the applications to display
|
||
* {string[]} choices: an array of choice strings
|
||
* @param {Gio.DBusMethodInvocation} invocation - invocation
|
||
*
|
||
* 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._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:
|
||
* @param {Array} _params - params
|
||
* @param {Gio.DBusMethodInvocation} _invocation - invocation
|
||
*
|
||
* 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();
|
||
}
|
||
}
|