1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-20 10:05:22 -04:00

Compare commits

...

6 Commits

Author SHA1 Message Date
purian23 59431869dc fix(keybinds): guard missing fields in cheatsheet search filter
Fixes #2116
2026-06-03 20:06:14 -04:00
purian23 6e7aca8b15 feat(window-rules): add niri default-floating-position rule
- Closes #2018
2026-06-03 19:43:23 -04:00
purian23 6f387b0481 fix(windowrules): honor $XDG_CONFIG_HOME for config paths
- Window rule read/write/includes detection and setup hardcoded
`$HOME/.config` so rules weren't applied when `XDG_CONFIG_HOME` pointed
elsewhere.
- Fixes #2289
2026-06-03 19:01:25 -04:00
purian23 82d4364032 feat(hyprland): add Resize on Border layout option 2026-06-03 18:45:33 -04:00
purian23 e3de54c941 feat(workspace): optionally group app icons on the active workspace
Closes #1208
2026-06-03 18:32:53 -04:00
purian23 6991b45fbe fix(settings): surface Windows Rules Tab for Hyprland
- small hyprland parser update
2026-06-03 17:39:44 -04:00
16 changed files with 290 additions and 119 deletions
+3 -12
View File
@@ -87,10 +87,7 @@ func runResolveInclude(cmd *cobra.Command, args []string) {
}
func checkHyprlandInclude(filename string) (IncludeResult, error) {
configDir, err := utils.ExpandPath("$HOME/.config/hypr")
if err != nil {
return IncludeResult{}, err
}
configDir := filepath.Join(utils.XDGConfigHome(), "hypr")
targetPath := filepath.Join(configDir, "dms", filename)
result := IncludeResult{}
@@ -191,10 +188,7 @@ func hyprlandFindIncludeHyprlang(filePath, target string, processed map[string]b
}
func checkNiriInclude(filename string) (IncludeResult, error) {
configDir, err := utils.ExpandPath("$HOME/.config/niri")
if err != nil {
return IncludeResult{}, err
}
configDir := filepath.Join(utils.XDGConfigHome(), "niri")
targetPath := filepath.Join(configDir, "dms", filename)
result := IncludeResult{}
@@ -270,10 +264,7 @@ func niriFindInclude(filePath, target string, processed map[string]bool) bool {
}
func checkMangoWCInclude(filename string) (IncludeResult, error) {
configDir, err := utils.ExpandPath("$HOME/.config/mango")
if err != nil {
return IncludeResult{}, err
}
configDir := filepath.Join(utils.XDGConfigHome(), "mango")
targetPath := filepath.Join(configDir, "dms", filename)
result := IncludeResult{}
+2 -2
View File
@@ -235,9 +235,9 @@ func runSetupDmsConfig(name string) error {
var dmsDir string
switch compositor {
case "niri":
dmsDir = filepath.Join(os.Getenv("HOME"), ".config", "niri", "dms")
dmsDir = filepath.Join(utils.XDGConfigHome(), "niri", "dms")
case "hyprland":
dmsDir = filepath.Join(os.Getenv("HOME"), ".config", "hypr", "dms")
dmsDir = filepath.Join(utils.XDGConfigHome(), "hypr", "dms")
}
if err := os.MkdirAll(dmsDir, 0o755); err != nil {
+5 -16
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
@@ -146,10 +147,7 @@ func runWindowrulesList(cmd *cobra.Command, args []string) {
switch compositor {
case "niri":
configDir, err := utils.ExpandPath("$HOME/.config/niri")
if err != nil {
log.Fatalf("Failed to expand niri config path: %v", err)
}
configDir := filepath.Join(utils.XDGConfigHome(), "niri")
parseResult, err := providers.ParseNiriWindowRules(configDir)
if err != nil {
@@ -182,10 +180,7 @@ func runWindowrulesList(cmd *cobra.Command, args []string) {
result.DMSStatus = parseResult.DMSStatus
case "hyprland":
configDir, err := utils.ExpandPath("$HOME/.config/hypr")
if err != nil {
log.Fatalf("Failed to expand hyprland config path: %v", err)
}
configDir := filepath.Join(utils.XDGConfigHome(), "hypr")
parseResult, err := providers.ParseHyprlandWindowRules(configDir)
if err != nil {
@@ -315,16 +310,10 @@ func runWindowrulesReorder(cmd *cobra.Command, args []string) {
func getWindowRulesProvider(compositor string) windowrules.WritableProvider {
switch compositor {
case "niri":
configDir, err := utils.ExpandPath("$HOME/.config/niri")
if err != nil {
return nil
}
configDir := filepath.Join(utils.XDGConfigHome(), "niri")
return providers.NewNiriWritableProvider(configDir)
case "hyprland":
configDir, err := utils.ExpandPath("$HOME/.config/hypr")
if err != nil {
return nil
}
configDir := filepath.Join(utils.XDGConfigHome(), "hypr")
return providers.NewHyprlandWritableProvider(configDir)
default:
return nil
@@ -799,11 +799,7 @@ func (p *HyprlandWritableProvider) loadDMSRulesFromLua(data []byte, rulesPath st
Actions: *acts,
}
if wr.ID == "" {
if wr.MatchCriteria.AppID != "" {
wr.ID = wr.MatchCriteria.AppID
} else {
wr.ID = wr.MatchCriteria.Title
}
wr.ID = fmt.Sprintf("dms_rule_%d", len(rules))
}
rules = append(rules, wr)
}
@@ -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")
}
+20 -16
View File
@@ -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 {
+2
View File
@@ -173,6 +173,7 @@ Singleton {
property int hyprlandLayoutGapsOverride: -1
property int hyprlandLayoutRadiusOverride: -1
property int hyprlandLayoutBorderSize: -1
property bool hyprlandResizeOnBorder: false
property int mangoLayoutGapsOverride: -1
property int mangoLayoutRadiusOverride: -1
property int mangoLayoutBorderSize: -1
@@ -372,6 +373,7 @@ Singleton {
property bool showWorkspaceApps: false
property bool workspaceDragReorder: true
property bool groupWorkspaceApps: true
property bool groupActiveWorkspaceApps: false
property int maxWorkspaceIcons: 3
property int workspaceAppIconSizeOffset: 0
property bool workspaceFollowFocus: false
@@ -29,6 +29,7 @@ var SPEC = {
hyprlandLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
hyprlandLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
hyprlandLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
hyprlandResizeOnBorder: { def: false, onChange: "updateCompositorLayout" },
mangoLayoutGapsOverride: { def: -1, onChange: "updateCompositorLayout" },
mangoLayoutRadiusOverride: { def: -1, onChange: "updateCompositorLayout" },
mangoLayoutBorderSize: { def: -1, onChange: "updateCompositorLayout" },
@@ -134,6 +135,7 @@ var SPEC = {
maxWorkspaceIcons: { def: 3 },
workspaceAppIconSizeOffset: { def: 0 },
groupWorkspaceApps: { def: true },
groupActiveWorkspaceApps: { def: false },
workspaceFollowFocus: { def: false },
showOccupiedWorkspacesOnly: { def: false },
reverseScrolling: { def: false },
+4 -4
View File
@@ -81,7 +81,7 @@ DankModal {
StyledText {
Layout.alignment: Qt.AlignLeft
text: KeybindsService.cheatsheet.title || i18n("Keybinds")
text: KeybindsService.cheatsheet.title || I18n.tr("Keybinds")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.primary
@@ -133,9 +133,9 @@ DankModal {
let hasSubcats = false;
for (let i = 0; i < binds.length; i++) {
const bind = binds[i];
const keyLower = bind.key.toLowerCase();
const descLower = bind.desc.toLowerCase();
const actionLower = bind.action.toLowerCase();
const keyLower = (bind.key || "").toLowerCase();
const descLower = (bind.desc || "").toLowerCase();
const actionLower = (bind.action || "").toLowerCase();
if (bind.hideOnOverlay)
continue;
@@ -311,7 +311,7 @@ Rectangle {
"text": I18n.tr("Window Rules"),
"icon": "select_window",
"tabIndex": 28,
"niriOnly": true
"hyprlandNiriOnly": true
}
]
},
+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")
}
@@ -340,7 +340,8 @@ Item {
const keyBase = (w.app_id || w.appId || w.class || w.windowClass || "unknown");
const moddedId = Paths.moddedAppId(keyBase);
const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${moddedId}_${i}` : moddedId;
const groupThisWs = SettingsData.groupWorkspaceApps && (!isActiveWs || SettingsData.groupActiveWorkspaceApps);
const key = groupThisWs ? moddedId : `${moddedId}_${i}`;
if (!byApp[key]) {
const isQuickshell = keyBase === "org.quickshell" || keyBase === "com.danklinux.dms";
@@ -1091,7 +1092,7 @@ Item {
}
}
return (SettingsData.groupWorkspaceApps && !isActive) ? groupedCount : totalCount;
return (SettingsData.groupWorkspaceApps && (!isActive || SettingsData.groupActiveWorkspaceApps)) ? groupedCount : totalCount;
}
readonly property real baseWidth: root.isVertical ? (SettingsData.showWorkspaceApps ? Math.max(widgetHeight * 0.7, root.appIconSize + Theme.spacingXS * 2) : widgetHeight * 0.5) : (isActive ? Math.max(root.widgetHeight * 1.05, root.appIconSize * 1.6) : Math.max(root.widgetHeight * 0.7, root.appIconSize * 1.2))
@@ -1883,6 +1884,12 @@ Item {
delegateRoot.updateAllData();
}
}
Connections {
target: root
function onCurrentWorkspaceChanged() {
delegateRoot.updateAllData();
}
}
Connections {
target: NiriService
enabled: CompositorService.isNiri
@@ -1907,6 +1914,12 @@ Item {
function onAppIdSubstitutionsChanged() {
delegateRoot.updateAllData();
}
function onGroupWorkspaceAppsChanged() {
delegateRoot.updateAllData();
}
function onGroupActiveWorkspaceAppsChanged() {
delegateRoot.updateAllData();
}
}
Connections {
target: DwlService
@@ -2159,6 +2159,16 @@ Item {
defaultValue: 2
onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue)
}
SettingsToggleRow {
tab: "theme"
tags: ["hyprland", "resize", "border", "mouse", "drag"]
settingKey: "hyprlandResizeOnBorder"
text: I18n.tr("Resize on Border")
description: I18n.tr("Resize windows by dragging their edges with the mouse")
checked: SettingsData.hyprlandResizeOnBorder
onToggled: checked => SettingsData.set("hyprlandResizeOnBorder", checked)
}
}
SettingsCard {
@@ -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"),
@@ -125,6 +125,16 @@ Item {
onToggled: checked => SettingsData.set("groupWorkspaceApps", checked)
}
SettingsToggleRow {
settingKey: "groupActiveWorkspaceApps"
tags: ["workspace", "apps", "icons", "group", "grouped", "active", "focused"]
text: I18n.tr("Group Active Workspace")
description: I18n.tr("Also group repeated application icons on the active workspace")
checked: SettingsData.groupActiveWorkspaceApps
visible: SettingsData.showWorkspaceApps && SettingsData.groupWorkspaceApps
onToggled: checked => SettingsData.set("groupActiveWorkspaceApps", checked)
}
SettingsToggleRow {
settingKey: "workspaceActiveAppHighlightEnabled"
tags: ["workspace", "apps", "icons", "highlight", "active", "focused"]
+2
View File
@@ -257,6 +257,7 @@ Singleton {
const cornerRadius = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutRadiusOverride >= 0) ? SettingsData.hyprlandLayoutRadiusOverride : defaultRadius;
const gaps = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutGapsOverride >= 0) ? SettingsData.hyprlandLayoutGapsOverride : defaultGaps;
const borderSize = (typeof SettingsData !== "undefined" && SettingsData.hyprlandLayoutBorderSize >= 0) ? SettingsData.hyprlandLayoutBorderSize : defaultBorderSize;
const resizeOnBorder = (typeof SettingsData !== "undefined" && SettingsData.hyprlandResizeOnBorder) ? true : false;
let content = `-- Auto-generated by DMS do not edit manually
@@ -265,6 +266,7 @@ hl.config({
gaps_in = ${gaps},
gaps_out = ${gaps},
border_size = ${borderSize},
resize_on_border = ${resizeOnBorder},
},
decoration = {
rounding = ${cornerRadius},