## page was renamed from InputEventProcessing <> This is a puny attempt to explain how the X Server generates and processes input events. This document was created as part of the development for [[Projects/MPX|MPX]], the Multi-Pointer X Server. This document does not replace a good look at the source code. It just helps understanding what happens and what order functions are called. And it gives a general overview on how events are born and sent to the client. We do not give any warranty that the information here is complete and/or accurate. The information here concentrates on pointer events but some is the same for keyboard events. '''Updated 17.06.2010. Reflects input processing in X servers 1.7 through to including 1.9''' == Overview == Generally, input events live through two stages: Event generation and event processing. In the event generation stage, input is gathered from the connected devices and transformed into abstract input events, the so-called InternalEvents. In the processing stage, these InternalEvents events are converted to protocol events, depending on the event masks of the windows. An InternalEvent may be converted into a core event, an XI 1.x event or an XI2 event. More events such as enter and leave events are generated during the processing stage as well. The event generation stage is part of the interrupt handling. The event processing stage is part of the processing loop (''Dispatch()''). In between those two stages, there is the event queue. Events are put on the event queue after the creation stage and taken off again at the start of the processing stage. Only InternalEvents are ever on the event queue. There are only a few directories that are interesting for all that: * ''xserver/dix'' ... device independent X. The events.c file is handling most of the events. * ''xserver/mi'' ... machine independent X. Mouse cursor rendering stuff. * ''xserver/hw/xfree86/common'' ... some additional stuff, especially the driver interface. * ''xserver/Xi'' ... X Input Extension protocol stuff. The method the server spends the most time in is ''Dispatch()'', and in this method the server mostly waits in ''WaitForSomething()'' for requests from the clients and to send off accumulated input events from the input devices to the clients. Lots and lots of functions are called using function pointers. Finding them can be very frustrating. See [[Development/Documentation/UsingCtags|how to set up ctags]] to jump around in the source and find functions easier. === The DESIGN document === There is a document that describes the design of the X server. Depending on where you have the source tree the document is in xserver/hw/xfree86/doc/DESIGN.sgml or if you have the xserver-xorg package installed you should have it in /usr/share/doc/xserver-xorg/DESIGN.gz. It's worth a read but I did not find a lot of information about how input events are handled. === An important requirement to understand events === X has the concept of core devices. These are the devices that are visible in the core protocol (i.e. whenever a client issues a GrabPointer request, the core pointer is picked). With the introduction of X Input in 1994, the definition of an extension device was added. These devices could also send XI events (e.g. DeviceMotionNotify). A device could only be either an XI or a core device, not both - hence the need for the ChangePointerDevice and ChangeKeyboardDevice requests. However, an extension device what was configured to "SendCoreEvents" would cause both XI events on the device and core events on the core pointer device. X server 1.4 introduced the notion of a "virtual core pointer" and "virtual core keyboard" (VCP and VCK, respectively). These devices are hardcoded to be the core devices with all physical devices now being extension devices. This obsoleted the ChangePointerDevice and ChangeKeyboardDevice request, the core devices were always the virtual ones. A device configured to "SendCoreEvents" would send cause the VCP or VCK to generate a core event as well as the extension event on the device itself. X server 1.7 introduced XI2 and the master/slave device hierarchy. VCP and VCK are the first two "master devices", with all physical devices being "attached" to either one. These physical devices are referred to as "slave devices". Events are generated by the slave devices and then move up to the respective master device. A slave device may only generate XI 1.x or XI2 events, a master device may generate core events as well. With MPX, there may be more than one pair of master device but the principle remains the same. All event generation is in ''dix/getevents.c'', see ''GetPointerEvents()'' and ''GetKeyboardEvents()'' as starting points. == Event creation == When a device emits events, a SIGIO is fired and the ''xf86SIGIO()'' handler is called which in turn calls the ''xf86SigioReadInput()'' for the given socket. The latter in turn calls the read input function for the pointer provided. For the mouse driver, this function is ''MouseReadInput()''. The evdev driver has it own handler (''EvdevReadInput()'') and so do all other drivers. ''MouseReadInput'' is one of the functions in the ''InputInfoPtr'' of the mouse driver. It is set when the input driver is initialised and ''MousePreInit()'' is called (see section 5.6 in the DESIGN doc). ''MouseReadInput()'' does all the processing for the different mouse protocols and then posts the event via ''MousePostEvent()'' (again a function pointer in the ''InputInfoPtr'') into ''MouseDoPostEvent()''. * So, if you are using the mouse, the sequence executed on the driver's side is: ''MouseReadInput()'', ''MousePostEvent()'', ''MouseDoPostEvent()''; * The generic sequence is ''Driver-specific ReadInput'', ''driver-specific processsing'', ''xf86Post{Motion|Button|Keyboard|Proximity}Event()'' For a motion event, the driver calls now ''xf86PostMotionEvent()'' and we are back on the server's side. For button events it is ''xf86PostButtonEvent()''. Those in turn call ''GetPointerEvents()'' (''GetKeyboardEvents()'' for keyboard events) which creates the necessary number of events and returns them to the caller. ''GetTimeInMillis()'' is called inside ''GetPointerEvents()'' and timestamps the OS time on the event. Inside the same function, ''miPointerSetPosition()'' is called to re-paint the mouse on the screen. It calls ''miPointerMoved()''. The ''miPointerMoved()'' decides to '''start the hw or the sw management/rendering of the cursor''' (see section ''Cursor rendering''). After this choose the events are put - one by one - onto the event queue using ''mieqEnqueue()''. Note that all this is inside the SIGIO handler, this is important as you may not allocate of free memory at any time in this stage. ''GetPointerEvents()'' will generate a number of InternalEvents, for this tutorial the interesting onces are the DeviceEvents which represent physical input (motion, button, key events) '''To sum it up in short: each time a interrupt happens on one of the sockets to an input event, the device driver reads the data, hands it back to the X Server which constructs one or more ''InternalEvents'' and puts it onto the event queue.''' == Event processing == The event processing stage is the stage where the events are taken off the event queue, individually processed and then sent to the client. Also, more abstract input events (enter and leave notifies) are generated synthetically here. All input are processed in the DDX ''ProcessInputEvents()''. The actual processing is done in ''mieqProcessInputEvents()'' which runs through the event queue from beginning to end. Main entry point for DIX-specific processing is ''ProcessOtherEvent()'', all events pass through here. Note at this point that the XKB extension wraps ''ProcessOtherEvents()'' and is called before we get to POE. XKB is not subject to this tutorial. ''ProcessOtherEvent()'' does a few things. It updates the DIX-internal device state with the information from the event, then gathers some state required for the event itself. For example it grabs the modifier state from the keyboard to be put into mouse events as additional info. Finally, it calls down into the delivery paths that eventually write the protocol event onto the wire. At this point, we're still dealing with InternalEvents only. ''ProcessOtherEvents()'' also calls ''CheckMotion()''. This function updates the cursor sprite's position and then sets the event's coordinates to the new sprite positions. Finally, we compare the window the updated sprite is over with the previous one and call ''DoEnterLeaveEvent()'' if necessary. If the window has changed, we also issue a call to ''PostNewCursor()'' which basically changes to the updated cursor shape. Let us see what ''DoEnterLeaveEvent()'' does. If the old window is a parent of the new window, we issue a ''LeaveNotify'' to the old window, then recursively send ''EnterNotify'' events to the ancestors of the target window (this is done in ''EnterNotifies()'') and then finally a ''EnterNotify'' to our new window. If the old window is a child of the new window, we do the same but with the leave and enter notifies swapped around. Finally, if the window are not related, we send a ''LeaveNotify'' to the old window and then recursively to its parents (using ''LeaveNotifies()''), then recursively send ''EnterNotify'' events (using ''EnterNotifies()'' again) to the new window's parents and finally a ''EnterNotify'' to the new window. Remember that there are multiple types of ''EnterNotify'' and ''LeaveNotify'' events. The ones sent to the parents are all of type ''NotifyVirtual'' (or ''NotifyNonlinearVirtual'' if the windows are unrelated). The ones sent to the old and the new window are of types ''NotifyAncestor'' or ''NotifyInferior'' for related windows and ''NotifyNonlinear'' for unrelated windows. All enter and leave events are constructed in ''EnterLeaveEvent()''. A ''xEvent'' is created, filled with values and then sent to the window using ''DeliverEventsToWindow()''. Again, rootX and rootY is taken from the sprite coordinates. This is the simple explanation, the real implementation is somewhat more difficult as we need to synchronise Enter/Leave events to be protocol-correct even if there are multiple master devices present. So now that we have finished the enter/leave events we concentrate on what the final event processing consists of. The rule here is: an InternalEvent may be delivered as exactly one protocol type, but possibly to multiple clients. So if two clients both selected for core events, both will get the core event. If one client selected for core events and one for XI events, only the XI event is delivered. In the final event delivery path, the client masks are checked on each window in the delivery path and the InternalEvent is converted to the respective protocol event. The event is adopted to the window in ''FixUpEventFromWindow()'' and then delivered to the window with ''DeliverEventsToWindow()''. ''FixUpEventFromWindow()'' adopts the window specific values to the event's window (the child, eventX and eventY values). If the delivery failed to a given window, the parent is tried until we run out of parent windows. ''DeliverEventToWindow()'' calls ''TryClientEvents()'' to write the events to the client. If the event is a button press event, ''DeliverEventToWindow()'' also activates the implicit pointer grab (a grab that is deactivated automatically on the next button release event). Now we have completed event processing, all the events were written to the client and we jump back to the last lines of ''ProcessInputEvents()''. What is left now is cursor rendering (if applicable), called with ''miPointerUpdateSprite()''. '''Again, a short summary of the event processing stage: the server takes the events off the queue, fills them with the right variables, generate enter and leave notifies if necessary and writes them to the client.''' == Cursor rendering == Cursor rendering is a bit complicated to understand and hard to debug. It is a layered architecture to do as much in hardware as possible and pretty much everything is called via function pointers. Some need for function pointers has been removed with 1.9, but the basic priniciple is the same. === hw cursor === If the cursor is fully rendered in hardware, ''xf86CursorMoveCursor()'' and ''xf86MoveCursor()'' are the two first functions called. These functions are called just after the ''miPointerMoved()'', the function that decides if the render will be in sw or hw, on the event creation stage. ''xf86MoveCursor()'' will call the video driver function desired to take care of the hw rendering. On my case, ''ATIMach64SetCursorPosition()'' is called. It do the calculations and paint the sprites on the memory mapped directly to the output stream. In other words, '''exactly on this moment the mouse is moved on the screen'''. === sw cursor === If it is done in sofware, the cursor has to be back-buffered. Every time it moves we restore the previous image, save the window at the target position, then render the cursor into the stream. We start with everything at the end of ''ProcessInputEvents()'' and the call to ''miPointerUpdateSprite()''. Here we grab the current coordinates of the pointer (remember, they were set when we called ''miPointerMove()'' in the event generation stage) and call the ''MoveCursor'' function in the ''spriteFuncs'' of the ''miPointerScreenRec'' struct. Of course, if the cursor has changed screen or the shape has changed, this needs to be taken care of too. The ''MoveCursor'' function is set to ''miSpriteMoveCursor()'' which just calls ''miSpriteSetCursor()''. This function first checks whether the cursor has changed at all and then the new positions of the cursor. The cursor is then removed with ''miSpriteRemoveCursor()'' and then restored at the new position with ''miSpriteRestoreCursor()''. ''miSpriteRemoveCursor()'' is fairly simple, it just calls the restore function ''miDCRestoreUnderCursor()'', which then calls the next layer (damage) to copy the saved area into the window at a given position. ''miSpriteRestoreCursor()'' saves the area under the cursor (''miDCSaveUnderCursor()'') into the buffer and then puts up the cursor again (''miDCPutUpCursor()''). If, as mentioned before, the new position is insided the saved buffer, a call to ''miDCChangeSave()'' updates the saved region and a call to ''miDCMoveCursor()'' will move the cursor. This moving doesn't cause any flickering, the remove and restore procedure may flicker. As easy as this sounds, there is more to cursor rendering. Quite a fair bit of work is done outside this explicit rendering calls that are issued when all input events have been processed. Interestingly, pretty much all other function that handle sprite rendering (everything with ''miSprite...'') basically remove the cursor from the screen if necessary (i.e. when the window is moved). The one exception is the block handler function (called when there's nothing else to do and the server would block while waiting for input). ''miSpriteBlockHandler()'' checks if the cursor was previously removed but should be visible and renders it to the screen again if necessary. '''What must be clear on the cursor rendering is: hw cursor is rendered before the event be enqueued (i.e., on the event creation stage) and sw cursor is rendered after the ''ProcessInputEvents()'' (i.e., after the event creation and after the event processing stage).''' ---- CategoryServerInternals