mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-18 09:14:01 -04:00
fix(shell): re-commit layer surfaces on screen reconnect instead of rebuilding bars
This commit is contained in:
+1
-1
Submodule dank-qml-common updated: 720d750895...f61341cc12
@@ -0,0 +1,88 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property var log: Log.scoped("SurfaceRecovery")
|
||||
property var _windows: []
|
||||
|
||||
function track(window) {
|
||||
if (!window || _windows.includes(window))
|
||||
return;
|
||||
_windows = _windows.concat([window]);
|
||||
}
|
||||
|
||||
function untrack(window) {
|
||||
if (!_windows.includes(window))
|
||||
return;
|
||||
_windows = _windows.filter(w => w !== window);
|
||||
}
|
||||
|
||||
function freeEdge(window) {
|
||||
const a = window.anchors;
|
||||
if (!a.bottom)
|
||||
return "bottom";
|
||||
if (!a.top)
|
||||
return "top";
|
||||
if (!a.right)
|
||||
return "right";
|
||||
if (!a.left)
|
||||
return "left";
|
||||
return "";
|
||||
}
|
||||
|
||||
// wlr-layer-shell set_margin: "Setting this value for edges you are not anchored to has no effect"
|
||||
function refresh(window) {
|
||||
if (!window)
|
||||
return false;
|
||||
const edge = freeEdge(window);
|
||||
if (edge === "")
|
||||
return false;
|
||||
switch (edge) {
|
||||
case "bottom":
|
||||
window.margins.bottom = window.margins.bottom ? 0 : 1;
|
||||
break;
|
||||
case "top":
|
||||
window.margins.top = window.margins.top ? 0 : 1;
|
||||
break;
|
||||
case "right":
|
||||
window.margins.right = window.margins.right ? 0 : 1;
|
||||
break;
|
||||
case "left":
|
||||
window.margins.left = window.margins.left ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function refreshAll() {
|
||||
let refreshed = 0;
|
||||
for (const window of _windows) {
|
||||
if (refresh(window))
|
||||
refreshed++;
|
||||
}
|
||||
log.info("Refreshed", refreshed, "of", _windows.length, "layer surfaces");
|
||||
return refreshed;
|
||||
}
|
||||
|
||||
function fitsScreen(window) {
|
||||
if (!window?.screen || !window.visible)
|
||||
return true;
|
||||
if (window.width <= 0 || window.height <= 0)
|
||||
return false;
|
||||
const a = window.anchors;
|
||||
if (a.left && a.right && window.width > window.screen.width)
|
||||
return false;
|
||||
if (a.top && a.bottom && window.height > window.screen.height)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function staleWindows() {
|
||||
return _windows.filter(w => !fitsScreen(w));
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,14 @@ PanelWindow {
|
||||
|
||||
BackgroundEffect.blurRegion: body.blurRegion
|
||||
|
||||
Component.onCompleted: KeyboardFocus.registerBarWindow(barWindow)
|
||||
Component.onDestruction: KeyboardFocus.unregisterBarWindow(barWindow)
|
||||
Component.onCompleted: {
|
||||
KeyboardFocus.registerBarWindow(barWindow);
|
||||
SurfaceRecovery.track(barWindow);
|
||||
}
|
||||
Component.onDestruction: {
|
||||
KeyboardFocus.unregisterBarWindow(barWindow);
|
||||
SurfaceRecovery.untrack(barWindow);
|
||||
}
|
||||
|
||||
IdleInhibitor {
|
||||
window: barWindow
|
||||
|
||||
@@ -43,6 +43,9 @@ Variants {
|
||||
implicitHeight: body.surfaceImplicitHeight
|
||||
exclusiveZone: body.surfaceExclusiveZone
|
||||
|
||||
Component.onCompleted: SurfaceRecovery.track(dock)
|
||||
Component.onDestruction: SurfaceRecovery.untrack(dock)
|
||||
|
||||
WindowBlur {
|
||||
targetWindow: dock
|
||||
blurEnabled: body.effectiveBlurEnabled && !body.usesConnectedFrameChrome
|
||||
@@ -80,6 +83,9 @@ Variants {
|
||||
WlrLayershell.namespace: "dms:dock-exclusion"
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
|
||||
Component.onCompleted: SurfaceRecovery.track(dockExclusion)
|
||||
Component.onDestruction: SurfaceRecovery.untrack(dockExclusion)
|
||||
|
||||
anchors {
|
||||
top: !body.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true
|
||||
bottom: !body.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true
|
||||
|
||||
@@ -86,6 +86,7 @@ Scope {
|
||||
}
|
||||
|
||||
component EdgeExclusion: PanelWindow {
|
||||
id: edgeExclusion
|
||||
required property var targetScreen
|
||||
property real exclusionSize: SettingsData.frameThickness
|
||||
|
||||
@@ -103,6 +104,9 @@ Scope {
|
||||
implicitWidth: 1
|
||||
implicitHeight: 1
|
||||
|
||||
Component.onCompleted: SurfaceRecovery.track(edgeExclusion)
|
||||
Component.onDestruction: SurfaceRecovery.untrack(edgeExclusion)
|
||||
|
||||
anchors {
|
||||
top: anchorTop
|
||||
bottom: anchorBottom
|
||||
|
||||
@@ -226,6 +226,12 @@ Item {
|
||||
screenReconnectDebounce.restart();
|
||||
}
|
||||
|
||||
function refreshScreenSurfaces() {
|
||||
log.info("Refreshing layer surfaces, screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
||||
SurfaceRecovery.refreshAll();
|
||||
surfaceRefreshVerifyTimer.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: screenReconnectDebounce
|
||||
// Wide enough to collapse the output-remove + output-re-add pair that one
|
||||
@@ -236,15 +242,27 @@ Item {
|
||||
root._screenRecoveryCooldown = true;
|
||||
root._screenRecoveryPending = false;
|
||||
screenReconnectCooldown.restart();
|
||||
root.triggerSurfaceRecovery("screen-reconnect");
|
||||
root.refreshScreenSurfaces();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: surfaceRefreshVerifyTimer
|
||||
interval: 800
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
const stale = SurfaceRecovery.staleWindows();
|
||||
if (stale.length === 0)
|
||||
return;
|
||||
log.warn("Layer surfaces still stale after refresh:", stale.map(w => (w.screen?.name ?? "?") + ":" + w.width + "x" + w.height).join(","));
|
||||
root.triggerSurfaceRecovery("stale-surfaces");
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: screenReconnectCooldown
|
||||
// Must exceed the full two-pass surfaceResumeRecoveryTimer sequence
|
||||
// (800 + 2000 ms) so the cooldown still covers an in-flight recovery;
|
||||
// raise this if those passes are lengthened.
|
||||
// Must exceed surfaceRefreshVerifyTimer plus the two-pass
|
||||
// surfaceResumeRecoveryTimer sequence (800 + 800 + 2000 ms).
|
||||
interval: 4000
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
@@ -295,6 +313,7 @@ Item {
|
||||
// its cooldown expires.
|
||||
screenReconnectDebounce.stop();
|
||||
screenReconnectCooldown.stop();
|
||||
surfaceRefreshVerifyTimer.stop();
|
||||
root._screenRecoveryCooldown = false;
|
||||
root._screenRecoveryPending = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user