diff --git a/README.md b/README.md index 925f4d5..b9099ec 100644 --- a/README.md +++ b/README.md @@ -1,225 +1,90 @@ -# Korin Timer (Linux) +# Korin Timer -Eigenständige Neu-Implementierung eines 2-Step-Title-Switching-Timers als -Overlay (kein Reverse Engineering, keine Codeübernahme aus proprietärer -Software - nur nach Funktionsbeschreibung neu gebaut). +Korin Timer ist ein transparentes Linux-Overlay für Elsword. Es zeigt die +Cooldowns deiner Titel an und lässt sich komplett über globale Hotkeys +bedienen. -## Funktionsprinzip +## Schnellstart -- **Ohne Vor-Aktivierung** (Normalfall): Hotkey drücken startet den - Cooldown-Timer direkt, ein einziger Druck reicht. -- **Mit Vor-Aktivierung** (optional, pro Titel im Settings-Fenster - einstellbar): eine zusätzliche Taste/Kombination - z.B. eine Taste, die - im Spiel ohnehin gedrückt wird - die den Titel in Standby versetzt - (gepulster Rahmen zeigt das an). Die Haupttaste startet dann, *ein - einziges Mal gedrückt*, den Cooldown; sie allein (ohne vorherige - Vor-Aktivierung) macht in diesem Modus nichts. -- **Standby-Timeout** (optional, pro Titel, 0 = aus, wirkt nur im - Vor-Aktivierungs-Modus): springt automatisch zurück auf Idle, wenn die - Haupttaste nicht innerhalb der eingestellten Sekundenzahl nach der - Vor-Aktivierung gedrückt wird - inklusive Countdown-Anzeige im Overlay, - solange er läuft. -- **Neu triggerbar** (Checkbox pro Titel, aus per Default): normalerweise - wird die Haupttaste während laufendem Cooldown ignoriert. Mit dieser - Option gedrückt startet sie den Cooldown stattdessen neu (volle Dauer ab - dem Zeitpunkt des Drucks) - für Buffs, die man aktiv auffrischen will. -- **Dogma-Modus** (`dogma_mode: true` in der Config, Schalter im - Settings-Fenster): solange irgendein Cooldown läuft, werden Hotkeys für - *andere* Titel ignoriert. Aus, wenn alle Titel unabhängig voneinander - gleichzeitig laufen sollen. -- **Verschieben**: `Strg+Alt` gedrückt halten + mit der linken Maustaste aufs - Overlay klicken und ziehen. Die neue Position wird beim Loslassen in der - Config-Datei des aktiven Charakter-Profils (`overlay.x`/`overlay.y`, - siehe unten) gespeichert und bleibt über Neustarts erhalten. Funktioniert - wie die Hotkeys über - rohes `evdev` (siehe unten) - das Overlay ist click-through, bekommt also - nie normale Mausereignisse vom Fenstersystem. (Nicht nur `Alt`, weil das - mit GNOMEs eigenem "Alt+Drag verschiebt jedes Fenster"-Standardverhalten - kollidiert.) +1. Öffne im Repository den Bereich **Releases** und lade + `Korin-Timer.AppImage` herunter. +2. Mache die Datei ausführbar und starte sie: -## Warum XWayland/EWMH statt Layer-Shell + ```bash + chmod +x Korin-Timer.AppImage + ./Korin-Timer.AppImage + ``` -Erster Ansatz war `gtk4-layer-shell` (`wlr-layer-shell`-Protokoll) - das -funktioniert aber nur auf wlroots-Compositors (Sway, Hyprland). **GNOME/Mutter -implementiert dieses Protokoll nicht.** Getestet gegen eine echte GNOME- -Wayland-Session: die Layer-Shell-Initialisierung schlug fehl -(`compositor does not support the Layer Shell protocol`). +3. Beim ersten Start öffnen sich Overlay und Einstellungsfenster. Lege dort + deine Titel, Hotkeys und Cooldowns an und klicke auf **Speichern**. -Stattdessen läuft das Overlay über XWayland als normales X11-Fenster mit -EWMH-Hints (`_NET_WM_STATE_ABOVE`, `_NET_WM_STATE_SKIP_TASKBAR`, Klick-durch -via XShape-Extension). Das funktioniert auf GNOME, KDE *und* wlroots- -Compositors, weil XWayland praktisch überall mitläuft. Einzige Falle dabei: -Mutter respektiert `_NET_WM_STATE_ABOVE` nur, wenn es per ClientMessage -**nach** dem Mapping des Fensters gesendet wird (nicht als Property davor, -im Gegensatz zu SKIP_TASKBAR/SKIP_PAGER) - siehe `x11_overlay.raise_above()`. - -Das umgeht auch das ursprüngliche Wine-Problem: statt eines transparenten -DirectX-Fensters unter Wine (das dort schwarz statt durchsichtig gerendert -wurde) ist das hier ein natives GTK4-Fenster mit echter RGBA-Transparenz. - -## Charakter-Profile - -Jeder Charakter hat eine eigene, vollständige Config unter -`~/.config/titletimer/profiles/.json` (Titel, Hotkeys, Cooldowns, -Dogma-Modus, Overlay-Position - alles). Im Einstellungsfenster oben eine -Zeile "Charakter:" mit Dropdown + `Neu`/`Duplizieren`/`Umbenennen`/`Löschen`: - -- **Neu**: legt ein Profil mit den Beispiel-Titeln aus `config.example.json` - an, das direkt umbenannt/umgebaut werden kann. -- **Duplizieren**: kopiert das aktuell aktive Profil unter neuem Namen - - praktisch für einen zweiten Charakter mit ähnlichem Titel-Setup. -- **Umbenennen** / **Löschen**: benennt die Profil-Datei um bzw. entfernt - sie (der letzte verbleibende Charakter lässt sich nicht löschen). - -Profil-Wechsel im Dropdown lädt sofort das gewählte Profil - laufendes -Overlay übernimmt es ohne Neustart, wie beim normalen "Speichern". Nicht -gespeicherte Änderungen am vorherigen Profil gehen beim Wechsel verloren -(genau wie beim Schließen des Fensters ohne zu speichern). Das zuletzt -aktive Profil wird gemerkt (`~/.config/titletimer/last_profile.txt`) und -beim nächsten Start automatisch wieder geladen. - -Bereits vorhandene Configs aus einer Version vor diesem Feature -(`~/.config/titletimer/config.json`) werden beim ersten Start automatisch -zu einem Profil namens "Default" migriert (per Umbenennen in -`profiles/Default.json`) - kein manueller Schritt nötig. - -`--config ` umgeht das Profil-System komplett und lädt direkt eine -beliebige Datei (z.B. zum Testen) - dann ist die Profil-Zeile im -Einstellungsfenster ausgeblendet, da es kein Profil-Konzept dafür gibt. - -## Setup (aus dem Quellcode, ohne AppImage) - -Falls du nicht das AppImage nutzt, sondern direkt aus `src/` starten willst, -brauchst du GTK4/PyGObject/evdev/xlib systemweit oder per `nix-shell` -(siehe `shell.nix` im Repo - relevant auf NixOS, wo es kein systemweites -`python3`/GTK4 auf dem `PATH` gibt): +Die App benötigt Leserechte auf die Eingabegeräte, damit Hotkeys außerhalb +des Fensters funktionieren. Führe einmal aus und melde dich anschließend +vollständig ab und wieder an: ```bash -# Arch/CachyOS -sudo pacman -S python-gobject gtk4 gtk4-layer-shell python-evdev python-xlib -# NixOS -nix-shell # nutzt die shell.nix im Repo-Root - -# Nutzer muss in der input-Gruppe sein, damit evdev /dev/input lesen darf sudo usermod -aG input "$USER" -# danach ab- und wieder anmelden (Gruppenmitgliedschaft wird erst beim -# nächsten Login aktiv) ``` -Config: Falls beim ersten Start noch kein Charakter-Profil existiert -(`~/.config/titletimer/profiles/`, siehe oben), wird automatisch eines -namens "Default" aus der eingebauten `config.example.json` angelegt (auch -im AppImage - keine separate Datei nötig). Danach anpassen - entweder -per Hand: +## Bedienung -```bash -$EDITOR ~/.config/titletimer/profiles/Default.json -# hotkey ist entweder ein einzelner evdev-Keycode-String ("KEY_F1") oder -# eine Liste für eine Tastenkombination (["KEY_LEFTCTRL", "KEY_F1"]) - alle -# gelisteten Tasten muessen gleichzeitig gehalten werden. Keycode-Namen: -# python3 -c "from evdev import ecodes; print([k for k in dir(ecodes) if k.startswith('KEY_')])" -``` +- Drücke den Hotkey eines Titels, um seinen Cooldown zu starten. +- Optional kann ein Titel erst per Vor-Aktivierungs-Hotkey in den Standby + wechseln. Erst der normale Hotkey startet dann den Cooldown. +- Mit **Neu triggerbar** startet derselbe Hotkey einen bereits laufenden + Cooldown erneut. +- Im Dogma-Modus ist immer nur ein Titel gleichzeitig aktiv. +- Verschiebe das Overlay mit **Strg + Alt + linker Maustaste ziehen**. + Die Position wird im aktiven Profil gespeichert. -oder über das eingebaute Einstellungsfenster (Titel hinzufügen/entfernen, -Hotkeys per Klick-und-Tastendruck erfassen - auch Mehrfachkombinationen -wie Strg+F1 -, Cooldowns, Farben, optionales Icon pro Titel, Dogma-Modus, -Anker/Rand/Skalierung, sowie die per Alt+Drag gesetzte Position -zurücksetzen) - das öffnet sich automatisch mit dem Overlay zusammen. -"Speichern" wirkt sofort auf das laufende Overlay, kein Neustart nötig -(ein aktuell laufender Cooldown wird dabei zurückgesetzt). +Das Einstellungsfenster muss geöffnet bleiben: Sein Schließen beendet auch +das rahmenlose, klickdurchlässige Overlay. -Starten (aus dem Projektverzeichnis): +## Profile + +Jeder Charakter erhält ein eigenes Profil unter +`~/.config/titletimer/profiles/`. Über das Dropdown im Einstellungsfenster +kannst du Profile anlegen, duplizieren, umbenennen, wechseln und löschen. +Ein Wechsel übernimmt die neue Konfiguration sofort; nicht gespeicherte +Änderungen des vorherigen Profils gehen dabei verloren. + +## Neues Release erstellen + +Jeder Push auf `main` startet automatisch einen Gitea-Actions-Build. Nach +einem erfolgreichen Lauf: + +1. Öffne **Actions** und den aktuellen erfolgreichen Build. +2. Lade das Artefakt `Korin-Timer.AppImage` herunter. +3. Öffne **Releases** → **New Release**. +4. Erstelle einen Tag, etwa `v0.1.0`, und hänge die AppImage-Datei an. +5. Veröffentliche das Release. + +Das Actions-Artefakt wird nach 30 Tagen gelöscht; der Release-Anhang bleibt +verfügbar. + +## Aus dem Quellcode starten + +Für Entwicklung brauchst du GTK4, PyGObject, `evdev` und `python-xlib`. +Danach startest du die Anwendung aus dem Projektverzeichnis mit: ```bash PYTHONPATH=src python3 -m titletimer ``` -Startet Overlay **und** Einstellungsfenster zusammen. Das Einstellungs- -fenster zu schließen beendet die ganze App (auch das Overlay) - das ist -aktuell der einzige Weg, das rahmenlose, click-through Overlay wieder zu -stoppen. Nur das Einstellungsfenster ohne Overlay: +Nur das Einstellungsfenster öffnest du mit: ```bash PYTHONPATH=src python3 -m titletimer --settings -# oder: ./Korin-Timer.AppImage --settings ``` -## AppImage bauen (voll gebündelt, keine Systemabhängigkeiten) +## AppImage lokal bauen + +Der CI-Workflow ist der empfohlene Buildweg. In einer Debian-artigen +Umgebung kann das AppImage auch lokal gebaut werden: ```bash ./packaging/build-appimage.sh ``` -Das AppImage ist **vollständig in sich geschlossen**: eigener -Python-Interpreter + Standardbibliothek, GTK4, `gtk4-layer-shell`, -PyGObject, pycairo, `evdev`, `python-xlib` - und deren *gesamter* -transitiver Shared-Library-Baum (~78 `.so`-Dateien), inklusive `ld.so` und -`libc` selbst. Nichts davon kommt vom Zielsystem. - -Warum so radikal gebündelt: Auf NixOS gibt es kein FHS-`/usr/bin/python3` -und kein System-GTK4 auf dem `PATH` - der ursprüngliche Ansatz ("GTK4 ist -auf so gut wie jedem Desktop schon da") war für NixOS schlicht falsch. -`packaging/bundle-runtime.sh` sammelt den kompletten Abhängigkeitsbaum per -rekursivem `ldd` über Python3-Binary, PyGObject-Extensions -(`_gi`, `_gi_cairo`), pycairo, `libgtk-4.so.1` und -`libgtk4-layer-shell.so.0` ein. `AppRun` ruft danach nicht mehr `python3` -über `PATH` auf, sondern das gebündelte `ld-linux-x86-64.so.2` direkt mit -`--library-path` auf das gebündelte `lib/`-Verzeichnis, plus -`PYTHONHOME`/`PYTHONPATH`/`GI_TYPELIB_PATH` auf die gebündelten Pfade. -Damit entfällt auch die vorherige Sorge um `evdev`s Python-ABI-Tag -(CPython-Minor-Version-Mismatch) komplett - es ist ja unser eigener -Interpreter, keiner vom Zielsystem. - -Größe: ca. 28 MB (statt vorher 1,4 MB) - der Preis für echte -Systemunabhängigkeit. - -Der Build erzeugt `build/Korin-Timer.AppImage`. Das Artefakt gehört nicht -zum Repository und wird nicht eingecheckt. - -```bash -chmod +x build/Korin-Timer.AppImage # nur falls Ausführbarkeit fehlt -./build/Korin-Timer.AppImage -``` - -Einzige verbleibende Voraussetzung auf dem Zielsystem: die `input`-Gruppen- -Mitgliedschaft für `evdev` (s.o.) - das kann eine AppImage-Datei nicht -selbst mitbringen, das ist eine Kernel-Berechtigung. - -**Wie das `.AppImage` selbst gebaut wurde**: `appimagetool`s eigene -AppImage-Datei ist selbst eine statisch-PIE-gelinkte ELF-Datei ohne -`PT_INTERP` - in meiner Sandbox (ein eingeschränkter Podman-Container) -ließ sich dieses Binärformat gar nicht ausführen (`execve` schlug mit -ENOENT fehl, unabhängig von FUSE). Deshalb baut das Skript jetzt -automatisch alternativ von Hand: die separate `runtime-x86_64`-Datei (der -reine ELF-Loader-Stub) direkt mit `mksquashfs AppDir` zusammen-`cat`en - -exakt das, was `appimagetool` intern auch tut. Auf deinem echten System -sollte `appimagetool` normal durchlaufen; falls nicht, greift derselbe -Fallback automatisch. - -## Was tatsächlich getestet wurde - -- **Config-Loader + State-Machine** (2-Step-Umschaltung, Dogma-Mutex, - Cooldown-Expiry): per Skript ausgeführt und alle Assertions verifiziert. -- **GTK4/GdkX11/evdev-Imports**: installiert und erfolgreich importiert. -- **Overlay live gegen deine echte laufende GNOME-Wayland-Session getestet** - (nicht nur eine isolierte Testumgebung): Fenster wird erzeugt, `evdev` - findet deine echten Tastatur-Devices, und per `xprop` verifiziert: - `_NET_WM_STATE_ABOVE`, `_NET_WM_STATE_SKIP_TASKBAR`, - `_NET_WM_STATE_SKIP_PAGER` und `_NET_WM_WINDOW_TYPE_UTILITY` sind - tatsächlich gesetzt, Fenster läuft ohne Exceptions. -- **AppImage-Datei selbst**: ELF-Header und eingebettetes SquashFS per - `unsquashfs` an der korrekten Byte-Offset-Grenze extrahiert und geprüft - (`AppRun`, `.desktop`-Datei lesbar) - der Aufbau der Datei ist also - korrekt. **Nicht** verifiziert: das tatsächliche Doppelklick-Starten der - `.AppImage`, weil meine Sandbox dieses Binärformat generell nicht - ausführen kann (s.o.) - das musst du einmal bei dir bestätigen. -- **Nicht** verifiziert: wie es *visuell* aussieht (Puls-Rahmen-Optik, - Transparenz-Feinschliff) und ob es zuverlässig über einem Vollbild-Spiel - liegt - das kannst nur du im echten Gameplay beurteilen. - -## Aktueller Funktionsumfang - -Nur der 2-Step Title-Switching-Timer + Dogma-Mode ist implementiert (siehe -Absprache). Flow-System (Pet-Tracking), Horary Loop Timer, Custom/Foto-Timer -und Post-it-Labels aus dem Original sind bewusst noch nicht gebaut - können -bei Bedarf nachgezogen werden. +Das Ergebnis liegt anschließend unter `build/Korin-Timer.AppImage` und wird +nicht ins Repository eingecheckt.