Descovered a but on Slint where if the reported sizes differ preferences would not rport. HOpefully fixed. This could probably affect more than just Slint, just happened to catch it there.

This commit is contained in:
Storm Dragon committed 2026-11-01 14:33:50 -05:00
1 parent 7591f65b58
commit d0fdce7285
9 files changed
+90

No files matched your search

+1
View File
@@ -121,6 +121,7 @@ type Adapter struct {
foregroundReader *xorg.ForegroundReader // GLib thread only
foregroundProcesses map[int]bool // GLib thread; provider PID matches for current client
foreground atomic.Pointer[ForegroundState]
preferencesPID atomic.Int64 // Owned preferences helper; zero when closed.
echoFocus atomic.Pointer[echoFocus]
eventListener *C.AtspiEventListener // GLib owner; released with subscriptions.
foregroundChanges chan struct{}
@@ -129,6 +129,14 @@ func (adapter *Adapter) matchForeground(window *C.AtspiAccessible, id ObjectID,
}
return false
}
// Tiling window managers can report GTK's frame and X11's client at
// different origins and sizes. Our own active preferences child is known
// by its launched PID; require X11 to confirm that process is foreground.
if preferences_foreground_matches(state, pid, adapter.preferencesPID.Load()) {
adapter.foregroundWindow = id
adapter.foregroundRecovery = 0
return true
}
component := C.atspi_accessible_get_component_iface(window)
if component == nil {
if check != nil {
+11
View File
@@ -26,6 +26,17 @@ type ForegroundState struct {
Epoch uint64
}
// SetPreferencesProcess scopes geometry-independent foreground matching to the
// UI child launched by this reader. Clear it when that child exits.
func (adapter *Adapter) SetPreferencesProcess(pid int) {
adapter.preferencesPID.Store(int64(pid))
}
func preferences_foreground_matches(client xorg.Foreground, pid int, preferencesPID int64) bool {
return client.Known && client.Window != 0 && preferencesPID > 0 &&
int64(pid) == preferencesPID && client.PID == pid
}
func foregroundWindowMatches(client xorg.Foreground, pid int, bounds Rectangle) bool {
if client.PID > 0 && pid > 0 && client.PID != pid {
return false
+31
View File
@@ -44,6 +44,37 @@ func TestForegroundWindowCorrelationSteamBigPictureScale(t *testing.T) {
}
}
func TestPreferencesForegroundIdentity(t *testing.T) {
// Slint/i3 reports GTK's frame and the X11 client with different borders.
client := xorg.Foreground{Known: true, Window: 45, PID: 123,
X: 2, Y: 18, Width: 1912, Height: 974, OuterX: 2, OuterY: 18, OuterWidth: 1912, OuterHeight: 974}
if foregroundWindowMatches(client, 123, Rectangle{Width: 1916, Height: 994}) {
t.Fatal("fixture must reproduce the reported bounds mismatch")
}
for _, test := range []struct {
name string
client xorg.Foreground
pid int
owned int64
want bool
}{
{"owned foreground helper", client, 123, 123, true},
{"helper closed", client, 123, 0, false},
{"another reader's helper", client, 123, 124, false},
{"other provider", client, 124, 123, false},
{"helper in background", xorg.Foreground{Known: true, Window: 46, PID: 124}, 123, 123, false},
{"missing foreground PID", xorg.Foreground{Known: true, Window: 45}, 123, 123, false},
{"empty workspace", xorg.Foreground{Known: true, PID: 123}, 123, 123, false},
{"unknown foreground", xorg.Foreground{Window: 45, PID: 123}, 123, 123, false},
} {
t.Run(test.name, func(t *testing.T) {
if got := preferences_foreground_matches(test.client, test.pid, test.owned); got != test.want {
t.Fatalf("match = %v, want %v", got, test.want)
}
})
}
}
func TestForegroundMenuPopupCorrelation(t *testing.T) {
client := xorg.Foreground{Known: true, Window: 45, PID: 123}
main := NewObjectID(":1.40", "/main")
@@ -77,6 +77,8 @@ func TestNativePreferencesDropdownEscape(t *testing.T) {
if err := command.Start(); err != nil {
t.Fatal(err)
}
adapter.SetPreferencesProcess(command.Process.Pid)
defer adapter.SetPreferencesProcess(0)
helperDone := make(chan error, 1)
go func() { helperDone <- command.Wait() }()
helperJoined := false
@@ -118,6 +120,9 @@ func TestNativePreferencesDropdownEscape(t *testing.T) {
select {
case event := <-adapter.Events():
t.Logf("%s %s %q capture=%s", event.Type, event.Source.Role, event.Source.Name, event.SnapshotDuration)
if (event.Type == WindowActivatedEvent || event.Type == FocusedStateEvent && event.Detail1 == 1) && event.ForegroundMismatch {
t.Fatalf("owned preferences focus rejected: %+v", event)
}
if event.Type == FocusedStateEvent && event.Detail1 == 1 {
// Match the running reader's browser-mode classification.
// Without these fresh ancestry queries, stale cached focus