mount-operation: implement org.Gtk.MountOperationHandler
Use the ShellMountOperation dialogs we have to implement a DBus API allowing other processes to display them. Since GtkMountOperation now tries to call into our DBus implementation, every application that uses a GtkMountOperation will gain integration with our shell dialogs (but will still handle the actual communication with GVfs). https://bugzilla.gnome.org/show_bug.cgi?id=678516
This commit is contained in:
parent
01c07fbea1
commit
6b5f9a647a
@ -33,6 +33,7 @@ const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
|||||||
const Scripting = imports.ui.scripting;
|
const Scripting = imports.ui.scripting;
|
||||||
const SessionMode = imports.ui.sessionMode;
|
const SessionMode = imports.ui.sessionMode;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
const TelepathyClient = imports.ui.telepathyClient;
|
const TelepathyClient = imports.ui.telepathyClient;
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
const Magnifier = imports.ui.magnifier;
|
const Magnifier = imports.ui.magnifier;
|
||||||
@ -60,6 +61,7 @@ let ctrlAltTabManager = null;
|
|||||||
let recorder = null;
|
let recorder = null;
|
||||||
let sessionMode = null;
|
let sessionMode = null;
|
||||||
let shellDBusService = null;
|
let shellDBusService = null;
|
||||||
|
let shellMountOpDBusService = null;
|
||||||
let modalCount = 0;
|
let modalCount = 0;
|
||||||
let modalActorFocusStack = [];
|
let modalActorFocusStack = [];
|
||||||
let uiGroup = null;
|
let uiGroup = null;
|
||||||
@ -150,6 +152,7 @@ function start() {
|
|||||||
|
|
||||||
sessionMode = new SessionMode.SessionMode();
|
sessionMode = new SessionMode.SessionMode();
|
||||||
shellDBusService = new ShellDBus.GnomeShell();
|
shellDBusService = new ShellDBus.GnomeShell();
|
||||||
|
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
|
||||||
|
|
||||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||||
// also initialize ShellAppSystem first. ShellAppSystem
|
// also initialize ShellAppSystem first. ShellAppSystem
|
||||||
|
@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
@ -144,17 +145,17 @@ const ShellMountOperation = new Lang.Class({
|
|||||||
this._dialog.open();
|
this._dialog.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onAskPassword: function(op, message) {
|
_onAskPassword: function(op, message, defaultUser, defaultDomain, flags) {
|
||||||
if (this._existingDialog) {
|
if (this._existingDialog) {
|
||||||
this._dialog = this._existingDialog;
|
this._dialog = this._existingDialog;
|
||||||
this._dialog.reaskPassword();
|
this._dialog.reaskPassword();
|
||||||
} else {
|
} else {
|
||||||
this._dialog = new ShellMountPasswordDialog(message, this._gicon);
|
this._dialog = new ShellMountPasswordDialog(message, this._gicon, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dialogId = this._dialog.connect('response', Lang.bind(this,
|
this._dialogId = this._dialog.connect('response', Lang.bind(this,
|
||||||
function(object, choice, password, remember) {
|
function(object, choice, password, remember) {
|
||||||
if (choice == '-1') {
|
if (choice == -1) {
|
||||||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||||||
} else {
|
} else {
|
||||||
if (remember)
|
if (remember)
|
||||||
@ -267,7 +268,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
Name: 'ShellMountPasswordDialog',
|
Name: 'ShellMountPasswordDialog',
|
||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
|
|
||||||
_init: function(message, gicon) {
|
_init: function(message, gicon, flags) {
|
||||||
let strings = message.split('\n');
|
let strings = message.split('\n');
|
||||||
this.parent({ styleClass: 'prompt-dialog' });
|
this.parent({ styleClass: 'prompt-dialog' });
|
||||||
|
|
||||||
@ -326,10 +327,14 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
this._errorMessageLabel.hide();
|
this._errorMessageLabel.hide();
|
||||||
this._messageBox.add(this._errorMessageLabel);
|
this._messageBox.add(this._errorMessageLabel);
|
||||||
|
|
||||||
|
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
||||||
this._rememberChoice = new CheckBox.CheckBox();
|
this._rememberChoice = new CheckBox.CheckBox();
|
||||||
this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
|
this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
|
||||||
this._rememberChoice.actor.checked = true;
|
this._rememberChoice.actor.checked = true;
|
||||||
this._messageBox.add(this._rememberChoice.actor);
|
this._messageBox.add(this._rememberChoice.actor);
|
||||||
|
} else {
|
||||||
|
this._rememberChoice = null;
|
||||||
|
}
|
||||||
|
|
||||||
let buttons = [{ label: _("Cancel"),
|
let buttons = [{ label: _("Cancel"),
|
||||||
action: Lang.bind(this, this._onCancelButton),
|
action: Lang.bind(this, this._onCancelButton),
|
||||||
@ -358,6 +363,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
_onEntryActivate: function() {
|
_onEntryActivate: function() {
|
||||||
this.emit('response', 1,
|
this.emit('response', 1,
|
||||||
this._passwordEntry.get_text(),
|
this._passwordEntry.get_text(),
|
||||||
|
this._rememberChoice &&
|
||||||
this._rememberChoice.actor.checked);
|
this._rememberChoice.actor.checked);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -455,3 +461,253 @@ const ShellProcessesDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
||||||
|
|
||||||
|
const GnomeShellMountOpIface = <interface name="org.Gtk.MountOperationHandler">
|
||||||
|
<method name="AskPassword">
|
||||||
|
<arg type="s" direction="in" name="object_id"/>
|
||||||
|
<arg type="s" direction="in" name="message"/>
|
||||||
|
<arg type="s" direction="in" name="icon_name"/>
|
||||||
|
<arg type="s" direction="in" name="default_user"/>
|
||||||
|
<arg type="s" direction="in" name="default_domain"/>
|
||||||
|
<arg type="u" direction="in" name="flags"/>
|
||||||
|
<arg type="u" direction="out" name="response"/>
|
||||||
|
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||||
|
</method>
|
||||||
|
<method name="AskQuestion">
|
||||||
|
<arg type="s" direction="in" name="object_id"/>
|
||||||
|
<arg type="s" direction="in" name="message"/>
|
||||||
|
<arg type="s" direction="in" name="icon_name"/>
|
||||||
|
<arg type="as" direction="in" name="choices"/>
|
||||||
|
<arg type="u" direction="out" name="response"/>
|
||||||
|
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||||
|
</method>
|
||||||
|
<method name="ShowProcesses">
|
||||||
|
<arg type="s" direction="in" name="object_id"/>
|
||||||
|
<arg type="s" direction="in" name="message"/>
|
||||||
|
<arg type="s" direction="in" name="icon_name"/>
|
||||||
|
<arg type="ai" direction="in" name="application_pids"/>
|
||||||
|
<arg type="as" direction="in" name="choices"/>
|
||||||
|
<arg type="u" direction="out" name="response"/>
|
||||||
|
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||||
|
</method>
|
||||||
|
<method name="Close"/>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const ShellMountOperationType = {
|
||||||
|
NONE: 0,
|
||||||
|
ASK_PASSWORD: 1,
|
||||||
|
ASK_QUESTION: 2,
|
||||||
|
SHOW_PROCESSES: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const GnomeShellMountOpHandler = new Lang.Class({
|
||||||
|
Name: 'GnomeShellMountOpHandler',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
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: function() {
|
||||||
|
this._currentId = null;
|
||||||
|
this._currentInvocation = null;
|
||||||
|
this._currentType = ShellMountOperationType.NONE;
|
||||||
|
},
|
||||||
|
|
||||||
|
_clearCurrentRequest: function(response, details) {
|
||||||
|
if (this._currentInvocation) {
|
||||||
|
this._currentInvocation.return_value(
|
||||||
|
GLib.Variant.new('(ua{sv})', [response, details]));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._ensureEmptyRequest();
|
||||||
|
},
|
||||||
|
|
||||||
|
_setCurrentRequest: function(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: function() {
|
||||||
|
if (this._dialog) {
|
||||||
|
this._dialog.close();
|
||||||
|
this._dialog = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_createGIcon: function(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: function(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', Lang.bind(this,
|
||||||
|
function(object, choice, password, remember) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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: function(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', Lang.bind(this,
|
||||||
|
function(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: function(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', Lang.bind(this,
|
||||||
|
function(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: function(params, invocation) {
|
||||||
|
this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
|
||||||
|
this._closeDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user