1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-07 19:59:14 -04:00

feat(window-rules): add niri default-floating-position rule

- Closes #2018
This commit is contained in:
purian23
2026-06-03 19:43:23 -04:00
parent 6f387b0481
commit 6e7aca8b15
4 changed files with 233 additions and 77 deletions
@@ -67,6 +67,9 @@ type NiriWindowRule struct {
BgXray *bool
BgNoise *float64
BgSaturation *float64
DefaultFloatingX *int
DefaultFloatingY *int
DefaultFloatingRelative string
Source string
}
@@ -316,6 +319,8 @@ func (p *NiriRulesParser) parseWindowRuleNode(node *document.Node) {
rule.DrawBorderWithBg = &b
case "background-effect":
p.parseBackgroundEffectNode(child, &rule)
case "default-floating-position":
p.parseFloatingPositionNode(child, &rule)
}
}
@@ -444,6 +449,25 @@ func (p *NiriRulesParser) parseBackgroundEffectNode(node *document.Node, rule *N
}
}
func (p *NiriRulesParser) parseFloatingPositionNode(node *document.Node, rule *NiriWindowRule) {
if node.Properties == nil {
return
}
if val, ok := node.Properties.Get("x"); ok {
if n, err := strconv.Atoi(strings.TrimSpace(val.ValueString())); err == nil {
rule.DefaultFloatingX = &n
}
}
if val, ok := node.Properties.Get("y"); ok {
if n, err := strconv.Atoi(strings.TrimSpace(val.ValueString())); err == nil {
rule.DefaultFloatingY = &n
}
}
if val, ok := node.Properties.Get("relative-to"); ok {
rule.DefaultFloatingRelative = val.ValueString()
}
}
func (p *NiriRulesParser) parseFloatArg(node *document.Node) (float64, bool) {
if len(node.Arguments) == 0 {
return 0, false
@@ -605,6 +629,9 @@ func ConvertNiriRulesToWindowRules(niriRules []NiriWindowRule) []windowrules.Win
BackgroundXray: nr.BgXray,
BackgroundNoise: nr.BgNoise,
BackgroundSaturation: nr.BgSaturation,
DefaultFloatingX: nr.DefaultFloatingX,
DefaultFloatingY: nr.DefaultFloatingY,
DefaultFloatingRelativeTo: nr.DefaultFloatingRelative,
},
}
result = append(result, wr)
@@ -815,6 +842,9 @@ func (p *NiriWritableProvider) LoadDMSRules() ([]windowrules.WindowRule, error)
BackgroundXray: nr.BgXray,
BackgroundNoise: nr.BgNoise,
BackgroundSaturation: nr.BgSaturation,
DefaultFloatingX: nr.DefaultFloatingX,
DefaultFloatingY: nr.DefaultFloatingY,
DefaultFloatingRelativeTo: nr.DefaultFloatingRelative,
},
}
@@ -989,6 +1019,14 @@ func (p *NiriWritableProvider) formatRule(rule windowrules.WindowRule) string {
lines = append(lines, " }")
}
if a.DefaultFloatingX != nil && a.DefaultFloatingY != nil {
line := fmt.Sprintf(" default-floating-position x=%d y=%d", *a.DefaultFloatingX, *a.DefaultFloatingY)
if a.DefaultFloatingRelativeTo != "" {
line += fmt.Sprintf(" relative-to=%q", a.DefaultFloatingRelativeTo)
}
lines = append(lines, line)
}
lines = append(lines, "}")
return strings.Join(lines, "\n")
}
+4
View File
@@ -47,6 +47,10 @@ type Actions struct {
BackgroundXray *bool `json:"backgroundXray,omitempty"`
BackgroundNoise *float64 `json:"backgroundNoise,omitempty"`
BackgroundSaturation *float64 `json:"backgroundSaturation,omitempty"`
DefaultFloatingX *int `json:"defaultFloatingX,omitempty"`
DefaultFloatingY *int `json:"defaultFloatingY,omitempty"`
DefaultFloatingRelativeTo string `json:"defaultFloatingRelativeTo,omitempty"`
Size string `json:"size,omitempty"`
Move string `json:"move,omitempty"`
Monitor string `json:"monitor,omitempty"`
+112 -1
View File
@@ -74,6 +74,9 @@ FloatingWindow {
noiseSlider.value = 5;
saturationEnabled.checked = false;
saturationSlider.value = 100;
floatingXInput.text = "";
floatingYInput.text = "";
floatingRelativeDropdown.currentValue = "top-left";
minWidthInput.text = "";
maxWidthInput.text = "";
minHeightInput.text = "";
@@ -183,6 +186,10 @@ FloatingWindow {
saturationEnabled.checked = hasSaturation;
saturationSlider.value = hasSaturation ? Math.round(actions.backgroundSaturation * 100) : 100;
floatingXInput.text = (actions.defaultFloatingX !== undefined && actions.defaultFloatingX !== null) ? String(actions.defaultFloatingX) : "";
floatingYInput.text = (actions.defaultFloatingY !== undefined && actions.defaultFloatingY !== null) ? String(actions.defaultFloatingY) : "";
floatingRelativeDropdown.currentValue = actions.defaultFloatingRelativeTo || "top-left";
minWidthInput.text = actions.minWidth !== undefined ? String(actions.minWidth) : "";
maxWidthInput.text = actions.maxWidth !== undefined ? String(actions.maxWidth) : "";
minHeightInput.text = actions.minHeight !== undefined ? String(actions.minHeight) : "";
@@ -327,6 +334,15 @@ FloatingWindow {
if (saturationEnabled.checked && isNiri)
actions.backgroundSaturation = saturationSlider.value / 100;
const floatX = parseInt(floatingXInput.text);
const floatY = parseInt(floatingYInput.text);
if (isNiri && !isNaN(floatX) && !isNaN(floatY)) {
actions.defaultFloatingX = floatX;
actions.defaultFloatingY = floatY;
if (floatingRelativeDropdown.currentValue && floatingRelativeDropdown.currentValue !== "top-left")
actions.defaultFloatingRelativeTo = floatingRelativeDropdown.currentValue;
}
const minW = parseInt(minWidthInput.text);
const maxW = parseInt(maxWidthInput.text);
const minH = parseInt(minHeightInput.text);
@@ -496,7 +512,7 @@ FloatingWindow {
id: mc
property string label: ""
property int triState: 0
property string unsetLabel: I18n.tr("Any")
property string unsetLabel: I18n.tr("Default")
property bool readOnly: false
readonly property var stateText: [mc.unsetLabel, "true", "false"]
readonly property var stateColor: [Theme.surfaceVariantText, Theme.primary, Theme.error]
@@ -1239,6 +1255,101 @@ FloatingWindow {
}
}
SectionHeader {
title: I18n.tr("Floating Position")
visible: isNiri
}
StyledText {
width: parent.width
visible: isNiri
text: I18n.tr("Initial position for floating windows. Set both X and Y; anchor controls which corner/edge they're relative to.")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
Row {
width: parent.width
spacing: Theme.spacingM
visible: isNiri
Column {
width: (parent.width - Theme.spacingM * 2) / 3
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("X")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
horizontalAlignment: Text.AlignLeft
}
InputField {
width: parent.width
hasFocus: floatingXInput.activeFocus
DankTextField {
id: floatingXInput
anchors.fill: parent
font.pixelSize: Theme.fontSizeSmall
textColor: Theme.surfaceText
placeholderText: "px"
backgroundColor: "transparent"
enabled: root.visible
}
}
}
Column {
width: (parent.width - Theme.spacingM * 2) / 3
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Y")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
horizontalAlignment: Text.AlignLeft
}
InputField {
width: parent.width
hasFocus: floatingYInput.activeFocus
DankTextField {
id: floatingYInput
anchors.fill: parent
font.pixelSize: Theme.fontSizeSmall
textColor: Theme.surfaceText
placeholderText: "px"
backgroundColor: "transparent"
enabled: root.visible
}
}
}
Column {
width: (parent.width - Theme.spacingM * 2) / 3
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Anchor")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
horizontalAlignment: Text.AlignLeft
}
DankDropdown {
id: floatingRelativeDropdown
width: parent.width
dropdownWidth: parent.width
compactMode: true
options: ["top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right"]
}
}
}
SectionHeader {
title: I18n.tr("Size Constraints")
}
@@ -121,6 +121,9 @@ Item {
"backgroundXray": I18n.tr("X-Ray"),
"backgroundNoise": I18n.tr("Noise"),
"backgroundSaturation": I18n.tr("Saturation"),
"defaultFloatingX": I18n.tr("Float X"),
"defaultFloatingY": I18n.tr("Float Y"),
"defaultFloatingRelativeTo": I18n.tr("Float Anchor"),
"borderColor": I18n.tr("Border Color"),
"focusRingColor": I18n.tr("Focus Ring Color"),
"focusRingOff": I18n.tr("Focus Ring Off"),