Possible fix for mate's window switcher.
This commit is contained in:
1 parent
eb5b2038d6
commit
e9a2dc1975
11 files changed
+472
No files matched your search
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package atspi
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNativeMateWindowSwitcherOutsideForeground(t *testing.T) {
|
||||
if os.Getenv("CTHULHU_NATIVE_WINDOW_SWITCHER") != "1" {
|
||||
t.Skip("requires private Xorg/AT-SPI session")
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
adapter := New()
|
||||
if err := adapter.Start(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer adapter.Stop(context.Background())
|
||||
start := func(name string) (io.WriteCloser, string) {
|
||||
command := exec.CommandContext(ctx, "/usr/bin/python3", "../../tests/gtk_window_switcher.py", name)
|
||||
input, err := command.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
output, err := command.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command.Stderr = os.Stderr
|
||||
if err := command.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { input.Close(); command.Process.Kill(); command.Wait() })
|
||||
line, err := bufio.NewReader(output).ReadString('\n')
|
||||
fields := strings.Fields(line)
|
||||
if err != nil || len(fields) != 2 || fields[0] != "ready" {
|
||||
t.Fatalf("fixture readiness: %q, %v", line, err)
|
||||
}
|
||||
return input, fields[1]
|
||||
}
|
||||
switcher, _ := start("marco")
|
||||
foreground, xid := start("editor")
|
||||
if _, err := adapter.CaptureDesktop(ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if output, err := exec.CommandContext(ctx, "xdotool", "windowfocus", "--sync", xid).CombinedOutput(); err != nil {
|
||||
t.Fatalf("focus: %s, %v", output, err)
|
||||
}
|
||||
wait := func(eventType, title string, switcher bool) Event {
|
||||
t.Helper()
|
||||
var last Event
|
||||
count := 0
|
||||
for {
|
||||
select {
|
||||
case event := <-adapter.Events():
|
||||
last = event
|
||||
count++
|
||||
if event.Type == eventType && (event.Source.Name == title || event.Payload == title) {
|
||||
if IsWindowSwitcherSelection(event) != switcher {
|
||||
t.Fatalf("switcher classification: %+v", event)
|
||||
}
|
||||
return event
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("missing %s %q; background-filtered=%d received=%d last=%+v", eventType, title, adapter.backgroundEventsFiltered.Load(), count, last)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(foreground, "select Foreground ready")
|
||||
owned := wait(TextInsertedEvent, "Foreground ready", false)
|
||||
if owned.ForegroundMismatch || !owned.Foreground.Client.Known {
|
||||
t.Fatalf("fixture has no correlated foreground: %+v", owned)
|
||||
}
|
||||
for _, title := range []string{"Editor", "Terminal", "Editor"} {
|
||||
fmt.Fprintln(switcher, "select "+title)
|
||||
event := wait(TextInsertedEvent, title, true)
|
||||
if !event.ForegroundMismatch || event.Foreground != owned.Foreground || event.Source.Focused {
|
||||
t.Fatalf("switcher acquired foreground/native focus: %+v", event)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(switcher, "showing")
|
||||
wait(ShowingStateEvent, "Editor", true)
|
||||
// The provider stays separate from the old foreground after the popup
|
||||
// disappears. Ordinary application events still use native correlation.
|
||||
fmt.Fprintln(switcher, "hide")
|
||||
fmt.Fprintln(foreground, "select Foreground retained")
|
||||
retained := wait(TextInsertedEvent, "Foreground retained", false)
|
||||
if retained.ForegroundMismatch || retained.Window != owned.Window {
|
||||
t.Fatalf("switcher changed foreground ownership: %+v", retained)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user