Search code examples
cstructunionsxlibxorg

Accessing different members of a c union simultaneously


I've encountered a piece of code which seems to use different members a union at the same time:

XEvent ev;

if(handler[ev.type])
    (handler[ev.type])(&ev);

Handler is an array of functions. Here is the definition of XEvent:

typedef union _XEvent{
    int type;/*must not be changed*/
    XAnyEvent xany;
    XKeyEvent xkey;
    XButtonEvent xbutton;
............
} Xevent;

All the struct members of XEvent have an int as there first member. The called function uses the appropriate member structure of XEvent.

void
kpress(XEvent *ev) {
    XKeyEvent *e = &ev->xkey;

The problem is that XKeyEvent seems to use the value of its first int member as well to determine whether the event was a key press or key release.

typedef struct {
    int type; /* KeyPress or KeyRelease */
    unsigned long serial;   /* # of last request processed by server */
    .............
} XKeyEvent;

What am I missing here?

Note: The above code belongs to simple terminal, a terminal emulator. And all the data structures mentioned belong to Xlib.


Solution

  • It took a while until I understood where you think your problem is - Because actually, there is none...

    You seem to be assuming that there must be a 1:1 relationship between event type ints and structures valid in the union. No, there isn't.

    What Xlib does is: It will put the same XKeyEvent structure for both KeyPress and KeyRelease events (they use the same data members, thus can be used for both event cases).

    The X11 windowing system sends around XEvents as opaque structures (or in OOP terminology "base classes") that the receiver can cast to the original structure (or in OOP terminology "derived classes") according to the event type. The overlapping int member "type" is used as a type selector.

    This is done to be able to "route" events in generic code to the right place without having to handle each event type. Only the interested party (the actual receiver) will cast the inner union to the correct type and "extract" the data members it is interested in.