[gnome-shell] mount-operation: implement org.Gtk.MountOperationHandler
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] mount-operation: implement org.Gtk.MountOperationHandler
- Date: Fri, 22 Jun 2012 20:49:50 +0000 (UTC)
commit 6b5f9a647a9e2020766cbf4477aa684b3ebe4170
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Wed Jun 20 17:23:34 2012 -0400
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
js/ui/main.js | 3 +
js/ui/shellMountOperation.js | 272 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 267 insertions(+), 8 deletions(-)
---
diff --git a/js/ui/main.js b/js/ui/main.js
index bc5a3df..b2ef94d 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -33,6 +33,7 @@ const WindowAttentionHandler = imports.ui.windowAttentionHandler;
const Scripting = imports.ui.scripting;
const SessionMode = imports.ui.sessionMode;
const ShellDBus = imports.ui.shellDBus;
+const ShellMountOperation = imports.ui.shellMountOperation;
const TelepathyClient = imports.ui.telepathyClient;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
@@ -60,6 +61,7 @@ let ctrlAltTabManager = null;
let recorder = null;
let sessionMode = null;
let shellDBusService = null;
+let shellMountOpDBusService = null;
let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null;
@@ -150,6 +152,7 @@ function start() {
sessionMode = new SessionMode.SessionMode();
shellDBusService = new ShellDBus.GnomeShell();
+ shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
diff --git a/js/ui/shellMountOperation.js b/js/ui/shellMountOperation.js
index dd4910a..465891a 100644
--- a/js/ui/shellMountOperation.js
+++ b/js/ui/shellMountOperation.js
@@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Signals = imports.signals;
const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
@@ -144,17 +145,17 @@ const ShellMountOperation = new Lang.Class({
this._dialog.open();
},
- _onAskPassword: function(op, message) {
+ _onAskPassword: function(op, message, defaultUser, defaultDomain, flags) {
if (this._existingDialog) {
this._dialog = this._existingDialog;
this._dialog.reaskPassword();
} 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,
function(object, choice, password, remember) {
- if (choice == '-1') {
+ if (choice == -1) {
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
} else {
if (remember)
@@ -267,7 +268,7 @@ const ShellMountPasswordDialog = new Lang.Class({
Name: 'ShellMountPasswordDialog',
Extends: ModalDialog.ModalDialog,
- _init: function(message, gicon) {
+ _init: function(message, gicon, flags) {
let strings = message.split('\n');
this.parent({ styleClass: 'prompt-dialog' });
@@ -326,10 +327,14 @@ const ShellMountPasswordDialog = new Lang.Class({
this._errorMessageLabel.hide();
this._messageBox.add(this._errorMessageLabel);
- this._rememberChoice = new CheckBox.CheckBox();
- this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
- this._rememberChoice.actor.checked = true;
- this._messageBox.add(this._rememberChoice.actor);
+ if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
+ this._rememberChoice = new CheckBox.CheckBox();
+ this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
+ this._rememberChoice.actor.checked = true;
+ this._messageBox.add(this._rememberChoice.actor);
+ } else {
+ this._rememberChoice = null;
+ }
let buttons = [{ label: _("Cancel"),
action: Lang.bind(this, this._onCancelButton),
@@ -358,6 +363,7 @@ const ShellMountPasswordDialog = new Lang.Class({
_onEntryActivate: function() {
this.emit('response', 1,
this._passwordEntry.get_text(),
+ this._rememberChoice &&
this._rememberChoice.actor.checked);
}
});
@@ -455,3 +461,253 @@ const ShellProcessesDialog = new Lang.Class({
}
});
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();
+ }
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]