const GLib = imports.gi.GLib; const Gio = imports.gi.Gio; const Clutter = imports.gi.Clutter; const Lang = imports.lang; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; const Signals = imports.signals; const St = imports.gi.St; const Main = imports.ui.main; const WorkspacesView = imports.ui.workspacesView; const Workspace = imports.ui.workspace; const WorkspaceThumbnail = imports.ui.workspaceThumbnail; const Overview = imports.ui.overview; const IconGrid = imports.ui.iconGrid; const PopupMenu = imports.ui.popupMenu; const DND = imports.ui.dnd; const Util = imports.misc.util; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = Me.imports.convenience; const MyWorkspaceThumbnail = Me.imports.myWorkspaceThumbnail; const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); const _ = Gettext.gettext; var CAPTION_APP_ICON_ZOOM = 8; let TASKBAR_TOOLTIP_SHOW_TIME = 150; let TASKBAR_TOOLTIP_HIDE_TIME = 100; let TASKBAR_TOOLTIP_HOVER_TIMEOUT = 10; const WindowAppsUpdateAction = { ADD: 0, REMOVE: 1, CLEARALL: 2 }; const CaptionPosition = { BOTTOM: 0, TOP: 1 }; /* Return the actual position reverseing left and right in rtl */ function getPosition(settings) { let position = settings.get_enum('dock-position'); if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { if (position == St.Side.LEFT) position = St.Side.RIGHT; else if (position == St.Side.RIGHT) position = St.Side.LEFT; } return position; } var TaskbarIcon = class WorkspacesToDock_TaskbarIcon { constructor(app, metaWin, caption) { this._caption = caption; this._mySettings = caption._mySettings; this._app = app; this._metaWin = metaWin; if (this._mySettings.get_enum('workspace-caption-position') == CaptionPosition.TOP) { this._captionYAlign = Clutter.ActorAlign.START; } else { this._captionYAlign = Clutter.ActorAlign.END; } let iconParams = {setSizeManually: true, showLabel: false}; iconParams['createIcon'] = (iconSize) => { return app.create_icon_texture(iconSize);}; this._icon = new IconGrid.BaseIcon(app.get_name(), iconParams); this._icon.add_style_class_name('workspacestodock-caption-windowapps-button-icon'); this._iconSize = this._mySettings.get_double('workspace-caption-taskbar-icon-size'); this._icon.setIconSize(this._mySettings.get_double('workspace-caption-taskbar-icon-size')); this.actor = new St.Button({ style_class:'workspacestodock-caption-windowapps-button', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign }); this.actor.set_child(this._icon); this.actor._delegate = this; // this._tooltipText = this._app.get_name(); this._tooltipHoverTimeoutId = 0; this._tooltipText = this._metaWin.title; this.tooltip = new St.Label({ style_class: 'dash-label workspacestodock-caption-windowapps-button-tooltip'}); this.tooltip.hide(); Main.layoutManager.addChrome(this.tooltip); Main.layoutManager.uiGroup.set_child_below_sibling(this.tooltip, Main.layoutManager.modalDialogGroup); this.tooltip_actor = this.tooltip; // Connect signals this.actor.connect('button-release-event', this._onButtonRelease.bind(this)); this.actor.connect('enter-event', this._onButtonEnter.bind(this)); this.actor.connect('leave-event', this._onButtonLeave.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this)); // Make actor draggable this._draggable = DND.makeDraggable(this.actor); } _onDestroy() { this.tooltip.hide(); this.tooltip.destroy(); } _onButtonEnter(actor, event) { let icon = actor._delegate._icon; let zoomSize = this._mySettings.get_double('workspace-caption-taskbar-icon-size') + CAPTION_APP_ICON_ZOOM; icon.setIconSize(zoomSize); if (this._mySettings.get_boolean('workspace-caption-taskbar-tooltips')) { if (this._tooltipHoverTimeoutId > 0) { GLib.source_remove(this._tooltipHoverTimeoutId); this._tooltipHoverTimeoutId = 0; } this._tooltipHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, TASKBAR_TOOLTIP_HOVER_TIMEOUT, this.showTooltip.bind(this)); } } _onButtonLeave(actor, event) { let icon = actor._delegate._icon; icon.setIconSize(this._mySettings.get_double('workspace-caption-taskbar-icon-size')); this.hideTooltip(); } _onButtonRelease(actor, event) { let mouseButton = event.get_button(); if (mouseButton == 1) { if (this._caption._menu.isOpen) { this._caption._menu.close(); } this._caption.activateMetaWindow(this._metaWin); } if (mouseButton == 2) { this._caption.closeMetaWindow(this._metaWin); } this.hideTooltip(); return Clutter.EVENT_PROPAGATE; } getDragActor() { this.hideTooltip(); return this._app.create_icon_texture(this._iconSize); } // Returns the original actor that should align with the actor // we show as the item is being dragged. getDragActorSource() { this.hideTooltip(); return this._icon; } showTooltip() { if (this._tooltipHoverTimeoutId > 0) { GLib.source_remove(this._tooltipHoverTimeoutId); this._tooltipHoverTimeoutId = 0; } if (!this._tooltipText) return; this._tooltipText = this._metaWin.title; this.tooltip.set_text(this._tooltipText); this.tooltip.opacity = 0; this.tooltip.show(); let [buttonStageX, buttonStageY] = this.actor.get_transformed_position(); let labelWidth = this.tooltip.get_width(); let buttonWidth = this.actor.get_width(); let x = buttonStageX + (buttonWidth / 2) - (labelWidth / 2); let labelHeight = this.tooltip.get_height(); let y = buttonStageY - labelHeight; // Get monitor screen info let preferredMonitorIndex = this._mySettings.get_int('preferred-monitor'); let monitorIndex = (Main.layoutManager.primaryIndex + preferredMonitorIndex) % Main.layoutManager.monitors.length ; let monitor = Main.layoutManager.monitors[monitorIndex]; // Check that tooltip is not off screen // Correct tooltip position if necessary let position = getPosition(this._mySettings); if (position == St.Side.LEFT) { if (x < monitor.x) x = monitor.x; } if (position == St.Side.RIGHT) { if ((x + labelWidth) > (monitor.x + monitor.width)) x = (monitor.x + monitor.width) - labelWidth; } if (position == St.Side.TOP || position == St.Side.BOTTOM) { if (x < monitor.x) x = monitor.x; if ((x + labelWidth) > (monitor.x + monitor.width)) x = (monitor.x + monitor.width) - labelWidth; } this.tooltip.set_position(x, y); this.tooltip.ease({ opacity: 255, duration: TASKBAR_TOOLTIP_SHOW_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD }); } hideTooltip() { if (this._tooltipHoverTimeoutId > 0) { GLib.source_remove(this._tooltipHoverTimeoutId); this._tooltipHoverTimeoutId = 0; } this.tooltip.ease({ opacity: 0, duration: TASKBAR_TOOLTIP_HIDE_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { this.tooltip.hide(); } }); } }; var MenuTaskListItem = class WorkspacesToDock_MenuTaskListItem { constructor(app, metaWin, caption) { this._metaWin = metaWin; this._caption = caption; this._mySettings = caption._mySettings; let iconParams = {setSizeManually: true, showLabel: false}; iconParams['createIcon'] = (iconSize) => { return app.create_icon_texture(iconSize);}; this._icon = new IconGrid.BaseIcon(app.get_name(), iconParams); this._icon.add_style_class_name('workspacestodock-caption-windowapps-menu-icon'); this._icon.setIconSize(this._mySettings.get_double('workspace-caption-menu-icon-size')); // this._label = new St.Label({ text: app.get_name(), style_class: 'workspacestodock-caption-windowapps-menu-label' }); this._label = new St.Label({ text: this._metaWin.title, style_class: 'workspacestodock-caption-windowapps-menu-label', x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER, x_expand: true }); this._buttonBox = new St.BoxLayout({ style_class:'workspacestodock-caption-windowapps-menu-button', x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER, x_expand: true }); this._buttonBox.add_actor(this._icon); this._buttonBox.add_actor(this._label); this._closeButton = new St.Button({ style_class:'workspacestodock-caption-windowapps-menu-close', x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER }); // this._closeButton.add_style_class_name('window-close'); this._closeIcon = new St.Icon({ icon_name: 'window-close-symbolic', style_class: 'popup-menu-icon' }); this._closeButton.set_size(this._mySettings.get_double('workspace-caption-menu-icon-size'), this._mySettings.get_double('workspace-caption-menu-icon-size')); this._closeButton.set_child(this._closeIcon); this.actor = new St.BoxLayout({ reactive: true, style_class: 'popup-menu-item workspacestodock-caption-windowapps-menu-item' }); this.actor._delegate = this; this._ornament = 0; this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' }); this.actor.add_actor(this._ornamentLabel); this.actor.add_actor(this._buttonBox); this.actor.add_actor(this._closeButton); // Connect signals this._closeButton.connect('button-release-event', this._onCloseButtonRelease.bind(this)); this.actor.connect('button-release-event', this._onButtonRelease.bind(this)); this.actor.connect('enter-event', this._onItemEnter.bind(this)); this.actor.connect('leave-event', this._onItemLeave.bind(this)); } _onItemEnter(actor, event) { this.actor.add_style_pseudo_class('active'); } _onItemLeave(actor, event) { this.actor.remove_style_pseudo_class('active'); } _onButtonRelease(actor, event) { let mouseButton = event.get_button(); if (mouseButton == 1) { this._caption.activateMetaWindow(this._metaWin); } return Clutter.EVENT_PROPAGATE; } _onCloseButtonRelease(actor, event) { let mouseButton = event.get_button(); if (mouseButton == 1) { this._caption.closeMetaWindow(this._metaWin); } return Clutter.EVENT_PROPAGATE; } }; var ThumbnailCaption = class WorkspacesToDock_ThumbnailCaption { constructor(thumbnail) { this._thumbnail = thumbnail; this._settings = new Gio.Settings({ schema: MyWorkspaceThumbnail.MUTTER_SCHEMA }); this._mySettings = Convenience.getSettings('org.gnome.shell.extensions.workspaces-to-dock'); this._position = getPosition(this._mySettings); this._isHorizontal = (this._position == St.Side.TOP || this._position == St.Side.BOTTOM); if (this._mySettings.get_enum('workspace-caption-position') == CaptionPosition.TOP) { this._captionYAlign = Clutter.ActorAlign.START; } else { this._captionYAlign = Clutter.ActorAlign.END; } this.actor = new St.Bin({ name: 'workspacestodockCaptionContainer', reactive: false, style_class: 'workspacestodock-workspace-caption-container', x_fill: true, y_align: this._captionYAlign, x_align: Clutter.ActorAlign.START }); this._wsCaptionBackground = new St.Bin({ name: 'workspacestodockCaptionBackground', reactive: false, style_class: 'workspacestodock-workspace-caption-background' }); if (this._mySettings.get_enum('workspace-caption-position') == CaptionPosition.TOP) this._wsCaptionBackground.add_style_class_name('caption-top'); this._taskBar = []; this._taskBarBox = null; this._menuTaskListBox = null; this._thumbnailShowId = 0; this._afterWindowAddedId = this._thumbnail.metaWorkspace.connect_after('window-added', this._onAfterWindowAdded.bind(this)); this._afterWindowRemovedId = this._thumbnail.metaWorkspace.connect_after('window-removed', this._onAfterWindowRemoved.bind(this)); this._switchWorkspaceNotifyId = global.window_manager.connect('switch-workspace', this.activeWorkspaceChanged.bind(this)); this._menuManager = new PopupMenu.PopupMenuManager(this.actor); this._initCaption(); this._thumbnailShowId = this._thumbnail.connect("show", this._initTaskbar.bind(this)); } destroy() { this.workspaceRemoved(); if (this._taskBarBox) { this._taskBarBox.destroy_all_children(); this._taskBarBox = null; } if (this._menu) { this._menu.close(); this._menu.destroy(); } } workspaceRemoved() { if (this._afterWindowAddedId > 0) { this._thumbnail.metaWorkspace.disconnect(this._afterWindowAddedId); this._afterWindowAddedId = 0; } if (this._afterWindowRemovedId > 0) { this._thumbnail.metaWorkspace.disconnect(this._afterWindowRemovedId); this._afterWindowRemovedId = 0; } if (this._switchWorkspaceNotifyId > 0) { global.window_manager.disconnect(this._switchWorkspaceNotifyId); this._switchWorkspaceNotifyId = 0; } for (let i = 0; i < this._taskBar.length; i++) { this._taskBar[i].metaWin.disconnect(this._taskBar[i].signalFocusedId); } this._taskBar = []; } // Tests if @actor belongs to this workspace and monitor _isMyWindow(actor, isMetaWin) { let win; if (isMetaWin) { win = actor; } else { win = actor.meta_window; } return win.located_on_workspace(this._thumbnail.metaWorkspace) && (win.get_monitor() == this._thumbnail.monitorIndex); } // Tests if @win should be shown in the Overview _isOverviewWindow(window, isMetaWin) { let win; if (isMetaWin) { win = window; } else { win = window.get_meta_window(); } return !win.skip_taskbar && win.showing_on_its_workspace(); } // Tests if window app should be shown on this workspace _isMinimizedWindow(actor, isMetaWin) { let win; if (isMetaWin) { win = actor; } else { win = actor.meta_window; } return (!win.skip_taskbar && win.minimized); } // Tests if window app should be shown on this workspace _showWindowAppOnThisWorkspace(actor, isMetaWin) { let win; if (isMetaWin) { win = actor; } else { win = actor.meta_window; } let workspaceManager = global.workspace_manager; let activeWorkspace = workspaceManager.get_active_workspace(); if (this._settings.get_boolean('workspaces-only-on-primary')) { return (this._thumbnail.metaWorkspace == activeWorkspace && !win.skip_taskbar && win.is_on_all_workspaces()); } else { return (win.located_on_workspace(this._thumbnail.metaWorkspace) && !win.skip_taskbar && win.showing_on_its_workspace()); } } _initCaption() { if (this._mySettings.get_boolean('workspace-captions')) { this._wsCaption = new St.BoxLayout({ name: 'workspacestodockCaption', reactive: false, style_class: 'workspacestodock-workspace-caption', pack_start: true }); let currentItems = this._mySettings.get_strv('workspace-caption-items'); for (let i = 0; i < currentItems.length; i++) { let elements = currentItems[i].split(':'); let item = elements[0] let expandState = (elements[1] == "true"? true: false); switch (item) { case "number": this._wsNumber = new St.Label({ name: 'workspacestodockCaptionNumber', text: '', x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER }); this._wsNumberBox = new St.BoxLayout({ name: 'workspacestodockCaptionNumberBox', style_class: 'workspacestodock-caption-number', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign, x_expand: expandState, y_expand: expandState }); this._wsNumberBox.add_actor(this._wsNumber); this._wsCaption.add_actor(this._wsNumberBox); break; case "name": this._wsName = new St.Label({ name: 'workspacestodockCaptionName', text: '', x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER }); this._wsNameBox = new St.BoxLayout({ name: 'workspacestodockCaptionNameBox', style_class: 'workspacestodock-caption-name', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign, x_expand: expandState }); this._wsNameBox.add_actor(this._wsName); this._wsCaption.add_actor(this._wsNameBox); break; case "windowcount": this._wsWindowCount = new St.Label({ name: 'workspacestodockCaptionWindowCount', text: '', x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER }); this._wsWindowCountBox = new St.BoxLayout({ name: 'workspacestodockCaptionWindowCountBox', style_class: 'workspacestodock-caption-windowcount', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign, x_expand: expandState }); if (this._mySettings.get_boolean('workspace-caption-windowcount-image')) { this._wsWindowCountBox.remove_style_class_name("workspacestodock-caption-windowcount"); this._wsWindowCountBox.add_style_class_name("workspacestodock-caption-windowcount-image"); } this._wsWindowCountBox.add_actor(this._wsWindowCount); this._wsCaption.add_actor(this._wsWindowCountBox); break; case "windowapps": this._taskBarBox = new St.BoxLayout({ name: 'workspacestodockCaptionWindowApps', reactive: false, style_class: 'workspacestodock-caption-windowapps', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign, x_expand: expandState, y_expand: expandState }); this._wsCaption.add_actor(this._taskBarBox); break; case "spacer": this._wsSpacer = new St.Label({ name: 'workspacestodockCaptionSpacer', text: '', x_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER, x_expand: expandState, y_expand: expandState }); this._wsSpacerBox = new St.BoxLayout({ name: 'workspacestodockCaptionSpacerBox', style_class: 'workspacestodock-caption-spacer', x_align: Clutter.ActorAlign.START, y_align: this._captionYAlign, x_expand: expandState, y_expand: expandState }); this._wsSpacerBox.add_actor(this._wsSpacer); this._wsCaption.add_actor(this._wsSpacerBox); break; } } // Add caption to thumbnail actor this.actor.add_actor(this._wsCaption); this._thumbnail.add_actor(this._wsCaptionBackground); this._thumbnail.add_actor(this.actor); // Make thumbnail background transparent so that it doesn't show through // on edges where border-radius is set on caption this._thumbnail.set_style("background-color: rgba(0,0,0,0.0)"); // Create menu and menuitems let side = this._position; this._menu = new PopupMenu.PopupMenu(this._wsCaption, 0.5, side); // Set popup menu boxpointer point to center vertically on caption background // Otherwise the point lands at the top of the caption background because // the caption actually extends up another 18px. if (!this._isHorizontal) this._menu.setSourceAlignment(.8); this._menu.actor.add_style_class_name('workspacestodock-caption-windowapps-menu'); this._menu.connect('open-state-changed', (menu, open) => { if (open) { // Set popup menu flag so that dock knows not to hide this._thumbnail._thumbnailsBox.setPopupMenuFlag(true); // Set windowAppsBox icons back to normal (not zoomed) if (this._taskBarBox) { let children = this._taskBarBox.get_children(); for (let i=0; i < children.length; i++) { children[i]._delegate._icon.setIconSize(this._mySettings.get_double('workspace-caption-taskbar-icon-size')); } } } else { // Unset popup menu flag this._thumbnail._thumbnailsBox.setPopupMenuFlag(false); } }); let item = new PopupMenu.PopupMenuItem(_("Extension Preferences")); item.connect('activate', this._showExtensionPreferences.bind(this)); this._menu.addMenuItem(item); // Add to chrome and hide //Main.layoutManager.addChrome(this._menu.actor); Main.uiGroup.add_actor(this._menu.actor); this._menu.actor.hide(); // Add menu to menu manager this._menuManager.addMenu(this._menu); } } // function initializes the taskbar icons _initTaskbar() { if(this._thumbnailShowId > 0){ this._thumbnail.disconnect(this._thumbnailShowId); this._thumbnailShowId = 0; } else { return; } // Create initial task icons for app windows on workspace let windows = global.get_window_actors(); for (let i = 0; i < windows.length; i++) { let metaWin = windows[i].get_meta_window(); if (!metaWin) continue; let tracker = Shell.WindowTracker.get_default(); let app = tracker.get_window_app(metaWin); if (app) { let button = new TaskbarIcon(app, metaWin, this); if (metaWin.has_focus()) { button.actor.add_style_class_name('workspacestodock-caption-windowapps-button-active'); } if ((this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) || (this._isMyWindow(windows[i]) && this._isMinimizedWindow(windows[i])) || this._showWindowAppOnThisWorkspace(windows[i])) { button.actor.visible = true; } else { button.actor.visible = false; } if (this._taskBarBox) { this._taskBarBox.add_actor(button.actor); } let winInfo = {}; winInfo.app = app; winInfo.metaWin = metaWin; winInfo.signalFocusedId = metaWin.connect('notify::appears-focused', this._onWindowChanged.bind(this, metaWin)); this._taskBar.push(winInfo); } } // Update window count this._updateWindowCount(); } // function called when the active workspace is changed // windows visible on all workspaces are moved to active workspace activeWorkspaceChanged() { let windows = global.get_window_actors(); let workspaceManager = global.workspace_manager; let activeWorkspace = workspaceManager.get_active_workspace(); for (let i = 0; i < windows.length; i++) { let metaWin = windows[i].get_meta_window(); if (!metaWin) continue; if ((this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) || (this._isMyWindow(windows[i]) && this._isMinimizedWindow(windows[i])) || this._showWindowAppOnThisWorkspace(windows[i])) { // Show taskbar icon if already present let index = -1; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWin) { index = i; if (this._taskBarBox) { let buttonActor = this._taskBarBox.get_child_at_index(index); buttonActor.visible = true; } break; } } if (index > -1) continue; } else { // Hide taskbar icon let index = -1; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWin) { index = i; if (this._taskBarBox) { let buttonActor = this._taskBarBox.get_child_at_index(index); buttonActor.visible = false; } break; } } } } // Update window count this._updateWindowCount(); } _onAfterWindowAdded(metaWorkspace, metaWin) { this._doAfterWindowAdded(metaWin); } _doAfterWindowAdded(metaWin) { let win = metaWin.get_compositor_private(); if (!win) { // Newly-created windows are added to a workspace before // the compositor finds out about them... let id = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { if (this.actor && metaWin.get_compositor_private()) this._doAfterWindowAdded(metaWin); return GLib.SOURCE_REMOVE; }); GLib.Source.set_name_by_id(id, '[gnome-shell] this._doAfterWindowAdded'); return; } this._thumbnail._thumbnailsBox.updateTaskbars(metaWin, WindowAppsUpdateAction.ADD); } _onAfterWindowRemoved(metaWorkspace, metaWin) { this._thumbnail._thumbnailsBox.updateTaskbars(metaWin, WindowAppsUpdateAction.REMOVE); } _onWindowChanged(metaWin) { if (!this._taskBarBox) return; let index = -1; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWin) { index = i; break; } } if (index > -1) { let buttonActor = this._taskBarBox.get_child_at_index(index); if (metaWin.appears_focused) { buttonActor.add_style_class_name('workspacestodock-caption-windowapps-button-active'); } else { buttonActor.remove_style_class_name('workspacestodock-caption-windowapps-button-active'); } } } // NOTE: The caption popup menu is now called from the thumbnailsbox button release event. // This allows us to keep the caption boxlayout non-reactive so that thumbnail window clones // are draggable. showCaptionMenu() { if (this._menu.isOpen) { this._menu.close(); return Clutter.EVENT_STOP; } this._menu.removeAll(); this._menuTaskListBox = new St.BoxLayout({vertical: true}); let menuTaskListItemCount = 0; if (this._taskBarBox) { for (let i=0; i < this._taskBar.length; i++) { let buttonActor = this._taskBarBox.get_child_at_index(i); let metaWin = this._taskBar[i].metaWin; let app = this._taskBar[i].app; let item = new MenuTaskListItem(app, metaWin, this); if (buttonActor.visible) { menuTaskListItemCount ++; } else { item.actor.visible = false; } this._menuTaskListBox.add_actor(item.actor); } } let windowAppsListsection = new PopupMenu.PopupMenuSection(); windowAppsListsection.actor.add_actor(this._menuTaskListBox); let appsArray = this._menuTaskListBox.get_children(); if (menuTaskListItemCount > 0) { this._menu.addMenuItem(windowAppsListsection); if (menuTaskListItemCount > 1) { let item1 = new PopupMenu.PopupMenuItem(_('Close All Applications')); item1.connect('activate', this._closeAllMetaWindows.bind(this)); this._menu.addMenuItem(item1); } this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); } let item2 = new PopupMenu.PopupMenuItem(_("Extension Preferences")); item2.connect('activate', this._showExtensionPreferences.bind(this)); this._menu.addMenuItem(item2); this._menu.open(); return Clutter.EVENT_STOP; } activateMetaWindow(metaWin) { let workspaceManager = global.workspace_manager; let activeWorkspace = workspaceManager.get_active_workspace(); if (activeWorkspace != this._thumbnail.metaWorkspace) { this._thumbnail.activate(global.get_current_time()); metaWin.activate(global.get_current_time()); } else { if (!metaWin.has_focus()) { metaWin.activate(global.get_current_time()); } else { metaWin.minimize(); } } } _showExtensionPreferences(menuItem, event) { if (typeof ExtensionUtils.openPrefs === 'function') { ExtensionUtils.openPrefs(); } else { Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); } } closeMetaWindow(metaWin) { let metaWindow = metaWin; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWindow) { // Delete metaWindow metaWindow.delete(global.get_current_time()); } } } _closeAllMetaWindows(menuItem, event) { if (this._taskBarBox) { for (let i = 0; i < this._taskBar.length; i++) { let buttonActor = this._taskBarBox.get_child_at_index(i); if (buttonActor.visible) { // Delete metaWindow this._taskBar[i].metaWin.delete(global.get_current_time()); } // NOTE: bug quiting all GIMP windows // even tried this _taskBar[i].app.request_quit(); // Gnome Shell has same issue .. selecting quit from panel app menu only closes current Gimp window // Unity has same issue .. https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1123593 } } } updateTaskbar(metaWin, action) { if (action == WindowAppsUpdateAction.ADD) { let index = -1; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWin) { index = i; if (this._taskBarBox) { let buttonActor = this._taskBarBox.get_child_at_index(index); if ((this._isMyWindow(metaWin, true) && this._isOverviewWindow(metaWin, true)) || (this._isMyWindow(metaWin, true) && this._isMinimizedWindow(metaWin, true)) || this._showWindowAppOnThisWorkspace(metaWin, true)) { buttonActor.visible = true; } else { buttonActor.visible = false; } } break; } } if (index < 0) { let tracker = Shell.WindowTracker.get_default(); if (!metaWin.skip_taskbar) { let app = tracker.get_window_app(metaWin); if (app) { let button = new TaskbarIcon(app, metaWin, this); if (metaWin.has_focus()) { button.actor.add_style_class_name('workspacestodock-caption-windowapps-button-active'); } if ((this._isMyWindow(metaWin, true) && this._isOverviewWindow(metaWin, true)) || (this._isMyWindow(metaWin, true) && this._isMinimizedWindow(metaWin, true)) || this._showWindowAppOnThisWorkspace(metaWin, true)) { button.actor.visible = true; } else { button.actor.visible = false; } if (this._taskBarBox) { this._taskBarBox.add_actor(button.actor); } let winInfo = {}; winInfo.app = app; winInfo.metaWin = metaWin; winInfo.signalFocusedId = metaWin.connect('notify::appears-focused', this._onWindowChanged.bind(this, metaWin)); this._taskBar.push(winInfo); } } } } else if (action == WindowAppsUpdateAction.REMOVE) { let index = -1; for (let i = 0; i < this._taskBar.length; i++) { if (this._taskBar[i].metaWin == metaWin) { index = i; break; } } if (index > -1) { // Disconnect window focused signal metaWin.disconnect(this._taskBar[index].signalFocusedId); // Remove button from windowApps list and windowAppsBox container this._taskBar.splice(index, 1); if (this._taskBarBox) { let buttonActor = this._taskBarBox.get_child_at_index(index); this._taskBarBox.remove_actor(buttonActor); buttonActor.destroy(); } // Remove menuItem if (this._menuTaskListBox) { let menuItemActor = this._menuTaskListBox.get_child_at_index(index); if (menuItemActor) { this._menuTaskListBox.remove_actor(menuItemActor); menuItemActor.destroy(); } } } } // Update window count this._updateWindowCount(); } _updateWindowCount() { if (!this._wsWindowCountBox) return; let className = ""; let winCount = 0; let winMax = 4; for (let i = 0; i < this._taskBar.length; i++) { let metaWin = this._taskBar[i].metaWin; if ((this._isMyWindow(metaWin, true) && this._isOverviewWindow(metaWin, true)) || (this._isMyWindow(metaWin, true) && this._isMinimizedWindow(metaWin, true)) || this._showWindowAppOnThisWorkspace(metaWin, true)) { winCount ++; } } if (!this._mySettings.get_boolean('workspace-caption-windowcount-image')) { // clear box images for(let i = 1; i <= winMax; i++){ let className = 'workspacestodock-caption-windowcount-image-'+i; this._wsWindowCountBox.remove_style_class_name(className); } // Set label text if (winCount > 0) { this._wsWindowCount.set_text(""+winCount); } else { this._wsWindowCount.set_text(""); } } else { // clear label text this._wsWindowCount.set_text(""); // Set background image class if (winCount > winMax) winCount = winMax; for(let i = 1; i <= winMax; i++){ let className = 'workspacestodock-caption-windowcount-image-'+i; if (i != winCount) { this._wsWindowCountBox.remove_style_class_name(className); } else { this._wsWindowCountBox.add_style_class_name(className); } } } } updateCaption(i, captionHeight, captionBackgroundHeight) { let unscale = 1/this._thumbnail._thumbnailsBox._scale; let containerWidth = this._thumbnail._thumbnailsBox._porthole.width * this._thumbnail._thumbnailsBox._scale; let containerHeight = this._thumbnail._thumbnailsBox._porthole.height * this._thumbnail._thumbnailsBox._scale; if (!this._wsCaptionBackground) return; this._wsCaptionBackground.set_scale(unscale, unscale); // ISSUE: Gnome uses monitor screen to create background actor // passingthru67: Reposition background to match workspace desktop porthole let px = this._thumbnail._thumbnailsBox._porthole.x - Main.layoutManager.monitors[this._thumbnail.monitorIndex].x; let py = this._thumbnail._thumbnailsBox._porthole.y - Main.layoutManager.monitors[this._thumbnail.monitorIndex].y; if (this._mySettings.get_enum('workspace-caption-position') == CaptionPosition.TOP) { this._wsCaptionBackground.set_position(0, 0); this._thumbnail._contents.set_position(-this._thumbnail._thumbnailsBox._porthole.x, -this._thumbnail._thumbnailsBox._porthole.y + (captionBackgroundHeight * unscale)); } else { this._wsCaptionBackground.set_position(0, this._thumbnail._thumbnailsBox._porthole.height); this._thumbnail._contents.set_position(-this._thumbnail._thumbnailsBox._porthole.x, -this._thumbnail._thumbnailsBox._porthole.y); } this._thumbnail._bgManager.backgroundActor.set_clip(px, py, this._thumbnail._thumbnailsBox._porthole.width, this._thumbnail._thumbnailsBox._porthole.height); this._wsCaptionBackground.set_size(containerWidth, captionBackgroundHeight); if (!this.actor) return; this.actor.set_scale(unscale, unscale); this.actor.set_size(containerWidth, containerHeight + captionBackgroundHeight); if (!this._wsCaption) return; this._wsCaption.height = captionHeight; // constrains height to caption height if (this._wsNumber) this._wsNumber.set_text(""+(i+1)); if (this._wsNumberBox) this._wsNumberBox.height = captionBackgroundHeight - 2; if (this._wsName) this._wsName.set_text(Meta.prefs_get_workspace_name(i)); if (this._wsNameBox) this._wsNameBox.height = captionBackgroundHeight - 2; if (this._wsWindowCountBox) this._wsWindowCountBox.height = captionBackgroundHeight - 2; if (this._taskBarBox) this._taskBarBox.height = captionHeight; let workspaceManager = global.workspace_manager; if (i == workspaceManager.get_active_workspace_index()) { if (this._wsCaptionBackground) { this._wsCaptionBackground.add_style_class_name('workspacestodock-workspace-caption-background-current'); if (this._mySettings.get_enum('workspace-caption-position') == CaptionPosition.TOP) this._wsCaptionBackground.add_style_class_name('caption-top'); } if (this._wsCaption) this._wsCaption.add_style_class_name('workspacestodock-workspace-caption-current'); if (this._wsNumberBox) this._wsNumberBox.add_style_class_name('workspacestodock-caption-number-current'); if (this._wsNameBox) this._wsNameBox.add_style_class_name('workspacestodock-caption-name-current'); if (this._wsWindowCountBox) { if (this._mySettings.get_boolean('workspace-caption-windowcount-image')) { this._wsWindowCountBox.add_style_class_name('workspacestodock-caption-windowcount-image-current'); } else { this._wsWindowCountBox.add_style_class_name('workspacestodock-caption-windowcount-current'); } } if (this._wsSpacerBox) this._wsSpacerBox.add_style_class_name('workspacestodock-caption-spacer-current'); } else { if (this._wsCaptionBackground) this._wsCaptionBackground.remove_style_class_name('workspacestodock-workspace-caption-background-current'); if (this._wsCaption) this._wsCaption.remove_style_class_name('workspacestodock-workspace-caption-current'); if (this._wsNumberBox) this._wsNumberBox.remove_style_class_name('workspacestodock-caption-number-current'); if (this._wsNameBox) this._wsNameBox.remove_style_class_name('workspacestodock-caption-name-current'); if (this._wsWindowCountBox) { if (this._mySettings.get_boolean('workspace-caption-windowcount-image')) { this._wsWindowCountBox.remove_style_class_name('workspacestodock-caption-windowcount-image-current'); } else { this._wsWindowCountBox.remove_style_class_name('workspacestodock-caption-windowcount-current'); } } if (this._wsSpacerBox) this._wsSpacerBox.remove_style_class_name('workspacestodock-caption-spacer-current'); } } };