Added distro logo (for SidePanel widget)

BarTab: add toggle for distro logo replacement
DistroLogoService: handle all logo detection logic
SidePanelToggle: add support for distro logo
WidgetLoader: fix small issue with with screen null warning
This commit is contained in:
Ly-sec 2025-09-02 17:01:38 +02:00
parent 91b355689c
commit eea1586772
5 changed files with 129 additions and 4 deletions

View file

@ -122,6 +122,7 @@ Singleton {
property bool alwaysShowBatteryPercentage: false property bool alwaysShowBatteryPercentage: false
property bool showNetworkStats: false property bool showNetworkStats: false
property real backgroundOpacity: 1.0 property real backgroundOpacity: 1.0
property bool useDistroLogo: false
property string showWorkspaceLabel: "none" property string showWorkspaceLabel: "none"
property list<string> monitors: [] property list<string> monitors: []
@ -142,8 +143,6 @@ Singleton {
property real radiusRatio: 1.0 property real radiusRatio: 1.0
// Animation speed multiplier (0.1x - 2.0x) // Animation speed multiplier (0.1x - 2.0x)
property real animationSpeed: 1.0 property real animationSpeed: 1.0
// Replace sidepanel toggle with distro logo (shown in bar and/or side panel)
property bool useDistroLogoForSidepanel: false
} }
// location // location

View file

@ -1,4 +1,6 @@
import Quickshell import Quickshell
import Quickshell.Widgets
import QtQuick.Effects
import qs.Commons import qs.Commons
import qs.Widgets import qs.Widgets
import qs.Services import qs.Services
@ -9,7 +11,7 @@ NIconButton {
property ShellScreen screen property ShellScreen screen
property real scaling: 1.0 property real scaling: 1.0
icon: "widgets" icon: Settings.data.bar.useDistroLogo ? "" : "widgets"
tooltipText: "Open side panel" tooltipText: "Open side panel"
sizeRatio: 0.8 sizeRatio: 0.8
@ -20,4 +22,25 @@ NIconButton {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onClicked: PanelService.getPanel("sidePanel")?.toggle(screen) onClicked: PanelService.getPanel("sidePanel")?.toggle(screen)
// When enabled, draw the distro logo instead of the icon glyph
IconImage {
id: logo
anchors.centerIn: parent
width: root.width * 0.6
height: width
source: Settings.data.bar.useDistroLogo ? DistroLogoService.osLogo : ""
visible: false //Settings.data.bar.useDistroLogo && source !== ""
smooth: true
}
MultiEffect {
anchors.fill: logo
source: logo
//visible: logo.visible
colorization: 1
brightness: 1
saturation: 1
colorizationColor: root.hovering ? Color.mSurfaceVariant : Color.mOnSurface
}
} }

View file

@ -97,6 +97,15 @@ ColumnLayout {
} }
} }
NToggle {
label: "Replace SidePanel toggle with distro logo"
description: "Show distro logo instead of the SidePanel toggle button in the bar."
checked: Settings.data.bar.useDistroLogo
onToggled: checked => {
Settings.data.bar.useDistroLogo = checked
}
}
NComboBox { NComboBox {
label: "Show Workspaces Labels" label: "Show Workspaces Labels"
description: "Display the workspace name or index in the workspace indicator" description: "Display the workspace name or index in the workspace indicator"

View file

@ -0,0 +1,94 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
Singleton {
id: root
// Public properties
property string osPretty: ""
property string osLogo: ""
// Internal helpers
function buildCandidates(name) {
const n = (name || "").trim()
if (!n)
return []
const sizes = ["512x512", "256x256", "128x128", "64x64", "48x48", "32x32", "24x24", "22x22", "16x16"]
const exts = ["svg", "png"]
const candidates = []
// pixmaps
for (const ext of exts) {
candidates.push(`/usr/share/pixmaps/${n}.${ext}`)
}
// hicolor scalable and raster sizes
candidates.push(`/usr/share/icons/hicolor/scalable/apps/${n}.svg`)
for (const s of sizes) {
for (const ext of exts) {
candidates.push(`/usr/share/icons/hicolor/${s}/apps/${n}.${ext}`)
}
}
// Generic icon themes under /usr/share/icons (common cases)
for (const ext of exts) {
candidates.push(`/usr/share/icons/${n}.${ext}`)
candidates.push(`/usr/share/icons/${n}/${n}.${ext}`)
candidates.push(`/usr/share/icons/${n}/apps/${n}.${ext}`)
}
return candidates
}
function resolveLogo(name) {
const all = buildCandidates(name)
if (all.length === 0)
return
const script = all.map(p => `if [ -f "${p}" ]; then echo "${p}"; exit 0; fi`).join("; ") + "; exit 1"
probe.command = ["sh", "-c", script]
probe.running = true
}
// Read /etc/os-release and trigger resolution
FileView {
id: osInfo
path: "/etc/os-release"
onLoaded: {
try {
const lines = text().split("\n")
const val = k => {
const l = lines.find(x => x.startsWith(k + "="))
return l ? l.split("=")[1].replace(/"/g, "") : ""
}
root.osPretty = val("PRETTY_NAME") || val("NAME")
const logoName = val("LOGO")
if (logoName)
resolveLogo(logoName)
} catch (e) {
Logger.warn("DistroLogoService", "failed to read os-release", e)
}
}
}
Process {
id: probe
onExited: code => {
const p = String(stdout.text || "").trim()
if (code === 0 && p) {
root.osLogo = `file://${p}`
Logger.log("DistroLogoService", "found", root.osLogo)
} else {
root.osLogo = ""
Logger.warn("DistroLogoService", "none found")
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
}
}

View file

@ -13,7 +13,7 @@ Item {
Connections { Connections {
target: ScalingService target: ScalingService
function onScaleChanged(screenName, scale) { function onScaleChanged(screenName, scale) {
if ((loader.item.screen !== null) && (screenName === loader.item.screen.name)) { if (loader.item && loader.item.screen && screenName === loader.item.screen.name) {
loader.item['scaling'] = scale loader.item['scaling'] = scale
} }
} }