xdg-user-dirs im Autostart, kanshi VM-Moduswahl

This commit is contained in:
humocs-man
2026-09-27 20:04:00 +02:00
parent 2e7ea3e5b5
commit 2afe810d73
2 changed files with 51 additions and 12 deletions
+6
View File
@@ -1,6 +1,12 @@
# labwc-Autostart – fluffy-pancake (Noctalia-Zweig) # labwc-Autostart – fluffy-pancake (Noctalia-Zweig)
# Tastatur/Locale stehen in ~/.config/labwc/environment. # Tastatur/Locale stehen in ~/.config/labwc/environment.
# 0. XDG-Standardordner (Dokumente, Bilder, Videos, ...) anlegen bzw.
# bei Locale-Wechsel umbenennen. Laeuft unter labwc sonst nie
# (kein X-Session-Autostart); u.a. braucht Noctalias Wallpaper-Picker
# ~/Bilder. Idempotent - macht bei existierenden Ordnern nichts.
xdg-user-dirs-update >/dev/null 2>&1 || true
# 1. Output-Profile (gedockt/ungedockt). Schreibt die kanshi-Config nur, # 1. Output-Profile (gedockt/ungedockt). Schreibt die kanshi-Config nur,
# wenn sie fehlt oder von kanshi-autoconfig verwaltet wird. # wenn sie fehlt oder von kanshi-autoconfig verwaltet wird.
# Eigene Hand-Edits bleiben unangetastet. # Eigene Hand-Edits bleiben unangetastet.
+45 -12
View File
@@ -10,10 +10,18 @@ Verhalten:
--print Vorschlag auf stdout, schreibt nichts. --print Vorschlag auf stdout, schreibt nichts.
--apply Schreibt (mit Backup *.bak), fragt nicht. --apply Schreibt (mit Backup *.bak), fragt nicht.
--apply-if-managed Schreibt nur, wenn die Config fehlt oder den Marker --apply-if-managed Schreibt nur, wenn die Config fehlt oder den Marker
'# kanshi-autoconfig: managed' enthaelt. '# kanshi-autoconfig: managed' enthaelt. Bei
-> Hand-Edits bleiben unangetastet. Wird vom unveraendertem Output-Set bleibt eine verwaltete Config
unangetastet (Modus-Tweaks inklusive). Wird vom
labwc-Autostart bei jedem Login aufgerufen. labwc-Autostart bei jedem Login aufgerufen.
Moduswahl: Auf echter Hardware der EDID-preferred-Modus (meist nativ =
richtig). In VMs meldet die Firmware oft einen Kleinstmodus als preferred
(QEMU: 1280x800) - dort wird 1920x1080@60 genommen, wenn angeboten, sonst
preferred. Einmal geschrieben bleibt die Config bei gleichem Output-Set
erhalten (Modus-Tweaks inklusive); neu generiert wird nur bei geaendertem
Output-Set (Docking) oder per --apply.
Faellt die Erkennung fehl (kein Wayland, kein wlr-randr), wird eine Faellt die Erkennung fehl (kein Wayland, kein wlr-randr), wird eine
reine Fallback-Config geschrieben, damit nie ein schwarzer Bildschirm reine Fallback-Config geschrieben, damit nie ein schwarzer Bildschirm
ohne Layout dasteht. ohne Layout dasteht.
@@ -30,8 +38,39 @@ MARKER = "# kanshi-autoconfig: managed"
CONFIG_PATH = Path.home() / ".config" / "kanshi" / "config" CONFIG_PATH = Path.home() / ".config" / "kanshi" / "config"
def detect_vm():
"""True, wenn wir virtualisiert laufen (QEMU/Boxes-Test)."""
try:
proc = subprocess.run(
["systemd-detect-virt", "--vm"], capture_output=True, timeout=10
)
except (FileNotFoundError, subprocess.TimeoutExpired):
return False
return proc.returncode == 0
def norm_rate(value):
if isinstance(value, (int, float)) and value > 1000:
return value / 1000 # mHz -> Hz
return value
def choose_mode(modes, current, in_vm):
"""Modus waehlen: VM-Heuristik, sonst preferred, sonst current/erster."""
if in_vm:
for m in modes:
rate = norm_rate(m.get("refresh") or m.get("rate")) or 0
if m.get("width") == 1920 and m.get("height") == 1080 and round(rate) == 60:
return m
for m in modes:
if m.get("preferred"):
return m
return current or (modes[0] if modes else None)
def detect_outputs(): def detect_outputs():
"""Liste von Dicts: name, internal, width, height, rate, scale.""" """Liste von Dicts: name, internal, width, height, rate, scale."""
in_vm = detect_vm()
try: try:
proc = subprocess.run( proc = subprocess.run(
["wlr-randr", "--json"], capture_output=True, text=True, timeout=10 ["wlr-randr", "--json"], capture_output=True, text=True, timeout=10
@@ -51,23 +90,17 @@ def detect_outputs():
if out.get("connected") is False: if out.get("connected") is False:
continue continue
modes = out.get("modes", []) or [] modes = out.get("modes", []) or []
preferred = next((m for m in modes if m.get("preferred")), None)
current = out.get("current_mode") or out.get("mode") current = out.get("current_mode") or out.get("mode")
chosen = preferred or current or (modes[0] if modes else None) chosen = choose_mode(modes, current, in_vm)
if not chosen: if not chosen:
continue continue
width = chosen.get("width")
height = chosen.get("height")
rate = chosen.get("refresh") or chosen.get("rate")
if isinstance(rate, (int, float)) and rate > 1000:
rate = rate / 1000 # mHz -> Hz
outputs.append( outputs.append(
{ {
"name": name, "name": name,
"internal": name.startswith(("eDP-", "LVDS-", "DSI-")), "internal": name.startswith(("eDP-", "LVDS-", "DSI-")),
"width": width, "width": chosen.get("width"),
"height": height, "height": chosen.get("height"),
"rate": rate, "rate": norm_rate(chosen.get("refresh") or chosen.get("rate")),
"scale": out.get("scale", 1) or 1, "scale": out.get("scale", 1) or 1,
} }
) )