1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00
This commit is contained in:
bbedward
2025-10-21 23:13:54 -04:00
parent 90bc890190
commit 967b7d05de
43 changed files with 2203 additions and 7271 deletions

View File

@@ -1,5 +1,4 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
@@ -17,67 +16,300 @@ Singleton {
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
property bool useNiriSorting: isNiri && NiriService
property var sortedToplevels: {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values) {
property var sortedToplevels: sortedToplevelsCache
property var sortedToplevelsCache: []
property bool _sortScheduled: false
property bool _refreshScheduled: false
property bool _hasRefreshedOnce: false
property var _coordCache: ({})
Timer {
id: refreshTimer
interval: 40
repeat: false
onTriggered: {
try {
Hyprland.refreshToplevels()
} catch(e) {}
_refreshScheduled = false
_hasRefreshedOnce = true
scheduleSort()
}
}
function scheduleSort() {
if (_sortScheduled) return
_sortScheduled = true
Qt.callLater(function() {
_sortScheduled = false
sortedToplevelsCache = computeSortedToplevels()
})
}
function scheduleRefresh() {
if (!isHyprland) return
if (_refreshScheduled) return
_refreshScheduled = true
refreshTimer.restart()
}
Connections {
target: ToplevelManager.toplevels
function onValuesChanged() { root.scheduleSort() }
}
Connections {
target: Hyprland.toplevels
function onValuesChanged() {
root._hasRefreshedOnce = false
root.scheduleSort()
}
}
Connections {
target: Hyprland.workspaces
function onValuesChanged() { root.scheduleSort() }
}
Connections {
target: Hyprland
function onFocusedWorkspaceChanged() { root.scheduleSort() }
}
Component.onCompleted: {
detectCompositor()
scheduleSort()
Qt.callLater(() => NiriService.generateNiriLayoutConfig())
}
function computeSortedToplevels() {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values)
return []
}
if (useNiriSorting) {
if (useNiriSorting)
return NiriService.sortToplevels(ToplevelManager.toplevels.values)
if (isHyprland)
return sortHyprlandToplevelsSafe()
return Array.from(ToplevelManager.toplevels.values)
}
function _get(o, path, fallback) {
try {
let v = o
for (let i = 0; i < path.length; i++) {
if (v === null || v === undefined) return fallback
v = v[path[i]]
}
return (v === undefined || v === null) ? fallback : v
} catch (e) { return fallback }
}
function sortHyprlandToplevelsSafe() {
if (!Hyprland.toplevels || !Hyprland.toplevels.values) return []
if (_refreshScheduled) return sortedToplevelsCache
const items = Array.from(Hyprland.toplevels.values)
function _get(o, path, fb) {
try {
let v = o
for (let k of path) { if (v == null) return fb; v = v[k] }
return (v == null) ? fb : v
} catch(e) { return fb }
}
if (isHyprland) {
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
let snap = []
let missingAnyPosition = false
let hasNewWindow = false
for (let i = 0; i < items.length; i++) {
const t = items[i]
if (!t) continue
const sortedHyprland = hyprlandToplevels.sort((a, b) => {
if (a.monitor && b.monitor) {
const monitorCompare = a.monitor.name.localeCompare(b.monitor.name)
if (monitorCompare !== 0) {
return monitorCompare
}
}
const addr = t.address || ""
const li = t.lastIpcObject || null
if (a.workspace && b.workspace) {
const workspaceCompare = a.workspace.id - b.workspace.id
if (workspaceCompare !== 0) {
return workspaceCompare
}
}
const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "")
const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER)
const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER)
if (a.lastIpcObject && b.lastIpcObject && a.lastIpcObject.at && b.lastIpcObject.at) {
const aX = a.lastIpcObject.at[0]
const bX = b.lastIpcObject.at[0]
const aY = a.lastIpcObject.at[1]
const bY = b.lastIpcObject.at[1]
const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER)
const xCompare = aX - bX
if (Math.abs(xCompare) > 10) {
return xCompare
}
return aY - bY
}
const at = _get(li, ["at"], null)
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : NaN
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : NaN
if (a.lastIpcObject && !b.lastIpcObject) {
return -1
}
if (!a.lastIpcObject && b.lastIpcObject) {
return 1
}
if (!(atX === atX) || !(atY === atY)) {
const cached = _coordCache[addr]
if (cached) {
atX = cached.x
atY = cached.y
} else {
if (addr) hasNewWindow = true
missingAnyPosition = true
atX = 1e9
atY = 1e9
}
} else if (addr) {
_coordCache[addr] = { x: atX, y: atY }
}
if (a.title && b.title) {
return a.title.localeCompare(b.title)
}
const relX = Number.isFinite(monX) ? (atX - monX) : atX
const relY = Number.isFinite(monY) ? (atY - monY) : atY
return 0
})
return sortedHyprland.map(hyprToplevel => hyprToplevel.wayland).filter(wayland => wayland !== null)
snap.push({
monKey: String(monName),
monOrderX: Number.isFinite(monX) ? monX : Number.MAX_SAFE_INTEGER,
monOrderY: Number.isFinite(monY) ? monY : Number.MAX_SAFE_INTEGER,
wsId: (typeof wsId === "number") ? wsId : Number.MAX_SAFE_INTEGER,
x: relX,
y: relY,
title: t.title || "",
address: addr,
wayland: t.wayland
})
}
return ToplevelManager.toplevels.values
if (missingAnyPosition && hasNewWindow) {
_hasRefreshedOnce = false
scheduleRefresh()
}
const groups = new Map()
for (const it of snap) {
const key = it.monKey + "::" + it.wsId
if (!groups.has(key)) groups.set(key, [])
groups.get(key).push(it)
}
let groupList = []
for (const [key, arr] of groups) {
const repr = arr[0]
groupList.push({
key,
monKey: repr.monKey,
monOrderX: repr.monOrderX,
monOrderY: repr.monOrderY,
wsId: repr.wsId,
items: arr
})
}
groupList.sort((a, b) => {
if (a.monOrderX !== b.monOrderX) return a.monOrderX - b.monOrderX
if (a.monOrderY !== b.monOrderY) return a.monOrderY - b.monOrderY
if (a.monKey !== b.monKey) return a.monKey.localeCompare(b.monKey)
if (a.wsId !== b.wsId) return a.wsId - b.wsId
return 0
})
const COLUMN_THRESHOLD = 48
const JITTER_Y = 6
let ordered = []
for (const g of groupList) {
const arr = g.items
const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b)
let colCenters = []
if (xs.length > 0) {
for (const x of xs) {
if (colCenters.length === 0) {
colCenters.push(x)
} else {
const last = colCenters[colCenters.length - 1]
if (x - last >= COLUMN_THRESHOLD) {
colCenters.push(x)
}
}
}
} else {
colCenters = [0]
}
for (const it of arr) {
let bestCol = 0
let bestDist = Number.POSITIVE_INFINITY
for (let ci = 0; ci < colCenters.length; ci++) {
const d = Math.abs(it.x - colCenters[ci])
if (d < bestDist) {
bestDist = d
bestCol = ci
}
}
it._col = bestCol
}
arr.sort((a, b) => {
if (a._col !== b._col) return a._col - b._col
const dy = a.y - b.y
if (Math.abs(dy) > JITTER_Y) return dy
if (a.title !== b.title) return a.title.localeCompare(b.title)
if (a.address !== b.address) return a.address.localeCompare(b.address)
return 0
})
ordered.push.apply(ordered, arr)
}
return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined)
}
function filterCurrentWorkspace(toplevels, screen) {
if (useNiriSorting) return NiriService.filterCurrentWorkspace(toplevels, screen)
if (isHyprland) return filterHyprlandCurrentWorkspaceSafe(toplevels, screen)
return toplevels
}
function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) {
if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) return toplevels
let currentWorkspaceId = null
try {
const hy = Array.from(Hyprland.toplevels.values)
for (const t of hy) {
const mon = _get(t, ["monitor", "name"], "")
const wsId = _get(t, ["workspace", "id"], null)
const active = !!_get(t, ["activated"], false)
if (mon === screenName && wsId !== null) {
if (active) { currentWorkspaceId = wsId; break }
if (currentWorkspaceId === null) currentWorkspaceId = wsId
}
}
if (currentWorkspaceId === null && Hyprland.workspaces) {
const wss = Array.from(Hyprland.workspaces.values)
const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null)
for (const ws of wss) {
const monName = _get(ws, ["monitor"], "")
const wsId = _get(ws, ["id"], null)
if (monName === screenName && wsId !== null) {
if (focusedId !== null && wsId === focusedId) { currentWorkspaceId = wsId; break }
if (currentWorkspaceId === null) currentWorkspaceId = wsId
}
}
}
} catch (e) {
console.warn("CompositorService: workspace snapshot failed:", e)
}
if (currentWorkspaceId === null) return toplevels
// Map wayland → wsId snapshot
let map = new Map()
try {
const hy = Array.from(Hyprland.toplevels.values)
for (const t of hy) {
const wsId = _get(t, ["workspace", "id"], null)
if (t && t.wayland && wsId !== null) map.set(t.wayland, wsId)
}
} catch (e) {}
return toplevels.filter(w => map.get(w) === currentWorkspaceId)
}
Timer {
@@ -91,86 +323,30 @@ Singleton {
}
}
function filterCurrentWorkspace(toplevels, screen) {
if (useNiriSorting) {
return NiriService.filterCurrentWorkspace(toplevels, screen)
}
if (isHyprland) {
return filterHyprlandCurrentWorkspace(toplevels, screen)
}
return toplevels
}
function filterHyprlandCurrentWorkspace(toplevels, screenName) {
if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) {
return toplevels
}
let currentWorkspaceId = null
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
for (const hyprToplevel of hyprlandToplevels) {
if (hyprToplevel.monitor && hyprToplevel.monitor.name === screenName && hyprToplevel.workspace) {
if (hyprToplevel.activated) {
currentWorkspaceId = hyprToplevel.workspace.id
break
}
if (currentWorkspaceId === null) {
currentWorkspaceId = hyprToplevel.workspace.id
}
}
}
if (currentWorkspaceId === null && Hyprland.workspaces) {
const workspaces = Array.from(Hyprland.workspaces.values)
for (const workspace of workspaces) {
if (workspace.monitor && workspace.monitor === screenName) {
if (Hyprland.focusedWorkspace && workspace.id === Hyprland.focusedWorkspace.id) {
currentWorkspaceId = workspace.id
break
}
if (currentWorkspaceId === null) {
currentWorkspaceId = workspace.id
}
}
}
}
if (currentWorkspaceId === null) {
return toplevels
}
return toplevels.filter(toplevel => {
for (const hyprToplevel of hyprlandToplevels) {
if (hyprToplevel.wayland === toplevel) {
return hyprToplevel.workspace && hyprToplevel.workspace.id === currentWorkspaceId
}
}
return false
})
}
function detectCompositor() {
if (hyprlandSignature && hyprlandSignature.length > 0) {
isHyprland = true
isNiri = false
compositor = "hyprland"
console.log("CompositorService: Detected Hyprland")
try {
Hyprland.refreshToplevels()
} catch(e) {}
return
}
if (niriSocket && niriSocket.length > 0) {
Proc.runCommand("niriSocketCheck", ["test", "-S", root.niriSocket], (output, exitCode) => {
Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => {
if (exitCode === 0) {
root.isNiri = true
root.isHyprland = false
root.compositor = "niri"
console.log("CompositorService: Detected Niri with socket:", root.niriSocket)
isNiri = true
isHyprland = false
compositor = "niri"
console.log("CompositorService: Detected Niri with socket:", niriSocket)
NiriService.generateNiriBinds()
} else {
root.isHyprland = false
root.isNiri = true
root.compositor = "niri"
isHyprland = false
isNiri = true
compositor = "niri"
console.warn("CompositorService: Niri socket check failed, defaulting to Niri anyway")
}
}, 0)
@@ -183,22 +359,14 @@ Singleton {
}
function powerOffMonitors() {
if (isNiri) {
return NiriService.powerOffMonitors()
}
if (isHyprland) {
return Hyprland.dispatch("dpms off")
}
if (isNiri) return NiriService.powerOffMonitors()
if (isHyprland) return Hyprland.dispatch("dpms off")
console.warn("CompositorService: Cannot power off monitors, unknown compositor")
}
function powerOnMonitors() {
if (isNiri) {
return NiriService.powerOnMonitors()
}
if (isHyprland) {
return Hyprland.dispatch("dpms on")
}
if (isNiri) return NiriService.powerOnMonitors()
if (isHyprland) return Hyprland.dispatch("dpms on")
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
}
}
}

View File

@@ -41,6 +41,7 @@ Singleton {
signal loginctlStateUpdate(var data)
signal loginctlEvent(var event)
signal capabilitiesReceived()
signal credentialsRequest(var data)
Component.onCompleted: {
if (socketPath && socketPath.length > 0) {
@@ -261,6 +262,8 @@ Singleton {
capabilitiesReceived()
} else if (service === "network") {
networkStateUpdate(data)
} else if (service === "network.credentials") {
credentialsRequest(data)
} else if (service === "loginctl") {
if (data.event) {
loginctlEvent(data)

View File

@@ -79,8 +79,21 @@ Singleton {
property int refCount: 0
property bool stateInitialized: false
property string credentialsToken: ""
property string credentialsSSID: ""
property string credentialsSetting: ""
property var credentialsFields: []
property var credentialsHints: []
property string credentialsReason: ""
property bool credentialsRequested: false
property string pendingConnectionSSID: ""
property var pendingConnectionStartTime: 0
property bool wasConnecting: false
signal networksUpdated
signal connectionChanged
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason)
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
@@ -120,6 +133,10 @@ Singleton {
function onCapabilitiesChanged() {
checkDMSCapabilities()
}
function onCredentialsRequest(data) {
handleCredentialsRequest(data)
}
}
function checkDMSCapabilities() {
@@ -143,6 +160,18 @@ Singleton {
}
}
function handleCredentialsRequest(data) {
credentialsToken = data.token || ""
credentialsSSID = data.ssid || ""
credentialsSetting = data.setting || "802-11-wireless-security"
credentialsFields = data.fields || ["psk"]
credentialsHints = data.hints || []
credentialsReason = data.reason || "Credentials required"
credentialsRequested = true
credentialsNeeded(credentialsToken, credentialsSSID, credentialsSetting, credentialsFields, credentialsHints, credentialsReason)
}
function addRef() {
refCount++
if (refCount === 1 && networkAvailable) {
@@ -177,6 +206,9 @@ Singleton {
}
function updateState(state) {
const previousConnecting = isConnecting
const previousConnectingSSID = connectingSSID
networkStatus = state.networkStatus || "disconnected"
primaryConnection = state.primaryConnection || ""
@@ -225,6 +257,45 @@ Singleton {
connectionError = state.lastError || ""
lastConnectionError = state.lastError || ""
if (pendingConnectionSSID) {
if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) {
if (DMSService.verboseLogs) {
const elapsed = Date.now() - pendingConnectionStartTime
console.log("NetworkManagerService: Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms")
}
ToastService.showInfo(`Connected to ${pendingConnectionSSID}`)
if (userPreference === "wifi" || userPreference === "auto") {
setConnectionPriority("wifi")
}
pendingConnectionSSID = ""
connectionStatus = "connected"
} else if (previousConnecting && !isConnecting && !wifiConnected) {
const elapsed = Date.now() - pendingConnectionStartTime
if (elapsed < 5000) {
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Quick connection failure, likely authentication error")
}
connectionStatus = "invalid_password"
} else {
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Connection failed for", pendingConnectionSSID)
}
if (connectionError === "connection-failed") {
ToastService.showError(I18n.tr("Connection failed. Check password and try again."))
} else if (connectionError) {
ToastService.showError(I18n.tr("Failed to connect to ") + pendingConnectionSSID)
}
connectionStatus = "failed"
pendingConnectionSSID = ""
}
}
}
wasConnecting = isConnecting
connectionChanged()
}
@@ -242,11 +313,11 @@ Singleton {
connectionError = response.error
lastConnectionError = response.error
connectionStatus = "failed"
ToastService.showError(`Failed to activate configuration`)
ToastService.showError(I18n.tr("Failed to activate configuration"))
} else {
connectionError = ""
connectionStatus = "connected"
ToastService.showInfo(`Configuration activated`)
ToastService.showInfo(I18n.tr("Configuration activated"))
}
isConnecting = false
@@ -280,42 +351,47 @@ Singleton {
function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "") {
if (!networkAvailable || isConnecting) return
connectingSSID = ssid
pendingConnectionSSID = ssid
pendingConnectionStartTime = Date.now()
connectionError = ""
connectionStatus = "connecting"
credentialsRequested = false
const params = { ssid: ssid }
if (password) params.password = password
if (username) params.username = username
if (anonymousIdentity) params.anonymousIdentity = anonymousIdentity
if (domainSuffixMatch) params.domainSuffixMatch = domainSuffixMatch
if (DMSService.apiVersion >= 7) {
if (password || username) {
params.password = password
if (username) params.username = username
if (anonymousIdentity) params.anonymousIdentity = anonymousIdentity
if (domainSuffixMatch) params.domainSuffixMatch = domainSuffixMatch
params.interactive = false
} else {
params.interactive = true
}
} else {
if (password) params.password = password
if (username) params.username = username
if (anonymousIdentity) params.anonymousIdentity = anonymousIdentity
if (domainSuffixMatch) params.domainSuffixMatch = domainSuffixMatch
}
DMSService.sendRequest("network.wifi.connect", params, response => {
if (response.error) {
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Connection request failed:", response.error)
}
connectionError = response.error
lastConnectionError = response.error
connectionStatus = response.error.includes("password") || response.error.includes("authentication")
? "invalid_password"
: "failed"
if (connectionStatus === "invalid_password") {
passwordDialogShouldReopen = true
ToastService.showError(`Invalid password for ${ssid}`)
} else {
ToastService.showError(`Failed to connect to ${ssid}`)
}
pendingConnectionSSID = ""
connectionStatus = "failed"
ToastService.showError(I18n.tr("Failed to start connection to ") + ssid)
} else {
connectionError = ""
connectionStatus = "connected"
ToastService.showInfo(`Connected to ${ssid}`)
if (userPreference === "wifi" || userPreference === "auto") {
setConnectionPriority("wifi")
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Connection request sent for", ssid)
}
}
isConnecting = false
connectingSSID = ""
})
}
@@ -324,15 +400,60 @@ Singleton {
DMSService.sendRequest("network.wifi.disconnect", null, response => {
if (response.error) {
ToastService.showError("Failed to disconnect WiFi")
ToastService.showError(I18n.tr("Failed to disconnect WiFi"))
} else {
ToastService.showInfo("Disconnected from WiFi")
ToastService.showInfo(I18n.tr("Disconnected from WiFi"))
currentWifiSSID = ""
connectionStatus = ""
}
})
}
function submitCredentials(token, secrets, save) {
if (!networkAvailable || DMSService.apiVersion < 7) return
const params = {
token: token,
secrets: secrets,
save: save || false
}
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Submitting credentials for token", token)
}
credentialsRequested = false
DMSService.sendRequest("network.credentials.submit", params, response => {
if (response.error) {
console.warn("NetworkManagerService: Failed to submit credentials:", response.error)
}
})
}
function cancelCredentials(token) {
if (!networkAvailable || DMSService.apiVersion < 7) return
const params = {
token: token,
cancel: true
}
if (DMSService.verboseLogs) {
console.log("NetworkManagerService: Cancelling credentials for token", token)
}
credentialsRequested = false
pendingConnectionSSID = ""
connectionStatus = "cancelled"
DMSService.sendRequest("network.credentials.submit", params, response => {
if (response.error) {
console.warn("NetworkManagerService: Failed to cancel credentials:", response.error)
}
})
}
function forgetWifiNetwork(ssid) {
if (!networkAvailable) return
@@ -341,7 +462,7 @@ Singleton {
if (response.error) {
console.warn("Failed to forget network:", response.error)
} else {
ToastService.showInfo(`Forgot network ${ssid}`)
ToastService.showInfo(I18n.tr("Forgot network ") + ssid)
savedConnections = savedConnections.filter(s => s.ssid !== ssid)
savedWifiNetworks = savedWifiNetworks.filter(s => s.ssid !== ssid)
@@ -374,7 +495,7 @@ Singleton {
console.warn("Failed to toggle WiFi:", response.error)
} else if (response.result) {
wifiEnabled = response.result.enabled
ToastService.showInfo(wifiEnabled ? "WiFi enabled" : "WiFi disabled")
ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled"))
}
})
}
@@ -384,9 +505,9 @@ Singleton {
DMSService.sendRequest("network.wifi.enable", null, response => {
if (response.error) {
ToastService.showError("Failed to enable WiFi")
ToastService.showError(I18n.tr("Failed to enable WiFi"))
} else {
ToastService.showInfo("WiFi enabled")
ToastService.showInfo(I18n.tr("WiFi enabled"))
}
})
}

View File

@@ -69,8 +69,17 @@ Singleton {
property bool subscriptionConnected: activeService?.subscriptionConnected ?? false
property string credentialsToken: activeService?.credentialsToken ?? ""
property string credentialsSSID: activeService?.credentialsSSID ?? ""
property string credentialsSetting: activeService?.credentialsSetting ?? ""
property var credentialsFields: activeService?.credentialsFields ?? []
property var credentialsHints: activeService?.credentialsHints ?? []
property string credentialsReason: activeService?.credentialsReason ?? ""
property bool credentialsRequested: activeService?.credentialsRequested ?? false
signal networksUpdated
signal connectionChanged
signal credentialsNeeded(string token, string ssid, string setting, var fields, var hints, string reason)
property bool usingLegacy: false
property var activeService: null
@@ -122,6 +131,9 @@ Singleton {
if (activeService.connectionChanged) {
activeService.connectionChanged.connect(root.connectionChanged)
}
if (activeService.credentialsNeeded) {
activeService.credentialsNeeded.connect(root.credentialsNeeded)
}
}
}
@@ -258,4 +270,16 @@ Singleton {
activeService.connectToSpecificWiredConfig(uuid)
}
}
function submitCredentials(token, secrets, save) {
if (activeService && activeService.submitCredentials) {
activeService.submitCredentials(token, secrets, save)
}
}
function cancelCredentials(token) {
if (activeService && activeService.cancelCredentials) {
activeService.cancelCredentials(token)
}
}
}

View File

@@ -19,10 +19,6 @@ binds {
spawn "dms" "ipc" "call" "notifications" "toggle";
}
Mod+Y hotkey-overlay-title="Browse Wallpapers" {
spawn "dms" "ipc" "call" "dankdash" "wallpaper";
}
Mod+Shift+N hotkey-overlay-title="Notepad" {
spawn "dms" "ipc" "call" "notepad" "toggle";
}