xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #173: xi-events.patch

File xi-events.patch, 33.7 KB (added by Antoine Martin, 4 years ago)

handle XI2 events

  • xpra/x11/gtk2/constants.txt

     
    4747ColormapNotify
    4848ClientMessage
    4949MappingNotify
    50 #GenericEvent (not available on all platforms)
     50GenericEvent
    5151LASTEvent
    5252
    5353# Configure event mask:
  • xpra/x11/gtk2/gdk_bindings.pyx

     
    2121verbose = Logger("x11", "bindings", "gtk", "verbose")
    2222
    2323
     24cdef extern from "string.h":
     25    void* memset(void * ptr, int value, size_t num)
     26
    2427###################################
    2528# Headers, python magic
    2629###################################
     
    229232        unsigned int state      # key or button mask
    230233        unsigned int button
    231234        Bool same_screen
     235    ctypedef struct XGenericEventCookie:
     236        int            type     # of event. Always GenericEvent
     237        unsigned long  serial
     238        Bool           send_event
     239        Display        *display
     240        int            extension    #major opcode of extension that caused the event
     241        int            evtype       #actual event type
     242        unsigned int   cookie
     243        void           *data
    232244    ctypedef union XEvent:
    233245        int type
    234246        XAnyEvent xany
     
    249261        XReparentEvent xreparent
    250262        XDestroyWindowEvent xdestroywindow
    251263        XPropertyEvent xproperty
     264        XGenericEventCookie xcookie
    252265
    253266    Bool XQueryExtension(Display * display, char *name,
    254267                         int *major_opcode_return, int *first_event_return, int *first_error_return)
     
    256269    Status XQueryTree(Display * display, Window w,
    257270                      Window * root, Window * parent,
    258271                      Window ** children, unsigned int * nchildren)
     272    int XFlush(Display *dpy)
     273    Window XDefaultRootWindow(Display * display)
    259274
     275    Bool XGetEventData(Display *display, XGenericEventCookie *cookie)
     276    void XFreeEventData(Display *display, XGenericEventCookie *cookie)
    260277
     278
    261279cdef extern from "X11/extensions/xfixeswire.h":
    262280    unsigned int XFixesCursorNotify
    263281    unsigned long XFixesDisplayCursorNotifyMask
     
    344362        Window      window
    345363        Bool        event_only
    346364
     365cdef extern from "X11/extensions/XInput2.h":
     366    ctypedef struct XIEventMask:
     367        int                 deviceid
     368        int                 mask_len
     369        unsigned char*      mask
     370    Status XIQueryVersion(Display *display, int *major_version_inout, int *minor_version_inout)
     371    Status XISelectEvents(Display *display, Window win, XIEventMask *masks, int num_masks)
     372    int XI_LASTEVENT
     373    int XI_DeviceChanged
     374    int XI_KeyPress
     375    int XI_KeyRelease
     376    int XI_ButtonPress
     377    int XI_ButtonRelease
     378    int XI_Motion
     379    int XI_Enter
     380    int XI_Leave
     381    int XI_FocusIn
     382    int XI_FocusOut
     383    int XI_HierarchyChanged
     384    int XI_PropertyEvent
     385    int XI_RawKeyPress
     386    int XI_RawKeyRelease
     387    int XI_RawButtonPress
     388    int XI_RawButtonRelease
     389    int XI_RawMotion
     390    int XI_TouchBegin
     391    int XI_TouchUpdate
     392    int XI_TouchEnd
     393    int XI_TouchOwnership
     394    int XI_RawTouchBegin
     395    int XI_RawTouchUpdate
     396    int XI_RawTouchEnd
    347397
     398    int XIAllDevices
     399    int XIAllMasterDevices
     400    ctypedef struct XIValuatorState:
     401        int           mask_len
     402        unsigned char *mask
     403        double        *values
     404   
     405    ctypedef struct XIRawEvent:
     406        int           type      #GenericEvent
     407        unsigned long serial
     408        Bool          send_event
     409        Display       *display
     410        int           extension #XI extension offset
     411        int           evtype    #XI_RawKeyPress, XI_RawKeyRelease, etc
     412        Time          time
     413        int           deviceid
     414        int           sourceid
     415        int           detail
     416        int           flags
     417        XIValuatorState valuators
     418        double        *raw_values
     419
     420    ctypedef struct XIDeviceEvent:
     421        int           type
     422        unsigned long serial
     423        Bool          send_event
     424        Display       *display
     425        int           extension
     426        int           evtype
     427        Time          time
     428        int           deviceid
     429        int           sourceid
     430        int           detail
     431        Window        root
     432        Window        event
     433        Window        child
     434        double        root_x
     435        double        root_y
     436        double        event_x
     437        double        event_y
     438        int           flags
     439        #XIButtonState       buttons
     440        #XIValuatorState     valuators
     441        #XIModifierState     mods
     442        #XIGroupState        group
     443
     444
    348445######
    349446# GDK primitives, and wrappers for Xlib
    350447######
     
    692789    return event_base
    693790
    694791
     792cdef int XI_OPCODE = 0
     793cdef int get_xi_opcode(int major=2, int minor=2):
     794    cdef Display * xdisplay                             #@DuplicatedSignature
     795    display = gtk.gdk.get_default_root_window().get_display()
     796    xdisplay = get_xdisplay_for(display)
     797    cdef int xi_opcode, event, error
     798    if not XQueryExtension(xdisplay, "XInputExtension", &xi_opcode, &event, &error):
     799        log.warn("Warning: XI2 events are not supported")
     800        return 0
     801    cdef int rmajor = major, rminor = minor
     802    cdef int rc = XIQueryVersion(xdisplay, &rmajor, &rminor)
     803    if rc == BadRequest:
     804        log.warn("Warning: no XI2 %i.%i support,", major, minor)
     805        log.warn(" server supports version %i.%i only", rmajor, rminor)
     806        return 0
     807    elif rc:
     808        log.warn("Warning: Xlib bug querying XI2, code %i", rc)
     809        return 0
     810    global XI_OPCODE
     811    XI_OPCODE = xi_opcode
     812    return xi_opcode
     813
     814DEF MAX_XI_EVENTS = 100
     815DEF XI_EVENT_MASK_SIZE = 100//8
     816cdef select_xi2_events():
     817    cdef Display * xdisplay                             #@DuplicatedSignature
     818    display = gtk.gdk.get_default_root_window().get_display()
     819    xdisplay = get_xdisplay_for(display)
     820    cdef Window win = XDefaultRootWindow(xdisplay)
     821
     822    assert XI_LASTEVENT<MAX_XI_EVENTS, "bug: source needs to be updated, XI_LASTEVENT=%i" % XI_LASTEVENT
     823    cdef XIEventMask evmasks[1]
     824    cdef unsigned char mask1[XI_EVENT_MASK_SIZE]
     825    memset(mask1, 0, XI_EVENT_MASK_SIZE)
     826
     827    # select for button and key events from all master devices
     828    #define XISetMask(ptr, event)   (((unsigned char*)(ptr))[(event)>>3] |=  (1 << ((event) & 7)))
     829    #XISetMask(mask1, XI_RawMotion)
     830    for e in (XI_RawKeyPress, XI_RawKeyRelease, XI_RawMotion):
     831        mask1[e>>3] = 1<< (e & 0x7)
     832
     833    evmasks[0].deviceid = XIAllMasterDevices    #XIAllDevices
     834    evmasks[0].mask_len = XI_EVENT_MASK_SIZE
     835    evmasks[0].mask = mask1
     836    XISelectEvents(xdisplay, win, evmasks, 1)
     837    XFlush(xdisplay)
     838
    695839cdef init_x11_events():
    696840    global _x_event_signals, event_type_names, debug_route_events, XKBNotify, CursorNotify, DamageNotify
    697841    XKBNotify = get_XKB_event_base()
    698842    CursorNotify = XFixesCursorNotify+get_XFixes_event_base()
    699843    DamageNotify = XDamageNotify+get_XDamage_event_base()
    700     cdef int xshape_base = get_XShape_event_base()
    701844    _x_event_signals = {
    702845        MapRequest          : (None, "child-map-request-event"),
    703846        ConfigureRequest    : (None, "child-configure-request-event"),
     
    756899        XKBNotify           : "XKBNotify",
    757900        CursorNotify        : "CursorNotify",
    758901        DamageNotify        : "DamageNotify",
    759         #GenericEvent        : "GenericEvent",    #Old versions of X11 don't have this defined, ignore it
     902        GenericEvent        : "GenericEvent",
    760903        }
     904    cdef int xshape_base = get_XShape_event_base()
    761905    if xshape_base>=0:
    762906        global ShapeNotify
    763907        ShapeNotify = xshape_base
     
    764908        _x_event_signals[ShapeNotify] = ("xpra-shape-event", None)
    765909        event_type_names[ShapeNotify] = "ShapeNotify"
    766910        log("added ShapeNotify=%s", ShapeNotify)
     911    cdef int xi_opcode = get_xi_opcode()
     912    if xi_opcode>0:
     913        select_xi2_events()
     914        log("XI events selected: opcode=%i", xi_opcode)
     915        _x_event_signals[xi_opcode+XI_RawMotion] = ("xpra-raw-motion-event", None)
     916        event_type_names[xi_opcode+XI_RawMotion] = "XI_RawMotion"
     917        for e, name, xpra_event_name in (
     918            (XI_DeviceChanged,      "XI_DeviceChanged",     "xi-device-changed"),
     919            (XI_KeyPress,           "XI_KeyPress",          "xi-key-press"),
     920            (XI_KeyRelease,         "XI_KeyRelease",        "xi-key-release"),
     921            (XI_ButtonPress,        "XI_ButtonPress",       "xi-button-press"),
     922            (XI_ButtonRelease,      "XI_ButtonRelease",     "xi-button-release"),
     923            (XI_Motion,             "XI_Motion",            "xi-motion"),
     924            (XI_Enter,              "XI_Enter",             "xi-enter"),
     925            (XI_Leave,              "XI_Leave",             "xi-leave"),
     926            (XI_FocusIn,            "XI_FocusIn",           "xi-focus-in"),
     927            (XI_FocusOut,           "XI_FocusOut",          "xi-focus-out"),
     928            (XI_HierarchyChanged,   "XI_HierarchyChanged",  "xi-focus-changed"),
     929            (XI_PropertyEvent,      "XI_PropertyEvent",     "xi-property-event"),
     930            (XI_RawKeyPress,        "XI_RawKeyPress",       "xi-raw-key-press"),
     931            (XI_RawKeyRelease,      "XI_RawKeyRelease",     "xi-raw-key-release"),
     932            (XI_RawButtonPress,     "XI_RawButtonPress",    "xi-raw-button-press"),
     933            (XI_RawButtonRelease,   "XI_RawButtonRelease",  "xi-raw-button-release"),
     934            (XI_RawMotion,          "XI_RawMotion",         "xi-raw-motion"),
     935            (XI_TouchBegin,         "XI_TouchBegin",        "xi-touch-begin"),
     936            (XI_TouchUpdate,        "XI_TouchUpdate",       "xi-touch-update"),
     937            (XI_TouchEnd,           "XI_TouchEnd",          "xi-touch-end"),
     938            (XI_TouchOwnership,     "XI_TouchOwnership",    "xi-touch-ownership"),
     939            (XI_RawTouchBegin,      "XI_RawTouchBegin",     "xi-raw-touch-begin"),
     940            (XI_RawTouchUpdate,     "XI_RawTouchUpdate",    "xi-raw-touch-update"),
     941            (XI_RawTouchEnd,        "XI_RawTouchEnd",       "xi-raw-touch-end"),
     942            ):
     943            _x_event_signals[xi_opcode+e] = (xpra_event_name, None)
     944            event_type_names[xi_opcode+e] = name
    767945    for k,v in event_type_names.items():
    768946        names_to_event_type[v] = k
    769947    verbose("x_event_signals=%s", _x_event_signals)
     
    9481126cdef GdkFilterReturn x_event_filter(GdkXEvent * e_gdk,
    9491127                                    GdkEvent * gdk_event,
    9501128                                    void * userdata) with gil:
    951     cdef XEvent * e
    952     cdef XDamageNotifyEvent * damage_e
    953     cdef XFixesCursorNotifyEvent * cursor_e
    954     cdef XkbAnyEvent * xkb_e
    955     cdef XkbBellNotifyEvent * bell_e
    956     cdef XShapeEvent * shape_e
    957     cdef object my_events
    9581129    cdef object event_args
    959     cdef object d
    9601130    cdef object pyev
    9611131    cdef double start = monotonic_time()
    9621132    e = <XEvent*>e_gdk
    963     event_type = event_type_names.get(e.type, e.type)
    964     if e.xany.send_event and e.type not in (ClientMessage, UnmapNotify):
    965         log("x_event_filter ignoring %s send_event", event_type)
     1133    cdef int etype
     1134
     1135    pyev = parse_xevent(e_gdk, gdk_event, userdata)
     1136    log.info("pyev=%s", pyev)
     1137    if not pyev:
    9661138        return GDK_FILTER_CONTINUE
     1139    etype = pyev.type
    9671140    try:
    9681141        my_events = _x_event_signals
    969         event_args = my_events.get(e.type)
    970         log("x_event_filter event=%s/%s window=%#x", event_args, event_type, e.xany.window)
     1142        event_args = my_events.get(etype)
    9711143        if event_args is not None:
    972             d = wrap(<cGObject*>gdk_x11_lookup_xdisplay(e.xany.display))
    973             pyev = X11Event(event_type)
    974             pyev.type = e.type
    975             pyev.send_event = e.xany.send_event
    976             pyev.display = d
    977             pyev.serial = e.xany.serial
    978             # Unmarshal:
    979             try:
    980                 if e.type != XKBNotify:
    981                     pyev.delivered_to = _gw(d, e.xany.window)
    982 
    983                 if e.type == DamageNotify:
    984                     damage_e = <XDamageNotifyEvent*>e
    985                     pyev.window = _gw(d, e.xany.window)
    986                     pyev.damage = damage_e.damage
    987                     pyev.x = damage_e.area.x
    988                     pyev.y = damage_e.area.y
    989                     pyev.width = damage_e.area.width
    990                     pyev.height = damage_e.area.height
    991                 elif e.type == MapRequest:
    992                     pyev.window = _gw(d, e.xmaprequest.window)
    993                 elif e.type == ConfigureRequest:
    994                     pyev.window = _gw(d, e.xconfigurerequest.window)
    995                     pyev.x = e.xconfigurerequest.x
    996                     pyev.y = e.xconfigurerequest.y
    997                     pyev.width = e.xconfigurerequest.width
    998                     pyev.height = e.xconfigurerequest.height
    999                     pyev.border_width = e.xconfigurerequest.border_width
    1000                     try:
    1001                         # In principle there are two cases here: .above is
    1002                         # XNone (i.e. not specified in the original request),
    1003                         # or .above is an invalid window (i.e. it was
    1004                         # specified by the client, but it specified something
    1005                         # weird).  I don't see any reason to handle these
    1006                         # differently, though.
    1007                         pyev.above = _gw(d, e.xconfigurerequest.above)
    1008                     except XError:
    1009                         pyev.above = None
    1010                     pyev.above = e.xconfigurerequest.above
    1011                     pyev.detail = e.xconfigurerequest.detail
    1012                     pyev.value_mask = e.xconfigurerequest.value_mask
    1013                 elif e.type == ResizeRequest:
    1014                     pyev.window = _gw(d, e.xresizerequest.window)
    1015                     pyev.width = e.xresizerequest.width
    1016                     pyev.height = e.xresizerequest.height
    1017                 elif e.type in (FocusIn, FocusOut):
    1018                     pyev.window = _gw(d, e.xfocus.window)
    1019                     pyev.mode = e.xfocus.mode
    1020                     pyev.detail = e.xfocus.detail
    1021                 elif e.type in (EnterNotify, LeaveNotify):
    1022                     pyev.window = _gw(d, e.xcrossing.window)
    1023                     pyev.mode = e.xcrossing.mode
    1024                     pyev.detail = e.xcrossing.detail
    1025                     pyev.subwindow = _gw(d, e.xcrossing.subwindow)
    1026                     pyev.focus = e.xcrossing.focus
    1027                 elif e.type == ClientMessage:
    1028                     pyev.window = _gw(d, e.xany.window)
    1029                     if long(e.xclient.message_type) > (long(2) ** 32):
    1030                         log.warn("Xlib claims that this ClientEvent's 32-bit "
    1031                                  + "message_type is %s.  "
    1032                                  + "Note that this is >2^32.  "
    1033                                  + "This makes no sense, so I'm ignoring it.",
    1034                                  e.xclient.message_type)
    1035                         return GDK_FILTER_CONTINUE
    1036                     pyev.message_type = get_pyatom(d, e.xclient.message_type)
    1037                     pyev.format = e.xclient.format
    1038                     # I am lazy.  Add this later if needed for some reason.
    1039                     if pyev.format != 32:
    1040                         #things like _KDE_SPLASH_PROGRESS and _NET_STARTUP_INFO will come through here
    1041                         log("FIXME: Ignoring ClientMessage type=%s with format=%s (!=32)", pyev.message_type, pyev.format)
    1042                         return GDK_FILTER_CONTINUE
    1043                     pieces = []
    1044                     for i in range(5):
    1045                         # Mask with 0xffffffff to prevent sign-extension on
    1046                         # architectures where Python's int is 64-bits.
    1047                         pieces.append(int(e.xclient.data.l[i]) & 0xffffffff)
    1048                     pyev.data = tuple(pieces)
    1049                 elif e.type == CreateNotify:
    1050                     pyev.window = _gw(d, e.xcreatewindow.window)
    1051                     pyev.width = e.xcreatewindow.width
    1052                     pyev.height = e.xcreatewindow.height
    1053                 elif e.type == MapNotify:
    1054                     pyev.window = _gw(d, e.xmap.window)
    1055                     pyev.override_redirect = e.xmap.override_redirect
    1056                 elif e.type == UnmapNotify:
    1057                     pyev.window = _gw(d, e.xunmap.window)
    1058                 elif e.type == DestroyNotify:
    1059                     pyev.window = _gw(d, e.xdestroywindow.window)
    1060                 elif e.type == PropertyNotify:
    1061                     pyev.window = _gw(d, e.xany.window)
    1062                     pyev.atom = trap.call_synced(get_pyatom, d, e.xproperty.atom)
    1063                 elif e.type == ConfigureNotify:
    1064                     pyev.window = _gw(d, e.xconfigure.window)
    1065                     pyev.x = e.xconfigure.x
    1066                     pyev.y = e.xconfigure.y
    1067                     pyev.width = e.xconfigure.width
    1068                     pyev.height = e.xconfigure.height
    1069                     pyev.border_width = e.xconfigure.border_width
    1070                     pyev.above = e.xconfigure.above
    1071                 elif e.type == CirculateNotify:
    1072                     pyev.window = _gw(d, e.xcirculaterequest.window)
    1073                     pyev.place = e.xcirculaterequest.place
    1074                 elif e.type == ReparentNotify:
    1075                     pyev.window = _gw(d, e.xreparent.window)
    1076                 elif e.type == KeyPress:
    1077                     pyev.window = _gw(d, e.xany.window)
    1078                     pyev.hardware_keycode = e.xkey.keycode
    1079                     pyev.state = e.xkey.state
    1080                 elif e.type == CursorNotify:
    1081                     pyev.window = _gw(d, e.xany.window)
    1082                     cursor_e = <XFixesCursorNotifyEvent*>e
    1083                     pyev.cursor_serial = cursor_e.cursor_serial
    1084                     pyev.cursor_name = trap.call_synced(get_pyatom, d, cursor_e.cursor_name)
    1085                 elif e.type == MotionNotify:
    1086                     pyev.window = _gw(d, e.xmotion.window)
    1087                     pyev.root = _gw(d, e.xmotion.root)
    1088                     pyev.subwindow = _gw(d, e.xmotion.subwindow)
    1089                     pyev.time = e.xmotion.time
    1090                     pyev.x = e.xmotion.x
    1091                     pyev.y = e.xmotion.y
    1092                     pyev.x_root = e.xmotion.x_root
    1093                     pyev.y_root = e.xmotion.y_root
    1094                     pyev.state = e.xmotion.state
    1095                     pyev.is_hint = e.xmotion.is_hint
    1096                     pyev.same_screen = e.xmotion.same_screen
    1097                 elif e.type == ShapeNotify:
    1098                     shape_e = <XShapeEvent*> e
    1099                     pyev.window = _gw(d, shape_e.window)
    1100                     pyev.kind = shape_e.kind
    1101                     pyev.x = shape_e.x
    1102                     pyev.y = shape_e.y
    1103                     pyev.width = shape_e.width
    1104                     pyev.height = shape_e.height
    1105                     pyev.shaped = shape_e.shaped
    1106                 elif e.type == XKBNotify:
    1107                     # note we could just cast directly to XkbBellNotifyEvent
    1108                     # but this would be dirty, and we may want to catch
    1109                     # other types of XKB events in the future
    1110                     xkb_e = <XkbAnyEvent*>e
    1111                     verbose("XKBNotify event received xkb_type=%s", xkb_e.xkb_type)
    1112                     if xkb_e.xkb_type!=XkbBellNotify:
    1113                         return GDK_FILTER_CONTINUE
    1114                     bell_e = <XkbBellNotifyEvent*>e
    1115                     pyev.type = "bell"
    1116                     pyev.device = int(bell_e.device)
    1117                     pyev.percent = int(bell_e.percent)
    1118                     pyev.pitch = int(bell_e.pitch)
    1119                     pyev.duration = int(bell_e.duration)
    1120                     pyev.bell_class = int(bell_e.bell_class)
    1121                     pyev.bell_id = int(bell_e.bell_id)
    1122                     # no idea why window is not set in XkbBellNotifyEvent
    1123                     # since we can fire it from a specific window
    1124                     # but we need one for the dispatch logic, so use root if unset
    1125                     if bell_e.window!=0:
    1126                         verbose("using bell_e.window=%#x", bell_e.window)
    1127                         pyev.window = _gw(d, bell_e.window)
    1128                     else:
    1129                         rw = d.get_default_screen().get_root_window()
    1130                         pyev.window = rw
    1131                         verbose("bell using root window=%#x", pyev.window)
    1132                     pyev.event_only = bool(bell_e.event_only)
    1133                     pyev.delivered_to = pyev.window
    1134                     pyev.window_model = None
    1135                     pyev.bell_name = get_pyatom(d, bell_e.name)
    1136                 else:
    1137                     log.info("not handled: %s", event_type_names.get(e.type, e.type))
    1138             except XError as ex:
    1139                 if ex.msg==BadWindow:
    1140                     if e.type == DestroyNotify:
    1141                         #happens too often, don't bother with the debug message
    1142                         pass
    1143                     else:
    1144                         log("Some window in our event disappeared before we could " \
    1145                             + "handle the event %s/%s using %s; so I'm just ignoring it instead. python event=%s", e.type, event_type, event_args, pyev)
    1146                 else:
    1147                     msg = "X11 error %s parsing the event %s/%s using %s; so I'm just ignoring it instead. python event=%s", get_error_text(ex.msg), e.type, event_type, event_args, pyev
    1148                     log.error(*msg)
    1149             else:
    1150                 signal, parent_signal = event_args
    1151                 _route_event(pyev, signal, parent_signal)
    1152         log("x_event_filter event=%s/%s took %.1fms", event_args, event_type, 1000.0*(monotonic_time()-start))
     1144            signal, parent_signal = event_args
     1145            _route_event(pyev, signal, parent_signal)
     1146        log.info("x_event_filter event=%s/%s took %.1fms", event_args, event_type_names.get(etype, etype), 1000.0*(monotonic_time()-start))
    11531147    except (KeyboardInterrupt, SystemExit):
    11541148        verbose("exiting on KeyboardInterrupt/SystemExit")
    11551149        gtk_main_quit_really()
     
    11581152    return GDK_FILTER_CONTINUE
    11591153
    11601154
     1155cdef parse_xevent(GdkXEvent * e_gdk, GdkEvent * gdk_event, void * userdata) with gil:
     1156    cdef XEvent * e
     1157    cdef XDamageNotifyEvent * damage_e
     1158    cdef XFixesCursorNotifyEvent * cursor_e
     1159    cdef XkbAnyEvent * xkb_e
     1160    cdef XkbBellNotifyEvent * bell_e
     1161    cdef XShapeEvent * shape_e
     1162    cdef object event_args
     1163    cdef object d
     1164    cdef object pyev
     1165    e = <XEvent*>e_gdk
     1166    cdef int etype = e.type
     1167    event_type = event_type_names.get(etype, etype)
     1168    if e.xany.send_event and etype not in (ClientMessage, UnmapNotify):
     1169        log("x_event_filter ignoring %s send_event", event_type)
     1170        return None
     1171    global _x_event_signals
     1172
     1173    d = wrap(<cGObject*>gdk_x11_lookup_xdisplay(e.xany.display))
     1174
     1175    if etype == GenericEvent:
     1176        global XI_OPCODE
     1177        cookie = e.xcookie
     1178        if cookie.extension == XI_OPCODE:
     1179            return parse_xi_event(d, e.xany.display, &e.xcookie)
     1180
     1181    event_args = _x_event_signals.get(etype)
     1182    log("x_event_filter event=%s/%s window=%#x", event_args, event_type, e.xany.window)
     1183    if event_args is None:
     1184        return None
     1185
     1186    pyev = X11Event(event_type)
     1187    pyev.type = etype
     1188    pyev.display = d
     1189    pyev.send_event = e.xany.send_event
     1190    pyev.serial = e.xany.serial
     1191    # Unmarshal:
     1192    try:
     1193        if etype != XKBNotify:
     1194            pyev.delivered_to = _gw(d, e.xany.window)
     1195
     1196        if etype == DamageNotify:
     1197            damage_e = <XDamageNotifyEvent*>e
     1198            pyev.window = _gw(d, e.xany.window)
     1199            pyev.damage = damage_e.damage
     1200            pyev.x = damage_e.area.x
     1201            pyev.y = damage_e.area.y
     1202            pyev.width = damage_e.area.width
     1203            pyev.height = damage_e.area.height
     1204        elif etype == MapRequest:
     1205            pyev.window = _gw(d, e.xmaprequest.window)
     1206        elif etype == ConfigureRequest:
     1207            pyev.window = _gw(d, e.xconfigurerequest.window)
     1208            pyev.x = e.xconfigurerequest.x
     1209            pyev.y = e.xconfigurerequest.y
     1210            pyev.width = e.xconfigurerequest.width
     1211            pyev.height = e.xconfigurerequest.height
     1212            pyev.border_width = e.xconfigurerequest.border_width
     1213            try:
     1214                # In principle there are two cases here: .above is
     1215                # XNone (i.e. not specified in the original request),
     1216                # or .above is an invalid window (i.e. it was
     1217                # specified by the client, but it specified something
     1218                # weird).  I don't see any reason to handle these
     1219                # differently, though.
     1220                pyev.above = _gw(d, e.xconfigurerequest.above)
     1221            except XError:
     1222                pyev.above = None
     1223            pyev.above = e.xconfigurerequest.above
     1224            pyev.detail = e.xconfigurerequest.detail
     1225            pyev.value_mask = e.xconfigurerequest.value_mask
     1226        elif etype == ResizeRequest:
     1227            pyev.window = _gw(d, e.xresizerequest.window)
     1228            pyev.width = e.xresizerequest.width
     1229            pyev.height = e.xresizerequest.height
     1230        elif etype in (FocusIn, FocusOut):
     1231            pyev.window = _gw(d, e.xfocus.window)
     1232            pyev.mode = e.xfocus.mode
     1233            pyev.detail = e.xfocus.detail
     1234        elif etype in (EnterNotify, LeaveNotify):
     1235            pyev.window = _gw(d, e.xcrossing.window)
     1236            pyev.mode = e.xcrossing.mode
     1237            pyev.detail = e.xcrossing.detail
     1238            pyev.subwindow = _gw(d, e.xcrossing.subwindow)
     1239            pyev.focus = e.xcrossing.focus
     1240        elif etype == ClientMessage:
     1241            pyev.window = _gw(d, e.xany.window)
     1242            if long(e.xclient.message_type) > (long(2) ** 32):
     1243                log.warn("Xlib claims that this ClientEvent's 32-bit "
     1244                         + "message_type is %s.  "
     1245                         + "Note that this is >2^32.  "
     1246                         + "This makes no sense, so I'm ignoring it.",
     1247                         e.xclient.message_type)
     1248                return GDK_FILTER_CONTINUE
     1249            pyev.message_type = get_pyatom(d, e.xclient.message_type)
     1250            pyev.format = e.xclient.format
     1251            # I am lazy.  Add this later if needed for some reason.
     1252            if pyev.format != 32:
     1253                #things like _KDE_SPLASH_PROGRESS and _NET_STARTUP_INFO will come through here
     1254                log("FIXME: Ignoring ClientMessage type=%s with format=%s (!=32)", pyev.message_type, pyev.format)
     1255                return GDK_FILTER_CONTINUE
     1256            pieces = []
     1257            for i in range(5):
     1258                # Mask with 0xffffffff to prevent sign-extension on
     1259                # architectures where Python's int is 64-bits.
     1260                pieces.append(int(e.xclient.data.l[i]) & 0xffffffff)
     1261            pyev.data = tuple(pieces)
     1262        elif etype == CreateNotify:
     1263            pyev.window = _gw(d, e.xcreatewindow.window)
     1264            pyev.width = e.xcreatewindow.width
     1265            pyev.height = e.xcreatewindow.height
     1266        elif etype == MapNotify:
     1267            pyev.window = _gw(d, e.xmap.window)
     1268            pyev.override_redirect = e.xmap.override_redirect
     1269        elif etype == UnmapNotify:
     1270            pyev.window = _gw(d, e.xunmap.window)
     1271        elif etype == DestroyNotify:
     1272            pyev.window = _gw(d, e.xdestroywindow.window)
     1273        elif etype == PropertyNotify:
     1274            pyev.window = _gw(d, e.xany.window)
     1275            pyev.atom = trap.call_synced(get_pyatom, d, e.xproperty.atom)
     1276        elif etype == ConfigureNotify:
     1277            pyev.window = _gw(d, e.xconfigure.window)
     1278            pyev.x = e.xconfigure.x
     1279            pyev.y = e.xconfigure.y
     1280            pyev.width = e.xconfigure.width
     1281            pyev.height = e.xconfigure.height
     1282            pyev.border_width = e.xconfigure.border_width
     1283            pyev.above = e.xconfigure.above
     1284        elif etype == CirculateNotify:
     1285            pyev.window = _gw(d, e.xcirculaterequest.window)
     1286            pyev.place = e.xcirculaterequest.place
     1287        elif etype == ReparentNotify:
     1288            pyev.window = _gw(d, e.xreparent.window)
     1289        elif etype == KeyPress:
     1290            pyev.window = _gw(d, e.xany.window)
     1291            pyev.hardware_keycode = e.xkey.keycode
     1292            pyev.state = e.xkey.state
     1293        elif etype == CursorNotify:
     1294            pyev.window = _gw(d, e.xany.window)
     1295            cursor_e = <XFixesCursorNotifyEvent*>e
     1296            pyev.cursor_serial = cursor_e.cursor_serial
     1297            pyev.cursor_name = trap.call_synced(get_pyatom, d, cursor_e.cursor_name)
     1298        elif etype == MotionNotify:
     1299            pyev.window = _gw(d, e.xmotion.window)
     1300            pyev.root = _gw(d, e.xmotion.root)
     1301            pyev.subwindow = _gw(d, e.xmotion.subwindow)
     1302            pyev.time = e.xmotion.time
     1303            pyev.x = e.xmotion.x
     1304            pyev.y = e.xmotion.y
     1305            pyev.x_root = e.xmotion.x_root
     1306            pyev.y_root = e.xmotion.y_root
     1307            pyev.state = e.xmotion.state
     1308            pyev.is_hint = e.xmotion.is_hint
     1309            pyev.same_screen = e.xmotion.same_screen
     1310        elif etype == ShapeNotify:
     1311            shape_e = <XShapeEvent*> e
     1312            pyev.window = _gw(d, shape_e.window)
     1313            pyev.kind = shape_e.kind
     1314            pyev.x = shape_e.x
     1315            pyev.y = shape_e.y
     1316            pyev.width = shape_e.width
     1317            pyev.height = shape_e.height
     1318            pyev.shaped = shape_e.shaped
     1319        elif etype == XKBNotify:
     1320            # note we could just cast directly to XkbBellNotifyEvent
     1321            # but this would be dirty, and we may want to catch
     1322            # other types of XKB events in the future
     1323            xkb_e = <XkbAnyEvent*>e
     1324            verbose("XKBNotify event received xkb_type=%s", xkb_e.xkb_type)
     1325            if xkb_e.xkb_type!=XkbBellNotify:
     1326                return GDK_FILTER_CONTINUE
     1327            bell_e = <XkbBellNotifyEvent*>e
     1328            pyev.type = "bell"
     1329            pyev.device = int(bell_e.device)
     1330            pyev.percent = int(bell_e.percent)
     1331            pyev.pitch = int(bell_e.pitch)
     1332            pyev.duration = int(bell_e.duration)
     1333            pyev.bell_class = int(bell_e.bell_class)
     1334            pyev.bell_id = int(bell_e.bell_id)
     1335            # no idea why window is not set in XkbBellNotifyEvent
     1336            # since we can fire it from a specific window
     1337            # but we need one for the dispatch logic, so use root if unset
     1338            if bell_e.window!=0:
     1339                verbose("using bell_e.window=%#x", bell_e.window)
     1340                pyev.window = _gw(d, bell_e.window)
     1341            else:
     1342                rw = d.get_default_screen().get_root_window()
     1343                pyev.window = rw
     1344                verbose("bell using root window=%#x", pyev.window)
     1345            pyev.event_only = bool(bell_e.event_only)
     1346            pyev.delivered_to = pyev.window
     1347            pyev.window_model = None
     1348            pyev.bell_name = get_pyatom(d, bell_e.name)
     1349        else:
     1350            log.info("not handled: %s", event_type_names.get(etype, etype))
     1351    except XError as ex:
     1352        log.warn("XError: %s", ex, exc_info=True)
     1353        if ex.msg==BadWindow:
     1354            if etype == DestroyNotify:
     1355                #happens too often, don't bother with the debug message
     1356                pass
     1357            else:
     1358                log("Some window in our event disappeared before we could " \
     1359                    + "handle the event %s/%s using %s; so I'm just ignoring it instead. python event=%s", etype, event_type, event_args, pyev)
     1360        else:
     1361            msg = "X11 error %s parsing the event %s/%s using %s; so I'm just ignoring it instead. python event=%s", get_error_text(ex.msg), etype, event_type, event_args, pyev
     1362            log.error(*msg)
     1363        return None
     1364    return pyev
     1365
     1366
     1367cdef parse_xi_event(d, Display *display, XGenericEventCookie *cookie):
     1368    cdef XIDeviceEvent *device_e
     1369    cdef XIRawEvent *xiraw_e
     1370    cdef int i = 0, j = 0
     1371    if not XGetEventData(display, cookie):
     1372        return None
     1373    xiraw_e = <XIRawEvent*> cookie.data
     1374    win = _gw(d, XDefaultRootWindow(display))
     1375    cdef int xi_type = cookie.evtype
     1376    etype = XI_OPCODE+xi_type
     1377    event_type = event_type_names.get(etype, etype)
     1378
     1379    pyev = X11Event(event_type)
     1380    pyev.type = etype
     1381    pyev.display = d
     1382    pyev.send_event = xiraw_e.send_event
     1383    pyev.serial = xiraw_e.serial
     1384    pyev.time = xiraw_e.time
     1385    pyev.source = xiraw_e.sourceid
     1386    pyev.device = xiraw_e.deviceid
     1387    pyev.detail = xiraw_e.detail
     1388    pyev.flags = xiraw_e.flags
     1389    mask = []
     1390    values = []
     1391    raw_values = []
     1392    for i in range(xiraw_e.valuators.mask_len):
     1393        if xiraw_e.valuators.mask[i//8] & (1 << (i & 0x7)):
     1394            mask.append(i)
     1395            values.append(j)
     1396            raw_values.append(xiraw_e.raw_values[j])
     1397            j += 1
     1398    pyev.valuators = {
     1399        "mask"      : mask,
     1400        "values"    : values,
     1401        }
     1402    if xi_type in (XI_RawKeyPress, XI_RawKeyRelease):
     1403        log.info("%s!", event_type)
     1404        device_e = <XIDeviceEvent*> cookie.data
     1405        #root, child
     1406        #win =  _gw(d, XDefaultRootWindow(device_e.event))
     1407        pyev.root_x = device_e.root_x
     1408        pyev.root_y = device_e.root_y
     1409        pyev.event_x = device_e.event_x
     1410        pyev.event_y = device_e.event_y
     1411        #XIButtonState       buttons
     1412        #XIValuatorState     valuators
     1413        #XIModifierState     mods
     1414        #XIGroupState        group
     1415    XFreeEventData(display, cookie)
     1416    pyev.window = win
     1417    pyev.delivered_to = win
     1418    log.warn("%s", pyev)
     1419    return pyev
     1420
     1421
    11611422_INIT_X11_FILTER_DONE = False
    11621423def init_x11_filter():
     1424    log.warn("init_x11_filter()")
    11631425    """ returns True if we did initialize it, False if it was already initialized """
    11641426    global _INIT_X11_FILTER_DONE
    11651427    if _INIT_X11_FILTER_DONE: