56 lines
2.3 KiB
Go
56 lines
2.3 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package atspi
|
|
|
|
import (
|
|
"math"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/platform/xorg"
|
|
)
|
|
|
|
// Epoch changes with the foreground client, including departure to an empty
|
|
// workspace. Moving/resizing the same client does not reset reading ownership.
|
|
type ForegroundState struct {
|
|
Client xorg.Foreground
|
|
Epoch uint64
|
|
}
|
|
|
|
func foregroundWindowMatches(client xorg.Foreground, pid int, bounds Rectangle) bool {
|
|
if client.PID > 0 && pid > 0 && client.PID != pid {
|
|
return false
|
|
}
|
|
if !bounds.Valid() || client.Width <= 0 || client.Height <= 0 {
|
|
return false
|
|
}
|
|
inner := Rectangle{X: int32(client.X), Y: int32(client.Y), Width: int32(client.Width), Height: int32(client.Height)}
|
|
outer := Rectangle{X: int32(client.OuterX), Y: int32(client.OuterY), Width: int32(client.OuterWidth), Height: int32(client.OuterHeight)}
|
|
return bounds == inner || bounds == outer ||
|
|
scaledWindowMatches(bounds, inner) || scaledWindowMatches(bounds, outer)
|
|
}
|
|
|
|
// Some Chromium windows report AT-SPI extents in logical pixels while X11
|
|
// reports physical pixels. Require the same origin and proportional dimensions
|
|
// so a smaller dialog or unrelated sibling cannot claim the foreground client.
|
|
func scaledWindowMatches(accessible, xWindow Rectangle) bool {
|
|
if !accessible.Valid() || !xWindow.Valid() || accessible.X != xWindow.X || accessible.Y != xWindow.Y {
|
|
return false
|
|
}
|
|
scaleX := float64(xWindow.Width) / float64(accessible.Width)
|
|
scaleY := float64(xWindow.Height) / float64(accessible.Height)
|
|
if scaleX < 0.5 || scaleX > 3 || scaleY < 0.5 || scaleY > 3 {
|
|
return false
|
|
}
|
|
return math.Abs(scaleX-scaleY) <= 0.01*math.Max(scaleX, scaleY)
|
|
}
|
|
|
|
// A menu popup remains within the foreground application's AT-SPI bus even
|
|
// when its own accessible frame does not match the X11 foreground client's
|
|
// bounds. The caller must confirm an active menu window or a focused menu item.
|
|
func foregroundMenuPopupMatches(client xorg.Foreground, foregroundWindow, popupWindow ObjectID, pid int, menuContext bool) bool {
|
|
return menuContext && client.Window != 0 && foregroundWindow.Valid() && popupWindow.Valid() &&
|
|
foregroundWindow != popupWindow && foregroundWindow.BusName == popupWindow.BusName &&
|
|
(client.PID <= 0 || pid <= 0 || client.PID == pid)
|
|
}
|