1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-12 00:32:17 -04:00

feature: add login sound functionality and settings entry (#2155)

* added login sound functionality and settings entry

* Removed debug warning that was accidentally left in

* loginSound is off by default, and fixed toggle not working

* Prevent login sound from playing in the same session

---------

Co-authored-by: Iris <iris@raidev.eu>
This commit is contained in:
Iris
2026-04-06 21:11:00 +03:00
committed by GitHub
parent 3f7f6c5d2c
commit e224417593
8 changed files with 100 additions and 2 deletions

View File

@@ -434,6 +434,7 @@ Singleton {
property bool soundNewNotification: true property bool soundNewNotification: true
property bool soundVolumeChanged: true property bool soundVolumeChanged: true
property bool soundPluggedIn: true property bool soundPluggedIn: true
property bool soundLogin: false
property int acMonitorTimeout: 0 property int acMonitorTimeout: 0
property int acLockTimeout: 0 property int acLockTimeout: 0

View File

@@ -242,6 +242,7 @@ var SPEC = {
soundsEnabled: { def: true }, soundsEnabled: { def: true },
useSystemSoundTheme: { def: false }, useSystemSoundTheme: { def: false },
soundLogin: { def: false },
soundNewNotification: { def: true }, soundNewNotification: { def: true },
soundVolumeChanged: { def: true }, soundVolumeChanged: { def: true },
soundPluggedIn: { def: true }, soundPluggedIn: { def: true },

View File

@@ -221,10 +221,22 @@ Item {
} }
} }
Timer {
id: loginSoundTimer
// Half a second delay before playing login sound, otherwise the sound may be cut off
// 50 is the minimum that seems to work, but 500 is safer
interval: 500
repeat: false
onTriggered: {
AudioService.playLoginSoundIfApplicable();
}
}
Component.onCompleted: { Component.onCompleted: {
dockRecreateDebounce.start(); dockRecreateDebounce.start();
// Force PolkitService singleton to initialize // Force PolkitService singleton to initialize
PolkitService.polkitAvailable; PolkitService.polkitAvailable;
loginSoundTimer.start();
} }
Loader { Loader {

View File

@@ -91,6 +91,16 @@ Item {
visible: AudioService.gsettingsAvailable visible: AudioService.gsettingsAvailable
} }
SettingsToggleRow {
tab: "sounds"
tags: ["sound", "login", "startup", "boot"]
settingKey: "soundLogin"
text: I18n.tr("Login")
description: I18n.tr("Play sound after logging in")
checked: SettingsData.soundLogin
onToggled: checked => SettingsData.set("soundLogin", checked)
}
SettingsToggleRow { SettingsToggleRow {
tab: "sounds" tab: "sounds"
tags: ["sound", "notification", "new"] tags: ["sound", "notification", "new"]

View File

@@ -26,6 +26,7 @@ Singleton {
property var powerUnplugSound: null property var powerUnplugSound: null
property var normalNotificationSound: null property var normalNotificationSound: null
property var criticalNotificationSound: null property var criticalNotificationSound: null
property var loginSound: null
property real notificationsVolume: 1.0 property real notificationsVolume: 1.0
property bool notificationsAudioMuted: false property bool notificationsAudioMuted: false
@@ -67,6 +68,16 @@ Singleton {
} }
} }
// Used in playLoginSoundIfApplicable()
Process {
id: loginSoundChecker
onExited: (exitCode) => {
if (exitCode === 0) {
playLoginSound();
}
}
}
function getAvailableSinks() { function getAvailableSinks() {
const hidden = SessionData.hiddenOutputDeviceNames ?? []; const hidden = SessionData.hiddenOutputDeviceNames ?? [];
return Pipewire.nodes.values.filter(node => node.audio && node.isSink && !node.isStream && !hidden.includes(node.name)); return Pipewire.nodes.values.filter(node => node.audio && node.isSink && !node.isStream && !hidden.includes(node.name));
@@ -395,7 +406,7 @@ EOFCONFIG
const themesToSearch = themeName !== "freedesktop" ? `${themeName} freedesktop` : themeName; const themesToSearch = themeName !== "freedesktop" ? `${themeName} freedesktop` : themeName;
const script = ` const script = `
for event_key in audio-volume-change power-plug power-unplug message message-new-instant; do for event_key in audio-volume-change power-plug power-unplug message message-new-instant desktop-login; do
found=0 found=0
case "$event_key" in case "$event_key" in
@@ -457,7 +468,8 @@ EOFCONFIG
"power-plug": "../assets/sounds/plasma/power-plug.wav", "power-plug": "../assets/sounds/plasma/power-plug.wav",
"power-unplug": "../assets/sounds/plasma/power-unplug.wav", "power-unplug": "../assets/sounds/plasma/power-unplug.wav",
"message": "../assets/sounds/freedesktop/message.wav", "message": "../assets/sounds/freedesktop/message.wav",
"message-new-instant": "../assets/sounds/freedesktop/message-new-instant.wav" "message-new-instant": "../assets/sounds/freedesktop/message-new-instant.wav",
"desktop-login": "../assets/sounds/freedesktop/desktop-login.wav"
}; };
const specialConditions = { const specialConditions = {
@@ -551,6 +563,10 @@ EOFCONFIG
criticalNotificationSound.destroy(); criticalNotificationSound.destroy();
criticalNotificationSound = null; criticalNotificationSound = null;
} }
if (loginSound) {
loginSound.destroy();
loginSound = null;
}
} }
function createSoundPlayers() { function createSoundPlayers() {
@@ -622,6 +638,19 @@ EOFCONFIG
} }
} }
`, root, "AudioService.CriticalNotificationSound"); `, root, "AudioService.CriticalNotificationSound");
const loginPath = getSoundPath("desktop-login");
loginSound = Qt.createQmlObject(`
import QtQuick
import QtMultimedia
MediaPlayer {
source: "${loginPath}"
audioOutput: AudioOutput {
${deviceProperty}volume: notificationsVolume
}
}
`, root, "AudioService.LoginSound");
} catch (e) { } catch (e) {
console.warn("AudioService: Error creating sound players:", e); console.warn("AudioService: Error creating sound players:", e);
} }
@@ -661,6 +690,31 @@ EOFCONFIG
criticalNotificationSound.play(); criticalNotificationSound.play();
} }
function playLoginSound() {
if (!soundsAvailable || !loginSound || notificationsAudioMuted || isMediaPlaying()) {
return;
}
loginSound.play();
}
function playLoginSoundIfApplicable() {
if (SettingsData.soundsEnabled && SettingsData.soundLogin && !notificationsAudioMuted) {
// plays login sound on session start, but only if a specific file doesn't exist,
// to prevent it from playing on every DMS restart during the session
const runtimeDir = Quickshell.env("XDG_RUNTIME_DIR");
const sessionId = Quickshell.env("XDG_SESSION_ID") || "0";
if (!runtimeDir) return;
const loginFile = `${runtimeDir}/danklinux.login-${sessionId}`;
// if file doesn't exist, touch it (0)
// If it exists, do nothing (1)
loginSoundChecker.command = ["sh", "-c", `[ ! -f ${loginFile} ] && touch ${loginFile}`];
loginSoundChecker.running = true;
}
}
function playVolumeChangeSoundIfEnabled() { function playVolumeChangeSoundIfEnabled() {
if (SettingsData.soundsEnabled && SettingsData.soundVolumeChanged && !notificationsAudioMuted) { if (SettingsData.soundsEnabled && SettingsData.soundVolumeChanged && !notificationsAudioMuted) {
playVolumeChangeSound(); playVolumeChangeSound();

Binary file not shown.

Binary file not shown.

View File

@@ -5101,6 +5101,26 @@
], ],
"description": "Play sounds for system events" "description": "Play sounds for system events"
}, },
{
"section": "soundLogin",
"label": "Login",
"tabIndex": 15,
"category": "Sounds",
"keywords": [
"after",
"audio",
"boot",
"effects",
"logging",
"login",
"play",
"sfx",
"sound",
"sounds",
"startup"
],
"description": "Play sound after logging in"
},
{ {
"section": "soundNewNotification", "section": "soundNewNotification",
"label": "New Notification", "label": "New Notification",