用于XMotionEvent的ctypes和XPeekIfEvent:分段错误

时间:2015-10-12 06:36:22

标签: python c segmentation-fault x11 ctypes

我在XPeekIfEvent执行libX11时遇到问题, 它第二次被调用我得到了一个分段错误。 当我将send_event添加到结构中时会发生这种情况。

如果您在代码中看到@NOTE,则会向我发送一条说明。

整个代码可在此处获取:https://github.com/Centril/sublime-autohide-sidebar/blob/9f3e505c1b78a474de569299fddb704e3dc77d8f/x.py

相关文件:

来自Xlib.hX.h的相关C / C ++定义:

// X.h
typedef unsigned long XID;
typedef XID Window;
typedef CARD32 XID;
typedef CARD32 Time;
typedef XID Window;

// Xlib.h
#define Bool int

typedef struct _XDisplay Display;
struct _XDisplay;       /* Forward declare before use for C++ */

typedef struct {
    int type;       /* of event */
    unsigned long serial;   /* # of last request processed by server */
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;   /* Display the event was read from */
    Window window;          /* "event" window reported relative to */
    Window root;            /* root window that the event occurred on */
    Window subwindow;   /* child window */
    Time time;      /* milliseconds */
    int x, y;       /* pointer x, y coordinates in event window */
    int x_root, y_root; /* coordinates relative to root */
    unsigned int state; /* key or button mask */
    char is_hint;       /* detail */
    Bool same_screen;   /* same screen flag */
} XMotionEvent;
typedef XMotionEvent XPointerMovedEvent;

typedef struct {
    int type;
    unsigned long serial;   /* # of last request processed by server */
    Bool send_event;    /* true if this came from a SendEvent request */
    Display *display;/* Display the event was read from */
    Window window;  /* window on which event was requested in event mask */
} XAnyEvent;

/*
 * this union is defined so Xlib can always use the same sized
 * event structure internally, to avoid memory fragmentation.
 */
typedef union _XEvent {
        int type;       /* must not be changed; first element */
    XAnyEvent xany;
    XKeyEvent xkey;
    XButtonEvent xbutton;
    XMotionEvent xmotion;
    XCrossingEvent xcrossing;
    XFocusChangeEvent xfocus;
    XExposeEvent xexpose;
    XGraphicsExposeEvent xgraphicsexpose;
    XNoExposeEvent xnoexpose;
    XVisibilityEvent xvisibility;
    XCreateWindowEvent xcreatewindow;
    XDestroyWindowEvent xdestroywindow;
    XUnmapEvent xunmap;
    XMapEvent xmap;
    XMapRequestEvent xmaprequest;
    XReparentEvent xreparent;
    XConfigureEvent xconfigure;
    XGravityEvent xgravity;
    XResizeRequestEvent xresizerequest;
    XConfigureRequestEvent xconfigurerequest;
    XCirculateEvent xcirculate;
    XCirculateRequestEvent xcirculaterequest;
    XPropertyEvent xproperty;
    XSelectionClearEvent xselectionclear;
    XSelectionRequestEvent xselectionrequest;
    XSelectionEvent xselection;
    XColormapEvent xcolormap;
    XClientMessageEvent xclient;
    XMappingEvent xmapping;
    XErrorEvent xerror;
    XKeymapEvent xkeymap;
    XGenericEvent xgeneric;
    XGenericEventCookie xcookie;
    long pad[24];
} XEvent;

我的代码如下(删除了一些不相关的部分......):

# License: GPL2+

# Typedefs:
class Display( Structure ):
    _fields_ = []

Bool = c_int
Time = c_ulong
Atom = c_ulong
#Display = c_int
DisplayPtr = POINTER( Display )
Window = c_ulong
WindowPtr = POINTER( Window )
XPointer = c_char_p

# Typedefs: Structs & Unions & FunPtr:s:
class XAnyEvent( Structure ):
    _fields_ = [
        ('type', c_int),
        ('serial', c_ulong),
        ('send_event', Bool),
        ('display', DisplayPtr ),
        ('window', Window)
    ]

class XMotionEvent( Structure ):
    _fields_ = [
        ('type', c_int),
        ('serial', c_ulong),
        ('send_event', Bool),
        ('display', DisplayPtr ),
        ('window', Window),
        ('root', Window),
        ('subwindow', Window),
        ('time', Time),
        ('x', c_int), ('y', c_int),
        ('x_root', c_int), ('y_root', c_int),
        ('state', c_uint),
        ('is_hint', c_char),
        ('same_screen', Bool)
    ]

class XEvent( Union ):
    _fields_ = [
        ('type', c_int),
        ('xany', XAnyEvent),
        ('xmotion', XMotionEvent)
    ]

EventPredicate = CFUNCTYPE( Bool, DisplayPtr, POINTER( XEvent ), XPointer )

# Constants:
MotionNotify = 6
PointerMotionMask = (1 << 6)

# @NOTE: irrelevant parts removed.
# @NOTE: Assume sublimes is a list of X11 Window:s but wrapped.

for w in sublimes: w.select_input( PointerMotionMask )

# NOTE: All of the below really happens in another thread:

def motion_predicate( d, e, a ):
    return e.contents.type == MotionNotify
pred = EventPredicate( motion_predicate )

# Event pump:
atexit.register( self.stop )
event = XEvent()
while self.alive:
    print( "a" )
    print( "#6")
    # NOTE: Here we fail!
    x.XPeekIfEvent( disp, byref( event ), pred, None )
    print( event )
    print( "type", event.type )
    print( "b" )

如果删除typeXAnyEventXMotionEvent以外的所有字段 它可以工作,否则它会因分段错误而失败:

window 81788931 pid 2990 title ~/programming/sublime-autohide-sidebar/x.py (sublime-autohide-sidebar) - Sublime Text
window 82632928 pid 2990 title untitled - Sublime Text
#1
#1
<__main__.XEvent object at 0x7f9a873b4bf8>
#2 type 6
#3
#1
Segmentation fault (core dumped)

或者:

window 81788931 pid 2990 title ~/programming/sublime-autohide-sidebar/x.py (sublime-autohide-sidebar) - Sublime Text
window 82632928 pid 2990 title untitled - Sublime Text
#1
*** Error in `python3': malloc(): memory corruption (fast): 0x00007fb904001060 ***
Aborted (core dumped)

当我实际在其中一个窗口内移动鼠标时会发生这种情况。

我错过了什么?

1 个答案:

答案 0 :(得分:0)

在这篇SO帖子中回答: https://jsfiddle.net/tw79mvau/1/

......我将解决方案改编为:

class XMotionEvent( Structure ):
    _fields_ = [
        ('type', c_int),
        ('serial', c_ulong),
        ('send_event', Bool),
        ('display', DisplayPtr ),
        ('window', Window),
        ('root', Window),
        ('subwindow', Window),
        ('time', Time),
        ('x', c_int), ('y', c_int),
        ('x_root', c_int), ('y_root', c_int),
        ('state', c_uint),
        ('is_hint', c_char),
        ('same_screen', Bool)
    ]

class XEvent( Union ):
    _fields_ = [
        ('type', c_int),
        ('xmotion', XMotionEvent),
        ('pad', c_long * 24),
    ]