1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-16 09:12:47 -04:00

Compare commits

..

4 Commits

Author SHA1 Message Date
purian23 07dbba6c53 notifications(Settings): Update notifs popout settings overflow 2026-03-20 19:09:03 -04:00
Linken Quy Dinh a53b9afb44 fix: multi-monitor wallpaper cycling not working (#2042)
Fixed a QML property binding timing issue where dynamically created timers
and processes for per-monitor wallpaper cycling were being assigned to
properties and then immediately read back, which could return undefined
or stale values.

The fix stores the created object in a local variable before assigning
to the property map, ensuring a valid reference is always used.

Affected functions:
- startMonitorCycling() - timer creation
- cycleToNextWallpaper() - process creation
- cycleToPrevWallpaper() - process creation
2026-03-20 17:38:36 -04:00
purian23 a0c7ffd6b9 dankinstall(Arch): improve AUR package installation logic 2026-03-20 17:03:30 -04:00
bbedward 7ca1d2325a core: use QS_APP_ID instead of pragma 2026-03-20 12:38:42 -04:00
6 changed files with 137 additions and 42 deletions
+6
View File
@@ -192,6 +192,9 @@ func runShellInteractive(session bool) {
} }
} }
// ! TODO - remove when QS 0.3 is up and we can use the pragma
cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms")
if isSessionManaged && hasSystemdRun() { if isSessionManaged && hasSystemdRun() {
cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope") cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope")
} }
@@ -432,6 +435,9 @@ func runShellDaemon(session bool) {
} }
} }
// ! TODO - remove when QS 0.3 is up and we can use the pragma
cmd.Env = append(cmd.Env, "QS_APP_ID=com.danklinux.dms")
if isSessionManaged && hasSystemdRun() { if isSessionManaged && hasSystemdRun() {
cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope") cmd.Env = append(cmd.Env, "DMS_DEFAULT_LAUNCH_PREFIX=systemd-run --user --scope")
} }
+92 -24
View File
@@ -135,6 +135,42 @@ func (a *ArchDistribution) packageInstalled(pkg string) bool {
return err == nil return err == nil
} }
// parseSRCINFODeps reads a .SRCINFO file and returns runtime dep and makedep package
func parseSRCINFODeps(srcinfoPath string) (deps []string, makedeps []string, err error) {
data, err := os.ReadFile(srcinfoPath)
if err != nil {
return nil, nil, err
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
var pkg string
var target *[]string
switch {
case strings.HasPrefix(line, "makedepends = "):
pkg = strings.TrimPrefix(line, "makedepends = ")
target = &makedeps
case strings.HasPrefix(line, "depends = "):
pkg = strings.TrimPrefix(line, "depends = ")
target = &deps
default:
continue
}
// Strip version constraint (>=, <=, >, <, =) and colon-descriptions
if idx := strings.IndexAny(pkg, "><:="); idx >= 0 {
pkg = pkg[:idx]
}
pkg = strings.TrimSpace(pkg)
if pkg != "" {
*target = append(*target, pkg)
}
}
return deps, makedeps, nil
}
func (a *ArchDistribution) isInSystemRepo(pkg string) bool {
return exec.Command("pacman", "-Si", pkg).Run() == nil
}
func (a *ArchDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping { func (a *ArchDistribution) GetPackageMapping(wm deps.WindowManager) map[string]PackageMapping {
return a.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant)) return a.GetPackageMappingWithVariants(wm, make(map[string]deps.PackageVariant))
} }
@@ -524,6 +560,16 @@ func (a *ArchDistribution) reorderAURPackages(packages []string) []string {
} }
func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64) error { func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64) error {
return a.installSingleAURPackageInternal(ctx, pkg, sudoPassword, progressChan, startProgress, endProgress, make(map[string]bool))
}
func (a *ArchDistribution) installSingleAURPackageInternal(ctx context.Context, pkg, sudoPassword string, progressChan chan<- InstallProgressMsg, startProgress, endProgress float64, visited map[string]bool) error {
if visited[pkg] {
a.log(fmt.Sprintf("Skipping %s (already being installed, cycle detected)", pkg))
return nil
}
visited[pkg] = true
homeDir, err := os.UserHomeDir() homeDir, err := os.UserHomeDir()
if err != nil { if err != nil {
return fmt.Errorf("failed to get user home directory: %w", err) return fmt.Errorf("failed to get user home directory: %w", err)
@@ -610,39 +656,61 @@ func (a *ArchDistribution) installSingleAURPackage(ctx context.Context, pkg, sud
progressChan <- InstallProgressMsg{ progressChan <- InstallProgressMsg{
Phase: PhaseAURPackages, Phase: PhaseAURPackages,
Progress: startProgress + 0.3*(endProgress-startProgress), Progress: startProgress + 0.3*(endProgress-startProgress),
Step: fmt.Sprintf("Installing dependencies for %s...", pkg), Step: fmt.Sprintf("Resolving dependencies for %s...", pkg),
IsComplete: false, IsComplete: false,
CommandInfo: "Installing package dependencies and makedepends", CommandInfo: "Classifying dependencies as system or AUR",
} }
// Install dependencies from .SRCINFO runtimeDeps, makeDeps, err := parseSRCINFODeps(srcinfoPath)
depFilter := "" if err != nil {
if pkg == "dms-shell-git" { return fmt.Errorf("failed to parse .SRCINFO for %s: %w", pkg, err)
depFilter = ` | sed -E 's/[[:space:]]*(quickshell|dgop)[[:space:]]*/ /g' | tr -s ' '`
} }
depsCmd := exec.CommandContext(ctx, "bash", "-c", seen := make(map[string]bool)
fmt.Sprintf(` var systemPkgs []string
deps=$(grep "depends = " "%s" | grep -v "makedepends" | sed 's/.*depends = //' | tr '\n' ' ' %s | sed 's/[[:space:]]*$//') var aurPkgs []string
if [ ! -z "$deps" ] && [ "$deps" != " " ]; then
echo '%s' | sudo -S pacman -S --needed --noconfirm $deps
fi
`, srcinfoPath, depFilter, sudoPassword))
if err := a.runWithProgress(depsCmd, progressChan, PhaseAURPackages, startProgress+0.3*(endProgress-startProgress), startProgress+0.35*(endProgress-startProgress)); err != nil { for _, dep := range append(runtimeDeps, makeDeps...) {
return fmt.Errorf("FAILED to install runtime dependencies for %s: %w", pkg, err) if seen[dep] || a.packageInstalled(dep) {
continue
}
seen[dep] = true
if a.isInSystemRepo(dep) {
systemPkgs = append(systemPkgs, dep)
} else {
aurPkgs = append(aurPkgs, dep)
}
} }
makedepsCmd := exec.CommandContext(ctx, "bash", "-c", if len(systemPkgs) > 0 {
fmt.Sprintf(` progressChan <- InstallProgressMsg{
makedeps=$(grep -E "^[[:space:]]*makedepends = " "%s" | sed 's/^[[:space:]]*makedepends = //' | tr '\n' ' ') Phase: PhaseAURPackages,
if [ ! -z "$makedeps" ]; then Progress: startProgress + 0.32*(endProgress-startProgress),
echo '%s' | sudo -S pacman -S --needed --noconfirm $makedeps Step: fmt.Sprintf("Installing %d system dependencies for %s...", len(systemPkgs), pkg),
fi IsComplete: false,
`, srcinfoPath, sudoPassword)) CommandInfo: fmt.Sprintf("sudo pacman -S --needed --noconfirm %s", strings.Join(systemPkgs, " ")),
}
if err := a.installSystemPackages(ctx, systemPkgs, sudoPassword, progressChan); err != nil {
return fmt.Errorf("failed to install system dependencies for %s: %w", pkg, err)
}
}
if err := a.runWithProgress(makedepsCmd, progressChan, PhaseAURPackages, startProgress+0.35*(endProgress-startProgress), startProgress+0.4*(endProgress-startProgress)); err != nil { for _, aurDep := range aurPkgs {
return fmt.Errorf("FAILED to install make dependencies for %s: %w", pkg, err) a.log(fmt.Sprintf("Dependency %s is AUR-only, building from source...", aurDep))
progressChan <- InstallProgressMsg{
Phase: PhaseAURPackages,
Progress: startProgress + 0.35*(endProgress-startProgress),
Step: fmt.Sprintf("Installing AUR dependency %s for %s...", aurDep, pkg),
IsComplete: false,
CommandInfo: fmt.Sprintf("Building AUR dependency: %s", aurDep),
}
if err := a.installSingleAURPackageInternal(ctx, aurDep, sudoPassword, progressChan,
startProgress+0.35*(endProgress-startProgress),
startProgress+0.39*(endProgress-startProgress),
visited,
); err != nil {
return fmt.Errorf("failed to install AUR dependency %s for %s: %w", aurDep, pkg, err)
}
} }
} }
@@ -173,12 +173,18 @@ DankPopout {
property var externalKeyboardController: null property var externalKeyboardController: null
property real cachedHeaderHeight: 32 property real cachedHeaderHeight: 32
readonly property real settingsMaxHeight: {
const screenH = root.screen ? root.screen.height : 1080;
const maxPopupH = screenH * 0.8;
const overhead = cachedHeaderHeight + Theme.spacingL * 2 + Theme.spacingM * 2;
return Math.max(200, maxPopupH - overhead - 150);
}
implicitHeight: { implicitHeight: {
let baseHeight = Theme.spacingL * 2; let baseHeight = Theme.spacingL * 2;
baseHeight += cachedHeaderHeight; baseHeight += cachedHeaderHeight;
baseHeight += Theme.spacingM * 2; baseHeight += Theme.spacingM * 2;
const settingsHeight = notificationSettings.expanded ? notificationSettings.contentHeight : 0; const settingsHeight = notificationSettings.expanded ? Math.min(notificationSettings.naturalContentHeight, settingsMaxHeight) : 0;
const currentListHeight = root.shouldBeVisible ? notificationList.stableContentHeight : notificationList.listContentHeight; const currentListHeight = root.shouldBeVisible ? notificationList.stableContentHeight : notificationList.listContentHeight;
let listHeight = notificationHeader.currentTab === 0 ? currentListHeight : Math.max(200, NotificationService.historyList.length * 80); let listHeight = notificationHeader.currentTab === 0 ? currentListHeight : Math.max(200, NotificationService.historyList.length * 80);
if (notificationHeader.currentTab === 0 && NotificationService.groupedNotifications.length === 0) { if (notificationHeader.currentTab === 0 && NotificationService.groupedNotifications.length === 0) {
@@ -272,6 +278,7 @@ DankPopout {
NotificationSettings { NotificationSettings {
id: notificationSettings id: notificationSettings
expanded: notificationHeader.showSettings expanded: notificationHeader.showSettings
maxAllowedHeight: notificationContent.settingsMaxHeight
} }
Item { Item {
@@ -6,10 +6,11 @@ Rectangle {
id: root id: root
property bool expanded: false property bool expanded: false
readonly property real contentHeight: contentColumn.height + Theme.spacingL * 2 property real maxAllowedHeight: 0
readonly property real naturalContentHeight: contentColumn.height + Theme.spacingL * 2
width: parent.width width: parent.width
height: expanded ? contentHeight : 0 height: expanded ? (maxAllowedHeight > 0 ? Math.min(naturalContentHeight, maxAllowedHeight) : naturalContentHeight) : 0
visible: expanded visible: expanded
clip: true clip: true
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -105,6 +106,15 @@ Rectangle {
return Math.round(value / 60000) + " " + I18n.tr("minutes"); return Math.round(value / 60000) + " " + I18n.tr("minutes");
} }
Flickable {
id: settingsFlickable
anchors.fill: parent
contentHeight: contentColumn.height + Theme.spacingL * 2
clip: true
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.DragAndOvershootBounds
interactive: root.naturalContentHeight > root.height
Column { Column {
id: contentColumn id: contentColumn
anchors.top: parent.top anchors.top: parent.top
@@ -435,4 +445,5 @@ Rectangle {
} }
} }
} }
}
} }
@@ -194,10 +194,11 @@ Singleton {
var timer = monitorTimers[screenName]; var timer = monitorTimers[screenName];
if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) { if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) {
var newTimers = Object.assign({}, monitorTimers); var newTimers = Object.assign({}, monitorTimers);
newTimers[screenName] = monitorTimerComponent.createObject(root); var newTimer = monitorTimerComponent.createObject(root);
newTimers[screenName].targetScreen = screenName; newTimer.targetScreen = screenName;
newTimers[screenName] = newTimer;
monitorTimers = newTimers; monitorTimers = newTimers;
timer = monitorTimers[screenName]; timer = newTimer;
} }
if (timer) { if (timer) {
timer.interval = settings.interval * 1000; timer.interval = settings.interval * 1000;
@@ -258,9 +259,10 @@ Singleton {
var process = monitorProcesses[screenName]; var process = monitorProcesses[screenName];
if (!process) { if (!process) {
var newProcesses = Object.assign({}, monitorProcesses); var newProcesses = Object.assign({}, monitorProcesses);
newProcesses[screenName] = monitorProcessComponent.createObject(root); var newProcess = monitorProcessComponent.createObject(root);
newProcesses[screenName] = newProcess;
monitorProcesses = newProcesses; monitorProcesses = newProcesses;
process = monitorProcesses[screenName]; process = newProcess;
} }
if (process) { if (process) {
@@ -290,9 +292,10 @@ Singleton {
var process = monitorProcesses[screenName]; var process = monitorProcesses[screenName];
if (!process) { if (!process) {
var newProcesses = Object.assign({}, monitorProcesses); var newProcesses = Object.assign({}, monitorProcesses);
newProcesses[screenName] = monitorProcessComponent.createObject(root); var newProcess = monitorProcessComponent.createObject(root);
newProcesses[screenName] = newProcess;
monitorProcesses = newProcesses; monitorProcesses = newProcesses;
process = monitorProcesses[screenName]; process = newProcess;
} }
if (process) { if (process) {
+1 -1
View File
@@ -5,7 +5,7 @@
//@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1 //@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Material //@ pragma Env QT_QUICK_CONTROLS_STYLE=Material
//@ pragma UseQApplication //@ pragma UseQApplication
//@ pragma AppId com.danklinux.dms // ! TODO - replace pragma AppId when next QS releases, remove from GO launch injection.
import QtQuick import QtQuick
import Quickshell import Quickshell