mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b27f362b44 | ||
|
|
325e3bc19b | ||
|
|
9215985335 | ||
|
|
293179daa6 | ||
|
|
4fe79dbe85 | ||
|
|
55d738e917 | ||
|
|
986b07f4a9 | ||
|
|
450c2e91ed | ||
|
|
4d06333624 | ||
|
|
fbe4122404 | ||
|
|
baf9b5e6f3 | ||
|
|
c88fc20701 | ||
|
|
b1078d6c73 | ||
|
|
5033d10246 | ||
|
|
986993a890 | ||
|
|
19b13a1e81 | ||
|
|
76637fab33 | ||
|
|
0a79d9a187 | ||
|
|
36b3b3c7ae | ||
|
|
8caeca0c08 | ||
|
|
1c323f54ee | ||
|
|
7ed0b752a8 | ||
|
|
0569906f7c | ||
|
|
2a7cf187ad | ||
|
|
cc5b98a5d2 | ||
|
|
1478c92f49 | ||
|
|
e1785a1738 | ||
|
|
44ebd2918c | ||
|
|
c87fa0de5e | ||
|
|
7b26692c8e | ||
|
|
b294e391e7 | ||
|
|
85f8e362e6 | ||
|
|
d68a6a1056 | ||
|
|
3dae9c0639 | ||
|
|
aede6b064a | ||
|
|
76b168020c | ||
|
|
5e36b1454a | ||
|
|
bd35fbac4d | ||
|
|
e081ec19cc | ||
|
|
d870d8bad6 | ||
|
|
20fd13c836 | ||
|
|
59f98b151d | ||
|
|
4ac1990c12 | ||
|
|
0a5105cc62 | ||
|
|
a9f8b835ee | ||
|
|
0109bd5bda | ||
|
|
01dad64c6d | ||
|
|
ee38f57f6d |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -24,6 +24,8 @@ assignees: ""
|
||||
|
||||
- [ ] niri
|
||||
- [ ] Hyprland
|
||||
- [ ] dwl (MangoWC)
|
||||
- [ ] sway
|
||||
- [ ] Other (specify)
|
||||
|
||||
## Distribution
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -21,6 +21,8 @@ Is this feature specific to one compositor?
|
||||
- [ ] All compositors
|
||||
- [ ] niri
|
||||
- [ ] Hyprland
|
||||
- [ ] dwl (MangoWC)
|
||||
- [ ] sway
|
||||
|
||||
## Proposed Solution
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/support_request.md
vendored
2
.github/ISSUE_TEMPLATE/support_request.md
vendored
@@ -10,6 +10,8 @@ assignees: ""
|
||||
|
||||
- [ ] niri
|
||||
- [ ] Hyprland
|
||||
- [ ] dwl (MangoWC)
|
||||
- [ ] sway
|
||||
- [ ] other
|
||||
|
||||
## Distribution
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -49,9 +49,9 @@ jobs:
|
||||
set -e
|
||||
PREVIOUS_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "")
|
||||
if [ -z "$PREVIOUS_TAG" ]; then
|
||||
CHANGELOG=$(git log --oneline --pretty=format:"- %s (%h)" --author='^(?!github-actions\[bot\])' | head -50)
|
||||
CHANGELOG=$(git log --oneline --pretty=format:"%an|%s (%h)" | grep -v "^github-actions\[bot\]|" | sed 's/^[^|]*|/- /' | head -50)
|
||||
else
|
||||
CHANGELOG=$(git log --oneline --pretty=format:"- %s (%h)" --author='^(?!github-actions\[bot\])' "${PREVIOUS_TAG}..${TAG}")
|
||||
CHANGELOG=$(git log --oneline --pretty=format:"%an|%s (%h)" "${PREVIOUS_TAG}..${TAG}" | grep -v "^github-actions\[bot\]|" | sed 's/^[^|]*|/- /')
|
||||
fi
|
||||
|
||||
cat > RELEASE_BODY.md << 'EOF'
|
||||
|
||||
@@ -10,17 +10,18 @@ Singleton {
|
||||
|
||||
property int defaultDebounceMs: 50
|
||||
property int defaultTimeoutMs: 10000
|
||||
property var _procDebouncers: ({}) // id -> { timer, command, callback, waitMs }
|
||||
property var _procDebouncers: ({})
|
||||
|
||||
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
||||
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs
|
||||
const timeout = (typeof timeoutMs === "number" && timeoutMs > 0) ? timeoutMs : defaultTimeoutMs
|
||||
let procId = id ? id : Math.random()
|
||||
const isRandomId = !id
|
||||
|
||||
if (!_procDebouncers[procId]) {
|
||||
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
||||
t.triggered.connect(function() { _launchProc(procId) })
|
||||
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout }
|
||||
t.triggered.connect(function() { _launchProc(procId, isRandomId) })
|
||||
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout, isRandomId: isRandomId }
|
||||
} else {
|
||||
_procDebouncers[procId].command = command
|
||||
_procDebouncers[procId].callback = callback
|
||||
@@ -33,7 +34,7 @@ Singleton {
|
||||
entry.timer.restart()
|
||||
}
|
||||
|
||||
function _launchProc(id) {
|
||||
function _launchProc(id, isRandomId) {
|
||||
const entry = _procDebouncers[id]
|
||||
if (!entry) return
|
||||
|
||||
@@ -92,6 +93,15 @@ Singleton {
|
||||
}
|
||||
try { proc.destroy() } catch (_) {}
|
||||
try { timeoutTimer.destroy() } catch (_) {}
|
||||
|
||||
if (isRandomId || entry.isRandomId) {
|
||||
Qt.callLater(function() {
|
||||
if (_procDebouncers[id]) {
|
||||
try { _procDebouncers[id].timer.destroy() } catch (_) {}
|
||||
delete _procDebouncers[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
proc.running = true
|
||||
|
||||
@@ -131,6 +131,7 @@ Singleton {
|
||||
property bool showWorkspaceApps: false
|
||||
property int maxWorkspaceIcons: 3
|
||||
property bool workspacesPerMonitor: true
|
||||
property bool dwlShowAllTags: false
|
||||
property var workspaceNameIcons: ({})
|
||||
property bool waveProgressEnabled: true
|
||||
property bool clockCompactMode: false
|
||||
@@ -433,6 +434,7 @@ Singleton {
|
||||
maxWorkspaceIcons = settings.maxWorkspaceIcons !== undefined ? settings.maxWorkspaceIcons : 3
|
||||
workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({})
|
||||
workspacesPerMonitor = settings.workspacesPerMonitor !== undefined ? settings.workspacesPerMonitor : true
|
||||
dwlShowAllTags = settings.dwlShowAllTags !== undefined ? settings.dwlShowAllTags : false
|
||||
waveProgressEnabled = settings.waveProgressEnabled !== undefined ? settings.waveProgressEnabled : true
|
||||
clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false
|
||||
focusedWindowCompactMode = settings.focusedWindowCompactMode !== undefined ? settings.focusedWindowCompactMode : false
|
||||
@@ -470,6 +472,7 @@ Singleton {
|
||||
spotlightModalViewMode = settings.spotlightModalViewMode !== undefined ? settings.spotlightModalViewMode : "list"
|
||||
sortAppsAlphabetically = settings.sortAppsAlphabetically !== undefined ? settings.sortAppsAlphabetically : false
|
||||
networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto"
|
||||
vpnLastConnected = settings.vpnLastConnected !== undefined ? settings.vpnLastConnected : ""
|
||||
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"
|
||||
if (settings.useOSLogo !== undefined) {
|
||||
launcherLogoMode = settings.useOSLogo ? "os" : "apps"
|
||||
@@ -647,6 +650,7 @@ Singleton {
|
||||
"showWorkspaceApps": showWorkspaceApps,
|
||||
"maxWorkspaceIcons": maxWorkspaceIcons,
|
||||
"workspacesPerMonitor": workspacesPerMonitor,
|
||||
"dwlShowAllTags": dwlShowAllTags,
|
||||
"workspaceNameIcons": workspaceNameIcons,
|
||||
"waveProgressEnabled": waveProgressEnabled,
|
||||
"clockCompactMode": clockCompactMode,
|
||||
@@ -665,6 +669,7 @@ Singleton {
|
||||
"spotlightModalViewMode": spotlightModalViewMode,
|
||||
"sortAppsAlphabetically": sortAppsAlphabetically,
|
||||
"networkPreference": networkPreference,
|
||||
"vpnLastConnected": vpnLastConnected,
|
||||
"iconTheme": iconTheme,
|
||||
"launcherLogoMode": launcherLogoMode,
|
||||
"launcherLogoCustomPath": launcherLogoCustomPath,
|
||||
@@ -774,7 +779,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
const validKeys = ["currentThemeName", "customThemeFile", "matugenScheme", "runUserMatugenTemplates", "matugenTargetMonitor", "dankBarTransparency", "dankBarWidgetTransparency", "popupTransparency", "dockTransparency", "use24HourClock", "showSeconds", "useFahrenheit", "nightModeEnabled", "weatherLocation", "weatherCoordinates", "useAutoLocation", "weatherEnabled", "showLauncherButton", "showWorkspaceSwitcher", "showFocusedWindow", "showWeather", "showMusic", "showClipboard", "showCpuUsage", "showMemUsage", "showCpuTemp", "showGpuTemp", "selectedGpuIndex", "enabledGpuPciIds", "showSystemTray", "showClock", "showNotificationButton", "showBattery", "showControlCenterButton", "controlCenterShowNetworkIcon", "controlCenterShowBluetoothIcon", "controlCenterShowAudioIcon", "controlCenterWidgets", "showWorkspaceIndex", "workspaceScrolling", "showWorkspacePadding", "showWorkspaceApps", "maxWorkspaceIcons", "workspacesPerMonitor", "workspaceNameIcons", "waveProgressEnabled", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsCurrentWorkspace", "runningAppsGroupByApp", "clockDateFormat", "lockDateFormat", "mediaSize", "dankBarLeftWidgets", "dankBarCenterWidgets", "dankBarRightWidgets", "appLauncherViewMode", "spotlightModalViewMode", "sortAppsAlphabetically", "networkPreference", "iconTheme", "launcherLogoMode", "launcherLogoCustomPath", "launcherLogoColorOverride", "launcherLogoColorInvertOnMode", "launcherLogoBrightness", "launcherLogoContrast", "launcherLogoSizeOffset", "fontFamily", "monoFontFamily", "fontWeight", "fontScale", "dankBarFontScale", "notepadUseMonospace", "notepadFontFamily", "notepadFontSize", "notepadShowLineNumbers", "notepadTransparencyOverride", "notepadLastCustomTransparency", "soundsEnabled", "useSystemSoundTheme", "soundNewNotification", "soundVolumeChanged", "soundPluggedIn", "gtkThemingEnabled", "qtThemingEnabled", "syncModeWithPortal", "showDock", "dockAutoHide", "dockGroupByApp", "dockOpenOnOverview", "dockPosition", "dockSpacing", "dockBottomGap", "dockIconSize", "dockIndicatorStyle", "cornerRadius", "notificationOverlayEnabled", "dankBarAutoHide", "dankBarOpenOnOverview", "dankBarVisible", "dankBarSpacing", "dankBarBottomGap", "dankBarInnerPadding", "dankBarSquareCorners", "dankBarNoBackground", "dankBarGothCornersEnabled", "dankBarBorderEnabled", "dankBarBorderColor", "dankBarBorderOpacity", "dankBarBorderThickness", "popupGapsAuto", "popupGapsManual", "dankBarPosition", "lockScreenShowPowerActions", "enableFprint", "maxFprintTries", "hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase", "wallpaperFillMode", "blurredWallpaperLayer", "blurWallpaperOnOverview", "notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical", "notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm", "customPowerActionLock", "customPowerActionLogout", "customPowerActionSuspend", "customPowerActionHibernate", "customPowerActionReboot", "customPowerActionPowerOff", "updaterUseCustomCommand", "updaterCustomCommand", "updaterTerminalAdditionalParams", "screenPreferences", "showOnLastDisplay", "animationSpeed", "customAnimationDuration", "acMonitorTimeout", "acLockTimeout", "acSuspendTimeout", "acHibernateTimeout", "batteryMonitorTimeout", "batteryLockTimeout", "batterySuspendTimeout", "batteryHibernateTimeout", "lockBeforeSuspend", "loginctlLockIntegration", "launchPrefix", "brightnessDevicePins", "configVersion"]
|
||||
const validKeys = ["currentThemeName", "customThemeFile", "matugenScheme", "runUserMatugenTemplates", "matugenTargetMonitor", "dankBarTransparency", "dankBarWidgetTransparency", "popupTransparency", "dockTransparency", "use24HourClock", "showSeconds", "useFahrenheit", "nightModeEnabled", "weatherLocation", "weatherCoordinates", "useAutoLocation", "weatherEnabled", "showLauncherButton", "showWorkspaceSwitcher", "showFocusedWindow", "showWeather", "showMusic", "showClipboard", "showCpuUsage", "showMemUsage", "showCpuTemp", "showGpuTemp", "selectedGpuIndex", "enabledGpuPciIds", "showSystemTray", "showClock", "showNotificationButton", "showBattery", "showControlCenterButton", "controlCenterShowNetworkIcon", "controlCenterShowBluetoothIcon", "controlCenterShowAudioIcon", "controlCenterWidgets", "showWorkspaceIndex", "workspaceScrolling", "showWorkspacePadding", "showWorkspaceApps", "maxWorkspaceIcons", "workspacesPerMonitor", "dwlShowAllTags", "workspaceNameIcons", "waveProgressEnabled", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "runningAppsCurrentWorkspace", "runningAppsGroupByApp", "clockDateFormat", "lockDateFormat", "mediaSize", "dankBarLeftWidgets", "dankBarCenterWidgets", "dankBarRightWidgets", "appLauncherViewMode", "spotlightModalViewMode", "sortAppsAlphabetically", "networkPreference", "vpnLastConnected", "iconTheme", "launcherLogoMode", "launcherLogoCustomPath", "launcherLogoColorOverride", "launcherLogoColorInvertOnMode", "launcherLogoBrightness", "launcherLogoContrast", "launcherLogoSizeOffset", "fontFamily", "monoFontFamily", "fontWeight", "fontScale", "dankBarFontScale", "notepadUseMonospace", "notepadFontFamily", "notepadFontSize", "notepadShowLineNumbers", "notepadTransparencyOverride", "notepadLastCustomTransparency", "soundsEnabled", "useSystemSoundTheme", "soundNewNotification", "soundVolumeChanged", "soundPluggedIn", "gtkThemingEnabled", "qtThemingEnabled", "syncModeWithPortal", "showDock", "dockAutoHide", "dockGroupByApp", "dockOpenOnOverview", "dockPosition", "dockSpacing", "dockBottomGap", "dockIconSize", "dockIndicatorStyle", "cornerRadius", "notificationOverlayEnabled", "dankBarAutoHide", "dankBarOpenOnOverview", "dankBarVisible", "dankBarSpacing", "dankBarBottomGap", "dankBarInnerPadding", "dankBarSquareCorners", "dankBarNoBackground", "dankBarGothCornersEnabled", "dankBarBorderEnabled", "dankBarBorderColor", "dankBarBorderOpacity", "dankBarBorderThickness", "popupGapsAuto", "popupGapsManual", "dankBarPosition", "lockScreenShowPowerActions", "enableFprint", "maxFprintTries", "hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase", "wallpaperFillMode", "blurredWallpaperLayer", "blurWallpaperOnOverview", "notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical", "notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm", "customPowerActionLock", "customPowerActionLogout", "customPowerActionSuspend", "customPowerActionHibernate", "customPowerActionReboot", "customPowerActionPowerOff", "updaterUseCustomCommand", "updaterCustomCommand", "updaterTerminalAdditionalParams", "screenPreferences", "showOnLastDisplay", "animationSpeed", "customAnimationDuration", "acMonitorTimeout", "acLockTimeout", "acSuspendTimeout", "acHibernateTimeout", "batteryMonitorTimeout", "batteryLockTimeout", "batterySuspendTimeout", "batteryHibernateTimeout", "lockBeforeSuspend", "loginctlLockIntegration", "launchPrefix", "brightnessDevicePins", "configVersion"]
|
||||
|
||||
try {
|
||||
const content = settingsFile.text()
|
||||
@@ -965,7 +970,7 @@ Singleton {
|
||||
}
|
||||
return {
|
||||
"x": relativeX,
|
||||
"y": barThickness + dankBarSpacing + dankBarBottomGap + Theme.popupDistance,
|
||||
"y": barThickness + dankBarSpacing + Theme.popupDistance,
|
||||
"width": widgetWidth
|
||||
}
|
||||
}
|
||||
@@ -1270,6 +1275,11 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDwlShowAllTags(enabled) {
|
||||
dwlShowAllTags = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setWorkspaceNameIcon(workspaceName, iconData) {
|
||||
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons))
|
||||
iconMap[workspaceName] = iconData
|
||||
|
||||
@@ -111,12 +111,12 @@ Singleton {
|
||||
console.info("Theme: Matugen now available, regenerating colors for dynamic theme")
|
||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
|
||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||
if (rawWallpaperPath.startsWith("#")) {
|
||||
setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
const effectivePath = rawWallpaperPath.startsWith("we:") ? (stateDir + "/we_screenshots/" + rawWallpaperPath.substring(3) + ".jpg") : rawWallpaperPath
|
||||
if (effectivePath.startsWith("#")) {
|
||||
setDesiredTheme("hex", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
} else {
|
||||
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
setDesiredTheme("image", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -126,12 +126,12 @@ Singleton {
|
||||
|
||||
if (currentTheme === dynamic) {
|
||||
if (rawWallpaperPath) {
|
||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||
if (rawWallpaperPath.startsWith("#")) {
|
||||
setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
const effectivePath = rawWallpaperPath.startsWith("we:") ? (stateDir + "/we_screenshots/" + rawWallpaperPath.substring(3) + ".jpg") : rawWallpaperPath
|
||||
if (effectivePath.startsWith("#")) {
|
||||
setDesiredTheme("hex", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
} else {
|
||||
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
setDesiredTheme("image", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -148,7 +148,6 @@ Singleton {
|
||||
}
|
||||
|
||||
if (primaryColor) {
|
||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||
setDesiredTheme("hex", primaryColor, isLight, iconTheme, matugenType)
|
||||
}
|
||||
}
|
||||
@@ -812,11 +811,12 @@ Singleton {
|
||||
const desiredPath = stateDir + "/matugen.desired.json"
|
||||
|
||||
Quickshell.execDetached(["sh", "-c", `mkdir -p '${stateDir}' && cat > '${desiredPath}' << 'EOF'\n${json}\nEOF`])
|
||||
Quickshell.execDetached(["rm", "-f", stateDir + "/matugen.key"])
|
||||
workerRunning = true
|
||||
const syncModeWithPortal = (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal) ? "true" : "false"
|
||||
if (rawWallpaperPath.startsWith("we:")) {
|
||||
console.log("Theme: Starting matugen worker (WE wallpaper)")
|
||||
systemThemeGenerator.command = ["sh", "-c", `sleep 1 && ${shellDir}/scripts/matugen-worker.sh '${stateDir}' '${shellDir}' '${configDir}' '${syncModeWithPortal}' --run`]
|
||||
console.log("Theme: Starting matugen worker (WE wallpaper, waiting for screenshot)")
|
||||
systemThemeGenerator.command = ["sh", "-c", `sleep 3 && ${shellDir}/scripts/matugen-worker.sh '${stateDir}' '${shellDir}' '${configDir}' '${syncModeWithPortal}' --run`]
|
||||
} else {
|
||||
console.log("Theme: Starting matugen worker")
|
||||
systemThemeGenerator.command = [shellDir + "/scripts/matugen-worker.sh", stateDir, shellDir, configDir, syncModeWithPortal, "--run"]
|
||||
@@ -837,10 +837,11 @@ Singleton {
|
||||
return
|
||||
}
|
||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||
if (rawWallpaperPath.startsWith("#")) {
|
||||
setDesiredTheme("hex", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
const effectivePath = rawWallpaperPath.startsWith("we:") ? (stateDir + "/we_screenshots/" + rawWallpaperPath.substring(3) + ".jpg") : rawWallpaperPath
|
||||
if (effectivePath.startsWith("#")) {
|
||||
setDesiredTheme("hex", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
} else {
|
||||
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType)
|
||||
setDesiredTheme("image", effectivePath, isLight, iconTheme, selectedMatugenType)
|
||||
}
|
||||
} else {
|
||||
let primaryColor
|
||||
|
||||
@@ -54,7 +54,7 @@ Item {
|
||||
|
||||
Loader {
|
||||
id: blurredWallpaperBackgroundLoader
|
||||
active: SettingsData.blurredWallpaperLayer
|
||||
active: SettingsData.blurredWallpaperLayer && CompositorService.isNiri
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: BlurredWallpaperBackground {}
|
||||
|
||||
@@ -135,24 +135,22 @@ Item {
|
||||
}
|
||||
|
||||
function toggle(tab: string): string {
|
||||
root.dankDashPopoutLoader.active = true
|
||||
if (root.dankDashPopoutLoader.item) {
|
||||
if (root.dankDashPopoutLoader.item.dashVisible) {
|
||||
root.dankDashPopoutLoader.item.dashVisible = false
|
||||
} else {
|
||||
if (root.dankBarLoader.item && root.dankBarLoader.item.triggerWallpaperBrowserOnFocusedScreen()) {
|
||||
if (root.dankDashPopoutLoader.item) {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "wallpaper":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 2
|
||||
break
|
||||
case "weather":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0
|
||||
break
|
||||
default:
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
root.dankDashPopoutLoader.item.dashVisible = true
|
||||
}
|
||||
return "DASH_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
@@ -17,17 +17,7 @@ PanelWindow {
|
||||
property real height: 300
|
||||
readonly property real screenWidth: screen ? screen.width : 1920
|
||||
readonly property real screenHeight: screen ? screen.height : 1080
|
||||
readonly property real dpr: {
|
||||
if (CompositorService.isNiri && screen) {
|
||||
const niriScale = NiriService.displayScales[screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
return (screen?.devicePixelRatio) || 1
|
||||
}
|
||||
readonly property real dpr: CompositorService.getScreenScale(screen)
|
||||
property bool showBackground: true
|
||||
property real backgroundOpacity: 0.5
|
||||
property string positioning: "center"
|
||||
|
||||
@@ -20,78 +20,68 @@ StyledRect {
|
||||
signal itemClicked(int index, string path, string name, bool isDir)
|
||||
signal itemSelected(int index, string path, string name, bool isDir)
|
||||
|
||||
function getFileExtension(fileName) {
|
||||
const parts = fileName.split('.')
|
||||
if (parts.length > 1) {
|
||||
return parts[parts.length - 1].toLowerCase()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function determineFileType(fileName) {
|
||||
const ext = getFileExtension(fileName)
|
||||
|
||||
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"]
|
||||
if (imageExts.includes(ext)) {
|
||||
return "image"
|
||||
}
|
||||
|
||||
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]
|
||||
if (videoExts.includes(ext)) {
|
||||
return "video"
|
||||
}
|
||||
|
||||
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]
|
||||
if (audioExts.includes(ext)) {
|
||||
return "audio"
|
||||
}
|
||||
|
||||
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]
|
||||
if (codeExts.includes(ext)) {
|
||||
return "code"
|
||||
}
|
||||
|
||||
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]
|
||||
if (docExts.includes(ext)) {
|
||||
return "document"
|
||||
}
|
||||
|
||||
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]
|
||||
if (archiveExts.includes(ext)) {
|
||||
return "archive"
|
||||
}
|
||||
|
||||
if (!ext || fileName.indexOf('.') === -1) {
|
||||
return "binary"
|
||||
}
|
||||
|
||||
return "file"
|
||||
}
|
||||
|
||||
function isImageFile(fileName) {
|
||||
if (!fileName) {
|
||||
return false
|
||||
}
|
||||
const ext = fileName.toLowerCase().split('.').pop()
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
|
||||
return determineFileType(fileName) === "image"
|
||||
}
|
||||
|
||||
function getFileIcon(fileName, isDir) {
|
||||
if (isDir) {
|
||||
return "folder"
|
||||
function getIconForFile(fileName) {
|
||||
const lowerName = fileName.toLowerCase()
|
||||
if (lowerName.startsWith("dockerfile")) {
|
||||
return "docker"
|
||||
}
|
||||
if (!fileName) {
|
||||
return "description"
|
||||
}
|
||||
const ext = fileName.toLowerCase().split('.').pop()
|
||||
const iconMap = {
|
||||
"mp3": 'music_note',
|
||||
"wav": 'music_note',
|
||||
"flac": 'music_note',
|
||||
"ogg": 'music_note',
|
||||
"aac": 'music_note',
|
||||
"mp4": 'movie',
|
||||
"mkv": 'movie',
|
||||
"avi": 'movie',
|
||||
"mov": 'movie',
|
||||
"webm": 'movie',
|
||||
"flv": 'movie',
|
||||
"wmv": 'movie',
|
||||
"jpg": 'image',
|
||||
"jpeg": 'image',
|
||||
"png": 'image',
|
||||
"gif": 'image',
|
||||
"bmp": 'image',
|
||||
"webp": 'image',
|
||||
"svg": 'image',
|
||||
"pdf": 'picture_as_pdf',
|
||||
"zip": 'folder_zip',
|
||||
"rar": 'folder_zip',
|
||||
"7z": 'folder_zip',
|
||||
"tar": 'folder_zip',
|
||||
"gz": 'folder_zip',
|
||||
"bz2": 'folder_zip',
|
||||
"xz": 'folder_zip',
|
||||
"txt": 'description',
|
||||
"md": 'description',
|
||||
"doc": 'description',
|
||||
"docx": 'description',
|
||||
"odt": 'description',
|
||||
"rtf": 'description',
|
||||
"sh": 'terminal',
|
||||
"py": 'code',
|
||||
"js": 'code',
|
||||
"ts": 'code',
|
||||
"cpp": 'code',
|
||||
"c": 'code',
|
||||
"h": 'code',
|
||||
"java": 'code',
|
||||
"go": 'code',
|
||||
"rs": 'code',
|
||||
"php": 'code',
|
||||
"rb": 'code',
|
||||
"qml": 'code',
|
||||
"html": 'code',
|
||||
"css": 'code',
|
||||
"json": 'data_object',
|
||||
"xml": 'data_object',
|
||||
"yaml": 'data_object',
|
||||
"yml": 'data_object',
|
||||
"toml": 'data_object'
|
||||
}
|
||||
return iconMap[ext] || 'description'
|
||||
const ext = fileName.split('.').pop()
|
||||
return ext || ""
|
||||
}
|
||||
|
||||
width: weMode ? 245 : iconSizes[iconSizeIndex] + 16
|
||||
@@ -179,9 +169,9 @@ StyledRect {
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
DankNFIcon {
|
||||
anchors.centerIn: parent
|
||||
name: getFileIcon(delegateRoot.fileName, delegateRoot.fileIsDir)
|
||||
name: delegateRoot.fileIsDir ? "folder" : getIconForFile(delegateRoot.fileName)
|
||||
size: iconSizes[iconSizeIndex] * 0.45
|
||||
color: delegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText
|
||||
visible: (!delegateRoot.fileIsDir && !isImageFile(delegateRoot.fileName)) || (delegateRoot.fileIsDir && !weMode)
|
||||
|
||||
@@ -19,78 +19,68 @@ StyledRect {
|
||||
signal itemClicked(int index, string path, string name, bool isDir)
|
||||
signal itemSelected(int index, string path, string name, bool isDir)
|
||||
|
||||
function getFileExtension(fileName) {
|
||||
const parts = fileName.split('.')
|
||||
if (parts.length > 1) {
|
||||
return parts[parts.length - 1].toLowerCase()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function determineFileType(fileName) {
|
||||
const ext = getFileExtension(fileName)
|
||||
|
||||
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"]
|
||||
if (imageExts.includes(ext)) {
|
||||
return "image"
|
||||
}
|
||||
|
||||
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]
|
||||
if (videoExts.includes(ext)) {
|
||||
return "video"
|
||||
}
|
||||
|
||||
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]
|
||||
if (audioExts.includes(ext)) {
|
||||
return "audio"
|
||||
}
|
||||
|
||||
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]
|
||||
if (codeExts.includes(ext)) {
|
||||
return "code"
|
||||
}
|
||||
|
||||
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]
|
||||
if (docExts.includes(ext)) {
|
||||
return "document"
|
||||
}
|
||||
|
||||
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]
|
||||
if (archiveExts.includes(ext)) {
|
||||
return "archive"
|
||||
}
|
||||
|
||||
if (!ext || fileName.indexOf('.') === -1) {
|
||||
return "binary"
|
||||
}
|
||||
|
||||
return "file"
|
||||
}
|
||||
|
||||
function isImageFile(fileName) {
|
||||
if (!fileName) {
|
||||
return false
|
||||
}
|
||||
const ext = fileName.toLowerCase().split('.').pop()
|
||||
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
|
||||
return determineFileType(fileName) === "image"
|
||||
}
|
||||
|
||||
function getFileIcon(fileName, isDir) {
|
||||
if (isDir) {
|
||||
return "folder"
|
||||
function getIconForFile(fileName) {
|
||||
const lowerName = fileName.toLowerCase()
|
||||
if (lowerName.startsWith("dockerfile")) {
|
||||
return "docker"
|
||||
}
|
||||
if (!fileName) {
|
||||
return "description"
|
||||
}
|
||||
const ext = fileName.toLowerCase().split('.').pop()
|
||||
const iconMap = {
|
||||
"mp3": 'music_note',
|
||||
"wav": 'music_note',
|
||||
"flac": 'music_note',
|
||||
"ogg": 'music_note',
|
||||
"aac": 'music_note',
|
||||
"mp4": 'movie',
|
||||
"mkv": 'movie',
|
||||
"avi": 'movie',
|
||||
"mov": 'movie',
|
||||
"webm": 'movie',
|
||||
"flv": 'movie',
|
||||
"wmv": 'movie',
|
||||
"jpg": 'image',
|
||||
"jpeg": 'image',
|
||||
"png": 'image',
|
||||
"gif": 'image',
|
||||
"bmp": 'image',
|
||||
"webp": 'image',
|
||||
"svg": 'image',
|
||||
"pdf": 'picture_as_pdf',
|
||||
"zip": 'folder_zip',
|
||||
"rar": 'folder_zip',
|
||||
"7z": 'folder_zip',
|
||||
"tar": 'folder_zip',
|
||||
"gz": 'folder_zip',
|
||||
"bz2": 'folder_zip',
|
||||
"xz": 'folder_zip',
|
||||
"txt": 'description',
|
||||
"md": 'description',
|
||||
"doc": 'description',
|
||||
"docx": 'description',
|
||||
"odt": 'description',
|
||||
"rtf": 'description',
|
||||
"sh": 'terminal',
|
||||
"py": 'code',
|
||||
"js": 'code',
|
||||
"ts": 'code',
|
||||
"cpp": 'code',
|
||||
"c": 'code',
|
||||
"h": 'code',
|
||||
"java": 'code',
|
||||
"go": 'code',
|
||||
"rs": 'code',
|
||||
"php": 'code',
|
||||
"rb": 'code',
|
||||
"qml": 'code',
|
||||
"html": 'code',
|
||||
"css": 'code',
|
||||
"json": 'data_object',
|
||||
"xml": 'data_object',
|
||||
"yaml": 'data_object',
|
||||
"yml": 'data_object',
|
||||
"toml": 'data_object'
|
||||
}
|
||||
return iconMap[ext] || 'description'
|
||||
const ext = fileName.split('.').pop()
|
||||
return ext || ""
|
||||
}
|
||||
|
||||
function formatFileSize(size) {
|
||||
@@ -168,9 +158,9 @@ StyledRect {
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
DankNFIcon {
|
||||
anchors.centerIn: parent
|
||||
name: getFileIcon(listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
|
||||
name: listDelegateRoot.fileIsDir ? "folder" : getIconForFile(listDelegateRoot.fileName)
|
||||
size: Theme.iconSize - 2
|
||||
color: listDelegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText
|
||||
visible: listDelegateRoot.fileIsDir || !isImageFile(listDelegateRoot.fileName)
|
||||
|
||||
@@ -34,8 +34,8 @@ DankModal {
|
||||
}
|
||||
|
||||
objectName: "settingsModal"
|
||||
width: 800
|
||||
height: 800
|
||||
width: Math.min(800, screenWidth * 0.9)
|
||||
height: Math.min(800, screenHeight * 0.85)
|
||||
visible: false
|
||||
onBackgroundClicked: () => {
|
||||
return hide();
|
||||
|
||||
@@ -54,17 +54,25 @@ Variants {
|
||||
}
|
||||
|
||||
function getFillMode(modeName) {
|
||||
switch(modeName) {
|
||||
case "Stretch": return Image.Stretch
|
||||
case "Fit":
|
||||
case "PreserveAspectFit": return Image.PreserveAspectFit
|
||||
case "Fill":
|
||||
case "PreserveAspectCrop": return Image.PreserveAspectCrop
|
||||
case "Tile": return Image.Tile
|
||||
case "TileVertically": return Image.TileVertically
|
||||
case "TileHorizontally": return Image.TileHorizontally
|
||||
case "Pad": return Image.Pad
|
||||
default: return Image.PreserveAspectCrop
|
||||
switch (modeName) {
|
||||
case "Stretch":
|
||||
return Image.Stretch
|
||||
case "Fit":
|
||||
case "PreserveAspectFit":
|
||||
return Image.PreserveAspectFit
|
||||
case "Fill":
|
||||
case "PreserveAspectCrop":
|
||||
return Image.PreserveAspectCrop
|
||||
case "Tile":
|
||||
return Image.Tile
|
||||
case "TileVertically":
|
||||
return Image.TileVertically
|
||||
case "TileHorizontally":
|
||||
return Image.TileHorizontally
|
||||
case "Pad":
|
||||
return Image.Pad
|
||||
default:
|
||||
return Image.PreserveAspectCrop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,33 +84,77 @@ Variants {
|
||||
Component.onCompleted: {
|
||||
if (source) {
|
||||
const formattedSource = source.startsWith("file://") ? source : "file://" + source
|
||||
wallpaperImage.source = formattedSource
|
||||
setWallpaperImmediate(formattedSource)
|
||||
}
|
||||
isInitialized = true
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
weProc.stop()
|
||||
}
|
||||
|
||||
property bool isInitialized: false
|
||||
property real transitionProgress: 0
|
||||
readonly property bool transitioning: transitionAnimation.running
|
||||
|
||||
onSourceChanged: {
|
||||
const isWE = source.startsWith("we:")
|
||||
const isColor = source.startsWith("#")
|
||||
|
||||
if (isWE) {
|
||||
wallpaperImage.source = ""
|
||||
setWallpaperImmediate("")
|
||||
weProc.start(source.substring(3))
|
||||
} else {
|
||||
weProc.stop()
|
||||
if (!source) {
|
||||
wallpaperImage.source = ""
|
||||
setWallpaperImmediate("")
|
||||
} else if (isColor) {
|
||||
wallpaperImage.source = ""
|
||||
setWallpaperImmediate("")
|
||||
} else {
|
||||
wallpaperImage.source = source.startsWith("file://") ? source : "file://" + source
|
||||
if (!isInitialized || !currentWallpaper.source) {
|
||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source)
|
||||
isInitialized = true
|
||||
} else {
|
||||
changeWallpaper(source.startsWith("file://") ? source : "file://" + source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setWallpaperImmediate(newSource) {
|
||||
transitionAnimation.stop()
|
||||
root.transitionProgress = 0.0
|
||||
currentWallpaper.source = newSource
|
||||
nextWallpaper.source = ""
|
||||
currentWallpaper.opacity = 1
|
||||
nextWallpaper.opacity = 0
|
||||
}
|
||||
|
||||
function changeWallpaper(newPath) {
|
||||
if (newPath === currentWallpaper.source)
|
||||
return
|
||||
if (!newPath || newPath.startsWith("#"))
|
||||
return
|
||||
|
||||
if (root.transitioning) {
|
||||
transitionAnimation.stop()
|
||||
root.transitionProgress = 0
|
||||
currentWallpaper.source = nextWallpaper.source
|
||||
nextWallpaper.source = ""
|
||||
}
|
||||
|
||||
if (!currentWallpaper.source) {
|
||||
setWallpaperImmediate(newPath)
|
||||
return
|
||||
}
|
||||
|
||||
nextWallpaper.source = newPath
|
||||
|
||||
if (nextWallpaper.status === Image.Ready) {
|
||||
transitionAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: !root.source || root.isColorSource
|
||||
@@ -114,21 +166,78 @@ Variants {
|
||||
}
|
||||
|
||||
Image {
|
||||
id: wallpaperImage
|
||||
id: currentWallpaper
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
opacity: 1
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
cache: true
|
||||
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
Image {
|
||||
id: nextWallpaper
|
||||
anchors.fill: parent
|
||||
source: wallpaperImage
|
||||
blurEnabled: true
|
||||
blur: 0.8
|
||||
blurMax: 75
|
||||
visible: false
|
||||
opacity: 0
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
cache: true
|
||||
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||
|
||||
onStatusChanged: {
|
||||
if (status !== Image.Ready)
|
||||
return
|
||||
|
||||
if (!root.transitioning) {
|
||||
transitionAnimation.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: blurredLayer
|
||||
anchors.fill: parent
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
source: currentWallpaper
|
||||
blurEnabled: true
|
||||
blur: 0.8
|
||||
blurMax: 75
|
||||
opacity: 1 - root.transitionProgress
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
source: nextWallpaper
|
||||
blurEnabled: true
|
||||
blur: 0.8
|
||||
blurMax: 75
|
||||
opacity: root.transitionProgress
|
||||
}
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
id: transitionAnimation
|
||||
target: root
|
||||
property: "transitionProgress"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: 1000
|
||||
easing.type: Easing.InOutCubic
|
||||
onFinished: {
|
||||
Qt.callLater(() => {
|
||||
if (nextWallpaper.source && nextWallpaper.status === Image.Ready && !nextWallpaper.source.toString().startsWith("#")) {
|
||||
currentWallpaper.source = nextWallpaper.source
|
||||
}
|
||||
nextWallpaper.source = ""
|
||||
currentWallpaper.opacity = 1
|
||||
nextWallpaper.opacity = 0
|
||||
root.transitionProgress = 0.0
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,7 @@ Item {
|
||||
anchors.topMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0)
|
||||
anchors.bottomMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0)
|
||||
|
||||
readonly property real dpr: {
|
||||
if (CompositorService.isNiri && barWindow.screen) {
|
||||
const niriScale = NiriService.displayScales[barWindow.screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && barWindow.screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === barWindow.screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
return barWindow.screen?.devicePixelRatio || 1
|
||||
}
|
||||
readonly property real dpr: CompositorService.getScreenScale(barWindow.screen)
|
||||
|
||||
function requestRepaint() {
|
||||
debounceTimer.restart()
|
||||
|
||||
@@ -4,6 +4,7 @@ import QtQuick.Effects
|
||||
import QtQuick.Shapes
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.I3
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
import Quickshell.Services.Notifications
|
||||
@@ -31,6 +32,9 @@ Item {
|
||||
focusedScreenName = Hyprland.focusedWorkspace.monitor.name
|
||||
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||
focusedScreenName = NiriService.currentOutput
|
||||
} else if (CompositorService.isSway) {
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
|
||||
focusedScreenName = focusedWs?.monitor?.name || ""
|
||||
}
|
||||
|
||||
if (!focusedScreenName && barVariants.instances.length > 0) {
|
||||
@@ -55,6 +59,9 @@ Item {
|
||||
focusedScreenName = Hyprland.focusedWorkspace.monitor.name
|
||||
} else if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||
focusedScreenName = NiriService.currentOutput
|
||||
} else if (CompositorService.isSway) {
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
|
||||
focusedScreenName = focusedWs?.monitor?.name || ""
|
||||
}
|
||||
|
||||
if (!focusedScreenName && barVariants.instances.length > 0) {
|
||||
@@ -110,9 +117,9 @@ Item {
|
||||
return
|
||||
}
|
||||
|
||||
if (clockButtonRef && dankDashPopoutLoader.item.setTriggerPosition) {
|
||||
const globalPos = clockButtonRef.mapToGlobal(0, 0)
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.width)
|
||||
if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) {
|
||||
const globalPos = clockButtonRef.visualContent.mapToGlobal(0, 0)
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.visualWidth)
|
||||
const section = clockButtonRef.section || "center"
|
||||
dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen)
|
||||
} else {
|
||||
@@ -173,19 +180,7 @@ Item {
|
||||
readonly property color _surfaceContainer: Theme.surfaceContainer
|
||||
readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency
|
||||
readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
|
||||
readonly property real _dpr: {
|
||||
if (CompositorService.isNiri && barWindow.screen) {
|
||||
const niriScale = NiriService.displayScales[barWindow.screen.name]
|
||||
if (niriScale !== undefined)
|
||||
return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && barWindow.screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === barWindow.screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined)
|
||||
return hyprlandMonitor.scale
|
||||
}
|
||||
return (barWindow.screen?.devicePixelRatio) || 1
|
||||
}
|
||||
readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen)
|
||||
|
||||
property string screenName: modelData.name
|
||||
readonly property int notificationCount: NotificationService.notifications.length
|
||||
@@ -551,6 +546,163 @@ Item {
|
||||
componentMapRevision++
|
||||
}
|
||||
|
||||
readonly property var sortedToplevels: {
|
||||
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, barWindow.screenName);
|
||||
}
|
||||
|
||||
function getRealWorkspaces() {
|
||||
if (CompositorService.isNiri) {
|
||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return NiriService.getCurrentOutputWorkspaceNumbers()
|
||||
}
|
||||
const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName).map(ws => ws.idx + 1)
|
||||
return workspaces.length > 0 ? workspaces : [1, 2]
|
||||
} else if (CompositorService.isHyprland) {
|
||||
const workspaces = Hyprland.workspaces?.values || []
|
||||
|
||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
const sorted = workspaces.slice().sort((a, b) => a.id - b.id)
|
||||
const filtered = sorted.filter(ws => ws.id > -1)
|
||||
return filtered.length > 0 ? filtered : [{"id": 1, "name": "1"}]
|
||||
}
|
||||
|
||||
const monitorWorkspaces = workspaces.filter(ws => {
|
||||
return ws.lastIpcObject && ws.lastIpcObject.monitor === barWindow.screenName && ws.id > -1
|
||||
})
|
||||
|
||||
if (monitorWorkspaces.length === 0) {
|
||||
return [{"id": 1, "name": "1"}]
|
||||
}
|
||||
|
||||
return monitorWorkspaces.sort((a, b) => a.id - b.id)
|
||||
} else if (CompositorService.isDwl) {
|
||||
if (!DwlService.dwlAvailable) {
|
||||
return [0]
|
||||
}
|
||||
if (SettingsData.dwlShowAllTags) {
|
||||
return Array.from({length: DwlService.tagCount}, (_, i) => i)
|
||||
}
|
||||
return DwlService.getVisibleTags(barWindow.screenName)
|
||||
} else if (CompositorService.isSway) {
|
||||
const workspaces = I3.workspaces?.values || []
|
||||
if (workspaces.length === 0) return [{"num": 1}]
|
||||
|
||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return workspaces.slice().sort((a, b) => a.num - b.num)
|
||||
}
|
||||
|
||||
const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === barWindow.screenName)
|
||||
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [{"num": 1}]
|
||||
}
|
||||
return [1]
|
||||
}
|
||||
|
||||
function getCurrentWorkspace() {
|
||||
if (CompositorService.isNiri) {
|
||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return NiriService.getCurrentWorkspaceNumber()
|
||||
}
|
||||
const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active)
|
||||
return activeWs ? activeWs.idx + 1 : 1
|
||||
} else if (CompositorService.isHyprland) {
|
||||
const monitors = Hyprland.monitors?.values || []
|
||||
const currentMonitor = monitors.find(monitor => monitor.name === barWindow.screenName)
|
||||
return currentMonitor?.activeWorkspace?.id ?? 1
|
||||
} else if (CompositorService.isDwl) {
|
||||
if (!DwlService.dwlAvailable) return 0
|
||||
const outputState = DwlService.getOutputState(barWindow.screenName)
|
||||
if (!outputState || !outputState.tags) return 0
|
||||
const activeTags = DwlService.getActiveTags(barWindow.screenName)
|
||||
return activeTags.length > 0 ? activeTags[0] : 0
|
||||
} else if (CompositorService.isSway) {
|
||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
|
||||
return focusedWs ? focusedWs.num : 1
|
||||
}
|
||||
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === barWindow.screenName && ws.focused === true)
|
||||
return focusedWs ? focusedWs.num : 1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
function switchWorkspace(direction) {
|
||||
const realWorkspaces = getRealWorkspaces()
|
||||
if (realWorkspaces.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
if (CompositorService.isNiri) {
|
||||
const currentWs = getCurrentWorkspace()
|
||||
const currentIndex = realWorkspaces.findIndex(ws => ws === currentWs)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex !== validIndex) {
|
||||
NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1)
|
||||
}
|
||||
} else if (CompositorService.isHyprland) {
|
||||
const currentWs = getCurrentWorkspace()
|
||||
const currentIndex = realWorkspaces.findIndex(ws => ws.id === currentWs)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex !== validIndex) {
|
||||
Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`)
|
||||
}
|
||||
} else if (CompositorService.isDwl) {
|
||||
const currentTag = getCurrentWorkspace()
|
||||
const currentIndex = realWorkspaces.findIndex(tag => tag === currentTag)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex !== validIndex) {
|
||||
DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex])
|
||||
}
|
||||
} else if (CompositorService.isSway) {
|
||||
const currentWs = getCurrentWorkspace()
|
||||
const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex !== validIndex) {
|
||||
try { I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`) } catch(_){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function switchApp(deltaY) {
|
||||
const windows = sortedToplevels;
|
||||
if (windows.length < 2) {
|
||||
return;
|
||||
}
|
||||
let currentIndex = -1;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = currentIndex + 1;
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1;
|
||||
} else {
|
||||
nextIndex = currentIndex - 1;
|
||||
}
|
||||
}
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
}
|
||||
|
||||
readonly property int availableWidth: width
|
||||
readonly property int launcherButtonWidth: 40
|
||||
readonly property int workspaceSwitcherWidth: 120
|
||||
@@ -683,6 +835,60 @@ Item {
|
||||
id: stackContainer
|
||||
anchors.fill: parent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
z: -1
|
||||
|
||||
property real scrollAccumulator: 0
|
||||
property real touchpadThreshold: 500
|
||||
property bool actionInProgress: false
|
||||
|
||||
Timer {
|
||||
id: cooldownTimer
|
||||
interval: 100
|
||||
onTriggered: parent.actionInProgress = false
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
if (actionInProgress) {
|
||||
wheel.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
const deltaY = wheel.angleDelta.y
|
||||
const deltaX = wheel.angleDelta.x
|
||||
|
||||
if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
topBarContent.switchApp(deltaX)
|
||||
wheel.accepted = false
|
||||
return
|
||||
}
|
||||
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
|
||||
const direction = deltaY < 0 ? 1 : -1
|
||||
|
||||
if (isMouseWheel) {
|
||||
topBarContent.switchWorkspace(direction)
|
||||
actionInProgress = true
|
||||
cooldownTimer.restart()
|
||||
} else {
|
||||
scrollAccumulator += deltaY
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
const touchDirection = scrollAccumulator < 0 ? 1 : -1
|
||||
topBarContent.switchWorkspace(touchDirection)
|
||||
scrollAccumulator = 0
|
||||
actionInProgress = true
|
||||
cooldownTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
wheel.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: horizontalStack
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -12,7 +12,7 @@ BasePill {
|
||||
id: root
|
||||
|
||||
property bool compactMode: SettingsData.keyboardLayoutNameCompactMode
|
||||
property string currentLayout: ""
|
||||
property string currentLayout: CompositorService.isNiri ? NiriService.getCurrentKeyboardLayoutName() : ""
|
||||
property string hyprlandKeyboard: ""
|
||||
|
||||
content: Component {
|
||||
@@ -83,24 +83,14 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: updateTimer
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
Component.onCompleted: {
|
||||
if (CompositorService.isHyprland) {
|
||||
updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
updateLayout()
|
||||
}
|
||||
|
||||
function updateLayout() {
|
||||
if (CompositorService.isNiri) {
|
||||
root.currentLayout = NiriService.getCurrentKeyboardLayoutName()
|
||||
} else if (CompositorService.isHyprland) {
|
||||
if (CompositorService.isHyprland) {
|
||||
Proc.runCommand(null, ["hyprctl", "-j", "devices"], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
root.currentLayout = "Unknown"
|
||||
|
||||
@@ -37,7 +37,7 @@ BasePill {
|
||||
}
|
||||
|
||||
IconImage {
|
||||
visible: SettingsData.launcherLogoMode === "compositor"
|
||||
visible: SettingsData.launcherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway)
|
||||
anchors.centerIn: parent
|
||||
width: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset)
|
||||
height: Theme.barIconSize(root.barThickness, SettingsData.launcherLogoSizeOffset)
|
||||
@@ -48,6 +48,10 @@ BasePill {
|
||||
return "file://" + Theme.shellDir + "/assets/niri.svg"
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return "file://" + Theme.shellDir + "/assets/hyprland.svg"
|
||||
} else if (CompositorService.isDwl) {
|
||||
return "file://" + Theme.shellDir + "/assets/mango.png"
|
||||
} else if (CompositorService.isSway) {
|
||||
return "file://" + Theme.shellDir + "/assets/sway.svg"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ Item {
|
||||
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
|
||||
|
||||
IconImage {
|
||||
id: iconImg
|
||||
anchors.centerIn: parent
|
||||
width: Theme.barIconSize(root.barThickness)
|
||||
height: Theme.barIconSize(root.barThickness)
|
||||
@@ -123,6 +124,21 @@ Item {
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
mipmap: true
|
||||
visible: status === Image.Ready
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: !iconImg.visible
|
||||
text: {
|
||||
const itemId = trayItem?.id || ""
|
||||
if (!itemId) {
|
||||
return "?"
|
||||
}
|
||||
return itemId.charAt(0).toUpperCase()
|
||||
}
|
||||
font.pixelSize: 10
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +219,7 @@ Item {
|
||||
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
|
||||
|
||||
IconImage {
|
||||
id: iconImg
|
||||
anchors.centerIn: parent
|
||||
width: Theme.barIconSize(root.barThickness)
|
||||
height: Theme.barIconSize(root.barThickness)
|
||||
@@ -210,6 +227,21 @@ Item {
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
mipmap: true
|
||||
visible: status === Image.Ready
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: !iconImg.visible
|
||||
text: {
|
||||
const itemId = trayItem?.id || ""
|
||||
if (!itemId) {
|
||||
return "?"
|
||||
}
|
||||
return itemId.charAt(0).toUpperCase()
|
||||
}
|
||||
font.pixelSize: 10
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.I3
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -28,14 +29,26 @@ Item {
|
||||
_desktopEntriesUpdateTrigger++
|
||||
}
|
||||
}
|
||||
|
||||
property int currentWorkspace: {
|
||||
if (CompositorService.isNiri) {
|
||||
return getNiriActiveWorkspace()
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return getHyprlandActiveWorkspace()
|
||||
} else if (CompositorService.isDwl) {
|
||||
const activeTags = getDwlActiveTags()
|
||||
return activeTags.length > 0 ? activeTags[0] : 0
|
||||
} else if (CompositorService.isSway) {
|
||||
return getSwayActiveWorkspace()
|
||||
}
|
||||
return 1
|
||||
}
|
||||
property var dwlActiveTags: {
|
||||
if (CompositorService.isDwl) {
|
||||
return getDwlActiveTags()
|
||||
}
|
||||
return []
|
||||
}
|
||||
property var workspaceList: {
|
||||
if (CompositorService.isNiri) {
|
||||
const baseList = getNiriWorkspaces()
|
||||
@@ -43,13 +56,42 @@ Item {
|
||||
}
|
||||
if (CompositorService.isHyprland) {
|
||||
const baseList = getHyprlandWorkspaces()
|
||||
// Filter out special workspaces
|
||||
const filteredList = baseList.filter(ws => ws.id > -1)
|
||||
return SettingsData.showWorkspacePadding ? padWorkspaces(filteredList) : filteredList
|
||||
}
|
||||
if (CompositorService.isDwl) {
|
||||
const baseList = getDwlTags()
|
||||
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
|
||||
}
|
||||
if (CompositorService.isSway) {
|
||||
const baseList = getSwayWorkspaces()
|
||||
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
|
||||
}
|
||||
return [1]
|
||||
}
|
||||
|
||||
function getSwayWorkspaces() {
|
||||
const workspaces = I3.workspaces?.values || []
|
||||
if (workspaces.length === 0) return [{"num": 1}]
|
||||
|
||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return workspaces.slice().sort((a, b) => a.num - b.num)
|
||||
}
|
||||
|
||||
const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === root.screenName)
|
||||
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [{"num": 1}]
|
||||
}
|
||||
|
||||
function getSwayActiveWorkspace() {
|
||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
|
||||
return focusedWs ? focusedWs.num : 1
|
||||
}
|
||||
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === root.screenName && ws.focused === true)
|
||||
return focusedWs ? focusedWs.num : 1
|
||||
}
|
||||
|
||||
function getWorkspaceIcons(ws) {
|
||||
_desktopEntriesUpdateTrigger
|
||||
if (!SettingsData.showWorkspaceApps || !ws) {
|
||||
@@ -69,15 +111,35 @@ Item {
|
||||
targetWorkspaceId = workspace.id
|
||||
} else if (CompositorService.isHyprland) {
|
||||
targetWorkspaceId = ws.id !== undefined ? ws.id : ws
|
||||
} else if (CompositorService.isDwl) {
|
||||
if (typeof ws !== "object" || ws.tag === undefined) {
|
||||
return []
|
||||
}
|
||||
targetWorkspaceId = ws.tag
|
||||
} else if (CompositorService.isSway) {
|
||||
targetWorkspaceId = ws.num !== undefined ? ws.num : ws
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
|
||||
const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels
|
||||
|
||||
|
||||
const byApp = {}
|
||||
const isActiveWs = CompositorService.isNiri ? NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active) : targetWorkspaceId === root.currentWorkspace
|
||||
let isActiveWs = false
|
||||
if (CompositorService.isNiri) {
|
||||
isActiveWs = NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active)
|
||||
} else if (CompositorService.isSway) {
|
||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
|
||||
isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false
|
||||
} else if (CompositorService.isDwl) {
|
||||
const output = DwlService.getOutputState(root.screenName)
|
||||
if (output && output.tags) {
|
||||
const tag = output.tags.find(t => t.tag === targetWorkspaceId)
|
||||
isActiveWs = tag ? (tag.state === 1) : false
|
||||
}
|
||||
} else {
|
||||
isActiveWs = targetWorkspaceId === root.currentWorkspace
|
||||
}
|
||||
|
||||
wins.forEach((w, i) => {
|
||||
if (!w) {
|
||||
@@ -87,8 +149,9 @@ Item {
|
||||
let winWs = null
|
||||
if (CompositorService.isNiri) {
|
||||
winWs = w.workspace_id
|
||||
} else if (CompositorService.isSway) {
|
||||
winWs = w.workspace?.num
|
||||
} else {
|
||||
// For Hyprland, we need to find the corresponding Hyprland toplevel to get workspace
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || [])
|
||||
const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w)
|
||||
winWs = hyprToplevel?.workspace?.id
|
||||
@@ -110,14 +173,14 @@ Item {
|
||||
"type": "icon",
|
||||
"icon": icon,
|
||||
"isSteamApp": isSteamApp,
|
||||
"active": !!(w.activated || (CompositorService.isNiri && w.is_focused)),
|
||||
"active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)),
|
||||
"count": 1,
|
||||
"windowId": w.address || w.id,
|
||||
"fallbackText": w.appId || w.class || w.title || ""
|
||||
}
|
||||
} else {
|
||||
byApp[key].count++
|
||||
if (w.activated || (CompositorService.isNiri && w.is_focused)) {
|
||||
if ((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)) {
|
||||
byApp[key].active = true
|
||||
}
|
||||
}
|
||||
@@ -128,10 +191,16 @@ Item {
|
||||
|
||||
function padWorkspaces(list) {
|
||||
const padded = list.slice()
|
||||
const placeholder = CompositorService.isHyprland ? {
|
||||
"id": -1,
|
||||
"name": ""
|
||||
} : -1
|
||||
let placeholder
|
||||
if (CompositorService.isHyprland) {
|
||||
placeholder = {"id": -1, "name": ""}
|
||||
} else if (CompositorService.isDwl) {
|
||||
placeholder = {"tag": -1}
|
||||
} else if (CompositorService.isSway) {
|
||||
placeholder = {"num": -1}
|
||||
} else {
|
||||
placeholder = -1
|
||||
}
|
||||
while (padded.length < 3) {
|
||||
padded.push(placeholder)
|
||||
}
|
||||
@@ -199,7 +268,6 @@ Item {
|
||||
return Hyprland.focusedWorkspace ? Hyprland.focusedWorkspace.id : 1
|
||||
}
|
||||
|
||||
// Find the monitor object for this screen
|
||||
const monitors = Hyprland.monitors?.values || []
|
||||
const currentMonitor = monitors.find(monitor => monitor.name === root.screenName)
|
||||
|
||||
@@ -207,10 +275,44 @@ Item {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Use the monitor's active workspace ID (like original config)
|
||||
return currentMonitor.activeWorkspace?.id ?? 1
|
||||
}
|
||||
|
||||
function getDwlTags() {
|
||||
if (!DwlService.dwlAvailable) {
|
||||
return [{"tag": 0}, {"tag": 1}]
|
||||
}
|
||||
|
||||
const output = DwlService.getOutputState(root.screenName)
|
||||
if (!output || !output.tags || output.tags.length === 0) {
|
||||
return [{"tag": 0}]
|
||||
}
|
||||
|
||||
if (SettingsData.dwlShowAllTags) {
|
||||
return output.tags.map(tag => ({"tag": tag.tag, "state": tag.state, "clients": tag.clients, "focused": tag.focused}))
|
||||
}
|
||||
|
||||
const visibleTagIndices = DwlService.getVisibleTags(root.screenName)
|
||||
return visibleTagIndices.map(tagIndex => {
|
||||
const tagData = output.tags.find(t => t.tag === tagIndex)
|
||||
return {
|
||||
"tag": tagIndex,
|
||||
"state": tagData?.state ?? 0,
|
||||
"clients": tagData?.clients ?? 0,
|
||||
"focused": tagData?.focused ?? false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getDwlActiveTags() {
|
||||
if (!DwlService.dwlAvailable) {
|
||||
return [0]
|
||||
}
|
||||
|
||||
const activeTags = DwlService.getActiveTags(root.screenName)
|
||||
return activeTags.length > 0 ? activeTags : [0]
|
||||
}
|
||||
|
||||
readonly property real padding: Math.max(Theme.spacingXS, Theme.spacingS * (widgetHeight / 30))
|
||||
readonly property real visualWidth: isVertical ? widgetHeight : (workspaceRow.implicitWidth + padding * 2)
|
||||
readonly property real visualHeight: isVertical ? (workspaceRow.implicitHeight + padding * 2) : widgetHeight
|
||||
@@ -219,6 +321,10 @@ Item {
|
||||
return root.workspaceList.filter(ws => {
|
||||
if (CompositorService.isHyprland) {
|
||||
return ws && ws.id !== -1
|
||||
} else if (CompositorService.isDwl) {
|
||||
return ws && ws.tag !== -1
|
||||
} else if (CompositorService.isSway) {
|
||||
return ws && ws.num !== -1
|
||||
}
|
||||
return ws !== -1
|
||||
})
|
||||
@@ -255,12 +361,42 @@ Item {
|
||||
}
|
||||
|
||||
Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`)
|
||||
} else if (CompositorService.isDwl) {
|
||||
const realWorkspaces = getRealWorkspaces()
|
||||
if (realWorkspaces.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = realWorkspaces.findIndex(ws => ws.tag === root.currentWorkspace)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex === validIndex) {
|
||||
return
|
||||
}
|
||||
|
||||
DwlService.switchToTag(root.screenName, realWorkspaces[nextIndex].tag)
|
||||
} else if (CompositorService.isSway) {
|
||||
const realWorkspaces = getRealWorkspaces()
|
||||
if (realWorkspaces.length < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = realWorkspaces.findIndex(ws => ws.num === root.currentWorkspace)
|
||||
const validIndex = currentIndex === -1 ? 0 : currentIndex
|
||||
const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0)
|
||||
|
||||
if (nextIndex === validIndex) {
|
||||
return
|
||||
}
|
||||
|
||||
try { I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`) } catch(_){}
|
||||
}
|
||||
}
|
||||
|
||||
width: isVertical ? barThickness : visualWidth
|
||||
height: isVertical ? visualHeight : barThickness
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway
|
||||
|
||||
Rectangle {
|
||||
id: visualBackground
|
||||
@@ -280,104 +416,11 @@ Item {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
|
||||
property real scrollAccumulator: 0
|
||||
property real touchpadThreshold: 500
|
||||
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton && CompositorService.isHyprland && root.hyprlandOverviewLoader?.item) {
|
||||
root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen
|
||||
}
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
const deltaY = wheel.angleDelta.y
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
|
||||
const direction = deltaY < 0 ? 1 : -1
|
||||
|
||||
if (isMouseWheel) {
|
||||
if (!SettingsData.workspaceScrolling || !CompositorService.isNiri) {
|
||||
switchWorkspace(direction)
|
||||
}
|
||||
else {
|
||||
const windows = root.sortedToplevels;
|
||||
if (windows.length < 2) {
|
||||
return;
|
||||
}
|
||||
let currentIndex = -1;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = currentIndex +1;
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length -1;
|
||||
} else {
|
||||
nextIndex = currentIndex - 1
|
||||
}
|
||||
}
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
scrollAccumulator += deltaY
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
const touchDirection = scrollAccumulator < 0 ? 1 : -1
|
||||
if (!SettingsData.workspaceScrolling || !CompositorService.isNiri) {
|
||||
switchWorkspace(touchDirection)
|
||||
}
|
||||
else {
|
||||
const windows = root.sortedToplevels;
|
||||
if (windows.length < 2) {
|
||||
return;
|
||||
}
|
||||
let currentIndex = -1;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = currentIndex +1;
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length -1;
|
||||
} else {
|
||||
nextIndex = currentIndex - 1
|
||||
}
|
||||
}
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
}
|
||||
|
||||
scrollAccumulator = 0
|
||||
}
|
||||
}
|
||||
|
||||
wheel.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
@@ -396,12 +439,20 @@ Item {
|
||||
property bool isActive: {
|
||||
if (CompositorService.isHyprland) {
|
||||
return modelData && modelData.id === root.currentWorkspace
|
||||
} else if (CompositorService.isDwl) {
|
||||
return modelData && root.dwlActiveTags.includes(modelData.tag)
|
||||
} else if (CompositorService.isSway) {
|
||||
return modelData && modelData.num === root.currentWorkspace
|
||||
}
|
||||
return modelData === root.currentWorkspace
|
||||
}
|
||||
property bool isPlaceholder: {
|
||||
if (CompositorService.isHyprland) {
|
||||
return modelData && modelData.id === -1
|
||||
} else if (CompositorService.isDwl) {
|
||||
return modelData && modelData.tag === -1
|
||||
} else if (CompositorService.isSway) {
|
||||
return modelData && modelData.num === -1
|
||||
}
|
||||
return modelData === -1
|
||||
}
|
||||
@@ -412,8 +463,11 @@ Item {
|
||||
property bool isUrgent: {
|
||||
if (CompositorService.isHyprland) {
|
||||
return modelData?.urgent ?? false
|
||||
}
|
||||
if (CompositorService.isNiri) {
|
||||
} else if (CompositorService.isNiri) {
|
||||
return loadedIsUrgent
|
||||
} else if (CompositorService.isDwl) {
|
||||
return modelData?.state === 2
|
||||
} else if (CompositorService.isSway) {
|
||||
return loadedIsUrgent
|
||||
}
|
||||
return false
|
||||
@@ -456,15 +510,29 @@ Item {
|
||||
hoverEnabled: !isPlaceholder
|
||||
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||
enabled: !isPlaceholder
|
||||
onClicked: {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (isPlaceholder) {
|
||||
return
|
||||
}
|
||||
|
||||
const isRightClick = mouse.button === Qt.RightButton
|
||||
|
||||
if (CompositorService.isNiri) {
|
||||
NiriService.switchToWorkspace(modelData - 1)
|
||||
} else if (CompositorService.isHyprland && modelData?.id) {
|
||||
Hyprland.dispatch(`workspace ${modelData.id}`)
|
||||
} else if (CompositorService.isDwl && modelData?.tag !== undefined) {
|
||||
console.log("DWL click - tag:", modelData.tag, "rightClick:", isRightClick)
|
||||
if (isRightClick) {
|
||||
console.log("Calling toggleTag")
|
||||
DwlService.toggleTag(root.screenName, modelData.tag)
|
||||
} else {
|
||||
console.log("Calling switchToTag")
|
||||
DwlService.switchToTag(root.screenName, modelData.tag)
|
||||
}
|
||||
} else if (CompositorService.isSway && modelData?.num) {
|
||||
try { I3.dispatch(`workspace number ${modelData.num}`) } catch(_){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,9 +555,13 @@ Item {
|
||||
wsData = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.screenName) || null;
|
||||
} else if (CompositorService.isHyprland) {
|
||||
wsData = modelData;
|
||||
} else if (CompositorService.isDwl) {
|
||||
wsData = modelData;
|
||||
} else if (CompositorService.isSway) {
|
||||
wsData = modelData;
|
||||
}
|
||||
delegateRoot.loadedWorkspaceData = wsData;
|
||||
delegateRoot.loadedIsUrgent = wsData?.is_urgent ?? false;
|
||||
delegateRoot.loadedIsUrgent = wsData?.urgent ?? false;
|
||||
|
||||
var icData = null;
|
||||
if (wsData?.name) {
|
||||
@@ -499,7 +571,11 @@ Item {
|
||||
delegateRoot.loadedHasIcon = icData !== null;
|
||||
|
||||
if (SettingsData.showWorkspaceApps) {
|
||||
delegateRoot.loadedIcons = root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData));
|
||||
if (CompositorService.isDwl || CompositorService.isSway) {
|
||||
delegateRoot.loadedIcons = root.getWorkspaceIcons(modelData);
|
||||
} else {
|
||||
delegateRoot.loadedIcons = root.getWorkspaceIcons(CompositorService.isHyprland ? modelData : (modelData === -1 ? null : modelData));
|
||||
}
|
||||
} else {
|
||||
delegateRoot.loadedIcons = [];
|
||||
}
|
||||
@@ -521,8 +597,14 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.primary : isUrgent ? Theme.error : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha
|
||||
|
||||
border.width: isUrgent && !isActive ? 2 : 0
|
||||
border.color: isUrgent && !isActive ? Theme.error : Theme.withAlpha(Theme.error, 0)
|
||||
border.width: {
|
||||
if (isUrgent && !isActive) return 2
|
||||
return 0
|
||||
}
|
||||
border.color: {
|
||||
if (isUrgent && !isActive) return Theme.error
|
||||
return Theme.withAlpha(Theme.error, 0)
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
enabled: (!SettingsData.showWorkspaceApps || SettingsData.maxWorkspaceIcons <= 3)
|
||||
@@ -554,6 +636,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: appIconsLoader
|
||||
anchors.fill: parent
|
||||
@@ -744,11 +833,29 @@ Item {
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
const isPlaceholder = CompositorService.isHyprland ? (modelData?.id === -1) : (modelData === -1)
|
||||
let isPlaceholder
|
||||
if (CompositorService.isHyprland) {
|
||||
isPlaceholder = modelData?.id === -1
|
||||
} else if (CompositorService.isDwl) {
|
||||
isPlaceholder = modelData?.tag === -1
|
||||
} else if (CompositorService.isSway) {
|
||||
isPlaceholder = modelData?.num === -1
|
||||
} else {
|
||||
isPlaceholder = modelData === -1
|
||||
}
|
||||
|
||||
if (isPlaceholder) {
|
||||
return index + 1
|
||||
}
|
||||
return CompositorService.isHyprland ? (modelData?.id || "") : (modelData - 1);
|
||||
|
||||
if (CompositorService.isHyprland) {
|
||||
return modelData?.id || ""
|
||||
} else if (CompositorService.isDwl) {
|
||||
return (modelData?.tag !== undefined) ? (modelData.tag + 1) : ""
|
||||
} else if (CompositorService.isSway) {
|
||||
return modelData?.num || ""
|
||||
}
|
||||
return modelData - 1
|
||||
}
|
||||
color: (isActive || isUrgent) ? Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95) : isPlaceholder ? Theme.surfaceTextAlpha : Theme.surfaceTextMedium
|
||||
font.pixelSize: Theme.barTextSize(barThickness)
|
||||
@@ -776,6 +883,16 @@ Item {
|
||||
function onShowWorkspaceAppsChanged() { delegateRoot.updateAllData() }
|
||||
function onWorkspaceNameIconsChanged() { delegateRoot.updateAllData() }
|
||||
}
|
||||
Connections {
|
||||
target: DwlService
|
||||
enabled: CompositorService.isDwl
|
||||
function onStateChanged() { delegateRoot.updateAllData() }
|
||||
}
|
||||
Connections {
|
||||
target: I3.workspaces
|
||||
enabled: CompositorService.isSway
|
||||
function onValuesChanged() { delegateRoot.updateAllData() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ Scope {
|
||||
id: root
|
||||
|
||||
property bool lockSecured: false
|
||||
property bool unlockInProgress: false
|
||||
|
||||
readonly property alias passwd: passwd
|
||||
readonly property alias fprint: fprint
|
||||
@@ -50,7 +51,11 @@ Scope {
|
||||
|
||||
onCompleted: res => {
|
||||
if (res === PamResult.Success) {
|
||||
root.unlockRequested();
|
||||
if (!root.unlockInProgress) {
|
||||
root.unlockInProgress = true;
|
||||
fprint.abort();
|
||||
root.unlockRequested();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,7 +97,11 @@ Scope {
|
||||
return;
|
||||
|
||||
if (res === PamResult.Success) {
|
||||
root.unlockRequested();
|
||||
if (!root.unlockInProgress) {
|
||||
root.unlockInProgress = true;
|
||||
passwd.abort();
|
||||
root.unlockRequested();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,8 +171,11 @@ Scope {
|
||||
root.state = "";
|
||||
root.fprintState = "";
|
||||
root.lockMessage = "";
|
||||
root.unlockInProgress = false;
|
||||
} else {
|
||||
fprint.abort();
|
||||
passwd.abort();
|
||||
root.unlockInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,59 @@ Item {
|
||||
id: aboutTab
|
||||
|
||||
property bool isHyprland: CompositorService.isHyprland
|
||||
property bool isNiri: CompositorService.isNiri
|
||||
property bool isSway: CompositorService.isSway
|
||||
property bool isDwl: CompositorService.isDwl
|
||||
|
||||
property string compositorName: {
|
||||
if (isHyprland) return "hyprland"
|
||||
if (isSway) return "sway"
|
||||
if (isDwl) return "mangowc"
|
||||
return "niri"
|
||||
}
|
||||
|
||||
property string compositorLogo: {
|
||||
if (isHyprland) return "/assets/hyprland.svg"
|
||||
if (isSway) return "/assets/sway.svg"
|
||||
if (isDwl) return "/assets/mango.png"
|
||||
return "/assets/niri.svg"
|
||||
}
|
||||
|
||||
property string compositorUrl: {
|
||||
if (isHyprland) return "https://hypr.land"
|
||||
if (isSway) return "https://swaywm.org"
|
||||
if (isDwl) return "https://github.com/DreamMaoMao/mangowc"
|
||||
return "https://github.com/YaLTeR/niri"
|
||||
}
|
||||
|
||||
property string compositorTooltip: {
|
||||
if (isHyprland) return "Hyprland Website"
|
||||
if (isSway) return "Sway Website"
|
||||
if (isDwl) return "mangowc GitHub"
|
||||
return "niri GitHub"
|
||||
}
|
||||
|
||||
property string dmsDiscordUrl: "https://discord.gg/vT8Sfjy7sx"
|
||||
property string dmsDiscordTooltip: "niri/dms Discord"
|
||||
|
||||
property string compositorDiscordUrl: {
|
||||
if (isHyprland) return "https://discord.com/invite/hQ9XvMUjjr"
|
||||
if (isDwl) return "https://discord.gg/CPjbDxesh5"
|
||||
return ""
|
||||
}
|
||||
|
||||
property string compositorDiscordTooltip: {
|
||||
if (isHyprland) return "Hyprland Discord Server"
|
||||
if (isDwl) return "mangowc Discord Server"
|
||||
return ""
|
||||
}
|
||||
|
||||
property string redditUrl: "https://reddit.com/r/niri"
|
||||
property string redditTooltip: "r/niri Subreddit"
|
||||
|
||||
property bool showMatrix: isNiri && !isHyprland && !isSway && !isDwl
|
||||
property bool showCompositorDiscord: isHyprland || isDwl
|
||||
property bool showReddit: isNiri && !isHyprland && !isSway && !isDwl
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
@@ -69,14 +122,19 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: 24
|
||||
width: {
|
||||
if (isHyprland) {
|
||||
return compositorButton.width + discordButton.width + Theme.spacingM + redditButton.width + Theme.spacingM
|
||||
} else {
|
||||
return compositorButton.width + matrixButton.width + 4 + discordButton.width + Theme.spacingM + redditButton.width + Theme.spacingM
|
||||
let baseWidth = compositorButton.width + dmsDiscordButton.width + Theme.spacingM
|
||||
if (showMatrix) {
|
||||
baseWidth += matrixButton.width + 4
|
||||
}
|
||||
if (showCompositorDiscord) {
|
||||
baseWidth += compositorDiscordButton.width + Theme.spacingM
|
||||
}
|
||||
if (showReddit) {
|
||||
baseWidth += redditButton.width + Theme.spacingM
|
||||
}
|
||||
return baseWidth
|
||||
}
|
||||
|
||||
// Compositor logo (Niri or Hyprland)
|
||||
Item {
|
||||
id: compositorButton
|
||||
width: 24
|
||||
@@ -86,14 +144,14 @@ Item {
|
||||
x: 0
|
||||
|
||||
property bool hovered: false
|
||||
property string tooltipText: isHyprland ? "Hyprland Website" : "niri GitHub"
|
||||
property string tooltipText: compositorTooltip
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + (isHyprland ? "/assets/hyprland.svg" : "/assets/niri.svg")
|
||||
"") + compositorLogo
|
||||
sourceSize: Qt.size(24, 24)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -105,18 +163,16 @@ Item {
|
||||
hoverEnabled: true
|
||||
onEntered: parent.hovered = true
|
||||
onExited: parent.hovered = false
|
||||
onClicked: Qt.openUrlExternally(
|
||||
isHyprland ? "https://hypr.land" : "https://github.com/YaLTeR/niri")
|
||||
onClicked: Qt.openUrlExternally(compositorUrl)
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix button (only for Niri)
|
||||
Item {
|
||||
id: matrixButton
|
||||
width: 30
|
||||
height: 24
|
||||
x: compositorButton.x + compositorButton.width + 4
|
||||
visible: !isHyprland
|
||||
visible: showMatrix
|
||||
|
||||
property bool hovered: false
|
||||
property string tooltipText: "niri Matrix Chat"
|
||||
@@ -149,16 +205,15 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Discord button
|
||||
Item {
|
||||
id: discordButton
|
||||
id: dmsDiscordButton
|
||||
width: 20
|
||||
height: 20
|
||||
x: isHyprland ? compositorButton.x + compositorButton.width + Theme.spacingM : matrixButton.x + matrixButton.width + Theme.spacingM
|
||||
x: showMatrix ? matrixButton.x + matrixButton.width + Theme.spacingM : compositorButton.x + compositorButton.width + Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
property bool hovered: false
|
||||
property string tooltipText: isHyprland ? "Hyprland Discord Server" : "niri Discord Server"
|
||||
property string tooltipText: dmsDiscordTooltip
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
@@ -177,21 +232,52 @@ Item {
|
||||
hoverEnabled: true
|
||||
onEntered: parent.hovered = true
|
||||
onExited: parent.hovered = false
|
||||
onClicked: Qt.openUrlExternally(
|
||||
isHyprland ? "https://discord.com/invite/hQ9XvMUjjr" : "https://discord.gg/vT8Sfjy7sx")
|
||||
onClicked: Qt.openUrlExternally(dmsDiscordUrl)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: compositorDiscordButton
|
||||
width: 20
|
||||
height: 20
|
||||
x: dmsDiscordButton.x + dmsDiscordButton.width + Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: showCompositorDiscord
|
||||
|
||||
property bool hovered: false
|
||||
property string tooltipText: compositorDiscordTooltip
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + "/assets/discord.svg"
|
||||
sourceSize: Qt.size(20, 20)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onEntered: parent.hovered = true
|
||||
onExited: parent.hovered = false
|
||||
onClicked: Qt.openUrlExternally(compositorDiscordUrl)
|
||||
}
|
||||
}
|
||||
|
||||
// Reddit button
|
||||
Item {
|
||||
id: redditButton
|
||||
width: 20
|
||||
height: 20
|
||||
x: discordButton.x + discordButton.width + Theme.spacingM
|
||||
x: showCompositorDiscord ? compositorDiscordButton.x + compositorDiscordButton.width + Theme.spacingM : dmsDiscordButton.x + dmsDiscordButton.width + Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: showReddit
|
||||
|
||||
property bool hovered: false
|
||||
property string tooltipText: isHyprland ? "r/hyprland Subreddit" : "r/niri Subreddit"
|
||||
property string tooltipText: redditTooltip
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
@@ -210,8 +296,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
onEntered: parent.hovered = true
|
||||
onExited: parent.hovered = false
|
||||
onClicked: Qt.openUrlExternally(
|
||||
isHyprland ? "https://reddit.com/r/hyprland" : "https://reddit.com/r/niri")
|
||||
onClicked: Qt.openUrlExternally(redditUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,8 +591,9 @@ Item {
|
||||
property var hoveredButton: {
|
||||
if (compositorButton.hovered) return compositorButton
|
||||
if (matrixButton.visible && matrixButton.hovered) return matrixButton
|
||||
if (discordButton.hovered) return discordButton
|
||||
if (redditButton.hovered) return redditButton
|
||||
if (dmsDiscordButton.hovered) return dmsDiscordButton
|
||||
if (compositorDiscordButton.visible && compositorDiscordButton.hovered) return compositorDiscordButton
|
||||
if (redditButton.visible && redditButton.hovered) return redditButton
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -697,7 +697,7 @@ Item {
|
||||
text: I18n.tr("Show on Last Display")
|
||||
description: I18n.tr("Always show when there's only one connected display")
|
||||
checked: displaysTab.getShowOnLastDisplay(parent.componentId)
|
||||
visible: !displaysTab.getScreenPreferences(parent.componentId).includes("all") && ["dankBar", "dock", "notifications", "osd", "toast"].includes(parent.componentId)
|
||||
visible: !displaysTab.getScreenPreferences(parent.componentId).includes("all") && ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(parent.componentId)
|
||||
onToggled: (checked) => {
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked);
|
||||
}
|
||||
|
||||
@@ -87,9 +87,16 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: {
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo")]
|
||||
if (CompositorService.isNiri || CompositorService.isHyprland) {
|
||||
const compositorName = CompositorService.isNiri ? "niri" : "Hyprland"
|
||||
modes.push(compositorName)
|
||||
if (CompositorService.isNiri) {
|
||||
modes.push("niri")
|
||||
} else if (CompositorService.isHyprland) {
|
||||
modes.push("Hyprland")
|
||||
} else if (CompositorService.isDwl) {
|
||||
modes.push("mango")
|
||||
} else if (CompositorService.isSway) {
|
||||
modes.push("Sway")
|
||||
} else {
|
||||
modes.push(I18n.tr("Compositor"))
|
||||
}
|
||||
modes.push(I18n.tr("Custom"))
|
||||
return modes
|
||||
@@ -97,12 +104,8 @@ Item {
|
||||
currentIndex: {
|
||||
if (SettingsData.launcherLogoMode === "apps") return 0
|
||||
if (SettingsData.launcherLogoMode === "os") return 1
|
||||
if (SettingsData.launcherLogoMode === "compositor") {
|
||||
return (CompositorService.isNiri || CompositorService.isHyprland) ? 2 : -1
|
||||
}
|
||||
if (SettingsData.launcherLogoMode === "custom") {
|
||||
return (CompositorService.isNiri || CompositorService.isHyprland) ? 3 : 2
|
||||
}
|
||||
if (SettingsData.launcherLogoMode === "compositor") return 2
|
||||
if (SettingsData.launcherLogoMode === "custom") return 3
|
||||
return 0
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
@@ -111,13 +114,9 @@ Item {
|
||||
SettingsData.setLauncherLogoMode("apps")
|
||||
} else if (index === 1) {
|
||||
SettingsData.setLauncherLogoMode("os")
|
||||
} else if (CompositorService.isNiri || CompositorService.isHyprland) {
|
||||
if (index === 2) {
|
||||
SettingsData.setLauncherLogoMode("compositor")
|
||||
} else if (index === 3) {
|
||||
SettingsData.setLauncherLogoMode("custom")
|
||||
}
|
||||
} else if (index === 2) {
|
||||
SettingsData.setLauncherLogoMode("compositor")
|
||||
} else if (index === 3) {
|
||||
SettingsData.setLauncherLogoMode("custom")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,17 +65,6 @@ Item {
|
||||
checked)
|
||||
}
|
||||
}
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Window Scrolling")
|
||||
description: I18n.tr("Scroll through windows, rather than workspaces")
|
||||
checked: SettingsData.workspaceScrolling
|
||||
visible: CompositorService.isNiri
|
||||
onToggled: checked => {
|
||||
return SettingsData.setWorkspaceScrolling(checked)
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Workspace Padding")
|
||||
@@ -149,6 +138,17 @@ Item {
|
||||
return SettingsData.setWorkspacesPerMonitor(checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show All Tags")
|
||||
description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)")
|
||||
checked: SettingsData.dwlShowAllTags
|
||||
visible: CompositorService.isDwl
|
||||
onToggled: checked => {
|
||||
return SettingsData.setDwlShowAllTags(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
README.md
14
README.md
@@ -12,7 +12,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
A modern Wayland desktop shell built with [Quickshell](https://quickshell.org/) and [Go](https://go.dev/). Optimized for the [niri](https://github.com/YaLTeR/niri) and [Hyprland](https://hyprland.org/) compositors.
|
||||
A modern Wayland desktop shell built with [Quickshell](https://quickshell.org/) and [Go](https://go.dev/). Optimized for the [niri](https://github.com/YaLTeR/niri), [Hyprland](https://hyprland.org/), [sway](https://swaywm.org/), and [dwl/mangowc](https://github.com/DreamMaoMao/mangowc) compositors.
|
||||
|
||||
Features notifications, app launcher, wallpaper customization, and fully customizable with [plugins](https://github.com/AvengeMedia/dms-plugin-registry).
|
||||
|
||||
@@ -134,7 +134,7 @@ curl -fsSL https://install.danklinux.com | sh
|
||||
|
||||
### Compositor Setup
|
||||
|
||||
DankMaterialShell particularly aims at supporting the **niri** and **Hyprland** compositors, but it does support more wayland compositors with a diminished feature set (no monitor off, workspace switcher, overview integration, etc.):
|
||||
DankMaterialShell particularly aims at supporting the **niri**, **Hyprland**, **sway**, and **dwl/MangoWC** compositors, but it does support more wayland compositors with a diminished feature set (no monitor off, workspace switcher, overview integration, etc.):
|
||||
|
||||
**Niri**:
|
||||
```bash
|
||||
@@ -164,6 +164,10 @@ sudo dnf copr enable solopasha/hyprland && sudo dnf install hyprland
|
||||
|
||||
For detailed Hyprland installation instructions, see the [Hyprland wiki](https://wiki.hypr.land/Getting-Started/Installation/).
|
||||
|
||||
**sway/dwl (MangoWC)**:
|
||||
|
||||
TODO - not documented.
|
||||
|
||||
### Dank Shell Installation
|
||||
|
||||
*feel free to contribute steps for other distributions*
|
||||
@@ -438,15 +442,9 @@ layer-rule {
|
||||
If using "Blur Layer" option, you may want the blurred layer to appear on overview only, that can be done with some layer rules:
|
||||
|
||||
```kdl
|
||||
layer-rule {
|
||||
match namespace="dms:blurwallpaper"
|
||||
opacity 0.0
|
||||
}
|
||||
|
||||
layer-rule {
|
||||
match namespace="dms:blurwallpaper"
|
||||
place-within-backdrop true
|
||||
opacity 1.0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -12,10 +12,13 @@ Singleton {
|
||||
|
||||
property bool isHyprland: false
|
||||
property bool isNiri: false
|
||||
property bool isDwl: false
|
||||
property bool isSway: false
|
||||
property string compositor: "unknown"
|
||||
|
||||
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
readonly property string niriSocket: Quickshell.env("NIRI_SOCKET")
|
||||
readonly property string swaySocket: Quickshell.env("SWAYSOCK")
|
||||
property bool useNiriSorting: isNiri && NiriService
|
||||
|
||||
property var sortedToplevels: sortedToplevelsCache
|
||||
@@ -26,6 +29,30 @@ Singleton {
|
||||
property bool _hasRefreshedOnce: false
|
||||
|
||||
property var _coordCache: ({})
|
||||
property int _refreshCount: 0
|
||||
property real _refreshWindowStart: 0
|
||||
readonly property int _maxRefreshesPerSecond: 3
|
||||
|
||||
function getScreenScale(screen) {
|
||||
if (!screen) return 1
|
||||
|
||||
if (isNiri && screen) {
|
||||
const niriScale = NiriService.displayScales[screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
|
||||
if (isHyprland && screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
|
||||
if (isDwl && screen) {
|
||||
const dwlScale = DwlService.getOutputScale(screen.name)
|
||||
if (dwlScale !== undefined && dwlScale > 0) return dwlScale
|
||||
}
|
||||
|
||||
return screen?.devicePixelRatio || 1
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
@@ -53,6 +80,19 @@ Singleton {
|
||||
function scheduleRefresh() {
|
||||
if (!isHyprland) return
|
||||
if (_refreshScheduled) return
|
||||
|
||||
const now = Date.now()
|
||||
if (now - _refreshWindowStart > 1000) {
|
||||
_refreshCount = 0
|
||||
_refreshWindowStart = now
|
||||
}
|
||||
|
||||
if (_refreshCount >= _maxRefreshesPerSecond) {
|
||||
console.warn("CompositorService: Refresh rate limit exceeded, skipping refresh")
|
||||
return
|
||||
}
|
||||
|
||||
_refreshCount++
|
||||
_refreshScheduled = true
|
||||
refreshTimer.restart()
|
||||
}
|
||||
@@ -87,6 +127,15 @@ Singleton {
|
||||
Qt.callLater(() => NiriService.generateNiriLayoutConfig())
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DwlService
|
||||
function onStateChanged() {
|
||||
if (isDwl && !isHyprland && !isNiri) {
|
||||
scheduleSort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function computeSortedToplevels() {
|
||||
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values)
|
||||
return []
|
||||
@@ -125,6 +174,18 @@ Singleton {
|
||||
} catch(e) { return fb }
|
||||
}
|
||||
|
||||
let currentAddresses = new Set()
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const addr = items[i]?.address
|
||||
if (addr) currentAddresses.add(addr)
|
||||
}
|
||||
|
||||
for (let cachedAddr in _coordCache) {
|
||||
if (!currentAddresses.has(cachedAddr)) {
|
||||
delete _coordCache[cachedAddr]
|
||||
}
|
||||
}
|
||||
|
||||
let snap = []
|
||||
let missingAnyPosition = false
|
||||
let hasNewWindow = false
|
||||
@@ -331,6 +392,8 @@ Singleton {
|
||||
if (hyprlandSignature && hyprlandSignature.length > 0) {
|
||||
isHyprland = true
|
||||
isNiri = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
compositor = "hyprland"
|
||||
console.info("CompositorService: Detected Hyprland")
|
||||
try {
|
||||
@@ -344,34 +407,103 @@ Singleton {
|
||||
if (exitCode === 0) {
|
||||
isNiri = true
|
||||
isHyprland = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
compositor = "niri"
|
||||
console.info("CompositorService: Detected Niri with socket:", niriSocket)
|
||||
NiriService.generateNiriBinds()
|
||||
NiriService.generateNiriBlurrule()
|
||||
} else {
|
||||
isHyprland = false
|
||||
isNiri = true
|
||||
compositor = "niri"
|
||||
console.warn("CompositorService: Niri socket check failed, defaulting to Niri anyway")
|
||||
}
|
||||
}, 0)
|
||||
return
|
||||
}
|
||||
|
||||
if (swaySocket && swaySocket.length > 0) {
|
||||
Proc.runCommand("swaySocketCheck", ["test", "-S", swaySocket], (output, exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
isNiri = false
|
||||
isHyprland = false
|
||||
isDwl = false
|
||||
isSway = true
|
||||
compositor = "sway"
|
||||
console.info("CompositorService: Detected Sway with socket:", swaySocket)
|
||||
}
|
||||
}, 0)
|
||||
return
|
||||
}
|
||||
|
||||
if (DMSService.dmsAvailable) {
|
||||
Qt.callLater(checkForDwl)
|
||||
} else {
|
||||
isHyprland = false
|
||||
isNiri = false
|
||||
isDwl = false
|
||||
isSway = false
|
||||
compositor = "unknown"
|
||||
console.warn("CompositorService: No compositor detected")
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
function onCapabilitiesReceived() {
|
||||
if (!isHyprland && !isNiri && !isDwl) {
|
||||
checkForDwl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkForDwl() {
|
||||
if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) {
|
||||
isHyprland = false
|
||||
isNiri = false
|
||||
isDwl = true
|
||||
compositor = "dwl"
|
||||
console.info("CompositorService: Detected DWL via DMS capability")
|
||||
}
|
||||
}
|
||||
|
||||
function powerOffMonitors() {
|
||||
if (isNiri) return NiriService.powerOffMonitors()
|
||||
if (isHyprland) return Hyprland.dispatch("dpms off")
|
||||
if (isDwl) return _dwlPowerOffMonitors()
|
||||
if (isSway) { try { I3.dispatch("output * dpms off") } catch(_){} return }
|
||||
console.warn("CompositorService: Cannot power off monitors, unknown compositor")
|
||||
}
|
||||
|
||||
function powerOnMonitors() {
|
||||
if (isNiri) return NiriService.powerOnMonitors()
|
||||
if (isHyprland) return Hyprland.dispatch("dpms on")
|
||||
if (isDwl) return _dwlPowerOnMonitors()
|
||||
if (isSway) { try { I3.dispatch("output * dpms on") } catch(_){} return }
|
||||
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
|
||||
}
|
||||
|
||||
function _dwlPowerOffMonitors() {
|
||||
if (!Quickshell.screens || Quickshell.screens.length === 0) {
|
||||
console.warn("CompositorService: No screens available for DWL power off")
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
const screen = Quickshell.screens[i]
|
||||
if (screen && screen.name) {
|
||||
Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + screen.name])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _dwlPowerOnMonitors() {
|
||||
if (!Quickshell.screens || Quickshell.screens.length === 0) {
|
||||
console.warn("CompositorService: No screens available for DWL power on")
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
const screen = Quickshell.screens[i]
|
||||
if (screen && screen.name) {
|
||||
Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ Singleton {
|
||||
signal capabilitiesReceived()
|
||||
signal credentialsRequest(var data)
|
||||
signal bluetoothPairingRequest(var data)
|
||||
signal dwlStateUpdate(var data)
|
||||
|
||||
Component.onCompleted: {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
@@ -266,6 +267,8 @@ Singleton {
|
||||
}
|
||||
} else if (service === "bluetooth.pairing") {
|
||||
bluetoothPairingRequest(data)
|
||||
} else if (service === "dwl") {
|
||||
dwlStateUpdate(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
259
Services/DwlService.qml
Normal file
259
Services/DwlService.qml
Normal file
@@ -0,0 +1,259 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool dwlAvailable: false
|
||||
property var outputs: ({})
|
||||
property var tagCount: 9
|
||||
property var layouts: []
|
||||
property string activeOutput: ""
|
||||
property var outputScales: ({})
|
||||
|
||||
signal stateChanged()
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
function onCapabilitiesReceived() {
|
||||
checkCapabilities()
|
||||
}
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkCapabilities()
|
||||
} else {
|
||||
dwlAvailable = false
|
||||
}
|
||||
}
|
||||
function onDwlStateUpdate(data) {
|
||||
if (dwlAvailable) {
|
||||
handleStateUpdate(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (DMSService.dmsAvailable) {
|
||||
checkCapabilities()
|
||||
}
|
||||
if (dwlAvailable) {
|
||||
refreshOutputScales()
|
||||
}
|
||||
}
|
||||
|
||||
function checkCapabilities() {
|
||||
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
|
||||
dwlAvailable = false
|
||||
return
|
||||
}
|
||||
|
||||
const hasDwl = DMSService.capabilities.includes("dwl")
|
||||
if (hasDwl && !dwlAvailable) {
|
||||
dwlAvailable = true
|
||||
console.info("DwlService: DWL capability detected")
|
||||
requestState()
|
||||
refreshOutputScales()
|
||||
} else if (!hasDwl) {
|
||||
dwlAvailable = false
|
||||
}
|
||||
}
|
||||
|
||||
function requestState() {
|
||||
if (!DMSService.isConnected || !dwlAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
DMSService.sendRequest("dwl.getState", null, response => {
|
||||
if (response.result) {
|
||||
handleStateUpdate(response.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleStateUpdate(state) {
|
||||
outputs = state.outputs || {}
|
||||
tagCount = state.tagCount || 9
|
||||
layouts = state.layouts || []
|
||||
activeOutput = state.activeOutput || ""
|
||||
stateChanged()
|
||||
}
|
||||
|
||||
function setTags(outputName, tagmask, toggleTagset) {
|
||||
if (!DMSService.isConnected || !dwlAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
DMSService.sendRequest("dwl.setTags", {
|
||||
"output": outputName,
|
||||
"tagmask": tagmask,
|
||||
"toggleTagset": toggleTagset
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("DwlService: setTags error:", response.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setClientTags(outputName, andTags, xorTags) {
|
||||
if (!DMSService.isConnected || !dwlAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
DMSService.sendRequest("dwl.setClientTags", {
|
||||
"output": outputName,
|
||||
"andTags": andTags,
|
||||
"xorTags": xorTags
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("DwlService: setClientTags error:", response.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setLayout(outputName, index) {
|
||||
if (!DMSService.isConnected || !dwlAvailable) {
|
||||
return
|
||||
}
|
||||
|
||||
DMSService.sendRequest("dwl.setLayout", {
|
||||
"output": outputName,
|
||||
"index": index
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("DwlService: setLayout error:", response.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getOutputState(outputName) {
|
||||
if (!outputs || !outputs[outputName]) {
|
||||
return null
|
||||
}
|
||||
return outputs[outputName]
|
||||
}
|
||||
|
||||
function getActiveTags(outputName) {
|
||||
const output = getOutputState(outputName)
|
||||
if (!output || !output.tags) {
|
||||
return []
|
||||
}
|
||||
return output.tags.filter(tag => tag.state === 1).map(tag => tag.tag)
|
||||
}
|
||||
|
||||
function getTagsWithClients(outputName) {
|
||||
const output = getOutputState(outputName)
|
||||
if (!output || !output.tags) {
|
||||
return []
|
||||
}
|
||||
return output.tags.filter(tag => tag.clients > 0).map(tag => tag.tag)
|
||||
}
|
||||
|
||||
function getUrgentTags(outputName) {
|
||||
const output = getOutputState(outputName)
|
||||
if (!output || !output.tags) {
|
||||
return []
|
||||
}
|
||||
return output.tags.filter(tag => tag.state === 2).map(tag => tag.tag)
|
||||
}
|
||||
|
||||
function switchToTag(outputName, tagIndex) {
|
||||
const tagmask = 1 << tagIndex
|
||||
setTags(outputName, tagmask, 0)
|
||||
}
|
||||
|
||||
function toggleTag(outputName, tagIndex) {
|
||||
const output = getOutputState(outputName)
|
||||
if (!output || !output.tags) {
|
||||
console.log("toggleTag: no output or tags for", outputName)
|
||||
return
|
||||
}
|
||||
|
||||
let currentMask = 0
|
||||
output.tags.forEach(tag => {
|
||||
if (tag.state === 1) {
|
||||
currentMask |= (1 << tag.tag)
|
||||
}
|
||||
})
|
||||
|
||||
const clickedMask = 1 << tagIndex
|
||||
const newMask = currentMask ^ clickedMask
|
||||
|
||||
console.log("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2))
|
||||
|
||||
if (newMask === 0) {
|
||||
console.log("toggleTag: newMask is 0, switching to tag", tagIndex)
|
||||
setTags(outputName, 1 << tagIndex, 0)
|
||||
} else {
|
||||
console.log("toggleTag: setting combined mask", newMask)
|
||||
setTags(outputName, newMask, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function quit() {
|
||||
Quickshell.execDetached(["mmsg", "-d", "quit"])
|
||||
}
|
||||
|
||||
Process {
|
||||
id: scaleQueryProcess
|
||||
command: ["mmsg", "-A"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
const newScales = {}
|
||||
const lines = text.trim().split('\n')
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split(/\s+/)
|
||||
if (parts.length >= 3 && parts[1] === "scale_factor") {
|
||||
const outputName = parts[0]
|
||||
const scale = parseFloat(parts[2])
|
||||
if (!isNaN(scale)) {
|
||||
newScales[outputName] = scale
|
||||
}
|
||||
}
|
||||
}
|
||||
outputScales = newScales
|
||||
} catch (e) {
|
||||
console.warn("DwlService: Failed to parse mmsg output:", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("DwlService: mmsg failed with exit code:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshOutputScales() {
|
||||
if (!dwlAvailable) return
|
||||
scaleQueryProcess.running = true
|
||||
}
|
||||
|
||||
function getOutputScale(outputName) {
|
||||
return outputScales[outputName]
|
||||
}
|
||||
|
||||
function getVisibleTags(outputName) {
|
||||
const output = getOutputState(outputName)
|
||||
if (!output || !output.tags) {
|
||||
return [0]
|
||||
}
|
||||
|
||||
const visibleTags = new Set([0])
|
||||
|
||||
output.tags.forEach(tag => {
|
||||
if (tag.state === 1 || tag.clients > 0) {
|
||||
visibleTags.add(tag.tag)
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(visibleTags).sort((a, b) => a - b)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: getKeybinds
|
||||
running: true
|
||||
running: false
|
||||
command: [root.scriptPath, "--path", root.hyprConfigPath]
|
||||
|
||||
stdout: SplitParser {
|
||||
@@ -31,9 +31,22 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (code) => {
|
||||
if (code !== 0) {
|
||||
console.warn("[HyprKeybindsService] Process exited with code:", code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
getKeybinds.running = true
|
||||
}
|
||||
|
||||
function reload() {
|
||||
getKeybinds.running = true
|
||||
getKeybinds.running = false
|
||||
Qt.callLater(function() {
|
||||
getKeybinds.running = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import qs.Common
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property int refCount: 0
|
||||
property bool isActive: false
|
||||
property string networkStatus: "disconnected"
|
||||
property string primaryConnection: ""
|
||||
@@ -56,8 +55,6 @@ Singleton {
|
||||
property string connectionError: ""
|
||||
|
||||
property bool isScanning: false
|
||||
property bool autoScan: false
|
||||
|
||||
property bool wifiAvailable: true
|
||||
property bool wifiToggling: false
|
||||
property bool changingPreference: false
|
||||
@@ -66,7 +63,6 @@ Singleton {
|
||||
property string connectionStatus: ""
|
||||
property string lastConnectionError: ""
|
||||
property bool passwordDialogShouldReopen: false
|
||||
property bool autoRefreshEnabled: false
|
||||
property string wifiPassword: ""
|
||||
property string forgetSSID: ""
|
||||
|
||||
@@ -109,114 +105,20 @@ Singleton {
|
||||
root.userPreference = SettingsData.networkPreference
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
nmStateMonitor.running = false
|
||||
}
|
||||
|
||||
function activate() {
|
||||
if (!isActive) {
|
||||
isActive = true
|
||||
console.info("LegacyNetworkService: Activating...")
|
||||
initializeDBusMonitors()
|
||||
doRefreshNetworkState()
|
||||
}
|
||||
}
|
||||
|
||||
function addRef() {
|
||||
refCount++
|
||||
if (refCount === 1) {
|
||||
startAutoScan()
|
||||
}
|
||||
}
|
||||
|
||||
function removeRef() {
|
||||
refCount = Math.max(0, refCount - 1)
|
||||
if (refCount === 0) {
|
||||
stopAutoScan()
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDBusMonitors() {
|
||||
nmStateMonitor.running = true
|
||||
doRefreshNetworkState()
|
||||
}
|
||||
|
||||
Process {
|
||||
id: nmStateMonitor
|
||||
command: lowPriorityCmd.concat(["gdbus", "monitor", "--system", "--dest", "org.freedesktop.NetworkManager"])
|
||||
running: false
|
||||
|
||||
property var lastRefreshTime: 0
|
||||
property int minRefreshInterval: 1000
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
const now = Date.now()
|
||||
if (line.includes("PropertiesChanged") && line.includes("org.freedesktop.NetworkManager.AccessPoint")) {
|
||||
if (line.includes("'Strength'") && root.activeAccessPointPath && line.includes(root.activeAccessPointPath)) {
|
||||
parseSignalStrengthFromDbus(line)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (line.includes("StateChanged") ||
|
||||
line.includes("PrimaryConnectionChanged") ||
|
||||
line.includes("WirelessEnabled") ||
|
||||
(line.includes("ActiveConnection") && line.includes("State"))) {
|
||||
|
||||
if (now - nmStateMonitor.lastRefreshTime > nmStateMonitor.minRefreshInterval) {
|
||||
nmStateMonitor.lastRefreshTime = now
|
||||
refreshNetworkState()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0 && !restartTimer.running) {
|
||||
console.warn("NetworkManager monitor failed, restarting in 5s")
|
||||
restartTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: restartTimer
|
||||
interval: 5000
|
||||
running: false
|
||||
onTriggered: nmStateMonitor.running = true
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshDebounceTimer
|
||||
interval: 100
|
||||
running: false
|
||||
onTriggered: doRefreshNetworkState()
|
||||
}
|
||||
|
||||
function refreshNetworkState() {
|
||||
refreshDebounceTimer.restart()
|
||||
}
|
||||
|
||||
function parseSignalStrengthFromDbus(line) {
|
||||
const strengthMatch = line.match(/'Strength': <byte (0x[0-9a-fA-F]+)>/)
|
||||
if (strengthMatch) {
|
||||
const hexValue = strengthMatch[1]
|
||||
const strength = parseInt(hexValue, 16)
|
||||
if (strength >= 0 && strength <= 100) {
|
||||
root.wifiSignalStrength = strength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doRefreshNetworkState() {
|
||||
updatePrimaryConnection()
|
||||
updateDeviceStates()
|
||||
updateActiveConnections()
|
||||
updateWifiState()
|
||||
if (root.refCount > 0 && root.wifiEnabled) {
|
||||
scanWifiNetworks()
|
||||
}
|
||||
}
|
||||
|
||||
function updatePrimaryConnection() {
|
||||
@@ -333,9 +235,6 @@ Singleton {
|
||||
getEthernetIP.running = true
|
||||
} else {
|
||||
root.ethernetIP = ""
|
||||
if (root.networkStatus === "ethernet") {
|
||||
updatePrimaryConnection()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -907,18 +806,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function startAutoScan() {
|
||||
root.autoScan = true
|
||||
root.autoRefreshEnabled = true
|
||||
if (root.wifiEnabled) {
|
||||
scanWifi()
|
||||
}
|
||||
}
|
||||
|
||||
function stopAutoScan() {
|
||||
root.autoScan = false
|
||||
root.autoRefreshEnabled = false
|
||||
}
|
||||
|
||||
function fetchNetworkInfo(ssid) {
|
||||
root.networkInfoSSID = ssid
|
||||
|
||||
@@ -6,6 +6,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.I3
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
|
||||
@@ -184,7 +185,16 @@ Singleton {
|
||||
return
|
||||
}
|
||||
|
||||
// Hyprland fallback
|
||||
if (CompositorService.isDwl) {
|
||||
DwlService.quit()
|
||||
return
|
||||
}
|
||||
|
||||
if (CompositorService.isSway) {
|
||||
try { I3.dispatch("exit") } catch(_){}
|
||||
return
|
||||
}
|
||||
|
||||
Hyprland.dispatch("exit")
|
||||
} else {
|
||||
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLogout])
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
layer-rule {
|
||||
match namespace="dms:blurwallpaper"
|
||||
opacity 0.0
|
||||
}
|
||||
|
||||
layer-rule {
|
||||
match namespace="dms:blurwallpaper"
|
||||
place-within-backdrop true
|
||||
opacity 1.0
|
||||
}
|
||||
@@ -14,6 +14,10 @@ Item {
|
||||
|
||||
// This is for file browser, particularly - might want another map later for app IDs
|
||||
readonly property var iconMap: ({
|
||||
// --- special types ---
|
||||
"folder": "\u{F024B}",
|
||||
"file": "\u{F0214}",
|
||||
|
||||
// --- special filenames (no extension) ---
|
||||
"docker": "\u{F0868}",
|
||||
"makefile": "\u{F09EE}",
|
||||
@@ -22,6 +26,7 @@ Item {
|
||||
|
||||
// --- programming languages ---
|
||||
"rs": "\u{F1617}",
|
||||
"dart": "\u{e798}",
|
||||
"go": "\u{F07D3}",
|
||||
"py": "\u{F0320}",
|
||||
"js": "\u{F031E}",
|
||||
@@ -72,6 +77,7 @@ Item {
|
||||
"rtf": "\u{F09EE}",
|
||||
"ppt": "\u{F09EE}",
|
||||
"pptx": "\u{F09EE}",
|
||||
"log": "\u{F09EE}",
|
||||
"xls": "\u{F021C}",
|
||||
"xlsx": "\u{F021C}",
|
||||
|
||||
@@ -104,7 +110,7 @@ Item {
|
||||
})
|
||||
|
||||
|
||||
readonly property string text: iconMap[name] || ""
|
||||
readonly property string text: iconMap[name] || iconMap["file"] || ""
|
||||
|
||||
function getIconForFile(fileName) {
|
||||
const lowerName = fileName.toLowerCase()
|
||||
|
||||
@@ -75,17 +75,7 @@ PanelWindow {
|
||||
|
||||
readonly property real screenWidth: root.screen.width
|
||||
readonly property real screenHeight: root.screen.height
|
||||
readonly property real dpr: {
|
||||
if (CompositorService.isNiri && root.screen) {
|
||||
const niriScale = NiriService.displayScales[root.screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && root.screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === root.screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
return root.screen?.devicePixelRatio || 1
|
||||
}
|
||||
readonly property real dpr: CompositorService.getScreenScale(root.screen)
|
||||
|
||||
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
|
||||
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
|
||||
|
||||
@@ -57,6 +57,15 @@ PanelWindow {
|
||||
WlrLayershell.exclusiveZone: 0
|
||||
WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: root.width - contentRect.width
|
||||
y: 0
|
||||
width: contentRect.width
|
||||
height: root.height
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
id: contentRect
|
||||
layer.enabled: true
|
||||
|
||||
BIN
assets/mango.png
Normal file
BIN
assets/mango.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
47
assets/sway.svg
Normal file
47
assets/sway.svg
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="1589.1 -0.1 410.9 383.1" enable-background="new 1589.1 -0.1 410.9 383.1" xml:space="preserve">
|
||||
<polygon fill="#FF4040" points="1794.4,383 1589.1,304.6 1589.1,273.2 1794.4,291.5 1999.9,273.2 1999.9,304.6 "/>
|
||||
<path fill="#AFA137" d="M1794.4,351.4l-205.3-78.2c0,0,13.6-5.3,16.2-6.2c12.2-4.5,25-8.3,36.8-13.4c24.5-10.9,51.4-17.8,78.2-18.2
|
||||
c15.4-0.2,29.8,4.5,44.8,2.2c17.4-2.9,34.1-9.4,51.6-12.9c31.6-6,62.3,2.2,91.5,13.8c30,11.8,59.2,22.3,89.3,33.8
|
||||
c0.9,0.4,1.6,0.5,2.5,0.9L1794.4,351.4z"/>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#C6ADAC" d="M1656.3,277.2c-2.5-57,55.2-87.7,97.8-111.1c37.2-20.3,83.7-46.8,74.1-96.4c-2-10.3-17.8-6-15.8,4.4
|
||||
c4.4,22.7-8.5,39.9-25.8,53c-20.3,15.4-43.7,26.3-65.9,38.8c-40.8,23.2-83.1,59.9-81,111.3
|
||||
C1640.5,287.7,1656.8,287.7,1656.3,277.2L1656.3,277.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#C6ADAC" d="M1728,183.7c56.6,11.8,116.4-5.1,158.3-45c7.6-7.3-4-18.9-11.6-11.6c-37.4,35.8-91.7,51.4-142.3,40.8
|
||||
C1722,165.9,1717.6,181.5,1728,183.7L1728,183.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#68751C" d="M1727.8,64.8c14.9,3.6,40.1-13.6,51.4-19.1c14.5-7.1,29.6-12.5,44.3-19.1c5.6-2.5,24-8.3,24.1-16.5
|
||||
c0.4-10.2-19.1-10.7-25.4-10c-12.9,1.3-25.4,5.3-37.8,8.9c-12.7,3.8-25,8.9-36.8,15.2c-8.9,4.7-21.1,13.1-26.3,21.8
|
||||
c-3.3,5.3-3.1,13.1,2,16.7C1724.5,63.7,1726.2,64.4,1727.8,64.8z"/>
|
||||
<path fill="#68751C" d="M1819.1,37.2c2.5-1.5,5.1-2.7,7.6-4c21.1-10,45.4-18.2,69.3-20c20.9-1.6,43.9-5.4,64.6,0.2
|
||||
c10.7,2.9,22.5,13.3,16.9,23.2c-4.2,7.4-21.2,17.4-28.7,22.9c-27.4,19.4-65.7,28-100.7,29.8c-25.4,1.3-67.3-13.3-44.1-40.7
|
||||
C1808,44.1,1813.3,40.5,1819.1,37.2z"/>
|
||||
<path fill="#68751C" d="M1958.9,60.1c5.8,0.2,12.5,1.6,15.2,6.9c2.2,4.4,0.5,9.6-2.5,13.3c-3.3,3.6-7.6,5.6-12.2,7.4
|
||||
c-22.5,9.4-46.6,15.1-71,16.7c-6.7,0.4-13.8,0.5-20.3-1.6s-12.3-7.1-14.2-13.6c-4-15.1,29-20,37.9-21.6s17.8-2.7,26.7-3.1
|
||||
C1932,63.5,1945.1,59.5,1958.9,60.1z"/>
|
||||
<path fill="#68751C" d="M1955.6,158.8c-8.9-22-62.4,2.2-74.6,10c-4.5,2.9-9.3,7.3-8.3,12.5c0.9,5.6,7.6,8.2,13.4,8.9
|
||||
C1900.2,192,1966.1,184.8,1955.6,158.8z"/>
|
||||
<path fill="#68751C" d="M1787.5,87.7c-2.2,14.5-21.8,30.5-34.9,35c-12.7,4.5-33.9-4.9-26.1-20.3c6.9-13.4,41-37.4,55.9-27.6
|
||||
C1786.6,77.5,1788.2,83,1787.5,87.7z"/>
|
||||
<path fill="#68751C" d="M1825.1,159.9c20.9,2.5,42.3-0.2,61.9-7.6c4.4-1.6,8.9-3.8,10.7-8.2c1.3-3.3,0.4-7.3-2.2-9.6
|
||||
c-2.5-2.4-6.5-3.1-9.6-1.6c-5.8-6.4-16-5.8-24.5-4.2c-13.4,2.7-26.7,7.6-38.8,14c-4.4,2.4-9.3,6.4-8,11.1
|
||||
C1815.8,157.9,1820.9,159.4,1825.1,159.9z"/>
|
||||
<path fill="#68751C" d="M1849.4,143c27.6,6.2,57.9-1.8,81.5-17.1c3.1-2,6.5-5.1,6-8.9c-0.7-4.5-6.5-6-11.3-5.8
|
||||
c-26.9,0.4-54.1,7.1-77.5,20.7c-2.7,1.5-5.6,4-4.9,6.9C1844,141.4,1846.9,142.5,1849.4,143z"/>
|
||||
<g>
|
||||
<path fill="#68751C" d="M1711.1,106.4c2.5-3.1,4.7-6.9,3.6-10.5c-5.1-20.1-32.5,6-39,12c-8.3,7.6-8,14.3,5.6,14.3
|
||||
C1692.6,122,1704.4,114.5,1711.1,106.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -16,6 +16,8 @@ Source0: {{{ git_dir_pack }}}
|
||||
|
||||
BuildRequires: git-core
|
||||
BuildRequires: rpkg
|
||||
# For the _tmpfilesdir macro.
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
Requires: greetd
|
||||
Requires: (quickshell-git or quickshell)
|
||||
@@ -150,7 +152,7 @@ chmod 755 %{buildroot}%{_bindir}/dms-greeter-sync
|
||||
install -Dm644 Modules/Greetd/README.md %{buildroot}%{_docdir}/dms-greeter/README.md
|
||||
|
||||
# Create cache directory for greeter data
|
||||
install -dm750 %{buildroot}%{_localstatedir}/cache/dms-greeter
|
||||
install -Dpm0644 ./systemd/tmpfiles-dms-greeter.conf %{buildroot}%{_tmpfilesdir}/dms-greeter.conf
|
||||
|
||||
# Create greeter home directory
|
||||
install -dm755 %{buildroot}%{_sharedstatedir}/greeter
|
||||
@@ -181,8 +183,7 @@ fi
|
||||
%{_bindir}/dms-greeter
|
||||
%{_bindir}/dms-greeter-sync
|
||||
%{_datadir}/quickshell/dms-greeter/
|
||||
%dir %attr(0750,greeter,greeter) %{_localstatedir}/cache/dms-greeter
|
||||
%dir %attr(0755,greeter,greeter) %{_sharedstatedir}/greeter
|
||||
%{_tmpfilesdir}/%{name}.conf
|
||||
|
||||
%pre
|
||||
# Create greeter user/group if they don't exist (greetd expects this)
|
||||
|
||||
2
dms.spec
2
dms.spec
@@ -47,7 +47,7 @@ Suggests: qt6ct
|
||||
|
||||
%description
|
||||
DankMaterialShell (DMS) is a modern Wayland desktop shell built with Quickshell
|
||||
and optimized for the niri and hyprland compositors. Features notifications,
|
||||
and optimized for the niri, hyprland, sway, and dwl (MangoWC) compositors. Features notifications,
|
||||
app launcher, wallpaper customization, and fully customizable with plugins.
|
||||
|
||||
Includes auto-theming for GTK/Qt apps with matugen, 20+ customizable widgets,
|
||||
|
||||
@@ -508,12 +508,12 @@ Dashboard popup control with tab selection for overview, media, and weather info
|
||||
|
||||
**Functions:**
|
||||
- `open [tab]` - Show dashboard popup with optional tab selection
|
||||
- Parameters: `tab` - Optional tab to open: "" (default), "overview", "media", or "weather"
|
||||
- Parameters: `tab` - Tab to open: "", "overview", "media", or "weather"
|
||||
- Returns: Success/failure message
|
||||
- `close` - Hide dashboard popup
|
||||
- Returns: Success/failure message
|
||||
- `toggle [tab]` - Toggle dashboard popup visibility with optional tab selection
|
||||
- Parameters: `tab` - Optional tab to open when showing: "" (default), "overview", "media", or "weather"
|
||||
- Parameters: `tab` - Tab to open when showing: "", "overview", "media", or "weather"
|
||||
- Returns: Success/failure message
|
||||
|
||||
### Target: `dankdash`
|
||||
|
||||
@@ -21,11 +21,11 @@ apply_qt_colors() {
|
||||
local config_file="$1"
|
||||
|
||||
if [ -f "$config_file" ]; then
|
||||
if grep -q '^\\[Appearance\\]' "$config_file"; then
|
||||
if grep -q '^\[Appearance\]' "$config_file"; then
|
||||
if grep -q '^custom_palette=' "$config_file"; then
|
||||
sed -i 's/^custom_palette=.*/custom_palette=true/' "$config_file"
|
||||
else
|
||||
sed -i '/^\\[Appearance\\]/a custom_palette=true' "$config_file"
|
||||
sed -i '/^\[Appearance\]/a custom_palette=true' "$config_file"
|
||||
fi
|
||||
|
||||
if grep -q '^color_scheme_path=' "$config_file"; then
|
||||
|
||||
3
systemd/tmpfiles-dms-greeter.conf
Normal file
3
systemd/tmpfiles-dms-greeter.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# Path Mode User Group Age Argument
|
||||
d /var/cache/dms-greeter 0750 greeter greeter -
|
||||
d /var/lib/greeter 0755 greeter greeter -
|
||||
@@ -14,13 +14,13 @@
|
||||
{
|
||||
"term": "- Stateless System Monitoring",
|
||||
"context": "- Stateless System Monitoring",
|
||||
"reference": "Modules/Settings/AboutTab.qml:432",
|
||||
"reference": "Modules/Settings/AboutTab.qml:517",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "- Support Us With a Star ⭐",
|
||||
"context": "- Support Us With a Star ⭐",
|
||||
"reference": "Modules/Settings/AboutTab.qml:397",
|
||||
"reference": "Modules/Settings/AboutTab.qml:482",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -62,7 +62,7 @@
|
||||
{
|
||||
"term": "About",
|
||||
"context": "About",
|
||||
"reference": "Modules/Settings/AboutTab.qml:251, Modals/Settings/SettingsSidebar.qml:44",
|
||||
"reference": "Modules/Settings/AboutTab.qml:336, Modals/Settings/SettingsSidebar.qml:44",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -146,7 +146,7 @@
|
||||
{
|
||||
"term": "Always show a minimum of 3 workspaces, even if fewer are available",
|
||||
"context": "Always show a minimum of 3 workspaces, even if fewer are available",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:82",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:71",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -212,7 +212,7 @@
|
||||
{
|
||||
"term": "Apps are ordered by usage frequency, then last used, then alphabetically.",
|
||||
"context": "Apps are ordered by usage frequency, then last used, then alphabetically.",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:608",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:607",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -404,13 +404,13 @@
|
||||
{
|
||||
"term": "Back",
|
||||
"context": "Back",
|
||||
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:479",
|
||||
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:511",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Balanced palette with focused accents (default).",
|
||||
"context": "Balanced palette with focused accents (default).",
|
||||
"reference": "Common/Theme.qml:216",
|
||||
"reference": "Common/Theme.qml:215",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -512,7 +512,7 @@
|
||||
{
|
||||
"term": "Brightness",
|
||||
"context": "Brightness",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:324",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:323",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -584,7 +584,7 @@
|
||||
{
|
||||
"term": "Choose Launcher Logo Color",
|
||||
"context": "Choose Launcher Logo Color",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:251",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:250",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -662,7 +662,7 @@
|
||||
{
|
||||
"term": "Color Override",
|
||||
"context": "Color Override",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:187",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:186",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -680,7 +680,7 @@
|
||||
{
|
||||
"term": "Colorful mix of bright contrasting accents.",
|
||||
"context": "Colorful mix of bright contrasting accents.",
|
||||
"reference": "Common/Theme.qml:240",
|
||||
"reference": "Common/Theme.qml:239",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -731,6 +731,12 @@
|
||||
"reference": "Modules/Settings/WidgetsTabSection.qml:521",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Compositor",
|
||||
"context": "Compositor",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:99",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Configuration activated",
|
||||
"context": "Configuration activated",
|
||||
@@ -788,7 +794,7 @@
|
||||
{
|
||||
"term": "Contrast",
|
||||
"context": "Contrast",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:353",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:352",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -878,7 +884,7 @@
|
||||
{
|
||||
"term": "Custom",
|
||||
"context": "Custom",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:94, Modules/Settings/LauncherTab.qml:200",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:101, Modules/Settings/LauncherTab.qml:199",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -926,7 +932,7 @@
|
||||
{
|
||||
"term": "DMS out of date",
|
||||
"context": "DMS out of date",
|
||||
"reference": "Services/DMSService.qml:229",
|
||||
"reference": "Services/DMSService.qml:230",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -980,7 +986,7 @@
|
||||
{
|
||||
"term": "Default",
|
||||
"context": "Default",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:200",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:199",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -998,7 +1004,7 @@
|
||||
{
|
||||
"term": "Derives colors that closely match the underlying image.",
|
||||
"context": "Derives colors that closely match the underlying image.",
|
||||
"reference": "Common/Theme.qml:228",
|
||||
"reference": "Common/Theme.qml:227",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1070,7 +1076,7 @@
|
||||
{
|
||||
"term": "Display application icons in workspace indicators",
|
||||
"context": "Display application icons in workspace indicators",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:93",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:82",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1100,7 +1106,7 @@
|
||||
{
|
||||
"term": "Diverse palette spanning the full spectrum.",
|
||||
"context": "Diverse palette spanning the full spectrum.",
|
||||
"reference": "Common/Theme.qml:252",
|
||||
"reference": "Common/Theme.qml:251",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1136,7 +1142,7 @@
|
||||
{
|
||||
"term": "Donate on Ko-fi",
|
||||
"context": "Donate on Ko-fi",
|
||||
"reference": "Modules/Settings/AboutTab.qml:486",
|
||||
"reference": "Modules/Settings/AboutTab.qml:571",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1508,7 +1514,7 @@
|
||||
{
|
||||
"term": "Github:",
|
||||
"context": "Github:",
|
||||
"reference": "Modules/Settings/AboutTab.qml:370",
|
||||
"reference": "Modules/Settings/AboutTab.qml:455",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1580,13 +1586,13 @@
|
||||
{
|
||||
"term": "High-contrast palette for strong visual distinction.",
|
||||
"context": "High-contrast palette for strong visual distinction.",
|
||||
"reference": "Common/Theme.qml:224",
|
||||
"reference": "Common/Theme.qml:223",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "High-fidelity palette that preserves source hues.",
|
||||
"context": "High-fidelity palette that preserves source hues.",
|
||||
"reference": "Common/Theme.qml:236",
|
||||
"reference": "Common/Theme.qml:235",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1700,7 +1706,7 @@
|
||||
{
|
||||
"term": "Invert on mode change",
|
||||
"context": "Invert on mode change",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:382",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:381",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1718,31 +1724,31 @@
|
||||
{
|
||||
"term": "Last launched %1",
|
||||
"context": "Last launched %1",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:708",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:707",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Last launched %1 day%2 ago",
|
||||
"context": "Last launched %1 day%2 ago",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:704",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:703",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Last launched %1 hour%2 ago",
|
||||
"context": "Last launched %1 hour%2 ago",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:699",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:698",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Last launched %1 minute%2 ago",
|
||||
"context": "Last launched %1 minute%2 ago",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:694",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:693",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Last launched just now",
|
||||
"context": "Last launched just now",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:691",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:690",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1760,7 +1766,7 @@
|
||||
{
|
||||
"term": "Launch Prefix",
|
||||
"context": "Launch Prefix",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:433",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:432",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1808,7 +1814,7 @@
|
||||
{
|
||||
"term": "Lively palette with saturated accents.",
|
||||
"context": "Lively palette with saturated accents.",
|
||||
"reference": "Common/Theme.qml:220",
|
||||
"reference": "Common/Theme.qml:219",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1916,7 +1922,7 @@
|
||||
{
|
||||
"term": "Max apps to show",
|
||||
"context": "Max apps to show",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:114",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:103",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -1964,7 +1970,7 @@
|
||||
{
|
||||
"term": "Minimal palette built around a single hue.",
|
||||
"context": "Minimal palette built around a single hue.",
|
||||
"reference": "Common/Theme.qml:244",
|
||||
"reference": "Common/Theme.qml:243",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2006,7 +2012,7 @@
|
||||
{
|
||||
"term": "Muted palette with subdued, calming tones.",
|
||||
"context": "Muted palette with subdued, calming tones.",
|
||||
"reference": "Common/Theme.qml:248",
|
||||
"reference": "Common/Theme.qml:247",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2354,7 +2360,7 @@
|
||||
{
|
||||
"term": "Per-Monitor Workspaces",
|
||||
"context": "Per-Monitor Workspaces",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:145",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:134",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2450,7 +2456,7 @@
|
||||
{
|
||||
"term": "Plugins:",
|
||||
"context": "Plugins:",
|
||||
"reference": "Modules/Settings/AboutTab.qml:347",
|
||||
"reference": "Modules/Settings/AboutTab.qml:432",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2516,7 +2522,7 @@
|
||||
{
|
||||
"term": "Primary",
|
||||
"context": "Primary",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:200",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:199",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2588,7 +2594,7 @@
|
||||
{
|
||||
"term": "Recently Used Apps",
|
||||
"context": "Recently Used Apps",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:578",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:577",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2624,7 +2630,7 @@
|
||||
{
|
||||
"term": "Resources",
|
||||
"context": "Resources",
|
||||
"reference": "Modules/Settings/AboutTab.qml:309",
|
||||
"reference": "Modules/Settings/AboutTab.qml:394",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2705,12 +2711,6 @@
|
||||
"reference": "Services/AppSearchService.qml:175",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Scroll through windows, rather than workspaces",
|
||||
"context": "Scroll through windows, rather than workspaces",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:71",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Search file contents",
|
||||
"context": "Search file contents",
|
||||
@@ -2774,7 +2774,7 @@
|
||||
{
|
||||
"term": "Select an image file...",
|
||||
"context": "Select an image file...",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:152",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:151",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2855,6 +2855,12 @@
|
||||
"reference": "Modals/Clipboard/ClipboardKeyboardHints.qml:9",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show All Tags",
|
||||
"context": "Show All Tags",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:144",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show Confirmation on Power Actions",
|
||||
"context": "Show Confirmation on Power Actions",
|
||||
@@ -2882,7 +2888,13 @@
|
||||
{
|
||||
"term": "Show Workspace Apps",
|
||||
"context": "Show Workspace Apps",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:92",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:81",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show all 9 tags instead of only occupied tags (DWL only)",
|
||||
"context": "Show all 9 tags instead of only occupied tags (DWL only)",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:145",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2918,7 +2930,7 @@
|
||||
{
|
||||
"term": "Show only workspaces belonging to each specific monitor.",
|
||||
"context": "Show only workspaces belonging to each specific monitor.",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:146",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:135",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -2978,13 +2990,13 @@
|
||||
{
|
||||
"term": "Size Offset",
|
||||
"context": "Size Offset",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:273",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:272",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Sort Alphabetically",
|
||||
"context": "Sort Alphabetically",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:488",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:487",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3038,13 +3050,13 @@
|
||||
{
|
||||
"term": "Support Development",
|
||||
"context": "Support Development",
|
||||
"reference": "Modules/Settings/AboutTab.qml:471",
|
||||
"reference": "Modules/Settings/AboutTab.qml:556",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Surface",
|
||||
"context": "Surface",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:200",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:199",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3110,7 +3122,7 @@
|
||||
{
|
||||
"term": "System Monitoring:",
|
||||
"context": "System Monitoring:",
|
||||
"reference": "Modules/Settings/AboutTab.qml:405",
|
||||
"reference": "Modules/Settings/AboutTab.qml:490",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3254,7 +3266,7 @@
|
||||
{
|
||||
"term": "To update, run the following command:",
|
||||
"context": "To update, run the following command:",
|
||||
"reference": "Services/DMSService.qml:230",
|
||||
"reference": "Services/DMSService.qml:231",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3482,7 +3494,7 @@
|
||||
{
|
||||
"term": "Vibrant palette with playful saturation.",
|
||||
"context": "Vibrant palette with playful saturation.",
|
||||
"reference": "Common/Theme.qml:232",
|
||||
"reference": "Common/Theme.qml:231",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3554,13 +3566,13 @@
|
||||
{
|
||||
"term": "Website:",
|
||||
"context": "Website:",
|
||||
"reference": "Modules/Settings/AboutTab.qml:324",
|
||||
"reference": "Modules/Settings/AboutTab.qml:409",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.",
|
||||
"context": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:517",
|
||||
"reference": "Modules/Settings/LauncherTab.qml:516",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
@@ -3605,12 +3617,6 @@
|
||||
"reference": "Modules/DankDash/WeatherTab.qml:354, Modules/Settings/TimeWeatherTab.qml:1181",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Window Scrolling",
|
||||
"context": "Window Scrolling",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:70",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Workspace",
|
||||
"context": "Workspace",
|
||||
@@ -3626,7 +3632,7 @@
|
||||
{
|
||||
"term": "Workspace Padding",
|
||||
"context": "Workspace Padding",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:81",
|
||||
"reference": "Modules/Settings/WidgetTweaksTab.qml:70",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "Modo Compatto"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": ""
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "Compositor:"
|
||||
},
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: Pulisce Tutto • Esc: Chiude"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": ""
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "Chiedi Conferma per Azione Engertiche"
|
||||
},
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "Mostra Apps Workspace"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": ""
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": "Mostra sull'ultimo display"
|
||||
},
|
||||
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "コンパクトモード"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": "コンポジター"
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "コンポジター:"
|
||||
},
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: すべてクリア • Esc: 閉じる"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": "すべてのタグを表示"
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "電源アクションの確認を表示"
|
||||
},
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "ワークスペースアプリを表示"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": "占有タグのみではなく、9 つのタグをすべて表示 (DWL のみ)"
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": "最後のディスプレイに表示"
|
||||
},
|
||||
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "Modo Compacto"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": ""
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "Compositor:"
|
||||
},
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: Apagar tudo • Esc: Fechar"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": ""
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "Mostrar Confirmação em Ações de Energia"
|
||||
},
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "Mostrar Aplicativos da Área de Trabalho Virtual"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": ""
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": ""
|
||||
},
|
||||
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "Kompakt Mod"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": "Kompozitör"
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "Kompozitör:"
|
||||
},
|
||||
@@ -612,7 +615,7 @@
|
||||
"Enable WiFi": "WiFi Etkinleştir"
|
||||
},
|
||||
"Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": {
|
||||
"Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Compositor tarafından hedeflenebilir bulanıklık katmanını etkinleştir (isim alanı: dms:blurwallpaper). Manuel Niri yapılandırması gerektirir."
|
||||
"Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.": "Kompozitör tarafından hedeflenebilir bulanıklık katmanını etkinleştir (isim alanı: dms:blurwallpaper). Manuel Niri yapılandırması gerektirir."
|
||||
},
|
||||
"Enable fingerprint authentication": {
|
||||
"Enable fingerprint authentication": "Parmak izi kimlik doğrulamasını etkinleştir"
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: Tümünü Temizle • Esc: Kapat"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": ""
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "Güç Eylemlerinde Onay Göster"
|
||||
},
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "Çalışma Alanı Uygulamalarını Göster"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": ""
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": "Son Ekranda Göster"
|
||||
},
|
||||
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "紧凑模式"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": "合成器"
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "合成器:"
|
||||
},
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: 清空 • Esc: 关闭"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": "显示所有标签"
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "显示电源操作确认弹窗"
|
||||
},
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "显示工作区内应用"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": "显示所有 9 个标签,而非仅占用的标签(仅限 DWL)"
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": "上一个显示器"
|
||||
},
|
||||
|
||||
@@ -9,22 +9,22 @@
|
||||
"- Stateless System Monitoring": "- 無狀態系統監控"
|
||||
},
|
||||
"- Support Us With a Star ⭐": {
|
||||
"- Support Us With a Star ⭐": "- 用星星 ⭐ 支持我們"
|
||||
"- Support Us With a Star ⭐": "- 給我們點個 Star ⭐ 來支持我們"
|
||||
},
|
||||
"1 event": {
|
||||
"1 event": "1 個活動"
|
||||
},
|
||||
"24-Hour Format": {
|
||||
"24-Hour Format": "24小時制"
|
||||
"24-Hour Format": "24 小時制"
|
||||
},
|
||||
"24-hour format": {
|
||||
"24-hour format": "24小時制"
|
||||
"24-hour format": "24 小時制"
|
||||
},
|
||||
"3rd party": {
|
||||
"3rd party": "第三方"
|
||||
},
|
||||
"7-Day Forecast": {
|
||||
"7-Day Forecast": "七天天氣預報"
|
||||
"7-Day Forecast": "七天氣象預報"
|
||||
},
|
||||
"A file with this name already exists. Do you want to overwrite it?": {
|
||||
"A file with this name already exists. Do you want to overwrite it?": "檔案名稱已存在。是否要覆蓋它?"
|
||||
@@ -69,7 +69,7 @@
|
||||
"Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close": "Alt+←/Backspace: 返回 • F1/I: 檔案資訊 • F10: 幫助 • Esc: 關閉"
|
||||
},
|
||||
"Always Show OSD Percentage": {
|
||||
"Always Show OSD Percentage": "始終顯示 OSD 百分比"
|
||||
"Always Show OSD Percentage": "OSD 始終顯示百分比"
|
||||
},
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": {
|
||||
"Always show a minimum of 3 workspaces, even if fewer are available": "始終顯示至少 3 個工作區,即使可用的工作區較少"
|
||||
@@ -93,16 +93,16 @@
|
||||
"Apply": "套用"
|
||||
},
|
||||
"Apply GTK Colors": {
|
||||
"Apply GTK Colors": "套用 GTK 色彩"
|
||||
"Apply GTK Colors": "套用 GTK 顏色"
|
||||
},
|
||||
"Apply Qt Colors": {
|
||||
"Apply Qt Colors": "套用 Qt 色彩"
|
||||
"Apply Qt Colors": "套用 Qt 顏色"
|
||||
},
|
||||
"Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": {
|
||||
"Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates.": "應用暖色溫以減輕眼睛疲勞。使用下方的自動化設定來控制其啟動時間。"
|
||||
},
|
||||
"Apps Icon": {
|
||||
"Apps Icon": "App 圖示"
|
||||
"Apps Icon": "啟動器圖示"
|
||||
},
|
||||
"Apps are ordered by usage frequency, then last used, then alphabetically.": {
|
||||
"Apps are ordered by usage frequency, then last used, then alphabetically.": "應用程式按使用頻率、最後使用時間、字母順序排列。"
|
||||
@@ -168,22 +168,22 @@
|
||||
"Automatic Control": "自動控制"
|
||||
},
|
||||
"Automatic Cycling": {
|
||||
"Automatic Cycling": "自動循環"
|
||||
"Automatic Cycling": "桌布自動輪替"
|
||||
},
|
||||
"Automatically calculate popup distance from bar edge.": {
|
||||
"Automatically calculate popup distance from bar edge.": "自動計算彈出框與資訊欄的距離。"
|
||||
},
|
||||
"Automatically cycle through wallpapers in the same folder": {
|
||||
"Automatically cycle through wallpapers in the same folder": "自動循環更換同一資料夾中的桌布"
|
||||
"Automatically cycle through wallpapers in the same folder": "自動輪替更換同一資料夾中的桌布"
|
||||
},
|
||||
"Automatically detect location based on IP address": {
|
||||
"Automatically detect location based on IP address": ""
|
||||
"Automatically detect location based on IP address": "根據IP位址自動偵測位置"
|
||||
},
|
||||
"Automatically determine your location using your IP address": {
|
||||
"Automatically determine your location using your IP address": "使用您的 IP 位址自動確定您的位置"
|
||||
},
|
||||
"Automatically extract colors from wallpaper": {
|
||||
"Automatically extract colors from wallpaper": "自動從壁紙中提取顏色"
|
||||
"Automatically extract colors from wallpaper": "自動從桌布中提取顏色"
|
||||
},
|
||||
"Automatically hide the top bar to expand screen real estate": {
|
||||
"Automatically hide the top bar to expand screen real estate": "自動隱藏頂部欄以擴大螢幕空間"
|
||||
@@ -207,7 +207,7 @@
|
||||
"Back": "返回"
|
||||
},
|
||||
"Balanced palette with focused accents (default).": {
|
||||
"Balanced palette with focused accents (default).": ""
|
||||
"Balanced palette with focused accents (default).": "顏色平衡且帶有重點點綴的調色板 (預設)。"
|
||||
},
|
||||
"Battery": {
|
||||
"Battery": "電池"
|
||||
@@ -216,7 +216,7 @@
|
||||
"Battery level and power management": "電量與電源管理"
|
||||
},
|
||||
"Battery not detected - only AC power settings available": {
|
||||
"Battery not detected - only AC power settings available": "未偵測到電池 - 僅 AC 電源設定可用"
|
||||
"Battery not detected - only AC power settings available": "未偵測到電池 - 僅提供交流電源設定"
|
||||
},
|
||||
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": {
|
||||
"Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen": "將鎖定畫面綁定到 loginctl 的 dbus 訊號。如果使用外部鎖屏,請停用"
|
||||
@@ -234,7 +234,7 @@
|
||||
"Blur on Overview": "模糊概覽"
|
||||
},
|
||||
"Blur wallpaper when niri overview is open": {
|
||||
"Blur wallpaper when niri overview is open": "當 niri 概覽打開時,模糊壁紙"
|
||||
"Blur wallpaper when niri overview is open": "當 niri 概覽打開時模糊桌布"
|
||||
},
|
||||
"Border": {
|
||||
"Border": "邊框"
|
||||
@@ -255,7 +255,7 @@
|
||||
"Bottom Section": "下方區塊"
|
||||
},
|
||||
"Bottom dock for pinned and running applications": {
|
||||
"Bottom dock for pinned and running applications": ""
|
||||
"Bottom dock for pinned and running applications": "底部 Dock 用於固定和正在運行的應用程式"
|
||||
},
|
||||
"Brightness": {
|
||||
"Brightness": "亮度"
|
||||
@@ -333,16 +333,16 @@
|
||||
"Close": "關閉"
|
||||
},
|
||||
"Color Override": {
|
||||
"Color Override": "色彩覆蓋"
|
||||
"Color Override": "顏色覆蓋"
|
||||
},
|
||||
"Color Picker": {
|
||||
"Color Picker": "色彩選擇器"
|
||||
"Color Picker": "顏色選擇器"
|
||||
},
|
||||
"Color temperature for night mode": {
|
||||
"Color temperature for night mode": "夜晚模式色溫"
|
||||
},
|
||||
"Colorful mix of bright contrasting accents.": {
|
||||
"Colorful mix of bright contrasting accents.": "明亮對比的色彩組合。"
|
||||
"Colorful mix of bright contrasting accents.": "明亮對比點綴的繽紛組合。"
|
||||
},
|
||||
"Command or script to run instead of the standard hibernate procedure": {
|
||||
"Command or script to run instead of the standard hibernate procedure": "代替標準休眠的指令或腳本"
|
||||
@@ -368,6 +368,9 @@
|
||||
"Compact Mode": {
|
||||
"Compact Mode": "緊湊模式"
|
||||
},
|
||||
"Compositor": {
|
||||
"Compositor": "合成器"
|
||||
},
|
||||
"Compositor:": {
|
||||
"Compositor:": "合成器:"
|
||||
},
|
||||
@@ -489,7 +492,7 @@
|
||||
"Dank Bar Widget Transparency": "Dank Bar 部件透明度"
|
||||
},
|
||||
"Dank Suite:": {
|
||||
"Dank Suite:": ""
|
||||
"Dank Suite:": "Dank 套件:"
|
||||
},
|
||||
"DankBar Font Scale": {
|
||||
"DankBar Font Scale": "Dank Bar 字體縮放"
|
||||
@@ -510,7 +513,7 @@
|
||||
"Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close": "Del: 清除 • Shift+Del: 清除所有 • 1-9: 動作 • F10: 幫助 • Esc: 關閉"
|
||||
},
|
||||
"Derives colors that closely match the underlying image.": {
|
||||
"Derives colors that closely match the underlying image.": ""
|
||||
"Derives colors that closely match the underlying image.": "提取與底層圖像高度匹配的顏色。"
|
||||
},
|
||||
"Desktop background images": {
|
||||
"Desktop background images": "桌面背景圖片"
|
||||
@@ -537,7 +540,7 @@
|
||||
"Disk Usage": "硬碟使用率"
|
||||
},
|
||||
"Dismiss": {
|
||||
"Dismiss": ""
|
||||
"Dismiss": "忽略"
|
||||
},
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": {
|
||||
"Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen": "顯示一個帶有固定和正在運行的應用程式的 Dock,這些應用程式可以放置在螢幕的頂部、底部、左側或右側邊緣"
|
||||
@@ -561,7 +564,7 @@
|
||||
"Displays the active keyboard layout and allows switching": "顯示目前鍵盤布局且允許切換"
|
||||
},
|
||||
"Diverse palette spanning the full spectrum.": {
|
||||
"Diverse palette spanning the full spectrum.": ""
|
||||
"Diverse palette spanning the full spectrum.": "涵蓋整個光譜的多元調色板。"
|
||||
},
|
||||
"Do Not Disturb": {
|
||||
"Do Not Disturb": "請勿打擾"
|
||||
@@ -582,7 +585,7 @@
|
||||
"Donate on Ko-fi": "在 Ko-fi 上捐款"
|
||||
},
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": {
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖曳部件即可在版塊內重新排序。使用眼睛圖示隱藏/顯示部件(保持間距),或使用 X 將其完全移除。"
|
||||
"Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.": "拖曳部件即可在版塊內重新排序。使用眼睛圖示隱藏/顯示部件 (會保持間距),或使用 X 將其完全移除。"
|
||||
},
|
||||
"Duration": {
|
||||
"Duration": "持續時間"
|
||||
@@ -618,7 +621,7 @@
|
||||
"Enable fingerprint authentication": "啟用指紋驗證"
|
||||
},
|
||||
"Enable loginctl lock integration": {
|
||||
"Enable loginctl lock integration": "啟用 loginctl lock 集成"
|
||||
"Enable loginctl lock integration": "啟用 loginctl 鎖定整合"
|
||||
},
|
||||
"End": {
|
||||
"End": "結束"
|
||||
@@ -654,7 +657,7 @@
|
||||
"Enter password for ": "輸入密碼 "
|
||||
},
|
||||
"Exclusive Zone Offset": {
|
||||
"Exclusive Zone Offset": "專屬區域偏移"
|
||||
"Exclusive Zone Offset": "獨佔區域偏移"
|
||||
},
|
||||
"Execute templates from ~/.config/matugen/config.toml": {
|
||||
"Execute templates from ~/.config/matugen/config.toml": "從 ~/.config/matugen/config.toml 執行模板"
|
||||
@@ -696,7 +699,7 @@
|
||||
"Failed to start connection to ": "無法啟動連線到 "
|
||||
},
|
||||
"Feels Like": {
|
||||
"Feels Like": "感覺像"
|
||||
"Feels Like": "體感溫度"
|
||||
},
|
||||
"File Already Exists": {
|
||||
"File Already Exists": "檔案已經存在"
|
||||
@@ -714,19 +717,19 @@
|
||||
"Focused Window": "視窗對焦"
|
||||
},
|
||||
"Font Family": {
|
||||
"Font Family": "字型"
|
||||
"Font Family": "字體"
|
||||
},
|
||||
"Font Scale": {
|
||||
"Font Scale": "字型比例"
|
||||
"Font Scale": "字體比例"
|
||||
},
|
||||
"Font Settings": {
|
||||
"Font Settings": "字型設定"
|
||||
"Font Settings": "字體設定"
|
||||
},
|
||||
"Font Size": {
|
||||
"Font Size": "字型大小"
|
||||
"Font Size": "字體大小"
|
||||
},
|
||||
"Font Weight": {
|
||||
"Font Weight": "字型寬度"
|
||||
"Font Weight": "字體粗細"
|
||||
},
|
||||
"Force Kill Process": {
|
||||
"Force Kill Process": "強制結束程序"
|
||||
@@ -741,7 +744,7 @@
|
||||
"Forgot network ": "忘記網路 "
|
||||
},
|
||||
"Format Legend": {
|
||||
"Format Legend": ""
|
||||
"Format Legend": "格式說明"
|
||||
},
|
||||
"Framework:": {
|
||||
"Framework:": "框架:"
|
||||
@@ -765,7 +768,7 @@
|
||||
"Gamma Control": "Gamma 控制"
|
||||
},
|
||||
"Gamma control not available. Requires DMS API v6+.": {
|
||||
"Gamma control not available. Requires DMS API v6+.": ""
|
||||
"Gamma control not available. Requires DMS API v6+.": "Gamma 控制不可用。需要 DMS API v6+。"
|
||||
},
|
||||
"Geoclue service not running - cannot auto-detect location": {
|
||||
"Geoclue service not running - cannot auto-detect location": "Geoclue 服務未運作 - 無法自動偵測位置"
|
||||
@@ -777,7 +780,7 @@
|
||||
"Good": "好"
|
||||
},
|
||||
"Goth Corners": {
|
||||
"Goth Corners": ""
|
||||
"Goth Corners": "圓角介面融合"
|
||||
},
|
||||
"Graphics": {
|
||||
"Graphics": "圖形"
|
||||
@@ -786,13 +789,13 @@
|
||||
"Group by App": "App 分組"
|
||||
},
|
||||
"Group multiple windows of the same app together with a window count indicator": {
|
||||
"Group multiple windows of the same app together with a window count indicator": ""
|
||||
"Group multiple windows of the same app together with a window count indicator": "將同一應用程式的多個視窗匯集在一起,並附帶視窗數量指示器"
|
||||
},
|
||||
"Health": {
|
||||
"Health": "健康狀態"
|
||||
},
|
||||
"Height to Edge Gap (Exclusive Zone)": {
|
||||
"Height to Edge Gap (Exclusive Zone)": ""
|
||||
"Height to Edge Gap (Exclusive Zone)": "邊緣間隙高度 (獨佔區域)"
|
||||
},
|
||||
"Hex:": {
|
||||
"Hex:": "色碼:"
|
||||
@@ -816,7 +819,7 @@
|
||||
"Hour": "小時"
|
||||
},
|
||||
"How often to change wallpaper": {
|
||||
"How often to change wallpaper": "多久更換一次壁紙"
|
||||
"How often to change wallpaper": "多久更換一次桌布"
|
||||
},
|
||||
"Humidity": {
|
||||
"Humidity": "濕度"
|
||||
@@ -831,7 +834,7 @@
|
||||
"Icon Theme": "圖示主題"
|
||||
},
|
||||
"Idle Inhibitor": {
|
||||
"Idle Inhibitor": ""
|
||||
"Idle Inhibitor": "空閒抑制器"
|
||||
},
|
||||
"Idle Settings": {
|
||||
"Idle Settings": "閒置設定"
|
||||
@@ -849,7 +852,7 @@
|
||||
"Incorrect password": "密碼錯誤"
|
||||
},
|
||||
"Indicator Style": {
|
||||
"Indicator Style": ""
|
||||
"Indicator Style": "指示樣式"
|
||||
},
|
||||
"Individual Batteries": {
|
||||
"Individual Batteries": "獨立電池"
|
||||
@@ -918,7 +921,7 @@
|
||||
"Left Section": "左方區塊"
|
||||
},
|
||||
"Light Mode": {
|
||||
"Light Mode": "白天模式"
|
||||
"Light Mode": "淺色主題"
|
||||
},
|
||||
"Lines: %1": {
|
||||
"Lines: %1": "行數:"
|
||||
@@ -966,16 +969,16 @@
|
||||
"Manual Show/Hide": "手動顯示/隱藏"
|
||||
},
|
||||
"Material Colors": {
|
||||
"Material Colors": "手動調整色彩"
|
||||
"Material Colors": "手動調整顏色"
|
||||
},
|
||||
"Matugen Palette": {
|
||||
"Matugen Palette": ""
|
||||
"Matugen Palette": "Matugen 調色板"
|
||||
},
|
||||
"Matugen Settings": {
|
||||
"Matugen Settings": "Matugen 設定"
|
||||
},
|
||||
"Matugen Target Monitor": {
|
||||
"Matugen Target Monitor": ""
|
||||
"Matugen Target Monitor": "Matugen 目標監視器"
|
||||
},
|
||||
"Max apps to show": {
|
||||
"Max apps to show": "最多顯示App"
|
||||
@@ -1017,7 +1020,7 @@
|
||||
"Monitor Selection:": "螢幕選擇:"
|
||||
},
|
||||
"Monitor whose wallpaper drives dynamic theming colors": {
|
||||
"Monitor whose wallpaper drives dynamic theming colors": ""
|
||||
"Monitor whose wallpaper drives dynamic theming colors": "系統介面顏色依據哪一個螢幕上的桌布來決定"
|
||||
},
|
||||
"Monospace Font": {
|
||||
"Monospace Font": "等寬字體"
|
||||
@@ -1074,7 +1077,7 @@
|
||||
"No Active Players": "無播放器"
|
||||
},
|
||||
"No Background": {
|
||||
"No Background": "無背景"
|
||||
"No Background": "部件無背景"
|
||||
},
|
||||
"No Bluetooth adapter found": {
|
||||
"No Bluetooth adapter found": "未找到藍芽適配器"
|
||||
@@ -1113,7 +1116,7 @@
|
||||
"Notepad": "筆記本"
|
||||
},
|
||||
"Notepad Font Settings": {
|
||||
"Notepad Font Settings": "筆記本字型設定"
|
||||
"Notepad Font Settings": "筆記本字體設定"
|
||||
},
|
||||
"Notepad Slideout": {
|
||||
"Notepad Slideout": "記事本滑出"
|
||||
@@ -1146,7 +1149,7 @@
|
||||
"Numbers": "數字"
|
||||
},
|
||||
"OS Logo": {
|
||||
"OS Logo": "發行版Logo"
|
||||
"OS Logo": "發行版 Logo"
|
||||
},
|
||||
"Office": {
|
||||
"Office": "辦公"
|
||||
@@ -1194,10 +1197,10 @@
|
||||
"Password": "密碼"
|
||||
},
|
||||
"Per-Mode Wallpapers": {
|
||||
"Per-Mode Wallpapers": "每種模式的桌布"
|
||||
"Per-Mode Wallpapers": "以主題區分桌布"
|
||||
},
|
||||
"Per-Monitor Wallpapers": {
|
||||
"Per-Monitor Wallpapers": "每台螢幕的桌布"
|
||||
"Per-Monitor Wallpapers": "以螢幕區分桌布"
|
||||
},
|
||||
"Per-Monitor Workspaces": {
|
||||
"Per-Monitor Workspaces": "每台螢幕的工作區"
|
||||
@@ -1272,10 +1275,10 @@
|
||||
"Power Options": "電源選項"
|
||||
},
|
||||
"Power Profile Degradation": {
|
||||
"Power Profile Degradation": ""
|
||||
"Power Profile Degradation": "電源配置降級"
|
||||
},
|
||||
"Pressure": {
|
||||
"Pressure": "壓力"
|
||||
"Pressure": "氣壓"
|
||||
},
|
||||
"Prevent screen timeout": {
|
||||
"Prevent screen timeout": "防止螢幕超時"
|
||||
@@ -1284,7 +1287,7 @@
|
||||
"Primary": "主要"
|
||||
},
|
||||
"Privacy Indicator": {
|
||||
"Privacy Indicator": ""
|
||||
"Privacy Indicator": "隱私指示器"
|
||||
},
|
||||
"Process": {
|
||||
"Process": "程序"
|
||||
@@ -1404,10 +1407,10 @@
|
||||
"Select Launcher Logo": "選擇啟動器 Logo"
|
||||
},
|
||||
"Select a color from the palette or use custom sliders": {
|
||||
"Select a color from the palette or use custom sliders": ""
|
||||
"Select a color from the palette or use custom sliders": "從調色板中選取一個顏色,或使用滑條調整"
|
||||
},
|
||||
"Select a preset or drag the slider to customize": {
|
||||
"Select a preset or drag the slider to customize": ""
|
||||
"Select a preset or drag the slider to customize": "選擇上方預設選項或拉動滑條調整"
|
||||
},
|
||||
"Select a widget to add to the ": {
|
||||
"Select a widget to add to the ": "選擇一個部件加到 "
|
||||
@@ -1416,13 +1419,13 @@
|
||||
"Select an image file...": "選擇一張圖片..."
|
||||
},
|
||||
"Select font weight": {
|
||||
"Select font weight": "選擇字型寬度"
|
||||
"Select font weight": "選擇字體粗細"
|
||||
},
|
||||
"Select monitor to configure wallpaper": {
|
||||
"Select monitor to configure wallpaper": "選擇指定螢幕桌布"
|
||||
},
|
||||
"Select monospace font for process list and technical displays": {
|
||||
"Select monospace font for process list and technical displays": ""
|
||||
"Select monospace font for process list and technical displays": "寬字體用於處理程序列表和技術顯示"
|
||||
},
|
||||
"Select system font family": {
|
||||
"Select system font family": "選擇系統字體"
|
||||
@@ -1431,7 +1434,7 @@
|
||||
"Select system sound theme": "選擇系統音效主題"
|
||||
},
|
||||
"Select the palette algorithm used for wallpaper-based colors": {
|
||||
"Select the palette algorithm used for wallpaper-based colors": ""
|
||||
"Select the palette algorithm used for wallpaper-based colors": "請選擇調色板演算法,以桌布的顏色為基底。"
|
||||
},
|
||||
"Select which transitions to include in randomization": {
|
||||
"Select which transitions to include in randomization": "選擇要包含在隨機中的轉換效果"
|
||||
@@ -1446,7 +1449,7 @@
|
||||
"Set different wallpapers for each connected monitor": "為每個連接的螢幕設定不同的桌布"
|
||||
},
|
||||
"Set different wallpapers for light and dark mode": {
|
||||
"Set different wallpapers for light and dark mode": "為明暗模式設定不同的桌布"
|
||||
"Set different wallpapers for light and dark mode": "為淺色/深色主題設定不同的桌布"
|
||||
},
|
||||
"Settings": {
|
||||
"Settings": "設定"
|
||||
@@ -1454,6 +1457,9 @@
|
||||
"Shift+Del: Clear All • Esc: Close": {
|
||||
"Shift+Del: Clear All • Esc: Close": "Shift+Del: 清除所有 • Esc: 關閉"
|
||||
},
|
||||
"Show All Tags": {
|
||||
"Show All Tags": "顯示所有標籤"
|
||||
},
|
||||
"Show Confirmation on Power Actions": {
|
||||
"Show Confirmation on Power Actions": "顯示電源操作確認"
|
||||
},
|
||||
@@ -1461,7 +1467,7 @@
|
||||
"Show Dock": "顯示 Dock"
|
||||
},
|
||||
"Show Line Numbers": {
|
||||
"Show Line Numbers": ""
|
||||
"Show Line Numbers": "顯示行數"
|
||||
},
|
||||
"Show Power Actions": {
|
||||
"Show Power Actions": "顯示電源選項"
|
||||
@@ -1469,6 +1475,9 @@
|
||||
"Show Workspace Apps": {
|
||||
"Show Workspace Apps": "顯示工作區應用程式"
|
||||
},
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": {
|
||||
"Show all 9 tags instead of only occupied tags (DWL only)": "顯示所有 9 個標籤,而非僅顯示已佔用的標籤 (僅限 DWL)"
|
||||
},
|
||||
"Show on Last Display": {
|
||||
"Show on Last Display": "在最後顯示幕上顯示"
|
||||
},
|
||||
@@ -1524,7 +1533,7 @@
|
||||
"Sound Theme": "音效主題"
|
||||
},
|
||||
"Spacer": {
|
||||
"Spacer": ""
|
||||
"Spacer": "空白間隔"
|
||||
},
|
||||
"Spacing": {
|
||||
"Spacing": "間距"
|
||||
@@ -1563,7 +1572,7 @@
|
||||
"Switch User": "切換使用者"
|
||||
},
|
||||
"Sync Mode with Portal": {
|
||||
"Sync Mode with Portal": ""
|
||||
"Sync Mode with Portal": "透過 Portal 同步主題模式"
|
||||
},
|
||||
"Sync dark mode with settings portals for system-wide theme hints": {
|
||||
"Sync dark mode with settings portals for system-wide theme hints": "將暗模式與設定入口網站同步以取得系統範圍的主題提示"
|
||||
@@ -1584,7 +1593,7 @@
|
||||
"System Monitoring:": "系統監視器:"
|
||||
},
|
||||
"System Tray": {
|
||||
"System Tray": "系統任務欄"
|
||||
"System Tray": "系統匣"
|
||||
},
|
||||
"System Update": {
|
||||
"System Update": "系統更新"
|
||||
@@ -1599,19 +1608,19 @@
|
||||
"System bar with widgets and system information": "帶有部件和系統資訊的系統欄"
|
||||
},
|
||||
"System notification area icons": {
|
||||
"System notification area icons": "系統通知區域圖示"
|
||||
"System notification area icons": "顯示常駐程式狀態圖示和系統通知"
|
||||
},
|
||||
"System toast notifications": {
|
||||
"System toast notifications": ""
|
||||
"System toast notifications": "系統快顯通知"
|
||||
},
|
||||
"System tray icons": {
|
||||
"System tray icons": "系統任務欄圖示"
|
||||
"System tray icons": "系統匣圖示"
|
||||
},
|
||||
"System update custom command": {
|
||||
"System update custom command": "自訂系統更新指令"
|
||||
},
|
||||
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": {
|
||||
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": ""
|
||||
"Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select": "Tab/Shift+Tab: 切換焦點 • ←→↑↓: 切換焦點 • Enter/Space: 選擇"
|
||||
},
|
||||
"Technical Details": {
|
||||
"Technical Details": "技術細節"
|
||||
@@ -1629,7 +1638,7 @@
|
||||
"The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.": "DMS_SOCKET 環境變數未設定或套接字不可用。自動插件管理需要 DMS_SOCKET。"
|
||||
},
|
||||
"The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": {
|
||||
"The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "以下設定將修改您的 GTK 和 Qt 設定。如果您希望保留目前配置,請備份它們(qt5ct.conf|qt6ct.conf 和 ~/.config/gtk-3.0|gtk-4.0)。"
|
||||
"The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).": "以下設定將修改您的 GTK 和 Qt 設定。如果您希望保留目前配置,請備份 (qt5ct.conf|qt6ct.conf 和 ~/.config/gtk-3.0|gtk-4.0)。"
|
||||
},
|
||||
"Theme & Colors": {
|
||||
"Theme & Colors": "主題和顏色"
|
||||
@@ -1659,7 +1668,7 @@
|
||||
"To update, run the following command:": "若要更新,請執行以下命令:"
|
||||
},
|
||||
"Toast Messages": {
|
||||
"Toast Messages": ""
|
||||
"Toast Messages": "快顯通知"
|
||||
},
|
||||
"Today": {
|
||||
"Today": "今天"
|
||||
@@ -1680,7 +1689,7 @@
|
||||
"Top Section": "上方區塊"
|
||||
},
|
||||
"Transition Effect": {
|
||||
"Transition Effect": "過渡效果"
|
||||
"Transition Effect": "切換動畫效果"
|
||||
},
|
||||
"Turn off monitors after": {
|
||||
"Turn off monitors after": "關閉螢幕之後"
|
||||
@@ -1734,7 +1743,7 @@
|
||||
"Use animated wave progress bars for media playback": "在媒體播放使用動畫波浪進度條"
|
||||
},
|
||||
"Use automatic location detection (geoclue2)": {
|
||||
"Use automatic location detection (geoclue2)": ""
|
||||
"Use automatic location detection (geoclue2)": "使用自動位置偵測(geoclue2)"
|
||||
},
|
||||
"Use custom command for update your system": {
|
||||
"Use custom command for update your system": "使用自訂指令更新您的系統"
|
||||
@@ -1773,7 +1782,7 @@
|
||||
"VPN status and quick connect": "VPN 狀態和快速連接"
|
||||
},
|
||||
"Vibrant palette with playful saturation.": {
|
||||
"Vibrant palette with playful saturation.": ""
|
||||
"Vibrant palette with playful saturation.": "色彩鮮明且飽和度活潑的調色板。"
|
||||
},
|
||||
"Visibility": {
|
||||
"Visibility": "能見度"
|
||||
@@ -1788,7 +1797,7 @@
|
||||
"Volume Changed": "音量改變"
|
||||
},
|
||||
"Volume, brightness, and other system OSDs": {
|
||||
"Volume, brightness, and other system OSDs": ""
|
||||
"Volume, brightness, and other system OSDs": "音量、亮度及其他系統OSD"
|
||||
},
|
||||
"Wallpaper": {
|
||||
"Wallpaper": "桌布"
|
||||
@@ -1833,7 +1842,7 @@
|
||||
"Widgets": "部件"
|
||||
},
|
||||
"Wind": {
|
||||
"Wind": "風"
|
||||
"Wind": "風速"
|
||||
},
|
||||
"Window Scrolling": {
|
||||
"Window Scrolling": "視窗滾動"
|
||||
|
||||
@@ -853,6 +853,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Compositor",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Configuration activated",
|
||||
"translation": "",
|
||||
@@ -3156,13 +3163,6 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Scroll through windows, rather than workspaces",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Search file contents",
|
||||
"translation": "",
|
||||
@@ -3331,6 +3331,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show All Tags",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show Confirmation on Power Actions",
|
||||
"translation": "",
|
||||
@@ -3366,6 +3373,13 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show all 9 tags instead of only occupied tags (DWL only)",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Show on Last Display",
|
||||
"translation": "",
|
||||
@@ -4206,13 +4220,6 @@
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Window Scrolling",
|
||||
"translation": "",
|
||||
"context": "",
|
||||
"reference": "",
|
||||
"comment": ""
|
||||
},
|
||||
{
|
||||
"term": "Workspace",
|
||||
"translation": "",
|
||||
|
||||
Reference in New Issue
Block a user