159 lines
6.5 KiB
Go
159 lines
6.5 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
package atspi
|
|
|
|
import (
|
|
"git.stormux.org/storm/cthulhu/internal/platform/xorg"
|
|
"testing"
|
|
)
|
|
|
|
func TestForegroundWindowCorrelation(t *testing.T) {
|
|
client := xorg.Foreground{Known: true, Window: 45, PID: 123, X: 10, Y: 30, Width: 400, Height: 300, OuterX: 8, OuterY: 5, OuterWidth: 404, OuterHeight: 327}
|
|
for _, test := range []struct {
|
|
name string
|
|
pid int
|
|
bounds Rectangle
|
|
want bool
|
|
}{
|
|
{"client", 123, Rectangle{10, 30, 400, 300}, true},
|
|
{"decorated", 123, Rectangle{8, 5, 404, 327}, true},
|
|
{"other process", 124, Rectangle{10, 30, 400, 300}, false},
|
|
{"same process other window", 123, Rectangle{420, 30, 400, 300}, false},
|
|
{"same process scaled window", 123, Rectangle{10, 30, 200, 150}, true},
|
|
{"scaled window shifted", 123, Rectangle{11, 30, 200, 150}, false},
|
|
{"scaled window wrong aspect", 123, Rectangle{10, 30, 200, 120}, false},
|
|
{"scaled window too small", 123, Rectangle{10, 30, 100, 75}, false},
|
|
{"other process scaled window", 124, Rectangle{10, 30, 200, 150}, false},
|
|
{"dialog", 123, Rectangle{40, 50, 200, 100}, false},
|
|
{"missing bounds", 123, Rectangle{}, false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := foregroundWindowMatches(client, test.pid, test.bounds); got != test.want {
|
|
t.Fatalf("match = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestForegroundWindowCorrelationSteamBigPictureScale(t *testing.T) {
|
|
client := xorg.Foreground{Known: true, Window: 83886130, PID: 111, X: 0, Y: 0, Width: 1920, Height: 1080,
|
|
OuterX: 0, OuterY: 0, OuterWidth: 1920, OuterHeight: 1080}
|
|
if !foregroundWindowMatches(client, 111, Rectangle{X: 0, Y: 0, Width: 1353, Height: 761}) {
|
|
t.Fatal("same-process logical-pixel frame did not match X11 foreground")
|
|
}
|
|
}
|
|
|
|
func TestForegroundReparentedFrameCorrelation(t *testing.T) {
|
|
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,
|
|
FrameX: 0, FrameY: 0, FrameWidth: 1916, FrameHeight: 994}
|
|
for _, test := range []struct {
|
|
name string
|
|
pid int
|
|
bounds Rectangle
|
|
want bool
|
|
}{
|
|
{"actual WM frame", 123, Rectangle{0, 0, 1916, 994}, true},
|
|
{"client still accepted", 123, Rectangle{2, 18, 1912, 974}, true},
|
|
{"other process same frame size", 124, Rectangle{0, 0, 1916, 994}, false},
|
|
{"same process other frame", 123, Rectangle{1920, 0, 1916, 994}, false},
|
|
{"same process smaller dialog", 123, Rectangle{20, 30, 400, 300}, false},
|
|
{"scaled frame same origin", 123, Rectangle{0, 0, 958, 497}, true},
|
|
{"scaled frame wrong origin", 123, Rectangle{1, 0, 958, 497}, false},
|
|
{"scaled frame wrong aspect", 123, Rectangle{0, 0, 958, 400}, false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := foregroundWindowMatches(client, test.pid, test.bounds); got != test.want {
|
|
t.Fatalf("match = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
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")
|
|
popup := NewObjectID(":1.40", "/popup")
|
|
for _, test := range []struct {
|
|
name string
|
|
client xorg.Foreground
|
|
main ObjectID
|
|
popup ObjectID
|
|
pid int
|
|
menu bool
|
|
want bool
|
|
}{
|
|
{"active menu in foreground application", client, main, popup, 123, true, true},
|
|
{"inactive menu", client, main, popup, 123, false, false},
|
|
{"other application", client, main, NewObjectID(":1.41", "/popup"), 123, true, false},
|
|
{"other process", client, main, popup, 124, true, false},
|
|
{"ordinary sibling window", client, main, popup, 123, false, false},
|
|
{"no foreground client", xorg.Foreground{Known: true}, main, popup, 123, true, false},
|
|
{"no owned main window", client, ObjectID{}, popup, 123, true, false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := foregroundMenuPopupMatches(test.client, test.main, test.popup, test.pid, test.menu); got != test.want {
|
|
t.Fatalf("match = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestForegroundWindowReplacement(t *testing.T) {
|
|
previous := NewObjectID(":1.40", "/gtk_frame")
|
|
candidate := NewObjectID(":1.40", "/gecko_frame")
|
|
sibling := NewObjectID(":1.40", "/other_window")
|
|
for _, test := range []struct {
|
|
name string
|
|
previous, candidate ObjectID
|
|
windows []ObjectID
|
|
want bool
|
|
}{
|
|
{"replaced application root", previous, candidate, []ObjectID{candidate, sibling}, true},
|
|
{"existing sibling cannot take ownership", previous, candidate, []ObjectID{previous, candidate}, false},
|
|
{"unregistered candidate", previous, candidate, []ObjectID{sibling}, false},
|
|
{"missing window list", previous, candidate, nil, false},
|
|
{"other provider", previous, NewObjectID(":1.41", "/frame"), []ObjectID{NewObjectID(":1.41", "/frame")}, false},
|
|
{"no previous owner", ObjectID{}, candidate, []ObjectID{candidate}, false},
|
|
{"unchanged owner", candidate, candidate, []ObjectID{candidate}, false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := foregroundWindowReplaced(test.previous, test.candidate, test.windows); got != test.want {
|
|
t.Fatalf("replacement = %v, want %v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|