summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/appIcons.js
diff options
context:
space:
mode:
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.js1635
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 */
-}