GUI: Power-Menu (Beenden, Neustarten, Herunterfahren)

Haengt vor Reboot/Shutdown alle Datentraeger sauber aus. Verwendet
systemctl mit Fallback auf reboot/poweroff/shutdown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-10-22 12:48:42 +02:00
co-authored by Claude Opus 4.8
parent cbd7e74b1c
commit 7282153c27
3 changed files with 46 additions and 1 deletions
+6
View File
@@ -6,6 +6,12 @@ Versionierung nach [SemVer](https://semver.org/lang/de/).
## [Unreleased] ## [Unreleased]
### Added
- GUI: Einträge „Beenden", „Neustarten" und „Herunterfahren" (hängt vorher
alle Datenträger sauber aus).
## [0.1.1] - 2026-10-22
### Added ### Added
- GUI (tkinter) zum Auflisten, Mounten und Aushängen von Partitionen. - GUI (tkinter) zum Auflisten, Mounten und Aushängen von Partitionen.
- Linux-Backend: Passwort leeren, neues SHA-512-Passwort setzen, Konto entsperren. - Linux-Backend: Passwort leeren, neues SHA-512-Passwort setzen, Konto entsperren.
+39
View File
@@ -12,6 +12,8 @@ Benoetigt root und ein X-Display (laeuft im Live-System automatisch).
from __future__ import annotations from __future__ import annotations
import os import os
import shutil
import subprocess
import sys import sys
import threading import threading
import tkinter as tk import tkinter as tk
@@ -81,6 +83,15 @@ class App(tk.Tk):
self.log = tk.Text(logf, height=8, state="disabled", wrap="word") self.log = tk.Text(logf, height=8, state="disabled", wrap="word")
self.log.pack(fill="both", expand=True, padx=4, pady=4) self.log.pack(fill="both", expand=True, padx=4, pady=4)
power = ttk.Frame(self)
power.pack(fill="x", **pad)
ttk.Button(power, text="Herunterfahren",
command=self.do_shutdown).pack(side="right", padx=4)
ttk.Button(power, text="Neustarten",
command=self.do_reboot).pack(side="right", padx=4)
ttk.Button(power, text="Beenden",
command=self._on_close).pack(side="right", padx=4)
self._log("PC-Unlocker gestartet. Datentraeger auswaehlen und mounten.") self._log("PC-Unlocker gestartet. Datentraeger auswaehlen und mounten.")
def _log(self, msg: str) -> None: def _log(self, msg: str) -> None:
@@ -298,6 +309,34 @@ class App(tk.Tk):
disks.unmount_all(self.parts) disks.unmount_all(self.parts)
self.destroy() self.destroy()
def _power(self, action: str, label: str, cmds: list[list[str]]) -> None:
"""Alles aushaengen und System herunterfahren/neustarten."""
if not messagebox.askyesno("Bestaetigen", f"System jetzt {label}?"):
return
disks.unmount_all(self.parts)
self._log(f"Alle Datentraeger ausgehaengt. System wird {label}...")
self.update_idletasks()
for cmd in cmds:
if shutil.which(cmd[0]) is None:
continue
try:
subprocess.Popen(cmd)
self.destroy()
return
except Exception: # noqa: BLE001
continue
messagebox.showerror(
"Fehler", f"Konnte nicht {label} (kein passendes Kommando gefunden).")
def do_reboot(self) -> None:
self._power("reboot", "neu starten",
[["systemctl", "reboot"], ["reboot"]])
def do_shutdown(self) -> None:
self._power("poweroff", "herunterfahren",
[["systemctl", "poweroff"], ["poweroff"],
["shutdown", "-h", "now"]])
def main() -> int: def main() -> int:
if os.geteuid() != 0: if os.geteuid() != 0:
+1 -1
View File
@@ -1,3 +1,3 @@
"""PC-Unlocker: Offline-Recovery fuer lokale Linux- und Windows-Konten.""" """PC-Unlocker: Offline-Recovery fuer lokale Linux- und Windows-Konten."""
__version__ = "0.1.0" __version__ = "0.1.1"