[gnome-shell] Bug 574697 - Slide the workspaces back in if the u



commit 39eb5636872bda7fe8cfc4792a3ef5d515ee9bc0
Author: Marina Zhurakhinskaya <marinaz redhat com>
Date:   Wed Mar 11 15:21:45 2009 -0400

    Bug 574697 - Slide the workspaces back in if the user starts dragging a document or an application item in the expanded display mode
    
    Sliding the workspaces back in when the user starts dragging an item in the
    expanded display mode allows the user to select a workspace in which the item
    should be launched and stay in the overlay mode.
    
    This patch adds code to dnd.js that handles notifying actors when a drag item is being dragged over them. Overlay code uses such notification to unset expanded display modes and trigger sliding in of the workspaces.
    
    If the drag is cancelled the drag item snaps back to its source or disappears at the original position of its source if the source is no longer displayed.
---
 js/ui/dnd.js            |   46 ++++++++++++++++++++++++++++++++++++-----
 js/ui/genericDisplay.js |   51 +++++++++++++++++++++++++++++++++++++++-------
 js/ui/overlay.js        |   24 +++++++++++++++++++++-
 3 files changed, 106 insertions(+), 15 deletions(-)

diff --git a/js/ui/dnd.js b/js/ui/dnd.js
index d72edf7..9404339 100644
--- a/js/ui/dnd.js
+++ b/js/ui/dnd.js
@@ -1,10 +1,9 @@
 /* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
 
-const Lang = imports.lang;
-const Signals = imports.signals;
-
 const Clutter = imports.gi.Clutter;
 const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Signals = imports.signals;
 const Tweener = imports.ui.tweener;
 
 const SNAP_BACK_ANIMATION_TIME = 0.25;
@@ -80,6 +79,13 @@ _Draggable.prototype = {
 
             if (this.actor._delegate && this.actor._delegate.getDragActor) {
                 this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
+                // Drag actor does not always have to be the same as actor. For example drag actor
+                // can be an image that's part of the actor. So to perform "snap back" correctly we need
+                // to know what was the drag actor source.
+                if (this.actor._delegate.getDragActorSource)
+                    this._dragActorSource = this.actor._delegate.getDragActorSource();
+                else  
+                    this._dragActorSource = this.actor;
                 this._dragOrigParent = undefined;
                 this._ungrabActor(actor);
                 this._grabActor(this._dragActor);
@@ -88,6 +94,7 @@ _Draggable.prototype = {
                 this._dragOffsetY = this._dragActor.y - this._dragStartY;
             } else {
                 this._dragActor = actor;
+                this._dragActorSource = undefined;
                 this._dragOrigParent = actor.get_parent();
                 this._dragOrigX = this._dragActor.x;
                 this._dragOrigY = this._dragActor.y;
@@ -112,6 +119,24 @@ _Draggable.prototype = {
         if (this._dragActor) {
             this._dragActor.set_position(stageX + this._dragOffsetX,
                                          stageY + this._dragOffsetY);
+            // Because we want to find out what other actor is located at the current position of this._dragActor,
+            // we have to temporarily hide this._dragActor.
+            this._dragActor.hide(); 
+            let target = actor.get_stage().get_actor_at_pos(stageX + this._dragOffsetX, stageY + this._dragOffsetY);
+            this._dragActor.show();
+            while (target) {
+                if (target._delegate && target._delegate.handleDragOver) {
+                    let [targX, targY] = target.get_transformed_position();
+                    // We currently loop through all parents on drag-over even if one of the children has handled it.
+                    // We can check the return value of the function and break the loop if it's true if we don't want
+                    // to continue checking the parents.
+                    target._delegate.handleDragOver(this.actor._delegate, actor,
+                                                    (stageX + this._dragOffsetX + this._xOffset - targX) / target.scale_x,
+                                                    (stageY + this._dragOffsetY + this._yOffset - targY) / target.scale_y,
+                                                    event.get_time());
+                }
+                target = target.get_parent();
+            }  
         }
 
         return true;
@@ -151,10 +176,19 @@ _Draggable.prototype = {
             target = target.get_parent();
         }
 
+        // Snap back to the actor source if the source is still around, snap back 
+        // to the original location if the actor itself was being dragged or the
+        // source is no longer around.
+        let snapBackX = this._dragStartX + this._dragOffsetX;
+        let snapBackY = this._dragStartY + this._dragOffsetY;
+        if (this._dragActorSource && this._dragActorSource.visible) {
+            [snapBackX, snapBackY] = this._dragActorSource.get_transformed_position();
+        }
+
         // No target, so snap back
         Tweener.addTween(actor,
-                         { x: this._dragStartX + this._dragOffsetX,
-                           y: this._dragStartY + this._dragOffsetY,
+                         { x: snapBackX,
+                           y: snapBackY,
                            time: SNAP_BACK_ANIMATION_TIME,
                            transition: "easeOutQuad",
                            onComplete: this._onSnapBackComplete,
@@ -178,4 +212,4 @@ Signals.addSignalMethods(_Draggable.prototype);
 
 function makeDraggable(actor) {
     return new _Draggable(actor);
-}
\ No newline at end of file
+}
diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js
index ba8222c..93ead60 100644
--- a/js/ui/genericDisplay.js
+++ b/js/ui/genericDisplay.js
@@ -64,13 +64,17 @@ GenericDisplayItem.prototype = {
         this._name = null;
         this._description = null;
         this._icon = null;
+
+        this.dragActor = null;
     },
 
-    //// Draggable interface ////
+    //// Draggable object interface ////
+
+    // Returns a cloned texture of the item's icon to represent the item as it 
+    // is being dragged. 
     getDragActor: function(stageX, stageY) {
-        // FIXME: assumes this._icon is a Clutter.Texture
-        let icon = new Clutter.Clone({ source: this._icon });
-        [icon.width, icon.height] = this._icon.get_transformed_size();
+        this.dragActor = new Clutter.Clone({ source: this._icon });
+        [this.dragActor.width, this.dragActor.height] = this._icon.get_transformed_size();
 
         // If the user dragged from the icon itself, then position
         // the dragActor over the original icon. Otherwise center it
@@ -79,12 +83,18 @@ GenericDisplayItem.prototype = {
         let [iconWidth, iconHeight] = this._icon.get_transformed_size();
         if (stageX > iconX && stageX <= iconX + iconWidth &&
             stageY > iconY && stageY <= iconY + iconHeight)
-            icon.set_position(iconX, iconY);
+            this.dragActor.set_position(iconX, iconY);
         else
-            icon.set_position(stageX - icon.width / 2, stageY - icon.height / 2);
-        return icon;
+            this.dragActor.set_position(stageX - this.dragActor.width / 2, stageY - this.dragActor.height / 2);
+        return this.dragActor;
     },
     
+    // Returns the original icon that is being used as a source for the cloned texture
+    // that represents the item as it is being dragged.
+    getDragActorSource: function() {
+        return this._icon;
+    },
+
     //// Public methods ////
 
     // Highlights the item by setting a different background color than the default 
@@ -388,7 +398,32 @@ GenericDisplay.prototype = {
             this.selectUp();
         } 
 
-        displayItem.actor.destroy();
+        if (displayItem.dragActor) {
+            // The user might be handling a dragActor when the list of items 
+            // changes (for example, if the dragging caused us to transition
+            // from an expanded overlay view to the regular view). So we need
+            // to keep the item around so that the drag and drop action initiated
+            // by the user can be completed. However, we remove the item from the list.
+            // 
+            // For some reason, just removing the displayItem.actor
+            // is not enough to get displayItem._icon.visible
+            // to return false, so we hide the display item and
+            // all its children first. (We check displayItem._icon.visible
+            // when deciding if a dragActor has a place to snap back to
+            // in case the drop was not accepted by any actor.)
+            displayItem.actor.hide_all();
+            this._grid.remove_actor(displayItem.actor);
+            // We should not destroy the actor up-front, because that would also
+            // destroy the icon that was used to clone the image for the drag actor.
+            // We destroy it once the dragActor is destroyed instead.             
+            displayItem.dragActor.connect('destroy',
+                                          function(item) {
+                                              displayItem.actor.destroy();
+                                          });
+           
+        } else {
+            displayItem.actor.destroy();
+        }
         delete this._displayedItems[itemId];
         this._displayedItemsCount--;        
     },
diff --git a/js/ui/overlay.js b/js/ui/overlay.js
index 3d2624f..cfb1b94 100644
--- a/js/ui/overlay.js
+++ b/js/ui/overlay.js
@@ -568,6 +568,8 @@ Overlay.prototype = {
         }
 
         this._group = new Clutter.Group();
+        this._group._delegate = this;
+
         this.visible = false;
 
         let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR,
@@ -604,7 +606,7 @@ Overlay.prototype = {
                                  { x: displayGridColumnWidth * asideXFactor,
                                    time: ANIMATION_TIME,
                                    transition: "easeOutQuad"
-                                 });               
+                                 });
             }    
         });
         this._sideshow.connect('less-activated', function(sideshow) {
@@ -621,6 +623,24 @@ Overlay.prototype = {
         });
     },
 
+    //// Draggable target interface ////
+
+    // Unsets the expanded display mode if a GenericDisplayItem is being 
+    // dragged over the overlay, i.e. as soon as it starts being dragged.
+    // This slides the workspaces back in and allows the user to place
+    // the item on any workspace.
+    handleDragOver : function(source, actor, x, y, time) {
+        if (source instanceof GenericDisplay.GenericDisplayItem) {
+            this._sideshow._unsetMoreAppsMode();
+            this._sideshow._unsetMoreDocsMode();
+            return true;
+        }
+  
+        return false;
+    },
+
+    //// Public methods ////
+
     show : function() {
         if (this.visible)
             return;
@@ -690,6 +710,8 @@ Overlay.prototype = {
                          });
     },
 
+    //// Private methods ////
+
     _hideDone: function() {
         let global = Shell.Global.get();
 



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