[gnome-shell-extensions] DriveMenu: make it independent of PlacesDisplay



commit dfcff4b297e166ead665cfe6a02e6e7f8a1dda68
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Tue Oct 2 20:31:12 2012 +0200

    DriveMenu: make it independent of PlacesDisplay
    
    That module was removed from GNOME Shell 3.6, so reimplement for mounts
    only, borrowing code and behaviour from the resident message tray source.

 extensions/drive-menu/extension.js |  129 ++++++++++++++++++++++++++++-------
 1 files changed, 103 insertions(+), 26 deletions(-)
---
diff --git a/extensions/drive-menu/extension.js b/extensions/drive-menu/extension.js
index e96f41f..0ffe585 100644
--- a/extensions/drive-menu/extension.js
+++ b/extensions/drive-menu/extension.js
@@ -11,25 +11,25 @@ const Main = imports.ui.main;
 const Panel = imports.ui.panel;
 const PanelMenu = imports.ui.panelMenu;
 const PopupMenu = imports.ui.popupMenu;
-const PlaceDisplay = imports.ui.placeDisplay;
+const ShellMountOperation = imports.ui.shellMountOperation;
 
 const ExtensionUtils = imports.misc.extensionUtils;
 const Me = ExtensionUtils.getCurrentExtension();
 const Convenience = Me.imports.convenience;
 
-const DriveMenuItem = new Lang.Class({
-    Name: 'DriveMenu.DriveMenuItem',
+const MountMenuItem = new Lang.Class({
+    Name: 'DriveMenu.MountMenuItem',
     Extends: PopupMenu.PopupBaseMenuItem,
 
-    _init: function(place) {
+    _init: function(mount) {
 	this.parent();
 
-	this.place = place;
-
-	this.label = new St.Label({ text: place.name });
+	this.label = new St.Label({ text: mount.get_name() });
 	this.addActor(this.label);
         this.actor.label_actor = this.label;
 
+	this.mount = mount;
+
 	let ejectIcon = new St.Icon({ icon_name: 'media-eject-symbolic',
 				      style_class: 'popup-menu-icon ' });
 	let ejectButton = new St.Button({ child: ejectIcon });
@@ -38,11 +38,44 @@ const DriveMenuItem = new Lang.Class({
     },
 
     _eject: function() {
-	this.place.remove();
+        let mountOp = new ShellMountOperation.ShellMountOperation(this.mount);
+
+	if (this.mount.can_eject())
+	    this.mount.eject_with_operation(Gio.MountUnmountFlags.NONE,
+                                            mountOp.mountOp,
+					    null, // Gio.Cancellable
+					    Lang.bind(this, this._ejectFinish));
+	else
+	    this.mount.unmount_with_operation(Gio.MountUnmountFlags.NONE,
+                                              mountOp.mountOp,
+			                      null, // Gio.Cancellable
+			                      Lang.bind(this, this._unmountFinish));
+    },
+
+    _unmountFinish: function(mount, result) {
+	try {
+	    mount.unmount_with_operation_finish(result);
+	} catch(e) {
+	    this._reportFailure(e);
+	}
+    },
+
+    _ejectFinish: function(mount, result) {
+	try {
+	    mount.eject_with_operation_finish(result);
+	} catch(e) {
+	    this._reportFailure(e);
+	}
+    },
+
+    _reportFailure: function(exception) {
+	let msg = _("Ejecting drive '%s' failed:").format(this.mount.get_name());
+	Main.notifyError(msg, exception.message);
     },
 
     activate: function(event) {
-	this.place.launch({ timestamp: event.get_time() });
+        Gio.AppInfo.launch_default_for_uri(this.mount.get_root().get_uri(),
+                                           global.create_app_launch_context());
 
 	this.parent(event);
     }
@@ -55,39 +88,83 @@ const DriveMenu = new Lang.Class({
     _init: function() {
 	this.parent('media-eject-symbolic', _("Removable devices"));
 
-	this._manager = new PlaceDisplay.PlacesManager();
-	this._updatedId = this._manager.connect('mounts-updated', Lang.bind(this, this._update));
+	this._monitor = Gio.VolumeMonitor.get();
+	this._addedId = this._monitor.connect('mount-added', Lang.bind(this, function(monitor, mount) {
+	    this._addMount(mount);
+	    this._updateMenuVisibility();
+	}));
+	this._removedId = this._monitor.connect('mount-removed', Lang.bind(this, function(monitor, mount) {
+	    this._removeMount(mount);
+	    this._updateMenuVisibility();
+	}));
 
-	this._contentSection = new PopupMenu.PopupMenuSection();
-	this.menu.addMenuItem(this._contentSection);
+	this._mounts = [ ];
 
-	this._update();
+	this._monitor.get_mounts().forEach(Lang.bind(this, this._addMount));
 
 	this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-	this.menu.addAction(_("Open file manager"), function(event) {
+	this.menu.addAction(_("Open File"), function(event) {
 	    let appSystem = Shell.AppSystem.get_default();
 	    let app = appSystem.lookup_app('nautilus.desktop');
 	    app.activate_full(-1, event.get_time());
 	});
+
+	this._updateMenuVisibility();
     },
 
-    _update: function() {
-	this._contentSection.removeAll();
+    _updateMenuVisibility: function() {
+	if (this._mounts.length > 0)
+	    this.actor.show();
+	else
+	    this.actor.hide();
+    },
+
+    _isMountInteresting: function(mount) {
+        if (!mount.can_eject() && !mount.can_unmount())
+            return false;
+
+        let volume = mount.get_volume();
+
+        if (volume == null) {
+            // probably a GDaemonMount, could be network or
+            // local, but we can't tell; assume it's local for now
+            return true;
+        }
+
+        return volume.get_identifier('class') != 'network';
+    },
 
-	let mounts = this._manager.getMounts();
-	let any = false;
-	for (let i = 0; i < mounts.length; i++) {
-	    if (mounts[i].isRemovable()) {
-		this._contentSection.addMenuItem(new DriveMenuItem(mounts[i]));
-		any = true;
+    _addMount: function(mount) {
+	if (!this._isMountInteresting(mount))
+	    return;
+
+	let item = new MountMenuItem(mount);
+	this._mounts.unshift(item);
+	this.menu.addMenuItem(item, 0);
+    },
+
+    _removeMount: function(mount) {
+	if (!this._isMountInteresting(mount))
+	    return;
+
+	for (let i = 0; i < this._mounts.length; i++) {
+	    let item = this._mounts[i];
+	    if (item.mount == mount) {
+		item.destroy();
+		this._mounts.splice(i, 1);
+		return;
 	    }
 	}
-
-	this.actor.visible = any;
+	log ('Removing a mount that was never added to the menu');
     },
 
     destroy: function() {
-	this._manager.disconnect(this._updatedId);
+        if (this._connectedId) {
+	    this._monitor.disconnect(this._connectedId);
+	    this._monitor.disconnect(this._disconnectedId);
+            this._connectedId = 0;
+            this._disconnectedId = 0;
+        }
 
 	this.parent();
     },



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]