Fix AT-SPI queue flush deadlock
This commit is contained in:
@@ -186,6 +186,64 @@ class EventManagerCompositorContextRegressionTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(list(self.manager._eventQueue.queue), [currentEvent])
|
||||
|
||||
def test_flush_classifies_outside_queue_lock_and_preserves_nested_event(self) -> None:
|
||||
staleEvent = FakeEvent("object:children-changed:add", source="stale")
|
||||
currentEvent = FakeEvent("object:children-changed:add", source="current")
|
||||
nestedEvent = FakeEvent("object:state-changed:focused", source="nested", detail1=1)
|
||||
self.manager._eventQueue.put(staleEvent)
|
||||
self.manager._eventQueue.put(currentEvent)
|
||||
self.manager._ignore = mock.Mock(return_value=False)
|
||||
self.manager._prioritizeSelfHostedFocusedEvent = mock.Mock(return_value=False)
|
||||
self.manager._queuePrintln = mock.Mock()
|
||||
self.manager._inFlood = mock.Mock(return_value=False)
|
||||
self.manager._shouldSuspendEventsFor = mock.Mock(return_value=False)
|
||||
self.manager._dequeue = mock.Mock(return_value=False)
|
||||
script = types.SimpleNamespace(eventCache={})
|
||||
|
||||
def classify_event(event) -> bool:
|
||||
self.assertFalse(self.manager._gidleLock.locked())
|
||||
if event is staleEvent:
|
||||
self.manager._enqueue(nestedEvent)
|
||||
return True
|
||||
return False
|
||||
|
||||
self.manager._event_is_from_stale_context = mock.Mock(side_effect=classify_event)
|
||||
self.manager._should_preserve_during_suppression = mock.Mock(return_value=False)
|
||||
|
||||
with (
|
||||
mock.patch.object(event_manager.AXObject, "get_application", return_value=object()),
|
||||
mock.patch.object(event_manager.GLib, "idle_add", return_value=1),
|
||||
mock.patch.object(
|
||||
event_manager.cthulhu.cthulhuApp.scriptManager,
|
||||
"get_script",
|
||||
return_value=script,
|
||||
),
|
||||
mock.patch.object(
|
||||
event_manager.AXUtilities,
|
||||
"get_application_toolkit_name",
|
||||
return_value="VCL",
|
||||
),
|
||||
):
|
||||
self.manager._flush_stale_atspi_events()
|
||||
|
||||
self.assertEqual(list(self.manager._eventQueue.queue), [currentEvent, nestedEvent])
|
||||
self.manager._dequeue.assert_not_called()
|
||||
|
||||
def test_flush_restores_retained_and_unexamined_events_after_exception(self) -> None:
|
||||
firstEvent = FakeEvent("object:children-changed:add", source="first")
|
||||
secondEvent = FakeEvent("object:children-changed:add", source="second")
|
||||
self.manager._eventQueue.put(firstEvent)
|
||||
self.manager._eventQueue.put(secondEvent)
|
||||
self.manager._event_is_from_stale_context = mock.Mock(
|
||||
side_effect=RuntimeError("property lookup failed"),
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError, "property lookup failed"):
|
||||
self.manager._flush_stale_atspi_events()
|
||||
|
||||
self.assertEqual(list(self.manager._eventQueue.queue), [firstEvent, secondEvent])
|
||||
self.assertFalse(self.manager._flushingStaleAtspiEvents)
|
||||
|
||||
def test_stale_background_event_does_not_activate_script_during_suppression(self) -> None:
|
||||
script = mock.Mock()
|
||||
script.isActivatableEvent.return_value = True
|
||||
|
||||
Reference in New Issue
Block a user