Blob Blame History Raw
From b9b0433d1fbe3ada728fdf20cbff8d4b4d0fa215 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Thu, 27 Feb 2020 22:52:41 +0100
Subject: [PATCH 12/37] dash: Reuse as much as possible upstream code

Many functions in dash were just copy-pasted from upstream source, and this
may lead to living with non-updated code, so instead of this just re-use
the default methods, given that JS is nice (or not?) enough to allow to do
that easily.

The only difference is in handleDragOver where we had to temporarily mock
some properties in order to adapt the code for the horizontal mode and to
compute the icons size based on the actual scrollview content, instead of
the visible box area.

Less code to maintain, yay!

LP: #1867763
LP: #1867613
---
 dash.js | 417 ++++++++++++++++----------------------------------------
 1 file changed, 119 insertions(+), 298 deletions(-)

diff --git a/dash.js b/dash.js
index 455499a..e86421a 100644
--- a/dash.js
+++ b/dash.js
@@ -309,6 +309,123 @@ var MyDash = GObject.registerClass({
         this._signalsHandler.destroy();
     }
 
+    _onDragBegin() {
+        return Dash.Dash.prototype._onDragBegin.call(this, ...arguments);
+    }
+
+    _onDragCancelled() {
+        return Dash.Dash.prototype._onDragCancelled.call(this, ...arguments);
+    }
+
+    _onDragEnd() {
+        return Dash.Dash.prototype._onDragEnd.call(this, ...arguments);
+    }
+
+    _endDrag() {
+        return Dash.Dash.prototype._endDrag.call(this, ...arguments);
+    }
+
+    _onDragMotion() {
+        return Dash.Dash.prototype._onDragMotion.call(this, ...arguments);
+    }
+
+    _appIdListToHash() {
+        return Dash.Dash.prototype._appIdListToHash.call(this, ...arguments);
+    }
+
+    _queueRedisplay() {
+        return Dash.Dash.prototype._queueRedisplay.call(this, ...arguments);
+    }
+
+    _hookUpLabel() {
+        return Dash.Dash.prototype._hookUpLabel.call(this, ...arguments);
+    }
+
+    _syncLabel() {
+        return Dash.Dash.prototype._syncLabel.call(this, ...arguments);
+    }
+
+    _clearDragPlaceholder() {
+        return Dash.Dash.prototype._clearDragPlaceholder.call(this, ...arguments);
+    }
+
+    _clearEmptyDropTarget() {
+        return Dash.Dash.prototype._clearEmptyDropTarget.call(this, ...arguments);
+    }
+
+    handleDragOver(source, actor, x, y, time) {
+        let ret;
+        if (!this._isHorizontal) {
+            Object.defineProperty(this._box, 'height', {
+                configurable: true,
+                get: () => this._box.get_children().reduce((a, c) => a + c.height, 0),
+            });
+
+            ret = Dash.Dash.prototype.handleDragOver.call(this, source, actor, x, y, time);
+
+            delete this._box.height;
+
+            if (ret == DND.DragMotionResult.CONTINUE)
+                return ret;
+        } else {
+            Object.defineProperty(this._box, 'height', {
+                configurable: true,
+                get: () => this._box.get_children().reduce((a, c) => a + c.width, 0),
+            });
+
+            let replacedPlaceholderHeight = false;
+            if (this._dragPlaceholder) {
+                replacedPlaceholderHeight = true;
+                Object.defineProperty(this._dragPlaceholder, 'height', {
+                    configurable: true,
+                    get: () => this._dragPlaceholder.width,
+                });
+            }
+
+            ret = Dash.Dash.prototype.handleDragOver.call(this, source, actor, y, x, time);
+
+            delete this._box.height;
+            if (replacedPlaceholderHeight && this._dragPlaceholder)
+                delete this._dragPlaceholder.height;
+
+            if (ret == DND.DragMotionResult.CONTINUE)
+                return ret;
+
+            if (this._dragPlaceholder) {
+                this._dragPlaceholder.child.set_width(this.iconSize / 2);
+                this._dragPlaceholder.child.set_height(this.iconSize);
+
+                let pos = this._dragPlaceholderPos;
+                if (this._isHorizontal && (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL))
+                    pos = this._box.get_children() - 1 - pos;
+
+                if (pos != this._dragPlaceholderPos) {
+                    this._dragPlaceholderPos = pos;
+                    this._box.set_child_at_index(this._dragPlaceholder,
+                        this._dragPlaceholderPos)
+                }
+            }
+        }
+
+        if (this._dragPlaceholder) {
+            // Ensure the next and previous icon are visible when moving the placeholder
+            // (I assume there's room for both of them)
+            if (this._dragPlaceholderPos > 0)
+                ensureActorVisibleInScrollView(this._scrollView,
+                    this._box.get_children()[this._dragPlaceholderPos - 1]);
+
+            if (this._dragPlaceholderPos < this._box.get_children().length - 1)
+                ensureActorVisibleInScrollView(this._scrollView,
+                    this._box.get_children()[this._dragPlaceholderPos + 1]);
+        }
+
+        return ret;
+    }
+
+    acceptDrop() {
+        return Dash.Dash.prototype.acceptDrop.call(this, ...arguments);
+    }
+
     _onScrollEvent(actor, event) {
         // If scroll is not used because the icon is resized, let the scroll event propagate.
         if (!Docking.DockManager.settings.get_boolean('icon-size-fixed'))
@@ -354,88 +471,6 @@ var MyDash = GObject.registerClass({
         return Clutter.EVENT_STOP;
     }
 
-    _onDragBegin() {
-        this._dragCancelled = false;
-        this._dragMonitor = {
-            dragMotion: this._onDragMotion.bind(this)
-        };
-        DND.addDragMonitor(this._dragMonitor);
-
-        if (this._box.get_n_children() == 0) {
-            this._emptyDropTarget = new Dash.EmptyDropTargetItem();
-            this._box.insert_child_at_index(this._emptyDropTarget, 0);
-            this._emptyDropTarget.show(true);
-        }
-    }
-
-    _onDragCancelled() {
-        this._dragCancelled = true;
-        this._endDrag();
-    }
-
-    _onDragEnd() {
-        if (this._dragCancelled)
-            return;
-
-        this._endDrag();
-    }
-
-    _endDrag() {
-        this._clearDragPlaceholder();
-        this._clearEmptyDropTarget();
-        this._showAppsIcon.setDragApp(null);
-        DND.removeDragMonitor(this._dragMonitor);
-    }
-
-    _onDragMotion(dragEvent) {
-        let app = Dash.getAppFromSource(dragEvent.source);
-        if (app == null)
-            return DND.DragMotionResult.CONTINUE;
-
-        let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor);
-
-        if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
-            this._clearDragPlaceholder();
-
-        if (showAppsHovered)
-            this._showAppsIcon.setDragApp(app);
-        else
-            this._showAppsIcon.setDragApp(null);
-
-        return DND.DragMotionResult.CONTINUE;
-    }
-
-    _appIdListToHash(apps) {
-        let ids = {};
-        for (let i = 0; i < apps.length; i++)
-            ids[apps[i].get_id()] = apps[i];
-        return ids;
-    }
-
-    _queueRedisplay() {
-        Main.queueDeferredWork(this._workId);
-    }
-
-    _hookUpLabel(item, appIcon) {
-        item.child.connect('notify::hover', () => {
-            this._syncLabel(item, appIcon);
-        });
-
-        let id = Main.overview.connect('hiding', () => {
-            this._labelShowing = false;
-            item.hideLabel();
-        });
-        item.child.connect('destroy', function() {
-            Main.overview.disconnect(id);
-        });
-
-        if (appIcon) {
-            appIcon.connect('sync-tooltip', () => {
-                this._syncLabel(item, appIcon);
-            });
-        }
-    }
-
     _createAppItem(app) {
         let appIcon = new AppIcons.MyAppIcon(this._remoteModel, app,
             this._monitorIndex);
@@ -528,18 +563,9 @@ var MyDash = GObject.registerClass({
     }
 
     _itemMenuStateChanged(item, opened) {
-        // When the menu closes, it calls sync_hover, which means
-        // that the notify::hover handler does everything we need to.
-        if (opened) {
-            if (this._showLabelTimeoutId > 0) {
-                GLib.source_remove(this._showLabelTimeoutId);
-                this._showLabelTimeoutId = 0;
-            }
+        Dash.Dash.prototype.acceptDrop.call(this, item, opened);
 
-            item.label.opacity = 0;
-            item.label.hide();
-        }
-        else {
+        if (!opened) {
             // I want to listen from outside when a menu is closed. I used to
             // add a custom signal to the appIcon, since gnome 3.8 the signal
             // calling this callback was added upstream.
@@ -547,49 +573,6 @@ var MyDash = GObject.registerClass({
         }
     }
 
-    _syncLabel(item, appIcon) {
-        let shouldShow = appIcon ? appIcon.shouldShowTooltip() : item.child.get_hover();
-
-        if (shouldShow) {
-            if (this._showLabelTimeoutId == 0) {
-                let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
-                let actor = (item instanceof Clutter.Actor) ? item : item.actor;
-                let destroyId = actor.connect('destroy', () => {
-                    if (this._showLabelTimeoutId)
-                        GLib.source_remove(this._showLabelTimeoutId);
-                });
-                this._showLabelTimeoutId = GLib.timeout_add(
-                    GLib.PRIORITY_DEFAULT, timeout, () => {
-                    this._showLabelTimeoutId = 0;
-                    actor.disconnect(destroyId);
-                    this._labelShowing = true;
-                    item.showLabel();
-                    return GLib.SOURCE_REMOVE;
-                });
-                GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
-                if (this._resetHoverTimeoutId > 0) {
-                    GLib.source_remove(this._resetHoverTimeoutId);
-                    this._resetHoverTimeoutId = 0;
-                }
-            }
-        }
-        else {
-            if (this._showLabelTimeoutId > 0)
-                GLib.source_remove(this._showLabelTimeoutId);
-            this._showLabelTimeoutId = 0;
-            item.hideLabel();
-            if (this._labelShowing) {
-                this._resetHoverTimeoutId = GLib.timeout_add(
-                    GLib.PRIORITY_DEFAULT, DASH_ITEM_HOVER_TIMEOUT, () => {
-                    this._labelShowing = false;
-                    this._resetHoverTimeoutId = 0;
-                    return GLib.SOURCE_REMOVE;
-                });
-                GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing');
-            }
-        }
-    }
-
     _adjustIconSize() {
         // For the icon size, we only consider children which are "proper"
         // icons (i.e. ignoring drag placeholders) and which are not
@@ -960,168 +943,6 @@ var MyDash = GObject.registerClass({
 
     }
 
-    _clearDragPlaceholder() {
-        if (this._dragPlaceholder) {
-            this._animatingPlaceholdersCount++;
-            this._dragPlaceholder.animateOutAndDestroy();
-            this._dragPlaceholder.connect('destroy', () => {
-                this._animatingPlaceholdersCount--;
-            });
-            this._dragPlaceholder = null;
-        }
-        this._dragPlaceholderPos = -1;
-    }
-
-    _clearEmptyDropTarget() {
-        if (this._emptyDropTarget) {
-            this._emptyDropTarget.animateOutAndDestroy();
-            this._emptyDropTarget = null;
-        }
-    }
-
-    handleDragOver(source, actor, x, y, time) {
-        let app = Dash.getAppFromSource(source);
-
-        // Don't allow favoriting of transient apps
-        if (app == null || app.is_window_backed())
-            return DND.DragMotionResult.NO_DROP;
-
-        if (!this._shellSettings.is_writable('favorite-apps') ||
-            !Docking.DockManager.settings.get_boolean('show-favorites'))
-            return DND.DragMotionResult.NO_DROP;
-
-        let favorites = AppFavorites.getAppFavorites().getFavorites();
-        let numFavorites = favorites.length;
-
-        let favPos = favorites.indexOf(app);
-
-        let children = this._box.get_children();
-        let numChildren = children.length;
-        let boxHeight = 0;
-        for (let i = 0; i < numChildren; i++)
-            boxHeight += this._isHorizontal?children[i].width:children[i].height;
-
-        // Keep the placeholder out of the index calculation; assuming that
-        // the remove target has the same size as "normal" items, we don't
-        // need to do the same adjustment there.
-        if (this._dragPlaceholder) {
-            boxHeight -= this._isHorizontal?this._dragPlaceholder.width:this._dragPlaceholder.height;
-            numChildren--;
-        }
-
-        let pos;
-        if (!this._emptyDropTarget) {
-            pos = Math.floor((this._isHorizontal?x:y) * numChildren / boxHeight);
-            if (pos >  numChildren)
-                pos = numChildren;
-        }
-        else
-            pos = 0; // always insert at the top when dash is empty
-
-        // Take into account childredn position in rtl
-        if (this._isHorizontal && (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL))
-            pos = numChildren - pos;
-
-        if ((pos != this._dragPlaceholderPos) && (pos <= numFavorites) && (this._animatingPlaceholdersCount == 0)) {
-            this._dragPlaceholderPos = pos;
-
-            // Don't allow positioning before or after self
-            if ((favPos != -1) && (pos == favPos || pos == favPos + 1)) {
-                this._clearDragPlaceholder();
-                return DND.DragMotionResult.CONTINUE;
-            }
-
-            // If the placeholder already exists, we just move
-            // it, but if we are adding it, expand its size in
-            // an animation
-            let fadeIn;
-            if (this._dragPlaceholder) {
-                this._dragPlaceholder.destroy();
-                fadeIn = false;
-            }
-            else
-                fadeIn = true;
-
-            this._dragPlaceholder = new Dash.DragPlaceholderItem();
-            this._dragPlaceholder.child.set_width (this.iconSize);
-            this._dragPlaceholder.child.set_height (this.iconSize / 2);
-            this._box.insert_child_at_index(this._dragPlaceholder,
-                                            this._dragPlaceholderPos);
-            this._dragPlaceholder.show(fadeIn);
-            // Ensure the next and previous icon are visible when moving the placeholder
-            // (I assume there's room for both of them)
-            if (this._dragPlaceholderPos > 1)
-                ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[this._dragPlaceholderPos-1]);
-            if (this._dragPlaceholderPos < this._box.get_children().length-1)
-                ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[this._dragPlaceholderPos+1]);
-        }
-
-        // Remove the drag placeholder if we are not in the
-        // "favorites zone"
-        if (pos > numFavorites)
-            this._clearDragPlaceholder();
-
-        if (!this._dragPlaceholder)
-            return DND.DragMotionResult.NO_DROP;
-
-        let srcIsFavorite = (favPos != -1);
-
-        if (srcIsFavorite)
-            return DND.DragMotionResult.MOVE_DROP;
-
-        return DND.DragMotionResult.COPY_DROP;
-    }
-
-    /**
-     * Draggable target interface
-     */
-    acceptDrop(source, actor, x, y, time) {
-        let app = Dash.getAppFromSource(source);
-
-        // Don't allow favoriting of transient apps
-        if (app == null || app.is_window_backed())
-            return false;
-
-        if (!this._shellSettings.is_writable('favorite-apps') ||
-            !Docking.DockManager.settings.get_boolean('show-favorites'))
-            return false;
-
-        let id = app.get_id();
-
-        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
-
-        let srcIsFavorite = (id in favorites);
-
-        let favPos = 0;
-        let children = this._box.get_children();
-        for (let i = 0; i < this._dragPlaceholderPos; i++) {
-            if (this._dragPlaceholder && (children[i] == this._dragPlaceholder))
-                continue;
-
-            let childId = children[i].child.app.get_id();
-            if (childId == id)
-                continue;
-            if (childId in favorites)
-                favPos++;
-        }
-
-        // No drag placeholder means we don't wan't to favorite the app
-        // and we are dragging it to its original position
-        if (!this._dragPlaceholder)
-            return true;
-
-        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
-            let appFavorites = AppFavorites.getAppFavorites();
-            if (srcIsFavorite)
-                appFavorites.moveFavoriteToPos(id, favPos);
-            else
-                appFavorites.addFavoriteAtPos(id, favPos);
-            return false;
-        });
-
-        return true;
-    }
-
     get showAppsButton() {
         return this._showAppsIcon.toggleButton;
     }
-- 
2.26.0