Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

ProcessInputEvents()

As seen at section 3.2.5 the following part of code appears twice at the Dispatch() loop:

if (*icheck[0] != *icheck[1])
{
    ProcessInputEvents();
    FlushIfCriticalOutputPending();
}

The icheck

InitInput() calls mieqInit() as:

 mieqInit ((DevicePtr)xf86Info.pKeyboard, (DevicePtr)xf86Info.pMouse);

mieqInit() is implemented as:

Bool
mieqInit (pKbd, pPtr)
    DevicePtr	pKbd, pPtr;
{
    miEventQueue.head = miEventQueue.tail = 0;
    miEventQueue.lastEventTime = GetTimeInMillis ();
    miEventQueue.pKbd = pKbd;
    miEventQueue.pPtr = pPtr;
    miEventQueue.lastMotion = FALSE;
    miEventQueue.pEnqueueScreen = screenInfo.screens[0];
    miEventQueue.pDequeueScreen = miEventQueue.pEnqueueScreen;
    SetInputCheck (&miEventQueue.head, &miEventQueue.tail);
    return TRUE;
}

The two DevicePtr that are passed as arguments in mieqInit(), pKbd and pPtr, are obtained from xf86Info as:

(DevicePtr)xf86Info.pKeyboard

and

(DevicePtr)xf86Info.pMouse

respectively.

We previously met xf86Info at section 3.2.3, where xf86Info.pKeyboard and xf86Info.pMouse were filled (see instructions with blue characters in InitInput source code at section 3.2.3 and especially the yellow comment in section 3.2.3. See also the next 'gold' text box in the current section).

mieqInit() calls SetInputCheck() as:

    SetInputCheck (&miEventQueue.head, &miEventQueue.tail);

where miEventQueue is defined in mieq.c as:

typedef struct _EventQueue {
    HWEventQueueType	head, tail;	    /* long for SetInputCheck */
    CARD32	lastEventTime;	    /* to avoid time running backwards */
    Bool	lastMotion;
    EventRec	events[QUEUE_SIZE]; /* static allocation for signals */
    DevicePtr	pKbd, pPtr;	    /* device pointer, to get funcs */
    ScreenPtr	pEnqueueScreen;	    /* screen events are being delivered to */
    ScreenPtr	pDequeueScreen;	    /* screen events are being dispatched to */
} EventQueueRec, *EventQueuePtr;

static EventQueueRec miEventQueue;

SetInputCheck() sets as checkForInput[0] the &miEventQueue.head and as checkForInput[1] the &miEventQueue.tail. It is implemented as:

_X_EXPORT void
SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1)
{
    checkForInput[0] = c0;
    checkForInput[1] = c1;
}

Therefore if the head and the tail of the event queue do not point to the same node (there are events in the queue) ProcessInputEvents() and FlushIfCriticalOutputPending() are called.

ProcessInputEvents()

For ProcessInputEvents() we read at its comment:

/*
 * ProcessInputEvents --
 *      Retrieve all waiting input events and pass them to DIX in their
 *      correct chronological order. Only reads from the system pointer
 *      and keyboard.
 */ 

What is an event? Read:

Overview of the X Window System.

How are events processed? Read:

Input Event Processing.

ProcessInputEvents() is implemented as:

void
ProcessInputEvents ()
{
  int x, y;
#ifdef INHERIT_LOCK_STATE
  static int generation = 0;
#endif

    /*
     * With INHERIT_LOCK_STATE defined, the initial state of CapsLock, NumLock
     * and ScrollLock will be set to match that of the VT the server is
     * running on.
     */
#ifdef INHERIT_LOCK_STATE
    if (generation != serverGeneration) {
      xEvent kevent;
      DevicePtr pKeyboard = xf86Info.pKeyboard;
      extern unsigned int xf86InitialCaps, xf86InitialNum, xf86InitialScroll;

      generation = serverGeneration;
      kevent.u.keyButtonPointer.time = GetTimeInMillis();
      kevent.u.keyButtonPointer.rootX = 0;
      kevent.u.keyButtonPointer.rootY = 0;
      kevent.u.u.type = KeyPress;


      if (xf86InitialCaps) {
        kevent.u.u.detail = xf86InitialCaps;
        (* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
        xf86InitialCaps = 0;
      }
      if (xf86InitialNum) {
        kevent.u.u.detail = xf86InitialNum;
        (* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
        xf86InitialNum = 0;
      }
      if (xf86InitialScroll) {
        kevent.u.u.detail = xf86InitialScroll;
        (* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
        xf86InitialScroll = 0;
      }
    }
#endif

  xf86Info.inputPending = FALSE;


#ifdef XINPUT
  xf86eqProcessInputEvents();
#else
  mieqProcessInputEvents();
#endif
  miPointerUpdate();

  miPointerPosition(&x, &y);
  xf86SetViewport(xf86Info.currentScreen, x, y);
}

The most important lines of ProcessInputEvents() are the last ones:

 mieqProcessInputEvents();

  miPointerUpdate();

  miPointerPosition(&x, &y);
  xf86SetViewport(xf86Info.currentScreen, x, y);

mieqProcessInputEvents() processes events previously queued via mieqEnqueue(). The point this took place is described at dmx4.html. Function mieqProcessInputEvents() is implemented in as:

void mieqProcessInputEvents ()
{
    EventRec	*e;
    int		x, y;
    xEvent	xe;

    while (miEventQueue.head != miEventQueue.tail)
    {
	if (screenIsSaved == SCREEN_SAVER_ON)
	    SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset);

	e = &miEventQueue.events[miEventQueue.head];
	/*
	 * Assumption - screen switching can only occur on motion events
	 */
	if (e->pScreen != miEventQueue.pDequeueScreen)
	{
	    miEventQueue.pDequeueScreen = e->pScreen;
	    x = e->event.u.keyButtonPointer.rootX;
	    y = e->event.u.keyButtonPointer.rootY;
	    if (miEventQueue.head == QUEUE_SIZE - 1)
	    	miEventQueue.head = 0;
	    else
	    	++miEventQueue.head;
	    NewCurrentScreen (miEventQueue.pDequeueScreen, x, y);
	}
	else
	{
	    xe = e->event;
	    if (miEventQueue.head == QUEUE_SIZE - 1)
	    	miEventQueue.head = 0;
	    else
	    	++miEventQueue.head;
	    switch (xe.u.u.type) 
	    {
	    case KeyPress:
	    case KeyRelease:
	    	(*miEventQueue.pKbd->processInputProc)
				(&xe, (DeviceIntPtr)miEventQueue.pKbd, 1);
	    	break;
	    default:
	    	(*miEventQueue.pPtr->processInputProc)
				(&xe, (DeviceIntPtr)miEventQueue.pPtr, 1);
	    	break;
	    }
	}
    }
}

EventRec is implemented in mieq.c as:

typedef struct _Event {
    xEvent	event;
    ScreenPtr	pScreen;
} EventRec, *EventPtr;

xEvent in defined in Xproto.h as:

/*****************************************************************
 * xEvent
 *    All events are 32 bytes
 *****************************************************************/

typedef struct _xEvent {
    union {
	struct {
	    BYTE type;
	    BYTE detail;
	    CARD16 sequenceNumber B16;
	    } u;
	struct {
            CARD32 pad00 B32;
	    Time time B32;
	    Window root B32, event B32, child B32;
	    INT16 rootX B16, rootY B16, eventX B16, eventY B16;
	    KeyButMask state B16;
	    BOOL sameScreen;		
	    BYTE pad1;
	} keyButtonPointer;
	struct {
            CARD32 pad00 B32;
            Time time B32;
	    Window root B32, event B32, child B32;
	    INT16 rootX B16, rootY B16, eventX B16, eventY B16;
	    KeyButMask state B16;
	    BYTE mode; 			/* really XMode */
	    BYTE flags;		/* sameScreen and focus booleans, packed together */
#define ELFlagFocus        (1<<0)
#define ELFlagSameScreen   (1<<1)
	} enterLeave;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    BYTE mode; 			/* really XMode */
	    BYTE pad1, pad2, pad3;
	} focus;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    CARD16 x B16, y B16, width B16, height B16;
	    CARD16 count B16;
	    CARD16 pad2 B16;
	} expose;
	struct {
            CARD32 pad00 B32;
	    Drawable drawable B32;
	    CARD16 x B16, y B16, width B16, height B16;
	    CARD16 minorEvent B16;
	    CARD16 count B16;
	    BYTE majorEvent;
	    BYTE pad1, pad2, pad3;
	} graphicsExposure;
	struct {
            CARD32 pad00 B32;
	    Drawable drawable B32;
	    CARD16 minorEvent B16;
	    BYTE majorEvent;
	    BYTE bpad;
	} noExposure;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    CARD8 state;
	    BYTE pad1, pad2, pad3;
	} visibility;
	struct {
            CARD32 pad00 B32;
	    Window parent B32, window B32;
	    INT16 x B16, y B16;
	    CARD16 width B16, height B16, borderWidth B16;
	    BOOL override;
	    BYTE bpad;
        } createNotify;
/*
 * The event feilds in the structures for DestroyNotify, UnmapNotify,
 * MapNotify, ReparentNotify, ConfigureNotify, CirclulateNotify, GravityNotify,
 * must be at the same offset because server internal code is depending upon
 * this to patch up the events before they are delivered.
 * Also note that MapRequest, ConfigureRequest and CirculateRequest have
 * the same offset for the event window.
 */
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32;
	} destroyNotify;
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32;
	    BOOL fromConfigure;
	    BYTE pad1, pad2, pad3;
        } unmapNotify;
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32;
	    BOOL override;
	    BYTE pad1, pad2, pad3;
        } mapNotify;
	struct {
            CARD32 pad00 B32;
	    Window parent B32, window B32;
        } mapRequest;
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32, parent B32;
	    INT16 x B16, y B16;
	    BOOL override;
	    BYTE pad1, pad2, pad3;
	} reparent;
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32, aboveSibling B32;
	    INT16 x B16, y B16;
	    CARD16 width B16, height B16, borderWidth B16;
	    BOOL override;		
	    BYTE bpad;
	} configureNotify;
	struct {
            CARD32 pad00 B32;
	    Window parent B32, window B32, sibling B32;
	    INT16 x B16, y B16;
	    CARD16 width B16, height B16, borderWidth B16;
	    CARD16 valueMask B16;
	    CARD32 pad1 B32;
	} configureRequest;
	struct {
            CARD32 pad00 B32;
	    Window event B32, window B32;
	    INT16 x B16, y B16;
	    CARD32 pad1 B32, pad2 B32, pad3 B32, pad4 B32;
	} gravity;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    CARD16 width B16, height B16;
	} resizeRequest;
	struct {
/* The event field in the circulate record is really the parent when this
   is used as a CirculateRequest insteaad of a CircluateNotify */
            CARD32 pad00 B32;
	    Window event B32, window B32, parent B32;
	    BYTE place;			/* Top or Bottom */
	    BYTE pad1, pad2, pad3;
	} circulate;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    Atom atom B32;
	    Time time B32;
	    BYTE state;			/* NewValue or Deleted */
	    BYTE pad1;
	    CARD16 pad2 B16;
	} property;
	struct {
            CARD32 pad00 B32;
            Time time B32;     
	    Window window B32;
	    Atom atom B32;
	} selectionClear;
	struct {
            CARD32 pad00 B32;
            Time time B32;    
	    Window owner B32, requestor B32;
	    Atom selection B32, target B32, property B32;
	} selectionRequest;
	struct {
            CARD32 pad00 B32;
            Time time B32;   
	    Window requestor B32;
	    Atom selection B32, target B32, property B32;
	} selectionNotify;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    Colormap colormap B32;
#if defined(__cplusplus) || defined(c_plusplus)
	    BOOL c_new;
#else
	    BOOL new;
#endif
	    BYTE state;			/* Installed or UnInstalled */
	    BYTE pad1, pad2;
	} colormap;
	struct {
	    CARD32 pad00 B32;
	    CARD8 request;
	    KeyCode firstKeyCode;
	    CARD8 count;
	    BYTE pad1;
	} mappingNotify;
	struct {
            CARD32 pad00 B32;
	    Window window B32;
	    union {
		struct {
		    Atom type B32;
		    INT32 longs0 B32;
		    INT32 longs1 B32;
		    INT32 longs2 B32;
		    INT32 longs3 B32;
		    INT32 longs4 B32;
		} l;
		struct {
		    Atom type B32;
		    INT16 shorts0 B16;
		    INT16 shorts1 B16;
		    INT16 shorts2 B16;
		    INT16 shorts3 B16;
		    INT16 shorts4 B16;
		    INT16 shorts5 B16;
		    INT16 shorts6 B16;
		    INT16 shorts7 B16;
		    INT16 shorts8 B16;
		    INT16 shorts9 B16;
		} s;
		struct {
		    Atom type B32;
		    INT8 bytes[20];
		} b;
	    } u; 
	} clientMessage;
    } u;
} xEvent;

The while loop iterates until the head of miEventQueue (which is increased by one in each iteration) reached the tail. At each pass xe the current event is extracted from e, the EventRec of the queue.

In the case the EventRec's pScreen is not the same as the queue's pDequeueScreen NewCurrentScreen is called. For NewCurrentScreen() we read at Definition of the Porting Layer:

"If your ddx provides some mechanism for the user to magically move the pointer between multiple screens, you need to inform DIX when this occurs. You should call NewCurrentScreen to accomplish this, specifying the new screen and the new x and y coordinates of the pointer on that screen."

The mechanism described here is Xinerama (PanoramiX).

Otherwise (the most common case) the type of the EventRec is examined and accordingly one of the following functions are called:

*miEventQueue.pKbd->processInputProc

or

*miEventQueue.pPtr->processInputProc

The first is called for KeyPress or KeyRelease event (keyboard) and the second for mouse events.

The actual processInputProc

As seen previously mieqInit() was called from InitInput() as:

 
mieqInit ((DevicePtr)xf86Info.pKeyboard, (DevicePtr)xf86Info.pMouse);
Those arguments are passed to the pKbd and pPtr (both of type DevicePtr) of miEventQueue:
    miEventQueue.pKbd = pKbd;
    miEventQueue.pPtr = pPtr;
As seen in section 3.2.3, InitInput() assigned to those pointers the corePointer dev:
xf86Info.pKeyboard = coreKeyboard->dev;
xf86Info.pMouse = corePointer->dev;
Therefore the two processInputProc routines, for the keyboard and the mouse event handling:

*miEventQueue.pKbd->processInputProc
*miEventQueue.pPtr->processInputProc
become respectivelly (see especially the gold box of section 3.2.3):

ProcessKeyboardEvent()

and

ProcessPointerEvent()

The next function ProcessInputEvents() calls is miPointerUpdate(), which updates the pointer.

The ProcessInputEvents() instruction:

miPointerPosition(&x, &y);
implemented at mipointer.c obtains the position of the pointer and assigns its coordinations to x and y. Then ProcessInputEvents() calls:
xf86SetViewport(xf86Info.currentScreen, x, y);
which is implemented at xf86Cursor.c, which as we read from its comment "Scroll the visual part of the screen so the pointer is visible".

FlushIfCriticalOutputPending()

FlushIfCriticalOutputPending() is implemented as:

void
FlushIfCriticalOutputPending(void)
{
    if (CriticalOutputPending)
	FlushAllOutput();
}

CriticalOutputPending is defined as Boolean in io.c. It is set by SetCriticalOutputPending(), and remains TRUE until output is flushed.

SetCriticalOutputPending() is called from TryClientEvents, which is called for instance from ProcSetSelectionOwner() (one of the client request dispatching routines included in ProcVector[]).

FlushAllOutput() is described in section 3.2.5.4.

REFERENCES

Input Event Processing