// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later // Package webscripts owns application-specific web exceptions. It consumes // copied semantics, never native accessibles, and does not depend on the reader. package webscripts import "time" type Script uint8 const ( Default Script = iota Steam ) // MatchProcess uses the provider's verified process identity, not a page title // or the ambiguous AT-SPI application name "Chromium". func MatchProcess(processName string) Script { if processName == "steamwebhelper" { return Steam } return Default } // Notification contains only the selected root identity and bounded content. type Notification struct { BusName, RootPath, Text string WindowPath string } type NotificationCandidate struct { Role, Live, ContainerLive string } func NotificationEvent(eventType string, detail int) bool { return eventType == "object:text-changed:insert" || eventType == "object:children-changed:add" || eventType == "object:state-changed:showing" && detail != 0 } func HandlesNotification(processName, eventType string, detail int, message *Notification) bool { return MatchProcess(processName) == Steam && NotificationEvent(eventType, detail) && message != nil && message.BusName != "" && message.RootPath != "" } // Registry is owned by the reader's event loop. The loop owns its timer and // presents completed messages using the shared speech/braille/history services. type Registry struct { steam steamNotifications } func (registry *Registry) Receive(processName, eventType string, detail int, message *Notification, now time.Time) ([]string, bool) { if !HandlesNotification(processName, eventType, detail, message) { return nil, false } return registry.steam.queue(*message, now), true } func (registry *Registry) Flush(now time.Time) []string { return registry.steam.flush(now) } func (registry *Registry) Deadline() time.Time { return registry.steam.deadline() } func (registry *Registry) Reset() { registry.steam = steamNotifications{} } // Retire removes delayed content whose accessible root has been destroyed. func (registry *Registry) Retire(busName, rootPath string) { for key, pending := range registry.steam.pending { if key.busName == busName && (key.rootPath == rootPath || pending.windowPath == rootPath) { delete(registry.steam.pending, key) } } }