7fdcae5d14
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
44 lines
1.3 KiB
Go
44 lines
1.3 KiB
Go
//go:build linux
|
|
|
|
package enforce
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/jezek/xgbutil"
|
|
"github.com/jezek/xgbutil/ewmh"
|
|
"github.com/jezek/xgbutil/icccm"
|
|
)
|
|
|
|
// NewGuard returns the real X11 window-minimize guard.
|
|
func NewGuard() Guard { return x11Guard{} }
|
|
|
|
type x11Guard struct{}
|
|
|
|
// MinimizeActive iconifies the currently-focused window by sending an ICCCM
|
|
// WM_CHANGE_STATE -> IconicState client message to the root window. It opens a
|
|
// short-lived X connection per call: enforcement fires at most once per drift
|
|
// observation (which is debounce-gated upstream), so there is no shared
|
|
// connection or event loop to manage, and nothing to race on shutdown. Any X
|
|
// failure is returned for the caller to log; the caller never blocks on it.
|
|
func (x11Guard) MinimizeActive(_ context.Context) error {
|
|
X, err := xgbutil.NewConn()
|
|
if err != nil {
|
|
return fmt.Errorf("enforce: cannot connect to X server: %w", err)
|
|
}
|
|
defer X.Conn().Close()
|
|
|
|
active, err := ewmh.ActiveWindowGet(X)
|
|
if err != nil {
|
|
return fmt.Errorf("enforce: no active window: %w", err)
|
|
}
|
|
if active == 0 {
|
|
return nil // nothing focused; nothing to minimize
|
|
}
|
|
if err := ewmh.ClientEvent(X, active, "WM_CHANGE_STATE", icccm.StateIconic); err != nil {
|
|
return fmt.Errorf("enforce: minimize request failed: %w", err)
|
|
}
|
|
return nil
|
|
}
|