diff options
| author | AlexanderCurl <alexc@alexc.hu> | 2026-04-18 17:46:06 +0100 |
|---|---|---|
| committer | AlexanderCurl <alexc@alexc.hu> | 2026-04-18 17:46:06 +0100 |
| commit | 70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch) | |
| tree | ab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js | |
| parent | 5d94c0a7d44a2255b81815a52a7056a94a39842d (diff) | |
| download | RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.tar.gz RaveOS-PKGBUILD-70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69.zip | |
Replaced file structures for themes in the correct format
Diffstat (limited to 'raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js')
| -rw-r--r-- | raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js | 1635 |
1 files changed, 0 insertions, 1635 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js b/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js deleted file mode 100644 index 6b0ac24..0000000 --- a/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js +++ /dev/null @@ -1,1635 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -import { - Clutter, - Gio, - GLib, - GObject, - Meta, - Mtk, - Shell, - St, -} from './dependencies/gi.js'; - -import { - AppDisplay, - AppFavorites, - BoxPointer, - Dash, - Main, - PopupMenu, -} from './dependencies/shell/ui.js'; - -import { - ParentalControlsManager, - Util, -} from './dependencies/shell/misc.js'; - -import { - AppIconIndicators, - DBusMenuUtils, - Docking, - Locations, - Theming, - Utils, - WindowPreview, -} from './imports.js'; - -import {Extension} from './dependencies/shell/extensions/extension.js'; - -// Use __ () and N__() for the extension gettext domain, and reuse -// the shell domain with the default _() and N_() -const {gettext: __, ngettext} = Extension; - -const DBusMenu = await DBusMenuUtils.haveDBusMenu(); - -const tracker = Shell.WindowTracker.get_default(); - -const Labels = Object.freeze({ - ISOLATE_MONITORS: Symbol('isolate-monitors'), - ISOLATE_WORKSPACES: Symbol('isolate-workspaces'), - URGENT_WINDOWS: Symbol('urgent-windows'), -}); - -const clickAction = Object.freeze({ - SKIP: 0, - MINIMIZE: 1, - LAUNCH: 2, - CYCLE_WINDOWS: 3, - MINIMIZE_OR_OVERVIEW: 4, - PREVIEWS: 5, - MINIMIZE_OR_PREVIEWS: 6, - FOCUS_OR_PREVIEWS: 7, - FOCUS_OR_APP_SPREAD: 8, - FOCUS_MINIMIZE_OR_PREVIEWS: 9, - FOCUS_MINIMIZE_OR_APP_SPREAD: 10, - QUIT: 11, -}); - -const scrollAction = Object.freeze({ - DO_NOTHING: 0, - CYCLE_WINDOWS: 1, - SWITCH_WORKSPACE: 2, -}); - -// module "Dash" did not export DASH_ITEM_LABEL_SHOW_TIME, so let's define it. -const DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME ?? 150; - -let recentlyClickedAppLoopId = 0; -let recentlyClickedApp = null; -let recentlyClickedAppWindows = null; -let recentlyClickedAppIndex = 0; -let recentlyClickedAppMonitor = -1; - -/** - * Extend AppIcon - * - * - Apply a css class based on the number of windows of each application (#N); - * - Customized indicators for running applications in place of the default "dot" style which is hidden (#N); - * a class of the form "running#N" is applied to the AppWellIcon actor. - * like the original .running one. - * - Add a .focused style to the focused app - * - Customize click actions. - * - Update minimization animation target - * - Update menu if open on windows change - */ -const DockAbstractAppIcon = GObject.registerClass({ - GTypeFlags: GObject.TypeFlags.ABSTRACT, - Properties: { - 'focused': GObject.ParamSpec.boolean( - 'focused', 'focused', 'focused', - GObject.ParamFlags.READWRITE, - false), - 'running': GObject.ParamSpec.boolean( - 'running', 'running', 'running', - GObject.ParamFlags.READWRITE, - false), - 'urgent': GObject.ParamSpec.boolean( - 'urgent', 'urgent', 'urgent', - GObject.ParamFlags.READWRITE, - false), - 'updating': GObject.ParamSpec.boolean( - 'updating', 'updating', 'updating', - GObject.ParamFlags.READWRITE, - false), - 'windows-count': GObject.ParamSpec.uint( - 'windows-count', 'windows-count', 'windows-count', - GObject.ParamFlags.READWRITE, - 0, GLib.MAXUINT32, 0), - }, -}, class DockAbstractAppIcon extends Dash.DashIcon { - // settings are required inside. - _init(app, monitorIndex, iconAnimator) { - super._init(app); - - // a prefix is required to avoid conflicting with the parent class variable - this.monitorIndex = monitorIndex; - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this.iconAnimator = iconAnimator; - this._indicator = new AppIconIndicators.AppIconIndicator(this); - this._urgentWindows = new Set(); - - // Monitor windows-changes instead of app state. - // Keep using the same Id and function callback (that is extended) - if (this._stateChangedId > 0) { - this.app.disconnect(this._stateChangedId); - this._stateChangedId = 0; - } - - this._signalsHandler.add(this.app, 'windows-changed', () => this._updateWindows()); - this._signalsHandler.add(this.app, 'notify::state', () => this._updateRunningState()); - this._signalsHandler.add(global.display, 'window-demands-attention', (_dpy, window) => - this._onWindowDemandsAttention(window)); - this._signalsHandler.add(global.display, 'window-marked-urgent', (_dpy, window) => - this._onWindowDemandsAttention(window)); - - // In Wayland sessions, this signal is needed to track the state of windows dragged - // from one monitor to another. As this is triggered quite often (whenever a new - // window of any application opened or moved to a different desktop), - // we restrict this signal to the case when Labels.ISOLATE_MONITORS is true, - // and if there are at least 2 monitors. - if (Docking.DockManager.settings.isolateMonitors && - Main.layoutManager.monitors.length > 1) { - this._signalsHandler.addWithLabel(Labels.ISOLATE_MONITORS, - global.display, - 'window-entered-monitor', - this._onWindowEntered.bind(this)); - } - - this.connect('notify::running', () => { - if (this.running) - this.add_style_class_name('running'); - else - this.remove_style_class_name('running'); - }); - this.notify('running'); - - this.connect('notify::focused', () => { - if (this.focused) - this.add_style_class_name('focused'); - else - this.remove_style_class_name('focused'); - }); - this.notify('focused'); - - this.connect('notify::updating', () => { - if (this.updating) - this.add_style_class_name('updating'); - else - this.remove_style_class_name('updating'); - }); - this.notify('updating'); - - const {notificationsMonitor} = Docking.DockManager.getDefault(); - - this.connect('notify::urgent', () => { - const icon = this.icon._iconBin; - this._signalsHandler.removeWithLabel(Labels.URGENT_WINDOWS); - if (this.urgent) { - if (Docking.DockManager.settings.danceUrgentApplications && - notificationsMonitor.enabled) { - icon.set_pivot_point(0.5, 0.5); - this.iconAnimator.addAnimation(icon, 'wiggle'); - } - if (this.running && !this._urgentWindows.size) { - const urgentWindows = this.getInterestingWindows(); - urgentWindows.forEach(w => (w._manualUrgency = true)); - this._updateUrgentWindows(urgentWindows); - } - } else { - this.iconAnimator.removeAnimation(icon, 'wiggle'); - icon.rotation_angle_z = 0; - this._urgentWindows.forEach(w => delete w._manualUrgency); - this._updateUrgentWindows(); - } - }); - this.notify('urgent'); - - this._progressOverlayArea = null; - this._progress = 0; - - [ - 'apply-custom-theme', - 'running-indicator-style', - 'show-icons-emblems', - 'show-icons-notifications-counter', - 'application-counter-overrides-notifications', - ].forEach(key => { - this._signalsHandler.add( - Docking.DockManager.settings, - `changed::${key}`, () => { - this._indicator.destroy(); - this._indicator = new AppIconIndicators.AppIconIndicator(this); - } - ); - }); - - this._signalsHandler.add(notificationsMonitor, 'state-changed', () => { - this._indicator.destroy(); - this._indicator = new AppIconIndicators.AppIconIndicator(this); - }); - - this._updateState(); - this._numberOverlay(); - - this._previewMenuManager = null; - this._previewMenu = null; - } - - _onDestroy() { - super._onDestroy(); - - // This is necessary due to an upstream bug - // https://bugzilla.gnome.org/show_bug.cgi?id=757556 - // It can be safely removed once it get solved upstream. - this._menu?.close(false); - delete this._menu; - } - - ownsWindow(window) { - return this.app === tracker.get_window_app(window); - } - - _onWindowEntered(metaScreen, monitorIndex, metaWin) { - if (this.ownsWindow(metaWin)) - this._updateWindows(); - } - - vfunc_scroll_event(scrollEvent) { - const {settings} = Docking.DockManager; - const isEnabled = settings.scrollAction === scrollAction.CYCLE_WINDOWS; - if (!isEnabled) - return Clutter.EVENT_PROPAGATE; - - // We only activate windows of running applications, i.e. we never open new windows - // We check if the app is running, and that the # of windows is > 0 in - // case we use workspace isolation, - if (!this.running) - return Clutter.EVENT_PROPAGATE; - - if (this._optionalScrollCycleWindowsDeadTimeId) { - return Clutter.EVENT_PROPAGATE; - } else { - this._optionalScrollCycleWindowsDeadTimeId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, 250, () => { - this._optionalScrollCycleWindowsDeadTimeId = 0; - }); - } - - let direction = null; - - switch (scrollEvent.direction) { - case Clutter.ScrollDirection.UP: - direction = Meta.MotionDirection.UP; - break; - case Clutter.ScrollDirection.DOWN: - direction = Meta.MotionDirection.DOWN; - break; - case Clutter.ScrollDirection.SMOOTH: { - const [, dy] = Clutter.get_current_event().get_scroll_delta(); - if (dy < 0) - direction = Meta.MotionDirection.UP; - else if (dy > 0) - direction = Meta.MotionDirection.DOWN; - } - break; - } - - if (!Main.overview.visible) { - const reversed = direction === Meta.MotionDirection.UP; - if (this.focused && !this._urgentWindows.size) { - this._cycleThroughWindows(reversed); - } else { - // Activate the first window - const windows = this.getInterestingWindows(); - if (windows.length > 0) { - const [w] = windows; - Main.activateWindow(w); - } - } - } else { - this.app.activate(); - } - return Clutter.EVENT_STOP; - } - - _updateWindows() { - if (this._menu && this._menu.isOpen) - this._menu.update(); - - this._updateState(); - this.updateIconGeometry(); - } - - _updateState() { - this._urgentWindows.clear(); - const interestingWindows = this.getInterestingWindows(); - this.windowsCount = interestingWindows.length; - this._updateRunningState(); - this._updateFocusState(); - this._updateUrgentWindows(interestingWindows); - - if (Docking.DockManager.settings.isolateWorkspaces) { - this._signalsHandler.removeWithLabel(Labels.ISOLATE_WORKSPACES); - interestingWindows.forEach(window => - this._signalsHandler.addWithLabel(Labels.ISOLATE_WORKSPACES, - window, 'workspace-changed', () => this._updateWindows())); - } - } - - _updateRunningState() { - this.running = (this.app.state === Shell.AppState.RUNNING) && this.windowsCount; - } - - _updateFocusState() { - this.focused = tracker.focus_app === this.app && this.running; - } - - _updateUrgentWindows(interestingWindows) { - this._signalsHandler.removeWithLabel(Labels.URGENT_WINDOWS); - this._urgentWindows.clear(); - if (interestingWindows === undefined) - interestingWindows = this.getInterestingWindows(); - interestingWindows.filter(isWindowUrgent).forEach(win => this._addUrgentWindow(win)); - this.urgent = !!this._urgentWindows.size; - } - - _onWindowDemandsAttention(window) { - if (this.ownsWindow(window) && isWindowUrgent(window)) - this._addUrgentWindow(window); - } - - _updateDotStyle() { - super._updateDotStyle(); - const themeNode = this._dot.get_theme_node(); - this._dot.translationX = themeNode.get_length('offset-x'); - } - - _addUrgentWindow(window) { - if (this._urgentWindows.has(window)) - return; - - if (window._manualUrgency && window.has_focus()) { - delete window._manualUrgency; - return; - } - - this._urgentWindows.add(window); - this.urgent = true; - - const onDemandsAttentionChanged = () => { - if (!isWindowUrgent(window)) - this._updateUrgentWindows(); - }; - - if (window.demandsAttention) { - this._signalsHandler.addWithLabel(Labels.URGENT_WINDOWS, window, - 'notify::demands-attention', () => onDemandsAttentionChanged()); - } - if (window.urgent) { - this._signalsHandler.addWithLabel(Labels.URGENT_WINDOWS, window, - 'notify::urgent', () => onDemandsAttentionChanged()); - } - if (window._manualUrgency) { - this._signalsHandler.addWithLabel(Labels.URGENT_WINDOWS, window, - 'focus', () => { - delete window._manualUrgency; - onDemandsAttentionChanged(); - }); - } - } - - /** - * Update target for minimization animation - */ - updateIconGeometry() { - // If (for unknown reason) the actor is not on the stage the reported size - // and position are random values, which might exceeds the integer range - // resulting in an error when assigned to the a rect. This is a more like - // a workaround to prevent flooding the system with errors. - if (!this.get_stage()) - return; - - const rect = new Mtk.Rectangle(); - - [rect.x, rect.y] = this.get_transformed_position(); - [rect.width, rect.height] = this.get_transformed_size(); - - let windows = this.getWindows(); - if (Docking.DockManager.settings.multiMonitor) { - const {monitorIndex} = this; - windows = windows.filter(w => w.get_monitor() === monitorIndex); - } - windows.forEach(w => w.set_icon_geometry(rect)); - } - - _updateRunningStyle() { - // The logic originally in this function has been moved to - // AppIconIndicatorBase._updateDefaultDot(). However it cannot be removed as - // it called by the parent constructor. - } - - popupMenu() { - this._removeMenuTimeout?.(); - this.fake_release(); - this._draggable.fakeRelease?.(); - - if (!this._menu) { - this._menu = new DockAppIconMenu(this); - this._menu.connect('activate-window', (menu, window) => { - if (window) { - Main.activateWindow(window); - } else { - Main.overview.hide(); - Main.panel.closeCalendar(); - } - }); - this._menu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) { - this._onMenuPoppedDown(); - } else { - // Setting the max-height is s useful if part of the menu is - // scrollable so the minimum height is smaller than the natural height. - const monitorIndex = Main.layoutManager.findIndexForActor(this); - const workArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); - const position = Utils.getPosition(); - const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); - const isHorizontal = position === St.Side.TOP || position === St.Side.BOTTOM; - // If horizontal also remove the height of the dash - const {dockFixed: fixedDock} = Docking.DockManager.settings; - const additionalMargin = isHorizontal && !fixedDock ? Main.overview.dash.height : 0; - const verticalMargins = this._menu.actor.margin_top + this._menu.actor.margin_bottom; - const maxMenuHeight = workArea.height - additionalMargin - verticalMargins; - // Also set a max width to the menu, so long labels (long windows title) get truncated - this._menu.actor.style = 'max-width: 400px; ' + - `max-height: ${Math.round(maxMenuHeight / scaleFactor)}px;`; - } - }); - const id = Main.overview.connect('hiding', () => { - this._menu.close(); - }); - this._menu.actor.connect('destroy', () => { - Main.overview.disconnect(id); - }); - - this._menuManager.addMenu(this._menu); - } - - this.emit('menu-state-changed', true); - - this.set_hover(true); - this._menu.popup(); - // Removed in GNOME 50. - this._menuManager.ignoreRelease?.(); - this.emit('sync-tooltip'); - - return false; - } - - activate(button) { - const event = Clutter.get_current_event(); - let modifiers = event ? event.get_state() : 0; - - // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.) - modifiers &= Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK; - - // We don't change the CTRL-click behavior: in such case we just chain - // up the parent method and return. - if (modifiers & Clutter.ModifierType.CONTROL_MASK) { - // Keep default behavior: launch new window - // By calling the parent method I make it compatible - // with other extensions tweaking ctrl + click - super.activate(button); - return; - } - - // We check what type of click we have and if the modifier SHIFT is - // being used. We then define what buttonAction should be for this - // event. - let buttonAction = 0; - const {settings} = Docking.DockManager; - if (button && button === 2) { - if (modifiers & Clutter.ModifierType.SHIFT_MASK) - buttonAction = settings.shiftMiddleClickAction; - else - buttonAction = settings.middleClickAction; - } else if (button && button === 1) { - if (modifiers & Clutter.ModifierType.SHIFT_MASK) - buttonAction = settings.shiftClickAction; - else - buttonAction = settings.clickAction; - } - - switch (buttonAction) { - case clickAction.FOCUS_OR_APP_SPREAD: - if (!Docking.DockManager.getDefault().appSpread.supported) - buttonAction = clickAction.FOCUS_OR_PREVIEWS; - break; - - case clickAction.FOCUS_MINIMIZE_OR_APP_SPREAD: - if (!Docking.DockManager.getDefault().appSpread.supported) - buttonAction = clickAction.FOCUS_MINIMIZE_OR_PREVIEWS; - break; - } - - // We check if the app is running, and that the # of windows is > 0 in - // case we use workspace isolation. - const windows = this.getInterestingWindows(); - - // Some action modes (e.g. MINIMIZE_OR_OVERVIEW) require overview to remain open - // This variable keeps track of this - let shouldHideOverview = true; - - // We customize the action only when the application is already running - if (this.running) { - const hasUrgentWindows = !!this._urgentWindows.size; - const singleOrUrgentWindows = windows.length === 1 || hasUrgentWindows; - switch (buttonAction) { - case clickAction.MINIMIZE: - // In overview just activate the app, unless the action is explicitly - // requested with a keyboard modifier - if (!Main.overview.visible || modifiers) { - // If we have button=2 or a modifier, allow minimization even if - // the app is not focused - if (this.focused && !hasUrgentWindows || button === 2 || - modifiers & Clutter.ModifierType.SHIFT_MASK) { - // minimize all windows on double click and always in - // the case of primary click without additional modifiers - let clickCount = 0; - if (Clutter.EventType.CLUTTER_BUTTON_PRESS) - clickCount = event.get_click_count(); - const allWindows = (button === 1 && !modifiers) || clickCount > 1; - this._minimizeWindow(allWindows); - } else { - this._activateAllWindows(); - } - } else { - const [w] = windows; - Main.activateWindow(w); - } - break; - - case clickAction.MINIMIZE_OR_OVERVIEW: - // When a single window is present, toggle minimization - // If only one windows is present toggle minimization, but - // only when triggered with the simple click action - // (no modifiers, no middle click). - if (singleOrUrgentWindows && !modifiers && button === 1) { - const [w] = windows; - if (this.focused) { - if (buttonAction !== clickAction.FOCUS_OR_APP_SPREAD) { - // Window is raised, minimize it - this._minimizeWindow(w); - } - } else { - // Window is minimized, raise it - Main.activateWindow(w); - } - // Launch overview when multiple windows are present - // TODO: only show current app windows when gnome shell API will allow it - } else { - shouldHideOverview = false; - Main.overview.toggle(); - } - break; - - case clickAction.CYCLE_WINDOWS: - if (!Main.overview.visible) { - if (this.focused && !hasUrgentWindows) { - this._cycleThroughWindows(); - } else { - // Activate the first window - const [w] = windows; - Main.activateWindow(w); - } - } else { - this.app.activate(); - } - break; - - case clickAction.FOCUS_OR_PREVIEWS: - if (this.focused && !hasUrgentWindows && - (windows.length > 1 || modifiers || button !== 1)) { - this._windowPreviews(); - } else { - // Activate the first window - const [w] = windows; - Main.activateWindow(w); - } - break; - - case clickAction.FOCUS_MINIMIZE_OR_PREVIEWS: - if (this.focused && !hasUrgentWindows) { - if (windows.length > 1 || modifiers || button !== 1) - this._windowPreviews(); - else if (!Main.overview.visible) - this._minimizeWindow(); - } else { - // Activate the first window - const [w] = windows; - Main.activateWindow(w); - } - break; - - case clickAction.LAUNCH: - this.launchNewWindow(); - break; - - case clickAction.PREVIEWS: - if (!Main.overview.visible) { - // If only one windows is present just switch to it, - // but only when triggered with the simple click action - // (no modifiers, no middle click). - if (singleOrUrgentWindows && !modifiers && button === 1) { - const [w] = windows; - Main.activateWindow(w); - } else { - this._windowPreviews(); - } - } else { - this.app.activate(); - } - break; - - case clickAction.MINIMIZE_OR_PREVIEWS: - // When a single window is present, toggle minimization - // If only one windows is present toggle minimization, but only - // when triggered with the standard click action (no modifiers, - // no middle click). - if (!Main.overview.visible) { - if (singleOrUrgentWindows && !modifiers && button === 1) { - const [w] = windows; - if (this.focused) { - // Window is raised, minimize it - this._minimizeWindow(w); - } else { - // Window is minimized, raise it - Main.activateWindow(w); - } - } else { - // Launch previews when multiple windows are present - this._windowPreviews(); - } - } else { - this.app.activate(); - } - break; - - case clickAction.FOCUS_OR_APP_SPREAD: - if (this.focused && !singleOrUrgentWindows && !modifiers && button === 1) { - shouldHideOverview = false; - Docking.DockManager.getDefault().appSpread.toggle(this.app); - } else { - // Activate the first window - Main.activateWindow(windows[0]); - } - break; - - case clickAction.FOCUS_MINIMIZE_OR_APP_SPREAD: - if (this.focused && !singleOrUrgentWindows && !modifiers && button === 1) { - shouldHideOverview = false; - Docking.DockManager.getDefault().appSpread.toggle(this.app); - } else if (!this.focused) { - // Activate the first window - Main.activateWindow(windows[0]); - } else { - this._minimizeWindow(); - } - break; - - case clickAction.QUIT: - this.closeAllWindows(); - break; - - case clickAction.SKIP: - Main.activateWindow(windows[0]); - break; - } - } else { - this.launchNewWindow(); - } - - // Hide overview except when action mode requires it - if (shouldHideOverview) - Main.overview.hide(); - } - - shouldShowTooltip() { - return super.shouldShowTooltip() && !this._previewMenu?.isOpen && - !Docking.DockManager.settings.hideTooltip; - } - - _windowPreviews() { - if (!this._previewMenu) { - this._previewMenuManager = new PopupMenu.PopupMenuManager(this); - - this._previewMenu = new WindowPreview.WindowPreviewMenu(this); - - this._previewMenuManager.addMenu(this._previewMenu); - - this._previewMenu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - }); - const id = Main.overview.connect('hiding', () => { - this._previewMenu.close(); - }); - this._previewMenu.actor.connect('destroy', () => { - Main.overview.disconnect(id); - }); - } - - this.emit('menu-state-changed', !this._previewMenu.isOpen); - - if (this._previewMenu.isOpen) - this._previewMenu.close(); - else - this._previewMenu.popup(); - - return false; - } - - // Try to do the right thing when attempting to launch a new window of an app. In - // particular, if the application doesn't allow to launch a new window, activate - // the existing window instead. - launchNewWindow() { - if (this.updating) { - const icon = Gio.Icon.new_for_string('action-unavailable-symbolic'); - Main.osdWindowManager.show(-1, icon, - _('%s is updating, try again later').format(this.name), - null); - return; - } - - if (this.app.state === Shell.AppState.RUNNING && - this.app.can_open_new_window()) { - this.animateLaunch(); - this.app.open_new_window(-1); - } else { - // Try to manually activate the first window. Otherwise, when the - // app is activated by switching to a different workspace, a launch - // spinning icon is shown and disappears only after a timeout. - const windows = this.getWindows(); - if (windows.length > 0) { - Main.activateWindow(windows[0]); - } else { - this.app.activate(); - this.animateLaunch(); - } - } - } - - _numberOverlay() { - // Add label for a Hot-Key visual aid - this._numberOverlayLabel = new St.Label(); - this._numberOverlayBin = new St.Bin({ - child: this._numberOverlayLabel, - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.START, - x_expand: true, y_expand: true, - }); - this._numberOverlayLabel.add_style_class_name('number-overlay'); - this._numberOverlayOrder = -1; - this._numberOverlayBin.hide(); - - this._iconContainer.add_child(this._numberOverlayBin); - } - - updateNumberOverlay() { - // We apply an overall scale factor that might come from a HiDPI monitor. - // Clutter dimensions are in physical pixels, but CSS measures are in logical - // pixels, so make sure to consider the scale. - const scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - // Set the font size to something smaller than the whole icon so it is - // still visible. The border radius is large to make the shape circular - const [minWidth_, natWidth] = this._iconContainer.get_preferred_width(-1); - const fontSize = Math.round(Math.max(12, 0.3 * natWidth) / scaleFactor); - const size = Math.round(fontSize * 1.2); - this._numberOverlayLabel.set_style( - `font-size: ${fontSize}px;` + - `border-radius: ${this.icon.iconSize}px;` + - `width: ${size}px; height: ${size}px;` - ); - } - - setNumberOverlay(number) { - this._numberOverlayOrder = number; - this._numberOverlayLabel.set_text(number.toString()); - } - - toggleNumberOverlay(activate) { - if (activate && this._numberOverlayOrder > -1) { - this.updateNumberOverlay(); - this._numberOverlayBin.show(); - } else { - this._numberOverlayBin.hide(); - } - } - - _minimizeWindow(param) { - // Param true make all app windows minimize - const windows = this.getInterestingWindows(); - const currentWorkspace = global.workspace_manager.get_active_workspace(); - for (let i = 0; i < windows.length; i++) { - const w = windows[i]; - if (w.get_workspace() === currentWorkspace && w.showing_on_its_workspace()) { - w.minimize(); - // Just minimize one window. By specification it should be the - // focused window on the current workspace. - if (!param) - break; - } - } - } - - // By default only non minimized windows are activated. - // This activates all windows in the current workspace. - _activateAllWindows() { - // First activate first window so workspace is switched if needed. - // We don't do this if isolation is on! - if (!Docking.DockManager.settings.isolateWorkspaces && - !Docking.DockManager.settings.isolateMonitors) { - if (!this.running) - this.animateLaunch(); - this.app.activate(); - } - - // then activate all other app windows in the current workspace - const windows = this.getInterestingWindows(); - const activeWorkspace = global.workspace_manager.get_active_workspace_index(); - - if (windows.length <= 0) - return; - - for (let i = windows.length - 1; i >= 0; i--) { - if (windows[i].get_workspace()?.index() === activeWorkspace) - Main.activateWindow(windows[i]); - } - } - - // This closes all windows of the app. - closeAllWindows() { - const windows = this.getInterestingWindows(); - const time = global.get_current_time(); - windows.forEach(w => w.delete(time)); - } - - _cycleThroughWindows(reversed) { - // Store for a little amount of time last clicked app and its windows - // since the order changes upon window interaction - const MEMORY_TIME = 3000; - - const appWindows = this.getInterestingWindows(); - - if (appWindows.length < 1) - return; - - if (recentlyClickedAppLoopId > 0) - GLib.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, MEMORY_TIME, this._resetRecentlyClickedApp); - - // If there isn't already a list of windows for the current app, - // or the stored list is outdated, use the current windows list. - const monitorIsolation = Docking.DockManager.settings.isolateMonitors; - if (!recentlyClickedApp || - recentlyClickedApp.get_id() !== this.app.get_id() || - recentlyClickedAppWindows.length !== appWindows.length || - (recentlyClickedAppMonitor !== this.monitorIndex && monitorIsolation)) { - recentlyClickedApp = this.app; - recentlyClickedAppWindows = appWindows; - recentlyClickedAppMonitor = this.monitorIndex; - recentlyClickedAppIndex = 0; - } - - if (reversed) { - recentlyClickedAppIndex--; - if (recentlyClickedAppIndex < 0) - recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1; - } else { - recentlyClickedAppIndex++; - } - const index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; - const window = recentlyClickedAppWindows[index]; - - Main.activateWindow(window); - } - - _resetRecentlyClickedApp() { - if (recentlyClickedAppLoopId > 0) - GLib.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId = 0; - recentlyClickedApp = null; - recentlyClickedAppWindows = null; - recentlyClickedAppIndex = 0; - recentlyClickedAppMonitor = -1; - - return false; - } - - getWindows() { - return this.app.get_windows(); - } - - // Filter out unnecessary windows, for instance - // nautilus desktop window. - getInterestingWindows() { - const interestingWindows = getInterestingWindows(this.getWindows(), - this.monitorIndex); - - if (!this._urgentWindows.size) - return interestingWindows; - - return [...new Set([...this._urgentWindows, ...interestingWindows])]; - } - - getSnapName() { - return this.app.appInfo?.get_string('X-SnapInstanceName'); - } -}); - -const DockAppIcon = GObject.registerClass({ -}, class DockAppIcon extends DockAbstractAppIcon { - _init(app, monitorIndex, iconAnimator) { - super._init(app, monitorIndex, iconAnimator); - - this._signalsHandler.add(tracker, 'notify::focus-app', () => this._updateFocusState()); - } -}); - -const DockLocationAppIcon = GObject.registerClass({ -}, class DockLocationAppIcon extends DockAbstractAppIcon { - _init(app, monitorIndex, iconAnimator) { - if (!(app.appInfo instanceof Locations.LocationAppInfo)) - throw new Error('Provided application %s is not a Location'.format(app)); - - super._init(app, monitorIndex, iconAnimator); - - if (Docking.DockManager.settings.isolateLocations) { - this._signalsHandler.add(tracker, 'notify::focus-app', () => this._updateFocusState()); - } else { - this._signalsHandler.add(global.display, 'notify::focus-window', - () => this._updateFocusState()); - } - - this._signalsHandler.add(this.app, 'notify::icon', () => this.icon.update()); - } - - get location() { - return this.app.location; - } - - _updateFocusState() { - if (Docking.DockManager.settings.isolateLocations) { - super._updateFocusState(); - return; - } - - this.focused = this.app.isFocused && this.running; - } -}); - -/** - * @param app - * @param monitorIndex - * @param iconAnimator - */ -export function makeAppIcon(app, monitorIndex, iconAnimator) { - if (app.appInfo instanceof Locations.LocationAppInfo) - return new DockLocationAppIcon(app, monitorIndex, iconAnimator); - - return new DockAppIcon(app, monitorIndex, iconAnimator); -} - -/** - * DockAppIconMenu - * - * - set popup arrow side based on dash orientation - * - Add close windows option based on quitfromdash extension - * (https://github.com/deuill/shell-extension-quitfromdash) - * - Add open windows thumbnails instead of list - * - update menu when application windows change - */ -const DockAppIconMenu = class DockAppIconMenu extends PopupMenu.PopupMenu { - constructor(source) { - super(source, 0.5, Utils.getPosition()); - - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - - // We want to keep the item hovered while the menu is up - this.blockSourceEvents = true; - - this.actor.add_style_class_name('app-menu'); - this.actor.add_style_class_name('dock-app-menu'); - - // Chain our visibility and lifecycle to that of the source - this._signalsHandler.add(source, 'notify::mapped', () => { - if (!source.mapped) - this.close(); - }); - source.connect('destroy', () => this.destroy()); - - Main.uiGroup.add_child(this.actor); - - const {remoteModel} = Docking.DockManager.getDefault(); - const remoteModelApp = remoteModel?.lookupById(this.sourceActor?.app?.id); - if (remoteModelApp && DBusMenu) { - const [onQuickList, onDynamicSection] = Utils.splitHandler((sender, - {quicklist}, dynamicSection) => { - dynamicSection.removeAll(); - if (quicklist) { - quicklist.get_children().forEach(remoteItem => - dynamicSection.addMenuItem( - DBusMenuUtils.makePopupMenuItem(remoteItem, false))); - } - }); - - this._signalsHandler.add([ - remoteModelApp, - 'quicklist-changed', - onQuickList, - ], [ - this, - 'dynamic-section-changed', - onDynamicSection, - ]); - } - } - - destroy() { - super.destroy(); - delete this.sourceActor; - delete this._signalsHandler; - } - - _appendSeparator() { - this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - } - - _appendMenuItem(labelText, params) { - const item = new PopupMenu.PopupMenuItem(labelText, params); - this.addMenuItem(item); - return item; - } - - popup(_activatingButton) { - this._rebuildMenu(); - this.open(BoxPointer.PopupAnimation.FULL); - } - - removeAll() { - super.removeAll(); - - delete this._allWindowsMenuItem; - delete this._quitMenuItem; - } - - _rebuildMenu() { - this.removeAll(); - - const appItemLabel = this.sourceActor.updating - ? _('%s is being updated…').format(this.sourceActor.name) - : this.sourceActor.name; - this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(appItemLabel)); - - const {app} = this.sourceActor; - - if (Docking.DockManager.settings.showWindowsPreview) { - // Display the app windows menu items and the separator between windows - // of the current desktop and other windows. - const windows = this.sourceActor.getInterestingWindows(); - - this._allWindowsMenuItem = new PopupMenu.PopupSubMenuMenuItem(__('All Windows'), false); - if (this._allWindowsMenuItem.menu?.actor) - this._allWindowsMenuItem.menu.actor.overlayScrollbars = true; - this._allWindowsMenuItem.hide(); - if (windows.length > 0) - this.addMenuItem(this._allWindowsMenuItem); - } else { - const windows = this.sourceActor.getInterestingWindows(); - - if (windows.length > 0) { - this.addMenuItem( - /* Translators: This is the heading of a list of open windows */ - new PopupMenu.PopupSeparatorMenuItem(_('Open Windows'))); - } - - windows.forEach(window => { - const title = window.title ? window.title : app.get_name(); - const item = this._appendMenuItem(title); - item.connect('activate', () => { - this.emit('activate-window', window); - }); - }); - } - - if (!app.is_window_backed()) { - this._appendSeparator(); - - const appInfo = app.get_app_info(); - const actions = this.sourceActor.updating ? [] : appInfo.list_actions(); - if (!this.sourceActor.updating && - app.can_open_new_window() && - actions.indexOf('new-window') === -1) { - const newMenuItem = this._appendMenuItem(_('New Window')); - newMenuItem.connect('activate', () => { - if (app.state === Shell.AppState.STOPPED) - this.sourceActor.animateLaunch(); - - app.open_new_window(-1); - this.emit('activate-window', null); - }); - this._appendSeparator(); - } - - if (!this.sourceActor.updating && - Docking.DockManager.getDefault().discreteGpuAvailable && - app.state === Shell.AppState.STOPPED) { - const appPrefersNonDefaultGPU = appInfo.get_boolean('PrefersNonDefaultGPU'); - const gpuPref = appPrefersNonDefaultGPU - ? Shell.AppLaunchGpu.DEFAULT - : Shell.AppLaunchGpu.DISCRETE; - const gpuMenuItem = this._appendMenuItem(appPrefersNonDefaultGPU - ? _('Launch using Integrated Graphics Card') - : _('Launch using Discrete Graphics Card')); - gpuMenuItem.connect('activate', () => { - this.sourceActor.animateLaunch(); - app.launch(0, -1, gpuPref); - this.emit('activate-window', null); - }); - } - - for (let i = 0; i < actions.length; i++) { - const action = actions[i]; - const item = this._appendMenuItem(appInfo.get_action_name(action)); - item.sensitive = !appInfo.busy; - item.connect('activate', (emitter, event) => { - app.launch_action(action, event.get_time(), -1); - this.emit('activate-window', null); - }); - } - - const canFavorite = global.settings.is_writable('favorite-apps') && - (this.sourceActor instanceof DockAppIcon) && - ParentalControlsManager.getDefault().shouldShowApp(app.appInfo); - - if (canFavorite) { - this._appendSeparator(); - - const isFavorite = AppFavorites.getAppFavorites().isFavorite(app.get_id()); - if (isFavorite) { - const item = this._appendMenuItem(_('Unpin')); - item.connect('activate', () => { - const favs = AppFavorites.getAppFavorites(); - favs.removeFavorite(app.get_id()); - }); - } else { - const item = this._appendMenuItem(__('Pin to Dock')); - item.connect('activate', () => { - const favs = AppFavorites.getAppFavorites(); - favs.addFavorite(app.get_id()); - }); - } - } - - if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop') && - this.sourceActor instanceof DockAppIcon && - !this.sourceActor.getSnapName()) { - this._appendSeparator(); - const item = this._appendMenuItem(_('App Details')); - item.connect('activate', () => { - const id = app.get_id(); - const args = GLib.Variant.new('(ss)', [id, '']); - Gio.DBus.get(Gio.BusType.SESSION, null, - (o, res) => { - const 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(); - }); - }); - } - - if (this.sourceActor instanceof DockAppIcon) { - const snapName = this.sourceActor.getSnapName(); - const snapStore = snapName - ? Shell.AppSystem.get_default().lookup_app( - 'snap-store_snap-store.desktop') : null; - - if (snapStore) { - this._appendSeparator(); - const item = this._appendMenuItem(_('App Details')); - item.connect('activate', (_, event) => { - snapStore.activate_full(-1, event.get_time()); - Util.spawnApp( - [...snapStore.appInfo.get_commandline().split(' '), snapName]); - Main.overview.hide(); - }); - } - } - } - - // dynamic menu - const items = this._getMenuItems(); - let i = items.length; - if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) - i -= 2; - - if (global.settings.is_writable('favorite-apps')) - i -= 2; - - if (i < 0) - i = 0; - - const dynamicSection = new PopupMenu.PopupMenuSection(); - this.addMenuItem(dynamicSection, i); - this.emit('dynamic-section-changed', dynamicSection); - - // quit menu - this._appendSeparator(); - this._quitMenuItem = this._appendMenuItem(_('Quit')); - this._quitMenuItem.connect('activate', () => this.sourceActor.closeAllWindows()); - - this.update(); - } - - // update menu content when application windows change. This is desirable as actions - // acting on windows (closing) are performed while the menu is shown. - update() { - // update, show or hide the quit menu - if (this.sourceActor.windowsCount > 0) { - if (this.sourceActor.windowsCount === 1) { - this._quitMenuItem.label.set_text(_('Quit')); - } else { - this._quitMenuItem.label.set_text(ngettext( - 'Quit %d Window', 'Quit %d Windows', this.sourceActor.windowsCount).format( - this.sourceActor.windowsCount)); - } - - this._quitMenuItem.actor.show(); - } else { - this._quitMenuItem.actor.hide(); - } - - if (Docking.DockManager.settings.showWindowsPreview) { - const windows = this.sourceActor.getInterestingWindows(); - - // update, show, or hide the allWindows menu - // Check if there are new windows not already displayed. In such case, - // repopulate the allWindows menu. Windows removal is already handled - // by each preview being connected to the destroy signal - const oldWindows = this._allWindowsMenuItem.menu._getMenuItems().map(item => { - return item._window; - }); - - const newWindows = windows.filter(w => - oldWindows.indexOf(w) < 0); - if (newWindows.length > 0) { - this._populateAllWindowMenu(windows); - - // Try to set the width to that of the submenu. - // TODO: can't get the actual size, getting a bit less. - // Temporary workaround: add 15px to compensate - this._allWindowsMenuItem.width = this._allWindowsMenuItem.menu.actor.width + 15; - } - - // The menu is created hidden and never hidden after being shown. - // Instead, a signal connected to its items destroy will set is - // insensitive if no more windows preview are shown. - if (windows.length > 0) { - this._allWindowsMenuItem.show(); - this._allWindowsMenuItem.setSensitive(true); - - if (Docking.DockManager.settings.defaultWindowsPreviewToOpen) - this._allWindowsMenuItem.menu.open(); - } - } - - // Update separators - this._getMenuItems().forEach(item => { - if ('label' in item) - this._updateSeparatorVisibility(item); - }); - } - - _populateAllWindowMenu(windows) { - this._allWindowsMenuItem.menu.removeAll(); - - if (windows.length > 0) { - const activeWorkspace = global.workspace_manager.get_active_workspace(); - let separatorShown = windows[0].get_workspace() !== activeWorkspace; - - for (let i = 0; i < windows.length; i++) { - const window = windows[i]; - if (!separatorShown && window.get_workspace() !== activeWorkspace) { - this._allWindowsMenuItem.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - separatorShown = true; - } - - const item = new WindowPreview.WindowPreviewMenuItem(window, - St.Side.LEFT); - this._allWindowsMenuItem.menu.addMenuItem(item); - item.connect('activate', () => { - this.emit('activate-window', window); - }); - - // This is to achieve a more graceful transition when the last - // window is closed. - item.connect('destroy', () => { - // It's still counting the item just going to be destroyed - if (this._allWindowsMenuItem.menu._getMenuItems().length === 1) - this._allWindowsMenuItem.setSensitive(false); - }); - } - } - } -}; - -/** - * @param w - */ -function isWindowUrgent(w) { - return w.urgent || w.demandsAttention || w._manualUrgency; -} - -/** - * Filter out unnecessary windows, for instance - * nautilus desktop window. - * - * @param windows - * @param monitorIndex - */ -export function getInterestingWindows(windows, monitorIndex) { - const {settings} = Docking.DockManager; - - // When using workspace isolation, we filter out windows - // that are neither in the current workspace nor marked urgent - if (settings.isolateWorkspaces) { - const showUrgent = settings.workspaceAgnosticUrgentWindows; - const activeWorkspace = global.workspace_manager.get_active_workspace(); - windows = windows.filter(w => { - const inWorkspace = w.get_workspace() === activeWorkspace; - return inWorkspace || (showUrgent && isWindowUrgent(w)); - }); - } - - if (settings.isolateMonitors && monitorIndex >= 0) { - windows = windows.filter(w => { - return w.get_monitor() === monitorIndex; - }); - } - - return windows.filter(w => !w.skipTaskbar); -} - -/** - * A ShowAppsIcon improved class. - * - * - set label position based on dash orientation - * Note: we are am reusing most machinery of the appIcon class. - * - implement a popupMenu based on the AppIcon code - * Note: we are reusing most machinery of the appIcon class) - * - */ - -export const DockShowAppsIcon = GObject.registerClass({ - Signals: { - 'menu-state-changed': {param_types: [GObject.TYPE_BOOLEAN]}, - 'sync-tooltip': {}, - }, -} -, class DockShowAppsIcon extends Dash.ShowAppsIcon { - _init(position) { - super._init(); - - // Re-use appIcon methods - const {prototype: appIconPrototype} = AppDisplay.AppIcon; - this.toggleButton.y_expand = false; - this.toggleButton.connect('popup-menu', () => - appIconPrototype._onKeyboardPopupMenu.call(this)); - this.toggleButton.connect('clicked', () => - this._removeMenuTimeout()); - - this.reactive = true; - this.toggleButton.popupMenu = (...args) => - this.popupMenu(...args); - this.toggleButton._setPopupTimeout = (...args) => - this._setPopupTimeout(...args); - this.toggleButton._removeMenuTimeout = (...args) => - this._removeMenuTimeout(...args); - - this.label?.add_style_class_name(Theming.PositionStyleClass[position]); - if (Docking.DockManager.settings.customThemeShrink) - this.label?.add_style_class_name('shrink'); - - this._menu = null; - this._menuManager = new PopupMenu.PopupMenuManager(this); - this._menuTimeoutId = 0; - - this._maybeEnablePopupGestures(); - } - - _createIcon(size) { - this._iconActor = super._createIcon(size); - this._iconActor.fallbackIconName = this._iconActor.iconName; - this._iconActor.fallbackGicon = this._iconActor.gicon; - this._iconActor.iconName = `view-app-grid-${Main.sessionMode.currentMode}-symbolic`; - return this._iconActor; - } - - vfunc_leave_event(...args) { - return AppDisplay.AppIcon.prototype.vfunc_leave_event.call( - this.toggleButton, ...args); - } - - vfunc_button_press_event(...args) { - try { - // TODO: Drop this when not supporting GNOME 48 (and older) anymore. - return AppDisplay.AppIcon.prototype.vfunc_button_press_event.call( - this.toggleButton, ...args); - } catch { - return Clutter.EVENT_PROPAGATE; - } - } - - vfunc_touch_event(...args) { - try { - // TODO: Drop this when not supporting GNOME 48 (and older) anymore. - return AppDisplay.AppIcon.prototype.vfunc_touch_event.call( - this.toggleButton, ...args); - } catch { - return Clutter.EVENT_PROPAGATE; - } - } - - showLabel(...args) { - itemShowLabel.call(this, ...args); - } - - setForcedHighlight(...args) { - AppDisplay.AppIcon.prototype.setForcedHighlight.call(this, ...args); - } - - _onMenuPoppedDown(...args) { - AppDisplay.AppIcon.prototype._onMenuPoppedDown.call(this, ...args); - } - - _setPopupTimeout(...args) { - AppDisplay.AppIcon.prototype._setPopupTimeout.call(this, ...args); - } - - _removeMenuTimeout(...args) { - AppDisplay.AppIcon.prototype._removeMenuTimeout?.call(this, ...args); - } - - _hasPopupMenu() { - return Docking.DockManager.extension.uuid !== 'ubuntu-dock@ubuntu.com'; - } - - _maybeEnablePopupGestures() { - if (!this._hasPopupMenu()) - return; - - if (!Clutter.LongPressGesture || !Clutter.ClickGesture) - return; - - const longPressGesture = new Clutter.LongPressGesture(); - longPressGesture.connect('recognize', () => this.popupMenu()); - this.add_action(longPressGesture); - - const rightClickGesture = new Clutter.ClickGesture({ - required_button: Clutter.BUTTON_SECONDARY, - recognize_on_press: true, - }); - rightClickGesture.connect('recognize', () => this.popupMenu()); - this.add_action(rightClickGesture); - } - - popupMenu() { - if (!this._hasPopupMenu()) - return false; - - this._removeMenuTimeout(); - this.toggleButton.fake_release(); - - if (!this._menu) { - this._menu = new DockShowAppsIconMenu(this); - this._menu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - }); - const id = Main.overview.connect('hiding', () => { - this._menu.close(); - }); - this._menu.actor.connect('destroy', () => { - Main.overview.disconnect(id); - }); - this._menuManager.addMenu(this._menu); - } - - this.emit('menu-state-changed', true); - - this.toggleButton.set_hover(true); - this._menu.popup(); - // Removed in GNOME 50. - this._menuManager.ignoreRelease?.(); - this.emit('sync-tooltip'); - - return false; - } -}); - - -/** - * A menu for the showAppsIcon - */ -class DockShowAppsIconMenu extends DockAppIconMenu { - _rebuildMenu() { - this.removeAll(); - - this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(__('Dash to Dock'))); - - const item = this._appendMenuItem(_('Settings')); - item.connect('activate', () => - Docking.DockManager.extension.openPreferences()); - } -} - -/** - * This function is used for both DockShowAppsIcon and DockDashItemContainer - */ -export function itemShowLabel() { - /* eslint-disable no-invalid-this */ - // Check if the label is still present at all. When switching workspace, the - // item might have been destroyed in between. - if (!this._labelText || !this.label.get_stage()) - return; - - this.label.set_text(this._labelText); - this.label.opacity = 0; - this.label.show(); - - const [stageX, stageY] = this.get_transformed_position(); - const node = this.label.get_theme_node(); - - const itemWidth = this.allocation.x2 - this.allocation.x1; - const itemHeight = this.allocation.y2 - this.allocation.y1; - - const labelWidth = this.label.get_width(); - const labelHeight = this.label.get_height(); - - let x, y, xOffset, yOffset; - - const position = Utils.getPosition(); - const labelOffset = node.get_length('-x-offset'); - - switch (position) { - case St.Side.LEFT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = stageX + this.get_width() + xOffset; - break; - case St.Side.RIGHT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = Math.round(stageX) - labelWidth - xOffset; - break; - case St.Side.TOP: - y = stageY + labelOffset + itemHeight; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - case St.Side.BOTTOM: - yOffset = labelOffset; - y = stageY - labelHeight - yOffset; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - } - - // keep the label inside the screen border - // Only needed fot the x coordinate. - - // Leave a few pixel gap - const gap = 5; - const monitor = Main.layoutManager.findMonitorForActor(this); - if (x - monitor.x < gap) - x += monitor.x - x + labelOffset; - else if (x + labelWidth > monitor.x + monitor.width - gap) - x -= x + labelWidth - (monitor.x + monitor.width) + gap; - - this.label.remove_all_transitions(); - this.label.set_position(x, y); - this.label.ease({ - opacity: 255, - duration: DASH_ITEM_LABEL_SHOW_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - /* eslint-enable no-invalid-this */ -} |