diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 5f9a2df5f..a2ae129a4 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -1093,8 +1093,7 @@ class AppDisplay extends BaseAppView { } _canAccept(source) { - return (source instanceof AppIcon) || - (source instanceof FolderIcon); + return source instanceof AppViewItem; } handleDragOver(source) { @@ -1249,6 +1248,162 @@ var AppSearchProvider = class AppSearchProvider { } }; +var AppViewItem = GObject.registerClass( +class AppViewItem extends St.Button { + _init(params = {}, isDraggable = true) { + super._init({ + pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }), + reactive: true, + button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO, + can_focus: true, + ...params, + }); + + this._delegate = this; + + if (isDraggable) { + this._draggable = DND.makeDraggable(this); + this._draggable.connect('drag-begin', this._onDragBegin.bind(this)); + this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this)); + this._draggable.connect('drag-end', this._onDragEnd.bind(this)); + } + + this._otherIconIsHovering = false; + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._dragMonitor) { + DND.removeDragMonitor(this._dragMonitor); + this._dragMonitor = null; + } + + if (this._draggable) { + if (this._dragging) + Main.overview.endItemDrag(this); + this._draggable = null; + } + } + + _onDragBegin() { + this._dragging = true; + this.scaleAndFade(); + Main.overview.beginItemDrag(this); + } + + _onDragCancelled() { + this._dragging = false; + Main.overview.cancelledItemDrag(this); + } + + _onDragEnd() { + this._dragging = false; + this.undoScaleAndFade(); + Main.overview.endItemDrag(this); + } + + scaleIn() { + this.scale_x = 0; + this.scale_y = 0; + + this.ease({ + scale_x: 1, + scale_y: 1, + duration: APP_ICON_SCALE_IN_TIME, + delay: APP_ICON_SCALE_IN_DELAY, + mode: Clutter.AnimationMode.EASE_OUT_QUINT, + }); + } + + scaleAndFade() { + this.reactive = false; + this.ease({ + scale_x: 0.75, + scale_y: 0.75, + opacity: 128, + }); + } + + undoScaleAndFade() { + this.reactive = true; + this.ease({ + scale_x: 1.0, + scale_y: 1.0, + opacity: 255, + }); + } + + _canAccept(source) { + return source !== this; + } + + _setHoveringByDnd(hovering) { + if (this._otherIconIsHovering === hovering) + return; + + this._otherIconIsHovering = hovering; + + if (hovering) { + this._dragMonitor = { + dragMotion: this._onDragMotion.bind(this), + }; + DND.addDragMonitor(this._dragMonitor); + } else { + DND.removeDragMonitor(this._dragMonitor); + } + } + + _onDragMotion(dragEvent) { + if (!this.contains(dragEvent.targetActor)) + this._setHoveringByDnd(false); + + return DND.DragMotionResult.CONTINUE; + } + + _withinLeeways(x) { + return x < IconGrid.LEFT_DIVIDER_LEEWAY || + x > this.width - IconGrid.RIGHT_DIVIDER_LEEWAY; + } + + handleDragOver(source, _actor, x) { + if (source === this) + return DND.DragMotionResult.NO_DROP; + + if (!this._canAccept(source)) + return DND.DragMotionResult.CONTINUE; + + if (this._withinLeeways(x)) { + this._setHoveringByDnd(false); + return DND.DragMotionResult.CONTINUE; + } + + this._setHoveringByDnd(true); + + return DND.DragMotionResult.MOVE_DROP; + } + + acceptDrop(source, _actor, x) { + this._setHoveringByDnd(false); + + if (!this._canAccept(source)) + return false; + + if (this._withinLeeways(x)) + return DND.DragMotionResult.CONTINUE; + + return true; + } + + get id() { + return this._id; + } + + get name() { + return this._name; + } +}); + var FolderGrid = GObject.registerClass( class FolderGrid extends IconGrid.IconGrid { _init() { @@ -2042,34 +2197,26 @@ var AppIcon = GObject.registerClass({ 'menu-state-changed': { param_types: [GObject.TYPE_BOOLEAN] }, 'sync-tooltip': {}, }, -}, class AppIcon extends St.Button { +}, class AppIcon extends AppViewItem { _init(app, iconParams = {}) { - super._init({ - style_class: 'app-well-app', - pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }), - reactive: true, - button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO, - can_focus: true, - }); + // Get the isDraggable property without passing it on to the BaseIcon: + const appIconParams = Params.parse(iconParams, { isDraggable: true }, true); + const isDraggable = appIconParams['isDraggable']; + delete iconParams['isDraggable']; + + super._init({ style_class: 'app-well-app' }, isDraggable); this.app = app; - this.id = app.get_id(); - this.name = app.get_name(); + this._id = app.get_id(); + this._name = app.get_name(); this._iconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(), x_expand: true, y_expand: true }); this.set_child(this._iconContainer); - this._delegate = this; - this._folderPreviewId = 0; - // Get the isDraggable property without passing it on to the BaseIcon: - let appIconParams = Params.parse(iconParams, { isDraggable: true }, true); - let isDraggable = appIconParams['isDraggable']; - delete iconParams['isDraggable']; - iconParams['createIcon'] = this._createIcon.bind(this); iconParams['setSizeManually'] = true; this.icon = new IconGrid.BaseIcon(app.get_name(), iconParams); @@ -2092,37 +2239,16 @@ var AppIcon = GObject.registerClass({ this._menu = null; this._menuManager = new PopupMenu.PopupMenuManager(this); - if (isDraggable) { - this._draggable = DND.makeDraggable(this); - this._draggable.connect('drag-begin', () => { - this._dragging = true; - this.scaleAndFade(); - this._removeMenuTimeout(); - Main.overview.beginItemDrag(this); - }); - this._draggable.connect('drag-cancelled', () => { - this._dragging = false; - Main.overview.cancelledItemDrag(this); - }); - this._draggable.connect('drag-end', () => { - this._dragging = false; - this.undoScaleAndFade(); - Main.overview.endItemDrag(this); - }); - } - - this._otherIconIsHovering = false; - this._menuTimeoutId = 0; this._stateChangedId = this.app.connect('notify::state', () => { this._updateRunningStyle(); }); this._updateRunningStyle(); - - this.connect('destroy', this._onDestroy.bind(this)); } _onDestroy() { + super._onDestroy(); + if (this._folderPreviewId > 0) { GLib.source_remove(this._folderPreviewId); this._folderPreviewId = 0; @@ -2130,20 +2256,15 @@ var AppIcon = GObject.registerClass({ if (this._stateChangedId > 0) this.app.disconnect(this._stateChangedId); - if (this._dragMonitor) { - DND.removeDragMonitor(this._dragMonitor); - this._dragMonitor = null; - } - - if (this._draggable) { - if (this._dragging) - Main.overview.endItemDrag(this); - this._draggable = null; - } this._stateChangedId = 0; this._removeMenuTimeout(); } + _onDragBegin() { + this._removeMenuTimeout(); + super._onDragBegin(); + } + _createIcon(iconSize) { return this.app.create_icon_texture(iconSize); } @@ -2289,19 +2410,6 @@ var AppIcon = GObject.registerClass({ this.icon.animateZoomOutAtPos(x, y); } - scaleIn() { - this.scale_x = 0; - this.scale_y = 0; - - this.ease({ - scale_x: 1, - scale_y: 1, - duration: APP_ICON_SCALE_IN_TIME, - delay: APP_ICON_SCALE_IN_DELAY, - mode: Clutter.AnimationMode.EASE_OUT_QUINT, - }); - } - shellWorkspaceLaunch(params) { let { stack } = new Error(); log('shellWorkspaceLaunch is deprecated, use app.open_new_window() instead\n%s'.format(stack)); @@ -2326,24 +2434,6 @@ var AppIcon = GObject.registerClass({ return this.hover && (!this._menu || !this._menu.isOpen); } - scaleAndFade() { - this.reactive = false; - this.ease({ - scale_x: 0.75, - scale_y: 0.75, - opacity: 128, - }); - } - - undoScaleAndFade() { - this.reactive = true; - this.ease({ - scale_x: 1.0, - scale_y: 1.0, - opacity: 255, - }); - } - _showFolderPreview() { this.icon.label.opacity = 0; this.icon.icon.ease({ @@ -2372,14 +2462,9 @@ var AppIcon = GObject.registerClass({ if (this._otherIconIsHovering == hovering) return; - this._otherIconIsHovering = hovering; + super._setHoveringByDnd(hovering); if (hovering) { - this._dragMonitor = { - dragMotion: this._onDragMotion.bind(this), - }; - DND.addDragMonitor(this._dragMonitor); - if (this._folderPreviewId > 0) return; @@ -2391,8 +2476,6 @@ 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; @@ -2402,42 +2485,9 @@ var AppIcon = GObject.registerClass({ } } - _onDragMotion(dragEvent) { - if (!this.contains(dragEvent.targetActor)) - this._setHoveringByDnd(false); - - return DND.DragMotionResult.CONTINUE; - } - - _withinLeeways(x) { - return x < IconGrid.LEFT_DIVIDER_LEEWAY || - x > this.width - IconGrid.RIGHT_DIVIDER_LEEWAY; - } - - handleDragOver(source, _actor, x) { - if (source == this) - return DND.DragMotionResult.NO_DROP; - - if (!this._canAccept(source)) - return DND.DragMotionResult.CONTINUE; - - if (this._withinLeeways(x)) { - this._setHoveringByDnd(false); - return DND.DragMotionResult.CONTINUE; - } - - this._setHoveringByDnd(true); - - return DND.DragMotionResult.MOVE_DROP; - } - - acceptDrop(source, _actor, x) { - this._setHoveringByDnd(false); - - if (!this._canAccept(source)) - return false; - - if (this._withinLeeways(x)) + acceptDrop(source, actor, x) { + const accepted = super.acceptDrop(source, actor, x); + if (!accepted) return false; let view = _getViewFromIcon(this);