Snippet #1525
on 2021/07/27 15:06:39 (UTC) by V. V. as Python
-
#!/usr/bin/python3
-
# coding=utf-8 license=Apache-2.0
-
-
"""
-
Tool to follow caret position reported by applications.
-
-
Listens to caret move events and prints and displays the reported positions to
-
ease debugging apps and toolkits.
-
"""
-
-
import pyatspi
-
-
import cairo
-
import gi
-
gi.require_version('Gtk', '3.0')
-
from gi.repository import Gtk, GLib
-
-
-
class BaseListener:
-
def __init__(self, types):
-
self.__types = types
-
-
def __enter__(self):
-
for t in self.__types:
-
pyatspi.Registry.registerEventListener(self._on_event, t)
-
pyatspi.Registry.start()
-
-
def __exit__(self, *args, **kwargs):
-
pyatspi.Registry.stop()
-
for t in self.__types:
-
pyatspi.Registry.deregisterEventListener(self._on_event, t)
-
-
def _on_event(self, event):
-
return False
-
-
-
def main(listener):
-
try:
-
with listener as dummy:
-
pass
-
except KeyboardInterrupt:
-
pass
-
-
-
class Highlight(Gtk.Window):
-
""" A overlay to highlight an area on screen.
-
TODO: make the window input-less """
-
def __init__(self, x, y, w, h):
-
super().__init__(type=Gtk.WindowType.POPUP, app_paintable=True)
-
self.set_default_size(w, h)
-
self.move(x, y)
-
-
self.do_screen_changed(None)
-
-
def do_screen_changed(self, previous_screen):
-
screen = self.get_screen()
-
visual = screen.get_rgba_visual()
-
if visual:
-
self.set_visual(visual)
-
-
def do_draw(self, cr):
-
cr.set_source_rgba(1, 0, 0, 0.2)
-
cr.set_operator(cairo.OPERATOR_SOURCE)
-
cr.paint()
-
cr.set_source_rgba(1, 0, 0, 0.8)
-
alloc = self.get_allocation()
-
cr.rectangle(alloc.x, alloc.y, alloc.width, alloc.height)
-
cr.stroke()
-
return True
-
-
-
class Listener(BaseListener):
-
def __init__(self, apps=None):
-
super().__init__(types=[
-
"object:text-caret-moved",
-
])
-
-
self.apps = [app.casefold() for app in apps] if apps else []
-
-
self.area = None
-
self.area_clear_id = 0
-
-
def _update_area(self, extents):
-
def clear():
-
if self.area:
-
self.area.destroy()
-
self.area = None
-
self.area_clear_id = 0
-
return False
-
-
if self.area:
-
self.area.destroy()
-
GLib.source_remove(self.area_clear_id)
-
self.area = Highlight(*extents)
-
self.area.show()
-
self.area_clear_id = GLib.timeout_add(2000, clear)
-
-
def _on_event(self, event):
-
if super()._on_event(event):
-
return True
-
-
if event.type != "object:text-caret-moved":
-
return False
-
-
if self.apps and event.host_application.name.casefold() not in self.apps:
-
return False
-
-
text = event.source.queryText()
-
extents = text.getCharacterExtents(event.detail1, pyatspi.DESKTOP_COORDS)
-
-
print(event)
-
print("\tx=%s y=%s w=%s h=%s" % extents)
-
-
self._update_area(extents)
-
-
return True
-
-
-
if __name__ == '__main__':
-
from sys import argv
-
-
main(Listener(apps=(argv[1:] if len(argv) > 1 else None)))
Recent Snippets
- #157071 by Anonymous (499 days ago)
- #156876 by Anonymous (500 days ago)
- #154030 by Anonymous (504 days ago)
- #140524 by Anonymous (523 days ago)
- #137907 by rotense (527 days ago)
- #131892 by Anonymous (534 days ago)