From 2c5c462aaaa0b1729397529021493515c676c8a2 Mon Sep 17 00:00:00 2001 From: Olaf Luijks Date: Fri, 14 Nov 2025 04:15:55 +0100 Subject: [PATCH] HostService: add user display name and use it in UI - Add username/envRealName/realName and displayName to HostService - Resolve real name from `getent passwd $USER` with NOCTALIA_REALNAME override - Use HostService.displayName on the lock screen and in the Control Center profile card --- Modules/LockScreen/LockContext.qml | 3 +- Modules/LockScreen/LockScreen.qml | 3 +- .../ControlCenter/Cards/ProfileCard.qml | 3 +- Modules/Panels/Settings/Tabs/GeneralTab.qml | 2 +- Services/System/HostService.qml | 40 +++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Modules/LockScreen/LockContext.qml b/Modules/LockScreen/LockContext.qml index ed31d0fa..31b07f34 100644 --- a/Modules/LockScreen/LockContext.qml +++ b/Modules/LockScreen/LockContext.qml @@ -2,6 +2,7 @@ import QtQuick import Quickshell import Quickshell.Services.Pam import qs.Commons +import qs.Services.System Scope { id: root @@ -40,7 +41,7 @@ Scope { PamContext { id: pam config: "login" - user: Quickshell.env("USER") + user: HostService.displayName onPamMessage: { Logger.i("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired) diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index 4bf8b4d5..b4938c52 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -15,6 +15,7 @@ import qs.Services.Location import qs.Services.Media import qs.Services.Compositor import qs.Services.UI +import qs.Services.System import qs.Widgets import qs.Widgets.AudioSpectrum @@ -336,7 +337,7 @@ Loader { // Welcome back + Username on one line NText { - text: I18n.tr("lock-screen.welcome-back") + " " + (Quickshell.env("USER").charAt(0).toUpperCase() + Quickshell.env("USER").slice(1)) + "!" + text: I18n.tr("lock-screen.welcome-back") + " " + HostService.displayName + "!" pointSize: Style.fontSizeXXL font.weight: Font.Medium color: Color.mOnSurface diff --git a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml index 2a75e700..a03858f0 100644 --- a/Modules/Panels/ControlCenter/Cards/ProfileCard.qml +++ b/Modules/Panels/ControlCenter/Cards/ProfileCard.qml @@ -7,6 +7,7 @@ import Quickshell.Widgets import qs.Commons import qs.Modules.Panels.ControlCenter.Cards import qs.Modules.Panels.Settings +import qs.Services.System import qs.Services.UI import qs.Widgets @@ -37,7 +38,7 @@ NBox { Layout.fillWidth: true spacing: Style.marginXXS NText { - text: Quickshell.env("USER") || "user" + text: HostService.displayName font.weight: Style.fontWeightBold font.capitalization: Font.Capitalize } diff --git a/Modules/Panels/Settings/Tabs/GeneralTab.qml b/Modules/Panels/Settings/Tabs/GeneralTab.qml index 955ed3a7..4e7e5732 100644 --- a/Modules/Panels/Settings/Tabs/GeneralTab.qml +++ b/Modules/Panels/Settings/Tabs/GeneralTab.qml @@ -33,7 +33,7 @@ ColumnLayout { NTextInputButton { label: I18n.tr("settings.general.profile.picture.label", { - "user": Quickshell.env("USER" || "User") + "user": HostService.displayName }) description: I18n.tr("settings.general.profile.picture.description") text: Settings.data.general.avatarImage diff --git a/Services/System/HostService.qml b/Services/System/HostService.qml index adcd766d..6a6129e7 100644 --- a/Services/System/HostService.qml +++ b/Services/System/HostService.qml @@ -14,6 +14,28 @@ Singleton { property bool isNixOS: false property bool isReady: false + // User info + readonly property string username: (Quickshell.env("USER") || "") + readonly property string envRealName: (Quickshell.env("NOCTALIA_REALNAME") || "") + property string realName: "" + + readonly property string displayName: { + // Explicit override + if (envRealName && envRealName.length > 0) + return envRealName + + // Name from getent + if (realName && realName.length > 0) + return realName + + // Fallback: capitalized $USER + if (username && username.length > 0) + return username.charAt(0).toUpperCase() + username.slice(1) + + // Last resort: placeholder + return "User" + } + function init() { Logger.i("HostService", "Service started") } @@ -111,4 +133,22 @@ Singleton { stdout: StdioCollector {} stderr: StdioCollector {} } + + // Resolve GECOS real name once on startup + Process { + id: realNameProcess + command: ["sh", "-c", "getent passwd \"$USER\" | cut -d: -f5 | cut -d, -f1"] + running: true + + stdout: StdioCollector { + onStreamFinished: { + const name = String(text || "").trim() + if (name.length > 0) { + root.realName = name + Logger.i("HostService", "resolved real name", name) + } + } + } + stderr: StdioCollector {} + } }