107 lines
4.2 KiB
Go
107 lines
4.2 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
)
|
|
|
|
func ownerEvent(eventType, bus, window, focus string) atspi.Event {
|
|
event := atspi.NewEvent(eventType, atspi.Snapshot{BusName: bus, Path: focus})
|
|
event.Window = atspi.NewObjectID(bus, window)
|
|
return event
|
|
}
|
|
|
|
func TestWindowOwnerKeepsWindowAndFocusIndependent(t *testing.T) {
|
|
var owner windowOwner
|
|
activation := ownerEvent(atspi.WindowActivatedEvent, ":1.40", "/window", "/button")
|
|
if owner.activate(activation) {
|
|
t.Fatal("first activation was treated as duplicate")
|
|
}
|
|
if owner.window != activation.Window || owner.focus != activation.Source.ID() || owner.applicationBus != ":1.40" {
|
|
t.Fatalf("owner = %#v", owner)
|
|
}
|
|
|
|
focus := ownerEvent(atspi.FocusedStateEvent, ":1.40", "/window", "/entry")
|
|
if !owner.follow(focus) || owner.window != activation.Window || owner.focus != focus.Source.ID() {
|
|
t.Fatalf("focus did not remain in active window: %#v", owner)
|
|
}
|
|
if !owner.activate(activation) || owner.focus != focus.Source.ID() {
|
|
t.Fatal("duplicate activation replaced descendant focus")
|
|
}
|
|
}
|
|
|
|
func TestFocusBeforeActivationStillAdmitsFirstWindowActivation(t *testing.T) {
|
|
var owner windowOwner
|
|
focus := ownerEvent(atspi.FocusedStateEvent, ":1.40", "/window", "/entry")
|
|
focus.Source.Focused = true
|
|
if !owner.follow(focus) || owner.activated {
|
|
t.Fatalf("focus-first ownership = %#v", owner)
|
|
}
|
|
activation := ownerEvent(atspi.WindowActivatedEvent, ":1.40", "/window", "/window")
|
|
if owner.activate(activation) || owner.focus != focus.Source.ID() {
|
|
t.Fatalf("first activation lost focus or was skipped: %#v", owner)
|
|
}
|
|
if !owner.activate(activation) {
|
|
t.Fatal("repeated activation was not suppressed")
|
|
}
|
|
}
|
|
|
|
func TestWindowOwnerRejectsBackgroundFocusAndUnrelatedLifecycle(t *testing.T) {
|
|
var owner windowOwner
|
|
owner.activate(ownerEvent(atspi.WindowActivatedEvent, ":1.40", "/window", "/button"))
|
|
if owner.follow(ownerEvent(atspi.FocusedStateEvent, ":1.41", "/other", "/entry")) {
|
|
t.Fatal("background focus changed ownership")
|
|
}
|
|
if owner.end(ownerEvent(atspi.WindowDestroyedEvent, ":1.41", "/other", "/other"), false) {
|
|
t.Fatal("unrelated destruction cleared ownership")
|
|
}
|
|
if !owner.window.Valid() {
|
|
t.Fatal("unrelated lifecycle cleared active window")
|
|
}
|
|
}
|
|
|
|
func TestWindowOwnerHandlesTransientDeactivationAndDestruction(t *testing.T) {
|
|
var owner windowOwner
|
|
activation := ownerEvent(atspi.WindowActivatedEvent, ":1.40", "/window", "/button")
|
|
owner.activate(activation)
|
|
deactivation := ownerEvent(atspi.WindowDeactivatedEvent, ":1.40", "/window", "/window")
|
|
deactivation.Source.StatesKnown = true
|
|
deactivation.Source.Active = true
|
|
if owner.end(deactivation, false) || !owner.window.Valid() {
|
|
t.Fatal("active key-grab deactivation cleared ownership")
|
|
}
|
|
deactivation.Source.StatesKnown = false
|
|
deactivation.Source.Active = false
|
|
if owner.end(deactivation, true) || !owner.window.Valid() {
|
|
t.Fatal("consumed-command deactivation cleared ownership")
|
|
}
|
|
destruction := ownerEvent(atspi.WindowDestroyedEvent, ":1.40", "/window", "/window")
|
|
if !owner.end(destruction, true) || owner.window.Valid() || owner.focus.Valid() || owner.applicationBus != "" {
|
|
t.Fatalf("destruction did not clear ownership: %#v", owner)
|
|
}
|
|
}
|
|
|
|
func TestWindowOwnerClearsDefunctFocusWithoutDroppingWindow(t *testing.T) {
|
|
var owner windowOwner
|
|
activation := ownerEvent(atspi.WindowActivatedEvent, ":1.40", "/window", "/button")
|
|
owner.activate(activation)
|
|
defunct := atspi.NewEvent(atspi.DefunctStateEvent, activation.Source)
|
|
defunct.Detail1 = 1
|
|
windowEnded, focusEnded := owner.defunct(defunct)
|
|
if windowEnded || !focusEnded || !owner.window.Valid() || owner.focus.Valid() {
|
|
t.Fatalf("defunct focus result = windowEnded:%v focusEnded:%v owner:%#v", windowEnded, focusEnded, owner)
|
|
}
|
|
|
|
windowDefunct := atspi.NewEvent(atspi.DefunctStateEvent, atspi.Snapshot{BusName: ":1.40", Path: "/window"})
|
|
windowDefunct.Detail1 = 1
|
|
windowEnded, focusEnded = owner.defunct(windowDefunct)
|
|
if !windowEnded || !focusEnded || owner.window.Valid() || owner.applicationBus != "" {
|
|
t.Fatalf("defunct window result = windowEnded:%v focusEnded:%v owner:%#v", windowEnded, focusEnded, owner)
|
|
}
|
|
}
|