Try to improve window title reading.

This commit is contained in:
Storm Dragon
2026-05-31 00:48:44 -04:00
parent 6cd745dc57
commit 43996e7b8c
3 changed files with 221 additions and 6 deletions
@@ -0,0 +1,97 @@
import sys
import unittest
from pathlib import Path
from unittest import mock
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cthulhu import where_am_i_presenter
from cthulhu.plugins.WindowTitleReader.plugin import WindowTitleReader
class WindowTitleFallbackRegressionTests(unittest.TestCase):
def test_activate_registers_reader_api_and_starts_fallback_tracking(self):
plugin = WindowTitleReader()
plugin.app = mock.Mock()
with (
mock.patch.object(plugin, "_register_keybinding"),
mock.patch.object(plugin, "_start_tracking") as startTracking,
):
plugin.activate(plugin)
plugin.app.getDynamicApiManager.return_value.registerAPI.assert_called_once_with(
"WindowTitleReader",
plugin,
overwrite=True,
)
startTracking.assert_called_once_with()
def test_poll_schedules_fallback_after_active_window_changes(self):
plugin = WindowTitleReader()
plugin._pollSourceId = 1
plugin._lastActiveWindowId = 100
activeWindow = mock.Mock(id=200)
with (
mock.patch.object(plugin, "_get_active_window", return_value=activeWindow),
mock.patch.object(plugin, "_get_current_title", return_value="XTerm"),
mock.patch.object(plugin, "_schedule_fallback_title") as scheduleFallback,
):
self.assertTrue(plugin._poll_window_title())
scheduleFallback.assert_called_once_with()
def test_poll_keeps_previous_window_across_transient_missing_active_window(self):
plugin = WindowTitleReader()
plugin._pollSourceId = 1
plugin._lastActiveWindowId = 100
with mock.patch.object(plugin, "_get_active_window", return_value=None):
self.assertTrue(plugin._poll_window_title())
self.assertEqual(plugin._lastActiveWindowId, 100)
def test_fallback_is_empty_when_atspi_exposes_same_title(self):
plugin = WindowTitleReader()
plugin._pollSourceId = 1
activeWindow = mock.Mock()
with (
mock.patch.object(plugin, "_get_active_window", return_value=activeWindow),
mock.patch.object(plugin, "_get_current_title", return_value="Terminal"),
):
self.assertEqual(plugin.get_fallback_title("Terminal"), "")
def test_fallback_replaces_wine_desktop_title(self):
plugin = WindowTitleReader()
plugin._pollSourceId = 1
activeWindow = mock.Mock()
with (
mock.patch.object(plugin, "_get_active_window", return_value=activeWindow),
mock.patch.object(plugin, "_get_current_title", return_value="Game Window"),
):
self.assertEqual(plugin.get_fallback_title("Wine Desktop"), "Game Window")
def test_present_title_uses_fallback_instead_of_atspi_title(self):
presenter = where_am_i_presenter.WhereAmIPresenter()
script = mock.Mock()
script.speechGenerator.generateTitle.return_value = [("Wine Desktop", None)]
with (
mock.patch.object(where_am_i_presenter.cthulhu_state, "locusOfFocus", object()),
mock.patch.object(where_am_i_presenter.AXObject, "is_dead", return_value=False),
mock.patch.object(
presenter,
"_get_fallback_title",
return_value="Game Window",
),
):
self.assertTrue(presenter.present_title(script))
script.presentMessage.assert_called_once_with("Game Window")
if __name__ == "__main__":
unittest.main()