diff --git a/CLAUDE.md b/CLAUDE.md index 1c0209b..d528089 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,4 +89,7 @@ Never test against the real setup: enrolling and the PAM files belong to the use - A development daemon needs no root: `face-unlockd --socket $XDG_RUNTIME_DIR/fu/socket --state-dir DIR --config FILE --models DIR`. It skips polkit when it does not run as root. Point the other parts at it with `FU_SOCKET`. +- face-unlock's own lock screen checks the password with PAM. `FU_PAM_CONFDIR=DIR` points it at a + `face-unlock-lock` file of its own (pam_permit, pam_deny), so no test counts as a wrong password + for the real account. - `make check` after every change. New strings: `po/update-pot.sh`, then translate them in every `po/*.po`. diff --git a/CMakeLists.txt b/CMakeLists.txt index 012f71e..30c68c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,9 +102,11 @@ install(TARGETS face-unlock-ctl DESTINATION ${FU_LIBEXECDIR}) # The PAM module # --------------------------------------------------------------------------- +# The PAM module, and the agent's own lock screen, which checks the password. +find_path(PAM_INCLUDE_DIR security/pam_modules.h REQUIRED) +find_library(PAM_LIBRARY pam REQUIRED) + if(FU_BUILD_PAM) - find_path(PAM_INCLUDE_DIR security/pam_modules.h REQUIRED) - find_library(PAM_LIBRARY pam REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(SYSTEMD IMPORTED_TARGET libsystemd) @@ -155,6 +157,9 @@ if(FU_BUILD_AGENT) src/agent/lockers.cpp src/agent/inputwatcher.cpp src/agent/wayland.cpp + src/agent/sessionlock.cpp + src/agent/lockscreencontroller.cpp + src/agent/wallpaper.cpp src/agent/enrollcontroller.cpp ) target_include_directories(face-unlock-agent PRIVATE src/agent) @@ -164,13 +169,14 @@ if(FU_BUILD_AGENT) qt6_generate_wayland_protocol_client_sources(face-unlock-agent FILES ${CMAKE_CURRENT_SOURCE_DIR}/protocols/kde-lockscreen-overlay-v1.xml - ${CMAKE_CURRENT_SOURCE_DIR}/protocols/ext-idle-notify-v1.xml) + ${CMAKE_CURRENT_SOURCE_DIR}/protocols/ext-idle-notify-v1.xml + ${CMAKE_CURRENT_SOURCE_DIR}/protocols/ext-session-lock-v1.xml) # The QML files sit next to the module's qmldir in the resources, so they # see each other (and the Theme singleton) without importing anything. # Under /qt/qml, which the engine searches, or an installed agent finds no # types (the build directory only works by its FaceUnlock/qmldir). - set(FU_QML_FILES Theme FaceGlyph LockGlyph Checkmark Bubble TickRing Enroll PillButton) + set(FU_QML_FILES Theme FaceGlyph LockGlyph Checkmark Bubble TickRing Enroll PillButton LockScreen) foreach(f ${FU_QML_FILES}) set_source_files_properties(src/agent/qml/${f}.qml PROPERTIES QT_RESOURCE_ALIAS ${f}.qml) endforeach() @@ -192,6 +198,7 @@ if(FU_BUILD_AGENT) src/agent/qml/TickRing.qml src/agent/qml/Enroll.qml src/agent/qml/PillButton.qml + src/agent/qml/LockScreen.qml ) target_link_libraries(face-unlock-agent PRIVATE @@ -200,7 +207,9 @@ if(FU_BUILD_AGENT) LayerShellQt::Interface KF6::I18n KF6::I18nQml fu_common + ${PAM_LIBRARY} ) + target_include_directories(face-unlock-agent PRIVATE ${PAM_INCLUDE_DIR}) install(TARGETS face-unlock-agent DESTINATION ${FU_LIBEXECDIR}) endif() @@ -223,6 +232,16 @@ if(FU_BUILD_TESTS) target_link_libraries(test_images PRIVATE fu_core) if(FU_BUILD_AGENT) + add_executable(test_lockscreen tests/test_lockscreen.cpp src/agent/lockscreencontroller.cpp) + target_include_directories(test_lockscreen PRIVATE src/agent ${PAM_INCLUDE_DIR}) + target_link_libraries(test_lockscreen PRIVATE Qt6::Core KF6::I18n ${PAM_LIBRARY}) + add_test(NAME lockscreen COMMAND test_lockscreen) + + add_executable(test_wallpaper tests/test_wallpaper.cpp src/agent/wallpaper.cpp) + target_include_directories(test_wallpaper PRIVATE src/agent) + target_link_libraries(test_wallpaper PRIVATE Qt6::Core) + add_test(NAME wallpaper COMMAND test_wallpaper) + add_executable(test_lockers tests/test_lockers.cpp src/agent/lockers.cpp) target_include_directories(test_lockers PRIVATE src/agent) target_link_libraries(test_lockers PRIVATE Qt6::Core) diff --git a/README.md b/README.md index eeb1bf9..bf47570 100644 --- a/README.md +++ b/README.md @@ -74,8 +74,8 @@ desktops, on Wayland: |---|---|---|---| | KDE Plasma 6 | ✅ | ✅ | ✅ above the lock screen too | | GNOME | ✅ | ✅ | ✅ above the lock screen too | -| Hyprland | ✅ hyprlock, swaylock, gtklock or waylock | ✅ | ✅ once the lock screen is gone | -| Niri | ✅ swaylock, hyprlock, gtklock or waylock | ✅ | ✅ once the lock screen is gone | +| Hyprland | ✅ hyprlock, swaylock, gtklock, waylock, or face-unlock's own | ✅ | ✅ on face-unlock's own lock screen too | +| Niri | ✅ swaylock, hyprlock, gtklock, waylock, or face-unlock's own | ✅ | ✅ on face-unlock's own lock screen too | On GNOME a small GNOME extension draws the bubble. Turning face unlock on switches it on; right after installing, log out and back in once. @@ -86,10 +86,43 @@ press Enter on the empty password field to scan. hyprlock and swaylock also scan by themselves when you come back. Those lock screens cover the bubble, which shows the tick once they are gone. +For the bubble on the lock screen, use face-unlock's own: `face-unlock lock`. +It shows the wallpaper of your desktop (from swaybg, awww, hyprpaper or +wpaperd). Under **Settings** you can pick a picture instead, or a folder to take +one from at random, blurred if you like. + Admin prompts and setting up a face need a polkit agent there (for example hyprpolkitagent). Hyprland without uwsm does not start the part that watches the lock screen by itself: the menu shows what to add to its config. +
+Hyprland and Niri: face-unlock's lock screen on a key + +`~/.config/hypr/hyprland.conf`, and `lock_cmd` in `hypridle.conf`: + +```ini +bind = SUPER, L, exec, face-unlock lock +``` + +`~/.config/hypr/hyprland.lua` (Hyprland 0.56 and newer): + +```lua +hl.bind("SUPER + L", hl.dsp.exec_cmd("face-unlock lock")) +``` + +`~/.config/niri/config.kdl`, and `face-unlock lock` in swayidle: + +```kdl +binds { + Mod+Alt+L { spawn "face-unlock" "lock"; } +} +``` + +`face-unlock lock` returns as soon as the screen is locked, so it also works +for locking before sleep. + +
+
Coming from plasma-face-unlock? diff --git a/doc/face-unlock.1.scd b/doc/face-unlock.1.scd index 43412d4..ac105cc 100644 --- a/doc/face-unlock.1.scd +++ b/doc/face-unlock.1.scd @@ -18,9 +18,8 @@ a printed one does not either. A bubble at the top of the screen shows what is going on: it drops down when the camera starts looking, the face in it looks around, and when it recognises -somebody two green rings spin and land around a tick. On Plasma and GNOME it -shows above the lock screen too. *Animation speed* makes all of it faster or -slower. +somebody two green rings spin and land around a tick. It shows above the lock +screen too. *Animation speed* makes all of it faster or slower. Run without a command it shows an interactive menu. Everything it can be told is reachable from there; the settings files behind it do not need to be edited @@ -60,6 +59,12 @@ It is a convenience, not a security upgrade. See *HOW SAFE IS THIS*. *status* What is on, and when the last unlock was. +*lock* + Lock the screen. On Hyprland, Niri and other compositors whose lock + screen is a program of its own, with face-unlock's own lock screen, + which shows the bubble (see *DESKTOPS*). Elsewhere with the desktop's + lock screen. Returns once the screen is locked. + *-h*, *--help* Show a summary of the commands. @@ -196,8 +201,8 @@ does not start a scan with every key. When the face matches, the agent unlocks the session the way its lock screen wants it: through logind, as *loginctl unlock-session* does, on Plasma and -GNOME, and with SIGUSR1 for hyprlock and swaylock. Any other lock screen -opens itself, through PAM (see *DESKTOPS*). +GNOME, by itself on its own lock screen, and with SIGUSR1 for hyprlock and +swaylock. Any other lock screen opens itself, through PAM (see *DESKTOPS*). Unlocked through logind, Plasma's lock screen cuts off its own password prompt and counts that as a wrong password. After a face unlock the daemon resets the @@ -212,7 +217,8 @@ is under *DESKTOPS*. # DESKTOPS -All of them on Wayland. sudo and admin prompts work the same everywhere. +All of them on Wayland. sudo and admin prompts work the same everywhere, and +so does the bubble, above the lock screen too. *KDE Plasma 6* The lock is seen through org.freedesktop.ScreenSaver and logind, and @@ -240,6 +246,17 @@ All of them on Wayland. sudo and admin prompts work the same everywhere. when somebody comes back, and opens them with SIGUSR1. Those lock screens cover the bubble, which shows the tick once they are gone. + For the bubble on the lock screen there is face-unlock's own: *lock*. + It shows the time, a password field (PAM service _face-unlock-lock_ + when an administrator wrote one, else the distribution's password-auth, + common-auth or login) and the bubble, and a face opens it straight + away. Behind it is the picture on the desktop, as swaybg, awww (swww), + hyprpaper or wpaperd show it. *Wallpaper* under *Settings* puts another + picture there, one at random from a folder, or _none_; *Blur the + wallpaper* blurs it. If the agent dies while this screen is locked, the + compositor keeps it locked, and the agent takes the lock back when it + starts again. + Hyprland only starts the agent's user service under uwsm. Without it, *enable* and *status* show what to add to its config. @@ -310,7 +327,10 @@ _/run/face-unlock/socket_ _$XDG_RUNTIME_DIR/face-unlock/agent.socket_ Where the daemon tells the agent about scans it did not start, for the - bubble. + bubble, and where *lock* asks it to lock. + +_$XDG_RUNTIME_DIR/face-unlock/locked_ + There while face-unlock's own lock screen is up. _/usr/share/gnome-shell/extensions/face-unlock@loonixtools.github.io/_ The GNOME Shell extension that draws the bubble on GNOME. diff --git a/po/de.po b/po/de.po index 555c91c..a4461b5 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.0\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-23 22:32+0200\n" "Last-Translator: Felitendo\n" "Language-Team: German\n" @@ -59,8 +59,8 @@ msgstr "Es wurde kein Gesicht hinzugefügt." msgid "First, set up your face." msgstr "Richte zuerst dein Gesicht ein." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Einstellung konnte nicht gespeichert werden." @@ -113,16 +113,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Es ist noch kein Gesicht eingerichtet." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "an" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "aus" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s Aufnahmen, %s dazugelernt" @@ -152,7 +152,7 @@ msgstr "Gesichtsentsperrung einschalten" msgid "Turn it off (faces are kept)" msgstr "Ausschalten (Gesichter bleiben erhalten)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Gesicht hinzufügen" @@ -169,22 +169,26 @@ msgid "Look at the camera and see what it sees" msgstr "In die Kamera schauen und sehen, was sie sieht" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Bildschirm sperren" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Anzeigen, was eingeschaltet ist" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Diese Hilfe anzeigen" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Die Version anzeigen" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Ohne Befehl wird ein interaktives Menü angezeigt." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -192,42 +196,42 @@ msgstr "" "Starte das als dein eigener Benutzer, nicht als root. Wenn nötig, wird nach " "deinem Passwort gefragt." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Unbekannter Befehl: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "nie" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "gerade eben" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "vor 1 Minute" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "vor %d Minuten" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "vor 1 Stunde" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "vor %d Stunden" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "vor 1 Tag" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "vor %d Tagen" @@ -371,11 +375,11 @@ msgstr "" msgid "[y/N]" msgstr "[j/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "AN" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "AUS" @@ -416,7 +420,7 @@ msgstr "langsam" msgid "%s seconds" msgstr "%s Sekunden" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automatisch" @@ -436,8 +440,8 @@ msgstr "läuft nicht" msgid "Turning face unlock on again starts it." msgstr "Die Gesichtsentsperrung erneut einzuschalten startet ihn." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Gesichter" @@ -494,7 +498,7 @@ msgstr "Letzte Entsperrung" msgid "The lock screen agent is not running." msgstr "Der Sperrbildschirm-Dienst läuft nicht." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -502,16 +506,17 @@ msgstr "" "Unter GNOME zeigt eine kleine GNOME-Erweiterung die Bubble. Beim Einschalten " "der Gesichtsentsperrung wird sie mit eingeschaltet." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Scannt, wenn du zu hyprlock oder swaylock zurückkommst, und öffnet sie. " -"Jeder andere Sperrbildschirm scannt, wenn du Enter im leeren Passwortfeld " -"drückst." +"Scannt, wenn du zu hyprlock, swaylock oder zum Sperrbildschirm von face-" +"unlock zurückkommst (`face-unlock lock`, mit der Bubble), und öffnet sie. " +"Andere Sperrbildschirme scannen mit Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -519,7 +524,7 @@ msgstr "" "Entsperrt den Sperrbildschirm, wenn er dein Gesicht sieht. Aus: Dort geht " "nur dein Passwort." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -527,7 +532,7 @@ msgstr "" "Scannt, wenn du auf dem Sperrbildschirm eine Taste drückst oder die Maus " "bewegst, und wenn der Computer aufwacht." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -535,7 +540,7 @@ msgstr "" "Scannt, sobald der Bildschirm gesperrt wird. Normalerweise aus: Sperrst du " "selbst, würde er gleich wieder entsperren." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -543,7 +548,21 @@ msgstr "" "sudo nimmt dein Gesicht statt des Passworts. Passt es nicht, tippst du wie " "gewohnt dein Passwort." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"Das Bild hinter dem Sperrbildschirm von face-unlock (`face-unlock lock`). " +"Leer: das von deinem Desktop. Oder eine Datei, ein Ordner, aus dem zufällig " +"eins genommen wird, oder `none`. Enter zum Eintippen." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Zeichnet das Bild hinter dem Sperrbildschirm von face-unlock weich." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -552,7 +571,7 @@ msgstr "" "Der Sperrbildschirm nimmt dein Gesicht in seiner Passwortprüfung. Drück " "Enter im leeren Feld für einen Scan. Hier gefunden: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -560,18 +579,18 @@ msgstr "" "Die Passwort-Fenster deines Desktops und von Apps, zum Beispiel beim " "Installieren. Passt das Gesicht nicht, tippst du dein Passwort." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Du musst blinzeln oder den Kopf leicht drehen. Das hält auch ausgedruckte " "Fotos auf." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Keine Prüfung. Nur zum Ausprobieren einer Kamera." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -579,22 +598,22 @@ msgstr "" "Hält Fotos auf Handy, Tablet oder Hochglanzpapier auf. Blinzeln ist nicht " "nötig. Ein matter Ausdruck kann durchkommen." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Seltener Verwechslungen, aber mit Brille oder bei schlechtem Licht erkennt " "es dich vielleicht nicht." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Erkennt dich leichter, aber auch jemanden, der dir sehr ähnlich sieht." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "Der Standard. Passt für die meisten." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -602,7 +621,7 @@ msgstr "" "Deine Augen müssen offen sein und auf den Bildschirm schauen. So entsperrt " "es nicht, wenn du wegschaust oder schläfst." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -611,11 +630,11 @@ msgstr "" "neu einrichten. Eine Infrarot-Kamera braucht ihr Licht (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Wie lange die Kamera nach deinem Gesicht sucht, bevor sie aufgibt." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -623,7 +642,7 @@ msgstr "" "Nach einem sicheren Treffer merkt es sich, wie du gerade aussiehst. So musst " "du nach neuer Frisur oder Brille nichts neu einrichten." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -631,82 +650,99 @@ msgstr "" "Kein Scan bei zugeklapptem Laptop, zum Beispiel am Schreibtisch mit externem " "Bildschirm." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "Die Bubble oben am Bildschirm zeigt, was die Kamera gerade macht." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Eine kleine Pille mit einem Schloss, das aufgeht." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "" "Eine Insel mit einem Gesicht, das sich umschaut, danach Ringe und ein Haken." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Wie schnell sich die Bubble bewegt." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Zeigt die Bubble auch, wenn sudo oder eine Admin-Abfrage dein Gesicht scannt." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automatisch (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(Infrarot)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(nicht angeschlossen)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "wie Desktop" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "keins" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Bild oder Ordner:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Nicht gefunden: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Einstellungen" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ auswählen ←→ oder Leertaste: ändern q: zurück" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "für alle Nutzer, fragt nach deinem Passwort" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Hoch/Runter: wählen, Leertaste: an/aus, r: umbenennen, d: löschen, a: " "hinzufügen, q: zurück" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Es ist noch kein Gesicht eingerichtet. Drück a, um eins hinzuzufügen." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Neuer Name:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "„%s“ löschen?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Gesichtsentsperrung ein- oder ausschalten" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Ausprobieren" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Beenden" @@ -767,6 +803,14 @@ msgstr "Scannen, wenn du zurückkommst" msgid "Scan right after locking" msgstr "Gleich nach dem Sperren scannen" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Hintergrundbild" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Hintergrundbild weichzeichnen" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Passwort-Abfragen" @@ -928,23 +972,31 @@ msgstr "" msgid "The face could not be added (%1)." msgstr "Das Gesicht konnte nicht hinzugefügt werden (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Falsches Passwort" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "Gesichtsentsperrung für Sperrbildschirm, sudo und Admin-Abfragen" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Ein Gesicht einrichten." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Wie das neue Gesicht heißen soll." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Den Bildschirm sperren." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Die Animationen der Bubble einmal abspielen." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Bubble-Stil für die Demo: full oder minimal." @@ -1025,3 +1077,15 @@ msgstr "Los geht's" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Fertig" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Passwort" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Schau in die Kamera oder tippe dein Passwort" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Tippe dein Passwort" diff --git a/po/es.po b/po/es.po index 537609e..a200849 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Spanish\n" @@ -58,8 +58,8 @@ msgstr "No se añadió ninguna cara." msgid "First, set up your face." msgstr "Primero, configura tu cara." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "No se pudo guardar el ajuste." @@ -114,16 +114,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Todavía no hay ninguna cara configurada." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "activado" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "desactivado" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s muestras, %s aprendidas" @@ -153,7 +153,7 @@ msgstr "Activar el desbloqueo facial" msgid "Turn it off (faces are kept)" msgstr "Desactivarlo (las caras se conservan)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Añadir una cara" @@ -170,22 +170,26 @@ msgid "Look at the camera and see what it sees" msgstr "Mirar a la cámara y ver lo que ve" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Bloquear la pantalla" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Mostrar qué está activado" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Mostrar esta ayuda" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Mostrar la versión" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Sin comando se muestra un menú interactivo." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -193,42 +197,42 @@ msgstr "" "Ejecuta esto con tu propio usuario, no como root. Pide tu contraseña cuando " "la necesita." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Comando desconocido: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "nunca" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "ahora mismo" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "hace 1 minuto" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "hace %d minutos" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "hace 1 hora" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "hace %d horas" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "hace 1 día" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "hace %d días" @@ -372,11 +376,11 @@ msgstr "" msgid "[y/N]" msgstr "[s/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "ACTIVADO" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "DESACTIVADO" @@ -417,7 +421,7 @@ msgstr "lenta" msgid "%s seconds" msgstr "%s segundos" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automática" @@ -437,8 +441,8 @@ msgstr "detenido" msgid "Turning face unlock on again starts it." msgstr "Al volver a activar el desbloqueo facial, se inicia." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Caras" @@ -495,7 +499,7 @@ msgstr "Último desbloqueo" msgid "The lock screen agent is not running." msgstr "El agente de la pantalla de bloqueo no se está ejecutando." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -503,15 +507,17 @@ msgstr "" "En GNOME, una pequeña extensión de GNOME muestra la burbuja. Al activar el " "desbloqueo facial se activa también." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Escanea cuando vuelves a hyprlock o swaylock y los abre. Cualquier otra " -"pantalla de bloqueo escanea al pulsar Intro en el campo de contraseña vacío." +"Escanea cuando vuelves a hyprlock, swaylock o la pantalla de bloqueo propia " +"de face-unlock (`face-unlock lock`, con la burbuja) y los abre. Las demás " +"pantallas de bloqueo escanean con Intro." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -519,7 +525,7 @@ msgstr "" "Desbloquea la pantalla de bloqueo cuando ve tu cara. Desactivado: ahí solo " "sirve tu contraseña." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -527,7 +533,7 @@ msgstr "" "Escanea cuando pulsas una tecla o mueves el ratón en la pantalla de bloqueo, " "y cuando el equipo se despierta." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -535,7 +541,7 @@ msgstr "" "Escanea en cuanto se bloquea la pantalla. Desactivado por defecto: si la " "bloqueas tú, se desbloquearía enseguida." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -543,7 +549,21 @@ msgstr "" "sudo usa tu cara en lugar de la contraseña. Si no coincide, escribes la " "contraseña como siempre." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"La imagen detrás de la pantalla de bloqueo de face-unlock (`face-unlock " +"lock`). Vacío: la de tu escritorio. O un archivo, una carpeta de la que se " +"elige una al azar, o `none`. Intro para escribirla." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Desenfoca la imagen detrás de la pantalla de bloqueo de face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -552,7 +572,7 @@ msgstr "" "La pantalla de bloqueo acepta tu cara en su comprobación de contraseña. " "Pulsa Intro en el campo vacío para escanear. Encontradas aquí: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -560,18 +580,18 @@ msgstr "" "Las ventanas de contraseña de tu escritorio y de las aplicaciones, por " "ejemplo al instalar software. Si no coincide, escribes la contraseña." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Tienes que parpadear o girar un poco la cabeza. Esto también frena las fotos " "impresas." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Sin comprobación. Solo para probar una cámara." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -579,24 +599,24 @@ msgstr "" "Frena fotos en un móvil, una tableta o papel brillante. No hace falta " "parpadear. Una foto impresa en papel mate puede pasar." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Menos coincidencias erróneas, pero puede que no te reconozca con gafas o con " "poca luz." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "" "Te reconoce con más facilidad, pero también a alguien que se parezca mucho a " "ti." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "El valor por defecto. Adecuado para la mayoría." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -604,7 +624,7 @@ msgstr "" "Tus ojos tienen que estar abiertos y mirando a la pantalla. Así no se " "desbloquea mientras miras a otro lado o duermes." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -613,11 +633,11 @@ msgstr "" "tu cara. Una cámara infrarroja necesita su luz encendida (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Cuánto tiempo busca la cámara tu cara antes de rendirse." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -625,7 +645,7 @@ msgstr "" "Tras una coincidencia segura, recuerda tu aspecto actual. Así, un corte de " "pelo nuevo o unas gafas no piden configurar de nuevo." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -633,85 +653,102 @@ msgstr "" "Sin escaneo mientras el portátil está cerrado, por ejemplo en un escritorio " "con una pantalla externa." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "" "La burbuja en la parte superior de la pantalla muestra lo que hace la cámara." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Una pequeña pastilla con un candado que se abre." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "" "Una isla con una cara que mira alrededor, luego anillos y una marca de " "verificación." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "La velocidad a la que se mueve la burbuja." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Muestra la burbuja también cuando sudo o una solicitud de administrador " "escanea tu cara." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automática (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(infrarroja)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(no conectada)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "como el escritorio" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "ninguna" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Imagen o carpeta:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "No encontrado: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Ajustes" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ elegir ←→ o Espacio: cambiar q: volver" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "para todos los usuarios, pide tu contraseña" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Arriba/Abajo: elegir, Espacio: activar/desactivar, r: renombrar, d: borrar, " "a: añadir, q: volver" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Todavía no hay ninguna cara configurada. Pulsa a para añadir una." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Nuevo nombre:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "¿Borrar «%s»?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Activar o desactivar el desbloqueo facial" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Probarlo" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Salir" @@ -771,6 +808,14 @@ msgstr "Escanear cuando vuelvas" msgid "Scan right after locking" msgstr "Escanear justo después de bloquear" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Fondo de pantalla" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Desenfocar el fondo" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Solicitudes de contraseña" @@ -930,25 +975,33 @@ msgstr "" msgid "The face could not be added (%1)." msgstr "No se pudo añadir la cara (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Contraseña incorrecta" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Desbloqueo facial para la pantalla de bloqueo, sudo y las solicitudes de " "administrador" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Configurar una cara." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Cómo llamar a la nueva cara." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Bloquear la pantalla." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Reproducir una vez las animaciones de la burbuja." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Estilo de burbuja para la demo: full o minimal." @@ -1029,3 +1082,15 @@ msgstr "Empezar" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Hecho" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Contraseña" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Mira a la cámara o escribe tu contraseña" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Escribe tu contraseña" diff --git a/po/face-unlock.pot b/po/face-unlock.pot index a86cb0f..14daa52 100644 --- a/po/face-unlock.pot +++ b/po/face-unlock.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -54,8 +54,8 @@ msgstr "" msgid "First, set up your face." msgstr "" -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "" @@ -98,16 +98,16 @@ msgstr "" msgid "No face is set up yet." msgstr "" -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "" @@ -137,7 +137,7 @@ msgstr "" msgid "Turn it off (faces are kept)" msgstr "" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "" @@ -154,63 +154,67 @@ msgid "Look at the camera and see what it sees" msgstr "" #: src/face-unlock:200 -msgid "Show what is on" +msgid "Lock the screen" msgstr "" #: src/face-unlock:201 -msgid "Show this help" +msgid "Show what is on" msgstr "" #: src/face-unlock:202 +msgid "Show this help" +msgstr "" + +#: src/face-unlock:203 msgid "Show the version" msgstr "" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "" -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." msgstr "" -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "" @@ -350,11 +354,11 @@ msgstr "" msgid "[y/N]" msgstr "" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "" @@ -395,7 +399,7 @@ msgstr "" msgid "%s seconds" msgstr "" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "" @@ -415,8 +419,8 @@ msgstr "" msgid "Turning face unlock on again starts it." msgstr "" -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "" @@ -473,183 +477,212 @@ msgstr "" msgid "The lock screen agent is not running." msgstr "" -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." msgstr "" -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." msgstr "" -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." msgstr "" -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." msgstr "" -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." msgstr "" -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "" + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " "empty field to scan. Found here: %s." msgstr "" -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." msgstr "" -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "" -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." msgstr "" -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "" -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "" -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." msgstr "" -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." msgstr "" -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "" -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." msgstr "" -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." msgstr "" -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "" -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "" -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "" -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "" -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "" -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "" @@ -705,6 +738,14 @@ msgstr "" msgid "Scan right after locking" msgstr "" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "" + #: src/lib/menu.sh msgid "Password prompts" msgstr "" @@ -861,23 +902,31 @@ msgstr "" msgid "The face could not be added (%1)." msgstr "" -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "" -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "" -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "" + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "" -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "" @@ -952,3 +1001,15 @@ msgstr "" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "" diff --git a/po/fr.po b/po/fr.po index 6888d8e..402331f 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: French\n" @@ -60,8 +60,8 @@ msgstr "Aucun visage n'a été ajouté." msgid "First, set up your face." msgstr "Configurez d'abord votre visage." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Impossible d'enregistrer le réglage." @@ -116,16 +116,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Aucun visage n'est encore configuré." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "activé" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "désactivé" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s échantillons, %s appris" @@ -155,7 +155,7 @@ msgstr "Activer le déverrouillage facial" msgid "Turn it off (faces are kept)" msgstr "Le désactiver (les visages sont conservés)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Ajouter un visage" @@ -172,22 +172,26 @@ msgid "Look at the camera and see what it sees" msgstr "Regarder la caméra et voir ce qu'elle voit" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Verrouiller l'écran" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Afficher ce qui est activé" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Afficher cette aide" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Afficher la version" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Sans commande, un menu interactif s'affiche." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -195,42 +199,42 @@ msgstr "" "Lancez ceci avec votre propre utilisateur, pas en root. Le mot de passe est " "demandé quand il le faut." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Commande inconnue : %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "jamais" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "à l'instant" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "il y a 1 minute" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "il y a %d minutes" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "il y a 1 heure" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "il y a %d heures" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "il y a 1 jour" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "il y a %d jours" @@ -376,11 +380,11 @@ msgstr "" msgid "[y/N]" msgstr "[o/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "ACTIVÉ" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "DÉSACTIVÉ" @@ -421,7 +425,7 @@ msgstr "lent" msgid "%s seconds" msgstr "%s secondes" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automatique" @@ -441,8 +445,8 @@ msgstr "arrêté" msgid "Turning face unlock on again starts it." msgstr "Réactiver le déverrouillage facial le démarre." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Visages" @@ -499,7 +503,7 @@ msgstr "Dernier déverrouillage" msgid "The lock screen agent is not running." msgstr "L'agent de l'écran de verrouillage ne tourne pas." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -507,16 +511,17 @@ msgstr "" "Sous GNOME, une petite extension GNOME affiche la bulle. Activer le " "déverrouillage facial l'active aussi." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Scanne quand vous revenez à hyprlock ou swaylock et les ouvre. Tout autre " -"écran de verrouillage scanne quand vous appuyez sur Entrée dans le champ du " -"mot de passe vide." +"Scanne quand vous revenez à hyprlock, swaylock ou à l'écran de verrouillage " +"de face-unlock (`face-unlock lock`, avec la bulle) et les ouvre. Les autres " +"écrans de verrouillage scannent avec Entrée." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -524,7 +529,7 @@ msgstr "" "Déverrouille l'écran de verrouillage quand il voit votre visage. Désactivé : " "seul votre mot de passe fonctionne." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -532,7 +537,7 @@ msgstr "" "Scanne quand vous appuyez sur une touche ou bougez la souris sur l'écran de " "verrouillage, et au réveil de l'ordinateur." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -540,7 +545,7 @@ msgstr "" "Scanne dès que l'écran se verrouille. Désactivé par défaut : si vous " "verrouillez vous-même, il se déverrouillerait aussitôt." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -548,7 +553,21 @@ msgstr "" "sudo prend votre visage au lieu du mot de passe. Sinon, vous tapez le mot de " "passe comme d'habitude." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"L'image derrière l'écran de verrouillage de face-unlock (`face-unlock " +"lock`). Vide : celle de votre bureau. Ou un fichier, un dossier où en " +"prendre une au hasard, ou `none`. Entrée pour la saisir." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Floute l'image derrière l'écran de verrouillage de face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -557,7 +576,7 @@ msgstr "" "L'écran de verrouillage accepte votre visage dans sa vérification du mot de " "passe. Appuyez sur Entrée dans le champ vide pour scanner. Trouvés ici : %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -565,18 +584,18 @@ msgstr "" "Les fenêtres de mot de passe de votre bureau et des applications, par " "exemple pour installer un logiciel. Sinon, vous tapez le mot de passe." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Vous devez cligner des yeux ou tourner un peu la tête. Cela bloque aussi les " "photos imprimées." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Aucun contrôle. Seulement pour essayer une caméra." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -584,24 +603,24 @@ msgstr "" "Bloque les photos sur un téléphone, une tablette ou du papier brillant. Pas " "besoin de cligner des yeux. Une photo imprimée mate peut passer." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Moins d'erreurs de correspondance, mais il peut ne pas vous reconnaître avec " "des lunettes ou sous une mauvaise lumière." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "" "Vous reconnaît plus facilement, mais aussi quelqu'un qui vous ressemble " "beaucoup." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "La valeur par défaut. Convient à la plupart des gens." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -609,7 +628,7 @@ msgstr "" "Vos yeux doivent être ouverts et tournés vers l'écran. Ainsi, rien ne se " "déverrouille quand vous regardez ailleurs ou dormez." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -618,11 +637,11 @@ msgstr "" "reconfigurez votre visage. Une caméra infrarouge doit avoir sa lumière " "allumée (linux-enable-ir-emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Combien de temps la caméra cherche votre visage avant d'abandonner." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -631,7 +650,7 @@ msgstr "" "nouvelle coupe ou des lunettes ne demandent donc pas de nouvelle " "configuration." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -639,84 +658,101 @@ msgstr "" "Pas de scan quand le portable est fermé, par exemple à un bureau avec un " "écran externe." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "La bulle en haut de l'écran montre ce que fait la caméra." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Une petite pilule avec un cadenas qui s'ouvre." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "" "Un îlot avec un visage qui regarde autour de lui, puis des anneaux et une " "coche." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "La vitesse à laquelle la bulle bouge." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Affiche aussi la bulle quand sudo ou une demande d'administration scanne " "votre visage." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automatique (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(infrarouge)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(non branchée)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "comme le bureau" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "aucun" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Image ou dossier :" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Introuvable : %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Réglages" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ choisir ←→ ou Espace : changer q : retour" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "pour tous, demande votre mot de passe" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Haut/Bas : choisir, Espace : activer/désactiver, r : renommer, d : " "supprimer, a : ajouter, q : retour" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Aucun visage n'est encore configuré. Appuyez sur a pour en ajouter un." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Nouveau nom :" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Supprimer « %s » ?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Activer ou désactiver le déverrouillage facial" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Essayer" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Quitter" @@ -777,6 +813,14 @@ msgstr "Scanner à votre retour" msgid "Scan right after locking" msgstr "Scanner juste après le verrouillage" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Fond d'écran" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Flouter le fond d'écran" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Demandes de mot de passe" @@ -936,25 +980,33 @@ msgstr "La caméra est occupée par un autre scan. Réessayez dans un instant." msgid "The face could not be added (%1)." msgstr "Le visage n'a pas pu être ajouté (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Mot de passe incorrect" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Déverrouillage facial pour l'écran de verrouillage, sudo et les demandes " "d'administration" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Configurer un visage." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Le nom du nouveau visage." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Verrouiller l'écran." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Jouer une fois les animations de la bulle." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Style de bulle pour la démo : full ou minimal." @@ -1036,3 +1088,15 @@ msgstr "Commencer" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Terminé" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Mot de passe" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Regardez la caméra ou tapez votre mot de passe" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Tapez votre mot de passe" diff --git a/po/it.po b/po/it.po index 8090599..ff1434e 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Italian\n" @@ -58,8 +58,8 @@ msgstr "Nessun volto aggiunto." msgid "First, set up your face." msgstr "Per prima cosa, configura il tuo volto." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Impossibile salvare l'impostazione." @@ -110,16 +110,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Nessun volto ancora configurato." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "attivo" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "disattivo" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s campioni, %s appresi" @@ -149,7 +149,7 @@ msgstr "Attiva lo sblocco con il volto" msgid "Turn it off (faces are kept)" msgstr "Disattivalo (i volti restano salvati)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Aggiungi un volto" @@ -166,22 +166,26 @@ msgid "Look at the camera and see what it sees" msgstr "Guarda la fotocamera e vedi cosa vede" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Blocca lo schermo" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Mostra cosa è attivo" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Mostra questo aiuto" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Mostra la versione" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Senza comando viene mostrato un menu interattivo." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -189,42 +193,42 @@ msgstr "" "Esegui questo con il tuo utente, non come root. Chiede la password quando " "serve." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Comando sconosciuto: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "mai" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "proprio ora" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 minuto fa" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d minuti fa" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 ora fa" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d ore fa" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 giorno fa" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d giorni fa" @@ -369,11 +373,11 @@ msgstr "" msgid "[y/N]" msgstr "[s/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "ATTIVO" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "DISATTIVO" @@ -414,7 +418,7 @@ msgstr "lenta" msgid "%s seconds" msgstr "%s secondi" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automatica" @@ -434,8 +438,8 @@ msgstr "non in esecuzione" msgid "Turning face unlock on again starts it." msgstr "Riattivare lo sblocco con il volto lo avvia." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Volti" @@ -492,7 +496,7 @@ msgstr "Ultimo sblocco" msgid "The lock screen agent is not running." msgstr "L'agente della schermata di blocco non è in esecuzione." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -500,15 +504,17 @@ msgstr "" "Su GNOME una piccola estensione di GNOME mostra la bolla. Attivando lo " "sblocco con il volto si attiva anche lei." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Scansiona quando torni a hyprlock o swaylock e li apre. Ogni altra schermata " -"di blocco scansiona quando premi Invio nel campo password vuoto." +"Scansiona quando torni a hyprlock, swaylock o alla schermata di blocco di " +"face-unlock (`face-unlock lock`, con la bolla) e li apre. Le altre schermate " +"di blocco scansionano con Invio." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -516,7 +522,7 @@ msgstr "" "Sblocca la schermata di blocco quando vede il tuo volto. Disattivo: lì " "funziona solo la password." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -524,7 +530,7 @@ msgstr "" "Esegue la scansione quando premi un tasto o muovi il mouse sulla schermata " "di blocco, e quando il computer si riattiva." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -532,7 +538,7 @@ msgstr "" "Esegue la scansione appena lo schermo si blocca. Disattivo di norma: se lo " "blocchi tu, si sbloccherebbe subito." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -540,7 +546,21 @@ msgstr "" "sudo usa il tuo volto al posto della password. Se non corrisponde, digiti la " "password come al solito." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"L'immagine dietro la schermata di blocco di face-unlock (`face-unlock " +"lock`). Vuoto: quella del tuo desktop. Oppure un file, una cartella da cui " +"prenderne una a caso, o `none`. Invio per scriverla." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Sfoca l'immagine dietro la schermata di blocco di face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -549,7 +569,7 @@ msgstr "" "La schermata di blocco accetta il tuo volto nel controllo della password. " "Premi Invio nel campo vuoto per scansionare. Trovate qui: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -557,18 +577,18 @@ msgstr "" "Le finestre della password del tuo desktop e delle app, per esempio quando " "installi software. Se non corrisponde, digiti la password." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Devi sbattere le palpebre o girare un po' la testa. Questo ferma anche le " "foto stampate." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Nessun controllo. Solo per provare una fotocamera." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -576,22 +596,22 @@ msgstr "" "Ferma le foto su un telefono, un tablet o carta lucida. Non serve sbattere " "le palpebre. Una foto stampata opaca può passare." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Meno scambi di persona, ma potrebbe non riconoscerti con gli occhiali o con " "poca luce." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Ti riconosce più facilmente, ma anche qualcuno che ti somiglia molto." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "Il valore predefinito. Va bene per la maggior parte delle persone." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -599,7 +619,7 @@ msgstr "" "I tuoi occhi devono essere aperti e rivolti allo schermo. Così non si " "sblocca mentre guardi altrove o dormi." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -608,11 +628,11 @@ msgstr "" "nuovo il tuo volto. Una fotocamera a infrarossi ha bisogno della sua luce " "(linux-enable-ir-emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Per quanto tempo la fotocamera cerca il tuo volto prima di arrendersi." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -621,7 +641,7 @@ msgstr "" "nuovo taglio di capelli o gli occhiali non richiedono una nuova " "configurazione." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -629,82 +649,99 @@ msgstr "" "Nessuna scansione quando il portatile è chiuso, per esempio alla scrivania " "con uno schermo esterno." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "La bolla in cima allo schermo mostra cosa sta facendo la fotocamera." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Una piccola pillola con un lucchetto che si apre." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Un'isola con un volto che si guarda intorno, poi anelli e una spunta." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Quanto velocemente si muove la bolla." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Mostra la bolla anche quando sudo o una richiesta di amministratore " "scansiona il tuo volto." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automatica (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(infrarossi)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(non collegata)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "come il desktop" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "nessuno" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Immagine o cartella:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Non trovato: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Impostazioni" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ scegli ←→ o Spazio: cambia q: indietro" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "per tutti gli utenti, chiede la tua password" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Su/Giù: scegli, Spazio: attiva/disattiva, r: rinomina, d: elimina, a: " "aggiungi, q: indietro" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Nessun volto ancora configurato. Premi a per aggiungerne uno." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Nuovo nome:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Eliminare «%s»?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Attiva o disattiva lo sblocco con il volto" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Provalo" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Esci" @@ -765,6 +802,14 @@ msgstr "Scansiona quando torni" msgid "Scan right after locking" msgstr "Scansiona subito dopo il blocco" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Sfondo" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Sfoca lo sfondo" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Richieste di password" @@ -924,25 +969,33 @@ msgstr "" msgid "The face could not be added (%1)." msgstr "Impossibile aggiungere il volto (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Password errata" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Sblocco con il volto per la schermata di blocco, sudo e le richieste di " "amministratore" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Configura un volto." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Come chiamare il nuovo volto." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Blocca lo schermo." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Riproduci una volta le animazioni della bolla." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Stile della bolla per la demo: full o minimal." @@ -1024,3 +1077,15 @@ msgstr "Iniziamo" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Fatto" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Password" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Guarda la fotocamera o digita la password" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Digita la password" diff --git a/po/ja.po b/po/ja.po index cdd44f7..14e9a40 100644 --- a/po/ja.po +++ b/po/ja.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Japanese\n" @@ -57,8 +57,8 @@ msgstr "顔は追加されませんでした。" msgid "First, set up your face." msgstr "まず顔を登録してください。" -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "設定を保存できませんでした。" @@ -106,16 +106,16 @@ msgstr "顔認証はオフです。顔データは残っています。「顔」 msgid "No face is set up yet." msgstr "まだ顔が登録されていません。" -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "オン" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "オフ" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "サンプル %s 件、学習 %s 件" @@ -145,7 +145,7 @@ msgstr "顔認証をオンにする" msgid "Turn it off (faces are kept)" msgstr "オフにする(顔データは残ります)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "顔を追加" @@ -162,22 +162,26 @@ msgid "Look at the camera and see what it sees" msgstr "カメラを見て、カメラに映るものを確認する" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "画面をロック" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "オンになっている機能を表示" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "このヘルプを表示" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "バージョンを表示" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "コマンドなしで起動すると、対話式メニューが表示されます。" -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -185,42 +189,42 @@ msgstr "" "root ではなく、自分のユーザーで実行してください。必要なときはパスワードを尋ね" "ます。" -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "不明なコマンド: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "なし" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "たった今" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 分前" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d 分前" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 時間前" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d 時間前" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 日前" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d 日前" @@ -364,11 +368,11 @@ msgstr "" msgid "[y/N]" msgstr "[y/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "オン" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "オフ" @@ -409,7 +413,7 @@ msgstr "遅い" msgid "%s seconds" msgstr "%s 秒" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "自動" @@ -429,8 +433,8 @@ msgstr "停止中" msgid "Turning face unlock on again starts it." msgstr "顔認証をもう一度オンにすると起動します。" -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "顔" @@ -487,7 +491,7 @@ msgstr "最後のロック解除" msgid "The lock screen agent is not running." msgstr "ロック画面エージェントが動いていません。" -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -495,15 +499,17 @@ msgstr "" "GNOME では小さな GNOME 拡張機能がバブルを表示します。顔認証をオンにすると一緒" "に有効になります。" -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"hyprlock や swaylock に戻ってきたときにスキャンして開きます。それ以外のロック" -"画面は、空のパスワード欄で Enter を押すとスキャンします。" +"hyprlock、swaylock、face-unlock のロック画面(`face-unlock lock`、バブル付" +"き)に戻ってきたときにスキャンして開きます。ほかのロック画面は Enter でスキャ" +"ンします。" -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -511,7 +517,7 @@ msgstr "" "顔を認識するとロック画面を解除します。オフ: ロック画面ではパスワードだけが使" "えます。" -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -519,7 +525,7 @@ msgstr "" "ロック画面でキーを押すかマウスを動かしたとき、そしてコンピューターがスリープ" "から復帰したときにスキャンします。" -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -527,7 +533,7 @@ msgstr "" "画面がロックされるとすぐにスキャンします。既定はオフ: 自分でロックすると、す" "ぐに解除されてしまうためです。" -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -535,7 +541,20 @@ msgstr "" "sudo でパスワードの代わりに顔を使います。一致しなければ、いつも通りパスワード" "を入力します。" -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"face-unlock のロック画面(`face-unlock lock`)の背景画像。空欄: デスクトップ" +"と同じ画像。またはファイル、ランダムに選ぶフォルダー、`none`。Enter で入力。" + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "face-unlock のロック画面の背景画像をぼかします。" + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -544,7 +563,7 @@ msgstr "" "ロック画面のパスワード確認で顔が使えます。空の欄で Enter を押すとスキャンしま" "す。見つかったもの: %s。" -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -552,16 +571,16 @@ msgstr "" "デスクトップやアプリのパスワード画面です(ソフトウェアのインストール時な" "ど)。一致しなければパスワードを入力します。" -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "まばたきするか、少し顔を動かす必要があります。印刷した写真も防げます。" -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "チェックしません。カメラを試すときだけ使ってください。" -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -569,22 +588,22 @@ msgstr "" "スマホ、タブレット、光沢紙に映った写真を防ぎます。まばたきは不要です。つや消" "しの印刷写真は通ることがあります。" -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "誤認識は減りますが、眼鏡をかけているときや暗いときに認識されないことがありま" "す。" -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "認識されやすくなりますが、あなたによく似た人も認識されやすくなります。" -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "既定値です。ほとんどの人に適しています。" -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -592,7 +611,7 @@ msgstr "" "目を開けて画面を見ている必要があります。よそ見や居眠りの間にロック解除されま" "せん。" -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -600,11 +619,11 @@ msgstr "" "「自動」は最初の通常のカメラを使います。変更したら顔を登録し直してください。" "赤外線カメラはライトをオンにする必要があります(linux-enable-ir-emitter)。" -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "カメラが顔を探してからあきらめるまでの時間です。" -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -612,7 +631,7 @@ msgstr "" "確実に一致したとき、今の見た目を覚えます。髪型を変えたり眼鏡をかけたりして" "も、登録し直す必要はありません。" -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -620,79 +639,96 @@ msgstr "" "ノートパソコンを閉じているときはスキャンしません。外部モニターにつないで机で" "使う場合などです。" -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "画面上部のバブルに、カメラの状態が表示されます。" -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "鍵が開く小さなピルです。" -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "あたりを見回す顔のアイランド。そのあとリングとチェックマークが出ます。" -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "バブルが動く速さです。" -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "sudo や管理者の認証で顔をスキャンするときにもバブルを表示します。" -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "自動(%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(赤外線)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(未接続)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "デスクトップと同じ" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "なし" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "画像またはフォルダー:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "見つかりません: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "設定" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ 選択 ←→ またはスペース: 変更 q: 戻る" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "全ユーザー共通、パスワードが必要" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "上/下: 選択、スペース: オン/オフ、r: 名前を変更、d: 削除、a: 追加、q: 戻る" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "まだ顔が登録されていません。a を押して追加してください。" -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "新しい名前:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "「%s」を削除しますか?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "顔認証のオン/オフ" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "試す" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "終了" @@ -751,6 +787,14 @@ msgstr "戻ってきたらスキャン" msgid "Scan right after locking" msgstr "ロック直後にスキャン" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "壁紙" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "壁紙をぼかす" + #: src/lib/menu.sh msgid "Password prompts" msgstr "パスワードの入力画面" @@ -907,23 +951,31 @@ msgstr "カメラは別のスキャン中です。少ししてからもう一度 msgid "The face could not be added (%1)." msgstr "顔を追加できませんでした(%1)。" -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "パスワードが違います" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "ロック画面、sudo、管理者の認証のための顔認証" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "顔を登録します。" -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "新しい顔の名前。" -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "画面をロックします。" + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "バブルのアニメーションを一度再生します。" -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "デモのバブルスタイル: full または minimal。" @@ -1004,3 +1056,15 @@ msgstr "はじめる" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "完了" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "パスワード" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "カメラを見るか、パスワードを入力してください" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "パスワードを入力してください" diff --git a/po/ko.po b/po/ko.po index feb03e8..ea0a6b5 100644 --- a/po/ko.po +++ b/po/ko.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Korean\n" @@ -57,8 +57,8 @@ msgstr "얼굴이 추가되지 않았습니다." msgid "First, set up your face." msgstr "먼저 얼굴을 등록하세요." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "설정을 저장하지 못했습니다." @@ -107,16 +107,16 @@ msgstr "" msgid "No face is set up yet." msgstr "아직 등록된 얼굴이 없습니다." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "켜짐" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "꺼짐" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "샘플 %s개, 학습 %s개" @@ -146,7 +146,7 @@ msgstr "얼굴 잠금 해제 켜기" msgid "Turn it off (faces are kept)" msgstr "끄기 (얼굴 데이터는 유지)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "얼굴 추가" @@ -163,63 +163,67 @@ msgid "Look at the camera and see what it sees" msgstr "카메라를 보고 카메라에 보이는 것을 확인" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "화면 잠그기" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "켜져 있는 기능 보기" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "이 도움말 보기" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "버전 보기" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "명령 없이 실행하면 대화형 메뉴가 나옵니다." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." msgstr "root가 아닌 본인 사용자로 실행하세요. 필요하면 비밀번호를 묻습니다." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "알 수 없는 명령: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "없음" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "방금" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1분 전" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d분 전" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1시간 전" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d시간 전" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1일 전" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d일 전" @@ -363,11 +367,11 @@ msgstr "" msgid "[y/N]" msgstr "[y/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "켜짐" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "꺼짐" @@ -408,7 +412,7 @@ msgstr "느리게" msgid "%s seconds" msgstr "%s초" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "자동" @@ -428,8 +432,8 @@ msgstr "실행 중 아님" msgid "Turning face unlock on again starts it." msgstr "얼굴 잠금 해제를 다시 켜면 시작됩니다." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "얼굴" @@ -486,7 +490,7 @@ msgstr "마지막 잠금 해제" msgid "The lock screen agent is not running." msgstr "잠금 화면 에이전트가 실행 중이 아닙니다." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -494,22 +498,23 @@ msgstr "" "GNOME에서는 작은 GNOME 확장이 버블을 보여 줍니다. 얼굴 잠금 해제를 켜면 함께 " "켜집니다." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"hyprlock이나 swaylock으로 돌아오면 스캔해서 엽니다. 다른 잠금 화면은 빈 비밀" -"번호 칸에서 Enter를 누르면 스캔합니다." +"hyprlock, swaylock 또는 face-unlock 자체 잠금 화면(`face-unlock lock`, 버블 " +"포함)으로 돌아오면 스캔해서 엽니다. 다른 잠금 화면은 Enter로 스캔합니다." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." msgstr "" "얼굴을 보면 잠금 화면을 해제합니다. 꺼짐: 잠금 화면에서는 비밀번호만 됩니다." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -517,7 +522,7 @@ msgstr "" "잠금 화면에서 키를 누르거나 마우스를 움직일 때, 그리고 컴퓨터가 깨어날 때 스" "캔합니다." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -525,7 +530,7 @@ msgstr "" "화면이 잠기자마자 스캔합니다. 기본값은 꺼짐: 직접 잠그면 곧바로 다시 풀려 버" "리기 때문입니다." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -533,7 +538,20 @@ msgstr "" "sudo가 비밀번호 대신 얼굴을 사용합니다. 일치하지 않으면 평소처럼 비밀번호를 " "입력합니다." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"face-unlock 잠금 화면(`face-unlock lock`)의 배경 그림. 비워 두면 바탕 화면의 " +"그림. 또는 파일, 무작위로 고를 폴더, `none`. Enter로 입력." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "face-unlock 잠금 화면의 배경 그림을 흐리게 합니다." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -542,7 +560,7 @@ msgstr "" "잠금 화면의 비밀번호 확인에서 얼굴을 받습니다. 빈 칸에서 Enter를 누르면 스캔" "합니다. 찾은 것: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -550,16 +568,16 @@ msgstr "" "데스크톱과 앱의 비밀번호 창입니다. 예를 들어 소프트웨어를 설치할 때입니다. 일" "치하지 않으면 비밀번호를 입력합니다." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "눈을 깜빡이거나 고개를 살짝 돌려야 합니다. 인쇄한 사진도 막아 줍니다." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "검사하지 않습니다. 카메라를 시험할 때만 쓰세요." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -567,22 +585,22 @@ msgstr "" "휴대폰, 태블릿, 광택지에 있는 사진을 막습니다. 눈을 깜빡일 필요는 없습니다. " "무광 인쇄 사진은 통과할 수 있습니다." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "잘못 일치하는 경우가 줄지만, 안경을 쓰거나 조명이 나쁘면 알아보지 못할 수 있" "습니다." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "더 쉽게 알아보지만, 당신과 많이 닮은 사람도 알아볼 수 있습니다." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "기본값입니다. 대부분의 사람에게 알맞습니다." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -590,7 +608,7 @@ msgstr "" "눈을 뜨고 화면을 보고 있어야 합니다. 그래서 다른 곳을 보거나 자는 동안에는 풀" "리지 않습니다." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -598,11 +616,11 @@ msgstr "" "자동은 첫 번째 일반 카메라를 사용합니다. 바꾼 뒤에는 얼굴을 다시 등록하세요. " "적외선 카메라는 조명을 켜야 합니다 (linux-enable-ir-emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "카메라가 포기하기 전까지 얼굴을 찾는 시간입니다." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -610,7 +628,7 @@ msgstr "" "확실히 일치하면 지금 모습을 기억합니다. 그래서 머리 모양이 바뀌거나 안경을 써" "도 다시 등록할 필요가 없습니다." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -618,79 +636,96 @@ msgstr "" "노트북을 덮었을 때는 스캔하지 않습니다. 예를 들어 외부 모니터를 연결해 책상에" "서 쓸 때입니다." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "화면 위쪽의 버블이 카메라가 하는 일을 보여 줍니다." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "자물쇠가 열리는 작은 알약입니다." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "주위를 둘러보는 얼굴이 있는 아일랜드, 그다음 링과 체크 표시입니다." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "버블이 움직이는 속도입니다." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "sudo나 관리자 인증 창이 얼굴을 스캔할 때도 버블을 보여 줍니다." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "자동 (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(적외선)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(연결 안 됨)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "바탕 화면과 같음" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "없음" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "그림 또는 폴더:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "찾을 수 없음: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "설정" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ 선택 ←→ 또는 스페이스: 변경 q: 뒤로" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "모든 사용자에게 적용, 비밀번호 필요" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "위/아래: 선택, 스페이스: 켜기/끄기, r: 이름 바꾸기, d: 삭제, a: 추가, q: 뒤로" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "아직 등록된 얼굴이 없습니다. a를 눌러 추가하세요." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "새 이름:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "\"%s\" 항목을 삭제할까요?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "얼굴 잠금 해제 켜기/끄기" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "사용해 보기" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "끝내기" @@ -750,6 +785,14 @@ msgstr "돌아오면 스캔" msgid "Scan right after locking" msgstr "잠근 직후 스캔" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "배경 화면" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "배경 화면 흐리게" + #: src/lib/menu.sh msgid "Password prompts" msgstr "비밀번호 입력 창" @@ -907,23 +950,31 @@ msgstr "카메라가 다른 스캔으로 사용 중입니다. 잠시 후 다시 msgid "The face could not be added (%1)." msgstr "얼굴을 추가하지 못했습니다 (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "비밀번호가 틀렸습니다" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "잠금 화면, sudo, 관리자 인증 창을 위한 얼굴 잠금 해제" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "얼굴을 등록합니다." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "새 얼굴의 이름." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "화면을 잠급니다." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "버블 애니메이션을 한 번 재생합니다." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "데모용 버블 스타일: full 또는 minimal." @@ -1003,3 +1054,15 @@ msgstr "시작하기" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "완료" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "비밀번호" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "카메라를 보거나 비밀번호를 입력하세요" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "비밀번호를 입력하세요" diff --git a/po/nl.po b/po/nl.po index 3eeaf21..01520cd 100644 --- a/po/nl.po +++ b/po/nl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Dutch\n" @@ -58,8 +58,8 @@ msgstr "Er is geen gezicht toegevoegd." msgid "First, set up your face." msgstr "Stel eerst je gezicht in." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Kon de instelling niet opslaan." @@ -110,16 +110,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Er is nog geen gezicht ingesteld." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "aan" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "uit" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s opnames, %s bijgeleerd" @@ -149,7 +149,7 @@ msgstr "Gezichtsontgrendeling aanzetten" msgid "Turn it off (faces are kept)" msgstr "Uitzetten (gezichten blijven bewaard)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Een gezicht toevoegen" @@ -166,22 +166,26 @@ msgid "Look at the camera and see what it sees" msgstr "In de camera kijken en zien wat hij ziet" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Scherm vergrendelen" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Tonen wat er aan staat" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Deze hulp tonen" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "De versie tonen" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Zonder opdracht verschijnt een interactief menu." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -189,42 +193,42 @@ msgstr "" "Voer dit uit als je eigen gebruiker, niet als root. Het vraagt om je " "wachtwoord als dat nodig is." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Onbekende opdracht: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "nooit" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "zojuist" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 minuut geleden" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d minuten geleden" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 uur geleden" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d uur geleden" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 dag geleden" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d dagen geleden" @@ -368,11 +372,11 @@ msgstr "" msgid "[y/N]" msgstr "[j/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "AAN" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "UIT" @@ -413,7 +417,7 @@ msgstr "langzaam" msgid "%s seconds" msgstr "%s seconden" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automatisch" @@ -433,8 +437,8 @@ msgstr "draait niet" msgid "Turning face unlock on again starts it." msgstr "Gezichtsontgrendeling opnieuw aanzetten start hem." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Gezichten" @@ -491,7 +495,7 @@ msgstr "Laatste ontgrendeling" msgid "The lock screen agent is not running." msgstr "De agent voor het vergrendelscherm draait niet." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -499,15 +503,17 @@ msgstr "" "Op GNOME toont een kleine GNOME-extensie de bubbel. Als je " "gezichtsontgrendeling inschakelt, gaat die ook aan." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Scant als je terugkomt bij hyprlock of swaylock en opent ze. Elk ander " -"vergrendelscherm scant als je op Enter drukt in het lege wachtwoordveld." +"Scant als je terugkomt bij hyprlock, swaylock of het eigen vergrendelscherm " +"van face-unlock (`face-unlock lock`, met de bubbel) en opent ze. Andere " +"vergrendelschermen scannen met Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -515,7 +521,7 @@ msgstr "" "Ontgrendelt het vergrendelscherm als het je gezicht ziet. Uit: daar werkt " "alleen je wachtwoord." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -523,7 +529,7 @@ msgstr "" "Scant als je op het vergrendelscherm een toets indrukt of de muis beweegt, " "en als de computer ontwaakt." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -531,7 +537,7 @@ msgstr "" "Scant zodra het scherm vergrendelt. Standaard uit: vergrendel je zelf, dan " "zou het meteen weer ontgrendelen." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -539,7 +545,21 @@ msgstr "" "sudo neemt je gezicht in plaats van het wachtwoord. Geen match: je typt " "zoals gewoonlijk je wachtwoord." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"De afbeelding achter het vergrendelscherm van face-unlock (`face-unlock " +"lock`). Leeg: die van je bureaublad. Of een bestand, een map waaruit er " +"willekeurig een wordt gekozen, of `none`. Enter om te typen." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Vervaagt de afbeelding achter het vergrendelscherm van face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -548,7 +568,7 @@ msgstr "" "Het vergrendelscherm neemt je gezicht in zijn wachtwoordcontrole. Druk op " "Enter in het lege veld om te scannen. Hier gevonden: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -556,18 +576,18 @@ msgstr "" "De wachtwoordvensters van je bureaublad en apps, bijvoorbeeld bij het " "installeren van software. Geen match: je typt je wachtwoord." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Je moet knipperen of je hoofd een beetje draaien. Dat houdt ook geprinte " "foto's tegen." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Helemaal geen controle. Alleen om een camera uit te proberen." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -575,22 +595,22 @@ msgstr "" "Houdt foto's op een telefoon, tablet of glanzend papier tegen. Knipperen is " "niet nodig. Een matte geprinte foto kan erdoor komen." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Minder verwisselingen, maar met een bril of bij slecht licht herkent het je " "misschien niet." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Herkent je makkelijker, maar ook iemand die veel op je lijkt." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "De standaard. Goed voor de meeste mensen." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -598,7 +618,7 @@ msgstr "" "Je ogen moeten open zijn en naar het scherm kijken. Zo ontgrendelt het niet " "als je wegkijkt of slaapt." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -607,11 +627,11 @@ msgstr "" "opnieuw in. Een infraroodcamera heeft zijn lampje nodig (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Hoe lang de camera naar je gezicht zoekt voordat hij opgeeft." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -619,7 +639,7 @@ msgstr "" "Na een zekere match onthoudt het hoe je er nu uitziet. Een nieuw kapsel of " "een bril vraagt dus niet om opnieuw instellen." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -627,80 +647,97 @@ msgstr "" "Geen scan als de laptop dicht is, bijvoorbeeld aan een bureau met een extern " "scherm." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "De bubbel boven aan het scherm laat zien wat de camera doet." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Een kleine pil met een slot dat opengaat." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Een eiland met een gezicht dat rondkijkt, daarna ringen en een vinkje." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Hoe snel de bubbel beweegt." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "Toont de bubbel ook als sudo of een beheerdersvraag je gezicht scant." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automatisch (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(infrarood)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(niet aangesloten)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "zoals bureaublad" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "geen" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Afbeelding of map:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Niet gevonden: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Instellingen" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ kiezen ←→ of Spatie: wijzigen q: terug" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "voor alle gebruikers, vraagt om je wachtwoord" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Omhoog/Omlaag: kiezen, Spatie: aan/uit, r: hernoemen, d: verwijderen, a: " "toevoegen, q: terug" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Er is nog geen gezicht ingesteld. Druk op a om er een toe te voegen." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Nieuwe naam:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "“%s” verwijderen?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Gezichtsontgrendeling aan- of uitzetten" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Uitproberen" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Afsluiten" @@ -762,6 +799,14 @@ msgstr "Scannen als je terugkomt" msgid "Scan right after locking" msgstr "Scannen direct na vergrendelen" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Achtergrond" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Achtergrond vervagen" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Wachtwoordvragen" @@ -921,24 +966,32 @@ msgstr "De camera is bezig met een andere scan. Probeer het zo opnieuw." msgid "The face could not be added (%1)." msgstr "Het gezicht kon niet worden toegevoegd (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Verkeerd wachtwoord" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Gezichtsontgrendeling voor het vergrendelscherm, sudo en beheerdersvragen" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Een gezicht instellen." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Hoe het nieuwe gezicht moet heten." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Het scherm vergrendelen." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "De animaties van de bubbel één keer afspelen." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Bubbelstijl voor de demo: full of minimal." @@ -1019,3 +1072,15 @@ msgstr "Aan de slag" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Klaar" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Wachtwoord" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Kijk naar de camera of typ je wachtwoord" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Typ je wachtwoord" diff --git a/po/pl.po b/po/pl.po index b92f013..e989cba 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Polish\n" @@ -59,8 +59,8 @@ msgstr "Nie dodano żadnej twarzy." msgid "First, set up your face." msgstr "Najpierw skonfiguruj swoją twarz." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Nie udało się zapisać ustawienia." @@ -111,16 +111,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Nie skonfigurowano jeszcze żadnej twarzy." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "wł." #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "wył." -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "próbki: %s, wyuczone: %s" @@ -150,7 +150,7 @@ msgstr "Włącz odblokowywanie twarzą" msgid "Turn it off (faces are kept)" msgstr "Wyłącz je (twarze zostają zachowane)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Dodaj twarz" @@ -167,22 +167,26 @@ msgid "Look at the camera and see what it sees" msgstr "Spójrz w kamerę i zobacz, co widzi" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Zablokuj ekran" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Pokaż, co jest włączone" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Pokaż tę pomoc" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Pokaż wersję" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Bez polecenia wyświetla się interaktywne menu." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -190,42 +194,42 @@ msgstr "" "Uruchom to jako swój użytkownik, nie jako root. Hasło zostanie zapytane, gdy " "będzie potrzebne." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Nieznane polecenie: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "nigdy" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "przed chwilą" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 minutę temu" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d min temu" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 godzinę temu" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d godz. temu" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 dzień temu" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d dni temu" @@ -369,11 +373,11 @@ msgstr "" msgid "[y/N]" msgstr "[t/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "WŁ." -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "WYŁ." @@ -414,7 +418,7 @@ msgstr "wolna" msgid "%s seconds" msgstr "%s s" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automatyczna" @@ -434,8 +438,8 @@ msgstr "nie działa" msgid "Turning face unlock on again starts it." msgstr "Ponowne włączenie odblokowywania twarzą ją uruchomi." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Twarze" @@ -492,7 +496,7 @@ msgstr "Ostatnie odblokowanie" msgid "The lock screen agent is not running." msgstr "Agent ekranu blokady nie działa." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -500,15 +504,17 @@ msgstr "" "W GNOME dymek pokazuje małe rozszerzenie GNOME. Włączenie odblokowywania " "twarzą włącza też je." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Skanuje, gdy wracasz do hyprlock lub swaylock, i je otwiera. Każdy inny " -"ekran blokady skanuje po naciśnięciu Enter w pustym polu hasła." +"Skanuje, gdy wracasz do hyprlock, swaylock lub własnego ekranu blokady face-" +"unlock (`face-unlock lock`, z dymkiem), i je otwiera. Inne ekrany blokady " +"skanują po Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -516,7 +522,7 @@ msgstr "" "Odblokowuje ekran blokady, gdy widzi twoją twarz. Wyłączone: działa tam " "tylko hasło." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -524,7 +530,7 @@ msgstr "" "Skanuje, gdy naciśniesz klawisz lub poruszysz myszą na ekranie blokady, oraz " "gdy komputer się wybudzi." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -532,7 +538,7 @@ msgstr "" "Skanuje od razu po zablokowaniu ekranu. Domyślnie wyłączone: gdy zablokujesz " "sam, od razu by się odblokował." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -540,7 +546,21 @@ msgstr "" "sudo przyjmuje twarz zamiast hasła. Gdy nie pasuje, wpisujesz hasło jak " "zwykle." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"Obraz za ekranem blokady face-unlock (`face-unlock lock`). Puste: ten z " +"pulpitu. Albo plik, folder, z którego losowany jest obraz, albo `none`. " +"Enter, aby wpisać." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Rozmywa obraz za ekranem blokady face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -549,7 +569,7 @@ msgstr "" "Ekran blokady przyjmuje twarz przy sprawdzaniu hasła. Naciśnij Enter w " "pustym polu, aby skanować. Znalezione tutaj: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -557,18 +577,18 @@ msgstr "" "Okna haseł pulpitu i aplikacji, na przykład przy instalowaniu programów. Gdy " "twarz nie pasuje, wpisujesz hasło." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Musisz mrugnąć albo lekko obrócić głowę. To zatrzymuje też wydrukowane " "zdjęcia." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Bez żadnej kontroli. Tylko do wypróbowania kamery." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -576,22 +596,22 @@ msgstr "" "Zatrzymuje zdjęcia na telefonie, tablecie lub błyszczącym papierze. Nie " "trzeba mrugać. Matowy wydruk może przejść." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Mniej pomyłek, ale może cię nie rozpoznać w okularach albo przy słabym " "świetle." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Łatwiej cię rozpoznaje, ale też kogoś bardzo do ciebie podobnego." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "Domyślna. Pasuje większości osób." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -599,7 +619,7 @@ msgstr "" "Twoje oczy muszą być otwarte i patrzeć na ekran. Dzięki temu nie odblokuje, " "gdy patrzysz w bok lub śpisz." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -608,11 +628,11 @@ msgstr "" "nowa. Kamera na podczerwień potrzebuje włączonego światła (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Jak długo kamera szuka twojej twarzy, zanim się podda." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -620,7 +640,7 @@ msgstr "" "Po pewnym dopasowaniu zapamiętuje, jak teraz wyglądasz. Nowa fryzura czy " "okulary nie wymagają więc ponownej konfiguracji." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -628,81 +648,98 @@ msgstr "" "Bez skanowania, gdy laptop jest zamknięty, na przykład przy biurku z " "zewnętrznym ekranem." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "Dymek u góry ekranu pokazuje, co robi kamera." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Mała pigułka z kłódką, która się otwiera." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Wyspa z twarzą, która się rozgląda, potem pierścienie i ptaszek." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Jak szybko porusza się dymek." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Pokazuje dymek także wtedy, gdy sudo lub okno administratora skanuje twarz." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automatyczna (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(podczerwień)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(niepodłączona)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "jak na pulpicie" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "brak" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Obraz lub folder:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Nie znaleziono: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Ustawienia" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ wybierz ←→ lub Spacja: zmień q: wstecz" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "dla wszystkich użytkowników, pyta o hasło" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Góra/Dół: wybierz, Spacja: wł./wył., r: zmień nazwę, d: usuń, a: dodaj, q: " "wstecz" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Nie skonfigurowano jeszcze żadnej twarzy. Naciśnij a, aby dodać." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Nowa nazwa:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Usunąć „%s”?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Włącz lub wyłącz odblokowywanie twarzą" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Wypróbuj" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Zakończ" @@ -759,6 +796,14 @@ msgstr "Skanuj, gdy wracasz" msgid "Scan right after locking" msgstr "Skanuj zaraz po zablokowaniu" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Tapeta" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Rozmyj tapetę" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Okna haseł" @@ -917,23 +962,31 @@ msgstr "Kamera jest zajęta innym skanowaniem. Spróbuj ponownie za chwilę." msgid "The face could not be added (%1)." msgstr "Nie udało się dodać twarzy (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Złe hasło" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "Odblokowywanie twarzą dla ekranu blokady, sudo i okien administratora" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Skonfiguruj twarz." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Jak nazwać nową twarz." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Zablokuj ekran." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Odtwórz raz animacje dymka." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Styl dymka w demo: full lub minimal." @@ -1014,3 +1067,15 @@ msgstr "Zaczynamy" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Gotowe" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Hasło" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Spójrz w kamerę albo wpisz hasło" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Wpisz hasło" diff --git a/po/pt_BR.po b/po/pt_BR.po index 574b866..a516b7e 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Brazilian Portuguese\n" @@ -58,8 +58,8 @@ msgstr "Nenhum rosto foi adicionado." msgid "First, set up your face." msgstr "Primeiro, configure o seu rosto." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Não foi possível salvar a configuração." @@ -111,16 +111,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Nenhum rosto configurado ainda." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "ativado" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "desativado" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s amostras, %s aprendidas" @@ -150,7 +150,7 @@ msgstr "Ativar o desbloqueio facial" msgid "Turn it off (faces are kept)" msgstr "Desativar (os rostos são mantidos)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Adicionar um rosto" @@ -167,22 +167,26 @@ msgid "Look at the camera and see what it sees" msgstr "Olhar para a câmera e ver o que ela vê" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Bloquear a tela" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Mostrar o que está ativado" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Mostrar esta ajuda" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Mostrar a versão" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Sem comando, um menu interativo é exibido." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -190,42 +194,42 @@ msgstr "" "Execute isto com o seu próprio usuário, não como root. Ele pede a sua senha " "quando precisa." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Comando desconhecido: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "nunca" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "agora mesmo" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "há 1 minuto" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "há %d minutos" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "há 1 hora" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "há %d horas" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "há 1 dia" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "há %d dias" @@ -369,11 +373,11 @@ msgstr "" msgid "[y/N]" msgstr "[s/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "ATIVADO" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "DESATIVADO" @@ -414,7 +418,7 @@ msgstr "lenta" msgid "%s seconds" msgstr "%s segundos" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "automática" @@ -434,8 +438,8 @@ msgstr "parado" msgid "Turning face unlock on again starts it." msgstr "Ativar o desbloqueio facial de novo o inicia." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Rostos" @@ -492,7 +496,7 @@ msgstr "Último desbloqueio" msgid "The lock screen agent is not running." msgstr "O agente da tela de bloqueio não está em execução." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -500,16 +504,17 @@ msgstr "" "No GNOME, uma pequena extensão do GNOME mostra a bolha. Ativar o desbloqueio " "facial também a ativa." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Escaneia quando você volta ao hyprlock ou swaylock e os abre. Qualquer outra " -"tela de bloqueio escaneia quando você pressiona Enter no campo de senha " -"vazio." +"Escaneia quando você volta ao hyprlock, swaylock ou à tela de bloqueio do " +"face-unlock (`face-unlock lock`, com a bolha) e os abre. As outras telas de " +"bloqueio escaneiam com Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -517,7 +522,7 @@ msgstr "" "Desbloqueia a tela de bloqueio quando vê o seu rosto. Desativado: lá só a " "sua senha funciona." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -525,7 +530,7 @@ msgstr "" "Faz a leitura quando você aperta uma tecla ou mexe o mouse na tela de " "bloqueio, e quando o computador acorda." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -533,7 +538,7 @@ msgstr "" "Faz a leitura assim que a tela é bloqueada. Desativado por padrão: se você " "mesmo bloquear, ela desbloquearia logo em seguida." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -541,7 +546,21 @@ msgstr "" "O sudo usa o seu rosto em vez da senha. Se não corresponder, você digita a " "senha como sempre." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"A imagem atrás da tela de bloqueio do face-unlock (`face-unlock lock`). " +"Vazio: a da sua área de trabalho. Ou um arquivo, uma pasta da qual uma é " +"escolhida ao acaso, ou `none`. Enter para digitar." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Desfoca a imagem atrás da tela de bloqueio do face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -550,7 +569,7 @@ msgstr "" "A tela de bloqueio aceita seu rosto na verificação de senha. Pressione Enter " "no campo vazio para escanear. Encontradas aqui: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -558,18 +577,18 @@ msgstr "" "As janelas de senha da sua área de trabalho e dos apps, por exemplo ao " "instalar programas. Se não corresponder, você digita a senha." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Você precisa piscar ou virar um pouco a cabeça. Isso também barra fotos " "impressas." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Nenhuma verificação. Só para testar uma câmera." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -577,23 +596,23 @@ msgstr "" "Barra fotos em celular, tablet ou papel brilhante. Não é preciso piscar. Uma " "foto impressa em papel fosco pode passar." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Menos confusões, mas talvez não reconheça você de óculos ou com pouca luz." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "" "Reconhece você com mais facilidade, mas também alguém muito parecido com " "você." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "O padrão. Serve para a maioria das pessoas." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -601,7 +620,7 @@ msgstr "" "Seus olhos precisam estar abertos e voltados para a tela. Assim não " "desbloqueia enquanto você olha para outro lado ou dorme." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -610,11 +629,11 @@ msgstr "" "rosto de novo. Uma câmera infravermelha precisa da luz ligada (linux-enable-" "ir-emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Quanto tempo a câmera procura o seu rosto antes de desistir." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -622,7 +641,7 @@ msgstr "" "Após uma correspondência segura, ele guarda a sua aparência atual. Assim, um " "corte de cabelo novo ou óculos não exigem nova configuração." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -630,82 +649,99 @@ msgstr "" "Nenhuma leitura com o notebook fechado, por exemplo numa mesa com uma tela " "externa." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "A bolha no topo da tela mostra o que a câmera está fazendo." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Uma pequena pílula com um cadeado que se abre." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Uma ilha com um rosto que olha em volta, depois anéis e um visto." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "A velocidade com que a bolha se move." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Mostra a bolha também quando o sudo ou um pedido de administrador lê o seu " "rosto." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "automática (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(infravermelha)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(não conectada)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "igual à área de trabalho" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "nenhum" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Imagem ou pasta:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Não encontrado: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Configurações" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ escolher ←→ ou Espaço: mudar q: voltar" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "para todos os usuários, pede a sua senha" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Cima/Baixo: escolher, Espaço: ativar/desativar, r: renomear, d: apagar, a: " "adicionar, q: voltar" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Nenhum rosto configurado ainda. Aperte a para adicionar um." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Novo nome:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Apagar \"%s\"?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Ativar ou desativar o desbloqueio facial" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Testar" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Sair" @@ -765,6 +801,14 @@ msgstr "Ler quando você voltar" msgid "Scan right after locking" msgstr "Ler logo após bloquear" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Papel de parede" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Desfocar o papel de parede" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Pedidos de senha" @@ -924,25 +968,33 @@ msgstr "A câmera está ocupada com outra leitura. Tente de novo em instantes." msgid "The face could not be added (%1)." msgstr "Não foi possível adicionar o rosto (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Senha incorreta" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Desbloqueio facial para a tela de bloqueio, o sudo e os pedidos de " "administrador" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Configurar um rosto." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Como chamar o novo rosto." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Bloquear a tela." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Reproduzir as animações da bolha uma vez." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Estilo da bolha para a demonstração: full ou minimal." @@ -1022,3 +1074,15 @@ msgstr "Começar" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Concluído" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Senha" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Olhe para a câmera ou digite sua senha" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Digite sua senha" diff --git a/po/ru.po b/po/ru.po index 9e682d8..1ed8936 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Russian\n" @@ -59,8 +59,8 @@ msgstr "Лицо не добавлено." msgid "First, set up your face." msgstr "Сначала настройте своё лицо." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Не удалось сохранить настройку." @@ -111,16 +111,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Ещё не настроено ни одного лица." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "вкл." #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "выкл." -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "образцов: %s, выучено: %s" @@ -150,7 +150,7 @@ msgstr "Включить разблокировку по лицу" msgid "Turn it off (faces are kept)" msgstr "Выключить её (лица сохраняются)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Добавить лицо" @@ -167,22 +167,26 @@ msgid "Look at the camera and see what it sees" msgstr "Посмотреть в камеру и увидеть, что она видит" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Заблокировать экран" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Показать, что включено" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Показать эту справку" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Показать версию" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Без команды открывается интерактивное меню." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -190,42 +194,42 @@ msgstr "" "Запускайте это от своего пользователя, не от root. Пароль будет запрошен, " "когда он понадобится." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Неизвестная команда: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "никогда" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "только что" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 минуту назад" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d мин назад" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 час назад" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d ч назад" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 день назад" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d дн. назад" @@ -369,11 +373,11 @@ msgstr "" msgid "[y/N]" msgstr "[д/Н]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "ВКЛ" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "ВЫКЛ" @@ -414,7 +418,7 @@ msgstr "медленная" msgid "%s seconds" msgstr "%s с" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "автоматически" @@ -434,8 +438,8 @@ msgstr "не запущена" msgid "Turning face unlock on again starts it." msgstr "Повторное включение разблокировки по лицу запустит её." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Лица" @@ -492,7 +496,7 @@ msgstr "Последняя разблокировка" msgid "The lock screen agent is not running." msgstr "Агент экрана блокировки не запущен." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -500,16 +504,17 @@ msgstr "" "В GNOME пузырь показывает небольшое расширение GNOME. Оно включается вместе " "с разблокировкой по лицу." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Сканирует, когда вы возвращаетесь к hyprlock или swaylock, и открывает их. " -"Любой другой экран блокировки сканирует, когда вы нажимаете Enter в пустом " -"поле пароля." +"Сканирует, когда вы возвращаетесь к hyprlock, swaylock или к экрану " +"блокировки face-unlock (`face-unlock lock`, с пузырём), и открывает их. " +"Другие экраны блокировки сканируют по Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -517,7 +522,7 @@ msgstr "" "Снимает блокировку экрана, когда видит ваше лицо. Выкл.: там работает только " "пароль." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -525,7 +530,7 @@ msgstr "" "Сканирует, когда вы нажимаете клавишу или двигаете мышь на экране " "блокировки, и когда компьютер просыпается." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -533,7 +538,7 @@ msgstr "" "Сканирует сразу после блокировки экрана. По умолчанию выкл.: если вы " "блокируете сами, он тут же разблокировался бы." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -541,7 +546,21 @@ msgstr "" "sudo принимает ваше лицо вместо пароля. Не совпало: вы вводите пароль как " "обычно." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"Картинка за экраном блокировки face-unlock (`face-unlock lock`). Пусто: та, " +"что на рабочем столе. Или файл, папка, из которой берётся случайная, или " +"`none`. Нажмите Enter, чтобы ввести." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Размывает картинку за экраном блокировки face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -550,7 +569,7 @@ msgstr "" "Экран блокировки принимает ваше лицо при проверке пароля. Нажмите Enter в " "пустом поле, чтобы сканировать. Найдено здесь: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -558,18 +577,18 @@ msgstr "" "Окна ввода пароля рабочего стола и приложений, например при установке " "программ. Не совпало: вы вводите пароль." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Нужно моргнуть или слегка повернуть голову. Это также останавливает " "распечатанные фото." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Никакой проверки. Только чтобы опробовать камеру." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -577,22 +596,22 @@ msgstr "" "Останавливает фото на телефоне, планшете или глянцевой бумаге. Моргать не " "нужно. Матовое распечатанное фото может пройти." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Меньше ошибочных совпадений, но может не узнать вас в очках или при плохом " "свете." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Узнаёт вас легче, но и того, кто очень на вас похож." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "По умолчанию. Подходит большинству." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -600,7 +619,7 @@ msgstr "" "Ваши глаза должны быть открыты и смотреть на экран. Так он не " "разблокируется, пока вы смотрите в сторону или спите." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -609,11 +628,11 @@ msgstr "" "заново. Инфракрасной камере нужна включённая подсветка (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Как долго камера ищет ваше лицо, прежде чем сдаться." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -621,7 +640,7 @@ msgstr "" "После уверенного совпадения запоминает, как вы выглядите сейчас. Новая " "стрижка или очки не требуют новой настройки." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -629,82 +648,99 @@ msgstr "" "Без сканирования, когда ноутбук закрыт, например за столом с внешним " "монитором." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "Пузырь вверху экрана показывает, что делает камера." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Маленькая таблетка с замком, который открывается." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Остров с лицом, которое оглядывается, затем кольца и галочка." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Как быстро движется пузырь." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Показывает пузырь и тогда, когда sudo или запрос администратора сканирует " "ваше лицо." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "автоматически (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(инфракрасная)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(не подключена)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "как на рабочем столе" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "нет" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Картинка или папка:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Не найдено: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Настройки" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ выбор ←→ или Пробел: изменить q: назад" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "для всех пользователей, запрашивает пароль" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Вверх/Вниз: выбор, Пробел: вкл./выкл., r: переименовать, d: удалить, a: " "добавить, q: назад" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Ещё не настроено ни одного лица. Нажмите a, чтобы добавить." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Новое имя:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Удалить «%s»?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Включить или выключить разблокировку по лицу" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Попробовать" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Выход" @@ -762,6 +798,14 @@ msgstr "Сканировать при возвращении" msgid "Scan right after locking" msgstr "Сканировать сразу после блокировки" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Обои" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Размыть обои" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Запросы пароля" @@ -921,24 +965,32 @@ msgstr "Камера занята другим сканированием. По msgid "The face could not be added (%1)." msgstr "Не удалось добавить лицо (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Неверный пароль" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Разблокировка по лицу для экрана блокировки, sudo и запросов администратора" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Настроить лицо." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Как назвать новое лицо." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Заблокировать экран." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Один раз проиграть анимации пузыря." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Стиль пузыря для демо: full или minimal." @@ -1020,3 +1072,15 @@ msgstr "Начать" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Готово" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Пароль" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Посмотрите в камеру или введите пароль" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Введите пароль" diff --git a/po/tr.po b/po/tr.po index ee85414..277df5d 100644 --- a/po/tr.po +++ b/po/tr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Turkish\n" @@ -57,8 +57,8 @@ msgstr "Hiç yüz eklenmedi." msgid "First, set up your face." msgstr "Önce yüzünüzü kurun." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Ayar kaydedilemedi." @@ -107,16 +107,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Henüz hiç yüz kurulmadı." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "açık" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "kapalı" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s örnek, %s öğrenilen" @@ -146,7 +146,7 @@ msgstr "Yüzle kilit açmayı aç" msgid "Turn it off (faces are kept)" msgstr "Kapat (yüzler saklanır)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Yüz ekle" @@ -163,22 +163,26 @@ msgid "Look at the camera and see what it sees" msgstr "Kameraya bak ve onun ne gördüğünü gör" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Ekranı kilitle" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Neyin açık olduğunu göster" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Bu yardımı göster" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Sürümü göster" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Komut verilmezse etkileşimli bir menü gösterilir." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -186,42 +190,42 @@ msgstr "" "Bunu root olarak değil, kendi kullanıcınızla çalıştırın. Gerektiğinde " "parolanızı sorar." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Bilinmeyen komut: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "hiçbir zaman" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "az önce" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 dakika önce" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d dakika önce" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 saat önce" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d saat önce" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 gün önce" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d gün önce" @@ -365,11 +369,11 @@ msgstr "" msgid "[y/N]" msgstr "[e/H]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "AÇIK" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "KAPALI" @@ -410,7 +414,7 @@ msgstr "yavaş" msgid "%s seconds" msgstr "%s saniye" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "otomatik" @@ -430,8 +434,8 @@ msgstr "çalışmıyor" msgid "Turning face unlock on again starts it." msgstr "Yüzle kilit açmayı yeniden açmak onu başlatır." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Yüzler" @@ -488,7 +492,7 @@ msgstr "Son kilit açma" msgid "The lock screen agent is not running." msgstr "Kilit ekranı aracısı çalışmıyor." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -496,15 +500,17 @@ msgstr "" "GNOME'da baloncuğu küçük bir GNOME uzantısı gösterir. Yüzle kilit açmayı " "açınca o da açılır." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"hyprlock'a ya da swaylock'a döndüğünüzde tarar ve onları açar. Diğer kilit " -"ekranları boş parola alanında Enter'a bastığınızda tarar." +"hyprlock'a, swaylock'a ya da face-unlock'un kendi kilit ekranına (`face-" +"unlock lock`, baloncukla) döndüğünüzde tarar ve onları açar. Diğer kilit " +"ekranları Enter ile tarar." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -512,7 +518,7 @@ msgstr "" "Yüzünüzü görünce kilit ekranını açar. Kapalı: orada yalnızca parolanız " "çalışır." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -520,7 +526,7 @@ msgstr "" "Kilit ekranında bir tuşa bastığınızda ya da fareyi oynattığınızda ve " "bilgisayar uyandığında tarar." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -528,7 +534,7 @@ msgstr "" "Ekran kilitlenir kilitlenmez tarar. Varsayılan olarak kapalı: kendiniz " "kilitlerseniz hemen yeniden açılırdı." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -536,7 +542,21 @@ msgstr "" "sudo parola yerine yüzünüzü kullanır. Eşleşmezse parolayı her zamanki gibi " "yazarsınız." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"face-unlock kilit ekranının (`face-unlock lock`) arkasındaki resim. Boş: " +"masaüstünüzdeki resim. Ya da bir dosya, rastgele seçilecek bir klasör veya " +"`none`. Yazmak için Enter." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "face-unlock kilit ekranının arkasındaki resmi bulanıklaştırır." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -545,7 +565,7 @@ msgstr "" "Kilit ekranı parola denetiminde yüzünüzü kabul eder. Taramak için boş alanda " "Enter'a basın. Burada bulunanlar: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -553,18 +573,18 @@ msgstr "" "Masaüstünüzün ve uygulamaların parola pencereleri, örneğin yazılım kurarken. " "Eşleşmezse parolayı yazarsınız." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Göz kırpmanız ya da başınızı biraz çevirmeniz gerekir. Bu, basılı " "fotoğrafları da durdurur." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Hiç denetim yok. Yalnızca bir kamerayı denemek için." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -572,21 +592,21 @@ msgstr "" "Telefon, tablet ya da parlak kâğıttaki fotoğrafları durdurur. Göz kırpmanız " "gerekmez. Mat basılı bir fotoğraf geçebilir." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Daha az yanlış eşleşme, ama gözlükle ya da kötü ışıkta sizi tanımayabilir." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Sizi daha kolay tanır, ama size çok benzeyen birini de." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "Varsayılan. Çoğu kişi için uygun." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -594,7 +614,7 @@ msgstr "" "Gözleriniz açık ve ekrana dönük olmalı. Böylece başka yere bakarken ya da " "uyurken kilit açılmaz." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -603,11 +623,11 @@ msgstr "" "kurun. Kızılötesi kameranın ışığının açık olması gerekir (linux-enable-ir-" "emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Kameranın vazgeçmeden önce yüzünüzü ne kadar aradığı." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -615,88 +635,105 @@ msgstr "" "Kesin bir eşleşmeden sonra şu anki görünüşünüzü hatırlar. Böylece yeni saç " "kesimi ya da gözlük yeniden kurulum gerektirmez." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." msgstr "Dizüstü kapalıyken tarama yok, örneğin harici ekranlı bir masada." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "Ekranın üstündeki baloncuk kameranın ne yaptığını gösterir." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Açılan bir kilidi olan küçük bir hap." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "" "Etrafına bakan bir yüzü olan bir ada, ardından halkalar ve bir onay işareti." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Baloncuğun ne kadar hızlı hareket ettiği." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "sudo ya da bir yönetici istemi yüzünüzü taradığında da baloncuğu gösterir." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "otomatik (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(kızılötesi)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(bağlı değil)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "masaüstüyle aynı" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "yok" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Resim ya da klasör:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Bulunamadı: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Ayarlar" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ seç ←→ ya da Boşluk: değiştir q: geri" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "tüm kullanıcılar için, parolanızı sorar" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Yukarı/Aşağı: seç, Boşluk: aç/kapat, r: yeniden adlandır, d: sil, a: ekle, " "q: geri" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Henüz hiç yüz kurulmadı. Eklemek için a tuşuna basın." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Yeni ad:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "\"%s\" silinsin mi?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Yüzle kilit açmayı aç ya da kapat" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Dene" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Çık" @@ -756,6 +793,14 @@ msgstr "Geri döndüğünüzde tara" msgid "Scan right after locking" msgstr "Kilitledikten hemen sonra tara" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Duvar kâğıdı" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Duvar kâğıdını bulanıklaştır" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Parola istemleri" @@ -912,23 +957,31 @@ msgstr "Kamera başka bir taramayla meşgul. Birazdan yeniden deneyin." msgid "The face could not be added (%1)." msgstr "Yüz eklenemedi (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Yanlış parola" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "Kilit ekranı, sudo ve yönetici istemleri için yüzle kilit açma" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Bir yüz kur." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Yeni yüzün adı." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Ekranı kilitle." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Baloncuğun animasyonlarını bir kez oynat." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Demo için baloncuk stili: full ya da minimal." @@ -1009,3 +1062,15 @@ msgstr "Başlayalım" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Bitti" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Parola" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Kameraya bakın ya da parolanızı yazın" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Parolanızı yazın" diff --git a/po/uk.po b/po/uk.po index a5d39fa..507adab 100644 --- a/po/uk.po +++ b/po/uk.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Ukrainian\n" @@ -59,8 +59,8 @@ msgstr "Обличчя не додано." msgid "First, set up your face." msgstr "Спершу налаштуйте своє обличчя." -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "Не вдалося зберегти налаштування." @@ -112,16 +112,16 @@ msgstr "" msgid "No face is set up yet." msgstr "Ще не налаштовано жодного обличчя." -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "увімк." #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "вимк." -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "зразків: %s, вивчено: %s" @@ -151,7 +151,7 @@ msgstr "Увімкнути розблокування обличчям" msgid "Turn it off (faces are kept)" msgstr "Вимкнути його (обличчя зберігаються)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "Додати обличчя" @@ -168,22 +168,26 @@ msgid "Look at the camera and see what it sees" msgstr "Подивитися в камеру і побачити, що вона бачить" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "Заблокувати екран" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "Показати, що увімкнено" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "Показати цю довідку" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "Показати версію" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "Без команди відкривається інтерактивне меню." -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." @@ -191,42 +195,42 @@ msgstr "" "Запускайте це від свого користувача, не від root. Пароль буде запитано, коли " "він знадобиться." -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "Невідома команда: %s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "ніколи" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "щойно" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 хвилину тому" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d хв тому" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 годину тому" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d год тому" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 день тому" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d дн. тому" @@ -370,11 +374,11 @@ msgstr "" msgid "[y/N]" msgstr "[т/Н]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "УВІМК" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "ВИМК" @@ -415,7 +419,7 @@ msgstr "повільна" msgid "%s seconds" msgstr "%s с" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "автоматично" @@ -435,8 +439,8 @@ msgstr "не запущена" msgid "Turning face unlock on again starts it." msgstr "Повторне ввімкнення розблокування обличчям запустить її." -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "Обличчя" @@ -493,7 +497,7 @@ msgstr "Останнє розблокування" msgid "The lock screen agent is not running." msgstr "Агент екрана блокування не запущено." -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." @@ -501,16 +505,17 @@ msgstr "" "У GNOME бульбашку показує невелике розширення GNOME. Воно вмикається разом " "із розблокуванням обличчям." -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"Сканує, коли ви повертаєтеся до hyprlock чи swaylock, і відкриває їх. Будь-" -"який інший екран блокування сканує, коли ви натискаєте Enter у порожньому " -"полі пароля." +"Сканує, коли ви повертаєтеся до hyprlock, swaylock або до власного екрана " +"блокування face-unlock (`face-unlock lock`, з бульбашкою), і відкриває їх. " +"Інші екрани блокування сканують за Enter." -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." @@ -518,7 +523,7 @@ msgstr "" "Розблоковує екран блокування, коли бачить ваше обличчя. Вимк.: там працює " "лише пароль." -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." @@ -526,7 +531,7 @@ msgstr "" "Сканує, коли ви натискаєте клавішу або рухаєте мишею на екрані блокування, і " "коли комп'ютер прокидається." -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." @@ -534,7 +539,7 @@ msgstr "" "Сканує одразу після блокування екрана. Типово вимк.: якщо ви блокуєте самі, " "він одразу б розблокувався." -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." @@ -542,7 +547,21 @@ msgstr "" "sudo приймає ваше обличчя замість пароля. Не збіглося: ви вводите пароль як " "зазвичай." -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"Зображення за екраном блокування face-unlock (`face-unlock lock`). Порожньо: " +"те, що на робочому столі. Або файл, тека, з якої береться випадкове, або " +"`none`. Натисніть Enter, щоб ввести." + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "Розмиває зображення за екраном блокування face-unlock." + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -551,7 +570,7 @@ msgstr "" "Екран блокування приймає ваше обличчя під час перевірки пароля. Натисніть " "Enter у порожньому полі, щоб сканувати. Знайдено тут: %s." -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." @@ -559,17 +578,17 @@ msgstr "" "Вікна введення пароля робочого столу і програм, наприклад під час " "встановлення програм. Не збіглося: ви вводите пароль." -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "" "Треба кліпнути або трохи повернути голову. Це також зупиняє надруковані фото." -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "Жодної перевірки. Лише щоб випробувати камеру." -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." @@ -577,22 +596,22 @@ msgstr "" "Зупиняє фото на телефоні, планшеті чи глянцевому папері. Кліпати не треба. " "Матове надруковане фото може пройти." -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "" "Менше хибних збігів, але може не впізнати вас в окулярах або при поганому " "світлі." -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "Впізнає вас легше, але й того, хто дуже на вас схожий." -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "Типове значення. Підходить більшості." -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." @@ -600,7 +619,7 @@ msgstr "" "Ваші очі мають бути розплющені й дивитися на екран. Так він не " "розблокується, коли ви дивитеся вбік або спите." -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -609,11 +628,11 @@ msgstr "" "знову. Інфрачервоній камері потрібне ввімкнене підсвічування (linux-enable-" "ir-emitter)." -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "Як довго камера шукає ваше обличчя, перш ніж здатися." -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." @@ -621,7 +640,7 @@ msgstr "" "Після впевненого збігу запам'ятовує, як ви виглядаєте зараз. Нова зачіска чи " "окуляри не потребують нового налаштування." -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." @@ -629,82 +648,99 @@ msgstr "" "Без сканування, коли ноутбук закрито, наприклад за столом із зовнішнім " "монітором." -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "Бульбашка вгорі екрана показує, що робить камера." -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "Маленька пігулка із замком, що відкривається." -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "Острів з обличчям, яке озирається, потім кільця і галочка." -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "Як швидко рухається бульбашка." -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "" "Показує бульбашку й тоді, коли sudo або запит адміністратора сканує ваше " "обличчя." -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "автоматично (%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(інфрачервона)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(не під'єднана)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "як на робочому столі" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "немає" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "Зображення або тека:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "Не знайдено: %s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "Налаштування" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ вибір ←→ або Пробіл: змінити q: назад" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "для всіх користувачів, запитує пароль" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "" "Вгору/Вниз: вибір, Пробіл: увімк./вимк., r: перейменувати, d: видалити, a: " "додати, q: назад" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "Ще не налаштовано жодного обличчя. Натисніть a, щоб додати." -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "Нова назва:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "Видалити «%s»?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "Увімкнути або вимкнути розблокування обличчям" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "Спробувати" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "Вийти" @@ -762,6 +798,14 @@ msgstr "Сканувати, коли ви повертаєтеся" msgid "Scan right after locking" msgstr "Сканувати одразу після блокування" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "Шпалери" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "Розмити шпалери" + #: src/lib/menu.sh msgid "Password prompts" msgstr "Запити пароля" @@ -920,24 +964,32 @@ msgstr "Камера зайнята іншим скануванням. Спро msgid "The face could not be added (%1)." msgstr "Не вдалося додати обличчя (%1)." -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "Неправильний пароль" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "" "Розблокування обличчям для екрана блокування, sudo і запитів адміністратора" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "Налаштувати обличчя." -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "Як назвати нове обличчя." -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "Заблокувати екран." + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "Один раз програти анімації бульбашки." -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "Стиль бульбашки для демо: full або minimal." @@ -1019,3 +1071,15 @@ msgstr "Почати" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "Готово" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "Пароль" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "Подивіться в камеру або введіть пароль" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "Введіть пароль" diff --git a/po/zh_CN.po b/po/zh_CN.po index 90e898d..92d677a 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: face-unlock 1.0.1\n" "Report-Msgid-Bugs-To: https://github.com/LoonixTools/face-unlock/issues\n" -"POT-Creation-Date: 2026-09-26 19:34+0200\n" +"POT-Creation-Date: 2026-09-26 19:35+0200\n" "PO-Revision-Date: 2026-09-24 12:00+0200\n" "Last-Translator: Felitendo\n" "Language-Team: Chinese (simplified)\n" @@ -53,8 +53,8 @@ msgstr "没有添加人脸。" msgid "First, set up your face." msgstr "请先设置你的人脸。" -#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:466 -#: src/lib/menu.sh:470 src/lib/menu.sh:476 src/lib/menu.sh:478 +#: src/face-unlock:100 src/face-unlock:139 src/lib/menu.sh:500 +#: src/lib/menu.sh:504 src/lib/menu.sh:510 src/lib/menu.sh:512 msgid "Could not save the setting." msgstr "无法保存设置。" @@ -98,16 +98,16 @@ msgstr "人脸解锁已关闭。你的人脸会保留;可在“人脸”中删 msgid "No face is set up yet." msgstr "尚未设置任何人脸。" -#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:628 +#: src/face-unlock:168 src/lib/menu.sh:180 src/lib/menu.sh:664 msgid "on" msgstr "开" #: src/face-unlock:168 src/lib/menu.sh:182 src/lib/menu.sh:192 -#: src/lib/menu.sh:629 +#: src/lib/menu.sh:665 msgid "off" msgstr "关" -#: src/face-unlock:170 src/lib/menu.sh:646 +#: src/face-unlock:170 src/lib/menu.sh:682 #, sh-printf-format msgid "%s samples, %s learned" msgstr "%s 个样本,已学习 %s 个" @@ -137,7 +137,7 @@ msgstr "开启人脸解锁" msgid "Turn it off (faces are kept)" msgstr "关闭(保留人脸)" -#: src/face-unlock:196 src/lib/menu.sh:712 +#: src/face-unlock:196 src/lib/menu.sh:748 msgid "Add a face" msgstr "添加人脸" @@ -154,63 +154,67 @@ msgid "Look at the camera and see what it sees" msgstr "看着摄像头,查看它看到的画面" #: src/face-unlock:200 +msgid "Lock the screen" +msgstr "锁定屏幕" + +#: src/face-unlock:201 msgid "Show what is on" msgstr "显示已开启的功能" -#: src/face-unlock:201 +#: src/face-unlock:202 msgid "Show this help" msgstr "显示此帮助" -#: src/face-unlock:202 +#: src/face-unlock:203 msgid "Show the version" msgstr "显示版本" -#: src/face-unlock:204 +#: src/face-unlock:205 msgid "Without a command an interactive menu is shown." msgstr "不带命令时显示交互式菜单。" -#: src/face-unlock:223 +#: src/face-unlock:224 msgid "" "Run this as your own user, not as root. It asks for your password when it " "needs to." msgstr "请以你自己的用户运行,不要用 root。需要时会询问你的密码。" -#: src/face-unlock:245 src/lib/system.sh:101 +#: src/face-unlock:247 src/lib/system.sh:101 #, sh-printf-format msgid "Unknown command: %s" msgstr "未知命令:%s" -#: src/lib/common.sh:169 +#: src/lib/common.sh:171 msgid "never" msgstr "从未" -#: src/lib/common.sh:179 +#: src/lib/common.sh:181 msgid "just now" msgstr "刚刚" -#: src/lib/common.sh:181 +#: src/lib/common.sh:183 msgid "1 minute ago" msgstr "1 分钟前" -#: src/lib/common.sh:184 +#: src/lib/common.sh:186 #, sh-printf-format msgid "%d minutes ago" msgstr "%d 分钟前" -#: src/lib/common.sh:186 +#: src/lib/common.sh:188 msgid "1 hour ago" msgstr "1 小时前" -#: src/lib/common.sh:189 +#: src/lib/common.sh:191 #, sh-printf-format msgid "%d hours ago" msgstr "%d 小时前" -#: src/lib/common.sh:191 +#: src/lib/common.sh:193 msgid "1 day ago" msgstr "1 天前" -#: src/lib/common.sh:194 +#: src/lib/common.sh:196 #, sh-printf-format msgid "%d days ago" msgstr "%d 天前" @@ -350,11 +354,11 @@ msgstr "尝试次数过多。人脸解锁已暂停,直到你用密码解锁。 msgid "[y/N]" msgstr "[y/N]" -#: src/lib/menu.sh:172 src/lib/menu.sh:531 +#: src/lib/menu.sh:172 src/lib/menu.sh:566 msgid "ON" msgstr "开启" -#: src/lib/menu.sh:174 src/lib/menu.sh:532 +#: src/lib/menu.sh:174 src/lib/menu.sh:567 msgid "OFF" msgstr "关闭" @@ -395,7 +399,7 @@ msgstr "慢" msgid "%s seconds" msgstr "%s 秒" -#: src/lib/menu.sh:202 src/lib/menu.sh:441 +#: src/lib/menu.sh:202 src/lib/menu.sh:447 msgid "automatic" msgstr "自动" @@ -415,8 +419,8 @@ msgstr "未运行" msgid "Turning face unlock on again starts it." msgstr "重新开启人脸解锁即可启动它。" -#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:624 -#: src/lib/menu.sh:713 +#: src/lib/menu.sh:236 src/lib/menu.sh:238 src/lib/menu.sh:660 +#: src/lib/menu.sh:749 msgid "Faces" msgstr "人脸" @@ -473,46 +477,60 @@ msgstr "上次解锁" msgid "The lock screen agent is not running." msgstr "锁屏代理没有运行。" -#: src/lib/menu.sh:314 +#: src/lib/menu.sh:318 msgid "" "On GNOME a small GNOME extension shows the bubble. Turning face unlock on " "switches it on." msgstr "" "在 GNOME 上,由一个小的 GNOME 扩展显示气泡。开启人脸解锁时会一并开启它。" -#: src/lib/menu.sh:318 +#: src/lib/menu.sh:322 msgid "" -"Scans when you come back to hyprlock or swaylock and opens them. Any other " -"lock screen scans when you press Enter on the empty password field." +"Scans when you come back to hyprlock, swaylock or face-unlock's own lock " +"screen (`face-unlock lock`, with the bubble), and opens them. Other lock " +"screens scan on Enter." msgstr "" -"回到 hyprlock 或 swaylock 时会扫描并打开它们。其他锁屏在空的密码框中按 Enter " -"时扫描。" +"回到 hyprlock、swaylock 或 face-unlock 自带的锁屏(`face-unlock lock`,带气" +"泡)时扫描并打开它们。其他锁屏按 Enter 扫描。" -#: src/lib/menu.sh:323 +#: src/lib/menu.sh:327 msgid "" "Unlocks the lock screen when it sees your face. Off: only your password " "works there." msgstr "看到你的脸时解锁锁屏。关闭:锁屏只能用密码。" -#: src/lib/menu.sh:324 +#: src/lib/menu.sh:328 msgid "" "Scans when you press a key or move the mouse on the lock screen, and when " "the computer wakes up." msgstr "在锁屏上按键或移动鼠标时,以及电脑唤醒时扫描。" -#: src/lib/menu.sh:325 +#: src/lib/menu.sh:329 msgid "" "Scans as soon as the screen locks. Off by default: if you lock it yourself, " "it would unlock again right away." msgstr "屏幕一锁定就扫描。默认关闭:如果是你自己锁的屏,它会马上又解锁。" -#: src/lib/menu.sh:326 +#: src/lib/menu.sh:330 msgid "" "sudo takes your face instead of the password. No match: you type the " "password as usual." msgstr "sudo 用你的脸代替密码。不匹配时,照常输入密码。" -#: src/lib/menu.sh:327 +#: src/lib/menu.sh:331 +msgid "" +"The picture behind face-unlock's own lock screen (`face-unlock lock`). " +"Empty: the one on your desktop. Or a file, a folder to take one from at " +"random, or `none`. Enter to type it." +msgstr "" +"face-unlock 锁屏(`face-unlock lock`)背后的图片。留空:用桌面的图片。或者一" +"个文件、从中随机挑选的文件夹,或 `none`。按 Enter 输入。" + +#: src/lib/menu.sh:332 +msgid "Blurs the picture behind face-unlock's own lock screen." +msgstr "模糊 face-unlock 锁屏背后的图片。" + +#: src/lib/menu.sh:333 #, sh-printf-format msgid "" "The lock screen takes your face in its password check. Press Enter on the " @@ -520,47 +538,47 @@ msgid "" msgstr "" "锁屏在检查密码时也接受你的人脸。在空白框中按 Enter 即可扫描。此处找到:%s。" -#: src/lib/menu.sh:328 +#: src/lib/menu.sh:334 msgid "" "The password windows of your desktop and apps, for example when you install " "software. No match: you type the password." msgstr "桌面和应用的密码窗口,例如安装软件时。不匹配时,输入密码即可。" -#: src/lib/menu.sh:329 +#: src/lib/menu.sh:335 msgid "" "You have to blink or turn your head a little. This also stops printed photos." msgstr "你需要眨眼或稍微转头。这也能挡住打印的照片。" -#: src/lib/menu.sh:330 +#: src/lib/menu.sh:336 msgid "No check at all. Only for trying out a camera." msgstr "完全不检测。仅用于试用摄像头。" -#: src/lib/menu.sh:331 +#: src/lib/menu.sh:337 msgid "" "Stops photos on a phone, a tablet or glossy paper. You do not have to blink. " "A matte printed photo can get through." msgstr "挡住手机、平板或光面纸上的照片。无需眨眼。哑光纸打印的照片可能会通过。" -#: src/lib/menu.sh:332 +#: src/lib/menu.sh:338 msgid "" "Fewer wrong matches, but it may not know you with glasses or in bad light." msgstr "误认更少,但戴眼镜或光线不好时可能认不出你。" -#: src/lib/menu.sh:333 +#: src/lib/menu.sh:339 msgid "Knows you more easily, but also somebody who looks a lot like you." msgstr "更容易认出你,但也更容易认出和你长得很像的人。" -#: src/lib/menu.sh:334 +#: src/lib/menu.sh:340 msgid "The default. Right for most people." msgstr "默认值。适合大多数人。" -#: src/lib/menu.sh:335 +#: src/lib/menu.sh:341 msgid "" "Your eyes have to be open and on the screen. So it does not unlock while you " "look away or sleep." msgstr "你的眼睛必须睁开并看着屏幕。这样你看向别处或睡着时不会解锁。" -#: src/lib/menu.sh:336 +#: src/lib/menu.sh:342 msgid "" "Automatic takes the first normal camera. After a change, set up your face " "again. An infrared camera needs its light on (linux-enable-ir-emitter)." @@ -568,94 +586,111 @@ msgstr "" "“自动”会使用第一个普通摄像头。更换后请重新设置人脸。红外摄像头需要打开它的补" "光灯(linux-enable-ir-emitter)。" -#: src/lib/menu.sh:337 +#: src/lib/menu.sh:343 msgid "How long the camera looks for your face before it gives up." msgstr "摄像头寻找你的脸多久后放弃。" -#: src/lib/menu.sh:338 +#: src/lib/menu.sh:344 msgid "" "After a sure match it keeps how you look now. So a new haircut or glasses " "need no new setup." msgstr "确定匹配后,会记住你现在的样子。所以换了发型或戴上眼镜也无需重新设置。" -#: src/lib/menu.sh:339 +#: src/lib/menu.sh:345 msgid "" "No scan while the laptop is closed, for example at a desk with an external " "screen." msgstr "笔记本合上时不扫描,例如在接了外接显示器的桌前。" -#: src/lib/menu.sh:340 +#: src/lib/menu.sh:346 msgid "The bubble at the top of the screen shows what the camera is doing." msgstr "屏幕顶部的气泡显示摄像头正在做什么。" -#: src/lib/menu.sh:341 +#: src/lib/menu.sh:347 msgid "A small pill with a lock that opens." msgstr "一个带锁的小药丸,锁会打开。" -#: src/lib/menu.sh:342 +#: src/lib/menu.sh:348 msgid "An island with a face that looks around, then rings and a tick." msgstr "一个岛,里面有一张四处张望的脸,然后是圆环和一个对勾。" -#: src/lib/menu.sh:343 +#: src/lib/menu.sh:349 msgid "How fast the bubble moves." msgstr "气泡移动的速度。" -#: src/lib/menu.sh:344 +#: src/lib/menu.sh:350 msgid "Shows the bubble when sudo or an admin prompt scans your face, too." msgstr "sudo 或管理员授权扫描你的脸时也显示气泡。" -#: src/lib/menu.sh:437 +#: src/lib/menu.sh:443 #, sh-printf-format msgid "automatic (%s)" msgstr "自动(%s)" -#: src/lib/menu.sh:447 +#: src/lib/menu.sh:453 msgid "(infrared)" msgstr "(红外)" -#: src/lib/menu.sh:451 +#: src/lib/menu.sh:457 msgid "(not connected)" msgstr "(未连接)" -#: src/lib/menu.sh:528 src/lib/menu.sh:714 +#: src/lib/menu.sh:466 +msgid "same as desktop" +msgstr "与桌面相同" + +#: src/lib/menu.sh:470 +msgid "none" +msgstr "无" + +#: src/lib/menu.sh:487 +msgid "Picture or folder:" +msgstr "图片或文件夹:" + +#: src/lib/menu.sh:492 +#, sh-printf-format +msgid "Not found: %s" +msgstr "未找到:%s" + +#: src/lib/menu.sh:563 src/lib/menu.sh:750 msgid "Settings" msgstr "设置" -#: src/lib/menu.sh:529 +#: src/lib/menu.sh:564 msgid "↑↓ select ←→ or Space: change q: back" msgstr "↑↓ 选择 ←→ 或空格:更改 q:返回" -#: src/lib/menu.sh:530 +#: src/lib/menu.sh:565 msgid "for all users, asks for your password" msgstr "对所有用户生效,需要你的密码" #. TRANSLATORS: keep the letters, they are the keys. -#: src/lib/menu.sh:626 +#: src/lib/menu.sh:662 msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back" msgstr "上/下:选择,空格:开/关,r:重命名,d:删除,a:添加,q:返回" -#: src/lib/menu.sh:627 +#: src/lib/menu.sh:663 msgid "No face is set up yet. Press a to add one." msgstr "尚未设置任何人脸。按 a 添加。" -#: src/lib/menu.sh:673 +#: src/lib/menu.sh:709 msgid "New name:" msgstr "新名称:" -#: src/lib/menu.sh:680 +#: src/lib/menu.sh:716 #, sh-printf-format msgid "Delete \"%s\"?" msgstr "删除“%s”?" -#: src/lib/menu.sh:711 +#: src/lib/menu.sh:747 msgid "Turn face unlock on or off" msgstr "开启或关闭人脸解锁" -#: src/lib/menu.sh:715 +#: src/lib/menu.sh:751 msgid "Try it" msgstr "试一试" -#: src/lib/menu.sh:716 +#: src/lib/menu.sh:752 msgid "Quit" msgstr "退出" @@ -711,6 +746,14 @@ msgstr "你回来时扫描" msgid "Scan right after locking" msgstr "锁定后立即扫描" +#: src/lib/menu.sh +msgid "Wallpaper" +msgstr "壁纸" + +#: src/lib/menu.sh +msgid "Blur the wallpaper" +msgstr "模糊壁纸" + #: src/lib/menu.sh msgid "Password prompts" msgstr "密码提示" @@ -867,23 +910,31 @@ msgstr "摄像头正忙于另一次扫描。请稍后重试。" msgid "The face could not be added (%1)." msgstr "无法添加人脸(%1)。" -#: src/agent/main.cpp:87 +#: src/agent/lockscreencontroller.cpp:172 +msgid "Wrong password" +msgstr "密码错误" + +#: src/agent/main.cpp:185 msgid "Face unlock for the lock screen, sudo and admin prompts" msgstr "用于锁屏、sudo 和管理员授权的人脸解锁" -#: src/agent/main.cpp:90 +#: src/agent/main.cpp:188 msgid "Set up a face." msgstr "设置一张人脸。" -#: src/agent/main.cpp:91 +#: src/agent/main.cpp:189 msgid "What to call the new face." msgstr "新人脸的名称。" -#: src/agent/main.cpp:92 +#: src/agent/main.cpp:190 +msgid "Lock the screen." +msgstr "锁定屏幕。" + +#: src/agent/main.cpp:191 msgid "Play the bubble's animations once." msgstr "播放一次气泡动画。" -#: src/agent/main.cpp:94 +#: src/agent/main.cpp:193 msgid "Bubble style for the demo: full or minimal." msgstr "演示用的气泡样式:full 或 minimal。" @@ -961,3 +1012,15 @@ msgstr "开始" #: src/agent/qml/Enroll.qml:193 msgid "Done" msgstr "完成" + +#: src/agent/qml/LockScreen.qml:171 +msgid "Password" +msgstr "密码" + +#: src/agent/qml/LockScreen.qml:185 +msgid "Look at the camera or type your password" +msgstr "看向摄像头或输入密码" + +#: src/agent/qml/LockScreen.qml:186 +msgid "Type your password" +msgstr "输入密码" diff --git a/protocols/ext-session-lock-v1.xml b/protocols/ext-session-lock-v1.xml new file mode 100644 index 0000000..19c12d2 --- /dev/null +++ b/protocols/ext-session-lock-v1.xml @@ -0,0 +1,328 @@ + + + + Copyright 2021 Isaac Freund + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + + + This protocol allows for a privileged Wayland client to lock the session + and display arbitrary graphics while the session is locked. + + The compositor may choose to restrict this protocol to a special client + launched by the compositor itself or expose it to all privileged clients, + this is compositor policy. + + The client is responsible for performing authentication and informing the + compositor when the session should be unlocked. If the client dies while + the session is locked the session remains locked, possibly permanently + depending on compositor policy. + + The key words "must", "must not", "required", "shall", "shall not", + "should", "should not", "recommended", "may", and "optional" in this + document are to be interpreted as described in IETF RFC 2119. + + Warning! The protocol described in this file is currently in the + testing phase. Backward compatible changes may be added together with + the corresponding interface version bump. Backward incompatible changes + can only be done by creating a new major version of the extension. + + + + + This interface is used to request that the session be locked. + + + + + This informs the compositor that the session lock manager object will + no longer be used. Existing objects created through this interface + remain valid. + + + + + + This request creates a session lock and asks the compositor to lock the + session. The compositor will send either the ext_session_lock_v1.locked + or ext_session_lock_v1.finished event on the created object in + response to this request. + + + + + + + + In response to the creation of this object the compositor must send + either the locked or finished event. + + The locked event indicates that the session is locked. This means + that the compositor must stop rendering and providing input to normal + clients. Instead the compositor must blank all outputs with an opaque + color such that their normal content is fully hidden. + + The only surfaces that should be rendered while the session is locked + are the lock surfaces created through this interface and optionally, + at the compositor's discretion, special privileged surfaces such as + input methods or portions of desktop shell UIs. + + The locked event must not be sent until a new "locked" frame (either + from a session lock surface or the compositor blanking the output) has + been presented on all outputs and no security sensitive normal/unlocked + content is possibly visible. + + The finished event should be sent immediately on creation of this + object if the compositor decides that the locked event will not be sent. + + The compositor may wait for the client to create and render session lock + surfaces before sending the locked event to avoid displaying intermediate + blank frames. However, it must impose a reasonable time limit if + waiting and send the locked event as soon as the hard requirements + described above can be met if the time limit expires. Clients should + immediately create lock surfaces for all outputs on creation of this + object to make this possible. + + This behavior of the locked event is required in order to prevent + possible race conditions with clients that wish to suspend the system + or similar after locking the session. Without these semantics, clients + triggering a suspend after receiving the locked event would race with + the first "locked" frame being presented and normal/unlocked frames + might be briefly visible as the system is resumed if the suspend + operation wins the race. + + If the client dies while the session is locked, the compositor must not + unlock the session in response. It is acceptable for the session to be + permanently locked if this happens. The compositor may choose to continue + to display the lock surfaces the client had mapped before it died or + alternatively fall back to a solid color, this is compositor policy. + + Compositors may also allow a secure way to recover the session, the + details of this are compositor policy. Compositors may allow a new + client to create a ext_session_lock_v1 object and take responsibility + for unlocking the session, they may even start a new lock client + instance automatically. + + + + + + + + + + + + + This informs the compositor that the lock object will no longer be + used. Existing objects created through this interface remain valid. + + After this request is made, lock surfaces created through this object + should be destroyed by the client as they will no longer be used by + the compositor. + + It is a protocol error to make this request if the locked event was + sent, the unlock_and_destroy request must be used instead. + + + + + + This client is now responsible for displaying graphics while the + session is locked and deciding when to unlock the session. + + The locked event must not be sent until a new "locked" frame has been + presented on all outputs and no security sensitive normal/unlocked + content is possibly visible. + + If this event is sent, making the destroy request is a protocol error, + the lock object must be destroyed using the unlock_and_destroy request. + + + + + + The compositor has decided that the session lock should be destroyed + as it will no longer be used by the compositor. Exactly when this + event is sent is compositor policy, but it must never be sent more + than once for a given session lock object. + + This might be sent because there is already another ext_session_lock_v1 + object held by a client, or the compositor has decided to deny the + request to lock the session for some other reason. This might also + be sent because the compositor implements some alternative, secure + way to authenticate and unlock the session. + + The finished event should be sent immediately on creation of this + object if the compositor decides that the locked event will not + be sent. + + If the locked event is sent on creation of this object the finished + event may still be sent at some later time in this object's + lifetime. This is compositor policy. + + Upon receiving this event, the client should make either the destroy + request or the unlock_and_destroy request, depending on whether or + not the locked event was received on this object. + + + + + + The client is expected to create lock surfaces for all outputs + currently present and any new outputs as they are advertised. These + won't be displayed by the compositor unless the lock is successful + and the locked event is sent. + + Providing a wl_surface which already has a role or already has a buffer + attached or committed is a protocol error, as is attaching/committing + a buffer before the first ext_session_lock_surface_v1.configure event. + + Attempting to create more than one lock surface for a given output + is a duplicate_output protocol error. + + + + + + + + + This request indicates that the session should be unlocked, for + example because the user has entered their password and it has been + verified by the client. + + This request also informs the compositor that the lock object will + no longer be used and should be destroyed. Existing objects created + through this interface remain valid. + + After this request is made, lock surfaces created through this object + should be destroyed by the client as they will no longer be used by + the compositor. + + It is a protocol error to make this request if the locked event has + not been sent. In that case, the lock object must be destroyed using + the destroy request. + + Note that a correct client that wishes to exit directly after unlocking + the session must use the wl_display.sync request to ensure the server + receives and processes the unlock_and_destroy request. Otherwise + there is no guarantee that the server has unlocked the session due + to the asynchronous nature of the Wayland protocol. For example, + the server might terminate the client with a protocol error before + it processes the unlock_and_destroy request. + + + + + + + The client may use lock surfaces to display a screensaver, render a + dialog to enter a password and unlock the session, or however else it + sees fit. + + On binding this interface the compositor will immediately send the + first configure event. After making the ack_configure request in + response to this event the client should attach and commit the first + buffer. Committing the surface before acking the first configure is a + protocol error. Committing the surface with a null buffer at any time + is a protocol error. + + The compositor is free to handle keyboard/pointer focus for lock + surfaces however it chooses. A reasonable way to do this would be to + give the first lock surface created keyboard focus and change keyboard + focus if the user clicks on other surfaces. + + + + + + + + + + + + This informs the compositor that the lock surface object will no + longer be used. + + It is recommended for a lock client to destroy lock surfaces if + their corresponding wl_output global is removed. + + If a lock surface on an active output is destroyed before the + ext_session_lock_v1.unlock_and_destroy event is sent, the compositor + must fall back to rendering a solid color. + + + + + + When a configure event is received, if a client commits the surface + in response to the configure event, then the client must make an + ack_configure request sometime before the commit request, passing + along the serial of the configure event. + + If the client receives multiple configure events before it can + respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending an + ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, + but only the last request sent before a commit indicates which + configure event the client really is responding to. + + Sending an ack_configure request consumes the configure event + referenced by the given serial, as well as all older configure events + sent on this object. + + It is a protocol error to issue multiple ack_configure requests + referencing the same configure event or to issue an ack_configure + request referencing a configure event older than the last configure + event acked for a given lock surface. + + + + + + + This event is sent once on binding the interface and may be sent again + at the compositor's discretion, for example if output geometry changes. + + The width and height are in surface-local coordinates and are exact + requirements. Failing to match these surface dimensions in the next + commit after acking a configure is a protocol error. + + + + + + + diff --git a/src/agent/agentsocket.cpp b/src/agent/agentsocket.cpp index 3130187..d4ecf3d 100644 --- a/src/agent/agentsocket.cpp +++ b/src/agent/agentsocket.cpp @@ -26,7 +26,7 @@ AgentSocket::AgentSocket(QObject *parent) continue; } auto buffer = std::make_shared(); - connect(socket, &QLocalSocket::readyRead, this, [this, socket, buffer] { + connect(socket, &QLocalSocket::readyRead, this, [this, socket, buffer, cred] { *buffer += socket->readAll(); if (buffer->size() > 64 * 1024) { socket->abort(); @@ -36,8 +36,12 @@ AgentSocket::AgentSocket(QObject *parent) while ((nl = buffer->indexOf('\n')) >= 0) { const QJsonObject o = QJsonDocument::fromJson(buffer->left(nl)).object(); buffer->remove(0, nl + 1); - if (o.value(u"event").toString() == u"scan") { + const QString what = o.value(u"event").toString(); + if (what == u"scan") { Q_EMIT scanEvent(o); + } else if (what == u"lock" && cred.uid == ::getuid()) { + m_waiting.append(socket); + Q_EMIT lockRequested(); } } }); @@ -58,6 +62,37 @@ bool AgentSocket::running() return probe.waitForConnected(500); } +bool AgentSocket::requestLock() +{ + QLocalSocket socket; + socket.connectToServer(path()); + if (!socket.waitForConnected(500)) { + return false; + } + socket.write(QJsonDocument(QJsonObject{{QStringLiteral("event"), QStringLiteral("lock")}}).toJson(QJsonDocument::Compact) + '\n'); + if (!socket.waitForBytesWritten(500)) { + return false; + } + // The answer comes once the compositor has the lock, so that an idle + // daemon that locks before sleep does not suspend an unlocked screen. + QByteArray answer; + while (!answer.contains('\n') && socket.waitForReadyRead(5000)) { + answer += socket.readAll(); + } + return QJsonDocument::fromJson(answer.left(answer.indexOf('\n'))).object().value(u"event").toString() == u"locked"; +} + +void AgentSocket::confirmLock() +{ + for (const QPointer &socket : std::as_const(m_waiting)) { + if (socket) { + socket->write(QJsonDocument(QJsonObject{{QStringLiteral("event"), QStringLiteral("locked")}}).toJson(QJsonDocument::Compact) + '\n'); + socket->flush(); + } + } + m_waiting.clear(); +} + bool AgentSocket::listen() { const QString p = path(); diff --git a/src/agent/agentsocket.h b/src/agent/agentsocket.h index 4b8045a..31b5f0d 100644 --- a/src/agent/agentsocket.h +++ b/src/agent/agentsocket.h @@ -7,13 +7,16 @@ // it is idle). // // Only root and this user may talk here, and all they can do is make the -// bubble move. +// bubble move, or (this user) ask for face-unlock's own lock screen. #pragma once #include +#include #include +#include #include +#include class AgentSocket : public QObject { @@ -26,11 +29,18 @@ public: // session starts the agent from its own config, and that must not make // two of them. static bool running(); + // Ask the running agent to lock the screen, and wait until it is. False + // when there is no agent or the lock did not come. + static bool requestLock(); + // Tell everybody waiting in requestLock() that the screen is locked. + void confirmLock(); static QString path(); Q_SIGNALS: void scanEvent(const QJsonObject &event); + void lockRequested(); private: QLocalServer m_server; + QList> m_waiting; }; diff --git a/src/agent/inputwatcher.cpp b/src/agent/inputwatcher.cpp index 2104565..2bdf002 100644 --- a/src/agent/inputwatcher.cpp +++ b/src/agent/inputwatcher.cpp @@ -175,6 +175,9 @@ InputWatcher::~InputWatcher() = default; void InputWatcher::watch(int calmMs) { stop(); + m_watching = true; + m_calmMs = calmMs; + m_calm.start(); auto *wayland = qGuiApp->nativeInterface(); if (!m_notifier->isActive() || !wayland || !wayland->seat()) { if (!m_mutter && QDBusConnection::sessionBus().interface()->isServiceRegistered(MutterService)) { @@ -205,8 +208,18 @@ void InputWatcher::watch(int calmMs) }); } +void InputWatcher::noteInput() +{ + if (m_watching && m_calm.elapsed() >= m_calmMs) { + m_watching = false; + QMetaObject::invokeMethod(this, &InputWatcher::input, Qt::QueuedConnection); + } + m_calm.restart(); +} + void InputWatcher::stop() { + m_watching = false; m_notification.reset(); if (m_mutter) { m_mutter->stop(); diff --git a/src/agent/inputwatcher.h b/src/agent/inputwatcher.h index 81c82a6..02f5a5a 100644 --- a/src/agent/inputwatcher.h +++ b/src/agent/inputwatcher.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include @@ -29,6 +30,9 @@ public: // calmMs. 0: the next input. Replaces what was watched before. void watch(int calmMs); void stop(); + // A key or the pointer on face-unlock's own lock screen, which sees them + // itself. Counts like input the compositor reports. + void noteInput(); Q_SIGNALS: void input(); @@ -37,4 +41,7 @@ private: std::unique_ptr m_notifier; std::unique_ptr m_notification; MutterIdle *m_mutter = nullptr; + bool m_watching = false; + int m_calmMs = 0; + QElapsedTimer m_calm; }; diff --git a/src/agent/lockcontroller.cpp b/src/agent/lockcontroller.cpp index 5c2cad3..cb82f66 100644 --- a/src/agent/lockcontroller.cpp +++ b/src/agent/lockcontroller.cpp @@ -4,6 +4,7 @@ #include "bubblecontroller.h" #include "daemonclient.h" +#include "lockscreencontroller.h" #include "userconfig.h" #include @@ -23,11 +24,18 @@ constexpr int CalmBeforeRetryMs = 2000; constexpr int ScanAfterWakeMs = 1000; } // namespace -LockController::LockController(BubbleController *bubble, UserConfig *config, QObject *parent) +LockController::LockController(BubbleController *bubble, UserConfig *config, SessionLock *lock, LockScreenController *screen, QObject *parent) : QObject(parent) , m_bubble(bubble) , m_config(config) + , m_screen(screen) { + if (lock) { + m_lock.setOwnLock(lock); + } + if (screen) { + connect(screen, &LockScreenController::input, &m_input, &InputWatcher::noteInput); + } m_armTimer.setSingleShot(true); connect(&m_armTimer, &QTimer::timeout, this, [this] { arm(0); @@ -68,7 +76,11 @@ void LockController::onLockedChanged(bool locked) return; } - if (!m_config->lockScreen()) { + const bool face = m_config->enabled() && m_config->lockScreen(); + if (m_screen) { + m_screen->setFaceUnlock(face); + } + if (!face) { return; } m_locked = true; diff --git a/src/agent/lockcontroller.h b/src/agent/lockcontroller.h index cb8a1ff..1244550 100644 --- a/src/agent/lockcontroller.h +++ b/src/agent/lockcontroller.h @@ -26,13 +26,16 @@ class BubbleController; class DaemonRequest; +class LockScreenController; +class SessionLock; class UserConfig; class LockController : public QObject { Q_OBJECT public: - LockController(BubbleController *bubble, UserConfig *config, QObject *parent = nullptr); + // lock and screen are face-unlock's own lock screen, where there is one. + LockController(BubbleController *bubble, UserConfig *config, SessionLock *lock, LockScreenController *screen, QObject *parent = nullptr); bool locked() const { @@ -53,6 +56,7 @@ private: BubbleController *m_bubble; UserConfig *m_config; + LockScreenController *m_screen; bool m_locked = false; bool m_stopped = false; QElapsedTimer m_lockedFor; diff --git a/src/agent/lockscreencontroller.cpp b/src/agent/lockscreencontroller.cpp new file mode 100644 index 0000000..ab1d43f --- /dev/null +++ b/src/agent/lockscreencontroller.cpp @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "lockscreencontroller.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace +{ +struct Conversation { + QByteArray password; +}; + +// Answers every hidden question with the password and every other one with +// nothing, as a lock screen that only asks for the password has to. +int converse(int count, const pam_message **messages, pam_response **responses, void *data) +{ + auto *conversation = static_cast(data); + auto *answers = static_cast(calloc(size_t(count), sizeof(pam_response))); + if (!answers) { + return PAM_BUF_ERR; + } + for (int i = 0; i < count; ++i) { + if (messages[i]->msg_style == PAM_PROMPT_ECHO_OFF) { + answers[i].resp = strdup(conversation->password.constData()); + } else if (messages[i]->msg_style == PAM_PROMPT_ECHO_ON) { + answers[i].resp = strdup(""); + } + } + *responses = answers; + return PAM_SUCCESS; +} + +QByteArray serviceName() +{ + static const char *const services[] = {"face-unlock-lock", "password-auth", "common-auth", "login"}; + static const char *const dirs[] = {"/etc/pam.d/", "/usr/lib/pam.d/", "/usr/share/pam.d/"}; + for (const char *service : services) { + for (const char *dir : dirs) { + if (QFile::exists(QString::fromLatin1(dir) + QString::fromLatin1(service))) { + return service; + } + } + } + return "login"; +} + +bool checkPassword(const QByteArray &user, const QByteArray &password) +{ + Conversation conversation{password}; + const pam_conv conv{converse, &conversation}; + pam_handle_t *pamh = nullptr; + // For development only, like the daemon's --socket: a directory of PAM + // files of its own, so a test never counts as a wrong password for the + // real account. + const QByteArray confdir = qgetenv("FU_PAM_CONFDIR"); + int rc = confdir.isEmpty() ? pam_start(serviceName().constData(), user.constData(), &conv, &pamh) + : pam_start_confdir("face-unlock-lock", user.constData(), &conv, confdir.constData(), &pamh); + if (rc == PAM_SUCCESS) { + rc = pam_authenticate(pamh, 0); + if (rc == PAM_SUCCESS) { + pam_setcred(pamh, PAM_REFRESH_CRED); + } + } + pam_end(pamh, rc); + std::memset(conversation.password.data(), 0, size_t(conversation.password.size())); + return rc == PAM_SUCCESS; +} + +passwd *me() +{ + return getpwuid(getuid()); +} +} // namespace + +LockScreenController::LockScreenController(QObject *parent) + : QObject(parent) +{ +} + +LockScreenController::~LockScreenController() +{ + clearPassword(); +} + +void LockScreenController::setPassword(const QString &password) +{ + if (m_password == password) { + return; + } + m_password = password; + Q_EMIT passwordChanged(); + if (!m_message.isEmpty()) { + m_message.clear(); + Q_EMIT messageChanged(); + } +} + +void LockScreenController::setFaceUnlock(bool on) +{ + if (m_faceUnlock != on) { + m_faceUnlock = on; + Q_EMIT faceUnlockChanged(); + } +} + +void LockScreenController::setBlur(bool blur) +{ + if (m_blur != blur) { + m_blur = blur; + Q_EMIT blurChanged(); + } +} + +QString LockScreenController::userName() const +{ + const passwd *pw = me(); + if (!pw) { + return {}; + } + // The full name from the comment field, else the login name. + const QString full = QString::fromLocal8Bit(pw->pw_gecos).section(u',', 0, 0).trimmed(); + return full.isEmpty() ? QString::fromLocal8Bit(pw->pw_name) : full; +} + +void LockScreenController::submit() +{ + if (m_busy || m_password.isEmpty()) { + return; + } + const passwd *pw = me(); + if (!pw) { + return; + } + m_busy = true; + Q_EMIT busyChanged(); + + const QByteArray user(pw->pw_name); + QByteArray password = m_password.toUtf8(); + QPointer self(this); + std::thread([self, user, password]() mutable { + const bool ok = checkPassword(user, password); + std::memset(password.data(), 0, size_t(password.size())); + QMetaObject::invokeMethod(qApp, [self, ok] { + if (self) { + self->finish(ok); + } + }); + }).detach(); +} + +void LockScreenController::finish(bool ok) +{ + m_busy = false; + Q_EMIT busyChanged(); + clearPassword(); + Q_EMIT passwordChanged(); + if (ok) { + Q_EMIT authenticated(); + return; + } + m_message = i18n("Wrong password"); + Q_EMIT messageChanged(); + Q_EMIT rejected(); +} + +void LockScreenController::activity() +{ + Q_EMIT input(); +} + +void LockScreenController::clearPassword() +{ + // What is still in memory of it, as far as a QString lets that happen. + m_password.fill(u' '); + m_password.clear(); +} + +void LockScreenController::reset() +{ + clearPassword(); + Q_EMIT passwordChanged(); + if (!m_message.isEmpty()) { + m_message.clear(); + Q_EMIT messageChanged(); + } +} diff --git a/src/agent/lockscreencontroller.h b/src/agent/lockscreencontroller.h new file mode 100644 index 0000000..762385a --- /dev/null +++ b/src/agent/lockscreencontroller.h @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// The own lock screen's side of things (see SessionLock): the password, +// whether it is being checked, what to say under it. +// +// The password is checked with PAM in a thread of its own, the way swaylock +// and hyprlock do it. The service is face-unlock-lock when an administrator +// has written one, else the distribution's plain password stack: +// password-auth (Fedora), common-auth (Debian, Ubuntu) or login. Not the face +// module: the face has its own way in here, the agent. + +#pragma once + +#include +#include + +class LockScreenController : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) + Q_PROPERTY(bool busy READ busy NOTIFY busyChanged) + // After a wrong password, until the next key. + Q_PROPERTY(QString message READ message NOTIFY messageChanged) + // Whether the face is looked for, which changes what the screen says. + Q_PROPERTY(bool faceUnlock READ faceUnlock NOTIFY faceUnlockChanged) + Q_PROPERTY(QString userName READ userName CONSTANT) + // Whether to blur the picture behind it. + Q_PROPERTY(bool blur READ blur NOTIFY blurChanged) +public: + explicit LockScreenController(QObject *parent = nullptr); + ~LockScreenController() override; + + QString password() const + { + return m_password; + } + void setPassword(const QString &password); + bool busy() const + { + return m_busy; + } + QString message() const + { + return m_message; + } + bool faceUnlock() const + { + return m_faceUnlock; + } + void setFaceUnlock(bool on); + QString userName() const; + bool blur() const + { + return m_blur; + } + void setBlur(bool blur); + + // Check the password typed so far. + Q_INVOKABLE void submit(); + // A key or the pointer on the lock screen. + Q_INVOKABLE void activity(); + + // A fresh lock: no password, nothing said. + void reset(); + +Q_SIGNALS: + void passwordChanged(); + void busyChanged(); + void messageChanged(); + void faceUnlockChanged(); + void blurChanged(); + void authenticated(); + // A wrong password, for the field to shake. + void rejected(); + void input(); + +private: + void finish(bool ok); + void clearPassword(); + + QString m_password; + QString m_message; + bool m_busy = false; + bool m_faceUnlock = true; + bool m_blur = false; +}; diff --git a/src/agent/lockwatcher.cpp b/src/agent/lockwatcher.cpp index ccb7228..2a59bdd 100644 --- a/src/agent/lockwatcher.cpp +++ b/src/agent/lockwatcher.cpp @@ -3,6 +3,7 @@ #include "lockwatcher.h" #include "lockers.h" +#include "sessionlock.h" #include "wayland.h" #include @@ -162,14 +163,20 @@ void LockWatcher::pollLockers() update(); } +void LockWatcher::setOwnLock(SessionLock *lock) +{ + m_own = lock; + connect(lock, &SessionLock::lockedChanged, this, &LockWatcher::update); +} + bool LockWatcher::canUnlock() const { - return !m_ownLockers || m_lockerRunning; + return (m_own && m_own->isLocked()) || !m_ownLockers || m_lockerRunning; } void LockWatcher::update() { - const bool locked = m_screenSaver || m_lockedHint || m_lockerRunning; + const bool locked = m_screenSaver || m_lockedHint || m_lockerRunning || (m_own && m_own->isLocked()); if (locked != m_locked) { m_locked = locked; Q_EMIT lockedChanged(locked); @@ -178,6 +185,10 @@ void LockWatcher::update() void LockWatcher::unlock() { + if (m_own && m_own->isLocked()) { + m_own->unlock(); + return; + } // Looked up again rather than taken from the last poll: a second is // long enough for a pid to belong to something else. Lockers::signal(SIGUSR1); diff --git a/src/agent/lockwatcher.h b/src/agent/lockwatcher.h index dd8ea3c..07e72a7 100644 --- a/src/agent/lockwatcher.h +++ b/src/agent/lockwatcher.h @@ -12,9 +12,9 @@ // (ext-session-lock). // // hyprlock and swaylock do not listen to logind. They unlock on SIGUSR1. -// Any other lock screen of that kind only opens itself: it gets the face -// through the PAM module in its own stack (see src/lib/pam.sh), when Enter is -// pressed. +// face-unlock's own lock screen (SessionLock) is simply told to. Any other +// lock screen of that kind only opens itself: it gets the face through the +// PAM module in its own stack (see src/lib/pam.sh), when Enter is pressed. // // None of this lowers the bar: any program running as this user can already // ask logind to unlock the session, or send its own lock screen a signal. The @@ -28,6 +28,8 @@ #include +class SessionLock; + class LockWatcher : public QObject { Q_OBJECT @@ -42,6 +44,7 @@ public: // logind unlocks (Plasma, GNOME), only hyprlock and swaylock elsewhere. bool canUnlock() const; void unlock(); + void setOwnLock(SessionLock *lock); Q_SIGNALS: void lockedChanged(bool locked); @@ -63,6 +66,7 @@ private: bool m_locked = false; // The compositor's lock screen is a program of its own. bool m_ownLockers = false; + SessionLock *m_own = nullptr; QString m_session; QTimer m_poll; }; diff --git a/src/agent/main.cpp b/src/agent/main.cpp index 98fd2c8..46d3440 100644 --- a/src/agent/main.cpp +++ b/src/agent/main.cpp @@ -5,6 +5,9 @@ // (no arguments) stay in the background: unlock the lock screen by face, // and show the bubble for every scan // --enroll open the window that sets up a face +// --lock lock the screen: with face-unlock's own lock screen +// where the lock screen is a program of its own (Hyprland, +// Niri), else through logind with the desktop's // --demo play the bubble's animations once, for trying out a // style (--bubble-style minimal) and for screenshots @@ -14,6 +17,8 @@ #include "bubblewindow.h" #include "enrollcontroller.h" #include "lockcontroller.h" +#include "lockscreencontroller.h" +#include "sessionlock.h" #include "userconfig.h" #include "wayland.h" @@ -23,11 +28,17 @@ #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include #include namespace @@ -55,6 +66,92 @@ int runEnroll(QGuiApplication &app, const QString &name) return controller.state() == u"done" ? 0 : code; } +// Where --lock tells the command that ran it that the screen is locked, when +// it forked to stay behind as the lock screen. -1: it did not. +int readyFd = -1; + +void signalReady(bool ok) +{ + if (readyFd >= 0) { + if (ok) { + [[maybe_unused]] const ssize_t n = write(readyFd, "1", 1); + } + close(readyFd); + readyFd = -1; + } +} + +// Whether an agent listens on its socket. Asked before Qt is up, to decide +// whether to fork. +bool agentListening() +{ + const char *runtime = getenv("XDG_RUNTIME_DIR"); + if (!runtime) { + return false; + } + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + const int len = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/face-unlock/agent.socket", runtime); + if (len <= 0 || size_t(len) >= sizeof(addr.sun_path)) { + return false; + } + const int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + const bool ok = fd >= 0 && connect(fd, reinterpret_cast(&addr), sizeof(addr)) == 0; + if (fd >= 0) { + close(fd); + } + return ok; +} + +// With no agent running, --lock stays behind as the lock screen until it is +// unlocked. The command that asked for it returns as soon as the screen is +// locked, the way swaylock -f does: an idle daemon locking before sleep +// waits for that, and not a moment longer. +void forkForLock(int argc, char **argv) +{ + bool lock = false; + for (int i = 1; i < argc; ++i) { + lock = lock || std::strcmp(argv[i], "--lock") == 0; + } + int fds[2]; + if (!lock || agentListening() || pipe(fds) != 0) { + return; + } + const pid_t pid = fork(); + if (pid < 0) { + close(fds[0]); + close(fds[1]); + return; + } + if (pid > 0) { + close(fds[1]); + char c = 0; + const bool locked = read(fds[0], &c, 1) == 1; + _exit(locked ? 0 : 1); + } + close(fds[0]); + setsid(); + readyFd = fds[1]; +} + +// Plasma and GNOME lock with their own lock screen when logind asks them to, +// as `loginctl lock-session` does. +int lockThroughLogind() +{ + const QString id = qEnvironmentVariable("XDG_SESSION_ID"); + QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.login1"), + QStringLiteral("/org/freedesktop/login1"), + QStringLiteral("org.freedesktop.login1.Manager"), + QStringLiteral("LockSession")); + call << (id.isEmpty() ? QStringLiteral("auto") : id); + const QDBusMessage reply = QDBusConnection::systemBus().call(call); + if (reply.type() == QDBusMessage::ErrorMessage) { + qWarning("logind would not lock: %s", qPrintable(reply.errorMessage())); + return 1; + } + return 0; +} + // The whole life of a bubble, twice: a face that is recognised after a blink, // then one that is not. void scheduleDemo(BubbleController *bubble) @@ -77,6 +174,7 @@ void scheduleDemo(BubbleController *bubble) int main(int argc, char **argv) { + forkForLock(argc, argv); QGuiApplication app(argc, argv); app.setApplicationName(QStringLiteral("face-unlock-agent")); app.setApplicationVersion(QStringLiteral(FU_VERSION)); @@ -89,10 +187,11 @@ int main(int argc, char **argv) parser.addVersionOption(); const QCommandLineOption enrollOpt(QStringLiteral("enroll"), i18n("Set up a face.")); const QCommandLineOption nameOpt(QStringLiteral("name"), i18n("What to call the new face."), QStringLiteral("name")); + const QCommandLineOption lockOpt(QStringLiteral("lock"), i18n("Lock the screen.")); const QCommandLineOption demoOpt(QStringLiteral("demo"), i18n("Play the bubble's animations once.")); // Not "--style": QGuiApplication takes that one for itself. const QCommandLineOption styleOpt(QStringLiteral("bubble-style"), i18n("Bubble style for the demo: full or minimal."), QStringLiteral("style")); - parser.addOptions({enrollOpt, nameOpt, demoOpt, styleOpt}); + parser.addOptions({enrollOpt, nameOpt, lockOpt, demoOpt, styleOpt}); parser.process(app); if (parser.isSet(enrollOpt)) { @@ -103,6 +202,13 @@ int main(int argc, char **argv) return runEnroll(app, name); } + const bool lockNow = parser.isSet(lockOpt); + if (lockNow && !SessionLock::available()) { + const int rc = lockThroughLogind(); + signalReady(rc == 0); + return rc; + } + app.setQuitOnLastWindowClosed(false); QQmlEngine engine; KLocalization::setupLocalizedContext(&engine); @@ -131,6 +237,9 @@ int main(int argc, char **argv) AgentSocket socket; if (AgentSocket::running()) { + if (lockNow) { + return AgentSocket::requestLock() ? 0 : 1; + } qInfo("an agent is already running in this session"); return 0; } @@ -141,6 +250,50 @@ int main(int argc, char **argv) service = std::make_unique(&bubble); } - LockController lock(&bubble, &config); + LockScreenController screen; + std::unique_ptr sessionLock; + if (SessionLock::available()) { + sessionLock = std::make_unique(&engine, &bubble, &screen, &config); + SessionLock *lock = sessionLock.get(); + QObject::connect(&socket, &AgentSocket::lockRequested, lock, [lock, &socket] { + lock->lock(); + if (lock->isConfirmed()) { + socket.confirmLock(); + } + }); + QObject::connect(lock, &SessionLock::confirmed, &socket, &AgentSocket::confirmLock); + } + LockController lock(&bubble, &config, sessionLock.get(), &screen); + + if (lockNow) { + // No agent was running, so this one is only here for the lock. It + // goes once the lock is gone and the bubble has finished. + QObject::connect(sessionLock.get(), &SessionLock::lockedChanged, &app, [&bubble](bool locked) { + if (locked) { + return; + } + if (!bubble.shown()) { + QCoreApplication::quit(); + } + QObject::connect(&bubble, &BubbleController::shownChanged, qApp, [&bubble] { + if (!bubble.shown()) { + QCoreApplication::quit(); + } + }); + QTimer::singleShot(5000, qApp, &QCoreApplication::quit); + }); + QObject::connect(sessionLock.get(), &SessionLock::confirmed, &app, [] { + signalReady(true); + }); + sessionLock->lock(); + if (!sessionLock->isLocked()) { + signalReady(false); + return 1; + } + } else if (sessionLock && QFile::exists(SessionLock::markerPath())) { + // The last agent went away with the screen locked, and the compositor + // kept it locked. Take the lock back, so it can be opened again. + sessionLock->lock(); + } return app.exec(); } diff --git a/src/agent/qml/LockScreen.qml b/src/agent/qml/LockScreen.qml new file mode 100644 index 0000000..19a0c86 --- /dev/null +++ b/src/agent/qml/LockScreen.qml @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// face-unlock's own lock screen, one per screen (see SessionLock): the time, +// the password, and on the main screen the bubble at the top, the same one +// that shows over the desktop. Behind it the desktop's picture, or the one +// the user set (see Wallpaper). + +import QtQuick +import QtQuick.Effects + +Item { + id: root + + required property var lock + required property var bubble + required property bool primary + required property url wallpaper + + property date now: new Date() + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: root.now = new Date() + } + + Rectangle { + anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0; color: "#11161D" } + GradientStop { position: 0.6; color: "#000000" } + } + } + + // Loaded aside, so a big picture does not hold up the lock, and faded in. + Item { + anchors.fill: parent + opacity: picture.status === Image.Ready ? 1 : 0 + visible: opacity > 0 + Behavior on opacity { + NumberAnimation { duration: 200 } + } + + Image { + id: picture + // Past the edges when blurred: the blur would pull in the nothing + // beyond them and darken the rim. + anchors.fill: parent + anchors.margins: root.lock.blur ? -64 : 0 + source: root.wallpaper + fillMode: Image.PreserveAspectCrop + sourceSize: Qt.size(root.width, root.height) + asynchronous: true + cache: false + layer.enabled: root.lock.blur + layer.effect: MultiEffect { + blurEnabled: true + blur: 1 + blurMax: 64 + } + } + // Dimmed a little, so the time and the password read on any picture. + Rectangle { + anchors.fill: parent + color: "#000000" + opacity: 0.35 + } + } + + // Any touch counts as somebody being back, and a click anywhere puts the + // keys into the password. + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.AllButtons + onPositionChanged: root.lock.activity() + onPressed: { + root.lock.activity() + field.forceActiveFocus() + } + } + + // Below the open bubble, which hangs from the top edge. + Column { + anchors.horizontalCenter: parent.horizontalCenter + y: Math.max(Theme.topGap + Theme.openHeight + 24, Math.round(parent.height * 0.2)) + spacing: 2 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: Theme.textPrimary + font.pixelSize: Math.max(56, Math.min(120, Math.round(root.height * 0.11))) + font.weight: Font.Light + text: Qt.formatTime(root.now, Qt.locale().timeFormat(Locale.ShortFormat)) + } + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: Theme.textDetail + font.pixelSize: 18 + font.weight: Font.Medium + text: Qt.formatDate(root.now, Qt.locale().dateFormat(Locale.LongFormat)) + } + } + + Column { + anchors.horizontalCenter: parent.horizontalCenter + y: Math.round(parent.height * 0.62) + spacing: 12 + + Text { + anchors.horizontalCenter: parent.horizontalCenter + color: Theme.textPrimary + font.pixelSize: 17 + font.weight: Font.DemiBold + text: root.lock.userName + } + + Rectangle { + id: pill + anchors.horizontalCenter: parent.horizontalCenter + width: 280 + height: 44 + radius: height / 2 + color: Theme.surfaceRaised + opacity: root.lock.busy ? 0.6 : 1 + border.width: field.activeFocus ? 1 : 0 + border.color: Qt.rgba(1, 1, 1, 0.18) + + property real shake: 0 + transform: Translate { x: pill.shake } + SequentialAnimation { + id: shakeAnimation + NumberAnimation { target: pill; property: "shake"; to: -10; duration: 55; easing.type: Easing.OutQuad } + NumberAnimation { target: pill; property: "shake"; to: 9; duration: 70 } + NumberAnimation { target: pill; property: "shake"; to: -6; duration: 65 } + NumberAnimation { target: pill; property: "shake"; to: 4; duration: 60 } + NumberAnimation { target: pill; property: "shake"; to: 0; duration: 55; easing.type: Easing.OutQuad } + } + + TextInput { + id: field + anchors.fill: parent + anchors.leftMargin: 20 + anchors.rightMargin: 20 + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignHCenter + echoMode: TextInput.Password + passwordCharacter: "●" + color: Theme.textPrimary + selectionColor: Theme.accent + font.pixelSize: 15 + clip: true + focus: true + // The dots show how far it is; a blinking bar in the middle + // of the empty field only cuts the word in it in two. + cursorDelegate: Item {} + readOnly: root.lock.busy + text: root.lock.password + onTextEdited: root.lock.password = text + onAccepted: root.lock.submit() + Keys.onPressed: event => { + root.lock.activity() + event.accepted = false + } + Component.onCompleted: forceActiveFocus() + } + Text { + anchors.centerIn: parent + color: Theme.textSecondary + font.pixelSize: 15 + text: i18n("Password") + visible: field.text.length === 0 + } + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + width: 360 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + color: root.lock.message.length > 0 ? Theme.failure : Theme.textDetail + font.pixelSize: 13 + font.weight: Font.Medium + text: root.lock.message.length > 0 ? root.lock.message + : root.lock.faceUnlock ? i18n("Look at the camera or type your password") + : i18n("Type your password") + } + } + + Connections { + target: root.lock + function onRejected() { + shakeAnimation.restart() + } + } + + // The bubble, where it shows over the desktop too. + Bubble { + visible: root.primary + anchors.horizontalCenter: parent.horizontalCenter + y: 0 + bubble: root.bubble + } +} diff --git a/src/agent/sessionlock.cpp b/src/agent/sessionlock.cpp new file mode 100644 index 0000000..c5859bd --- /dev/null +++ b/src/agent/sessionlock.cpp @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "sessionlock.h" + +#include "bubblecontroller.h" +#include "lockscreencontroller.h" +#include "userconfig.h" +#include "wallpaper.h" +#include "wayland.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qwayland-ext-session-lock-v1.h" + +// The manager, and through it the role every lock window gets. +class LockIntegration : public QtWaylandClient::QWaylandShellIntegrationTemplate, public QtWayland::ext_session_lock_manager_v1 +{ +public: + LockIntegration() + : QWaylandShellIntegrationTemplate(1) + { + } + ~LockIntegration() override + { + if (object()) { + destroy(); + } + } + QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override; + + // The lock the surfaces belong to. + ::ext_session_lock_v1 *current = nullptr; +}; + +// One screen's lock surface. Like LayerShellQt's layer surface: the size +// comes from the compositor, and nothing is drawn before it has sent one. +class LockSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::ext_session_lock_surface_v1 +{ +public: + LockSurface(::ext_session_lock_v1 *lock, QtWaylandClient::QWaylandWindow *window) + : QWaylandShellSurface(window) + { + init(ext_session_lock_v1_get_lock_surface(lock, window->waylandSurface()->object(), window->waylandScreen()->output())); + } + ~LockSurface() override + { + destroy(); + } + bool isExposed() const override + { + return m_configured; + } + // Qt commits a new role at once, as xdg-shell wants. A lock surface must + // not be committed before it has acknowledged its first size. + bool commitSurfaceRole() const override + { + return false; + } + void applyConfigure() override + { + window()->resizeFromApplyConfigure(m_size); + } + +protected: + void ext_session_lock_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override + { + ack_configure(serial); + m_size = QSize(int(width), int(height)); + if (!m_configured) { + m_configured = true; + applyConfigure(); + window()->updateExposure(); + } else { + window()->applyConfigureWhenPossible(); + } + } + +private: + QSize m_size; + bool m_configured = false; +}; + +QtWaylandClient::QWaylandShellSurface *LockIntegration::createShellSurface(QtWaylandClient::QWaylandWindow *window) +{ + return new LockSurface(current, window); +} + +class Lock : public QtWayland::ext_session_lock_v1 +{ +public: + Lock(::ext_session_lock_v1 *object, SessionLock *owner) + : QtWayland::ext_session_lock_v1(object) + , m_owner(owner) + { + } + +protected: + // Queued: not from inside the Wayland event, which the answer to it might + // destroy. + void ext_session_lock_v1_locked() override + { + QMetaObject::invokeMethod(m_owner, &SessionLock::onLocked, Qt::QueuedConnection); + } + void ext_session_lock_v1_finished() override + { + QMetaObject::invokeMethod(m_owner, &SessionLock::onFinished, Qt::QueuedConnection); + } + +private: + SessionLock *m_owner; +}; + +SessionLock::SessionLock(QQmlEngine *engine, BubbleController *bubble, LockScreenController *screen, UserConfig *config, QObject *parent) + : QObject(parent) + , m_engine(engine) + , m_bubble(bubble) + , m_screen(screen) + , m_config(config) +{ + connect(qGuiApp, &QGuiApplication::screenAdded, this, [this](QScreen *s) { + if (m_lock) { + addScreen(s); + } + }); + connect(qGuiApp, &QGuiApplication::screenRemoved, this, &SessionLock::removeScreen); + connect(m_screen, &LockScreenController::authenticated, this, &SessionLock::unlock); +} + +SessionLock::~SessionLock() +{ + // Leaving with the lock held keeps the session locked, which is the + // point. The windows go, the lock stays. + qDeleteAll(m_views); + delete m_lock; + delete m_integration; +} + +bool SessionLock::available() +{ + return Wayland::hasGlobal("ext_session_lock_manager_v1"); +} + +QString SessionLock::markerPath() +{ + return QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation) + QStringLiteral("/face-unlock/locked"); +} + +void SessionLock::lock() +{ + if (m_lock) { + return; + } + auto *qpa = QtWaylandClient::QWaylandIntegration::instance(); + if (!m_integration && qpa) { + m_integration = new LockIntegration; + if (!m_integration->initialize(qpa->display())) { + delete m_integration; + m_integration = nullptr; + } + } + if (!m_integration) { + qWarning("the compositor has no ext_session_lock_manager_v1, so this cannot lock the screen"); + return; + } + + m_confirmed = false; + m_unlockWanted = false; + m_lock = new Lock(m_integration->lock(), this); + m_integration->current = m_lock->object(); + m_screen->reset(); + m_pictures = Wallpaper::forLock(m_config->lockWallpaper()); + m_screen->setBlur(m_config->lockBlur()); + for (QScreen *s : QGuiApplication::screens()) { + addScreen(s); + } + + QDir().mkpath(QFileInfo(markerPath()).absolutePath()); + QFile marker(markerPath()); + if (!marker.open(QIODevice::WriteOnly)) { + qWarning("cannot write %s", qPrintable(markerPath())); + } + Q_EMIT lockedChanged(true); +} + +void SessionLock::addScreen(QScreen *screen) +{ + if (m_views.contains(screen) || !dynamic_cast(screen->handle())) { + return; + } + auto *view = new QQuickView(m_engine, nullptr); + view->setColor(Qt::black); + view->setScreen(screen); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->resize(screen->size()); + view->setInitialProperties({{QStringLiteral("lock"), QVariant::fromValue(m_screen)}, + {QStringLiteral("bubble"), QVariant::fromValue(m_bubble)}, + {QStringLiteral("wallpaper"), Wallpaper::pick(m_pictures, screen->name())}, + {QStringLiteral("primary"), screen == QGuiApplication::primaryScreen()}}); + view->loadFromModule(QStringLiteral("FaceUnlock"), QStringLiteral("LockScreen")); + for (const QQmlError &e : view->errors()) { + qWarning("%s", qPrintable(e.toString())); + } + view->create(); + if (auto *wayland = dynamic_cast(view->handle())) { + wayland->setShellIntegration(m_integration); + } + view->show(); + view->requestActivate(); + m_views.insert(screen, view); +} + +void SessionLock::removeScreen(QScreen *screen) +{ + if (auto view = m_views.take(screen)) { + delete view; + } +} + +void SessionLock::onLocked() +{ + if (!m_lock) { + return; + } + m_confirmed = true; + Q_EMIT confirmed(); + if (m_unlockWanted) { + unlock(); + } +} + +void SessionLock::onFinished() +{ + if (!m_lock) { + return; + } + // Refused (another lock screen is up) or ended by the compositor. + if (m_confirmed) { + m_lock->unlock_and_destroy(); + } else { + qWarning("the compositor did not let this lock the screen; is another lock screen running?"); + m_lock->destroy(); + } + release(); +} + +void SessionLock::unlock() +{ + if (!m_lock) { + return; + } + // Unlocking before the compositor has confirmed the lock is a protocol + // error. It follows as soon as it has. + if (!m_confirmed) { + m_unlockWanted = true; + return; + } + m_lock->unlock_and_destroy(); + release(); +} + +void SessionLock::release() +{ + qDeleteAll(m_views); + m_views.clear(); + delete m_lock; + m_lock = nullptr; + m_confirmed = false; + m_integration->current = nullptr; + QFile::remove(markerPath()); + // Out to the compositor now: an agent started only for this lock quits + // straight after. + Wayland::sync(); + m_screen->reset(); + Q_EMIT lockedChanged(false); +} diff --git a/src/agent/sessionlock.h b/src/agent/sessionlock.h new file mode 100644 index 0000000..abc0e77 --- /dev/null +++ b/src/agent/sessionlock.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// face-unlock's own lock screen, for whoever wants it on a compositor whose +// lock screen is a program of its own (ext-session-lock: Hyprland, Niri, +// Sway and others): `face-unlock lock`. +// +// Any other lock screen there covers the bubble, and only opens itself (it +// gets the face through PAM, see src/lib/pam.sh). This one is the lock +// screen, so the bubble shows on it and a face opens it straight away. The +// picture behind it is the user's choice (LockWallpaper). +// +// Qt knows no ext-session-lock, so each screen's window gets the lock surface +// role through Qt's shell integration, the way LayerShellQt gives windows the +// layer-shell role. If this program goes away while locked, the compositor +// keeps the session locked: that is the protocol's promise. + +#pragma once + +#include +#include +#include +#include + +class BubbleController; +class LockScreenController; +class UserConfig; +class QQmlEngine; +class QQuickView; +class QScreen; +class LockIntegration; +class Lock; + +class SessionLock : public QObject +{ + Q_OBJECT +public: + SessionLock(QQmlEngine *engine, BubbleController *bubble, LockScreenController *screen, UserConfig *config, QObject *parent = nullptr); + ~SessionLock() override; + + // Whether the compositor offers ext-session-lock. + static bool available(); + + // From the lock request until the lock is gone again. + bool isLocked() const + { + return m_lock != nullptr; + } + // The compositor has confirmed the lock: nothing unlocked is on screen. + bool isConfirmed() const + { + return m_confirmed; + } + + // A file that says the screen is locked, so that an agent started again + // after a crash locks again (see main.cpp). + static QString markerPath(); + +public Q_SLOTS: + void lock(); + void unlock(); + +Q_SIGNALS: + void lockedChanged(bool locked); + void confirmed(); + +private: + friend class Lock; + void onLocked(); + void onFinished(); + void addScreen(QScreen *screen); + void removeScreen(QScreen *screen); + void release(); + + QQmlEngine *m_engine; + BubbleController *m_bubble; + LockScreenController *m_screen; + UserConfig *m_config; + LockIntegration *m_integration = nullptr; + Lock *m_lock = nullptr; + bool m_confirmed = false; + bool m_unlockWanted = false; + QHash> m_views; + // The pictures behind it, by output (see Wallpaper). + QHash m_pictures; +}; diff --git a/src/agent/userconfig.cpp b/src/agent/userconfig.cpp index 5e97516..5c3dc96 100644 --- a/src/agent/userconfig.cpp +++ b/src/agent/userconfig.cpp @@ -29,6 +29,9 @@ QString UserConfig::path() void UserConfig::load() { const KeyValueFile kv = KeyValueFile::load(path()); + m_enabled = kv.boolean(QStringLiteral("Enabled"), false); + m_lockWallpaper = kv.value(QStringLiteral("LockWallpaper")); + m_lockBlur = kv.boolean(QStringLiteral("LockBlur"), false); m_lockScreen = kv.boolean(QStringLiteral("LockScreen"), true); m_scanOnWake = kv.boolean(QStringLiteral("ScanOnWake"), true); m_scanOnLock = kv.boolean(QStringLiteral("ScanOnLock"), false); diff --git a/src/agent/userconfig.h b/src/agent/userconfig.h index a53d670..eb475b9 100644 --- a/src/agent/userconfig.h +++ b/src/agent/userconfig.h @@ -17,6 +17,22 @@ class UserConfig : public QObject public: explicit UserConfig(QObject *parent = nullptr); + // Face unlock turned on at all. The agent's service only runs when it is, + // but the own lock screen (--lock) runs either way. + bool enabled() const + { + return m_enabled; + } + // The picture behind the own lock screen (see Wallpaper): empty for the + // desktop's, "none", a file, or a folder to take one from at random. + QString lockWallpaper() const + { + return m_lockWallpaper; + } + bool lockBlur() const + { + return m_lockBlur; + } // Unlock the lock screen by face. bool lockScreen() const { @@ -72,6 +88,9 @@ private: void load(); QFileSystemWatcher m_watcher; + bool m_enabled = false; + QString m_lockWallpaper; + bool m_lockBlur = false; bool m_lockScreen = true; bool m_scanOnWake = true; bool m_scanOnLock = false; diff --git a/src/agent/wallpaper.cpp b/src/agent/wallpaper.cpp new file mode 100644 index 0000000..e9855af --- /dev/null +++ b/src/agent/wallpaper.cpp @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "wallpaper.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ +// A picture, or one at random from a folder. +QUrl picture(const QString &setting) +{ + QString path = setting; + if (path.startsWith(u"~/")) { + path = QDir::homePath() + path.mid(1); + } + const QFileInfo info(path); + if (setting.isEmpty() || !info.exists()) { + return {}; + } + if (info.isFile()) { + return QUrl::fromLocalFile(info.absoluteFilePath()); + } + const QStringList pictures = QDir(path).entryList({QStringLiteral("*.jpg"), QStringLiteral("*.jpeg"), QStringLiteral("*.png"), QStringLiteral("*.webp")}, + QDir::Files | QDir::Readable); + if (pictures.isEmpty()) { + return {}; + } + return QUrl::fromLocalFile(QDir(path).absoluteFilePath(pictures.at(QRandomGenerator::global()->bounded(int(pictures.size()))))); +} + +// What a command prints, or nothing when it is not there or hangs. +QString run(const QString &program, const QStringList &args) +{ + QProcess process; + process.start(program, args); + if (!process.waitForFinished(1000) || process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { + process.kill(); + process.waitForFinished(100); + return {}; + } + return QString::fromLocal8Bit(process.readAllStandardOutput()); +} + +// The pictures the running wallpaper programs of this user show. +QHash desktop() +{ + QHash found; + const uint me = getuid(); + const QStringList pids = QDir(QStringLiteral("/proc")).entryList({QStringLiteral("[0-9]*")}, QDir::Dirs); + for (const QString &pid : pids) { + const QString dir = QStringLiteral("/proc/") + pid; + if (QFileInfo(dir).ownerId() != me) { + continue; + } + QFile comm(dir + QStringLiteral("/comm")); + if (!comm.open(QIODevice::ReadOnly)) { + continue; + } + const QByteArray name = comm.readAll().trimmed(); + if (name == "swaybg") { + QFile cmdline(dir + QStringLiteral("/cmdline")); + if (cmdline.open(QIODevice::ReadOnly)) { + QStringList args; + for (const QByteArray &arg : cmdline.readAll().split('\0')) { + args << QString::fromLocal8Bit(arg); + } + // Relative to where it was started. + const QDir cwd(QFileInfo(dir + QStringLiteral("/cwd")).symLinkTarget()); + QHash shown = Wallpaper::fromSwaybg(args.mid(1)); + for (QString &path : shown) { + path = cwd.absoluteFilePath(path); + } + found.insert(shown); + } + } else if (name == "awww-daemon" || name == "swww-daemon") { + found.insert(Wallpaper::fromAwww(run(QString::fromLatin1(name.left(4)), {QStringLiteral("query")}))); + } else if (name == "hyprpaper") { + found.insert(Wallpaper::fromList(run(QStringLiteral("hyprctl"), {QStringLiteral("hyprpaper"), QStringLiteral("listactive")}))); + } else if (name == "wpaperd") { + found.insert(Wallpaper::fromList(run(QStringLiteral("wpaperctl"), {QStringLiteral("all-wallpapers")}))); + } + } + return found; +} +} // namespace + +QHash Wallpaper::fromSwaybg(const QStringList &args) +{ + QHash found; + QString output; + for (int i = 0; i < args.size(); ++i) { + const QString &arg = args.at(i); + const bool hasNext = i + 1 < args.size(); + if ((arg == u"-o" || arg == u"--output") && hasNext) { + output = args.at(++i); + } else if (arg.startsWith(u"--output=")) { + output = arg.mid(9); + } else if ((arg == u"-i" || arg == u"--image") && hasNext) { + found.insert(output == u"*" ? QString() : output, args.at(++i)); + } else if (arg.startsWith(u"--image=")) { + found.insert(output == u"*" ? QString() : output, arg.mid(8)); + } + } + return found; +} + +QHash Wallpaper::fromAwww(const QString &text) +{ + // "eDP-1: 1920x1080, scale: 1, currently displaying: image: /a/b.jpg", + // with a namespace in front on awww. A plain colour is no picture. + static const QRegularExpression line(QStringLiteral("([^\\s:]+): \\d+x\\d+,.*currently displaying: image: (.+)$"), QRegularExpression::MultilineOption); + QHash found; + auto it = line.globalMatch(text); + while (it.hasNext()) { + const auto match = it.next(); + found.insert(match.captured(1), match.captured(2).trimmed()); + } + return found; +} + +QHash Wallpaper::fromList(const QString &text) +{ + // "eDP-1: /a/b.jpg", on older hyprpaper "eDP-1 = /a/b.jpg". + static const QRegularExpression line(QStringLiteral("^([^\\s:=]+)(?:: | = )(/.+)$"), QRegularExpression::MultilineOption); + QHash found; + auto it = line.globalMatch(text); + while (it.hasNext()) { + const auto match = it.next(); + found.insert(match.captured(1), match.captured(2).trimmed()); + } + return found; +} + +QHash Wallpaper::forLock(const QString &setting) +{ + QHash pictures; + if (setting.compare(u"none", Qt::CaseInsensitive) == 0) { + return pictures; + } + if (!setting.isEmpty()) { + const QUrl url = picture(setting); + if (!url.isEmpty()) { + pictures.insert(QString(), url); + } + return pictures; + } + const QHash shown = desktop(); + for (auto it = shown.cbegin(); it != shown.cend(); ++it) { + const QUrl url = picture(it.value()); + if (!url.isEmpty()) { + pictures.insert(it.key(), url); + } + } + return pictures; +} + +QUrl Wallpaper::pick(const QHash &pictures, const QString &output) +{ + if (pictures.isEmpty()) { + return {}; + } + if (pictures.contains(output)) { + return pictures.value(output); + } + if (pictures.contains(QString())) { + return pictures.value(QString()); + } + // Named differently than here: some picture of the desktop is still + // better than none. + QStringList outputs = pictures.keys(); + outputs.sort(); + return pictures.value(outputs.first()); +} diff --git a/src/agent/wallpaper.h b/src/agent/wallpaper.h new file mode 100644 index 0000000..1e33b02 --- /dev/null +++ b/src/agent/wallpaper.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// The picture behind face-unlock's own lock screen. By default the one on +// the desktop. Hyprland, niri and the like leave the wallpaper to a program +// of its own, so it comes from whichever of the common ones runs: swaybg, +// awww (once swww), hyprpaper or wpaperd, each for every output. + +#pragma once + +#include +#include +#include +#include + +namespace Wallpaper +{ +// The pictures for a lock by output name, "" for every other output. +// setting is LockWallpaper: empty for the desktop's, "none", a picture, or a +// folder to take one from at random. +QHash forLock(const QString &setting); +// The one for this output. +QUrl pick(const QHash &pictures, const QString &output); + +// What the programs tell, by output name. Apart for the tests. +QHash fromSwaybg(const QStringList &args); +// `awww query` and `swww query`. +QHash fromAwww(const QString &text); +// `hyprctl hyprpaper listactive` and `wpaperctl all-wallpapers`. +QHash fromList(const QString &text); +} diff --git a/src/agent/wayland.cpp b/src/agent/wayland.cpp index d0efc91..365177f 100644 --- a/src/agent/wayland.cpp +++ b/src/agent/wayland.cpp @@ -21,6 +21,12 @@ void onGlobalRemove(void *, wl_registry *, uint32_t) const wl_registry_listener listener = {onGlobal, onGlobalRemove}; +wl_display *display() +{ + auto *app = qGuiApp ? qGuiApp->nativeInterface() : nullptr; + return app ? app->display() : nullptr; +} + const QSet &globals() { static QSet names; @@ -30,17 +36,16 @@ const QSet &globals() } asked = true; - auto *app = qGuiApp ? qGuiApp->nativeInterface() : nullptr; - wl_display *display = app ? app->display() : nullptr; - if (!display) { + wl_display *d = display(); + if (!d) { return names; } - wl_event_queue *queue = wl_display_create_queue(display); - auto *wrapped = static_cast(wl_proxy_create_wrapper(display)); + wl_event_queue *queue = wl_display_create_queue(d); + auto *wrapped = static_cast(wl_proxy_create_wrapper(d)); wl_proxy_set_queue(reinterpret_cast(wrapped), queue); wl_registry *registry = wl_display_get_registry(wrapped); wl_registry_add_listener(registry, &listener, &names); - wl_display_roundtrip_queue(display, queue); + wl_display_roundtrip_queue(d, queue); wl_registry_destroy(registry); wl_proxy_wrapper_destroy(wrapped); wl_event_queue_destroy(queue); @@ -52,3 +57,13 @@ bool Wayland::hasGlobal(const char *interface) { return globals().contains(QByteArray(interface)); } + +void Wayland::sync() +{ + // On a queue of its own, like above: Qt reads the default one. + if (wl_display *d = display()) { + wl_event_queue *queue = wl_display_create_queue(d); + wl_display_roundtrip_queue(d, queue); + wl_event_queue_destroy(queue); + } +} diff --git a/src/agent/wayland.h b/src/agent/wayland.h index fbbdf1d..a6b9710 100644 --- a/src/agent/wayland.h +++ b/src/agent/wayland.h @@ -12,4 +12,7 @@ namespace Wayland // "zwlr_layer_shell_v1". Asked once, on an event queue of its own, so Qt's // own handling of the connection is not disturbed. bool hasGlobal(const char *interface); + +// Wait until the compositor has handled everything sent so far. +void sync(); } // namespace Wayland diff --git a/src/face-unlock b/src/face-unlock index 4e34178..704b89d 100644 --- a/src/face-unlock +++ b/src/face-unlock @@ -197,6 +197,7 @@ fu_do_help() { faces $(fu_msg "List the faces") remove ID $(fu_msg "Delete a face") test $(fu_msg "Look at the camera and see what it sees") + lock $(fu_msg "Lock the screen") status $(fu_msg "Show what is on") -h, --help $(fu_msg "Show this help") -V, --version $(fu_msg "Show the version") @@ -236,6 +237,7 @@ main() { remove|delete) fu_do_remove "$@" ;; test|try) fu_ensure_service && fu_test ;; status) fu_do_status ;; + lock) exec "$FU_AGENT" --lock ;; -h|--help|help) fu_do_help ;; -V|--version) printf '%s %s\n' "$FU_NAME" "$FU_VERSION" ;; diff --git a/src/lib/common.sh b/src/lib/common.sh index 303189a..ecce491 100644 --- a/src/lib/common.sh +++ b/src/lib/common.sh @@ -31,7 +31,9 @@ FU_SYSCONFIG="${FU_SYSCONFIG:-/etc/${FU_NAME}/config}" FU_UNIT_SOCKET="face-unlockd.socket" FU_UNIT_AGENT="face-unlock-agent.service" -# The desktop this runs in: plasma, gnome, hyprland, niri or other. +# The desktop this runs in: plasma, gnome, hyprland, niri or other. All but +# the first two have a lock screen that is a program of its own, and there +# face-unlock's own one (`face-unlock lock`) is on offer. case ":${XDG_CURRENT_DESKTOP:-}:" in *:KDE:*) FU_DESKTOP=plasma ;; *:GNOME:*) FU_DESKTOP=gnome ;; diff --git a/src/lib/menu.sh b/src/lib/menu.sh index 0703e90..16d3b8d 100644 --- a/src/lib/menu.sh +++ b/src/lib/menu.sh @@ -277,16 +277,20 @@ fu_ui_status() { # scope user (this user's file), sys (the system file, through sudo), # pam (the service of that name, through sudo), or group for a # heading, with only the label after it -# type bool, choice (steps through the choices) or camera +# type bool, choice (steps through the choices), camera, or path (typed +# in; empty for the desktop's picture) # needs a bool setting this one does nothing without; it is dimmed while # that is off # only lockers: only where the lock screen is a program of its own with a -# PAM file (Hyprland, Niri), see fu_pam_lockers_here +# PAM file (Hyprland, Niri), see fu_pam_lockers_here; ownlock: only +# where face-unlock's own lock screen can be used FU_SETTINGS=( "group|Lock screen" "user|LockScreen|bool|yes|Unlock with your face" "user|ScanOnWake|bool|yes|Scan when you come back||LockScreen" "user|ScanOnLock|bool|no|Scan right after locking||LockScreen" + "user|LockWallpaper|path||Wallpaper|||ownlock" + "user|LockBlur|bool|no|Blur the wallpaper|||ownlock" "group|Password prompts" "pam|sudo|bool|no|sudo in a terminal" "pam|polkit-1|bool|no|Admin prompts" @@ -315,7 +319,7 @@ fu_setting_help() { return ;; hyprland:LockScreen|niri:LockScreen) - fu_msg "Scans when you come back to hyprlock or swaylock and opens them. Any other lock screen scans when you press Enter on the empty password field." + fu_msg "Scans when you come back to hyprlock, swaylock or face-unlock's own lock screen (\`face-unlock lock\`, with the bubble), and opens them. Other lock screens scan on Enter." return ;; esac @@ -324,6 +328,8 @@ fu_setting_help() { ScanOnWake:*) fu_msg "Scans when you press a key or move the mouse on the lock screen, and when the computer wakes up." ;; ScanOnLock:*) fu_msg "Scans as soon as the screen locks. Off by default: if you lock it yourself, it would unlock again right away." ;; sudo:*) fu_msg "sudo takes your face instead of the password. No match: you type the password as usual." ;; + LockWallpaper:*) fu_msg "The picture behind face-unlock's own lock screen (\`face-unlock lock\`). Empty: the one on your desktop. Or a file, a folder to take one from at random, or \`none\`. Enter to type it." ;; + LockBlur:*) fu_msg "Blurs the picture behind face-unlock's own lock screen." ;; lockscreens:*) fu_msg "The lock screen takes your face in its password check. Press Enter on the empty field to scan. Found here: %s." "$(fu_pam_lockers_list)" ;; polkit-1:*) fu_msg "The password windows of your desktop and apps, for example when you install software. No match: you type the password." ;; Liveness:heavy) fu_msg "You have to blink or turn your head a little. This also stops printed photos." ;; @@ -451,6 +457,24 @@ _fu_camera_label() { printf '%s %s' "$value" "$(fu_msg "(not connected)")" } +# _fu_path_label +# A path as it fits in the list: with ~ for home, and cut from the left. +# Empty is the desktop's picture. +_fu_path_label() { + local path="$1" + if [[ -z $path ]]; then + fu_msg "same as desktop" + return + fi + if [[ ${path,,} == none ]]; then + fu_msg "none" + return + fi + [[ $path == "$HOME"/* ]] && path="~${path#"$HOME"}" + (( ${#path} > 36 )) && path="…${path: -35}" + printf '%s' "$path" +} + # _fu_setting_change _fu_setting_change() { local scope="$1" key="$2" type="$3" current="$4" options="$5" step="$6" next @@ -459,6 +483,16 @@ _fu_setting_change() { bool) if fu_is_true "$current"; then next=no; else next=yes; fi ;; choice) next="$(_fu_next_choice "$current" "$options" "$step")" ;; camera) next="$(_fu_next_camera "$current" "$step")" ;; + path) + printf '\n %s ' "$(fu_msg "Picture or folder:")" + fu_ui_read_line "$current" || return 0 + next="$FU_LINE_RESULT" + # shellcheck disable=SC2088 # typed by the user, expanded here + if [[ -n $next && ${next,,} != none && ! -e ${next/#\~/$HOME} ]]; then + fu_bad "$(fu_msg "Not found: %s" "$next")" + return 0 + fi + ;; esac case "$scope" in @@ -501,6 +535,7 @@ fu_ui_settings() { for spec in "${FU_SETTINGS[@]}"; do IFS='|' read -r scope key type default label choice need only <<< "$spec" [[ $only == lockers ]] && ! fu_pam_lockers_here && continue + [[ $only == ownlock && ( $FU_DESKTOP == plasma || $FU_DESKTOP == gnome ) ]] && continue # A heading has its label where the key would be. [[ $scope == group ]] && label="$key" key='' scopes+=("$scope"); keys+=("$key"); types+=("$type"); defaults+=("$default") @@ -568,6 +603,7 @@ fu_ui_settings() { fi ;; camera) shown="$(_fu_camera_label "${values[i]}")" ;; + path) shown="$(_fu_path_label "${values[i]}")" ;; *) shown="$(fu_value_label "${keys[i]}" "${values[i]}")" ;; esac # Arrows on the selected choice: left and right step through it. diff --git a/tests/test_lockscreen.cpp b/tests/test_lockscreen.cpp new file mode 100644 index 0000000..9a7fff6 --- /dev/null +++ b/tests/test_lockscreen.cpp @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// The password on face-unlock's own lock screen, through real PAM but with +// PAM files of its own (FU_PAM_CONFDIR), so no test ever counts as a wrong +// password for the real account. + +#include "lockscreencontroller.h" + +#include +#include +#include +#include +#include + +#include + +namespace +{ +int failures = 0; + +void check(bool ok, const char *what) +{ + std::printf("%s %s\n", ok ? "ok " : "FAIL", what); + if (!ok) { + ++failures; + } +} + +// Types the password into a fresh controller and waits for the verdict: +// 1 let in, 0 refused, -1 no answer. +int attempt(const QString &stack, const QString &password, QString *message = nullptr) +{ + QTemporaryDir dir; + QFile file(dir.filePath(QStringLiteral("face-unlock-lock"))); + if (!file.open(QIODevice::WriteOnly)) { + return -1; + } + file.write(stack.toUtf8()); + file.close(); + qputenv("FU_PAM_CONFDIR", dir.path().toLocal8Bit()); + + LockScreenController lock; + int verdict = -1; + QObject::connect(&lock, &LockScreenController::authenticated, [&] { + verdict = 1; + QCoreApplication::quit(); + }); + QObject::connect(&lock, &LockScreenController::rejected, [&] { + verdict = 0; + QCoreApplication::quit(); + }); + QTimer::singleShot(5000, &QCoreApplication::quit); + lock.setPassword(password); + lock.submit(); + QCoreApplication::exec(); + if (message) { + *message = lock.message(); + } + check(lock.password().isEmpty(), "the password is gone once it was checked"); + return verdict; +} +} // namespace + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + check(attempt(QStringLiteral("auth required pam_permit.so\n"), QStringLiteral("secret")) == 1, "a stack that says yes unlocks"); + + QString message; + check(attempt(QStringLiteral("auth required pam_deny.so\n"), QStringLiteral("secret"), &message) == 0, "a stack that says no does not"); + check(!message.isEmpty(), "and the screen says so"); + + // Nothing typed: nothing to check, and nothing happens. + LockScreenController empty; + bool answered = false; + QObject::connect(&empty, &LockScreenController::authenticated, [&] { + answered = true; + }); + empty.submit(); + check(!empty.busy() && !answered, "an empty password is not sent"); + + std::printf("\n%s\n", failures ? "SOME CHECKS FAILED" : "all checks passed"); + return failures ? 1 : 0; +} diff --git a/tests/test_wallpaper.cpp b/tests/test_wallpaper.cpp new file mode 100644 index 0000000..b11fd69 --- /dev/null +++ b/tests/test_wallpaper.cpp @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// +// The desktop's picture for face-unlock's own lock screen, from what the +// wallpaper programs say (real output of swaybg 1.2, awww 0.12, swww 0.9, +// hyprpaper 0.7 and 0.8, wpaperd 1.3), and what the setting picks. + +#include "wallpaper.h" + +#include +#include +#include + +#include + +namespace +{ +int failures = 0; + +void check(bool ok, const char *what) +{ + std::printf("%s %s\n", ok ? "ok " : "FAIL", what); + if (!ok) { + ++failures; + } +} + +using Map = QHash; +} // namespace + +int main() +{ + check(Wallpaper::fromSwaybg({QStringLiteral("-i"), QStringLiteral("/w/a.jpg"), QStringLiteral("-m"), QStringLiteral("fill")}) + == Map{{QString(), QStringLiteral("/w/a.jpg")}}, + "swaybg: one picture everywhere"); + check(Wallpaper::fromSwaybg({QStringLiteral("-o"), QStringLiteral("eDP-1"), QStringLiteral("-i"), QStringLiteral("/w/a.jpg"), QStringLiteral("--output=DP-2"), + QStringLiteral("--image=/w/b.png"), QStringLiteral("-o"), QStringLiteral("*"), QStringLiteral("-c"), QStringLiteral("000000")}) + == Map{{QStringLiteral("eDP-1"), QStringLiteral("/w/a.jpg")}, {QStringLiteral("DP-2"), QStringLiteral("/w/b.png")}}, + "swaybg: one per output, a colour is no picture"); + + check(Wallpaper::fromAwww(QStringLiteral(": winit: 1280x742, scale: 1, currently displaying: image: /w/my pic.jpg\n")) + == Map{{QStringLiteral("winit"), QStringLiteral("/w/my pic.jpg")}}, + "awww: with the namespace in front, spaces in the path"); + check(Wallpaper::fromAwww(QStringLiteral("eDP-1: 1920x1080, scale: 1, currently displaying: image: /w/a.jpg\n" + "DP-2: 2560x1440, scale: 1, currently displaying: color: 000000\n")) + == Map{{QStringLiteral("eDP-1"), QStringLiteral("/w/a.jpg")}}, + "swww: a colour is no picture"); + + check(Wallpaper::fromList(QStringLiteral("WAYLAND-1: /w/a.jpg\nDP-2: /w/b.png\n")) + == Map{{QStringLiteral("WAYLAND-1"), QStringLiteral("/w/a.jpg")}, {QStringLiteral("DP-2"), QStringLiteral("/w/b.png")}}, + "hyprpaper 0.8 and wpaperd"); + check(Wallpaper::fromList(QStringLiteral("eDP-1 = /w/a.jpg\n")) == Map{{QStringLiteral("eDP-1"), QStringLiteral("/w/a.jpg")}}, "hyprpaper 0.7"); + check(Wallpaper::fromList(QStringLiteral("no wallpapers active\n")).isEmpty(), "nothing shown, nothing found"); + + QTemporaryDir dir; + QFile a(dir.filePath(QStringLiteral("a.jpg"))); + check(a.open(QIODevice::WriteOnly), "a picture to point at"); + a.close(); + const QUrl url = QUrl::fromLocalFile(a.fileName()); + + check(Wallpaper::forLock(QStringLiteral("none")).isEmpty(), "none is none"); + check(Wallpaper::forLock(a.fileName()) == QHash{{QString(), url}}, "a picture set goes everywhere"); + check(Wallpaper::forLock(dir.path()) == QHash{{QString(), url}}, "a folder set gives one from it"); + check(Wallpaper::forLock(dir.filePath(QStringLiteral("gone.jpg"))).isEmpty(), "a picture that is gone gives none"); + + const QUrl b = QUrl::fromLocalFile(QStringLiteral("/w/b.png")); + const QHash both{{QStringLiteral("eDP-1"), url}, {QString(), b}}; + check(Wallpaper::pick(both, QStringLiteral("eDP-1")) == url, "an output gets its own"); + check(Wallpaper::pick(both, QStringLiteral("DP-2")) == b, "else the one for all"); + check(Wallpaper::pick({{QStringLiteral("eDP-1"), url}}, QStringLiteral("winit")) == url, "else any of the desktop's"); + check(Wallpaper::pick({}, QStringLiteral("eDP-1")).isEmpty(), "and none when there is none"); + + std::printf("\n%s\n", failures ? "SOME CHECKS FAILED" : "all checks passed"); + return failures ? 1 : 0; +}