Harden XTerm handoff and web event routing

This commit is contained in:
Storm Dragon
2026-07-28 20:01:20 -04:00
parent f92fd33089
commit 1a9ae285d9
8 changed files with 674 additions and 76 deletions
@@ -0,0 +1,102 @@
import sys
import types
import unittest
from pathlib import Path
from unittest import mock
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
stubCthulhu = types.ModuleType("cthulhu.cthulhu")
stubCthulhu.cthulhuApp = mock.Mock()
sys.modules.setdefault("cthulhu.cthulhu", stubCthulhu)
from cthulhu import event_manager
class FakeEvent:
def __init__(self, event_type, source="window", detail1=0):
self.type = event_type
self.source = source
self.detail1 = detail1
self.detail2 = 0
self.any_data = None
class EventManagerXtermHandoffRegressionTests(unittest.TestCase):
def setUp(self) -> None:
listener = mock.Mock()
fakeAtspi = types.SimpleNamespace(
Accessible=event_manager.Atspi.Accessible,
EventListener=types.SimpleNamespace(new=mock.Mock(return_value=listener)),
Role=event_manager.Atspi.Role,
)
self.listenerPatch = mock.patch.object(event_manager, "Atspi", fakeAtspi)
self.listenerPatch.start()
self.addCleanup(self.listenerPatch.stop)
self.manager = event_manager.EventManager(mock.Mock(), asyncMode=False)
self.manager._active = True
self.manager._inputEventManager = mock.Mock()
self.manager._inputEventManager.should_suppress_atspi_events_for_xterm.return_value = True
self.manager._get_scriptForEvent = mock.Mock()
def test_window_activate_is_dropped_while_xterm_is_foreground(self) -> None:
event = FakeEvent("window:activate")
with (
mock.patch.object(event_manager.debug, "printObjectEvent"),
mock.patch.object(event_manager.debug, "printMessage"),
):
self.manager._processObjectEvent(event)
self.manager._get_scriptForEvent.assert_not_called()
self.manager._inputEventManager.should_suppress_atspi_events_for_xterm.assert_called_once_with(
refresh=True,
)
def test_active_frame_event_is_dropped_while_xterm_is_foreground(self) -> None:
event = FakeEvent("object:state-changed:active", detail1=1)
with (
mock.patch.object(event_manager.debug, "printObjectEvent"),
mock.patch.object(event_manager.debug, "printMessage"),
mock.patch.object(event_manager.AXUtilities, "is_frame", return_value=True),
):
self.manager._processObjectEvent(event)
self.manager._get_scriptForEvent.assert_not_called()
self.manager._inputEventManager.should_suppress_atspi_events_for_xterm.assert_called_once_with(
refresh=True,
)
def test_focused_event_is_dropped_while_xterm_is_foreground(self) -> None:
event = FakeEvent("object:state-changed:focused", detail1=1)
with (
mock.patch.object(event_manager.debug, "printObjectEvent"),
mock.patch.object(event_manager.debug, "printMessage"),
):
self.manager._processObjectEvent(event)
self.manager._get_scriptForEvent.assert_not_called()
self.manager._inputEventManager.should_suppress_atspi_events_for_xterm.assert_called_once_with(
refresh=True,
)
def test_background_event_is_dropped_during_xterm_handoff_without_refresh(self) -> None:
event = FakeEvent("object:text-changed:insert")
with (
mock.patch.object(event_manager.debug, "printObjectEvent"),
mock.patch.object(event_manager.debug, "printMessage"),
):
self.manager._processObjectEvent(event)
self.manager._get_scriptForEvent.assert_not_called()
self.manager._inputEventManager.should_suppress_atspi_events_for_xterm.assert_called_once_with(
refresh=False,
)
if __name__ == "__main__":
unittest.main()