diff --git a/quickshell/Common/ConnectedSurfaceDescriptor.js b/quickshell/Common/ConnectedSurfaceDescriptor.js index 0eda4a109..f5af5b2d7 100644 --- a/quickshell/Common/ConnectedSurfaceDescriptor.js +++ b/quickshell/Common/ConnectedSurfaceDescriptor.js @@ -6,7 +6,8 @@ var VALID_KINDS = { "launcher": true, "dock": true, "notification": true, - "island": true + "island": true, + "slideout": true }; var VALID_PHASES = { diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 846e4b594..080a1249d 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -388,7 +388,11 @@ Singleton { property real frameRounding: Spec.SPEC.frameRounding.def onFrameRoundingChanged: saveSettings() property var frameScreenPreferences: Spec.SPEC.frameScreenPreferences.def - onFrameScreenPreferencesChanged: saveSettings() + onFrameScreenPreferencesChanged: { + saveSettings(); + if (!_loading) + Qt.callLater(_reconcileConnectedFrameBarStyles); + } property real frameBarSize: Spec.SPEC.frameBarSize.def onFrameBarSizeChanged: saveSettings() property bool frameShowOnOverview: Spec.SPEC.frameShowOnOverview.def @@ -1138,6 +1142,10 @@ Singleton { property var updaterIgnoredPackages: Spec.SPEC.updaterIgnoredPackages.def property string displayNameMode: Spec.SPEC.displayNameMode.def + onDisplayNameModeChanged: { + if (!_loading) + _reconcileConnectedFrameBarStyles(); + } property var screenPreferences: Spec.SPEC.screenPreferences.def property var showOnLastDisplay: Spec.SPEC.showOnLastDisplay.def property var displayProfiles: Spec.SPEC.displayProfiles.def @@ -1515,6 +1523,14 @@ Singleton { }); } + Connections { + target: Quickshell + function onScreensChanged() { + if (!root._loading) + Qt.callLater(root._reconcileConnectedFrameBarStyles); + } + } + Connections { target: typeof SessionData !== "undefined" ? SessionData : null function onIsLightModeChanged() { @@ -2085,116 +2101,48 @@ Singleton { }; } - function _hasConnectedFrameBarStyleBackups() { - return connectedFrameBarStyleBackups && Object.keys(connectedFrameBarStyleBackups).length > 0; + function barUsesConnectedFrameStyle(config) { + if (!config || !connectedFrameModeActive) + return false; + return Quickshell.screens.some(screen => barConfigCoversScreen(config, screen) && isScreenInPreferences(screen, frameScreenPreferences)); } - function _captureConnectedFrameBarStyleBackups(configs, overwriteExisting) { + function _applyConnectedFrameBarStyles(configs) { if (!Array.isArray(configs)) - return; - - const nextBackups = JSON.parse(JSON.stringify(connectedFrameBarStyleBackups || {})); - const validIds = {}; - let changed = false; - - for (let i = 0; i < configs.length; i++) { - const config = configs[i]; - if (!config?.id) - continue; - validIds[config.id] = true; - - if (!overwriteExisting && nextBackups[config.id] !== undefined) - continue; - - const snapshot = _connectedFrameBarStyleSnapshot(config); - if (JSON.stringify(nextBackups[config.id]) !== JSON.stringify(snapshot)) { - nextBackups[config.id] = snapshot; - changed = true; - } - } - - if (overwriteExisting) { - for (const barId in nextBackups) { - if (validIds[barId]) - continue; - delete nextBackups[barId]; - changed = true; - } - } - - if (changed) - connectedFrameBarStyleBackups = nextBackups; - } - - function _restoreConnectedFrameBarStyleBackups() { - if (!_hasConnectedFrameBarStyleBackups()) - return; - - const backups = connectedFrameBarStyleBackups || {}; - const configs = JSON.parse(JSON.stringify(barConfigs)); - let changed = false; - - for (let i = 0; i < configs.length; i++) { - const backup = backups[configs[i].id]; - if (!backup) - continue; - for (const key in backup) { - if (configs[i][key] === backup[key]) - continue; - configs[i][key] = backup[key]; - changed = true; - } - } - - if (changed) - barConfigs = configs; - connectedFrameBarStyleBackups = ({}); - if (changed) - updateBarConfigs(); - } - - // Zeroes out connected-mode-hostile fields (shadow, square/goth corners, edge attach, border). - // Returns { configs, changed } — `configs` is the same ref when no change. - function _sanitizeBarConfigsForConnectedFrame(configs) { - if (!connectedFrameModeActive || !Array.isArray(configs)) return { "configs": configs, - "changed": false + "changed": false, + "backups": null }; + const backups = connectedFrameBarStyleBackups || {}; + const nextBackups = {}; + let backupsChanged = false; let anyChanged = false; + const zeroed = _connectedFrameBarStyleSnapshot(null); const out = configs.map(cfg => { - if (!cfg) + if (!cfg?.id) return cfg; - let dirty = false; - const s = Object.assign({}, cfg); - if ((s.shadowIntensity ?? 0) !== 0) { - s.shadowIntensity = 0; - dirty = true; + const covered = barUsesConnectedFrameStyle(cfg); + if (covered) { + nextBackups[cfg.id] = backups[cfg.id] ?? _connectedFrameBarStyleSnapshot(cfg); + backupsChanged = backupsChanged || backups[cfg.id] === undefined; } - if (s.squareCorners ?? false) { - s.squareCorners = false; - dirty = true; - } - if (s.attachToScreenEdge ?? false) { - s.attachToScreenEdge = false; - dirty = true; - } - if (s.gothCornersEnabled ?? false) { - s.gothCornersEnabled = false; - dirty = true; - } - if (s.borderEnabled ?? false) { - s.borderEnabled = false; - dirty = true; - } - if (dirty) - anyChanged = true; - return dirty ? s : cfg; + const target = covered ? zeroed : backups[cfg.id]; + if (!target) + return cfg; + const current = _connectedFrameBarStyleSnapshot(cfg); + if (Object.keys(target).every(key => current[key] === target[key])) + return cfg; + anyChanged = true; + return Object.assign({}, cfg, target); }); + + const backupsDirty = backupsChanged || Object.keys(nextBackups).length !== Object.keys(backups).length; return { "configs": anyChanged ? out : configs, - "changed": anyChanged + "changed": anyChanged, + "backups": backupsDirty ? nextBackups : null }; } @@ -2207,20 +2155,16 @@ Singleton { return Object.assign({}, config, backup); } - // Single entry point for connected-mode settings state. - // !active → restore backups function _reconcileConnectedFrameBarStyles() { - if (!connectedFrameModeActive) { - _restoreConnectedFrameBarStyleBackups(); + if (Quickshell.screens.length === 0) return; - } - if (!_hasConnectedFrameBarStyleBackups()) - _captureConnectedFrameBarStyleBackups(barConfigs, true); - const result = _sanitizeBarConfigsForConnectedFrame(barConfigs); - if (result.changed) { + const result = _applyConnectedFrameBarStyles(barConfigs); + if (result.changed) barConfigs = result.configs; + if (result.backups) + connectedFrameBarStyleBackups = result.backups; + if (result.changed) updateBarConfigs(); - } } function detectAvailableIconThemes() { @@ -2678,9 +2622,10 @@ Singleton { function addBarConfig(config) { const configs = JSON.parse(JSON.stringify(barConfigs)); configs.push(config); - if (connectedFrameModeActive) - _captureConnectedFrameBarStyleBackups(configs, false); - barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs; + const result = _applyConnectedFrameBarStyles(configs); + barConfigs = result.configs; + if (result.backups) + connectedFrameBarStyleBackups = result.backups; updateBarConfigs(); } @@ -2870,7 +2815,10 @@ Singleton { function _commitBarConfigs(configs) { for (const cfg of configs) _restoreIslandWidget(cfg, configs); - barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs; + const result = _applyConnectedFrameBarStyles(configs); + barConfigs = result.configs; + if (result.backups) + connectedFrameBarStyleBackups = result.backups; updateBarConfigs(); } diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index e3d120b27..19a3f2c25 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -1068,6 +1068,7 @@ Item { expandable: true expandedWidthValue: 960 edgeGap: SettingsData.notepadEffectiveEdgeGap + frameSurfaceEnabled: true slideEdge: SettingsData.notepadSlideoutSide customTransparency: Theme.notepadTransparency diff --git a/quickshell/Modals/Common/DModalHost.qml b/quickshell/Modals/Common/DModalHost.qml index 796e5a031..8761b34f0 100644 --- a/quickshell/Modals/Common/DModalHost.qml +++ b/quickshell/Modals/Common/DModalHost.qml @@ -68,7 +68,6 @@ Item { readonly property color effectiveBorderColor: frameOwnsConnectedChrome ? Theme.withAlpha(borderColor, 0) : borderColor readonly property real effectiveBorderWidth: frameOwnsConnectedChrome ? 0 : borderWidth readonly property real effectiveCornerRadius: frameOwnsConnectedChrome ? Theme.connectedSurfaceRadius : cornerRadius - readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled property bool enableShadow: modalHandle.enableShadow property alias modalFocusScope: focusScope property Item handleFocusScope: null @@ -547,7 +546,7 @@ Item { WindowBlur { targetWindow: contentWindow - blurEnabled: root.effectiveBlurEnabled && !root.frameOwnsConnectedChrome + blurEnabled: !root.frameOwnsConnectedChrome surfaceColor: root.effectiveBackgroundColor readonly property real s: Math.min(1, modalContainer.scaleValue) readonly property real op: Math.max(0, Math.min(1, (morph.value - 0.06) * 2)) diff --git a/quickshell/Modals/DLauncherV2/DLauncherV2ModalHost.qml b/quickshell/Modals/DLauncherV2/DLauncherV2ModalHost.qml index ce2c9545f..e97ee4be2 100644 --- a/quickshell/Modals/DLauncherV2/DLauncherV2ModalHost.qml +++ b/quickshell/Modals/DLauncherV2/DLauncherV2ModalHost.qml @@ -208,7 +208,6 @@ Item { readonly property color effectiveBorderColor: connectedSurfaceOverride ? Theme.withAlpha(borderColor, 0) : borderColor readonly property int effectiveBorderWidth: connectedSurfaceOverride ? 0 : borderWidth readonly property int paintedBorderWidth: connected ? (frameOwnsConnectedChrome ? 0 : effectiveBorderWidth) : Math.max(borderWidth, BlurService.borderWidth) - readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled readonly property var shadowLevel: Theme.elevationLevel3 readonly property real shadowFallbackOffset: Theme.spacingS @@ -919,7 +918,7 @@ Item { WindowBlur { targetWindow: contentWindow - blurEnabled: root.effectiveBlurEnabled && !root.frameOwnsConnectedChrome + blurEnabled: !root.frameOwnsConnectedChrome surfaceColor: root.backgroundColor readonly property real s: Math.min(1, contentContainer.scaleValue) readonly property bool clipDriven: root._fluidMotionActive && !root.connectedFluidMotion diff --git a/quickshell/Modules/Dock/Dock.qml b/quickshell/Modules/Dock/Dock.qml index b2dd0c3d9..669cdd5ac 100644 --- a/quickshell/Modules/Dock/Dock.qml +++ b/quickshell/Modules/Dock/Dock.qml @@ -67,7 +67,7 @@ Variants { WindowBlur { targetWindow: dock - blurEnabled: body.effectiveBlurEnabled && !body.usesConnectedFrameChrome + blurEnabled: !body.usesConnectedFrameChrome surfaceColor: body.surfaceColor blurX: body.blurX blurY: body.blurY diff --git a/quickshell/Modules/Dock/DockBody.qml b/quickshell/Modules/Dock/DockBody.qml index cbb1b7c1b..874b34626 100644 --- a/quickshell/Modules/Dock/DockBody.qml +++ b/quickshell/Modules/Dock/DockBody.qml @@ -216,7 +216,6 @@ FocusScope { readonly property real adjacentLeftBarWidth: !isVertical && !autoHide ? ShellLayout.dockAdjacentThickness(screen, "left") : 0 readonly property real dockMargin: dock.config.margin - readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled readonly property real effectiveDockMargin: dockGeometry.effectiveMargin readonly property real joinedEdgeMargin: dockGeometry.joinedEdgeMargin readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1 diff --git a/quickshell/Modules/Frame/FrameWindow.qml b/quickshell/Modules/Frame/FrameWindow.qml index e9f5476ee..c4548c624 100644 --- a/quickshell/Modules/Frame/FrameWindow.qml +++ b/quickshell/Modules/Frame/FrameWindow.qml @@ -127,6 +127,35 @@ PanelWindow { win._surfaceRevision; return ConnectedModeState.surfaceDescriptor(win._screenName, "popout"); } + component ConnectorBlurRegion: Region { + id: connectorBlur + required property string barSide + required property var body + required property string placement + required property real connectorRadius + property bool far: false + property bool bodyActive: true + + readonly property bool _active: bodyActive && connectorRadius > 0 + readonly property var _rect: far ? SurfaceGeometry.farConnectorRect(barSide, body, placement, connectorRadius, win._dpr) : SurfaceGeometry.connectorRect(barSide, body, placement, 0, connectorRadius, win._dpr) + readonly property string _arcCorner: far ? ConnectorGeometry.arcCorner(win._farConnectorBarSide(barSide, placement), win._farConnectorPlacement(barSide, placement)) : ConnectorGeometry.arcCorner(barSide, placement) + + x: _active ? Math.round(_rect.x) : 0 + y: _active ? Math.round(_rect.y) : 0 + width: _active ? Math.round(_rect.width) : 0 + height: _active ? Math.round(_rect.height) : 0 + + Region { + readonly property bool _active: connectorBlur.width > 0 && connectorBlur.height > 0 + + intersection: Intersection.Subtract + radius: connectorBlur.connectorRadius + x: _active ? Math.round(win._connectorCutoutX(connectorBlur.x, connectorBlur.width, connectorBlur._arcCorner, connectorBlur.connectorRadius)) : 0 + y: _active ? Math.round(win._connectorCutoutY(connectorBlur.y, connectorBlur.height, connectorBlur._arcCorner, connectorBlur.connectorRadius)) : 0 + width: _active ? Math.round(connectorBlur.connectorRadius * 2) : 0 + height: _active ? Math.round(connectorBlur.connectorRadius * 2) : 0 + } + } component DockBlurRegion: Region { id: dockBlur required property var dockSurface @@ -162,55 +191,19 @@ PanelWindow { width: _active ? _capWidth : 0 height: _active ? _capHeight : 0 } - Region { - id: _dockLeftConnectorBlurAnchor - - readonly property bool _active: _dockBodyBlurAnchor._active && dockBlur.connectorRadius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(dockBlur.descriptor.barSide, dockBlur.geometry, "left", 0, dockBlur.connectorRadius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _dockLeftConnectorCutout - - readonly property bool _active: _dockLeftConnectorBlurAnchor.width > 0 && _dockLeftConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(dockBlur.descriptor.barSide, "left") - - intersection: Intersection.Subtract - radius: dockBlur.connectorRadius - x: _active ? Math.round(win._connectorCutoutX(_dockLeftConnectorBlurAnchor.x, _dockLeftConnectorBlurAnchor.width, _arcCorner, dockBlur.connectorRadius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_dockLeftConnectorBlurAnchor.y, _dockLeftConnectorBlurAnchor.height, _arcCorner, dockBlur.connectorRadius)) : 0 - width: _active ? Math.round(dockBlur.connectorRadius * 2) : 0 - height: _active ? Math.round(dockBlur.connectorRadius * 2) : 0 - } + ConnectorBlurRegion { + barSide: dockBlur.descriptor.barSide + body: dockBlur.geometry + placement: "left" + bodyActive: _dockBodyBlurAnchor._active + connectorRadius: dockBlur.connectorRadius } - Region { - id: _dockRightConnectorBlurAnchor - - readonly property bool _active: _dockBodyBlurAnchor._active && dockBlur.connectorRadius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(dockBlur.descriptor.barSide, dockBlur.geometry, "right", 0, dockBlur.connectorRadius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _dockRightConnectorCutout - - readonly property bool _active: _dockRightConnectorBlurAnchor.width > 0 && _dockRightConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(dockBlur.descriptor.barSide, "right") - - intersection: Intersection.Subtract - radius: dockBlur.connectorRadius - x: _active ? Math.round(win._connectorCutoutX(_dockRightConnectorBlurAnchor.x, _dockRightConnectorBlurAnchor.width, _arcCorner, dockBlur.connectorRadius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_dockRightConnectorBlurAnchor.y, _dockRightConnectorBlurAnchor.height, _arcCorner, dockBlur.connectorRadius)) : 0 - width: _active ? Math.round(dockBlur.connectorRadius * 2) : 0 - height: _active ? Math.round(dockBlur.connectorRadius * 2) : 0 - } + ConnectorBlurRegion { + barSide: dockBlur.descriptor.barSide + body: dockBlur.geometry + placement: "right" + bodyActive: _dockBodyBlurAnchor._active + connectorRadius: dockBlur.connectorRadius } } @@ -253,6 +246,23 @@ PanelWindow { connector: SurfaceGeometry.connectorRadii(descriptor, body, win._ccr, radius, win._dpr, true).near }; } + readonly property var _slideoutDescriptor: { + win._surfaceRevision; + return ConnectedModeState.surfaceDescriptor(win._screenName, "slideout"); + } + readonly property var _slideoutSurface: { + const descriptor = win._slideoutDescriptor; + if (!win._connectedActive || !descriptor.visible) + return null; + const body = win._clampNear(descriptor.barSide, SurfaceGeometry.animatedBodyRect(descriptor, win._dpr)); + if (body.width < 1 || body.height < 1) + return null; + return { + descriptor: descriptor, + body: body, + radii: SurfaceGeometry.connectorRadii(descriptor, body, win._ccr, win._surfaceRadius, win._dpr, true) + }; + } readonly property var _modalDescriptor: { win._surfaceRevision; return ConnectedModeState.surfaceDescriptor(win._screenName, "modal"); @@ -324,7 +334,7 @@ PanelWindow { readonly property real _surfaceRadius: Theme.connectedSurfaceRadius readonly property real _seamOverlap: Theme.hairline(win._dpr) readonly property bool _disableLayer: Quickshell.env("DMS_DISABLE_LAYER") === "true" || Quickshell.env("DMS_DISABLE_LAYER") === "1" - readonly property bool _elevationShadow: win._connectedActive && Theme.elevationEnabled && !win._disableLayer + readonly property bool _elevationShadow: win._connectedActive && Theme.elevationEnabled && (SettingsData.barElevationEnabled || SettingsData.popoutElevationEnabled || SettingsData.modalElevationEnabled) && !win._disableLayer function _clampNear(side, b) { const r = { "x": b.x, @@ -387,7 +397,7 @@ PanelWindow { "param": Qt.vector4d(0, 0, 0, 0) }) - // Slots 0-3 hold popout, modal, notification and docks; the island's spring steps every frame, so it owns slot 4 alone. + // Slots 0-3 hold popout, modal, notification and docks; the island and slideout spring every frame, so each owns a slot alone (4, 5). readonly property var _sdfSlots: { win._surfaceRevision; const src = win._unifiedSurfaces(); @@ -415,6 +425,24 @@ PanelWindow { } }); } + + readonly property var _slideoutSdfSlot: { + const slideout = win._slideoutSurface; + if (!slideout) + return win._emptySdfSlot; + return win._sdfSlot({ + "side": slideout.descriptor.barSide, + "body": slideout.body, + "radii": { + "farCr": slideout.radii.far, + "startCr": slideout.radii.start, + "endCr": slideout.radii.end, + "farStartCr": slideout.radii.farStart, + "farEndCr": slideout.radii.farEnd, + "surfaceRadius": win._surfaceRadius + } + }); + } function _regionInt(value) { return Math.max(0, Math.round(Theme.px(value, win._dpr))); } @@ -534,59 +562,19 @@ PanelWindow { width: _active ? _capWidth : 0 height: _active ? _capHeight : 0 } - Region { - id: _popoutLeftConnectorBlurAnchor - - readonly property real _radius: win._popoutConnectorRadiusLeft - readonly property bool _active: _popoutBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._popoutDescriptor.barSide, win._popoutBodyGeometry, "left", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _popoutLeftConnectorCutout - - readonly property bool _active: _popoutLeftConnectorBlurAnchor.width > 0 && _popoutLeftConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._popoutDescriptor.barSide, "left") - readonly property real _radius: win._popoutConnectorRadiusLeft - - intersection: Intersection.Subtract - radius: win._popoutConnectorRadiusLeft - x: _active ? Math.round(win._connectorCutoutX(_popoutLeftConnectorBlurAnchor.x, _popoutLeftConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_popoutLeftConnectorBlurAnchor.y, _popoutLeftConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._popoutDescriptor.barSide + body: win._popoutBodyGeometry + placement: "left" + bodyActive: _popoutBodyBlurAnchor._active + connectorRadius: win._popoutConnectorRadiusLeft } - Region { - id: _popoutRightConnectorBlurAnchor - - readonly property real _radius: win._popoutConnectorRadiusRight - readonly property bool _active: _popoutBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._popoutDescriptor.barSide, win._popoutBodyGeometry, "right", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _popoutRightConnectorCutout - - readonly property bool _active: _popoutRightConnectorBlurAnchor.width > 0 && _popoutRightConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._popoutDescriptor.barSide, "right") - readonly property real _radius: win._popoutConnectorRadiusRight - - intersection: Intersection.Subtract - radius: win._popoutConnectorRadiusRight - x: _active ? Math.round(win._connectorCutoutX(_popoutRightConnectorBlurAnchor.x, _popoutRightConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_popoutRightConnectorBlurAnchor.y, _popoutRightConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._popoutDescriptor.barSide + body: win._popoutBodyGeometry + placement: "right" + bodyActive: _popoutBodyBlurAnchor._active + connectorRadius: win._popoutConnectorRadiusRight } Region { id: _popoutFarStartBodyBlurCap @@ -612,63 +600,21 @@ PanelWindow { width: _active ? Math.round(_rect.width) : 0 height: _active ? Math.round(_rect.height) : 0 } - Region { - id: _popoutFarStartConnectorBlurAnchor - - readonly property real _radius: win._effectivePopoutFarStartCcr - readonly property bool _active: _popoutBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._popoutDescriptor.barSide, win._popoutBodyGeometry, "left", _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _popoutFarStartConnectorCutout - - readonly property bool _active: _popoutFarStartConnectorBlurAnchor.width > 0 && _popoutFarStartConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._popoutDescriptor.barSide, "left") - readonly property string _placement: win._farConnectorPlacement(win._popoutDescriptor.barSide, "left") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectivePopoutFarStartCcr - - intersection: Intersection.Subtract - radius: win._effectivePopoutFarStartCcr - x: _active ? Math.round(win._connectorCutoutX(_popoutFarStartConnectorBlurAnchor.x, _popoutFarStartConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_popoutFarStartConnectorBlurAnchor.y, _popoutFarStartConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._popoutDescriptor.barSide + body: win._popoutBodyGeometry + placement: "left" + far: true + bodyActive: _popoutBodyBlurAnchor._active + connectorRadius: win._effectivePopoutFarStartCcr } - Region { - id: _popoutFarEndConnectorBlurAnchor - - readonly property real _radius: win._effectivePopoutFarEndCcr - readonly property bool _active: _popoutBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._popoutDescriptor.barSide, win._popoutBodyGeometry, "right", _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _popoutFarEndConnectorCutout - - readonly property bool _active: _popoutFarEndConnectorBlurAnchor.width > 0 && _popoutFarEndConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._popoutDescriptor.barSide, "right") - readonly property string _placement: win._farConnectorPlacement(win._popoutDescriptor.barSide, "right") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectivePopoutFarEndCcr - - intersection: Intersection.Subtract - radius: win._effectivePopoutFarEndCcr - x: _active ? Math.round(win._connectorCutoutX(_popoutFarEndConnectorBlurAnchor.x, _popoutFarEndConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_popoutFarEndConnectorBlurAnchor.y, _popoutFarEndConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._popoutDescriptor.barSide + body: win._popoutBodyGeometry + placement: "right" + far: true + bodyActive: _popoutBodyBlurAnchor._active + connectorRadius: win._effectivePopoutFarEndCcr } DockBlurRegion { @@ -713,59 +659,19 @@ PanelWindow { width: _active ? _capWidth : 0 height: _active ? _capHeight : 0 } - Region { - id: _notifLeftConnectorBlurAnchor - - readonly property real _radius: win._notifConnectorRadiusLeft - readonly property bool _active: _notifBodySceneBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._notifDescriptor.barSide, _notifBodySceneBlurAnchor, "left", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _notifLeftConnectorCutout - - readonly property bool _active: _notifLeftConnectorBlurAnchor.width > 0 && _notifLeftConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._notifDescriptor.barSide, "left") - readonly property real _radius: win._notifConnectorRadiusLeft - - intersection: Intersection.Subtract - radius: win._notifConnectorRadiusLeft - x: _active ? Math.round(win._connectorCutoutX(_notifLeftConnectorBlurAnchor.x, _notifLeftConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_notifLeftConnectorBlurAnchor.y, _notifLeftConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._notifDescriptor.barSide + body: _notifBodySceneBlurAnchor + placement: "left" + bodyActive: _notifBodySceneBlurAnchor._active + connectorRadius: win._notifConnectorRadiusLeft } - Region { - id: _notifRightConnectorBlurAnchor - - readonly property real _radius: win._notifConnectorRadiusRight - readonly property bool _active: _notifBodySceneBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._notifDescriptor.barSide, _notifBodySceneBlurAnchor, "right", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _notifRightConnectorCutout - - readonly property bool _active: _notifRightConnectorBlurAnchor.width > 0 && _notifRightConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._notifDescriptor.barSide, "right") - readonly property real _radius: win._notifConnectorRadiusRight - - intersection: Intersection.Subtract - radius: win._notifConnectorRadiusRight - x: _active ? Math.round(win._connectorCutoutX(_notifRightConnectorBlurAnchor.x, _notifRightConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_notifRightConnectorBlurAnchor.y, _notifRightConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._notifDescriptor.barSide + body: _notifBodySceneBlurAnchor + placement: "right" + bodyActive: _notifBodySceneBlurAnchor._active + connectorRadius: win._notifConnectorRadiusRight } Region { id: _notifFarStartBodyBlurCap @@ -791,63 +697,46 @@ PanelWindow { width: _active ? Math.round(_rect.width) : 0 height: _active ? Math.round(_rect.height) : 0 } - Region { - id: _notifFarStartConnectorBlurAnchor - - readonly property real _radius: win._effectiveNotifFarStartCcr - readonly property bool _active: _notifBodySceneBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._notifDescriptor.barSide, _notifBodySceneBlurAnchor, "left", _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _notifFarStartConnectorCutout - - readonly property bool _active: _notifFarStartConnectorBlurAnchor.width > 0 && _notifFarStartConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._notifDescriptor.barSide, "left") - readonly property string _placement: win._farConnectorPlacement(win._notifDescriptor.barSide, "left") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectiveNotifFarStartCcr - - intersection: Intersection.Subtract - radius: win._effectiveNotifFarStartCcr - x: _active ? Math.round(win._connectorCutoutX(_notifFarStartConnectorBlurAnchor.x, _notifFarStartConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_notifFarStartConnectorBlurAnchor.y, _notifFarStartConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._notifDescriptor.barSide + body: _notifBodySceneBlurAnchor + placement: "left" + far: true + bodyActive: _notifBodySceneBlurAnchor._active + connectorRadius: win._effectiveNotifFarStartCcr } + ConnectorBlurRegion { + barSide: win._notifDescriptor.barSide + body: _notifBodySceneBlurAnchor + placement: "right" + far: true + bodyActive: _notifBodySceneBlurAnchor._active + connectorRadius: win._effectiveNotifFarEndCcr + } + Region { - id: _notifFarEndConnectorBlurAnchor + id: _slideoutBodyBlurAnchor - readonly property real _radius: win._effectiveNotifFarEndCcr - readonly property bool _active: _notifBodySceneBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._notifDescriptor.barSide, _notifBodySceneBlurAnchor, "right", _radius, win._dpr) + readonly property bool _active: win._blurSurfacesActive && win._slideoutSurface !== null - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _notifFarEndConnectorCutout - - readonly property bool _active: _notifFarEndConnectorBlurAnchor.width > 0 && _notifFarEndConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._notifDescriptor.barSide, "right") - readonly property string _placement: win._farConnectorPlacement(win._notifDescriptor.barSide, "right") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectiveNotifFarEndCcr - - intersection: Intersection.Subtract - radius: win._effectiveNotifFarEndCcr - x: _active ? Math.round(win._connectorCutoutX(_notifFarEndConnectorBlurAnchor.x, _notifFarEndConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_notifFarEndConnectorBlurAnchor.y, _notifFarEndConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + x: _active ? Math.round(win._slideoutSurface.body.x) : 0 + y: _active ? Math.round(win._slideoutSurface.body.y) : 0 + width: _active ? Math.round(win._slideoutSurface.body.width) : 0 + height: _active ? Math.round(win._slideoutSurface.body.height) : 0 + } + ConnectorBlurRegion { + barSide: win._slideoutDescriptor.barSide + body: _slideoutBodyBlurAnchor + placement: "left" + far: true + connectorRadius: _slideoutBodyBlurAnchor._active ? Math.min(win._slideoutSurface.radii.farStart, win._slideoutSurface.body.width) : 0 + } + ConnectorBlurRegion { + barSide: win._slideoutDescriptor.barSide + body: _slideoutBodyBlurAnchor + placement: "right" + far: true + connectorRadius: _slideoutBodyBlurAnchor._active ? Math.min(win._slideoutSurface.radii.farEnd, win._slideoutSurface.body.width) : 0 } Region { @@ -875,59 +764,19 @@ PanelWindow { width: _active ? _capWidth : 0 height: _active ? _capHeight : 0 } - Region { - id: _modalLeftConnectorBlurAnchor - - readonly property real _radius: win._modalConnectorRadiusLeft - readonly property bool _active: _modalBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._modalDescriptor.barSide, win._modalBodyGeometry, "left", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _modalLeftConnectorCutout - - readonly property bool _active: _modalLeftConnectorBlurAnchor.width > 0 && _modalLeftConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._modalDescriptor.barSide, "left") - readonly property real _radius: win._modalConnectorRadiusLeft - - intersection: Intersection.Subtract - radius: win._modalConnectorRadiusLeft - x: _active ? Math.round(win._connectorCutoutX(_modalLeftConnectorBlurAnchor.x, _modalLeftConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_modalLeftConnectorBlurAnchor.y, _modalLeftConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._modalDescriptor.barSide + body: win._modalBodyGeometry + placement: "left" + bodyActive: _modalBodyBlurAnchor._active + connectorRadius: win._modalConnectorRadiusLeft } - Region { - id: _modalRightConnectorBlurAnchor - - readonly property real _radius: win._modalConnectorRadiusRight - readonly property bool _active: _modalBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.connectorRect(win._modalDescriptor.barSide, win._modalBodyGeometry, "right", 0, _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _modalRightConnectorCutout - - readonly property bool _active: _modalRightConnectorBlurAnchor.width > 0 && _modalRightConnectorBlurAnchor.height > 0 - readonly property string _arcCorner: ConnectorGeometry.arcCorner(win._modalDescriptor.barSide, "right") - readonly property real _radius: win._modalConnectorRadiusRight - - intersection: Intersection.Subtract - radius: win._modalConnectorRadiusRight - x: _active ? Math.round(win._connectorCutoutX(_modalRightConnectorBlurAnchor.x, _modalRightConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_modalRightConnectorBlurAnchor.y, _modalRightConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._modalDescriptor.barSide + body: win._modalBodyGeometry + placement: "right" + bodyActive: _modalBodyBlurAnchor._active + connectorRadius: win._modalConnectorRadiusRight } Region { id: _modalFarStartBodyBlurCap @@ -953,63 +802,21 @@ PanelWindow { width: _active ? Math.round(_rect.width) : 0 height: _active ? Math.round(_rect.height) : 0 } - Region { - id: _modalFarStartConnectorBlurAnchor - - readonly property real _radius: win._effectiveModalFarStartCcr - readonly property bool _active: _modalBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._modalDescriptor.barSide, win._modalBodyGeometry, "left", _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _modalFarStartConnectorCutout - - readonly property bool _active: _modalFarStartConnectorBlurAnchor.width > 0 && _modalFarStartConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._modalDescriptor.barSide, "left") - readonly property string _placement: win._farConnectorPlacement(win._modalDescriptor.barSide, "left") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectiveModalFarStartCcr - - intersection: Intersection.Subtract - radius: win._effectiveModalFarStartCcr - x: _active ? Math.round(win._connectorCutoutX(_modalFarStartConnectorBlurAnchor.x, _modalFarStartConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_modalFarStartConnectorBlurAnchor.y, _modalFarStartConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._modalDescriptor.barSide + body: win._modalBodyGeometry + placement: "left" + far: true + bodyActive: _modalBodyBlurAnchor._active + connectorRadius: win._effectiveModalFarStartCcr } - Region { - id: _modalFarEndConnectorBlurAnchor - - readonly property real _radius: win._effectiveModalFarEndCcr - readonly property bool _active: _modalBodyBlurAnchor._active && _radius > 0 - readonly property var _rect: SurfaceGeometry.farConnectorRect(win._modalDescriptor.barSide, win._modalBodyGeometry, "right", _radius, win._dpr) - - x: _active ? Math.round(_rect.x) : 0 - y: _active ? Math.round(_rect.y) : 0 - width: _active ? Math.round(_rect.width) : 0 - height: _active ? Math.round(_rect.height) : 0 - - Region { - id: _modalFarEndConnectorCutout - - readonly property bool _active: _modalFarEndConnectorBlurAnchor.width > 0 && _modalFarEndConnectorBlurAnchor.height > 0 - readonly property string _barSide: win._farConnectorBarSide(win._modalDescriptor.barSide, "right") - readonly property string _placement: win._farConnectorPlacement(win._modalDescriptor.barSide, "right") - readonly property string _arcCorner: ConnectorGeometry.arcCorner(_barSide, _placement) - readonly property real _radius: win._effectiveModalFarEndCcr - - intersection: Intersection.Subtract - radius: win._effectiveModalFarEndCcr - x: _active ? Math.round(win._connectorCutoutX(_modalFarEndConnectorBlurAnchor.x, _modalFarEndConnectorBlurAnchor.width, _arcCorner, _radius)) : 0 - y: _active ? Math.round(win._connectorCutoutY(_modalFarEndConnectorBlurAnchor.y, _modalFarEndConnectorBlurAnchor.height, _arcCorner, _radius)) : 0 - width: _active ? Math.round(_radius * 2) : 0 - height: _active ? Math.round(_radius * 2) : 0 - } + ConnectorBlurRegion { + barSide: win._modalDescriptor.barSide + body: win._modalBodyGeometry + placement: "right" + far: true + bodyActive: _modalBodyBlurAnchor._active + connectorRadius: win._effectiveModalFarEndCcr } } @@ -1334,6 +1141,10 @@ PanelWindow { property vector4d chromeCorner4: win._islandSdfSlot.corner property vector4d chromeK4: win._islandSdfSlot.k property vector4d chromeParam4: win._islandSdfSlot.param + property vector4d chromeRect5: win._slideoutSdfSlot.rect + property vector4d chromeCorner5: win._slideoutSdfSlot.corner + property vector4d chromeK5: win._slideoutSdfSlot.k + property vector4d chromeParam5: win._slideoutSdfSlot.param } Loader { diff --git a/quickshell/Modules/Notepad/Notepad.qml b/quickshell/Modules/Notepad/Notepad.qml index 002f43bde..d73a18a58 100644 --- a/quickshell/Modules/Notepad/Notepad.qml +++ b/quickshell/Modules/Notepad/Notepad.qml @@ -544,6 +544,7 @@ Item { id: notepadSettings anchors.fill: parent isVisible: showSettingsMenu + frameManagesGap: root.slideout?.frameOwnsConnectedChrome ?? false onSettingsRequested: showSettingsMenu = !showSettingsMenu onFindRequested: { showSettingsMenu = false; diff --git a/quickshell/Modules/Notepad/NotepadSettings.qml b/quickshell/Modules/Notepad/NotepadSettings.qml index 0ee5eb3f4..01ea96e5e 100644 --- a/quickshell/Modules/Notepad/NotepadSettings.qml +++ b/quickshell/Modules/Notepad/NotepadSettings.qml @@ -12,6 +12,7 @@ Item { property var cachedMonoFamilies: [] property bool fontsEnumerated: false property bool shortcutsExpanded: false + property bool frameManagesGap: false signal settingsRequested signal findRequested @@ -449,7 +450,8 @@ Item { anchors.leftMargin: -Theme.spacingM width: parent.width + Theme.spacingM text: I18n.tr("Auto Compositor Gaps") - description: I18n.tr("Inset the Notepad from screen edges using the compositor's configured gaps") + description: root.frameManagesGap ? I18n.tr("Managed by Frame in Connected Mode") : I18n.tr("Inset the Notepad from screen edges using the compositor's configured gaps") + enabled: !root.frameManagesGap checked: SettingsData.notepadUseCompositorGap onToggled: checked => { SettingsData.notepadUseCompositorGap = checked; @@ -469,6 +471,7 @@ Item { anchors.leftMargin: Theme.spacingXS width: parent.width - Theme.spacingXS * 2 visible: !SettingsData.notepadUseCompositorGap + enabled: !root.frameManagesGap value: SettingsData.notepadEdgeGap minimum: 0 maximum: 64 diff --git a/quickshell/Modules/Settings/DBarTab.qml b/quickshell/Modules/Settings/DBarTab.qml index 5ad773a6c..09bc5db24 100644 --- a/quickshell/Modules/Settings/DBarTab.qml +++ b/quickshell/Modules/Settings/DBarTab.qml @@ -20,6 +20,7 @@ Item { readonly property string clickThroughHint: I18n.tr("Disabled by Click through", "bar hover popouts card, Click through is the Advanced toggle name") readonly property bool selectedIslandFree: bar.selectedBarIsIsland && SettingsData.islandFreePlacement(bar.selectedBarConfig) readonly property bool selectedIslandDocked: bar.selectedBarIsIsland && !selectedIslandFree + readonly property bool popupGapsZeroed: SettingsData.barUsesConnectedFrameStyle(bar.selectedBarConfig) && !(bar.selectedBarConfig?.useOverlayLayer ?? false) readonly property int placementIndex: !bar.islandSetting("islandFloating") ? 0 : (bar.islandSetting("islandPlacement") === "free" ? 2 : 1) function setBarScreenPreferences(barId, prefs) { @@ -656,7 +657,7 @@ Item { text: I18n.tr("Auto popup gaps") description: I18n.tr("Gap between the bar and its popouts follows edge spacing", "bar auto popup gaps toggle description") tags: ["popup", "gaps", "auto"] - visible: !bar.selectedBarFrameStyled + visible: !bar.popupGapsZeroed checked: bar.selectedBarConfig?.popupGapsAuto ?? true onToggled: checked => SettingsData.updateBarConfig(bar.selectedBarId, { popupGapsAuto: checked @@ -664,7 +665,7 @@ Item { } SettingsSliderRow { - visible: !bar.selectedBarFrameStyled && !(bar.selectedBarConfig?.popupGapsAuto ?? true) + visible: !bar.popupGapsZeroed && !(bar.selectedBarConfig?.popupGapsAuto ?? true) text: I18n.tr("Gap size") tags: ["popup", "gaps", "size"] resetStore: bar diff --git a/quickshell/Modules/Settings/LauncherTab.qml b/quickshell/Modules/Settings/LauncherTab.qml index 923d1efb8..0ff3733b7 100644 --- a/quickshell/Modules/Settings/LauncherTab.qml +++ b/quickshell/Modules/Settings/LauncherTab.qml @@ -72,24 +72,16 @@ Item { title: I18n.tr("Default action") settingKey: "launcherStyle" - SettingsControlledBy { - visible: SettingsData.connectedFrameModeActive - parentModal: root.parentModal - section: "frameConnectedOptions" - settingLabel: I18n.tr("Default action") - reason: I18n.tr("Connected Frame Mode uses the connected launcher for default launcher shortcuts.") - } - SettingsButtonGroupRow { readonly property bool islandOffered: SettingsData.dankIslandEnabled || SettingsData.launcherStyle === "island" + readonly property bool spotlightOffered: !SettingsData.connectedFrameModeActive - visible: !SettingsData.connectedFrameModeActive settingKey: "launcherStyleSelector" tags: ["launcher", "style", "default", "spotlight", "full", "minimal", "island", "dankisland"] resetKeys: ["launcherStyle"] text: I18n.tr("Opens", "verb, row label, which launcher style the shortcut opens") - model: [I18n.tr("Full", "adjective, full size launcher style option"), I18n.tr("Spotlight", "launcher style option, small centered search bar")].concat(islandOffered ? [I18n.tr("Island")] : []) - values: ["full", "spotlight"].concat(islandOffered ? ["island"] : []) + model: [I18n.tr("Full", "adjective, full size launcher style option")].concat(spotlightOffered ? [I18n.tr("Spotlight", "launcher style option, small centered search bar")] : []).concat(islandOffered ? [I18n.tr("Island")] : []) + values: ["full"].concat(spotlightOffered ? ["spotlight"] : []).concat(islandOffered ? ["island"] : []) value: SettingsData.launcherStyle fallbackValue: "full" onValueSelected: value => SettingsData.set("launcherStyle", value) diff --git a/quickshell/Modules/Settings/Widgets/BarSelectionState.qml b/quickshell/Modules/Settings/Widgets/BarSelectionState.qml index 77abe7722..022207b7c 100644 --- a/quickshell/Modules/Settings/Widgets/BarSelectionState.qml +++ b/quickshell/Modules/Settings/Widgets/BarSelectionState.qml @@ -53,7 +53,7 @@ Item { return root.selectedBarScreens.filter(screen => ShellLayout.forScreen(screen)?.frameConfigured).length; } readonly property bool selectedBarFrameStyled: SettingsData.frameEnabled && root.frameStyledScreenCount === root.selectedBarScreens.length - readonly property bool selectedBarFrameSanitized: SettingsData.connectedFrameModeActive || root.selectedBarFrameStyled + readonly property bool selectedBarFrameSanitized: SettingsData.barUsesConnectedFrameStyle(root.selectedBarConfig) || root.selectedBarFrameStyled readonly property var positionChoices: ShellLayout.positionChoices(selectedBarConfig) function positionLabel(pos) { diff --git a/quickshell/Shaders/frag/connected_arc.frag b/quickshell/Shaders/frag/connected_arc.frag index ce77ac7ad..22406394c 100644 --- a/quickshell/Shaders/frag/connected_arc.frag +++ b/quickshell/Shaders/frag/connected_arc.frag @@ -16,7 +16,7 @@ layout(std140, binding = 0) uniform buf { vec4 shadowColor; // straight rgba; a = 0 disables both shadow terms vec4 shadowParam; // key: x = blur px, y = spread px, z,w = offset px vec4 ambientParam; // ambient: x = blur px, y = spread px, z = alpha - // Five chrome slots: rect = x,y,w,h px; corner and k = per-corner radii and junction fillets (TL, TR, BR, BL), + // Six chrome slots: rect = x,y,w,h px; corner and k = per-corner radii and junction fillets (TL, TR, BR, BL), // a corner is sharp exactly where its k > 0; param.x = active. vec4 chromeRect0; vec4 chromeCorner0; @@ -38,6 +38,10 @@ layout(std140, binding = 0) uniform buf { vec4 chromeCorner4; vec4 chromeK4; vec4 chromeParam4; + vec4 chromeRect5; + vec4 chromeCorner5; + vec4 chromeK5; + vec4 chromeParam5; } ubuf; float sdRoundBox(vec2 p, vec2 c, vec2 hs, float r) { @@ -85,6 +89,8 @@ float sceneDist(vec2 px) { d = smin(d, chromeDist(px, ubuf.chromeRect3, ubuf.chromeCorner3), chromeK(px, ubuf.chromeRect3, ubuf.chromeK3)); if (ubuf.chromeParam4.x > 0.5) d = smin(d, chromeDist(px, ubuf.chromeRect4, ubuf.chromeCorner4), chromeK(px, ubuf.chromeRect4, ubuf.chromeK4)); + if (ubuf.chromeParam5.x > 0.5) + d = smin(d, chromeDist(px, ubuf.chromeRect5, ubuf.chromeCorner5), chromeK(px, ubuf.chromeRect5, ubuf.chromeK5)); return d; } diff --git a/quickshell/Shaders/qsb/connected_arc.frag.qsb b/quickshell/Shaders/qsb/connected_arc.frag.qsb index 7911c0492..04f594454 100644 Binary files a/quickshell/Shaders/qsb/connected_arc.frag.qsb and b/quickshell/Shaders/qsb/connected_arc.frag.qsb differ diff --git a/quickshell/Widgets/DContextMenu.qml b/quickshell/Widgets/DContextMenu.qml index 0c7cfc721..283842c0c 100644 --- a/quickshell/Widgets/DContextMenu.qml +++ b/quickshell/Widgets/DContextMenu.qml @@ -31,7 +31,7 @@ Item { property int selectedMenuIndex: -1 property bool keyboardNavigation: false readonly property alias contextWindow: menuWindow - readonly property bool blurActive: renderActive && openState && BlurService.enabled && Theme.connectedSurfaceBlurEnabled + readonly property bool blurActive: renderActive && openState && BlurService.enabled readonly property real maxMenuWidth: Math.max(0, (targetScreen?.width ?? Theme.launcherWidthMicro) - menuMargin * 2) readonly property real maxMenuHeight: Math.max(0, (targetScreen?.height ?? Theme.launcherHeightDefault) - menuMargin * 2) diff --git a/quickshell/Widgets/DFloatingWindow.qml b/quickshell/Widgets/DFloatingWindow.qml index 6e4ce43f4..b0307258f 100644 --- a/quickshell/Widgets/DFloatingWindow.qml +++ b/quickshell/Widgets/DFloatingWindow.qml @@ -25,7 +25,7 @@ FloatingWindow { // No surfaceColor gate: compositor window rules can make this window translucent. WindowBlur { targetWindow: root - blurEnabled: root.contentVisible && Theme.connectedSurfaceBlurEnabled + blurEnabled: root.contentVisible blurX: 0 blurY: 0 blurWidth: root.visible ? root.width : 0 diff --git a/quickshell/Widgets/DPopoutHost.qml b/quickshell/Widgets/DPopoutHost.qml index c1d281559..97fb04615 100644 --- a/quickshell/Widgets/DPopoutHost.qml +++ b/quickshell/Widgets/DPopoutHost.qml @@ -1816,7 +1816,7 @@ Item { WindowBlur { id: popoutBlur targetWindow: contentWindow - blurEnabled: Theme.connectedSurfaceBlurEnabled && !root.frameOwnsConnectedChrome + blurEnabled: !root.frameOwnsConnectedChrome && (!root.usesConnectedSurfaceChrome || Theme.connectedSurfaceBlurEnabled) surfaceColor: chrome.surfaceColor readonly property real s: Math.min(1, contentContainer.scaleValue) diff --git a/quickshell/Widgets/DSlideout.qml b/quickshell/Widgets/DSlideout.qml index beeaa6626..9e9c0ec9c 100644 --- a/quickshell/Widgets/DSlideout.qml +++ b/quickshell/Widgets/DSlideout.qml @@ -28,7 +28,14 @@ PanelWindow { property real edgeGap: 0 property string slideEdge: "right" readonly property bool slideFromLeft: slideEdge === "left" - readonly property real surfaceOriginX: slideFromLeft ? 0 : Math.max(0, (modelData?.width ?? width) - width) + // Opt-in: the frame has a single slideout slot per screen. + property bool frameSurfaceEnabled: false + readonly property bool frameOwnsConnectedChrome: frameSurfaceEnabled && mappedVisible && CompositorService.canShareConnectedFrameChromeForScreen(modelData) + readonly property int frameInsetTop: _frameInset("top") + readonly property int frameInsetBottom: _frameInset("bottom") + readonly property int frameInsetEdge: _frameInset(slideEdge) + readonly property real surfaceOriginX: slideFromLeft ? frameInsetEdge : Math.max(0, (modelData?.width ?? width) - width - frameInsetEdge) + readonly property real surfaceOriginY: frameInsetTop property Component content: null property bool contentRequested: false property string title: "" @@ -71,9 +78,68 @@ PanelWindow { const padding = 24; const topLeft = slideContainer.mapToItem(null, 0, 0); const globalX = surfaceOriginX + topLeft.x; - return gx >= globalX - padding && gx < globalX + slideContainer.width + padding && gy >= topLeft.y - padding && gy < topLeft.y + slideContainer.height + padding; + const globalY = surfaceOriginY + topLeft.y; + return gx >= globalX - padding && gx < globalX + slideContainer.width + padding && gy >= globalY - padding && gy < globalY + slideContainer.height + padding; } + function _frameInset(edge) { + if (!frameOwnsConnectedChrome) + return 0; + return Math.max(0, Math.round(Theme.px(SettingsData.frameEdgeReservation(modelData, edge) + SettingsData.dockReservationForEdge(modelData, edge), dpr))); + } + + readonly property string _frameSlot: ConnectedModeState.surfaceSlot("slideout") + readonly property bool _frameClaimActive: frameOwnsConnectedChrome && mappedVisible && _slideoutScreenName !== "" + readonly property real _frameSurfaceOpacity: Theme.connectedSurfaceColor.a + readonly property var _frameMotion: ({ + "bodyX": surfaceOriginX + slideContainer.x, + "bodyY": surfaceOriginY + slideContainer.y, + "bodyW": slideContainer.width, + "bodyH": slideContainer.height, + "animX": slideoutSlideSnapX + }) + property string _claimedScreen: "" + property string _claimedOwner: "" + + function _releaseFrameClaim() { + if (!_claimedScreen) + return; + ConnectedModeState.releaseSurface(_claimedScreen, _frameSlot, _claimedOwner); + _claimedScreen = ""; + _claimedOwner = ""; + } + + function _syncFrameClaim() { + const owner = layerNamespace + ":" + _slideoutScreenName; + if (!_frameClaimActive || _claimedScreen !== _slideoutScreenName || _claimedOwner !== owner) + _releaseFrameClaim(); + if (!_frameClaimActive) + return; + if (ConnectedModeState.claimSurface(_slideoutScreenName, _frameSlot, Object.assign({ + "kind": "slideout", + "visible": true, + "presented": true, + "phase": "open", + "barSide": slideEdge, + "omitStartConnector": true, + "omitEndConnector": true, + "opacity": _frameSurfaceOpacity + }, _frameMotion), owner)) { + _claimedScreen = _slideoutScreenName; + _claimedOwner = owner; + } + } + + on_FrameClaimActiveChanged: _syncFrameClaim() + on_SlideoutScreenNameChanged: _syncFrameClaim() + onSlideEdgeChanged: _syncFrameClaim() + on_FrameSurfaceOpacityChanged: _syncFrameClaim() + on_FrameMotionChanged: { + if (_claimedScreen) + ConnectedModeState.setSurfaceMotion(_claimedScreen, _frameSlot, _claimedOwner, _frameMotion); + } + Component.onDestruction: _releaseFrameClaim() + function toggle() { if (isVisible) { hide(); @@ -103,22 +169,30 @@ PanelWindow { return !PopoutManager.cursorOverBar(PopoutManager.hoverCursorGlobalX, PopoutManager.hoverCursorGlobalY); } onDismissRequested: root.hideFromHoverDismiss() - onHoverMoved: (sceneX, sceneY) => PopoutManager.updateHoverCursor(root.surfaceOriginX + sceneX, sceneY) + onHoverMoved: (sceneX, sceneY) => PopoutManager.updateHoverCursor(root.surfaceOriginX + sceneX, root.surfaceOriginY + sceneY) } - readonly property bool slideoutBlurActive: root.visible && BlurService.enabled && Theme.connectedSurfaceBlurEnabled + readonly property bool slideoutBlurActive: root.visible && !root.frameOwnsConnectedChrome && BlurService.enabled && Theme.connectedSurfaceBlurEnabled readonly property string _slideoutScreenName: modelData?.name ?? "" WlrLayershell.layer: (!suppressOverlayLayer && (triggerUsesOverlayLayer || CompositorService.framePeerSurfacesUseOverlayForScreen(modelData))) ? WlrLayershell.Overlay : WlrLayershell.Top - WlrLayershell.exclusiveZone: 0 + // Frame-owned: sit exactly in the frame cutout so the claimed body matches the frame's own geometry. + WlrLayershell.exclusiveZone: frameOwnsConnectedChrome ? -1 : 0 + + margins { + top: root.frameInsetTop + bottom: root.frameInsetBottom + left: root.slideFromLeft ? root.frameInsetEdge : 0 + right: root.slideFromLeft ? 0 : root.frameInsetEdge + } WlrLayershell.keyboardFocus: isVisible && !ModalManager.currentModalsByScreen[_slideoutScreenName] ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None readonly property real dpr: CompositorService.getScreenScale(root.screen) readonly property real alignedWidth: Theme.px(expandable && expandedWidth ? expandedWidthValue : slideoutWidth, dpr) onAlignedWidthChanged: widthSpring.retarget(alignedWidth) readonly property real alignedHeight: Theme.px(modelData ? modelData.height : 800, dpr) - readonly property real alignedEdgeGap: Theme.px(edgeGap, dpr) + readonly property real alignedEdgeGap: frameOwnsConnectedChrome ? 0 : Theme.px(edgeGap, dpr) readonly property real slideoutSlideSnapX: Theme.snap(slideContainer.slideOffset, dpr) onIsVisibleChanged: { @@ -195,10 +269,10 @@ PanelWindow { clip: true readonly property color slideoutSurfaceColor: { - if (root.customTransparency >= 0) - return Theme.withAlpha(Theme.hostSurface, root.customTransparency); if (Theme.isConnectedEffect) return Theme.connectedSurfaceColor; + if (root.customTransparency >= 0) + return Theme.withAlpha(Theme.hostSurface, root.customTransparency); return Theme.readableSurface; } @@ -218,7 +292,7 @@ PanelWindow { Rectangle { anchors.fill: parent - color: Theme.isConnectedEffect ? contentRect.slideoutSurfaceColor : "transparent" + color: Theme.isConnectedEffect && !root.frameOwnsConnectedChrome ? contentRect.slideoutSurfaceColor : "transparent" radius: Theme.isConnectedEffect ? Theme.connectedSurfaceRadius : Theme.windowRadius border.color: Theme.isConnectedEffect ? Theme.withAlpha(BlurService.borderColor, 0) : BlurService.borderColor border.width: Theme.isConnectedEffect ? 0 : BlurService.borderWidth @@ -314,6 +388,7 @@ PanelWindow { WindowBlur { targetWindow: root + blurEnabled: root.slideoutBlurActive surfaceColor: contentRect.slideoutSurfaceColor blurX: root.slideoutBlurActive ? slideContainer.x + root.slideoutSlideSnapX : 0 blurY: root.slideoutBlurActive ? slideContainer.y : 0 diff --git a/quickshell/Widgets/WindowBlur.qml b/quickshell/Widgets/WindowBlur.qml index 9e2021664..4473f8ad7 100644 --- a/quickshell/Widgets/WindowBlur.qml +++ b/quickshell/Widgets/WindowBlur.qml @@ -10,7 +10,7 @@ Item { visible: false required property var targetWindow - property bool blurEnabled: Theme.connectedSurfaceBlurEnabled + property bool blurEnabled: true property color surfaceColor: "transparent" property real blurX: 0 property real blurY: 0 diff --git a/quickshell/tests/frame-bar-styles.test.mjs b/quickshell/tests/frame-bar-styles.test.mjs new file mode 100644 index 000000000..25e74e85d --- /dev/null +++ b/quickshell/tests/frame-bar-styles.test.mjs @@ -0,0 +1,111 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; +import vm from "node:vm"; + +function functions(source, indent, context) { + const pattern = new RegExp(`^${indent}function (\\w+)\\(([^)]*)\\)(?:: \\w+)? \\{([\\s\\S]*?)^${indent}\\}`, "gm"); + for (const [, name, parameters, body] of source.matchAll(pattern)) { + const args = parameters.replace(/:\s*\w+/g, ""); + vm.runInContext(`function ${name}(${args}) {${body}}`, context); + } + return context; +} + +const settingsSource = readFileSync(new URL("../Common/SettingsData.qml", import.meta.url), "utf8"); +const plain = value => JSON.parse(JSON.stringify(value)); +const styled = { shadowIntensity: 40, squareCorners: true, attachToScreenEdge: true, gothCornersEnabled: true, borderEnabled: true }; +const zeroed = { shadowIntensity: 0, squareCorners: false, attachToScreenEdge: false, gothCornersEnabled: false, borderEnabled: false }; +const style = cfg => Object.fromEntries(Object.keys(styled).map(key => [key, cfg[key]])); + +function frameSettings({ active = true, frameOn = ["A"], barConfigs, backups = {}, screens = [{ name: "A" }, { name: "B" }] } = {}) { + const settings = functions(settingsSource, " ", vm.createContext({ + Quickshell: { screens }, + connectedFrameModeActive: active, + frameScreenPreferences: frameOn, + connectedFrameBarStyleBackups: backups, + barConfigs: barConfigs ?? [{ id: "bar1", screenPreferences: ["A"], ...styled }, { id: "bar2", screenPreferences: ["B"], ...styled }] + })); + settings.barConfigCoversScreen = (cfg, screen) => cfg.screenPreferences.includes(screen.name); + settings.isScreenInPreferences = (screen, prefs) => prefs.includes(screen.name); + settings.updateBarConfigs = () => settings.updates++; + settings._restoreIslandWidget = () => {}; + settings.updates = 0; + return settings; +} + +const bar = (settings, id) => settings.barConfigs.find(cfg => cfg.id === id); + +test("only bars on a frame display are sanitized", () => { + const settings = frameSettings(); + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar1")), zeroed); + assert.deepEqual(style(bar(settings, "bar2")), styled); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), { bar1: styled }); + assert.equal(settings.barUsesConnectedFrameStyle(bar(settings, "bar1")), true); + assert.equal(settings.barUsesConnectedFrameStyle(bar(settings, "bar2")), false); + assert.equal(settings.barUsesConnectedFrameStyle(null), false); +}); + +test("moving the frame display swaps which bar is sanitized", () => { + const settings = frameSettings(); + settings._reconcileConnectedFrameBarStyles(); + settings.frameScreenPreferences = ["B"]; + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar1")), styled); + assert.deepEqual(style(bar(settings, "bar2")), zeroed); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), { bar2: styled }); +}); + +test("leaving connected mode restores all bars and clears backups", () => { + const settings = frameSettings({ frameOn: ["A", "B"] }); + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar2")), zeroed); + settings.connectedFrameModeActive = false; + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar1")), styled); + assert.deepEqual(style(bar(settings, "bar2")), styled); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), {}); + assert.equal(settings.barUsesConnectedFrameStyle(bar(settings, "bar1")), false); +}); + +test("legacy all-sanitized state self-heals on reconcile", () => { + const settings = frameSettings({ + barConfigs: [{ id: "bar1", screenPreferences: ["A"], ...zeroed }, { id: "bar2", screenPreferences: ["B"], ...zeroed }], + backups: { bar1: styled, bar2: styled, gone: styled } + }); + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar1")), zeroed); + assert.deepEqual(style(bar(settings, "bar2")), styled); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), { bar1: styled }); + assert.equal(settings.updates, 1); + settings._reconcileConnectedFrameBarStyles(); + assert.equal(settings.updates, 1, "a settled state does not write again"); +}); + +test("committing a bar onto a frame display captures its styling first", () => { + const settings = frameSettings({ barConfigs: [{ id: "bar2", screenPreferences: ["B"], ...styled }] }); + const configs = plain(settings.barConfigs); + configs[0].screenPreferences = ["A"]; + settings._commitBarConfigs(configs); + assert.deepEqual(style(bar(settings, "bar2")), zeroed); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), { bar2: styled }); +}); + +test("adding a bar off the frame display keeps its styling", () => { + const settings = frameSettings(); + settings._reconcileConnectedFrameBarStyles(); + settings.addBarConfig({ id: "bar3", screenPreferences: ["B"], ...styled }); + assert.deepEqual(style(bar(settings, "bar3")), styled); + assert.equal(plain(settings.connectedFrameBarStyleBackups).bar3, undefined); +}); + +test("an empty screen list leaves bar styles and backups alone", () => { + const settings = frameSettings(); + settings._reconcileConnectedFrameBarStyles(); + settings.Quickshell.screens = []; + settings._reconcileConnectedFrameBarStyles(); + assert.deepEqual(style(bar(settings, "bar1")), zeroed); + assert.deepEqual(plain(settings.connectedFrameBarStyleBackups), { bar1: styled }); + assert.equal(settings.updates, 1); +}); diff --git a/quickshell/tests/island-routing.test.mjs b/quickshell/tests/island-routing.test.mjs index fb0b98f38..3af1dd9e6 100644 --- a/quickshell/tests/island-routing.test.mjs +++ b/quickshell/tests/island-routing.test.mjs @@ -121,7 +121,7 @@ test("always-here is exclusive among islands and dots sharing a screen", () => { barConfigs: [{ id: "dot", dot: true, islandSharedRouting: "always" }, { id: "island", island: true }, { id: "remote", island: true, islandSharedRouting: "always" }] })); settings.updateBarConfigs = () => {}; - settings._sanitizeBarConfigsForConnectedFrame = configs => ({ configs }); + settings._applyConnectedFrameBarStyles = configs => ({ configs }); settings.barConfigCoversScreen = (cfg, screen) => covers[cfg.id].includes(screen.name); settings.setIslandSharedRouting("island", "always"); assert.deepEqual([...settings.barConfigs].map(cfg => cfg.islandSharedRouting), [undefined, "always", "always"], "same-screen always is reset, other-screen always is kept"); @@ -148,7 +148,7 @@ function hostedSettings(barConfigs, extra = {}) { settings.updateBarConfigs = () => {}; settings.barConfigCoversScreen = () => true; settings.getBarConfig = id => settings.barConfigs.find(cfg => cfg.id === id); - settings._sanitizeBarConfigsForConnectedFrame = configs => ({ configs }); + settings._applyConnectedFrameBarStyles = configs => ({ configs }); return settings; }