"""Controlled GTK test window: real native cursors and unique click sequences.""" import gi import json import time gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkPixbuf, GLib win = Gtk.Window(title='VDI native cursor acceptance') area = Gtk.DrawingArea() win.add(area) area.set_can_focus(True) area.set_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK) display = Gdk.Display.get_default() names = ['default', 'text', 'ew-resize', 'wait', 'none', 'crosshair', 'custom'] cursors = {name: Gdk.Cursor.new_from_name(display, name) for name in names[:4] + ['crosshair']} cursors['none'] = Gdk.Cursor.new_for_display(display, Gdk.CursorType.BLANK_CURSOR) pix = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 24, 24) pix.fill(0xff5030ff) cursors['custom'] = Gdk.Cursor.new_from_pixbuf(display, pix, 7, 9) current = None sequence = 0 def report(**kw): kw['t'] = time.monotonic() print(json.dumps(kw), flush=True) def motion(widget, event): global current index = min(6, int(event.x // (2560/7))) name = names[index] if name != current: area.get_window().set_cursor(cursors[name]) current = name report(event='shape', name=name) return False def button(widget, event): global sequence if event.type in (Gdk.EventType.BUTTON_PRESS, Gdk.EventType.DOUBLE_BUTTON_PRESS, Gdk.EventType.TRIPLE_BUTTON_PRESS): # GTK emits an extra double/triple notification, not another input. if event.type == Gdk.EventType.BUTTON_PRESS: sequence += 1 area.queue_draw_area(0, 1300, 1000, 140) report(event=event.type.value_nick, seq=sequence, x=event.x_root, y=event.y_root, button=event.button) return False def draw(widget, cr): cr.set_source_rgb(.94, .96, .98) cr.paint() cr.select_font_face('sans') cr.set_font_size(25) for i, name in enumerate(names): cr.set_source_rgb(.1, .15, .2) cr.move_to(40 + i*2560/7, 100) cr.show_text(name) cr.set_source_rgb(.65, .7, .8) cr.rectangle(i*2560/7, 120, 2, 1100) cr.fill() # Unique monotonic sequence, read from the actual decoded video. for bit in range(16): v = 1 if sequence & (1 << bit) else 0 cr.set_source_rgb(v, v, v) cr.rectangle(40 + bit*40, 1340, 40, 60) cr.fill() return False def key(widget, event): if event.keyval == Gdk.KEY_Escape: Gtk.main_quit() return False win.connect('destroy', Gtk.main_quit) win.connect('key-press-event', key) area.connect('motion-notify-event', motion) area.connect('button-press-event', button) area.connect('button-release-event', button) area.connect('draw', draw) win.fullscreen() win.show_all() win.present() area.grab_focus() report(event='ready') Gtk.main()