"""GTK provider geometry paired with independently measured X11 rectangles.""" import json import os import sys import gi gi.require_version('Gtk', '3.0') gi.require_version('GdkX11', '3.0') gi.require_version('Gdk', '3.0') from gi.repository import Gdk, GdkX11, GLib, Gtk from Xlib import X, Xatom, display def main(): window = Gtk.Window(title='OCR geometry fixture') window.set_decorated(False) window.set_default_size(300, 200) window.move(40, 30) fixed = Gtk.Fixed() window.add(fixed) painted = Gtk.DrawingArea() painted.set_size_request(80, 50) painted.set_can_focus(True) painted.get_accessible().set_name('Painted target') def draw(_widget, context): context.set_source_rgb(0.2, 0.4, 0.6) context.paint() return False painted.connect('draw', draw) fixed.put(painted, 10, 15) password = Gtk.Entry() password.set_visibility(False) password.get_accessible().set_name('Protected target') fixed.put(password, 10, 90) window.show_all() painted.grab_focus() Gdk.Display.get_default().sync() connection = display.Display() root = connection.screen().root activeAtom = connection.intern_atom('_NET_ACTIVE_WINDOW') clientId = GdkX11.X11Window.get_xid(window.get_window()) client = connection.create_resource_object('window', clientId) root.change_property(activeAtom, Xatom.WINDOW, 32, [clientId]) client.change_property(connection.intern_atom('_NET_WM_PID'), Xatom.CARDINAL, 32, [os.getpid()]) client.set_input_focus(X.RevertToParent, X.CurrentTime) connection.sync() def rectangle(widget): native = connection.create_resource_object('window', GdkX11.X11Window.get_xid(widget.get_window())) origin = root.translate_coords(native, 0, 0) geometry = native.get_geometry() return [origin.x, origin.y, origin.x + geometry.width, origin.y + geometry.height] def state(): connection.sync() return dict(window=clientId, target=rectangle(painted), focus=connection.get_input_focus().focus.id) GLib.idle_add(lambda: (print(json.dumps(state()), flush=True), False)[1]) def command_ready(_source, condition): if condition & GLib.IO_HUP: Gtk.main_quit() return False line = sys.stdin.readline() if not line: Gtk.main_quit() return False command = json.loads(line) action = command['action'] if action == 'hide': painted.hide() elif action == 'password': password.grab_focus() elif action == 'move': window.move(100, 60) elif action != 'state': raise ValueError('unknown fixture action') GLib.idle_add(lambda: (print(json.dumps(state()), flush=True), False)[1]) return True GLib.io_add_watch(sys.stdin, GLib.IO_IN | GLib.IO_HUP, command_ready) Gtk.main() connection.close() if __name__ == '__main__': main()