summaryrefslogtreecommitdiff
path: root/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js
diff options
context:
space:
mode:
authorAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
committerAlexanderCurl <alexc@alexc.hu>2026-04-18 17:46:06 +0100
commit70ca3fef77ee8bdc6e3ac28589a6fa08c024cc69 (patch)
treeab1123d4067c1b086dd6faa7ee4ea643236b565a /raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js
parent5d94c0a7d44a2255b81815a52a7056a94a39842d (diff)
downloadRaveOS-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/docking.js')
-rw-r--r--raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js2698
1 files changed, 0 insertions, 2698 deletions
diff --git a/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js b/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js
deleted file mode 100644
index 393b1de..0000000
--- a/raveos-theme/gnome/theme-data/extensions/installed/dash-to-dock@micxgx.gmail.com/docking.js
+++ /dev/null
@@ -1,2698 +0,0 @@
-// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-
-import {
- Clutter,
- GLib,
- Gio,
- GObject,
- Meta,
- Shell,
- St,
-} from './dependencies/gi.js';
-
-import {
- AppMenu,
- AppDisplay,
- Layout,
- Main,
- OverviewControls,
- PointerWatcher,
- Workspace,
- WorkspacesView,
- WorkspaceSwitcherPopup,
-} from './dependencies/shell/ui.js';
-
-import {
- AnimationUtils,
-} from './dependencies/shell/misc.js';
-
-import {
- AppIconsDecorator,
- AppSpread,
- DockDash,
- DesktopIconsIntegration,
- FileManager1API,
- Intellihide,
- LauncherAPI,
- Locations,
- NotificationsMonitor,
- Theming,
- Utils,
-} 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: __} = Extension;
-
-const {signals: Signals} = imports;
-
-const DOCK_DWELL_CHECK_INTERVAL = 100;
-const ICON_ANIMATOR_DURATION = 3000;
-const STARTUP_ANIMATION_TIME = 500;
-
-export const State = Object.freeze({
- HIDDEN: 0,
- SHOWING: 1,
- SHOWN: 2,
- HIDING: 3,
-});
-
-const scrollAction = Object.freeze({
- DO_NOTHING: 0,
- CYCLE_WINDOWS: 1,
- SWITCH_WORKSPACE: 2,
-});
-
-const Labels = Object.freeze({
- INITIALIZE: Symbol('initialize'),
- ISOLATION: Symbol('isolation'),
- LOCATIONS: Symbol('locations'),
- MAIN_DASH: Symbol('main-dash'),
- OLD_DASH_CHANGES: Symbol('old-dash-changes'),
- SETTINGS: Symbol('settings'),
- STARTUP_ANIMATION: Symbol('startup-animation'),
- WORKSPACE_SWITCH_SCROLL: Symbol('workspace-switch-scroll'),
-});
-
-/**
- * A simple St.Widget with one child whose allocation takes into account the
- * slide out of its child via the slide-x property ([0:1]).
- *
- * Required since I want to track the input region of this container which is
- * based on its allocation even if the child overflows the parent actor. By doing
- * this the region of the dash that is slide-out is not stealing anymore the input
- * regions making the extension usable when the primary monitor is the right one.
- *
- * The slide-x parameter can be used to directly animate the sliding. The parent
- * must have a WEST (SOUTH) anchor_point to achieve the sliding to the RIGHT (BOTTOM)
- * side.
- */
-const DashSlideContainer = GObject.registerClass({
- Properties: {
- 'monitor-index': GObject.ParamSpec.uint(
- 'monitor-index', 'monitor-index', 'monitor-index',
- GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
- 0, GLib.MAXUINT32, 0),
- 'side': GObject.ParamSpec.enum(
- 'side', 'side', 'side',
- GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
- St.Side, St.Side.LEFT),
- 'slide-x': GObject.ParamSpec.double(
- 'slide-x', 'slide-x', 'slide-x',
- GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
- 0, 1, 1),
- },
-}, class DashSlideContainer extends St.Bin {
- _init(params = {}) {
- super._init(params);
-
- this._slideoutSize = 0; // minimum size when slided out
- this.connect('notify::slide-x', () => this.queue_relayout());
-
- if (this.side === St.Side.TOP && DockManager.settings.dockFixed) {
- this._signalsHandler = new Utils.GlobalSignalsHandler(this);
- this._signalsHandler.add(Main.panel, 'notify::height',
- () => this.queue_relayout());
- }
- }
-
- vfunc_allocate(box) {
- const contentBox = this.get_theme_node().get_content_box(box);
-
- this.set_allocation(box);
-
- if (!this.child)
- return;
-
- const availWidth = contentBox.x2 - contentBox.x1;
- let availHeight = contentBox.y2 - contentBox.y1;
- const [, , natChildWidth, natChildHeight] =
- this.child.get_preferred_size();
-
- const childWidth = natChildWidth;
- const childHeight = natChildHeight;
-
- const childBox = new Clutter.ActorBox();
-
- const slideoutSize = this._slideoutSize;
-
- if (this.side === St.Side.LEFT) {
- childBox.x1 = (this.slideX - 1) * (childWidth - slideoutSize);
- childBox.x2 = slideoutSize + this.slideX * (childWidth - slideoutSize);
- childBox.y1 = 0;
- childBox.y2 = childBox.y1 + childHeight;
- } else if ((this.side === St.Side.RIGHT) || (this.side === St.Side.BOTTOM)) {
- childBox.x1 = 0;
- childBox.x2 = childWidth;
- childBox.y1 = 0;
- childBox.y2 = childBox.y1 + childHeight;
- } else if (this.side === St.Side.TOP) {
- const monitor = Main.layoutManager.monitors[this.monitorIndex];
- let yOffset = 0;
- if (Main.panel.x === monitor.x && Main.panel.y === monitor.y &&
- DockManager.settings.dockFixed)
- yOffset = Main.panel.height;
- childBox.x1 = 0;
- childBox.x2 = childWidth;
- childBox.y1 = (this.slideX - 1) * (childHeight - slideoutSize) + yOffset;
- childBox.y2 = slideoutSize + this.slideX * (childHeight - slideoutSize) + yOffset;
- availHeight += yOffset;
- }
-
- this.child.allocate(childBox);
-
- this.child.set_clip(-childBox.x1, -childBox.y1,
- -childBox.x1 + availWidth, -childBox.y1 + availHeight);
- }
-
- /**
- * Just the child width but taking into account the slided out part
- *
- * @param forHeight
- */
- vfunc_get_preferred_width(forHeight) {
- let [minWidth, natWidth] = super.vfunc_get_preferred_width(forHeight || 0);
- if ((this.side === St.Side.LEFT) || (this.side === St.Side.RIGHT)) {
- minWidth = (minWidth - this._slideoutSize) * this.slideX + this._slideoutSize;
- natWidth = (natWidth - this._slideoutSize) * this.slideX + this._slideoutSize;
- }
- return [minWidth, natWidth];
- }
-
- /**
- * Just the child height but taking into account the slided out part
- *
- * @param forWidth
- */
- vfunc_get_preferred_height(forWidth) {
- let [minHeight, natHeight] = super.vfunc_get_preferred_height(forWidth || 0);
- if ((this.side === St.Side.TOP) || (this.side === St.Side.BOTTOM)) {
- minHeight = (minHeight - this._slideoutSize) * this.slideX + this._slideoutSize;
- natHeight = (natHeight - this._slideoutSize) * this.slideX + this._slideoutSize;
-
- if (this.side === St.Side.TOP && DockManager.settings.dockFixed) {
- const monitor = Main.layoutManager.monitors[this.monitorIndex];
- if (Main.panel.x === monitor.x && Main.panel.y === monitor.y) {
- minHeight += Main.panel.height;
- natHeight += Main.panel.height;
- }
- }
- }
- return [minHeight, natHeight];
- }
-});
-
-const DockedDash = GObject.registerClass({
- Properties: {
- 'is-main': GObject.ParamSpec.boolean(
- 'is-main', 'is-main', 'is-main',
- GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
- false),
- 'monitor-index': GObject.ParamSpec.uint(
- 'monitor-index', 'monitor-index', 'monitor-index',
- GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
- 0, GLib.MAXUINT32, 0),
- },
- Signals: {
- 'showing': {},
- 'hiding': {},
- },
-}, class DashToDock extends St.Bin {
- _init(params) {
- this._position = Utils.getPosition();
-
- // This is the centering actor
- super._init({
- ...params,
- name: 'dashtodockContainer',
- reactive: false,
- style_class: Theming.PositionStyleClass[this._position],
- });
-
- if (this.monitorIndex === undefined) {
- // Hello turkish locale, gjs has instead defined this.monitorIndex
- // See: https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/742
- this.monitorIndex = this.monitor_index;
- }
-
- this._rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
-
- // Load settings
- const {settings} = DockManager;
- this._isHorizontal = (this._position === St.Side.TOP) || (this._position === St.Side.BOTTOM);
-
- // Temporary ignore hover events linked to autohide for whatever reason
- this._ignoreHover = false;
- this._oldIgnoreHover = null;
- // This variables are linked to the settings regardles of autohide or intellihide
- // being temporary disable. Get set by _updateVisibilityMode;
- this._autohideIsEnabled = null;
- this._intellihideIsEnabled = null;
-
- // This variable marks if _disableUnredirect() is called
- // to help restore the original state when intelihide is disabled.
- this._unredirectDisabled = false;
-
- // Create intellihide object to monitor windows overlapping
- this._intellihide = new Intellihide.Intellihide(this.monitorIndex);
-
- // initialize dock state
- this._dockState = State.HIDDEN;
-
- // Put dock on the required monitor
- this._monitor = Main.layoutManager.monitors[this.monitorIndex];
-
- // this store size and the position where the dash is shown;
- // used by intellihide module to check window overlap.
- this.staticBox = new Clutter.ActorBox();
-
- // Initialize pressure barrier variables
- this._canUsePressure = false;
- this._pressureBarrier = null;
- this._barrier = null;
- this._removeBarrierTimeoutId = 0;
-
- // Initialize dwelling system variables
- this._dockDwelling = false;
- this._dockWatch = null;
- this._dockDwellUserTime = 0;
- this._dockDwellTimeoutId = 0;
-
- // Create a new dash object
- this.dash = new DockDash.DockDash(this.monitorIndex);
-
- if (Main.overview.isDummy || !settings.showShowAppsButton)
- this.dash.hideShowAppsButton();
-
- // Create the containers for sliding in and out and
- // centering, turn on track hover
- // This is the sliding actor whose allocation is to be tracked for input regions
- this._slider = new DashSlideContainer({
- monitor_index: this._monitor.index,
- side: this._position,
- slide_x: Main.layoutManager._startingUp ? 0 : 1,
- ...this._isHorizontal ? {
- x_align: Clutter.ActorAlign.CENTER,
- } : {
- y_align: Clutter.ActorAlign.CENTER,
- },
- });
-
- // This is the actor whose hover status us tracked for autohide
- this._box = new St.BoxLayout({
- name: 'dashtodockBox',
- reactive: true,
- track_hover: true,
- });
- this._box.connect('notify::hover', this._hoverChanged.bind(this));
-
- // Connect global signals
- this._signalsHandler = new Utils.GlobalSignalsHandler(this);
- this._bindSettingsChanges();
- this._signalsHandler.add([
- // update when workarea changes, for instance if other extensions modify the struts
- // (like moving th panel at the bottom)
- global.display,
- 'workareas-changed',
- this._resetPosition.bind(this),
- ], [
- global.display,
- 'in-fullscreen-changed',
- this._updateBarrier.bind(this),
- ], [
- // Monitor windows overlapping
- this._intellihide,
- 'status-changed',
- this._updateDashVisibility.bind(this),
- ], [
- this.dash,
- 'menu-opened',
- () => {
- this._onMenuOpened();
- },
- ], [
- // sync hover after a popupmenu is closed
- this.dash,
- 'menu-closed',
- () => {
- this._onMenuClosed();
- },
- ], [
- this.dash,
- 'notify::requires-visibility',
- () => this._updateDashVisibility(),
- ]);
-
- if (!Main.overview.isDummy) {
- this._signalsHandler.add([
- Main.overview,
- 'item-drag-begin',
- this._onDragStart.bind(this),
- ], [
- Main.overview,
- 'item-drag-end',
- this._onDragEnd.bind(this),
- ], [
- Main.overview,
- 'item-drag-cancelled',
- this._onDragEnd.bind(this),
- ], [
- Main.overview,
- 'showing',
- this._onOverviewShowing.bind(this),
- ], [
- Main.overview,
- 'hiding',
- this._onOverviewHiding.bind(this),
- ],
- [
- Main.overview,
- 'hidden',
- this._onOverviewHidden.bind(this),
- ]);
- }
-
- this._themeManager = new Theming.ThemeManager(this);
- this._signalsHandler.add(this._themeManager, 'updated',
- () => this.dash.resetAppIcons());
-
- this._signalsHandler.add(DockManager.iconTheme, 'changed',
- () => this.dash.resetAppIcons());
-
- // Since the actor is not a topLevel child and its parent is now not added to the Chrome,
- // the allocation change of the parent container (slide in and slideout) doesn't trigger
- // anymore an update of the input regions. Force the update manually.
- this.connect('notify::allocation',
- Main.layoutManager._queueUpdateRegions.bind(Main.layoutManager));
-
-
- // Since Clutter has no longer ClutterAllocationFlags,
- // "allocation-changed" signal has been removed. MR !1245
- this.dash._container.connect('notify::allocation', this._updateStaticBox.bind(this));
- this._slider.connect(this._isHorizontal ? 'notify::x' : 'notify::y',
- this._updateStaticBox.bind(this));
-
- // Load optional features that need to be activated for one dock only
- if (this.isMain)
- this._enableExtraFeatures();
- // Load optional features that need to be activated once per dock
- this._optionalScrollWorkspaceSwitch();
-
- // Delay operations that require the shell to be fully loaded and with
- // user theme applied.
-
- this._signalsHandler.addWithLabel(Labels.INITIALIZE, global.stage,
- 'after-paint', () => this._initialize());
-
- // Add dash container actor and the container to the Chrome.
- this.set_child(this._slider);
- this._slider.set_child(this._box);
- this._box.add_child(this.dash);
-
- // Add aligning container without tracking it for input region
- this._trackDock();
-
- // Create and apply height/width constraint to the dash.
- if (this._isHorizontal) {
- this.connect('notify::width', () => {
- this.dash.setMaxSize(this.width, this.height);
- });
- } else {
- this.connect('notify::height', () => {
- this.dash.setMaxSize(this.width, this.height);
- });
- }
-
- if (this._position === St.Side.RIGHT) {
- this.connect('notify::width', () =>
- (this.translation_x = -this.width));
- } else if (this._position === St.Side.BOTTOM) {
- this.connect('notify::height', () =>
- (this.translation_y = -this.height));
- }
-
- // Set initial position
- this._resetPosition();
-
- this.connect('destroy', this._onDestroy.bind(this));
- }
-
- get position() {
- return this._position;
- }
-
- get isHorizontal() {
- return this._isHorizontal;
- }
-
- _untrackDock() {
- Main.layoutManager.untrackChrome(this);
- }
-
- _trackDock() {
- if (DockManager.settings.dockFixed) {
- if (this.get_parent())
- Main.layoutManager.removeChrome(this);
- Main.layoutManager.addChrome(this, {
- trackFullscreen: true,
- affectsStruts: true,
- });
- } else {
- if (this.get_parent())
- Main.layoutManager.removeChrome(this);
- Main.layoutManager.addChrome(this);
- }
- }
-
- _initialize() {
- this._signalsHandler.removeWithLabel(Labels.INITIALIZE);
-
- // Apply custom css class according to the settings
- this._themeManager.updateCustomTheme();
-
- this._updateVisibilityMode();
-
- // In case we are already inside the overview when the extension is loaded,
- // for instance on unlocking the screen if it was locked with the overview open.
- if (Main.overview.visibleTarget)
- this._onOverviewShowing();
-
- this._updateAutoHideBarriers();
- }
-
- _onDestroy() {
- // The dash, intellihide and themeManager have global signals as well internally
- this.dash.destroy();
- this._intellihide.destroy();
- this._themeManager.destroy();
-
- if (this._marginLater) {
- Utils.laterRemove(this._marginLater);
- delete this._marginLater;
- }
-
- if (this._triggerTimeoutId)
- GLib.source_remove(this._triggerTimeoutId);
-
- this._restoreUnredirect();
-
- // Remove barrier timeout
- if (this._removeBarrierTimeoutId > 0)
- GLib.source_remove(this._removeBarrierTimeoutId);
-
- // Remove existing barrier
- this._removeBarrier();
-
- // Remove pointer watcher
- if (this._dockWatch) {
- PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch);
- this._dockWatch = null;
- }
- }
-
- _updateAutoHideBarriers() {
- // Remove pointer watcher
- if (this._dockWatch) {
- PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch);
- this._dockWatch = null;
- }
-
- // Setup pressure barrier (GS38+ only)
- this._updatePressureBarrier();
- this._updateBarrier();
-
- // setup dwelling system if pressure barriers are not available
- this._setupDockDwellIfNeeded();
- }
-
- _bindSettingsChanges() {
- const {settings} = DockManager;
- this._signalsHandler.add([
- settings,
- 'changed::scroll-action',
- () => {
- this._optionalScrollWorkspaceSwitch();
- },
- ], [
- settings,
- 'changed::dash-max-icon-size',
- () => {
- this.dash.setIconSize(settings.dashMaxIconSize);
- },
- ], [
- settings,
- 'changed::icon-size-fixed',
- () => {
- this.dash.setIconSize(settings.dashMaxIconSize);
- },
- ], [
- settings,
- 'changed::show-favorites',
- () => {
- this.dash.resetAppIcons();
- },
- ], [
- settings,
- 'changed::show-trash',
- () => {
- this.dash.resetAppIcons();
- },
- Utils.SignalsHandlerFlags.CONNECT_AFTER,
- ], [
- settings,
- 'changed::show-mounts',
- () => {
- this.dash.resetAppIcons();
- },
- Utils.SignalsHandlerFlags.CONNECT_AFTER,
- ], [
- settings,
- 'changed::isolate-locations',
- () => this.dash.resetAppIcons(),
- Utils.SignalsHandlerFlags.CONNECT_AFTER,
- ], [
- settings,
- 'changed::dance-urgent-applications',
- () => this.dash.resetAppIcons(),
- Utils.SignalsHandlerFlags.CONNECT_AFTER,
- ], [
- settings,
- 'changed::show-running',
- () => {
- this.dash.resetAppIcons();
- },
- ], [
- settings,
- 'changed::show-apps-always-in-the-edge',
- () => {
- this.dash.updateShowAppsButton();
- },
- ], [
- settings,
- 'changed::show-apps-at-top',
- () => {
- this.dash.updateShowAppsButton();
- },
- ], [
- settings,
- 'changed::show-show-apps-button',
- () => {
- if (!Main.overview.isDummy &&
- settings.showShowAppsButton)
- this.dash.showShowAppsButton();
- else
- this.dash.hideShowAppsButton();
- },
- ], [
- settings,
- 'changed::dock-fixed',
- () => {
- this._untrackDock();
- this._trackDock();
-
- this._resetPosition();
- this._updateAutoHideBarriers();
- this._updateVisibilityMode();
- },
- ], [
- settings,
- 'changed::manualhide',
- () => {
- this._updateVisibilityMode();
- },
- ], [
- settings,
- 'changed::intellihide',
- () => {
- this._updateVisibilityMode();
- this._updateVisibleDesktop();
- },
- ], [
- settings,
- 'changed::intellihide-mode',
- () => {
- this._intellihide.forceUpdate();
- },
- ], [
- settings,
- 'changed::autohide',
- () => {
- this._updateVisibilityMode();
- this._updateAutoHideBarriers();
- },
- ], [
- settings,
- 'changed::autohide-in-fullscreen',
- this._updateBarrier.bind(this),
- ], [
- settings,
- 'changed::show-dock-urgent-notify',
- () => {
- this.dash.resetAppIcons();
- },
- ],
- [
- settings,
- 'changed::extend-height',
- this._resetPosition.bind(this),
- ], [
- settings,
- 'changed::height-fraction',
- this._resetPosition.bind(this),
- ], [
- settings,
- 'changed::always-center-icons',
- () => this.dash.resetAppIcons(),
- ], [
- settings,
- 'changed::require-pressure-to-show',
- () => this._updateAutoHideBarriers(),
- ], [
- settings,
- 'changed::pressure-threshold',
- () => {
- this._updatePressureBarrier();
- this._updateBarrier();
- },
- ]);
- }
-
- _disableUnredirect() {
- if (!this._unredirectDisabled) {
- if (Meta.disable_unredirect_for_display !== undefined)
- Meta.disable_unredirect_for_display(global.display);
- else if (global.compositor.disable_unredirect !== undefined)
- global.compositor.disable_unredirect();
- this._unredirectDisabled = true;
- }
- }
-
- _restoreUnredirect() {
- if (this._unredirectDisabled) {
- if (Meta.enable_unredirect_for_display !== undefined)
- Meta.enable_unredirect_for_display(global.display);
- else if (global.compositor.enable_unredirect !== undefined)
- global.compositor.enable_unredirect();
- this._unredirectDisabled = false;
- }
- }
-
- /**
- * This is call when visibility settings change
- */
- _updateVisibilityMode() {
- const {settings} = DockManager;
- if (DockManager.settings.dockFixed || DockManager.settings.manualhide) {
- this._autohideIsEnabled = false;
- this._intellihideIsEnabled = false;
- } else {
- this._autohideIsEnabled = settings.autohide;
- this._intellihideIsEnabled = settings.intellihide;
- }
-
- if (this._autohideIsEnabled)
- this.add_style_class_name('autohide');
- else
- this.remove_style_class_name('autohide');
-
- if (this._intellihideIsEnabled) {
- this._intellihide.enable();
- } else {
- this._intellihide.disable();
- this._restoreUnredirect();
- }
-
- this._updateDashVisibility();
- }
-
- /**
- * Show/hide dash based on, in order of priority:
- * overview visibility
- * fixed mode
- * intellihide
- * autohide
- * overview visibility
- */
- _updateDashVisibility() {
- if (DockManager.settings.manualhide) {
- this._ignoreHover = true;
- this._removeAnimations();
- this._animateOut(0, 0);
- return;
- }
-
- if (Main.overview.visibleTarget)
- return;
-
- const {settings} = DockManager;
-
- if (DockManager.settings.dockFixed) {
- this._removeAnimations();
- this._animateIn(settings.animationTime, 0);
- } else if (this._intellihideIsEnabled) {
- if (!this.dash.requiresVisibility && this._intellihide.getOverlapStatus()) {
- this._ignoreHover = false;
- // Do not hide if autohide is enabled and mouse is hover
- if (!this._box.hover || !this._autohideIsEnabled)
- this._animateOut(settings.animationTime, 0);
- } else {
- this._ignoreHover = true;
- this._removeAnimations();
- this._animateIn(settings.animationTime, 0);
- }
- } else if (this._autohideIsEnabled) {
- this._ignoreHover = false;
-
- if (this._box.hover || this.dash.requiresVisibility)
- this._animateIn(settings.animationTime, 0);
- else
- this._animateOut(settings.animationTime, 0);
- } else {
- this._animateOut(settings.animationTime, 0);
- }
- }
-
- _onOverviewShowing() {
- this.add_style_class_name('overview');
-
- this._ignoreHover = true;
- this._intellihide.disable();
- this._removeAnimations();
- this._animateIn(DockManager.settings.animationTime, 0);
- }
-
- _onOverviewHiding() {
- this._intellihide.enable();
- this._updateDashVisibility();
- }
-
- _onOverviewHidden() {
- this.remove_style_class_name('overview');
- this._updateDashVisibility();
- }
-
- _onMenuOpened() {
- this._ignoreHover = true;
- }
-
- _onMenuClosed() {
- this._ignoreHover = false;
- this._box.sync_hover();
- this._updateDashVisibility();
- }
-
- _hoverChanged() {
- if (!this._ignoreHover) {
- // Skip if dock is not in autohide mode for instance because it is shown
- // by intellihide.
- if (this._autohideIsEnabled) {
- if (this._box.hover || Main.overview.visible)
- this._show();
- else
- this._hide();
- }
- }
- }
-
- getDockState() {
- return this._dockState;
- }
-
- _show() {
- this._delayedHide = false;
- if ((this._dockState === State.HIDDEN) || (this._dockState === State.HIDING)) {
- if (this._dockState === State.HIDING)
- // suppress all potential queued transitions - i.e. added but not started,
- // always give priority to show
- this._removeAnimations();
-
- this.emit('showing');
- this._animateIn(DockManager.settings.animationTime, 0);
- }
- }
-
- _hide() {
- // If no hiding animation is running or queued
- if ((this._dockState === State.SHOWN) || (this._dockState === State.SHOWING)) {
- const {settings} = DockManager;
- const delay = settings.hideDelay;
-
- if (this._dockState === State.SHOWING) {
- // if a show already started, let it finish; queue hide without removing the show.
- // to obtain this, we wait for the animateIn animation to be completed
- this._delayedHide = true;
- return;
- }
-
- this.emit('hiding');
- this._animateOut(settings.animationTime, delay);
- }
- }
-
- _animateIn(time, delay) {
- if (this._intellihideIsEnabled)
- this._disableUnredirect();
- this._dockState = State.SHOWING;
- this.dash.iconAnimator.start();
- this._delayedHide = false;
-
- this._slider.ease_property('slide-x', 1, {
- duration: time * 1000,
- delay: delay * 1000,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- this._dockState = State.SHOWN;
- // Remove barrier so that mouse pointer is released and can
- // monitors on other side of dock.
- // NOTE: Delay needed to keep mouse from moving past dock and
- // re-hiding dock immediately. This gives users an opportunity
- // to hover over the dock
- if (this._removeBarrierTimeoutId > 0)
- GLib.source_remove(this._removeBarrierTimeoutId);
-
- if (!this._delayedHide) {
- this._removeBarrierTimeoutId = GLib.timeout_add(
- GLib.PRIORITY_DEFAULT, 100, this._removeBarrier.bind(this));
- } else {
- this._hide();
- }
- },
- });
- }
-
- _animateOut(time, delay) {
- this._dockState = State.HIDING;
-
- this._slider.ease_property('slide-x', 0, {
- duration: time * 1000,
- delay: delay * 1000,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- this._dockState = State.HIDDEN;
- if (this._intellihideIsEnabled)
- this._restoreUnredirect();
- // Remove queued barrier removal timeout if any
- if (this._removeBarrierTimeoutId > 0)
- GLib.source_remove(this._removeBarrierTimeoutId);
- this._updateBarrier();
- this.dash.iconAnimator.pause();
- },
- });
- }
-
- /**
- * Dwelling system based on the GNOME Shell 3.14 messageTray code.
- */
- _setupDockDwellIfNeeded() {
- // If we don't have extended barrier features, then we need
- // to support the old tray dwelling mechanism.
- if (this._autohideIsEnabled &&
- (!Utils.supportsExtendedBarriers() ||
- !DockManager.settings.requirePressureToShow)) {
- const pointerWatcher = PointerWatcher.getPointerWatcher();
- this._dockWatch = pointerWatcher.addWatch(
- DOCK_DWELL_CHECK_INTERVAL, this._checkDockDwell.bind(this));
- this._dockDwelling = false;
- this._dockDwellUserTime = 0;
- }
- }
-
- _checkDockDwell(x, y) {
- const workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index);
- let shouldDwell;
- // Check for the correct screen edge, extending the sensitive area to the whole workarea,
- // minus 1 px to avoid conflicting with other active corners.
- if (this._position === St.Side.LEFT) {
- shouldDwell = (x === this._monitor.x) && (y > workArea.y) &&
- (y < workArea.y + workArea.height);
- } else if (this._position === St.Side.RIGHT) {
- shouldDwell = (x === this._monitor.x + this._monitor.width - 1) &&
- (y > workArea.y) && (y < workArea.y + workArea.height);
- } else if (this._position === St.Side.TOP) {
- shouldDwell = (y === this._monitor.y) && (x > workArea.x) &&
- (x < workArea.x + workArea.width);
- } else if (this._position === St.Side.BOTTOM) {
- shouldDwell = (y === this._monitor.y + this._monitor.height - 1) &&
- (x > workArea.x) && (x < workArea.x + workArea.width);
- }
-
- if (shouldDwell) {
- // We only set up dwell timeout when the user is not hovering over the dock
- // already (!this._box.hover).
- // The _dockDwelling variable is used so that we only try to
- // fire off one dock dwell - if it fails (because, say, the user has the mouse down),
- // we don't try again until the user moves the mouse up and down again.
- if (!this._dockDwelling && !this._box.hover && (this._dockDwellTimeoutId === 0)) {
- // Save the interaction timestamp so we can detect user input
- const focusWindow = global.display.focus_window;
- this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0;
-
- this._dockDwellTimeoutId = GLib.timeout_add(
- GLib.PRIORITY_DEFAULT,
- DockManager.settings.showDelay * 1000,
- this._dockDwellTimeout.bind(this));
- GLib.Source.set_name_by_id(this._dockDwellTimeoutId,
- '[dash-to-dock] this._dockDwellTimeout');
- }
- this._dockDwelling = true;
- } else {
- this._cancelDockDwell();
- this._dockDwelling = false;
- }
- }
-
- _cancelDockDwell() {
- if (this._dockDwellTimeoutId !== 0) {
- GLib.source_remove(this._dockDwellTimeoutId);
- this._dockDwellTimeoutId = 0;
- }
- }
-
- _dockDwellTimeout() {
- this._dockDwellTimeoutId = 0;
-
- if (!DockManager.settings.autohideInFullscreen &&
- this._monitor.inFullscreen)
- return GLib.SOURCE_REMOVE;
-
- // We don't want to open the tray when a modal dialog
- // is up, so we check the modal count for that. When we are in the
- // overview we have to take the overview's modal push into account
- if (Main.modalCount > (Main.overview.visible ? 1 : 0))
- return GLib.SOURCE_REMOVE;
-
- // If the user interacted with the focus window since we started the tray
- // dwell (by clicking or typing), don't activate the message tray
- const focusWindow = global.display.focus_window;
- const currentUserTime = focusWindow ? focusWindow.user_time : 0;
- if (currentUserTime !== this._dockDwellUserTime)
- return GLib.SOURCE_REMOVE;
-
- // Reuse the pressure version function, the logic is the same
- this._onPressureSensed();
- return GLib.SOURCE_REMOVE;
- }
-
- _updatePressureBarrier() {
- const {settings} = DockManager;
- this._canUsePressure = Utils.supportsExtendedBarriers();
- const {pressureThreshold} = settings;
-
- // Remove existing pressure barrier
- if (this._pressureBarrier) {
- this._pressureBarrier.destroy();
- this._pressureBarrier = null;
- }
-
- if (this._barrier) {
- this._barrier.destroy();
- this._barrier = null;
- }
-
- // Create new pressure barrier based on pressure threshold setting
- if (this._canUsePressure && this._autohideIsEnabled &&
- DockManager.settings.requirePressureToShow) {
- this._pressureBarrier = new Layout.PressureBarrier(
- pressureThreshold, settings.showDelay * 1000,
- Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW);
- this._pressureBarrier.connect('trigger', _barrier => {
- if (!settings.autohideInFullscreen && this._monitor.inFullscreen)
- return;
- this._onPressureSensed();
- });
- }
- }
-
- /**
- * handler for mouse pressure sensed
- */
- _onPressureSensed() {
- if (Main.overview.visibleTarget)
- return;
-
- if (this._triggerTimeoutId)
- GLib.source_remove(this._triggerTimeoutId);
-
- // In case the mouse move away from the dock area before hovering it,
- // in such case the leave event would never be triggered and the dock
- // would stay visible forever.
- this._triggerTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => {
- const [x, y, mods_] = global.get_pointer();
- let shouldHide = true;
- switch (this._position) {
- case St.Side.LEFT:
- if (x <= this.staticBox.x2 &&
- x >= this._monitor.x &&
- y >= this._monitor.y &&
- y <= this._monitor.y + this._monitor.height)
- shouldHide = false;
-
- break;
- case St.Side.RIGHT:
- if (x >= this.staticBox.x1 &&
- x <= this._monitor.x + this._monitor.width &&
- y >= this._monitor.y &&
- y <= this._monitor.y + this._monitor.height)
- shouldHide = false;
-
- break;
- case St.Side.TOP:
- if (x >= this._monitor.x &&
- x <= this._monitor.x + this._monitor.width &&
- y <= this.staticBox.y2 &&
- y >= this._monitor.y)
- shouldHide = false;
-
- break;
- case St.Side.BOTTOM:
- if (x >= this._monitor.x &&
- x <= this._monitor.x + this._monitor.width &&
- y >= this.staticBox.y1 &&
- y <= this._monitor.y + this._monitor.height)
- shouldHide = false;
- }
- if (shouldHide) {
- this._triggerTimeoutId = 0;
- this._hoverChanged();
- return GLib.SOURCE_REMOVE;
- } else {
- return GLib.SOURCE_CONTINUE;
- }
- });
-
- this._show();
- }
-
- /**
- * Remove pressure barrier
- */
- _removeBarrier() {
- if (this._barrier) {
- if (this._pressureBarrier)
- this._pressureBarrier.removeBarrier(this._barrier);
- this._barrier.destroy();
- this._barrier = null;
- }
- this._removeBarrierTimeoutId = 0;
- return false;
- }
-
- /**
- * Update pressure barrier size
- */
- _updateBarrier() {
- // Remove existing barrier
- this._removeBarrier();
-
- // The barrier needs to be removed in fullscreen with autohide disabled
- // otherwise the mouse can get trapped on monitor.
- if (this._monitor.inFullscreen &&
- !DockManager.settings.autohideInFullscreen)
- return;
-
- // Manually reset pressure barrier
- // This is necessary because we remove the pressure barrier when it is
- // triggered to show the dock
- if (this._pressureBarrier) {
- this._pressureBarrier._reset();
- this._pressureBarrier._isTriggered = false;
- }
-
- // Create new barrier
- // The barrier extends to the whole workarea, minus 1 px to avoid
- // conflicting with other active corners
- // Note: dash in fixed position doesn't use pressure barrier.
- if (this._canUsePressure && this._autohideIsEnabled &&
- DockManager.settings.requirePressureToShow) {
- let x1, x2, y1, y2, direction;
- const workArea = Main.layoutManager.getWorkAreaForMonitor(
- this._monitor.index);
-
- if (this._position === St.Side.LEFT) {
- x1 = this._monitor.x + 1;
- x2 = x1;
- y1 = workArea.y + 1;
- y2 = workArea.y + workArea.height - 1;
- direction = Meta.BarrierDirection.POSITIVE_X;
- } else if (this._position === St.Side.RIGHT) {
- x1 = this._monitor.x + this._monitor.width - 1;
- x2 = x1;
- y1 = workArea.y + 1;
- y2 = workArea.y + workArea.height - 1;
- direction = Meta.BarrierDirection.NEGATIVE_X;
- } else if (this._position === St.Side.TOP) {
- x1 = workArea.x + 1;
- x2 = workArea.x + workArea.width - 1;
- y1 = this._monitor.y;
- y2 = y1;
- direction = Meta.BarrierDirection.POSITIVE_Y;
- } else if (this._position === St.Side.BOTTOM) {
- x1 = workArea.x + 1;
- x2 = workArea.x + workArea.width - 1;
- y1 = this._monitor.y + this._monitor.height;
- y2 = y1;
- direction = Meta.BarrierDirection.NEGATIVE_Y;
- }
-
- if (this._pressureBarrier && this._dockState === State.HIDDEN) {
- this._barrier = new Meta.Barrier({
- backend: global.backend,
- x1,
- x2,
- y1,
- y2,
- directions: direction,
- });
- this._pressureBarrier.addBarrier(this._barrier);
- }
- }
- }
-
- _isPrimaryMonitor() {
- return this.monitorIndex === Main.layoutManager.primaryIndex;
- }
-
- _resetPosition() {
- // Ensure variables linked to settings are updated.
- this._updateVisibilityMode();
-
- const {dockFixed: fixedIsEnabled, dockExtended: extendHeight} = DockManager.settings;
-
- if (fixedIsEnabled)
- this.add_style_class_name('fixed');
- else
- this.remove_style_class_name('fixed');
-
- // Note: do not use the workarea coordinates in the direction on which the dock is placed,
- // to avoid a loop [position change -> workArea change -> position change] with
- // fixed dock.
- const workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex);
-
- let fraction = DockManager.settings.heightFraction;
- if (extendHeight)
- fraction = 1;
- else if ((fraction < 0) || (fraction > 1))
- fraction = 0.95;
-
- if (this._isHorizontal) {
- this.width = Math.round(fraction * workArea.width);
-
- let posY = this._monitor.y;
- if (this._position === St.Side.BOTTOM)
- posY += this._monitor.height;
-
- this.x = workArea.x + Math.round((1 - fraction) / 2 * workArea.width);
- this.y = posY;
-
- if (extendHeight) {
- this.dash._container.set_width(this.width);
- this.add_style_class_name('extended');
- } else {
- this.dash._container.set_width(-1);
- this.remove_style_class_name('extended');
- }
- } else {
- this.height = Math.round(fraction * workArea.height);
-
- let posX = this._monitor.x;
- if (this._position === St.Side.RIGHT)
- posX += this._monitor.width;
-
- this.x = posX;
- this.y = workArea.y + Math.round((1 - fraction) / 2 * workArea.height);
-
- if (extendHeight) {
- this.dash._container.set_height(this.height);
- this.add_style_class_name('extended');
- } else {
- this.dash._container.set_height(-1);
- this.remove_style_class_name('extended');
- }
- }
- }
-
- _updateVisibleDesktop() {
- if (!this._intellihideIsEnabled)
- return;
-
- const {desktopIconsUsableArea} = DockManager.getDefault();
- if (this._position === St.Side.BOTTOM)
- desktopIconsUsableArea.setMargins(this.monitorIndex, 0, this._box.height, 0, 0);
- else if (this._position === St.Side.TOP)
- desktopIconsUsableArea.setMargins(this.monitorIndex, this._box.height, 0, 0, 0);
- else if (this._position === St.Side.RIGHT)
- desktopIconsUsableArea.setMargins(this.monitorIndex, 0, 0, 0, this._box.width);
- else if (this._position === St.Side.LEFT)
- desktopIconsUsableArea.setMargins(this.monitorIndex, 0, 0, this._box.width, 0);
- }
-
- _updateStaticBox() {
- this.staticBox.init_rect(
- this.x + this._slider.x - (this._position === St.Side.RIGHT ? this._box.width : 0),
- this.y + this._slider.y - (this._position === St.Side.BOTTOM ? this._box.height : 0),
- this._box.width,
- this._box.height
- );
-
- this._intellihide.updateTargetBox(this.staticBox);
- this._updateVisibleDesktop();
- }
-
- _removeAnimations() {
- this._slider.remove_all_transitions();
- }
-
- _onDragStart() {
- this._oldIgnoreHover = this._ignoreHover;
- this._ignoreHover = true;
- this._animateIn(DockManager.settings.animationTime, 0);
- }
-
- _onDragEnd() {
- if (this._oldIgnoreHover)
- this._ignoreHover = this._oldIgnoreHover;
- this._oldIgnoreHover = null;
- this._box.sync_hover();
- this._updateDashVisibility();
- }
-
- /**
- * Show dock and give key focus to it
- */
- _onAccessibilityFocus() {
- this._box.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
- this._animateIn(DockManager.settings.animationTime, 0);
- }
-
- // Optional features to be enabled only for the main Dock
- _enableExtraFeatures() {
- // Restore dash accessibility
- Main.ctrlAltTabManager.addGroup(
- this.dash, _('Dash'), 'user-bookmarks-symbolic',
- {focusCallback: this._onAccessibilityFocus.bind(this)});
- }
-
- /**
- * Switch workspace by scrolling over the dock
- */
- _optionalScrollWorkspaceSwitch() {
- const isEnabled = () =>
- DockManager.settings.scrollAction === scrollAction.SWITCH_WORKSPACE;
-
- const enable = () => {
- this._signalsHandler.removeWithLabel(Labels.WORKSPACE_SWITCH_SCROLL);
-
- this._signalsHandler.addWithLabel(Labels.WORKSPACE_SWITCH_SCROLL,
- this._box, 'scroll-event', (_, e) => onScrollEvent(e));
- };
-
- const disable = () => {
- this._signalsHandler.removeWithLabel(Labels.WORKSPACE_SWITCH_SCROLL);
-
- if (this._optionalScrollWorkspaceSwitchDeadTimeId) {
- GLib.source_remove(this._optionalScrollWorkspaceSwitchDeadTimeId);
- this._optionalScrollWorkspaceSwitchDeadTimeId = 0;
- }
- };
-
- DockManager.settings.connect('changed::scroll-action', () => {
- if (isEnabled())
- enable();
- else
- disable();
- });
-
- if (isEnabled())
- enable();
-
- // This was inspired to desktop-scroller@obsidien.github.com
- const onScrollEvent = event => {
- // When in overview change workspace only in windows view
- if (Main.overview.visible)
- return false;
-
- const activeWs = global.workspace_manager.get_active_workspace();
- let direction = null;
-
- let prevDirection, nextDirection;
- if (global.workspace_manager.layout_columns > global.workspace_manager.layout_rows) {
- prevDirection = Meta.MotionDirection.UP;
- nextDirection = Meta.MotionDirection.DOWN;
- } else {
- prevDirection = Meta.MotionDirection.LEFT;
- nextDirection = Meta.MotionDirection.RIGHT;
- }
-
- switch (event.get_scroll_direction()) {
- case Clutter.ScrollDirection.UP:
- direction = prevDirection;
- break;
- case Clutter.ScrollDirection.DOWN:
- direction = nextDirection;
- break;
- case Clutter.ScrollDirection.SMOOTH: {
- const [dx_, dy] = event.get_scroll_delta();
- if (dy < 0)
- direction = prevDirection;
- else if (dy > 0)
- direction = nextDirection;
- }
- break;
- }
-
- if (direction) {
- // Prevent scroll events from triggering too many workspace switches
- // by adding a 250ms dead time between each scroll event.
- // Useful on laptops when using a touch pad.
-
- // During the deadtime do nothing
- if (this._optionalScrollWorkspaceSwitchDeadTimeId) {
- return false;
- } else {
- this._optionalScrollWorkspaceSwitchDeadTimeId = GLib.timeout_add(
- GLib.PRIORITY_DEFAULT, 250, () => {
- this._optionalScrollWorkspaceSwitchDeadTimeId = 0;
- });
- }
-
- let ws;
-
- ws = activeWs.get_neighbor(direction);
-
- if (!Main.wm._workspaceSwitcherPopup) {
- // Support Workspace Grid extension showing their custom
- // Grid Workspace Switcher
- if (global.workspace_manager.workspace_grid !== undefined) {
- Main.wm._workspaceSwitcherPopup =
- global.workspace_manager.workspace_grid.getWorkspaceSwitcherPopup();
- } else {
- Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
- }
- }
- // Set the actor non reactive, so that it doesn't prevent the
- // clicks events from reaching the dash actor. I can't see a reason
- // why it should be reactive.
- Main.wm._workspaceSwitcherPopup.reactive = false;
- Main.wm._workspaceSwitcherPopup.connect('destroy', () => {
- Main.wm._workspaceSwitcherPopup = null;
- });
-
- // If Workspace Grid is installed, let them handle the scroll behavior.
- if (global.workspace_manager.workspace_grid !== undefined)
- ws = global.workspace_manager.workspace_grid.actionMoveWorkspace(direction);
- else
- Main.wm.actionMoveWorkspace(ws);
-
- // Do not show workspaceSwitcher in overview
- if (!Main.overview.visible)
- Main.wm._workspaceSwitcherPopup.display(ws.index());
-
- return true;
- } else {
- return false;
- }
- };
- }
-
- _activateApp(appIndex) {
- const children = this.dash._box.get_children().filter(actor => {
- return actor.child &&
- actor.child.app;
- });
-
- // Apps currently in the dash
- const apps = children.map(actor => {
- return actor.child;
- });
-
- // Activate with button = 1, i.e. same as left click
- const button = 1;
- if (appIndex < apps.length)
- apps[appIndex].activate(button);
- }
-});
-
-/*
- * Handle keyboard shortcuts
- */
-const NUM_HOTKEYS = 10;
-
-const KeyboardShortcuts = class DashToDockKeyboardShortcuts {
- constructor() {
- this._signalsHandler = new Utils.GlobalSignalsHandler();
-
- this._hotKeysEnabled = false;
- if (DockManager.settings.hotKeys)
- this._enableHotKeys();
-
- this._signalsHandler.add([
- DockManager.settings,
- 'changed::hot-keys',
- () => {
- if (DockManager.settings.hotKeys)
- this._enableHotKeys.bind(this)();
- else
- this._disableHotKeys.bind(this)();
- },
- ]);
-
- this._optionalNumberOverlay();
- }
-
- destroy() {
- DockManager.allDocks.forEach(dock => {
- if (dock._numberOverlayTimeoutId) {
- GLib.source_remove(dock._numberOverlayTimeoutId);
- dock._numberOverlayTimeoutId = 0;
- }
- });
-
- // Remove keybindings
- this._disableHotKeys();
- this._disableExtraShortcut();
- this._signalsHandler.destroy();
- }
-
- _enableHotKeys() {
- if (this._hotKeysEnabled)
- return;
-
- // Setup keyboard bindings for dash elements
- const keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'];
- const {mainDock} = DockManager.getDefault();
- keys.forEach(function (key) {
- for (let i = 0; i < NUM_HOTKEYS; i++) {
- const appNum = i;
- Main.wm.addKeybinding(key + (i + 1), DockManager.settings,
- Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
- Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
- () => {
- mainDock._activateApp(appNum);
- this._showOverlay();
- });
- }
- }, this);
-
- this._hotKeysEnabled = true;
- }
-
- _disableHotKeys() {
- if (!this._hotKeysEnabled)
- return;
-
- const keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'];
- keys.forEach(key => {
- for (let i = 0; i < NUM_HOTKEYS; i++)
- Main.wm.removeKeybinding(key + (i + 1));
- }, this);
-
- this._hotKeysEnabled = false;
- }
-
- _optionalNumberOverlay() {
- const {settings} = DockManager;
- this._shortcutIsSet = false;
- // Enable extra shortcut if either 'overlay' or 'show-dock' are true
- if (settings.hotKeys &&
- (settings.hotkeysOverlay || settings.hotkeysShowDock))
- this._enableExtraShortcut();
-
- this._signalsHandler.add([
- settings,
- 'changed::hot-keys',
- this._checkHotkeysOptions.bind(this),
- ], [
- settings,
- 'changed::hotkeys-overlay',
- this._checkHotkeysOptions.bind(this),
- ], [
- settings,
- 'changed::hotkeys-show-dock',
- this._checkHotkeysOptions.bind(this),
- ]);
- }
-
- _checkHotkeysOptions() {
- const {settings} = DockManager;
-
- if (settings.hotKeys &&
- (settings.hotkeysOverlay || settings.hotkeysShowDock))
- this._enableExtraShortcut();
- else
- this._disableExtraShortcut();
- }
-
- _enableExtraShortcut() {
- if (!this._shortcutIsSet) {
- Main.wm.addKeybinding('shortcut', DockManager.settings,
- Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
- Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
- this._showOverlay.bind(this));
- this._shortcutIsSet = true;
- }
- }
-
- _disableExtraShortcut() {
- if (this._shortcutIsSet) {
- Main.wm.removeKeybinding('shortcut');
- this._shortcutIsSet = false;
- }
- }
-
- _showOverlay() {
- for (const dock of DockManager.allDocks) {
- if (DockManager.settings.hotkeysOverlay)
- dock.dash.toggleNumberOverlay(true);
-
- // Restart the counting if the shortcut is pressed again
- if (dock._numberOverlayTimeoutId) {
- GLib.source_remove(dock._numberOverlayTimeoutId);
- dock._numberOverlayTimeoutId = 0;
- }
-
- // Hide the overlay/dock after the timeout
- const timeout = DockManager.settings.shortcutTimeout * 1000;
- dock._numberOverlayTimeoutId = GLib.timeout_add(
- GLib.PRIORITY_DEFAULT, timeout, () => {
- dock._numberOverlayTimeoutId = 0;
- dock.dash.toggleNumberOverlay(false);
- // Hide the dock again if necessary
- dock._updateDashVisibility();
- });
-
- // Show the dock if it is hidden
- if (DockManager.settings.hotkeysShowDock) {
- const showDock = dock._intellihideIsEnabled || dock._autohideIsEnabled;
- if (showDock)
- dock._show();
- }
- }
- }
-};
-
-/**
- * Isolate overview to open new windows for inactive apps
- * Note: the future implementation is not fully contained here.
- * Some bits are around in other methods of other classes.
- * This class just take care of enabling/disabling the option.
- */
-const WorkspaceIsolation = class DashToDockWorkspaceIsolation {
- constructor() {
- const {settings} = DockManager;
-
- this._signalsHandler = new Utils.GlobalSignalsHandler();
- this._injectionsHandler = new Utils.InjectionsHandler();
-
- const updateAllDocks = () => {
- DockManager.allDocks.forEach(dock =>
- dock.dash.resetAppIcons());
- if (settings.isolateWorkspaces ||
- settings.isolateMonitors)
- this._enable.bind(this)();
- else
- this._disable.bind(this)();
- };
- this._signalsHandler.add(
- [settings, 'changed::isolate-workspaces', updateAllDocks],
- [settings, 'changed::workspace-agnostic-urgent-windows', updateAllDocks],
- [settings, 'changed::isolate-monitors', updateAllDocks]
- );
-
- if (settings.isolateWorkspaces ||
- settings.isolateMonitors)
- this._enable();
- }
-
- _enable() {
- // ensure I never double-register/inject
- // although it should never happen
- this._disable();
-
- DockManager.allDocks.forEach(dock => {
- this._signalsHandler.addWithLabel(
- Labels.ISOLATION,
- [global.display, 'restacked', () => dock.dash._queueRedisplay()],
- [global.display, 'window-marked-urgent', () => dock.dash._queueRedisplay()],
- [global.display, 'window-demands-attention', () => dock.dash._queueRedisplay()],
- [global.window_manager, 'switch-workspace', () => dock.dash._queueRedisplay()]
- );
-
- // This last signal is only needed for monitor isolation, as windows
- // might migrate from one monitor to another without triggering 'restacked'
- if (DockManager.settings.isolateMonitors) {
- this._signalsHandler.addWithLabel(Labels.ISOLATION,
- global.display,
- 'window-entered-monitor',
- dock.dash._queueRedisplay.bind(dock.dash));
- }
- }, this);
-
- /**
- * here this is the Shell.App
- */
- function IsolatedOverview() {
- // These lines take care of Nautilus for icons on Desktop
- const activeWorkspaceIndex =
- global.workspaceManager.get_active_workspace_index();
- const windows = this.get_windows().filter(w =>
- !w.skipTaskbar && w.get_workspace().index() === activeWorkspaceIndex);
-
- if (windows.length)
- return Main.activateWindow(windows[0]);
- return this.open_new_window(-1);
- }
-
- this._injectionsHandler.addWithLabel(Labels.ISOLATION,
- Shell.App.prototype,
- 'activate',
- IsolatedOverview);
- }
-
- _disable() {
- this._signalsHandler.removeWithLabel(Labels.ISOLATION);
- this._injectionsHandler.removeWithLabel(Labels.ISOLATION);
- }
-
- destroy() {
- this._signalsHandler.destroy();
- this._injectionsHandler.destroy();
- }
-};
-
-
-export class DockManager {
- constructor(extension) {
- if (DockManager._singleton)
- throw new Error('DashToDock has been already initialized');
- DockManager._singleton = this;
- this._extension = extension;
- this._signalsHandler = new Utils.GlobalSignalsHandler(this);
- this._methodInjections = new Utils.InjectionsHandler(this);
- this._vfuncInjections = new Utils.VFuncInjectionsHandler(this);
- this._propertyInjections = new Utils.PropertyInjectionsHandler(this);
- this._settings = this._extension.getSettings(
- 'org.gnome.shell.extensions.dash-to-dock');
- this._appSwitcherSettings = new Gio.Settings({schema_id: 'org.gnome.shell.app-switcher'});
- this._mapSettingsValues();
-
- this._iconTheme = new St.IconTheme();
-
- this._desktopIconsUsableArea = new DesktopIconsIntegration.DesktopIconsUsableAreaClass();
- this._oldDash = Main.overview.isDummy ? null : Main.overview.dash;
- this._discreteGpuAvailable = AppDisplay.discreteGpuAvailable;
- this._appSpread = new AppSpread.AppSpread();
- this._notificationsMonitor = new NotificationsMonitor.NotificationsMonitor();
-
- const needsRemoteModel = () =>
- !this._notificationsMonitor.dndMode && this._settings.showIconsEmblems;
-
- const ensureRemoteModel = () => {
- if (needsRemoteModel && !this._remoteModel) {
- this._remoteModel = new LauncherAPI.LauncherEntryRemoteModel();
- this._appIconsDecorator = new AppIconsDecorator.AppIconsDecorator();
- } else if (!needsRemoteModel) {
- this._remoteModel?.destroy();
- delete this._remoteModel;
- this._appIconsDecorator?.destroy();
- delete this._appIconsDecorator;
- }
- };
- ensureRemoteModel();
-
- this._notificationsMonitor.connect('changed', ensureRemoteModel);
- this._settings.connect('changed::show-icons-emblems', ensureRemoteModel);
-
- if (this._discreteGpuAvailable === undefined) {
- const updateDiscreteGpuAvailable = () => {
- const switcherooProxy = global.get_switcheroo_control();
- if (switcherooProxy) {
- const prop = switcherooProxy.get_cached_property('HasDualGpu');
- this._discreteGpuAvailable = prop?.unpack() ?? false;
- } else {
- this._discreteGpuAvailable = false;
- }
- };
- this._signalsHandler.add(global, 'notify::switcheroo-control',
- () => updateDiscreteGpuAvailable());
- updateDiscreteGpuAvailable();
- }
-
- // Connect relevant signals to the toggling function
- this._bindSettingsChanges();
-
- this._ensureLocations();
-
- /* Array of all the docks created */
- this._allDocks = [];
- this._createDocks();
-
- this._overrideAppMenus();
-
- // status variable: true when the overview is shown through the dash
- // applications button.
- this._forcedOverview = false;
- }
-
- static getDefault() {
- return DockManager._singleton;
- }
-
- static get allDocks() {
- return DockManager.getDefault()._allDocks;
- }
-
- static get extension() {
- return DockManager.getDefault().extension;
- }
-
- static get settings() {
- return DockManager.getDefault().settings;
- }
-
- get extension() {
- return this._extension;
- }
-
- get settings() {
- return this._settings;
- }
-
- static get iconTheme() {
- return DockManager.getDefault().iconTheme;
- }
-
- get settings() { // eslint-disable-line no-dupe-class-members
- return this._settings;
- }
-
- get iconTheme() {
- return this._iconTheme;
- }
-
- get fm1Client() {
- return this._fm1Client;
- }
-
- get remoteModel() {
- return this._remoteModel;
- }
-
- get mainDock() {
- return this._allDocks.length ? this._allDocks[0] : null;
- }
-
- get removables() {
- return this._removables;
- }
-
- get trash() {
- return this._trash;
- }
-
- get desktopIconsUsableArea() {
- return this._desktopIconsUsableArea;
- }
-
- get discreteGpuAvailable() {
- return AppDisplay.discreteGpuAvailable || this._discreteGpuAvailable;
- }
-
- get appSpread() {
- return this._appSpread;
- }
-
- get notificationsMonitor() {
- return this._notificationsMonitor;
- }
-
- getDockByMonitor(monitorIndex) {
- return this._allDocks.find(d => d.monitorIndex === monitorIndex);
- }
-
- _ensureLocations() {
- const {showMounts, showTrash} = this.settings;
-
- if (showTrash || showMounts) {
- if (!this._fm1Client)
- this._fm1Client = new FileManager1API.FileManager1Client();
- } else if (this._fm1Client) {
- this._fm1Client.destroy();
- this._fm1Client = null;
- }
-
- if (showMounts && !this._removables) {
- this._removables = new Locations.Removables();
- } else if (!showMounts && this._removables) {
- this._removables.destroy();
- this._removables = null;
- }
-
- if (showTrash && !this._trash) {
- this._trash = new Locations.Trash();
- } else if (!showTrash && this._trash) {
- this._trash.destroy();
- this._trash = null;
- }
-
- Locations.unWrapFileManagerApp();
- [this._methodInjections, this._propertyInjections].forEach(
- injections => injections.removeWithLabel(Labels.LOCATIONS));
-
- if (showMounts || showTrash) {
- if (this.settings.isolateLocations) {
- const fileManagerApp = Locations.wrapFileManagerApp();
-
- this._methodInjections.addWithLabel(Labels.LOCATIONS, [
- Shell.AppSystem.prototype, 'get_running',
- function (originalMethod, ...args) {
- /* eslint-disable no-invalid-this */
- const runningApps = originalMethod.call(this, ...args);
- const locationApps = Locations.getRunningApps();
- if (!locationApps.length)
- return runningApps;
-
- const fileManagerIdx = runningApps.indexOf(fileManagerApp);
- if (fileManagerIdx > -1 && fileManagerApp?.state !== Shell.AppState.RUNNING)
- runningApps.splice(fileManagerIdx, 1);
-
- return [...runningApps, ...locationApps].sort(Utils.shellAppCompare);
- /* eslint-enable no-invalid-this */
- },
- ],
- [
- Shell.WindowTracker.prototype, 'get_window_app',
- function (originalMethod, window) {
- /* eslint-disable no-invalid-this */
- const locationApp = Locations.getRunningApps().find(a =>
- a.get_windows().includes(window));
- return locationApp ?? originalMethod.call(this, window);
- /* eslint-enable no-invalid-this */
- },
- ],
- [
- Shell.WindowTracker.prototype, 'get_app_from_pid',
- function (originalMethod, pid) {
- /* eslint-disable no-invalid-this */
- const locationApp = Locations.getRunningApps().find(a =>
- a.get_pids().includes(pid));
- return locationApp ?? originalMethod.call(this, pid);
- /* eslint-enable no-invalid-this */
- },
- ]);
-
- const {get: defaultFocusAppGetter} = Object.getOwnPropertyDescriptor(
- Shell.WindowTracker.prototype, 'focus_app');
- this._propertyInjections.addWithLabel(Labels.LOCATIONS,
- Shell.WindowTracker.prototype, 'focus_app', {
- get() {
- const locationApp = Locations.getRunningApps().find(a => a.isFocused);
- return locationApp ?? defaultFocusAppGetter.call(this);
- },
- });
- }
- }
- }
-
- _toggle() {
- if (this._toggleLater)
- return;
-
- this._toggleLater = Utils.laterAdd(Meta.LaterType.BEFORE_REDRAW, () => {
- delete this._toggleLater;
- this._restoreDash();
- this._deleteDocks();
- this._createDocks();
- this.emit('toggled');
- });
- }
-
- _mapExternalSetting(settings, key, mappedKey, mapValueFunction) {
- const camelMappedKey = mappedKey.replace(/-([a-z\d])/g, k => k[1].toUpperCase());
-
- const dockPropertyDesc = Object.getOwnPropertyDescriptor(this.settings, camelMappedKey);
-
- if (!dockPropertyDesc)
- throw new Error('Setting %s not found in dock'.format(mappedKey));
-
- const mappedValue = () => mapValueFunction(settings.get_value(key).recursiveUnpack());
- Object.defineProperty(this.settings, camelMappedKey, {
- get: () => mappedValue() ?? dockPropertyDesc.value,
- set: value => {
- if (mappedValue())
- dockPropertyDesc.value = value;
- },
- });
-
- this._signalsHandler.addWithLabel(Labels.SETTINGS, settings,
- 'changed::%s'.format(key), () => {
- this._signalsHandler.blockWithLabel(Labels.SETTINGS);
- this.settings.emit('changed::%s'.format(mappedKey), mappedKey);
- this._signalsHandler.unblockWithLabel(Labels.SETTINGS);
- });
- }
-
- _mapSettingsValues() {
- this.settings.settingsSchema.list_keys().forEach(key => {
- const camelKey = key.replace(/-([a-z\d])/g, k => k[1].toUpperCase());
- const updateSetting = () => {
- const schemaKey = this.settings.settingsSchema.get_key(key);
- if (schemaKey.get_range().deepUnpack()[0] === 'enum')
- this.settings[camelKey] = this.settings.get_enum(key);
- else
- this.settings[camelKey] = this.settings.get_value(key).recursiveUnpack();
- };
- updateSetting();
- this._signalsHandler.addWithLabel(Labels.SETTINGS, this.settings,
- `changed::${key}`, updateSetting);
- if (key !== camelKey) {
- Object.defineProperty(this.settings, key,
- {get: () => this.settings[camelKey]});
- }
- });
- Object.defineProperties(this.settings, {
- dockExtended: {get: () => this.settings.extendHeight},
- });
- }
-
- _bindSettingsChanges() {
- // Connect relevant signals to the toggling function
- this._signalsHandler.addWithLabel(Labels.SETTINGS, [
- Utils.getMonitorManager(),
- 'monitors-changed',
- this._toggle.bind(this),
- ], [
- Main.sessionMode,
- 'updated',
- this._toggle.bind(this),
- ], [
- this._settings,
- 'changed::multi-monitor',
- this._toggle.bind(this),
- ], [
- this._settings,
- 'changed::preferred-monitor',
- this._toggle.bind(this),
- ], [
- this._settings,
- 'changed::preferred-monitor-by-connector',
- this._toggle.bind(this),
- ], [
- this._settings,
- 'changed::dock-position',
- this._toggle.bind(this),
- ], [
- this._settings,
- 'changed::extend-height',
- () => this._adjustPanelCorners(),
- ], [
- this._settings,
- 'changed::dock-fixed',
- () => this._adjustPanelCorners(),
- ], [
- this._settings,
- 'changed::show-trash',
- () => this._ensureLocations(),
- ], [
- this._settings,
- 'changed::show-mounts',
- () => this._ensureLocations(),
- ], [
- this._settings,
- 'changed::isolate-locations',
- () => this._ensureLocations(),
- ], [
- this._settings,
- 'changed::intellihide',
- () => {
- if (!this._settings.intellihide)
- this._desktopIconsUsableArea.resetMargins();
- },
- ]);
-
- this._mapExternalSetting(this._appSwitcherSettings, 'current-workspace-only',
- 'isolate-workspaces', value => value || undefined);
- }
-
- _createDocks() {
- // If there are no monitors (headless configurations, but it can also
- // happen temporary while disconnecting and reconnecting monitors), just
- // do nothing. When a monitor will be connected we we'll be notified and
- // and thus create the docks. This prevents pointing trying to access
- // monitors throughout the code, were we are assuming that at least the
- // primary monitor is present.
- if (Main.layoutManager.monitors.length <= 0)
- return;
-
-
- this._preferredMonitorIndex = this.settings.preferredMonitor;
- if (this._preferredMonitorIndex === -2) {
- const monitorManager = Utils.getMonitorManager();
- this._preferredMonitorIndex = monitorManager.get_monitor_for_connector(
- this.settings.preferredMonitorByConnector);
- } else if (this._preferredMonitorIndex >= 0) {
- // Primary monitor used to be always 0 in Gdk, but the shell has a different
- // concept (where the order depends on mutter order).
- // So even if now the extension settings may use the same logic of the shell
- // we prefer not to break the previously configured systems, and so we still
- // assume that the gsettings monitor numbering follows the old strategy.
- // This ensure the indexing in the settings and in the shell are matched,
- // i.e. that we start counting from the primaryMonitorIndex
- this._preferredMonitorIndex =
- (Main.layoutManager.primaryIndex + this._preferredMonitorIndex) %
- Main.layoutManager.monitors.length;
- }
-
- // In case of multi-monitor, we consider the dock on the primary monitor
- // to be the preferred (main) one regardless of the settings the dock
- // goes on the primary monitor also if the settings are inconsistent
- // (e.g. desired monitor not connected).
- if (this.settings.multiMonitor ||
- this._preferredMonitorIndex < 0 ||
- this._preferredMonitorIndex > Main.layoutManager.monitors.length - 1)
- this._preferredMonitorIndex = Main.layoutManager.primaryIndex;
-
-
- // First we create the main Dock, to get the extra features to bind to this one
- let dock = new DockedDash({
- monitorIndex: this._preferredMonitorIndex,
- isMain: true,
- });
- this._allDocks.push(dock);
-
- // connect app icon into the view selector
- dock.dash.showAppsButton.connect('notify::checked',
- this._onShowAppsButtonToggled.bind(this));
-
- // Make the necessary changes to Main.overview.dash
- this._prepareMainDash();
-
- // Adjust corners if necessary
- this._adjustPanelCorners();
-
- if (this.settings.multiMonitor) {
- const nMon = Main.layoutManager.monitors.length;
- for (let iMon = 0; iMon < nMon; iMon++) {
- if (iMon === this._preferredMonitorIndex)
- continue;
- dock = new DockedDash({monitorIndex: iMon});
- this._allDocks.push(dock);
- // connect app icon into the view selector
- dock.dash.showAppsButton.connect('notify::checked',
- this._onShowAppsButtonToggled.bind(this));
- }
- }
-
- // Load optional features. We load *after* the docks are created, since
- // we need to connect the signals to all dock instances.
- this._workspaceIsolation = new WorkspaceIsolation();
- this._keyboardShortcuts = new KeyboardShortcuts();
-
- this.emit('docks-ready');
- }
-
- _prepareStartupAnimation() {
- DockManager.allDocks.forEach(dock => {
- const {dash} = dock;
-
- dock.opacity = 255;
- dash.set({
- opacity: 0,
- translation_x: 0,
- translation_y: 0,
- });
- });
- }
-
- _runStartupAnimation() {
- DockManager.allDocks.forEach(dock => {
- const {dash} = dock;
-
- switch (dock.position) {
- case St.Side.LEFT:
- dash.translation_x = -dash.width;
- break;
- case St.Side.RIGHT:
- dash.translation_x = dash.width;
- break;
- case St.Side.BOTTOM:
- dash.translation_y = dash.height;
- break;
- case St.Side.TOP:
- dash.translation_y = -dash.height;
- break;
- }
-
- dash.ease({
- opacity: 255,
- translation_x: 0,
- translation_y: 0,
- duration: STARTUP_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
- });
- }
-
- _prepareMainDash() {
- // Ensure Main.overview.dash is set to our dash in dummy mode
- // while just use the default getter otherwise.
- // The getter must be dynamic and not set only when we've a dummy
- // overview because the mode can change dynamically.
- this._propertyInjections.removeWithLabel(Labels.MAIN_DASH);
- const defaultDashGetter = Object.getOwnPropertyDescriptor(
- Main.overview.constructor.prototype, 'dash').get;
- this._propertyInjections.addWithLabel(Labels.MAIN_DASH, Main.overview, 'dash', {
- get: () => Main.overview.isDummy
- ? this.mainDock.dash : defaultDashGetter.call(Main.overview),
- });
-
- if (Main.overview.isDummy)
- return;
-
- // Hide usual Dash
- this._oldDash.hide();
-
- // Also set dash width to 1, so it's almost not taken into account by code
- // calculating the reserved space in the overview. The reason to keep it at 1 is
- // to allow its visibility change to trigger an allocation of the appGrid which
- // in turn is triggering the appsIcon spring animation, required when no other
- // actors has this effect, i.e in horizontal mode and without the workspaceThumbnails
- // 1 static workspace only)
- this._oldDash.set_height(1);
-
- this._signalsHandler.addWithLabel(Labels.OLD_DASH_CHANGES, [
- this._oldDash,
- 'notify::visible',
- () => this._oldDash.hide(),
- ], [
- this._oldDash,
- 'notify::height',
- () => this._oldDash.set_height(1),
- ]);
-
- // Pretend I'm the dash: meant to make app grid swarm animation come from
- // the right position of the appShowButton.
- this.overviewControls.dash = this.mainDock.dash;
- this.searchController._showAppsButton = this.mainDock.dash.showAppsButton;
-
- // We also need to ignore max-size changes
- this._methodInjections.addWithLabel(Labels.MAIN_DASH, this._oldDash,
- 'setMaxSize', () => {});
- this._methodInjections.addWithLabel(Labels.MAIN_DASH, this._oldDash,
- 'allocate', () => {});
- // And to return the preferred height depending on the state
- this._methodInjections.addWithLabel(Labels.MAIN_DASH, this._oldDash,
- 'get_preferred_height', (_originalMethod, ...args) => {
- if (this.mainDock.isHorizontal && !this.settings.dockFixed)
- return this.mainDock.get_preferred_height(...args);
- return [0, 0];
- });
-
- // FIXME: https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2890
- // const { ControlsManagerLayout } = OverviewControls;
- const ControlsManagerLayout = this.overviewControls.layout_manager.constructor;
-
- const maybeAdjustBoxSize = (state, box, spacing) => {
- // ensure that an undefined value will be converted into a valid one
- spacing = spacing ?? 0;
-
- if (state === OverviewControls.ControlsState.WINDOW_PICKER) {
- const searchBox = this.overviewControls._searchEntry.get_allocation_box();
- const {shouldShow: wsThumbnails} = this.overviewControls._thumbnailsBox;
-
- if (!wsThumbnails) {
- box.y1 += spacing;
- box.y2 -= spacing;
- }
-
- box.y2 -= searchBox.get_height() + 2 * spacing;
- }
-
- return box;
- };
-
- const maybeAdjustBoxToDock = (state, box, spacing) => {
- maybeAdjustBoxSize(state, box, spacing);
-
- if (this.mainDock.isHorizontal || this.settings.dockFixed)
- return box;
-
- const [, preferredWidth] = this.mainDock.get_preferred_width(
- box.get_height());
-
- if (this.mainDock.position === St.Side.LEFT)
- box.x1 += preferredWidth;
- else if (this.mainDock.position === St.Side.RIGHT)
- box.x2 -= preferredWidth;
-
- return box;
- };
-
- this._vfuncInjections.addWithLabel(Labels.MAIN_DASH, ControlsManagerLayout.prototype,
- 'allocate', function (container) {
- /* eslint-disable no-invalid-this */
- const oldPostAllocation = this._runPostAllocation;
- this._runPostAllocation = () => {};
-
- const monitor = Main.layoutManager.findMonitorForActor(container);
- const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index);
- const startX = workArea.x - monitor.x;
- const startY = workArea.y - monitor.y;
- const workAreaBox = new Clutter.ActorBox();
- workAreaBox.set_origin(startX, startY);
- workAreaBox.set_size(workArea.width, workArea.height);
-
- // GNOME 46 changes "spacing" to "_spacing".
- const spacing = this.spacing ?? this._spacing;
-
- maybeAdjustBoxToDock(undefined, workAreaBox, spacing);
- const oldStartY = workAreaBox.y1;
-
- const propertyInjections = new Utils.PropertyInjectionsHandler();
- propertyInjections.add(Main.layoutManager.panelBox, 'height', {value: startY});
-
- if (Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y)
- workAreaBox.y1 -= oldStartY;
-
- this.vfunc_allocate(container, workAreaBox);
-
- propertyInjections.destroy();
- workAreaBox.y1 = oldStartY;
-
- const adjustActorHorizontalAllocation = actor => {
- if (!actor.visible || !workAreaBox.x1)
- return;
-
- const contentBox = actor.get_allocation_box();
- contentBox.set_size(workAreaBox.get_width(), contentBox.get_height());
- contentBox.set_origin(workAreaBox.x1, contentBox.y1);
- actor.allocate(contentBox);
- };
-
- [this._searchEntry, this._workspacesThumbnails, this._searchController].forEach(
- actor => adjustActorHorizontalAllocation(actor));
-
- this._runPostAllocation = oldPostAllocation;
- this._runPostAllocation();
- /* eslint-enable no-invalid-this */
- });
-
- /**
- * This can be removed or bypassed when GNOME/gnome-shell!1892 will be merged
- *
- * @param originalFunction
- * @param state
- * @param workAreaBox
- * @param {...any} args
- */
- function workspaceBoxOriginFixer(originalFunction, state, workAreaBox, ...args) {
- /* eslint-disable no-invalid-this */
- const workspaceBox = originalFunction.call(this, state, workAreaBox, ...args);
- workspaceBox.set_origin(workAreaBox.x1, workspaceBox.y1);
- return workspaceBox;
- /* eslint-enable no-invalid-this */
- }
-
- this._methodInjections.addWithLabel(Labels.MAIN_DASH, [
- ControlsManagerLayout.prototype,
- '_computeWorkspacesBoxForState',
- function (originalFunction, state, ...args) {
- /* eslint-disable no-invalid-this */
- if (state === OverviewControls.ControlsState.HIDDEN)
- return originalFunction.call(this, state, ...args);
-
- const box = workspaceBoxOriginFixer.call(this, originalFunction, state, ...args);
- // GNOME 46 changes "spacing" to "_spacing".
- const spacing = this.spacing ?? this._spacing;
- const dock = DockManager.getDefault().getDockByMonitor(Main.layoutManager.primaryIndex);
- if (!dock)
- return box;
- else
- return maybeAdjustBoxSize(state, box, spacing);
- /* eslint-enable no-invalid-this */
- },
- ], [
- WorkspacesView.SecondaryMonitorDisplay.prototype,
- '_getWorkspacesBoxForState',
- function (originalFunction, state, ...args) {
- /* eslint-disable no-invalid-this */
- if (state === OverviewControls.ControlsState.HIDDEN)
- return originalFunction.call(this, state, ...args);
-
- const box = workspaceBoxOriginFixer.call(this, originalFunction, state, ...args);
- const dock = DockManager.getDefault().getDockByMonitor(this._monitorIndex);
- if (!dock)
- return box;
- if (state === OverviewControls.ControlsState.WINDOW_PICKER &&
- dock.position === St.Side.BOTTOM) {
- const [, preferredHeight] = dock.get_preferred_height(box.get_width());
- box.y2 -= preferredHeight;
- }
- return box;
- /* eslint-enable no-invalid-this */
- },
- ], [
- ControlsManagerLayout.prototype,
- '_getAppDisplayBoxForState',
- function (originalFunction, ...args) {
- /* eslint-disable no-invalid-this */
- return workspaceBoxOriginFixer.call(this, originalFunction, ...args);
- /* eslint-enable no-invalid-this */
- },
- ]);
-
- this._vfuncInjections.addWithLabel(Labels.MAIN_DASH, Workspace.WorkspaceBackground.prototype,
- 'allocate', function (box) {
- /* eslint-disable no-invalid-this */
- this.vfunc_allocate(box);
-
- // This code has been submitted upstream via GNOME/gnome-shell!1892
- // so can be removed when that gets merged (or bypassed on newer shell
- // versions).
- const monitor = Main.layoutManager.monitors[this._monitorIndex];
- const [contentWidth, contentHeight] = this._bin.get_content_box().get_size();
- const [mX1, mX2] = [monitor.x, monitor.x + monitor.width];
- const [mY1, mY2] = [monitor.y, monitor.y + monitor.height];
- const [wX1, wX2] = [this._workarea.x, this._workarea.x + this._workarea.width];
- const [wY1, wY2] = [this._workarea.y, this._workarea.y + this._workarea.height];
- const xScale = contentWidth / this._workarea.width;
- const yScale = contentHeight / this._workarea.height;
- const leftOffset = wX1 - mX1;
- const topOffset = wY1 - mY1;
- const rightOffset = mX2 - wX2;
- const bottomOffset = mY2 - wY2;
-
- const contentBox = new Clutter.ActorBox();
- contentBox.set_origin(-leftOffset * xScale, -topOffset * yScale);
- contentBox.set_size(
- contentWidth + (leftOffset + rightOffset) * xScale,
- contentHeight + (topOffset + bottomOffset) * yScale);
-
- this._backgroundGroup.allocate(contentBox);
- /* eslint-enable no-invalid-this */
- });
-
- // Reduce the space that the workspaces can use in secondary monitors
- this._methodInjections.addWithLabel(Labels.MAIN_DASH, WorkspacesView.WorkspacesView.prototype,
- '_getFirstFitAllWorkspaceBox', function (originalFunction, ...args) {
- /* eslint-disable no-invalid-this */
- const box = originalFunction.call(this, ...args);
- if (DockManager.settings.dockFixed ||
- this._monitorIndex === Main.layoutManager.primaryIndex)
- return box;
-
- const dock = DockManager.getDefault().getDockByMonitor(this._monitorIndex);
- if (!dock)
- return box;
-
- if (dock.isHorizontal) {
- const [, preferredHeight] = dock.get_preferred_height(box.get_width());
- box.y2 -= preferredHeight;
- if (dock.position === St.Side.TOP)
- box.set_origin(box.x1, box.y1 + preferredHeight);
- } else {
- const [, preferredWidth] = dock.get_preferred_width(box.get_height());
- box.x2 -= preferredWidth / 2;
- if (dock.position === St.Side.LEFT)
- box.set_origin(box.x1 + preferredWidth, box.y1);
- }
- return box;
- /* eslint-enable no-invalid-this */
- });
-
- if (AppDisplay.BaseAppView?.prototype?._pageForCoords) {
- // Ensure we handle Dnd events happening on the dock when we're
- // dragging from AppDisplay.
- // Remove when merged
- // https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2002
- this._methodInjections.addWithLabel(Labels.MAIN_DASH,
- AppDisplay.BaseAppView.prototype,
- '_pageForCoords', function (originalFunction, ...args) {
- /* eslint-disable no-invalid-this */
- if (!this._scrollView.has_pointer)
- return AppDisplay.SidePages.NONE;
- return originalFunction.call(this, ...args);
- /* eslint-enable no-invalid-this */
- });
- }
-
- if (Main.layoutManager._startingUp) {
- this._prepareStartupAnimation();
-
- const hadOverview = Main.sessionMode.hasOverview;
-
- // Convince LayoutManager to use the legacy startup animation:
- // Reset overview controls state to HIDDEN, as skipping the startup
- // overview leaves it stuck at WINDOW_PICKER
- if (this._settings.disableOverviewOnStartup) {
- Main.sessionMode.hasOverview = false;
- Main.overview._overview.controls._stateAdjustment.value =
- OverviewControls.ControlsState.HIDDEN;
- }
-
- this._signalsHandler.addWithLabel(Labels.STARTUP_ANIMATION,
- Main.layoutManager, 'startup-complete', () => {
- this._signalsHandler.removeWithLabel(Labels.STARTUP_ANIMATION);
- Main.sessionMode.hasOverview = hadOverview;
- this._runStartupAnimation();
- });
- }
- }
-
- _deleteDocks() {
- if (!this._allDocks.length)
- return;
-
- // Remove extra features
- this._workspaceIsolation.destroy();
- this._keyboardShortcuts.destroy();
- this._desktopIconsUsableArea.resetMargins();
-
- // Delete all docks
- this._allDocks.forEach(d => d.destroy());
- this._allDocks = [];
-
- this.emit('docks-destroyed');
- }
-
- _restoreDash() {
- if (!this._oldDash)
- return;
-
- this._signalsHandler.removeWithLabel(Labels.OLD_DASH_CHANGES);
- [this._methodInjections, this._vfuncInjections, this._propertyInjections].forEach(
- injections => injections.removeWithLabel(Labels.MAIN_DASH));
-
- this.overviewControls.layout_manager._dash = this._oldDash;
- this.overviewControls.dash = this._oldDash;
- this.searchController._showAppsButton = this._oldDash.showAppsButton;
- Main.overview.dash.show();
- Main.overview.dash.set_height(-1); // reset default dash size
- // This force the recalculation of the icon size
- Main.overview.dash._maxHeight = -1;
- }
-
- get overviewControls() {
- return Main.overview._overview.controls;
- }
-
- get searchController() {
- return this.overviewControls._searchController;
- }
-
- _onShowAppsButtonToggled(button) {
- const {checked} = button;
- const {overviewControls} = this;
-
- if (!Main.overview.visible) {
- this.mainDock.dash.showAppsButton._fromDesktop = true;
- Main.overview.show(OverviewControls.ControlsState.APP_GRID);
- } else if (!checked && this.mainDock.dash.showAppsButton._fromDesktop) {
- Main.overview.hide();
- this.mainDock.dash.showAppsButton._fromDesktop = false;
- } else {
- // TODO: I'm not sure how reliable this is, we might need to move the
- // _onShowAppsButtonToggled logic into the extension.
- if (!checked)
- this.mainDock.dash.showAppsButton._fromDesktop = false;
-
-
- // Instead of "syncing" the stock button, let's call its callback directly.
- overviewControls._onShowAppsButtonToggled();
- }
-
- // Because we "disconnected" from the search controller, we have to manage its state.
- this.searchController._setSearchActive(false);
- }
-
- _overrideAppMenus() {
- this._methodInjections.add(AppMenu.AppMenu.prototype,
- '_updateFavoriteItem', function (originalFunction, ...args) {
- /* eslint-disable no-invalid-this */
- originalFunction.call(this, ...args);
- if (!this._toggleFavoriteItem.visible)
- return;
-
- const {id} = this._app;
- this._toggleFavoriteItem.label.text = this._appFavorites.isFavorite(id)
- ? _('Unpin') : __('Pin to Dock');
- /* eslint-enable no-invalid-this */
- });
- }
-
- destroy() {
- this.emit('destroy');
- if (this._toggleLater) {
- Utils.laterRemove(this._toggleLater);
- delete this._toggleLater;
- }
- this._restoreDash();
- this._deleteDocks();
- this._revertPanelCorners();
- if (this._oldSelectorMargin)
- this.searchController.margin_bottom = this._oldSelectorMargin;
- if (this._fm1Client) {
- this._fm1Client.destroy();
- this._fm1Client = null;
- }
- this._notificationsMonitor.destroy();
- this._appSpread.destroy();
- this._trash?.destroy();
- this._trash = null;
- Locations.unWrapFileManagerApp();
- this._removables?.destroy();
- this._removables = null;
- this._iconTheme = null;
- this._remoteModel?.destroy();
- this._appIconsDecorator?.destroy();
- this._settings = null;
- this._appSwitcherSettings = null;
- this._oldDash = null;
-
- this._desktopIconsUsableArea?.destroy();
- this._desktopIconsUsableArea = null;
- this._extension = null;
- DockManager._singleton = null;
- }
-
- /**
- * Adjust Panel corners, remove this when 41 won't be supported anymore
- */
- _adjustPanelCorners() {
- if (!this._hasPanelCorners())
- return;
-
- const position = Utils.getPosition();
- const isHorizontal = (position === St.Side.TOP) || (position === St.Side.BOTTOM);
- const dockOnPrimary = this._settings.multiMonitor ||
- this._preferredMonitorIndex === Main.layoutManager.primaryIndex;
-
- if (!isHorizontal && dockOnPrimary && this.settings.dockExtended && this.settings.dockFixed) {
- Main.panel._rightCorner.hide();
- Main.panel._leftCorner.hide();
- } else {
- this._revertPanelCorners();
- }
- }
-
- _revertPanelCorners() {
- if (!this._hasPanelCorners())
- return;
-
- Main.panel._leftCorner.show();
- Main.panel._rightCorner.show();
- }
-
- _hasPanelCorners() {
- return !!Main.panel?._rightCorner && !!Main.panel?._leftCorner;
- }
-}
-Signals.addSignalMethods(DockManager.prototype);
-
-// This class drives long-running icon animations, to keep them running in sync
-// with each other, and to save CPU by pausing them when the dock is hidden.
-export class IconAnimator {
- constructor(actor) {
- this._count = 0;
- this._started = false;
- this._animations = {
- wiggle: [],
- };
- this._timeline = new Clutter.Timeline({
- duration: AnimationUtils.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1,
- repeat_count: -1,
- actor,
- });
-
- this._updateSettings();
- this._settingsChangedId = St.Settings.get().connect('notify',
- () => this._updateSettings());
-
- this._timeline.connect('new-frame', () => {
- const progress = this._timeline.get_progress();
- const wiggleRotation = progress < 1 / 6 ? 15 * Math.sin(progress * 24 * Math.PI) : 0;
- const wigglers = this._animations.wiggle;
- for (let i = 0, iMax = wigglers.length; i < iMax; i++)
- wigglers[i].target.rotation_angle_z = wiggleRotation;
- });
- }
-
- _updateSettings() {
- this._timeline.set_duration(
- AnimationUtils.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1);
- }
-
- destroy() {
- St.Settings.get().disconnect(this._settingsChangedId);
- this._timeline.stop();
- this._timeline = null;
- for (const pairs of Object.values(this._animations)) {
- for (let i = 0, iMax = pairs.length; i < iMax; i++) {
- const pair = pairs[i];
- pair.target.disconnect(pair.targetDestroyId);
- }
- }
- this._animations = null;
- }
-
- pause() {
- if (this._started && this._count > 0)
- this._timeline.stop();
-
- this._started = false;
- }
-
- start() {
- if (!this._started && this._count > 0)
- this._timeline.start();
-
- this._started = true;
- }
-
- addAnimation(target, name) {
- const targetDestroyId = target.connect('destroy',
- () => this.removeAnimation(target, name));
- this._animations[name].push({target, targetDestroyId});
- if (this._started && this._count === 0)
- this._timeline.start();
-
- this._count++;
- }
-
- removeAnimation(target, name) {
- const pairs = this._animations[name];
- for (let i = 0, iMax = pairs.length; i < iMax; i++) {
- const pair = pairs[i];
- if (pair.target === target) {
- target.disconnect(pair.targetDestroyId);
- pairs.splice(i, 1);
- this._count--;
- if (this._started && this._count === 0)
- this._timeline.stop();
-
- return;
- }
- }
- }
-}