1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

Merge branch 'master' of github.com:bbedward/DankMaterialShell into wip/plugins

This commit is contained in:
bbedward
2025-10-02 00:22:32 -04:00
10 changed files with 322 additions and 30 deletions

View File

@@ -333,9 +333,10 @@ Item {
bottom: barWindow.isVertical ? parent.bottom : undefined
}
// Only enable mouse handling while hidden (for reveal-on-edge logic).
hoverEnabled: SettingsData.dankBarAutoHide && !topBarCore.reveal
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
hoverEnabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview
acceptedButtons: Qt.NoButton
enabled: SettingsData.dankBarAutoHide && !topBarCore.reveal
enabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview
Item {
id: topBarContainer

View File

@@ -19,6 +19,9 @@ Item {
property string screenName: ""
property string randomFact: ""
property string hyprlandCurrentLayout: ""
property string hyprlandKeyboard: ""
property int hyprlandLayoutCount: 0
property bool isPrimaryScreen: {
if (!Qt.application.screens || Qt.application.screens.length === 0)
return true
@@ -61,6 +64,11 @@ Item {
sessionListProc.running = true
applyLastSuccessfulUser()
}
if (CompositorService.isHyprland) {
updateHyprlandLayout()
hyprlandLayoutUpdateTimer.start()
}
}
function applyLastSuccessfulUser() {
@@ -75,6 +83,56 @@ Item {
Component.onDestruction: {
WeatherService.removeRef()
if (CompositorService.isHyprland) {
hyprlandLayoutUpdateTimer.stop()
}
}
function updateHyprlandLayout() {
if (CompositorService.isHyprland) {
hyprlandLayoutProcess.running = true
}
}
Process {
id: hyprlandLayoutProcess
running: false
command: ["hyprctl", "-j", "devices"]
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text)
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
hyprlandKeyboard = mainKeyboard.name
if (mainKeyboard && mainKeyboard.active_keymap) {
const parts = mainKeyboard.active_keymap.split(" ")
if (parts.length > 0) {
hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase()
} else {
hyprlandCurrentLayout = mainKeyboard.active_keymap.substring(0, 2).toUpperCase()
}
} else {
hyprlandCurrentLayout = ""
}
if (mainKeyboard && mainKeyboard.layout_names) {
hyprlandLayoutCount = mainKeyboard.layout_names.length
} else {
hyprlandLayoutCount = 0
}
} catch (e) {
hyprlandCurrentLayout = ""
hyprlandLayoutCount = 0
}
}
}
}
Timer {
id: hyprlandLayoutUpdateTimer
interval: 1000
running: false
repeat: true
onTriggered: updateHyprlandLayout()
}
// ! This was for development and testing, just leaving so people can see how I did it.
@@ -438,6 +496,8 @@ Item {
StyledText {
Layout.fillWidth: true
Layout.preferredHeight: 20
Layout.topMargin: -Theme.spacingS
Layout.bottomMargin: -Theme.spacingS
text: {
if (GreeterState.pamState === "error")
return "Authentication error - try again"
@@ -448,7 +508,6 @@ Item {
color: Theme.error
font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: Text.AlignHCenter
visible: GreeterState.pamState !== ""
opacity: GreeterState.pamState !== "" ? 1 : 0
Behavior on opacity {
@@ -461,7 +520,7 @@ Item {
Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Theme.spacingS
Layout.topMargin: 0
Layout.preferredWidth: switchUserRow.width + Theme.spacingL * 2
Layout.preferredHeight: 40
radius: Theme.cornerRadius
@@ -516,6 +575,91 @@ Item {
anchors.margins: Theme.spacingXL
spacing: Theme.spacingL
Item {
width: keyboardLayoutRow.width
height: keyboardLayoutRow.height
anchors.verticalCenter: parent.verticalCenter
visible: {
if (CompositorService.isNiri) {
return NiriService.keyboardLayoutNames.length > 1
} else if (CompositorService.isHyprland) {
return hyprlandLayoutCount > 1
}
return false
}
Row {
id: keyboardLayoutRow
spacing: 4
Item {
width: Theme.iconSize
height: Theme.iconSize
DankIcon {
name: "keyboard"
size: Theme.iconSize
color: "white"
anchors.centerIn: parent
}
}
Item {
width: childrenRect.width
height: Theme.iconSize
StyledText {
text: {
if (CompositorService.isNiri) {
const layout = NiriService.getCurrentKeyboardLayoutName()
if (!layout) return ""
const parts = layout.split(" ")
if (parts.length > 0) {
return parts[0].substring(0, 2).toUpperCase()
}
return layout.substring(0, 2).toUpperCase()
} else if (CompositorService.isHyprland) {
return hyprlandCurrentLayout
}
return ""
}
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Light
color: "white"
anchors.verticalCenter: parent.verticalCenter
}
}
}
MouseArea {
id: keyboardLayoutArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (CompositorService.isNiri) {
NiriService.cycleKeyboardLayout()
} else if (CompositorService.isHyprland) {
Quickshell.execDetached([
"hyprctl",
"switchxkblayout",
hyprlandKeyboard,
"next"
])
updateHyprlandLayout()
}
}
}
}
Rectangle {
width: 1
height: 24
color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter
visible: MprisController.activePlayer
}
Row {
spacing: Theme.spacingS
visible: MprisController.activePlayer
@@ -970,7 +1114,7 @@ Item {
if (idx >= 0) {
GreeterState.currentSessionIndex = idx
GreeterState.selectedSession = GreeterState.sessionExecs[idx]
GreetdMemory.setLastSessionId(GreeterState.sessionExecs[idx].split(" ")[0])
GreetdMemory.setLastSessionId(GreeterState.sessionPaths[idx])
}
}
}
@@ -987,6 +1131,7 @@ Item {
property string currentSessionName: GreeterState.sessionList[GreeterState.currentSessionIndex] || ""
property int pendingParsers: 0
function finalizeSessionSelection() {
if (GreeterState.sessionList.length === 0) {
return
@@ -997,8 +1142,8 @@ Item {
const savedSession = GreetdMemory.lastSessionId
let foundSaved = false
if (savedSession) {
for (var i = 0; i < GreeterState.sessionExecs.length; i++) {
if (GreeterState.sessionExecs[i].toLowerCase().includes(savedSession.toLowerCase()) || GreeterState.sessionList[i].toLowerCase().includes(savedSession.toLowerCase())) {
for (var i = 0; i < GreeterState.sessionPaths.length; i++) {
if (GreeterState.sessionPaths[i] === savedSession) {
GreeterState.currentSessionIndex = i
foundSaved = true
break
@@ -1059,10 +1204,13 @@ Item {
if (!GreeterState.sessionList.includes(name)) {
let newList = GreeterState.sessionList.slice()
let newExecs = GreeterState.sessionExecs.slice()
let newPaths = GreeterState.sessionPaths.slice()
newList.push(name)
newExecs.push(exec)
newPaths.push(desktopPath)
GreeterState.sessionList = newList
GreeterState.sessionExecs = newExecs
GreeterState.sessionPaths = newPaths
root.sessionCount = GreeterState.sessionList.length
}
}
@@ -1098,17 +1246,16 @@ Item {
GreeterState.unlocking = true
const sessionCmd = GreeterState.selectedSession || GreeterState.sessionExecs[GreeterState.currentSessionIndex]
if (sessionCmd) {
GreetdMemory.setLastSessionId(sessionCmd.split(" ")[0])
GreetdMemory.setLastSessionId(GreeterState.sessionPaths[GreeterState.currentSessionIndex])
GreetdMemory.setLastSuccessfulUser(GreeterState.username)
Greetd.launch(sessionCmd.split(" "), [], true)
Greetd.launch(sessionCmd.split(" "), ["XDG_SESSION_TYPE=wayland"], true)
}
}
function onAuthFailure(message) {
GreeterState.pamState = "fail"
GreeterState.reset()
GreeterState.passwordBuffer = ""
inputField.text = ""
PortalService.profileImage = ""
placeholderDelay.restart()
}

View File

@@ -16,6 +16,7 @@ Singleton {
property var sessionList: []
property var sessionExecs: []
property var sessionPaths: []
property int currentSessionIndex: 0
function reset() {

View File

@@ -18,7 +18,7 @@ Manual installation:
1. Install `greetd` (in most distro's standard repositories)
2. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd`
- niri if you want to run the greeter under niri, hypr if you want to run the greeter under Hyprland
3. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/etc/greetd/start-dms.sh`
3. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh`
4. Edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` and replace `_DMS_PATH_` with the absolute path to dms, e.g. `/home/joecool/.config/quickshell/dms`
5. Edit or create `/etc/greetd/config.toml`
```toml
@@ -38,7 +38,7 @@ vt = 1
# in the `video` group.
user = "greeter"
command = "/etc/greetd/start-dms.sh"%
command = "/usr/local/bin/start-dms-greetd.sh"
```
Enable the greeter with `sudo systemctl enable greetd`

View File

@@ -1,6 +1,3 @@
env = DMS_RUN_GREETER,1
env = QT_QPA_PLATFORM,wayland
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
env = EGL_PLATFORM,gbm
exec = sh -c "qs -p _DMS_PATH_; hyprctl dispatch exit"

View File

@@ -4,8 +4,6 @@ hotkey-overlay {
environment {
DMS_RUN_GREETER "1"
QT_QPA_PLATFORM "wayland"
QT_WAYLAND_DISABLE_WINDOWDECORATION "1"
}
spawn-at-startup "sh" "-c" "qs -p _DMS_PATH_; niri msg action quit --skip-confirmation"

View File

@@ -1,3 +1,8 @@
#!/bin/sh
EGL_PLATFORM=gbm Hyprland -c /etc/greetd/dms-hypr.conf
export XDG_SESSION_TYPE=wayland
export QT_QPA_PLATFORM=wayland
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
export EGL_PLATFORM=gbm
exec Hyprland -c /etc/greetd/dms-hypr.conf

View File

@@ -1,3 +1,8 @@
#!/bin/sh
EGL_PLATFORM=gbm niri -c /etc/greetd/dms-niri.kdl
export XDG_SESSION_TYPE=wayland
export QT_QPA_PLATFORM=wayland
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
export EGL_PLATFORM=gbm
exec niri -c /etc/greetd/dms-niri.kdl

View File

@@ -20,6 +20,9 @@ Item {
property bool unlocking: false
property string pamState: ""
property string randomFact: ""
property string hyprlandCurrentLayout: ""
property string hyprlandKeyboard: ""
property int hyprlandLayoutCount: 0
signal unlockRequested
@@ -55,6 +58,11 @@ Item {
WeatherService.addRef()
UserInfoService.refreshUserInfo()
if (CompositorService.isHyprland) {
updateHyprlandLayout()
hyprlandLayoutUpdateTimer.start()
}
}
onDemoModeChanged: {
if (demoMode) {
@@ -63,6 +71,56 @@ Item {
}
Component.onDestruction: {
WeatherService.removeRef()
if (CompositorService.isHyprland) {
hyprlandLayoutUpdateTimer.stop()
}
}
function updateHyprlandLayout() {
if (CompositorService.isHyprland) {
hyprlandLayoutProcess.running = true
}
}
Process {
id: hyprlandLayoutProcess
running: false
command: ["hyprctl", "-j", "devices"]
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text)
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
hyprlandKeyboard = mainKeyboard.name
if (mainKeyboard && mainKeyboard.active_keymap) {
const parts = mainKeyboard.active_keymap.split(" ")
if (parts.length > 0) {
hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase()
} else {
hyprlandCurrentLayout = mainKeyboard.active_keymap.substring(0, 2).toUpperCase()
}
} else {
hyprlandCurrentLayout = ""
}
if (mainKeyboard && mainKeyboard.layout_names) {
hyprlandLayoutCount = mainKeyboard.layout_names.length
} else {
hyprlandLayoutCount = 0
}
} catch (e) {
hyprlandCurrentLayout = ""
hyprlandLayoutCount = 0
}
}
}
}
Timer {
id: hyprlandLayoutUpdateTimer
interval: 1000
running: false
repeat: true
onTriggered: updateHyprlandLayout()
}
Loader {
@@ -520,7 +578,7 @@ Item {
StyledText {
Layout.fillWidth: true
Layout.preferredHeight: root.pamState ? 20 : 0
Layout.preferredHeight: 20
text: {
if (root.pamState === "error") {
return "Authentication error - try again"
@@ -536,7 +594,6 @@ Item {
color: Theme.error
font.pixelSize: Theme.fontSizeSmall
horizontalAlignment: Text.AlignHCenter
visible: root.pamState !== ""
opacity: root.pamState !== "" ? 1 : 0
Behavior on opacity {
@@ -545,13 +602,6 @@ Item {
easing.type: Theme.standardEasing
}
}
Behavior on Layout.preferredHeight {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
@@ -572,6 +622,92 @@ Item {
anchors.margins: Theme.spacingXL
spacing: Theme.spacingL
Item {
width: keyboardLayoutRow.width
height: keyboardLayoutRow.height
anchors.verticalCenter: parent.verticalCenter
visible: {
if (CompositorService.isNiri) {
return NiriService.keyboardLayoutNames.length > 1
} else if (CompositorService.isHyprland) {
return hyprlandLayoutCount > 1
}
return false
}
Row {
id: keyboardLayoutRow
spacing: 4
Item {
width: Theme.iconSize
height: Theme.iconSize
DankIcon {
name: "keyboard"
size: Theme.iconSize
color: "white"
anchors.centerIn: parent
}
}
Item {
width: childrenRect.width
height: Theme.iconSize
StyledText {
text: {
if (CompositorService.isNiri) {
const layout = NiriService.getCurrentKeyboardLayoutName()
if (!layout) return ""
const parts = layout.split(" ")
if (parts.length > 0) {
return parts[0].substring(0, 2).toUpperCase()
}
return layout.substring(0, 2).toUpperCase()
} else if (CompositorService.isHyprland) {
return hyprlandCurrentLayout
}
return ""
}
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Light
color: "white"
anchors.verticalCenter: parent.verticalCenter
}
}
}
MouseArea {
id: keyboardLayoutArea
anchors.fill: parent
enabled: !demoMode
hoverEnabled: enabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (CompositorService.isNiri) {
NiriService.cycleKeyboardLayout()
} else if (CompositorService.isHyprland) {
Quickshell.execDetached([
"hyprctl",
"switchxkblayout",
hyprlandKeyboard,
"next"
])
updateHyprlandLayout()
}
}
}
}
Rectangle {
width: 1
height: 24
color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter
visible: MprisController.activePlayer
}
Row {
spacing: Theme.spacingS
visible: MprisController.activePlayer
@@ -1036,6 +1172,8 @@ Item {
return
}
console.log("Authentication failed:", res)
passwordField.text = ""
root.passwordBuffer = ""
if (res === PamResult.Error)
root.pamState = "error"
else if (res === PamResult.MaxTries)