93 lines
2.8 KiB
Python
93 lines
2.8 KiB
Python
|
|
"""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()
|