diff --git a/Makefile b/Makefile index 8ada6a2..3690105 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ UUID = dash-to-panel@jderose9.github.com BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md -EXTRA_MODULES = appIcons.js convenience.js panel.js panelStyle.js overview.js taskbar.js secondaryMenu.js windowPreview.js prefs.js Settings.ui +EXTRA_MODULES = appIcons.js convenience.js panel.js panelStyle.js overview.js taskbar.js windowPreview.js prefs.js Settings.ui EXTRA_IMAGES = highlight_bg.svg highlight_stacked_bg.svg TOLOCALIZE = prefs.js MSGSRC = $(wildcard po/*.po) diff --git a/appIcons.js b/appIcons.js index b2a54fe..6099840 100644 --- a/appIcons.js +++ b/appIcons.js @@ -40,13 +40,13 @@ const DND = imports.ui.dnd; const IconGrid = imports.ui.iconGrid; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; +const RemoteMenu = imports.ui.remoteMenu; const Tweener = imports.ui.tweener; const Util = imports.misc.util; const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; -const SecondaryMenu = Me.imports.secondaryMenu; const WindowPreview = Me.imports.windowPreview; const Taskbar = Me.imports.taskbar; @@ -302,7 +302,7 @@ const taskbarAppIcon = new Lang.Class({ this._draggable.fakeRelease(); if (!this._menu) { - this._menu = new SecondaryMenu.taskbarSecondaryMenu(this, this._dtpSettings); + this._menu = new taskbarSecondaryMenu(this, this._dtpSettings); this._menu.connect('activate-window', Lang.bind(this, function (menu, window) { this.activateWindow(window, this._dtpSettings); })); @@ -842,8 +842,233 @@ function getInterestingWindows(app, settings) { return windows; } +/** + * Extend AppIconMenu + * + * - set popup arrow side based on taskbar orientation + * - Add close windows option based on quitfromdash extension + * (https://github.com/deuill/shell-extension-quitfromdash) + */ -// define first this function to use it in extendDashItemContainer +const taskbarSecondaryMenu = new Lang.Class({ + Name: 'DashToPanel.SecondaryMenu', + Extends: AppDisplay.AppIconMenu, + + _init: function(source, settings) { + this._dtpSettings = settings; + + let side = Taskbar.getPosition(); + + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later + this.parent(source); + + // Change the initialized side where required. + this._arrowSide = side; + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + }, + + // helper function for the quit windows abilities + _closeWindowInstance: function(metaWindow) { + metaWindow.delete(global.get_current_time()); + }, + + _redisplay: function() { + this.removeAll(); + + let appMenu = this._source.app.menu; + if(appMenu) { + let remoteMenu = new RemoteMenu.RemoteMenu(this._source.actor, this._source.app.menu, this._source.app.action_group); + let appMenuItems = remoteMenu._getMenuItems(); + let isItemsAdded = false; + for(let appMenuIdx in appMenuItems){ + let menuItem = appMenuItems[appMenuIdx]; + let labelText = menuItem.actor.label_actor.text; + if(labelText == _("New Window") || labelText == _("Quit")) + continue; + + if(menuItem instanceof PopupMenu.PopupSeparatorMenuItem) + continue; + + isItemsAdded = true; + + // this ends up getting called multiple times, and bombing due to the signal id's being invalid + // on a 2nd pass. disconnect the base handler and attach our own that wraps the id's in if statements + menuItem.disconnect(menuItem._popupMenuDestroyId) + menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) { + if(menuItem._popupMenuDestroyId) { + menuItem.disconnect(menuItem._popupMenuDestroyId); + menuItem._popupMenuDestroyId = 0; + } + if(menuItem._activateId) { + menuItem.disconnect(menuItem._activateId); + menuItem._activateId = 0; + } + if(menuItem._activeChangeId) { + menuItem.disconnect(menuItem._activeChangeId); + menuItem._activeChangeId = 0; + } + if(menuItem._sensitiveChangeId) { + menuItem.disconnect(menuItem._sensitiveChangeId); + menuItem._sensitiveChangeId = 0; + } + this.disconnect(menuItem._parentSensitiveChangeId); + if (menuItem == this._activeMenuItem) + this._activeMenuItem = null; + })); + + menuItem.actor.get_parent().remove_child(menuItem.actor); + if(menuItem instanceof PopupMenu.PopupSubMenuMenuItem) { + let newSubMenuMenuItem = new PopupMenu.PopupSubMenuMenuItem(labelText); + let appSubMenuItems = menuItem.menu._getMenuItems(); + for(let appSubMenuIdx in appSubMenuItems){ + let subMenuItem = appSubMenuItems[appSubMenuIdx]; + subMenuItem.actor.get_parent().remove_child(subMenuItem.actor); + newSubMenuMenuItem.menu.addMenuItem(subMenuItem); + } + this.addMenuItem(newSubMenuMenuItem); + } else + this.addMenuItem(menuItem); + + } + + if(isItemsAdded) + this._appendSeparator(); + } + + let windows = this._source.app.get_windows().filter(function(w) { + return !w.skip_taskbar; + }); + + // Display the app windows menu items and the separator between windows + // of the current desktop and other windows. + let activeWorkspace = global.screen.get_active_workspace(); + let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace; + + for (let i = 0; i < windows.length; i++) { + let window = windows[i]; + if (!separatorShown && window.get_workspace() != activeWorkspace) { + this._appendSeparator(); + separatorShown = true; + } + let item = this._appendMenuItem(window.title); + item.connect('activate', Lang.bind(this, function() { + this.emit('activate-window', window); + })); + } + + if (!this._source.app.is_window_backed()) { + this._appendSeparator(); + + let appInfo = this._source.app.get_app_info(); + let actions = appInfo.list_actions(); + if (this._source.app.can_open_new_window() && + actions.indexOf('new-window') == -1) { + this._newWindowMenuItem = this._appendMenuItem(_("New Window")); + this._newWindowMenuItem.connect('activate', Lang.bind(this, function() { + if (this._source.app.state == Shell.AppState.STOPPED) + this._source.animateLaunch(); + + this._source.app.open_new_window(-1); + this.emit('activate-window', null); + })); + this._appendSeparator(); + } + + if (PopupMenu.discreteGpuAvailable && + this._source.app.state == Shell.AppState.STOPPED && + actions.indexOf('activate-discrete-gpu') == -1) { + this._onDiscreteGpuMenuItem = this._appendMenuItem(_("Launch using Dedicated Graphics Card")); + this._onDiscreteGpuMenuItem.connect('activate', Lang.bind(this, function() { + if (this._source.app.state == Shell.AppState.STOPPED) + this._source.animateLaunch(); + + this._source.app.launch(0, -1, true); + this.emit('activate-window', null); + })); + } + + for (let i = 0; i < actions.length; i++) { + let action = actions[i]; + let item = this._appendMenuItem(appInfo.get_action_name(action)); + item.connect('activate', Lang.bind(this, function(emitter, event) { + this._source.app.launch_action(action, event.get_time(), -1); + this.emit('activate-window', null); + })); + } + + let canFavorite = global.settings.is_writable('favorite-apps'); + + if (canFavorite) { + this._appendSeparator(); + + let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); + + if (isFavorite) { + let item = this._appendMenuItem(_("Remove from Favorites")); + item.connect('activate', Lang.bind(this, function() { + let favs = AppFavorites.getAppFavorites(); + favs.removeFavorite(this._source.app.get_id()); + })); + } else { + let item = this._appendMenuItem(_("Add to Favorites")); + item.connect('activate', Lang.bind(this, function() { + let favs = AppFavorites.getAppFavorites(); + favs.addFavorite(this._source.app.get_id()); + })); + } + } + + // if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { + // this._appendSeparator(); + // let item = this._appendMenuItem(_("Show Details")); + // item.connect('activate', Lang.bind(this, function() { + // let id = this._source.app.get_id(); + // let args = GLib.Variant.new('(ss)', [id, '']); + // Gio.DBus.get(Gio.BusType.SESSION, null, + // function(o, res) { + // let bus = Gio.DBus.get_finish(res); + // bus.call('org.gnome.Software', + // '/org/gnome/Software', + // 'org.gtk.Actions', 'Activate', + // GLib.Variant.new('(sava{sv})', + // ['details', [args], null]), + // null, 0, -1, null, null); + // Main.overview.hide(); + // }); + // })); + // } + } + + // quit menu + let app = this._source.app; + let count = getInterestingWindows(app, this._dtpSettings).length; + if ( count > 0) { + this._appendSeparator(); + let quitFromTaskbarMenuText = ""; + if (count == 1) + quitFromTaskbarMenuText = _("Quit"); + else + quitFromTaskbarMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); + + this._quitfromTaskbarMenuItem = this._appendMenuItem(quitFromTaskbarMenuText); + this._quitfromTaskbarMenuItem.connect('activate', Lang.bind(this, function() { + let app = this._source.app; + let windows = app.get_windows(); + for (let i = 0; i < windows.length; i++) { + this._closeWindowInstance(windows[i]) + } + })); + } + } +}); +Signals.addSignalMethods(taskbarSecondaryMenu.prototype); + +/** + * This function is used for both extendShowAppsIcon and extendDashItemContainer + */ function ItemShowLabel() { if (!this._labelText) return; @@ -897,4 +1122,98 @@ function ItemShowLabel() { time: DASH_ITEM_LABEL_SHOW_TIME, transition: 'easeOutQuad', }); -}; \ No newline at end of file +}; + + +/** + * Extend ShowAppsIcon + * + * - Pass settings to the constructor + * - set label position based on dash orientation + * - implement a popupMenu based on the AppIcon code + * + * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. + * thus use this ugly pattern. + */ +function extendShowAppsIcon(showAppsIcon, settings) { + showAppsIcon._dtpSettings = settings; + /* the variable equivalent to toggleButton has a different name in the appIcon class + (actor): duplicate reference to easily reuse appIcon methods */ + showAppsIcon.actor = showAppsIcon.toggleButton; + + // Re-use appIcon methods + showAppsIcon._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout; + showAppsIcon._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout; + showAppsIcon._onButtonPress = AppDisplay.AppIcon.prototype._onButtonPress; + showAppsIcon._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu; + showAppsIcon._onLeaveEvent = AppDisplay.AppIcon.prototype._onLeaveEvent; + showAppsIcon._onTouchEvent = AppDisplay.AppIcon.prototype._onTouchEvent; + showAppsIcon._onMenuPoppedDown = AppDisplay.AppIcon.prototype._onMenuPoppedDown; + + + // No action on clicked (showing of the appsview is controlled elsewhere) + showAppsIcon._onClicked = function(actor, button) { + showAppsIcon._removeMenuTimeout(); + }; + + showAppsIcon.actor.connect('leave-event', Lang.bind(showAppsIcon, showAppsIcon._onLeaveEvent)); + showAppsIcon.actor.connect('button-press-event', Lang.bind(showAppsIcon, showAppsIcon._onButtonPress)); + showAppsIcon.actor.connect('touch-event', Lang.bind(showAppsIcon, showAppsIcon._onTouchEvent)); + showAppsIcon.actor.connect('clicked', Lang.bind(showAppsIcon, showAppsIcon._onClicked)); + showAppsIcon.actor.connect('popup-menu', Lang.bind(showAppsIcon, showAppsIcon._onKeyboardPopupMenu)); + + showAppsIcon._menu = null; + showAppsIcon._menuManager = new PopupMenu.PopupMenuManager(showAppsIcon); + showAppsIcon._menuTimeoutId = 0; + + showAppsIcon.showLabel = ItemShowLabel; + + showAppsIcon.popupMenu = function() { + showAppsIcon._removeMenuTimeout(); + showAppsIcon.actor.fake_release(); + + if (!showAppsIcon._menu) { + showAppsIcon._menu = new MyShowAppsIconMenu(showAppsIcon, showAppsIcon._dtpSettings); + showAppsIcon._menu.connect('open-state-changed', Lang.bind(showAppsIcon, function(menu, isPoppedUp) { + if (!isPoppedUp) + showAppsIcon._onMenuPoppedDown(); + })); + let id = Main.overview.connect('hiding', Lang.bind(showAppsIcon, function() { + showAppsIcon._menu.close(); + })); + showAppsIcon._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); + showAppsIcon._menuManager.addMenu(showAppsIcon._menu); + } + + showAppsIcon.emit('menu-state-changed', true); + + showAppsIcon.actor.set_hover(true); + showAppsIcon._menu.popup(); + showAppsIcon._menuManager.ignoreRelease(); + showAppsIcon.emit('sync-tooltip'); + + return false; + }; + + Signals.addSignalMethods(showAppsIcon); +} + +/** + * A menu for the showAppsIcon + */ +const MyShowAppsIconMenu = new Lang.Class({ + Name: 'DashToPanel.ShowAppsIconMenu', + Extends: taskbarSecondaryMenu, + + _redisplay: function() { + this.removeAll(); + + let item = this._appendMenuItem('Dash to Panel ' + _('Settings')); + + item.connect('activate', function () { + Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); + }); + } +}); \ No newline at end of file diff --git a/secondaryMenu.js b/secondaryMenu.js deleted file mode 100644 index dd4d9f8..0000000 --- a/secondaryMenu.js +++ /dev/null @@ -1,259 +0,0 @@ -/* - * This file is part of the Dash-To-Panel extension for Gnome 3 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * - * Credits: - * This file is based on code from the Dash to Dock extension by micheleg - * and code from the Taskbar extension by Zorin OS - * Some code was also adapted from the upstream Gnome Shell source code. - */ - - -const AppDisplay = imports.ui.appDisplay; -const Lang = imports.lang; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Taskbar = Me.imports.taskbar; -const RemoteMenu = imports.ui.remoteMenu; -const PopupMenu = imports.ui.popupMenu; -const Shell = imports.gi.Shell; -const AppFavorites = imports.ui.appFavorites; -const Convenience = Me.imports.convenience; -const AppIcons = Me.imports.appIcons; - -/** - * Extend AppIconMenu - * - * - set popup arrow side based on taskbar orientation - * - Add close windows option based on quitfromdash extension - * (https://github.com/deuill/shell-extension-quitfromdash) - */ - -const taskbarSecondaryMenu = new Lang.Class({ - Name: 'DashToPanel.SecondaryMenu', - Extends: AppDisplay.AppIconMenu, - - _init: function(source, settings) { - - this._dtpSettings = settings; - - let side = Taskbar.getPosition(); - - // Damm it, there has to be a proper way of doing this... - // As I can't call the parent parent constructor (?) passing the side - // parameter, I overwite what I need later - this.parent(source); - - // Change the initialized side where required. - this._arrowSide = side; - this._boxPointer._arrowSide = side; - this._boxPointer._userArrowSide = side; - }, - - // helper function for the quit windows abilities - _closeWindowInstance: function(metaWindow) { - metaWindow.delete(global.get_current_time()); - }, - -_redisplay: function() { - this.removeAll(); - - let appMenu = this._source.app.menu; - if(appMenu) { - let remoteMenu = new RemoteMenu.RemoteMenu(this._source.actor, this._source.app.menu, this._source.app.action_group); - let appMenuItems = remoteMenu._getMenuItems(); - let isItemsAdded = false; - for(let appMenuIdx in appMenuItems){ - let menuItem = appMenuItems[appMenuIdx]; - let labelText = menuItem.actor.label_actor.text; - if(labelText == _("New Window") || labelText == _("Quit")) - continue; - - if(menuItem instanceof PopupMenu.PopupSeparatorMenuItem) - continue; - - isItemsAdded = true; - - // this ends up getting called multiple times, and bombing due to the signal id's being invalid - // on a 2nd pass. disconnect the base handler and attach our own that wraps the id's in if statements - menuItem.disconnect(menuItem._popupMenuDestroyId) - menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) { - if(menuItem._popupMenuDestroyId) { - menuItem.disconnect(menuItem._popupMenuDestroyId); - menuItem._popupMenuDestroyId = 0; - } - if(menuItem._activateId) { - menuItem.disconnect(menuItem._activateId); - menuItem._activateId = 0; - } - if(menuItem._activeChangeId) { - menuItem.disconnect(menuItem._activeChangeId); - menuItem._activeChangeId = 0; - } - if(menuItem._sensitiveChangeId) { - menuItem.disconnect(menuItem._sensitiveChangeId); - menuItem._sensitiveChangeId = 0; - } - this.disconnect(menuItem._parentSensitiveChangeId); - if (menuItem == this._activeMenuItem) - this._activeMenuItem = null; - })); - - menuItem.actor.get_parent().remove_child(menuItem.actor); - if(menuItem instanceof PopupMenu.PopupSubMenuMenuItem) { - let newSubMenuMenuItem = new PopupMenu.PopupSubMenuMenuItem(labelText); - let appSubMenuItems = menuItem.menu._getMenuItems(); - for(let appSubMenuIdx in appSubMenuItems){ - let subMenuItem = appSubMenuItems[appSubMenuIdx]; - subMenuItem.actor.get_parent().remove_child(subMenuItem.actor); - newSubMenuMenuItem.menu.addMenuItem(subMenuItem); - } - this.addMenuItem(newSubMenuMenuItem); - } else - this.addMenuItem(menuItem); - - } - - if(isItemsAdded) - this._appendSeparator(); - } - - let windows = this._source.app.get_windows().filter(function(w) { - return !w.skip_taskbar; - }); - - // Display the app windows menu items and the separator between windows - // of the current desktop and other windows. - let activeWorkspace = global.screen.get_active_workspace(); - let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace; - - for (let i = 0; i < windows.length; i++) { - let window = windows[i]; - if (!separatorShown && window.get_workspace() != activeWorkspace) { - this._appendSeparator(); - separatorShown = true; - } - let item = this._appendMenuItem(window.title); - item.connect('activate', Lang.bind(this, function() { - this.emit('activate-window', window); - })); - } - - if (!this._source.app.is_window_backed()) { - this._appendSeparator(); - - let appInfo = this._source.app.get_app_info(); - let actions = appInfo.list_actions(); - if (this._source.app.can_open_new_window() && - actions.indexOf('new-window') == -1) { - this._newWindowMenuItem = this._appendMenuItem(_("New Window")); - this._newWindowMenuItem.connect('activate', Lang.bind(this, function() { - if (this._source.app.state == Shell.AppState.STOPPED) - this._source.animateLaunch(); - - this._source.app.open_new_window(-1); - this.emit('activate-window', null); - })); - this._appendSeparator(); - } - - if (PopupMenu.discreteGpuAvailable && - this._source.app.state == Shell.AppState.STOPPED && - actions.indexOf('activate-discrete-gpu') == -1) { - this._onDiscreteGpuMenuItem = this._appendMenuItem(_("Launch using Dedicated Graphics Card")); - this._onDiscreteGpuMenuItem.connect('activate', Lang.bind(this, function() { - if (this._source.app.state == Shell.AppState.STOPPED) - this._source.animateLaunch(); - - this._source.app.launch(0, -1, true); - this.emit('activate-window', null); - })); - } - - for (let i = 0; i < actions.length; i++) { - let action = actions[i]; - let item = this._appendMenuItem(appInfo.get_action_name(action)); - item.connect('activate', Lang.bind(this, function(emitter, event) { - this._source.app.launch_action(action, event.get_time(), -1); - this.emit('activate-window', null); - })); - } - - let canFavorite = global.settings.is_writable('favorite-apps'); - - if (canFavorite) { - this._appendSeparator(); - - let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); - - if (isFavorite) { - let item = this._appendMenuItem(_("Remove from Favorites")); - item.connect('activate', Lang.bind(this, function() { - let favs = AppFavorites.getAppFavorites(); - favs.removeFavorite(this._source.app.get_id()); - })); - } else { - let item = this._appendMenuItem(_("Add to Favorites")); - item.connect('activate', Lang.bind(this, function() { - let favs = AppFavorites.getAppFavorites(); - favs.addFavorite(this._source.app.get_id()); - })); - } - } - - // if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { - // this._appendSeparator(); - // let item = this._appendMenuItem(_("Show Details")); - // item.connect('activate', Lang.bind(this, function() { - // let id = this._source.app.get_id(); - // let args = GLib.Variant.new('(ss)', [id, '']); - // Gio.DBus.get(Gio.BusType.SESSION, null, - // function(o, res) { - // let bus = Gio.DBus.get_finish(res); - // bus.call('org.gnome.Software', - // '/org/gnome/Software', - // 'org.gtk.Actions', 'Activate', - // GLib.Variant.new('(sava{sv})', - // ['details', [args], null]), - // null, 0, -1, null, null); - // Main.overview.hide(); - // }); - // })); - // } - } - - // quit menu - let app = this._source.app; - let count = AppIcons.getInterestingWindows(app, this._dtpSettings).length; - if ( count > 0) { - this._appendSeparator(); - let quitFromTaskbarMenuText = ""; - if (count == 1) - quitFromTaskbarMenuText = _("Quit"); - else - quitFromTaskbarMenuText = _("Quit") + ' ' + count + ' ' + _("Windows"); - - this._quitfromTaskbarMenuItem = this._appendMenuItem(quitFromTaskbarMenuText); - this._quitfromTaskbarMenuItem.connect('activate', Lang.bind(this, function() { - let app = this._source.app; - let windows = app.get_windows(); - for (let i = 0; i < windows.length; i++) { - this._closeWindowInstance(windows[i]) - } - })); - } - } -}); diff --git a/taskbar.js b/taskbar.js index cb0b758..e1737be 100644 --- a/taskbar.js +++ b/taskbar.js @@ -46,7 +46,6 @@ const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; -const SecondaryMenu = Me.imports.secondaryMenu; const WindowPreview = Me.imports.windowPreview; const AppIcons = Me.imports.appIcons; @@ -218,9 +217,8 @@ const taskbar = new Lang.Class({ this._scrollView.add_actor(this._box); this._showAppsIcon = new Dash.ShowAppsIcon(); - this._showAppsIcon.showLabel = AppIcons.ItemShowLabel; + AppIcons.extendShowAppsIcon(this._showAppsIcon, this._dtpSettings); this.showAppsButton = this._showAppsIcon.toggleButton; - this._showAppsIcon.actor = this.showAppsButton; this.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); @@ -229,6 +227,11 @@ const taskbar = new Lang.Class({ this._showAppsIcon.icon.setIconSize(this.iconSize); this._hookUpLabel(this._showAppsIcon); + let appsIcon = this._showAppsIcon; + appsIcon.connect('menu-state-changed', Lang.bind(this, function(appsIcon, opened) { + this._itemMenuStateChanged(appsIcon, opened); + })); + this._container.add_actor(this._showAppsIcon); if (!this._dtpSettings.get_boolean('show-show-apps-button')) @@ -399,6 +402,7 @@ const taskbar = new Lang.Class({ _endDrag: function() { this._clearDragPlaceholder(); this._clearEmptyDropTarget(); + this._showAppsIcon.setDragApp(null); DND.removeDragMonitor(this._dragMonitor); }, @@ -407,9 +411,16 @@ const taskbar = new Lang.Class({ if (app == null) return DND.DragMotionResult.CONTINUE; - if (!this._box.contains(dragEvent.targetActor)) + 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; },