From a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 Mon Sep 17 00:00:00 2001 From: Nippy Date: Sat, 9 May 2026 13:33:09 +0200 Subject: raveos update --- .../quickshell/Modules/Greetd/GreeterContent.qml | 1908 -------------------- 1 file changed, 1908 deletions(-) delete mode 100644 raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml') diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml deleted file mode 100644 index fa82315..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/Greetd/GreeterContent.qml +++ /dev/null @@ -1,1908 +0,0 @@ -import QtCore -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Qt.labs.folderlistmodel -import Quickshell -import Quickshell.Hyprland -import Quickshell.Io -import Quickshell.Services.Greetd -import qs.Common -import qs.Services -import qs.Widgets -import qs.Modules.Lock - -Item { - id: root - - function encodeFileUrl(path) { - if (!path) - return ""; - return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); - } - - readonly property string xdgDataDirs: Quickshell.env("XDG_DATA_DIRS") - property string screenName: "" - property string hyprlandCurrentLayout: "" - property string hyprlandKeyboard: "" - property int hyprlandLayoutCount: 0 - property bool isPrimaryScreen: !Quickshell.screens?.length || screenName === Quickshell.screens[0]?.name - - signal launchRequested - - property bool weatherInitialized: false - property bool awaitingExternalAuth: false - property bool pendingPasswordResponse: false - property bool passwordSubmitRequested: false - property bool cancelingExternalAuthForPassword: false - property int defaultAuthTimeoutMs: 10000 - property int externalAuthTimeoutMs: 30000 - property int memoryFlushDelayMs: 120 - property string pendingLaunchCommand: "" - property var pendingLaunchEnv: [] - property int passwordFailureCount: 0 - property int passwordAttemptLimitHint: 0 - property string authFeedbackMessage: "" - property string greetdPamText: "" - property string systemAuthPamText: "" - property string commonAuthPamText: "" - property string passwordAuthPamText: "" - property string systemLoginPamText: "" - property string systemLocalLoginPamText: "" - property string commonAuthPcPamText: "" - property string loginPamText: "" - property string faillockConfigText: "" - property bool greeterWallpaperOverrideExists: false - property string externalAuthAutoStartedForUser: "" - property int passwordSessionTransitionRetryCount: 0 - property int maxPasswordSessionTransitionRetries: 2 - property bool fprintdProbeComplete: false - property bool fprintdHasDevice: false - // Falls back to PAM-only detection until the fprintd D-Bus probe completes. - readonly property bool greeterPamHasFprint: greeterPamStackHasModule("pam_fprintd") && (!fprintdProbeComplete || fprintdHasDevice) - readonly property bool greeterPamHasU2f: greeterPamStackHasModule("pam_u2f") - readonly property bool greeterExternalAuthAvailable: (greeterPamHasFprint && GreetdSettings.greeterEnableFprint) || (greeterPamHasU2f && GreetdSettings.greeterEnableU2f) - readonly property bool greeterPamHasExternalAuth: greeterPamHasFprint || greeterPamHasU2f - - function initWeatherService() { - if (weatherInitialized) - return; - if (!GreetdSettings.settingsLoaded) - return; - if (!GreetdSettings.weatherEnabled) - return; - weatherInitialized = true; - WeatherService.addRef(); - WeatherService.forceRefresh(); - } - - function stripPamComment(line) { - if (!line) - return ""; - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("//")) - return ""; - const hashIdx = trimmed.indexOf("//"); - if (hashIdx >= 0) - return trimmed.substring(0, hashIdx).trim(); - return trimmed; - } - - function pamModuleEnabled(pamText, moduleName) { - if (!pamText || !moduleName) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(moduleName)) - return true; - } - return false; - } - - function pamTextIncludesFile(pamText, filename) { - if (!pamText || !filename) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes(filename) && (line.includes("include") || line.includes("substack") || line.startsWith("@include"))) - return true; - } - return false; - } - - function greeterPamStackHasModule(moduleName) { - if (pamModuleEnabled(greetdPamText, moduleName)) - return true; - const includedPamStacks = [ - ["system-auth", systemAuthPamText], - ["common-auth", commonAuthPamText], - ["password-auth", passwordAuthPamText], - ["system-login", systemLoginPamText], - ["system-local-login", systemLocalLoginPamText], - ["common-auth-pc", commonAuthPcPamText], - ["login", loginPamText] - ]; - for (let i = 0; i < includedPamStacks.length; i++) { - const stack = includedPamStacks[i]; - if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName)) - return true; - } - return false; - } - - function usesPamLockoutPolicy(pamText) { - if (!pamText) - return false; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (line.includes("pam_faillock.so") || line.includes("pam_tally2.so") || line.includes("pam_tally.so")) - return true; - } - return false; - } - - function parsePamLineDenyValue(pamText) { - if (!pamText) - return -1; - const lines = pamText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - if (!line.includes("pam_faillock.so") && !line.includes("pam_tally2.so") && !line.includes("pam_tally.so")) - continue; - const denyMatch = line.match(/\bdeny\s*=\s*(\d+)\b/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function parseFaillockDenyValue(configText) { - if (!configText) - return -1; - const lines = configText.split(/\r?\n/); - for (let i = 0; i < lines.length; i++) { - const line = stripPamComment(lines[i]); - if (!line) - continue; - const denyMatch = line.match(/^deny\s*=\s*(\d+)\s*$/i); - if (!denyMatch) - continue; - const parsed = parseInt(denyMatch[1], 10); - if (!isNaN(parsed)) - return parsed; - } - return -1; - } - - function refreshPasswordAttemptPolicyHint() { - const pamSources = [greetdPamText, systemAuthPamText, commonAuthPamText, passwordAuthPamText, systemLoginPamText, systemLocalLoginPamText, commonAuthPcPamText, loginPamText]; - let lockoutConfigured = false; - let denyFromPam = -1; - for (let i = 0; i < pamSources.length; i++) { - const source = pamSources[i]; - if (!source) - continue; - if (usesPamLockoutPolicy(source)) - lockoutConfigured = true; - const denyValue = parsePamLineDenyValue(source); - if (denyValue >= 0 && (denyFromPam < 0 || denyValue < denyFromPam)) - denyFromPam = denyValue; - } - - if (!lockoutConfigured) { - passwordAttemptLimitHint = 0; - return; - } - - const denyFromConfig = parseFaillockDenyValue(faillockConfigText); - if (denyFromConfig >= 0) { - passwordAttemptLimitHint = denyFromConfig; - return; - } - - if (denyFromPam >= 0) { - passwordAttemptLimitHint = denyFromPam; - return; - } - - // pam_faillock default deny value when no explicit config is set. - passwordAttemptLimitHint = 3; - } - - function isLikelyLockoutMessage(message) { - const lower = (message || "").toLowerCase(); - return lower.includes("account is locked") || lower.includes("too many") || lower.includes("maximum number of") || lower.includes("auth_err"); - } - - function currentAuthMessage() { - if (GreeterState.pamState === "error") - return I18n.tr("Authentication error - try again"); - if (GreeterState.pamState === "max") - return I18n.tr("Too many failed attempts - account may be locked"); - if (GreeterState.pamState === "fail") { - if (passwordAttemptLimitHint > 0) { - const attempt = Math.max(1, Math.min(passwordFailureCount, passwordAttemptLimitHint)); - const remaining = Math.max(passwordAttemptLimitHint - attempt, 0); - if (remaining > 0) { - return I18n.tr("Incorrect password - attempt %1 of %2 (lockout may follow)").arg(attempt).arg(passwordAttemptLimitHint); - } - return I18n.tr("Incorrect password - next failures may trigger account lockout"); - } - return I18n.tr("Incorrect password"); - } - return ""; - } - - function clearAuthFeedback() { - GreeterState.pamState = ""; - authFeedbackMessage = ""; - } - - function resetPasswordSessionTransition(clearSubmitRequest) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - if (clearSubmitRequest) - passwordSubmitRequested = false; - } - - Connections { - target: GreetdSettings - function onSettingsLoadedChanged() { - if (GreetdSettings.settingsLoaded) { - initWeatherService(); - if (isPrimaryScreen) { - applyLastSuccessfulUser(); - finalizeSessionSelection(); - } - } - } - - function onRememberLastUserChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastUser && GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - applyLastSuccessfulUser(); - } - - function onRememberLastSessionChanged() { - if (!isPrimaryScreen) - return; - if (!GreetdSettings.rememberLastSession && GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - finalizeSessionSelection(); - } - } - - FileView { - id: greetdPamWatcher - path: "/etc/pam.d/greetd" - printErrors: false - onLoaded: { - root.greetdPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.greetdPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemAuthPamWatcher - path: "/etc/pam.d/system-auth" - printErrors: false - onLoaded: { - root.systemAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPamWatcher - path: "/etc/pam.d/common-auth" - printErrors: false - onLoaded: { - root.commonAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: passwordAuthPamWatcher - path: "/etc/pam.d/password-auth" - printErrors: false - onLoaded: { - root.passwordAuthPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.passwordAuthPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLoginPamWatcher - path: "/etc/pam.d/system-login" - printErrors: false - onLoaded: { - root.systemLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: systemLocalLoginPamWatcher - path: "/etc/pam.d/system-local-login" - printErrors: false - onLoaded: { - root.systemLocalLoginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.systemLocalLoginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: commonAuthPcPamWatcher - path: "/etc/pam.d/common-auth-pc" - printErrors: false - onLoaded: { - root.commonAuthPcPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.commonAuthPcPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: loginPamWatcher - path: "/etc/pam.d/login" - printErrors: false - onLoaded: { - root.loginPamText = text(); - root.refreshPasswordAttemptPolicyHint(); - root.maybeAutoStartExternalAuth(); - } - onLoadFailed: { - root.loginPamText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - FileView { - id: faillockConfigWatcher - path: "/etc/security/faillock.conf" - printErrors: false - onLoaded: { - root.faillockConfigText = text(); - root.refreshPasswordAttemptPolicyHint(); - } - onLoadFailed: { - root.faillockConfigText = ""; - root.refreshPasswordAttemptPolicyHint(); - } - } - - Component.onCompleted: { - initWeatherService(); - refreshPasswordAttemptPolicyHint(); - - if (isPrimaryScreen) - applyLastSuccessfulUser(); - - if (CompositorService.isHyprland) - updateHyprlandLayout(); - - fprintdDeviceProbe.running = true; - } - - function applyLastSuccessfulUser() { - if (!GreetdSettings.settingsLoaded || !GreetdSettings.rememberLastUser) - return; - const lastUser = GreetdMemory.lastSuccessfulUser; - if (lastUser && !GreeterState.showPasswordInput && !GreeterState.username) { - GreeterState.username = lastUser; - GreeterState.usernameInput = lastUser; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(lastUser); - maybeAutoStartExternalAuth(); - } - } - - function submitUsername(rawValue) { - const user = (rawValue || "").trim(); - if (!user) - return; - if (GreeterState.username !== user) { - passwordFailureCount = 0; - clearAuthFeedback(); - externalAuthAutoStartedForUser = ""; - } - GreeterState.username = user; - GreeterState.showPasswordInput = true; - PortalService.getGreeterUserProfileImage(user); - GreeterState.passwordBuffer = ""; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - maybeAutoStartExternalAuth(); - } - - function submitBufferedPassword() { - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - // Some PAM stacks expect an explicit empty response to advance U2F/fprint or fail normally. - Greetd.respond(GreeterState.passwordBuffer || ""); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - return true; - } - - function requestPasswordSessionTransition() { - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && !hasPasswordBuffer) - return; - if (cancelingExternalAuthForPassword) - return; - if (passwordSessionTransitionRetryCount >= maxPasswordSessionTransitionRetries) { - pendingPasswordResponse = false; - awaitingExternalAuth = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - resetPasswordSessionTransition(true); - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - return; - } - cancelingExternalAuthForPassword = true; - passwordSessionTransitionRetryCount = passwordSessionTransitionRetryCount + 1; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - Greetd.cancelSession(); - } - - function startAuthSession(submitPassword) { - submitPassword = submitPassword === true; - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (GreeterState.unlocking) - return; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (Greetd.state !== GreetdState.Inactive) { - if (pendingPasswordResponse && submitPassword) - submitBufferedPassword(); - else if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (cancelingExternalAuthForPassword) { - if (submitPassword) - passwordSubmitRequested = true; - return; - } - if (!submitPassword && !hasPasswordBuffer && !root.greeterExternalAuthAvailable) - return; - pendingPasswordResponse = false; - passwordSubmitRequested = submitPassword; - awaitingExternalAuth = !submitPassword && !hasPasswordBuffer && root.greeterExternalAuthAvailable; - // Use greeterExternalAuthAvailable so systems with pam_fprintd but no hardware don't incur the 30 s wait. - const waitingOnPamExternalBeforePassword = submitPassword && root.greeterExternalAuthAvailable; - authTimeout.interval = (awaitingExternalAuth || waitingOnPamExternalBeforePassword) ? externalAuthTimeoutMs : defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.createSession(GreeterState.username); - } - - function maybeAutoStartExternalAuth() { - if (!GreeterState.showPasswordInput || !GreeterState.username) - return; - if (!root.greeterExternalAuthAvailable) - return; - if (GreeterState.unlocking || Greetd.state !== GreetdState.Inactive) - return; - if (passwordSubmitRequested || cancelingExternalAuthForPassword) - return; - if (GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0) - return; - if (externalAuthAutoStartedForUser === GreeterState.username) - return; - - externalAuthAutoStartedForUser = GreeterState.username; - startAuthSession(false); - } - - function isExternalAuthPrompt(message, responseRequired) { - // Non-response PAM messages commonly represent waiting states (fprint/U2F/token touch). - return !responseRequired; - } - - Component.onDestruction: { - if (weatherInitialized) - WeatherService.removeRef(); - } - - function updateHyprlandLayout() { - if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true; - } - } - - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text); - const mainKeyboard = data.keyboards.find(kb => kb.main === true); - if (!mainKeyboard) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - return; - } - hyprlandKeyboard = mainKeyboard.name; - if (mainKeyboard.active_keymap) { - const parts = mainKeyboard.active_keymap.split(" "); - hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase(); - } else { - hyprlandCurrentLayout = ""; - } - hyprlandLayoutCount = mainKeyboard.layout ? mainKeyboard.layout.split(",").length : 0; - } catch (e) { - hyprlandCurrentLayout = ""; - hyprlandLayoutCount = 0; - } - } - } - } - - // Probe fprintd D-Bus for physically enrolled scanners to eliminate PAM stack false-positives. - Process { - id: fprintdDeviceProbe - running: false - // sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable, - // keeping the PAM-only fallback active in those cases. - command: ["sh", "-c", - "command -v gdbus >/dev/null 2>&1 || { echo PROBE_UNAVAILABLE; exit 0; }; " + - "gdbus call --system " + - "--dest net.reactivated.Fprint " + - "--object-path /net/reactivated/Fprint/Manager " + - "--method net.reactivated.Fprint.Manager.GetDevices 2>/dev/null " + - "|| echo PROBE_UNAVAILABLE"] - stdout: StdioCollector { - onStreamFinished: { - if (text.includes("PROBE_UNAVAILABLE")) - return; // PAM-only fallback stays active - root.fprintdHasDevice = text.includes("objectpath"); - root.fprintdProbeComplete = true; - root.maybeAutoStartExternalAuth(); - } - } - onExited: function(exitCode, exitStatus) { - if (!root.fprintdProbeComplete) - root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active - } - } - - Connections { - target: CompositorService.isHyprland ? Hyprland : null - enabled: CompositorService.isHyprland - - function onRawEvent(event) { - if (event.name === "activelayout") - updateHyprlandLayout(); - } - } - - Connections { - target: GreetdMemory - enabled: isPrimaryScreen - function onLastSuccessfulUserChanged() { - applyLastSuccessfulUser(); - } - function onMemoryReadyChanged() { - finalizeSessionSelection(); - } - } - - Connections { - target: GreeterState - function onUsernameChanged() { - if (GreeterState.username) { - PortalService.getGreeterUserProfileImage(GreeterState.username); - } - } - } - - FileView { - id: greeterWallpaperOverrideFile - path: GreetdSettings.greeterWallpaperOverridePath - printErrors: false - watchChanges: true - onLoaded: root.greeterWallpaperOverrideExists = true - onLoadFailed: root.greeterWallpaperOverrideExists = false - } - - Connections { - target: GreetdSettings - function onGreeterWallpaperOverridePathChanged() { - if (!GreetdSettings.greeterWallpaperOverridePath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - function onGreeterWallpaperPathChanged() { - if (!GreetdSettings.greeterWallpaperPath) { - root.greeterWallpaperOverrideExists = false; - return; - } - greeterWallpaperOverrideFile.reload(); - } - } - - DankBackdrop { - anchors.fill: parent - screenName: root.screenName - visible: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return false; - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return !currentWallpaper || currentWallpaper === "" || (currentWallpaper && currentWallpaper.startsWith("#")); - } - } - - Image { - id: wallpaperBackground - - anchors.fill: parent - source: { - if (GreetdSettings.greeterWallpaperPath !== "" && root.greeterWallpaperOverrideExists) - return encodeFileUrl(GreetdSettings.greeterWallpaperOverridePath); - var _ = SessionData.perMonitorWallpaper; - var __ = SessionData.monitorWallpapers; - var currentWallpaper = SessionData.getMonitorWallpaper(screenName); - return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; - } - fillMode: Theme.getFillMode(GreetdSettings.getEffectiveWallpaperFillMode()) - smooth: true - asynchronous: false - cache: true - visible: source !== "" - layer.enabled: true - - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - blur: 0.8 - blurMax: 32 - blurMultiplier: 1 - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - anchors.fill: parent - color: "black" - opacity: 0.4 - } - - SystemClock { - id: systemClock - precision: SystemClock.Seconds - } - - Rectangle { - anchors.fill: parent - color: "transparent" - - Item { - id: clockContainer - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.verticalCenter - anchors.bottomMargin: 60 - width: parent.width - height: clockText.implicitHeight - - Row { - id: clockText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - spacing: 0 - - property string fullTimeStr: { - const format = GreetdSettings.getEffectiveTimeFormat(); - return systemClock.date.toLocaleTimeString(I18n.locale(), format); - } - property var timeParts: fullTimeStr.split(':') - property string hours: timeParts[0] || "" - property string minutes: timeParts[1] || "" - property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : "" - property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '') - property string ampm: { - const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i); - return match ? match[0].trim() : ""; - } - property bool hasSeconds: timeParts.length > 2 - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.hours.length > 1 ? clockText.hours[1] : clockText.hours.length > 0 ? clockText.hours[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: ":" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - } - - StyledText { - width: 75 - text: clockText.minutes.length > 0 ? clockText.minutes[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: 75 - text: clockText.minutes.length > 1 ? clockText.minutes[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: clockText.hasSeconds ? ":" : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 0 ? clockText.seconds[0] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 75 - text: clockText.hasSeconds && clockText.seconds.length > 1 ? clockText.seconds[1] : "" - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - horizontalAlignment: Text.AlignHCenter - visible: clockText.hasSeconds - } - - StyledText { - width: 20 - text: " " - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - - StyledText { - text: clockText.ampm - font.pixelSize: 120 - font.weight: Font.Light - color: "white" - visible: clockText.ampm !== "" - } - } - } - - StyledText { - id: dateText - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: clockContainer.bottom - anchors.topMargin: 4 - text: { - return systemClock.date.toLocaleDateString(I18n.locale(), GreetdSettings.getEffectiveLockDateFormat()); - } - font.pixelSize: Theme.fontSizeXLarge - color: "white" - opacity: 0.9 - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: dateText.bottom - anchors.topMargin: Theme.spacingL - width: 380 - height: 140 - - ColumnLayout { - anchors.fill: parent - spacing: Theme.spacingM - - RowLayout { - spacing: Theme.spacingL - Layout.fillWidth: true - - DankCircularImage { - Layout.preferredWidth: 60 - Layout.preferredHeight: 60 - imageSource: { - if (PortalService.profileImage === "") - return ""; - if (PortalService.profileImage.startsWith("/")) - return encodeFileUrl(PortalService.profileImage); - return PortalService.profileImage; - } - fallbackIcon: "person" - visible: GreetdSettings.lockScreenShowProfileImage - } - - Rectangle { - property bool showPassword: false - - Layout.fillWidth: true - Layout.preferredHeight: 60 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) - border.color: inputField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3) - border.width: inputField.activeFocus ? 2 : 1 - - DankIcon { - id: lockIcon - - anchors.left: parent.left - anchors.leftMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - name: GreeterState.showPasswordInput ? "lock" : "person" - size: 20 - color: inputField.activeFocus ? Theme.primary : Theme.surfaceVariantText - } - - TextInput { - id: inputField - - property bool syncingFromState: false - - anchors.fill: parent - anchors.leftMargin: lockIcon.width + Theme.spacingM * 2 - anchors.rightMargin: { - let margin = Theme.spacingM; - if (GreeterState.showPasswordInput && revealButton.visible) { - margin += revealButton.width; - } - if (externalAuthButton.visible) { - margin += externalAuthButton.width; - } - if (virtualKeyboardButton.visible) { - margin += virtualKeyboardButton.width; - } - if (enterButton.visible) { - margin += enterButton.width + 2; - } - return margin; - } - opacity: 0 - focus: true - echoMode: GreeterState.showPasswordInput ? (parent.showPassword ? TextInput.Normal : TextInput.Password) : TextInput.Normal - onTextChanged: { - if (syncingFromState) - return; - if (GreeterState.showPasswordInput) { - GreeterState.passwordBuffer = text; - if (!text || text.length === 0) - root.passwordSubmitRequested = false; - } else { - GreeterState.usernameInput = text; - } - } - onAccepted: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (text.trim()) { - root.submitUsername(text); - syncingFromState = true; - text = ""; - syncingFromState = false; - } - } - } - - Component.onCompleted: { - syncingFromState = true; - text = GreeterState.showPasswordInput ? GreeterState.passwordBuffer : GreeterState.usernameInput; - syncingFromState = false; - if (isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - onVisibleChanged: { - if (visible && isPrimaryScreen && !powerMenu.isVisible) - forceActiveFocus(); - } - } - - KeyboardController { - id: keyboard_controller - target: inputField - rootObject: root - } - - StyledText { - id: placeholder - - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.unlocking) { - return I18n.tr("Logging in..."); - } - if (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse) { - return I18n.tr("Authenticating..."); - } - if (GreeterState.showPasswordInput) { - return I18n.tr("Password..."); - } - return I18n.tr("Username..."); - } - color: (GreeterState.unlocking || (Greetd.state !== GreetdState.Inactive && !awaitingExternalAuth && !pendingPasswordResponse)) ? Theme.primary : Theme.outline - font.pixelSize: Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - StyledText { - anchors.left: lockIcon.right - anchors.leftMargin: Theme.spacingM - anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))) - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - text: { - if (GreeterState.showPasswordInput) { - if (parent.showPassword) { - return GreeterState.passwordBuffer; - } - return "•".repeat(GreeterState.passwordBuffer.length); - } - return GreeterState.usernameInput; - } - color: Theme.surfaceText - font.pixelSize: (GreeterState.showPasswordInput && !parent.showPassword) ? Theme.fontSizeLarge : Theme.fontSizeMedium - opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length > 0 : GreeterState.usernameInput.length > 0) ? 1 : 0 - clip: true - elide: Text.ElideNone - horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - } - - DankActionButton { - id: revealButton - - anchors.right: externalAuthButton.visible ? externalAuthButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: parent.showPassword ? "visibility_off" : "visibility" - buttonSize: 32 - visible: GreeterState.showPasswordInput && GreeterState.passwordBuffer.length > 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: parent.showPassword = !parent.showPassword - } - DankActionButton { - id: externalAuthButton - - anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right) - anchors.rightMargin: 0 - anchors.verticalCenter: parent.verticalCenter - iconName: root.greeterPamHasFprint ? "fingerprint" : "key" - buttonSize: 32 - visible: GreeterState.showPasswordInput && root.greeterExternalAuthAvailable && GreeterState.passwordBuffer.length === 0 && (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: root.startAuthSession(false) - } - DankActionButton { - id: virtualKeyboardButton - - anchors.right: enterButton.visible ? enterButton.left : parent.right - anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard" - buttonSize: 32 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: visible - onClicked: { - if (keyboard_controller.isKeyboardActive) { - keyboard_controller.hide(); - } else { - keyboard_controller.show(); - } - } - } - - DankActionButton { - id: enterButton - - anchors.right: parent.right - anchors.rightMargin: 2 - anchors.verticalCenter: parent.verticalCenter - iconName: "keyboard_return" - buttonSize: 36 - visible: (Greetd.state === GreetdState.Inactive || awaitingExternalAuth || pendingPasswordResponse) && !GreeterState.unlocking - enabled: true - onClicked: { - if (GreeterState.showPasswordInput) { - root.startAuthSession(true); - } else { - if (inputField.text.trim()) { - root.submitUsername(inputField.text); - inputField.text = ""; - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - - StyledText { - Layout.fillWidth: true - Layout.preferredHeight: 38 - Layout.topMargin: -Theme.spacingS - Layout.bottomMargin: -Theme.spacingS - text: root.authFeedbackMessage - color: Theme.error - font.pixelSize: Theme.fontSizeSmall - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 2 - opacity: root.authFeedbackMessage !== "" ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Rectangle { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 0 - Layout.preferredWidth: switchUserRow.width + Theme.spacingL * 2 - Layout.preferredHeight: 40 - radius: Theme.cornerRadius - color: Theme.surfaceContainer - opacity: GreeterState.showPasswordInput ? 1 : 0 - enabled: GreeterState.showPasswordInput - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.standardEasing - } - } - - Row { - id: switchUserRow - anchors.centerIn: parent - spacing: Theme.spacingS - - DankIcon { - name: "people" - size: Theme.iconSize - 4 - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Switch User") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - StateLayer { - stateColor: Theme.primary - cornerRadius: parent.radius - enabled: !GreeterState.unlocking && Greetd.state === GreetdState.Inactive && GreeterState.showPasswordInput - onClicked: { - GreeterState.reset(); - root.externalAuthAutoStartedForUser = ""; - inputField.text = ""; - PortalService.profileImage = ""; - } - } - } - } - } - - Row { - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingXL - spacing: Theme.spacingL - - Item { - width: keyboardLayoutRow.width - height: keyboardLayoutRow.height - anchors.verticalCenter: parent.verticalCenter - visible: { - if (CompositorService.isNiri) { - return NiriService.keyboardLayoutNames.length > 1; - } else if (CompositorService.isHyprland) { - return hyprlandLayoutCount > 1; - } - return false; - } - - Row { - id: keyboardLayoutRow - spacing: 4 - - Item { - width: Theme.iconSize - height: Theme.iconSize - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: "white" - anchors.centerIn: parent - } - } - - Item { - width: childrenRect.width - height: Theme.iconSize - - StyledText { - text: { - if (CompositorService.isNiri) { - const layout = NiriService.getCurrentKeyboardLayoutName(); - if (!layout) - return ""; - const parts = layout.split(" "); - if (parts.length > 0) { - return parts[0].substring(0, 2).toUpperCase(); - } - return layout.substring(0, 2).toUpperCase(); - } else if (CompositorService.isHyprland) { - return hyprlandCurrentLayout; - } - return ""; - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - MouseArea { - id: keyboardLayoutArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - if (CompositorService.isNiri) { - NiriService.cycleKeyboardLayout(); - } else if (CompositorService.isHyprland) { - Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]); - updateHyprlandLayout(); - } - } - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: { - const keyboardVisible = (CompositorService.isNiri && NiriService.keyboardLayoutNames.length > 1) || (CompositorService.isHyprland && hyprlandLayoutCount > 1); - return keyboardVisible && GreetdSettings.weatherEnabled && WeatherService.weather.available; - } - } - - Row { - spacing: 6 - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) - size: Theme.iconSize - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: (GreetdSettings.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: GreetdSettings.weatherEnabled && WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable) - } - - Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio) - - DankIcon { - name: NetworkService.networkStatus === "ethernet" ? "lan" : NetworkService.wifiSignalIcon - size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) - anchors.verticalCenter: parent.verticalCenter - visible: NetworkService.networkStatus !== "disconnected" - } - - DankIcon { - name: "bluetooth" - size: Theme.iconSize - 2 - color: "white" - anchors.verticalCenter: parent.verticalCenter - visible: BluetoothService.available && BluetoothService.enabled - } - - DankIcon { - name: { - if (!AudioService.sink?.audio) { - return "volume_up"; - } - if (AudioService.sink.audio.muted) - return "volume_off"; - if (AudioService.sink.audio.volume === 0) - return "volume_mute"; - if (AudioService.sink.audio.volume * 100 < 33) { - return "volume_down"; - } - return "volume_up"; - } - size: Theme.iconSize - 2 - color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white" - anchors.verticalCenter: parent.verticalCenter - visible: AudioService.sink && AudioService.sink.audio - } - } - - Rectangle { - width: 1 - height: 24 - color: Qt.rgba(255, 255, 255, 0.2) - anchors.verticalCenter: parent.verticalCenter - visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio)) - } - - Row { - spacing: 4 - visible: BatteryService.batteryAvailable - anchors.verticalCenter: parent.verticalCenter - - DankIcon { - name: { - if (BatteryService.isCharging) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.isPluggedIn) { - if (BatteryService.batteryLevel >= 90) { - return "battery_charging_full"; - } - - if (BatteryService.batteryLevel >= 80) { - return "battery_charging_90"; - } - - if (BatteryService.batteryLevel >= 60) { - return "battery_charging_80"; - } - - if (BatteryService.batteryLevel >= 50) { - return "battery_charging_60"; - } - - if (BatteryService.batteryLevel >= 30) { - return "battery_charging_50"; - } - - if (BatteryService.batteryLevel >= 20) { - return "battery_charging_30"; - } - - return "battery_charging_20"; - } - if (BatteryService.batteryLevel >= 95) { - return "battery_full"; - } - - if (BatteryService.batteryLevel >= 85) { - return "battery_6_bar"; - } - - if (BatteryService.batteryLevel >= 70) { - return "battery_5_bar"; - } - - if (BatteryService.batteryLevel >= 55) { - return "battery_4_bar"; - } - - if (BatteryService.batteryLevel >= 40) { - return "battery_3_bar"; - } - - if (BatteryService.batteryLevel >= 25) { - return "battery_2_bar"; - } - - return "battery_1_bar"; - } - size: Theme.iconSize - color: { - if (BatteryService.isLowBattery && !BatteryService.isCharging) { - return Theme.error; - } - - if (BatteryService.isCharging || BatteryService.isPluggedIn) { - return Theme.primary; - } - - return "white"; - } - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: BatteryService.batteryLevel + "%" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Light - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - } - } - - DankActionButton { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.margins: Theme.spacingXL - visible: GreetdSettings.lockScreenShowPowerActions - iconName: "power_settings_new" - iconColor: Theme.error - buttonSize: 40 - onClicked: powerMenu.show() - } - - Item { - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.margins: Theme.spacingXL - width: Math.max(200, currentSessionMetrics.width + 80) - height: 60 - - StyledTextMetrics { - id: currentSessionMetrics - text: root.currentSessionName - } - - property real longestSessionWidth: { - let maxWidth = 0; - for (var i = 0; i < sessionMetricsRepeater.count; i++) { - const item = sessionMetricsRepeater.itemAt(i); - if (item && item.width > maxWidth) { - maxWidth = item.width; - } - } - return maxWidth; - } - - Repeater { - id: sessionMetricsRepeater - model: GreeterState.sessionList - delegate: StyledTextMetrics { - text: modelData - } - } - - DankDropdown { - id: sessionDropdown - anchors.fill: parent - text: "" - description: "" - currentValue: root.currentSessionName - options: GreeterState.sessionList - enableFuzzySearch: GreeterState.sessionList.length > 5 - popupWidthOffset: 0 - popupWidth: Math.max(250, parent.longestSessionWidth + 100) - openUpwards: true - alignPopupRight: true - onValueChanged: value => { - const idx = GreeterState.sessionList.indexOf(value); - if (idx < 0) - return; - GreeterState.currentSessionIndex = idx; - GreeterState.selectedSession = GreeterState.sessionExecs[idx]; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[idx]; - } - } - } - } - - property string currentSessionName: GreeterState.sessionList[GreeterState.currentSessionIndex] || "" - - function finalizeSessionSelection() { - if (GreeterState.sessionList.length === 0) - return; - if (!GreetdMemory.memoryReady) - return; - if (!GreetdSettings.settingsLoaded) - return; - - const savedSession = GreetdSettings.rememberLastSession ? GreetdMemory.lastSessionId : ""; - if (savedSession && GreetdSettings.rememberLastSession) { - for (var i = 0; i < GreeterState.sessionPaths.length; i++) { - if (GreeterState.sessionPaths[i] === savedSession) { - GreeterState.currentSessionIndex = i; - GreeterState.selectedSession = GreeterState.sessionExecs[i] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[i]; - return; - } - } - } - - GreeterState.currentSessionIndex = 0; - GreeterState.selectedSession = GreeterState.sessionExecs[0] || ""; - GreeterState.selectedSessionPath = GreeterState.sessionPaths[0] || ""; - } - - property var sessionDirs: { - const homeDir = Quickshell.env("HOME") || ""; - const dirs = ["/usr/share/wayland-sessions", "/usr/share/xsessions", "/usr/local/share/wayland-sessions", "/usr/local/share/xsessions"]; - - if (homeDir) { - dirs.push(homeDir + "/.local/share/wayland-sessions"); - dirs.push(homeDir + "/.local/share/xsessions"); - } - - if (xdgDataDirs) { - xdgDataDirs.split(":").forEach(dir => { - if (dir) { - dirs.push(dir + "/wayland-sessions"); - dirs.push(dir + "/xsessions"); - } - }); - } - return dirs; - } - - property var _pendingFiles: ({}) - property int _pendingCount: 0 - - function _addSession(path, name, exec) { - if (!name || !exec || GreeterState.sessionList.includes(name)) - return; - GreeterState.sessionList = GreeterState.sessionList.concat([name]); - GreeterState.sessionExecs = GreeterState.sessionExecs.concat([exec]); - GreeterState.sessionPaths = GreeterState.sessionPaths.concat([path]); - } - - function _parseDesktopFile(content, path) { - let name = ""; - let exec = ""; - const lines = content.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!name && line.startsWith("Name=")) - name = line.substring(5).trim(); - else if (!exec && line.startsWith("Exec=")) - exec = line.substring(5).trim(); - if (name && exec) - break; - } - _addSession(path, name, exec); - } - - function _loadDesktopFile(filePath) { - if (_pendingFiles[filePath]) - return; - _pendingFiles[filePath] = true; - _pendingCount++; - - const loader = desktopFileLoader.createObject(root, { - "filePath": filePath - }); - } - - function _onFileLoaded(filePath) { - _pendingCount--; - if (_pendingCount === 0) - Qt.callLater(finalizeSessionSelection); - } - - Component { - id: desktopFileLoader - - FileView { - id: fv - property string filePath: "" - path: filePath - - onLoaded: { - root._parseDesktopFile(text(), filePath); - root._onFileLoaded(filePath); - fv.destroy(); - } - - onLoadFailed: { - root._onFileLoaded(filePath); - fv.destroy(); - } - } - } - - Repeater { - model: isPrimaryScreen ? sessionDirs : [] - - Item { - required property string modelData - - FolderListModel { - folder: encodeFileUrl(modelData) - nameFilters: ["*.desktop"] - showDirs: false - showDotAndDotDot: false - - onStatusChanged: { - if (status !== FolderListModel.Ready) - return; - for (let i = 0; i < count; i++) { - let fp = get(i, "filePath"); - if (fp.startsWith("file://")) - fp = fp.substring(7); - root._loadDesktopFile(fp); - } - } - } - } - } - - Connections { - target: Greetd - enabled: isPrimaryScreen - - function onAuthMessage(message, error, responseRequired, echoResponse) { - if (responseRequired) { - cancelingExternalAuthForPassword = false; - passwordSessionTransitionRetryCount = 0; - awaitingExternalAuth = false; - pendingPasswordResponse = true; - const hasPasswordBuffer = GreeterState.passwordBuffer && GreeterState.passwordBuffer.length > 0; - if (!passwordSubmitRequested && hasPasswordBuffer) - passwordSubmitRequested = true; - if (passwordSubmitRequested && !root.submitBufferedPassword()) - passwordSubmitRequested = false; - if (passwordSubmitRequested || hasPasswordBuffer) { - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - } else { - authTimeout.stop(); - } - return; - } - pendingPasswordResponse = false; - const externalPrompt = root.isExternalAuthPrompt(message, responseRequired); - if (!passwordSubmitRequested) - awaitingExternalAuth = root.greeterExternalAuthAvailable && externalPrompt; - if (awaitingExternalAuth || (passwordSubmitRequested && externalPrompt && root.greeterPamHasExternalAuth)) - authTimeout.interval = externalAuthTimeoutMs; - else - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.restart(); - Greetd.respond(""); - } - - function onStateChanged() { - if (Greetd.state === GreetdState.Inactive) { - const resumePasswordSubmit = cancelingExternalAuthForPassword && passwordSubmitRequested; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - cancelingExternalAuthForPassword = false; - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - if (resumePasswordSubmit) { - Qt.callLater(function() { - root.startAuthSession(true); - }); - return; - } - resetPasswordSessionTransition(true); - } - } - - function onReadyToLaunch() { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - passwordFailureCount = 0; - clearAuthFeedback(); - const sessionCmd = GreeterState.selectedSession || GreeterState.sessionExecs[GreeterState.currentSessionIndex]; - const sessionPath = GreeterState.selectedSessionPath || GreeterState.sessionPaths[GreeterState.currentSessionIndex]; - if (!sessionCmd) { - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - return; - } - - GreeterState.unlocking = true; - launchTimeout.restart(); - if (GreetdSettings.rememberLastSession) { - GreetdMemory.setLastSessionId(sessionPath); - } else if (GreetdMemory.lastSessionId) { - GreetdMemory.setLastSessionId(""); - } - if (GreetdSettings.rememberLastUser) { - GreetdMemory.setLastSuccessfulUser(GreeterState.username); - } else if (GreetdMemory.lastSuccessfulUser) { - GreetdMemory.setLastSuccessfulUser(""); - } - pendingLaunchCommand = sessionCmd; - pendingLaunchEnv = ["XDG_SESSION_TYPE=wayland"]; - memoryFlushTimer.restart(); - } - - function onAuthFailure(message) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - if (isLikelyLockoutMessage(message)) { - GreeterState.pamState = "max"; - } else { - GreeterState.pamState = "fail"; - passwordFailureCount = passwordFailureCount + 1; - } - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - - function onError(error) { - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - authTimeout.stop(); - launchTimeout.stop(); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: memoryFlushTimer - interval: memoryFlushDelayMs - onTriggered: { - if (!pendingLaunchCommand) - return; - const sessionCommand = pendingLaunchCommand; - const launchEnv = pendingLaunchEnv; - pendingLaunchCommand = ""; - pendingLaunchEnv = []; - Greetd.launch(sessionCommand.split(" "), launchEnv); - } - } - - Timer { - id: authTimeout - interval: defaultAuthTimeoutMs - onTriggered: { - if (GreeterState.unlocking || Greetd.state === GreetdState.Inactive) - return; - awaitingExternalAuth = false; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - authTimeout.interval = defaultAuthTimeoutMs; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - GreeterState.passwordBuffer = ""; - inputField.text = ""; - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: launchTimeout - interval: 8000 - onTriggered: { - if (!GreeterState.unlocking) - return; - pendingPasswordResponse = false; - resetPasswordSessionTransition(true); - GreeterState.unlocking = false; - GreeterState.pamState = "error"; - authFeedbackMessage = currentAuthMessage(); - placeholderDelay.restart(); - Greetd.cancelSession(); - } - } - - Timer { - id: placeholderDelay - interval: 4000 - onTriggered: clearAuthFeedback() - } - - LockPowerMenu { - id: powerMenu - showLogout: false - powerActionConfirmOverride: GreetdSettings.powerActionConfirm - powerActionHoldDurationOverride: GreetdSettings.powerActionHoldDuration - powerMenuActionsOverride: GreetdSettings.powerMenuActions - powerMenuDefaultActionOverride: GreetdSettings.powerMenuDefaultAction - powerMenuGridLayoutOverride: GreetdSettings.powerMenuGridLayout - requiredActions: ["poweroff"] - onClosed: { - if (isPrimaryScreen && inputField && inputField.forceActiveFocus) { - Qt.callLater(() => inputField.forceActiveFocus()); - } - } - } -} -- cgit v1.3