mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-09 15:08:31 -04:00
feat(Xray): Automatic Xray blur effects for Niri & Hyprland layouts
- Utilizes include layout within niri configs & hyprland's layout layer rules for lua configs
This commit is contained in:
@@ -176,10 +176,14 @@ Singleton {
|
|||||||
property int niriLayoutGapsOverride: -1
|
property int niriLayoutGapsOverride: -1
|
||||||
property int niriLayoutRadiusOverride: -1
|
property int niriLayoutRadiusOverride: -1
|
||||||
property int niriLayoutBorderSize: -1
|
property int niriLayoutBorderSize: -1
|
||||||
|
property bool niriLayoutXrayEnabled: false
|
||||||
|
property bool niriLayoutBarXrayEnabled: true
|
||||||
property int hyprlandLayoutGapsOverride: -1
|
property int hyprlandLayoutGapsOverride: -1
|
||||||
property int hyprlandLayoutRadiusOverride: -1
|
property int hyprlandLayoutRadiusOverride: -1
|
||||||
property int hyprlandLayoutBorderSize: -1
|
property int hyprlandLayoutBorderSize: -1
|
||||||
property bool hyprlandResizeOnBorder: false
|
property bool hyprlandResizeOnBorder: false
|
||||||
|
property bool hyprlandLayoutXrayEnabled: false
|
||||||
|
property bool hyprlandLayoutBarXrayEnabled: true
|
||||||
property int mangoLayoutGapsOverride: -1
|
property int mangoLayoutGapsOverride: -1
|
||||||
property int mangoLayoutRadiusOverride: -1
|
property int mangoLayoutRadiusOverride: -1
|
||||||
property int mangoLayoutBorderSize: -1
|
property int mangoLayoutBorderSize: -1
|
||||||
|
|||||||
@@ -28,10 +28,14 @@ var SPEC = {
|
|||||||
niriLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
niriLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
niriLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
niriLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
niriLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
niriLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
|
niriLayoutXrayEnabled: { def: false, onChange: "updateCompositorLayout" },
|
||||||
|
niriLayoutBarXrayEnabled: { def: true, onChange: "updateCompositorLayout" },
|
||||||
hyprlandLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
hyprlandLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
hyprlandLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
hyprlandLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
hyprlandLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
hyprlandLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
hyprlandResizeOnBorder: { def: false, onChange: "updateCompositorLayout" },
|
hyprlandResizeOnBorder: { def: false, onChange: "updateCompositorLayout" },
|
||||||
|
hyprlandLayoutXrayEnabled: { def: false, onChange: "updateCompositorLayout" },
|
||||||
|
hyprlandLayoutBarXrayEnabled: { def: true, onChange: "updateCompositorLayout" },
|
||||||
mangoLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
mangoLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
|
||||||
|
|||||||
@@ -310,6 +310,26 @@ Item {
|
|||||||
defaultValue: 2
|
defaultValue: 2
|
||||||
onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue)
|
onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
tags: ["niri", "xray", "blur", "background-effect", "performance"]
|
||||||
|
settingKey: "niriLayoutXrayEnabled"
|
||||||
|
text: I18n.tr("Xray Blur Effect")
|
||||||
|
description: SettingsData.niriLayoutXrayEnabled ? I18n.tr("Xray on makes the windows background visible through to the wallpaper") : I18n.tr("Xray off shows the real background beneath the blurred surfaces")
|
||||||
|
checked: SettingsData.niriLayoutXrayEnabled
|
||||||
|
onToggled: checked => SettingsData.set("niriLayoutXrayEnabled", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
// Hidden in Frame Connected mode, where it has no target
|
||||||
|
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
||||||
|
tags: ["niri", "xray", "bar", "frame", "performance"]
|
||||||
|
settingKey: "niriLayoutBarXrayEnabled"
|
||||||
|
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
||||||
|
description: SettingsData.niriLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar"))
|
||||||
|
checked: SettingsData.niriLayoutBarXrayEnabled
|
||||||
|
onToggled: checked => SettingsData.set("niriLayoutBarXrayEnabled", checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
@@ -416,6 +436,26 @@ Item {
|
|||||||
checked: SettingsData.hyprlandResizeOnBorder
|
checked: SettingsData.hyprlandResizeOnBorder
|
||||||
onToggled: checked => SettingsData.set("hyprlandResizeOnBorder", checked)
|
onToggled: checked => SettingsData.set("hyprlandResizeOnBorder", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
tags: ["hyprland", "xray", "blur", "background-effect", "performance"]
|
||||||
|
settingKey: "hyprlandLayoutXrayEnabled"
|
||||||
|
text: I18n.tr("Xray Blur Effect")
|
||||||
|
description: SettingsData.hyprlandLayoutXrayEnabled ? I18n.tr("Xray on makes the windows background visible through to the wallpaper") : I18n.tr("Xray off shows the real background beneath the blurred surfaces")
|
||||||
|
checked: SettingsData.hyprlandLayoutXrayEnabled
|
||||||
|
onToggled: checked => SettingsData.set("hyprlandLayoutXrayEnabled", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
// Hidden in Frame Connected mode, where it has no target
|
||||||
|
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
||||||
|
tags: ["hyprland", "xray", "bar", "frame", "performance"]
|
||||||
|
settingKey: "hyprlandLayoutBarXrayEnabled"
|
||||||
|
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
||||||
|
description: SettingsData.hyprlandLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar"))
|
||||||
|
checked: SettingsData.hyprlandLayoutBarXrayEnabled
|
||||||
|
onToggled: checked => SettingsData.set("hyprlandLayoutBarXrayEnabled", checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
|
|||||||
@@ -1812,6 +1812,40 @@ Item {
|
|||||||
defaultValue: 35
|
defaultValue: 35
|
||||||
onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100)
|
onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: xrayHintRow.implicitHeight
|
||||||
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: xrayHintRow
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "info"
|
||||||
|
size: Theme.iconSizeSmall
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width - Theme.iconSizeSmall - Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: I18n.tr("Xray specific options for blurred surfaces live in Compositor → Layout")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.primary
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: PopoutService.openSettingsWithTab("compositor_layout")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
|
|||||||
@@ -258,6 +258,14 @@ Singleton {
|
|||||||
const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps;
|
const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps;
|
||||||
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
|
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
|
||||||
const resizeOnBorder = (typeof SettingsData !== "undefined" && SettingsData.hyprlandResizeOnBorder) ? true : false;
|
const resizeOnBorder = (typeof SettingsData !== "undefined" && SettingsData.hyprlandResizeOnBorder) ? true : false;
|
||||||
|
const xrayEnabled = typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutXrayEnabled;
|
||||||
|
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.hyprlandLayoutBarXrayEnabled;
|
||||||
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
|
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
||||||
|
|
||||||
|
// Hyprland's `xray = false` is still in early development, so unlike niri we never emit it (unset already
|
||||||
|
// samples real content) - we only force xray=true
|
||||||
|
const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame");
|
||||||
|
|
||||||
let content = `-- Auto-generated by DMS — do not edit manually
|
let content = `-- Auto-generated by DMS — do not edit manually
|
||||||
|
|
||||||
@@ -274,6 +282,23 @@ hl.config({
|
|||||||
})
|
})
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
if (xrayEnabled) {
|
||||||
|
content += `
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "^dms:.*$" },
|
||||||
|
xray = true,
|
||||||
|
})
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
if (barFrameXrayEnabled && barFrameTargetNamespace) {
|
||||||
|
content += `
|
||||||
|
hl.layer_rule({
|
||||||
|
match = { namespace = "^${barFrameTargetNamespace}$" },
|
||||||
|
xray = true,
|
||||||
|
})
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
log.warn("Failed to write layout config:", output);
|
log.warn("Failed to write layout config:", output);
|
||||||
|
|||||||
@@ -1087,6 +1087,37 @@ Singleton {
|
|||||||
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius;
|
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutRadiusOverride >= 0) ? SettingsData.niriLayoutRadiusOverride : defaultRadius;
|
||||||
const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps;
|
const gaps = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutGapsOverride >= 0) ? SettingsData.niriLayoutGapsOverride : defaultGaps;
|
||||||
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
|
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.niriLayoutBorderSize >= 0) ? SettingsData.niriLayoutBorderSize : defaultBorderSize;
|
||||||
|
const xrayEnabled = typeof SettingsData !== "undefined" && SettingsData.niriLayoutXrayEnabled;
|
||||||
|
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.niriLayoutBarXrayEnabled;
|
||||||
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
|
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
||||||
|
|
||||||
|
// The one wallpaper-flush surface to force xray=true on: bar (Frame off) or Frame's Separate-mode border
|
||||||
|
const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame");
|
||||||
|
|
||||||
|
let xrayRules = "";
|
||||||
|
if (!xrayEnabled) {
|
||||||
|
let excludes = "";
|
||||||
|
if (frameEnabled)
|
||||||
|
excludes += `
|
||||||
|
exclude namespace="^dms:bar$"`;
|
||||||
|
xrayRules += `
|
||||||
|
layer-rule {
|
||||||
|
match namespace=".*"` + excludes + `
|
||||||
|
background-effect {
|
||||||
|
xray false
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
if (barFrameXrayEnabled && barFrameTargetNamespace) {
|
||||||
|
xrayRules += `
|
||||||
|
layer-rule {
|
||||||
|
match namespace="^${barFrameTargetNamespace}$"
|
||||||
|
background-effect {
|
||||||
|
xray true
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
const dmsWarning = `// ! DO NOT EDIT !
|
const dmsWarning = `// ! DO NOT EDIT !
|
||||||
// ! AUTO-GENERATED BY DMS !
|
// ! AUTO-GENERATED BY DMS !
|
||||||
@@ -1111,7 +1142,7 @@ Singleton {
|
|||||||
clip-to-geometry true
|
clip-to-geometry true
|
||||||
tiled-state true
|
tiled-state true
|
||||||
draw-border-with-background false
|
draw-border-with-background false
|
||||||
}`;
|
}` + xrayRules;
|
||||||
|
|
||||||
const alttabContent = dmsWarning + `recent-windows {
|
const alttabContent = dmsWarning + `recent-windows {
|
||||||
highlight {
|
highlight {
|
||||||
|
|||||||
@@ -8642,6 +8642,46 @@
|
|||||||
],
|
],
|
||||||
"description": "Width of window border and focus ring"
|
"description": "Width of window border and focus ring"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "hyprlandLayoutBarXrayEnabled",
|
||||||
|
"label": "Frame Xray",
|
||||||
|
"tabIndex": 37,
|
||||||
|
"category": "Personalization",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"bar",
|
||||||
|
"custom",
|
||||||
|
"customize",
|
||||||
|
"frame",
|
||||||
|
"hyprland",
|
||||||
|
"makes",
|
||||||
|
"performance",
|
||||||
|
"personal",
|
||||||
|
"personalization",
|
||||||
|
"xray"
|
||||||
|
],
|
||||||
|
"description": "Xray on makes the Frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"section": "niriLayoutBarXrayEnabled",
|
||||||
|
"label": "Frame Xray",
|
||||||
|
"tabIndex": 37,
|
||||||
|
"category": "Personalization",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"bar",
|
||||||
|
"custom",
|
||||||
|
"customize",
|
||||||
|
"frame",
|
||||||
|
"makes",
|
||||||
|
"niri",
|
||||||
|
"performance",
|
||||||
|
"personal",
|
||||||
|
"personalization",
|
||||||
|
"xray"
|
||||||
|
],
|
||||||
|
"description": "Xray on makes the Frame"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "hyprlandLayout",
|
"section": "hyprlandLayout",
|
||||||
"label": "Hyprland Layout Overrides",
|
"label": "Hyprland Layout Overrides",
|
||||||
@@ -9119,6 +9159,66 @@
|
|||||||
],
|
],
|
||||||
"description": "Space between windows"
|
"description": "Space between windows"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": "hyprlandLayoutXrayEnabled",
|
||||||
|
"label": "Xray Blur Effect",
|
||||||
|
"tabIndex": 37,
|
||||||
|
"category": "Personalization",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"background",
|
||||||
|
"background-effect",
|
||||||
|
"bg",
|
||||||
|
"blur",
|
||||||
|
"custom",
|
||||||
|
"customize",
|
||||||
|
"desktop",
|
||||||
|
"effect",
|
||||||
|
"hyprland",
|
||||||
|
"image",
|
||||||
|
"makes",
|
||||||
|
"performance",
|
||||||
|
"personal",
|
||||||
|
"personalization",
|
||||||
|
"picture",
|
||||||
|
"through",
|
||||||
|
"visible",
|
||||||
|
"wallpaper",
|
||||||
|
"windows",
|
||||||
|
"xray"
|
||||||
|
],
|
||||||
|
"description": "Xray on makes the windows background visible through to the wallpaper"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"section": "niriLayoutXrayEnabled",
|
||||||
|
"label": "Xray Blur Effect",
|
||||||
|
"tabIndex": 37,
|
||||||
|
"category": "Personalization",
|
||||||
|
"keywords": [
|
||||||
|
"appearance",
|
||||||
|
"background",
|
||||||
|
"background-effect",
|
||||||
|
"bg",
|
||||||
|
"blur",
|
||||||
|
"custom",
|
||||||
|
"customize",
|
||||||
|
"desktop",
|
||||||
|
"effect",
|
||||||
|
"image",
|
||||||
|
"makes",
|
||||||
|
"niri",
|
||||||
|
"performance",
|
||||||
|
"personal",
|
||||||
|
"personalization",
|
||||||
|
"picture",
|
||||||
|
"through",
|
||||||
|
"visible",
|
||||||
|
"wallpaper",
|
||||||
|
"windows",
|
||||||
|
"xray"
|
||||||
|
],
|
||||||
|
"description": "Xray on makes the windows background visible through to the wallpaper"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": "windowRules",
|
"section": "windowRules",
|
||||||
"label": "Window Rules",
|
"label": "Window Rules",
|
||||||
|
|||||||
Reference in New Issue
Block a user