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

Compare commits

..

6 Commits

Author SHA1 Message Date
bbedward
8d0f256f74 fix: missing appID references 2026-03-20 10:04:55 -04:00
bbedward
1a9449da1b qs: set app ID to com.danklinux.dms 2026-03-20 10:03:33 -04:00
bbedward
1caf8942b7 popout: avoid calling functions on stale references 2026-03-20 09:35:58 -04:00
Dimariqe
9efbcbcd20 fix: redraw wallpaper after DMS lock screen is dismissed (#2037)
After unlocking the screen (startup lock or wake from sleep), the desktop
showed Hyprland's background color instead of the wallpaper.

WallpaperBackground disables QML updates via updatesEnabled after a 1-second
settle timer. While WlSessionLock is active, Hyprland does not composite the
background layer, so when the lock is released it needs a fresh Wayland buffer
— but none is committed because the render loop is already paused.

The previous attempt used SessionService.sessionUnlocked, which is unreliable
for the startup lock case: DMSService is not yet connected when lock() is
called at startup, so notifyLoginctl is a no-op and the loginctl state never
transitions, meaning sessionUnlocked never fires.

Fix by tracking the shell lock state directly from Lock.qml's shouldLock via
a new IdleService.isShellLocked property. WallpaperBackground watches this and
re-enables rendering for 1 second on unlock, ensuring a fresh buffer is
committed to Wayland before the compositor resumes displaying the layer.
2026-03-20 09:29:32 -04:00
Youseffo13
3d07b8c9c1 Fixed mux tab having same id as locale tab (#2031)
* Feat: fix mux tab having same id as locale tab

* Feat: updated some icon

* Update KeybindsModal.qml
2026-03-20 09:27:46 -04:00
bbedward
dae74a40c0 wallpaper: tweak binding again for updatesEnabled 2026-03-20 09:22:42 -04:00
21 changed files with 112 additions and 77 deletions

View File

@@ -1,5 +1,13 @@
This file is more of a quick reference so I know what to account for before next releases.
# 1.5.0
- Overhauled shadows
- App ID changed to com.danklinux.dms - breaking for window rules
- Greeter stuff
- Terminal mux
- Locale overrides
- new neovim theming
# 1.4.0
- Overhauled system monitor, graphs, styling

View File

@@ -252,6 +252,7 @@ window-rule {
// Open dms windows as floating by default
window-rule {
match app-id=r#"org.quickshell$"#
match app-id=r#"com.danklinux.dms$"#
open-floating true
}
debug {

View File

@@ -72,7 +72,8 @@ Singleton {
}
function resolveIconPath(iconName: string): string {
if (!iconName) return "";
if (!iconName)
return "";
const moddedId = moddedAppId(iconName);
if (moddedId !== iconName) {
if (moddedId.startsWith("~") || moddedId.startsWith("/"))
@@ -85,7 +86,8 @@ Singleton {
}
function resolveIconUrl(iconName: string): string {
if (!iconName) return "";
if (!iconName)
return "";
const moddedId = moddedAppId(iconName);
if (moddedId !== iconName) {
if (moddedId.startsWith("~") || moddedId.startsWith("/"))
@@ -98,7 +100,8 @@ Singleton {
}
function getAppIcon(appId: string, desktopEntry: var): string {
if (appId === "org.quickshell") {
// ! TODO - after QS 0.3, we can install our icon properly
if (appId === "org.quickshell" || appId === "com.danklinux.dms") {
return Qt.resolvedUrl("../assets/danklogo.svg");
}
@@ -118,7 +121,7 @@ Singleton {
}
function getAppName(appId: string, desktopEntry: var): string {
if (appId === "org.quickshell") {
if (appId === "org.quickshell" || appId === "com.danklinux.dms") {
return "dms";
}

View File

@@ -12,6 +12,27 @@ Singleton {
signal popoutOpening
signal popoutChanged
function _closePopout(popout) {
switch (true) {
case popout.dashVisible !== undefined:
popout.dashVisible = false;
return;
case popout.notificationHistoryVisible !== undefined:
popout.notificationHistoryVisible = false;
return;
default:
popout.close();
}
}
function _isStale(popout) {
try {
return !popout || !("shouldBeVisible" in popout);
} catch (e) {
return true;
}
}
function showPopout(popout) {
if (!popout || !popout.screen)
return;
@@ -23,13 +44,11 @@ Singleton {
const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout || otherPopout === popout)
continue;
if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false;
} else {
otherPopout.close();
if (_isStale(otherPopout)) {
currentPopoutsByScreen[otherScreenName] = null;
continue;
}
_closePopout(otherPopout);
}
currentPopoutsByScreen[screenName] = popout;
@@ -51,15 +70,9 @@ Singleton {
function closeAllPopouts() {
for (const screenName in currentPopoutsByScreen) {
const popout = currentPopoutsByScreen[screenName];
if (!popout)
if (!popout || _isStale(popout))
continue;
if (popout.dashVisible !== undefined) {
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false;
} else {
popout.close();
}
_closePopout(popout);
}
currentPopoutsByScreen = {};
}
@@ -90,6 +103,12 @@ Singleton {
if (!otherPopout)
continue;
if (_isStale(otherPopout)) {
currentPopoutsByScreen[otherScreenName] = null;
currentPopoutTriggers[otherScreenName] = null;
continue;
}
if (otherPopout === popout) {
movedFromOtherScreen = true;
currentPopoutsByScreen[otherScreenName] = null;
@@ -97,45 +116,26 @@ Singleton {
continue;
}
if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false;
} else {
otherPopout.close();
}
_closePopout(otherPopout);
}
if (currentPopout && currentPopout !== popout) {
if (currentPopout.dashVisible !== undefined) {
currentPopout.dashVisible = false;
} else if (currentPopout.notificationHistoryVisible !== undefined) {
currentPopout.notificationHistoryVisible = false;
if (_isStale(currentPopout)) {
currentPopoutsByScreen[screenName] = null;
currentPopoutTriggers[screenName] = null;
} else {
currentPopout.close();
_closePopout(currentPopout);
}
}
if (currentPopout === popout && popout.shouldBeVisible && !movedFromOtherScreen) {
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
if (popout.dashVisible !== undefined) {
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false;
} else {
popout.close();
}
_closePopout(popout);
return;
}
if (triggerId === undefined) {
if (popout.dashVisible !== undefined) {
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false;
} else {
popout.close();
}
_closePopout(popout);
return;
}

View File

@@ -81,7 +81,7 @@ DankModal {
StyledText {
Layout.alignment: Qt.AlignLeft
text: KeybindsService.cheatsheet.title || "Keybinds"
text: KeybindsService.cheatsheet.title || i18n("Keybinds")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.primary
@@ -309,10 +309,12 @@ DankModal {
id: keyText
anchors.centerIn: parent
color: Theme.secondary
text: modelData.key || ""
text: (modelData.key || "").replace(/\+/g, " + ")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
isMonospace: true
elide: Text.ElideRight
width: Math.min(implicitWidth, 148)
}
}
@@ -325,6 +327,7 @@ DankModal {
font.pixelSize: Theme.fontSizeSmall
opacity: 0.9
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
}
}

View File

@@ -507,7 +507,7 @@ FocusScope {
Loader {
id: muxLoader
anchors.fill: parent
active: root.currentIndex === 30
active: root.currentIndex === 32
visible: active
focus: active

View File

@@ -156,7 +156,7 @@ Rectangle {
{
"id": "running_apps",
"text": I18n.tr("Running Apps"),
"icon": "apps",
"icon": "app_registration",
"tabIndex": 19,
"hyprlandNiriOnly": true
},
@@ -237,7 +237,7 @@ Rectangle {
{
"id": "system",
"text": I18n.tr("System"),
"icon": "computer",
"icon": "memory",
"collapsedByDefault": true,
"children": [
{
@@ -270,7 +270,7 @@ Rectangle {
"id": "multiplexers",
"text": I18n.tr("Multiplexers"),
"icon": "terminal",
"tabIndex": 30
"tabIndex": 32
},
{
"id": "window_rules",

View File

@@ -100,10 +100,10 @@ Variants {
Connections {
target: currentWallpaper
function onStatusChanged() {
if (currentWallpaper.status === Image.Ready) {
root._renderSettling = true;
renderSettleTimer.restart();
}
if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error)
return;
root._renderSettling = true;
renderSettleTimer.restart();
}
}
@@ -206,6 +206,7 @@ Variants {
visible: false
opacity: 1
asynchronous: true
retainWhileLoading: true
smooth: true
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
@@ -218,6 +219,7 @@ Variants {
visible: false
opacity: 0
asynchronous: true
retainWhileLoading: true
smooth: true
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
@@ -300,6 +302,8 @@ Variants {
root.useNextForEffect = false;
nextWallpaper.source = "";
root.transitionProgress = 0.0;
root._renderSettling = true;
renderSettleTimer.restart();
root.effectActive = false;
}
}

View File

@@ -248,7 +248,7 @@ BasePill {
let appId = Paths.moddedAppId(rawAppId);
let coreAppData = null;
if (rawAppId === "org.quickshell") {
if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") {
coreAppData = getCoreAppDataByTitle(toplevel.title);
if (coreAppData) {
appId = coreAppData.builtInPluginId;
@@ -697,7 +697,7 @@ BasePill {
mipmap: true
asynchronous: true
visible: status === Image.Ready && !coreIcon.visible
layer.enabled: appItem.appId === "org.quickshell"
layer.enabled: appItem.appId === "org.quickshell" || appItem.appId === "com.danklinux.dms"
layer.smooth: true
layer.mipmap: true
layer.effect: MultiEffect {
@@ -990,7 +990,7 @@ BasePill {
break;
}
const shouldHidePin = modelData.appId === "org.quickshell";
const shouldHidePin = modelData.appId === "org.quickshell" || modelData.appId === "com.danklinux.dms";
const moddedId = Paths.moddedAppId(modelData.appId);
const desktopEntry = moddedId ? DesktopEntries.heuristicLookup(moddedId) : null;

View File

@@ -16,7 +16,7 @@ PanelWindow {
property int margin: 10
property bool hidePin: false
property var desktopEntry: null
property bool isDmsWindow: appData?.appId === "org.quickshell"
property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms"
property bool isVertical: false
property string edge: "top"

View File

@@ -145,7 +145,7 @@ BasePill {
smooth: true
mipmap: true
asynchronous: true
layer.enabled: activeWindow && activeWindow.appId === "org.quickshell"
layer.enabled: activeWindow && (activeWindow.appId === "org.quickshell" || activeWindow.appId === "com.danklinux.dms")
layer.smooth: true
layer.mipmap: true
layer.effect: MultiEffect {

View File

@@ -296,7 +296,7 @@ BasePill {
mipmap: true
asynchronous: true
visible: status === Image.Ready
layer.enabled: appId === "org.quickshell"
layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms"
layer.smooth: true
layer.mipmap: true
layer.effect: MultiEffect {
@@ -550,7 +550,7 @@ BasePill {
mipmap: true
asynchronous: true
visible: status === Image.Ready
layer.enabled: appId === "org.quickshell"
layer.enabled: appId === "org.quickshell" || appId === "com.danklinux.dms"
layer.smooth: true
layer.mipmap: true
layer.effect: MultiEffect {

View File

@@ -286,7 +286,7 @@ Item {
const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${moddedId}_${i}` : moddedId;
if (!byApp[key]) {
const isQuickshell = keyBase === "org.quickshell";
const isQuickshell = keyBase === "org.quickshell" || keyBase === "com.danklinux.dms";
const isSteamApp = Paths.isSteamApp(moddedId);
const desktopEntry = DesktopEntries.heuristicLookup(moddedId);
const icon = Paths.getAppIcon(moddedId, desktopEntry);

View File

@@ -344,7 +344,7 @@ Item {
groupedToplevel.activate();
}
} else if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms";
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
break;
@@ -391,7 +391,7 @@ Item {
break;
case "grouped":
if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms";
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
break;
@@ -414,7 +414,7 @@ Item {
} else if (mouse.button === Qt.RightButton) {
if (!contextMenu)
return;
const shouldHidePin = appData.appId === "org.quickshell";
const shouldHidePin = appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms";
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
}
@@ -471,7 +471,7 @@ Item {
id: iconImg
anchors.centerIn: parent
implicitSize: appData && appData.appId === "org.quickshell" ? actualIconSize * 0.85 : actualIconSize
implicitSize: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms") ? actualIconSize * 0.85 : actualIconSize
source: {
if (!appData || appData.appId === "__SEPARATOR__") {
return "";
@@ -485,7 +485,7 @@ Item {
smooth: true
asynchronous: true
visible: status === Image.Ready && !coreIcon.visible
layer.enabled: appData && appData.appId === "org.quickshell"
layer.enabled: appData && (appData.appId === "org.quickshell" || appData.appId === "com.danklinux.dms")
layer.smooth: true
layer.mipmap: true
layer.effect: MultiEffect {

View File

@@ -161,7 +161,7 @@ Item {
let appId = Paths.moddedAppId(rawAppId);
let coreAppData = null;
if (rawAppId === "org.quickshell") {
if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") {
coreAppData = getCoreAppDataByTitle(toplevel.title);
if (coreAppData)
appId = coreAppData.builtInPluginId;
@@ -241,7 +241,7 @@ Item {
let coreAppData = null;
let isCoreApp = false;
if (rawAppId === "org.quickshell") {
if (rawAppId === "org.quickshell" || rawAppId === "com.danklinux.dms") {
coreAppData = getCoreAppDataByTitle(toplevel.title);
if (coreAppData)
isCoreApp = true;

View File

@@ -17,7 +17,7 @@ PanelWindow {
property int margin: 10
property bool hidePin: false
property var desktopEntry: null
property bool isDmsWindow: appData?.appId === "org.quickshell"
property bool isDmsWindow: appData?.appId === "org.quickshell" || appData?.appId === "com.danklinux.dms"
property var dockApps: null
function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen, parentDockApps) {

View File

@@ -14,6 +14,7 @@ Scope {
property bool shouldLock: false
onShouldLockChanged: {
IdleService.isShellLocked = shouldLock;
if (shouldLock && lockPowerOffArmed) {
lockStateCheck.restart();
}

View File

@@ -12,7 +12,7 @@ Item {
"zellij"
]
DankFlickable {
DankFlickable {
anchors.fill: parent
clip: true
contentHeight: mainColumn.height + Theme.spacingXL
@@ -79,7 +79,6 @@ DankFlickable {
onTextEdited: SettingsData.set("muxCustomCommand", text)
}
}
}
SettingsCard {

View File

@@ -93,10 +93,10 @@ Variants {
Connections {
target: currentWallpaper
function onStatusChanged() {
if (currentWallpaper.status === Image.Ready) {
root._renderSettling = true;
renderSettleTimer.restart();
}
if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error)
return;
root._renderSettling = true;
renderSettleTimer.restart();
}
}
@@ -151,6 +151,16 @@ Variants {
}
}
Connections {
target: IdleService
function onIsShellLockedChanged() {
if (!IdleService.isShellLocked) {
root._renderSettling = true;
renderSettleTimer.restart();
}
}
}
Timer {
id: renderSettleTimer
interval: 1000
@@ -188,7 +198,7 @@ Variants {
Component.onCompleted: {
if (typeof wallpaperWindow.updatesEnabled !== "undefined")
wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || root.overviewBlurActive || root._overviewBlurSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || root.overviewBlurActive || root._overviewBlurSettling || root.pendingWallpaper !== "" || root._deferredSource !== "" || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
if (!source) {
root._renderSettling = false;
@@ -320,6 +330,7 @@ Variants {
opacity: 1
layer.enabled: false
asynchronous: true
retainWhileLoading: true
smooth: true
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
@@ -333,6 +344,7 @@ Variants {
opacity: 0
layer.enabled: false
asynchronous: true
retainWhileLoading: true
smooth: true
cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
@@ -591,6 +603,8 @@ Variants {
root.transitionProgress = 0.0;
currentWallpaper.layer.enabled = false;
nextWallpaper.layer.enabled = false;
root._renderSettling = true;
renderSettleTimer.restart();
root.effectActive = false;
if (!root.pendingWallpaper)

View File

@@ -64,6 +64,7 @@ Singleton {
property var suspendMonitor: null
property var lockComponent: null
property bool monitorsOff: false
property bool isShellLocked: false
function wake() {
requestMonitorOn();

View File

@@ -5,6 +5,7 @@
//@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1
//@ pragma Env QT_QUICK_CONTROLS_STYLE=Material
//@ pragma UseQApplication
//@ pragma AppId com.danklinux.dms
import QtQuick
import Quickshell