From 702417ce83eb9a4c4bd491eaf0fa802ffee9b4ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Wed, 30 Oct 2019 00:06:10 +0100 Subject: [PATCH] appDisplay: Only use dragMonitor for one icon at a time Instead of adding a dragMonitor for every icon in the grid as soon as one icon is getting dragged, only add a dragMonitor for the icon that is currently being dragged over (ie. the current drag-target). With a large number of icons in the iconGrid, this should significantly reduce lags while dragging. We can do this by detecting the DnD-entering of an icon or folder using the `handleDragOver()` callback of drag-targets, adding the dragMonitor because we know an icon is hovering above the drag-target and then detecting the DnD-leaving of the drag-target by using the `dragMotion()` handler, where we remove the dragMonitor again as soon as the targetActor is no longer our actor (ie. the drag-target). https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/849 --- js/ui/appDisplay.js | 94 ++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 0621acdae..b191d5814 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -1499,10 +1499,7 @@ var FolderIcon = GObject.registerClass({ this.view = new FolderView(this._folder, id, parentView); - this._itemDragBeginId = Main.overview.connect( - 'item-drag-begin', this._onDragBegin.bind(this)); - this._itemDragEndId = Main.overview.connect( - 'item-drag-end', this._onDragEnd.bind(this)); + this._iconIsHovering = false; this.connect('destroy', this._onDestroy.bind(this)); @@ -1512,9 +1509,6 @@ var FolderIcon = GObject.registerClass({ } _onDestroy() { - Main.overview.disconnect(this._itemDragBeginId); - Main.overview.disconnect(this._itemDragEndId); - if (this._dragMonitor) { DND.removeDragMonitor(this._dragMonitor); this._dragMonitor = null; @@ -1552,29 +1546,32 @@ var FolderIcon = GObject.registerClass({ return this.view.getAllItems().map(item => item.id); } - _onDragBegin() { - this._dragMonitor = { - dragMotion: this._onDragMotion.bind(this), - }; - DND.addDragMonitor(this._dragMonitor); + _setHoveringByDnd(hovering) { + if (this._iconIsHovering == hovering) + return; + + this._iconIsHovering = hovering; + + if (hovering) { + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this), + }; + DND.addDragMonitor(this._dragMonitor); + this.add_style_pseudo_class('drop'); + } else { + DND.removeDragMonitor(this._dragMonitor); + this.remove_style_pseudo_class('drop'); + } } _onDragMotion(dragEvent) { - let target = dragEvent.targetActor; - - if (!this.contains(target) || !this._canAccept(dragEvent.source)) - this.remove_style_pseudo_class('drop'); - else - this.add_style_pseudo_class('drop'); + if (!this.contains(dragEvent.targetActor) || + !this._canAccept(dragEvent.source)) + this._setHoveringByDnd(false); return DND.DragMotionResult.CONTINUE; } - _onDragEnd() { - this.remove_style_pseudo_class('drop'); - DND.removeDragMonitor(this._dragMonitor); - } - _canAccept(source) { if (!(source instanceof AppIcon)) return false; @@ -1593,10 +1590,14 @@ var FolderIcon = GObject.registerClass({ if (!this._canAccept(source)) return DND.DragMotionResult.NO_DROP; + this._setHoveringByDnd(true); + return DND.DragMotionResult.MOVE_DROP; } acceptDrop(source) { + this._setHoveringByDnd(false); + if (!this._canAccept(source)) return false; @@ -2026,7 +2027,6 @@ var AppIcon = GObject.registerClass({ this._delegate = this; - this._hasDndHover = false; this._folderPreviewId = 0; // Get the isDraggable property without passing it on to the BaseIcon: @@ -2075,11 +2075,7 @@ var AppIcon = GObject.registerClass({ }); } - this._dragMonitor = null; - this._itemDragBeginId = Main.overview.connect( - 'item-drag-begin', this._onDragBegin.bind(this)); - this._itemDragEndId = Main.overview.connect( - 'item-drag-end', this._onDragEnd.bind(this)); + this._otherIconIsHovering = false; this._menuTimeoutId = 0; this._stateChangedId = this.app.connect('notify::state', () => { @@ -2091,9 +2087,6 @@ var AppIcon = GObject.registerClass({ } _onDestroy() { - Main.overview.disconnect(this._itemDragBeginId); - Main.overview.disconnect(this._itemDragEndId); - if (this._folderPreviewId > 0) { GLib.source_remove(this._folderPreviewId); this._folderPreviewId = 0; @@ -2340,7 +2333,17 @@ var AppIcon = GObject.registerClass({ } _setHoveringByDnd(hovering) { + if (this._otherIconIsHovering == hovering) + return; + + this._otherIconIsHovering = hovering; + if (hovering) { + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this), + }; + DND.addDragMonitor(this._dragMonitor); + if (this._folderPreviewId > 0) return; @@ -2352,6 +2355,8 @@ var AppIcon = GObject.registerClass({ return GLib.SOURCE_REMOVE; }); } else { + DND.removeDragMonitor(this._dragMonitor); + if (this._folderPreviewId > 0) { GLib.source_remove(this._folderPreviewId); this._folderPreviewId = 0; @@ -2361,32 +2366,13 @@ var AppIcon = GObject.registerClass({ } } - _onDragBegin() { - this._dragMonitor = { - dragMotion: this._onDragMotion.bind(this), - }; - DND.addDragMonitor(this._dragMonitor); - } - _onDragMotion(dragEvent) { - let target = dragEvent.targetActor; - let isHovering = target == this || this.contains(target); - let canDrop = this._canAccept(dragEvent.source); - let hasDndHover = isHovering && canDrop; - - if (this._hasDndHover != hasDndHover) { - this._setHoveringByDnd(hasDndHover); - this._hasDndHover = hasDndHover; - } + if (!this.contains(dragEvent.targetActor)) + this._setHoveringByDnd(false); return DND.DragMotionResult.CONTINUE; } - _onDragEnd() { - this.remove_style_pseudo_class('drop'); - DND.removeDragMonitor(this._dragMonitor); - } - handleDragOver(source) { if (source == this) return DND.DragMotionResult.NO_DROP; @@ -2394,6 +2380,8 @@ var AppIcon = GObject.registerClass({ if (!this._canAccept(source)) return DND.DragMotionResult.CONTINUE; + this._setHoveringByDnd(true); + return DND.DragMotionResult.MOVE_DROP; }