feat(02-02): implement PPID chain walk + workspace resolution

- ReadPPID parses PPid from /proc/PID/status
- ResolveWorkspace walks PPID chain (max 20 levels) to find terminal workspace
- BuildTerminalWorkspaceMap traverses i3 tree + X11 _NET_WM_PID
- RealX11Resolver wraps xgbutil/ewmh for production use
- Interfaces I3TreeProvider and X11PIDResolver for testability
- Fix unused imports in daemon.go (Rule 3: blocking build)
This commit is contained in:
Pierre Martin
2026-03-23 17:43:58 +01:00
parent 5315e88494
commit a2fb37e2b5
2 changed files with 116 additions and 5 deletions

42
x11_resolver.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"os"
"github.com/BurntSushi/xgb/xproto"
"github.com/BurntSushi/xgbutil"
"github.com/BurntSushi/xgbutil/ewmh"
)
// RealX11Resolver lit _NET_WM_PID via la connexion X11.
type RealX11Resolver struct {
xu *xgbutil.XUtil
}
// NewRealX11Resolver ouvre une connexion X11. Retourne une erreur si $DISPLAY est absent.
func NewRealX11Resolver() (*RealX11Resolver, error) {
if os.Getenv("DISPLAY") == "" {
return nil, fmt.Errorf("DISPLAY not set, cannot resolve X11 PIDs")
}
xu, err := xgbutil.NewConn()
if err != nil {
return nil, fmt.Errorf("X11 connection failed: %w", err)
}
return &RealX11Resolver{xu: xu}, nil
}
func (r *RealX11Resolver) GetPID(windowID int64) (int, error) {
pid, err := ewmh.WmPidGet(r.xu, xproto.Window(windowID))
if err != nil {
return 0, err
}
return int(pid), nil
}
// Close ferme la connexion X11.
func (r *RealX11Resolver) Close() {
if r.xu != nil {
r.xu.Conn().Close()
}
}