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:
@@ -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
|
||||
@@ -575,36 +599,39 @@ func ConvertNiriRulesToWindowRules(niriRules []NiriWindowRule) []windowrules.Win
|
||||
},
|
||||
Matches: convertNiriMatches(nr.Matches),
|
||||
Actions: windowrules.Actions{
|
||||
Opacity: nr.Opacity,
|
||||
OpenFloating: nr.OpenFloating,
|
||||
OpenMaximized: nr.OpenMaximized,
|
||||
OpenMaximizedToEdges: nr.OpenMaximizedToEdges,
|
||||
OpenFullscreen: nr.OpenFullscreen,
|
||||
OpenFocused: nr.OpenFocused,
|
||||
OpenOnOutput: nr.OpenOnOutput,
|
||||
OpenOnWorkspace: nr.OpenOnWorkspace,
|
||||
DefaultColumnWidth: nr.DefaultColumnWidth,
|
||||
DefaultWindowHeight: nr.DefaultWindowHeight,
|
||||
VariableRefreshRate: nr.VariableRefreshRate,
|
||||
BlockOutFrom: nr.BlockOutFrom,
|
||||
DefaultColumnDisplay: nr.DefaultColumnDisplay,
|
||||
ScrollFactor: nr.ScrollFactor,
|
||||
CornerRadius: nr.CornerRadius,
|
||||
ClipToGeometry: nr.ClipToGeometry,
|
||||
TiledState: nr.TiledState,
|
||||
MinWidth: nr.MinWidth,
|
||||
MaxWidth: nr.MaxWidth,
|
||||
MinHeight: nr.MinHeight,
|
||||
MaxHeight: nr.MaxHeight,
|
||||
BorderColor: nr.BorderColor,
|
||||
FocusRingColor: nr.FocusRingColor,
|
||||
FocusRingOff: nr.FocusRingOff,
|
||||
BorderOff: nr.BorderOff,
|
||||
DrawBorderWithBg: nr.DrawBorderWithBg,
|
||||
BackgroundBlur: nr.BgBlur,
|
||||
BackgroundXray: nr.BgXray,
|
||||
BackgroundNoise: nr.BgNoise,
|
||||
BackgroundSaturation: nr.BgSaturation,
|
||||
Opacity: nr.Opacity,
|
||||
OpenFloating: nr.OpenFloating,
|
||||
OpenMaximized: nr.OpenMaximized,
|
||||
OpenMaximizedToEdges: nr.OpenMaximizedToEdges,
|
||||
OpenFullscreen: nr.OpenFullscreen,
|
||||
OpenFocused: nr.OpenFocused,
|
||||
OpenOnOutput: nr.OpenOnOutput,
|
||||
OpenOnWorkspace: nr.OpenOnWorkspace,
|
||||
DefaultColumnWidth: nr.DefaultColumnWidth,
|
||||
DefaultWindowHeight: nr.DefaultWindowHeight,
|
||||
VariableRefreshRate: nr.VariableRefreshRate,
|
||||
BlockOutFrom: nr.BlockOutFrom,
|
||||
DefaultColumnDisplay: nr.DefaultColumnDisplay,
|
||||
ScrollFactor: nr.ScrollFactor,
|
||||
CornerRadius: nr.CornerRadius,
|
||||
ClipToGeometry: nr.ClipToGeometry,
|
||||
TiledState: nr.TiledState,
|
||||
MinWidth: nr.MinWidth,
|
||||
MaxWidth: nr.MaxWidth,
|
||||
MinHeight: nr.MinHeight,
|
||||
MaxHeight: nr.MaxHeight,
|
||||
BorderColor: nr.BorderColor,
|
||||
FocusRingColor: nr.FocusRingColor,
|
||||
FocusRingOff: nr.FocusRingOff,
|
||||
BorderOff: nr.BorderOff,
|
||||
DrawBorderWithBg: nr.DrawBorderWithBg,
|
||||
BackgroundBlur: nr.BgBlur,
|
||||
BackgroundXray: nr.BgXray,
|
||||
BackgroundNoise: nr.BgNoise,
|
||||
BackgroundSaturation: nr.BgSaturation,
|
||||
DefaultFloatingX: nr.DefaultFloatingX,
|
||||
DefaultFloatingY: nr.DefaultFloatingY,
|
||||
DefaultFloatingRelativeTo: nr.DefaultFloatingRelative,
|
||||
},
|
||||
}
|
||||
result = append(result, wr)
|
||||
@@ -785,36 +812,39 @@ func (p *NiriWritableProvider) LoadDMSRules() ([]windowrules.WindowRule, error)
|
||||
},
|
||||
Matches: convertNiriMatches(nr.Matches),
|
||||
Actions: windowrules.Actions{
|
||||
Opacity: nr.Opacity,
|
||||
OpenFloating: nr.OpenFloating,
|
||||
OpenMaximized: nr.OpenMaximized,
|
||||
OpenMaximizedToEdges: nr.OpenMaximizedToEdges,
|
||||
OpenFullscreen: nr.OpenFullscreen,
|
||||
OpenFocused: nr.OpenFocused,
|
||||
OpenOnOutput: nr.OpenOnOutput,
|
||||
OpenOnWorkspace: nr.OpenOnWorkspace,
|
||||
DefaultColumnWidth: nr.DefaultColumnWidth,
|
||||
DefaultWindowHeight: nr.DefaultWindowHeight,
|
||||
VariableRefreshRate: nr.VariableRefreshRate,
|
||||
BlockOutFrom: nr.BlockOutFrom,
|
||||
DefaultColumnDisplay: nr.DefaultColumnDisplay,
|
||||
ScrollFactor: nr.ScrollFactor,
|
||||
CornerRadius: nr.CornerRadius,
|
||||
ClipToGeometry: nr.ClipToGeometry,
|
||||
TiledState: nr.TiledState,
|
||||
MinWidth: nr.MinWidth,
|
||||
MaxWidth: nr.MaxWidth,
|
||||
MinHeight: nr.MinHeight,
|
||||
MaxHeight: nr.MaxHeight,
|
||||
BorderColor: nr.BorderColor,
|
||||
FocusRingColor: nr.FocusRingColor,
|
||||
FocusRingOff: nr.FocusRingOff,
|
||||
BorderOff: nr.BorderOff,
|
||||
DrawBorderWithBg: nr.DrawBorderWithBg,
|
||||
BackgroundBlur: nr.BgBlur,
|
||||
BackgroundXray: nr.BgXray,
|
||||
BackgroundNoise: nr.BgNoise,
|
||||
BackgroundSaturation: nr.BgSaturation,
|
||||
Opacity: nr.Opacity,
|
||||
OpenFloating: nr.OpenFloating,
|
||||
OpenMaximized: nr.OpenMaximized,
|
||||
OpenMaximizedToEdges: nr.OpenMaximizedToEdges,
|
||||
OpenFullscreen: nr.OpenFullscreen,
|
||||
OpenFocused: nr.OpenFocused,
|
||||
OpenOnOutput: nr.OpenOnOutput,
|
||||
OpenOnWorkspace: nr.OpenOnWorkspace,
|
||||
DefaultColumnWidth: nr.DefaultColumnWidth,
|
||||
DefaultWindowHeight: nr.DefaultWindowHeight,
|
||||
VariableRefreshRate: nr.VariableRefreshRate,
|
||||
BlockOutFrom: nr.BlockOutFrom,
|
||||
DefaultColumnDisplay: nr.DefaultColumnDisplay,
|
||||
ScrollFactor: nr.ScrollFactor,
|
||||
CornerRadius: nr.CornerRadius,
|
||||
ClipToGeometry: nr.ClipToGeometry,
|
||||
TiledState: nr.TiledState,
|
||||
MinWidth: nr.MinWidth,
|
||||
MaxWidth: nr.MaxWidth,
|
||||
MinHeight: nr.MinHeight,
|
||||
MaxHeight: nr.MaxHeight,
|
||||
BorderColor: nr.BorderColor,
|
||||
FocusRingColor: nr.FocusRingColor,
|
||||
FocusRingOff: nr.FocusRingOff,
|
||||
BorderOff: nr.BorderOff,
|
||||
DrawBorderWithBg: nr.DrawBorderWithBg,
|
||||
BackgroundBlur: nr.BgBlur,
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -47,22 +47,26 @@ type Actions struct {
|
||||
BackgroundXray *bool `json:"backgroundXray,omitempty"`
|
||||
BackgroundNoise *float64 `json:"backgroundNoise,omitempty"`
|
||||
BackgroundSaturation *float64 `json:"backgroundSaturation,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
Move string `json:"move,omitempty"`
|
||||
Monitor string `json:"monitor,omitempty"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
Tile *bool `json:"tile,omitempty"`
|
||||
NoFocus *bool `json:"nofocus,omitempty"`
|
||||
NoBorder *bool `json:"noborder,omitempty"`
|
||||
NoShadow *bool `json:"noshadow,omitempty"`
|
||||
NoDim *bool `json:"nodim,omitempty"`
|
||||
NoBlur *bool `json:"noblur,omitempty"`
|
||||
NoAnim *bool `json:"noanim,omitempty"`
|
||||
NoRounding *bool `json:"norounding,omitempty"`
|
||||
Pin *bool `json:"pin,omitempty"`
|
||||
Opaque *bool `json:"opaque,omitempty"`
|
||||
ForcergbX *bool `json:"forcergbx,omitempty"`
|
||||
Idleinhibit string `json:"idleinhibit,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"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
Tile *bool `json:"tile,omitempty"`
|
||||
NoFocus *bool `json:"nofocus,omitempty"`
|
||||
NoBorder *bool `json:"noborder,omitempty"`
|
||||
NoShadow *bool `json:"noshadow,omitempty"`
|
||||
NoDim *bool `json:"nodim,omitempty"`
|
||||
NoBlur *bool `json:"noblur,omitempty"`
|
||||
NoAnim *bool `json:"noanim,omitempty"`
|
||||
NoRounding *bool `json:"norounding,omitempty"`
|
||||
Pin *bool `json:"pin,omitempty"`
|
||||
Opaque *bool `json:"opaque,omitempty"`
|
||||
ForcergbX *bool `json:"forcergbx,omitempty"`
|
||||
Idleinhibit string `json:"idleinhibit,omitempty"`
|
||||
}
|
||||
|
||||
type WindowRule struct {
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user