1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

dankbar: support multiple bars and per-display bars

- Migrate settings to v2
  - Up to 4 bars
  - Per-bar settings instead of global
This commit is contained in:
bbedward
2025-11-22 15:28:06 -05:00
parent 4f32376f22
commit a3a27e07fa
69 changed files with 5567 additions and 3846 deletions

View File

@@ -9,155 +9,167 @@ Singleton {
property var currentPopoutsByScreen: ({})
property var currentPopoutTriggers: ({})
function showPopout(popout) {
if (!popout || !popout.screen) return
signal popoutOpening
signal popoutChanged
const screenName = popout.screen.name
function showPopout(popout) {
if (!popout || !popout.screen)
return;
popoutOpening();
const screenName = popout.screen.name;
for (const otherScreenName in currentPopoutsByScreen) {
const otherPopout = currentPopoutsByScreen[otherScreenName]
if (!otherPopout || otherPopout === popout) continue
const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout || otherPopout === popout)
continue;
if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false
otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false
otherPopout.notificationHistoryVisible = false;
} else {
otherPopout.close()
otherPopout.close();
}
}
currentPopoutsByScreen[screenName] = popout
ModalManager.closeAllModalsExcept(null)
TrayMenuManager.closeAllMenus()
currentPopoutsByScreen[screenName] = popout;
popoutChanged();
ModalManager.closeAllModalsExcept(null);
}
function hidePopout(popout) {
if (!popout || !popout.screen) return
const screenName = popout.screen.name
if (!popout || !popout.screen)
return;
const screenName = popout.screen.name;
if (currentPopoutsByScreen[screenName] === popout) {
currentPopoutsByScreen[screenName] = null
currentPopoutTriggers[screenName] = null
currentPopoutsByScreen[screenName] = null;
currentPopoutTriggers[screenName] = null;
popoutChanged();
}
}
function closeAllPopouts() {
for (const screenName in currentPopoutsByScreen) {
const popout = currentPopoutsByScreen[screenName]
if (!popout) continue
const popout = currentPopoutsByScreen[screenName];
if (!popout)
continue;
if (popout.dashVisible !== undefined) {
popout.dashVisible = false
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false
popout.notificationHistoryVisible = false;
} else {
popout.close()
popout.close();
}
}
currentPopoutsByScreen = {}
currentPopoutsByScreen = {};
}
function getActivePopout(screen) {
if (!screen) return null
return currentPopoutsByScreen[screen.name] || null
if (!screen)
return null;
return currentPopoutsByScreen[screen.name] || null;
}
function requestPopout(popout, tabIndex, triggerSource) {
if (!popout || !popout.screen) return
if (!popout || !popout.screen)
return;
const screenName = popout.screen.name;
const currentPopout = currentPopoutsByScreen[screenName];
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex;
const screenName = popout.screen.name
const currentPopout = currentPopoutsByScreen[screenName]
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex
const willOpen = !(currentPopout === popout && popout.shouldBeVisible && triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId);
if (willOpen) {
popoutOpening();
}
let justClosedSamePopout = false
let justClosedSamePopout = false;
for (const otherScreenName in currentPopoutsByScreen) {
if (otherScreenName === screenName) continue
const otherPopout = currentPopoutsByScreen[otherScreenName]
if (!otherPopout) continue
if (otherScreenName === screenName)
continue;
const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout)
continue;
if (otherPopout === popout) {
justClosedSamePopout = true
justClosedSamePopout = true;
}
if (otherPopout.dashVisible !== undefined) {
otherPopout.dashVisible = false
otherPopout.dashVisible = false;
} else if (otherPopout.notificationHistoryVisible !== undefined) {
otherPopout.notificationHistoryVisible = false
otherPopout.notificationHistoryVisible = false;
} else {
otherPopout.close()
otherPopout.close();
}
}
if (currentPopout && currentPopout !== popout) {
if (currentPopout.dashVisible !== undefined) {
currentPopout.dashVisible = false
currentPopout.dashVisible = false;
} else if (currentPopout.notificationHistoryVisible !== undefined) {
currentPopout.notificationHistoryVisible = false
currentPopout.notificationHistoryVisible = false;
} else {
currentPopout.close()
currentPopout.close();
}
}
if (currentPopout === popout && popout.shouldBeVisible) {
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
if (popout.dashVisible !== undefined) {
popout.dashVisible = false
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false
popout.notificationHistoryVisible = false;
} else {
popout.close()
popout.close();
}
return
return;
}
if (triggerId === undefined) {
if (popout.dashVisible !== undefined) {
popout.dashVisible = false
popout.dashVisible = false;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = false
popout.notificationHistoryVisible = false;
} else {
popout.close()
popout.close();
}
return
return;
}
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
popout.currentTabIndex = tabIndex
popout.currentTabIndex = tabIndex;
}
currentPopoutTriggers[screenName] = triggerId
return
currentPopoutTriggers[screenName] = triggerId;
}
currentPopoutTriggers[screenName] = triggerId
currentPopoutsByScreen[screenName] = popout
currentPopoutTriggers[screenName] = triggerId;
currentPopoutsByScreen[screenName] = popout;
popoutChanged();
if (tabIndex !== undefined && popout.currentTabIndex !== undefined) {
popout.currentTabIndex = tabIndex
popout.currentTabIndex = tabIndex;
}
if (currentPopout !== popout) {
ModalManager.closeAllModalsExcept(null)
ModalManager.closeAllModalsExcept(null);
}
TrayMenuManager.closeAllMenus()
if (justClosedSamePopout) {
Qt.callLater(() => {
if (popout.dashVisible !== undefined) {
popout.dashVisible = true
popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true
popout.notificationHistoryVisible = true;
} else {
popout.open()
popout.open();
}
})
});
} else {
if (popout.dashVisible !== undefined) {
popout.dashVisible = true
popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true
popout.notificationHistoryVisible = true;
} else {
popout.open()
popout.open();
}
}
}

View File

@@ -67,13 +67,21 @@ Singleton {
})
out.streamFinished.connect(function() {
capturedOut = out.text || ""
try {
capturedOut = out.text || ""
} catch (e) {
capturedOut = ""
}
outSeen = true
maybeComplete()
})
err.streamFinished.connect(function() {
capturedErr = err.text || ""
try {
capturedErr = err.text || ""
} catch (e) {
capturedErr = ""
}
errSeen = true
maybeComplete()
})
@@ -88,8 +96,14 @@ Singleton {
function maybeComplete() {
if (!exitSeen || !outSeen || !errSeen) return
timeoutTimer.stop()
if (typeof entry.callback === "function") {
try { entry.callback(capturedOut, exitCodeValue) } catch (e) { console.warn("runCommand callback error:", e) }
if (entry && entry.callback && typeof entry.callback === "function") {
try {
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : ""
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1
entry.callback(safeOutput, safeExitCode)
} catch (e) {
console.warn("runCommand callback error for command:", entry.command, "Error:", e)
}
}
try { proc.destroy() } catch (_) {}
try { timeoutTimer.destroy() } catch (_) {}

View File

@@ -15,7 +15,7 @@ import "settings/SettingsStore.js" as Store
Singleton {
id: root
readonly property int settingsConfigVersion: 1
readonly property int settingsConfigVersion: 2
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
@@ -70,8 +70,6 @@ Singleton {
property string matugenScheme: "scheme-tonal-spot"
property bool runUserMatugenTemplates: true
property string matugenTargetMonitor: ""
property real dankBarTransparency: 1.0
property real dankBarWidgetTransparency: 1.0
property real popupTransparency: 1.0
property real dockTransparency: 1
property string widgetBackgroundColor: "sch"
@@ -168,10 +166,6 @@ Singleton {
property string lockDateFormat: ""
property int mediaSize: 1
property var dankBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
property var dankBarCenterWidgets: ["music", "clock", "weather"]
property var dankBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
property var dankBarWidgetOrder: []
property string appLauncherViewMode: "list"
property string spotlightModalViewMode: "list"
@@ -268,39 +262,9 @@ Singleton {
property string dockIndicatorStyle: "circle"
property bool notificationOverlayEnabled: false
property bool dankBarAutoHide: false
property int dankBarAutoHideDelay: 250
property bool dankBarOpenOnOverview: false
property bool dankBarVisible: true
property int overviewRows: 2
property int overviewColumns: 5
property real overviewScale: 0.16
property real dankBarSpacing: 4
property real dankBarBottomGap: 0
property real dankBarInnerPadding: 4
property int dankBarPosition: SettingsData.Position.Top
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
onDankBarAutoHideDelayChanged: saveSettings()
property bool dankBarSquareCorners: false
property bool dankBarNoBackground: false
property bool dankBarGothCornersEnabled: false
property bool dankBarGothCornerRadiusOverride: false
property real dankBarGothCornerRadiusValue: 12
property bool dankBarBorderEnabled: false
property string dankBarBorderColor: "surfaceText"
property real dankBarBorderOpacity: 1.0
property real dankBarBorderThickness: 1
onDankBarGothCornerRadiusOverrideChanged: saveSettings()
onDankBarGothCornerRadiusValueChanged: saveSettings()
onDankBarBorderColorChanged: saveSettings()
onDankBarBorderOpacityChanged: saveSettings()
onDankBarBorderThicknessChanged: saveSettings()
property bool popupGapsAuto: true
property int popupGapsManual: 4
property bool modalDarkenBackground: true
@@ -343,6 +307,39 @@ Singleton {
property var screenPreferences: ({})
property var showOnLastDisplay: ({})
property var barConfigs: [{
id: "default",
name: "Main Bar",
enabled: true,
position: 0,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: ["music", "clock", "weather"],
rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: 4,
innerPadding: 4,
bottomGap: 0,
transparency: 1.0,
widgetTransparency: 1.0,
squareCorners: false,
noBackground: false,
gothCornersEnabled: false,
gothCornerRadiusOverride: false,
gothCornerRadiusValue: 12,
borderEnabled: false,
borderColor: "surfaceText",
borderOpacity: 1.0,
borderThickness: 1,
fontScale: 1.0,
autoHide: false,
autoHideDelay: 250,
openOnOverview: false,
visible: true,
popupGapsAuto: true,
popupGapsManual: 4
}]
signal forceDankBarLayoutRefresh
signal forceDockLayoutRefresh
signal widgetDataChanged
@@ -456,7 +453,8 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
applyStoredTheme: applyStoredTheme,
regenSystemThemes: regenSystemThemes,
updateNiriLayout: updateNiriLayout,
applyStoredIconTheme: applyStoredIconTheme
applyStoredIconTheme: applyStoredIconTheme,
updateBarConfigs: updateBarConfigs
})
function set(key, value) {
@@ -467,24 +465,22 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
_loading = true
try {
const txt = settingsFile.text()
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null
let obj = (txt && txt.trim()) ? JSON.parse(txt) : null
const oldVersion = obj?.configVersion ?? 0
if (oldVersion < settingsConfigVersion) {
const migrated = Store.migrateToVersion(obj, settingsConfigVersion)
if (migrated) {
settingsFile.setText(JSON.stringify(migrated, null, 2))
obj = migrated
}
}
Store.parse(root, obj)
const shouldMigrate = Store.migrate(root, obj)
applyStoredTheme()
applyStoredIconTheme()
Processes.detectIcons()
Processes.detectQtTools()
if (obj && obj.configVersion === undefined) {
const cleaned = Store.cleanup(txt)
if (cleaned) {
settingsFile.setText(cleaned)
}
saveSettings()
}
if (shouldMigrate) {
savePluginSettings()
saveSettings()
}
} catch (e) {
console.warn("SettingsData: Failed to load settings:", e.message)
applyStoredTheme()
@@ -548,7 +544,10 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
}
function initializeListModels() {
Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, dankBarLeftWidgets, dankBarCenterWidgets, dankBarRightWidgets)
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
Lists.init(leftWidgetsModel, centerWidgetsModel, rightWidgetsModel, defaultBar.leftWidgets, defaultBar.centerWidgets, defaultBar.rightWidgets)
}
}
function updateListModel(listModel, order) {
@@ -579,77 +578,302 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
}
function getPopupYPosition(barHeight) {
const gothOffset = dankBarGothCornersEnabled ? Theme.cornerRadius : 0
return barHeight + dankBarSpacing + dankBarBottomGap - gothOffset + Theme.popupDistance
const defaultBar = barConfigs[0] || getBarConfig("default")
const gothOffset = defaultBar?.gothCornersEnabled ? Theme.cornerRadius : 0
const spacing = defaultBar?.spacing ?? 4
const bottomGap = defaultBar?.bottomGap ?? 0
return barHeight + spacing + bottomGap - gothOffset + Theme.popupDistance
}
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth) {
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth, barSpacing, barPosition, barConfig) {
const screenX = screen ? screen.x : 0
const screenY = screen ? screen.y : 0
const relativeX = globalPos.x - screenX
const relativeY = globalPos.y - screenY
const defaultBar = barConfigs[0] || getBarConfig("default")
const spacing = barSpacing !== undefined ? barSpacing : (defaultBar?.spacing ?? 4)
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0)
if (dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right) {
const useAutoGaps = (barConfig && barConfig.popupGapsAuto !== undefined) ? barConfig.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true)
const manualGapValue = (barConfig && barConfig.popupGapsManual !== undefined) ? barConfig.popupGapsManual : (defaultBar?.popupGapsManual ?? 4)
const popupGap = useAutoGaps ? Math.max(4, spacing) : manualGapValue
switch (position) {
case SettingsData.Position.Left:
return {
"x": relativeY,
"y": barThickness + dankBarSpacing + Theme.popupDistance,
"x": barThickness + spacing + popupGap,
"y": relativeY,
"width": widgetWidth
}
case SettingsData.Position.Right:
return {
"x": (screen?.width || 0) - (barThickness + spacing + popupGap),
"y": relativeY,
"width": widgetWidth
}
case SettingsData.Position.Bottom:
return {
"x": relativeX,
"y": (screen?.height || 0) - (barThickness + spacing + bottomGap + popupGap),
"width": widgetWidth
}
default:
return {
"x": relativeX,
"y": barThickness + spacing + bottomGap + popupGap,
"width": widgetWidth
}
}
return {
"x": relativeX,
"y": barThickness + dankBarSpacing + Theme.popupDistance,
"width": widgetWidth
}
}
function getBarBounds(screen, barThickness) {
function getAdjacentBarInfo(screen, barPosition, barConfig) {
if (!screen || !barConfig) {
return { "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 }
}
if (barConfig.autoHide) {
return { "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 }
}
const enabledBars = getEnabledBarConfigs()
const defaultBar = barConfigs[0] || getBarConfig("default")
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
let topBar = 0
let bottomBar = 0
let leftBar = 0
let rightBar = 0
for (let i = 0; i < enabledBars.length; i++) {
const other = enabledBars[i]
if (other.id === barConfig.id) continue
if (other.autoHide) continue
const otherScreens = other.screenPreferences || ["all"]
const barScreens = barConfig.screenPreferences || ["all"]
const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") ||
otherScreens.some(s => isScreenInPreferences(screen, [s]))
if (!onSameScreen) continue
const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4)
const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4)
const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing
const useAutoGaps = other.popupGapsAuto !== undefined ? other.popupGapsAuto : (defaultBar?.popupGapsAuto ?? true)
const manualGap = other.popupGapsManual !== undefined ? other.popupGapsManual : (defaultBar?.popupGapsManual ?? 4)
const popupGap = useAutoGaps ? Math.max(4, otherSpacing) : manualGap
switch (other.position) {
case SettingsData.Position.Top:
topBar = Math.max(topBar, otherThickness + popupGap)
break
case SettingsData.Position.Bottom:
bottomBar = Math.max(bottomBar, otherThickness + popupGap)
break
case SettingsData.Position.Left:
leftBar = Math.max(leftBar, otherThickness + popupGap)
break
case SettingsData.Position.Right:
rightBar = Math.max(rightBar, otherThickness + popupGap)
break
}
}
return { "topBar": topBar, "bottomBar": bottomBar, "leftBar": leftBar, "rightBar": rightBar }
}
function getBarBounds(screen, barThickness, barPosition, barConfig) {
if (!screen) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
const wingRadius = dankBarGothCornerRadiusOverride ? dankBarGothCornerRadiusValue : Theme.cornerRadius
const wingSize = dankBarGothCornersEnabled ? Math.max(0, wingRadius) : 0
const defaultBar = barConfigs[0] || getBarConfig("default")
const wingRadius = (defaultBar?.gothCornerRadiusOverride ?? false) ? (defaultBar?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius
const wingSize = (defaultBar?.gothCornersEnabled ?? false) ? Math.max(0, wingRadius) : 0
const screenWidth = screen.width
const screenHeight = screen.height
const position = barPosition !== undefined ? barPosition : (defaultBar?.position ?? SettingsData.Position.Top)
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : (defaultBar?.bottomGap ?? 0)) : (defaultBar?.bottomGap ?? 0)
if (dankBarPosition === SettingsData.Position.Top) {
return {
"x": 0,
"y": 0,
"width": screenWidth,
"height": barThickness + dankBarSpacing + wingSize,
"wingSize": wingSize
}
} else if (dankBarPosition === SettingsData.Position.Bottom) {
return {
"x": 0,
"y": screenHeight - barThickness - dankBarSpacing - wingSize,
"width": screenWidth,
"height": barThickness + dankBarSpacing + wingSize,
"wingSize": wingSize
}
} else if (dankBarPosition === SettingsData.Position.Left) {
return {
"x": 0,
"y": 0,
"width": barThickness + dankBarSpacing + wingSize,
"height": screenHeight,
"wingSize": wingSize
}
} else if (dankBarPosition === SettingsData.Position.Right) {
return {
"x": screenWidth - barThickness - dankBarSpacing - wingSize,
"y": 0,
"width": barThickness + dankBarSpacing + wingSize,
"height": screenHeight,
"wingSize": wingSize
let topOffset = 0
let bottomOffset = 0
let leftOffset = 0
let rightOffset = 0
if (barConfig) {
const enabledBars = getEnabledBarConfigs()
for (let i = 0; i < enabledBars.length; i++) {
const other = enabledBars[i]
if (other.id === barConfig.id) continue
const otherScreens = other.screenPreferences || ["all"]
const barScreens = barConfig.screenPreferences || ["all"]
const onSameScreen = otherScreens.includes("all") || barScreens.includes("all") ||
otherScreens.some(s => isScreenInPreferences(screen, [s]))
if (!onSameScreen) continue
const otherSpacing = other.spacing !== undefined ? other.spacing : (defaultBar?.spacing ?? 4)
const otherPadding = other.innerPadding !== undefined ? other.innerPadding : (defaultBar?.innerPadding ?? 4)
const otherThickness = Math.max(26 + otherPadding * 0.6, Theme.barHeight - 4 - (8 - otherPadding)) + otherSpacing + wingSize
const otherBottomGap = other.bottomGap !== undefined ? other.bottomGap : (defaultBar?.bottomGap ?? 0)
switch (other.position) {
case SettingsData.Position.Top:
if (position === SettingsData.Position.Top && other.id < barConfig.id) {
topOffset += otherThickness // Simple stacking for same pos
} else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) {
topOffset = Math.max(topOffset, otherThickness)
}
break
case SettingsData.Position.Bottom:
if (position === SettingsData.Position.Bottom && other.id < barConfig.id) {
bottomOffset += (otherThickness + otherBottomGap)
} else if (position === SettingsData.Position.Left || position === SettingsData.Position.Right) {
bottomOffset = Math.max(bottomOffset, otherThickness + otherBottomGap)
}
break
case SettingsData.Position.Left:
if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) {
leftOffset = Math.max(leftOffset, otherThickness)
} else if (position === SettingsData.Position.Left && other.id < barConfig.id) {
leftOffset += otherThickness
}
break
case SettingsData.Position.Right:
if (position === SettingsData.Position.Top || position === SettingsData.Position.Bottom) {
rightOffset = Math.max(rightOffset, otherThickness)
} else if (position === SettingsData.Position.Right && other.id < barConfig.id) {
rightOffset += otherThickness
}
break
}
}
}
switch (position) {
case SettingsData.Position.Top:
return {
"x": leftOffset,
"y": topOffset + bottomGap,
"width": screenWidth - leftOffset - rightOffset,
"height": barThickness + wingSize,
"wingSize": wingSize
}
case SettingsData.Position.Bottom:
return {
"x": leftOffset,
"y": screenHeight - barThickness - wingSize - bottomGap - bottomOffset,
"width": screenWidth - leftOffset - rightOffset,
"height": barThickness + wingSize,
"wingSize": wingSize
}
case SettingsData.Position.Left:
return {
"x": 0,
"y": topOffset,
"width": barThickness + wingSize,
"height": screenHeight - topOffset - bottomOffset,
"wingSize": wingSize
}
case SettingsData.Position.Right:
return {
"x": screenWidth - barThickness - wingSize,
"y": topOffset,
"width": barThickness + wingSize,
"height": screenHeight - topOffset - bottomOffset,
"wingSize": wingSize
}
}
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
function updateBarConfigs() {
barConfigsChanged()
saveSettings()
}
function getBarConfig(barId) {
return barConfigs.find(cfg => cfg.id === barId) || null
}
function addBarConfig(config) {
const configs = JSON.parse(JSON.stringify(barConfigs))
configs.push(config)
barConfigs = configs
updateBarConfigs()
}
function updateBarConfig(barId, updates) {
const configs = JSON.parse(JSON.stringify(barConfigs))
const index = configs.findIndex(cfg => cfg.id === barId)
if (index === -1) return
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position
Object.assign(configs[index], updates)
barConfigs = configs
updateBarConfigs()
if (positionChanged) {
NotificationService.clearAllPopups()
}
}
function checkBarCollisions(barId) {
const bar = getBarConfig(barId)
if (!bar || !bar.enabled) return []
const conflicts = []
const enabledBars = getEnabledBarConfigs()
for (let i = 0; i < enabledBars.length; i++) {
const other = enabledBars[i]
if (other.id === barId) continue
const samePosition = bar.position === other.position
if (!samePosition) continue
const barScreens = bar.screenPreferences || ["all"]
const otherScreens = other.screenPreferences || ["all"]
const hasAll = barScreens.includes("all") || otherScreens.includes("all")
if (hasAll) {
conflicts.push({
barId: other.id,
barName: other.name,
reason: "Same position on all screens"
})
continue
}
const overlapping = barScreens.some(screen => otherScreens.includes(screen))
if (overlapping) {
conflicts.push({
barId: other.id,
barName: other.name,
reason: "Same position on overlapping screens"
})
}
}
return conflicts
}
function deleteBarConfig(barId) {
if (barId === "default") return
const configs = barConfigs.filter(cfg => cfg.id !== barId)
barConfigs = configs
updateBarConfigs()
}
function getEnabledBarConfigs() {
return barConfigs.filter(cfg => cfg.enabled)
}
function getScreenDisplayName(screen) {
if (!screen) return ""
if (displayNameMode === "model" && screen.model) {
@@ -686,6 +910,7 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
}
function sendTestNotifications() {
NotificationService.clearAllPopups()
sendTestNotification(0)
testNotifTimer1.start()
testNotifTimer2.start()
@@ -765,20 +990,22 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
function setShowDock(enabled) {
showDock = enabled
if (enabled && dockPosition === dankBarPosition) {
if (dankBarPosition === SettingsData.Position.Top) {
const defaultBar = barConfigs[0] || getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
if (enabled && dockPosition === barPos) {
if (barPos === SettingsData.Position.Top) {
setDockPosition(SettingsData.Position.Bottom)
return
}
if (dankBarPosition === SettingsData.Position.Bottom) {
if (barPos === SettingsData.Position.Bottom) {
setDockPosition(SettingsData.Position.Top)
return
}
if (dankBarPosition === SettingsData.Position.Left) {
if (barPos === SettingsData.Position.Left) {
setDockPosition(SettingsData.Position.Right)
return
}
if (dankBarPosition === SettingsData.Position.Right) {
if (barPos === SettingsData.Position.Right) {
setDockPosition(SettingsData.Position.Left)
return
}
@@ -788,16 +1015,18 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
function setDockPosition(position) {
dockPosition = position
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) {
const defaultBar = barConfigs[0] || getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
if (position === SettingsData.Position.Bottom && barPos === SettingsData.Position.Bottom && showDock) {
setDankBarPosition(SettingsData.Position.Top)
}
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) {
if (position === SettingsData.Position.Top && barPos === SettingsData.Position.Top && showDock) {
setDankBarPosition(SettingsData.Position.Bottom)
}
if (position === SettingsData.Position.Left && dankBarPosition === SettingsData.Position.Left && showDock) {
if (position === SettingsData.Position.Left && barPos === SettingsData.Position.Left && showDock) {
setDankBarPosition(SettingsData.Position.Right)
}
if (position === SettingsData.Position.Right && dankBarPosition === SettingsData.Position.Right && showDock) {
if (position === SettingsData.Position.Right && barPos === SettingsData.Position.Right && showDock) {
setDankBarPosition(SettingsData.Position.Left)
}
saveSettings()
@@ -805,14 +1034,19 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
}
function setDankBarSpacing(spacing) {
set("dankBarSpacing", spacing)
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { spacing: spacing })
}
if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
NiriService.generateNiriLayoutConfig()
}
}
function setDankBarPosition(position) {
dankBarPosition = position
const defaultBar = barConfigs[0] || getBarConfig("default")
if (!defaultBar) return
if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) {
setDockPosition(SettingsData.Position.Top)
return
@@ -829,34 +1063,45 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
setDockPosition(SettingsData.Position.Left)
return
}
saveSettings()
updateBarConfig(defaultBar.id, { position: position })
}
function setDankBarLeftWidgets(order) {
dankBarLeftWidgets = order
updateListModel(leftWidgetsModel, order)
saveSettings()
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { leftWidgets: order })
updateListModel(leftWidgetsModel, order)
}
}
function setDankBarCenterWidgets(order) {
dankBarCenterWidgets = order
updateListModel(centerWidgetsModel, order)
saveSettings()
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { centerWidgets: order })
updateListModel(centerWidgetsModel, order)
}
}
function setDankBarRightWidgets(order) {
dankBarRightWidgets = order
updateListModel(rightWidgetsModel, order)
saveSettings()
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { rightWidgets: order })
updateListModel(rightWidgetsModel, order)
}
}
function resetDankBarWidgetsToDefault() {
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]
var defaultCenter = ["music", "clock", "weather"]
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]
dankBarLeftWidgets = defaultLeft
dankBarCenterWidgets = defaultCenter
dankBarRightWidgets = defaultRight
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, {
leftWidgets: defaultLeft,
centerWidgets: defaultCenter,
rightWidgets: defaultRight
})
}
updateListModel(leftWidgetsModel, defaultLeft)
updateListModel(centerWidgetsModel, defaultCenter)
updateListModel(rightWidgetsModel, defaultRight)
@@ -876,7 +1121,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
showBattery = true
showControlCenterButton = true
showCapsLockIndicator = true
saveSettings()
}
function setWorkspaceNameIcon(workspaceName, iconData) {
@@ -900,8 +1144,10 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
}
function toggleDankBarVisible() {
dankBarVisible = !dankBarVisible
saveSettings()
const defaultBar = barConfigs[0] || getBarConfig("default")
if (defaultBar) {
updateBarConfig(defaultBar.id, { visible: !defaultBar.visible })
}
}
function toggleShowDock() {
@@ -1028,31 +1274,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
property bool pluginSettingsFileExists: false
IpcHandler {
function reveal(): string {
root.dankBarVisible = true
root.saveSettings()
return "BAR_SHOW_SUCCESS"
}
function hide(): string {
root.dankBarVisible = false
root.saveSettings()
return "BAR_HIDE_SUCCESS"
}
function toggle(): string {
root.toggleDankBarVisible()
return root.dankBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
}
function status(): string {
return root.dankBarVisible ? "visible" : "hidden"
}
target: "bar"
}
IpcHandler {
function reveal(): string {
root.setShowDock(true)

View File

@@ -15,6 +15,7 @@ import "StockThemes.js" as StockThemes
Singleton {
id: root
readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell"
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
@@ -22,7 +23,12 @@ Singleton {
readonly property real popupDistance: {
if (typeof SettingsData === "undefined")
return 4
return SettingsData.popupGapsAuto ? Math.max(4, SettingsData.dankBarSpacing) : SettingsData.popupGapsManual
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return 4
const useAuto = defaultBar.popupGapsAuto ?? true
const manualValue = defaultBar.popupGapsManual ?? 4
const spacing = defaultBar.spacing ?? 4
return useAuto ? Math.max(4, spacing) : manualValue
}
property string currentTheme: "blue"
@@ -465,7 +471,6 @@ Singleton {
property real iconSizeLarge: 32
property real panelTransparency: 0.85
property real widgetTransparency: typeof SettingsData !== "undefined" && SettingsData.dankBarWidgetTransparency !== undefined ? SettingsData.dankBarWidgetTransparency : 1.0
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0
function screenTransition() {
@@ -650,20 +655,6 @@ Singleton {
return isLightMode ? Qt.darker(baseColor, factor) : Qt.lighter(baseColor, factor)
}
property var widgetBackground: {
const colorMode = typeof SettingsData !== "undefined" ? SettingsData.widgetBackgroundColor : "sch"
switch (colorMode) {
case "s":
return Qt.rgba(surface.r, surface.g, surface.b, widgetTransparency)
case "sc":
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, widgetTransparency)
case "sch":
return Qt.rgba(surfaceContainerHigh.r, surfaceContainerHigh.g, surfaceContainerHigh.b, widgetTransparency)
case "sth":
default:
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, widgetTransparency)
}
}
property color widgetIconColor: {
if (typeof SettingsData === "undefined") {
@@ -703,9 +694,9 @@ Singleton {
return Math.round((barThickness / 48) * (iconSize + defaultOffset))
}
function barTextSize(barThickness) {
function barTextSize(barThickness, fontScale) {
const scale = barThickness / 48
const dankBarScale = (typeof SettingsData !== "undefined" ? SettingsData.dankBarFontScale : 1.0)
const dankBarScale = fontScale !== undefined ? fontScale : 1.0
if (scale <= 0.75)
return Math.round(fontSizeSmall * 0.9 * dankBarScale)
if (scale >= 1.25)

View File

@@ -6,26 +6,30 @@ import QtQuick
Singleton {
id: root
property var activeTrayBars: ({})
property var activeTrayMenus: ({})
function register(screenName, trayBar) {
if (!screenName || !trayBar) return
activeTrayBars[screenName] = trayBar
function registerMenu(screenName, menu) {
if (!screenName || !menu) return
const newMenus = Object.assign({}, activeTrayMenus)
newMenus[screenName] = menu
activeTrayMenus = newMenus
}
function unregister(screenName) {
function unregisterMenu(screenName) {
if (!screenName) return
delete activeTrayBars[screenName]
const newMenus = Object.assign({}, activeTrayMenus)
delete newMenus[screenName]
activeTrayMenus = newMenus
}
function closeAllMenus() {
for (const screenName in activeTrayBars) {
const trayBar = activeTrayBars[screenName]
if (!trayBar) continue
trayBar.menuOpen = false
if (trayBar.currentTrayMenu) {
trayBar.currentTrayMenu.showMenu = false
for (const screenName in activeTrayMenus) {
const menu = activeTrayMenus[screenName]
if (!menu) continue
if (typeof menu.close === "function") {
menu.close()
} else if (menu.showMenu !== undefined) {
menu.showMenu = false
}
}
}

View File

@@ -12,8 +12,6 @@ var SPEC = {
runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" },
matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" },
dankBarTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarTransparency"] },
dankBarWidgetTransparency: { def: 1.0, coerce: percentToUnit, migrate: ["topBarWidgetTransparency"] },
popupTransparency: { def: 1.0, coerce: percentToUnit },
dockTransparency: { def: 1.0, coerce: percentToUnit },
@@ -89,11 +87,6 @@ var SPEC = {
lockDateFormat: { def: "" },
mediaSize: { def: 1 },
dankBarLeftWidgets: { def: ["launcherButton", "workspaceSwitcher", "focusedWindow"], migrate: ["topBarLeftWidgets"] },
dankBarCenterWidgets: { def: ["music", "clock", "weather"], migrate: ["topBarCenterWidgets"] },
dankBarRightWidgets: { def: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], migrate: ["topBarRightWidgets"] },
dankBarWidgetOrder: { def: [] },
appLauncherViewMode: { def: "list" },
spotlightModalViewMode: { def: "list" },
sortAppsAlphabetically: { def: false },
@@ -127,7 +120,6 @@ var SPEC = {
monoFontFamily: { def: "Fira Code" },
fontWeight: { def: 400 },
fontScale: { def: 1.0 },
dankBarFontScale: { def: 1.0 },
notepadUseMonospace: { def: true },
notepadFontFamily: { def: "" },
@@ -177,31 +169,9 @@ var SPEC = {
dockIndicatorStyle: { def: "circle" },
notificationOverlayEnabled: { def: false },
dankBarAutoHide: { def: false, migrate: ["topBarAutoHide"] },
dankBarAutoHideDelay: { def: 250 },
dankBarOpenOnOverview: { def: false, migrate: ["topBarOpenOnOverview"] },
dankBarVisible: { def: true, migrate: ["topBarVisible"] },
overviewRows: { def: 2, persist: false },
overviewColumns: { def: 5, persist: false },
overviewScale: { def: 0.16, persist: false },
dankBarSpacing: { def: 4, migrate: ["topBarSpacing"], onChange: "updateNiriLayout" },
dankBarBottomGap: { def: 0, migrate: ["topBarBottomGap"] },
dankBarInnerPadding: { def: 4, migrate: ["topBarInnerPadding"] },
dankBarPosition: { def: 0, migrate: ["dankBarAtBottom", "topBarAtBottom"] },
dankBarIsVertical: { def: false, persist: false },
dankBarSquareCorners: { def: false, migrate: ["topBarSquareCorners"] },
dankBarNoBackground: { def: false, migrate: ["topBarNoBackground"] },
dankBarGothCornersEnabled: { def: false, migrate: ["topBarGothCornersEnabled"] },
dankBarGothCornerRadiusOverride: { def: false },
dankBarGothCornerRadiusValue: { def: 12 },
dankBarBorderEnabled: { def: false },
dankBarBorderColor: { def: "surfaceText" },
dankBarBorderOpacity: { def: 1.0 },
dankBarBorderThickness: { def: 1 },
popupGapsAuto: { def: true },
popupGapsManual: { def: 4 },
modalDarkenBackground: { def: true },
@@ -242,7 +212,40 @@ var SPEC = {
displayNameMode: { def: "system" },
screenPreferences: { def: {} },
showOnLastDisplay: { def: {} }
showOnLastDisplay: { def: {} },
barConfigs: { def: [{
id: "default",
name: "Main Bar",
enabled: true,
position: 0,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: ["music", "clock", "weather"],
rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: 4,
innerPadding: 4,
bottomGap: 0,
transparency: 1.0,
widgetTransparency: 1.0,
squareCorners: false,
noBackground: false,
gothCornersEnabled: false,
gothCornerRadiusOverride: false,
gothCornerRadiusValue: 12,
borderEnabled: false,
borderColor: "surfaceText",
borderOpacity: 1.0,
borderThickness: 1,
fontScale: 1.0,
autoHide: false,
autoHideDelay: 250,
openOnOverview: false,
visible: true,
popupGapsAuto: true,
popupGapsManual: 4
}], onChange: "updateBarConfigs" }
};
function getValidKeys() {

View File

@@ -5,6 +5,7 @@
function parse(root, jsonObj) {
var SPEC = SpecModule.SPEC;
for (var k in SPEC) {
if (k === "pluginSettings") continue;
var spec = SPEC[k];
root[k] = spec.def;
}
@@ -13,6 +14,7 @@ function parse(root, jsonObj) {
for (var k in jsonObj) {
if (!SPEC[k]) continue;
if (k === "pluginSettings") continue;
var raw = jsonObj[k];
var spec = SPEC[k];
var coerce = spec.coerce;
@@ -25,72 +27,93 @@ function toJson(root) {
var out = {};
for (var k in SPEC) {
if (SPEC[k].persist === false) continue;
if (k === "pluginSettings") continue;
out[k] = root[k];
}
out.configVersion = root.settingsConfigVersion;
return out;
}
function migrate(root, jsonObj) {
var SPEC = SpecModule.SPEC;
if (!jsonObj) return;
function migrateToVersion(obj, targetVersion) {
if (!obj) return null;
if (jsonObj.themeIndex !== undefined || jsonObj.themeIsDynamic !== undefined) {
var themeNames = ["blue", "deepBlue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral"];
if (jsonObj.themeIsDynamic) {
root.currentThemeName = "dynamic";
} else if (jsonObj.themeIndex >= 0 && jsonObj.themeIndex < themeNames.length) {
root.currentThemeName = themeNames[jsonObj.themeIndex];
}
console.info("Auto-migrated theme from index", jsonObj.themeIndex, "to", root.currentThemeName);
var settings = JSON.parse(JSON.stringify(obj));
var currentVersion = settings.configVersion || 0;
if (currentVersion >= targetVersion) {
return null;
}
if ((jsonObj.dankBarWidgetOrder && jsonObj.dankBarWidgetOrder.length > 0) ||
(jsonObj.topBarWidgetOrder && jsonObj.topBarWidgetOrder.length > 0)) {
if (jsonObj.dankBarLeftWidgets === undefined && jsonObj.dankBarCenterWidgets === undefined && jsonObj.dankBarRightWidgets === undefined) {
var widgetOrder = jsonObj.dankBarWidgetOrder || jsonObj.topBarWidgetOrder;
root.dankBarLeftWidgets = widgetOrder.filter(function(w) { return ["launcherButton", "workspaceSwitcher", "focusedWindow"].indexOf(w) >= 0; });
root.dankBarCenterWidgets = widgetOrder.filter(function(w) { return ["clock", "music", "weather"].indexOf(w) >= 0; });
root.dankBarRightWidgets = widgetOrder.filter(function(w) { return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].indexOf(w) >= 0; });
}
}
if (currentVersion < 2) {
console.info("Migrating settings from version", currentVersion, "to version 2");
if (jsonObj.useOSLogo !== undefined) {
root.launcherLogoMode = jsonObj.useOSLogo ? "os" : "apps";
root.launcherLogoColorOverride = jsonObj.osLogoColorOverride !== undefined ? jsonObj.osLogoColorOverride : "";
root.launcherLogoBrightness = jsonObj.osLogoBrightness !== undefined ? jsonObj.osLogoBrightness : 0.5;
root.launcherLogoContrast = jsonObj.osLogoContrast !== undefined ? jsonObj.osLogoContrast : 1;
}
if (jsonObj.mediaCompactMode !== undefined && jsonObj.mediaSize === undefined) {
root.mediaSize = jsonObj.mediaCompactMode ? 0 : 1;
}
for (var k in SPEC) {
var spec = SPEC[k];
if (!spec.migrate) continue;
for (var i = 0; i < spec.migrate.length; i++) {
var oldKey = spec.migrate[i];
if (jsonObj[oldKey] !== undefined && jsonObj[k] === undefined) {
var raw = jsonObj[oldKey];
var coerce = spec.coerce;
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
break;
if (settings.barConfigs === undefined) {
var position = 0;
if (settings.dankBarAtBottom !== undefined || settings.topBarAtBottom !== undefined) {
var atBottom = settings.dankBarAtBottom !== undefined ? settings.dankBarAtBottom : settings.topBarAtBottom;
position = atBottom ? 1 : 0;
} else if (settings.dankBarPosition !== undefined) {
position = settings.dankBarPosition;
}
var defaultConfig = {
id: "default",
name: "Main Bar",
enabled: true,
position: position,
screenPreferences: ["all"],
showOnLastDisplay: true,
leftWidgets: settings.dankBarLeftWidgets || ["launcherButton", "workspaceSwitcher", "focusedWindow"],
centerWidgets: settings.dankBarCenterWidgets || ["music", "clock", "weather"],
rightWidgets: settings.dankBarRightWidgets || ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"],
spacing: settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : 4,
innerPadding: settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : 4,
bottomGap: settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : 0,
transparency: settings.dankBarTransparency !== undefined ? settings.dankBarTransparency : 1.0,
widgetTransparency: settings.dankBarWidgetTransparency !== undefined ? settings.dankBarWidgetTransparency : 1.0,
squareCorners: settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : false,
noBackground: settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : false,
gothCornersEnabled: settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : false,
gothCornerRadiusOverride: settings.dankBarGothCornerRadiusOverride !== undefined ? settings.dankBarGothCornerRadiusOverride : false,
gothCornerRadiusValue: settings.dankBarGothCornerRadiusValue !== undefined ? settings.dankBarGothCornerRadiusValue : 12,
borderEnabled: settings.dankBarBorderEnabled !== undefined ? settings.dankBarBorderEnabled : false,
borderColor: settings.dankBarBorderColor || "surfaceText",
borderOpacity: settings.dankBarBorderOpacity !== undefined ? settings.dankBarBorderOpacity : 1.0,
borderThickness: settings.dankBarBorderThickness !== undefined ? settings.dankBarBorderThickness : 1,
fontScale: settings.dankBarFontScale !== undefined ? settings.dankBarFontScale : 1.0,
autoHide: settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : false,
autoHideDelay: settings.dankBarAutoHideDelay !== undefined ? settings.dankBarAutoHideDelay : 250,
openOnOverview: settings.dankBarOpenOnOverview !== undefined ? settings.dankBarOpenOnOverview : false,
visible: settings.dankBarVisible !== undefined ? settings.dankBarVisible : true,
popupGapsAuto: settings.popupGapsAuto !== undefined ? settings.popupGapsAuto : true,
popupGapsManual: settings.popupGapsManual !== undefined ? settings.popupGapsManual : 4
};
settings.barConfigs = [defaultConfig];
var legacyKeys = [
"dankBarLeftWidgets", "dankBarCenterWidgets", "dankBarRightWidgets",
"dankBarWidgetOrder", "dankBarAutoHide", "dankBarAutoHideDelay",
"dankBarOpenOnOverview", "dankBarVisible", "dankBarSpacing",
"dankBarBottomGap", "dankBarInnerPadding", "dankBarPosition",
"dankBarSquareCorners", "dankBarNoBackground", "dankBarGothCornersEnabled",
"dankBarGothCornerRadiusOverride", "dankBarGothCornerRadiusValue",
"dankBarBorderEnabled", "dankBarBorderColor", "dankBarBorderOpacity",
"dankBarBorderThickness", "popupGapsAuto", "popupGapsManual",
"dankBarAtBottom", "topBarAtBottom", "dankBarTransparency", "dankBarWidgetTransparency"
];
for (var i = 0; i < legacyKeys.length; i++) {
delete settings[legacyKeys[i]];
}
console.info("Migrated single bar settings to barConfigs");
}
settings.configVersion = 2;
}
if (jsonObj.dankBarAtBottom !== undefined || jsonObj.topBarAtBottom !== undefined) {
var atBottom = jsonObj.dankBarAtBottom !== undefined ? jsonObj.dankBarAtBottom : jsonObj.topBarAtBottom;
root.dankBarPosition = atBottom ? 1 : 0;
}
if (jsonObj.pluginSettings !== undefined) {
root.pluginSettings = jsonObj.pluginSettings;
return true;
}
return false;
return settings;
}
function cleanup(fileText) {
@@ -104,7 +127,6 @@ function cleanup(fileText) {
for (var key in settings) {
if (validKeys.indexOf(key) < 0) {
console.log("SettingsData: Removing unused key:", key);
delete settings[key];
needsSave = true;
}

View File

@@ -66,38 +66,32 @@ Item {
id: lock
}
Loader {
id: dankBarLoader
asynchronous: false
Repeater {
id: dankBarRepeater
model: ScriptModel {
values: SettingsData.barConfigs
}
property var currentPosition: SettingsData.dankBarPosition
property bool initialized: false
property var hyprlandOverviewLoaderRef: hyprlandOverviewLoader
sourceComponent: DankBar {
hyprlandOverviewLoader: dankBarLoader.hyprlandOverviewLoaderRef
delegate: Loader {
id: barLoader
active: modelData.enabled
asynchronous: false
onColorPickerRequested: {
if (colorPickerModal.shouldBeVisible) {
colorPickerModal.close()
} else {
colorPickerModal.show()
sourceComponent: DankBar {
barConfig: modelData
hyprlandOverviewLoader: dankBarRepeater.hyprlandOverviewLoaderRef
onColorPickerRequested: {
if (colorPickerModal.shouldBeVisible) {
colorPickerModal.close()
} else {
colorPickerModal.show()
}
}
}
}
Component.onCompleted: {
initialized = true
}
onCurrentPositionChanged: {
if (!initialized)
return
const component = sourceComponent
sourceComponent = null
sourceComponent = component
}
}
Loader {
@@ -126,7 +120,6 @@ Item {
if (!initialized)
return
console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock")
const comp = sourceComponent
sourceComponent = null
sourceComponent = comp
@@ -137,7 +130,7 @@ Item {
id: dankDashPopoutLoader
active: false
asynchronous: true
asynchronous: false
sourceComponent: Component {
DankDashPopout {
@@ -513,7 +506,7 @@ Item {
dankDashPopoutLoader: dankDashPopoutLoader
notepadSlideoutVariants: notepadSlideoutVariants
hyprKeybindsModalLoader: hyprKeybindsModalLoader
dankBarLoader: dankBarLoader
dankBarRepeater: dankBarRepeater
hyprlandOverviewLoader: hyprlandOverviewLoader
}

View File

@@ -1,5 +1,4 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import qs.Common
@@ -14,36 +13,43 @@ Item {
required property var dankDashPopoutLoader
required property var notepadSlideoutVariants
required property var hyprKeybindsModalLoader
required property var dankBarLoader
required property var dankBarRepeater
required property var hyprlandOverviewLoader
function getFirstBar() {
if (!root.dankBarRepeater || root.dankBarRepeater.count === 0)
return null;
const firstLoader = root.dankBarRepeater.itemAt(0);
return firstLoader ? firstLoader.item : null;
}
IpcHandler {
function open() {
root.powerMenuModalLoader.active = true
root.powerMenuModalLoader.active = true;
if (root.powerMenuModalLoader.item)
root.powerMenuModalLoader.item.openCentered()
root.powerMenuModalLoader.item.openCentered();
return "POWERMENU_OPEN_SUCCESS"
return "POWERMENU_OPEN_SUCCESS";
}
function close() {
if (root.powerMenuModalLoader.item)
root.powerMenuModalLoader.item.close()
root.powerMenuModalLoader.item.close();
return "POWERMENU_CLOSE_SUCCESS"
return "POWERMENU_CLOSE_SUCCESS";
}
function toggle() {
root.powerMenuModalLoader.active = true
root.powerMenuModalLoader.active = true;
if (root.powerMenuModalLoader.item) {
if (root.powerMenuModalLoader.item.shouldBeVisible) {
root.powerMenuModalLoader.item.close()
root.powerMenuModalLoader.item.close();
} else {
root.powerMenuModalLoader.item.openCentered()
root.powerMenuModalLoader.item.openCentered();
}
}
return "POWERMENU_TOGGLE_SUCCESS"
return "POWERMENU_TOGGLE_SUCCESS";
}
target: "powermenu"
@@ -51,26 +57,26 @@ Item {
IpcHandler {
function open(): string {
root.processListModalLoader.active = true
root.processListModalLoader.active = true;
if (root.processListModalLoader.item)
root.processListModalLoader.item.show()
root.processListModalLoader.item.show();
return "PROCESSLIST_OPEN_SUCCESS"
return "PROCESSLIST_OPEN_SUCCESS";
}
function close(): string {
if (root.processListModalLoader.item)
root.processListModalLoader.item.hide()
root.processListModalLoader.item.hide();
return "PROCESSLIST_CLOSE_SUCCESS"
return "PROCESSLIST_CLOSE_SUCCESS";
}
function toggle(): string {
root.processListModalLoader.active = true
root.processListModalLoader.active = true;
if (root.processListModalLoader.item)
root.processListModalLoader.item.toggle()
root.processListModalLoader.item.toggle();
return "PROCESSLIST_TOGGLE_SUCCESS"
return "PROCESSLIST_TOGGLE_SUCCESS";
}
target: "processlist"
@@ -78,27 +84,33 @@ Item {
IpcHandler {
function open(): string {
if (root.dankBarLoader.item) {
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen()
return "CONTROL_CENTER_OPEN_SUCCESS"
const bar = root.getFirstBar();
if (bar) {
bar.triggerControlCenterOnFocusedScreen();
return "CONTROL_CENTER_OPEN_SUCCESS";
}
return "CONTROL_CENTER_OPEN_FAILED"
return "CONTROL_CENTER_OPEN_FAILED";
}
function close(): string {
if (root.controlCenterLoader.item) {
root.controlCenterLoader.item.close()
return "CONTROL_CENTER_CLOSE_SUCCESS"
function hide(): string {
if (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) {
root.controlCenterLoader.item.close();
return "CONTROL_CENTER_HIDE_SUCCESS";
}
return "CONTROL_CENTER_CLOSE_FAILED"
return "CONTROL_CENTER_HIDE_FAILED";
}
function toggle(): string {
if (root.dankBarLoader.item) {
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen()
return "CONTROL_CENTER_TOGGLE_SUCCESS"
const bar = root.getFirstBar();
if (bar) {
bar.triggerControlCenterOnFocusedScreen();
return "CONTROL_CENTER_TOGGLE_SUCCESS";
}
return "CONTROL_CENTER_TOGGLE_FAILED"
return "CONTROL_CENTER_TOGGLE_FAILED";
}
function status(): string {
return (root.controlCenterLoader.item && root.controlCenterLoader.item.shouldBeVisible) ? "visible" : "hidden";
}
target: "control-center"
@@ -106,55 +118,56 @@ Item {
IpcHandler {
function open(tab: string): string {
root.dankDashPopoutLoader.active = true
root.dankDashPopoutLoader.active = true;
if (root.dankDashPopoutLoader.item) {
switch (tab.toLowerCase()) {
case "media":
root.dankDashPopoutLoader.item.currentTabIndex = 1
break
root.dankDashPopoutLoader.item.currentTabIndex = 1;
break;
case "weather":
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
break
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0;
break;
default:
root.dankDashPopoutLoader.item.currentTabIndex = 0
break
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_OPEN_SUCCESS"
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen);
root.dankDashPopoutLoader.item.dashVisible = true;
return "DASH_OPEN_SUCCESS";
}
return "DASH_OPEN_FAILED"
return "DASH_OPEN_FAILED";
}
function close(): string {
if (root.dankDashPopoutLoader.item) {
root.dankDashPopoutLoader.item.dashVisible = false
return "DASH_CLOSE_SUCCESS"
root.dankDashPopoutLoader.item.dashVisible = false;
return "DASH_CLOSE_SUCCESS";
}
return "DASH_CLOSE_FAILED"
return "DASH_CLOSE_FAILED";
}
function toggle(tab: string): string {
if (root.dankBarLoader.item && root.dankBarLoader.item.triggerWallpaperBrowserOnFocusedScreen()) {
const bar = root.getFirstBar();
if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
if (root.dankDashPopoutLoader.item) {
switch (tab.toLowerCase()) {
case "media":
root.dankDashPopoutLoader.item.currentTabIndex = 1
break
root.dankDashPopoutLoader.item.currentTabIndex = 1;
break;
case "wallpaper":
root.dankDashPopoutLoader.item.currentTabIndex = 2
break
root.dankDashPopoutLoader.item.currentTabIndex = 2;
break;
case "weather":
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0
break
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0;
break;
default:
root.dankDashPopoutLoader.item.currentTabIndex = 0
break
root.dankDashPopoutLoader.item.currentTabIndex = 0;
break;
}
}
return "DASH_TOGGLE_SUCCESS"
return "DASH_TOGGLE_SUCCESS";
}
return "DASH_TOGGLE_FAILED"
return "DASH_TOGGLE_FAILED";
}
target: "dash"
@@ -163,68 +176,68 @@ Item {
IpcHandler {
function getFocusedScreenName() {
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
return Hyprland.focusedWorkspace.monitor.name
return Hyprland.focusedWorkspace.monitor.name;
}
if (CompositorService.isNiri && NiriService.currentOutput) {
return NiriService.currentOutput
return NiriService.currentOutput;
}
return ""
return "";
}
function getActiveNotepadInstance() {
if (root.notepadSlideoutVariants.instances.length === 0) {
return null
return null;
}
if (root.notepadSlideoutVariants.instances.length === 1) {
return root.notepadSlideoutVariants.instances[0]
return root.notepadSlideoutVariants.instances[0];
}
var focusedScreen = getFocusedScreenName()
var focusedScreen = getFocusedScreenName();
if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) {
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
var slideout = root.notepadSlideoutVariants.instances[i]
var slideout = root.notepadSlideoutVariants.instances[i];
if (slideout.modelData && slideout.modelData.name === focusedScreen) {
return slideout
return slideout;
}
}
}
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
var slideout = root.notepadSlideoutVariants.instances[i]
var slideout = root.notepadSlideoutVariants.instances[i];
if (slideout.isVisible) {
return slideout
return slideout;
}
}
return root.notepadSlideoutVariants.instances[0]
return root.notepadSlideoutVariants.instances[0];
}
function open(): string {
var instance = getActiveNotepadInstance()
var instance = getActiveNotepadInstance();
if (instance) {
instance.show()
return "NOTEPAD_OPEN_SUCCESS"
instance.show();
return "NOTEPAD_OPEN_SUCCESS";
}
return "NOTEPAD_OPEN_FAILED"
return "NOTEPAD_OPEN_FAILED";
}
function close(): string {
var instance = getActiveNotepadInstance()
var instance = getActiveNotepadInstance();
if (instance) {
instance.hide()
return "NOTEPAD_CLOSE_SUCCESS"
instance.hide();
return "NOTEPAD_CLOSE_SUCCESS";
}
return "NOTEPAD_CLOSE_FAILED"
return "NOTEPAD_CLOSE_FAILED";
}
function toggle(): string {
var instance = getActiveNotepadInstance()
var instance = getActiveNotepadInstance();
if (instance) {
instance.toggle()
return "NOTEPAD_TOGGLE_SUCCESS"
instance.toggle();
return "NOTEPAD_TOGGLE_SUCCESS";
}
return "NOTEPAD_TOGGLE_FAILED"
return "NOTEPAD_TOGGLE_FAILED";
}
target: "notepad"
@@ -232,31 +245,31 @@ Item {
IpcHandler {
function toggle(): string {
SessionService.toggleIdleInhibit()
return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled"
SessionService.toggleIdleInhibit();
return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled";
}
function enable(): string {
SessionService.enableIdleInhibit()
return "Idle inhibit enabled"
SessionService.enableIdleInhibit();
return "Idle inhibit enabled";
}
function disable(): string {
SessionService.disableIdleInhibit()
return "Idle inhibit disabled"
SessionService.disableIdleInhibit();
return "Idle inhibit disabled";
}
function status(): string {
return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled"
return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled";
}
function reason(newReason: string): string {
if (!newReason) {
return `Current reason: ${SessionService.inhibitReason}`
return `Current reason: ${SessionService.inhibitReason}`;
}
SessionService.setInhibitReason(newReason)
return `Inhibit reason set to: ${newReason}`
SessionService.setInhibitReason(newReason);
return `Inhibit reason set to: ${newReason}`;
}
target: "inhibit"
@@ -264,42 +277,42 @@ Item {
IpcHandler {
function list(): string {
return MprisController.availablePlayers.map(p => p.identity).join("\n")
return MprisController.availablePlayers.map(p => p.identity).join("\n");
}
function play(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canPlay) {
MprisController.activePlayer.play()
MprisController.activePlayer.play();
}
}
function pause(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canPause) {
MprisController.activePlayer.pause()
MprisController.activePlayer.pause();
}
}
function playPause(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canTogglePlaying) {
MprisController.activePlayer.togglePlaying()
MprisController.activePlayer.togglePlaying();
}
}
function previous(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canGoPrevious) {
MprisController.activePlayer.previous()
MprisController.activePlayer.previous();
}
}
function next(): void {
if (MprisController.activePlayer && MprisController.activePlayer.canGoNext) {
MprisController.activePlayer.next()
MprisController.activePlayer.next();
}
}
function stop(): void {
if (MprisController.activePlayer) {
MprisController.activePlayer.stop()
MprisController.activePlayer.stop();
}
}
@@ -309,78 +322,78 @@ Item {
IpcHandler {
function toggle(provider: string): string {
if (!provider) {
return "ERROR: No provider specified"
return "ERROR: No provider specified";
}
KeybindsService.loadProvider(provider)
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProvider(provider);
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close()
root.hyprKeybindsModalLoader.item.close();
} else {
root.hyprKeybindsModalLoader.item.open()
root.hyprKeybindsModalLoader.item.open();
}
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`;
}
return `KEYBINDS_TOGGLE_FAILED: ${provider}`
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
}
function toggleWithPath(provider: string, path: string): string {
if (!provider) {
return "ERROR: No provider specified"
return "ERROR: No provider specified";
}
KeybindsService.loadProviderWithPath(provider, path)
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProviderWithPath(provider, path);
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close()
root.hyprKeybindsModalLoader.item.close();
} else {
root.hyprKeybindsModalLoader.item.open()
root.hyprKeybindsModalLoader.item.open();
}
return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`
return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`;
}
return `KEYBINDS_TOGGLE_FAILED: ${provider}`
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
}
function open(provider: string): string {
if (!provider) {
return "ERROR: No provider specified"
return "ERROR: No provider specified";
}
KeybindsService.loadProvider(provider)
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProvider(provider);
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open()
return `KEYBINDS_OPEN_SUCCESS: ${provider}`
root.hyprKeybindsModalLoader.item.open();
return `KEYBINDS_OPEN_SUCCESS: ${provider}`;
}
return `KEYBINDS_OPEN_FAILED: ${provider}`
return `KEYBINDS_OPEN_FAILED: ${provider}`;
}
function openWithPath(provider: string, path: string): string {
if (!provider) {
return "ERROR: No provider specified"
return "ERROR: No provider specified";
}
KeybindsService.loadProviderWithPath(provider, path)
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProviderWithPath(provider, path);
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open()
return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})`
root.hyprKeybindsModalLoader.item.open();
return `KEYBINDS_OPEN_SUCCESS: ${provider} (${path})`;
}
return `KEYBINDS_OPEN_FAILED: ${provider}`
return `KEYBINDS_OPEN_FAILED: ${provider}`;
}
function close(): string {
if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.close()
return "KEYBINDS_CLOSE_SUCCESS"
root.hyprKeybindsModalLoader.item.close();
return "KEYBINDS_CLOSE_SUCCESS";
}
return "KEYBINDS_CLOSE_FAILED"
return "KEYBINDS_CLOSE_FAILED";
}
target: "keybinds"
@@ -389,67 +402,67 @@ Item {
IpcHandler {
function openBinds(): string {
if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
KeybindsService.loadProvider("hyprland")
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProvider("hyprland");
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.open()
return "HYPR_KEYBINDS_OPEN_SUCCESS"
root.hyprKeybindsModalLoader.item.open();
return "HYPR_KEYBINDS_OPEN_SUCCESS";
}
return "HYPR_KEYBINDS_OPEN_FAILED"
return "HYPR_KEYBINDS_OPEN_FAILED";
}
function closeBinds(): string {
if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
if (root.hyprKeybindsModalLoader.item) {
root.hyprKeybindsModalLoader.item.close()
return "HYPR_KEYBINDS_CLOSE_SUCCESS"
root.hyprKeybindsModalLoader.item.close();
return "HYPR_KEYBINDS_CLOSE_SUCCESS";
}
return "HYPR_KEYBINDS_CLOSE_FAILED"
return "HYPR_KEYBINDS_CLOSE_FAILED";
}
function toggleBinds(): string {
if (!CompositorService.isHyprland) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
KeybindsService.loadProvider("hyprland")
root.hyprKeybindsModalLoader.active = true
KeybindsService.loadProvider("hyprland");
root.hyprKeybindsModalLoader.active = true;
if (root.hyprKeybindsModalLoader.item) {
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
root.hyprKeybindsModalLoader.item.close()
root.hyprKeybindsModalLoader.item.close();
} else {
root.hyprKeybindsModalLoader.item.open()
root.hyprKeybindsModalLoader.item.open();
}
return "HYPR_KEYBINDS_TOGGLE_SUCCESS"
return "HYPR_KEYBINDS_TOGGLE_SUCCESS";
}
return "HYPR_KEYBINDS_TOGGLE_FAILED"
return "HYPR_KEYBINDS_TOGGLE_FAILED";
}
function toggleOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen
return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS"
root.hyprlandOverviewLoader.item.overviewOpen = !root.hyprlandOverviewLoader.item.overviewOpen;
return root.hyprlandOverviewLoader.item.overviewOpen ? "OVERVIEW_OPEN_SUCCESS" : "OVERVIEW_CLOSE_SUCCESS";
}
function closeOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
root.hyprlandOverviewLoader.item.overviewOpen = false
return "OVERVIEW_CLOSE_SUCCESS"
root.hyprlandOverviewLoader.item.overviewOpen = false;
return "OVERVIEW_CLOSE_SUCCESS";
}
function openOverview(): string {
if (!CompositorService.isHyprland || !root.hyprlandOverviewLoader.item) {
return "HYPR_NOT_AVAILABLE"
return "HYPR_NOT_AVAILABLE";
}
root.hyprlandOverviewLoader.item.overviewOpen = true
return "OVERVIEW_OPEN_SUCCESS"
root.hyprlandOverviewLoader.item.overviewOpen = true;
return "OVERVIEW_OPEN_SUCCESS";
}
target: "hypr"
@@ -457,12 +470,63 @@ Item {
IpcHandler {
function wallpaper(): string {
if (root.dankBarLoader.item && root.dankBarLoader.item.triggerWallpaperBrowserOnFocusedScreen()) {
return "SUCCESS: Toggled wallpaper browser"
const bar = root.getFirstBar();
if (bar && bar.triggerWallpaperBrowserOnFocusedScreen()) {
return "SUCCESS: Toggled wallpaper browser";
}
return "ERROR: Failed to toggle wallpaper browser"
return "ERROR: Failed to toggle wallpaper browser";
}
target: "dankdash"
}
IpcHandler {
function reveal(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
SettingsData.updateBarConfig(bar.id, {
visible: true
});
return `BAR_${index}_SHOW_SUCCESS`;
}
function hide(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
SettingsData.updateBarConfig(bar.id, {
visible: false
});
return `BAR_${index}_HIDE_SUCCESS`;
}
function toggle(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
const newVisible = !(bar.visible ?? true);
SettingsData.updateBarConfig(bar.id, {
visible: newVisible
});
return newVisible ? `BAR_${index}_SHOW_SUCCESS` : `BAR_${index}_HIDE_SUCCESS`;
}
function status(index: int): string {
const idx = index - 1;
if (idx < 0 || idx >= SettingsData.barConfigs.length) {
return `BAR_${index}_NOT_FOUND`;
}
const bar = SettingsData.barConfigs[idx];
return (bar.visible ?? true) ? "visible" : "hidden";
}
target: "bar"
}
}

View File

@@ -192,8 +192,8 @@ DankModal {
positioning: parentBounds.width > 0 ? "custom" : "center"
customPosition: {
if (parentBounds.width > 0) {
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const barExclusionZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
const effectiveBarThickness = Math.max(26 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) * 0.6 + (SettingsData.barConfigs[0]?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (SettingsData.barConfigs[0]?.innerPadding ?? 4)))
const barExclusionZone = effectiveBarThickness + (SettingsData.barConfigs[0]?.spacing ?? 4) + (SettingsData.barConfigs[0]?.bottomGap ?? 0)
const screenW = parentScreen?.width ?? 1920
const screenH = parentScreen?.height ?? 1080
const margin = Theme.spacingL
@@ -201,8 +201,8 @@ DankModal {
let targetX = parentBounds.x + (parentBounds.width - width) / 2
let targetY = parentBounds.y + (parentBounds.height - height) / 2
const minY = SettingsData.dankBarPosition === SettingsData.Position.Top ? barExclusionZone + margin : margin
const maxY = SettingsData.dankBarPosition === SettingsData.Position.Bottom ? screenH - height - barExclusionZone - margin : screenH - height - margin
const minY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Top ? barExclusionZone + margin : margin
const maxY = (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Bottom ? screenH - height - barExclusionZone - margin : screenH - height - margin
targetY = Math.max(minY, Math.min(maxY, targetY))

View File

@@ -21,18 +21,8 @@ DankPopout {
open()
}
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: 520
popupHeight: 600
triggerX: Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 40
positioning: ""
screen: triggerScreen

View File

@@ -189,6 +189,7 @@ Variants {
MultiEffect {
anchors.fill: parent
source: currentWallpaper
visible: currentWallpaper.source !== ""
blurEnabled: true
blur: 0.8
blurMax: 75
@@ -199,6 +200,7 @@ Variants {
MultiEffect {
anchors.fill: parent
source: nextWallpaper
visible: nextWallpaper.source !== ""
blurEnabled: true
blur: 0.8
blurMax: 75

View File

@@ -51,10 +51,6 @@ DankPopout {
readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
function setTriggerPosition(x, y, width, section, screen) {
StateUtils.setTriggerPosition(root, x, y, width, section, screen)
}
function openWithSection(section) {
StateUtils.openWithSection(root, section)
}
@@ -70,8 +66,8 @@ DankPopout {
const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400
return Math.min(maxHeight, contentHeight)
}
triggerX: (triggerScreen?.width ?? 1920) - 600 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerX: 0
triggerY: 0
triggerWidth: 80
positioning: ""
screen: triggerScreen

View File

@@ -8,15 +8,17 @@ Item {
required property var barWindow
required property var axis
required property var barConfig
anchors.fill: parent
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0)
anchors.rightMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0)
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 bool gothEnabled: barConfig?.gothCornersEnabled ?? false
anchors.leftMargin: -(gothEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0)
anchors.rightMargin: -(gothEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0)
anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0)
anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0)
readonly property real dpr: CompositorService.getScreenScale(barWindow.screen)
@@ -65,8 +67,8 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr)
property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
onWingChanged: root.requestRepaint()
onRtChanged: root.requestRepaint()
@@ -83,6 +85,8 @@ Item {
Connections {
target: barWindow
function on_BgColorChanged() { root.requestRepaint() }
function onGothCornersEnabledChanged() { root.requestRepaint() }
function onWingtipsRadiusChanged() { root.requestRepaint() }
}
Connections {
@@ -91,12 +95,6 @@ Item {
function onSurfaceContainerChanged() { root.requestRepaint() }
}
Connections {
target: SettingsData
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
}
onPaint: {
const ctx = getContext("2d")
const W = barWindow.isVertical ? correctHeight : correctWidth
@@ -104,10 +102,11 @@ Item {
const R = wing
const RT = rt
const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
const barPos = barConfig?.position ?? 0
const isTop = barPos === SettingsData.Position.Top
const isBottom = barPos === SettingsData.Position.Bottom
const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
function drawTopPath() {
ctx.beginPath()
@@ -168,8 +167,8 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr)
property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0
onWingChanged: root.requestRepaint()
@@ -188,6 +187,8 @@ Item {
Connections {
target: barWindow
function on_BgColorChanged() { root.requestRepaint() }
function onGothCornersEnabledChanged() { root.requestRepaint() }
function onWingtipsRadiusChanged() { root.requestRepaint() }
}
Connections {
@@ -196,12 +197,6 @@ Item {
function onSurfaceChanged() { root.requestRepaint() }
}
Connections {
target: SettingsData
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
}
onPaint: {
const ctx = getContext("2d")
const W = barWindow.isVertical ? correctHeight : correctWidth
@@ -209,10 +204,11 @@ Item {
const R = wing
const RT = rt
const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
const barPos = barConfig?.position ?? 0
const isTop = barPos === SettingsData.Position.Top
const isBottom = barPos === SettingsData.Position.Bottom
const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
function drawTopPath() {
ctx.beginPath()
@@ -265,7 +261,7 @@ Item {
Canvas {
id: barBorder
anchors.fill: parent
visible: SettingsData.dankBarBorderEnabled
visible: barConfig?.borderEnabled ?? false
renderTarget: Canvas.FramebufferObject
renderStrategy: Canvas.Cooperative
@@ -273,9 +269,9 @@ Item {
readonly property real correctHeight: Theme.px(root.height, dpr)
canvasSize: Qt.size(correctWidth, correctHeight)
property real wing: SettingsData.dankBarGothCornersEnabled ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.px(Theme.cornerRadius, dpr)
property bool borderEnabled: SettingsData.dankBarBorderEnabled
property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0
property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr)
property bool borderEnabled: barConfig?.borderEnabled ?? false
antialiasing: rt > 0 || wing > 0
@@ -302,15 +298,9 @@ Item {
}
Connections {
target: SettingsData
function onDankBarBorderColorChanged() { root.requestRepaint() }
function onDankBarBorderOpacityChanged() { root.requestRepaint() }
function onDankBarBorderThicknessChanged() { root.requestRepaint() }
function onDankBarSpacingChanged() { root.requestRepaint() }
function onDankBarSquareCornersChanged() { root.requestRepaint() }
function onDankBarTransparencyChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusOverrideChanged() { root.requestRepaint() }
function onDankBarGothCornerRadiusValueChanged() { root.requestRepaint() }
target: barWindow
function onGothCornersEnabledChanged() { root.requestRepaint() }
function onWingtipsRadiusChanged() { root.requestRepaint() }
}
onPaint: {
@@ -322,12 +312,13 @@ Item {
const R = wing
const RT = rt
const H = H_raw - (R > 0 ? R : 0)
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
const barPos = barConfig?.position ?? 0
const isTop = barPos === SettingsData.Position.Top
const isBottom = barPos === SettingsData.Position.Bottom
const isLeft = barPos === SettingsData.Position.Left
const isRight = barPos === SettingsData.Position.Right
const spacing = SettingsData.dankBarSpacing
const spacing = barConfig?.spacing ?? 4
const hasEdgeGap = spacing > 0 || RT > 0
ctx.reset()
@@ -345,14 +336,14 @@ Item {
ctx.rotate(Math.PI / 2)
}
const uiThickness = Math.max(1, SettingsData.dankBarBorderThickness ?? 1)
const uiThickness = Math.max(1, barConfig?.borderThickness ?? 1)
const devThickness = Math.max(1, Math.round(Theme.px(uiThickness, dpr)))
const key = SettingsData.dankBarBorderColor || "surfaceText"
const key = barConfig?.borderColor || "surfaceText"
const base = (key === "surfaceText") ? Theme.surfaceText
: (key === "primary") ? Theme.primary
: Theme.secondary
const color = Theme.withAlpha(base, SettingsData.dankBarBorderOpacity ?? 1.0)
const color = Theme.withAlpha(base, barConfig?.borderOpacity ?? 1.0)
ctx.globalCompositeOperation = "source-over"
ctx.fillStyle = color

View File

@@ -13,6 +13,8 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
@@ -25,238 +27,238 @@ Item {
function updateLayout() {
if ((isVertical ? height : width) <= 0 || !visible) {
return
return;
}
centerWidgets = []
totalWidgets = 0
totalSize = 0
centerWidgets = [];
totalWidgets = 0;
totalSize = 0;
let configuredWidgets = 0
let configuredMiddleWidget = null
let configuredLeftWidget = null
let configuredRightWidget = null
let configuredWidgets = 0;
let configuredMiddleWidget = null;
let configuredLeftWidget = null;
let configuredRightWidget = null;
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
const item = centerRepeater.itemAt(i);
if (item && getWidgetVisible(item.widgetId)) {
configuredWidgets++
configuredWidgets++;
}
}
const isOddConfigured = configuredWidgets % 2 === 1
const configuredMiddlePos = Math.floor(configuredWidgets / 2)
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1)
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2)
let currentConfigIndex = 0
const isOddConfigured = configuredWidgets % 2 === 1;
const configuredMiddlePos = Math.floor(configuredWidgets / 2);
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1);
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2);
let currentConfigIndex = 0;
for (var i = 0; i < centerRepeater.count; i++) {
const item = centerRepeater.itemAt(i)
const item = centerRepeater.itemAt(i);
if (item && getWidgetVisible(item.widgetId)) {
if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) {
configuredMiddleWidget = item.item
configuredMiddleWidget = item.item;
}
if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) {
configuredLeftWidget = item.item
configuredLeftWidget = item.item;
}
if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) {
configuredRightWidget = item.item
configuredRightWidget = item.item;
}
if (item.active && item.item) {
centerWidgets.push(item.item)
totalWidgets++
totalSize += isVertical ? item.item.height : item.item.width
centerWidgets.push(item.item);
totalWidgets++;
totalSize += isVertical ? item.item.height : item.item.width;
}
currentConfigIndex++
currentConfigIndex++;
}
}
if (totalWidgets === 0) {
return
return;
}
if (totalWidgets > 1) {
totalSize += spacing * (totalWidgets - 1)
totalSize += spacing * (totalWidgets - 1);
}
positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget)
positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
}
function positionWidgets(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget) {
const parentCenter = (isVertical ? height : width) / 2
const isOddConfigured = configuredWidgets % 2 === 1
const parentCenter = (isVertical ? height : width) / 2;
const isOddConfigured = configuredWidgets % 2 === 1;
centerWidgets.forEach(widget => {
if (isVertical) {
widget.anchors.verticalCenter = undefined
widget.anchors.verticalCenter = undefined;
} else {
widget.anchors.horizontalCenter = undefined
widget.anchors.horizontalCenter = undefined;
}
})
});
if (isOddConfigured && configuredMiddleWidget) {
const middleWidget = configuredMiddleWidget
const middleIndex = centerWidgets.indexOf(middleWidget)
const middleSize = isVertical ? middleWidget.height : middleWidget.width
const middleWidget = configuredMiddleWidget;
const middleIndex = centerWidgets.indexOf(middleWidget);
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
middleWidget.y = parentCenter - (middleSize / 2);
} else {
middleWidget.x = parentCenter - (middleSize / 2)
middleWidget.x = parentCenter - (middleSize / 2);
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size);
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
}
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
currentPos += spacing;
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
}
} else {
if (totalWidgets === 1) {
const widget = centerWidgets[0]
const size = isVertical ? widget.height : widget.width
const widget = centerWidgets[0];
const size = isVertical ? widget.height : widget.width;
if (isVertical) {
widget.y = parentCenter - (size / 2)
widget.y = parentCenter - (size / 2);
} else {
widget.x = parentCenter - (size / 2)
widget.x = parentCenter - (size / 2);
}
return
return;
}
if (!configuredLeftWidget || !configuredRightWidget) {
if (totalWidgets % 2 === 1) {
const middleIndex = Math.floor(totalWidgets / 2)
const middleWidget = centerWidgets[middleIndex]
const middleIndex = Math.floor(totalWidgets / 2);
const middleWidget = centerWidgets[middleIndex];
if (!middleWidget) {
return
return;
}
const middleSize = isVertical ? middleWidget.height : middleWidget.width
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
if (isVertical) {
middleWidget.y = parentCenter - (middleSize / 2)
middleWidget.y = parentCenter - (middleSize / 2);
} else {
middleWidget.x = parentCenter - (middleSize / 2)
middleWidget.x = parentCenter - (middleSize / 2);
}
let currentPos = isVertical ? middleWidget.y : middleWidget.x
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
for (var i = middleIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size);
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
}
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
for (var i = middleIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
currentPos += spacing;
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
}
} else {
const leftIndex = (totalWidgets / 2) - 1
const rightIndex = totalWidgets / 2
const fallbackLeft = centerWidgets[leftIndex]
const fallbackRight = centerWidgets[rightIndex]
const leftIndex = (totalWidgets / 2) - 1;
const rightIndex = totalWidgets / 2;
const fallbackLeft = centerWidgets[leftIndex];
const fallbackRight = centerWidgets[rightIndex];
if (!fallbackLeft || !fallbackRight) {
return
return;
}
const halfSpacing = spacing / 2
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width
const halfSpacing = spacing / 2;
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width;
if (isVertical) {
fallbackLeft.y = parentCenter - halfSpacing - leftSize
fallbackRight.y = parentCenter + halfSpacing
fallbackLeft.y = parentCenter - halfSpacing - leftSize;
fallbackRight.y = parentCenter + halfSpacing;
} else {
fallbackLeft.x = parentCenter - halfSpacing - leftSize
fallbackRight.x = parentCenter + halfSpacing
fallbackLeft.x = parentCenter - halfSpacing - leftSize;
fallbackRight.x = parentCenter + halfSpacing;
}
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x;
for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size);
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
}
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width)
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width);
for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
currentPos += spacing;
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
}
}
return
return;
}
const leftWidget = configuredLeftWidget
const rightWidget = configuredRightWidget
const leftIndex = centerWidgets.indexOf(leftWidget)
const rightIndex = centerWidgets.indexOf(rightWidget)
const halfSpacing = spacing / 2
const leftSize = isVertical ? leftWidget.height : leftWidget.width
const leftWidget = configuredLeftWidget;
const rightWidget = configuredRightWidget;
const leftIndex = centerWidgets.indexOf(leftWidget);
const rightIndex = centerWidgets.indexOf(rightWidget);
const halfSpacing = spacing / 2;
const leftSize = isVertical ? leftWidget.height : leftWidget.width;
if (isVertical) {
leftWidget.y = parentCenter - halfSpacing - leftSize
rightWidget.y = parentCenter + halfSpacing
leftWidget.y = parentCenter - halfSpacing - leftSize;
rightWidget.y = parentCenter + halfSpacing;
} else {
leftWidget.x = parentCenter - halfSpacing - leftSize
rightWidget.x = parentCenter + halfSpacing
leftWidget.x = parentCenter - halfSpacing - leftSize;
rightWidget.x = parentCenter + halfSpacing;
}
let currentPos = isVertical ? leftWidget.y : leftWidget.x
let currentPos = isVertical ? leftWidget.y : leftWidget.x;
for (var i = leftIndex - 1; i >= 0; i--) {
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos -= (spacing + size)
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
currentPos -= (spacing + size);
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
}
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width);
for (var i = rightIndex + 1; i < totalWidgets; i++) {
currentPos += spacing
currentPos += spacing;
if (isVertical) {
centerWidgets[i].y = currentPos
centerWidgets[i].y = currentPos;
} else {
centerWidgets[i].x = currentPos
centerWidgets[i].x = currentPos;
}
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
}
}
}
@@ -268,8 +270,8 @@ Item {
"cpuTemp": DgopService.dgopAvailable,
"gpuTemp": DgopService.dgopAvailable,
"network_speed_monitor": DgopService.dgopAvailable
}
return widgetVisibility[widgetId] ?? true
};
return widgetVisibility[widgetId] ?? true;
}
function getWidgetComponent(widgetId) {
@@ -302,19 +304,19 @@ Item {
"notepadButton": "notepadButtonComponent",
"colorPicker": "colorPickerComponent",
"systemUpdate": "systemUpdateComponent"
}
};
// For built-in components, get from components property
const componentKey = baseMap[widgetId]
const componentKey = baseMap[widgetId];
if (componentKey && root.components[componentKey]) {
return root.components[componentKey]
return root.components[componentKey];
}
// For plugin components, get from PluginService
var parts = widgetId.split(":")
var pluginId = parts[0]
let pluginComponents = PluginService.getWidgetComponents()
return pluginComponents[pluginId] || null
var parts = widgetId.split(":");
var pluginId = parts[0];
let pluginComponents = PluginService.getWidgetComponents();
return pluginComponents[pluginId] || null;
}
height: parent.height
@@ -329,24 +331,24 @@ Item {
}
Component.onCompleted: {
layoutTimer.restart()
layoutTimer.restart();
}
onWidthChanged: {
if (width > 0) {
layoutTimer.restart()
layoutTimer.restart();
}
}
onHeightChanged: {
if (height > 0) {
layoutTimer.restart()
layoutTimer.restart();
}
}
onVisibleChanged: {
if (visible && (isVertical ? height : width) > 0) {
layoutTimer.restart()
layoutTimer.restart();
}
}
@@ -354,146 +356,149 @@ Item {
id: centerRepeater
model: root.widgetsModel
Loader {
property string widgetId: model.widgetId
property var widgetData: model
property int spacerSize: model.size || 20
property var itemData: modelData
property string widgetId: itemData.widgetId
property var widgetData: itemData
property int spacerSize: itemData.size || 20
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
active: root.getWidgetVisible(model.widgetId) && (model.widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: root.getWidgetComponent(model.widgetId)
opacity: (model.enabled !== false) ? 1 : 0
active: root.getWidgetVisible(itemData.widgetId) && (itemData.widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: root.getWidgetComponent(itemData.widgetId)
opacity: (itemData.enabled !== false) ? 1 : 0
asynchronous: false
onLoaded: {
if (!item) {
return
return;
}
item.widthChanged.connect(() => layoutTimer.restart())
item.heightChanged.connect(() => layoutTimer.restart())
item.widthChanged.connect(() => {
if (layoutTimer)
layoutTimer.restart();
});
item.heightChanged.connect(() => {
if (layoutTimer)
layoutTimer.restart();
});
if (root.axis && "axis" in item) {
item.axis = Qt.binding(() => root.axis)
item.axis = Qt.binding(() => root.axis);
}
if (root.axis && "isVertical" in item) {
try {
item.isVertical = Qt.binding(() => root.axis.isVertical)
} catch (e) {
}
item.isVertical = Qt.binding(() => root.axis.isVertical);
} catch (e) {}
}
// Inject properties for plugin widgets
if ("section" in item) {
item.section = root.section
item.section = root.section;
}
if ("parentScreen" in item) {
item.parentScreen = Qt.binding(() => root.parentScreen)
item.parentScreen = Qt.binding(() => root.parentScreen);
}
if ("widgetThickness" in item) {
item.widgetThickness = Qt.binding(() => root.widgetThickness)
item.widgetThickness = Qt.binding(() => root.widgetThickness);
}
if ("barThickness" in item) {
item.barThickness = Qt.binding(() => root.barThickness)
item.barThickness = Qt.binding(() => root.barThickness);
}
if ("barSpacing" in item) {
item.barSpacing = Qt.binding(() => root.barSpacing);
}
if ("barConfig" in item) {
item.barConfig = Qt.binding(() => root.barConfig);
}
if ("sectionSpacing" in item) {
item.sectionSpacing = Qt.binding(() => root.spacing)
item.sectionSpacing = Qt.binding(() => root.spacing);
}
if ("isFirst" in item) {
item.isFirst = Qt.binding(() => {
for (var i = 0; i < centerRepeater.count; i++) {
const checkItem = centerRepeater.itemAt(i)
const checkItem = centerRepeater.itemAt(i);
if (checkItem && checkItem.active && checkItem.item) {
return checkItem.item === item
return checkItem.item === item;
}
}
return false
})
return false;
});
}
if ("isLast" in item) {
item.isLast = Qt.binding(() => {
for (var i = centerRepeater.count - 1; i >= 0; i--) {
const checkItem = centerRepeater.itemAt(i)
const checkItem = centerRepeater.itemAt(i);
if (checkItem && checkItem.active && checkItem.item) {
return checkItem.item === item
return checkItem.item === item;
}
}
return false
})
return false;
});
}
if ("isLeftBarEdge" in item) {
item.isLeftBarEdge = false
item.isLeftBarEdge = false;
}
if ("isRightBarEdge" in item) {
item.isRightBarEdge = false
item.isRightBarEdge = false;
}
if ("isTopBarEdge" in item) {
item.isTopBarEdge = false
item.isTopBarEdge = false;
}
if ("isBottomBarEdge" in item) {
item.isBottomBarEdge = false
item.isBottomBarEdge = false;
}
if (item.pluginService !== undefined) {
var parts = model.widgetId.split(":")
var pluginId = parts[0]
var variantId = parts.length > 1 ? parts[1] : null
var parts = model.widgetId.split(":");
var pluginId = parts[0];
var variantId = parts.length > 1 ? parts[1] : null;
if (item.pluginId !== undefined) {
item.pluginId = pluginId
item.pluginId = pluginId;
}
if (item.variantId !== undefined) {
item.variantId = variantId
item.variantId = variantId;
}
if (item.variantData !== undefined && variantId) {
item.variantData = PluginService.getPluginVariantData(pluginId, variantId)
item.variantData = PluginService.getPluginVariantData(pluginId, variantId);
}
item.pluginService = PluginService
item.pluginService = PluginService;
}
if (item.popoutService !== undefined) {
item.popoutService = PopoutService
item.popoutService = PopoutService;
}
layoutTimer.restart()
layoutTimer.restart();
}
onActiveChanged: {
layoutTimer.restart()
layoutTimer.restart();
}
}
}
Connections {
target: widgetsModel
function onCountChanged() {
layoutTimer.restart()
}
}
// Listen for plugin changes and refresh components
Connections {
target: PluginService
function onPluginLoaded(pluginId) {
// Force refresh of component lookups
for (var i = 0; i < centerRepeater.count; i++) {
var item = centerRepeater.itemAt(i)
var item = centerRepeater.itemAt(i);
if (item && item.widgetId.startsWith(pluginId)) {
item.sourceComponent = root.getWidgetComponent(item.widgetId)
item.sourceComponent = root.getWidgetComponent(item.widgetId);
}
}
}
function onPluginUnloaded(pluginId) {
// Force refresh of component lookups
for (var i = 0; i < centerRepeater.count; i++) {
var item = centerRepeater.itemAt(i)
var item = centerRepeater.itemAt(i);
if (item && item.widgetId.startsWith(pluginId)) {
item.sourceComponent = root.getWidgetComponent(item.widgetId)
item.sourceComponent = root.getWidgetComponent(item.widgetId);
}
}
}
}
}
}

View File

@@ -1,92 +1,169 @@
import QtQuick
import QtQuick.Controls
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
import Quickshell.Services.SystemTray
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Modules
import qs.Modules.DankBar.Widgets
import qs.Modules.DankBar.Popouts
import qs.Services
import qs.Widgets
Item {
id: root
required property var barConfig
signal colorPickerRequested
signal barReady(var barConfig)
property alias barVariants: barVariants
property var hyprlandOverviewLoader: null
property bool systemTrayMenuOpen: false
property alias leftWidgetsModel: leftWidgetsModel
property alias centerWidgetsModel: centerWidgetsModel
property alias rightWidgetsModel: rightWidgetsModel
ScriptModel {
id: leftWidgetsModel
values: {
root.barConfig;
const leftWidgets = root.barConfig?.leftWidgets || [];
return leftWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
ScriptModel {
id: centerWidgetsModel
values: {
root.barConfig;
const centerWidgets = root.barConfig?.centerWidgets || [];
return centerWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
ScriptModel {
id: rightWidgetsModel
values: {
root.barConfig;
const rightWidgets = root.barConfig?.rightWidgets || [];
return rightWidgets.map((w, index) => {
if (typeof w === "string") {
return {
widgetId: w,
id: w + "_" + index,
enabled: true
};
} else {
const obj = Object.assign({}, w);
obj.widgetId = w.id || w.widgetId;
obj.id = (w.id || w.widgetId) + "_" + index;
obj.enabled = w.enabled !== false;
return obj;
}
});
}
}
function triggerControlCenterOnFocusedScreen() {
let focusedScreenName = ""
let focusedScreenName = "";
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
focusedScreenName = Hyprland.focusedWorkspace.monitor.name
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
} else if (CompositorService.isNiri && NiriService.currentOutput) {
focusedScreenName = NiriService.currentOutput
focusedScreenName = NiriService.currentOutput;
} else if (CompositorService.isSway) {
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
focusedScreenName = focusedWs?.monitor?.name || ""
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
focusedScreenName = focusedWs?.monitor?.name || "";
}
if (!focusedScreenName && barVariants.instances.length > 0) {
const firstBar = barVariants.instances[0]
firstBar.triggerControlCenter()
return true
const firstBar = barVariants.instances[0];
firstBar.triggerControlCenter();
return true;
}
for (var i = 0; i < barVariants.instances.length; i++) {
const barInstance = barVariants.instances[i]
const barInstance = barVariants.instances[i];
if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) {
barInstance.triggerControlCenter()
return true
barInstance.triggerControlCenter();
return true;
}
}
return false
return false;
}
function triggerWallpaperBrowserOnFocusedScreen() {
let focusedScreenName = ""
let focusedScreenName = "";
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
focusedScreenName = Hyprland.focusedWorkspace.monitor.name
focusedScreenName = Hyprland.focusedWorkspace.monitor.name;
} else if (CompositorService.isNiri && NiriService.currentOutput) {
focusedScreenName = NiriService.currentOutput
focusedScreenName = NiriService.currentOutput;
} else if (CompositorService.isSway) {
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true)
focusedScreenName = focusedWs?.monitor?.name || ""
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
focusedScreenName = focusedWs?.monitor?.name || "";
}
if (!focusedScreenName && barVariants.instances.length > 0) {
const firstBar = barVariants.instances[0]
firstBar.triggerWallpaperBrowser()
return true
const firstBar = barVariants.instances[0];
firstBar.triggerWallpaperBrowser();
return true;
}
for (var i = 0; i < barVariants.instances.length; i++) {
const barInstance = barVariants.instances[i]
const barInstance = barVariants.instances[i];
if (barInstance.modelData && barInstance.modelData.name === focusedScreenName) {
barInstance.triggerWallpaperBrowser()
return true
barInstance.triggerWallpaperBrowser();
return true;
}
}
return false
return false;
}
Variants {
id: barVariants
model: SettingsData.getFilteredScreens("dankBar")
model: {
const prefs = root.barConfig?.screenPreferences || ["all"];
if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) {
return Quickshell.screens;
}
const filtered = Quickshell.screens.filter(screen => SettingsData.isScreenInPreferences(screen, prefs));
if (filtered.length === 0 && root.barConfig?.showOnLastDisplay && Quickshell.screens.length === 1) {
return Quickshell.screens;
}
return filtered;
}
delegate: DankBarWindow {
rootWindow: root
barConfig: root.barConfig
leftWidgetsModel: root.leftWidgetsModel
centerWidgetsModel: root.centerWidgetsModel
rightWidgetsModel: root.rightWidgetsModel
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +1,113 @@
import QtQuick
import QtQuick.Controls
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
import Quickshell.Services.SystemTray
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Modules
import qs.Modules.DankBar.Widgets
import qs.Modules.DankBar.Popouts
import qs.Services
import qs.Widgets
PanelWindow {
id: barWindow
required property var rootWindow
required property var barConfig
property var modelData: item
property var hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null
property var leftWidgetsModel
property var centerWidgetsModel
property var rightWidgetsModel
property var controlCenterButtonRef: null
property var clockButtonRef: null
function triggerControlCenter() {
controlCenterLoader.active = true
controlCenterLoader.active = true;
if (!controlCenterLoader.item) {
return
return;
}
if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) {
const globalPos = controlCenterButtonRef.mapToGlobal(0, 0)
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width)
const section = controlCenterButtonRef.section || "right"
controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen)
const globalPos = controlCenterButtonRef.mapToGlobal(0, 0);
// Calculate barPosition from axis.edge
const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width, barConfig?.spacing ?? 4, barPosition, barConfig);
const section = controlCenterButtonRef.section || "right";
controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig);
} else {
controlCenterLoader.item.triggerScreen = barWindow.screen
controlCenterLoader.item.triggerScreen = barWindow.screen;
}
controlCenterLoader.item.toggle()
controlCenterLoader.item.toggle();
if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) {
NetworkService.scanWifi()
NetworkService.scanWifi();
}
}
function triggerWallpaperBrowser() {
dankDashPopoutLoader.active = true
dankDashPopoutLoader.active = true;
if (!dankDashPopoutLoader.item) {
return
return;
}
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)
// Calculate barPosition from axis.edge
const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
const section = clockButtonRef.section || "center";
// For center section widgets, use center section bounds for DankDash centering
let triggerPos, triggerWidth;
if (section === "center") {
const centerSection = barWindow.isVertical ? (barWindow.axis?.edge === "left" ? topBarContent.vCenterSection : topBarContent.vCenterSection) : topBarContent.hCenterSection;
if (centerSection) {
// For vertical bars, use center Y of section; for horizontal, use left edge
if (barWindow.isVertical) {
const centerY = centerSection.height / 2;
const centerGlobalPos = centerSection.mapToGlobal(0, centerY);
triggerPos = centerGlobalPos;
triggerWidth = centerSection.height;
} else {
// For horizontal bars, use left edge (DankPopout will center it)
const centerGlobalPos = centerSection.mapToGlobal(0, 0);
triggerPos = centerGlobalPos;
triggerWidth = centerSection.width;
}
} else {
triggerPos = clockButtonRef.visualContent.mapToGlobal(0, 0);
triggerWidth = clockButtonRef.visualWidth;
}
} else {
triggerPos = clockButtonRef.visualContent.mapToGlobal(0, 0);
triggerWidth = clockButtonRef.visualWidth;
}
const pos = SettingsData.getPopupTriggerPosition(triggerPos, barWindow.screen, barWindow.effectiveBarThickness, triggerWidth, barConfig?.spacing ?? 4, barPosition, barConfig);
dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen, barPosition, barWindow.effectiveBarThickness, barConfig?.spacing ?? 4, barConfig);
} else {
dankDashPopoutLoader.item.triggerScreen = barWindow.screen
dankDashPopoutLoader.item.triggerScreen = barWindow.screen;
}
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2)
PopoutManager.requestPopout(dankDashPopoutLoader.item, 2, (barConfig?.id ?? "default") + "-2");
}
readonly property var dBarLayer: {
switch (Quickshell.env("DMS_DANKBAR_LAYER")) {
case "bottom":
return WlrLayer.Bottom
return WlrLayer.Bottom;
case "overlay":
return WlrLayer.Overlay
return WlrLayer.Overlay;
case "background":
return WlrLayer.background
return WlrLayer.background;
default:
return WlrLayer.Top
return WlrLayer.Top;
}
}
WlrLayershell.layer: dBarLayer
WlrLayershell.layer: {
if ((barConfig?.autoHide ?? false) && topBarCore.reveal) {
return WlrLayer.Overlay;
}
return dBarLayer;
}
WlrLayershell.namespace: "dms:bar"
signal colorPickerRequested
@@ -92,39 +119,134 @@ PanelWindow {
AxisContext {
id: axis
edge: {
switch (SettingsData.dankBarPosition) {
switch (barConfig?.position ?? 0) {
case SettingsData.Position.Top:
return "top"
return "top";
case SettingsData.Position.Bottom:
return "bottom"
return "bottom";
case SettingsData.Position.Left:
return "left"
return "left";
case SettingsData.Position.Right:
return "right"
return "right";
default:
return "top"
return "top";
}
}
}
readonly property bool isVertical: axis.isVertical
property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled
property real wingtipsRadius: SettingsData.dankBarGothCornerRadiusOverride ? SettingsData.dankBarGothCornerRadiusValue : Theme.cornerRadius
property bool gothCornersEnabled: barConfig?.gothCornersEnabled ?? false
property real wingtipsRadius: barConfig?.gothCornerRadiusOverride ? (barConfig?.gothCornerRadiusValue ?? 12) : Theme.cornerRadius
readonly property real _wingR: Math.max(0, wingtipsRadius)
readonly property color _surfaceContainer: Theme.surfaceContainer
readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency
readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? (barConfig?.transparency ?? 1.0)
readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen)
property string screenName: modelData.name
readonly property int notificationCount: NotificationService.notifications.length
readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4)))
readonly property real widgetThickness: Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6)
readonly property bool hasAdjacentTopBar: {
if (barConfig?.autoHide ?? false)
return false;
if (!isVertical)
return false;
return SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Top && bc.position !== 0)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
}
readonly property bool hasAdjacentBottomBar: {
if (barConfig?.autoHide ?? false)
return false;
if (!isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Bottom && bc.position !== 1)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
readonly property bool hasAdjacentLeftBar: {
if (barConfig?.autoHide ?? false)
return false;
if (isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Left && bc.position !== 2)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
readonly property bool hasAdjacentRightBar: {
if (barConfig?.autoHide ?? false)
return false;
if (isVertical)
return false;
const result = SettingsData.barConfigs.some(bc => {
if (!bc.enabled || bc.id === barConfig?.id)
return false;
if (bc.autoHide)
return false;
if (!(bc.visible ?? true))
return false;
if (bc.position !== SettingsData.Position.Right && bc.position !== 3)
return false;
const onThisScreen = bc.screenPreferences.includes(screenName) || bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all");
if (!onThisScreen)
return false;
if (bc.showOnLastDisplay && screenName !== barWindow.screen.name)
return false;
return true;
});
return result;
}
screen: modelData
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + (barConfig?.spacing ?? 4) + ((barConfig?.gothCornersEnabled ?? false) ? _wingR : 0), _dpr) : 0
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + (barConfig?.spacing ?? 4) + ((barConfig?.gothCornersEnabled ?? false) ? _wingR : 0), _dpr) : 0
color: "transparent"
property var nativeInhibitor: null
@@ -132,18 +254,18 @@ PanelWindow {
Component.onCompleted: {
if (SettingsData.forceStatusBarLayoutRefresh) {
SettingsData.forceStatusBarLayoutRefresh.connect(() => {
Qt.callLater(() => {
stackContainer.visible = false
Qt.callLater(() => {
stackContainer.visible = true
})
})
})
Qt.callLater(() => {
stackContainer.visible = false;
Qt.callLater(() => {
stackContainer.visible = true;
});
});
});
}
updateGpuTempConfig()
updateGpuTempConfig();
inhibitorInitTimer.start()
inhibitorInitTimer.start();
}
Timer {
@@ -152,7 +274,7 @@ PanelWindow {
repeat: false
onTriggered: {
if (SessionService.nativeInhibitorAvailable) {
createNativeInhibitor()
createNativeInhibitor();
}
}
}
@@ -160,32 +282,35 @@ PanelWindow {
Connections {
target: PluginService
function onPluginLoaded(pluginId) {
console.info("DankBar: Plugin loaded:", pluginId)
SettingsData.widgetDataChanged()
console.info("DankBar: Plugin loaded:", pluginId);
SettingsData.widgetDataChanged();
}
function onPluginUnloaded(pluginId) {
console.info("DankBar: Plugin unloaded:", pluginId)
SettingsData.widgetDataChanged()
console.info("DankBar: Plugin unloaded:", pluginId);
SettingsData.widgetDataChanged();
}
}
function updateGpuTempConfig() {
const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])]
const leftWidgets = barConfig?.leftWidgets || [];
const centerWidgets = barConfig?.centerWidgets || [];
const rightWidgets = barConfig?.rightWidgets || [];
const allWidgets = [...leftWidgets, ...centerWidgets, ...rightWidgets];
const hasGpuTempWidget = allWidgets.some(widget => {
const widgetId = typeof widget === "string" ? widget : widget.id
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false)
return widgetId === "gpuTemp" && widgetEnabled
})
const widgetId = typeof widget === "string" ? widget : widget.id;
const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false);
return widgetId === "gpuTemp" && widgetEnabled;
});
DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled
DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled;
DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled;
DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled;
}
function createNativeInhibitor() {
if (!SessionService.nativeInhibitorAvailable) {
return
return;
}
try {
@@ -196,121 +321,88 @@ PanelWindow {
IdleInhibitor {
enabled: false
}
`
`;
nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor")
nativeInhibitor.window = barWindow
nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited)
nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor");
nativeInhibitor.window = barWindow;
nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited);
nativeInhibitor.enabledChanged.connect(function () {
console.log("DankBar: Native inhibitor enabled changed to:", nativeInhibitor.enabled)
if (SessionService.idleInhibited !== nativeInhibitor.enabled) {
SessionService.idleInhibited = nativeInhibitor.enabled
SessionService.inhibitorChanged()
SessionService.idleInhibited = nativeInhibitor.enabled;
SessionService.inhibitorChanged();
}
})
console.log("DankBar: Created native Wayland IdleInhibitor for", barWindow.screenName)
});
} catch (e) {
console.warn("DankBar: Failed to create native IdleInhibitor:", e)
nativeInhibitor = null
nativeInhibitor = null;
}
}
Connections {
function onDankBarLeftWidgetsChanged() {
barWindow.updateGpuTempConfig()
function onBarConfigChanged() {
barWindow.updateGpuTempConfig();
}
function onDankBarCenterWidgetsChanged() {
barWindow.updateGpuTempConfig()
}
function onDankBarRightWidgetsChanged() {
barWindow.updateGpuTempConfig()
}
target: SettingsData
target: rootWindow
}
Connections {
function onNvidiaGpuTempEnabledChanged() {
barWindow.updateGpuTempConfig()
barWindow.updateGpuTempConfig();
}
function onNonNvidiaGpuTempEnabledChanged() {
barWindow.updateGpuTempConfig()
barWindow.updateGpuTempConfig();
}
target: SessionData
}
Connections {
target: barWindow.screen
function onGeometryChanged() {
Qt.callLater(forceWidgetRefresh)
}
}
Timer {
id: refreshTimer
interval: 0
running: false
repeat: false
onTriggered: {
forceWidgetRefresh()
}
}
readonly property int barPos: barConfig?.position ?? 0
Connections {
target: axis
function onChanged() {
Qt.application.active
refreshTimer.restart()
}
}
anchors.top: !isVertical ? (barPos === SettingsData.Position.Top) : true
anchors.bottom: !isVertical ? (barPos === SettingsData.Position.Bottom) : true
anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left)
anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right)
anchors.top: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Top) : true
anchors.bottom: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom) : true
anchors.left: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Left)
anchors.right: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Right)
exclusiveZone: (!SettingsData.dankBarVisible || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap)
exclusiveZone: (!(barConfig?.visible ?? true) || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4) + (barConfig?.bottomGap ?? 0))
Item {
id: inputMask
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr)
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr)
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false)
readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow
readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide)
readonly property int maskThickness: showing ? barThickness : 1
x: {
if (!axis.isVertical) {
return 0
return 0;
} else {
switch (SettingsData.dankBarPosition) {
switch (barPos) {
case SettingsData.Position.Left:
return 0
return 0;
case SettingsData.Position.Right:
return parent.width - maskThickness
return parent.width - maskThickness;
default:
return 0
return 0;
}
}
}
y: {
if (axis.isVertical) {
return 0
return 0;
} else {
switch (SettingsData.dankBarPosition) {
switch (barPos) {
case SettingsData.Position.Top:
return 0
return 0;
case SettingsData.Position.Bottom:
return parent.height - maskThickness
return parent.height - maskThickness;
default:
return 0
return 0;
}
}
}
@@ -327,112 +419,97 @@ PanelWindow {
anchors.fill: parent
layer.enabled: true
property real backgroundTransparency: SettingsData.dankBarTransparency
property bool autoHide: SettingsData.dankBarAutoHide
property real backgroundTransparency: barConfig?.transparency ?? 1.0
property bool autoHide: barConfig?.autoHide ?? false
property bool revealSticky: false
Timer {
id: revealHold
interval: SettingsData.dankBarAutoHideDelay
interval: barConfig?.autoHideDelay ?? 250
repeat: false
onTriggered: topBarCore.revealSticky = false
onTriggered: {
if (!topBarMouseArea.containsMouse && !topBarCore.hasActivePopout) {
topBarCore.revealSticky = false;
}
}
}
property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dankBarOpenOnOverview || topBarMouseArea.containsMouse || hasActivePopout || revealSticky
return (barConfig?.openOnOverview ?? false) || topBarMouseArea.containsMouse || hasActivePopout || revealSticky;
}
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky)
return (barConfig?.visible ?? true) && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky);
}
readonly property bool hasActivePopout: {
const loaders = [{
"loader": appDrawerLoader,
"prop": "shouldBeVisible"
}, {
"loader": dankDashPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": processListPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": notificationCenterLoader,
"prop": "shouldBeVisible"
}, {
"loader": batteryPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": layoutPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": vpnPopoutLoader,
"prop": "shouldBeVisible"
}, {
"loader": controlCenterLoader,
"prop": "shouldBeVisible"
}, {
"loader": clipboardHistoryModalPopup,
"prop": "visible"
}, {
"loader": systemUpdateLoader,
"prop": "shouldBeVisible"
}]
return loaders.some(item => {
if (item.loader && item.loader.item) {
return item.loader.item[item.prop]
}
return false
}) || rootWindow.systemTrayMenuOpen
property bool hasActivePopout: false
onHasActivePopoutChanged: evaluateReveal()
Connections {
target: PopoutManager
function onPopoutChanged() {
const screenName = barWindow.screen.name;
const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
const trayOpen = rootWindow.systemTrayMenuOpen;
topBarCore.hasActivePopout = !!(activePopout || activeTrayMenu || trayOpen);
}
}
Connections {
function onDankBarTransparencyChanged() {
topBarCore.backgroundTransparency = SettingsData.dankBarTransparency
function onBarConfigChanged() {
topBarCore.backgroundTransparency = barConfig?.transparency ?? 1.0;
topBarCore.autoHide = barConfig?.autoHide ?? false;
revealHold.interval = barConfig?.autoHideDelay ?? 250;
}
target: SettingsData
target: rootWindow
}
function evaluateReveal() {
if (!autoHide)
return;
if (topBarMouseArea.containsMouse || hasActivePopout) {
revealSticky = true;
revealHold.stop();
return;
}
revealHold.restart();
}
Connections {
target: topBarMouseArea
function onContainsMouseChanged() {
if (topBarMouseArea.containsMouse) {
topBarCore.revealSticky = true
revealHold.stop()
} else {
if (topBarCore.autoHide && !topBarCore.hasActivePopout) {
revealHold.restart()
}
}
topBarCore.evaluateReveal();
}
}
onHasActivePopoutChanged: {
if (hasActivePopout) {
revealSticky = true
revealHold.stop()
} else if (autoHide && !topBarMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
Connections {
target: PopoutManager
function onPopoutOpening() {
topBarCore.evaluateReveal();
}
}
MouseArea {
id: topBarMouseArea
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
y: !barWindow.isVertical ? (barPos === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
x: barWindow.isVertical ? (barPos === SettingsData.Position.Right ? parent.width - width : 0) : 0
height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr) : undefined
width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + (barConfig?.spacing ?? 4), barWindow._dpr) : undefined
anchors {
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
left: !barWindow.isVertical ? parent.left : (barPos === SettingsData.Position.Left ? parent.left : undefined)
right: !barWindow.isVertical ? parent.right : (barPos === SettingsData.Position.Right ? parent.right : undefined)
top: barWindow.isVertical ? parent.top : undefined
bottom: barWindow.isVertical ? parent.bottom : undefined
}
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
hoverEnabled: SettingsData.dankBarAutoHide && !inOverview
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false)
hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout
acceptedButtons: Qt.NoButton
enabled: SettingsData.dankBarAutoHide && !inOverview
enabled: (barConfig?.autoHide ?? false) && !inOverview
Item {
id: topBarContainer
@@ -440,8 +517,8 @@ PanelWindow {
transform: Translate {
id: topBarSlide
x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0
y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0
x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0
y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (barPos === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0
Behavior on x {
NumberAnimation {
@@ -460,16 +537,18 @@ PanelWindow {
Item {
id: barUnitInset
property int spacingPx: Theme.px(barConfig?.spacing ?? 4, barWindow._dpr)
anchors.fill: parent
anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr))
anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
anchors.leftMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "left" ? spacingPx : 0)
anchors.rightMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "right" ? spacingPx : 0)
anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx)
anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0)
BarCanvas {
id: barBackground
barWindow: barWindow
axis: axis
barConfig: barWindow.barConfig
}
MouseArea {
@@ -491,39 +570,39 @@ PanelWindow {
onWheel: wheel => {
if (actionInProgress) {
wheel.accepted = false
return
wheel.accepted = false;
return;
}
const deltaY = wheel.angleDelta.y
const deltaX = wheel.angleDelta.x
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
topBarContent.switchApp(deltaX);
wheel.accepted = false;
return;
}
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
const direction = deltaY < 0 ? 1 : -1
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()
topBarContent.switchWorkspace(direction);
actionInProgress = true;
cooldownTimer.restart();
} else {
scrollAccumulator += deltaY
scrollAccumulator += deltaY;
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
const touchDirection = scrollAccumulator < 0 ? 1 : -1
topBarContent.switchWorkspace(touchDirection)
scrollAccumulator = 0
actionInProgress = true
cooldownTimer.restart()
const touchDirection = scrollAccumulator < 0 ? 1 : -1;
topBarContent.switchWorkspace(touchDirection);
scrollAccumulator = 0;
actionInProgress = true;
cooldownTimer.restart();
}
}
wheel.accepted = false
wheel.accepted = false;
}
}
@@ -531,6 +610,10 @@ PanelWindow {
id: topBarContent
barWindow: barWindow
rootWindow: rootWindow
barConfig: barWindow.barConfig
leftWidgetsModel: barWindow.leftWidgetsModel
centerWidgetsModel: barWindow.centerWidgetsModel
rightWidgetsModel: barWindow.rightWidgetsModel
}
}
}

View File

@@ -11,13 +11,15 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false)
implicitHeight: layoutLoader.item ? (layoutLoader.item.implicitHeight || layoutLoader.item.height) : 0
implicitWidth: layoutLoader.item ? (layoutLoader.item.implicitWidth || layoutLoader.item.width) : 0
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
Loader {
id: layoutLoader
@@ -35,14 +37,15 @@ Item {
model: root.widgetsModel
Item {
readonly property real rowSpacing: parent.widgetSpacing
property var itemData: modelData
width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
widgetId: itemData.widgetId
widgetData: itemData
spacerSize: itemData.size || 20
components: root.components
isInColumn: false
axis: root.axis
@@ -50,8 +53,10 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
isFirst: model.index === 0
isLast: model.index === rowRepeater.count - 1
barSpacing: root.barSpacing
barConfig: root.barConfig
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing
isLeftBarEdge: true
isRightBarEdge: false
@@ -64,22 +69,23 @@ Item {
Component {
id: columnComp
Column {
width: Math.max(parent.width, 200)
width: parent.width
readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS
spacing: widgetSpacing
Repeater {
id: columnRepeater
model: root.widgetsModel
Item {
readonly property real columnSpacing: parent.widgetSpacing
width: parent.width
readonly property real columnSpacing: parent.widgetSpacing
property var itemData: modelData
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
widgetId: itemData.widgetId
widgetData: itemData
spacerSize: itemData.size || 20
components: root.components
isInColumn: true
axis: root.axis
@@ -87,8 +93,10 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
isFirst: model.index === 0
isLast: model.index === columnRepeater.count - 1
barSpacing: root.barSpacing
barConfig: root.barConfig
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing
isTopBarEdge: true
isBottomBarEdge: false

View File

@@ -15,14 +15,6 @@ DankPopout {
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
function isActiveProfile(profile) {
if (typeof PowerProfiles === "undefined") {
return false;
@@ -45,8 +37,6 @@ DankPopout {
popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70
positioning: ""
screen: triggerScreen

View File

@@ -14,18 +14,30 @@ DankPopout {
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
root.screen = screen
storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4)
storedBarSpacing = barSpacing !== undefined ? barSpacing : 4
storedBarConfig = barConfig
const pos = barPosition !== undefined ? barPosition : 0
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0
setBarContext(pos, bottomGap)
updateOutputState()
}
onScreenChanged: updateOutputState()
function updateOutputState() {
if (triggerScreen && DwlService.dwlAvailable) {
outputState = DwlService.getOutputState(triggerScreen.name)
if (screen && DwlService.dwlAvailable) {
outputState = DwlService.getOutputState(screen.name)
} else {
outputState = null
}
@@ -89,8 +101,6 @@ DankPopout {
popupWidth: 300
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 550
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70
positioning: ""
screen: triggerScreen
@@ -271,19 +281,13 @@ DankPopout {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
console.log("DWLLayoutPopout: Pressed layout", modelData, "at index", index)
console.log("DWLLayoutPopout: triggerScreen:", root.triggerScreen, "dwlAvailable:", DwlService.dwlAvailable)
if (!root.triggerScreen) {
console.error("DWLLayoutPopout: triggerScreen is null!")
return
}
if (!DwlService.dwlAvailable) {
console.error("DWLLayoutPopout: DwlService not available!")
return
}
console.log("DWLLayoutPopout: CALLING setLayout with output:", root.triggerScreen.name, "index:", index)
DwlService.setLayout(root.triggerScreen.name, index)
root.close()
}

View File

@@ -30,20 +30,9 @@ DankPopout {
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
popupWidth: 360
popupHeight: Math.min(Screen.height - 100, contentLoader.item ? contentLoader.item.implicitHeight : 260)
triggerX: Screen.width - 380 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
triggerWidth: 70
positioning: ""
screen: triggerScreen
shouldBeVisible: false

View File

@@ -11,6 +11,8 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
@@ -37,14 +39,15 @@ Item {
model: root.widgetsModel
Item {
readonly property real rowSpacing: parent.widgetSpacing
property var itemData: modelData
width: widgetLoader.item ? widgetLoader.item.width : 0
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.verticalCenter: parent.verticalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
widgetId: itemData.widgetId
widgetData: itemData
spacerSize: itemData.size || 20
components: root.components
isInColumn: false
axis: root.axis
@@ -52,8 +55,10 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
isFirst: model.index === 0
isLast: model.index === rowRepeater.count - 1
barSpacing: root.barSpacing
barConfig: root.barConfig
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing
isLeftBarEdge: false
isRightBarEdge: true
@@ -66,22 +71,23 @@ Item {
Component {
id: columnComp
Column {
width: parent ? parent.width : 0
width: parent.width
readonly property real widgetSpacing: noBackground ? 2 : Theme.spacingXS
spacing: widgetSpacing
Repeater {
id: columnRepeater
model: root.widgetsModel
Item {
readonly property real columnSpacing: parent.widgetSpacing
width: parent.width
readonly property real columnSpacing: parent.widgetSpacing
property var itemData: modelData
height: widgetLoader.item ? widgetLoader.item.height : 0
WidgetHost {
id: widgetLoader
anchors.horizontalCenter: parent.horizontalCenter
widgetId: model.widgetId
widgetData: model
spacerSize: model.size || 20
widgetId: itemData.widgetId
widgetData: itemData
spacerSize: itemData.size || 20
components: root.components
isInColumn: true
axis: root.axis
@@ -89,8 +95,10 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
isFirst: model.index === 0
isLast: model.index === columnRepeater.count - 1
barSpacing: root.barSpacing
barConfig: root.barConfig
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing
isTopBarEdge: false
isBottomBarEdge: true

View File

@@ -1,5 +1,4 @@
import QtQuick
import Quickshell.Services.Mpris
import qs.Services
Loader {
@@ -15,6 +14,8 @@ Loader {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property bool isFirst: false
property bool isLast: false
property real sectionSpacing: 0
@@ -27,9 +28,7 @@ Loader {
readonly property bool orientationMatches: (axis?.isVertical ?? false) === isInColumn
active: orientationMatches &&
getWidgetVisible(widgetId, DgopService.dgopAvailable) &&
(widgetId !== "music" || MprisController.activePlayer !== null)
active: orientationMatches && getWidgetVisible(widgetId, DgopService.dgopAvailable) && (widgetId !== "music" || MprisController.activePlayer !== null)
sourceComponent: getWidgetComponent(widgetId, components)
opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0
@@ -67,6 +66,22 @@ Loader {
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "barSpacing" in root.item
property: "barSpacing"
value: root.barSpacing
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "barConfig" in root.item
property: "barConfig"
value: root.barConfig
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "axis" in root.item
@@ -141,33 +156,32 @@ Loader {
onLoaded: {
if (item) {
contentItemReady(item)
contentItemReady(item);
if (axis && "isVertical" in item) {
try {
item.isVertical = axis.isVertical
} catch (e) {
}
item.isVertical = axis.isVertical;
} catch (e) {}
}
if (item.pluginService !== undefined) {
var parts = widgetId.split(":")
var pluginId = parts[0]
var variantId = parts.length > 1 ? parts[1] : null
var parts = widgetId.split(":");
var pluginId = parts[0];
var variantId = parts.length > 1 ? parts[1] : null;
if (item.pluginId !== undefined) {
item.pluginId = pluginId
item.pluginId = pluginId;
}
if (item.variantId !== undefined) {
item.variantId = variantId
item.variantId = variantId;
}
if (item.variantData !== undefined && variantId) {
item.variantData = PluginService.getPluginVariantData(pluginId, variantId)
item.variantData = PluginService.getPluginVariantData(pluginId, variantId);
}
item.pluginService = PluginService
item.pluginService = PluginService;
}
if (item.popoutService !== undefined) {
item.popoutService = PopoutService
item.popoutService = PopoutService;
}
}
}
@@ -203,17 +217,17 @@ Loader {
"colorPicker": components.colorPickerComponent,
"systemUpdate": components.systemUpdateComponent,
"layout": components.layoutComponent
}
};
if (componentMap[widgetId]) {
return componentMap[widgetId]
return componentMap[widgetId];
}
var parts = widgetId.split(":")
var pluginId = parts[0]
var parts = widgetId.split(":");
var pluginId = parts[0];
let pluginMap = PluginService.getWidgetComponents()
return pluginMap[pluginId] || null
let pluginMap = PluginService.getWidgetComponents();
return pluginMap[pluginId] || null;
}
function getWidgetVisible(widgetId, dgopAvailable) {
@@ -224,12 +238,12 @@ Loader {
"gpuTemp": dgopAvailable,
"network_speed_monitor": dgopAvailable,
"layout": CompositorService.isDwl && DwlService.dwlAvailable
}
};
return widgetVisibility[widgetId] ?? true
return widgetVisibility[widgetId] ?? true;
}
function getWidgetEnabled(enabled) {
return enabled !== false
return enabled !== false;
}
}

View File

@@ -1,5 +1,4 @@
import QtQuick
import Quickshell.Services.UPower
import qs.Common
import qs.Modules.Plugins
import qs.Services
@@ -11,7 +10,22 @@ BasePill {
property bool batteryPopupVisible: false
property var popoutTarget: null
signal toggleBatteryPopup()
readonly property int barPosition: {
switch (axis?.edge) {
case "top":
return 0;
case "bottom":
return 1;
case "left":
return 2;
case "right":
return 3;
default:
return 0;
}
}
signal toggleBatteryPopup
visible: true
@@ -31,25 +45,25 @@ BasePill {
size: Theme.barIconSize(battery.barThickness)
color: {
if (!BatteryService.batteryAvailable) {
return Theme.widgetIconColor
return Theme.widgetIconColor;
}
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error
return Theme.error;
}
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary
return Theme.primary;
}
return Theme.widgetIconColor
return Theme.widgetIconColor;
}
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: BatteryService.batteryLevel.toString()
font.pixelSize: Theme.barTextSize(battery.barThickness)
font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
visible: BatteryService.batteryAvailable
@@ -60,7 +74,7 @@ BasePill {
id: batteryContent
visible: !battery.isVerticalOrientation
anchors.centerIn: parent
spacing: SettingsData.dankBarNoBackground ? 1 : 2
spacing: (barConfig?.noBackground ?? false) ? 1 : 2
DankIcon {
name: BatteryService.getBatteryIcon()
@@ -85,7 +99,7 @@ BasePill {
StyledText {
text: `${BatteryService.batteryLevel}%`
font.pixelSize: Theme.barTextSize(battery.barThickness)
font.pixelSize: Theme.barTextSize(battery.barThickness, battery.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
@@ -102,13 +116,7 @@ BasePill {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = battery.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, battery.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
toggleBatteryPopup()
toggleBatteryPopup();
}
}
}
}

View File

@@ -35,7 +35,7 @@ BasePill {
return String(display).padStart(2, '0').charAt(0)
}
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -51,7 +51,7 @@ BasePill {
return String(display).padStart(2, '0').charAt(1)
}
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -64,7 +64,7 @@ BasePill {
StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -72,7 +72,7 @@ BasePill {
StyledText {
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -86,7 +86,7 @@ BasePill {
StyledText {
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(0)
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -94,7 +94,7 @@ BasePill {
StyledText {
text: String(systemClock?.date?.getSeconds()).padStart(2, '0').charAt(1)
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -126,7 +126,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(0)
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -140,7 +140,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
return value.charAt(1)
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -159,7 +159,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(0)
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -173,7 +173,7 @@ BasePill {
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
return value.charAt(1)
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.primary
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
@@ -192,7 +192,7 @@ BasePill {
text: {
return systemClock?.date?.toLocaleTimeString(Qt.locale(), SettingsData.getEffectiveTimeFormat())
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.baseline: dateText.baseline
}
@@ -214,7 +214,7 @@ BasePill {
}
return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d")
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.clockCompactMode
@@ -235,12 +235,6 @@ BasePill {
height: root.height + root.topMargin + root.bottomMargin
cursorShape: Qt.PointingHandCursor
onPressed: {
if (root.popoutTarget && root.popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = root.parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.visualWidth)
root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen)
}
root.clockClicked()
}
}

View File

@@ -236,22 +236,4 @@ BasePill {
}
}
}
MouseArea {
x: -root.leftMargin
y: -root.topMargin
width: root.width + root.leftMargin + root.rightMargin
height: root.height + root.topMargin + root.bottomMargin
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.clicked()
}
}
}

View File

@@ -15,6 +15,8 @@ BasePill {
property var widgetData: null
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal cpuClicked()
Component.onCompleted: {
DgopService.addRef(["cpu"]);
}
@@ -58,7 +60,7 @@ BasePill {
return DgopService.cpuUsage.toFixed(0);
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -95,7 +97,7 @@ BasePill {
return DgopService.cpuUsage.toFixed(0) + "%";
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -103,7 +105,7 @@ BasePill {
StyledTextMetrics {
id: cpuBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100%"
}
@@ -125,16 +127,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "cpu");
}
DgopService.setSortBy("cpu")
cpuClicked()
}
}
}

View File

@@ -15,6 +15,8 @@ BasePill {
property var widgetData: null
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal cpuTempClicked()
Component.onCompleted: {
DgopService.addRef(["cpu"]);
}
@@ -58,7 +60,7 @@ BasePill {
return Math.round(DgopService.cpuTemperature).toString();
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -95,7 +97,7 @@ BasePill {
return Math.round(DgopService.cpuTemperature) + "°";
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -103,7 +105,7 @@ BasePill {
StyledTextMetrics {
id: tempBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100°"
}
@@ -125,16 +127,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "cpu_temp");
}
DgopService.setSortBy("cpu")
cpuTempClicked()
}
}
}

View File

@@ -64,7 +64,7 @@ BasePill {
StyledText {
text: layout.currentLayoutSymbol
font.pixelSize: Theme.barTextSize(layout.barThickness)
font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -74,7 +74,7 @@ BasePill {
id: layoutContent
visible: !layout.isVerticalOrientation
anchors.centerIn: parent
spacing: SettingsData.dankBarNoBackground ? 1 : 2
spacing: (barConfig?.noBackground ?? false) ? 1 : 2
DankIcon {
name: layout.getLayoutIcon(layout.currentLayoutSymbol)
@@ -85,7 +85,7 @@ BasePill {
StyledText {
text: layout.currentLayoutSymbol
font.pixelSize: Theme.barTextSize(layout.barThickness)
font.pixelSize: Theme.barTextSize(layout.barThickness, layout.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
}
@@ -94,12 +94,6 @@ BasePill {
}
onClicked: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = layout.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, layout.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
toggleLayoutPopup()
}

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Modules.Plugins
import qs.Services
@@ -11,71 +10,90 @@ BasePill {
property var widgetData: null
property string mountPath: (widgetData && widgetData.mountPath !== undefined) ? widgetData.mountPath : "/"
property bool isHovered: mouseArea.containsMouse
property bool isAutoHideBar: false
property var selectedMount: {
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
return null
return null;
}
const currentMountPath = root.mountPath || "/"
const currentMountPath = root.mountPath || "/";
for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === currentMountPath) {
return DgopService.diskMounts[i]
return DgopService.diskMounts[i];
}
}
for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === "/") {
return DgopService.diskMounts[i]
return DgopService.diskMounts[i];
}
}
return DgopService.diskMounts[0] || null
return DgopService.diskMounts[0] || null;
}
property real diskUsagePercent: {
if (!selectedMount || !selectedMount.percent) {
return 0
return 0;
}
const percentStr = selectedMount.percent.replace("%", "")
return parseFloat(percentStr) || 0
const percentStr = selectedMount.percent.replace("%", "");
return parseFloat(percentStr) || 0;
}
Component.onCompleted: {
DgopService.addRef(["diskmounts"])
DgopService.addRef(["diskmounts"]);
}
Component.onDestruction: {
DgopService.removeRef(["diskmounts"])
DgopService.removeRef(["diskmounts"]);
}
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0;
}
if (isAutoHideBar) {
return 0;
}
if (parentScreen.y > 0) {
const spacing = barConfig?.spacing ?? 4;
const offset = barThickness + spacing;
return offset;
}
return 0;
}
Connections {
function onWidgetDataChanged() {
root.mountPath = Qt.binding(() => {
return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/"
})
return (root.widgetData && root.widgetData.mountPath !== undefined) ? root.widgetData.mountPath : "/";
});
root.selectedMount = Qt.binding(() => {
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
return null
return null;
}
const currentMountPath = root.mountPath || "/"
const currentMountPath = root.mountPath || "/";
for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === currentMountPath) {
return DgopService.diskMounts[i]
return DgopService.diskMounts[i];
}
}
for (let i = 0; i < DgopService.diskMounts.length; i++) {
if (DgopService.diskMounts[i].mount === "/") {
return DgopService.diskMounts[i]
return DgopService.diskMounts[i];
}
}
return DgopService.diskMounts[0] || null
})
return DgopService.diskMounts[0] || null;
});
}
target: SettingsData
@@ -97,12 +115,12 @@ BasePill {
size: Theme.barIconSize(root.barThickness)
color: {
if (root.diskUsagePercent > 90) {
return Theme.tempDanger
return Theme.tempDanger;
}
if (root.diskUsagePercent > 75) {
return Theme.tempWarning
return Theme.tempWarning;
}
return Theme.surfaceText
return Theme.surfaceText;
}
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -110,11 +128,11 @@ BasePill {
StyledText {
text: {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--"
return "--";
}
return root.diskUsagePercent.toFixed(0)
return root.diskUsagePercent.toFixed(0);
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -131,12 +149,12 @@ BasePill {
size: Theme.barIconSize(root.barThickness)
color: {
if (root.diskUsagePercent > 90) {
return Theme.tempDanger
return Theme.tempDanger;
}
if (root.diskUsagePercent > 75) {
return Theme.tempWarning
return Theme.tempWarning;
}
return Theme.surfaceText
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
@@ -144,11 +162,11 @@ BasePill {
StyledText {
text: {
if (!root.selectedMount) {
return "--"
return "--";
}
return root.selectedMount.mount
return root.selectedMount.mount;
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -158,11 +176,11 @@ BasePill {
StyledText {
text: {
if (root.diskUsagePercent === undefined || root.diskUsagePercent === null || root.diskUsagePercent === 0) {
return "--%"
return "--%";
}
return root.diskUsagePercent.toFixed(0) + "%"
return root.diskUsagePercent.toFixed(0) + "%";
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -170,7 +188,7 @@ BasePill {
StyledTextMetrics {
id: diskBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100%"
}
@@ -200,24 +218,25 @@ BasePill {
hoverEnabled: root.isVerticalOrientation
onEntered: {
if (root.isVerticalOrientation && root.selectedMount) {
tooltipLoader.active = true
tooltipLoader.active = true;
if (tooltipLoader.item) {
const globalPos = mapToGlobal(width / 2, height / 2)
const currentScreen = root.parentScreen || Screen
const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0
const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft)
const globalPos = mapToGlobal(width / 2, height / 2);
const currentScreen = root.parentScreen || Screen;
const screenX = currentScreen ? currentScreen.x : 0;
const screenY = currentScreen ? currentScreen.y : 0;
const relativeY = globalPos.y - screenY;
const adjustedY = relativeY + root.minTooltipY;
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
const isLeft = root.axis?.edge === "left";
tooltipLoader.item.show(root.selectedMount.mount, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft);
}
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
tooltipLoader.item.hide();
}
tooltipLoader.active = false
tooltipLoader.active = false;
}
}
}

View File

@@ -18,6 +18,23 @@ BasePill {
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
property var activeDesktopEntry: null
property bool isHovered: mouseArea.containsMouse
property bool isAutoHideBar: false
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return barThickness + (barSpacing || 4)
}
return 0
}
Component.onCompleted: {
updateDesktopEntry()
@@ -80,7 +97,6 @@ BasePill {
return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id
} catch (e) {
console.error("FocusedApp: hasWindowsOnCurrentWorkspace error:", e)
return false
}
}
@@ -167,7 +183,7 @@ BasePill {
const desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId);
return desktopEntry && desktopEntry.name ? desktopEntry.name : activeWindow.appId;
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
@@ -178,7 +194,7 @@ BasePill {
StyledText {
text: "•"
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: !compactMode && appText.text && titleText.text
@@ -203,7 +219,7 @@ BasePill {
return title;
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
@@ -229,14 +245,16 @@ BasePill {
const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0
const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
// Add minTooltipY offset to account for top bar
const adjustedY = relativeY + root.minTooltipY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
const appName = activeDesktopEntry && activeDesktopEntry.name ? activeDesktopEntry.name : activeWindow.appId
const title = activeWindow.title || ""
const tooltipText = appName + (title ? " • " + title : "")
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, currentScreen, isLeft, !isLeft)
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft)
}
}
}

View File

@@ -15,6 +15,9 @@ BasePill {
property var widgetData: null
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
signal gpuTempClicked()
property real displayTemp: {
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
return 0;
@@ -29,15 +32,18 @@ BasePill {
function updateWidgetPciId(pciId) {
const sections = ["left", "center", "right"];
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return
for (let s = 0; s < sections.length; s++) {
const sectionId = sections[s];
let widgets = [];
if (sectionId === "left") {
widgets = SettingsData.dankBarLeftWidgets.slice();
widgets = (defaultBar.leftWidgets || []).slice();
} else if (sectionId === "center") {
widgets = SettingsData.dankBarCenterWidgets.slice();
widgets = (defaultBar.centerWidgets || []).slice();
} else if (sectionId === "right") {
widgets = SettingsData.dankBarRightWidgets.slice();
widgets = (defaultBar.rightWidgets || []).slice();
}
for (let i = 0; i < widgets.length; i++) {
const widget = widgets[i];
@@ -122,7 +128,7 @@ BasePill {
return Math.round(root.displayTemp).toString();
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -159,7 +165,7 @@ BasePill {
return Math.round(root.displayTemp) + "°";
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -167,7 +173,7 @@ BasePill {
StyledTextMetrics {
id: gpuTempBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "100°"
}
@@ -189,16 +195,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("cpu");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "gpu_temp");
}
DgopService.setSortBy("cpu")
gpuTempClicked()
}
}

View File

@@ -50,7 +50,7 @@ BasePill {
}
return root.currentLayout.substring(0, 2).toUpperCase()
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -64,7 +64,7 @@ BasePill {
StyledText {
text: root.currentLayout
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
}

View File

@@ -174,7 +174,7 @@ BasePill {
anchors.verticalCenter: parent.verticalCenter
text: textContainer.displayText
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
wrapMode: Text.NoWrap
x: needsScrolling ? -scrollOffset : 0

View File

@@ -53,7 +53,7 @@ BasePill {
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M"
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.info
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -65,7 +65,7 @@ BasePill {
if (rate < 1024 * 1024) return (rate / 1024).toFixed(0) + "K"
return (rate / (1024 * 1024)).toFixed(0) + "M"
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.error
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -90,13 +90,13 @@ BasePill {
StyledText {
text: "↓"
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.info
}
StyledText {
text: DgopService.networkRxRate > 0 ? root.formatNetworkSpeed(DgopService.networkRxRate) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -105,7 +105,7 @@ BasePill {
StyledTextMetrics {
id: rxBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "88.8 MB/s"
}
@@ -126,13 +126,13 @@ BasePill {
StyledText {
text: "↑"
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.error
}
StyledText {
text: DgopService.networkTxRate > 0 ? root.formatNetworkSpeed(DgopService.networkTxRate) : "0 B/s"
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -141,7 +141,7 @@ BasePill {
StyledTextMetrics {
id: txBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: "88.8 MB/s"
}

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
@@ -14,14 +13,15 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property var barConfig: null
property bool showMicIcon: SettingsData.privacyShowMicIcon
property bool showCameraIcon: SettingsData.privacyShowCameraIcon
property bool showScreenSharingIcon: SettingsData.privacyShowScreenShareIcon
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
readonly property bool hasActivePrivacy: showMicIcon || showCameraIcon || showScreenSharingIcon || PrivacyService.anyPrivacyActive
readonly property int activeCount: ( showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive)
readonly property int activeCount: (showMicIcon ? 1 : PrivacyService.microphoneActive) + (showCameraIcon ? 1 : PrivacyService.cameraActive) + (showScreenSharingIcon ? 1 : PrivacyService.screensharingActive)
readonly property real contentWidth: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real contentHeight: hasActivePrivacy ? (activeCount * 18 + (activeCount - 1) * Theme.spacingXS) : 0
readonly property real visualWidth: isVertical ? widgetThickness : (hasActivePrivacy ? (contentWidth + horizontalPadding * 2) : 0)
@@ -38,14 +38,15 @@ Item {
width: root.visualWidth
height: root.visualHeight
anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent"
if (barConfig?.noBackground ?? false) {
return "transparent";
}
const baseColor = Theme.widgetBaseBackgroundColor
return Qt.rgba(privacyArea.containsMouse ? Theme.errorPressed.r : baseColor.r, privacyArea.containsMouse ? Theme.errorPressed.g : baseColor.g, privacyArea.containsMouse ? Theme.errorPressed.b : baseColor.b, (privacyArea.containsMouse ? Theme.errorPressed.a : baseColor.a) * Theme.widgetTransparency)
const baseColor = privacyArea.containsMouse ? Theme.errorPressed : Theme.errorHover;
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
return Theme.withAlpha(baseColor, transparency);
}
Column {
@@ -61,10 +62,11 @@ Item {
DankIcon {
name: {
const sourceAudio = AudioService.source?.audio
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0
if (muted) return "mic_off"
return "mic"
const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted)
return "mic_off";
return "mic";
}
size: Theme.iconSizeSmall
color: Theme.error
@@ -128,10 +130,11 @@ Item {
DankIcon {
name: {
const sourceAudio = AudioService.source?.audio
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0
if (muted) return "mic_off"
return "mic"
const sourceAudio = AudioService.source?.audio;
const muted = !sourceAudio || sourceAudio.muted || sourceAudio.volume === 0.0;
if (muted)
return "mic_off";
return "mic";
}
size: Theme.iconSizeSmall
color: PrivacyService.microphoneActive ? Theme.error : Theme.surfaceText
@@ -191,8 +194,7 @@ Item {
hoverEnabled: hasActivePrivacy
enabled: hasActivePrivacy
cursorShape: Qt.PointingHandCursor
onClicked: {
}
onClicked: {}
}
Rectangle {
@@ -213,7 +215,7 @@ Item {
id: tooltipText
anchors.centerIn: parent
text: PrivacyService.getPrivacySummary()
font.pixelSize: Theme.barTextSize(barThickness)
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor
}

View File

@@ -17,6 +17,8 @@ BasePill {
property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false
readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0
signal ramClicked()
Component.onCompleted: {
DgopService.addRef(["memory"]);
}
@@ -60,7 +62,7 @@ BasePill {
return DgopService.memoryUsage.toFixed(0);
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -68,7 +70,7 @@ BasePill {
StyledText {
visible: root.showSwap && DgopService.totalSwapKB > 0
text: root.swapUsage.toFixed(0)
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -109,7 +111,7 @@ BasePill {
}
return ramText;
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignLeft
@@ -118,7 +120,7 @@ BasePill {
StyledTextMetrics {
id: ramBaseline
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
text: {
if (!root.showSwap) {
return "100%";
@@ -148,16 +150,8 @@ BasePill {
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
DgopService.setSortBy("memory");
if (popoutTarget) {
PopoutManager.requestPopout(popoutTarget, undefined, "memory");
}
DgopService.setSortBy("memory")
ramClicked()
}
}
}

View File

@@ -11,6 +11,7 @@ import qs.Widgets
Item {
id: root
property var barConfig: null
property bool isVertical: axis?.isVertical ?? false
property var axis: null
property string section: "left"
@@ -19,8 +20,46 @@ Item {
property var topBar: null
property real widgetThickness: 30
property real barThickness: 48
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
property real barSpacing: 4
property bool isAutoHideBar: false
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 2 : Theme.spacingS
property Item windowRoot: (Window.window ? Window.window.contentItem : null)
readonly property real effectiveBarThickness: {
if (barThickness > 0 && barSpacing > 0) {
return barThickness + barSpacing
}
const innerPadding = barConfig?.innerPadding ?? 4
const spacing = barConfig?.spacing ?? 4
return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing
}
readonly property var barBounds: {
if (!parentScreen || !barConfig) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1))
return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig)
}
readonly property real barY: barBounds.y
readonly property real minTooltipY: {
if (!parentScreen || !isVertical) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return effectiveBarThickness
}
return 0
}
property int _desktopEntriesUpdateTrigger: 0
property int _toplevelsUpdateTrigger: 0
@@ -75,7 +114,6 @@ Item {
})
return Array.from(appGroups.values())
} catch (e) {
console.error("RunningApps: groupedWindows error:", e)
return []
}
}
@@ -101,19 +139,20 @@ Item {
width: root.isVertical ? root.widgetThickness : root.calculatedSize
height: root.isVertical ? root.calculatedSize : root.widgetThickness
anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
clip: false
color: {
if (windowCount === 0) {
return "transparent"
}
if (SettingsData.dankBarNoBackground) {
if ((barConfig?.noBackground ?? false)) {
return "transparent"
}
const baseColor = Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0
return Theme.withAlpha(baseColor, transparency)
}
}
@@ -353,7 +392,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.runningAppsCompactMode
text: windowTitle
font.pixelSize: Theme.barTextSize(barThickness)
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor
elide: Text.ElideRight
maximumLineCount: 1
@@ -390,18 +429,25 @@ Item {
windowContextMenuLoader.active = true
if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject
// Pass bar context
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY
const xPos = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, relativeY, true, root.axis?.edge)
// Add minTooltipY offset to account for top bar
const adjustedY = relativeY + root.minTooltipY
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const relativeX = globalPos.x - screenX
const yPos = Theme.barHeight + SettingsData.dankBarSpacing - 7
const yPos = root.barThickness + root.barSpacing - 7
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
}
}
@@ -416,16 +462,18 @@ Item {
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
const adjustedY = relativeY + root.minTooltipY
const finalX = screenX + tooltipX
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS)
? (screenHeight - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS - 35)
: (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}
@@ -586,7 +634,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
visible: !SettingsData.runningAppsCompactMode
text: windowTitle
font.pixelSize: Theme.barTextSize(barThickness)
font.pixelSize: Theme.barTextSize(barThickness, barConfig?.fontScale)
color: Theme.widgetTextColor
elide: Text.ElideRight
maximumLineCount: 1
@@ -623,18 +671,25 @@ Item {
windowContextMenuLoader.active = true
if (windowContextMenuLoader.item) {
windowContextMenuLoader.item.currentWindow = toplevelObject
// Pass bar context
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY
const xPos = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, relativeY, true, root.axis?.edge)
// Add minTooltipY offset to account for top bar
const adjustedY = relativeY + root.minTooltipY
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const relativeX = globalPos.x - screenX
const yPos = Theme.barHeight + SettingsData.dankBarSpacing - 7
const yPos = root.barThickness + root.barSpacing - 7
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
}
}
@@ -649,16 +704,18 @@ Item {
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(delegateItem.tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
const adjustedY = relativeY + root.minTooltipY
const finalX = screenX + tooltipX
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
const isBottom = root.axis?.edge === "bottom"
const tooltipY = isBottom
? (screenHeight - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS - 35)
: (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS)
? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35)
: (root.barThickness + root.barSpacing + Theme.spacingXS)
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}
@@ -699,6 +756,28 @@ Item {
property bool isVertical: false
property string edge: "top"
// New properties for bar context
property int triggerBarPosition: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top)
property real triggerBarThickness: 0
property real triggerBarSpacing: 0
property var triggerBarConfig: null
readonly property real effectiveBarThickness: {
if (triggerBarThickness > 0 && triggerBarSpacing > 0) {
return triggerBarThickness + triggerBarSpacing
}
return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4)
}
property var barBounds: {
if (!contextMenuWindow.screen || !triggerBarConfig) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig)
}
property real barY: barBounds.y
function showAt(x, y, vertical, barEdge) {
screen = root.parentScreen
anchorPos = Qt.point(x, y)
@@ -752,7 +831,7 @@ Item {
}
y: {
if (contextMenuWindow.isVertical) {
const top = 10
const top = Math.max(barY, 10)
const bottom = contextMenuWindow.height - height - 10
const want = contextMenuWindow.anchorPos.y - height / 2
return Math.max(top, Math.min(bottom, want))

File diff suppressed because it is too large Load Diff

View File

@@ -62,8 +62,8 @@ BasePill {
color: Theme.error
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6
anchors.rightMargin: (barConfig?.noBackground ?? false) ? 0 : 6
anchors.topMargin: (barConfig?.noBackground ?? false) ? 0 : 6
visible: root.isVerticalOrientation && root.hasUpdates && !root.isChecking
}
@@ -111,7 +111,7 @@ BasePill {
id: countText
anchors.verticalCenter: parent.verticalCenter
text: SystemUpdateService.updateCount.toString()
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
visible: root.hasUpdates && !root.isChecking
}

View File

@@ -13,7 +13,26 @@ BasePill {
}
property var popoutTarget: null
property var barConfig: null
property bool isHovered: clickArea.containsMouse
property real barSpacing: 4
property bool isAutoHideBar: false
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0
}
if (isAutoHideBar) {
return 0
}
if (parentScreen.y > 0) {
return barThickness + barSpacing
}
return 0
}
signal toggleVpnPopup()
@@ -56,51 +75,47 @@ BasePill {
acceptedButtons: Qt.LeftButton
enabled: !DMSNetworkService.isBusy
onPressed: {
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
}
root.toggleVpnPopup();
root.toggleVpnPopup()
}
onEntered: {
if (root.parentScreen && !(popoutTarget && popoutTarget.shouldBeVisible)) {
tooltipLoader.active = true
if (tooltipLoader.item) {
let tooltipText = ""
if (!DMSNetworkService.connected) {
tooltipText = "VPN Disconnected"
} else {
const names = DMSNetworkService.activeNames || []
if (names.length <= 1) {
const name = names[0] || ""
const maxLength = 25
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName
} else {
const name = names[0]
const maxLength = 20
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1)
}
}
if (!root.parentScreen || (popoutTarget?.shouldBeVisible)) return
if (root.isVerticalOrientation) {
const globalPos = mapToGlobal(width / 2, height / 2)
const screenX = root.parentScreen ? root.parentScreen.x : 0
const screenY = root.parentScreen ? root.parentScreen.y : 0
const relativeY = globalPos.y - screenY
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
} else {
const globalPos = mapToGlobal(width / 2, height)
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
tooltipLoader.active = true
if (!tooltipLoader.item) return
let tooltipText = ""
if (!DMSNetworkService.connected) {
tooltipText = "VPN Disconnected"
} else {
const names = DMSNetworkService.activeNames || []
if (names.length <= 1) {
const name = names[0] || ""
const maxLength = 25
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName
} else {
const name = names[0]
const maxLength = 20
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1)
}
}
if (root.isVerticalOrientation) {
const globalPos = mapToGlobal(width / 2, height / 2)
const currentScreen = root.parentScreen || Screen
const screenX = currentScreen ? currentScreen.x : 0
const screenY = currentScreen ? currentScreen.y : 0
const relativeY = globalPos.y - screenY
const adjustedY = relativeY + root.minTooltipY
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
const isLeft = root.axis?.edge === "left"
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft)
} else {
const globalPos = mapToGlobal(width / 2, height)
const tooltipY = root.barThickness + root.barSpacing + Theme.spacingXS
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
}
}
onExited: {
if (tooltipLoader.item) {

View File

@@ -43,7 +43,7 @@ BasePill {
const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
return temp;
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -70,7 +70,7 @@ BasePill {
const temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C");
}
font.pixelSize: Theme.barTextSize(root.barThickness)
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
color: Theme.widgetTextColor
anchors.verticalCenter: parent.verticalCenter
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,30 +18,8 @@ DankPopout {
property var triggerScreen: null
property int currentTabIndex: 0
function setTriggerPosition(x, y, width, section, screen) {
triggerSection = section
triggerScreen = screen
triggerY = y
if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)) {
const screenWidth = screen ? screen.width : Screen.width
triggerX = (screenWidth - popupWidth) / 2
triggerWidth = popupWidth
} else if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)) {
const screenHeight = screen ? screen.height : Screen.height
triggerX = (screenHeight - popupHeight) / 2
triggerWidth = popupHeight
} else {
triggerX = x
triggerWidth = width
}
}
popupWidth: 700
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
triggerX: Screen.width - 620 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 80
screen: triggerScreen
shouldBeVisible: dashVisible

View File

@@ -17,7 +17,7 @@ Item {
property MprisPlayer activePlayer: MprisController.activePlayer
property var allPlayers: MprisController.availablePlayers
readonly property bool isRightEdge: SettingsData.dankBarPosition === SettingsData.Position.Right
readonly property bool isRightEdge: (SettingsData.barConfigs[0]?.position ?? SettingsData.Position.Top) === SettingsData.Position.Right
property var defaultSink: AudioService.sink
// Palette that stays stable across track switches until new colors are ready

View File

@@ -37,18 +37,24 @@ Variants {
readonly property real widgetHeight: SettingsData.dockIconSize
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10
readonly property real barSpacing: {
const barIsHorizontal = (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)
const barIsVertical = (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)
const samePosition = (SettingsData.dockPosition === SettingsData.dankBarPosition)
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return 0
const barPos = defaultBar.position ?? SettingsData.Position.Top
const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom)
const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right)
const samePosition = (SettingsData.dockPosition === barPos)
const dockIsHorizontal = !isVertical
const dockIsVertical = isVertical
if (!SettingsData.dankBarVisible) return 0
if (!(defaultBar.visible ?? true)) return 0
const spacing = defaultBar.spacing ?? 4
const bottomGap = defaultBar.bottomGap ?? 0
if (dockIsHorizontal && barIsHorizontal && samePosition) {
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
return spacing + effectiveBarHeight + bottomGap
}
if (dockIsVertical && barIsVertical && samePosition) {
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
return spacing + effectiveBarHeight + bottomGap
}
return 0
}

View File

@@ -8,7 +8,7 @@ Rectangle {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: Theme.widgetBackground
color: Theme.surfaceContainerHigh
signal dismissed

View File

@@ -26,19 +26,8 @@ DankPopout {
}
}
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: 0
triggerY: 0
triggerWidth: 40
positioning: ""
screen: triggerScreen
shouldBeVisible: notificationHistoryVisible

View File

@@ -137,80 +137,55 @@ PanelWindow {
right: getRightMargin()
}
function getBarInfo() {
if (!screen) return { topBar: 0, bottomBar: 0, leftBar: 0, rightBar: 0 }
return SettingsData.getAdjacentBarInfo(screen, SettingsData.notificationPopupPosition, {
id: "notification-popup",
screenPreferences: [screen.name],
autoHide: false
})
}
function getTopMargin() {
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left
if (!isTop) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Top) {
base = exclusiveZone
}
const barInfo = getBarInfo()
const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance
return base + screenY
}
function getBottomMargin() {
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right
if (!isBottom) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
let base = Theme.popupDistance
if (barPos === SettingsData.Position.Bottom) {
base = exclusiveZone
}
const barInfo = getBarInfo()
const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance
return base + screenY
}
function getLeftMargin() {
if (isTopCenter) {
return (screen.width - implicitWidth) / 2
}
if (isTopCenter) return (screen.width - implicitWidth) / 2
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom
if (!isLeft) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
if (barPos === SettingsData.Position.Left) {
return exclusiveZone
}
return Theme.popupDistance
const barInfo = getBarInfo()
return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance
}
function getRightMargin() {
if (isTopCenter) return 0
const popupPos = SettingsData.notificationPopupPosition
const barPos = SettingsData.dankBarPosition
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right
if (!isRight) return 0
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
if (barPos === SettingsData.Position.Right) {
return exclusiveZone
}
return Theme.popupDistance
const barInfo = getBarInfo()
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance
}
readonly property real dpr: CompositorService.getScreenScale(win.screen)
@@ -241,14 +216,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / blurMax))
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -1,7 +1,5 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: root
@@ -12,6 +10,8 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property alias content: contentLoader.sourceComponent
property bool isVerticalOrientation: axis?.isVertical ?? false
property bool isFirst: false
@@ -21,7 +21,7 @@ Item {
property bool isRightBarEdge: false
property bool isTopBarEdge: false
property bool isBottomBarEdge: false
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real horizontalPadding: (barConfig?.noBackground ?? false) ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
readonly property real visualWidth: isVerticalOrientation ? widgetThickness : (contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0)
readonly property real visualHeight: isVerticalOrientation ? (contentLoader.item ? (contentLoader.item.implicitHeight + horizontalPadding * 2) : 0) : widgetThickness
readonly property alias visualContent: visualContent
@@ -32,8 +32,8 @@ Item {
readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0
readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0
signal clicked()
signal rightClicked()
signal clicked
signal rightClicked
width: isVerticalOrientation ? barThickness : visualWidth
height: isVerticalOrientation ? visualHeight : barThickness
@@ -43,15 +43,16 @@ Item {
width: root.visualWidth
height: root.visualHeight
anchors.centerIn: parent
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
radius: (barConfig?.noBackground ?? false) ? 0 : Theme.cornerRadius
color: {
if (SettingsData.dankBarNoBackground) {
return "transparent"
if (barConfig?.noBackground ?? false) {
return "transparent";
}
const isHovered = mouseArea.containsMouse || (root.isHovered ?? false)
const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
const isHovered = mouseArea.containsMouse || (root.isHovered || false);
const baseColor = isHovered ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
return Theme.withAlpha(baseColor, transparency);
}
Loader {
@@ -73,16 +74,26 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: function (mouse) {
if (mouse.button === Qt.RightButton) {
root.rightClicked()
return
root.rightClicked();
return;
}
if (popoutTarget && popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth)
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
if (popoutTarget) {
// Ensure bar context is set first if supported
if (popoutTarget.setBarContext) {
const pos = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const bottomGap = root.barConfig ? (root.barConfig.bottomGap !== undefined ? root.barConfig.bottomGap : 0) : 0;
popoutTarget.setBarContext(pos, bottomGap);
}
if (popoutTarget.setTriggerPosition) {
const globalPos = root.visualContent.mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig);
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig);
}
}
root.clicked()
root.clicked();
}
}
}

View File

@@ -1,7 +1,5 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: root
@@ -13,6 +11,8 @@ Item {
property var parentScreen: null
property real widgetThickness: 30
property real barThickness: 48
property real barSpacing: 4
property var barConfig: null
property string pluginId: ""
property var pluginService: null
@@ -33,8 +33,8 @@ Item {
property Component ccDetailContent: null
property real ccDetailHeight: 250
signal ccWidgetToggled()
signal ccWidgetExpanded()
signal ccWidgetToggled
signal ccWidgetExpanded
property var pluginData: ({})
property var variants: []
@@ -45,55 +45,55 @@ Item {
readonly property bool hasPopout: popoutContent !== null
Component.onCompleted: {
loadPluginData()
loadPluginData();
}
onPluginServiceChanged: {
loadPluginData()
loadPluginData();
}
onPluginIdChanged: {
loadPluginData()
loadPluginData();
}
Connections {
target: pluginService
function onPluginDataChanged(changedPluginId) {
if (changedPluginId === pluginId) {
loadPluginData()
loadPluginData();
}
}
}
function loadPluginData() {
if (!pluginService || !pluginId) {
pluginData = {}
variants = []
return
pluginData = {};
variants = [];
return;
}
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId)
variants = pluginService.getPluginVariants(pluginId)
pluginData = SettingsData.getPluginSettingsForPlugin(pluginId);
variants = pluginService.getPluginVariants(pluginId);
}
function createVariant(variantName, variantConfig) {
if (!pluginService || !pluginId) {
return null
return null;
}
return pluginService.createPluginVariant(pluginId, variantName, variantConfig)
return pluginService.createPluginVariant(pluginId, variantName, variantConfig);
}
function removeVariant(variantId) {
if (!pluginService || !pluginId) {
return
return;
}
pluginService.removePluginVariant(pluginId, variantId)
pluginService.removePluginVariant(pluginId, variantId);
}
function updateVariant(variantId, variantConfig) {
if (!pluginService || !pluginId) {
return
return;
}
pluginService.updatePluginVariant(pluginId, variantId, variantConfig)
pluginService.updatePluginVariant(pluginId, variantId, variantConfig);
}
width: isVertical ? (hasVerticalPill ? verticalPill.width : 0) : (hasHorizontalPill ? horizontalPill.width : 0)
@@ -108,30 +108,32 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
barSpacing: root.barSpacing
barConfig: root.barConfig
content: root.horizontalBarPill
onClicked: {
if (pillClickAction) {
if (pillClickAction.length === 0) {
pillClickAction()
pillClickAction();
} else {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen);
}
} else if (hasPopout) {
pluginPopout.toggle()
pluginPopout.toggle();
}
}
onRightClicked: {
if (pillRightClickAction) {
if (pillRightClickAction.length === 0) {
pillRightClickAction()
pillRightClickAction();
} else {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen);
}
}
}
@@ -146,31 +148,33 @@ Item {
parentScreen: root.parentScreen
widgetThickness: root.widgetThickness
barThickness: root.barThickness
barSpacing: root.barSpacing
barConfig: root.barConfig
content: root.verticalBarPill
isVerticalOrientation: true
onClicked: {
if (pillClickAction) {
if (pillClickAction.length === 0) {
pillClickAction()
pillClickAction();
} else {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillClickAction(pos.x, pos.y, pos.width, section, currentScreen);
}
} else if (hasPopout) {
pluginPopout.toggle()
pluginPopout.toggle();
}
}
onRightClicked: {
if (pillRightClickAction) {
if (pillRightClickAction.length === 0) {
pillRightClickAction()
pillRightClickAction();
} else {
const globalPos = mapToGlobal(0, 0)
const currentScreen = parentScreen || Screen
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen)
const globalPos = mapToGlobal(0, 0);
const currentScreen = parentScreen || Screen;
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width);
pillRightClickAction(pos.x, pos.y, pos.width, section, currentScreen);
}
}
}
@@ -178,7 +182,7 @@ Item {
function closePopout() {
if (pluginPopout) {
pluginPopout.close()
pluginPopout.close();
}
}

View File

@@ -13,14 +13,6 @@ DankPopout {
property real contentWidth: 400
property real contentHeight: 0
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
triggerScreen = screen
}
popupWidth: contentWidth
popupHeight: contentHeight
screen: triggerScreen

View File

@@ -19,14 +19,6 @@ DankPopout {
property var parentWidget: null
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
function hide() {
close();
if (processContextMenu.visible) {
@@ -40,8 +32,6 @@ DankPopout {
popupWidth: 600
popupHeight: 600
triggerX: Screen.width - 600 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 55
positioning: ""
screen: triggerScreen

File diff suppressed because it is too large Load Diff

View File

@@ -9,53 +9,83 @@ import qs.Widgets
Item {
id: displaysTab
property var variantComponents: [{
"id": "dankBar",
"name": "Dank Bar",
"description": I18n.tr("System bar with widgets and system information"),
"icon": "toolbar"
}, {
"id": "dock",
"name": I18n.tr("Application Dock"),
"description": I18n.tr("Bottom dock for pinned and running applications"),
"icon": "dock"
}, {
"id": "notifications",
"name": I18n.tr("Notification Popups"),
"description": I18n.tr("Notification toast popups"),
"icon": "notifications"
}, {
"id": "wallpaper",
"name": I18n.tr("Wallpaper"),
"description": I18n.tr("Desktop background images"),
"icon": "wallpaper"
}, {
"id": "osd",
"name": I18n.tr("On-Screen Displays"),
"description": I18n.tr("Volume, brightness, and other system OSDs"),
"icon": "picture_in_picture"
}, {
"id": "toast",
"name": I18n.tr("Toast Messages"),
"description": I18n.tr("System toast notifications"),
"icon": "campaign"
}, {
"id": "notepad",
"name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("Quick note-taking slideout panel"),
"icon": "sticky_note_2"
}, {
"id": "systemTray",
"name": I18n.tr("System Tray"),
"description": I18n.tr("System tray icons"),
"icon": "notifications"
}]
function getBarComponentsFromSettings() {
const bars = SettingsData.barConfigs || []
return bars.map(bar => ({
"id": "bar:" + bar.id,
"name": bar.name || "Bar",
"description": I18n.tr("Individual bar configuration"),
"icon": "toolbar",
"barId": bar.id
}))
}
property var variantComponents: getVariantComponentsList()
function getVariantComponentsList() {
return [
...getBarComponentsFromSettings(),
{
"id": "dock",
"name": I18n.tr("Application Dock"),
"description": I18n.tr("Bottom dock for pinned and running applications"),
"icon": "dock"
}, {
"id": "notifications",
"name": I18n.tr("Notification Popups"),
"description": I18n.tr("Notification toast popups"),
"icon": "notifications"
}, {
"id": "wallpaper",
"name": I18n.tr("Wallpaper"),
"description": I18n.tr("Desktop background images"),
"icon": "wallpaper"
}, {
"id": "osd",
"name": I18n.tr("On-Screen Displays"),
"description": I18n.tr("Volume, brightness, and other system OSDs"),
"icon": "picture_in_picture"
}, {
"id": "toast",
"name": I18n.tr("Toast Messages"),
"description": I18n.tr("System toast notifications"),
"icon": "campaign"
}, {
"id": "notepad",
"name": I18n.tr("Notepad Slideout"),
"description": I18n.tr("Quick note-taking slideout panel"),
"icon": "sticky_note_2"
}, {
"id": "systemTray",
"name": I18n.tr("System Tray"),
"description": I18n.tr("System tray icons"),
"icon": "notifications"
}
]
}
Connections {
target: SettingsData
function onBarConfigsChanged() {
variantComponents = getVariantComponentsList()
}
}
function getScreenPreferences(componentId) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.screenPreferences || ["all"]
}
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"];
}
function setScreenPreferences(componentId, screenNames) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { screenPreferences: screenNames })
return
}
var prefs = SettingsData.screenPreferences || {};
var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = screenNames;
@@ -63,10 +93,20 @@ Item {
}
function getShowOnLastDisplay(componentId) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
const barConfig = SettingsData.getBarConfig(barId)
return barConfig?.showOnLastDisplay ?? true
}
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false;
}
function setShowOnLastDisplay(componentId, enabled) {
if (componentId.startsWith("bar:")) {
const barId = componentId.substring(4)
SettingsData.updateBarConfig(barId, { showOnLastDisplay: enabled })
return
}
var prefs = SettingsData.showOnLastDisplay || {};
var newPrefs = Object.assign({}, prefs);
newPrefs[componentId] = enabled;
@@ -251,7 +291,6 @@ Item {
}
onTabClicked: index => {
console.log("Tab clicked:", index, "Setting mode to:", index === 1 ? "location" : "time")
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time")
currentIndex = index
}
@@ -756,8 +795,9 @@ Item {
displaysTab.setScreenPreferences(parent.componentId, ["all"])
} else {
displaysTab.setScreenPreferences(parent.componentId, [])
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(parent.componentId)) {
displaysTab.setShowOnLastDisplay(parent.componentId, true)
const cid = parent.componentId
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
displaysTab.setShowOnLastDisplay(cid, true)
}
}
}
@@ -769,9 +809,11 @@ Item {
description: I18n.tr("Always show when there's only one connected display")
checked: displaysTab.getShowOnLastDisplay(parent.componentId)
visible: {
var prefs = displaysTab.getScreenPreferences(parent.componentId)
var isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
return !isAll && ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(parent.componentId)
const prefs = displaysTab.getScreenPreferences(parent.componentId)
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
const cid = parent.componentId
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(cid) || cid.startsWith("bar:")
return !isAll && isRelevantComponent
}
onToggled: (checked) => {
displaysTab.setShowOnLastDisplay(parent.componentId, checked)
@@ -854,4 +896,4 @@ Item {
}
}
}

View File

@@ -755,43 +755,6 @@ Item {
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Dank Bar Transparency")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: I18n.tr("Controls opacity of the DankBar panel background")
font.pixelSize: Theme.fontSizeSmall - 2
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
DankSlider {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dankBarTransparency",
newValue / 100)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
@@ -808,14 +771,14 @@ Item {
StyledText {
id: transparencyLabel
text: I18n.tr("Dank Bar Widget Transparency")
text: I18n.tr("Widget Background Color")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: I18n.tr("Controls opacity of individual widgets inside DankBar")
text: I18n.tr("Choose the background color for widgets")
font.pixelSize: Theme.fontSizeSmall - 2
color: Theme.surfaceVariantText
width: parent.width
@@ -855,23 +818,6 @@ Item {
}
}
}
DankSlider {
width: parent.width
height: 24
value: Math.round(
SettingsData.dankBarWidgetTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dankBarWidgetTransparency",
newValue / 100)
}
}
}
Column {

View File

@@ -11,22 +11,12 @@ DankPopout {
property var parentWidget: null
property var triggerScreen: null
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x;
triggerY = y;
triggerWidth = width;
triggerSection = section;
triggerScreen = screen;
}
Ref {
service: SystemUpdateService
}
popupWidth: 400
popupHeight: 500
triggerX: Screen.width - 600 - Theme.spacingL
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
triggerWidth: 55
positioning: ""
screen: triggerScreen

View File

@@ -72,7 +72,7 @@ PanelWindow {
width: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth
height: toastContent.height + Theme.spacingL * 2
anchors.horizontalCenter: parent.horizontalCenter
y: Theme.barHeight - 4 + SettingsData.dankBarSpacing + 2
y: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2
color: {
switch (ToastService.currentLevel) {
case ToastService.levelError:

View File

@@ -463,7 +463,7 @@ Variants {
MultiEffect {
anchors.fill: parent
source: effectLoader.active ? effectLoader.item : (root.actualTransitionType === "none" ? currentWallpaper : null)
visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview
visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && source !== null
blurEnabled: true
blur: 0.8
blurMax: 75

View File

@@ -26,38 +26,42 @@ Singleton {
property var sortedToplevels: []
property bool _sortScheduled: false
signal toplevelsChanged()
signal toplevelsChanged
function getScreenScale(screen) {
if (!screen) return 1
if (!screen)
return 1;
if (Quickshell.env("QT_WAYLAND_FORCE_DPI") || Quickshell.env("QT_SCALE_FACTOR")) {
return screen.devicePixelRatio || 1
return screen.devicePixelRatio || 1;
}
if (WlrOutputService.wlrOutputAvailable && screen) {
const wlrOutput = WlrOutputService.getOutput(screen.name)
const wlrOutput = WlrOutputService.getOutput(screen.name);
if (wlrOutput?.enabled && wlrOutput.scale !== undefined && wlrOutput.scale > 0) {
return Math.round(wlrOutput.scale * 20) / 20
return Math.round(wlrOutput.scale * 20) / 20;
}
}
if (isNiri && screen) {
const niriScale = NiriService.displayScales[screen.name]
if (niriScale !== undefined) return niriScale
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
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
const dwlScale = DwlService.getOutputScale(screen.name);
if (dwlScale !== undefined && dwlScale > 0)
return dwlScale;
}
return screen?.devicePixelRatio || 1
return screen?.devicePixelRatio || 1;
}
Timer {
@@ -65,127 +69,129 @@ Singleton {
interval: 100
repeat: false
onTriggered: {
_sortScheduled = false
sortedToplevels = computeSortedToplevels()
toplevelsChanged()
_sortScheduled = false;
sortedToplevels = computeSortedToplevels();
toplevelsChanged();
}
}
function scheduleSort() {
if (_sortScheduled) return
_sortScheduled = true
sortDebounceTimer.restart()
if (_sortScheduled)
return;
_sortScheduled = true;
sortDebounceTimer.restart();
}
Connections {
target: ToplevelManager.toplevels
function onValuesChanged() { root.scheduleSort() }
function onValuesChanged() {
root.scheduleSort();
}
}
Connections {
target: isHyprland ? Hyprland : null
enabled: isHyprland
function onRawEvent(event) {
if (event.name === "openwindow" ||
event.name === "closewindow" ||
event.name === "movewindow" ||
event.name === "movewindowv2" ||
event.name === "workspace" ||
event.name === "workspacev2" ||
event.name === "focusedmon" ||
event.name === "focusedmonv2" ||
event.name === "activewindow" ||
event.name === "activewindowv2" ||
event.name === "changefloatingmode" ||
event.name === "fullscreen" ||
event.name === "moveintogroup" ||
event.name === "moveoutofgroup") {
if (event.name === "openwindow" || event.name === "closewindow" || event.name === "movewindow" || event.name === "movewindowv2" || event.name === "workspace" || event.name === "workspacev2" || event.name === "focusedmon" || event.name === "focusedmonv2" || event.name === "activewindow" || event.name === "activewindowv2" || event.name === "changefloatingmode" || event.name === "fullscreen" || event.name === "moveintogroup" || event.name === "moveoutofgroup") {
try {
Hyprland.refreshToplevels()
} catch(e) {}
root.scheduleSort()
Hyprland.refreshToplevels();
} catch (e) {}
root.scheduleSort();
}
}
}
Connections {
target: NiriService
function onWindowsChanged() { root.scheduleSort() }
function onWindowsChanged() {
root.scheduleSort();
}
}
Component.onCompleted: {
detectCompositor()
scheduleSort()
Qt.callLater(() => NiriService.generateNiriLayoutConfig())
detectCompositor();
scheduleSort();
Qt.callLater(() => NiriService.generateNiriLayoutConfig());
}
Connections {
target: DwlService
function onStateChanged() {
if (isDwl && !isHyprland && !isNiri) {
scheduleSort()
scheduleSort();
}
}
}
function computeSortedToplevels() {
if (!ToplevelManager.toplevels || !ToplevelManager.toplevels.values)
return []
return [];
if (useNiriSorting)
return NiriService.sortToplevels(ToplevelManager.toplevels.values)
return NiriService.sortToplevels(ToplevelManager.toplevels.values);
if (isHyprland)
return sortHyprlandToplevelsSafe()
return sortHyprlandToplevelsSafe();
return Array.from(ToplevelManager.toplevels.values)
return Array.from(ToplevelManager.toplevels.values);
}
function _get(o, path, fallback) {
try {
let v = o
let v = o;
for (let i = 0; i < path.length; i++) {
if (v === null || v === undefined) return fallback
v = v[path[i]]
if (v === null || v === undefined)
return fallback;
v = v[path[i]];
}
return (v === undefined || v === null) ? fallback : v
} catch (e) { return fallback }
return (v === undefined || v === null) ? fallback : v;
} catch (e) {
return fallback;
}
}
function sortHyprlandToplevelsSafe() {
if (!Hyprland.toplevels || !Hyprland.toplevels.values) return []
if (!Hyprland.toplevels || !Hyprland.toplevels.values)
return [];
const items = Array.from(Hyprland.toplevels.values)
const items = Array.from(Hyprland.toplevels.values);
function _get(o, path, fb) {
try {
let v = o
for (let k of path) { if (v == null) return fb; v = v[k] }
return (v == null) ? fb : v
} catch(e) { return fb }
let v = o;
for (let k of path) {
if (v == null)
return fb;
v = v[k];
}
return (v == null) ? fb : v;
} catch (e) {
return fb;
}
}
let snap = []
let snap = [];
for (let i = 0; i < items.length; i++) {
const t = items[i]
if (!t) continue
const t = items[i];
if (!t)
continue;
const addr = t.address || "";
if (!addr)
continue;
const li = t.lastIpcObject || null;
const addr = t.address || ""
if (!addr) continue
const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "");
const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER);
const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER);
const li = t.lastIpcObject || null
const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER);
const monName = _get(li, ["monitor"], null) ?? _get(t, ["monitor", "name"], "")
const monX = _get(t, ["monitor", "x"], Number.MAX_SAFE_INTEGER)
const monY = _get(t, ["monitor", "y"], Number.MAX_SAFE_INTEGER)
const at = _get(li, ["at"], null);
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9;
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9;
const wsId = _get(li, ["workspace", "id"], null) ?? _get(t, ["workspace", "id"], Number.MAX_SAFE_INTEGER)
const at = _get(li, ["at"], null)
let atX = (at !== null && at !== undefined && typeof at[0] === "number") ? at[0] : 1e9
let atY = (at !== null && at !== undefined && typeof at[1] === "number") ? at[1] : 1e9
const relX = Number.isFinite(monX) ? (atX - monX) : atX
const relY = Number.isFinite(monY) ? (atY - monY) : atY
const relX = Number.isFinite(monX) ? (atX - monX) : atX;
const relY = Number.isFinite(monY) ? (atY - monY) : atY;
snap.push({
monKey: String(monName),
@@ -197,19 +203,20 @@ Singleton {
title: t.title || "",
address: addr,
wayland: t.wayland
})
});
}
const groups = new Map()
const groups = new Map();
for (const it of snap) {
const key = it.monKey + "::" + it.wsId
if (!groups.has(key)) groups.set(key, [])
groups.get(key).push(it)
const key = it.monKey + "::" + it.wsId;
if (!groups.has(key))
groups.set(key, []);
groups.get(key).push(it);
}
let groupList = []
let groupList = [];
for (const [key, arr] of groups) {
const repr = arr[0]
const repr = arr[0];
groupList.push({
key,
monKey: repr.monKey,
@@ -217,122 +224,143 @@ Singleton {
monOrderY: repr.monOrderY,
wsId: repr.wsId,
items: arr
})
});
}
groupList.sort((a, b) => {
if (a.monOrderX !== b.monOrderX) return a.monOrderX - b.monOrderX
if (a.monOrderY !== b.monOrderY) return a.monOrderY - b.monOrderY
if (a.monKey !== b.monKey) return a.monKey.localeCompare(b.monKey)
if (a.wsId !== b.wsId) return a.wsId - b.wsId
return 0
})
if (a.monOrderX !== b.monOrderX)
return a.monOrderX - b.monOrderX;
if (a.monOrderY !== b.monOrderY)
return a.monOrderY - b.monOrderY;
if (a.monKey !== b.monKey)
return a.monKey.localeCompare(b.monKey);
if (a.wsId !== b.wsId)
return a.wsId - b.wsId;
return 0;
});
const COLUMN_THRESHOLD = 48
const JITTER_Y = 6
const COLUMN_THRESHOLD = 48;
const JITTER_Y = 6;
let ordered = []
let ordered = [];
for (const g of groupList) {
const arr = g.items
const arr = g.items;
const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b)
let colCenters = []
const xs = arr.map(it => it.x).filter(x => Number.isFinite(x)).sort((a, b) => a - b);
let colCenters = [];
if (xs.length > 0) {
for (const x of xs) {
if (colCenters.length === 0) {
colCenters.push(x)
colCenters.push(x);
} else {
const last = colCenters[colCenters.length - 1]
const last = colCenters[colCenters.length - 1];
if (x - last >= COLUMN_THRESHOLD) {
colCenters.push(x)
colCenters.push(x);
}
}
}
} else {
colCenters = [0]
colCenters = [0];
}
for (const it of arr) {
let bestCol = 0
let bestDist = Number.POSITIVE_INFINITY
let bestCol = 0;
let bestDist = Number.POSITIVE_INFINITY;
for (let ci = 0; ci < colCenters.length; ci++) {
const d = Math.abs(it.x - colCenters[ci])
const d = Math.abs(it.x - colCenters[ci]);
if (d < bestDist) {
bestDist = d
bestCol = ci
bestDist = d;
bestCol = ci;
}
}
it._col = bestCol
it._col = bestCol;
}
arr.sort((a, b) => {
if (a._col !== b._col) return a._col - b._col
if (a._col !== b._col)
return a._col - b._col;
const dy = a.y - b.y
if (Math.abs(dy) > JITTER_Y) return dy
const dy = a.y - b.y;
if (Math.abs(dy) > JITTER_Y)
return dy;
if (a.title !== b.title) return a.title.localeCompare(b.title)
if (a.address !== b.address) return a.address.localeCompare(b.address)
return 0
})
if (a.title !== b.title)
return a.title.localeCompare(b.title);
if (a.address !== b.address)
return a.address.localeCompare(b.address);
return 0;
});
ordered.push.apply(ordered, arr)
ordered.push.apply(ordered, arr);
}
return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined)
return ordered.map(x => x.wayland).filter(w => w !== null && w !== undefined);
}
function filterCurrentWorkspace(toplevels, screen) {
if (useNiriSorting) return NiriService.filterCurrentWorkspace(toplevels, screen)
if (isHyprland) return filterHyprlandCurrentWorkspaceSafe(toplevels, screen)
return toplevels
if (useNiriSorting)
return NiriService.filterCurrentWorkspace(toplevels, screen);
if (isHyprland)
return filterHyprlandCurrentWorkspaceSafe(toplevels, screen);
return toplevels;
}
function filterHyprlandCurrentWorkspaceSafe(toplevels, screenName) {
if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels) return toplevels
if (!toplevels || toplevels.length === 0 || !Hyprland.toplevels)
return toplevels;
let currentWorkspaceId = null
let currentWorkspaceId = null;
try {
const hy = Array.from(Hyprland.toplevels.values)
const hy = Array.from(Hyprland.toplevels.values);
for (const t of hy) {
const mon = _get(t, ["monitor", "name"], "")
const wsId = _get(t, ["workspace", "id"], null)
const active = !!_get(t, ["activated"], false)
const mon = _get(t, ["monitor", "name"], "");
const wsId = _get(t, ["workspace", "id"], null);
const active = !!_get(t, ["activated"], false);
if (mon === screenName && wsId !== null) {
if (active) { currentWorkspaceId = wsId; break }
if (currentWorkspaceId === null) currentWorkspaceId = wsId
if (active) {
currentWorkspaceId = wsId;
break;
}
if (currentWorkspaceId === null)
currentWorkspaceId = wsId;
}
}
if (currentWorkspaceId === null && Hyprland.workspaces) {
const wss = Array.from(Hyprland.workspaces.values)
const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null)
const wss = Array.from(Hyprland.workspaces.values);
const focusedId = _get(Hyprland, ["focusedWorkspace", "id"], null);
for (const ws of wss) {
const monName = _get(ws, ["monitor"], "")
const wsId = _get(ws, ["id"], null)
const monName = _get(ws, ["monitor"], "");
const wsId = _get(ws, ["id"], null);
if (monName === screenName && wsId !== null) {
if (focusedId !== null && wsId === focusedId) { currentWorkspaceId = wsId; break }
if (currentWorkspaceId === null) currentWorkspaceId = wsId
if (focusedId !== null && wsId === focusedId) {
currentWorkspaceId = wsId;
break;
}
if (currentWorkspaceId === null)
currentWorkspaceId = wsId;
}
}
}
} catch (e) {
console.warn("CompositorService: workspace snapshot failed:", e)
console.warn("CompositorService: workspace snapshot failed:", e);
}
if (currentWorkspaceId === null) return toplevels
if (currentWorkspaceId === null)
return toplevels;
// Map wayland → wsId snapshot
let map = new Map()
let map = new Map();
try {
const hy = Array.from(Hyprland.toplevels.values)
const hy = Array.from(Hyprland.toplevels.values);
for (const t of hy) {
const wsId = _get(t, ["workspace", "id"], null)
if (t && t.wayland && wsId !== null) map.set(t.wayland, wsId)
const wsId = _get(t, ["workspace", "id"], null);
if (t && t.wayland && wsId !== null)
map.set(t.wayland, wsId);
}
} catch (e) {}
return toplevels.filter(w => map.get(w) === currentWorkspaceId)
return toplevels.filter(w => map.get(w) === currentWorkspaceId);
}
Timer {
@@ -341,77 +369,76 @@ Singleton {
running: true
repeat: false
onTriggered: {
detectCompositor()
Qt.callLater(() => NiriService.generateNiriLayoutConfig())
detectCompositor();
Qt.callLater(() => NiriService.generateNiriLayoutConfig());
}
}
function detectCompositor() {
if (hyprlandSignature && hyprlandSignature.length > 0 &&
!niriSocket && !swaySocket && !labwcPid) {
isHyprland = true
isNiri = false
isDwl = false
isSway = false
isLabwc = false
compositor = "hyprland"
console.info("CompositorService: Detected Hyprland")
return
if (hyprlandSignature && hyprlandSignature.length > 0 && !niriSocket && !swaySocket && !labwcPid) {
isHyprland = true;
isNiri = false;
isDwl = false;
isSway = false;
isLabwc = false;
compositor = "hyprland";
console.info("CompositorService: Detected Hyprland");
return;
}
if (niriSocket && niriSocket.length > 0) {
Proc.runCommand("niriSocketCheck", ["test", "-S", niriSocket], (output, exitCode) => {
if (exitCode === 0) {
isNiri = true
isHyprland = false
isDwl = false
isSway = false
isLabwc = false
compositor = "niri"
console.info("CompositorService: Detected Niri with socket:", niriSocket)
NiriService.generateNiriBinds()
NiriService.generateNiriBlurrule()
isNiri = true;
isHyprland = false;
isDwl = false;
isSway = false;
isLabwc = false;
compositor = "niri";
console.info("CompositorService: Detected Niri with socket:", niriSocket);
NiriService.generateNiriBinds();
NiriService.generateNiriBlurrule();
}
}, 0)
return
}, 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
isLabwc = false
compositor = "sway"
console.info("CompositorService: Detected Sway with socket:", swaySocket)
isNiri = false;
isHyprland = false;
isDwl = false;
isSway = true;
isLabwc = false;
compositor = "sway";
console.info("CompositorService: Detected Sway with socket:", swaySocket);
}
}, 0)
return
}, 0);
return;
}
if (labwcPid && labwcPid.length > 0) {
isHyprland = false
isNiri = false
isDwl = false
isSway = false
isLabwc = true
compositor = "labwc"
console.info("CompositorService: Detected LabWC with PID:", labwcPid)
return
isHyprland = false;
isNiri = false;
isDwl = false;
isSway = false;
isLabwc = true;
compositor = "labwc";
console.info("CompositorService: Detected LabWC with PID:", labwcPid);
return;
}
if (DMSService.dmsAvailable) {
Qt.callLater(checkForDwl)
Qt.callLater(checkForDwl);
} else {
isHyprland = false
isNiri = false
isDwl = false
isSway = false
isLabwc = false
compositor = "unknown"
console.warn("CompositorService: No compositor detected")
isHyprland = false;
isNiri = false;
isDwl = false;
isSway = false;
isLabwc = false;
compositor = "unknown";
console.warn("CompositorService: No compositor detected");
}
}
@@ -419,65 +446,85 @@ Singleton {
target: DMSService
function onCapabilitiesReceived() {
if (!isHyprland && !isNiri && !isDwl && !isLabwc) {
checkForDwl()
checkForDwl();
}
}
}
function checkForDwl() {
if (DMSService.apiVersion >= 12 && DMSService.capabilities.includes("dwl")) {
isHyprland = false
isNiri = false
isDwl = true
isSway = false
isLabwc = false
compositor = "dwl"
console.info("CompositorService: Detected DWL via DMS capability")
isHyprland = false;
isNiri = false;
isDwl = true;
isSway = false;
isLabwc = false;
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 }
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "off"]) }
console.warn("CompositorService: Cannot power off monitors, unknown compositor")
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;
}
if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "off"]);
}
console.warn("CompositorService: Cannot power off monitors, unknown compositor");
}
function powerOnMonitors() {
if (isNiri) return NiriService.powerOnMonitors()
if (isHyprland) return Hyprland.dispatch("dpms on")
if (isDwl) return _dwlPowerOnMonitors()
if (isSway) { try { I3.dispatch("output * dpms on") } catch(_){} return }
if (isLabwc) { Quickshell.execDetached(["dms", "dpms", "on"]) }
console.warn("CompositorService: Cannot power on monitors, unknown compositor")
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;
}
if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "on"]);
}
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
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]
const screen = Quickshell.screens[i];
if (screen && screen.name) {
Quickshell.execDetached(["mmsg", "-d", "disable_monitor," + 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
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]
const screen = Quickshell.screens[i];
if (screen && screen.name) {
Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name])
Quickshell.execDetached(["mmsg", "-d", "enable_monitor," + screen.name]);
}
}
}

View File

@@ -962,7 +962,7 @@ Singleton {
console.log("NiriService: Generating layout config...")
const cornerRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12
const gaps = typeof SettingsData !== "undefined" ? Math.max(4, SettingsData.dankBarSpacing) : 4
const gaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4
const configContent = `layout {
gaps ${gaps}

View File

@@ -411,6 +411,16 @@ Singleton {
NotifWrapper {}
}
function clearAllPopups() {
for (const w of visibleNotifications) {
if (w) {
w.popup = false
}
}
visibleNotifications = []
notificationQueue = []
}
function clearAllNotifications() {
bulkDismissing = true
popupsDisabled = true

View File

@@ -428,9 +428,12 @@ Singleton {
return id !== widgetId
}
const leftWidgets = SettingsData.dankBarLeftWidgets
const centerWidgets = SettingsData.dankBarCenterWidgets
const rightWidgets = SettingsData.dankBarRightWidgets
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return
const leftWidgets = defaultBar.leftWidgets || []
const centerWidgets = defaultBar.centerWidgets || []
const rightWidgets = defaultBar.rightWidgets || []
const newLeft = leftWidgets.filter(filterWidget)
const newCenter = centerWidgets.filter(filterWidget)

View File

@@ -78,14 +78,19 @@ PanelWindow {
readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter
readonly property real barThickness: {
if (!SettingsData.dankBarVisible) return 0
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
return Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar || !(defaultBar.visible ?? true)) return 0
const innerPadding = defaultBar.innerPadding ?? 4
const widgetThickness = Math.max(20, 26 + innerPadding * 0.6)
return Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding))
}
readonly property real barOffset: {
if (!SettingsData.dankBarVisible) return 0
return barThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar || !(defaultBar.visible ?? true)) return 0
const spacing = defaultBar.spacing ?? 4
const bottomGap = defaultBar.bottomGap ?? 0
return barThickness + spacing + bottomGap
}
readonly property real dockThickness: {
@@ -102,23 +107,26 @@ PanelWindow {
const margin = Theme.spacingM
const centerX = (screenWidth - alignedWidth) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) {
case SettingsData.Position.Left:
case SettingsData.Position.Bottom:
const leftBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
const leftBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0
const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr)
case SettingsData.Position.Top:
case SettingsData.Position.Right:
const rightBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
const rightBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0
const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr)
case SettingsData.Position.LeftCenter:
const leftCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Left ? barOffset : 0
const leftCenterBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0
const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0
return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr)
case SettingsData.Position.RightCenter:
const rightCenterBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Right ? barOffset : 0
const rightCenterBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0
const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0
return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr)
case SettingsData.Position.TopCenter:
@@ -132,17 +140,20 @@ PanelWindow {
const margin = Theme.spacingM
const centerY = (screenHeight - alignedHeight) / 2
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
const barPos = defaultBar?.position ?? SettingsData.Position.Top
switch (SettingsData.osdPosition) {
case SettingsData.Position.Top:
case SettingsData.Position.Left:
case SettingsData.Position.TopCenter:
const topBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Top ? barOffset : 0
const topBarOffset = barPos === SettingsData.Position.Top ? barOffset : 0
const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0
return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr)
case SettingsData.Position.Right:
case SettingsData.Position.Bottom:
case SettingsData.Position.BottomCenter:
const bottomBarOffset = SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barOffset : 0
const bottomBarOffset = barPos === SettingsData.Position.Bottom ? barOffset : 0
const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0
return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr)
case SettingsData.Position.LeftCenter:
@@ -217,14 +228,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / blurMax))
shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -29,15 +29,23 @@ PanelWindow {
property list<real> animationExitCurve: Theme.expressiveCurves.emphasized
property bool shouldBeVisible: false
property real storedBarThickness: Theme.barHeight - 4
property real storedBarSpacing: 4
property var storedBarConfig: null
property var adjacentBarInfo: ({ "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 })
visible: false
readonly property real effectiveBarThickness: Math.max(26 + SettingsData.dankBarInnerPadding * 0.6, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing
readonly property real effectiveBarThickness: {
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing
}
readonly property var barBounds: {
if (!root.screen) {
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
}
return SettingsData.getBarBounds(root.screen, effectiveBarThickness)
return SettingsData.getBarBounds(root.screen, effectiveBarThickness, effectiveBarPosition, storedBarConfig)
}
readonly property real barX: barBounds.x
@@ -50,6 +58,31 @@ PanelWindow {
signal popoutClosed
signal backgroundClicked
function setBarContext(position, bottomGap) {
effectiveBarPosition = position !== undefined ? position : 0
effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0
}
function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) {
triggerX = x
triggerY = y
triggerWidth = width
triggerSection = section
root.screen = screen
storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4)
storedBarSpacing = barSpacing !== undefined ? barSpacing : 4
storedBarConfig = barConfig
const pos = barPosition !== undefined ? barPosition : 0
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0
// Get adjacent bar info for proper positioning
adjacentBarInfo = SettingsData.getAdjacentBarInfo(screen, pos, barConfig)
setBarContext(pos, bottomGap)
}
function open() {
closeTimer.stop()
shouldBeVisible = true
@@ -115,75 +148,71 @@ PanelWindow {
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
property int effectiveBarPosition: 0
property real effectiveBarBottomGap: 0
readonly property real alignedX: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left) {
return triggerY + SettingsData.dankBarBottomGap
} else if (SettingsData.dankBarPosition === SettingsData.Position.Right) {
return screenWidth - triggerY - SettingsData.dankBarBottomGap - popupWidth
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
let rawX = 0
if (effectiveBarPosition === SettingsData.Position.Left) {
rawX = triggerX
} else if (effectiveBarPosition === SettingsData.Position.Right) {
rawX = triggerX - popupWidth
} else {
const centerX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
return Math.max(Theme.popupDistance, Math.min(screenWidth - popupWidth - Theme.popupDistance, centerX))
rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap
const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap)
return Math.max(minX, Math.min(maxX, rawX))
}
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, rawX))
})(), dpr)
readonly property real alignedY: Theme.snap((() => {
if (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right) {
const centerY = triggerX + (triggerWidth / 2) - (popupHeight / 2)
return Math.max(Theme.popupDistance, Math.min(screenHeight - popupHeight - Theme.popupDistance, centerY))
} else if (SettingsData.dankBarPosition === SettingsData.Position.Bottom) {
return Math.max(Theme.popupDistance, screenHeight - triggerY - popupHeight)
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
let rawY = 0
if (effectiveBarPosition === SettingsData.Position.Bottom) {
rawY = triggerY - popupHeight
} else if (effectiveBarPosition === SettingsData.Position.Top) {
rawY = triggerY
} else {
return Math.min(screenHeight - popupHeight - Theme.popupDistance, triggerY)
rawY = triggerY - (popupHeight / 2)
const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap
const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap)
return Math.max(minY, Math.min(maxY, rawY))
}
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, rawY))
})(), dpr)
readonly property real maskX: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Left:
return root.barWidth > 0 ? root.barWidth : 0
case SettingsData.Position.Right:
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return 0
}
const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && root.barWidth > 0) ? root.barWidth : 0
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0
return Math.max(triggeringBarX, adjacentLeftBar)
}
readonly property real maskY: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top:
return root.barHeight > 0 ? root.barHeight : 0
case SettingsData.Position.Bottom:
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return 0
}
const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && root.barHeight > 0) ? root.barHeight : 0
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0
return Math.max(triggeringBarY, adjacentTopBar)
}
readonly property real maskWidth: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Left:
return root.barWidth > 0 ? root.width - root.barWidth : root.width
case SettingsData.Position.Right:
return root.barWidth > 0 ? root.width - root.barWidth : root.width
case SettingsData.Position.Top:
case SettingsData.Position.Bottom:
default:
return root.width
}
const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && root.barWidth > 0) ? root.barWidth : 0
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar)
return Math.max(100, root.width - maskX - rightExclusion)
}
readonly property real maskHeight: {
switch (SettingsData.dankBarPosition) {
case SettingsData.Position.Top:
return root.barHeight > 0 ? root.height - root.barHeight : root.height
case SettingsData.Position.Bottom:
return root.barHeight > 0 ? root.height - root.barHeight : root.height
case SettingsData.Position.Left:
case SettingsData.Position.Right:
default:
return root.height
}
const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && root.barHeight > 0) ? root.barHeight : 0
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar)
return Math.max(100, root.height - maskY - bottomExclusion)
}
mask: Region {
@@ -222,10 +251,10 @@ PanelWindow {
width: alignedWidth
height: alignedHeight
readonly property bool barTop: SettingsData.dankBarPosition === SettingsData.Position.Top
readonly property bool barBottom: SettingsData.dankBarPosition === SettingsData.Position.Bottom
readonly property bool barLeft: SettingsData.dankBarPosition === SettingsData.Position.Left
readonly property bool barRight: SettingsData.dankBarPosition === SettingsData.Position.Right
readonly property bool barTop: effectiveBarPosition === SettingsData.Position.Top
readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
readonly property bool barLeft: effectiveBarPosition === SettingsData.Position.Left
readonly property bool barRight: effectiveBarPosition === SettingsData.Position.Right
readonly property real offsetX: barLeft ? root.animationOffset : (barRight ? -root.animationOffset : 0)
readonly property real offsetY: barBottom ? -root.animationOffset : (barTop ? root.animationOffset : 0)
@@ -303,14 +332,15 @@ PanelWindow {
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
layer.textureMirroring: ShaderEffectSource.MirrorVertically
readonly property int blurMax: 64
layer.effect: MultiEffect {
id: shadowFx
autoPaddingEnabled: true
shadowEnabled: true
blurEnabled: false
maskEnabled: false
property int blurMax: 64
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / blurMax))
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / bgShadowLayer.blurMax))
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
shadowColor: {
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest

View File

@@ -28,9 +28,8 @@ Item {
function handleClick() {
if (!enabled) return
checked = !checked
clicked()
toggled(checked)
toggled(!checked)
}
StyledRect {

View File

@@ -50,13 +50,22 @@ PanelWindow {
margins {
left: {
if (alignLeft) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX)))
if (alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth)))
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.width ?? Screen.width) - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2)))
const screenWidth = targetScreen?.width ?? Screen.width
if (alignLeft) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX)))
} else if (alignRight) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth)))
} else {
return Math.round(Math.max(Theme.spacingS, Math.min(screenWidth - implicitWidth - Theme.spacingS, targetX - implicitWidth / 2)))
}
}
top: {
if (alignLeft || alignRight) return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2)))
return Math.round(Math.max(Theme.spacingS, Math.min((targetScreen?.height ?? Screen.height) - implicitHeight - Theme.spacingS, targetY)))
const screenHeight = targetScreen?.height ?? Screen.height
if (alignLeft || alignRight) {
return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY - implicitHeight / 2)))
} else {
return Math.round(Math.max(Theme.spacingS, Math.min(screenHeight - implicitHeight - Theme.spacingS, targetY)))
}
}
}

View File

@@ -45,24 +45,28 @@ Item {
Component.onCompleted: {
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $ID"], (output, exitCode) => {
if (exitCode !== 0) return
if (!root || exitCode !== 0 || !output) return
const distroId = output.trim()
if (!distroId) return
// Nerd fonts are better than images usually
const supportedDistroNFs = ["debian", "arch", "archcraft", "fedora", "nixos", "ubuntu", "guix", "gentoo", "endeavouros", "manjaro", "opensuse"]
if (supportedDistroNFs.includes(distroId)) {
if (!root) return
root.useNerdFont = true
root.nerdFontIcon = distroId
return
}
Proc.runCommand(null, ["sh", "-c", ". /etc/os-release && echo $LOGO"], (logoOutput, logoExitCode) => {
if (logoExitCode !== 0) return
if (!root || !iconImage || logoExitCode !== 0 || !logoOutput) return
const logo = logoOutput.trim()
if (!logo) return
if (logo === "cachyos") {
iconImage.source = "file:///usr/share/icons/cachyos.svg"
return
} else if (logo === "guix-icon") {
}
if (logo === "guix-icon") {
iconImage.source = "file:///run/current-system/profile/share/icons/hicolor/scalable/apps/guix-icon.svg"
return
}