From 3623291d6f3d028a401b30bce6059a1d18e69f85 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 14 Jul 2026 16:56:08 +0800 Subject: [PATCH 1/4] fix invisible dock edge hitbox --- autohide.js | 9 +++++++++ dock.js | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/autohide.js b/autohide.js index d47d6a7..6c8f478 100644 --- a/autohide.js +++ b/autohide.js @@ -26,12 +26,19 @@ const handledWindowTypes = [ ]; export let AutoHide = class { + _setDwellActive(active) { + if (this.dock.dwell) { + this.dock.dwell.reactive = active; + } + } + enable() { if (this._enabled) return; // console.log('enable autohide'); this._enabled = true; this._shown = true; this._dwell = 0; + this._setDwellActive(false); console.log('autohide enabled'); } @@ -149,6 +156,7 @@ export let AutoHide = class { this._dwell = 0; this.frameDelay = 0; this._shown = true; + this._setDwellActive(false); this.dock.slideIn(); } @@ -156,6 +164,7 @@ export let AutoHide = class { this._dwell = 0; this.frameDelay = 10; this._shown = false; + this._setDwellActive(true); this.dock.slideOut(); } diff --git a/dock.js b/dock.js index d3202ad..62fcd8f 100644 --- a/dock.js +++ b/dock.js @@ -126,7 +126,10 @@ export let Dock = GObject.registerClass( }); this.dwell = new St.Widget({ name: 'DockDwell', - reactive: true, + // The edge sensor is activated by AutoHide only while the dock is + // hidden. Leaving it reactive while the dock is shown intercepts + // clicks in the space vacated by a floating dock on Wayland. + reactive: false, track_hover: true, offscreen_redirect: Clutter.OffscreenRedirect.ALWAYS, }); @@ -426,9 +429,15 @@ export let Dock = GObject.registerClass( this._updateIconEffect(); + // GNOME 50 removed affectsInputRegion from addChrome(). On older + // releases it must remain disabled for the dock's animation container; + // otherwise its larger allocation becomes an invisible input region on + // X11 and blocks clicks around a floating dock. + const hasAffectsInputRegion = Config.PACKAGE_VERSION[0] == '4'; + Main.layoutManager.addChrome(this.struts, { affectsStruts: !this.extension.autohide_dash, - ...(Config.PACKAGE_VERSION[0] == '4' + ...(hasAffectsInputRegion ? { affectsInputRegion: true } : {}), trackFullscreen: false, @@ -436,13 +445,17 @@ export let Dock = GObject.registerClass( Main.layoutManager.addChrome(this, { affectsStruts: false, - // affectsInputRegion: false, + ...(hasAffectsInputRegion + ? { affectsInputRegion: false } + : {}), trackFullscreen: true, }); Main.layoutManager.addChrome(this.dwell, { affectsStruts: false, - // affectsInputRegion: false, + ...(hasAffectsInputRegion + ? { affectsInputRegion: false } + : {}), trackFullscreen: false, }); From 31394dd71928f479e58502817a919971b757757c Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Wed, 15 Jul 2026 21:53:20 +0800 Subject: [PATCH 2/4] keep dwell sensor in sync with dock visibility --- autohide.js | 12 +++++++++--- dock.js | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/autohide.js b/autohide.js index 6c8f478..72433e7 100644 --- a/autohide.js +++ b/autohide.js @@ -32,13 +32,20 @@ export let AutoHide = class { } } + _syncDwellActive() { + // The sensor must follow the dock's actual visibility, rather than the + // last requested transition. slideOut() can decline to hide while a + // flyout is open. + this._setDwellActive(this._enabled && this.dock._hidden); + } + enable() { if (this._enabled) return; // console.log('enable autohide'); this._enabled = true; this._shown = true; this._dwell = 0; - this._setDwellActive(false); + this._syncDwellActive(); console.log('autohide enabled'); } @@ -51,6 +58,7 @@ export let AutoHide = class { this.show(); this._enabled = false; + this._syncDwellActive(); let actors = global.get_window_actors(); let windows = actors.map((a) => a.get_meta_window()); @@ -156,7 +164,6 @@ export let AutoHide = class { this._dwell = 0; this.frameDelay = 0; this._shown = true; - this._setDwellActive(false); this.dock.slideIn(); } @@ -164,7 +171,6 @@ export let AutoHide = class { this._dwell = 0; this.frameDelay = 10; this._shown = false; - this._setDwellActive(true); this.dock.slideOut(); } diff --git a/dock.js b/dock.js index 62fcd8f..2fba0fe 100644 --- a/dock.js +++ b/dock.js @@ -341,16 +341,19 @@ export let Dock = GObject.registerClass( this._hidden = false; this._beginAnimation(); } + this.autohider._syncDwellActive(); } slideOut() { if (this._list && this._list.visible) { + this.autohider._syncDwellActive(); return; } if (!this._hidden) { this._hidden = true; this._beginAnimation(); } + this.autohider._syncDwellActive(); } getMonitor() { From 79c7e8bdd99cb463ba85c10409dcdfe23ea40107 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 16 Jul 2026 13:47:10 +0800 Subject: [PATCH 3/4] replace dwell hitbox with pointer barrier --- autohide.js | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++- dock.js | 1 + 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/autohide.js b/autohide.js index 72433e7..42cafb7 100644 --- a/autohide.js +++ b/autohide.js @@ -12,6 +12,7 @@ import { const DEBOUNCE_HIDE_TIMEOUT = 120; const PRESSURE_SENSE_DISTANCE = 40; +const PRESSURE_SENSE_TIMEOUT = 1000; // some codes lifted from dash-to-dock intellihide const handledWindowTypes = [ @@ -26,9 +27,124 @@ const handledWindowTypes = [ ]; export let AutoHide = class { + _supportsPointerBarriers() { + return ( + global.backend.capabilities & Meta.BackendCapabilities.BARRIERS + ); + } + + _destroyBarrier() { + if (this._barrier) { + this._barrier.destroy(); + this._barrier = null; + } + this._barrierGeometry = null; + this._barrierPressure = 0; + this._lastBarrierTime = 0; + } + + _barrierParams() { + let monitor = this.dock._monitor; + if (!monitor) return null; + + let params = { backend: global.backend }; + switch (this.dock._position) { + case DockPosition.LEFT: + Object.assign(params, { + x1: monitor.x, + x2: monitor.x, + y1: monitor.y, + y2: monitor.y + monitor.height, + directions: Meta.BarrierDirection.NEGATIVE_X, + }); + break; + case DockPosition.RIGHT: + Object.assign(params, { + x1: monitor.x + monitor.width, + x2: monitor.x + monitor.width, + y1: monitor.y, + y2: monitor.y + monitor.height, + directions: Meta.BarrierDirection.POSITIVE_X, + }); + break; + case DockPosition.TOP: + Object.assign(params, { + x1: monitor.x, + x2: monitor.x + monitor.width, + y1: monitor.y, + y2: monitor.y, + directions: Meta.BarrierDirection.NEGATIVE_Y, + }); + break; + default: + Object.assign(params, { + x1: monitor.x, + x2: monitor.x + monitor.width, + y1: monitor.y + monitor.height, + y2: monitor.y + monitor.height, + directions: Meta.BarrierDirection.POSITIVE_Y, + }); + break; + } + return params; + } + + _onBarrierHit(event) { + if (!this._enabled || this._shown) return; + if (!this.extension.pressure_sense) { + this.show(); + return; + } + + if (event.time - this._lastBarrierTime > PRESSURE_SENSE_TIMEOUT) { + this._barrierPressure = 0; + } + this._lastBarrierTime = event.time; + + let distance = this.dock.isVertical() + ? Math.abs(event.dx) + : Math.abs(event.dy); + this._barrierPressure += Math.min(15, distance); + + let threshold = + 100 - 80 * (this.extension.pressure_sense_sensitivity || 0); + if (this._barrierPressure >= threshold) { + this.show(); + } + } + + _updateBarrier() { + let params = this._barrierParams(); + if (!params) return; + + let geometry = [ + params.x1, + params.y1, + params.x2, + params.y2, + params.directions, + ].join(':'); + if (geometry == this._barrierGeometry) return; + + this._destroyBarrier(); + this._barrier = new Meta.Barrier(params); + this._barrier.connect('hit', (barrier, event) => { + this._onBarrierHit(event); + }); + this._barrierGeometry = geometry; + } + _setDwellActive(active) { if (this.dock.dwell) { - this.dock.dwell.reactive = active; + // Pointer barriers detect the screen edge without becoming a Clutter + // pick target, so clicks continue through to application windows. + this.dock.dwell.reactive = active && !this._supportsPointerBarriers(); + } + + if (!this._supportsPointerBarriers() || !active) { + this._destroyBarrier(); + } else { + this._updateBarrier(); } } diff --git a/dock.js b/dock.js index 2fba0fe..34ba075 100644 --- a/dock.js +++ b/dock.js @@ -1186,6 +1186,7 @@ export let Dock = GObject.registerClass( this.dwell.y = this.y; } } + this.autohider._syncDwellActive(); return true; } From 33e4a14406c1dff91a89a84b799f4e44333bbe21 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 16 Jul 2026 14:49:23 +0800 Subject: [PATCH 4/4] keep dock container non-reactive --- dock.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dock.js b/dock.js index 34ba075..b6230ad 100644 --- a/dock.js +++ b/dock.js @@ -67,6 +67,14 @@ export let Dock = GObject.registerClass( offscreen_redirect: Clutter.OffscreenRedirect.ALWAYS, }); + // Some extensions identify Dash-to-Dock by this actor's compatibility + // name and force it reactive after temporarily hiding it. The container + // covers the dock's full animation area, so that turns it into a large + // invisible input blocker. Its interactive children remain reactive. + this.connect('notify::reactive', () => { + if (this.reactive) this.reactive = false; + }); + this.extension = params.extension; this._alignment = DockAlignment.CENTER;