Definition of the Porting Layer for the X v11 Sample Server

1. The X Window SystemThe X Window System, or simply "X," is a windowing systemthat provides high-performance, high-level,device-independent graphics.X is a windowing system designed for bitmapped graphicdisplays. The display can have a simple, monochrome displayor it can have a color display with up to 32 bits per pixelwith a special graphics processor doing the work. (In thisdocument, monochrome means a black and white display withone bit per pixel. Even though the usual meaning ofmonochrome is more general, this special case is so commonthat we decided to reserve the word for this purpose.)X is designed for a networking environment where users canrun applications on machines other than their ownworkstations. Sometimes, the connection is over an Ethernetnetwork with a protocol such as TCP/IP; but, any "reliable"byte stream is allowable. A high-bandwidth byte stream ispreferable; RS-232 at 9600 baud would be slow withoutcompression techniques.X by itself allows great freedom of design. For instance,it does not include any user interface standard. Its intentis to "provide mechanism, not policy." By making itgeneral, it can be the foundation for a wide variety ofinteractive software.For a more detailed overview, see the document "The X WindowSystem." For details on the byte stream protocol, see "XWindow System protocol."2. OVERVIEW OF THE SERVERThe display server manages windows and simple graphicsrequests for the user on behalf of different clientapplications. The client applications can be running on anymachine on the network. The server mainly does threethings:• Responds to protocol requests from existing clients(mostly graphic and text drawing commands)• Sends device input (keystrokes and mouse actions) andother events to existing clients• Maintains client connectionsThe server code is organized into four major pieces:• Device Independent (DIX) layer - code shared among allimplementations• Operating System (OS) layer - code that is differentfor each operating system but is shared among allgraphic devices for this operating system• Device Dependent (DDX) layer - code that is(potentially) different for each combination ofoperating system and graphic device• Extension Interface - a standard way to add features tothe X serverThe "porting layer" consists of the OS and DDX layers; theseare actually parallel and neither one is on top of theother. The DIX layer is intended to be portable withoutchange to target systems and is not detailed here, althoughseveral routines in DIX that are called by DDX aredocumented. Extensions incorporate new functionality intothe server; and require additional functionality over asimple DDX.The following sections outline the functions of the layers.Section 3 briefly tells what you need to know about the DIXlayer. The OS layer is explained in Section 4. Section 5gives the theory of operation and procedural interface forthe DDX layer. Section 6 describes the functions whichexist for the extension writer.2.1. Notes On Resources and Large StructsX resources are C structs inside the server. Clientapplications create and manipulate these objects accordingto the rules of the X byte stream protocol. Clientapplications refer to resources with resource IDs, which are32-bit integers that are sent over the network. Within theserver, of course, they are just C structs, and we refer tothem by pointers.The DDX layer has several kinds of resources:• Window• Pixmap• Screen• Device• Colormap• Font• Cursor• Graphics ContextsThe type names of the more important server structs usuallyend in "Rec," such as "DeviceRec;" the pointer types usuallyend in "Ptr," such as "DevicePtr."The structs and important defined constants are declared in.h files that have names that suggest the name of theobject. For instance, there are two .h files for windows,window.h and windowstr.h. window.h defines only what needsto be defined in order to use windows without peeking insideof them; windowstr.h defines the structs with all of theircomponents in great detail for those who need it.Three kinds of fields are in these structs:• Attribute fields - struct fields that contain valueslike normal structs• Pointers to procedures, or structures of procedures,that operate on the object• A private field (or two) used by your DDX code to keepprivate data (probably a pointer to another datastructure), or an array of private fields, which issized as the server initializes.DIX calls through the struct’s procedure pointers to do itstasks. These procedures are set either directly orindirectly by DDX procedures. Most of the proceduresdescribed in the remainder of this document are accessedthrough one of these structs. For example, the procedure tocreate a pixmap is attached to a ScreenRec and might becalled by using the expression(* pScreen->CreatePixmap)(pScreen, width, height, depth).All procedure pointers must be set to some routine unlessnoted otherwise; a null pointer will have unfortunateconsequences.Procedure routines will be indicated in the documentation bythis convention:void pScreen->MyScreenRoutine(arg, arg, ...)as opposed to a free routine, not in a data structure:void MyFreeRoutine(arg, arg, ...)The attribute fields are mostly set by DIX; DDX should notmodify them unless noted otherwise.3. DIX LAYERThe DIX layer is the machine and device independent part ofX. The source should be common to all operating systems anddevices. The port process should not include changes tothis part, therefore internal interfaces to DIX modules arenot discussed, except for public interfaces to the DDX andthe OS layers.In the process of getting your server to work, if you thinkthat DIX must be modified for purposes other than bug fixes,you may be doing something wrong. Keep looking for a morecompatible solution. When the next release of the X servercode is available, you should be able to just drop in thenew DIX code and compile it. If you change DIX, you willhave to remember what changes you made and will have tochange the new sources before you can update to the newversion.The heart of the DIX code is a loop called the dispatchloop. Each time the processor goes around the loop, itsends off accumulated input events from the input devices tothe clients, and it processes requests from the clients.This loop is the most organized way for the server toprocess the asynchronous requests that it needs to process.Most of these operations are performed by OS and DDXroutines that you must supply.4. OS LAYERThis part of the source consists of a few routines that youhave to rewrite for each operating system. These OSfunctions maintain the client connections and schedule workto be done for clients. They also provide an interface tofont files, font name to file name translation, and lowlevel memory management.void OsInit()OsInit initializes your OS code, performing whatever tasksneed to be done. Frequently there is not much to be done.The sample server implementation is in Xserver/os/osinit.c.4.1. Scheduling and Request DeliveryThe main dispatch loop in DIX creates the illusion ofmultitasking between different windows, while the server isitself but a single process. The dispatch loop breaks upthe work for each client into small digestible parts. Someparts are requests from a client, such as individual graphiccommands. Some parts are events delivered to the client,such as keystrokes from the user. The processing of eventsand requests for different clients can be interleaved withone another so true multitasking is not needed in theserver.You must supply some of the pieces for proper schedulingbetween clients.int WaitForSomething(pClientReady)int *pClientReady;WaitForSomething is the scheduler procedure you must writethat will suspend your server process until something needsto be done. This call should make the server suspend untilone or more of the following occurs:• There is an input event from the user or hardware (seeSetInputCheck())• There are requests waiting from known clients, in whichcase you should return a count of clients stored inpClientReady• A new client tries to connect, in which case you shouldcreate the client and then continue waitingBefore WaitForSomething() computes the masks to pass toselect, it needs to see if there is anything to do on thework queue; if so, it must call a DIX routine calledProcessWorkQueue.extern WorkQueuePtr workQueue;if (workQueue)ProcessWorkQueue ();If WaitForSomething() decides it is about to do somethingthat might block (in the sample server, before it callsselect()) it must call a DIX routine called BlockHandler().void BlockHandler(pTimeout, pReadmask)pointer pTimeout;pointer pReadmask;The types of the arguments are for agreement between the OSand DDX implementations, but the pTimeout is a pointer tothe information determining how long the block is allowed tolast, and the pReadmask is a pointer to the informationdescribing the descriptors that will be waited on.In the sample server, pTimeout is a struct timeval **, andpReadmask is the address of the select() mask for reading.The DIX BlockHandler() iterates through the Screens, foreach one calling its BlockHandler. A BlockHandler isdeclared thus:void xxxBlockHandler(nscreen, pbdata, pptv, pReadmask)int nscreen;pointer pbdata;struct timeval ** pptv;pointer pReadmask;The arguments are the index of the Screen, the blockDatafield of the Screen, and the arguments to the DIXBlockHandler().Immediately after WaitForSomething returns from the block,even if it didn’t actually block, it must call the DIXroutine WakeupHandler().void WakeupHandler(result, pReadmask)int result;pointer pReadmask;Once again, the types are not specified by DIX. The resultis the success indicator for the thing that (may have)blocked, and the pReadmask is a mask of the descriptors thatcame active. In the sample server, result is the resultfrom select(), and pReadmask is the address of the select()mask for reading.The DIX WakeupHandler() calls each Screen’s WakeupHandler.A WakeupHandler is declared thus:void xxxWakeupHandler(nscreen, pbdata, err, pReadmask)int nscreen;pointer pbdata;unsigned long result;pointer pReadmask;The arguments are the index of the Screen, the blockDatafield of the Screen, and the arguments to the DIXWakeupHandler().In addition to the per-screen BlockHandlers, any module mayregister block and wakeup handlers (only together) using:Bool RegisterBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData)BlockHandlerProcPtr blockHandler;WakeupHandlerProcPtr wakeupHandler;pointer blockData;A FALSE return code indicates that the registration failedfor lack of memory. To remove a registered Block handler atother than server reset time (when they are all removedautomatically), use:RemoveBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData)BlockHandlerProcPtr blockHandler;WakeupHandlerProcPtr wakeupHandler;pointer blockData;All three arguments must match the values passed toRegisterBlockAndWakeupHandlers.These registered block handlers are called after theper-screen handlers:void (*BlockHandler) (blockData, pptv, pReadmask)pointer blockData;OSTimePtr pptv;pointer pReadmask;Any wakeup handlers registered withRegisterBlockAndWakeupHandlers will be called before theScreen handlers:void (*WakeupHandler) (blockData, err, pReadmask)pointer blockData;int err;pointer pReadmask;The WaitForSomething on the sample server also has a builtin screen saver that darkens the screen if no input happensfor a period of time. The sample server implementation isin Xserver/os/WaitFor.c.Note that WaitForSomething() may be called when you alreadyhave several outstanding things (events, requests, or newclients) queued up. For instance, your server may have justdone a large graphics request, and it may have been a longtime since WaitForSomething() was last called. If manyclients have lots of requests queued up, DIX will onlyservice some of them for a given client before going on tothe next client (see isItTimeToYield, below). Therefore,WaitForSomething() will have to report that these sameclients still have requests queued up the next time around.An implementation should return information on as manyoutstanding things as it can. For instance, if yourimplementation always checks for client data first and doesnot report any input events until there is no client dataleft, your mouse and keyboard might get locked out by anapplication that constantly barrages the server withgraphics drawing requests.A list of indexes (client->index) for clients with dataready to be read or processed should be returned inpClientReady, and the count of indexes returned as theresult value of the call. These are not clients that havefull requests ready, but any clients who have any data readyto be read or processed. The DIX dispatcher will processrequests from each client in turn by callingReadRequestFromClient(), below.WaitForSomething() must create new clients as they arerequested (by whatever mechanism at the transport level). Anew client is created by calling the DIX routine:ClientPtr NextAvailableClient(ospriv)pointer ospriv;This routine returns NULL if a new client cannot beallocated (e.g. maximum number of clients reached). Theospriv argument will be stored into the OS private field(pClient->osPrivate), to store OS private information aboutthe client. In the sample server, the osPrivate fieldcontains the number of the socket for this client. See also"New Client Connections." NextAvailableClient() will callInsertFakeRequest(), so you must be prepared for this.If there are outstanding input events, you should make surethat the two SetInputCheck() locations are unequal. The DIXdispatcher will call your implementation ofProcessInputEvents() until the SetInputCheck() locations areequal.The sample server contains an implementation ofWaitForSomething(). The following two routines indicate toWaitForSomething() what devices should be waited for. fdis an OS dependent type; in the sample server it is an openfile descriptor.int AddEnabledDevice(fd)int fd;int RemoveEnabledDevice(fd)int fd;These two routines are usually called by DDX from theinitialize cases of the Input Procedures that are stored inthe DeviceRec (the routine passed to AddInputDevice()). Thesample server implementation of AddEnabledDevice andRemoveEnabledDevice are in Xserver/os/connection.c.4.2. New Client ConnectionsThe process whereby a new client-server connection starts upis very dependent upon what your byte stream mechanism.This section describes byte stream initiation using examplesfrom the TCP/IP implementation on the sample server.The first thing that happens is a client initiates aconnection with the server. How a client knows to do thisdepends upon your network facilities and the Xlibimplementation. In a typical scenario, a user named Fred onhis X workstation is logged onto a Cray supercomputerrunning a command shell in an X window. Fred can type shellcommands and have the Cray respond as though the X serverwere a dumb terminal. Fred types in a command to run an Xclient application that was linked with Xlib. Xlib looks atthe shell environment variable DISPLAY, which has the value"fredsbittube:0.0." The host name of Fred’s workstation is"fredsbittube," and the 0s are for multiple screens andmultiple X server processes. (Precisely what happens onyour system depends upon how X and Xlib are implemented.)The client application calls a TCP routine on the Cray toopen a TCP connection for X to communicate with the networknode "fredsbittube." The TCP software on the Cray does thisby looking up the TCP address of "fredsbittube" and sendingan open request to TCP port 6000 on fredsbittube.All X servers on TCP listen for new clients on port 6000 bydefault; this is known as a "well-known port" in IPterminology.The server receives this request from its port 6000 andchecks where it came from to see if it is on the server’slist of "trustworthy" hosts to talk to. Then, it opensanother port for communications with the client. This isthe byte stream that all X communications will go over.Actually, it is a bit more complicated than that. Each Xserver process running on the host machine is called a"display." Each display can have more than one screen thatit manages. "corporatehydra:3.2" represents screen 2 ondisplay 3 on the multi-screened network node corporatehydra.The open request would be sent on well-known port number6003.Once the byte stream is set up, what goes on does not dependvery much upon whether or not it is TCP. The client sendsan xConnClientPrefix struct (see Xproto.h) that has theversion numbers for the version of Xlib it is running, somebyte-ordering information, and two character strings usedfor authorization. If the server does not like theauthorization strings or the version numbers do not matchwithin the rules, or if anything else is wrong, it sends afailure response with a reason string.If the information never comes, or comes much too slowly,the connection should be broken off. You must implement theconnection timeout. The sample server implements this bykeeping a timestamp for each still-connecting client and,each time just before it attempts to accept new connections,it closes any connection that are too old. The connectiontimeout can be set from the command line.You must implement whatever authorization schemes you wantto support. The sample server on the distribution tapesupports a simple authorization scheme. The only interfaceseen by DIX is:char *ClientAuthorized(client, proto_n, auth_proto, string_n, auth_string)ClientPtr client;unsigned int proto_n;char *auth_proto;unsigned int string_n;char *auth_string;DIX will only call this once per client, once it has readthe full initial connection data from the client. If theconnection should be accepted ClientAuthorized() shouldreturn NULL, and otherwise should return an error messagestring.Accepting new connections happens internally toWaitForSomething(). WaitForSomething() must call the DIXroutine NextAvailableClient() to create a client object.Processing of the initial connection data will be handled byDIX. Your OS layer must be able to map from a client towhatever information your OS code needs to communicate onthe given byte stream to the client. DIX uses thisClientPtr to refer to the client from now on. The sampleserver uses the osPrivate field in the ClientPtr to storethe file descriptor for the socket, the input and outputbuffers, and authorization information.To initialize the methods you choose to allow clients toconnect to your server, main() calls the routinevoid CreateWellKnownSockets()This routine is called only once, and not called when theserver is reset. To recreate any sockets during serverresets, the following routine is called from the main loop:void ResetWellKnownSockets()Sample implementations of both of these routines are foundin Xserver/os/connection.c.For more details, see the section called "Connection Setup"in the X protocol specification.4.3. Reading Data from ClientsRequests from the client are read in as a byte stream by theOS layer. They may be in the form of several blocks ofbytes delivered in sequence; requests may be broken up overblock boundaries or there may be many requests per block.Each request carries with it length information. It is theresponsibility of the following routine to break it up intorequest blocks.int ReadRequestFromClient(who)ClientPtr who;You must write the routine ReadRequestFromClient() to getone request from the byte stream belonging to client "who."You must swap the third and fourth bytes (the second 16-bitword) according to the byte-swap rules of the protocol todetermine the length of the request. This length ismeasured in 32-bit words, not in bytes. Therefore, thetheoretical maximum request is 256K. (However, the maximumlength allowed is dependent upon the server’s input buffer.This size is sent to the client upon connection. Themaximum size is the constant MAX_REQUEST_SIZE inXserver/include/os.h) The rest of the request you return isassumed NOT to be correctly swapped for internal use,because that is the responsibility of DIX.The ’who’ argument is the ClientPtr returned fromWaitForSomething. The return value indicating status shouldbe set to the (positive) byte count if the read issuccessful, 0 if the read was blocked, or a negative errorcode if an error happened.You must then store a pointer to the bytes of the request inthe client request buffer field; who->requestBuffer. Thiscan simply be a pointer into your buffer; DIX may modify itin place but will not otherwise cause damage. Of course,the request must be contiguous; you must shuffle it aroundin your buffers if not.The sample server implementation is in Xserver/os/io.c.DIX can insert data into the client stream, and can cause a"replay" of the current request.Bool InsertFakeRequest(client, data, count)ClientPtr client;char *data;int count;int ResetCurrentRequest(client)ClientPtr client;InsertFakeRequest() must insert the specified number ofbytes of data into the head of the input buffer for theclient. This may be a complete request, or it might be apartial request. For example, NextAvailableCient() willinsert a partial request in order to read the initialconnection data sent by the client. The routine returnsFALSE if memory could not be allocated.ResetCurrentRequest() should "back up" the input buffer sothat the currently executing request will be reexecuted.DIX may have altered some values (e.g. the overall requestlength), so you must recheck to see if you still have acomplete request. ResetCurrentRequest() should always causea yield (isItTimeToYield).4.4. Sending Events, Errors And Replies To Clientsint WriteToClient(who, n, buf)ClientPtr who;int n;char *buf;WriteToClient should write n bytes starting at buf to theClientPtr "who". It returns the number of bytes written,but for simplicity, the number returned must be either thesame value as the number requested, or -1, signaling anerror. The sample server implementation is inXserver/os/io.c.void SendErrorToClient(client, majorCode, minorCode, resId, errorCode)ClientPtr client;unsigned int majorCode;unsigned int minorCode;XID resId;int errorCode;SendErrorToClient can be used to send errors back toclients, although in most cases your request function shouldsimply return the error code, having set client->errorValueto the appropriate error value to return to the client, andDIX will call this function with the correct opcodes foryou. void FlushAllOutput()void FlushIfCriticalOutputPending()void SetCriticalOutputPending()These three routines may be implemented to support bufferedor delayed writes to clients, but at the very least, thestubs must exist. FlushAllOutput() unconditionally flushesall output to clients; FlushIfCriticalOutputPending()flushes output only if SetCriticalOutputPending() has becalled since the last time output was flushed. The sampleserver implementation is in Xserver/os/io.c and actuallyignores requests to flush output on a per-client basis if itknows that there are requests in that client’s input queue.4.5. Font SupportIn the sample server, fonts are encoded in disk files orfetched from the font server. For disk fonts, there is onefile per font, with a file name like "fixed.pcf". Fontserver fonts are read over the network using the X FontServer Protocol. The disk directories containing disk fontsand the names of the font servers are listed together in thecurrent "font path."In principle, you can put all your fonts in ROM or in RAM inyour server. You can put them all in one library file ondisk. You could generate them on the fly from strokedescriptions. By placing the appropriate code in the FontLibrary, you will automatically export fonts in that formatboth through the X server and the Font server.With the incorporation of font-server based fonts and theSpeedo donation from Bitstream, the font interfaces havebeen moved into a separate library, now called the FontLibrary (../fonts/lib). These routines are shared betweenthe X server and the Font server, so instead of thisdocument specifying what you must implement, simply refer tothe font library interface specification for the details.All of the interface code to the Font library is containedin dix/dixfonts.c4.6. Memory ManagementMemory management is based on functions in the C runtimelibrary. Xalloc(), Xrealloc(), and Xfree() work just likemalloc(), realloc(), and free(), except that you can pass anull pointer to Xrealloc() to have it allocate anew or passa null pointer to Xfree() and nothing will happen. Theversions in the sample server also do some checking that isuseful for debugging. Consult a C runtime library referencemanual for more details.The macros ALLOCATE_LOCAL and DEALLOCATE_LOCAL are providedin Xserver/include/os.h. These are useful if your compilersupports alloca() (or some method of allocating memory fromthe stack); and are defined appropriately on systems whichsupport it.Treat memory allocation carefully in your implementation.Memory leaks can be very hard to find and are frustrating toa user. An X server could be running for days or weekswithout being reset, just like a regular terminal. If youleak a few dozen k per day, that will add up and will causeproblems for users that leave their workstations on.4.7. Client SchedulingThe X server has the ability to schedule clients much likean operating system would, suspending and restarting themwithout regard for the state of their input buffers. Thisfunctionality allows the X server to suspend one client andcontinue processing requests from other clients whilewaiting for a long-term network activity (like loading afont) before continuing with the first client.Bool isItTimeToYield;isItTimeToYield is a global variable you can set if you wantto tell DIX to end the client’s "time slice" and startpaying attention to the next client. After the currentrequest is finished, DIX will move to the next client.In the sample server, ReadRequestFromClient() setsisItTimeToYield after 10 requests packets in a row are readfrom the same client.This scheduling algorithm can have a serious effect uponperformance when two clients are drawing into their windowssimultaneously. If it allows one client to run until itsrequest queue is empty by ignoring isItTimeToYield, theclient’s queue may in fact never empty and other clientswill be blocked out. On the other hand, if it switchsbetween different clients too quickly, performance maysuffer due to too much switching between contexts. Forexample, if a graphics processor needs to be set up withdrawing modes before drawing, and two different clients aredrawing with different modes into two different windows, youmay switch your graphics processor modes so often thatperformance is impacted.See the Strategies document for heuristics on settingisItTimeToYield.The following functions provide the ability to suspendrequest processing on a particular client, resuming it atsome later time:int IgnoreClient (who)ClientPtr who;int AttendClient (who)ClientPtr who;Ignore client is responsible for pretending that the givenclient doesn’t exist. WaitForSomething should not returnthis client as ready for reading and should not return ifonly this client is ready. AttendClient undoes whateverIgnoreClient did, setting it up for input again.Three functions support "process control" for X clients:Bool ClientSleep (client, function, closure)ClientPtr client;Bool (*function)();pointer closure;This suspends the current client (the calling routine isresponsible for making its way back to Dispatch()). No moreX requests will be processed for this client untilClientWakeup is called.Bool ClientSignal (client)ClientPtr client;This function causes a call to the (*function) parameterpassed to ClientSleep to be queued on the work queue. Thisdoes not automatically "wakeup" the client, but the functioncalled is free to do so by calling:ClientWakeup (client)ClientPtr client;This re-enables X request processing for the specifiedclient.4.8. Other OS FunctionsvoidErrorF(char *f, ...)voidFatalError(char *f, ...)voidError(str)char *str;You should write these three routines to provide fordiagnostic output from the dix and ddx layers, althoughimplementing them to produce no output will not affect thecorrectness of your server. ErrorF() and FatalError() takea printf() type of format specification in the firstargument and an implementation-dependent number of argumentsfollowing that. Normally, the formats passed to ErrorF()and FatalError() should be terminated with a newline.Error() provides an os interface for printing out the stringpassed as an argument followed by a meaningful explanationof the last system error. Normally the string does notcontain a newline, and it is only called by the ddx layer.In the sample implementation, Error() uses the perror()function.After printing the message arguments, FatalError() must beimplemented such that the server will call AbortDDX() togive the ddx layer a chance to reset the hardware, and thenterminate the server; it must not return.The sample server implementation for these routines is inXserver/os/util.c.4.9. Idiom SupportThe DBE specification introduces the notion of idioms, whichare groups of X requests which can be executed moreefficiently when taken as a whole compared to beingperformed individually and sequentially. This followingserver internal support to allows DBE implementations, aswell as other parts of the server, to do idiom processing.xReqPtr PeekNextRequest(xReqPtr req, ClientPtr client, Bool readmore)If req is NULL, the return value will be a pointer to thestart of the complete request that follows the one currentlybeing executed for the client. If req is not NULL, thefunction assumes that req is a pointer to a request in theclient’s request buffer, and the return value will be apointer to the the start of the complete request thatfollows req. If the complete request is not available, thefunction returns NULL; pointers to partial requests willnever be returned. If (and only if) readmore is TRUE,PeekNextRequest should try to read an additional requestfrom the client if one is not already available in theclient’s request buffer. If PeekNextRequest reads more datainto the request buffer, it should not move or change theexisting data.void SkipRequests(xReqPtr req, ClientPtr client, int numskipped)The requests for the client up to and including the onespecified by req will be skipped. numskipped must be thenumber of requests being skipped. Normal request processingwill resume with the request that follows req. The callermust not have modified the contents of the request buffer inany way (e.g., by doing byte swapping in place).Additionally, two macros in os.h operate on the xReq pointerreturned by PeekNextRequest:int ReqLen(xReqPtr req, ClientPtr client)The value of ReqLen is the request length in bytes of thegiven xReq.otherReqTypePtr CastxReq(xReq *req, otherReqTypePtr)The value of CastxReq is the conversion of the given requestpointer to an otherReqTypePtr (which should be a pointer toa protocol structure type). Only those fields which comeafter the length field of otherReqType may be accessed viathe returned pointer.Thus the first two fields of a request, reqType and data,can be accessed directly using the xReq * returned byPeekNextRequest. The next field, the length, can beaccessed with ReqLen. Fields beyond that can be accessedwith CastxReq. This complexity was necessary because of thereencoding of core protocol that can happen due to theBigRequests extension.5. DDX LAYERThis section describes the interface between DIX and DDX.While there may be an OS-dependent driver interface betweenDDX and the physical device, that interface is left to theDDX implementor and is not specified here.The DDX layer does most of its work through procedures thatare pointed to by different structs. As previouslydescribed, the behavior of these resources is largelydetermined by these procedure pointers. Most of theseroutines are for graphic display on the screen or supportfunctions thereof. The rest are for user input from inputdevices.5.1. INPUTIn this document "input" refers to input from the user, suchas mouse, keyboard, and bar code readers. X input devicesare of several types: keyboard, pointing device, and manyothers. The core server has support for extension devicesas described by the X Input Extension document; theinterfaces used by that extension are described elsewhere.The core devices are actually implemented as two collectionsof devices, the mouse is a ButtonDevice, a ValuatorDeviceand a PtrFeedbackDevice while the keyboard is a KeyDevice, aFocusDevice and a KbdFeedbackDevice. Each part implements aportion of the functionality of the device. Thisabstraction is hidden from view for core devices by DIX.You, the DDX programmer, are responsible for some of theroutines in this section. Others are DIX routines that youshould call to do the things you need to do in these DDXroutines. Pay attention to which is which.5.1.1. Input Device Data StructuresDIX keeps a global directory of devices in a central datastructure called InputInfo. For each device there is adevice structure called a DeviceRec. DIX can locate anyDeviceRec through InputInfo. In addition, it has a specialpointer to identify the main pointing device and a specialpointer to identify the main keyboard.The DeviceRec (Xserver/include/input.h) is adevice-independent structure that contains the state of aninput device. A DevicePtr is simply a pointer to aDeviceRec.An xEvent describes an event the server reports to a client.Defined in Xproto.h, it is a huge struct of union of structsthat have fields for all kinds of events. All of thevariants overlap, so that the struct is actually very smallin memory.5.1.2. Processing EventsThe main DDX input interface is the following routine:void ProcessInputEvents()You must write this routine to deliver input events from theuser. DIX calls it when input is pending (see nextsection), and possibly even when it is not. You shouldwrite it to get events from each device and deliver theevents to DIX. To deliver the events to DIX, DDX shouldcall the following routine:void DevicePtr->processInputProc(pEvent, device, count)xEventPtr events;DeviceIntPtr device;int count;This is the "input proc" for the device, a DIX procedure.DIX will fill in this procedure pointer to one of its ownroutines by the time ProcessInputEvents() is called thefirst time. Call this input proc routine as many times asneeded to deliver as many events as should be delivered.DIX will buffer them up and send them out as needed. Countis set to the number of event records which make up oneatomic device event and is always 1 for the core devices(see the X Input Extension for descriptions of devices whichmay use count > 1).For example, your ProcessInputEvents() routine might checkthe mouse and the keyboard. If the keyboard had severalkeystrokes queued up, it could just call the keyboard’sprocessInputProc as many times as needed to flush itsinternal queue.event is an xEvent struct you pass to the input proc. Whenthe input proc returns, it is finished with the event rec,and you can fill in new values and call the input proc againwith it.You should deliver the events in the same order that theywere generated.For keyboard and pointing devices the xEvent variant shouldbe keyButtonPointer. Fill in the following fields in thexEvent record:type is one of the following: KeyPress, KeyRelease, ButtonPress,ButtonRelease, or MotionNotifydetail for KeyPress or KeyRelease fields, this should be thekey number (not the ASCII code); otherwise unusedtime is the time that the event happened (32-bits, in milliseconds, arbitrary origin)rootX is the x coordinate of cursorrootY is the y coordinate of cursorThe rest of the fields are filled in by DIX.The time stamp is maintained by your code in the DDX layer,and it is your responsibility to stamp all events correctly.The x and y coordinates of the pointing device and the timemust be filled in for all event types including keyboardevents.The pointing device must report all button press and releaseevents. In addition, it should report a MotionNotify eventevery time it gets called if the pointing device has movedsince the last notify. Intermediate pointing device movesare stored in a special GetMotionEvents buffer, because mostclient programs are not interested in them.There are quite a collection of sample implementations ofthis routine, one for each supported device.5.1.3. Telling DIX When Input is PendingIn the server’s dispatch loop, DIX checks to see if there isany device input pending whenever WaitForSomething()returns. If the check says that input is pending, DIX callsthe DDX routine ProcessInputEvents().This check for pending input must be very quick; a procedurecall is too slow. The code that does the check is ahardwired IF statement in DIX code that simply compares thevalues pointed to by two pointers. If the values aredifferent, then it assumes that input is pending andProcessInputEvents() is called by DIX.You must pass pointers to DIX to tell it what values tocompare. The following procedure is used to set thesepointers:void SetInputCheck(p1, p2)long *p1, *p2;You should call it sometime during initialization toindicate to DIX the correct locations to check. You shouldpay special attention to the size of what they actuallypoint to, because the locations are assumed to be longs.These two pointers are initialized by DIX to point toarbitrary values that are different. In other words, if youforget to call this routine during initialization, the worstthing that will happen is that ProcessInputEvents will becalled when there are no events to process.p1 and p2 might point at the head and tail of some sharedmemory queue. Another use would be to have one point at aconstant 0, with the other pointing at some mask containing1s for each input device that has something pending.The DDX layer of the sample server calls SetInputCheck()once when the server’s private internal queue isinitialized. It passes pointers to the queue’s head andtail. See Xserver/mi/mieq.c.int TimeSinceLastInputEvent()DDX must time stamp all hardware input events. But DIXsometimes needs to know the time and the OS layer needs toknow the time since the last hardware input event in orderfor the screen saver to work. TimeSinceLastInputEvent()returns the this time in milliseconds.5.1.4. Controlling Input DevicesYou must write four routines to do various device-specificthings with the keyboard and pointing device. They can haveany name you wish because you pass the procedure pointers toDIX routines.int pInternalDevice->valuator->GetMotionProc(pdevice, coords, start, stop, pScreen)DeviceIntPtr pdevice;xTimecoord * coords;unsigned long start;unsigned long stop;ScreenPtr pScreen;You write this DDX routine to fill in coords with all themotion events that have times (32-bit count of milliseconds)between time start and time stop. It should return thenumber of motion events returned. If there is no motionevents support, this routine should do nothing and returnzero. The maximum number of coords to return is set inInitPointerDeviceStruct(), below.When the user drags the pointing device, the cursor positiontheoretically sweeps through an infinite number of points.Normally, a client that is concerned with points other thanthe starting and ending points will receive a pointer-moveevent only as often as the server generates them. (Moveevents do not queue up; each new one replaces the last inthe queue.) A server, if desired, can implement a scheme tosave these intermediate events in a motion buffer. A clientapplication, like a paint program, may then request thatthese events be delivered to it through the GetMotionProcroutine.void pInternalDevice->bell->BellProc(percent, pDevice, ctrl, unknown)int percent;DeviceIntPtr pDevice;pointer ctrl;int class;You need to write this routine to ring the bell on thekeyboard. loud is a number from 0 to 100, with 100 beingthe loudest. Class is either BellFeedbackClass orKbdFeedbackClass (from XI.h).void pInternalDevice->somedevice->CtrlProc(device, ctrl)DevicePtr device;SomethingCtrl *ctrl;You write two versions of this procedure, one for thekeyboard and one for the pointing device. DIX calls it toinform DDX when a client has requested changes in thecurrent settings for the particular device. For a keyboard,this might be the repeat threshold and rate. For a pointingdevice, this might be a scaling factor (coarse or fine) forposition reporting. See input.h for the ctrl structures.5.1.5. Input InitializationInput initialization is a bit complicated. It all startswith InitInput(), a routine that you write to callAddInputDevice() twice (once for pointing device and oncefor keyboard.) You also want to callRegisterKeyboardDevice() and RegisterPointerDevice() onthem.When you Add the devices, a routine you supply for eachdevice gets called to initialize them. Your individualinitialize routines must call InitKeyboardDeviceStruct() orInitPointerDeviceStruct(), depending upon which it is. Inother words, you indicate twice that the keyboard is thekeyboard and the pointer is the pointer.void InitInput(argc, argv)int argc;char **argv;InitInput is a DDX routine you must write to initialize theinput subsystem in DDX. It must call AddInputDevice() foreach device that might generate events. In addition, youmust register the main keyboard and pointing devices bycalling RegisterPointerDevice() andRegisterKeyboardDevice().DevicePtr AddInputDevice(deviceProc, autoStart)DeviceProc deviceProc;Bool autoStart;AddInputDevice is a DIX routine you call to create a deviceobject. deviceProc is a DDX routine that is called by DIXto do various operations. AutoStart should be TRUE fordevices that need to be turned on at initialization timewith a special call, as opposed to waiting for some clientapplication to turn them on. This routine returns NULL ifsufficient memory cannot be allocated to install the device.Note also that except for the main keyboard and pointingdevice, an extension is needed to provide for a clientinterface to a device.void RegisterPointerDevice(device)DevicePtr device;RegisterPointerDevice is a DIX routine that your DDX codecalls that makes that device the main pointing device. Thisroutine is called once upon initialization and cannot becalled again.void RegisterKeyboardDevice(device)DevicePtr device;RegisterKeyboardDevice makes the given device the mainkeyboard. This routine is called once upon initializationand cannot be called again.The following DIX procedures return the specified DevicePtr.They may or may not be useful to DDX implementors.DevicePtr LookupKeyboardDevice()LookupKeyboardDevice returns pointer for current mainkeyboard device.DevicePtr LookupPointerDevice()LookupPointerDevice returns pointer for current mainpointing device.A DeviceProc (the kind passed to AddInputDevice()) in thefollowing form:Bool pInternalDevice->DeviceProc(device, action);DeviceIntPtr device;int action;You must write a DeviceProc for each device. device pointsto the device record. action tells what action to take; itwill be one of these defined constants (defined ininput.h):• DEVICE_INIT - At DEVICE_INIT time, the device shouldinitialize itself by calling InitPointerDeviceStruct(),InitKeyboardDeviceStruct(), or a similar routine (seebelow) and "opening" the device if necessary. If youreturn a non-zero (i.e., != Success) value from theDEVICE_INIT call, that device will be consideredunavailable. If either the main keyboard or mainpointing device cannot be initialized, the DIX codewill refuse to continue booting up.• DEVICE_ON - If the DeviceProc is called with DEVICE_ON,then it is allowed to start putting events into theclient stream by calling through the ProcessInputProcin the device.• DEVICE_OFF - If the DeviceProc is called withDEVICE_OFF, no further events from that device shouldbe given to the DIX layer. The device will appear tobe dead to the user.• DEVICE_CLOSE - At DEVICE_CLOSE (terminate or reset)time, the device should be totally closed down.void InitPointerDeviceStruct(device, map, mapLength,GetMotionEvents, ControlProc, numMotionEvents)DevicePtr device;CARD8 *map;int mapLength;ValuatorMotionProcPtr ControlProc;PtrCtrlProcPtr GetMotionEvents;int numMotionEvents;InitPointerDeviceStruct is a DIX routine you call atDEVICE_INIT time to declare some operating routines anddata structures for a pointing device. map andmapLength are as described in the X Window Systemprotocol specification. ControlProc andGetMotionEvents are DDX routines, see above.numMotionEvents is for the motion-buffer-size for theGetMotionEvents request. A typical length for a motionbuffer would be 100 events. A server that does notimplement this capability should set numMotionEvents tozero.void InitKeyboardDeviceStruct(device, pKeySyms, pModifiers, Bell, ControlProc)DevicePtr device;KeySymsPtr pKeySyms;CARD8 *pModifiers;BellProcPtr Bell;KbdCtrlProcPtr ControlProc;You call this DIX routine when a keyboard device isinitialized and its device procedure is called withDEVICE_INIT. The formats of the keysyms and modifiermaps are defined in Xserver/include/input.h. Theydescribe the layout of keys on the keyboards, and theglyphs associated with them. ( See the next sectionfor information on setting up the modifier map and thekeysym map.) ControlProc and Bell are DDX routines,see above.5.1.6. Keyboard Mapping and KeycodesWhen you send a keyboard event, you send a report that agiven key has either been pressed or has been released.There must be a keycode for each key that identifies thekey; the keycode-to-key mapping can be any mapping youdesire, because you specify the mapping in a table you setup for DIX. However, you are restricted by the protocolspecification to keycode values in the range 8 to 255inclusive.The keycode mapping information that you set up consists ofthe following:• A minimum and maximum keycode number• An array of sets of keysyms for each key, that is oflength maxkeycode - minkeycode + 1. Each element ofthis array is a list of codes for symbols that are onthat key. There is no limit to the number of symbolsthat can be on a key.Once the map is set up, DIX keeps and maintains the client’schanges to it.The X protocol defines standard names to indicate thesymbol(s) printed on each keycap. (See X11/keysym.h)Legal modifier keys must generate both up and downtransitions. When a client tries to change a modifier key(for instance, to make "A" the "Control" key), DIX calls thefollowing routine, which should retuurn TRUE if the key canbe used as a modifier on the given device:Bool LegalModifier(key, pDev)unsigned int key;DevicePtr pDev;5.2. ScreensDifferent computer graphics displays have differentcapabilities. Some are simple monochrome frame buffers thatare just lying there in memory, waiting to be written into.Others are color displays with many bits per pixel usingsome color lookup table. Still others have high-speedgraphic processors that prefer to do all of the workthemselves, including maintaining their own high-level,graphic data structures.5.2.1. Screen Hardware RequirementsThe only requirement on screens is that you be able to bothread and write locations in the frame buffer. All screensmust have a depth of 32 or less (unless you use an Xextension to allow a greater depth). All screens must fitinto one of the classes listed in the section in thisdocument on Visuals and Depths.X uses the pixel as its fundamental unit of distance on thescreen. Therefore, most programs will measure everything inpixels.The sample server assumes square pixels. Serious WYSIWYG(what you see is what you get) applications for publishingand drawing programs will adjust for different screenresolutions automatically. Considerable work is involved incompensating for non-square pixels (a bit in the DDX codefor the sample server but quite a bit in the clientapplications).5.2.2. Data StructuresX supports multiple screens that are connected to the sameserver. Therefore, all the per-screen information isbundled into one data structure of attributes andprocedures, which is the ScreenRec (seeXserver/include/scrnintstr.h). The procedure entry pointsin a ScreenRec operate on regions, colormaps, cursors, andfonts, because these resources can differ in format from onescreen to another.Windows are areas on the screen that can be drawn into bygraphic routines. "Pixmaps" are off-screen graphic areasthat can be drawn into. They are both considered drawablesand are described in the section on Drawables. All graphicoperations work on drawables, and operations are availableto copy patches from one drawable to another.The pixel image data in all drawables is in a format that isprivate to DDX. In fact, each instance of a drawable isassociated with a given screen. Presumably, the pixel imagedata for pixmaps is chosen to be conveniently understood bythe hardware. All screens in a single server must be ableto handle all pixmaps depths declared in the connectionsetup information.Pixmap images are transferred to the server in one of twoways: XYPixmap or ZPimap. XYPixmaps are a series ofbitmaps, one for each bit plane of the image, using thebitmap padding rules from the connection setup. ZPixmapsare a series of bits, nibbles, bytes or words, one for eachpixel, using the format rules (padding and so on) for theappropriate depth.All screens in a given server must agree on a set of pixmapimage formats (PixmapFormat) to support (depth, number ofbits per pixel, etc.).There is no color interpretation of bits in the pixmap.Pixmaps do not contain pixel values. The interpretation ismade only when the bits are transferred onto the screen.The screenInfo structure (in scrnintstr.h) is a global datastructure that has a pointer to an array of ScreenRecs, onefor each screen on the server. (These constitute the oneand only description of each screen in the server.) Eachscreen has an identifying index (0, 1, 2, ...). Inaddition, the screenInfo struct contains global server-widedetails, such as the bit- and byte- order in all bit images,and the list of pixmap image formats that are supported.The X protocol insists that these must be the same for allscreens on the server.5.2.3. Output InitializationInitOutput(pScreenInfo, argc, argv)ScreenInfo *pScreenInfo;int argc;char **argv;Upon initialization, your DDX routine InitOutput() is calledby DIX. It is passed a pointer to screenInfo to initialize.It is also passed the argc and argv from main() for yourserver for the command-line arguments. These arguments mayindicate what or how many screen device(s) to use or in whatway to use them. For instance, your server command line mayallow a "-D" flag followed by the name of the screen deviceto use.Your InitOutput() routine should initialize each screen youwish to use by calling AddScreen(), and then it shouldinitialize the pixmap formats that you support by storingvalues directly into the screenInfo data structure. Youshould also set certain implementation-dependent numbers andprocedures in your screenInfo, which determines the pixmapand scanline padding rules for all screens in the server.int AddScreen(scrInitProc, argc, argv)Bool (*scrInitProc)();int argc;char **argv;You should call AddScreen(), a DIX procedure, inInitOutput() once for each screen to add it to thescreenInfo database. The first argument is aninitialization procedure for the screen that you supply.The second and third are the argc and argv from main(). Itreturns the screen number of the screen installed, or -1 ifthere is either insufficient memory to add the screen, or(*scrInitProc) returned FALSE.The scrInitProc should be of the following form:Bool scrInitProc(iScreen, pScreen, argc, argv)int iScreen;ScreenPtr pScreen;int argc;char **argv;iScreen is the index for this screen; 0 for the first oneinitialized, 1 for the second, etc. pScreen is the pointerto the screen’s new ScreenRec. argc and argv are as before.Your screen initialize procedure should return TRUE uponsuccess or FALSE if the screen cannot be initialized (forinstance, if the screen hardware does not exist on thismachine).This procedure must determine what actual device it issupposed to initialize. If you have a different procedurefor each screen, then it is no problem. If you have thesame procedure for multiple screens, it may have troublefiguring out which screen to initialize each time around,especially if InitOutput() does not initialize all of thescreens. It is probably easiest to have one procedure foreach screen.The initialization procedure should fill in all the screenprocedures for that screen (windowing functions, regionfunctions, etc.) and certain screen attributes for thatscreen.5.2.4. Region Routines in the ScreenRecA region is a dynamically allocated data structure thatdescribes an irregularly shaped piece of real estate in XYpixel space. You can think of it as a set of pixels on thescreen to be operated upon with set operations such as ANDand OR.A region is frequently implemented as a list of rectanglesor bitmaps that enclose the selected pixels. Regionoperators control the "clipping policy," or the operationsthat work on regions. (The sample server uses YX-bandedrectangles. Unless you have something already implementedfor your graphics system, you should keep thatimplementation.) The procedure pointers to the regionoperators are located in the ScreenRec data structure. Thedefinition of a region can be found in the fileXserver/include/regionstr.h. The region code is found inXserver/mi/miregion.c. DDX implementations using otherregion formats will need to supply different versions of theregion operators.Since the list of rectangles is unbounded in size, part ofthe region data structure is usually a large, dynamicallyallocated chunk of memory. As your region operatorscalculate logical combinations of regions, these blocks mayneed to be reallocated by your region software. Forinstance, in the sample server, a RegionRec has some headerinformation and a pointer to a dynamically allocatedrectangle list. Periodically, the rectangle list needs tobe expanded with Xrealloc(), whereupon the new pointer isremembered in the RegionRec.Most of the region operations come in two forms: a functionpointer in the Screen structure, and a macro. The servercan be compiled so that the macros make direct calls to theappropriate functions (instead of indirecting through ascreen function pointer), or it can be compiled so that themacros are identical to the function pointer forms. Makingdirect calls is faster on many architectures.RegionPtr pScreen->RegionCreate( rect, size)BoxPtr rect;int size;macro: RegionPtr REGION_CREATE(pScreen, rect, size)RegionCreate creates a region that describes ONE rectangle.The caller can avoid unnecessary reallocation and copying bydeclaring the probable maximum number of rectangles thatthis region will need to describe itself. Your regionroutines, though, cannot fail just because the region growsbeyond this size. The caller of this routine can passalmost anything as the size; the value is merely a goodguess as to the maximum size until it is proven wrong bysubsequent use. Your region procedures are then on theirown in estimating how big the region will get. Yourimplementation might ignore size, if applicable.void pScreen->RegionInit (pRegion, rect, size)RegionPtr pRegion;BoxPtr rect;int size;macro: REGION_INIT(pScreen, pRegion, rect, size)Given an existing raw region structure (such as an localvariable), this routine fills in the appropriate fields tomake this region as usable as one returned fromRegionCreate. This avoids the additional dynamic memoryallocation overhead for the region structure itself.Bool pScreen->RegionCopy(dstrgn, srcrgn)RegionPtr dstrgn, srcrgn;macro: Bool REGION_COPY(pScreen, dstrgn, srcrgn)RegionCopy copies the description of one region, srcrgn, toanother already-created region, dstrgn; returning TRUE ifthe copy succeeded, and FALSE otherwise.void pScreen->RegionDestroy( pRegion)RegionPtr pRegion;macro: REGION_DESTROY(pScreen, pRegion)RegionDestroy destroys a region and frees all allocatedmemory.void pScreen->RegionUninit (pRegion)RegionPtr pRegion;macro: REGION_UNINIT(pScreen, pRegion)Frees everything except the region structure itself, usefulwhen the region was originally passed to RegionInit insteadof received from RegionCreate. When this call returns,pRegion must not be reused until it has been RegionInit’edagain.Bool pScreen->Intersect(newReg, reg1, reg2)RegionPtr newReg, reg1, reg2;macro: Bool REGION_INTERSECT(pScreen, newReg, reg1, reg2)Bool pScreen->Union(newReg, reg1, reg2)RegionPtr newReg, reg1, reg2;macro: Bool REGION_UNION(pScreen, newReg, reg1, reg2)Bool pScreen->Subtract(newReg, regMinuend, regSubtrahend)RegionPtr newReg, regMinuend, regSubtrahend;macro: Bool REGION_UNION(pScreen, newReg, regMinuend, regSubtrahend)Bool pScreen->Inverse(newReg, pReg, pBox)RegionPtr newReg, pReg;BoxPtr pBox;macro: Bool REGION_INVERSE(pScreen, newReg, pReg, pBox)The above four calls all do basic logical operations onregions. They set the new region (which already exists) todescribe the logical intersection, union, set difference, orinverse of the region(s) that were passed in. Your routinesmust be able to handle a situation where the newReg is thesame region as one of the other region arguments.The subtract function removes the Subtrahend from theMinuend and puts the result in newReg.The inverse function returns a region that is the pBox minusthe region passed in. (A true "inverse" would make a regionthat extends to infinity in all directions but has holes inthe middle.) It is undefined for situations where theregion extends beyond the box.Each routine must return the value TRUE for success.void pScreen->RegionReset(pRegion, pBox)RegionPtr pRegion;BoxPtr pBox;macro: REGION_RESET(pScreen, pRegion, pBox)RegionReset sets the region to describe one rectangle andreallocates it to a size of one rectangle, if applicable.void pScreen->TranslateRegion(pRegion, x, y)RegionPtr pRegion;int x, y;macro: REGION_TRANSLATE(pScreen, pRegion, x, y)TranslateRegion simply moves a region +x in the x directionand +y in the y direction.int pScreen->RectIn(pRegion, pBox)RegionPtr pRegion;BoxPtr pBox;macro: int RECT_IN_REGION(pScreen, pRegion, pBox)RectIn returns one of the defined constants rgnIN, rgnOUT,or rgnPART, depending upon whether the box is entirelyinside the region, entirely outside of the region, or partlyin and partly out of the region. These constants aredefined in Xserver/include/region.h.Bool pScreen->PointInRegion(pRegion, x, y, pBox)RegionPtr pRegion;int x, y;BoxPtr pBox;macro: Bool POINT_IN_REGION(pScreen, pRegion, x, y, pBox)PointInRegion returns true if the point x, y is in theregion. In addition, it fills the rectangle pBox withcoordinates of a rectangle that is entirely inside ofpRegion and encloses the point. In the mi implementation,it is the largest such rectangle. (Due to the sample serverimplementation, this comes cheaply.)This routine used by DIX when tracking the pointing deviceand deciding whether to report mouse events or change thecursor. For instance, DIX needs to change the cursor whenit moves from one window to another. Due to overlappingwindows, the shape to check may be irregular. APointInRegion() call for every pointing device movement maybe too expensive. The pBox is a kind of wake-up box; DIXneed not call PointInRegion() again until the cursor wandersoutside of the returned box.Bool pScreen->RegionNotEmpty(pRegion)RegionPtr pRegion;macro: Bool REGION_NOTEMPTY(pScreen, pRegion)RegionNotEmpty is a boolean function that returns true orfalse depending upon whether the region encloses any pixels.void pScreen->RegionEmpty(pRegion)RegionPtr pRegion;macro: REGION_EMPTY(pScreen, pRegion)RegionEmpty sets the region to be empty.BoxPtr pScreen->RegionExtents(pRegion)RegionPtr pRegion;macro: REGION_EXTENTS(pScreen, pRegion)RegionExtents returns a rectangle that is the smallestpossible superset of the entire region. The caller will notmodify this rectangle, so it can be the one in your regionstruct.Bool pScreen->RegionAppend (pDstRgn, pRegion)RegionPtr pDstRgn;RegionPtr pRegion;macro: Bool REGION_APPEND(pScreen, pDstRgn, pRegion)Bool pScreen->RegionValidate (pRegion, pOverlap)RegionPtr pRegion;Bool *pOverlap;macro: Bool REGION_VALIDATE(pScreen, pRegion, pOverlap)These functions provide an optimization for clip listgeneration and must be used in conjunction. The combinedeffect is to produce the union of a collection of regions,by using RegionAppend several times, and finally callingRegionValidate which takes the intermediate representation(which needn’t be a valid region) and produces the desiredunion. pOverlap is set to TRUE if any of the originalregions overlap; FALSE otherwise.RegionPtr pScreen->BitmapToRegion (pPixmap)PixmapPtr pPixmap;macro: RegionPtr BITMAP_TO_REGION(pScreen, pPixmap)Given a depth-1 pixmap, this routine must create a validregion which includes all the areas of the pixmap filledwith 1’s and excludes the areas filled with 0’s. Thisroutine returns NULL if out of memory.RegionPtr pScreen->RectsToRegion (nrects, pRects, ordering)int nrects;xRectangle *pRects;int ordering;macro: RegionPtr RECTS_TO_REGION(pScreen, nrects, pRects, ordering)Given a client-supplied list of rectangles, produces aregion which includes the union of all the rectangles.Ordering may be used as a hint which describes how therectangles are sorted. As the hint is provided by a client,it must not be required to be correct, but the results whenit is not correct are not defined (core dump is not anoption here).void pScreen->SendGraphicsExpose(client,pRegion,drawable,major,minor)ClientPtr client;RegionPtr pRegion;XID drawable;int major;int minor;SendGraphicsExpose dispatches a list of GraphicsExposureevents which span the region to the specified client. Ifthe region is empty, or a NULL pointer, a NoExpose event issent instead.5.2.5. Cursor Routines for a ScreenA cursor is the visual form tied to the pointing device.The default cursor is an "X" shape, but the cursor can haveany shape. When a client creates a window, it declares whatshape the cursor will be when it strays into that window onthe screen.For each possible shape the cursor assumes, there is aCursorRec data structure. This data structure contains apointer to a CursorBits data structure which contains abitmap for the image of the cursor and a bitmap for a maskbehind the cursor, in addition, the CursorRec data structurecontains foreground and background colors for the cursor.The CursorBits data structure is shared among multipleCursorRec structures which use the same font and glyph todescribe both source and mask. The cursor image is appliedto the screen by applying the mask first, clearing 1 bits inits form to the background color, and then overwriting onthe source image, in the foreground color. (One bits of thesource image that fall on top of zero bits of the mask imageare undefined.) This way, a cursor can have transparentparts, and opaque parts in two colors. X allows any cursorsize, but some hardware cursor schemes allow a maximum of Npixels by M pixels. Therefore, you are allowed to transformthe cursor to a smaller size, but be sure to include thehot-spot.CursorBits in Xserver/include/cursorstr.h is adevice-independent structure containing a device-independentrepresentation of the bits for the source and mask. (Thisis possible because the bitmap representation is the samefor all screens.)When a cursor is created, it is "realized" for each screen.At realization time, each screen has the chance to convertthe bits into some other representation that may be moreconvenient (for instance, putting the cursor into off-screenmemory) and set up its device-private area in either theCursorRec data structure or CursorBits data structure asappropriate to possibly point to whatever data structuresare needed. It is more memory-conservative to sharerealizations by using the CursorBits private field, but thismakes the assumption that the realization is independent ofthe colors used (which is typically true). For instance,the following are the device private entries for aparticular screen and cursor:pCursor->devPriv[pScreen->myNum]pCursor->bits->devPriv[pScreen->myNum]This is done because the change from one cursor shape toanother must be fast and responsive; the cursor image shouldbe able to flutter as fast as the user moves it across thescreen.You must implement the following routines for your hardware:Bool pScreen->RealizeCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;Bool pScreen->UnrealizeCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;RealizeCursor and UnrealizeCursor should realize (allocateand calculate all data needed) and unrealize (free thedynamically allocated data) a given cursor when DIX needsthem. They are called whenever a device-independent cursoris created or destroyed. The source and mask bits pointedto by fields in pCurs are undefined for bits beyond theright edge of the cursor. This is so because the bits arein Bitmap format, which may have pad bits on the right edge.You should inhibit UnrealizeCursor() if the cursor iscurrently in use; this happens when the system is reset.Bool pScreen->DisplayCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;DisplayCursor should change the cursor on the given screento the one passed in. It is called by DIX when the usermoves the pointing device into a different window with adifferent cursor. The hotspot in the cursor should bealigned with the current cursor position.void pScreen->RecolorCursor( pScr, pCurs, displayed)ScreenPtr pScr;CursorPtr pCurs;Bool displayed;RecolorCursor notifies DDX that the colors in pCurs havechanged and indicates whether this is the cursor currentlybeing displayed. If it is, the cursor hardware state mayhave to be updated. Whether displayed or not, state createdat RealizeCursor time may have to be updated. A genericversion, miRecolorCursor, may be used that does anunrealize, a realize, and possibly a display (inmicursor.c); however this constrains UnrealizeCursor andRealizeCursor to always return TRUE as no error indicationis returned here.void pScreen->ConstrainCursor( pScr, pBox)ScreenPtr pScr;BoxPtr pBox;ConstrainCursor should cause the cursor to restrict itsmotion to the rectangle pBox. DIX code is capable ofenforcing this constraint by forcefully moving the cursor ifit strays out of the rectangle, but ConstrainCursor offers away to send a hint to the driver or hardware if such supportis available. This can prevent the cursor from wanderingout of the box, then jumping back, as DIX forces it back.void pScreen->PointerNonInterestBox( pScr, pBox)ScreenPtr pScr;BoxPtr pBox;PointerNonInterestBox is DIX’s way of telling the pointingdevice code not to report motion events while the cursor isinside a given rectangle on the given screen. It isoptional and, if not implemented, it should do nothing.This routine is called only when the client has declaredthat it is not interested in motion events in a givenwindow. The rectangle you get may be a subset of thatwindow. It saves DIX code the time required to discarduninteresting mouse motion events. This is only a hint,which may speed performance. Nothing in DIX currently callsPointerNonInterestBox.void pScreen->CursorLimits( pScr, pCurs, pHotBox, pTopLeftBox)ScreenPtr pScr;CursorPtr pCurs;BoxPtr pHotBox;BoxPtr pTopLeftBox; /* return value */CursorLimits should calculate the box that the cursor hotspot is physically capable of moving within, as a functionof the screen pScr, the device-independent cursor pCurs, anda box that DIX hypothetically would want the hot spotconfined within, pHotBox. This routine is for informing DIXonly; it alters no state within DDX.Bool pScreen->SetCursorPosition( pScr, newx, newy, generateEvent)ScreenPtr pScr;int newx;int newy;Bool generateEvent;SetCursorPosition should artificially move the cursor asthough the user had jerked the pointing device very quickly.This is called in response to the WarpPointer request fromthe client, and at other times. If generateEvent is True,the device should decide whether or not to callProcessInputEvents() and then it must callDevicePtr->processInputProc. Its effects are, of course,limited in value for absolute pointing devices such as atablet.void NewCurrentScreen(newScreen, x, y)ScreenPtr newScreen;int x,y;If your ddx provides some mechanism for the user tomagically move the pointer between multiple screens, youneed to inform DIX when this occurs. You should callNewCurrentScreen to accomplish this, specifying the newscreen and the new x and y coordinates of the pointer onthat screen.5.2.6. Visuals, Depths and Pixmap Formats for ScreensThe "depth" of a image is the number of bits that are usedper pixel to display it.The "bits per pixel" of a pixmap image that is sent over theclient byte stream is a number that is either 4, 8, 16, 24or 32. It is the number of bits used per pixel in Z format.For instance, a pixmap image that has a depth of six is bestsent in Z format as 8 bits per pixel.A "pixmap image format" or a "pixmap format" is adescription of the format of a pixmap image as it is sentover the byte stream. For each depth available on a server,there is one and only one pixmap format. This pixmap imageformat gives the bits per pixel and the scanline paddingunit. (For instance, are pixel rows padded to bytes, 16-bitwords, or 32-bit words?)For each screen, you must decide upon what depth(s) itsupports. You should only count the number of bits used forthe actual image. Some displays store additional bits toindicate what window this pixel is in, how close this objectis to a viewer, transparency, and other data; do not countthese bits.A "display class" tells whether the display is monochrome orcolor, whether there is a lookup table, and how the lookuptable works.A "visual" is a combination of depth, display class, and adescription of how the pixel values result in a color on thescreen. Each visual has a set of masks and offsets that areused to separate a pixel value into its red, green, and bluecomponents and a count of the number of colormap entries.Some of these fields are only meaningful when the classdictates so. Each visual also has a screen ID telling whichscreen it is usable on. Note that the depth does not implythe number of map_entries; for instance, a display can have8 bits per pixel but only 254 colormap entries for use byapplications (the other two being reserved by hardware forthe cursor).Each visual is identified by a 32-bit visual ID which theclient uses to choose what visual is desired on a givenwindow. Clients can be using more than one visual on thesame screen at the same time.The class of a display describes how this translation takesplace. There are three ways to do the translation.• Pseudo - The pixel value, as a whole, is looked up in atable of length map_entries to determine the color todisplay.• True - The pixel value is broken up into red, green,and blue fields, each of which are looked up inseparate red, green, and blue lookup tables, each oflength map_entries.• Gray - The pixel value is looked up in a table oflength map_entries to determine a gray level todisplay.In addition, the lookup table can be static (resultingcolors are fixed for each pixel value) or dynamic (lookupentries are under control of the client program). Thisleads to a total of six classes:• Static Gray - The pixel value (of however many bits)determines directly the level of gray that the pixelassumes.• Gray Scale - The pixel value is fed through a lookuptable to arrive at the level of gray to display for thegiven pixel.• Static Color - The pixel value is fed through a fixedlookup table that yields the color to display for thatpixel.• PseudoColor - The whole pixel value is fed through aprogrammable lookup table that has one color (includingred, green, and blue intensities) for each possiblepixel value, and that color is displayed.• True Color - Each pixel value consists of one or morebits that directly determine each primary colorintensity after being fed through a fixed table.• Direct Color - Each pixel value consists of one or morebits for each primary color. Each primary color valueis individually looked up in a table for that primarycolor, yielding an intensity for that primary color.For each pixel, the red value is looked up in the redtable, the green value in the green table, and the bluevalue in the blue table.Here are some examples:A simple monochrome 1 bit per pixel display is StaticGray.A display that has 2 bits per pixel for a choicebetween the colors of black, white, green and violet isStatic Color.A display that has three bits per pixel, where each bitturns on or off one of the red, green or blue guns, isin the True Color class.If you take the last example and scramble thecorrespondence between pixel values and colors itbecomes a Static Color display.A display has 8 bits per pixel. The 8 bits select oneentry out of 256 entries in a lookup table, each entryconsisting of 24 bits (8bits each for red, green, andblue). The display can show any 256 of 16 millioncolors on the screen at once. This is a pseudocolordisplay. The client application gets to fill thelookup table in this class of display.Imagine the same hardware from the last example. Yourserver software allows the user, on the command linethat starts up the server program, to fill the lookuptable to his liking once and for all. From then on,the server software would not change the lookup tableuntil it exits. For instance, the default might be alookup table with a reasonable sample of colors fromthroughout the color space. But the user could specifythat the table be filled with 256 steps of gray scalebecause he knew ahead of time he would be manipulatinga lot of black-and-white scanned photographs and notvery many color things. Clients would be presentedwith this unchangeable lookup table. Although thehardware qualifies as a PseudoColor display, the facadepresented to the X client is that this is a StaticColor display.You have to decide what kind of display you have orwant to pretend you have. When you initialize thescreen(s), this class value must be set in theVisualRec data structure along with other displaycharacteristics like the depth and other numbers.The allowable DepthRec’s and VisualRec’s are pointed toby fields in the ScreenRec. These are set up whenInitOutput() is called; you should Xalloc() appropriateblocks or use static variables initialized to thecorrect values.5.2.7. Colormaps for ScreensA colormap is a device-independent mapping between pixelvalues and colors displayed on the screen.Different windows on the same screen can have differentcolormaps at the same time. At any given time, the mostrecently installed colormap(s) will be in use in the serverso that its (their) windows’ colors will be guaranteed to becorrect. Other windows may be off-color. Although this mayseem to be chaotic, in practice most clients use the defaultcolormap for the screen.The default colormap for a screen is initialized when thescreen is initialized. It always remains in existence andis not owned by any regular client. It is owned by client 0(the server itself). Many clients will simply use thisdefault colormap for their drawing. Depending upon theclass of the screen, the entries in this colormap may bemodifiable by client applications.5.2.7.1. Colormap RoutinesYou need to implement the following routines to handle thedevice-dependent aspects of color maps. You will end upplacing pointers to these procedures in your ScreenRec datastructure(s). The sample server implementations of many ofthese routines are in both cfbcmap.c and mfbcmap.c; sincemfb does not do very much with color, the cfb versions aretypically more useful prototypes.Bool pScreen->CreateColormap(pColormap)ColormapPtr pColormap;This routine is called by the DIX CreateColormap routineafter it has allocated all the data for the new colormap andjust before it returns to the dispatcher. It is the DDXlayer’s chance to initialize the colormap, particularly ifit is a static map. See the following section for moredetails on initializing colormaps. The routine returnsFALSE if creation failed, such as due to memory limitations.Notice that the colormap has a devPriv field from which youcan hang any colormap specific storage you need. Since eachcolormap might need special information, we attached thefield to the colormap and not the visual.void pScreen->DestroyColormap(pColormap)ColormapPtr pColormap;This routine is called by the DIX FreeColormap routine afterit has uninstalled the colormap and notified all interestedparties, and before it has freed any of the colormapstorage. It is the DDX layer’s chance to free any data itadded to the colormap.void pScreen->InstallColormap(pColormap)ColormapPtr pColormap;InstallColormap should fill a lookup table on the screenwith which the colormap is associated with the colors inpColormap. If there is only one hardware lookup table forthe screen, then all colors on the screen may changesimultaneously.In the more general case of multiple hardware lookup tables,this may cause some other colormap to be uninstalled,meaning that windows that subscribed to the colormap thatwas uninstalled may end up being off-color. See the note,below, about uninstalling maps.void pScreen->UninstallColormap(pColormap)ColormapPtr pColormap;UninstallColormap should remove pColormap from screenpColormap->pScreen. Some other map, such as the default mapif possible, should be installed in place of pColormap ifapplicable. If pColormap is the default map, do nothing.If any client has requested ColormapNotify events, the DDXlayer must notify the client. (The routine WalkTree() is beused to find such windows. The DIX routines TellNoMap(),TellNewMap() and TellGainedMap() are provided to be used asthe procedure parameter to WalkTree. These procedures arein Xserver/dix/colormap.c.)int pScreen->ListInstalledColormaps(pScreen, pCmapList)ScreenPtr pScreen;XID *pCmapList;ListInstalledColormaps fills the pCMapList in with theresource ids of the installed maps and returns a count ofinstalled maps. pCmapList will point to an array of sizeMaxInstalledMaps that was allocated by the caller.void pScreen->StoreColors (pmap, ndef, pdefs)ColormapPtr pmap;int ndef;xColorItem *pdefs;StoreColors changes some of the entries in the colormappmap. The number of entries to change are ndef, and pdefspoints to the information describing what to change. Notethat partial changes of entries in the colormap are allowed.Only the colors indicated in the flags field of eachxColorItem need to be changed. However, all three colorfields will be sent with the proper value for the benefit ofscreens that may not be able to set part of a colormapvalue. If the screen is a static class, this routine doesnothing. The structure of colormap entries is nontrivial;see colormapst.h and the definition of xColorItem inXproto.h for more details.void pScreen->ResolveColor(pRed, pGreen, pBlue, pVisual)unsigned short *pRed, *pGreen, *pBlue;VisualPtr pVisual;Given a requested color, ResolveColor returns the nearestcolor that this hardware is capable of displaying on thisvisual. In other words, this rounds off each value, inplace, to the number of bits per primary color that yourscreen can use. Remember that each screen has one of theseroutines. The level of roundoff should be what you wouldexpect from the value you put in the bits_per_rgb field ofthe pVisual.Each value is an unsigned value ranging from 0 to 65535.The bits least likely to be used are the lowest ones.For example, if you had a pseudocolor display with anynumber of bits per pixel that had a lookup table supplying 6bits for each color gun (a total of 256K different colors),you would round off each value to 6 bits. Please don’tsimply truncate these values to the upper 6 bits, scale theresult so that the maximum value seen by the client will be65535 for each primary. This makes color values moreportable between different depth displays (a 6-bit truncatedwhite will not look white on an 8-bit display).5.2.7.2. Initializing a ColormapWhen a client requests a new colormap and when the servercreates the default colormap, the procedure CreateColormapin the DIX layer is invoked. That procedure allocatesmemory for the colormap and related storage such as thelists of which client owns which pixels. It then sets abit, BeingCreated, in the flags field of the ColormapRec andcalls the DDX layer’s CreateColormap routine. This is yourchance to initialize the colormap. If the colormap isstatic, which you can tell by looking at the class field,you will want to fill in each color cell to match thehardwares notion of the color for that pixel. If thecolormap is the default for the screen, which you can tellby looking at the IsDefault bit in the flags field, youshould allocate BlackPixel and WhitePixel to match thevalues you set in the pScreen structure. (Of course, youpicked those values to begin with.)You can also wait and use AllocColor() to allocateblackPixel and whitePixel after the default colormap hasbeen created. If the default colormap is static and youinitialized it in pScreen->CreateColormap, then use can useAllocColor afterwards to choose pixel values with theclosest rgb values to those desired for blackPixel andwhitePixel. If the default colormap is dynamic anduninitialized, then the rgb values you request will beobeyed, and AllocColor will again choose pixel values foryou. These pixel values can then be stored into the screen.There are two ways to fill in the colormap. The simplestway is to use the DIX function AllocColor.int AllocColor (pmap, pred, pgreen, pblue, pPix, client)ColormapPtr pmap;unsigned short *pred, *pgreen, *pblue;Pixel *pPix;int client;This takes three pointers to 16 bit color values and apointer to a suggested pixel value. The pixel value iseither an index into one colormap or a combination of threeindices depending on the type of pmap. If your colormapstarts out empty, and you don’t deliberately pick the samevalue twice, you will always get your suggested pixel. Thetruly nervous could check that the value returned in *pPixis the one AllocColor was called with. If you don’t carewhich pixel is used, or would like them sequentiallyallocated from entry 0, set *pPix to 0. This will find thefirst free pixel and use that.AllocColor will take care of all the bookkeeping and willcall StoreColors to get the colormap rgb values initialized.The hardware colormap will be changed whenever this colormapis installed.If for some reason AllocColor doesn’t do what you want, youcan do your own bookkeeping and call StoreColors yourself.This is much more difficult and shouldn’t be necessary formost devices.5.2.8. Fonts for ScreensA font is a set of bitmaps that depict the symbols in acharacter set. Each font is for only one typeface in agiven size, in other words, just one bitmap for eachcharacter. Parallel fonts may be available in a variety ofsizes and variations, including "bold" and "italic." Xsupports fonts for 8-bit and 16-bit character codes (fororiental languages that have more than 256 characters in thefont). Glyphs are bitmaps for individual characters.The source comes with some useful font files in an ASCII,plain-text format that should be comprehensible on a widevariety of operating systems. The text format, referred toas BDF, is a slight extension of the current Adobe 2.1Bitmap Distribution Format (Adobe Systems, Inc.).A short paper in PostScript format is included with thesample server that defines BDF. It includes helpfulpictures, which is why it is done in PostScript and is notincluded in this document.Your implementation should include some sort of fontcompiler to read these files and generate binary files thatare directly usable by your server implementation. Thesample server comes with the source for a font compiler.It is important the font properties contained in the BDFfiles are preserved across any font compilation. Inparticular, copyright information cannot be casually tossedaside without legal ramifications. Other properties will beimportant to some sophisticated applications.All clients get font information from the server.Therefore, your server can support any fonts it wants to.It should probably support at least the fonts supplied withthe X11 tape. In principle, you can convert fonts fromother sources or dream up your own fonts for use on yourserver.5.2.8.1. Portable Compiled FormatA font compiler is supplied with the sample server. It hascompile-time switches to convert the BDF files into aportable binary form, called Portable Compiled Format orPCF. This allows for an arbitrary data format inside thefile, and by describing the details of the format in theheader of the file, any PCF file can be read by any PCFreading client. By selecting the format which matches therequired internal format for your renderer, the PCF readercan avoid reformatting the data each time it is read in.The font compiler should be quite portable.The fonts included with the tape are stored in fonts/bdf.The font compiler is found in fonts/tools/bdftopcf.5.2.8.2. Font RealizationEach screen configured into the server has an opportunity atfont-load time to "realize" a font into some internal formatif necessary. This happens every time the font is loadedinto memory.A font (FontRec in Xserver/include/dixfontstr.h) is adevice-independent structure containing a device-independentrepresentation of the font. When a font is created, it is"realized" for each screen. At this point, the screen hasthe chance to convert the font into some other format. TheDDX layer can also put information in the devPrivatestorage.Bool pScreen->RealizeFont(pScr, pFont)ScreenPtr pScr;FontPtr pFont;Bool pScreen->UnrealizeFont(pScr, pFont)ScreenPtr pScr;FontPtr pFont;RealizeFont and UnrealizeFont should calculate and allocatethese extra data structures and dispose of them when nolonger needed. These are called in response to OpenFont andCloseFont requests from the client. The sample serverimplementation is in mfbfont.c (which does very little).5.2.9. Other Screen RoutinesYou must supply several other screen-specific routines foryour X server implementation. Some of these are describedin other sections:• GetImage() is described in the Drawing Primitivessection.• GetSpans() is described in the Pixblit routine section.• Several window and pixmap manipulation procedures aredescribed in the Window section under Drawables.• The CreateGC() routine is described under GraphicsContexts.void pScreen->QueryBestSize(kind, pWidth, pHeight)int kind;unsigned short *pWidth, *pHeight;ScreenPtr pScreen;QueryBestSize() returns the best sizes for cursors, tiles,and stipples in response to client requests. kind is one ofthe defined constants CursorShape, TileShape, orStippleShape (defined in X.h). For CursorShape, return themaximum width and height for cursors that you can handle.For TileShape and StippleShape, start with the suggestedvalues in pWidth and pHeight and modify them in place to beoptimal values that are greater than or equal to thesuggested values. The sample server implementation is inXserver/mfb/mfbmisc.c.pScreen->SourceValidate(pDrawable, x, y, width, height)DrawablePtr pDrawable;int x, y, width, height;SourceValidate should be called by CopyArea/CopyPlaneprimitives when the source drawable is not the same as thedestination, and the SourceValidate function pointer in thescreen is non-null. If you know that you will never needSourceValidate, you can avoid this check. Currently,SourceValidate is used by the mi software cursor code toremove the cursor from the screen when the source rectangleoverlaps the cursor position. x,y,width,height describe thesource rectangle (source relative, that is) for the copyoperation.Bool pScreen->SaveScreen(pScreen, on)ScreenPtr pScreen;int on;SaveScreen() is used for Screen Saver support (seeWaitForSomething()). pScreen is the screen to save.Bool pScreen->CloseScreen(pScreen)ScreenPtr pScreen;When the server is reset, it calls this routine for eachscreen.Bool pScreen->CreateScreenResources(pScreen)ScreenPtr pScreen;If this routine is not NULL, it will be called once perscreen per server initialization/reset after all moduleshave had a chance to register their devPrivates on allstructures that support them (see the section on devPrivatesbelow). If you need to create any resources that havedynamic devPrivates as part of your screen initialization,you should do so in this function instead of in the screeninit function passed to AddScreen to guarantee that theresources have a complete set of devPrivates. This routinereturns TRUE if successful.5.3. DrawablesA drawable is a descriptor of a surface that graphics aredrawn into, either a window on the screen or a pixmap inmemory.Each drawable has a type, class, ScreenPtr for the screen itis associated with, depth, position, size, and serialnumber. The type is one of the defined constantsDRAWABLE_PIXMAP, DRAWABLE_WINDOW and UNDRAWABLE_WINDOW. (Anundrawable window is used for window class InputOnly.) Theserial number is guaranteed to be unique across drawables,and is used in determining the validity of the clippinginformation in a GC. The screen selects the set ofprocedures used to manipulate and draw into the drawable.Position is used (currently) only by windows; pixmaps mustset these fields to 0,0 as this reduces the amount ofconditional code executed throughout the mi code. Sizeindicates the actual client-specified size of the drawable.There are, in fact, no other fields that a window drawableand pixmap drawable have in common besides those mentionedhere.Both PixmapRecs and WindowRecs are structs that start with adrawable and continue on with more fields. Pixmaps havedevPrivate pointers which usually point to the pixmap databut could conceivably be used for anything that DDX wants.Both windows and pixmaps have an array of devPrivatesunions, one entry of which will probably be used for DDXspecific data. Entries in this array are allocated usingAllocate{Window|Pixmap}PrivateIndex() (see Wrappers anddevPrivates below). This is done because different graphicshardware has different requirements for management; if thegraphics is always handled by a processor with anindependent address space, there is no point having apointer to the bit image itself.The definition of a drawable and a pixmap can be found inthe file Xserver/include/pixmapstr.h. The definition of awindow can be found in the file Xserver/include/windowstr.h.5.3.1. PixmapsA pixmap is a three-dimensional array of bits storedsomewhere offscreen, rather than in the visible portion ofthe screen’s display frame buffer. It can be used as asource or destination in graphics operations. There is noimplied interpretation of the pixel values in a pixmap,because it has no associated visual or colormap. There isonly a depth that indicates the number of significant bitsper pixel. Also, there is no implied physical size for eachpixel; all graphic units are in numbers of pixels.Therefore, a pixmap alone does not constitute a completeimage; it represents only a rectangular array of pixelvalues.Note that the pixmap data structure is reference-counted.The server implementation is free to put the pixmap dataanywhere it sees fit, according to its graphics hardwaresetup. Many implementations will simply have the datadynamically allocated in the server’s address space. Moresophisticated implementations may put the data inundisplayed framebuffer storage.In addition to dynamic devPrivates (see the section ondevPrivates below), the pixmap data structure has two fieldsthat are private to the device. Although you can use themfor anything you want, they have intended purposes. devKindis intended to be a device specific indication of the pixmaplocation (host memory, off-screen, etc.). In the sampleserver, since all pixmaps are in memory, devKind stores thewidth of the pixmap in bitmap scanline units. devPrivate isprobably a pointer to the bits in the pixmap.A bitmap is a pixmap that is one bit deep.PixmapPtr pScreen->CreatePixmap(pScreen, width, height, depth)ScreenPtr pScreen;int width, height, depth;This ScreenRec procedure must create a pixmap of the sizerequested. It must allocate a PixmapRec and fill in all ofthe fields. The reference count field must be set to 1. Ifwidth or height are zero, no space should be allocated forthe pixmap data, and if the implementation is using thedevPrivate field as a pointer to the pixmap data, it shouldbe set to NULL. If successful, it returns a pointer to thenew pixmap; if not, it returns NULL. SeeXserver/mfb/mfbpixmap.c for the sample serverimplementation.Bool pScreen->DestroyPixmap(pPixmap)PixmapPtr pPixmap;This ScreenRec procedure must "destroy" a pixmap. It shoulddecrement the reference count and, if zero, it mustdeallocate the PixmapRec and all attached devPrivate blocks.If successful, it returns TRUE. See Xserver/mfb/mfbpixmap.cfor the sample server implementation.BoolpScreen->ModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData)PixmapPtr pPixmap;int width;int height;int depth;int bitsPerPixel;int devKind;pointer pPixData;This routine takes a pixmap header (the PixmapRec plus allthe dynamic devPrivates) and initializes the fields of thePixmapRec to the parameters of the same name. pPixmap musthave been created via pScreen->CreatePixmap with a zerowidth or height to avoid allocating space for the pixmapdata. pPixData is assumed to be the pixmap data; it will bestored in an implementation-dependent place (usuallypPixmap->devPrivate.ptr). This routine returns TRUE ifsuccessful. See Xserver/mi/miscrinit.c for the sampleserver implementation.PixmapPtrGetScratchPixmapHeader(pScreen, width, height, depth, bitsPerPixel, devKind, pPixData)ScreenPtr pScreen;int width;int height;int depth;int bitsPerPixel;int devKind;pointer pPixData;void FreeScratchPixmapHeader(pPixmap)PixmapPtr pPixmap;DDX should use these two DIX routines when it has a bufferof raw image data that it wants to manipulate as a pixmaptemporarily, usually so that some other part of the servercan be leveraged to perform some operation on the data. Thedata should be passed in pPixData, and will be stored in animplementation-dependent place (usuallypPixmap->devPrivate.ptr). The other fields go into thecorresponding PixmapRec fields. If successful,GetScratchPixmapHeader returns a valid PixmapPtr which canbe used anywhere the server expects a pixmap, else itreturns NULL. The pixmap should be released when no longerneeded (usually within the same function that allocated it)with FreeScratchPixmapHeader.5.3.2. WindowsA window is a visible, or potentially visible, rectangle onthe screen. DIX windowing functions maintain an internaln-ary tree data structure, which represents the currentrelationships of the mapped windows. Windows that arecontained in another window are children of that window andare clipped to the boundaries of the parent. The rootwindow in the tree is the window for the entire screen.Sibling windows constitute a doubly-linked list; the parentwindow has a pointer to the head and tail of this list.Each child also has a pointer to its parent.The border of a window is drawn by a DDX procedure when DIXrequests that it be drawn. The contents of the window isdrawn by the client through requests to the server.Window painting is orchestrated through an expose eventsystem. When a region is exposed, DIX generates an exposeevent, telling the client to repaint the window and passingthe region that is the minimal area needed to be repainted.As a favor to clients, the server may retain the output tothe hidden parts of windows in off-screen memory; this iscalled "backing store". When a part of such a windowbecomes exposed, it can quickly move pixels into placeinstead of triggering an expose event and waiting for aclient on the other end of the network to respond. Even ifthe network response is insignificant, the time tointelligently paint a section of a window is usually morethan the time to just copy already-painted sections. Atbest, the repainting involves blanking out the area to abackground color, which will take about the same amount oftime. In this way, backing store can dramatically increasethe performance of window moves.On the other hand, backing store can be quite complex,because all graphics drawn to hidden areas must beintercepted and redirected to the off-screen windowsections. Not only can this be complicated for the serverprogrammer, but it can also impact window paintingperformance. The backing store implementation can choose,at any time, to forget pieces of backing that are writteninto, relying instead upon expose events to repaint forsimplicity.In X, the decision to use the backing-store scheme is madeby you, the server implementor. X provides hooks forimplementing backing store, therefore the decision to usethis strategy can be made on the fly. For example, you mayuse backing store only for certain windows that the userrequests or you may use backing store until memory runs out,at which time you start dropping pieces of backing as neededto make more room.When a window operation is requested by the client, such asa window being created or moved, a new state is computed.During this transition, DIX informs DDX what rectangles inwhat windows are about to become obscured and whatrectangles in what windows have become exposed. Thisprovides a hook for the implementation of backing store. IfDDX is unable to restore exposed regions, DIX generatesexpose events to the client. It is then the client’sresponsibility to paint the window parts that were exposedbut not restored.If a window is resized, pixels sometimes need to be moved,depending upon the application. The client can request"Gravity" so that certain blocks of the window are moved asa result of a resize. For instance, if the window hascontrols or other items that always hang on the edge of thewindow, and that edge is moved as a result of the resize,then those pixels should be moved to avoid having the clientrepaint it. If the client needs to repaint it anyway, suchan operation takes time, so it is desirable for the serverto approximate the appearance of the window as best it canwhile waiting for the client to do it perfectly. Gravity isused for that, also.The window has several fields used in drawing operations:• clipList - This region, in conjunction with the clientclip region in the gc, is used to clip output.clipList has the window’s children subtracted from it,in addition to pieces of sibling windows that overlapthis window. To get the list with the childrenincluded (subwindow-mode is IncludeInferiors), theroutine NotClippedByChildren(pWin) returns theunclipped region.• borderClip is the region used by CopyWindow andincludes the area of the window, its children, and theborder, but with the overlapping areas of siblingchildren removed.Most of the other fields are for DIX use only.5.3.2.1. Window Procedures in the ScreenRecYou should implement all of the following procedures andstore pointers to them in the screen record.The device-independent portion of the server "owns" thewindow tree. However, clever hardware might want to knowthe relationship of mapped windows. There are pointers toprocedures in the ScreenRec data structure that are calledto give the hardware a chance to update its internal state.These are helpers and hints to DDX only; they do not changethe window tree, which is only changed by DIX.Bool pScreen->CreateWindow(pWin)WindowPtr pWin;This routine is a hook for when DIX creates a window. Itshould fill in the "Window Procedures in the WindowRec"below and also allocate the devPrivate block for it.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->DestroyWindow(pWin);WindowPtr pWin;This routine is a hook for when DIX destroys a window. Itshould deallocate the devPrivate block for it and any otherblocks that need to be freed, besides doing other cleanupactions.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->PositionWindow(pWin, x, y);WindowPtr pWin;int x, y;This routine is a hook for when DIX moves or resizes awindow. It should do whatever private operations need to bedone when a window is moved or resized. For instance, ifDDX keeps a pixmap tile used for drawing the background orborder, and it keeps the tile rotated such that it islongword aligned to longword locations in the frame buffer,then you should rotate your tiles here. The actual graphicsinvolved in moving the pixels on the screen and drawing theborder are handled by CopyWindow(), below.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->RealizeWindow(pWin);WindowPtr pWin;Bool pScreen->UnrealizeWindow(pWin);WindowPtr pWin;These routines are hooks for when DIX maps (makes visible)and unmaps (makes invisible) a window. It should dowhatever private operations need to be done when thesehappen, such as allocating or deallocating structures thatare only needed for visible windows. RealizeWindow does NOTdraw the window border, background or contents;UnrealizeWindow does NOT erase the window or generateexposure events for underlying windows; this is taken careof by DIX. DIX does, however, call PaintWindowBackground()and PaintWindowBorder() to perform some of these.Bool pScreen->ChangeWindowAttributes(pWin, vmask)WindowPtr pWin;unsigned long vmask;ChangeWindowAttributes is called whenever DIX changes windowattributes, such as the size, front-to-back ordering, title,or anything of lesser severity that affects the windowitself. The sample server implements this routine. Itcomputes accelerators for quickly putting up background andborder tiles. (See description of the set of routinesstored in the WindowRec.)int pScreen->ValidateTree(pParent, pChild, kind)WindowPtr pParent, pChild;VTKind kind;ValidateTree calculates the clipping region for the parentwindow and all of its children. This routine must beprovided. The sample server has a machine-independentversion in Xserver/mi/mivaltree.c. This is a very difficultroutine to replace.void pScreen->PostValidateTree(pParent, pChild, kind)WindowPtr pParent, pChild;VTKind kind;If this routine is not NULL, DIX calls it shortly aftercalling ValidateTree, passing it the same arguments. Thisis useful for managing multi-layered framebuffers. Thesample server sets this to NULL.void pScreen->WindowExposures(pWin, pRegion, pBSRegion)WindowPtr pWin;RegionPtr pRegion;RegionPtr pBSRegion;The WindowExposures() routine paints the border andgenerates exposure events for the window. pRegion is anunoccluded region of the window, and pBSRegion is anoccluded region that has backing store. Since exposureevents include a rectangle describing what was exposed, thisroutine may have to send back a series of exposure events,one for each rectangle of the region. The count field inthe expose event is a hint to the client as to the number ofregions that are after this one. This routine must beprovided. The sample server has a machine-independentversion in Xserver/mi/miexpose.c.void pScreen->ClipNotify (pWin, dx, dy)WindowPtr pWin;int dx, dy;Whenever the cliplist for a window is changed, this functionis called to perform whatever hardware manipulations mightbe necessary. When called, the clip list and border clipregions in the window are set to the new values. dx,dy arethe distance that the window has been moved (if at all).5.3.2.2. Window Painting ProceduresIn addition to the procedures listed above, there are fourroutines which manipulate the actual window image directly.In the sample server, mi implementations will work for mostpurposes and mfb/cfb routines speed up situations, such assolid backgrounds/borders or tiles that are 8, 16 or 32pixels square.These three routines are used for systems that implement abacking-store scheme for it to know when to stash away areasof pixels and to restore or reposition them.void pScreen->ClearToBackground(pWin, x, y, w, h, generateExposures);WindowPtr pWin;int x, y, w, h;Bool generateExposures;This routine is called on a window in response to aClearToBackground request from the client. This request hastwo different but related functions, depending upongenerateExposures.If generateExposures is true, the client is declaring thatthe given rectangle on the window is incorrectly painted andneeds to be repainted. The sample server implementationcalculates the exposure region and hands it to the DIXprocedure HandleExposures(), which calls theWindowExposures() routine, below, for the window and all ofits child windows.If generateExposures is false, the client is trying tosimply erase part of the window to the background fillstyle. ClearToBackground should write the background coloror tile to the rectangle in question (probably usingPaintWindowBackground). If w or h is zero, it clears allthe way to the right or lower edge of the window.The sample server implementation is inXserver/mi/miwindow.c.void pScreen->PaintWindowBackground(pWin, region, kind)WindowPtr pWin;RegionPtr region;int kind; /* must be PW_BACKGROUND */void pScreen->PaintWindowBorder(pWin, region, kind)WindowPtr pWin;RegionPtr region;int kind; /* must be PW_BORDER */These two routines are for painting pieces of the windowbackground or border. They both actually paint the areadesignated by region. The kind parameter is a definedconstant that is always PW_BACKGROUND or PW_BORDER, asshown. Therefore, you can use the same routine for both.The defined constant tells the routine whether to use thewindow’s border fill style or its background fill style topaint the given region. Both fill styles consist of a unionwhich holds a tile pointer and a pixel value, along with aseparate variable which indicates which entry is valid. ForPW_BORDER, borderIsPixel != 0 indicates that the borderPixUnion contains a pixel value, else a tile. ForPW_BACKGROUND there are four values, contained inbackgroundState; None, ParentRelative, BackgroundPixmap andBackgroundPixel. None indicates that the region should beleft unfilled, while ParentRelative indicates that thebackground of the parent is inherited (see the Protocoldocument for the exact semantics).void pScreen->CopyWindow(pWin, oldpt, oldRegion);WindowPtr pWin;DDXPointRec oldpt;RegionPtr oldRegion;CopyWindow is called when a window is moved, and graphicallymoves to pixels of a window on the screen. It should notchange any other state within DDX (see PositionWindow(),above).oldpt is the old location of the upper-left corner.oldRegion is the old region it is coming from. The newlocation and new region is stored in the WindowRec.oldRegion might modified in place by this routine (thesample implementation does this).CopyArea could be used, except that this operation has morecomplications. First of all, you do not want to copy arectangle onto a rectangle. The original window may beobscured by other windows, and the new window location maybe similarly obscured. Second, some hardware supportsmultiple windows with multiple depths, and your routineneeds to take care of that.The pixels in oldRegion (with reference point oldpt) arecopied to the window’s new region (pWin->borderClip).pWin->borderClip is gotten directly from the window, ratherthan passing it as a parameter.The sample server implementation is inXserver/mfb/mfbwindow.c.5.3.2.3. Screen Operations for Backing StoreEach ScreenRec has six functions which provide the backingstore interface. For screens not supporting backing store,these pointers may be nul. Servers that implement somebacking store scheme must fill in the procedure pointers forthe procedures below, and must maintain the backStoragefield in each window struct. The sample implementation isin mi/mibstore.c.void pScreen->SaveDoomedAreas(pWin, pRegion, dx, dy)WindowPtr pWin;RegionPtr pRegion;int dx, dy;This routine saves the newly obscured region, pRegion, inbacking store. dx, dy indicate how far the window is beingmoved, useful as the obscured region is relative to thewindow as it will appear in the new location, rather thenrelative to the bits as the are on the screen when thefunction is invoked.RegionPtr pScreen->RestoreAreas(pWin, pRegion)WindowPtr pWin;RegionPtr pRegion;This looks at the exposed region of the window, pRegion, andtries to restore to the screen the parts that have beensaved. It removes the restored parts from the backingstorage (because they are now on the screen) and subtractsthe areas from the exposed region. The returned region isthe area of the window which should have expose eventsgenerated for and can be either a new region, pWin->exposed,or NULL. The region left in pRegion is set to the area ofthe window which should be painted with the windowbackground.RegionPtr pScreen->TranslateBackingStore(pWin, dx, dy, oldClip, oldx, oldy)WindowPtr pWin;int dx, dy;RegionPtr oldClip;int oldx, oldy;This is called when the window is moved or resized so thatthe backing store can be translated if necessary. oldClipis the old cliplist for the window, which is used to savedoomed areas if the window is moved underneath its parent asa result of bitgravity. The returned region representsoccluded areas of the window for which the backing storecontents are invalid.void pScreen->ExposeCopy(pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane)WindowPtr pSrc;DrawablePtr pDst;GCPtr pGC;RegionPtr prgnExposed;int srcx;int srcy;int dstx;int dsty;unsigned long plane;Copies a region from the backing store of pSrc to pDst.RegionPtr pScreen->ClearBackingStore(pWindow, x, y, w, h, generateExposures)WindowPtr pWindow;int x;int y;int w;int h;Bool generateExposures;Clear the given area of the backing pixmap with thebackground of the window. If generateExposures is TRUE,generate exposure events for the area. Note that if the areahas any part outside the saved portions of the window, we donot allow the count in the expose events to be 0, sincethere will be more expose events to come.void pScreen->DrawGuarantee(pWindow, pGC, guarantee)WindowPtr pWindow;GCPtr pGC;int guarantee;This informs the backing store layer that you are about tovalidate a gc with a window, and that subsequent output tothe window is (or is not) guaranteed to be already clippedto the visible regions of the window.5.3.2.4. Screen Operations for Multi-Layered FramebuffersThe following screen functions are useful if you have aframebuffer with multiple sets of independent bit planes,e.g. overlays or underlays in addition to the "main" planes.If you have a simple single-layer framebuffer, you shouldprobably use the mi versions of these routines inmi/miwindow.c. This can be easily accomplished by callingmiScreenInit.void pScreen->MarkWindow(pWin)WindowPtr pWin;This formerly dix function MarkWindow has moved to ddx andis accessed via this screen function. This function shouldstore something, usually a pointer to a device-dependentstructure, in pWin->valdata so that ValidateTree has theinformation it needs to validate the window.Bool pScreen->MarkOverlappedWindows(parent, firstChild, ppLayerWin)WindowPtr parent;WindowPtr firstChild;WindowPtr * ppLayerWin;This formerly dix function MarkWindow has moved to ddx andis accessed via this screen function. In the process, ithas grown another parameter: ppLayerWin, which is filled inwith a pointer to the window at which save under marking andValidateTree should begin. In the single-layeredframebuffer case, pLayerWin == pWin.Bool pScreen->ChangeSaveUnder(pLayerWin, firstChild)WindowPtr pLayerWin;WindowPtr firstChild;The dix functions ChangeSaveUnder and CheckSaveUnder havemoved to ddx and are accessed via this screen function.pLayerWin should be the window returned in the ppLayerWinparameter of MarkOverlappedWindows. The function may turnon backing store for windows that might be covered, and maypartially turn off backing store for windows. It returnsTRUE if PostChangeSaveUnder needs to be called to finishturning off backing store.void pScreen->PostChangeSaveUnder(pLayerWin, firstChild)WindowPtr pLayerWin;WindowPtr firstChild;The dix function DoChangeSaveUnder has moved to ddx and isaccessed via this screen function. This function completesthe job of turning off backing store that was started byChangeSaveUnder.void pScreen->MoveWindow(pWin, x, y, pSib, kind)WindowPtr pWin;int x;int y;WindowPtr pSib;VTKind kind;The formerly dix function MoveWindow has moved to ddx and isaccessed via this screen function. The new position of thewindow is given by x,y. kind is VTMove if the window isonly moving, or VTOther if the border is also changing.void pScreen->ResizeWindow(pWin, x, y, w, h, pSib)WindowPtr pWin;int x;int y;unsigned int w;unsigned int h;WindowPtr pSib;The formerly dix function SlideAndSizeWindow has moved toddx and is accessed via this screen function. The newposition is given by x,y. The new size is given by w,h.WindowPtr pScreen->GetLayerWindow(pWin)WindowPtr pWinThis is a new function which returns a child of the layerparent of pWin.void pScreen->HandleExposures(pWin)WindowPtr pWin;The formerly dix function HandleExposures has moved to ddxand is accessed via this screen function. This function iscalled after ValidateTree and uses the information containedin valdata to send exposures to windows.void pScreen->ReparentWindow(pWin, pPriorParent)WindowPtr pWin;WindowPtr pPriorParent;This function will be called when a window is reparented.At the time of the call, pWin will already be spliced intoits new position in the window tree, and pPriorParent is itsprevious parent. This function can be NULL.void pScreen->SetShape(pWin)WindowPtr pWin;The formerly dix function SetShape has moved to ddx and isaccessed via this screen function. The window’s new shapewill have already been stored in the window when thisfunction is called.void pScreen->ChangeBorderWidth(pWin, width)WindowPtr pWin;unsigned int width;The formerly dix function ChangeBorderWidth has moved to ddxand is accessed via this screen function. The new borderwidth is given by width.void pScreen->MarkUnrealizedWindow(pChild, pWin, fromConfigure)WindowPtr pChild;WindowPtr pWin;Bool fromConfigure;This function is called for windows that are beingunrealized as part of an UnrealizeTree. pChild is thewindow being unrealized, pWin is an ancestor, and thefromConfigure value is simply propogated from UnrealizeTree.5.4. Graphics Contexts and ValidationThis graphics context (GC) contains state variables such asforeground and background pixel value (color), the currentline style and width, the current tile or stipple forpattern generation, the current font for text generation,and other similar attributes.In many graphics systems, the equivalent of the graphicscontext and the drawable are combined as one entity. Themain distinction between the two kinds of status is that adrawable describes a writing surface and the writings thatmay have already been done on it, whereas a graphics contextdescribes the drawing process. A drawable is like achalkboard. A GC is like a piece of chalk.Unlike many similar systems, there is no "current penlocation." Every graphic operation is accompanied by thecoordinates where it is to happen.The GC also includes two vectors of procedure pointers, thefirst operate on the GC itself and are called GC funcs. Thesecond, called GC ops, contains the functions that carry outthe fundamental graphic operations such as drawing lines,polygons, arcs, text, and copying bitmaps. The DDX graphicsoftware can, if it wants to be smart, change these twovectors of procedure pointers to take advantage ofhardware/firmware in the server machine, which can do abetter job under certain circumstances. To reduce theamount of memory consumed by each GC, it is wise to create afew "boilerplate" GC ops vectors which can be shared byevery GC which matches the constraints for that set. Also,it is usually reasonable to have every GC created by aparticular module to share a common set of GC funcs.Samples of this sort of sharing can be seen in cfb/cfbgc.cand mfb/mfbgc.c.The DDX software is notified any time the client (or DIX)uses a changed GC. For instance, if the hardware hasspecial support for drawing fixed-width fonts, DDX canintercept changes to the current font in a GC just beforedrawing is done. It can plug into either a fixed-widthprocedure that makes the hardware draw characters, or avariable-width procedure that carefully lays out glyphs byhand in software, depending upon the new font that isselected.A definition of these structures can be found in the fileXserver/include/gcstruct.h.Also included in each GC is an array of devPrivates whichportions of the DDX can use for any reason. Entries in thisarray are allocated with AllocateGCPrivateIndex() (seeWrappers and Privates below).The DIX routines available for manipulating GCs areCreateGC, ChangeGC, CopyGC, SetClipRects, SetDashes, andFreeGC.GCPtr CreateGC(pDrawable, mask, pval, pStatus)DrawablePtr pDrawable;BITS32 mask;XID *pval;int *pStatus;int ChangeGC(pGC, mask, pval)GCPtr pGC;BITS32 mask;XID *pval;int CopyGC(pgcSrc, pgcDst, mask)GCPtr pgcSrc;GCPtr pgcDst;BITS32 mask;int SetClipRects(pGC, xOrigin, yOrigin, nrects, prects, ordering)GCPtr pGC;int xOrigin, yOrigin;int nrects;xRectangle *prects;int ordering;SetDashes(pGC, offset, ndash, pdash)GCPtr pGC;unsigned offset;unsigned ndash;unsigned char *pdash;int FreeGC(pGC, gid)GCPtr pGC;GContext gid;As a convenience, each Screen structure contains an array ofGCs that are preallocated, one at each depth the screensupports. These are particularly useful in the mi code.Two DIX routines must be used to get these GCs:GCPtr GetScratchGC(depth, pScreen)int depth;ScreenPtr pScreen;FreeScratchGC(pGC)GCPtr pGC;Always use these two routines, don’t try to extract thescratch GC yourself -- someone else might be using it, so anew one must be created on the fly.If you need a GC for a very long time, say until the serveris restarted, you should not take one from the pool used byGetScratchGC, but should get your own using CreateGC orCreateScratchGC. This leaves the ones in the pool free forroutines that only need it for a little while and don’t wantto pay a heavy cost to get it.GCPtr CreateScratchGC(pScreen, depth)ScreenPtr pScreen;int depth;NULL is returned if the GC cannot be created. The GCreturned can be freed with FreeScratchGC.5.4.1. Details of operationAt screen initialization, a screen must supply a GC creationprocedure. At GC creation, the screen must fill in GC funcsand GC ops vectors (Xserver/include/gcstruct.h). For anyparticular GC, the func vector must remain constant, whilethe op vector may vary. This invariant is to ensure thatWrappers work correctly.When a client request is processed that results in a changeto the GC, the device-independent state of the GC isupdated. This includes a record of the state that changed.Then the ChangeGC GC func is called. This is useful forgraphics subsystems that are able to process state changesin parallel with the server CPU. DDX may opt not to takeany action at GC-modify time. This is more efficient ifmultiple GC-modify requests occur between draws using agiven GC.Validation occurs at the first draw operation that specifiesthe GC after that GC was modified. DIX calls then theValidateGC GC func. DDX should then update its internalstate. DDX internal state may be stored as one or more ofthe following: 1) device private block on the GC; 2)hardware state; 3) changes to the GC ops.The GC contains a serial number, which is loaded with anumber fetched from the window that was drawn into the lasttime the GC was used. The serial number in the drawable ischanged when the drawable’s clipList or absCorner changes.Thus, by comparing the GC serial number with the drawableserial number, DIX can force a validate if the drawable hasbeen changed since the last time it was used with this GC.In addition, the drawable serial number is always guaranteedto have the most significant bit set to 0. Thus, the DDXlayer can set the most significant bit of the serial numberto 1 in a GC to force a validate the next time the GC isused. DIX also uses this technique to indicate that achange has been made to the GC by way of a SetGC, aSetDashes or a SetClip request.5.4.2. GC Handling RoutinesThe ScreenRec data structure has a pointer for CreateGC().Bool pScreen->CreateGC(pGC)GCPtr pGC;This routine must fill in the fields of a dynamicallyallocated GC that is passed in. It does NOT allocate the GCrecord itself or fill in the defaults; DIX does that.This must fill in both the GC funcs and ops; none of thedrawing functions will be called before the GC has beenvalidated, but the others (dealing with allocating of clipregions, changing and destroying the GC, etc.) might be.The GC funcs vector contains pointers to 7 routines and adevPrivate field:pGC->funcs->ChangeGC(pGC, changes)GCPtr pGC;unsigned long changes;This GC func is called immediately after a field in the GCis changed. changes is a bit mask indicating the changedfields of the GC in this request.The ChangeGC routine is useful if you have a system wherestate-changes to the GC can be swallowed immediately by yourgraphics system, and a validate is not necessary.pGC->funcs->ValidateGC(pGC, changes, pDraw)GCPtr pGC;unsigned long changes;DrawablePtr pDraw;ValidateGC is called by DIX just before the GC will be usedwhen one of many possible changes to the GC or the graphicssystem has happened. It can modify a devPrivates field ofthe GC or its contents, change the op vector, or changehardware according to the values in the GC. It may notchange the device-independent portion of the GC itself.In almost all cases, your ValidateGC() procedure should takethe regions that drawing needs to be clipped to and combinethem into a composite clip region, which you keep a pointerto in the private part of the GC. In this way, your drawingprimitive routines (and whatever is below them) can easilydetermine what to clip and where. You should combine theregions clientClip (the region that the client desires toclip output to) and the region returned byNotClippedByChildren(), in DIX. An example is inXserver/mfb/mfbgc.c.Some kinds of extension software may cause this routine tobe called more than originally intended; you should not relyon algorithms that will break under such circumstances.See the Strategies document for more information oncreatively using this routine.pGC->funcs->CopyGC(pGCSrc, mask, pGCDst)GCPtr pGCSrc;unsigned long mask;GCPtr pGCDst;This routine is called by DIX when a GC is being copied toanother GC. This is for situations where dynamicallyallocated chunks of memory are hanging off a GC devPrivatesfield which need to be transferred to the destination GC.pGC->funcs->DestroyGC(pGC)GCPtr pGC;This routine is called before the GC is destroyed for theentity interested in this GC to clean up after itself. Thisroutine is responsible for freeing any auxiliary storageallocated.5.4.3. GC Clip Region RoutinesThe GC clientClip field requires three procedures to manageit. These procedures are in the GC funcs vector. Theunderlying principle is that dix knows nothing about theinternals of the clipping information, (except when it hascome from the client), and so calls ddX whenever it needs tocopy, set, or destroy such information. It could have beenpossible for dix not to allow ddX to touch the field in theGC, and require it to keep its own copy in devPriv, butsince clip masks can be very large, this seems like a badidea. Thus, the server allows ddX to do whatever it wantsto the clientClip field of the GC, but requires it to do allmanipulation itself.void pGC->funcs->ChangeClip(pGC, type, pValue, nrects)GCPtr pGC;int type;char *pValue;int nrects;This routine is called whenever the client changes theclient clip region. The pGC points to the GC involved, thetype tells what form the region has been sent in. If typeis CT_NONE, then there is no client clip. If type isCT_UNSORTED, CT_YBANDED or CT_YXBANDED, then pValue pointerto a list of rectangles, nrects long. If type is CT_REGION,then pValue pointer to a RegionRec from the mi region code.If type is CT_PIXMAP pValue is a pointer to a pixmap. (Thedefines for CT_NONE, etc. are in Xserver/include/gc.h.)This routine is responsible for incrementing any necessaryreference counts (e.g. for a pixmap clip mask) for the newclipmask and freeing anything that used to be in the GC’sclipMask field. The lists of rectangles passed in can befreed with Xfree(), the regions can be destroyed with theRegionDestroy field in the screen, and pixmaps can bedestroyed by calling the screen’s DestroyPixmap function.DIX and MI code expect what they pass in to this to be freedor otherwise inaccessible, and will never look inside what’sbeen put in the GC. This is a good place to be wary ofstorage leaks.In the sample server, this routine transforms either thebitmap or the rectangle list into a region, so that futureroutines will have a more predictable starting point to workfrom. (The validate routine must take this client clipregion and merge it with other regions to arrive at acomposite clip region before any drawing is done.)void pGC->funcs->DestroyClip(pGC)GCPtr pGC;This routine is called whenever the client clip region mustbe destroyed. The pGC points to the GC involved. This callshould set the clipType field of the GC to CT_NONE. In thesample server, the pointer to the client clip region is setto NULL by this routine after destroying the region, so thatother software (including ChangeClip() above) will recognizethat there is no client clip region.void pGC->funcs->CopyClip(pgcDst, pgcSrc)GCPtr pgcDst, pgcSrc;This routine makes a copy of the clipMask and clipType frompgcSrc into pgcDst. It is responsible for destroying anyprevious clipMask in pgcDst. The clip mask in the sourcecan be the same as the clip mask in the dst (clients do thestrangest things), so care must be taken when destroyingthings. This call is required because dix does not know howto copy the clip mask from pgcSrc.5.5. Drawing PrimitivesThe X protocol (rules for the byte stream that goes betweenclient and server) does all graphics using primitiveoperations, which are called Drawing Primitives. Theseinclude line drawing, area filling, arcs, and text drawing.Your implementation must supply 16 routines to perform theseon your hardware. (The number 16 is arbitrary.)More specifically, 16 procedure pointers are in each GC opvector. At any given time, ALL of them MUST point to avalid procedure that attempts to do the operation assigned,although the procedure pointers may change and may point todifferent procedures to carry out the same operation. Asimple server will leave them all pointing to the same 16routines, while a more optimized implementation will switcheach from one procedure to another, depending upon what ismost optimal for the current GC and drawable.The sample server contains a considerable chunk of codecalled the mi (machine independent) routines, which serve asdrawing primitive routines. Many server implementationswill be able to use these as-is, because they work forarbitrary depths. They make no assumptions about theformats of pixmaps and frame buffers, since they call a setof routines known as the "Pixblit Routines" (see nextsection). They do assume that the way to draw is throughthese low-level routines that apply pixel values rows at atime. If your hardware or firmware gives more performancewhen things are done differently, you will want to take thisfact into account and rewrite some or all of the drawingprimitives to fit your needs.5.5.1. GC ComponentsThis section describes the fields in the GC that affect eachdrawing primitive. The only primitive that is not affectedis GetImage, which does not use a GC because its destinationis a protocol-style bit image. Since each drawing primitivemirrors exactly the X protocol request of the same name, youshould refer to the X protocol specification document formore details.ALL of these routines MUST CLIP to the appropriate regionsin the drawable. Since there are many regions to clip tosimultaneously, your ValidateGC routine should combine theseinto a unified clip region to which your drawing routinescan quickly refer. This is exactly what the cfb and mfbroutines supplied with the sample server do. The miimplementation passes responsibility for clipping whiledrawing down to the Pixblit routines.Also, all of them must adhere to the current plane mask.The plane mask has one bit for every bit plane in thedrawable; only planes with 1 bits in the mask are affectedby any drawing operation.All functions except for ImageText calls must obey the alufunction. This is usually Copy, but could be any of theallowable 16 raster-ops.All of the functions, except for CopyArea, might use thecurrent foreground and background pixel values. Each pixelvalue is 32 bits. These correspond to foreground andbackground colors, but you have to run them through thecolormap to find out what color the pixel values represent.Do not worry about the color, just apply the pixel value.The routines that draw lines (PolyLine, PolySegment,PolyRect, and PolyArc) use the line width, line style, capstyle, and join style. Line width is in pixels. The linestyle specifies whether it is solid or dashed, and what kindof dash. The cap style specifies whether Rounded, Butt,etc. The join style specifies whether joins between joinedlines are Miter, Round or Beveled. When lines cross as partof the same polyline, they are assumed to be drawn once.(See the X protocol specification for more details.)Zero-width lines are NOT meant to be really zero width; thisis the client’s way of telling you that you can optimizeline drawing with little regard to the end caps and joins.They are called "thin" lines and are meant to be one pixelwide. These are frequently done in hardware or in astreamlined assembly language routine.Lines with widths greater than zero, though, must all bedrawn with the same algorithm, because client softwareassumes that every jag on every line at an angle will comeat the same place. Two lines that should have one pixel inthe space between them (because of their distance apart andtheir widths) should have such a one-pixel line of spacebetween them if drawn, regardless of angle.The solid area fill routines (FillPolygon, PolyFillRect,PolyFillArc) all use the fill rule, which specifies subtleinterpretations of what points are inside and what areoutside of a given polygon. The PolyFillArc routine alsouses the arc mode, which specifies whether to fill piesegments or single-edge slices of an ellipse.The line drawing, area fill, and PolyText routines must allapply the correct "fill style." This can be either a solidforeground color, a transparent stipple, an opaque stipple,or a tile. Stipples are bitmaps where the 1 bits representthat the foreground color is written, and 0 bits representthat either the pixel is left alone (transparent) or thatthe background color is written (opaque). A tile is apixmap of the full depth of the GC that is applied in itsfull glory to all areas. The stipple and tile patterns canbe any rectangular size, although some implementations willbe faster for certain sizes such as 8x8 or 32x32. The miimplementation passes this responsibility down to thePixblit routines.See the X protocol document for full details. Thedescription of the CreateGC request has a very good,detailed description of these attributes.5.5.2. The PrimitivesThe Drawing Primitives are as follows:RegionPtr pGC->ops->CopyArea(src, dst, pGC, srcx, srcy, w, h, dstx, dsty)DrawablePtr dst, src;GCPtr pGC;int srcx, srcy, w, h, dstx, dsty;CopyArea copies a rectangle of pixels from one drawable toanother of the same depth. To effect scrolling, this mustbe able to copy from any drawable to itself, overlapped. Nosqueezing or stretching is done because the source anddestination are the same size. However, everything is stillclipped to the clip regions of the destination drawable.If pGC->graphicsExposures is True, any portions of thedestination which were not valid in the source (eitheroccluded by covering windows, or outside the bounds of thedrawable) should be collected together and returned as aregion (if this resultant region is empty, NULL can bereturned instead). Furthermore, the invalid bits of thesource are not copied to the destination and (when thedestination is a window) are filled with the backgroundtile. The sample routine miHandleExposures generates theappropriate return value and fills the invalid area usingpScreen->PaintWindowBackground.For instance, imagine a window that is partially obscured byother windows in front of it. As text is scrolled on yourwindow, the pixels that are scrolled out from underobscuring windows will not be available on the screen tocopy to the right places, and so an exposure event must besent for the client to correctly repaint them. Of course,if you implement some sort of backing store, you could dothis without resorting to exposure events.An example implementation is mfbCopyArea() inXserver/mfb/mfbbitblt.c.RegionPtr pGC->ops->CopyPlane(src, dst, pGC, srcx, srcy, w, h, dstx, dsty, plane)DrawablePtr dst, src;GCPtr pGC;int srcx, srcy, w, h, dstx, dsty;unsigned long plane;CopyPlane must copy one plane of a rectangle from the sourcedrawable onto the destination drawable. Because thisroutine only copies one bit out of each pixel, it can copybetween drawables of different depths. This is the only wayof copying between drawables of different depths, except forcopying bitmaps to pixmaps and applying foreground andbackground colors to it. All other conditions of CopyAreaapply to CopyPlane too.An example implementation is mfbCopyPlane() inXserver/mfb/mfbbitblt.c.void pGC->ops->PolyPoint(dst, pGC, mode, n, pPoint)DrawablePtr dst;GCPtr pGC;int mode;int n;DDXPointPtr pPoint;PolyPoint draws a set of one-pixel dots (foreground color)at the locations given in the array. mode is one of thedefined constants Origin (absolute coordinates) or Previous(each coordinate is relative to the last). Note that thisdoes not use the background color or any tiles or stipples.Example implementations are mfbPolyPoint() inXserver/mfb/mfbpolypnt.c and miPolyPoint inXserver/mi/mipolypnt.c.void pGC->ops->Polylines(dst, pGC, mode, n, pPoint)DrawablePtr dst;GCPtr pGC;int mode;int n;DDXPointPtr pPoint;Similar to PolyPoint, Polylines draws lines between thelocations given in the array. Zero-width lines are NOTmeant to be really zero width; this is the client’s way oftelling you that you can maximally optimize line drawingwith little regard to the end caps and joins. mode is oneof the defined constants Previous or Origin, depending uponwhether the points are each relative to the last or areabsolute.Example implementations are miWideLine() and miWideDash() inmi/miwideline.c and miZeroLine() in mi/mizerline.c.void pGC->ops->PolySegment(dst, pGC, n, pPoint)DrawablePtr dst;GCPtr pGC;int n;xSegment *pSegments;PolySegments draws unconnected lines between pairs of pointsin the array; the array must be of even size; nointerconnecting lines are drawn.An example implementation is miPolySegment() in mipolyseg.c.void pGC->ops->PolyRectangle(dst, pGC, n, pRect)DrawablePtr dst;GCPtr pGC;int n;xRectangle *pRect;PolyRectangle draws outlines of rectangles for eachrectangle in the array.An example implementation is miPolyRectangle() inXserver/mi/mipolyrect.c.void pGC->ops->PolyArc(dst, pGC, n, pArc)DrawablePtr dst;GCPtr pGC;int n;xArc*pArc;PolyArc draws connected conic arcs according to thedescriptions in the array. See the protocol specificationfor more details.Example implementations are miZeroPolyArc inXserver/mi/mizerarc. and miPolyArc() in Xserver/mi/miarc.c.void pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pPoint)DrawablePtr dst;GCPtr pGC;int shape;int mode;int count;DDXPointPtr pPoint;FillPolygon fills a polygon specified by the points in thearray with the appropriate fill style. If necessary, anextra border line is assumed between the starting and endinglines. The shape can be used as a hint to optimize filling;it indicates whether it is convex (all interior angles lessthan 180), nonconvex (some interior angles greater than 180but border does not cross itself), or complex (bordercrosses itself). You can choose appropriate algorithms orhardware based upon mode. mode is one of the definedconstants Previous or Origin, depending upon whether thepoints are each relative to the last or are absolute.An example implementation is miFillPolygon() inXserver/mi/mipoly.c.void pGC->ops->PolyFillRect(dst, pGC, n, pRect)DrawablePtr dst;GCPtr pGC;int n;xRectangle *pRect;PolyFillRect fills multiple rectangles.Example implementations are mfbPolyFillRect() inXserver/mfb/mfbfillrct.c and miPolyFillRect() inXserver/mi/mifillrct.c.void pGC->ops->PolyFillArc(dst, pGC, n, pArc)DrawablePtr dst;GCPtr pGC;int n;xArc *pArc;PolyFillArc fills a shape for each arc in the list that isbounded by the arc and one or two line segments with thecurrent fill style.An example implementation is miPolyFillArc() inXserver/mi/mifillarc.c.void pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBinImage)DrawablePtr dst;GCPtr pGC;int x, y, w, h;int format;char *pBinImage;PutImage copies a pixmap image into the drawable. Thepixmap image must be in X protocol format (either Bitmap,XYPixmap, or ZPixmap), and format tells the format. (Seethe X protocol specification for details on these formats).You must be able to accept all three formats, because theclient gets to decide which format to send. Either thedrawable and the pixmap image have the same depth, or thesource pixmap image must be a Bitmap. If a Bitmap, theforeground and background colors will be applied to thedestination.An example implementation is miPutImage() inXserver/mfb/mibitblt.c.void pScreen->GetImage(src, x, y, w, h, format, planeMask, pBinImage)DrawablePtr src;int x, y, w, h;unsigned int format;unsigned long planeMask;char *pBinImage;GetImage copies the bits from the source drawable into thedestination pointer. The bits are written into the bufferaccording to the server-defined pixmap padding rules.pBinImage is guaranteed to be big enough to hold all thebits that must be written.This routine does not correspond exactly to the X protocolGetImage request, since DIX has to break the reply up intobuffers of a size requested by the transport layer. Ifformat is ZPixmap, the bits are written in the ZFormat forthe depth of the drawable; if there is a 0 bit in theplaneMask for a particular plane, all pixels must have thebit in that plane equal to 0. If format is XYPixmap,planemask is guaranteed to have a single bit set; the bitsshould be written in Bitmap format, which is the format fora single plane of an XYPixmap.An example implementation is miGetImage() inXserver/mi/mibitblt.c.void pGC->ops->ImageText8(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;char *chars;ImageText8 draws text. The text is drawn in the foregroundcolor; the background color fills the remainder of thecharacter rectangles. The coordinates specify the baselineand start of the text.An example implementation is miImageText8() inXserver/mi/mipolytext.c.int pGC->ops->PolyText8(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;char *chars;PolyText8 works like ImageText8, except it draws with thecurrent fill style for special effects such as shaded text.See the X protocol specification for more details.An example implementation is miPolyText8() inXserver/mi/mipolytext.c.int pGC->ops->PolyText16(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;unsigned short *chars;void pGC->ops->ImageText16(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;unsigned short *chars;These two routines are the same as the "8" versions, exceptthat they are for 16-bit character codes (useful fororiental writing systems).The primary difference is in the way the characterinformation is looked up. The 8-bit and the 16-bit versionsobviously have different kinds of character values to lookup; the main goal of the lookup is to provide a pointer tothe CharInfo structs for the characters to draw and to passthese pointers to the Glyph routines. Given a CharInfostruct, lower-level software can draw the glyph desired withlittle concern for other characteristics of the font.16-bit character fonts have a row-and-column scheme, wherethe 2bytes of the character code constitute the row andcolumn in a square matrix of CharInfo structs. Each fonthas row and column minimum and maximum values; the CharInfostructures form a two-dimensional matrix.Example implementations are miPolyText16() andmiImageText16() in Xserver/mi/mipolytext.c.See the X protocol specification for more details on thesegraphic operations.There is a hook in the GC ops, called LineHelper, that usedto be used in the sample implementation by the code for widelines. It no longer servers any purpose in the sampleservers, but still exists, #ifdef’ed by NEED_LINEHELPER, incase someone needs it.5.6. Pixblit ProceduresThe Drawing Primitive functions must be defined for yourserver. One possible way to do this is to use the miroutines from the sample server. If you choose to use themi routines (even part of them!) you must implement thesePixblit routines. These routines read and write pixelvalues and deal directly with the image data.The Pixblit routines for the sample server are part of the"mfb" routines (for Monochrome Frame Buffer), and "cfb"routines (for Color Frame Buffer). As with the mi routines,the mfb and cfb routines are portable but are not asportable as the mi routines.The mfb routines only work for monochrome frame buffers, thesimplest type of display. Furthermore, they only work forscreens that organize their bits in rows of pixels on thescreen. (See the Strategies document for more details onporting mfb.) The cfb routines work for packed-pixeldisplays from 2 to 32 bits in depth, although they have abit of code which has been tuned to run on 8-bit (1 pixelper byte) displays.In other words, if you have a "normal" frame buffer typedisplay, you can probably use either the mfb or cfb code,and the mi code. If you have a stranger hardware, you willhave to supply your own Pixblit routines, but you can usethe mi routines on top of them. If you have better ways ofdoing some of the Drawing Primitive functions, then you maywant to supply some of your own Drawing Primitive routines.(Even people who write their own Drawing Primitives save atleast some of the mi code for certain special cases thattheir hardware or library or fancy algorithm does nothandle.)The client, DIX, and the machine-independent routines do notcarry the final responsibility of clipping. They all dependupon the Pixblit routines to do their clipping for them.The rule is, if you touch the frame buffer, you clip.(The higher level routines may decide to clip at a highlevel, but this is only for increased performance and cannotsubstitute for bottom-level clipping. For instance, the miroutines, DIX, or the client may decide to check allcharacter strings to be drawn and chop off all charactersthat would not be displayed. If so, it must retain thecharacter on the edge that is partly displayed so that thePixblit routines can clip off precisely at the right place.)To make this easier, all of the reasons to clip can becombined into one region in your ValidateGC procedure. Youtake this composite clip region with you into the Pixblitroutines. (The sample server does this.)Also, FillSpans() has to apply tile and stipple patterns.The patterns are all aligned to the window origin so thatwhen two people write patches that are contiguous, they willmerge nicely. (Really, they are aligned to the patOrg pointin the GC. This defaults to (0, 0) but can be set by theclient to anything.)However, the mi routines can translate (relocate) the pointsfrom window-relative to screen-relative if desired. If youset the miTranslate field in the GC (set it in the CreateGCor ValidateGC routine), then the mi output routines willtranslate all coordinates. If it is false, then thecoordinates will be passed window-relative. Screens with nohardware translation will probably set miTranslate to TRUE,so that geometry (e.g. polygons, rectangles) can betranslated, rather than having the resulting list ofscanlines translated; this is good because the list verticesin a drawing request will generally be much smaller than thelist of scanlines it produces. Similarly, hardware thatdoes translation can set miTranslate to FALSE, and avoid theextra addition per vertex, which can be (but is not always)important for getting the highest possible performance.(Contrast the behavior of GetSpans, which is not expected tobe called as often, and so has different constraints.) ThemiTranslate field is settable in each GC, if , for example,you are mixing several kinds of destinations (offscreenpixmaps, main memory pixmaps, backing store, and windows),all of which have different requirements, on one screen.As with other drawing routines, there are fields in the GCto direct higher code to the correct routine to execute foreach function. In this way, you can optimize for specialcases, for example, drawing solids versus drawing stipples.The Pixblit routines are broken up into three sets. TheSpan routines simply fill in rows of pixels. The Glyphroutines fill in character glyphs. The PushPixels routineis a three-input bitblt for more sophisticated imagecreation.It turns out that the Glyph and PushPixels routines actuallyhave a machine-independent implementation that depends uponthe Span routines. If you are really pressed for time, youcan use these versions, although they are quite slow.5.6.1. Span RoutinesFor these routines, all graphic operations have been reducedto "spans." A span is a horizontal row of pixels. If youcan design these routines which write into and read fromrows of pixels at a time, you can use the mi routines.Each routine takes a destination drawable to draw into, a GCto use while drawing, the number of spans to do, and twopointers to arrays that indicate the list of starting pointsand the list of widths of spans.void pGC->ops->FillSpans(dst, pGC, nSpans, pPoints, pWidths, sorted)DrawablePtr dst;GCPtr pGC;int nSpans;DDXPointPtr pPoints;int *pWidths;int sorted;FillSpans should fill horizontal rows of pixels with theappropriate patterns, stipples, etc., based on the values inthe GC. The starting points are in the array at pPoints;the widths are in pWidths. If sorted is true, the scanlines are in increasing y order, in which case you may beable to make assumptions and optimizations.GC components: alu, clipOrg, clientClip, and fillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).void pGC->ops->SetSpans(pDrawable, pGC, pSrc, ppt, pWidths, nSpans, sorted)DrawablePtr pDrawable;GCPtr pGC;char *pSrc;DDXPointPtr pPoints;int *pWidths;int nSpans;int sorted;For each span, this routine should copy pWidths bits frompSrc to pDrawable at pPoints using the raster-op from theGC. If sorted is true, the scan lines are in increasing yorder. The pixels in pSrc are padded according to thescreen’s padding rules. These can be used to supportinteresting extension libraries, for example, shadedprimitives. It does not use the tile and stipple.GC components: alu, clipOrg, and clientClipThe above functions are expected to handle all modifiers inthe current GC. Therefore, it is expedient to havedifferent routines to quickly handle common special casesand reload the procedure pointers at validate time, as withthe other output functions.void pScreen->GetSpans(pDrawable, wMax, pPoints, pWidths, nSpans)DrawablePtr pDrawable;int wMax;DDXPointPtr pPoints;int *pWidths;int nSpans;char *pDst;For each span, GetSpans gets bits from the drawable startingat pPoints and continuing for pWidths bits. Each scanlinereturned will be server-scanline padded. The routine canreturn NULL if memory cannot be allocated to hold theresult.GetSpans never translates -- for a window, the coordinatesare already screen-relative. Consider the case of hardwarethat doesn’t do translation: the mi code that calls ddX willtranslate each shape (rectangle, polygon,. etc.) beforescan-converting it, which requires many fewer additions thathaving GetSpans translate each span does. Conversely,consider hardware that does translate: it can set itstranslation point to (0, 0) and get each span, and the onlypenalty is the small number of additions required totranslate each shape being scan-converted by the callingcode. Contrast the behavior of FillSpans and SetSpans(discussed above under miTranslate), which are expected tobe used more often.Thus, the penalty to hardware that does hardware translationis negligible, and code that wants to call GetSpans() isgreatly simplified, both for extensions and themachine-independent core implementation.5.6.1.1. Glyph RoutinesThe Glyph routines draw individual character glyphs for textdrawing requests.You have a choice in implementing these routines. You canuse the mi versions; they depend ultimately upon the spanroutines. Although text drawing will work, it will be veryslow.void pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)DrawablePtr pDrawable;GCPtr pGC;int x , y;unsigned int nglyph;CharInfoRec **ppci; /* array of character info */pointer unused; /* unused since R5 */GC components: alu, clipOrg, clientClip, font, andfillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).void pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)DrawablePtr pDrawable;GCPtr pGC;int x , y;unsigned int nglyph;CharInfoRec **ppci; /* array of character info */pointer unused; /* unused since R5 */GC components: clipOrg, clientClip, font, fgPixel, bgPixelThese routines must copy the glyphs defined by the bitmapsin pglyphBase and the font metrics in ppci to theDrawablePtr, pDrawable. The poly routine follows all fill,stipple, and tile rules. The image routine simply blaststhe glyph onto the glyph’s rectangle, in foreground andbackground colors.More precisely, the Image routine fills the characterrectangle with the background color, and then the glyph isapplied in the foreground color. The glyph can extendoutside of the character rectangle. ImageGlyph() is usedfor terminal emulators and informal text purposes such asbutton labels.The exact specification for the Poly routine is that theglyph is painted with the current fill style. The characterrectangle is irrelevant for this operation. PolyText, at ahigher level, includes facilities for font changes withinstrings and such; it is to be used for WYSIWYG wordprocessing and similar systems.Both of these routines must clip themselves to the overallclipping region.Example implementations in mi are miPolyGlyphBlt() andmiImageGlyphBlt() in Xserver/mi/miglblt.c.5.6.1.2. PushPixels routineThe PushPixels routine writes the current fill style ontothe drawable in a certain shape defined by a bitmap.PushPixels is equivalent to using a second stipple. You canthing of it as pushing the fillStyle through a stencil.PushPixels is not used by any of the mi rendering code, butis used by the mi software cursor code.Suppose the stencil is:00111100and the stipple is: 10101010PushPixels result: 00101000You have a choice in implementing this routine. You can usethe mi version which depends ultimately upon FillSpans().Although it will work, it will be slow.void pGC->ops->PushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg)GCPtr pGC;PixmapPtr pBitMap;DrawablePtr pDrawable;int dx, dy, xOrg, yOrg;GC components: alu, clipOrg, clientClip, and fillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).PushPixels applys the foreground color, tile, or stipplefrom the pGC through a stencil onto pDrawable. pBitMappoints to a stencil (of which we use an area dx wide by dyhigh), which is oriented over the drawable at xOrg, yOrg.Where there is a 1 bit in the bitmap, the destination is setaccording to the current fill style. Where there is a 0 bitin the bitmap, the destination is left the way it is.This routine must clip to the overall clipping region.An Example implementation is miPushPixels() inXserver/mi/mipushpxl.c.5.7. Shutdown Proceduresvoid AbortDDX()void ddxGiveUp()Some hardware may require special work to be done before theserver exits so that it is not left in an intermediatestate. As explained in the OS layer, FatalError() will callAbortDDX() just before terminating the server. In addition,ddxGiveUp() will be called just before terminating theserver on a "clean" death. What AbortDDX() and ddxGiveUP dois left unspecified, only that stubs must exist in the ddxlayer. It is up to local implementors as to what theyshould accomplish before termination.5.7.1. Command Line Proceduresint ddxProcessArgument(argc, argv, i)int argc;char *argv[];int i;voidddxUseMsg()You should write these routines to deal withdevice-dependent command line arguments. The routineddxProcessArgument() is called with the command line, andthe current index into argv; you should return zero if theargument is not a device-dependent one, and otherwise returna count of the number of elements of argv that are part ofthis one argument. For a typical option (e.g.,"-realtime"), you should return the value one. This routinegets called before checks are made againstdevice-independent arguments, so it is possible to peek atall arguments or to override device-independent argumentprocessing. You can document the device-dependent argumentsin ddxUseMsg(), which will be called from UseMsg() afterprinting out the device-independent arguments.Porting Layer Definition - 3 - April 8, 1994
5.8. Wrappers and devPrivatesTwo new extensibility concepts have been developed forrelease 4, Wrappers and devPrivates. These replace the R3GCInterest queues, which were not a general enough mechanismfor many extensions and only provided hooks into a singledata structure.5.8.1. devPrivatesdevPrivates are arrays of values attached to various datastructures (Screens, GCs, Windows, and Pixmaps currently).These arrays are sized dynamically at server startup (andreset) time as various modules allocate portions of them.They can be used for any purpose; each array entry isactually a union, DevUnion, of common useful types (pointer,long and unsigned long). devPrivates must be allocated onstartup and whenever the server resets. To make thiseasier, the global variable "serverGeneration" isincremented each time devPrivates should be allocated, butbefore the initialization process begins, typical usagewould be:static int privateGeneration = 0;if (privateGeneration != serverGeneration){ allocate devPrivates here.privateGeneration = serverGeneration;}5.8.1.1. Screen devPrivatesAn index into every screen devPrivates array is allocatedwith int AllocateScreenPrivateIndex()This call can occur at any time, each existing devPrivatesarray is resized to accommodate the new entry. This routinereturns -1 indicating an allocation failure. Otherwise, thereturn value can be used to index the array of devPrivateson any screen:private = (PrivatePointer) pScreen->devPrivates[screenPrivateIndex].ptr;The pointer in each screen is not initialized byAllocateScreenPrivateIndex().5.8.1.2. Window devPrivatesAn index into every window devPrivates array is allocatedwith int AllocateWindowPrivateIndex ()AllocateWindowPrivateIndex() never returns an error. Thiscall must be associated with a call which causes a chunk ofmemory to be automatically allocated and attached to thedevPrivate entry on every screen which the module will needto use the index:Bool AllocateWindowPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;If this space is not always needed for every object, use 0as the amount. In this case, the pointer field of the entryin the devPrivates array is initialized to NULL. This callexists so that DIX may preallocate all of the space requiredfor an object with one call; this reduces memoryfragmentation considerably. AllocateWindowPrivate returnsFALSE on allocation failure. Both of these calls must occurbefore any window structures are allocated; the server iscareful to avoid window creation until all modules areinitialized, but do not call this after initialization. Atypical allocation sequence for WindowPrivates would be:privateInitialize (pScreen)ScreenPtr pScreen;{if (privateGeneration != serverGeneration){ windowPrivateIndex = AllocateWindowPrivateIndex();privateGeneration = serverGeneration;}return (AllocateWindowPrivate(pScreen, windowPrivateIndex,sizeof(windowPrivateStructure)));}5.8.1.3. GC and Pixmap devPrivatesThe calls for GCs and Pixmaps mirror the Window callsexactly; they have the same requirements and limitations:int AllocateGCPrivateIndex ()Bool AllocateGCPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;int AllocatePixmapPrivateIndex ()Bool AllocatePixmapPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;5.8.2. WrappersWrappers are not a body of code, nor an interface spec.They are, instead, a technique for hooking a new module intoan existing calling sequence. There are limitations onother portions of the server implementation which make usingwrappers possible; limits on when specific fields of datastructures may be modified. They are intended as areplacement for GCInterest queues, which were not generalenough to support existing modules; in particular softwarecursors and backing store both needed more control over theactivity. The general mechanism for using wrappers is:privateWrapperFunction (object, ...)ObjectPtr object;{ pre-wrapped-function-stuff ...object->functionVector = (void *) object->devPrivates[privateIndex].ptr;(*object->functionVector) (object, ...);/** this next line is occasionally required by the rules governing* wrapper functions. Always using it will not cause problems.* Not using it when necessary can cause severe troubles.*/object->devPrivates[privateIndex].ptr = (pointer) object->functionVector;object->functionVector = privateWrapperFunction;post-wrapped-function-stuff ...}privateInitialize (object)ObjectPtr object;{ object->devPrivates[privateIndex].ptr = (pointer) object->functionVector;object->functionVector = privateWrapperFunction;}Thus the privateWrapperFunction provides hooks forperforming work both before and after the wrapped functionhas been called; the process of resetting the functionVectoris called "unwrapping" while the process of fetching thewrapped function and replacing it with the wrapping functionis called "wrapping". It should be clear that GCInterestqueues could be emulated using wrappers. In general, anyfunction vectors contained in objects can be wrapped, butonly vectors in GCs and Screens have been tested.Wrapping screen functions is quite easy; each vector isindividually wrapped. Screen functions are not supposed tochange after initialization, so rewrapping is technicallynot necessary, but causes no problems.Wrapping GC functions is a bit more complicated. GC’s havetwo sets of function vectors, one hanging from gc->ops andthe other from gc->funcs. Wrappers should modify only thosevalues, not the internal values as they may be shared bymore than one GC (and, in the case of funcs, are probablyshared by all gcs). To wrap the ops, wrap the funcs and, ineach func wrapper, unwrap the ops and funcs, call down, andre-wrap. In each op wrapper, unwrap both the funcs and ops,call down and rewrap afterwards. The rule is: if you wrapfuncs+ops, you must always unwrap both before down calling.If you wrap ops, you must always pull the ops value out ofthe GC in the func wrapper and save it. If you wrap funcs,you needn’t pull the funcs value out of the GC to rewrap asthe func values are required to be constant. In this way,the wrapped validation routine can change the op vector andnot have it lost when your wrapper routine rewraps the GC.This occurs when the wrapped op revalidates the GC with newentries (many mi routines do this for opaque stipples ordouble dashes). The corollary to this rule is: Neverchange the func vector after CreateGC.5.9. Work QueueTo queue work for execution when all clients are in a stablestate (i.e. just before calling select() inWaitForSomething), call:Bool QueueWorkProc(function,client,closure)Bool (*function)();ClientPtr client;pointer closure;When the server is about to suspend itself, the givenfunction will be executed:(*function) (client, closure)Neither client nor closure are actually used inside the workqueue routines.6. Extension InterfacesThis section describes the functions which exist in DDX forextension writers to use.6.1. Extension initialization
6.2. Resource type allocation.
6.3. Macros and Other Helpers
7. Callback ManagerTo satisfy a growing number of requests for the introductionof ad hoc notification style hooks in the server, a genericcallback manager was introduced in R6. A callback listobject can be introduced for each new hook that is desired,and other modules in the server can register interest in thenew callback list. The following functions support theseoperations.Before getting bogged down in the interface details, antypical usage example should establish the framework. Let’slook at the ClientStateCallback in dix/dispatch.c. Thepurpose of this particular callback is to notify interesetedparties when a client’s state (initial, running, gone)changes. The callback is "created" in this case by simplydeclaring a variable:CallbackListPtr ClientStateCallback;Whenever the client’s state changes, the following codeappears, which notifies all intereseted parties of thechange:if (ClientStateCallback)CallCallbacks(&ClientStateCallback, (pointer)client);Interested parties subscribe to the ClientStateCallback listby saying:AddCallback(&ClientStateCallback, func, data);When CallCallbacks is invoked on the list, func will becalled thusly:(*func)(&ClientStateCallback, data, client)Now for the details.Bool CreateCallbackList(pcbl, cbfuncs)CallbackListPtr *pcbl;CallbackFuncsPtr cbfuncs;CreateCallbackList creates a callback list. We envisionthat this function will be rarely used because the callbacklist is created automatically (if it doesn’t already exist)when the first call to AddCallback is made on the list. Theonly reason to explicitly create the callback list with thisfunction is if you want to override the implementation ofsome of the other operations on the list by passing your owncbfuncs. You also lose something by explicit creation: youintroduce an order dependency during server startup becausethe list must be created before any modules subscribe to it.Returns TRUE if successful.Bool AddCallback(pcbl, callback, subscriber_data)CallbackListPtr *pcbl;CallbackProcPtr callback;pointer subscriber_data;Adds the (callback, subscriber_data) pair to the givencallback list. Creates the callback list if it doesn’texist. Returns TRUE if successful.Bool DeleteCallback(pcbl, callback, subscriber_data)CallbackListPtr *pcbl;CallbackProcPtr callback;pointer subscriber_data;Removes the (callback, data) pair to the given callback listif present. Returns TRUE if (callback, data) was found.void CallCallbacks(pcbl, call_data)CallbackListPtr *pcbl;pointer call_data;For each callback currently registered on the given callbacklist, call it as follows:(*callback)(pcbl, subscriber_data, call_data);void DeleteCallbackList(pcbl)CallbackListPtr *pcbl;Destroys the given callback list.Porting Layer Definition - 5 - April 8, 1994
8. Summary of RoutinesThis is a summary of the routines discussed in thisdocument. The procedure names are in alphabetical order.The Struct is the structure it is attached to; if blank,this procedure is not attached to a struct and must be namedas shown. The sample server provides implementations in thefollowing categories. Notice that many of the graphicsroutines have both mi and mfb implementations.Porting Layer Definition - 6 - April 8, 1994

Susan Angebranndt
Raymond Drewry
Philip Karlton
Todd Newman

Digital Equipment Corporation

minor revisions by
Bob Scheifler

Massachusetts Institute of Technology

Revised for Release 4 and Release 5 by
Keith Packard

MIT X Consortium

Revised for Release 6 by
David P. Wiggins

X Consortium

Porting Layer Definition - 1 - April 8, 1994

Copyright © 1994 X Consortium

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘‘Software’’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘‘AS IS’’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Porting Layer Definition - 2 - April 8, 1994

The following document explains the structure of the X Window System display server and the interfaces among the larger pieces. It is intended as a reference for programmers who are implementing an X Display Server on their workstation hardware. It is included with the X Window System source tape, along with the document "Strategies for Porting the X v11 Sample Server." The order in which you should read these documents is:

1)

Read the first section of the "Strategies for Porting" document (Overview of Porting Process).

2)

Skim over this document (the Definition document).

3)

Skim over the remainder of the Strategies document.

4)

Start planning and working, referring to the Strategies and Definition documents.

You may also want to look at the following documents:

"The X Window System" for an overview of X.

"Xlib - C Language X Interface" for a view of what the client programmer sees.

"X Window System Protocol" for a terse description of the byte stream protocol between the client and server.

LK201 and DEC are trademarks of Digital Equipment Corporation. Macintosh and Apple are trademarks of Apple Computer, Inc. PostScript is a trademark of Adobe Systems, Inc. Ethernet is a trademark of Xerox Corporation. X Window System is a trademark of X Consortium, Inc. Cray is a trademark of Cray Research, Inc.

To understand this document and the accompanying source code, you should know the C language. You should be familiar with 2D graphics and windowing concepts such as clipping, bitmaps, fonts, etc. You should have a general knowledge of the X Window System. To implement the server code on your hardware, you need to know a lot about your hardware, its graphic display device(s), and (possibly) its networking and multitasking facilities.

This document depends a lot on the source code, so you should have a listing of the code handy.

Some source on the distribution tape is directly compilable on your machine. Some of it will require modification. Other parts may have to be completely written from scratch.

The tape also includes source for a sample implementation of a display server which runs on a variety of color and monochrome displays which you will find useful for implementing any type of X server.

1. The X Window SystemThe X Window System, or simply "X," is a windowing systemthat provides high-performance, high-level,device-independent graphics.X is a windowing system designed for bitmapped graphicdisplays. The display can have a simple, monochrome displayor it can have a color display with up to 32 bits per pixelwith a special graphics processor doing the work. (In thisdocument, monochrome means a black and white display withone bit per pixel. Even though the usual meaning ofmonochrome is more general, this special case is so commonthat we decided to reserve the word for this purpose.)X is designed for a networking environment where users canrun applications on machines other than their ownworkstations. Sometimes, the connection is over an Ethernetnetwork with a protocol such as TCP/IP; but, any "reliable"byte stream is allowable. A high-bandwidth byte stream ispreferable; RS-232 at 9600 baud would be slow withoutcompression techniques.X by itself allows great freedom of design. For instance,it does not include any user interface standard. Its intentis to "provide mechanism, not policy." By making itgeneral, it can be the foundation for a wide variety ofinteractive software.For a more detailed overview, see the document "The X WindowSystem." For details on the byte stream protocol, see "XWindow System protocol."2. OVERVIEW OF THE SERVERThe display server manages windows and simple graphicsrequests for the user on behalf of different clientapplications. The client applications can be running on anymachine on the network. The server mainly does threethings:• Responds to protocol requests from existing clients(mostly graphic and text drawing commands)• Sends device input (keystrokes and mouse actions) andother events to existing clients• Maintains client connectionsThe server code is organized into four major pieces:• Device Independent (DIX) layer - code shared among allimplementations• Operating System (OS) layer - code that is differentfor each operating system but is shared among allgraphic devices for this operating system• Device Dependent (DDX) layer - code that is(potentially) different for each combination ofoperating system and graphic device• Extension Interface - a standard way to add features tothe X serverThe "porting layer" consists of the OS and DDX layers; theseare actually parallel and neither one is on top of theother. The DIX layer is intended to be portable withoutchange to target systems and is not detailed here, althoughseveral routines in DIX that are called by DDX aredocumented. Extensions incorporate new functionality intothe server; and require additional functionality over asimple DDX.The following sections outline the functions of the layers.Section 3 briefly tells what you need to know about the DIXlayer. The OS layer is explained in Section 4. Section 5gives the theory of operation and procedural interface forthe DDX layer. Section 6 describes the functions whichexist for the extension writer.2.1. Notes On Resources and Large StructsX resources are C structs inside the server. Clientapplications create and manipulate these objects accordingto the rules of the X byte stream protocol. Clientapplications refer to resources with resource IDs, which are32-bit integers that are sent over the network. Within theserver, of course, they are just C structs, and we refer tothem by pointers.The DDX layer has several kinds of resources:• Window• Pixmap• Screen• Device• Colormap• Font• Cursor• Graphics ContextsThe type names of the more important server structs usuallyend in "Rec," such as "DeviceRec;" the pointer types usuallyend in "Ptr," such as "DevicePtr."The structs and important defined constants are declared in.h files that have names that suggest the name of theobject. For instance, there are two .h files for windows,window.h and windowstr.h. window.h defines only what needsto be defined in order to use windows without peeking insideof them; windowstr.h defines the structs with all of theircomponents in great detail for those who need it.Three kinds of fields are in these structs:• Attribute fields - struct fields that contain valueslike normal structs• Pointers to procedures, or structures of procedures,that operate on the object• A private field (or two) used by your DDX code to keepprivate data (probably a pointer to another datastructure), or an array of private fields, which issized as the server initializes.DIX calls through the struct’s procedure pointers to do itstasks. These procedures are set either directly orindirectly by DDX procedures. Most of the proceduresdescribed in the remainder of this document are accessedthrough one of these structs. For example, the procedure tocreate a pixmap is attached to a ScreenRec and might becalled by using the expression(* pScreen->CreatePixmap)(pScreen, width, height, depth).All procedure pointers must be set to some routine unlessnoted otherwise; a null pointer will have unfortunateconsequences.Procedure routines will be indicated in the documentation bythis convention:void pScreen->MyScreenRoutine(arg, arg, ...)as opposed to a free routine, not in a data structure:void MyFreeRoutine(arg, arg, ...)The attribute fields are mostly set by DIX; DDX should notmodify them unless noted otherwise.3. DIX LAYERThe DIX layer is the machine and device independent part ofX. The source should be common to all operating systems anddevices. The port process should not include changes tothis part, therefore internal interfaces to DIX modules arenot discussed, except for public interfaces to the DDX andthe OS layers.In the process of getting your server to work, if you thinkthat DIX must be modified for purposes other than bug fixes,you may be doing something wrong. Keep looking for a morecompatible solution. When the next release of the X servercode is available, you should be able to just drop in thenew DIX code and compile it. If you change DIX, you willhave to remember what changes you made and will have tochange the new sources before you can update to the newversion.The heart of the DIX code is a loop called the dispatchloop. Each time the processor goes around the loop, itsends off accumulated input events from the input devices tothe clients, and it processes requests from the clients.This loop is the most organized way for the server toprocess the asynchronous requests that it needs to process.Most of these operations are performed by OS and DDXroutines that you must supply.4. OS LAYERThis part of the source consists of a few routines that youhave to rewrite for each operating system. These OSfunctions maintain the client connections and schedule workto be done for clients. They also provide an interface tofont files, font name to file name translation, and lowlevel memory management.void OsInit()OsInit initializes your OS code, performing whatever tasksneed to be done. Frequently there is not much to be done.The sample server implementation is in Xserver/os/osinit.c.4.1. Scheduling and Request DeliveryThe main dispatch loop in DIX creates the illusion ofmultitasking between different windows, while the server isitself but a single process. The dispatch loop breaks upthe work for each client into small digestible parts. Someparts are requests from a client, such as individual graphiccommands. Some parts are events delivered to the client,such as keystrokes from the user. The processing of eventsand requests for different clients can be interleaved withone another so true multitasking is not needed in theserver.You must supply some of the pieces for proper schedulingbetween clients.int WaitForSomething(pClientReady)int *pClientReady;WaitForSomething is the scheduler procedure you must writethat will suspend your server process until something needsto be done. This call should make the server suspend untilone or more of the following occurs:• There is an input event from the user or hardware (seeSetInputCheck())• There are requests waiting from known clients, in whichcase you should return a count of clients stored inpClientReady• A new client tries to connect, in which case you shouldcreate the client and then continue waitingBefore WaitForSomething() computes the masks to pass toselect, it needs to see if there is anything to do on thework queue; if so, it must call a DIX routine calledProcessWorkQueue.extern WorkQueuePtr workQueue;if (workQueue)ProcessWorkQueue ();If WaitForSomething() decides it is about to do somethingthat might block (in the sample server, before it callsselect()) it must call a DIX routine called BlockHandler().void BlockHandler(pTimeout, pReadmask)pointer pTimeout;pointer pReadmask;The types of the arguments are for agreement between the OSand DDX implementations, but the pTimeout is a pointer tothe information determining how long the block is allowed tolast, and the pReadmask is a pointer to the informationdescribing the descriptors that will be waited on.In the sample server, pTimeout is a struct timeval **, andpReadmask is the address of the select() mask for reading.The DIX BlockHandler() iterates through the Screens, foreach one calling its BlockHandler. A BlockHandler isdeclared thus:void xxxBlockHandler(nscreen, pbdata, pptv, pReadmask)int nscreen;pointer pbdata;struct timeval ** pptv;pointer pReadmask;The arguments are the index of the Screen, the blockDatafield of the Screen, and the arguments to the DIXBlockHandler().Immediately after WaitForSomething returns from the block,even if it didn’t actually block, it must call the DIXroutine WakeupHandler().void WakeupHandler(result, pReadmask)int result;pointer pReadmask;Once again, the types are not specified by DIX. The resultis the success indicator for the thing that (may have)blocked, and the pReadmask is a mask of the descriptors thatcame active. In the sample server, result is the resultfrom select(), and pReadmask is the address of the select()mask for reading.The DIX WakeupHandler() calls each Screen’s WakeupHandler.A WakeupHandler is declared thus:void xxxWakeupHandler(nscreen, pbdata, err, pReadmask)int nscreen;pointer pbdata;unsigned long result;pointer pReadmask;The arguments are the index of the Screen, the blockDatafield of the Screen, and the arguments to the DIXWakeupHandler().In addition to the per-screen BlockHandlers, any module mayregister block and wakeup handlers (only together) using:Bool RegisterBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData)BlockHandlerProcPtr blockHandler;WakeupHandlerProcPtr wakeupHandler;pointer blockData;A FALSE return code indicates that the registration failedfor lack of memory. To remove a registered Block handler atother than server reset time (when they are all removedautomatically), use:RemoveBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData)BlockHandlerProcPtr blockHandler;WakeupHandlerProcPtr wakeupHandler;pointer blockData;All three arguments must match the values passed toRegisterBlockAndWakeupHandlers.These registered block handlers are called after theper-screen handlers:void (*BlockHandler) (blockData, pptv, pReadmask)pointer blockData;OSTimePtr pptv;pointer pReadmask;Any wakeup handlers registered withRegisterBlockAndWakeupHandlers will be called before theScreen handlers:void (*WakeupHandler) (blockData, err, pReadmask)pointer blockData;int err;pointer pReadmask;The WaitForSomething on the sample server also has a builtin screen saver that darkens the screen if no input happensfor a period of time. The sample server implementation isin Xserver/os/WaitFor.c.Note that WaitForSomething() may be called when you alreadyhave several outstanding things (events, requests, or newclients) queued up. For instance, your server may have justdone a large graphics request, and it may have been a longtime since WaitForSomething() was last called. If manyclients have lots of requests queued up, DIX will onlyservice some of them for a given client before going on tothe next client (see isItTimeToYield, below). Therefore,WaitForSomething() will have to report that these sameclients still have requests queued up the next time around.An implementation should return information on as manyoutstanding things as it can. For instance, if yourimplementation always checks for client data first and doesnot report any input events until there is no client dataleft, your mouse and keyboard might get locked out by anapplication that constantly barrages the server withgraphics drawing requests.A list of indexes (client->index) for clients with dataready to be read or processed should be returned inpClientReady, and the count of indexes returned as theresult value of the call. These are not clients that havefull requests ready, but any clients who have any data readyto be read or processed. The DIX dispatcher will processrequests from each client in turn by callingReadRequestFromClient(), below.WaitForSomething() must create new clients as they arerequested (by whatever mechanism at the transport level). Anew client is created by calling the DIX routine:ClientPtr NextAvailableClient(ospriv)pointer ospriv;This routine returns NULL if a new client cannot beallocated (e.g. maximum number of clients reached). Theospriv argument will be stored into the OS private field(pClient->osPrivate), to store OS private information aboutthe client. In the sample server, the osPrivate fieldcontains the number of the socket for this client. See also"New Client Connections." NextAvailableClient() will callInsertFakeRequest(), so you must be prepared for this.If there are outstanding input events, you should make surethat the two SetInputCheck() locations are unequal. The DIXdispatcher will call your implementation ofProcessInputEvents() until the SetInputCheck() locations areequal.The sample server contains an implementation ofWaitForSomething(). The following two routines indicate toWaitForSomething() what devices should be waited for. fdis an OS dependent type; in the sample server it is an openfile descriptor.int AddEnabledDevice(fd)int fd;int RemoveEnabledDevice(fd)int fd;These two routines are usually called by DDX from theinitialize cases of the Input Procedures that are stored inthe DeviceRec (the routine passed to AddInputDevice()). Thesample server implementation of AddEnabledDevice andRemoveEnabledDevice are in Xserver/os/connection.c.4.2. New Client ConnectionsThe process whereby a new client-server connection starts upis very dependent upon what your byte stream mechanism.This section describes byte stream initiation using examplesfrom the TCP/IP implementation on the sample server.The first thing that happens is a client initiates aconnection with the server. How a client knows to do thisdepends upon your network facilities and the Xlibimplementation. In a typical scenario, a user named Fred onhis X workstation is logged onto a Cray supercomputerrunning a command shell in an X window. Fred can type shellcommands and have the Cray respond as though the X serverwere a dumb terminal. Fred types in a command to run an Xclient application that was linked with Xlib. Xlib looks atthe shell environment variable DISPLAY, which has the value"fredsbittube:0.0." The host name of Fred’s workstation is"fredsbittube," and the 0s are for multiple screens andmultiple X server processes. (Precisely what happens onyour system depends upon how X and Xlib are implemented.)The client application calls a TCP routine on the Cray toopen a TCP connection for X to communicate with the networknode "fredsbittube." The TCP software on the Cray does thisby looking up the TCP address of "fredsbittube" and sendingan open request to TCP port 6000 on fredsbittube.All X servers on TCP listen for new clients on port 6000 bydefault; this is known as a "well-known port" in IPterminology.The server receives this request from its port 6000 andchecks where it came from to see if it is on the server’slist of "trustworthy" hosts to talk to. Then, it opensanother port for communications with the client. This isthe byte stream that all X communications will go over.Actually, it is a bit more complicated than that. Each Xserver process running on the host machine is called a"display." Each display can have more than one screen thatit manages. "corporatehydra:3.2" represents screen 2 ondisplay 3 on the multi-screened network node corporatehydra.The open request would be sent on well-known port number6003.Once the byte stream is set up, what goes on does not dependvery much upon whether or not it is TCP. The client sendsan xConnClientPrefix struct (see Xproto.h) that has theversion numbers for the version of Xlib it is running, somebyte-ordering information, and two character strings usedfor authorization. If the server does not like theauthorization strings or the version numbers do not matchwithin the rules, or if anything else is wrong, it sends afailure response with a reason string.If the information never comes, or comes much too slowly,the connection should be broken off. You must implement theconnection timeout. The sample server implements this bykeeping a timestamp for each still-connecting client and,each time just before it attempts to accept new connections,it closes any connection that are too old. The connectiontimeout can be set from the command line.You must implement whatever authorization schemes you wantto support. The sample server on the distribution tapesupports a simple authorization scheme. The only interfaceseen by DIX is:char *ClientAuthorized(client, proto_n, auth_proto, string_n, auth_string)ClientPtr client;unsigned int proto_n;char *auth_proto;unsigned int string_n;char *auth_string;DIX will only call this once per client, once it has readthe full initial connection data from the client. If theconnection should be accepted ClientAuthorized() shouldreturn NULL, and otherwise should return an error messagestring.Accepting new connections happens internally toWaitForSomething(). WaitForSomething() must call the DIXroutine NextAvailableClient() to create a client object.Processing of the initial connection data will be handled byDIX. Your OS layer must be able to map from a client towhatever information your OS code needs to communicate onthe given byte stream to the client. DIX uses thisClientPtr to refer to the client from now on. The sampleserver uses the osPrivate field in the ClientPtr to storethe file descriptor for the socket, the input and outputbuffers, and authorization information.To initialize the methods you choose to allow clients toconnect to your server, main() calls the routinevoid CreateWellKnownSockets()This routine is called only once, and not called when theserver is reset. To recreate any sockets during serverresets, the following routine is called from the main loop:void ResetWellKnownSockets()Sample implementations of both of these routines are foundin Xserver/os/connection.c.For more details, see the section called "Connection Setup"in the X protocol specification.4.3. Reading Data from ClientsRequests from the client are read in as a byte stream by theOS layer. They may be in the form of several blocks ofbytes delivered in sequence; requests may be broken up overblock boundaries or there may be many requests per block.Each request carries with it length information. It is theresponsibility of the following routine to break it up intorequest blocks.int ReadRequestFromClient(who)ClientPtr who;You must write the routine ReadRequestFromClient() to getone request from the byte stream belonging to client "who."You must swap the third and fourth bytes (the second 16-bitword) according to the byte-swap rules of the protocol todetermine the length of the request. This length ismeasured in 32-bit words, not in bytes. Therefore, thetheoretical maximum request is 256K. (However, the maximumlength allowed is dependent upon the server’s input buffer.This size is sent to the client upon connection. Themaximum size is the constant MAX_REQUEST_SIZE inXserver/include/os.h) The rest of the request you return isassumed NOT to be correctly swapped for internal use,because that is the responsibility of DIX.The ’who’ argument is the ClientPtr returned fromWaitForSomething. The return value indicating status shouldbe set to the (positive) byte count if the read issuccessful, 0 if the read was blocked, or a negative errorcode if an error happened.You must then store a pointer to the bytes of the request inthe client request buffer field; who->requestBuffer. Thiscan simply be a pointer into your buffer; DIX may modify itin place but will not otherwise cause damage. Of course,the request must be contiguous; you must shuffle it aroundin your buffers if not.The sample server implementation is in Xserver/os/io.c.DIX can insert data into the client stream, and can cause a"replay" of the current request.Bool InsertFakeRequest(client, data, count)ClientPtr client;char *data;int count;int ResetCurrentRequest(client)ClientPtr client;InsertFakeRequest() must insert the specified number ofbytes of data into the head of the input buffer for theclient. This may be a complete request, or it might be apartial request. For example, NextAvailableCient() willinsert a partial request in order to read the initialconnection data sent by the client. The routine returnsFALSE if memory could not be allocated.ResetCurrentRequest() should "back up" the input buffer sothat the currently executing request will be reexecuted.DIX may have altered some values (e.g. the overall requestlength), so you must recheck to see if you still have acomplete request. ResetCurrentRequest() should always causea yield (isItTimeToYield).4.4. Sending Events, Errors And Replies To Clientsint WriteToClient(who, n, buf)ClientPtr who;int n;char *buf;WriteToClient should write n bytes starting at buf to theClientPtr "who". It returns the number of bytes written,but for simplicity, the number returned must be either thesame value as the number requested, or -1, signaling anerror. The sample server implementation is inXserver/os/io.c.void SendErrorToClient(client, majorCode, minorCode, resId, errorCode)ClientPtr client;unsigned int majorCode;unsigned int minorCode;XID resId;int errorCode;SendErrorToClient can be used to send errors back toclients, although in most cases your request function shouldsimply return the error code, having set client->errorValueto the appropriate error value to return to the client, andDIX will call this function with the correct opcodes foryou. void FlushAllOutput()void FlushIfCriticalOutputPending()void SetCriticalOutputPending()These three routines may be implemented to support bufferedor delayed writes to clients, but at the very least, thestubs must exist. FlushAllOutput() unconditionally flushesall output to clients; FlushIfCriticalOutputPending()flushes output only if SetCriticalOutputPending() has becalled since the last time output was flushed. The sampleserver implementation is in Xserver/os/io.c and actuallyignores requests to flush output on a per-client basis if itknows that there are requests in that client’s input queue.4.5. Font SupportIn the sample server, fonts are encoded in disk files orfetched from the font server. For disk fonts, there is onefile per font, with a file name like "fixed.pcf". Fontserver fonts are read over the network using the X FontServer Protocol. The disk directories containing disk fontsand the names of the font servers are listed together in thecurrent "font path."In principle, you can put all your fonts in ROM or in RAM inyour server. You can put them all in one library file ondisk. You could generate them on the fly from strokedescriptions. By placing the appropriate code in the FontLibrary, you will automatically export fonts in that formatboth through the X server and the Font server.With the incorporation of font-server based fonts and theSpeedo donation from Bitstream, the font interfaces havebeen moved into a separate library, now called the FontLibrary (../fonts/lib). These routines are shared betweenthe X server and the Font server, so instead of thisdocument specifying what you must implement, simply refer tothe font library interface specification for the details.All of the interface code to the Font library is containedin dix/dixfonts.c4.6. Memory ManagementMemory management is based on functions in the C runtimelibrary. Xalloc(), Xrealloc(), and Xfree() work just likemalloc(), realloc(), and free(), except that you can pass anull pointer to Xrealloc() to have it allocate anew or passa null pointer to Xfree() and nothing will happen. Theversions in the sample server also do some checking that isuseful for debugging. Consult a C runtime library referencemanual for more details.The macros ALLOCATE_LOCAL and DEALLOCATE_LOCAL are providedin Xserver/include/os.h. These are useful if your compilersupports alloca() (or some method of allocating memory fromthe stack); and are defined appropriately on systems whichsupport it.Treat memory allocation carefully in your implementation.Memory leaks can be very hard to find and are frustrating toa user. An X server could be running for days or weekswithout being reset, just like a regular terminal. If youleak a few dozen k per day, that will add up and will causeproblems for users that leave their workstations on.4.7. Client SchedulingThe X server has the ability to schedule clients much likean operating system would, suspending and restarting themwithout regard for the state of their input buffers. Thisfunctionality allows the X server to suspend one client andcontinue processing requests from other clients whilewaiting for a long-term network activity (like loading afont) before continuing with the first client.Bool isItTimeToYield;isItTimeToYield is a global variable you can set if you wantto tell DIX to end the client’s "time slice" and startpaying attention to the next client. After the currentrequest is finished, DIX will move to the next client.In the sample server, ReadRequestFromClient() setsisItTimeToYield after 10 requests packets in a row are readfrom the same client.This scheduling algorithm can have a serious effect uponperformance when two clients are drawing into their windowssimultaneously. If it allows one client to run until itsrequest queue is empty by ignoring isItTimeToYield, theclient’s queue may in fact never empty and other clientswill be blocked out. On the other hand, if it switchsbetween different clients too quickly, performance maysuffer due to too much switching between contexts. Forexample, if a graphics processor needs to be set up withdrawing modes before drawing, and two different clients aredrawing with different modes into two different windows, youmay switch your graphics processor modes so often thatperformance is impacted.See the Strategies document for heuristics on settingisItTimeToYield.The following functions provide the ability to suspendrequest processing on a particular client, resuming it atsome later time:int IgnoreClient (who)ClientPtr who;int AttendClient (who)ClientPtr who;Ignore client is responsible for pretending that the givenclient doesn’t exist. WaitForSomething should not returnthis client as ready for reading and should not return ifonly this client is ready. AttendClient undoes whateverIgnoreClient did, setting it up for input again.Three functions support "process control" for X clients:Bool ClientSleep (client, function, closure)ClientPtr client;Bool (*function)();pointer closure;This suspends the current client (the calling routine isresponsible for making its way back to Dispatch()). No moreX requests will be processed for this client untilClientWakeup is called.Bool ClientSignal (client)ClientPtr client;This function causes a call to the (*function) parameterpassed to ClientSleep to be queued on the work queue. Thisdoes not automatically "wakeup" the client, but the functioncalled is free to do so by calling:ClientWakeup (client)ClientPtr client;This re-enables X request processing for the specifiedclient.4.8. Other OS FunctionsvoidErrorF(char *f, ...)voidFatalError(char *f, ...)voidError(str)char *str;You should write these three routines to provide fordiagnostic output from the dix and ddx layers, althoughimplementing them to produce no output will not affect thecorrectness of your server. ErrorF() and FatalError() takea printf() type of format specification in the firstargument and an implementation-dependent number of argumentsfollowing that. Normally, the formats passed to ErrorF()and FatalError() should be terminated with a newline.Error() provides an os interface for printing out the stringpassed as an argument followed by a meaningful explanationof the last system error. Normally the string does notcontain a newline, and it is only called by the ddx layer.In the sample implementation, Error() uses the perror()function.After printing the message arguments, FatalError() must beimplemented such that the server will call AbortDDX() togive the ddx layer a chance to reset the hardware, and thenterminate the server; it must not return.The sample server implementation for these routines is inXserver/os/util.c.4.9. Idiom SupportThe DBE specification introduces the notion of idioms, whichare groups of X requests which can be executed moreefficiently when taken as a whole compared to beingperformed individually and sequentially. This followingserver internal support to allows DBE implementations, aswell as other parts of the server, to do idiom processing.xReqPtr PeekNextRequest(xReqPtr req, ClientPtr client, Bool readmore)If req is NULL, the return value will be a pointer to thestart of the complete request that follows the one currentlybeing executed for the client. If req is not NULL, thefunction assumes that req is a pointer to a request in theclient’s request buffer, and the return value will be apointer to the the start of the complete request thatfollows req. If the complete request is not available, thefunction returns NULL; pointers to partial requests willnever be returned. If (and only if) readmore is TRUE,PeekNextRequest should try to read an additional requestfrom the client if one is not already available in theclient’s request buffer. If PeekNextRequest reads more datainto the request buffer, it should not move or change theexisting data.void SkipRequests(xReqPtr req, ClientPtr client, int numskipped)The requests for the client up to and including the onespecified by req will be skipped. numskipped must be thenumber of requests being skipped. Normal request processingwill resume with the request that follows req. The callermust not have modified the contents of the request buffer inany way (e.g., by doing byte swapping in place).Additionally, two macros in os.h operate on the xReq pointerreturned by PeekNextRequest:int ReqLen(xReqPtr req, ClientPtr client)The value of ReqLen is the request length in bytes of thegiven xReq.otherReqTypePtr CastxReq(xReq *req, otherReqTypePtr)The value of CastxReq is the conversion of the given requestpointer to an otherReqTypePtr (which should be a pointer toa protocol structure type). Only those fields which comeafter the length field of otherReqType may be accessed viathe returned pointer.Thus the first two fields of a request, reqType and data,can be accessed directly using the xReq * returned byPeekNextRequest. The next field, the length, can beaccessed with ReqLen. Fields beyond that can be accessedwith CastxReq. This complexity was necessary because of thereencoding of core protocol that can happen due to theBigRequests extension.5. DDX LAYERThis section describes the interface between DIX and DDX.While there may be an OS-dependent driver interface betweenDDX and the physical device, that interface is left to theDDX implementor and is not specified here.The DDX layer does most of its work through procedures thatare pointed to by different structs. As previouslydescribed, the behavior of these resources is largelydetermined by these procedure pointers. Most of theseroutines are for graphic display on the screen or supportfunctions thereof. The rest are for user input from inputdevices.5.1. INPUTIn this document "input" refers to input from the user, suchas mouse, keyboard, and bar code readers. X input devicesare of several types: keyboard, pointing device, and manyothers. The core server has support for extension devicesas described by the X Input Extension document; theinterfaces used by that extension are described elsewhere.The core devices are actually implemented as two collectionsof devices, the mouse is a ButtonDevice, a ValuatorDeviceand a PtrFeedbackDevice while the keyboard is a KeyDevice, aFocusDevice and a KbdFeedbackDevice. Each part implements aportion of the functionality of the device. Thisabstraction is hidden from view for core devices by DIX.You, the DDX programmer, are responsible for some of theroutines in this section. Others are DIX routines that youshould call to do the things you need to do in these DDXroutines. Pay attention to which is which.5.1.1. Input Device Data StructuresDIX keeps a global directory of devices in a central datastructure called InputInfo. For each device there is adevice structure called a DeviceRec. DIX can locate anyDeviceRec through InputInfo. In addition, it has a specialpointer to identify the main pointing device and a specialpointer to identify the main keyboard.The DeviceRec (Xserver/include/input.h) is adevice-independent structure that contains the state of aninput device. A DevicePtr is simply a pointer to aDeviceRec.An xEvent describes an event the server reports to a client.Defined in Xproto.h, it is a huge struct of union of structsthat have fields for all kinds of events. All of thevariants overlap, so that the struct is actually very smallin memory.5.1.2. Processing EventsThe main DDX input interface is the following routine:void ProcessInputEvents()You must write this routine to deliver input events from theuser. DIX calls it when input is pending (see nextsection), and possibly even when it is not. You shouldwrite it to get events from each device and deliver theevents to DIX. To deliver the events to DIX, DDX shouldcall the following routine:void DevicePtr->processInputProc(pEvent, device, count)xEventPtr events;DeviceIntPtr device;int count;This is the "input proc" for the device, a DIX procedure.DIX will fill in this procedure pointer to one of its ownroutines by the time ProcessInputEvents() is called thefirst time. Call this input proc routine as many times asneeded to deliver as many events as should be delivered.DIX will buffer them up and send them out as needed. Countis set to the number of event records which make up oneatomic device event and is always 1 for the core devices(see the X Input Extension for descriptions of devices whichmay use count > 1).For example, your ProcessInputEvents() routine might checkthe mouse and the keyboard. If the keyboard had severalkeystrokes queued up, it could just call the keyboard’sprocessInputProc as many times as needed to flush itsinternal queue.event is an xEvent struct you pass to the input proc. Whenthe input proc returns, it is finished with the event rec,and you can fill in new values and call the input proc againwith it.You should deliver the events in the same order that theywere generated.For keyboard and pointing devices the xEvent variant shouldbe keyButtonPointer. Fill in the following fields in thexEvent record:type is one of the following: KeyPress, KeyRelease, ButtonPress,ButtonRelease, or MotionNotifydetail for KeyPress or KeyRelease fields, this should be thekey number (not the ASCII code); otherwise unusedtime is the time that the event happened (32-bits, in milliseconds, arbitrary origin)rootX is the x coordinate of cursorrootY is the y coordinate of cursorThe rest of the fields are filled in by DIX.The time stamp is maintained by your code in the DDX layer,and it is your responsibility to stamp all events correctly.The x and y coordinates of the pointing device and the timemust be filled in for all event types including keyboardevents.The pointing device must report all button press and releaseevents. In addition, it should report a MotionNotify eventevery time it gets called if the pointing device has movedsince the last notify. Intermediate pointing device movesare stored in a special GetMotionEvents buffer, because mostclient programs are not interested in them.There are quite a collection of sample implementations ofthis routine, one for each supported device.5.1.3. Telling DIX When Input is PendingIn the server’s dispatch loop, DIX checks to see if there isany device input pending whenever WaitForSomething()returns. If the check says that input is pending, DIX callsthe DDX routine ProcessInputEvents().This check for pending input must be very quick; a procedurecall is too slow. The code that does the check is ahardwired IF statement in DIX code that simply compares thevalues pointed to by two pointers. If the values aredifferent, then it assumes that input is pending andProcessInputEvents() is called by DIX.You must pass pointers to DIX to tell it what values tocompare. The following procedure is used to set thesepointers:void SetInputCheck(p1, p2)long *p1, *p2;You should call it sometime during initialization toindicate to DIX the correct locations to check. You shouldpay special attention to the size of what they actuallypoint to, because the locations are assumed to be longs.These two pointers are initialized by DIX to point toarbitrary values that are different. In other words, if youforget to call this routine during initialization, the worstthing that will happen is that ProcessInputEvents will becalled when there are no events to process.p1 and p2 might point at the head and tail of some sharedmemory queue. Another use would be to have one point at aconstant 0, with the other pointing at some mask containing1s for each input device that has something pending.The DDX layer of the sample server calls SetInputCheck()once when the server’s private internal queue isinitialized. It passes pointers to the queue’s head andtail. See Xserver/mi/mieq.c.int TimeSinceLastInputEvent()DDX must time stamp all hardware input events. But DIXsometimes needs to know the time and the OS layer needs toknow the time since the last hardware input event in orderfor the screen saver to work. TimeSinceLastInputEvent()returns the this time in milliseconds.5.1.4. Controlling Input DevicesYou must write four routines to do various device-specificthings with the keyboard and pointing device. They can haveany name you wish because you pass the procedure pointers toDIX routines.int pInternalDevice->valuator->GetMotionProc(pdevice, coords, start, stop, pScreen)DeviceIntPtr pdevice;xTimecoord * coords;unsigned long start;unsigned long stop;ScreenPtr pScreen;You write this DDX routine to fill in coords with all themotion events that have times (32-bit count of milliseconds)between time start and time stop. It should return thenumber of motion events returned. If there is no motionevents support, this routine should do nothing and returnzero. The maximum number of coords to return is set inInitPointerDeviceStruct(), below.When the user drags the pointing device, the cursor positiontheoretically sweeps through an infinite number of points.Normally, a client that is concerned with points other thanthe starting and ending points will receive a pointer-moveevent only as often as the server generates them. (Moveevents do not queue up; each new one replaces the last inthe queue.) A server, if desired, can implement a scheme tosave these intermediate events in a motion buffer. A clientapplication, like a paint program, may then request thatthese events be delivered to it through the GetMotionProcroutine.void pInternalDevice->bell->BellProc(percent, pDevice, ctrl, unknown)int percent;DeviceIntPtr pDevice;pointer ctrl;int class;You need to write this routine to ring the bell on thekeyboard. loud is a number from 0 to 100, with 100 beingthe loudest. Class is either BellFeedbackClass orKbdFeedbackClass (from XI.h).void pInternalDevice->somedevice->CtrlProc(device, ctrl)DevicePtr device;SomethingCtrl *ctrl;You write two versions of this procedure, one for thekeyboard and one for the pointing device. DIX calls it toinform DDX when a client has requested changes in thecurrent settings for the particular device. For a keyboard,this might be the repeat threshold and rate. For a pointingdevice, this might be a scaling factor (coarse or fine) forposition reporting. See input.h for the ctrl structures.5.1.5. Input InitializationInput initialization is a bit complicated. It all startswith InitInput(), a routine that you write to callAddInputDevice() twice (once for pointing device and oncefor keyboard.) You also want to callRegisterKeyboardDevice() and RegisterPointerDevice() onthem.When you Add the devices, a routine you supply for eachdevice gets called to initialize them. Your individualinitialize routines must call InitKeyboardDeviceStruct() orInitPointerDeviceStruct(), depending upon which it is. Inother words, you indicate twice that the keyboard is thekeyboard and the pointer is the pointer.void InitInput(argc, argv)int argc;char **argv;InitInput is a DDX routine you must write to initialize theinput subsystem in DDX. It must call AddInputDevice() foreach device that might generate events. In addition, youmust register the main keyboard and pointing devices bycalling RegisterPointerDevice() andRegisterKeyboardDevice().DevicePtr AddInputDevice(deviceProc, autoStart)DeviceProc deviceProc;Bool autoStart;AddInputDevice is a DIX routine you call to create a deviceobject. deviceProc is a DDX routine that is called by DIXto do various operations. AutoStart should be TRUE fordevices that need to be turned on at initialization timewith a special call, as opposed to waiting for some clientapplication to turn them on. This routine returns NULL ifsufficient memory cannot be allocated to install the device.Note also that except for the main keyboard and pointingdevice, an extension is needed to provide for a clientinterface to a device.void RegisterPointerDevice(device)DevicePtr device;RegisterPointerDevice is a DIX routine that your DDX codecalls that makes that device the main pointing device. Thisroutine is called once upon initialization and cannot becalled again.void RegisterKeyboardDevice(device)DevicePtr device;RegisterKeyboardDevice makes the given device the mainkeyboard. This routine is called once upon initializationand cannot be called again.The following DIX procedures return the specified DevicePtr.They may or may not be useful to DDX implementors.DevicePtr LookupKeyboardDevice()LookupKeyboardDevice returns pointer for current mainkeyboard device.DevicePtr LookupPointerDevice()LookupPointerDevice returns pointer for current mainpointing device.A DeviceProc (the kind passed to AddInputDevice()) in thefollowing form:Bool pInternalDevice->DeviceProc(device, action);DeviceIntPtr device;int action;You must write a DeviceProc for each device. device pointsto the device record. action tells what action to take; itwill be one of these defined constants (defined ininput.h):• DEVICE_INIT - At DEVICE_INIT time, the device shouldinitialize itself by calling InitPointerDeviceStruct(),InitKeyboardDeviceStruct(), or a similar routine (seebelow) and "opening" the device if necessary. If youreturn a non-zero (i.e., != Success) value from theDEVICE_INIT call, that device will be consideredunavailable. If either the main keyboard or mainpointing device cannot be initialized, the DIX codewill refuse to continue booting up.• DEVICE_ON - If the DeviceProc is called with DEVICE_ON,then it is allowed to start putting events into theclient stream by calling through the ProcessInputProcin the device.• DEVICE_OFF - If the DeviceProc is called withDEVICE_OFF, no further events from that device shouldbe given to the DIX layer. The device will appear tobe dead to the user.• DEVICE_CLOSE - At DEVICE_CLOSE (terminate or reset)time, the device should be totally closed down.void InitPointerDeviceStruct(device, map, mapLength,GetMotionEvents, ControlProc, numMotionEvents)DevicePtr device;CARD8 *map;int mapLength;ValuatorMotionProcPtr ControlProc;PtrCtrlProcPtr GetMotionEvents;int numMotionEvents;InitPointerDeviceStruct is a DIX routine you call atDEVICE_INIT time to declare some operating routines anddata structures for a pointing device. map andmapLength are as described in the X Window Systemprotocol specification. ControlProc andGetMotionEvents are DDX routines, see above.numMotionEvents is for the motion-buffer-size for theGetMotionEvents request. A typical length for a motionbuffer would be 100 events. A server that does notimplement this capability should set numMotionEvents tozero.void InitKeyboardDeviceStruct(device, pKeySyms, pModifiers, Bell, ControlProc)DevicePtr device;KeySymsPtr pKeySyms;CARD8 *pModifiers;BellProcPtr Bell;KbdCtrlProcPtr ControlProc;You call this DIX routine when a keyboard device isinitialized and its device procedure is called withDEVICE_INIT. The formats of the keysyms and modifiermaps are defined in Xserver/include/input.h. Theydescribe the layout of keys on the keyboards, and theglyphs associated with them. ( See the next sectionfor information on setting up the modifier map and thekeysym map.) ControlProc and Bell are DDX routines,see above.5.1.6. Keyboard Mapping and KeycodesWhen you send a keyboard event, you send a report that agiven key has either been pressed or has been released.There must be a keycode for each key that identifies thekey; the keycode-to-key mapping can be any mapping youdesire, because you specify the mapping in a table you setup for DIX. However, you are restricted by the protocolspecification to keycode values in the range 8 to 255inclusive.The keycode mapping information that you set up consists ofthe following:• A minimum and maximum keycode number• An array of sets of keysyms for each key, that is oflength maxkeycode - minkeycode + 1. Each element ofthis array is a list of codes for symbols that are onthat key. There is no limit to the number of symbolsthat can be on a key.Once the map is set up, DIX keeps and maintains the client’schanges to it.The X protocol defines standard names to indicate thesymbol(s) printed on each keycap. (See X11/keysym.h)Legal modifier keys must generate both up and downtransitions. When a client tries to change a modifier key(for instance, to make "A" the "Control" key), DIX calls thefollowing routine, which should retuurn TRUE if the key canbe used as a modifier on the given device:Bool LegalModifier(key, pDev)unsigned int key;DevicePtr pDev;5.2. ScreensDifferent computer graphics displays have differentcapabilities. Some are simple monochrome frame buffers thatare just lying there in memory, waiting to be written into.Others are color displays with many bits per pixel usingsome color lookup table. Still others have high-speedgraphic processors that prefer to do all of the workthemselves, including maintaining their own high-level,graphic data structures.5.2.1. Screen Hardware RequirementsThe only requirement on screens is that you be able to bothread and write locations in the frame buffer. All screensmust have a depth of 32 or less (unless you use an Xextension to allow a greater depth). All screens must fitinto one of the classes listed in the section in thisdocument on Visuals and Depths.X uses the pixel as its fundamental unit of distance on thescreen. Therefore, most programs will measure everything inpixels.The sample server assumes square pixels. Serious WYSIWYG(what you see is what you get) applications for publishingand drawing programs will adjust for different screenresolutions automatically. Considerable work is involved incompensating for non-square pixels (a bit in the DDX codefor the sample server but quite a bit in the clientapplications).5.2.2. Data StructuresX supports multiple screens that are connected to the sameserver. Therefore, all the per-screen information isbundled into one data structure of attributes andprocedures, which is the ScreenRec (seeXserver/include/scrnintstr.h). The procedure entry pointsin a ScreenRec operate on regions, colormaps, cursors, andfonts, because these resources can differ in format from onescreen to another.Windows are areas on the screen that can be drawn into bygraphic routines. "Pixmaps" are off-screen graphic areasthat can be drawn into. They are both considered drawablesand are described in the section on Drawables. All graphicoperations work on drawables, and operations are availableto copy patches from one drawable to another.The pixel image data in all drawables is in a format that isprivate to DDX. In fact, each instance of a drawable isassociated with a given screen. Presumably, the pixel imagedata for pixmaps is chosen to be conveniently understood bythe hardware. All screens in a single server must be ableto handle all pixmaps depths declared in the connectionsetup information.Pixmap images are transferred to the server in one of twoways: XYPixmap or ZPimap. XYPixmaps are a series ofbitmaps, one for each bit plane of the image, using thebitmap padding rules from the connection setup. ZPixmapsare a series of bits, nibbles, bytes or words, one for eachpixel, using the format rules (padding and so on) for theappropriate depth.All screens in a given server must agree on a set of pixmapimage formats (PixmapFormat) to support (depth, number ofbits per pixel, etc.).There is no color interpretation of bits in the pixmap.Pixmaps do not contain pixel values. The interpretation ismade only when the bits are transferred onto the screen.The screenInfo structure (in scrnintstr.h) is a global datastructure that has a pointer to an array of ScreenRecs, onefor each screen on the server. (These constitute the oneand only description of each screen in the server.) Eachscreen has an identifying index (0, 1, 2, ...). Inaddition, the screenInfo struct contains global server-widedetails, such as the bit- and byte- order in all bit images,and the list of pixmap image formats that are supported.The X protocol insists that these must be the same for allscreens on the server.5.2.3. Output InitializationInitOutput(pScreenInfo, argc, argv)ScreenInfo *pScreenInfo;int argc;char **argv;Upon initialization, your DDX routine InitOutput() is calledby DIX. It is passed a pointer to screenInfo to initialize.It is also passed the argc and argv from main() for yourserver for the command-line arguments. These arguments mayindicate what or how many screen device(s) to use or in whatway to use them. For instance, your server command line mayallow a "-D" flag followed by the name of the screen deviceto use.Your InitOutput() routine should initialize each screen youwish to use by calling AddScreen(), and then it shouldinitialize the pixmap formats that you support by storingvalues directly into the screenInfo data structure. Youshould also set certain implementation-dependent numbers andprocedures in your screenInfo, which determines the pixmapand scanline padding rules for all screens in the server.int AddScreen(scrInitProc, argc, argv)Bool (*scrInitProc)();int argc;char **argv;You should call AddScreen(), a DIX procedure, inInitOutput() once for each screen to add it to thescreenInfo database. The first argument is aninitialization procedure for the screen that you supply.The second and third are the argc and argv from main(). Itreturns the screen number of the screen installed, or -1 ifthere is either insufficient memory to add the screen, or(*scrInitProc) returned FALSE.The scrInitProc should be of the following form:Bool scrInitProc(iScreen, pScreen, argc, argv)int iScreen;ScreenPtr pScreen;int argc;char **argv;iScreen is the index for this screen; 0 for the first oneinitialized, 1 for the second, etc. pScreen is the pointerto the screen’s new ScreenRec. argc and argv are as before.Your screen initialize procedure should return TRUE uponsuccess or FALSE if the screen cannot be initialized (forinstance, if the screen hardware does not exist on thismachine).This procedure must determine what actual device it issupposed to initialize. If you have a different procedurefor each screen, then it is no problem. If you have thesame procedure for multiple screens, it may have troublefiguring out which screen to initialize each time around,especially if InitOutput() does not initialize all of thescreens. It is probably easiest to have one procedure foreach screen.The initialization procedure should fill in all the screenprocedures for that screen (windowing functions, regionfunctions, etc.) and certain screen attributes for thatscreen.5.2.4. Region Routines in the ScreenRecA region is a dynamically allocated data structure thatdescribes an irregularly shaped piece of real estate in XYpixel space. You can think of it as a set of pixels on thescreen to be operated upon with set operations such as ANDand OR.A region is frequently implemented as a list of rectanglesor bitmaps that enclose the selected pixels. Regionoperators control the "clipping policy," or the operationsthat work on regions. (The sample server uses YX-bandedrectangles. Unless you have something already implementedfor your graphics system, you should keep thatimplementation.) The procedure pointers to the regionoperators are located in the ScreenRec data structure. Thedefinition of a region can be found in the fileXserver/include/regionstr.h. The region code is found inXserver/mi/miregion.c. DDX implementations using otherregion formats will need to supply different versions of theregion operators.Since the list of rectangles is unbounded in size, part ofthe region data structure is usually a large, dynamicallyallocated chunk of memory. As your region operatorscalculate logical combinations of regions, these blocks mayneed to be reallocated by your region software. Forinstance, in the sample server, a RegionRec has some headerinformation and a pointer to a dynamically allocatedrectangle list. Periodically, the rectangle list needs tobe expanded with Xrealloc(), whereupon the new pointer isremembered in the RegionRec.Most of the region operations come in two forms: a functionpointer in the Screen structure, and a macro. The servercan be compiled so that the macros make direct calls to theappropriate functions (instead of indirecting through ascreen function pointer), or it can be compiled so that themacros are identical to the function pointer forms. Makingdirect calls is faster on many architectures.RegionPtr pScreen->RegionCreate( rect, size)BoxPtr rect;int size;macro: RegionPtr REGION_CREATE(pScreen, rect, size)RegionCreate creates a region that describes ONE rectangle.The caller can avoid unnecessary reallocation and copying bydeclaring the probable maximum number of rectangles thatthis region will need to describe itself. Your regionroutines, though, cannot fail just because the region growsbeyond this size. The caller of this routine can passalmost anything as the size; the value is merely a goodguess as to the maximum size until it is proven wrong bysubsequent use. Your region procedures are then on theirown in estimating how big the region will get. Yourimplementation might ignore size, if applicable.void pScreen->RegionInit (pRegion, rect, size)RegionPtr pRegion;BoxPtr rect;int size;macro: REGION_INIT(pScreen, pRegion, rect, size)Given an existing raw region structure (such as an localvariable), this routine fills in the appropriate fields tomake this region as usable as one returned fromRegionCreate. This avoids the additional dynamic memoryallocation overhead for the region structure itself.Bool pScreen->RegionCopy(dstrgn, srcrgn)RegionPtr dstrgn, srcrgn;macro: Bool REGION_COPY(pScreen, dstrgn, srcrgn)RegionCopy copies the description of one region, srcrgn, toanother already-created region, dstrgn; returning TRUE ifthe copy succeeded, and FALSE otherwise.void pScreen->RegionDestroy( pRegion)RegionPtr pRegion;macro: REGION_DESTROY(pScreen, pRegion)RegionDestroy destroys a region and frees all allocatedmemory.void pScreen->RegionUninit (pRegion)RegionPtr pRegion;macro: REGION_UNINIT(pScreen, pRegion)Frees everything except the region structure itself, usefulwhen the region was originally passed to RegionInit insteadof received from RegionCreate. When this call returns,pRegion must not be reused until it has been RegionInit’edagain.Bool pScreen->Intersect(newReg, reg1, reg2)RegionPtr newReg, reg1, reg2;macro: Bool REGION_INTERSECT(pScreen, newReg, reg1, reg2)Bool pScreen->Union(newReg, reg1, reg2)RegionPtr newReg, reg1, reg2;macro: Bool REGION_UNION(pScreen, newReg, reg1, reg2)Bool pScreen->Subtract(newReg, regMinuend, regSubtrahend)RegionPtr newReg, regMinuend, regSubtrahend;macro: Bool REGION_UNION(pScreen, newReg, regMinuend, regSubtrahend)Bool pScreen->Inverse(newReg, pReg, pBox)RegionPtr newReg, pReg;BoxPtr pBox;macro: Bool REGION_INVERSE(pScreen, newReg, pReg, pBox)The above four calls all do basic logical operations onregions. They set the new region (which already exists) todescribe the logical intersection, union, set difference, orinverse of the region(s) that were passed in. Your routinesmust be able to handle a situation where the newReg is thesame region as one of the other region arguments.The subtract function removes the Subtrahend from theMinuend and puts the result in newReg.The inverse function returns a region that is the pBox minusthe region passed in. (A true "inverse" would make a regionthat extends to infinity in all directions but has holes inthe middle.) It is undefined for situations where theregion extends beyond the box.Each routine must return the value TRUE for success.void pScreen->RegionReset(pRegion, pBox)RegionPtr pRegion;BoxPtr pBox;macro: REGION_RESET(pScreen, pRegion, pBox)RegionReset sets the region to describe one rectangle andreallocates it to a size of one rectangle, if applicable.void pScreen->TranslateRegion(pRegion, x, y)RegionPtr pRegion;int x, y;macro: REGION_TRANSLATE(pScreen, pRegion, x, y)TranslateRegion simply moves a region +x in the x directionand +y in the y direction.int pScreen->RectIn(pRegion, pBox)RegionPtr pRegion;BoxPtr pBox;macro: int RECT_IN_REGION(pScreen, pRegion, pBox)RectIn returns one of the defined constants rgnIN, rgnOUT,or rgnPART, depending upon whether the box is entirelyinside the region, entirely outside of the region, or partlyin and partly out of the region. These constants aredefined in Xserver/include/region.h.Bool pScreen->PointInRegion(pRegion, x, y, pBox)RegionPtr pRegion;int x, y;BoxPtr pBox;macro: Bool POINT_IN_REGION(pScreen, pRegion, x, y, pBox)PointInRegion returns true if the point x, y is in theregion. In addition, it fills the rectangle pBox withcoordinates of a rectangle that is entirely inside ofpRegion and encloses the point. In the mi implementation,it is the largest such rectangle. (Due to the sample serverimplementation, this comes cheaply.)This routine used by DIX when tracking the pointing deviceand deciding whether to report mouse events or change thecursor. For instance, DIX needs to change the cursor whenit moves from one window to another. Due to overlappingwindows, the shape to check may be irregular. APointInRegion() call for every pointing device movement maybe too expensive. The pBox is a kind of wake-up box; DIXneed not call PointInRegion() again until the cursor wandersoutside of the returned box.Bool pScreen->RegionNotEmpty(pRegion)RegionPtr pRegion;macro: Bool REGION_NOTEMPTY(pScreen, pRegion)RegionNotEmpty is a boolean function that returns true orfalse depending upon whether the region encloses any pixels.void pScreen->RegionEmpty(pRegion)RegionPtr pRegion;macro: REGION_EMPTY(pScreen, pRegion)RegionEmpty sets the region to be empty.BoxPtr pScreen->RegionExtents(pRegion)RegionPtr pRegion;macro: REGION_EXTENTS(pScreen, pRegion)RegionExtents returns a rectangle that is the smallestpossible superset of the entire region. The caller will notmodify this rectangle, so it can be the one in your regionstruct.Bool pScreen->RegionAppend (pDstRgn, pRegion)RegionPtr pDstRgn;RegionPtr pRegion;macro: Bool REGION_APPEND(pScreen, pDstRgn, pRegion)Bool pScreen->RegionValidate (pRegion, pOverlap)RegionPtr pRegion;Bool *pOverlap;macro: Bool REGION_VALIDATE(pScreen, pRegion, pOverlap)These functions provide an optimization for clip listgeneration and must be used in conjunction. The combinedeffect is to produce the union of a collection of regions,by using RegionAppend several times, and finally callingRegionValidate which takes the intermediate representation(which needn’t be a valid region) and produces the desiredunion. pOverlap is set to TRUE if any of the originalregions overlap; FALSE otherwise.RegionPtr pScreen->BitmapToRegion (pPixmap)PixmapPtr pPixmap;macro: RegionPtr BITMAP_TO_REGION(pScreen, pPixmap)Given a depth-1 pixmap, this routine must create a validregion which includes all the areas of the pixmap filledwith 1’s and excludes the areas filled with 0’s. Thisroutine returns NULL if out of memory.RegionPtr pScreen->RectsToRegion (nrects, pRects, ordering)int nrects;xRectangle *pRects;int ordering;macro: RegionPtr RECTS_TO_REGION(pScreen, nrects, pRects, ordering)Given a client-supplied list of rectangles, produces aregion which includes the union of all the rectangles.Ordering may be used as a hint which describes how therectangles are sorted. As the hint is provided by a client,it must not be required to be correct, but the results whenit is not correct are not defined (core dump is not anoption here).void pScreen->SendGraphicsExpose(client,pRegion,drawable,major,minor)ClientPtr client;RegionPtr pRegion;XID drawable;int major;int minor;SendGraphicsExpose dispatches a list of GraphicsExposureevents which span the region to the specified client. Ifthe region is empty, or a NULL pointer, a NoExpose event issent instead.5.2.5. Cursor Routines for a ScreenA cursor is the visual form tied to the pointing device.The default cursor is an "X" shape, but the cursor can haveany shape. When a client creates a window, it declares whatshape the cursor will be when it strays into that window onthe screen.For each possible shape the cursor assumes, there is aCursorRec data structure. This data structure contains apointer to a CursorBits data structure which contains abitmap for the image of the cursor and a bitmap for a maskbehind the cursor, in addition, the CursorRec data structurecontains foreground and background colors for the cursor.The CursorBits data structure is shared among multipleCursorRec structures which use the same font and glyph todescribe both source and mask. The cursor image is appliedto the screen by applying the mask first, clearing 1 bits inits form to the background color, and then overwriting onthe source image, in the foreground color. (One bits of thesource image that fall on top of zero bits of the mask imageare undefined.) This way, a cursor can have transparentparts, and opaque parts in two colors. X allows any cursorsize, but some hardware cursor schemes allow a maximum of Npixels by M pixels. Therefore, you are allowed to transformthe cursor to a smaller size, but be sure to include thehot-spot.CursorBits in Xserver/include/cursorstr.h is adevice-independent structure containing a device-independentrepresentation of the bits for the source and mask. (Thisis possible because the bitmap representation is the samefor all screens.)When a cursor is created, it is "realized" for each screen.At realization time, each screen has the chance to convertthe bits into some other representation that may be moreconvenient (for instance, putting the cursor into off-screenmemory) and set up its device-private area in either theCursorRec data structure or CursorBits data structure asappropriate to possibly point to whatever data structuresare needed. It is more memory-conservative to sharerealizations by using the CursorBits private field, but thismakes the assumption that the realization is independent ofthe colors used (which is typically true). For instance,the following are the device private entries for aparticular screen and cursor:pCursor->devPriv[pScreen->myNum]pCursor->bits->devPriv[pScreen->myNum]This is done because the change from one cursor shape toanother must be fast and responsive; the cursor image shouldbe able to flutter as fast as the user moves it across thescreen.You must implement the following routines for your hardware:Bool pScreen->RealizeCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;Bool pScreen->UnrealizeCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;RealizeCursor and UnrealizeCursor should realize (allocateand calculate all data needed) and unrealize (free thedynamically allocated data) a given cursor when DIX needsthem. They are called whenever a device-independent cursoris created or destroyed. The source and mask bits pointedto by fields in pCurs are undefined for bits beyond theright edge of the cursor. This is so because the bits arein Bitmap format, which may have pad bits on the right edge.You should inhibit UnrealizeCursor() if the cursor iscurrently in use; this happens when the system is reset.Bool pScreen->DisplayCursor( pScr, pCurs)ScreenPtr pScr;CursorPtr pCurs;DisplayCursor should change the cursor on the given screento the one passed in. It is called by DIX when the usermoves the pointing device into a different window with adifferent cursor. The hotspot in the cursor should bealigned with the current cursor position.void pScreen->RecolorCursor( pScr, pCurs, displayed)ScreenPtr pScr;CursorPtr pCurs;Bool displayed;RecolorCursor notifies DDX that the colors in pCurs havechanged and indicates whether this is the cursor currentlybeing displayed. If it is, the cursor hardware state mayhave to be updated. Whether displayed or not, state createdat RealizeCursor time may have to be updated. A genericversion, miRecolorCursor, may be used that does anunrealize, a realize, and possibly a display (inmicursor.c); however this constrains UnrealizeCursor andRealizeCursor to always return TRUE as no error indicationis returned here.void pScreen->ConstrainCursor( pScr, pBox)ScreenPtr pScr;BoxPtr pBox;ConstrainCursor should cause the cursor to restrict itsmotion to the rectangle pBox. DIX code is capable ofenforcing this constraint by forcefully moving the cursor ifit strays out of the rectangle, but ConstrainCursor offers away to send a hint to the driver or hardware if such supportis available. This can prevent the cursor from wanderingout of the box, then jumping back, as DIX forces it back.void pScreen->PointerNonInterestBox( pScr, pBox)ScreenPtr pScr;BoxPtr pBox;PointerNonInterestBox is DIX’s way of telling the pointingdevice code not to report motion events while the cursor isinside a given rectangle on the given screen. It isoptional and, if not implemented, it should do nothing.This routine is called only when the client has declaredthat it is not interested in motion events in a givenwindow. The rectangle you get may be a subset of thatwindow. It saves DIX code the time required to discarduninteresting mouse motion events. This is only a hint,which may speed performance. Nothing in DIX currently callsPointerNonInterestBox.void pScreen->CursorLimits( pScr, pCurs, pHotBox, pTopLeftBox)ScreenPtr pScr;CursorPtr pCurs;BoxPtr pHotBox;BoxPtr pTopLeftBox; /* return value */CursorLimits should calculate the box that the cursor hotspot is physically capable of moving within, as a functionof the screen pScr, the device-independent cursor pCurs, anda box that DIX hypothetically would want the hot spotconfined within, pHotBox. This routine is for informing DIXonly; it alters no state within DDX.Bool pScreen->SetCursorPosition( pScr, newx, newy, generateEvent)ScreenPtr pScr;int newx;int newy;Bool generateEvent;SetCursorPosition should artificially move the cursor asthough the user had jerked the pointing device very quickly.This is called in response to the WarpPointer request fromthe client, and at other times. If generateEvent is True,the device should decide whether or not to callProcessInputEvents() and then it must callDevicePtr->processInputProc. Its effects are, of course,limited in value for absolute pointing devices such as atablet.void NewCurrentScreen(newScreen, x, y)ScreenPtr newScreen;int x,y;If your ddx provides some mechanism for the user tomagically move the pointer between multiple screens, youneed to inform DIX when this occurs. You should callNewCurrentScreen to accomplish this, specifying the newscreen and the new x and y coordinates of the pointer onthat screen.5.2.6. Visuals, Depths and Pixmap Formats for ScreensThe "depth" of a image is the number of bits that are usedper pixel to display it.The "bits per pixel" of a pixmap image that is sent over theclient byte stream is a number that is either 4, 8, 16, 24or 32. It is the number of bits used per pixel in Z format.For instance, a pixmap image that has a depth of six is bestsent in Z format as 8 bits per pixel.A "pixmap image format" or a "pixmap format" is adescription of the format of a pixmap image as it is sentover the byte stream. For each depth available on a server,there is one and only one pixmap format. This pixmap imageformat gives the bits per pixel and the scanline paddingunit. (For instance, are pixel rows padded to bytes, 16-bitwords, or 32-bit words?)For each screen, you must decide upon what depth(s) itsupports. You should only count the number of bits used forthe actual image. Some displays store additional bits toindicate what window this pixel is in, how close this objectis to a viewer, transparency, and other data; do not countthese bits.A "display class" tells whether the display is monochrome orcolor, whether there is a lookup table, and how the lookuptable works.A "visual" is a combination of depth, display class, and adescription of how the pixel values result in a color on thescreen. Each visual has a set of masks and offsets that areused to separate a pixel value into its red, green, and bluecomponents and a count of the number of colormap entries.Some of these fields are only meaningful when the classdictates so. Each visual also has a screen ID telling whichscreen it is usable on. Note that the depth does not implythe number of map_entries; for instance, a display can have8 bits per pixel but only 254 colormap entries for use byapplications (the other two being reserved by hardware forthe cursor).Each visual is identified by a 32-bit visual ID which theclient uses to choose what visual is desired on a givenwindow. Clients can be using more than one visual on thesame screen at the same time.The class of a display describes how this translation takesplace. There are three ways to do the translation.• Pseudo - The pixel value, as a whole, is looked up in atable of length map_entries to determine the color todisplay.• True - The pixel value is broken up into red, green,and blue fields, each of which are looked up inseparate red, green, and blue lookup tables, each oflength map_entries.• Gray - The pixel value is looked up in a table oflength map_entries to determine a gray level todisplay.In addition, the lookup table can be static (resultingcolors are fixed for each pixel value) or dynamic (lookupentries are under control of the client program). Thisleads to a total of six classes:• Static Gray - The pixel value (of however many bits)determines directly the level of gray that the pixelassumes.• Gray Scale - The pixel value is fed through a lookuptable to arrive at the level of gray to display for thegiven pixel.• Static Color - The pixel value is fed through a fixedlookup table that yields the color to display for thatpixel.• PseudoColor - The whole pixel value is fed through aprogrammable lookup table that has one color (includingred, green, and blue intensities) for each possiblepixel value, and that color is displayed.• True Color - Each pixel value consists of one or morebits that directly determine each primary colorintensity after being fed through a fixed table.• Direct Color - Each pixel value consists of one or morebits for each primary color. Each primary color valueis individually looked up in a table for that primarycolor, yielding an intensity for that primary color.For each pixel, the red value is looked up in the redtable, the green value in the green table, and the bluevalue in the blue table.Here are some examples:A simple monochrome 1 bit per pixel display is StaticGray.A display that has 2 bits per pixel for a choicebetween the colors of black, white, green and violet isStatic Color.A display that has three bits per pixel, where each bitturns on or off one of the red, green or blue guns, isin the True Color class.If you take the last example and scramble thecorrespondence between pixel values and colors itbecomes a Static Color display.A display has 8 bits per pixel. The 8 bits select oneentry out of 256 entries in a lookup table, each entryconsisting of 24 bits (8bits each for red, green, andblue). The display can show any 256 of 16 millioncolors on the screen at once. This is a pseudocolordisplay. The client application gets to fill thelookup table in this class of display.Imagine the same hardware from the last example. Yourserver software allows the user, on the command linethat starts up the server program, to fill the lookuptable to his liking once and for all. From then on,the server software would not change the lookup tableuntil it exits. For instance, the default might be alookup table with a reasonable sample of colors fromthroughout the color space. But the user could specifythat the table be filled with 256 steps of gray scalebecause he knew ahead of time he would be manipulatinga lot of black-and-white scanned photographs and notvery many color things. Clients would be presentedwith this unchangeable lookup table. Although thehardware qualifies as a PseudoColor display, the facadepresented to the X client is that this is a StaticColor display.You have to decide what kind of display you have orwant to pretend you have. When you initialize thescreen(s), this class value must be set in theVisualRec data structure along with other displaycharacteristics like the depth and other numbers.The allowable DepthRec’s and VisualRec’s are pointed toby fields in the ScreenRec. These are set up whenInitOutput() is called; you should Xalloc() appropriateblocks or use static variables initialized to thecorrect values.5.2.7. Colormaps for ScreensA colormap is a device-independent mapping between pixelvalues and colors displayed on the screen.Different windows on the same screen can have differentcolormaps at the same time. At any given time, the mostrecently installed colormap(s) will be in use in the serverso that its (their) windows’ colors will be guaranteed to becorrect. Other windows may be off-color. Although this mayseem to be chaotic, in practice most clients use the defaultcolormap for the screen.The default colormap for a screen is initialized when thescreen is initialized. It always remains in existence andis not owned by any regular client. It is owned by client 0(the server itself). Many clients will simply use thisdefault colormap for their drawing. Depending upon theclass of the screen, the entries in this colormap may bemodifiable by client applications.5.2.7.1. Colormap RoutinesYou need to implement the following routines to handle thedevice-dependent aspects of color maps. You will end upplacing pointers to these procedures in your ScreenRec datastructure(s). The sample server implementations of many ofthese routines are in both cfbcmap.c and mfbcmap.c; sincemfb does not do very much with color, the cfb versions aretypically more useful prototypes.Bool pScreen->CreateColormap(pColormap)ColormapPtr pColormap;This routine is called by the DIX CreateColormap routineafter it has allocated all the data for the new colormap andjust before it returns to the dispatcher. It is the DDXlayer’s chance to initialize the colormap, particularly ifit is a static map. See the following section for moredetails on initializing colormaps. The routine returnsFALSE if creation failed, such as due to memory limitations.Notice that the colormap has a devPriv field from which youcan hang any colormap specific storage you need. Since eachcolormap might need special information, we attached thefield to the colormap and not the visual.void pScreen->DestroyColormap(pColormap)ColormapPtr pColormap;This routine is called by the DIX FreeColormap routine afterit has uninstalled the colormap and notified all interestedparties, and before it has freed any of the colormapstorage. It is the DDX layer’s chance to free any data itadded to the colormap.void pScreen->InstallColormap(pColormap)ColormapPtr pColormap;InstallColormap should fill a lookup table on the screenwith which the colormap is associated with the colors inpColormap. If there is only one hardware lookup table forthe screen, then all colors on the screen may changesimultaneously.In the more general case of multiple hardware lookup tables,this may cause some other colormap to be uninstalled,meaning that windows that subscribed to the colormap thatwas uninstalled may end up being off-color. See the note,below, about uninstalling maps.void pScreen->UninstallColormap(pColormap)ColormapPtr pColormap;UninstallColormap should remove pColormap from screenpColormap->pScreen. Some other map, such as the default mapif possible, should be installed in place of pColormap ifapplicable. If pColormap is the default map, do nothing.If any client has requested ColormapNotify events, the DDXlayer must notify the client. (The routine WalkTree() is beused to find such windows. The DIX routines TellNoMap(),TellNewMap() and TellGainedMap() are provided to be used asthe procedure parameter to WalkTree. These procedures arein Xserver/dix/colormap.c.)int pScreen->ListInstalledColormaps(pScreen, pCmapList)ScreenPtr pScreen;XID *pCmapList;ListInstalledColormaps fills the pCMapList in with theresource ids of the installed maps and returns a count ofinstalled maps. pCmapList will point to an array of sizeMaxInstalledMaps that was allocated by the caller.void pScreen->StoreColors (pmap, ndef, pdefs)ColormapPtr pmap;int ndef;xColorItem *pdefs;StoreColors changes some of the entries in the colormappmap. The number of entries to change are ndef, and pdefspoints to the information describing what to change. Notethat partial changes of entries in the colormap are allowed.Only the colors indicated in the flags field of eachxColorItem need to be changed. However, all three colorfields will be sent with the proper value for the benefit ofscreens that may not be able to set part of a colormapvalue. If the screen is a static class, this routine doesnothing. The structure of colormap entries is nontrivial;see colormapst.h and the definition of xColorItem inXproto.h for more details.void pScreen->ResolveColor(pRed, pGreen, pBlue, pVisual)unsigned short *pRed, *pGreen, *pBlue;VisualPtr pVisual;Given a requested color, ResolveColor returns the nearestcolor that this hardware is capable of displaying on thisvisual. In other words, this rounds off each value, inplace, to the number of bits per primary color that yourscreen can use. Remember that each screen has one of theseroutines. The level of roundoff should be what you wouldexpect from the value you put in the bits_per_rgb field ofthe pVisual.Each value is an unsigned value ranging from 0 to 65535.The bits least likely to be used are the lowest ones.For example, if you had a pseudocolor display with anynumber of bits per pixel that had a lookup table supplying 6bits for each color gun (a total of 256K different colors),you would round off each value to 6 bits. Please don’tsimply truncate these values to the upper 6 bits, scale theresult so that the maximum value seen by the client will be65535 for each primary. This makes color values moreportable between different depth displays (a 6-bit truncatedwhite will not look white on an 8-bit display).5.2.7.2. Initializing a ColormapWhen a client requests a new colormap and when the servercreates the default colormap, the procedure CreateColormapin the DIX layer is invoked. That procedure allocatesmemory for the colormap and related storage such as thelists of which client owns which pixels. It then sets abit, BeingCreated, in the flags field of the ColormapRec andcalls the DDX layer’s CreateColormap routine. This is yourchance to initialize the colormap. If the colormap isstatic, which you can tell by looking at the class field,you will want to fill in each color cell to match thehardwares notion of the color for that pixel. If thecolormap is the default for the screen, which you can tellby looking at the IsDefault bit in the flags field, youshould allocate BlackPixel and WhitePixel to match thevalues you set in the pScreen structure. (Of course, youpicked those values to begin with.)You can also wait and use AllocColor() to allocateblackPixel and whitePixel after the default colormap hasbeen created. If the default colormap is static and youinitialized it in pScreen->CreateColormap, then use can useAllocColor afterwards to choose pixel values with theclosest rgb values to those desired for blackPixel andwhitePixel. If the default colormap is dynamic anduninitialized, then the rgb values you request will beobeyed, and AllocColor will again choose pixel values foryou. These pixel values can then be stored into the screen.There are two ways to fill in the colormap. The simplestway is to use the DIX function AllocColor.int AllocColor (pmap, pred, pgreen, pblue, pPix, client)ColormapPtr pmap;unsigned short *pred, *pgreen, *pblue;Pixel *pPix;int client;This takes three pointers to 16 bit color values and apointer to a suggested pixel value. The pixel value iseither an index into one colormap or a combination of threeindices depending on the type of pmap. If your colormapstarts out empty, and you don’t deliberately pick the samevalue twice, you will always get your suggested pixel. Thetruly nervous could check that the value returned in *pPixis the one AllocColor was called with. If you don’t carewhich pixel is used, or would like them sequentiallyallocated from entry 0, set *pPix to 0. This will find thefirst free pixel and use that.AllocColor will take care of all the bookkeeping and willcall StoreColors to get the colormap rgb values initialized.The hardware colormap will be changed whenever this colormapis installed.If for some reason AllocColor doesn’t do what you want, youcan do your own bookkeeping and call StoreColors yourself.This is much more difficult and shouldn’t be necessary formost devices.5.2.8. Fonts for ScreensA font is a set of bitmaps that depict the symbols in acharacter set. Each font is for only one typeface in agiven size, in other words, just one bitmap for eachcharacter. Parallel fonts may be available in a variety ofsizes and variations, including "bold" and "italic." Xsupports fonts for 8-bit and 16-bit character codes (fororiental languages that have more than 256 characters in thefont). Glyphs are bitmaps for individual characters.The source comes with some useful font files in an ASCII,plain-text format that should be comprehensible on a widevariety of operating systems. The text format, referred toas BDF, is a slight extension of the current Adobe 2.1Bitmap Distribution Format (Adobe Systems, Inc.).A short paper in PostScript format is included with thesample server that defines BDF. It includes helpfulpictures, which is why it is done in PostScript and is notincluded in this document.Your implementation should include some sort of fontcompiler to read these files and generate binary files thatare directly usable by your server implementation. Thesample server comes with the source for a font compiler.It is important the font properties contained in the BDFfiles are preserved across any font compilation. Inparticular, copyright information cannot be casually tossedaside without legal ramifications. Other properties will beimportant to some sophisticated applications.All clients get font information from the server.Therefore, your server can support any fonts it wants to.It should probably support at least the fonts supplied withthe X11 tape. In principle, you can convert fonts fromother sources or dream up your own fonts for use on yourserver.5.2.8.1. Portable Compiled FormatA font compiler is supplied with the sample server. It hascompile-time switches to convert the BDF files into aportable binary form, called Portable Compiled Format orPCF. This allows for an arbitrary data format inside thefile, and by describing the details of the format in theheader of the file, any PCF file can be read by any PCFreading client. By selecting the format which matches therequired internal format for your renderer, the PCF readercan avoid reformatting the data each time it is read in.The font compiler should be quite portable.The fonts included with the tape are stored in fonts/bdf.The font compiler is found in fonts/tools/bdftopcf.5.2.8.2. Font RealizationEach screen configured into the server has an opportunity atfont-load time to "realize" a font into some internal formatif necessary. This happens every time the font is loadedinto memory.A font (FontRec in Xserver/include/dixfontstr.h) is adevice-independent structure containing a device-independentrepresentation of the font. When a font is created, it is"realized" for each screen. At this point, the screen hasthe chance to convert the font into some other format. TheDDX layer can also put information in the devPrivatestorage.Bool pScreen->RealizeFont(pScr, pFont)ScreenPtr pScr;FontPtr pFont;Bool pScreen->UnrealizeFont(pScr, pFont)ScreenPtr pScr;FontPtr pFont;RealizeFont and UnrealizeFont should calculate and allocatethese extra data structures and dispose of them when nolonger needed. These are called in response to OpenFont andCloseFont requests from the client. The sample serverimplementation is in mfbfont.c (which does very little).5.2.9. Other Screen RoutinesYou must supply several other screen-specific routines foryour X server implementation. Some of these are describedin other sections:• GetImage() is described in the Drawing Primitivessection.• GetSpans() is described in the Pixblit routine section.• Several window and pixmap manipulation procedures aredescribed in the Window section under Drawables.• The CreateGC() routine is described under GraphicsContexts.void pScreen->QueryBestSize(kind, pWidth, pHeight)int kind;unsigned short *pWidth, *pHeight;ScreenPtr pScreen;QueryBestSize() returns the best sizes for cursors, tiles,and stipples in response to client requests. kind is one ofthe defined constants CursorShape, TileShape, orStippleShape (defined in X.h). For CursorShape, return themaximum width and height for cursors that you can handle.For TileShape and StippleShape, start with the suggestedvalues in pWidth and pHeight and modify them in place to beoptimal values that are greater than or equal to thesuggested values. The sample server implementation is inXserver/mfb/mfbmisc.c.pScreen->SourceValidate(pDrawable, x, y, width, height)DrawablePtr pDrawable;int x, y, width, height;SourceValidate should be called by CopyArea/CopyPlaneprimitives when the source drawable is not the same as thedestination, and the SourceValidate function pointer in thescreen is non-null. If you know that you will never needSourceValidate, you can avoid this check. Currently,SourceValidate is used by the mi software cursor code toremove the cursor from the screen when the source rectangleoverlaps the cursor position. x,y,width,height describe thesource rectangle (source relative, that is) for the copyoperation.Bool pScreen->SaveScreen(pScreen, on)ScreenPtr pScreen;int on;SaveScreen() is used for Screen Saver support (seeWaitForSomething()). pScreen is the screen to save.Bool pScreen->CloseScreen(pScreen)ScreenPtr pScreen;When the server is reset, it calls this routine for eachscreen.Bool pScreen->CreateScreenResources(pScreen)ScreenPtr pScreen;If this routine is not NULL, it will be called once perscreen per server initialization/reset after all moduleshave had a chance to register their devPrivates on allstructures that support them (see the section on devPrivatesbelow). If you need to create any resources that havedynamic devPrivates as part of your screen initialization,you should do so in this function instead of in the screeninit function passed to AddScreen to guarantee that theresources have a complete set of devPrivates. This routinereturns TRUE if successful.5.3. DrawablesA drawable is a descriptor of a surface that graphics aredrawn into, either a window on the screen or a pixmap inmemory.Each drawable has a type, class, ScreenPtr for the screen itis associated with, depth, position, size, and serialnumber. The type is one of the defined constantsDRAWABLE_PIXMAP, DRAWABLE_WINDOW and UNDRAWABLE_WINDOW. (Anundrawable window is used for window class InputOnly.) Theserial number is guaranteed to be unique across drawables,and is used in determining the validity of the clippinginformation in a GC. The screen selects the set ofprocedures used to manipulate and draw into the drawable.Position is used (currently) only by windows; pixmaps mustset these fields to 0,0 as this reduces the amount ofconditional code executed throughout the mi code. Sizeindicates the actual client-specified size of the drawable.There are, in fact, no other fields that a window drawableand pixmap drawable have in common besides those mentionedhere.Both PixmapRecs and WindowRecs are structs that start with adrawable and continue on with more fields. Pixmaps havedevPrivate pointers which usually point to the pixmap databut could conceivably be used for anything that DDX wants.Both windows and pixmaps have an array of devPrivatesunions, one entry of which will probably be used for DDXspecific data. Entries in this array are allocated usingAllocate{Window|Pixmap}PrivateIndex() (see Wrappers anddevPrivates below). This is done because different graphicshardware has different requirements for management; if thegraphics is always handled by a processor with anindependent address space, there is no point having apointer to the bit image itself.The definition of a drawable and a pixmap can be found inthe file Xserver/include/pixmapstr.h. The definition of awindow can be found in the file Xserver/include/windowstr.h.5.3.1. PixmapsA pixmap is a three-dimensional array of bits storedsomewhere offscreen, rather than in the visible portion ofthe screen’s display frame buffer. It can be used as asource or destination in graphics operations. There is noimplied interpretation of the pixel values in a pixmap,because it has no associated visual or colormap. There isonly a depth that indicates the number of significant bitsper pixel. Also, there is no implied physical size for eachpixel; all graphic units are in numbers of pixels.Therefore, a pixmap alone does not constitute a completeimage; it represents only a rectangular array of pixelvalues.Note that the pixmap data structure is reference-counted.The server implementation is free to put the pixmap dataanywhere it sees fit, according to its graphics hardwaresetup. Many implementations will simply have the datadynamically allocated in the server’s address space. Moresophisticated implementations may put the data inundisplayed framebuffer storage.In addition to dynamic devPrivates (see the section ondevPrivates below), the pixmap data structure has two fieldsthat are private to the device. Although you can use themfor anything you want, they have intended purposes. devKindis intended to be a device specific indication of the pixmaplocation (host memory, off-screen, etc.). In the sampleserver, since all pixmaps are in memory, devKind stores thewidth of the pixmap in bitmap scanline units. devPrivate isprobably a pointer to the bits in the pixmap.A bitmap is a pixmap that is one bit deep.PixmapPtr pScreen->CreatePixmap(pScreen, width, height, depth)ScreenPtr pScreen;int width, height, depth;This ScreenRec procedure must create a pixmap of the sizerequested. It must allocate a PixmapRec and fill in all ofthe fields. The reference count field must be set to 1. Ifwidth or height are zero, no space should be allocated forthe pixmap data, and if the implementation is using thedevPrivate field as a pointer to the pixmap data, it shouldbe set to NULL. If successful, it returns a pointer to thenew pixmap; if not, it returns NULL. SeeXserver/mfb/mfbpixmap.c for the sample serverimplementation.Bool pScreen->DestroyPixmap(pPixmap)PixmapPtr pPixmap;This ScreenRec procedure must "destroy" a pixmap. It shoulddecrement the reference count and, if zero, it mustdeallocate the PixmapRec and all attached devPrivate blocks.If successful, it returns TRUE. See Xserver/mfb/mfbpixmap.cfor the sample server implementation.BoolpScreen->ModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData)PixmapPtr pPixmap;int width;int height;int depth;int bitsPerPixel;int devKind;pointer pPixData;This routine takes a pixmap header (the PixmapRec plus allthe dynamic devPrivates) and initializes the fields of thePixmapRec to the parameters of the same name. pPixmap musthave been created via pScreen->CreatePixmap with a zerowidth or height to avoid allocating space for the pixmapdata. pPixData is assumed to be the pixmap data; it will bestored in an implementation-dependent place (usuallypPixmap->devPrivate.ptr). This routine returns TRUE ifsuccessful. See Xserver/mi/miscrinit.c for the sampleserver implementation.PixmapPtrGetScratchPixmapHeader(pScreen, width, height, depth, bitsPerPixel, devKind, pPixData)ScreenPtr pScreen;int width;int height;int depth;int bitsPerPixel;int devKind;pointer pPixData;void FreeScratchPixmapHeader(pPixmap)PixmapPtr pPixmap;DDX should use these two DIX routines when it has a bufferof raw image data that it wants to manipulate as a pixmaptemporarily, usually so that some other part of the servercan be leveraged to perform some operation on the data. Thedata should be passed in pPixData, and will be stored in animplementation-dependent place (usuallypPixmap->devPrivate.ptr). The other fields go into thecorresponding PixmapRec fields. If successful,GetScratchPixmapHeader returns a valid PixmapPtr which canbe used anywhere the server expects a pixmap, else itreturns NULL. The pixmap should be released when no longerneeded (usually within the same function that allocated it)with FreeScratchPixmapHeader.5.3.2. WindowsA window is a visible, or potentially visible, rectangle onthe screen. DIX windowing functions maintain an internaln-ary tree data structure, which represents the currentrelationships of the mapped windows. Windows that arecontained in another window are children of that window andare clipped to the boundaries of the parent. The rootwindow in the tree is the window for the entire screen.Sibling windows constitute a doubly-linked list; the parentwindow has a pointer to the head and tail of this list.Each child also has a pointer to its parent.The border of a window is drawn by a DDX procedure when DIXrequests that it be drawn. The contents of the window isdrawn by the client through requests to the server.Window painting is orchestrated through an expose eventsystem. When a region is exposed, DIX generates an exposeevent, telling the client to repaint the window and passingthe region that is the minimal area needed to be repainted.As a favor to clients, the server may retain the output tothe hidden parts of windows in off-screen memory; this iscalled "backing store". When a part of such a windowbecomes exposed, it can quickly move pixels into placeinstead of triggering an expose event and waiting for aclient on the other end of the network to respond. Even ifthe network response is insignificant, the time tointelligently paint a section of a window is usually morethan the time to just copy already-painted sections. Atbest, the repainting involves blanking out the area to abackground color, which will take about the same amount oftime. In this way, backing store can dramatically increasethe performance of window moves.On the other hand, backing store can be quite complex,because all graphics drawn to hidden areas must beintercepted and redirected to the off-screen windowsections. Not only can this be complicated for the serverprogrammer, but it can also impact window paintingperformance. The backing store implementation can choose,at any time, to forget pieces of backing that are writteninto, relying instead upon expose events to repaint forsimplicity.In X, the decision to use the backing-store scheme is madeby you, the server implementor. X provides hooks forimplementing backing store, therefore the decision to usethis strategy can be made on the fly. For example, you mayuse backing store only for certain windows that the userrequests or you may use backing store until memory runs out,at which time you start dropping pieces of backing as neededto make more room.When a window operation is requested by the client, such asa window being created or moved, a new state is computed.During this transition, DIX informs DDX what rectangles inwhat windows are about to become obscured and whatrectangles in what windows have become exposed. Thisprovides a hook for the implementation of backing store. IfDDX is unable to restore exposed regions, DIX generatesexpose events to the client. It is then the client’sresponsibility to paint the window parts that were exposedbut not restored.If a window is resized, pixels sometimes need to be moved,depending upon the application. The client can request"Gravity" so that certain blocks of the window are moved asa result of a resize. For instance, if the window hascontrols or other items that always hang on the edge of thewindow, and that edge is moved as a result of the resize,then those pixels should be moved to avoid having the clientrepaint it. If the client needs to repaint it anyway, suchan operation takes time, so it is desirable for the serverto approximate the appearance of the window as best it canwhile waiting for the client to do it perfectly. Gravity isused for that, also.The window has several fields used in drawing operations:• clipList - This region, in conjunction with the clientclip region in the gc, is used to clip output.clipList has the window’s children subtracted from it,in addition to pieces of sibling windows that overlapthis window. To get the list with the childrenincluded (subwindow-mode is IncludeInferiors), theroutine NotClippedByChildren(pWin) returns theunclipped region.• borderClip is the region used by CopyWindow andincludes the area of the window, its children, and theborder, but with the overlapping areas of siblingchildren removed.Most of the other fields are for DIX use only.5.3.2.1. Window Procedures in the ScreenRecYou should implement all of the following procedures andstore pointers to them in the screen record.The device-independent portion of the server "owns" thewindow tree. However, clever hardware might want to knowthe relationship of mapped windows. There are pointers toprocedures in the ScreenRec data structure that are calledto give the hardware a chance to update its internal state.These are helpers and hints to DDX only; they do not changethe window tree, which is only changed by DIX.Bool pScreen->CreateWindow(pWin)WindowPtr pWin;This routine is a hook for when DIX creates a window. Itshould fill in the "Window Procedures in the WindowRec"below and also allocate the devPrivate block for it.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->DestroyWindow(pWin);WindowPtr pWin;This routine is a hook for when DIX destroys a window. Itshould deallocate the devPrivate block for it and any otherblocks that need to be freed, besides doing other cleanupactions.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->PositionWindow(pWin, x, y);WindowPtr pWin;int x, y;This routine is a hook for when DIX moves or resizes awindow. It should do whatever private operations need to bedone when a window is moved or resized. For instance, ifDDX keeps a pixmap tile used for drawing the background orborder, and it keeps the tile rotated such that it islongword aligned to longword locations in the frame buffer,then you should rotate your tiles here. The actual graphicsinvolved in moving the pixels on the screen and drawing theborder are handled by CopyWindow(), below.See Xserver/mfb/mfbwindow.c for the sample serverimplementation.Bool pScreen->RealizeWindow(pWin);WindowPtr pWin;Bool pScreen->UnrealizeWindow(pWin);WindowPtr pWin;These routines are hooks for when DIX maps (makes visible)and unmaps (makes invisible) a window. It should dowhatever private operations need to be done when thesehappen, such as allocating or deallocating structures thatare only needed for visible windows. RealizeWindow does NOTdraw the window border, background or contents;UnrealizeWindow does NOT erase the window or generateexposure events for underlying windows; this is taken careof by DIX. DIX does, however, call PaintWindowBackground()and PaintWindowBorder() to perform some of these.Bool pScreen->ChangeWindowAttributes(pWin, vmask)WindowPtr pWin;unsigned long vmask;ChangeWindowAttributes is called whenever DIX changes windowattributes, such as the size, front-to-back ordering, title,or anything of lesser severity that affects the windowitself. The sample server implements this routine. Itcomputes accelerators for quickly putting up background andborder tiles. (See description of the set of routinesstored in the WindowRec.)int pScreen->ValidateTree(pParent, pChild, kind)WindowPtr pParent, pChild;VTKind kind;ValidateTree calculates the clipping region for the parentwindow and all of its children. This routine must beprovided. The sample server has a machine-independentversion in Xserver/mi/mivaltree.c. This is a very difficultroutine to replace.void pScreen->PostValidateTree(pParent, pChild, kind)WindowPtr pParent, pChild;VTKind kind;If this routine is not NULL, DIX calls it shortly aftercalling ValidateTree, passing it the same arguments. Thisis useful for managing multi-layered framebuffers. Thesample server sets this to NULL.void pScreen->WindowExposures(pWin, pRegion, pBSRegion)WindowPtr pWin;RegionPtr pRegion;RegionPtr pBSRegion;The WindowExposures() routine paints the border andgenerates exposure events for the window. pRegion is anunoccluded region of the window, and pBSRegion is anoccluded region that has backing store. Since exposureevents include a rectangle describing what was exposed, thisroutine may have to send back a series of exposure events,one for each rectangle of the region. The count field inthe expose event is a hint to the client as to the number ofregions that are after this one. This routine must beprovided. The sample server has a machine-independentversion in Xserver/mi/miexpose.c.void pScreen->ClipNotify (pWin, dx, dy)WindowPtr pWin;int dx, dy;Whenever the cliplist for a window is changed, this functionis called to perform whatever hardware manipulations mightbe necessary. When called, the clip list and border clipregions in the window are set to the new values. dx,dy arethe distance that the window has been moved (if at all).5.3.2.2. Window Painting ProceduresIn addition to the procedures listed above, there are fourroutines which manipulate the actual window image directly.In the sample server, mi implementations will work for mostpurposes and mfb/cfb routines speed up situations, such assolid backgrounds/borders or tiles that are 8, 16 or 32pixels square.These three routines are used for systems that implement abacking-store scheme for it to know when to stash away areasof pixels and to restore or reposition them.void pScreen->ClearToBackground(pWin, x, y, w, h, generateExposures);WindowPtr pWin;int x, y, w, h;Bool generateExposures;This routine is called on a window in response to aClearToBackground request from the client. This request hastwo different but related functions, depending upongenerateExposures.If generateExposures is true, the client is declaring thatthe given rectangle on the window is incorrectly painted andneeds to be repainted. The sample server implementationcalculates the exposure region and hands it to the DIXprocedure HandleExposures(), which calls theWindowExposures() routine, below, for the window and all ofits child windows.If generateExposures is false, the client is trying tosimply erase part of the window to the background fillstyle. ClearToBackground should write the background coloror tile to the rectangle in question (probably usingPaintWindowBackground). If w or h is zero, it clears allthe way to the right or lower edge of the window.The sample server implementation is inXserver/mi/miwindow.c.void pScreen->PaintWindowBackground(pWin, region, kind)WindowPtr pWin;RegionPtr region;int kind; /* must be PW_BACKGROUND */void pScreen->PaintWindowBorder(pWin, region, kind)WindowPtr pWin;RegionPtr region;int kind; /* must be PW_BORDER */These two routines are for painting pieces of the windowbackground or border. They both actually paint the areadesignated by region. The kind parameter is a definedconstant that is always PW_BACKGROUND or PW_BORDER, asshown. Therefore, you can use the same routine for both.The defined constant tells the routine whether to use thewindow’s border fill style or its background fill style topaint the given region. Both fill styles consist of a unionwhich holds a tile pointer and a pixel value, along with aseparate variable which indicates which entry is valid. ForPW_BORDER, borderIsPixel != 0 indicates that the borderPixUnion contains a pixel value, else a tile. ForPW_BACKGROUND there are four values, contained inbackgroundState; None, ParentRelative, BackgroundPixmap andBackgroundPixel. None indicates that the region should beleft unfilled, while ParentRelative indicates that thebackground of the parent is inherited (see the Protocoldocument for the exact semantics).void pScreen->CopyWindow(pWin, oldpt, oldRegion);WindowPtr pWin;DDXPointRec oldpt;RegionPtr oldRegion;CopyWindow is called when a window is moved, and graphicallymoves to pixels of a window on the screen. It should notchange any other state within DDX (see PositionWindow(),above).oldpt is the old location of the upper-left corner.oldRegion is the old region it is coming from. The newlocation and new region is stored in the WindowRec.oldRegion might modified in place by this routine (thesample implementation does this).CopyArea could be used, except that this operation has morecomplications. First of all, you do not want to copy arectangle onto a rectangle. The original window may beobscured by other windows, and the new window location maybe similarly obscured. Second, some hardware supportsmultiple windows with multiple depths, and your routineneeds to take care of that.The pixels in oldRegion (with reference point oldpt) arecopied to the window’s new region (pWin->borderClip).pWin->borderClip is gotten directly from the window, ratherthan passing it as a parameter.The sample server implementation is inXserver/mfb/mfbwindow.c.5.3.2.3. Screen Operations for Backing StoreEach ScreenRec has six functions which provide the backingstore interface. For screens not supporting backing store,these pointers may be nul. Servers that implement somebacking store scheme must fill in the procedure pointers forthe procedures below, and must maintain the backStoragefield in each window struct. The sample implementation isin mi/mibstore.c.void pScreen->SaveDoomedAreas(pWin, pRegion, dx, dy)WindowPtr pWin;RegionPtr pRegion;int dx, dy;This routine saves the newly obscured region, pRegion, inbacking store. dx, dy indicate how far the window is beingmoved, useful as the obscured region is relative to thewindow as it will appear in the new location, rather thenrelative to the bits as the are on the screen when thefunction is invoked.RegionPtr pScreen->RestoreAreas(pWin, pRegion)WindowPtr pWin;RegionPtr pRegion;This looks at the exposed region of the window, pRegion, andtries to restore to the screen the parts that have beensaved. It removes the restored parts from the backingstorage (because they are now on the screen) and subtractsthe areas from the exposed region. The returned region isthe area of the window which should have expose eventsgenerated for and can be either a new region, pWin->exposed,or NULL. The region left in pRegion is set to the area ofthe window which should be painted with the windowbackground.RegionPtr pScreen->TranslateBackingStore(pWin, dx, dy, oldClip, oldx, oldy)WindowPtr pWin;int dx, dy;RegionPtr oldClip;int oldx, oldy;This is called when the window is moved or resized so thatthe backing store can be translated if necessary. oldClipis the old cliplist for the window, which is used to savedoomed areas if the window is moved underneath its parent asa result of bitgravity. The returned region representsoccluded areas of the window for which the backing storecontents are invalid.void pScreen->ExposeCopy(pSrc, pDst, pGC, prgnExposed, srcx, srcy, dstx, dsty, plane)WindowPtr pSrc;DrawablePtr pDst;GCPtr pGC;RegionPtr prgnExposed;int srcx;int srcy;int dstx;int dsty;unsigned long plane;Copies a region from the backing store of pSrc to pDst.RegionPtr pScreen->ClearBackingStore(pWindow, x, y, w, h, generateExposures)WindowPtr pWindow;int x;int y;int w;int h;Bool generateExposures;Clear the given area of the backing pixmap with thebackground of the window. If generateExposures is TRUE,generate exposure events for the area. Note that if the areahas any part outside the saved portions of the window, we donot allow the count in the expose events to be 0, sincethere will be more expose events to come.void pScreen->DrawGuarantee(pWindow, pGC, guarantee)WindowPtr pWindow;GCPtr pGC;int guarantee;This informs the backing store layer that you are about tovalidate a gc with a window, and that subsequent output tothe window is (or is not) guaranteed to be already clippedto the visible regions of the window.5.3.2.4. Screen Operations for Multi-Layered FramebuffersThe following screen functions are useful if you have aframebuffer with multiple sets of independent bit planes,e.g. overlays or underlays in addition to the "main" planes.If you have a simple single-layer framebuffer, you shouldprobably use the mi versions of these routines inmi/miwindow.c. This can be easily accomplished by callingmiScreenInit.void pScreen->MarkWindow(pWin)WindowPtr pWin;This formerly dix function MarkWindow has moved to ddx andis accessed via this screen function. This function shouldstore something, usually a pointer to a device-dependentstructure, in pWin->valdata so that ValidateTree has theinformation it needs to validate the window.Bool pScreen->MarkOverlappedWindows(parent, firstChild, ppLayerWin)WindowPtr parent;WindowPtr firstChild;WindowPtr * ppLayerWin;This formerly dix function MarkWindow has moved to ddx andis accessed via this screen function. In the process, ithas grown another parameter: ppLayerWin, which is filled inwith a pointer to the window at which save under marking andValidateTree should begin. In the single-layeredframebuffer case, pLayerWin == pWin.Bool pScreen->ChangeSaveUnder(pLayerWin, firstChild)WindowPtr pLayerWin;WindowPtr firstChild;The dix functions ChangeSaveUnder and CheckSaveUnder havemoved to ddx and are accessed via this screen function.pLayerWin should be the window returned in the ppLayerWinparameter of MarkOverlappedWindows. The function may turnon backing store for windows that might be covered, and maypartially turn off backing store for windows. It returnsTRUE if PostChangeSaveUnder needs to be called to finishturning off backing store.void pScreen->PostChangeSaveUnder(pLayerWin, firstChild)WindowPtr pLayerWin;WindowPtr firstChild;The dix function DoChangeSaveUnder has moved to ddx and isaccessed via this screen function. This function completesthe job of turning off backing store that was started byChangeSaveUnder.void pScreen->MoveWindow(pWin, x, y, pSib, kind)WindowPtr pWin;int x;int y;WindowPtr pSib;VTKind kind;The formerly dix function MoveWindow has moved to ddx and isaccessed via this screen function. The new position of thewindow is given by x,y. kind is VTMove if the window isonly moving, or VTOther if the border is also changing.void pScreen->ResizeWindow(pWin, x, y, w, h, pSib)WindowPtr pWin;int x;int y;unsigned int w;unsigned int h;WindowPtr pSib;The formerly dix function SlideAndSizeWindow has moved toddx and is accessed via this screen function. The newposition is given by x,y. The new size is given by w,h.WindowPtr pScreen->GetLayerWindow(pWin)WindowPtr pWinThis is a new function which returns a child of the layerparent of pWin.void pScreen->HandleExposures(pWin)WindowPtr pWin;The formerly dix function HandleExposures has moved to ddxand is accessed via this screen function. This function iscalled after ValidateTree and uses the information containedin valdata to send exposures to windows.void pScreen->ReparentWindow(pWin, pPriorParent)WindowPtr pWin;WindowPtr pPriorParent;This function will be called when a window is reparented.At the time of the call, pWin will already be spliced intoits new position in the window tree, and pPriorParent is itsprevious parent. This function can be NULL.void pScreen->SetShape(pWin)WindowPtr pWin;The formerly dix function SetShape has moved to ddx and isaccessed via this screen function. The window’s new shapewill have already been stored in the window when thisfunction is called.void pScreen->ChangeBorderWidth(pWin, width)WindowPtr pWin;unsigned int width;The formerly dix function ChangeBorderWidth has moved to ddxand is accessed via this screen function. The new borderwidth is given by width.void pScreen->MarkUnrealizedWindow(pChild, pWin, fromConfigure)WindowPtr pChild;WindowPtr pWin;Bool fromConfigure;This function is called for windows that are beingunrealized as part of an UnrealizeTree. pChild is thewindow being unrealized, pWin is an ancestor, and thefromConfigure value is simply propogated from UnrealizeTree.5.4. Graphics Contexts and ValidationThis graphics context (GC) contains state variables such asforeground and background pixel value (color), the currentline style and width, the current tile or stipple forpattern generation, the current font for text generation,and other similar attributes.In many graphics systems, the equivalent of the graphicscontext and the drawable are combined as one entity. Themain distinction between the two kinds of status is that adrawable describes a writing surface and the writings thatmay have already been done on it, whereas a graphics contextdescribes the drawing process. A drawable is like achalkboard. A GC is like a piece of chalk.Unlike many similar systems, there is no "current penlocation." Every graphic operation is accompanied by thecoordinates where it is to happen.The GC also includes two vectors of procedure pointers, thefirst operate on the GC itself and are called GC funcs. Thesecond, called GC ops, contains the functions that carry outthe fundamental graphic operations such as drawing lines,polygons, arcs, text, and copying bitmaps. The DDX graphicsoftware can, if it wants to be smart, change these twovectors of procedure pointers to take advantage ofhardware/firmware in the server machine, which can do abetter job under certain circumstances. To reduce theamount of memory consumed by each GC, it is wise to create afew "boilerplate" GC ops vectors which can be shared byevery GC which matches the constraints for that set. Also,it is usually reasonable to have every GC created by aparticular module to share a common set of GC funcs.Samples of this sort of sharing can be seen in cfb/cfbgc.cand mfb/mfbgc.c.The DDX software is notified any time the client (or DIX)uses a changed GC. For instance, if the hardware hasspecial support for drawing fixed-width fonts, DDX canintercept changes to the current font in a GC just beforedrawing is done. It can plug into either a fixed-widthprocedure that makes the hardware draw characters, or avariable-width procedure that carefully lays out glyphs byhand in software, depending upon the new font that isselected.A definition of these structures can be found in the fileXserver/include/gcstruct.h.Also included in each GC is an array of devPrivates whichportions of the DDX can use for any reason. Entries in thisarray are allocated with AllocateGCPrivateIndex() (seeWrappers and Privates below).The DIX routines available for manipulating GCs areCreateGC, ChangeGC, CopyGC, SetClipRects, SetDashes, andFreeGC.GCPtr CreateGC(pDrawable, mask, pval, pStatus)DrawablePtr pDrawable;BITS32 mask;XID *pval;int *pStatus;int ChangeGC(pGC, mask, pval)GCPtr pGC;BITS32 mask;XID *pval;int CopyGC(pgcSrc, pgcDst, mask)GCPtr pgcSrc;GCPtr pgcDst;BITS32 mask;int SetClipRects(pGC, xOrigin, yOrigin, nrects, prects, ordering)GCPtr pGC;int xOrigin, yOrigin;int nrects;xRectangle *prects;int ordering;SetDashes(pGC, offset, ndash, pdash)GCPtr pGC;unsigned offset;unsigned ndash;unsigned char *pdash;int FreeGC(pGC, gid)GCPtr pGC;GContext gid;As a convenience, each Screen structure contains an array ofGCs that are preallocated, one at each depth the screensupports. These are particularly useful in the mi code.Two DIX routines must be used to get these GCs:GCPtr GetScratchGC(depth, pScreen)int depth;ScreenPtr pScreen;FreeScratchGC(pGC)GCPtr pGC;Always use these two routines, don’t try to extract thescratch GC yourself -- someone else might be using it, so anew one must be created on the fly.If you need a GC for a very long time, say until the serveris restarted, you should not take one from the pool used byGetScratchGC, but should get your own using CreateGC orCreateScratchGC. This leaves the ones in the pool free forroutines that only need it for a little while and don’t wantto pay a heavy cost to get it.GCPtr CreateScratchGC(pScreen, depth)ScreenPtr pScreen;int depth;NULL is returned if the GC cannot be created. The GCreturned can be freed with FreeScratchGC.5.4.1. Details of operationAt screen initialization, a screen must supply a GC creationprocedure. At GC creation, the screen must fill in GC funcsand GC ops vectors (Xserver/include/gcstruct.h). For anyparticular GC, the func vector must remain constant, whilethe op vector may vary. This invariant is to ensure thatWrappers work correctly.When a client request is processed that results in a changeto the GC, the device-independent state of the GC isupdated. This includes a record of the state that changed.Then the ChangeGC GC func is called. This is useful forgraphics subsystems that are able to process state changesin parallel with the server CPU. DDX may opt not to takeany action at GC-modify time. This is more efficient ifmultiple GC-modify requests occur between draws using agiven GC.Validation occurs at the first draw operation that specifiesthe GC after that GC was modified. DIX calls then theValidateGC GC func. DDX should then update its internalstate. DDX internal state may be stored as one or more ofthe following: 1) device private block on the GC; 2)hardware state; 3) changes to the GC ops.The GC contains a serial number, which is loaded with anumber fetched from the window that was drawn into the lasttime the GC was used. The serial number in the drawable ischanged when the drawable’s clipList or absCorner changes.Thus, by comparing the GC serial number with the drawableserial number, DIX can force a validate if the drawable hasbeen changed since the last time it was used with this GC.In addition, the drawable serial number is always guaranteedto have the most significant bit set to 0. Thus, the DDXlayer can set the most significant bit of the serial numberto 1 in a GC to force a validate the next time the GC isused. DIX also uses this technique to indicate that achange has been made to the GC by way of a SetGC, aSetDashes or a SetClip request.5.4.2. GC Handling RoutinesThe ScreenRec data structure has a pointer for CreateGC().Bool pScreen->CreateGC(pGC)GCPtr pGC;This routine must fill in the fields of a dynamicallyallocated GC that is passed in. It does NOT allocate the GCrecord itself or fill in the defaults; DIX does that.This must fill in both the GC funcs and ops; none of thedrawing functions will be called before the GC has beenvalidated, but the others (dealing with allocating of clipregions, changing and destroying the GC, etc.) might be.The GC funcs vector contains pointers to 7 routines and adevPrivate field:pGC->funcs->ChangeGC(pGC, changes)GCPtr pGC;unsigned long changes;This GC func is called immediately after a field in the GCis changed. changes is a bit mask indicating the changedfields of the GC in this request.The ChangeGC routine is useful if you have a system wherestate-changes to the GC can be swallowed immediately by yourgraphics system, and a validate is not necessary.pGC->funcs->ValidateGC(pGC, changes, pDraw)GCPtr pGC;unsigned long changes;DrawablePtr pDraw;ValidateGC is called by DIX just before the GC will be usedwhen one of many possible changes to the GC or the graphicssystem has happened. It can modify a devPrivates field ofthe GC or its contents, change the op vector, or changehardware according to the values in the GC. It may notchange the device-independent portion of the GC itself.In almost all cases, your ValidateGC() procedure should takethe regions that drawing needs to be clipped to and combinethem into a composite clip region, which you keep a pointerto in the private part of the GC. In this way, your drawingprimitive routines (and whatever is below them) can easilydetermine what to clip and where. You should combine theregions clientClip (the region that the client desires toclip output to) and the region returned byNotClippedByChildren(), in DIX. An example is inXserver/mfb/mfbgc.c.Some kinds of extension software may cause this routine tobe called more than originally intended; you should not relyon algorithms that will break under such circumstances.See the Strategies document for more information oncreatively using this routine.pGC->funcs->CopyGC(pGCSrc, mask, pGCDst)GCPtr pGCSrc;unsigned long mask;GCPtr pGCDst;This routine is called by DIX when a GC is being copied toanother GC. This is for situations where dynamicallyallocated chunks of memory are hanging off a GC devPrivatesfield which need to be transferred to the destination GC.pGC->funcs->DestroyGC(pGC)GCPtr pGC;This routine is called before the GC is destroyed for theentity interested in this GC to clean up after itself. Thisroutine is responsible for freeing any auxiliary storageallocated.5.4.3. GC Clip Region RoutinesThe GC clientClip field requires three procedures to manageit. These procedures are in the GC funcs vector. Theunderlying principle is that dix knows nothing about theinternals of the clipping information, (except when it hascome from the client), and so calls ddX whenever it needs tocopy, set, or destroy such information. It could have beenpossible for dix not to allow ddX to touch the field in theGC, and require it to keep its own copy in devPriv, butsince clip masks can be very large, this seems like a badidea. Thus, the server allows ddX to do whatever it wantsto the clientClip field of the GC, but requires it to do allmanipulation itself.void pGC->funcs->ChangeClip(pGC, type, pValue, nrects)GCPtr pGC;int type;char *pValue;int nrects;This routine is called whenever the client changes theclient clip region. The pGC points to the GC involved, thetype tells what form the region has been sent in. If typeis CT_NONE, then there is no client clip. If type isCT_UNSORTED, CT_YBANDED or CT_YXBANDED, then pValue pointerto a list of rectangles, nrects long. If type is CT_REGION,then pValue pointer to a RegionRec from the mi region code.If type is CT_PIXMAP pValue is a pointer to a pixmap. (Thedefines for CT_NONE, etc. are in Xserver/include/gc.h.)This routine is responsible for incrementing any necessaryreference counts (e.g. for a pixmap clip mask) for the newclipmask and freeing anything that used to be in the GC’sclipMask field. The lists of rectangles passed in can befreed with Xfree(), the regions can be destroyed with theRegionDestroy field in the screen, and pixmaps can bedestroyed by calling the screen’s DestroyPixmap function.DIX and MI code expect what they pass in to this to be freedor otherwise inaccessible, and will never look inside what’sbeen put in the GC. This is a good place to be wary ofstorage leaks.In the sample server, this routine transforms either thebitmap or the rectangle list into a region, so that futureroutines will have a more predictable starting point to workfrom. (The validate routine must take this client clipregion and merge it with other regions to arrive at acomposite clip region before any drawing is done.)void pGC->funcs->DestroyClip(pGC)GCPtr pGC;This routine is called whenever the client clip region mustbe destroyed. The pGC points to the GC involved. This callshould set the clipType field of the GC to CT_NONE. In thesample server, the pointer to the client clip region is setto NULL by this routine after destroying the region, so thatother software (including ChangeClip() above) will recognizethat there is no client clip region.void pGC->funcs->CopyClip(pgcDst, pgcSrc)GCPtr pgcDst, pgcSrc;This routine makes a copy of the clipMask and clipType frompgcSrc into pgcDst. It is responsible for destroying anyprevious clipMask in pgcDst. The clip mask in the sourcecan be the same as the clip mask in the dst (clients do thestrangest things), so care must be taken when destroyingthings. This call is required because dix does not know howto copy the clip mask from pgcSrc.5.5. Drawing PrimitivesThe X protocol (rules for the byte stream that goes betweenclient and server) does all graphics using primitiveoperations, which are called Drawing Primitives. Theseinclude line drawing, area filling, arcs, and text drawing.Your implementation must supply 16 routines to perform theseon your hardware. (The number 16 is arbitrary.)More specifically, 16 procedure pointers are in each GC opvector. At any given time, ALL of them MUST point to avalid procedure that attempts to do the operation assigned,although the procedure pointers may change and may point todifferent procedures to carry out the same operation. Asimple server will leave them all pointing to the same 16routines, while a more optimized implementation will switcheach from one procedure to another, depending upon what ismost optimal for the current GC and drawable.The sample server contains a considerable chunk of codecalled the mi (machine independent) routines, which serve asdrawing primitive routines. Many server implementationswill be able to use these as-is, because they work forarbitrary depths. They make no assumptions about theformats of pixmaps and frame buffers, since they call a setof routines known as the "Pixblit Routines" (see nextsection). They do assume that the way to draw is throughthese low-level routines that apply pixel values rows at atime. If your hardware or firmware gives more performancewhen things are done differently, you will want to take thisfact into account and rewrite some or all of the drawingprimitives to fit your needs.5.5.1. GC ComponentsThis section describes the fields in the GC that affect eachdrawing primitive. The only primitive that is not affectedis GetImage, which does not use a GC because its destinationis a protocol-style bit image. Since each drawing primitivemirrors exactly the X protocol request of the same name, youshould refer to the X protocol specification document formore details.ALL of these routines MUST CLIP to the appropriate regionsin the drawable. Since there are many regions to clip tosimultaneously, your ValidateGC routine should combine theseinto a unified clip region to which your drawing routinescan quickly refer. This is exactly what the cfb and mfbroutines supplied with the sample server do. The miimplementation passes responsibility for clipping whiledrawing down to the Pixblit routines.Also, all of them must adhere to the current plane mask.The plane mask has one bit for every bit plane in thedrawable; only planes with 1 bits in the mask are affectedby any drawing operation.All functions except for ImageText calls must obey the alufunction. This is usually Copy, but could be any of theallowable 16 raster-ops.All of the functions, except for CopyArea, might use thecurrent foreground and background pixel values. Each pixelvalue is 32 bits. These correspond to foreground andbackground colors, but you have to run them through thecolormap to find out what color the pixel values represent.Do not worry about the color, just apply the pixel value.The routines that draw lines (PolyLine, PolySegment,PolyRect, and PolyArc) use the line width, line style, capstyle, and join style. Line width is in pixels. The linestyle specifies whether it is solid or dashed, and what kindof dash. The cap style specifies whether Rounded, Butt,etc. The join style specifies whether joins between joinedlines are Miter, Round or Beveled. When lines cross as partof the same polyline, they are assumed to be drawn once.(See the X protocol specification for more details.)Zero-width lines are NOT meant to be really zero width; thisis the client’s way of telling you that you can optimizeline drawing with little regard to the end caps and joins.They are called "thin" lines and are meant to be one pixelwide. These are frequently done in hardware or in astreamlined assembly language routine.Lines with widths greater than zero, though, must all bedrawn with the same algorithm, because client softwareassumes that every jag on every line at an angle will comeat the same place. Two lines that should have one pixel inthe space between them (because of their distance apart andtheir widths) should have such a one-pixel line of spacebetween them if drawn, regardless of angle.The solid area fill routines (FillPolygon, PolyFillRect,PolyFillArc) all use the fill rule, which specifies subtleinterpretations of what points are inside and what areoutside of a given polygon. The PolyFillArc routine alsouses the arc mode, which specifies whether to fill piesegments or single-edge slices of an ellipse.The line drawing, area fill, and PolyText routines must allapply the correct "fill style." This can be either a solidforeground color, a transparent stipple, an opaque stipple,or a tile. Stipples are bitmaps where the 1 bits representthat the foreground color is written, and 0 bits representthat either the pixel is left alone (transparent) or thatthe background color is written (opaque). A tile is apixmap of the full depth of the GC that is applied in itsfull glory to all areas. The stipple and tile patterns canbe any rectangular size, although some implementations willbe faster for certain sizes such as 8x8 or 32x32. The miimplementation passes this responsibility down to thePixblit routines.See the X protocol document for full details. Thedescription of the CreateGC request has a very good,detailed description of these attributes.5.5.2. The PrimitivesThe Drawing Primitives are as follows:RegionPtr pGC->ops->CopyArea(src, dst, pGC, srcx, srcy, w, h, dstx, dsty)DrawablePtr dst, src;GCPtr pGC;int srcx, srcy, w, h, dstx, dsty;CopyArea copies a rectangle of pixels from one drawable toanother of the same depth. To effect scrolling, this mustbe able to copy from any drawable to itself, overlapped. Nosqueezing or stretching is done because the source anddestination are the same size. However, everything is stillclipped to the clip regions of the destination drawable.If pGC->graphicsExposures is True, any portions of thedestination which were not valid in the source (eitheroccluded by covering windows, or outside the bounds of thedrawable) should be collected together and returned as aregion (if this resultant region is empty, NULL can bereturned instead). Furthermore, the invalid bits of thesource are not copied to the destination and (when thedestination is a window) are filled with the backgroundtile. The sample routine miHandleExposures generates theappropriate return value and fills the invalid area usingpScreen->PaintWindowBackground.For instance, imagine a window that is partially obscured byother windows in front of it. As text is scrolled on yourwindow, the pixels that are scrolled out from underobscuring windows will not be available on the screen tocopy to the right places, and so an exposure event must besent for the client to correctly repaint them. Of course,if you implement some sort of backing store, you could dothis without resorting to exposure events.An example implementation is mfbCopyArea() inXserver/mfb/mfbbitblt.c.RegionPtr pGC->ops->CopyPlane(src, dst, pGC, srcx, srcy, w, h, dstx, dsty, plane)DrawablePtr dst, src;GCPtr pGC;int srcx, srcy, w, h, dstx, dsty;unsigned long plane;CopyPlane must copy one plane of a rectangle from the sourcedrawable onto the destination drawable. Because thisroutine only copies one bit out of each pixel, it can copybetween drawables of different depths. This is the only wayof copying between drawables of different depths, except forcopying bitmaps to pixmaps and applying foreground andbackground colors to it. All other conditions of CopyAreaapply to CopyPlane too.An example implementation is mfbCopyPlane() inXserver/mfb/mfbbitblt.c.void pGC->ops->PolyPoint(dst, pGC, mode, n, pPoint)DrawablePtr dst;GCPtr pGC;int mode;int n;DDXPointPtr pPoint;PolyPoint draws a set of one-pixel dots (foreground color)at the locations given in the array. mode is one of thedefined constants Origin (absolute coordinates) or Previous(each coordinate is relative to the last). Note that thisdoes not use the background color or any tiles or stipples.Example implementations are mfbPolyPoint() inXserver/mfb/mfbpolypnt.c and miPolyPoint inXserver/mi/mipolypnt.c.void pGC->ops->Polylines(dst, pGC, mode, n, pPoint)DrawablePtr dst;GCPtr pGC;int mode;int n;DDXPointPtr pPoint;Similar to PolyPoint, Polylines draws lines between thelocations given in the array. Zero-width lines are NOTmeant to be really zero width; this is the client’s way oftelling you that you can maximally optimize line drawingwith little regard to the end caps and joins. mode is oneof the defined constants Previous or Origin, depending uponwhether the points are each relative to the last or areabsolute.Example implementations are miWideLine() and miWideDash() inmi/miwideline.c and miZeroLine() in mi/mizerline.c.void pGC->ops->PolySegment(dst, pGC, n, pPoint)DrawablePtr dst;GCPtr pGC;int n;xSegment *pSegments;PolySegments draws unconnected lines between pairs of pointsin the array; the array must be of even size; nointerconnecting lines are drawn.An example implementation is miPolySegment() in mipolyseg.c.void pGC->ops->PolyRectangle(dst, pGC, n, pRect)DrawablePtr dst;GCPtr pGC;int n;xRectangle *pRect;PolyRectangle draws outlines of rectangles for eachrectangle in the array.An example implementation is miPolyRectangle() inXserver/mi/mipolyrect.c.void pGC->ops->PolyArc(dst, pGC, n, pArc)DrawablePtr dst;GCPtr pGC;int n;xArc*pArc;PolyArc draws connected conic arcs according to thedescriptions in the array. See the protocol specificationfor more details.Example implementations are miZeroPolyArc inXserver/mi/mizerarc. and miPolyArc() in Xserver/mi/miarc.c.void pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pPoint)DrawablePtr dst;GCPtr pGC;int shape;int mode;int count;DDXPointPtr pPoint;FillPolygon fills a polygon specified by the points in thearray with the appropriate fill style. If necessary, anextra border line is assumed between the starting and endinglines. The shape can be used as a hint to optimize filling;it indicates whether it is convex (all interior angles lessthan 180), nonconvex (some interior angles greater than 180but border does not cross itself), or complex (bordercrosses itself). You can choose appropriate algorithms orhardware based upon mode. mode is one of the definedconstants Previous or Origin, depending upon whether thepoints are each relative to the last or are absolute.An example implementation is miFillPolygon() inXserver/mi/mipoly.c.void pGC->ops->PolyFillRect(dst, pGC, n, pRect)DrawablePtr dst;GCPtr pGC;int n;xRectangle *pRect;PolyFillRect fills multiple rectangles.Example implementations are mfbPolyFillRect() inXserver/mfb/mfbfillrct.c and miPolyFillRect() inXserver/mi/mifillrct.c.void pGC->ops->PolyFillArc(dst, pGC, n, pArc)DrawablePtr dst;GCPtr pGC;int n;xArc *pArc;PolyFillArc fills a shape for each arc in the list that isbounded by the arc and one or two line segments with thecurrent fill style.An example implementation is miPolyFillArc() inXserver/mi/mifillarc.c.void pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBinImage)DrawablePtr dst;GCPtr pGC;int x, y, w, h;int format;char *pBinImage;PutImage copies a pixmap image into the drawable. Thepixmap image must be in X protocol format (either Bitmap,XYPixmap, or ZPixmap), and format tells the format. (Seethe X protocol specification for details on these formats).You must be able to accept all three formats, because theclient gets to decide which format to send. Either thedrawable and the pixmap image have the same depth, or thesource pixmap image must be a Bitmap. If a Bitmap, theforeground and background colors will be applied to thedestination.An example implementation is miPutImage() inXserver/mfb/mibitblt.c.void pScreen->GetImage(src, x, y, w, h, format, planeMask, pBinImage)DrawablePtr src;int x, y, w, h;unsigned int format;unsigned long planeMask;char *pBinImage;GetImage copies the bits from the source drawable into thedestination pointer. The bits are written into the bufferaccording to the server-defined pixmap padding rules.pBinImage is guaranteed to be big enough to hold all thebits that must be written.This routine does not correspond exactly to the X protocolGetImage request, since DIX has to break the reply up intobuffers of a size requested by the transport layer. Ifformat is ZPixmap, the bits are written in the ZFormat forthe depth of the drawable; if there is a 0 bit in theplaneMask for a particular plane, all pixels must have thebit in that plane equal to 0. If format is XYPixmap,planemask is guaranteed to have a single bit set; the bitsshould be written in Bitmap format, which is the format fora single plane of an XYPixmap.An example implementation is miGetImage() inXserver/mi/mibitblt.c.void pGC->ops->ImageText8(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;char *chars;ImageText8 draws text. The text is drawn in the foregroundcolor; the background color fills the remainder of thecharacter rectangles. The coordinates specify the baselineand start of the text.An example implementation is miImageText8() inXserver/mi/mipolytext.c.int pGC->ops->PolyText8(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;char *chars;PolyText8 works like ImageText8, except it draws with thecurrent fill style for special effects such as shaded text.See the X protocol specification for more details.An example implementation is miPolyText8() inXserver/mi/mipolytext.c.int pGC->ops->PolyText16(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;unsigned short *chars;void pGC->ops->ImageText16(pDraw, pGC, x, y, count, chars)DrawablePtr pDraw;GCPtr pGC;int x, y;int count;unsigned short *chars;These two routines are the same as the "8" versions, exceptthat they are for 16-bit character codes (useful fororiental writing systems).The primary difference is in the way the characterinformation is looked up. The 8-bit and the 16-bit versionsobviously have different kinds of character values to lookup; the main goal of the lookup is to provide a pointer tothe CharInfo structs for the characters to draw and to passthese pointers to the Glyph routines. Given a CharInfostruct, lower-level software can draw the glyph desired withlittle concern for other characteristics of the font.16-bit character fonts have a row-and-column scheme, wherethe 2bytes of the character code constitute the row andcolumn in a square matrix of CharInfo structs. Each fonthas row and column minimum and maximum values; the CharInfostructures form a two-dimensional matrix.Example implementations are miPolyText16() andmiImageText16() in Xserver/mi/mipolytext.c.See the X protocol specification for more details on thesegraphic operations.There is a hook in the GC ops, called LineHelper, that usedto be used in the sample implementation by the code for widelines. It no longer servers any purpose in the sampleservers, but still exists, #ifdef’ed by NEED_LINEHELPER, incase someone needs it.5.6. Pixblit ProceduresThe Drawing Primitive functions must be defined for yourserver. One possible way to do this is to use the miroutines from the sample server. If you choose to use themi routines (even part of them!) you must implement thesePixblit routines. These routines read and write pixelvalues and deal directly with the image data.The Pixblit routines for the sample server are part of the"mfb" routines (for Monochrome Frame Buffer), and "cfb"routines (for Color Frame Buffer). As with the mi routines,the mfb and cfb routines are portable but are not asportable as the mi routines.The mfb routines only work for monochrome frame buffers, thesimplest type of display. Furthermore, they only work forscreens that organize their bits in rows of pixels on thescreen. (See the Strategies document for more details onporting mfb.) The cfb routines work for packed-pixeldisplays from 2 to 32 bits in depth, although they have abit of code which has been tuned to run on 8-bit (1 pixelper byte) displays.In other words, if you have a "normal" frame buffer typedisplay, you can probably use either the mfb or cfb code,and the mi code. If you have a stranger hardware, you willhave to supply your own Pixblit routines, but you can usethe mi routines on top of them. If you have better ways ofdoing some of the Drawing Primitive functions, then you maywant to supply some of your own Drawing Primitive routines.(Even people who write their own Drawing Primitives save atleast some of the mi code for certain special cases thattheir hardware or library or fancy algorithm does nothandle.)The client, DIX, and the machine-independent routines do notcarry the final responsibility of clipping. They all dependupon the Pixblit routines to do their clipping for them.The rule is, if you touch the frame buffer, you clip.(The higher level routines may decide to clip at a highlevel, but this is only for increased performance and cannotsubstitute for bottom-level clipping. For instance, the miroutines, DIX, or the client may decide to check allcharacter strings to be drawn and chop off all charactersthat would not be displayed. If so, it must retain thecharacter on the edge that is partly displayed so that thePixblit routines can clip off precisely at the right place.)To make this easier, all of the reasons to clip can becombined into one region in your ValidateGC procedure. Youtake this composite clip region with you into the Pixblitroutines. (The sample server does this.)Also, FillSpans() has to apply tile and stipple patterns.The patterns are all aligned to the window origin so thatwhen two people write patches that are contiguous, they willmerge nicely. (Really, they are aligned to the patOrg pointin the GC. This defaults to (0, 0) but can be set by theclient to anything.)However, the mi routines can translate (relocate) the pointsfrom window-relative to screen-relative if desired. If youset the miTranslate field in the GC (set it in the CreateGCor ValidateGC routine), then the mi output routines willtranslate all coordinates. If it is false, then thecoordinates will be passed window-relative. Screens with nohardware translation will probably set miTranslate to TRUE,so that geometry (e.g. polygons, rectangles) can betranslated, rather than having the resulting list ofscanlines translated; this is good because the list verticesin a drawing request will generally be much smaller than thelist of scanlines it produces. Similarly, hardware thatdoes translation can set miTranslate to FALSE, and avoid theextra addition per vertex, which can be (but is not always)important for getting the highest possible performance.(Contrast the behavior of GetSpans, which is not expected tobe called as often, and so has different constraints.) ThemiTranslate field is settable in each GC, if , for example,you are mixing several kinds of destinations (offscreenpixmaps, main memory pixmaps, backing store, and windows),all of which have different requirements, on one screen.As with other drawing routines, there are fields in the GCto direct higher code to the correct routine to execute foreach function. In this way, you can optimize for specialcases, for example, drawing solids versus drawing stipples.The Pixblit routines are broken up into three sets. TheSpan routines simply fill in rows of pixels. The Glyphroutines fill in character glyphs. The PushPixels routineis a three-input bitblt for more sophisticated imagecreation.It turns out that the Glyph and PushPixels routines actuallyhave a machine-independent implementation that depends uponthe Span routines. If you are really pressed for time, youcan use these versions, although they are quite slow.5.6.1. Span RoutinesFor these routines, all graphic operations have been reducedto "spans." A span is a horizontal row of pixels. If youcan design these routines which write into and read fromrows of pixels at a time, you can use the mi routines.Each routine takes a destination drawable to draw into, a GCto use while drawing, the number of spans to do, and twopointers to arrays that indicate the list of starting pointsand the list of widths of spans.void pGC->ops->FillSpans(dst, pGC, nSpans, pPoints, pWidths, sorted)DrawablePtr dst;GCPtr pGC;int nSpans;DDXPointPtr pPoints;int *pWidths;int sorted;FillSpans should fill horizontal rows of pixels with theappropriate patterns, stipples, etc., based on the values inthe GC. The starting points are in the array at pPoints;the widths are in pWidths. If sorted is true, the scanlines are in increasing y order, in which case you may beable to make assumptions and optimizations.GC components: alu, clipOrg, clientClip, and fillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).void pGC->ops->SetSpans(pDrawable, pGC, pSrc, ppt, pWidths, nSpans, sorted)DrawablePtr pDrawable;GCPtr pGC;char *pSrc;DDXPointPtr pPoints;int *pWidths;int nSpans;int sorted;For each span, this routine should copy pWidths bits frompSrc to pDrawable at pPoints using the raster-op from theGC. If sorted is true, the scan lines are in increasing yorder. The pixels in pSrc are padded according to thescreen’s padding rules. These can be used to supportinteresting extension libraries, for example, shadedprimitives. It does not use the tile and stipple.GC components: alu, clipOrg, and clientClipThe above functions are expected to handle all modifiers inthe current GC. Therefore, it is expedient to havedifferent routines to quickly handle common special casesand reload the procedure pointers at validate time, as withthe other output functions.void pScreen->GetSpans(pDrawable, wMax, pPoints, pWidths, nSpans)DrawablePtr pDrawable;int wMax;DDXPointPtr pPoints;int *pWidths;int nSpans;char *pDst;For each span, GetSpans gets bits from the drawable startingat pPoints and continuing for pWidths bits. Each scanlinereturned will be server-scanline padded. The routine canreturn NULL if memory cannot be allocated to hold theresult.GetSpans never translates -- for a window, the coordinatesare already screen-relative. Consider the case of hardwarethat doesn’t do translation: the mi code that calls ddX willtranslate each shape (rectangle, polygon,. etc.) beforescan-converting it, which requires many fewer additions thathaving GetSpans translate each span does. Conversely,consider hardware that does translate: it can set itstranslation point to (0, 0) and get each span, and the onlypenalty is the small number of additions required totranslate each shape being scan-converted by the callingcode. Contrast the behavior of FillSpans and SetSpans(discussed above under miTranslate), which are expected tobe used more often.Thus, the penalty to hardware that does hardware translationis negligible, and code that wants to call GetSpans() isgreatly simplified, both for extensions and themachine-independent core implementation.5.6.1.1. Glyph RoutinesThe Glyph routines draw individual character glyphs for textdrawing requests.You have a choice in implementing these routines. You canuse the mi versions; they depend ultimately upon the spanroutines. Although text drawing will work, it will be veryslow.void pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)DrawablePtr pDrawable;GCPtr pGC;int x , y;unsigned int nglyph;CharInfoRec **ppci; /* array of character info */pointer unused; /* unused since R5 */GC components: alu, clipOrg, clientClip, font, andfillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).void pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase)DrawablePtr pDrawable;GCPtr pGC;int x , y;unsigned int nglyph;CharInfoRec **ppci; /* array of character info */pointer unused; /* unused since R5 */GC components: clipOrg, clientClip, font, fgPixel, bgPixelThese routines must copy the glyphs defined by the bitmapsin pglyphBase and the font metrics in ppci to theDrawablePtr, pDrawable. The poly routine follows all fill,stipple, and tile rules. The image routine simply blaststhe glyph onto the glyph’s rectangle, in foreground andbackground colors.More precisely, the Image routine fills the characterrectangle with the background color, and then the glyph isapplied in the foreground color. The glyph can extendoutside of the character rectangle. ImageGlyph() is usedfor terminal emulators and informal text purposes such asbutton labels.The exact specification for the Poly routine is that theglyph is painted with the current fill style. The characterrectangle is irrelevant for this operation. PolyText, at ahigher level, includes facilities for font changes withinstrings and such; it is to be used for WYSIWYG wordprocessing and similar systems.Both of these routines must clip themselves to the overallclipping region.Example implementations in mi are miPolyGlyphBlt() andmiImageGlyphBlt() in Xserver/mi/miglblt.c.5.6.1.2. PushPixels routineThe PushPixels routine writes the current fill style ontothe drawable in a certain shape defined by a bitmap.PushPixels is equivalent to using a second stipple. You canthing of it as pushing the fillStyle through a stencil.PushPixels is not used by any of the mi rendering code, butis used by the mi software cursor code.Suppose the stencil is:00111100and the stipple is: 10101010PushPixels result: 00101000You have a choice in implementing this routine. You can usethe mi version which depends ultimately upon FillSpans().Although it will work, it will be slow.void pGC->ops->PushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg)GCPtr pGC;PixmapPtr pBitMap;DrawablePtr pDrawable;int dx, dy, xOrg, yOrg;GC components: alu, clipOrg, clientClip, and fillStyle.GC mode-dependent components: fgPixel (for fillStyle Solid);tile, patOrg (for fillStyle Tile); stipple, patOrg, fgPixel(for fillStyle Stipple); and stipple, patOrg, fgPixel andbgPixel (for fillStyle OpaqueStipple).PushPixels applys the foreground color, tile, or stipplefrom the pGC through a stencil onto pDrawable. pBitMappoints to a stencil (of which we use an area dx wide by dyhigh), which is oriented over the drawable at xOrg, yOrg.Where there is a 1 bit in the bitmap, the destination is setaccording to the current fill style. Where there is a 0 bitin the bitmap, the destination is left the way it is.This routine must clip to the overall clipping region.An Example implementation is miPushPixels() inXserver/mi/mipushpxl.c.5.7. Shutdown Proceduresvoid AbortDDX()void ddxGiveUp()Some hardware may require special work to be done before theserver exits so that it is not left in an intermediatestate. As explained in the OS layer, FatalError() will callAbortDDX() just before terminating the server. In addition,ddxGiveUp() will be called just before terminating theserver on a "clean" death. What AbortDDX() and ddxGiveUP dois left unspecified, only that stubs must exist in the ddxlayer. It is up to local implementors as to what theyshould accomplish before termination.5.7.1. Command Line Proceduresint ddxProcessArgument(argc, argv, i)int argc;char *argv[];int i;voidddxUseMsg()You should write these routines to deal withdevice-dependent command line arguments. The routineddxProcessArgument() is called with the command line, andthe current index into argv; you should return zero if theargument is not a device-dependent one, and otherwise returna count of the number of elements of argv that are part ofthis one argument. For a typical option (e.g.,"-realtime"), you should return the value one. This routinegets called before checks are made againstdevice-independent arguments, so it is possible to peek atall arguments or to override device-independent argumentprocessing. You can document the device-dependent argumentsin ddxUseMsg(), which will be called from UseMsg() afterprinting out the device-independent arguments.Porting Layer Definition - 3 - April 8, 1994

5.8. Wrappers and devPrivatesTwo new extensibility concepts have been developed forrelease 4, Wrappers and devPrivates. These replace the R3GCInterest queues, which were not a general enough mechanismfor many extensions and only provided hooks into a singledata structure.5.8.1. devPrivatesdevPrivates are arrays of values attached to various datastructures (Screens, GCs, Windows, and Pixmaps currently).These arrays are sized dynamically at server startup (andreset) time as various modules allocate portions of them.They can be used for any purpose; each array entry isactually a union, DevUnion, of common useful types (pointer,long and unsigned long). devPrivates must be allocated onstartup and whenever the server resets. To make thiseasier, the global variable "serverGeneration" isincremented each time devPrivates should be allocated, butbefore the initialization process begins, typical usagewould be:static int privateGeneration = 0;if (privateGeneration != serverGeneration){ allocate devPrivates here.privateGeneration = serverGeneration;}5.8.1.1. Screen devPrivatesAn index into every screen devPrivates array is allocatedwith int AllocateScreenPrivateIndex()This call can occur at any time, each existing devPrivatesarray is resized to accommodate the new entry. This routinereturns -1 indicating an allocation failure. Otherwise, thereturn value can be used to index the array of devPrivateson any screen:private = (PrivatePointer) pScreen->devPrivates[screenPrivateIndex].ptr;The pointer in each screen is not initialized byAllocateScreenPrivateIndex().5.8.1.2. Window devPrivatesAn index into every window devPrivates array is allocatedwith int AllocateWindowPrivateIndex ()AllocateWindowPrivateIndex() never returns an error. Thiscall must be associated with a call which causes a chunk ofmemory to be automatically allocated and attached to thedevPrivate entry on every screen which the module will needto use the index:Bool AllocateWindowPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;If this space is not always needed for every object, use 0as the amount. In this case, the pointer field of the entryin the devPrivates array is initialized to NULL. This callexists so that DIX may preallocate all of the space requiredfor an object with one call; this reduces memoryfragmentation considerably. AllocateWindowPrivate returnsFALSE on allocation failure. Both of these calls must occurbefore any window structures are allocated; the server iscareful to avoid window creation until all modules areinitialized, but do not call this after initialization. Atypical allocation sequence for WindowPrivates would be:privateInitialize (pScreen)ScreenPtr pScreen;{if (privateGeneration != serverGeneration){ windowPrivateIndex = AllocateWindowPrivateIndex();privateGeneration = serverGeneration;}return (AllocateWindowPrivate(pScreen, windowPrivateIndex,sizeof(windowPrivateStructure)));}5.8.1.3. GC and Pixmap devPrivatesThe calls for GCs and Pixmaps mirror the Window callsexactly; they have the same requirements and limitations:int AllocateGCPrivateIndex ()Bool AllocateGCPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;int AllocatePixmapPrivateIndex ()Bool AllocatePixmapPrivate (pScreen, index, amount)ScreenPtr pScreen;int index;unsigned amount;5.8.2. WrappersWrappers are not a body of code, nor an interface spec.They are, instead, a technique for hooking a new module intoan existing calling sequence. There are limitations onother portions of the server implementation which make usingwrappers possible; limits on when specific fields of datastructures may be modified. They are intended as areplacement for GCInterest queues, which were not generalenough to support existing modules; in particular softwarecursors and backing store both needed more control over theactivity. The general mechanism for using wrappers is:privateWrapperFunction (object, ...)ObjectPtr object;{ pre-wrapped-function-stuff ...object->functionVector = (void *) object->devPrivates[privateIndex].ptr;(*object->functionVector) (object, ...);/** this next line is occasionally required by the rules governing* wrapper functions. Always using it will not cause problems.* Not using it when necessary can cause severe troubles.*/object->devPrivates[privateIndex].ptr = (pointer) object->functionVector;object->functionVector = privateWrapperFunction;post-wrapped-function-stuff ...}privateInitialize (object)ObjectPtr object;{ object->devPrivates[privateIndex].ptr = (pointer) object->functionVector;object->functionVector = privateWrapperFunction;}Thus the privateWrapperFunction provides hooks forperforming work both before and after the wrapped functionhas been called; the process of resetting the functionVectoris called "unwrapping" while the process of fetching thewrapped function and replacing it with the wrapping functionis called "wrapping". It should be clear that GCInterestqueues could be emulated using wrappers. In general, anyfunction vectors contained in objects can be wrapped, butonly vectors in GCs and Screens have been tested.Wrapping screen functions is quite easy; each vector isindividually wrapped. Screen functions are not supposed tochange after initialization, so rewrapping is technicallynot necessary, but causes no problems.Wrapping GC functions is a bit more complicated. GC’s havetwo sets of function vectors, one hanging from gc->ops andthe other from gc->funcs. Wrappers should modify only thosevalues, not the internal values as they may be shared bymore than one GC (and, in the case of funcs, are probablyshared by all gcs). To wrap the ops, wrap the funcs and, ineach func wrapper, unwrap the ops and funcs, call down, andre-wrap. In each op wrapper, unwrap both the funcs and ops,call down and rewrap afterwards. The rule is: if you wrapfuncs+ops, you must always unwrap both before down calling.If you wrap ops, you must always pull the ops value out ofthe GC in the func wrapper and save it. If you wrap funcs,you needn’t pull the funcs value out of the GC to rewrap asthe func values are required to be constant. In this way,the wrapped validation routine can change the op vector andnot have it lost when your wrapper routine rewraps the GC.This occurs when the wrapped op revalidates the GC with newentries (many mi routines do this for opaque stipples ordouble dashes). The corollary to this rule is: Neverchange the func vector after CreateGC.5.9. Work QueueTo queue work for execution when all clients are in a stablestate (i.e. just before calling select() inWaitForSomething), call:Bool QueueWorkProc(function,client,closure)Bool (*function)();ClientPtr client;pointer closure;When the server is about to suspend itself, the givenfunction will be executed:(*function) (client, closure)Neither client nor closure are actually used inside the workqueue routines.6. Extension InterfacesThis section describes the functions which exist in DDX forextension writers to use.6.1. Extension initialization

This function should be called from your extensionInitProc which should be called by InitExtensions.

ExtensionEntry *AddExtension(name, NumEvents,NumErrors,

MainProc, SwappedMainProc, CloseDownProc, MinorOpcodeProc)

char *name; /*Null terminate string; case matters*/

int NumEvents;

int NumErrors;

int (* MainProc)(ClientPtr);/*Called if client matches server order*/

int (* SwappedMainProc)(ClientPtr);/*Called if client differs from server*/

void (* CloseDownProc)(ExtensionEntry *);

unsigned short (*MinorOpcodeProc)(ClientPtr);

name is the name used by clients to refer to the extension. NumEvents is the number of event types used by the extension, NumErrors is the number of error codes needed by the extension. MainProc is called whenever a client accesses the major opcode assigned to the extension. SwappedMainProc is identical, except the client using the extension has reversed byte-sex. CloseDownProc is called at server reset time to deallocate any private storage used by the extension. MinorOpcodeProc is used by DIX to place the appropriate value into errors. The DIX routine StandardMinorOpcode can be used here which takes the minor opcode from the normal place in the request (i.e. just after the major opcode).

6.2. Resource type allocation.

These functions should also be called from your extensionInitProc to allocate all of the various resource classes and types required for the extension. Each time the server resets, these types must be reallocated as the old allocations will have been discarded. Resource types are integer values starting at 1. Get a resource type by calling

RESTYPE CreateNewResourceType(deleteFunc)

deleteFunc will be called to destroy all resources with this type.

Resource classes are masks starting at 1 << 31 which can be or’ed with any resource type to provide attributes for the type. To allocate a new class bit, call

RESTYPE CreateNewResourceClass()

There are two ways of looking up resources, by type or by class. Classes are non-exclusive subsets of the space of all resources, so you can lookup the union of multiple classes. (RC_ANY is the union of all classes).

Note that the appropriate class bits must be or’ed into the value returned by CreateNewResourceType when calling resource lookup functions.

If you need to create a ‘‘private’’ resource ID for internal use, you can call FakeClientID.

XID FakeClientID(client)

int client;

This allocates from ID space reserved for the server.

To associate a resource value with an ID, use AddResource.

Bool AddResource(id, type, value)

XID id;

RESTYPE type;

pointer value;

The type should be the full type of the resource, including any class bits. If AddResource fails to allocate memory to store the resource, it will call the deleteFunc for the type, and then return False.

To free a resource, use one of the following.

void FreeResource(id, skipDeleteFuncType)

XID id;

RESTYPE skipDeleteFuncType;

void FreeResourceByType(id, type, skipFree)

XID id;

RESTYPE type;

Bool skipFree;

FreeResource frees all resources matching the given id, regardless of
type; the type’s deleteFunc will be called on each matching resource,
except that skipDeleteFuncType can be set to a single type for which
the deleteFunc should not be called (otherwise pass RT_NONE).
FreeResourceByType frees a specific resource matching a given id
and type; if skipFree is true, then the deleteFunc is not called.

To look up a resource, use one of the following.

pointer LookupIDByType(id, rtype)

XID id;

RESTYPE rtype;

pointer LookupIDByClass(id, classes)

XID id;

RESTYPE classes;

LookupIDByType finds a resource with the given id and exact type. LookupIDByClass finds a resource with the given id whose type is included in any one of the specified classes.

6.3. Macros and Other Helpers

There are a number of macros in Xserver/include/dix.h which are useful to the extension writer. Ones of particular interest are: REQUEST, REQUEST_SIZE_MATCH, REQUEST_AT_LEAST_SIZE, REQUEST_FIXED_SIZE, LEGAL_NEW_RESOURCE, LOOKUP_DRAWABLE, VERIFY_GC, and VALIDATE_DRAWABLE_AND_GC. Useful byte swapping macros can be found in Xserver/include/misc.h: lswapl, lswaps, LengthRestB, LengthRestS, LengthRestL, SwapRestS, SwapRestL, swapl, swaps, cpswapl, and cpswaps.
Porting Layer Definition - 4 - April 8, 1994

7. Callback ManagerTo satisfy a growing number of requests for the introductionof ad hoc notification style hooks in the server, a genericcallback manager was introduced in R6. A callback listobject can be introduced for each new hook that is desired,and other modules in the server can register interest in thenew callback list. The following functions support theseoperations.Before getting bogged down in the interface details, antypical usage example should establish the framework. Let’slook at the ClientStateCallback in dix/dispatch.c. Thepurpose of this particular callback is to notify interesetedparties when a client’s state (initial, running, gone)changes. The callback is "created" in this case by simplydeclaring a variable:CallbackListPtr ClientStateCallback;Whenever the client’s state changes, the following codeappears, which notifies all intereseted parties of thechange:if (ClientStateCallback)CallCallbacks(&ClientStateCallback, (pointer)client);Interested parties subscribe to the ClientStateCallback listby saying:AddCallback(&ClientStateCallback, func, data);When CallCallbacks is invoked on the list, func will becalled thusly:(*func)(&ClientStateCallback, data, client)Now for the details.Bool CreateCallbackList(pcbl, cbfuncs)CallbackListPtr *pcbl;CallbackFuncsPtr cbfuncs;CreateCallbackList creates a callback list. We envisionthat this function will be rarely used because the callbacklist is created automatically (if it doesn’t already exist)when the first call to AddCallback is made on the list. Theonly reason to explicitly create the callback list with thisfunction is if you want to override the implementation ofsome of the other operations on the list by passing your owncbfuncs. You also lose something by explicit creation: youintroduce an order dependency during server startup becausethe list must be created before any modules subscribe to it.Returns TRUE if successful.Bool AddCallback(pcbl, callback, subscriber_data)CallbackListPtr *pcbl;CallbackProcPtr callback;pointer subscriber_data;Adds the (callback, subscriber_data) pair to the givencallback list. Creates the callback list if it doesn’texist. Returns TRUE if successful.Bool DeleteCallback(pcbl, callback, subscriber_data)CallbackListPtr *pcbl;CallbackProcPtr callback;pointer subscriber_data;Removes the (callback, data) pair to the given callback listif present. Returns TRUE if (callback, data) was found.void CallCallbacks(pcbl, call_data)CallbackListPtr *pcbl;pointer call_data;For each callback currently registered on the given callbacklist, call it as follows:(*callback)(pcbl, subscriber_data, call_data);void DeleteCallbackList(pcbl)CallbackListPtr *pcbl;Destroys the given callback list.Porting Layer Definition - 5 - April 8, 1994

8. Summary of RoutinesThis is a summary of the routines discussed in thisdocument. The procedure names are in alphabetical order.The Struct is the structure it is attached to; if blank,this procedure is not attached to a struct and must be namedas shown. The sample server provides implementations in thefollowing categories. Notice that many of the graphicsroutines have both mi and mfb implementations.Porting Layer Definition - 6 - April 8, 1994

Image ddx3.png

Porting Layer Definition - 7 - April 8, 1994

Image ddx4.png

Porting Layer Definition - 8 - April 8, 1994

Table of Contents

The X Window System

. . . . . . . . . . . . . . . . . .
3

OVERVIEW OF THE SERVER

. . . . . . . . . . . . . . . . .
3

Notes On Resources and Large Structs

. . . . . . . . . .
3

DIX LAYER

. . . . . . . . . . . . . . . . . . . . . . .
3

OS LAYER

. . . . . . . . . . . . . . . . . . . . . . . .
3

Scheduling and Request Delivery

. . . . . . . . . . . .
3

New Client Connections

. . . . . . . . . . . . . . . . .
3

Reading Data from Clients

. . . . . . . . . . . . . . .
3

Inserting Data for Clients

. . . . . . . . . . . . . . .
3

Sending Events, Errors And Replies To Clients

. . . . .
3

Font Support

. . . . . . . . . . . . . . . . . . . . . .
3

Memory Management

. . . . . . . . . . . . . . . . . . .
3

Client Scheduling

. . . . . . . . . . . . . . . . . . .
3

Other OS Functions

. . . . . . . . . . . . . . . . . . .
3

Idiom Support

. . . . . . . . . . . . . . . . . . . . .
3

DDX LAYER

. . . . . . . . . . . . . . . . . . . . . . .
3

INPUT

. . . . . . . . . . . . . . . . . . . . . . . . .
3

Input Device Data Structures

. . . . . . . . . . . . . .
3

Processing Events

. . . . . . . . . . . . . . . . . . .
3

Telling DIX When Input is Pending

. . . . . . . . . . .
3

Controlling Input Devices

. . . . . . . . . . . . . . .
3

Input Initialization

. . . . . . . . . . . . . . . . . .
3

Keyboard Mapping and Keycodes

. . . . . . . . . . . . .
3

Screens

. . . . . . . . . . . . . . . . . . . . . . . .
3

Screen Hardware Requirements

. . . . . . . . . . . . . .
3

Data Structures

. . . . . . . . . . . . . . . . . . . .
3

Output Initialization

. . . . . . . . . . . . . . . . .
3

Region Routines in the ScreenRec

. . . . . . . . . . . .
3

Cursor Routines for a Screen

. . . . . . . . . . . . . .
3

Visuals, Depths and Pixmap Formats for Screens

. . . . .
3

Colormaps for Screens

. . . . . . . . . . . . . . . . .
3

Colormap Routines

. . . . . . . . . . . . . . . . . . .
3

Initializing a Colormap

. . . . . . . . . . . . . . . .
3

Fonts for Screens

. . . . . . . . . . . . . . . . . . .
3

Portable Compiled Format

. . . . . . . . . . . . . . . .
3

Font Realization

. . . . . . . . . . . . . . . . . . . .
3

Other Screen Routines

. . . . . . . . . . . . . . . . .
3

Drawables

. . . . . . . . . . . . . . . . . . . . . . .
3

Pixmaps

. . . . . . . . . . . . . . . . . . . . . . . .
3

Windows

. . . . . . . . . . . . . . . . . . . . . . . .
3

Window Procedures in the ScreenRec

. . . . . . . . . . .
3

Window Painting Procedures

. . . . . . . . . . . . . . .
3

Screen Operations for Backing Store

. . . . . . . . . .
3

Screen Operations for Multi-Layered Framebuffers

. . . .
3

Graphics Contexts and Validation

. . . . . . . . . . . .
3

Details of operation

. . . . . . . . . . . . . . . . . .
3

GC Handling Routines

. . . . . . . . . . . . . . . . . .
3

GC Clip Region Routines

. . . . . . . . . . . . . . . .
3

Drawing Primitives

. . . . . . . . . . . . . . . . . . .
3

GC Components

. . . . . . . . . . . . . . . . . . . . .
3

The Primitives

. . . . . . . . . . . . . . . . . . . . .
3

Pixblit Procedures

. . . . . . . . . . . . . . . . . . .
3

Span Routines

. . . . . . . . . . . . . . . . . . . . .
3

Glyph Routines

. . . . . . . . . . . . . . . . . . . . .
3

PushPixels routine

. . . . . . . . . . . . . . . . . . .
3

Shutdown Procedures

. . . . . . . . . . . . . . . . . .
3

Command Line Procedures

. . . . . . . . . . . . . . . .
3

Wrappers and devPrivates

. . . . . . . . . . . . . . . .
4

devPrivates

. . . . . . . . . . . . . . . . . . . . . .
4

Screen devPrivates

. . . . . . . . . . . . . . . . . . .
4

Window devPrivates

. . . . . . . . . . . . . . . . . . .
4

GC and Pixmap devPrivates

. . . . . . . . . . . . . . .
4

Wrappers

. . . . . . . . . . . . . . . . . . . . . . . .
4

Work Queue

. . . . . . . . . . . . . . . . . . . . . . .
4

Extension Interfaces

. . . . . . . . . . . . . . . . . .
4

Callback Manager

. . . . . . . . . . . . . . . . . . . .
5

Summary of Routines

. . . . . . . . . . . . . . . . . .
6

Porting Layer Definition - 1 - April 8, 1994