fix(frame): make connected mode honor the settings it overrides (#3665)

* fix(frame): make connected mode honor the settings it overrides

Several frame-mode behaviors contradicted what the settings UI shows:

- Frame -> Blur gated blur for every shell surface in connected mode,
  including the Settings window, polkit, context menus, OSDs and toasts.
  WindowBlur now defaults to Background blur; only surfaces painted
  with the frame color (connected popouts, slideouts, Control Center)
  follow Frame -> Blur, and frame-owned surfaces are blurred by the
  frame as before.
- The notepad slideout painted its own fill at the notepad
  transparency. On screens where the frame owns connected chrome it now
  claims a frame surface (new connected_arc slot 5), so the frame paints
  it flush with the cutout, with fillets, and follows the slide.
- Notification popups painted a card surface on top of the frame body,
  stacking fills. That layer is transparent when the frame paints it.
- Connected mode stripped shadow, border and corner styling from every
  bar, including bars on displays without a frame, and hid the rows.
  Styling is now stripped and restored per bar based on whether it
  covers a frame display, re-checked on screen, frame display and
  display-name-mode changes.
- Auto popup gaps and Gap size were hidden in separate mode although
  they still apply there; they now hide only in connected mode.
- The launcher style picker was hidden in connected mode while Island
  still overrode the connected launcher. Connected mode now always uses
  the connected launcher; the picker shows Full, disabled, with a note
  linking to the Bar layout picker.
- The frame shadow ignored Shadows -> Apply to -> Bars.

* fix(frame): address review feedback on connected mode

- Skip bar style reconciliation while the screen list is empty, so a
  hotplug doesn't restore and re-strip every bar.
- Replace the 16 copies of the connector blur anchor and cutout in
  FrameWindow with a ConnectorBlurRegion inline component.
- Let connected mode use the island launcher again now that the island
  can sit in any bar. The picker offers Full and Island there and hides
  Spotlight, which opens the full launcher in that mode anyway; the note
  and the SettingsControlledBy bar target are dropped.

* frame: address review findings on connected mode

---------

Co-authored-by: purian23 <[email protected]>
This commit is contained in:
Marlon Kranz
2026-10-10 00:04:17 -04:00
committed by GitHub
co-authored by purian23
parent 938971e758
commit 0444835016
22 changed files with 467 additions and 520 deletions
@@ -6,7 +6,8 @@ var VALID_KINDS = {
"launcher": true,
"dock": true,
"notification": true,
"island": true
"island": true,
"slideout": true
};
var VALID_PHASES = {
+59 -111
View File
@@ -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();
}
+1
View File
@@ -1068,6 +1068,7 @@ Item {
expandable: true
expandedWidthValue: 960
edgeGap: SettingsData.notepadEffectiveEdgeGap
frameSurfaceEnabled: true
slideEdge: SettingsData.notepadSlideoutSide
customTransparency: Theme.notepadTransparency
+1 -2
View File
@@ -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))
@@ -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
+1 -1
View File
@@ -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
-1
View File
@@ -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
+182 -371
View File
@@ -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 {
+1
View File
@@ -544,6 +544,7 @@ Item {
id: notepadSettings
anchors.fill: parent
isVisible: showSettingsMenu
frameManagesGap: root.slideout?.frameOwnsConnectedChrome ?? false
onSettingsRequested: showSettingsMenu = !showSettingsMenu
onFindRequested: {
showSettingsMenu = false;
@@ -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
+3 -2
View File
@@ -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
+3 -11
View File
@@ -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)
@@ -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) {
+7 -1
View File
@@ -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;
}
Binary file not shown.
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+84 -9
View File
@@ -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
+1 -1
View File
@@ -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
+111
View File
@@ -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);
});
+2 -2
View File
@@ -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;
}