diff options
author | Adam Jackson <ajax@redhat.com> | 2008-02-17 08:47:40 +1100 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2008-02-17 08:47:40 +1100 |
commit | 74e2e3975a962bd468d321d09271cc1c23235871 (patch) | |
tree | 8a0a5d059e27710a0721a716164d5d38586a2ed6 | |
parent | 27aa7a163ab71f0359a422d1fbf361af59e029e0 (diff) |
Import the source for the DDX documentation from old Xorg CVS.
-rw-r--r-- | specs/Xserver/ddx.tbl.ms | 5283 |
1 files changed, 5283 insertions, 0 deletions
diff --git a/specs/Xserver/ddx.tbl.ms b/specs/Xserver/ddx.tbl.ms new file mode 100644 index 0000000..620e08c --- /dev/null +++ b/specs/Xserver/ddx.tbl.ms @@ -0,0 +1,5283 @@ +.\" $Xorg: ddx.tbl.ms,v 1.3 2000/08/17 19:42:41 cpqbld Exp $ +.EF 'Porting Layer Definition'- % -'October 27, 2004' +.OF 'Porting Layer Definition'- % -'October 27, 2004' +.EH ''' +.OH ''' +.TL +Definition of the Porting Layer +for the X v11 Sample Server +.AU +Susan Angebranndt +.AU +Raymond Drewry +.AU +Philip Karlton +.AU +Todd Newman +.AI +Digital Equipment Corporation +.sp +minor revisions by +.AU +Bob Scheifler +.AI +Massachusetts Institute of Technology +.sp +Revised for Release 4 and Release 5 by +.AU +Keith Packard +.AI +MIT X Consortium +.sp +Revised for Release 6 by +.AU +David P. Wiggins +.AI +X Consortium +.sp +Minor Revisions for Release 6.8.2 by +.AU +Jim Gettys +.AI +X.org Foundation and Hewlett Packard +.LP +.bp +\& +.sp 15 +Copyright \(co 1994 X Consortium, Inc., 2004 X.org Foundation, Inc. +.LP +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: +.LP +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +.LP +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. +.bp +.LP +Note to the 2004 edition: at this time this document must be considered incomplete. +In particular, the new Render extension is still lacking good documentation, +and has become vital to high performance X implementations. +A new "fb" portable frame buffer graphics library (replacing "cfb") +is used by most implementations +to implement software rendering for most operations. Accelerating only a few +of the old "core" graphics functions is now needed, +as performance in software is "good enough" for most operations. +Modern applications +and desktop environments are now +much more sensitive to good implementation of the Render extension than in +most operations of the old X graphics model. +The shadow frame buffer implementation is also very useful in many circumstances, +and also needs documentation. +We hope to rectify these shortcomings in our documentation +in the future. +Help would be greatly appreciated. +.LP +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: +.IP 1) +Read the first section +of the "Strategies for Porting" document (Overview of Porting Process). +.IP 2) +Skim over this document (the Definition document). +.IP 3) +Skim over the remainder of the Strategies document. +.IP 4) +Start planning and working, referring to the Strategies +and Definition documents. +.LP +You may also want to look at the following documents: +.IP \(bu 5 +"The X Window System" +for an overview of X. +.IP \(bu 5 +"Xlib - C Language X Interface" +for a view of what the client programmer sees. +.IP \(bu 5 +"X Window System Protocol" +for a terse description of the byte stream protocol +between the client and server. +.LP +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 the X.org Foundation, Inc. +Cray is a trademark of Cray Research, Inc. + +.LP +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. +.LP +Some source in the distribution is directly compilable +on your machine. +Some of it will require +modification. +Other parts may have to be completely written from scratch. +.LP +The distribution also includes source for a sample implementation of a display +server which runs on a very wide variety of color and monochrome displays on +Linux and *BSD which you +will find useful for implementing any type of X server. + + +.NH 1 +The X Window System +.XS +The X Window System +.XE +.LP +The X Window System, or simply "X," is a +windowing system that provides high-performance, high-level, +device-independent graphics. + +X is a windowing system designed for bitmapped graphic displays. +The display can have a +simple, monochrome display or it can have a color display with up to 32 bits +per pixel with a special graphics processor doing the work. (In this +document, monochrome means a black and white display with one bit per pixel. +Even though the usual meaning of monochrome is more general, this special +case is so common that we decided to reserve the word for this purpose.) +In practice, monochrome displays are now almost unheard of, with 4 bit +gray scale displays being the low end. + +X is designed for a networking environment where +users can run applications on machines other than their own workstations. +Sometimes, the connection is over an Ethernet network with a protocol such as TCP/IP; +but, any "reliable" byte stream is allowable. +A high-bandwidth byte stream is preferable; RS-232 at +9600 baud would be slow without compression techniques. + +X by itself allows great freedom of design. +For instance, it does not include any user interface standard. +Its intent is to "provide mechanism, not policy." +By making it general, it can be the foundation for a wide +variety of interactive software. + +For a more detailed overview, see the document "The X Window System." +For details on the byte stream protocol, see "X Window System protocol." + +.NH 1 +OVERVIEW OF THE SERVER +.XS +OVERVIEW OF THE SERVER +.XE +.LP +The display server +manages windows and simple graphics requests +for the user on behalf of different client applications. +The client applications can be running on any machine on the network. +The server mainly does three things: +.IP \(bu 5 +Responds to protocol requests from existing clients +(mostly graphic and text drawing commands) +.IP \(bu 5 +Sends device input (keystrokes and mouse actions) and other events to existing clients +.IP \(bu 5 +Maintains client connections + +.LP +The server code is organized into four major pieces: + +.IP \(bu 5 +Device Independent (DIX) layer - code +shared among all implementations +.IP \(bu 5 +Operating System (OS) layer - code +that is different for each operating system +but is shared among all graphic +devices for this operating system +.IP \(bu 5 +Device Dependent (DDX) layer - code that is (potentially) +different for each combination of operating +system and graphic device +.IP \(bu 5 +Extension Interface - a standard way to add +features to the X server + +.LP +The "porting layer" consists of the OS and DDX layers; these are +actually parallel and neither one is on top of the other. +The DIX layer is intended to be portable +without change to target systems and is not +detailed here, although several routines +in DIX that are called by DDX are +documented. +Extensions incorporate new functionality into the server; and require +additional functionality over a simple DDX. +.LP +The following sections outline the functions of the layers. +Section 3 briefly tells what you need to know about the DIX layer. +The OS layer is explained in Section 4. +Section 5 gives the theory of operation and procedural interface for the +DDX layer. +Section 6 describes the functions which exist for the extension writer. + +.NH 2 +Notes On Resources and Large Structs +.XS +Notes On Resources and Large Structs +.XE +.LP +X resources are C structs inside the server. +Client applications create and manipulate these objects +according to the rules of the X byte stream protocol. +Client applications refer to resources with resource IDs, +which are 32-bit integers that are sent over the network. +Within the server, of course, they are just C structs, and we refer to them +by pointers. + +The DDX layer has several kinds of resources: +.IP \(bu 5 +Window +.IP \(bu 5 +Pixmap +.IP \(bu 5 +Screen +.IP \(bu 5 +Device +.IP \(bu 5 +Colormap +.IP \(bu 5 +Font +.IP \(bu 5 +Cursor +.IP \(bu 5 +Graphics Contexts +.LP +The type names of the more +important server +structs usually end in "Rec," such as "DeviceRec;" +the pointer types usually end in "Ptr," such as "DevicePtr." + +The structs and +important defined constants are declared +in .h files that have names that suggest the name of the object. +For instance, there are two .h files for windows, +window.h and windowstr.h. +window.h defines only what needs to be defined in order to use windows +without peeking inside of them; +windowstr.h defines the structs with all of their components in great detail +for those who need it. +.LP +Three kinds of fields are in these structs: +.IP \(bu 5 +Attribute fields - struct fields that contain values like normal structs +.IP \(bu 5 +Pointers to procedures, or structures of procedures, that operate on the +object +.IP \(bu 5 +A private field (or two) used by your DDX code to keep private data +(probably a pointer +to another data structure), or an array of private fields, which is +sized as the server initializes. +.LP +DIX calls through +the struct's procedure pointers to do its tasks. +These procedures are set either directly or indirectly by DDX procedures. +Most of +the procedures described in the remainder of this +document are accessed through one of these structs. +For example, the procedure to create a pixmap +is attached to a ScreenRec and might be called by using the expression +.nf + + (* pScreen->CreatePixmap)(pScreen, width, height, depth). + +.fi +All procedure pointers must be set to some routine unless noted otherwise; +a null pointer will have unfortunate consequences. + +Procedure routines will be indicated in the documentation by this convention: +.nf + + void pScreen->MyScreenRoutine(arg, arg, ...) + +.fi +as opposed to a free routine, not in a data structure: +.nf + + void MyFreeRoutine(arg, arg, ...) + +.fi + +The attribute fields are mostly set by DIX; DDX should not modify them +unless noted otherwise. + +.NH 1 +DIX LAYER +.XS +DIX LAYER +.XE +.LP +The DIX layer is the machine and device independent part of X. +The source should be common to all operating systems and devices. +The port process should not include changes to this part, therefore internal interfaces to DIX +modules are not discussed, except for public interfaces to the DDX and the OS layers. + +In the process of getting your server to work, if +you think that DIX must be modified for purposes other than bug fixes, +you may be doing something wrong. +Keep looking for a more compatible solution. +When the next release of the X server code is available, +you should be able to just drop in the new DIX code and compile it. +If you change DIX, +you will have to remember what changes you made and will have +to change the new sources before you can update to the new version. + +The heart of the DIX code is a loop called the dispatch loop. +Each time the processor goes around the loop, it sends off accumulated input events +from the input devices to the clients, and it processes requests from the clients. +This loop is the most organized way for the server to +process the asynchronous requests that +it needs to process. +Most of these operations are performed by OS and DDX routines that you must supply. + +.NH 1 +OS LAYER +.XS +OS LAYER +.XE +.LP +This part of the source consists of a few routines that you have to rewrite +for each operating system. +These OS functions maintain the client connections and schedule work +to be done for clients. +They also provide an interface to font files, +font name to file name translation, and +low level memory management. + +.nf + void OsInit() +.fi +OsInit initializes your OS code, performing whatever tasks need to be done. +Frequently there is not much to be done. +The sample server implementation is in Xserver/os/osinit.c. + +.NH 2 +Scheduling and Request Delivery +.XS +Scheduling and Request Delivery +.XE +.LP +The main dispatch loop in DIX creates the illusion of multitasking between +different windows, while the server is itself but a single process. +The dispatch loop breaks up the work for each client into small digestible parts. +Some parts are requests from a client, such as individual graphic commands. +Some parts are events delivered to the client, such as keystrokes from the user. +The processing of events and requests for different +clients can be interleaved with one another so true multitasking +is not needed in the server. +.LP +You must supply some of the pieces for proper scheduling between clients. +.nf + + int WaitForSomething(pClientReady) + int *pClientReady; +.fi +.LP +WaitForSomething is the scheduler procedure you must write that will +suspend your server process until something needs to be done. +This call should +make the server suspend until one or more of the following occurs: +.IP \(bu 5 +There is an input event from the user or hardware (see SetInputCheck()) +.IP \(bu 5 +There are requests waiting from known clients, in which case +you should return a count of clients stored in pClientReady +.IP \(bu 5 +A new client tries to connect, in which case you should create the +client and then continue waiting +.LP +Before WaitForSomething() computes the masks to pass to select, poll or +similar operating system interface, it needs to +see if there is anything to do on the work queue; if so, it must call a DIX +routine called ProcessWorkQueue. +.nf + extern WorkQueuePtr workQueue; + + if (workQueue) + ProcessWorkQueue (); +.fi +.LP +If WaitForSomething() decides it is about to do something that might block +(in the sample server, before it calls select() or poll) it must call a DIX +routine called BlockHandler(). +.nf + + void BlockHandler(pTimeout, pReadmask) + pointer pTimeout; + pointer pReadmask; +.fi +The types of the arguments are for agreement between the OS and DDX +implementations, but the pTimeout is a pointer to the information +determining how long the block is allowed to last, and the +pReadmask is a pointer to the information describing the descriptors +that will be waited on. +.LP +In the sample server, pTimeout is a struct timeval **, and pReadmask is +the address of the select() mask for reading. +.LP +The DIX BlockHandler() iterates through the Screens, for each one calling +its BlockHandler. A BlockHandler is declared thus: +.nf + + void xxxBlockHandler(nscreen, pbdata, pptv, pReadmask) + int nscreen; + pointer pbdata; + struct timeval ** pptv; + pointer pReadmask; +.fi +The arguments are the index of the Screen, the blockData field +of the Screen, and the arguments to the DIX BlockHandler(). +.LP +Immediately after WaitForSomething returns from the +block, even if it didn't actually block, it must call the DIX routine +WakeupHandler(). +.nf + + void WakeupHandler(result, pReadmask) + int result; + pointer pReadmask; +.fi +.LP +Once again, the types are not specified by DIX. The result is the +success indicator for the thing that (may have) blocked, +and the pReadmask is a mask of the descriptors that came active. +In the sample server, result is the result from select() (or equivalent +operating system function), and pReadmask is +the address of the select() mask for reading. +.LP +The DIX WakeupHandler() calls each Screen's +WakeupHandler. A WakeupHandler is declared thus: +.nf + + void xxxWakeupHandler(nscreen, pbdata, err, pReadmask) + int nscreen; + pointer pbdata; + unsigned long result; + pointer pReadmask; +.fi +The arguments are the index of the Screen, the blockData field +of the Screen, and the arguments to the DIX WakeupHandler(). +.LP +In addition to the per-screen BlockHandlers, any module may register +block and wakeup handlers (only together) using: +.nf + + Bool RegisterBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData) + BlockHandlerProcPtr blockHandler; + WakeupHandlerProcPtr wakeupHandler; + pointer blockData; +.fi +A FALSE return code indicates that the registration failed for lack of +memory. To remove a registered Block handler at other than server reset time +(when they are all removed automatically), use: +.nf + + RemoveBlockAndWakeupHandlers (blockHandler, wakeupHandler, blockData) + BlockHandlerProcPtr blockHandler; + WakeupHandlerProcPtr wakeupHandler; + pointer blockData; +.fi +All three arguments must match the values passed to +RegisterBlockAndWakeupHandlers. +.LP +These registered block handlers are called after the per-screen handlers: +.nf + + void (*BlockHandler) (blockData, pptv, pReadmask) + pointer blockData; + OSTimePtr pptv; + pointer pReadmask; +.fi +.LP +Sometimes block handlers need to adjust the time in a OSTimePtr structure, +which on UNIX family systems is generally represented by a struct timeval +consisting of seconds and microseconds in 32 bit values. +As a convenience to reduce error prone struct timeval computations which +require modulus arithmetic and correct overflow behavior in the face of +millisecond wrapping throrugh 32 bits, +.nf + + void AdjustWaitForDelay(pointer /*waitTime*, unsigned long /* newdelay */) + +.fi +has been provided. +.LP +Any wakeup handlers registered with RegisterBlockAndWakeupHandlers will +be called before the Screen handlers: +.nf + + void (*WakeupHandler) (blockData, err, pReadmask) + pointer blockData; + int err; + pointer pReadmask; +.fi +.LP +The WaitForSomething on the sample server also has a built +in screen saver that darkens the screen if no input happens for a period of time. +The sample server implementation is in Xserver/os/WaitFor.c. +.LP +Note that WaitForSomething() may be called when you already have several +outstanding things (events, requests, or new clients) queued up. +For instance, your server may have just done a large graphics request, +and it may have been a long time since WaitForSomething() was last called. +If many clients have lots of requests queued up, DIX will only service +some of them for a given client +before going on to the next client (see isItTimeToYield, below). +Therefore, WaitForSomething() will have to report that these same clients +still have requests queued up the next time around. +.LP +An implementation should return information on as +many outstanding things as it can. +For instance, if your implementation always checks for client data first and does not +report any input events until there is no client data left, +your mouse and keyboard might get locked out by an application that constantly +barrages the server with graphics drawing requests. +Therefore, as a general rule, input devices should always have priority over graphics +devices. +.LP +A list of indexes (client->index) for clients with data ready to be read or +processed should be returned in pClientReady, and the count of indexes +returned as the result value of the call. +These are not clients that have full requests ready, but any clients who have +any data ready to be read or processed. +The DIX dispatcher +will process requests from each client in turn by calling +ReadRequestFromClient(), below. +.LP +WaitForSomething() must create new clients as they are requested (by +whatever mechanism at the transport level). A new client is created +by calling the DIX routine: +.nf + + ClientPtr NextAvailableClient(ospriv) + pointer ospriv; +.fi +This routine returns NULL if a new client cannot be allocated (e.g. maximum +number of clients reached). The ospriv argument will be stored into the OS +private field (pClient->osPrivate), to store OS private information about the +client. In the sample server, the osPrivate field contains the +number of the socket for this client. See also "New Client Connections." +NextAvailableClient() will call InsertFakeRequest(), so you must be +prepared for this. +.LP +If there are outstanding input events, +you should make sure that the two SetInputCheck() locations are unequal. +The DIX dispatcher will call your implementation of ProcessInputEvents() +until the SetInputCheck() locations are equal. +.LP +The sample server contains an implementation of WaitForSomething(). +The +following two routines indicate to WaitForSomething() what devices should +be waited for. fd is an OS dependent type; in the sample server +it is an open file descriptor. +.nf + + int AddEnabledDevice(fd) + int fd; + + int RemoveEnabledDevice(fd) + int fd; +.fi +These two routines are +usually called by DDX from the initialize cases of the +Input Procedures that are stored in the DeviceRec (the +routine passed to AddInputDevice()). +The sample server implementation of AddEnabledDevice +and RemoveEnabledDevice are in Xserver/os/connection.c. +.NH 3 +Timer Facilities +.XS +Timer Facilities +.XE +.LP +Similarly, the X server or an extension may need to wait for some timeout. +Early X releases implemented this functionality using block and wakeup handlers, +but this has been rewritten to use a general timer facilty, and the +internal screen saver facilties reimplemented to use Timers. +These functions are TimerInit, TimerForce, TimerSet, TimerCheck, TimerCancel, +and TimerFree, as defined in Xserver/include/os.h. A callback function will be called +when the timer fires, along with the current time, and a user provided argument. +.nf + typedef struct _OsTimerRec *OsTimerPtr; + + typedef CARD32 (*OsTimerCallback)( + OsTimerPtr /* timer */, + CARD32 /* time */, + pointer /* arg */); + + OsTimerPtr TimerSet( OsTimerPtr /* timer */, + int /* flags */, + CARD32 /* millis */, + OsTimerCallback /* func */, + pointer /* arg */); + +.fi +.LP +TimerSet returns a pointer to a timer structure and sets a timer to the specified time +with the specified argument. The flags can be TimerAbsolute and TimerForceOld. +The TimerSetOld flag controls whether if the timer is reset and the timer is pending, the +whether the callback function will get called. +The TimerAbsolute flag sets the callback time to an absolute time in the future rather +than a time relative to when TimerSet is called. +TimerFree should be called to free the memory allocated +for the timer entry. +.nf + void TimerInit(void) + + Bool TimerForce(OsTimerPtr /* pTimer */) + + void TimerCheck(void); + + void TimerCancel(OsTimerPtr /* pTimer */) + + void TimerFree(OSTimerPtr /* pTimer */) +.fi +TimerInit frees any exisiting timer entries. TimerForce forces a call to the timer's +callback function and returns true if the timer entry existed, else it returns false and +does not call the callback function. TimerCancel will cancel the specified timer. +TimerFree calls TimerCancel and frees the specified timer. +Calling TimerCheck will force the server to see if any timer callbacks should be called. +.NH 2 +New Client Connections +.XS +New Client Connections +.XE +.LP +The process whereby a new client-server connection starts up is +very dependent upon what your byte stream mechanism. +This section describes byte stream initiation using examples from the TCP/IP +implementation on the sample server. +.LP +The first thing that happens is a client initiates a connection with the server. +How a client knows to do this depends upon your network facilities and the +Xlib implementation. +In a typical scenario, a user named Fred +on his X workstation is logged onto a Cray +supercomputer running a command shell in an X window. Fred can type shell +commands and have the Cray respond as though the X server were a dumb terminal. +Fred types in a command to run an X client application that was linked with Xlib. +Xlib looks at the 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 and multiple X server processes. +(Precisely what +happens on your system depends upon how X and Xlib are implemented.) +.LP +The client application calls a TCP routine on the +Cray to open a TCP connection for X +to communicate with the network node "fredsbittube." +The TCP software on the Cray does this by looking up the TCP +address of "fredsbittube" and sending an open request to TCP port 6000 +on fredsbittube. +.LP +All X servers on TCP listen for new clients on port 6000 by default; +this is known as a "well-known port" in IP terminology. +.LP +The server receives this request from its port 6000 +and checks where it came from to see if it is on the server's list +of "trustworthy" hosts to talk to. +Then, it opens another port for communications with the client. +This is the byte stream that all X communications will go over. +.LP +Actually, it is a bit more complicated than that. +Each X server process running on the host machine is called a "display." +Each display can have more than one screen that it manages. +"corporatehydra:3.2" represents screen 2 on display 3 on +the multi-screened network node corporatehydra. +The open request would be sent on well-known port number 6003. +.LP +Once the byte stream is set up, what goes on does not depend very much +upon whether or not it is TCP. +The client sends an xConnClientPrefix struct (see Xproto.h) that has the +version numbers for the version of Xlib it is running, some byte-ordering information, +and two character strings used for authorization. +If the server does not like the authorization strings +or the version numbers do not match within the rules, +or if anything else is wrong, it sends a failure +response with a reason string. +.LP +If the information never comes, or comes much too slowly, the connection +should be broken off. You must implement the connection timeout. The +sample server implements this by keeping 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 connection timeout can be set from the command line. +.LP +You must implement whatever authorization schemes you want to support. +The sample server on the distribution tape supports a simple authorization +scheme. The only interface seen by DIX is: +.nf + + 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; +.fi +.LP +DIX will only call this once per client, once it has read the full initial +connection data from the client. If the connection should be +accepted ClientAuthorized() should return NULL, and otherwise should +return an error message string. +.LP +Accepting new connections happens internally to WaitForSomething(). +WaitForSomething() must call the DIX routine NextAvailableClient() +to create a client object. +Processing of the initial connection data will be handled by DIX. +Your OS layer must be able to map from a client +to whatever information your OS code needs to communicate +on the given byte stream to the client. +DIX uses this ClientPtr to refer to +the client from now on. The sample server uses the osPrivate field in +the ClientPtr to store the file descriptor for the socket, the +input and output buffers, and authorization information. +.LP +To initialize the methods you choose to allow clients to connect to +your server, main() calls the routine +.nf + + void CreateWellKnownSockets() +.fi +.LP +This routine is called only once, and not called when the server +is reset. To recreate any sockets during server resets, the following +routine is called from the main loop: +.nf + + void ResetWellKnownSockets() +.fi +Sample implementations of both of these routines are found in +Xserver/os/connection.c. +.LP +For more details, see the section called "Connection Setup" in the X protocol specification. + +.NH 2 +Reading Data from Clients +.XS +Reading Data from Clients +.XE +.LP +Requests from the client are read in as a byte stream by the OS layer. +They may be in the form of several blocks of bytes delivered in sequence; requests may +be broken up over block boundaries or there may be many requests per block. +Each request carries with it length information. +It is the responsibility of the following routine to break it up into request blocks. +.nf + + int ReadRequestFromClient(who) + ClientPtr who; +.fi +.LP +You must write +the routine ReadRequestFromClient() to get one request from the byte stream +belonging to client "who." +You must swap the third and fourth bytes (the second 16-bit word) according to the +byte-swap rules of +the protocol to determine the length of the +request. +This length is measured in 32-bit words, not in bytes. Therefore, the +theoretical maximum request is 256K. +(However, the maximum length allowed is dependent upon the server's input +buffer. This size is sent to the client upon connection. The maximum +size is the constant MAX_REQUEST_SIZE in Xserver/include/os.h) +The rest of the request you return is +assumed NOT to be correctly swapped for internal +use, because that is the responsibility of DIX. +.LP +The 'who' argument is the ClientPtr returned from WaitForSomething. +The return value indicating status should be set to the (positive) byte count if the read is successful, +0 if the read was blocked, or a negative error code if an error happened. +.LP +You must then store a pointer to +the bytes of the request in the client request buffer field; +who->requestBuffer. This can simply be a pointer into your buffer; +DIX may modify it in place but will not otherwise cause damage. +Of course, the request must be contiguous; you must +shuffle it around in your buffers if not. + +The sample server implementation is in Xserver/os/io.c. + +.XS +Inserting Data for Clients +.XE +.LP +DIX can insert data into the client stream, and can cause a "replay" of +the current request. +.nf + + Bool InsertFakeRequest(client, data, count) + ClientPtr client; + char *data; + int count; + + int ResetCurrentRequest(client) + ClientPtr client; +.fi +.LP +InsertFakeRequest() must insert the specified number of bytes of data +into the head of the input buffer for the client. This may be a +complete request, or it might be a partial request. For example, +NextAvailableCient() will insert a partial request in order to read +the initial connection data sent by the client. The routine returns FALSE +if memory could not be allocated. ResetCurrentRequest() +should "back up" the input buffer so that the currently executing request +will be reexecuted. DIX may have altered some values (e.g. the overall +request length), so you must recheck to see if you still have a complete +request. ResetCurrentRequest() should always cause a yield (isItTimeToYield). + +.NH 2 +Sending Events, Errors And Replies To Clients +.XS +Sending Events, Errors And Replies To Clients +.XE +.LP +.nf + + int WriteToClient(who, n, buf) + ClientPtr who; + int n; + char *buf; +.fi +WriteToClient should write n bytes starting at buf to the +ClientPtr "who". +It returns the number of bytes written, but for simplicity, +the number returned must be either the same value as the number +requested, or -1, signaling an error. +The sample server implementation is in Xserver/os/io.c. +.LP +.nf + void SendErrorToClient(client, majorCode, minorCode, resId, errorCode) + ClientPtr client; + unsigned int majorCode; + unsigned int minorCode; + XID resId; + int errorCode; +.fi +SendErrorToClient can be used to send errors back to clients, +although in most cases your request function should simply return +the error code, having set client->errorValue to the appropriate +error value to return to the client, and DIX will call this +function with the correct opcodes for you. +.LP +.nf + + void FlushAllOutput() + + void FlushIfCriticalOutputPending() + + void SetCriticalOutputPending() +.fi +These three routines may be implemented to support buffered or delayed +writes to clients, but at the very least, the stubs must exist. +FlushAllOutput() unconditionally flushes all output to clients; +FlushIfCriticalOutputPending() flushes output only if +SetCriticalOutputPending() has be called since the last time output +was flushed. +The sample server implementation is in Xserver/os/io.c and +actually ignores requests to flush output on a per-client basis +if it knows that there +are requests in that client's input queue. +.NH 2 +Font Support +.XS +Font Support +.XE +.LP +In the sample server, fonts are encoded in disk files or fetched from the +font server. +For disk fonts, there is one file per font, with a file name like +"fixed.pcf". Font server fonts are read over the network using the +X Font Server Protocol. The disk directories containing disk fonts and +the names of the font servers are listed together in the current "font path." + +In principle, you can put all your fonts in ROM or in RAM in your server. +You can put them all in one library file on disk. +You could generate them on the fly from stroke descriptions. By placing the +appropriate code in the Font Library, you will automatically export fonts in +that format both through the X server and the Font server. + +With the incorporation of font-server based fonts and the Speedo donation +from Bitstream, the font interfaces have been moved into a separate +library, now called the Font Library (../fonts/lib). These routines are +shared between the X server and the Font server, so instead of this document +specifying what you must implement, simply refer to the font +library interface specification for the details. All of the interface code to the Font +library is contained in dix/dixfonts.c +.NH 2 +Memory Management +.XS +Memory Management +.XE +.LP +Memory management is based on functions in the C runtime library. +Xalloc(), Xrealloc(), and Xfree() work just like malloc(), realloc(), +and free(), except that you can pass a null pointer to Xrealloc() to +have it allocate anew or pass a null pointer to Xfree() and nothing +will happen. The versions in the sample server also do some checking +that is useful for debugging. Consult a C runtime library reference +manual for more details. + +The macros ALLOCATE_LOCAL and DEALLOCATE_LOCAL are provided in +Xserver/include/os.h. These are useful if your compiler supports +alloca() (or some method of allocating memory from the stack); and are +defined appropriately on systems which support it. + +Treat memory allocation carefully in your implementation. Memory +leaks can be very hard to find and are frustrating to a user. An X +server could be running for days or weeks without being reset, just +like a regular terminal. If you leak a few dozen k per day, that will +add up and will cause problems for users that leave their workstations +on. + +.NH 2 +Client Scheduling +.XS +Client Scheduling +.XE +.LP +The X server +has the ability to schedule clients much like an operating system would, +suspending and restarting them without regard for the state of their input +buffers. This functionality allows the X server to suspend one client and +continue processing requests from other clients while waiting for a +long-term network activity (like loading a font) before continuing with the +first client. +.nf + Bool isItTimeToYield; +.fi +.LP +isItTimeToYield is a global variable you can set +if you want to tell +DIX to end the client's "time slice" and start paying attention to the next client. +After the current request is finished, DIX will move to the next client. +.LP +In the sample +server, ReadRequestFromClient() sets isItTimeToYield after +10 requests packets in a row are read from the same client. +.LP +This scheduling algorithm can have a serious effect upon performance when two +clients are drawing into their windows simultaneously. +If it allows one client to run until its request +queue is empty by ignoring isItTimeToYield, the client's queue may +in fact never empty and other clients will be blocked out. +On the other hand, if it switchs between different clients too quickly, +performance may suffer due to too much switching between contexts. +For example, if a graphics processor needs to be set up with drawing modes +before drawing, and two different clients are drawing with +different modes into two different windows, you may +switch your graphics processor modes so often that performance is impacted. +.LP +See the Strategies document for +heuristics on setting isItTimeToYield. +.LP +The following functions provide the ability to suspend request +processing on a particular client, resuming it at some later time: +.nf + + int IgnoreClient (who) + ClientPtr who; + + int AttendClient (who) + ClientPtr who; +.fi +Ignore client is responsible for pretending that the given client doesn't +exist. WaitForSomething should not return this client as ready for reading +and should not return if only this client is ready. AttendClient undoes +whatever IgnoreClient did, setting it up for input again. +.LP +Three functions support "process control" for X clients: +.nf + + Bool ClientSleep (client, function, closure) + ClientPtr client; + Bool (*function)(); + pointer closure; + +.fi +.LP +This suspends the current client (the calling routine is responsible for +making its way back to Dispatch()). No more X requests will be processed +for this client until ClientWakeup is called. +.nf + + Bool ClientSignal (client) + ClientPtr client; + +.fi +.LP +This function causes a call to the (*function) parameter passed to +ClientSleep to be queued on the work queue. This does not automatically +"wakeup" the client, but the function called is free to do so by calling: +.nf + + ClientWakeup (client) + ClientPtr client; + +.fi +.LP +This re-enables X request processing for the specified client. +.NH 2 +Other OS Functions +.XS +Other OS Functions +.XE +.LP +.nf + void + ErrorF(char *f, ...) + + void + FatalError(char *f, ...) + + void + Error(str) + char *str; +.fi +.LP +You should write these three routines to provide for diagnostic output +from the dix and ddx layers, although implementing them to produce no +output will not affect the correctness of your server. ErrorF() and +FatalError() take a printf() type of format specification in the first +argument and an implementation-dependent number of arguments following +that. Normally, the formats passed to ErrorF() and FatalError() +should be terminated with a newline. Error() provides an os interface +for printing out the string passed as an argument followed by a +meaningful explanation of the last system error. Normally the string +does not contain a newline, and it is only called by the ddx layer. +In the sample implementation, Error() uses the perror() function. +.LP +After printing the message arguments, FatalError() must be implemented +such that the server will call AbortDDX() to give the ddx layer +a chance to reset the hardware, and then +terminate the server; it must not return. +.LP +The sample server implementation for these routines +is in Xserver/os/util.c. +.NH 2 +Idiom Support +.XS +Idiom Support +.XE +.LP +The DBE specification introduces the notion of idioms, which are +groups of X requests which can be executed more efficiently when taken +as a whole compared to being performed individually and sequentially. +This following server internal support to allows DBE +implementations, as well as other parts of the server, +to do idiom processing. +.LP +.nf + + xReqPtr PeekNextRequest(xReqPtr req, ClientPtr client, Bool readmore) +.fi +.LP +If req is NULL, the return value will be a pointer to the start of the +complete request that follows the one currently being executed for the +client. If req is not NULL, the function assumes that req is a +pointer to a request in the client's request buffer, and the return +value will be a pointer to the the start of the complete request that +follows req. If the complete request is not available, the function +returns NULL; pointers to partial requests will never be returned. If +(and only if) readmore is TRUE, PeekNextRequest should try to read an +additional request from the client if one is not already available in +the client's request buffer. If PeekNextRequest reads more data into +the request buffer, it should not move or change the existing data. +.LP +.nf + + void SkipRequests(xReqPtr req, ClientPtr client, int numskipped) +.fi +.LP +The requests for the client up to and including the one specified by +req will be skipped. numskipped must be the number of requests being +skipped. Normal request processing will resume with the request that +follows req. The caller must not have modified the contents of the +request buffer in any way (e.g., by doing byte swapping in place). +.LP +Additionally, two macros in os.h operate on the xReq +pointer returned by PeekNextRequest: +.LP +.nf + + int ReqLen(xReqPtr req, ClientPtr client) +.fi +.LP +The value of ReqLen is the request length in bytes of the given xReq. +.LP +.nf + + otherReqTypePtr CastxReq(xReq *req, otherReqTypePtr) +.fi +.LP +The value of CastxReq is the conversion of the given request pointer +to an otherReqTypePtr (which should be a pointer to a protocol +structure type). Only those fields which come after the length field +of otherReqType may be accessed via the returned pointer. +.LP +Thus the first two fields of a request, reqType and data, can be +accessed directly using the xReq * returned by PeekNextRequest. The +next field, the length, can be accessed with ReqLen. Fields beyond +that can be accessed with CastxReq. This complexity was necessary +because of the reencoding of core protocol that can happen due to the +BigRequests extension. +.NH 1 +DDX LAYER +.XS +DDX LAYER +.XE +.LP +This section describes the +interface between DIX and DDX. +While there may be an OS-dependent driver interface between DDX +and the physical device, that interface is left to the DDX +implementor and is not specified here. +.LP +The DDX layer does most of its work through procedures that are +pointed to by different structs. +As previously described, the behavior of these resources is largely determined by +these procedure pointers. +Most of these routines are for graphic display on the screen or support functions thereof. +The rest are for user input from input devices. + +.NH 2 +INPUT +.XS +INPUT +.XE +.LP +In this document "input" refers to input from the user, +such as mouse, keyboard, and +bar code readers. +X input devices are of several types: keyboard, pointing device, and +many others. The core server has support for extension devices as +described by the X Input Extension document; the interfaces used by +that extension are described elsewhere. The core devices are actually +implemented as two collections of devices, the mouse is a ButtonDevice, +a ValuatorDevice and a PtrFeedbackDevice while the keyboard is a KeyDevice, +a FocusDevice and a KbdFeedbackDevice. Each part implements a portion of +the functionality of the device. This abstraction is hidden from view for +core devices by DIX. + +You, the DDX programmer, are +responsible for some of the routines in this section. +Others are DIX routines that you should call to do the things you need to do in these DDX routines. +Pay attention to which is which. + +.NH 3 +Input Device Data Structures +.XS +Input Device Data Structures +.XE +.LP +DIX keeps a global directory of devices in a central data structure +called InputInfo. +For each device there is a device structure called a DeviceRec. +DIX can locate any DeviceRec through InputInfo. +In addition, it has a special pointer to identify the main pointing device +and a special pointer to identify the main keyboard. +.LP +The DeviceRec (Xserver/include/input.h) is a device-independent +structure that contains the state of an input device. +A DevicePtr is simply a pointer to a DeviceRec. +.LP +An xEvent describes an event the server reports to a client. +Defined in Xproto.h, it is a huge struct of union of structs that have fields for +all kinds of events. +All of the variants overlap, so that the struct is actually very small in memory. + +.NH 3 +Processing Events +.XS +Processing Events +.XE +.LP +The main DDX input interface is the following routine: +.nf + + void ProcessInputEvents() +.fi +You must write this routine to deliver input events from the user. +DIX calls it when input is pending (see next section), and possibly +even when it is not. +You should write it to get events from each device and deliver +the events to DIX. +To deliver the events to DIX, DDX should call the following +routine: +.nf + + void DevicePtr->processInputProc(pEvent, device, count) + xEventPtr events; + DeviceIntPtr device; + int count; +.fi +This is the "input proc" for the device, a DIX procedure. +DIX will fill in this procedure pointer to one of its own routines by +the time ProcessInputEvents() is called the first time. +Call this input proc routine as many times as needed to +deliver as many events as should be delivered. +DIX will buffer them up and send them out as needed. Count is set +to the number of event records which make up one atomic device event and +is always 1 for the core devices (see the X Input Extension for descriptions +of devices which may use count > 1). + +For example, your ProcessInputEvents() routine might check the mouse and the +keyboard. +If the keyboard had several keystrokes queued up, it could just call +the keyboard's processInputProc as many times as needed to flush its internal queue. + +event is an xEvent struct you pass to the input proc. +When the input proc returns, it is finished with the event rec, and you can fill +in new values and call the input proc again with it. + +You should deliver the events in the same order that they were generated. + +For keyboard and pointing devices the xEvent variant should be keyButtonPointer. +Fill in the following fields in the xEvent record: +.nf + + type is one of the following: KeyPress, KeyRelease, ButtonPress, + ButtonRelease, or MotionNotify + detail for KeyPress or KeyRelease fields, this should be the + key number (not the ASCII code); otherwise unused + time is the time that the event happened (32-bits, in milliseconds, arbitrary origin) + rootX is the x coordinate of cursor + rootY is the y coordinate of cursor + +.fi +The rest of the fields are filled in by DIX. +.LP +The time stamp is maintained by your code in the DDX layer, and it is your responsibility to +stamp all events correctly. +.LP +The x and y coordinates of the pointing device and the time must be filled in for all event types +including keyboard events. +.LP +The pointing device must report all button press and release events. +In addition, it should report a MotionNotify event every time it gets called +if the pointing device has moved since the last notify. +Intermediate pointing device moves are stored in a special GetMotionEvents buffer, +because most client programs are not interested in them. + +There are quite a collection of sample implementations of this routine, +one for each supported device. + +.NH 3 +Telling DIX When Input is Pending +.XS +Telling DIX When Input is Pending +.XE +.LP +In the server's dispatch loop, DIX checks to see +if there is any device input pending whenever WaitForSomething() returns. +If the check says that input is pending, DIX calls the +DDX routine ProcessInputEvents(). +.LP +This check for pending input must be very quick; a procedure call +is too slow. +The code that does the check is a hardwired IF +statement in DIX code that simply compares the values +pointed to by two pointers. +If the values are different, then it assumes that input is pending and +ProcessInputEvents() is called by DIX. +.LP +You must pass pointers to DIX to tell it what values to compare. +The following procedure +is used to set these pointers: +.nf + + void SetInputCheck(p1, p2) + long *p1, *p2; +.fi +.LP +You should call it sometime during initialization to indicate to DIX the +correct locations to check. +You should +pay special attention to the size of what they actually point to, +because the locations are assumed to be longs. + +These two pointers are initialized by DIX +to point to arbitrary values that +are different. +In other words, if you forget to call this routine during initialization, +the worst thing that will happen is that +ProcessInputEvents will be called when +there are no events to process. + +p1 and p2 might +point at the head and tail of some shared +memory queue. +Another use would be to have one point at a constant 0, with the +other pointing at some mask containing 1s +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 is initialized. +It passes pointers to the queue's head and tail. See Xserver/mi/mieq.c. + +.nf + int TimeSinceLastInputEvent() +.fi +DDX must time stamp all hardware input +events. But DIX sometimes needs to know the +time and the OS layer needs to know the time since the last hardware +input event in +order for the screen saver to work. TimeSinceLastInputEvent() returns +the this time in milliseconds. + +.NH 3 +Controlling Input Devices +.XS +Controlling Input Devices +.XE +.LP +You must write four routines to do various device-specific +things with the keyboard and pointing device. +They can have any name you wish because +you pass the procedure pointers to DIX routines. + +.nf + + int pInternalDevice->valuator->GetMotionProc(pdevice, coords, start, stop, pScreen) + DeviceIntPtr pdevice; + xTimecoord * coords; + unsigned long start; + unsigned long stop; + ScreenPtr pScreen; +.fi +You write this DDX routine to fill in coords with all the motion +events that have times (32-bit count of milliseconds) between time +start and time stop. It should return the number of motion events +returned. If there is no motion events support, this routine should +do nothing and return zero. The maximum number of coords to return is +set in InitPointerDeviceStruct(), below. + +When the user drags the pointing device, the cursor position +theoretically sweeps through an infinite number of points. Normally, +a client that is concerned with points other than the starting and +ending points will receive a pointer-move event only as often as the +server generates them. (Move events do not queue up; each new one +replaces the last in the queue.) A server, if desired, can implement +a scheme to save these intermediate events in a motion buffer. A +client application, like a paint program, may then request that these +events be delivered to it through the GetMotionProc routine. +.nf + + void pInternalDevice->bell->BellProc(percent, pDevice, ctrl, unknown) + int percent; + DeviceIntPtr pDevice; + pointer ctrl; + int class; +.fi +You need to write this routine to ring the bell on the keyboard. +loud is a number from 0 to 100, with 100 being the loudest. +Class is either BellFeedbackClass or KbdFeedbackClass (from XI.h). +.nf + + void pInternalDevice->somedevice->CtrlProc(device, ctrl) + DevicePtr device; + SomethingCtrl *ctrl; + +.fi +.LP +You write two versions of this procedure, one for the keyboard and one for the pointing device. +DIX calls it to inform DDX when a client has requested changes in the current +settings for the particular device. +For a keyboard, this might be the repeat threshold and rate. +For a pointing device, this might be a scaling factor (coarse or fine) for position reporting. +See input.h for the ctrl structures. + +.NH 3 +Input Initialization +.XS +Input Initialization +.XE +.LP +Input initialization is a bit complicated. +It all starts with InitInput(), a routine that you write to call +AddInputDevice() twice +(once for pointing device and once for keyboard.) +You also want to call RegisterKeyboardDevice() and RegisterPointerDevice() +on them. + +When you Add the devices, a routine you supply for each device +gets called to initialize them. +Your individual initialize routines must call InitKeyboardDeviceStruct() +or InitPointerDeviceStruct(), depending upon which it is. +In other words, you indicate twice that the keyboard is the keyboard and +the pointer is the pointer. +.nf + + void InitInput(argc, argv) + int argc; + char **argv; +.fi +.LP +InitInput is a DDX routine you must write to initialize the +input subsystem in DDX. +It must call AddInputDevice() for each device that might generate events. +In addition, you must register the main keyboard and pointing devices by +calling RegisterPointerDevice() and RegisterKeyboardDevice(). +.nf + + DevicePtr AddInputDevice(deviceProc, autoStart) + DeviceProc deviceProc; + Bool autoStart; +.fi +.LP +AddInputDevice is a DIX routine you call to create a device object. +deviceProc is a DDX routine that is called by DIX to do various operations. +AutoStart should be TRUE for devices that need to be turned on at +initialization time with a special call, as opposed to waiting for some +client application to +turn them on. +This routine returns NULL if sufficient memory cannot be allocated to +install the device. + +Note also that except for the main keyboard and pointing device, +an extension is needed to provide for a client interface to a device. +.nf + + void RegisterPointerDevice(device) + DevicePtr device; +.fi +.LP +RegisterPointerDevice is a DIX routine that your DDX code calls that +makes that device the main pointing device. +This routine is called once upon initialization and cannot be called again. +.nf + + void RegisterKeyboardDevice(device) + DevicePtr device; +.fi +.LP +RegisterKeyboardDevice makes the given device the main keyboard. +This routine is called once upon initialization and cannot be called again. + +The following DIX +procedures return the specified DevicePtr. They may or may not be useful +to DDX implementors. +.nf + + DevicePtr LookupKeyboardDevice() +.fi +.LP +LookupKeyboardDevice returns pointer for current main keyboard device. +.nf + + DevicePtr LookupPointerDevice() +.fi +.LP +LookupPointerDevice returns pointer for current main pointing device. + +.LP +A DeviceProc (the kind passed to AddInputDevice()) in the following form: +.nf + + Bool pInternalDevice->DeviceProc(device, action); + DeviceIntPtr device; + int action; +.fi +.LP +You must write a DeviceProc for each device. +device points to the device record. +action tells what action to take; +it will be one of these defined constants (defined in input.h): +.IP \(bu 5 +DEVICE_INIT - +At DEVICE_INIT time, the device should initialize itself by calling +InitPointerDeviceStruct(), InitKeyboardDeviceStruct(), or a similar +routine (see below) +and "opening" the device if necessary. +If you return a non-zero (i.e., != Success) value from the DEVICE_INIT +call, that device will be considered unavailable. If either the main keyboard +or main pointing device cannot be initialized, the DIX code will refuse +to continue booting up. +.IP \(bu 5 +DEVICE_ON - If the DeviceProc is called with DEVICE_ON, then it is +allowed to start +putting events into the client stream by calling through the ProcessInputProc +in the device. +.IP \(bu 5 +DEVICE_OFF - If the DeviceProc is called with DEVICE_OFF, no further +events from that +device should be given to the DIX layer. +The device will appear to be dead to the user. +.IP \(bu 5 +DEVICE_CLOSE - At DEVICE_CLOSE (terminate or reset) time, the device should +be totally closed down. +.nf + + void InitPointerDeviceStruct(device, map, mapLength, + GetMotionEvents, ControlProc, numMotionEvents) + DevicePtr device; + CARD8 *map; + int mapLength; + ValuatorMotionProcPtr ControlProc; + PtrCtrlProcPtr GetMotionEvents; + int numMotionEvents; +.fi +InitPointerDeviceStruct is a DIX routine you call at DEVICE_INIT time to declare +some operating routines and data structures for a pointing device. +map and mapLength are as described in the X Window +System protocol specification. +ControlProc and GetMotionEvents are DDX routines, see above. + +numMotionEvents is for the motion-buffer-size for the GetMotionEvents +request. +A typical length for a motion buffer would be 100 events. +A server that does not implement this capability should set +numMotionEvents to zero. +.nf + + void InitKeyboardDeviceStruct(device, pKeySyms, pModifiers, Bell, ControlProc) + DevicePtr device; + KeySymsPtr pKeySyms; + CARD8 *pModifiers; + BellProcPtr Bell; + KbdCtrlProcPtr ControlProc; + +.fi +You call this DIX routine when a keyboard device is initialized and +its device procedure is called with +DEVICE_INIT. +The formats of the keysyms and modifier maps are defined in +Xserver/include/input.h. +They describe the layout of keys on the keyboards, and the glyphs +associated with them. ( See the next section for information on +setting up the modifier map and the keysym map.) +ControlProc and Bell are DDX routines, see above. + +.NH 3 +Keyboard Mapping and Keycodes +.XS +Keyboard Mapping and Keycodes +.XE +.LP +When you send a keyboard event, you send a report that a given key has +either been pressed or has been released. There must be a keycode for +each key that identifies the key; the keycode-to-key mapping can be +any mapping you desire, because you specify the mapping in a table you +set up for DIX. However, you are restricted by the protocol +specification to keycode values in the range 8 to 255 inclusive. + +The keycode mapping information that you set up consists of the following: +.IP \(bu 5 +A minimum and maximum keycode number +.IP \(bu 5 +An array of sets of keysyms for each key, that is of length +maxkeycode - minkeycode + 1. +Each element of this array is a list of codes for symbols that are on that key. +There is no limit to the number of symbols that can be on a key. +.LP +Once the map is set up, DIX keeps and +maintains the client's changes to it. + +The X protocol defines standard names to indicate the symbol(s) +printed on each keycap. (See X11/keysym.h) + +Legal modifier keys must generate both up and down transitions. When +a client tries to change a modifier key (for instance, to make "A" the +"Control" key), DIX calls the following routine, which should retuurn +TRUE if the key can be used as a modifier on the given device: +.nf + + Bool LegalModifier(key, pDev) + unsigned int key; + DevicePtr pDev; +.fi +.NH 2 +Screens +.XS +Screens +.XE +.LP +Different computer graphics +displays have different capabilities. +Some are simple monochrome +frame buffers that are just lying +there in memory, waiting to be written into. +Others are color displays with many bits per pixel using some color lookup table. +Still others have high-speed graphic processors that prefer to do all of the work +themselves, +including maintaining their own high-level, graphic data structures. + +.NH 3 +Screen Hardware Requirements +.XS +Screen Hardware Requirements +.XE +.LP +The only requirement on screens is that you be able to both read +and write locations in the frame buffer. +All screens must have a depth of 32 or less (unless you use +an X extension to allow a greater depth). +All screens must fit into one of the classes listed in the section +in this document on Visuals and Depths. +.LP +X uses the pixel as its fundamental unit of distance on the screen. +Therefore, most programs will measure everything in pixels. +.LP +The sample server assumes square pixels. +Serious WYSIWYG (what you see is what you get) applications for +publishing and drawing programs will adjust for +different screen resolutions automatically. +Considerable work +is involved in compensating for non-square pixels (a bit in the DDX +code for the sample server but quite a bit in the client applications). + +.NH 3 +Data Structures +.XS +Data Structures +.XE +.LP +X supports multiple screens that are connected to the same +server. Therefore, all the per-screen information is bundled into one data +structure of attributes and procedures, which is the ScreenRec (see +Xserver/include/scrnintstr.h). +The procedure entry points in a ScreenRec operate on +regions, colormaps, cursors, and fonts, because these resources +can differ in format from one screen to another. + +Windows are areas on the screen that can be drawn into by graphic +routines. "Pixmaps" are off-screen graphic areas that can be drawn +into. They are both considered drawables and are described in the +section on Drawables. All graphic operations work on drawables, and +operations are available to copy patches from one drawable to another. + +The pixel image data in all drawables is in a format that is private +to DDX. In fact, each instance of a drawable is associated with a +given screen. Presumably, the pixel image data for pixmaps is chosen +to be conveniently understood by the hardware. All screens in a +single server must be able to handle all pixmaps depths declared in +the connection setup information. +.LP +Pixmap images are transferred to the server in one of two ways: +XYPixmap or ZPimap. XYPixmaps are a series of bitmaps, one for each +bit plane of the image, using the bitmap padding rules from the +connection setup. ZPixmaps are a series of bits, nibbles, bytes or +words, one for each pixel, using the format rules (padding and so on) +for the appropriate depth. +.LP +All screens in a given server must agree on a set of pixmap image +formats (PixmapFormat) to support (depth, number of bits per pixel, +etc.). +.LP +There is no color interpretation of bits in the pixmap. Pixmaps +do not contain pixel values. The interpretation is made only when +the bits are transferred onto the screen. +.LP +The screenInfo structure (in scrnintstr.h) is a global data structure +that has a pointer to an array of ScreenRecs, one for each screen on +the server. (These constitute the one and only description of each +screen in the server.) Each screen has an identifying index (0, 1, 2, ...). +In addition, the screenInfo struct contains global server-wide +details, 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 all screens on the server. + +.NH 3 +Output Initialization +.XS +Output Initialization +.XE +.LP +.nf + + InitOutput(pScreenInfo, argc, argv) + ScreenInfo *pScreenInfo; + int argc; + char **argv; +.fi +Upon initialization, your DDX routine InitOutput() is called by DIX. +It is passed a pointer to screenInfo to initialize. It is also passed +the argc and argv from main() for your server for the command-line +arguments. These arguments may indicate what or how many screen +device(s) to use or in what way to use them. For instance, your +server command line may allow a "-D" flag followed by the name of the +screen device to use. + +Your InitOutput() routine should initialize each screen you wish to +use by calling AddScreen(), and then it should initialize the pixmap +formats that you support by storing values directly into the +screenInfo data structure. You should also set certain +implementation-dependent numbers and procedures in your screenInfo, +which determines the pixmap and scanline padding rules for all screens +in the server. +.nf + + int AddScreen(scrInitProc, argc, argv) + Bool (*scrInitProc)(); + int argc; + char **argv; +.fi +You should call AddScreen(), a DIX procedure, in InitOutput() once for +each screen to add it to the screenInfo database. The first argument +is an initialization procedure for the screen that you supply. The +second and third are the argc and argv from main(). It returns the +screen number of the screen installed, or -1 if there is either +insufficient memory to add the screen, or (*scrInitProc) returned +FALSE. + +The scrInitProc should be of the following form: +.nf + + Bool scrInitProc(iScreen, pScreen, argc, argv) + int iScreen; + ScreenPtr pScreen; + int argc; + char **argv; +.fi +iScreen is the index for this screen; 0 for the first one initialized, +1 for the second, etc. pScreen is the pointer to the screen's new +ScreenRec. argc and argv are as before. Your screen initialize +procedure should return TRUE upon success or FALSE if the screen +cannot be initialized (for instance, if the screen hardware does not +exist on this machine). + +This procedure must determine what actual device it is supposed to initialize. +If you have a different procedure for each screen, then it is no problem. +If you have the same procedure for multiple screens, it may have trouble +figuring out which screen to initialize each time around, especially if +InitOutput() does not initialize all of the screens. +It is probably easiest to have one procedure for each screen. + +The initialization procedure should fill in all the screen procedures +for that screen (windowing functions, region functions, etc.) and certain +screen attributes for that screen. + +.NH 3 +Region Routines in the ScreenRec +.XS +Region Routines in the ScreenRec +.XE +.LP +A region is a dynamically allocated data structure that describes an +irregularly shaped piece of real estate in XY pixel space. You can +think of it as a set of pixels on the screen to be operated upon with +set operations such as AND and OR. +.LP +A region is frequently implemented as a list of rectangles or bitmaps +that enclose the selected pixels. Region operators control the +"clipping policy," or the operations that work on regions. (The +sample server uses YX-banded rectangles. Unless you have something +already implemented for your graphics system, you should keep that +implementation.) The procedure pointers to the region operators are +located in the ScreenRec data structure. The definition of a region +can be found in the file Xserver/include/regionstr.h. The region code +is found in Xserver/mi/miregion.c. DDX implementations using other +region formats will need to supply different versions of the region +operators. + +Since the list of rectangles is unbounded in size, part of the region +data structure is usually a large, dynamically allocated chunk of +memory. As your region operators calculate logical combinations of +regions, these blocks may need to be reallocated by your region +software. For instance, in the sample server, a RegionRec has some +header information and a pointer to a dynamically allocated rectangle +list. Periodically, the rectangle list needs to be expanded with +Xrealloc(), whereupon the new pointer is remembered in the RegionRec. + +Most of the region operations come in two forms: a function pointer in +the Screen structure, and a macro. The server can be compiled so that +the macros make direct calls to the appropriate functions (instead of +indirecting through a screen function pointer), or it can be compiled +so that the macros are identical to the function pointer forms. +Making direct calls is faster on many architectures. +.nf + + RegionPtr pScreen->RegionCreate( rect, size) + BoxPtr rect; + int size; + + macro: RegionPtr REGION_CREATE(pScreen, rect, size) + +.fi +RegionCreate creates a region that describes ONE rectangle. The +caller can avoid unnecessary reallocation and copying by declaring the +probable maximum number of rectangles that this region will need to +describe itself. Your region routines, though, cannot fail just +because the region grows beyond this size. The caller of this routine +can pass almost anything as the size; the value is merely a good guess +as to the maximum size until it is proven wrong by subsequent use. +Your region procedures are then on their own in estimating how big the +region will get. Your implementation might ignore size, if +applicable. +.nf + + void pScreen->RegionInit (pRegion, rect, size) + RegionPtr pRegion; + BoxPtr rect; + int size; + + macro: REGION_INIT(pScreen, pRegion, rect, size) + +.fi +Given an existing raw region structure (such as an local variable), this +routine fills in the appropriate fields to make this region as usable as +one returned from RegionCreate. This avoids the additional dynamic memory +allocation overhead for the region structure itself. +.nf + + Bool pScreen->RegionCopy(dstrgn, srcrgn) + RegionPtr dstrgn, srcrgn; + + macro: Bool REGION_COPY(pScreen, dstrgn, srcrgn) + +.fi +RegionCopy copies the description of one region, srcrgn, to another +already-created region, +dstrgn; returning TRUE if the copy succeeded, and FALSE otherwise. +.nf + + void pScreen->RegionDestroy( pRegion) + RegionPtr pRegion; + + macro: REGION_DESTROY(pScreen, pRegion) + +.fi +RegionDestroy destroys a region and frees all allocated memory. +.nf + + void pScreen->RegionUninit (pRegion) + RegionPtr pRegion; + + macro: REGION_UNINIT(pScreen, pRegion) + +.fi +Frees everything except the region structure itself, useful when the +region was originally passed to RegionInit instead of received from +RegionCreate. When this call returns, pRegion must not be reused until +it has been RegionInit'ed again. +.nf + + 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) + +.fi +The above four calls all do basic logical operations on regions. They +set the new region (which already exists) to describe the logical +intersection, union, set difference, or inverse of the region(s) that +were passed in. Your routines must be able to handle a situation +where the newReg is the same region as one of the other region +arguments. + +The subtract function removes the Subtrahend from the Minuend and +puts the result in newReg. + +The inverse function returns a region that is the pBox minus the +region passed in. (A true "inverse" would make a region that extends +to infinity in all directions but has holes in the middle.) It is +undefined for situations where the region extends beyond the box. + +Each routine must return the value TRUE for success. +.nf + + void pScreen->RegionReset(pRegion, pBox) + RegionPtr pRegion; + BoxPtr pBox; + + macro: REGION_RESET(pScreen, pRegion, pBox) + +.fi +RegionReset sets the region to describe +one rectangle and reallocates it to a size of one rectangle, if applicable. +.nf + + void pScreen->TranslateRegion(pRegion, x, y) + RegionPtr pRegion; + int x, y; + + macro: REGION_TRANSLATE(pScreen, pRegion, x, y) + +.fi +TranslateRegion simply moves a region +x in the x direction and +y in the y +direction. +.nf + + int pScreen->RectIn(pRegion, pBox) + RegionPtr pRegion; + BoxPtr pBox; + + macro: int RECT_IN_REGION(pScreen, pRegion, pBox) + +.fi +RectIn returns one of the defined constants rgnIN, rgnOUT, or rgnPART, +depending upon whether the box is entirely inside the region, entirely +outside of the region, or partly in and partly out of the region. +These constants are defined in Xserver/include/region.h. +.nf + + Bool pScreen->PointInRegion(pRegion, x, y, pBox) + RegionPtr pRegion; + int x, y; + BoxPtr pBox; + + macro: Bool POINT_IN_REGION(pScreen, pRegion, x, y, pBox) + +.fi +PointInRegion returns true if the point x, y is in the region. In +addition, it fills the rectangle pBox with coordinates of a rectangle +that is entirely inside of pRegion and encloses the point. In the mi +implementation, it is the largest such rectangle. (Due to the sample +server implementation, this comes cheaply.) + +This routine used by DIX when tracking the pointing device and +deciding whether to report mouse events or change the cursor. For +instance, DIX needs to change the cursor when it moves from one window +to another. Due to overlapping windows, the shape to check may be +irregular. A PointInRegion() call for every pointing device movement +may be too expensive. The pBox is a kind of wake-up box; DIX need not +call PointInRegion() again until the cursor wanders outside of the +returned box. +.nf + + Bool pScreen->RegionNotEmpty(pRegion) + RegionPtr pRegion; + + macro: Bool REGION_NOTEMPTY(pScreen, pRegion) + +.fi +RegionNotEmpty is a boolean function that returns +true or false depending upon whether the region encloses any pixels. +.nf + + void pScreen->RegionEmpty(pRegion) + RegionPtr pRegion; + + macro: REGION_EMPTY(pScreen, pRegion) + +.fi +RegionEmpty sets the region to be empty. +.nf + + BoxPtr pScreen->RegionExtents(pRegion) + RegionPtr pRegion; + + macro: REGION_EXTENTS(pScreen, pRegion) + +.fi +RegionExtents returns a rectangle that is the smallest +possible superset of the entire region. +The caller will not modify this rectangle, so it can be the one +in your region struct. +.nf + + 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) + +.fi +These functions provide an optimization for clip list generation and +must be used in conjunction. The combined effect is to produce the +union of a collection of regions, by using RegionAppend several times, +and finally calling RegionValidate which takes the intermediate +representation (which needn't be a valid region) and produces the +desired union. pOverlap is set to TRUE if any of the original +regions overlap; FALSE otherwise. +.nf + + RegionPtr pScreen->BitmapToRegion (pPixmap) + PixmapPtr pPixmap; + + macro: RegionPtr BITMAP_TO_REGION(pScreen, pPixmap) + +.fi +Given a depth-1 pixmap, this routine must create a valid region which +includes all the areas of the pixmap filled with 1's and excludes the +areas filled with 0's. This routine returns NULL if out of memory. +.nf + + RegionPtr pScreen->RectsToRegion (nrects, pRects, ordering) + int nrects; + xRectangle *pRects; + int ordering; + + macro: RegionPtr RECTS_TO_REGION(pScreen, nrects, pRects, ordering) + +.fi +Given a client-supplied list of rectangles, produces a region which includes +the union of all the rectangles. Ordering may be used as a hint which +describes how the rectangles are sorted. As the hint is provided by a +client, it must not be required to be correct, but the results when it is +not correct are not defined (core dump is not an option here). +.nf + + void pScreen->SendGraphicsExpose(client,pRegion,drawable,major,minor) + ClientPtr client; + RegionPtr pRegion; + XID drawable; + int major; + int minor; + +.fi +SendGraphicsExpose dispatches a list of GraphicsExposure events which +span the region to the specified client. If the region is empty, or +a NULL pointer, a NoExpose event is sent instead. +.NH 3 +Cursor Routines for a Screen +.XS +Cursor Routines for a Screen +.XE +.LP +A cursor is the visual form tied to the pointing device. The default +cursor is an "X" shape, but the cursor can have any shape. When a +client creates a window, it declares what shape the cursor will be +when it strays into that window on the screen. + +For each possible shape the cursor assumes, there is a CursorRec data +structure. This data structure contains a pointer to a CursorBits +data structure which contains a bitmap for the image of the cursor and +a bitmap for a mask behind the cursor, in addition, the CursorRec data +structure contains foreground and background colors for the cursor. +The CursorBits data structure is shared among multiple CursorRec +structures which use the same font and glyph to describe both source +and mask. The cursor image is applied to the screen by applying the +mask first, clearing 1 bits in its form to the background color, and +then overwriting on the source image, in the foreground color. (One +bits of the source image that fall on top of zero bits of the mask +image are undefined.) This way, a cursor can have transparent parts, +and opaque parts in two colors. X allows any cursor size, but some +hardware cursor schemes allow a maximum of N pixels by M pixels. +Therefore, you are allowed to transform the cursor to a smaller size, +but be sure to include the hot-spot. + +CursorBits in Xserver/include/cursorstr.h is a device-independent +structure containing a device-independent representation of the bits +for the source and mask. (This is possible because the bitmap +representation is the same for all screens.) + +When a cursor is created, it is "realized" for each screen. At +realization time, each screen has the chance to convert the bits into +some other representation that may be more convenient (for instance, +putting the cursor into off-screen memory) and set up its +device-private area in either the CursorRec data structure or +CursorBits data structure as appropriate to possibly point to whatever +data structures are needed. It is more memory-conservative to share +realizations by using the CursorBits private field, but this makes the +assumption that the realization is independent of the colors used +(which is typically true). For instance, the following are the device +private entries for a particular screen and cursor: +.nf + + pCursor->devPriv[pScreen->myNum] + pCursor->bits->devPriv[pScreen->myNum] + +.fi +This is done because the change from one cursor shape to another must +be fast and responsive; the cursor image should be able to flutter as +fast as the user moves it across the screen. + +You must implement the following routines for your hardware: +.nf + + Bool pScreen->RealizeCursor( pScr, pCurs) + ScreenPtr pScr; + CursorPtr pCurs; + + Bool pScreen->UnrealizeCursor( pScr, pCurs) + ScreenPtr pScr; + CursorPtr pCurs; + +.fi +RealizeCursor and UnrealizeCursor should realize (allocate and +calculate all data needed) and unrealize (free the dynamically +allocated data) a given cursor when DIX needs them. They are called +whenever a device-independent cursor is created or destroyed. The +source and mask bits pointed to by fields in pCurs are undefined for +bits beyond the right edge of the cursor. This is so because the bits +are in Bitmap format, which may have pad bits on the right edge. You +should inhibit UnrealizeCursor() if the cursor is currently in use; +this happens when the system is reset. +.nf + + Bool pScreen->DisplayCursor( pScr, pCurs) + ScreenPtr pScr; + CursorPtr pCurs; + +.fi +DisplayCursor should change the cursor on the given screen to the one +passed in. It is called by DIX when the user moves the pointing +device into a different window with a different cursor. The hotspot +in the cursor should be aligned with the current cursor position. +.nf + + void pScreen->RecolorCursor( pScr, pCurs, displayed) + ScreenPtr pScr; + CursorPtr pCurs; + Bool displayed; +.fi +.LP +RecolorCursor notifies DDX that the colors in pCurs have changed and +indicates whether this is the cursor currently being displayed. If it +is, the cursor hardware state may have to be updated. Whether +displayed or not, state created at RealizeCursor time may have to be +updated. A generic version, miRecolorCursor, may be used that +does an unrealize, a realize, and possibly a display (in micursor.c); +however this constrains UnrealizeCursor and RealizeCursor to always return +TRUE as no error indication is returned here. +.nf + + void pScreen->ConstrainCursor( pScr, pBox) + ScreenPtr pScr; + BoxPtr pBox; + +.fi +ConstrainCursor should cause the cursor to restrict its motion to the +rectangle pBox. DIX code is capable of enforcing this constraint by +forcefully moving the cursor if it strays out of the rectangle, but +ConstrainCursor offers a way to send a hint to the driver or hardware +if such support is available. This can prevent the cursor from +wandering out of the box, then jumping back, as DIX forces it back. +.nf + + void pScreen->PointerNonInterestBox( pScr, pBox) + ScreenPtr pScr; + BoxPtr pBox; + +.fi +PointerNonInterestBox is DIX's way of telling the pointing device code +not to report motion events while the cursor is inside a given +rectangle on the given screen. It is optional and, if not +implemented, it should do nothing. This routine is called only when +the client has declared that it is not interested in motion events in +a given window. The rectangle you get may be a subset of that window. +It saves DIX code the time required to discard uninteresting mouse +motion events. This is only a hint, which may speed performance. +Nothing in DIX currently calls PointerNonInterestBox. +.nf + + void pScreen->CursorLimits( pScr, pCurs, pHotBox, pTopLeftBox) + ScreenPtr pScr; + CursorPtr pCurs; + BoxPtr pHotBox; + BoxPtr pTopLeftBox; /* return value */ + +.fi +.LP +CursorLimits should calculate the box that the cursor hot spot is +physically capable of moving within, as a function of the screen pScr, +the device-independent cursor pCurs, and a box that DIX hypothetically +would want the hot spot confined within, pHotBox. This routine is for +informing DIX only; it alters no state within DDX. +.nf + + Bool pScreen->SetCursorPosition( pScr, newx, newy, generateEvent) + ScreenPtr pScr; + int newx; + int newy; + Bool generateEvent; + +.fi +.LP +SetCursorPosition should artificially move the cursor as though the +user had jerked the pointing device very quickly. This is called in +response to the WarpPointer request from the client, and at other +times. If generateEvent is True, the device should decide whether or +not to call ProcessInputEvents() and then it must call +DevicePtr->processInputProc. Its effects are, of course, limited in +value for absolute pointing devices such as a tablet. +.nf + + void NewCurrentScreen(newScreen, x, y) + ScreenPtr newScreen; + int x,y; + +.fi +.LP +If your ddx provides some mechanism for the user to magically move the +pointer between multiple screens, you need to inform DIX when this +occurs. You should call NewCurrentScreen to accomplish this, specifying +the new screen and the new x and y coordinates of the pointer on that screen. + +.NH 3 +Visuals, Depths and Pixmap Formats for Screens +.XS +Visuals, Depths and Pixmap Formats for Screens +.XE +.LP +The "depth" of a image is the number of bits that are used per pixel to display it. + +The "bits per pixel" of a pixmap image that is sent over the client +byte stream is a number that is either 4, 8, 16, 24 or 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 best sent in Z format as 8 bits per +pixel. + +A "pixmap image format" or a "pixmap format" is a description of the +format of a pixmap image as it is sent over the byte stream. For each +depth available on a server, there is one and only one pixmap format. +This pixmap image format gives the bits per pixel and the scanline +padding unit. (For instance, are pixel rows padded to bytes, 16-bit +words, or 32-bit words?) + +For each screen, you must decide upon what depth(s) it supports. You +should only count the number of bits used for the actual image. Some +displays store additional bits to indicate what window this pixel is +in, how close this object is to a viewer, transparency, and other +data; do not count these bits. + +A "display class" tells whether the display is monochrome or color, +whether there is a lookup table, and how the lookup table works. + +A "visual" is a combination of depth, display class, and a description +of how the pixel values result in a color on the screen. Each visual +has a set of masks and offsets that are used to separate a pixel value +into its red, green, and blue components and a count of the number of +colormap entries. Some of these fields are only meaningful when the +class dictates so. Each visual also has a screen ID telling which +screen it is usable on. Note that the depth does not imply the number +of map_entries; for instance, a display can have 8 bits per pixel but +only 254 colormap entries for use by applications (the other two being +reserved by hardware for the cursor). + +Each visual is identified by a 32-bit visual ID which the client uses +to choose what visual is desired on a given window. Clients can be +using more than one visual on the same screen at the same time. +.LP +The class of a display describes how this translation takes place. +There are three ways to do the translation. +.IP \(bu 5 +Pseudo - The pixel value, as a whole, is looked up +in a table of length map_entries to +determine the color to display. +.IP \(bu 5 +True - The +pixel value is broken up into red, green, and blue fields, each of which +are looked up in separate red, green, and blue lookup tables, +each of length map_entries. +.IP \(bu 5 +Gray - The pixel value is looked up in a table of length map_entries to +determine a gray level to display. +.LP +In addition, the lookup table can be static (resulting colors are fixed for each +pixel value) +or dynamic (lookup entries are under control of the client program). +This leads to a total of six classes: + +.IP \(bu 5 +Static Gray - The pixel value (of however many bits) determines directly the +level of gray +that the pixel assumes. +.IP \(bu 5 +Gray Scale - The pixel value is fed through a lookup table to arrive at the level +of gray to display +for the given pixel. +.IP \(bu 5 +Static Color - The pixel value is fed through a fixed lookup table that yields the +color to display +for that pixel. +.IP \(bu 5 +PseudoColor - The whole pixel value is fed through a programmable lookup +table that has one +color (including red, green, and blue intensities) for each possible pixel value, +and that color is displayed. +.IP \(bu 5 +True Color - Each pixel value consists of one or more bits +that directly determine each primary color intensity after being fed through +a fixed table. +.IP \(bu 5 +Direct Color - Each pixel value consists of one or more bits for each primary color. +Each primary color value is individually looked up in a table for that primary +color, yielding +an intensity for that primary color. +For each pixel, the red value is looked up in the +red table, the green value in the green table, and +the blue value in the blue table. +.LP +Here are some examples: +.IP +A simple monochrome 1 bit per pixel display is Static Gray. + +A display that has 2 bits per pixel for a choice +between the colors of black, white, green and violet is Static Color. + +A display that has three bits per pixel, where +each bit turns on or off one of the red, green or +blue guns, is in the True Color class. + +If you take the last example and scramble the +correspondence between pixel values and colors +it becomes a Static Color display. + +A display has 8 bits per pixel. The 8 bits select one entry out of 256 entries +in a lookup table, each entry consisting of 24 bits (8bits each for red, green, +and blue). +The display can show any 256 of 16 million colors on the screen at once. +This is a pseudocolor display. +The client application gets to fill the lookup table in this class of display. + +Imagine the same hardware from the last example. +Your server software allows the user, on the +command line that starts up the server +program, +to fill the lookup table to his liking once and for all. +From then on, the server software would not change the lookup table +until it exits. +For instance, the default might be a lookup table with a reasonable sample of +colors from throughout the color space. +But the user could specify that the table be filled with 256 steps of gray scale +because he knew ahead of time he would be manipulating a lot of black-and-white +scanned photographs +and not very many color things. +Clients would be presented with this unchangeable lookup table. +Although the hardware qualifies as a PseudoColor display, +the facade presented to the X client is that this is a Static Color display. + +You have to decide what kind of display you have or want +to pretend you have. +When you initialize the screen(s), this class value must be set in the +VisualRec data structure along with other display characteristics like the +depth and other numbers. + +The allowable DepthRec's and VisualRec's are pointed to by fields in the ScreenRec. +These are set up when InitOutput() is called; you should Xalloc() appropriate blocks +or use static variables initialized to the correct values. + +.NH 3 +Colormaps for Screens +.XS +Colormaps for Screens +.XE +.LP +A colormap is a device-independent +mapping between pixel values and colors displayed on the screen. + +Different windows on the same screen can have different +colormaps at the same time. +At any given time, the most recently installed +colormap(s) will be in use in the server +so that its (their) windows' colors will be guaranteed to be correct. +Other windows may be off-color. +Although this may seem to be chaotic, in practice most clients +use the default colormap for the screen. + +The default colormap for a screen is initialized when the screen is initialized. +It always remains in existence and is not owned by any regular client. It +is owned by client 0 (the server itself). +Many clients will simply use this default colormap for their drawing. +Depending upon the class of the screen, the entries in this colormap may +be modifiable by client applications. + +.NH 4 +Colormap Routines +.XS +Colormap Routines +.XE +.LP +You need to implement the following routines to handle the device-dependent +aspects of color maps. You will end up placing pointers to these procedures +in your ScreenRec data structure(s). The sample server implementations of +many of these routines are in both cfbcmap.c and mfbcmap.c; since mfb does +not do very much with color, the cfb versions are typically more useful +prototypes. +.nf + + Bool pScreen->CreateColormap(pColormap) + ColormapPtr pColormap; + +.fi +.LP +This routine is called by the DIX CreateColormap routine after it has allocated +all the data for the new colormap and just before it returns to the dispatcher. +It is the DDX layer's chance to initialize the colormap, particularly if it is +a static map. See the following +section for more details on initializing colormaps. +The routine returns FALSE if creation failed, such as due to memory +limitations. +Notice that the colormap has a devPriv field from which you can hang any +colormap specific storage you need. Since each colormap might need special +information, we attached the field to the colormap and not the visual. +.nf + + void pScreen->DestroyColormap(pColormap) + ColormapPtr pColormap; + +.fi +.LP +This routine is called by the DIX FreeColormap routine after it has uninstalled +the colormap and notified all interested parties, and before it has freed +any of the colormap storage. +It is the DDX layer's chance to free any data it added to the colormap. +.nf + + void pScreen->InstallColormap(pColormap) + ColormapPtr pColormap; + +.fi +.LP +InstallColormap should +fill a lookup table on the screen with which the colormap is associated with +the colors in pColormap. +If there is only one hardware lookup table for the screen, then all colors on +the screen may change simultaneously. + +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 +that was uninstalled may end up being off-color. +See the note, below, about uninstalling maps. +.nf + + void pScreen->UninstallColormap(pColormap) + ColormapPtr pColormap; + +.fi +.LP +UninstallColormap should +remove pColormap from screen pColormap->pScreen. +Some other map, such as the default map if possible, +should be installed in place of pColormap if applicable. +If +pColormap is the default map, do nothing. +If any client has requested ColormapNotify events, the DDX layer must notify the client. +(The routine WalkTree() is +be used to find such windows. The DIX routines TellNoMap(), +TellNewMap() and TellGainedMap() are provided to be used as +the procedure parameter to WalkTree. These procedures are in +Xserver/dix/colormap.c.) +.nf + + int pScreen->ListInstalledColormaps(pScreen, pCmapList) + ScreenPtr pScreen; + XID *pCmapList; + + +.fi +.LP +ListInstalledColormaps fills the pCMapList in with the resource ids +of the installed maps and returns a count of installed maps. +pCmapList will point to an array of size MaxInstalledMaps that was allocated +by the caller. +.nf + + void pScreen->StoreColors (pmap, ndef, pdefs) + ColormapPtr pmap; + int ndef; + xColorItem *pdefs; + +.fi +.LP +StoreColors changes some of the entries in the colormap pmap. +The number of entries to change are ndef, and pdefs points to the information +describing what to change. +Note that partial changes of entries in the colormap are allowed. +Only the colors +indicated in the flags field of each xColorItem need to be changed. +However, all three color fields will be sent with the proper value for the +benefit of screens that may not be able to set part of a colormap value. +If the screen is a static class, this routine does nothing. +The structure of colormap entries is nontrivial; see colormapst.h +and the definition of xColorItem in Xproto.h for +more details. +.nf + + void pScreen->ResolveColor(pRed, pGreen, pBlue, pVisual) + unsigned short *pRed, *pGreen, *pBlue; + VisualPtr pVisual; + + +.fi +.LP +Given a requested color, ResolveColor returns the nearest color that this hardware is +capable of displaying on this visual. +In other words, this rounds off each value, in place, to the number of bits +per primary color that your screen can use. +Remember that each screen has one of these routines. +The level of roundoff should be what you would expect from the value +you put in the bits_per_rgb field of the pVisual. + +Each value is an unsigned value ranging from 0 to 65535. +The bits least likely to be used are the lowest ones. +.LP +For example, if you had a pseudocolor display +with any number of bits per pixel +that had a lookup table supplying 6 bits for each color gun +(a total of 256K different colors), you would +round off each value to 6 bits. Please don't simply truncate these values +to the upper 6 bits, scale the result so that the maximum value seen +by the client will be 65535 for each primary. This makes color values +more portable between different depth displays (a 6-bit truncated white +will not look white on an 8-bit display). +.NH 4 +Initializing a Colormap +.XS +Initializing a Colormap +.XE +.LP +When a client requests a new colormap and when the server creates the default +colormap, the procedure CreateColormap in the DIX layer is invoked. +That procedure allocates memory for the colormap and related storage such as +the lists of which client owns which pixels. +It then sets a bit, BeingCreated, in the flags field of the ColormapRec +and calls the DDX layer's CreateColormap routine. +This is your chance to initialize the colormap. +If the colormap is static, which you can tell by looking at the class field, +you will want to fill in each color cell to match the hardwares notion of the +color for that pixel. +If the colormap is the default for the screen, which you can tell by looking +at the IsDefault bit in the flags field, you should allocate BlackPixel +and WhitePixel to match the values you set in the pScreen structure. +(Of course, you picked those values to begin with.) +.LP +You can also wait and use AllocColor() to allocate blackPixel +and whitePixel after the default colormap has been created. +If the default colormap is static and you initialized it in +pScreen->CreateColormap, then use can use AllocColor afterwards +to choose pixel values with the closest rgb values to those +desired for blackPixel and whitePixel. +If the default colormap is dynamic and uninitialized, then +the rgb values you request will be obeyed, and AllocColor will +again choose pixel values for you. +These pixel values can then be stored into the screen. +.LP +There are two ways to fill in the colormap. +The simplest way is to use the DIX function AllocColor. +.nf + +int AllocColor (pmap, pred, pgreen, pblue, pPix, client) + ColormapPtr pmap; + unsigned short *pred, *pgreen, *pblue; + Pixel *pPix; + int client; + +.fi +This takes three pointers to 16 bit color values and a pointer to a suggested +pixel value. The pixel value is either an index into one colormap or a +combination of three indices depending on the type of pmap. +If your colormap starts out empty, and you don't deliberately pick the same +value twice, you will always get your suggested pixel. +The truly nervous could check that the value returned in *pPix is the one +AllocColor was called with. +If you don't care which pixel is used, or would like them sequentially +allocated from entry 0, set *pPix to 0. This will find the first free +pixel and use that. +.LP +AllocColor will take care of all the bookkeeping and will +call StoreColors to get the colormap rgb values initialized. +The hardware colormap will be changed whenever this colormap +is installed. +.LP +If for some reason AllocColor doesn't do what you want, you can do your +own bookkeeping and call StoreColors yourself. This is much more difficult +and shouldn't be necessary for most devices. + +.NH 3 +Fonts for Screens +.XS +Fonts for Screens +.XE +.LP +A font is a set of bitmaps that depict the symbols in a character set. +Each font is for only one typeface in a given size, in other words, +just one bitmap for each character. Parallel fonts may be available +in a variety of sizes and variations, including "bold" and "italic." +X supports fonts for 8-bit and 16-bit character codes (for oriental +languages that have more than 256 characters in the font). 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 wide variety of operating +systems. The text format, referred to as BDF, is a slight extension +of the current Adobe 2.1 Bitmap Distribution Format (Adobe Systems, +Inc.). + +A short paper in PostScript format is included with the sample server +that defines BDF. It includes helpful pictures, which is why it is +done in PostScript and is not included in this document. + +Your implementation should include some sort of font compiler to read +these files and generate binary files that are directly usable by your +server implementation. The sample server comes with the source for a +font compiler. + +It is important the font properties contained in the BDF files are +preserved across any font compilation. In particular, copyright +information cannot be casually tossed aside without legal +ramifications. Other properties will be important 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 with the X11 tape. In principle, you can +convert fonts from other sources or dream up your own fonts for use on +your server. + +.NH 4 +Portable Compiled Format +.XS +Portable Compiled Format +.XE +.LP +A font compiler is supplied with the sample server. It has +compile-time switches to convert the BDF files into a portable binary +form, called Portable Compiled Format or PCF. This allows for an +arbitrary data format inside the file, and by describing the details +of the format in the header of the file, any PCF file can be read by +any PCF reading client. By selecting the format which matches the +required internal format for your renderer, the PCF reader can 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. +.NH 4 +Font Realization +.XS +Font Realization +.XE +.LP +Each screen configured into the server +has an opportunity at font-load time +to "realize" a font into some internal format if necessary. +This happens every time the font is loaded into memory. + +A font (FontRec in Xserver/include/dixfontstr.h) is +a device-independent structure containing a device-independent +representation of the font. When a font is created, it is "realized" +for each screen. At this point, the screen has the chance to convert +the font into some other format. The DDX layer can also put information +in the devPrivate storage. +.nf + + Bool pScreen->RealizeFont(pScr, pFont) + ScreenPtr pScr; + FontPtr pFont; + + Bool pScreen->UnrealizeFont(pScr, pFont) + ScreenPtr pScr; + FontPtr pFont; + +.fi +RealizeFont and UnrealizeFont should calculate and allocate these extra data structures and +dispose of them when no longer needed. +These are called in response to OpenFont and CloseFont requests from +the client. +The sample server implementation is in mfbfont.c (which does very little). + +.NH 3 +Other Screen Routines +.XS +Other Screen Routines +.XE +.LP +You must supply several other screen-specific routines for +your X server implementation. +Some of these are described in other sections: +.IP \(bu 5 +GetImage() is described in the Drawing Primitives section. +.IP \(bu 5 +GetSpans() is described in the Pixblit routine section. +.IP \(bu 5 +Several window and pixmap manipulation procedures are +described in the Window section under Drawables. +.IP \(bu 5 +The CreateGC() routine is described under Graphics Contexts. +.LP +.nf + + void pScreen->QueryBestSize(kind, pWidth, pHeight) + int kind; + unsigned short *pWidth, *pHeight; + ScreenPtr pScreen; + +.fi +QueryBestSize() returns the best sizes for cursors, tiles, and stipples +in response to client requests. +kind is one of the defined constants CursorShape, TileShape, or StippleShape +(defined in X.h). +For CursorShape, return the maximum width and +height for cursors that you can handle. +For TileShape and StippleShape, start with the suggested values in pWidth +and pHeight and modify them in place to be optimal values that are +greater than or equal to the suggested values. +The sample server implementation is in Xserver/mfb/mfbmisc.c. +.nf + + pScreen->SourceValidate(pDrawable, x, y, width, height) + DrawablePtr pDrawable; + int x, y, width, height; + +.fi +SourceValidate should be called by CopyArea/CopyPlane primitives when +the source drawable is not the same as the destination, and the +SourceValidate function pointer in the screen is non-null. If you know that +you will never need SourceValidate, you can avoid this check. Currently, +SourceValidate is used by the mi software cursor code to remove the cursor +from the screen when the source rectangle overlaps the cursor position. +x,y,width,height describe the source rectangle (source relative, that is) +for the copy operation. +.nf + + Bool pScreen->SaveScreen(pScreen, on) + ScreenPtr pScreen; + int on; + +.fi +SaveScreen() is used for Screen Saver support (see WaitForSomething()). +pScreen is the screen to save. +.nf + + Bool pScreen->CloseScreen(pScreen) + ScreenPtr pScreen; + +.fi +When the server is reset, it calls this routine for each screen. +.nf + + Bool pScreen->CreateScreenResources(pScreen) + ScreenPtr pScreen; + +.fi +If this routine is not NULL, it will be called once per screen per +server initialization/reset after all modules have had a chance to +register their devPrivates on all structures that support them (see +the section on devPrivates below). If you need to create any +resources that have dynamic devPrivates as part of your screen +initialization, you should do so in this function instead of in the +screen init function passed to AddScreen to guarantee that the +resources have a complete set of devPrivates. This routine returns +TRUE if successful. +.NH 2 +Drawables +.XS +Drawables +.XE +.LP +A drawable is a descriptor of a surface that graphics are drawn into, either +a window on the screen or a pixmap in memory. + +Each drawable has a type, class, +ScreenPtr for the screen it is associated with, depth, position, size, +and serial number. +The type is one of the defined constants DRAWABLE_PIXMAP, +DRAWABLE_WINDOW and UNDRAWABLE_WINDOW. +(An undrawable window is used for window class InputOnly.) +The serial number is guaranteed to be unique across drawables, and +is used in determining +the validity of the clipping information in a GC. +The screen selects the set of procedures used to manipulate and draw into the +drawable. Position is used (currently) only by windows; pixmaps must +set these fields to 0,0 as this reduces the amount of conditional code +executed throughout the mi code. Size indicates the actual client-specified +size of the drawable. +There are, in fact, no other fields that a window drawable and pixmap +drawable have in common besides those mentioned here. + +Both PixmapRecs and WindowRecs are structs that start with a drawable +and continue on with more fields. Pixmaps have devPrivate pointers +which usually point to the pixmap data but could conceivably be +used for anything that DDX wants. Both windows and pixmaps have an +array of devPrivates unions, one entry of which will probably be used +for DDX specific data. Entries in this array are allocated using +Allocate{Window|Pixmap}PrivateIndex() (see Wrappers and devPrivates +below). This is done because different graphics hardware has +different requirements for management; if the graphics is always +handled by a processor with an independent address space, there is no +point having a pointer to the bit image itself. + +The definition of a drawable and a pixmap can be found in the file +Xserver/include/pixmapstr.h. +The definition of a window can be found in the file Xserver/include/windowstr.h. + +.NH 3 +Pixmaps +.XS +Pixmaps +.XE +.LP +A pixmap is a three-dimensional array of bits stored somewhere offscreen, +rather than in the visible portion of the screen's display frame buffer. It +can be used as a source or destination in graphics operations. There is no +implied interpretation of the pixel values in a pixmap, because it has no +associated visual or colormap. There is only a depth that indicates the +number of significant bits per pixel. Also, there is no implied physical +size for each pixel; all graphic units are in numbers of pixels. Therefore, +a pixmap alone does not constitute a complete image; it represents only a +rectangular array of pixel values. + +Note that the pixmap data structure is reference-counted. + +The server implementation is free to put the pixmap data +anywhere it sees fit, according to its graphics hardware setup. Many +implementations will simply have the data dynamically allocated in the +server's address space. More sophisticated implementations may put the +data in undisplayed framebuffer storage. + +In addition to dynamic devPrivates (see the section on devPrivates +below), the pixmap data structure has two fields that are private to +the device. Although you can use them for anything you want, they +have intended purposes. devKind is intended to be a device specific +indication of the pixmap location (host memory, off-screen, etc.). In +the sample server, since all pixmaps are in memory, devKind stores the +width of the pixmap in bitmap scanline units. devPrivate is probably +a pointer to the bits in the pixmap. + +A bitmap is a pixmap that is one bit deep. +.nf + + PixmapPtr pScreen->CreatePixmap(pScreen, width, height, depth) + ScreenPtr pScreen; + int width, height, depth; + +.fi +This ScreenRec procedure must create a pixmap of the size +requested. +It must allocate a PixmapRec and fill in all of the fields. +The reference count field must be set to 1. +If width or height are zero, no space should be allocated +for the pixmap data, and if the implementation is using the +devPrivate field as a pointer to the pixmap data, it should be +set to NULL. +If successful, it returns a pointer to the new pixmap; if not, it returns NULL. +See Xserver/mfb/mfbpixmap.c for the sample server implementation. +.nf + + Bool pScreen->DestroyPixmap(pPixmap) + PixmapPtr pPixmap; + +.fi +This ScreenRec procedure must "destroy" a pixmap. +It should decrement the reference count and, if zero, it +must deallocate the PixmapRec and all attached devPrivate blocks. +If successful, it returns TRUE. +See Xserver/mfb/mfbpixmap.c for the sample server implementation. +.nf + + Bool + pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData) + PixmapPtr pPixmap; + int width; + int height; + int depth; + int bitsPerPixel; + int devKind; + pointer pPixData; + +.fi +This routine takes a pixmap header (the PixmapRec plus all the dynamic +devPrivates) and initializes the fields of the PixmapRec to the +parameters of the same name. pPixmap must have been created via +pScreen->CreatePixmap with a zero width or height to avoid +allocating space for the pixmap data. pPixData is assumed to be the +pixmap data; it will be stored in an implementation-dependent place +(usually pPixmap->devPrivate.ptr). This routine returns +TRUE if successful. See Xserver/mi/miscrinit.c for the sample +server implementation. +.nf + + PixmapPtr + GetScratchPixmapHeader(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; + +.fi +DDX should use these two DIX routines when it has a buffer of raw +image data that it wants to manipulate as a pixmap temporarily, +usually so that some other part of the server can be leveraged to +perform some operation on the data. The data should be passed in +pPixData, and will be stored in an implementation-dependent place +(usually pPixmap->devPrivate.ptr). The other +fields go into the corresponding PixmapRec fields. +If successful, GetScratchPixmapHeader returns a valid PixmapPtr which can +be used anywhere the server expects a pixmap, else +it returns NULL. The pixmap should be released when no longer needed +(usually within the same function that allocated it) +with FreeScratchPixmapHeader. +.NH 3 +Windows +.XS +Windows +.XE +.LP +A window is a visible, or potentially visible, rectangle on the screen. +DIX windowing functions maintain an internal n-ary tree data structure, which +represents the current relationships of the mapped windows. +Windows that are contained in another window are children of that window and +are clipped to the boundaries of the parent. +The root window in the tree is the window for the entire screen. +Sibling windows constitute a doubly-linked list; the parent window 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 DIX requests that it +be drawn. The contents of the window is drawn by the client through +requests to the server. + +Window painting is orchestrated through an expose event system. +When a region is exposed, +DIX generates an expose event, telling the client to repaint the window and +passing the region that is the minimal area needed to be repainted. + +As a favor to clients, the server may retain +the output to the hidden parts of windows +in off-screen memory; this is called "backing store". +When a part of such a window becomes exposed, it +can quickly move pixels into place instead of +triggering an expose event and waiting for a client on the other +end of the network to respond. +Even if the network response is insignificant, the time to +intelligently paint a section of a window is usually more than +the time to just copy already-painted sections. +At best, the repainting involves blanking out the area to a background color, +which will take about the +same amount of time. +In this way, backing store can dramatically increase the +performance of window moves. + +On the other hand, backing store can be quite complex, because +all graphics drawn to hidden areas must be intercepted and redirected +to the off-screen window sections. +Not only can this be complicated for the server programmer, +but it can also impact window painting performance. +The backing store implementation can choose, at any time, to +forget pieces of backing that are written into, relying instead upon +expose events to repaint for simplicity. + +In X, the decision to use the backing-store scheme is made +by you, the server implementor. +X provides hooks for implementing backing store, therefore +the decision to use this strategy can be made on the fly. +For example, you may use backing store only for certain windows +that the user requests or you may use backing store +until memory runs out, at which time you +start dropping pieces of backing as needed to make more room. + +When a window operation is requested by the client, +such as a window being created or moved, +a new state is computed. +During this transition, DIX informs DDX what rectangles in what windows are about to +become obscured and what rectangles in what windows have become exposed. +This provides a hook for the implementation of backing store. +If DDX is unable to restore exposed regions, DIX generates expose +events to the client. +It is then the client's responsibility to paint the +window parts that were exposed but 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 as a result of a resize. +For instance, if the window has controls or other items +that always hang on the edge of the +window, and that edge is moved as a result of the resize, +then those pixels should be moved +to avoid having the client repaint it. +If the client needs to repaint it anyway, such an operation takes +time, so it is desirable +for the server to approximate the appearance of the window as best +it can while waiting for the client +to do it perfectly. +Gravity is used for that, also. + +The window has several fields used in drawing +operations: +.IP \(bu 5 +clipList - This region, in conjunction with +the client clip 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 overlap this window. To get the list with the +children included (subwindow-mode is IncludeInferiors), +the routine NotClippedByChildren(pWin) returns the unclipped region. +.IP \(bu 5 +borderClip is the region used by CopyWindow and +includes the area of the window, its children, and the border, but with the +overlapping areas of sibling children removed. +.LP +Most of the other fields are for DIX use only. + +.NH 4 +Window Procedures in the ScreenRec +.XS +Window Procedures in the ScreenRec +.XE +.LP +You should implement +all of the following procedures and store pointers to them in the screen record. + +The device-independent portion of the server "owns" the window tree. +However, clever hardware might want to know the relationship of +mapped windows. There are pointers to procedures +in the ScreenRec data structure that are called to give the hardware +a chance to update its internal state. These are helpers and +hints to DDX only; +they do not change the window tree, which is only changed by DIX. +.nf + + Bool pScreen->CreateWindow(pWin) + WindowPtr pWin; + +.fi +This routine is a hook for when DIX creates a window. +It should 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 server implementation. +.nf + + Bool pScreen->DestroyWindow(pWin); + WindowPtr pWin; + +.fi +This routine is a hook for when DIX destroys a window. +It should deallocate the devPrivate block for it and any other blocks that need +to be freed, besides doing other cleanup actions. + +See Xserver/mfb/mfbwindow.c for the sample server implementation. +.nf + + Bool pScreen->PositionWindow(pWin, x, y); + WindowPtr pWin; + int x, y; + +.fi +This routine is a hook for when DIX moves or resizes a window. +It should do whatever private operations need to be done when a window is moved or resized. +For instance, if DDX keeps a pixmap tile used for drawing the background +or border, and it keeps the tile rotated such that it is longword +aligned to longword locations in the frame buffer, then you should rotate your tiles here. +The actual graphics involved in moving the pixels on the screen and drawing the +border are handled by CopyWindow(), below. +.LP +See Xserver/mfb/mfbwindow.c for the sample server implementation. +.nf + + Bool pScreen->RealizeWindow(pWin); + WindowPtr pWin; + + Bool pScreen->UnrealizeWindow(pWin); + WindowPtr pWin; + +.fi +These routines are hooks for when DIX maps (makes visible) and unmaps +(makes invisible) a window. It should do whatever private operations +need to be done when these happen, such as allocating or deallocating +structures that are only needed for visible windows. RealizeWindow +does NOT draw the window border, background or contents; +UnrealizeWindow does NOT erase the window or generate exposure events +for underlying windows; this is taken care of by DIX. DIX does, +however, call PaintWindowBackground() and PaintWindowBorder() to +perform some of these. +.nf + + Bool pScreen->ChangeWindowAttributes(pWin, vmask) + WindowPtr pWin; + unsigned long vmask; + +.fi +ChangeWindowAttributes is called whenever DIX changes window +attributes, such as the size, front-to-back ordering, title, or +anything of lesser severity that affects the window itself. The +sample server implements this routine. It computes accelerators for +quickly putting up background and border tiles. (See description of +the set of routines stored in the WindowRec.) +.nf + + int pScreen->ValidateTree(pParent, pChild, kind) + WindowPtr pParent, pChild; + VTKind kind; + +.fi +ValidateTree calculates the clipping region for the parent window and +all of its children. This routine must be provided. The sample server +has a machine-independent version in Xserver/mi/mivaltree.c. This is +a very difficult routine to replace. +.nf + + void pScreen->PostValidateTree(pParent, pChild, kind) + WindowPtr pParent, pChild; + VTKind kind; + +.fi +If this routine is not NULL, DIX calls it shortly after calling +ValidateTree, passing it the same arguments. This is useful for +managing multi-layered framebuffers. +The sample server sets this to NULL. +.nf + + void pScreen->WindowExposures(pWin, pRegion, pBSRegion) + WindowPtr pWin; + RegionPtr pRegion; + RegionPtr pBSRegion; + +.fi +The WindowExposures() routine +paints the border and generates exposure events for the window. +pRegion is an unoccluded region of the window, and pBSRegion is an +occluded region that has backing store. +Since exposure events include a rectangle describing what was exposed, +this routine may have to send back a series of exposure events, one for +each rectangle of the region. +The count field in the expose event is a hint to the +client as to the number of +regions that are after this one. +This routine must be provided. The sample +server has a machine-independent version in Xserver/mi/miexpose.c. +.nf + + void pScreen->ClipNotify (pWin, dx, dy) + WindowPtr pWin; + int dx, dy; + +.fi +Whenever the cliplist for a window is changed, this function is called to +perform whatever hardware manipulations might be necessary. When called, +the clip list and border clip regions in the window are set to the new +values. dx,dy are the distance that the window has been moved (if at all). +.NH 4 +Window Painting Procedures +.XS +Window Painting Procedures +.XE +.LP +In addition to the procedures listed above, there are four routines which +manipulate the actual window image directly. +In the sample server, mi implementations will work for +most purposes and mfb/cfb routines speed up situations, such +as solid backgrounds/borders or tiles that are 8, 16 or 32 pixels square. + +These three routines are used for systems that implement a backing-store scheme for it to +know when to stash away areas of pixels and to restore or reposition them. +.nf + + void pScreen->ClearToBackground(pWin, x, y, w, h, generateExposures); + WindowPtr pWin; + int x, y, w, h; + Bool generateExposures; + +.fi +This routine is called on a window in response to a ClearToBackground request +from the client. +This request has two different but related functions, depending upon generateExposures. + +If generateExposures is true, the client is declaring that the given rectangle +on the window is incorrectly painted and needs to be repainted. +The sample server implementation calculates the exposure region +and hands it to the DIX procedure HandleExposures(), which +calls the WindowExposures() routine, below, for the window +and all of its child windows. + +If generateExposures is false, the client is trying to simply erase part +of the window to the background fill style. +ClearToBackground should write the background color or tile to the +rectangle in question (probably using PaintWindowBackground). +If w or h is zero, it clears all the way to the right or lower edge of the window. + +The sample server implementation is in Xserver/mi/miwindow.c. +.nf + + 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 */ + +.fi +These two routines are for painting pieces of the window background or border. +They both actually paint the area designated by region. +The kind parameter is a defined constant that is always PW_BACKGROUND +or PW_BORDER, as shown. +Therefore, you can use the same routine for both. +The defined constant tells the routine whether to use the window's +border fill style or its background fill style to paint the given region. +Both fill styles consist of a union which holds a tile pointer and a pixel +value, along with a separate variable which indicates which entry is valid. +For PW_BORDER, borderIsPixel != 0 indicates that the border PixUnion +contains a pixel value, else a tile. For PW_BACKGROUND there are four +values, contained in backgroundState; None, ParentRelative, BackgroundPixmap +and BackgroundPixel. None indicates that the region should be left +unfilled, while ParentRelative indicates that the background of the parent is +inherited (see the Protocol document for the exact semantics). +.nf + + void pScreen->CopyWindow(pWin, oldpt, oldRegion); + WindowPtr pWin; + DDXPointRec oldpt; + RegionPtr oldRegion; + +.fi +CopyWindow is called when a window is moved, and graphically moves to +pixels of a window on the screen. It should not change 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 new location and new region is +stored in the WindowRec. oldRegion might modified in place by this +routine (the sample implementation does this). + +CopyArea could be used, except that this operation has more +complications. First of all, you do not want to copy a rectangle onto +a rectangle. The original window may be obscured by other windows, +and the new window location may be similarly obscured. Second, some +hardware supports multiple windows with multiple depths, and your +routine needs to take care of that. + +The pixels in oldRegion (with reference point oldpt) are copied to the +window's new region (pWin->borderClip). pWin->borderClip is gotten +directly from the window, rather than passing it as a parameter. + +The sample server implementation is in Xserver/mfb/mfbwindow.c. + +.NH 4 +Screen Operations for Backing Store +.XS +Screen Operations for Backing Store +.XE +.LP +Each ScreenRec has six functions which provide the backing store +interface. For screens not supporting backing store, these pointers +may be nul. Servers that implement some backing store scheme +must fill in the procedure pointers for the procedures below, +and must maintain the backStorage field in each window struct. +The sample implementation is in mi/mibstore.c. +.nf + + void pScreen->SaveDoomedAreas(pWin, pRegion, dx, dy) + WindowPtr pWin; + RegionPtr pRegion; + int dx, dy; + +.fi +This routine saves the newly obscured region, pRegion, in backing store. +dx, dy indicate how far the window is being moved, useful as the obscured +region is relative to the window as it will appear in the new location, +rather then relative to the bits as the are on the screen when the function +is invoked. +.nf + + RegionPtr pScreen->RestoreAreas(pWin, pRegion) + WindowPtr pWin; + RegionPtr pRegion; + +.fi +This looks at the exposed region of the window, pRegion, and tries to +restore to the screen the parts that have been saved. It removes the +restored parts from the backing storage (because they are now on the screen) +and subtracts the areas from the exposed region. The returned region is the +area of the window which should have expose events generated for and can be +either a new region, pWin->exposed, or NULL. The region left in +pRegion is set to the area of the window which should be painted with +the window background. +.nf + + RegionPtr pScreen->TranslateBackingStore(pWin, dx, dy, oldClip, oldx, oldy) + WindowPtr pWin; + int dx, dy; + RegionPtr oldClip; + int oldx, oldy; + +.fi +This is called when the window is moved or resized so that the backing +store can be translated if necessary. oldClip is the old cliplist for +the window, which is used to save doomed areas if the window is moved +underneath its parent as a result of bitgravity. The returned region +represents occluded areas of the window for which the backing store +contents are invalid. +.nf + + 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; + +.fi +Copies a region from the backing store of pSrc to pDst. +.nf + + RegionPtr pScreen->ClearBackingStore(pWindow, x, y, w, h, generateExposures) + WindowPtr pWindow; + int x; + int y; + int w; + int h; + Bool generateExposures; + +.fi +Clear the given area of the backing pixmap with the background of +the window. If generateExposures is TRUE, generate +exposure events for the area. Note that if the area has any +part outside the saved portions of the window, we do not allow the +count in the expose events to be 0, since there will be more +expose events to come. +.nf + + void pScreen->DrawGuarantee(pWindow, pGC, guarantee) + WindowPtr pWindow; + GCPtr pGC; + int guarantee; + +.fi +This informs the backing store layer that you are about to validate +a gc with a window, and that subsequent output to the window +is (or is not) guaranteed to be already clipped to the visible +regions of the window. + +.NH 4 +Screen Operations for Multi-Layered Framebuffers +.XS +Screen Operations for Multi-Layered Framebuffers +.XE +.LP +The following screen functions are useful if you have a framebuffer 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 should probably use the mi versions of these routines +in mi/miwindow.c. This can be easily accomplished by calling miScreenInit. +.nf + + void pScreen->MarkWindow(pWin) + WindowPtr pWin; + +.fi +This formerly dix function MarkWindow has moved to ddx and is accessed +via this screen function. This function should store something, +usually a pointer to a device-dependent structure, in pWin->valdata so +that ValidateTree has the information it needs to validate the window. +.nf + + Bool pScreen->MarkOverlappedWindows(parent, firstChild, ppLayerWin) + WindowPtr parent; + WindowPtr firstChild; + WindowPtr * ppLayerWin; + +.fi +This formerly dix function MarkWindow has moved to ddx and is accessed +via this screen function. In the process, it has grown another +parameter: ppLayerWin, which is filled in with a pointer to the window +at which save under marking and ValidateTree should begin. In the +single-layered framebuffer case, pLayerWin == pWin. +.nf + + Bool pScreen->ChangeSaveUnder(pLayerWin, firstChild) + WindowPtr pLayerWin; + WindowPtr firstChild; + +.fi +The dix functions ChangeSaveUnder and CheckSaveUnder have moved to ddx and +are accessed via this screen function. pLayerWin should be the window +returned in the ppLayerWin parameter of MarkOverlappedWindows. The function +may turn on backing store for windows that might be covered, and may partially +turn off backing store for windows. It returns TRUE if PostChangeSaveUnder +needs to be called to finish turning off backing store. +.nf + + void pScreen->PostChangeSaveUnder(pLayerWin, firstChild) + WindowPtr pLayerWin; + WindowPtr firstChild; + +.fi +The dix function DoChangeSaveUnder has moved to ddx and is accessed via +this screen function. This function completes the job of turning off +backing store that was started by ChangeSaveUnder. +.nf + + void pScreen->MoveWindow(pWin, x, y, pSib, kind) + WindowPtr pWin; + int x; + int y; + WindowPtr pSib; + VTKind kind; + +.fi +The formerly dix function MoveWindow has moved to ddx and is accessed via +this screen function. The new position of the window is given by +x,y. kind is VTMove if the window is only moving, or VTOther if +the border is also changing. +.nf + + void pScreen->ResizeWindow(pWin, x, y, w, h, pSib) + WindowPtr pWin; + int x; + int y; + unsigned int w; + unsigned int h; + WindowPtr pSib; + +.fi +The formerly dix function SlideAndSizeWindow has moved to ddx and is accessed via +this screen function. The new position is given by x,y. The new size +is given by w,h. +.nf + + WindowPtr pScreen->GetLayerWindow(pWin) + WindowPtr pWin + +.fi +This is a new function which returns a child of the layer parent of pWin. +.nf + + void pScreen->HandleExposures(pWin) + WindowPtr pWin; + +.fi +The formerly dix function HandleExposures has moved to ddx and is accessed via +this screen function. This function is called after ValidateTree and +uses the information contained in valdata to send exposures to windows. +.nf + + void pScreen->ReparentWindow(pWin, pPriorParent) + WindowPtr pWin; + WindowPtr pPriorParent; + +.fi +This function will be called when a window is reparented. At the time of +the call, pWin will already be spliced into its new position in the +window tree, and pPriorParent is its previous parent. This function +can be NULL. +.nf + + void pScreen->SetShape(pWin) + WindowPtr pWin; + +.fi +The formerly dix function SetShape has moved to ddx and is accessed via +this screen function. The window's new shape will have already been +stored in the window when this function is called. +.nf + + void pScreen->ChangeBorderWidth(pWin, width) + WindowPtr pWin; + unsigned int width; + +.fi +The formerly dix function ChangeBorderWidth has moved to ddx and is accessed via +this screen function. The new border width is given by width. +.nf + + void pScreen->MarkUnrealizedWindow(pChild, pWin, fromConfigure) + WindowPtr pChild; + WindowPtr pWin; + Bool fromConfigure; + +.fi +This function is called for windows that are being unrealized as part of +an UnrealizeTree. pChild is the window being unrealized, pWin is an +ancestor, and the fromConfigure value is simply propogated from UnrealizeTree. +.NH 2 +Graphics Contexts and Validation +.XS +Graphics Contexts and Validation +.XE +.LP +This graphics context (GC) contains state variables such as foreground and +background pixel value (color), the current line style and width, +the current tile or stipple for pattern generation, the current font for text +generation, and other similar attributes. + +In many graphics systems, the equivalent of the graphics context and the +drawable are combined as one entity. +The main distinction between the two kinds of status is that a drawable +describes a writing surface and the writings that may have already been done +on it, whereas a graphics context describes the drawing process. +A drawable is like a chalkboard. +A GC is like a piece of chalk. + +Unlike many similar systems, there is no "current pen location." +Every graphic operation is accompanied by the coordinates where it is to happen. + +The GC also includes two vectors of procedure pointers, the first +operate on the GC itself and are called GC funcs. The second, called +GC ops, +contains the functions that carry out the fundamental graphic operations +such as drawing lines, polygons, arcs, text, and copying bitmaps. +The DDX graphic software can, if it +wants to be smart, change these two vectors of procedure pointers +to take advantage of hardware/firmware in the server machine, which can do +a better job under certain circumstances. To reduce the amount of memory +consumed by each GC, it is wise to create a few "boilerplate" GC ops vectors +which can be shared by every GC which matches the constraints for that set. +Also, it is usually reasonable to have every GC created by a particular +module to share a common set of GC funcs. Samples of this sort of +sharing can be seen in cfb/cfbgc.c and mfb/mfbgc.c. + +The DDX software is notified any time the client (or DIX) uses a changed GC. +For instance, if the hardware has special support for drawing fixed-width +fonts, DDX can intercept changes to the current font in a GC just before +drawing is done. It can plug into either a fixed-width procedure that makes +the hardware draw characters, or a variable-width procedure that carefully +lays out glyphs by hand in software, depending upon the new font that is +selected. + +A definition of these structures can be found in the file +Xserver/include/gcstruct.h. + +Also included in each GC is an array of devPrivates which portions of the +DDX can use for any reason. Entries in this array are allocated with +AllocateGCPrivateIndex() (see Wrappers and Privates below). + +The DIX routines available for manipulating GCs are +CreateGC, ChangeGC, CopyGC, SetClipRects, SetDashes, and FreeGC. +.nf + + 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; + +.fi + +As a convenience, each Screen structure contains an array of +GCs that are preallocated, one at each depth the screen supports. +These are particularly useful in the mi code. Two DIX routines +must be used to get these GCs: +.nf + + GCPtr GetScratchGC(depth, pScreen) + int depth; + ScreenPtr pScreen; + + FreeScratchGC(pGC) + GCPtr pGC; + +.fi +Always use these two routines, don't try to extract the scratch +GC yourself -- someone else might be using it, so a new one must +be created on the fly. + +If you need a GC for a very long time, say until the server is restarted, +you should not take one from the pool used by GetScratchGC, but should +get your own using CreateGC or CreateScratchGC. +This leaves the ones in the pool free for routines that only need it for +a little while and don't want to pay a heavy cost to get it. +.nf + + GCPtr CreateScratchGC(pScreen, depth) + ScreenPtr pScreen; + int depth; + +.fi +NULL is returned if the GC cannot be created. +The GC returned can be freed with FreeScratchGC. + +.NH 3 +Details of operation +.XS +Details of operation +.XE +.LP +At screen initialization, a screen must supply a GC creation procedure. +At GC creation, the screen must fill in GC funcs and GC ops vectors +(Xserver/include/gcstruct.h). For any particular GC, the func vector +must remain constant, while the op vector may vary. This invariant is to +ensure that Wrappers work correctly. + +When a client request is processed that results in a change +to the GC, the device-independent state of the GC is updated. +This includes a record of the state that changed. +Then the ChangeGC GC func is called. +This is useful for graphics subsystems that are able to process +state changes in parallel with the server CPU. +DDX may opt not to take any action at GC-modify time. +This is more efficient if multiple GC-modify requests occur +between draws using a given GC. + +Validation occurs at the first draw operation that specifies the GC after +that GC was modified. DIX calls then the ValidateGC GC func. DDX should +then update its internal state. DDX internal state may be stored as one or +more of the 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 a number fetched from +the window that was drawn into the last time the GC was used. The serial +number in the drawable is changed when the drawable's +clipList or absCorner changes. Thus, by +comparing the GC serial number with the drawable serial number, DIX can +force a validate if the drawable has been changed since the last time it +was used with this GC. + +In addition, the drawable serial number is always guaranteed to have the +most significant bit set to 0. Thus, the DDX layer can set the most +significant bit of the serial number to 1 in a GC to force a validate the next time +the GC is used. DIX also uses this technique to indicate that a change has +been made to the GC by way of a SetGC, a SetDashes or a SetClip request. + +.NH 3 +GC Handling Routines +.XS +GC Handling Routines +.XE +.LP +The ScreenRec data structure has a pointer for +CreateGC(). +.nf + + Bool pScreen->CreateGC(pGC) + GCPtr pGC; +.fi +This routine must fill in the fields of +a dynamically allocated GC that is passed in. +It does NOT allocate the GC record itself or fill +in the defaults; DIX does that. + +This must fill in both the GC funcs and ops; none of the drawing +functions will be called before the GC has been validated, +but the others (dealing with allocating of clip regions, +changing and destroying the GC, etc.) might be. + +The GC funcs vector contains pointers to 7 +routines and a devPrivate field: +.nf + + pGC->funcs->ChangeGC(pGC, changes) + GCPtr pGC; + unsigned long changes; + +.fi +This GC func is called immediately after a field in the GC is changed. +changes is a bit mask indicating the changed fields of the GC in this +request. + +The ChangeGC routine is useful if you have a system where +state-changes to the GC can be swallowed immediately by your graphics +system, and a validate is not necessary. + +.nf + + pGC->funcs->ValidateGC(pGC, changes, pDraw) + GCPtr pGC; + unsigned long changes; + DrawablePtr pDraw; + +.fi +ValidateGC is called by DIX just before the GC will be used when one +of many possible changes to the GC or the graphics system has +happened. It can modify a devPrivates field of the GC or its +contents, change the op vector, or change hardware according to the +values in the GC. It may not change the device-independent portion of +the GC itself. + +In almost all cases, your ValidateGC() procedure should take the +regions that drawing needs to be clipped to and combine them into a +composite clip region, which you keep a pointer to in the private part +of the GC. In this way, your drawing primitive routines (and whatever +is below them) can easily determine what to clip and where. You +should combine the regions clientClip (the region that the client +desires to clip output to) and the region returned by +NotClippedByChildren(), in DIX. An example is in Xserver/mfb/mfbgc.c. + +Some kinds of extension software may cause this routine to be called +more than originally intended; you should not rely on algorithms that +will break under such circumstances. + +See the Strategies document for more information on creatively using +this routine. + +.nf + + pGC->funcs->CopyGC(pGCSrc, mask, pGCDst) + GCPtr pGCSrc; + unsigned long mask; + GCPtr pGCDst; + +.fi +This routine is called by DIX when a GC is being copied to another GC. +This is for situations where dynamically allocated chunks of memory +are hanging off a GC devPrivates field which need to be transferred to +the destination GC. +.nf + + pGC->funcs->DestroyGC(pGC) + GCPtr pGC; + +.fi +This routine is called before the GC is destroyed for the +entity interested in this GC to clean up after itself. +This routine is responsible for freeing any auxiliary storage allocated. + +.NH 3 +GC Clip Region Routines +.XS +GC Clip Region Routines +.XE +.LP +The GC clientClip field requires three procedures to manage it. These +procedures are in the GC funcs vector. The underlying principle is that dix +knows nothing about the internals of the clipping information, (except when +it has come from the client), and so calls ddX whenever it needs to copy, +set, or destroy such information. It could have been possible for dix not +to allow ddX to touch the field in the GC, and require it to keep its own +copy in devPriv, but since clip masks can be very large, this seems like a +bad idea. Thus, the server allows ddX to do whatever it wants to the +clientClip field of the GC, but requires it to do all manipulation itself. +.nf + + void pGC->funcs->ChangeClip(pGC, type, pValue, nrects) + GCPtr pGC; + int type; + char *pValue; + int nrects; + +.fi +This routine is called whenever the client changes the client clip +region. The pGC points to the GC involved, the type tells what form +the region has been sent in. If type is CT_NONE, then there is no +client clip. If type is CT_UNSORTED, CT_YBANDED or CT_YXBANDED, then +pValue pointer to 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. (The defines +for CT_NONE, etc. are in Xserver/include/gc.h.) This routine is +responsible for incrementing any necessary reference counts (e.g. for +a pixmap clip mask) for the new clipmask and freeing anything that +used to be in the GC's clipMask field. The lists of rectangles passed +in can be freed with Xfree(), the regions can be destroyed with the +RegionDestroy field in the screen, and pixmaps can be destroyed by +calling the screen's DestroyPixmap function. DIX and MI code expect +what they pass in to this to be freed or otherwise inaccessible, and +will never look inside what's been put in the GC. This is a good +place to be wary of storage leaks. +.LP +In the sample server, this routine transforms either the bitmap or the +rectangle list into a region, so that future routines will have a more +predictable starting point to work from. (The validate routine must +take this client clip region and merge it with other regions to arrive +at a composite clip region before any drawing is done.) +.nf + + void pGC->funcs->DestroyClip(pGC) + GCPtr pGC; + +.fi +This routine is called whenever the client clip region must be destroyed. +The pGC points to the GC involved. This call should set the clipType +field of the GC to CT_NONE. +In the sample server, the pointer to the client clip region is set to NULL +by this routine after destroying the region, so that other software +(including ChangeClip() above) will recognize that there is no client clip region. +.nf + + void pGC->funcs->CopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; + +.fi +This routine makes a copy of the clipMask and clipType from pgcSrc +into pgcDst. It is responsible for destroying any previous clipMask +in pgcDst. The clip mask in the source can be the same as the +clip mask in the dst (clients do the strangest things), so care must +be taken when destroying things. This call is required because dix +does not know how to copy the clip mask from pgcSrc. + +.NH 2 +Drawing Primitives +.XS +Drawing Primitives +.XE +.LP +The X protocol (rules for the byte stream that goes between client and server) +does all graphics using primitive +operations, which are called Drawing Primitives. +These include line drawing, area filling, arcs, and text drawing. +Your implementation must supply 16 routines +to perform these on your hardware. +(The number 16 is arbitrary.) + +More specifically, 16 procedure pointers are in each +GC op vector. +At any given time, ALL of them MUST point to a valid procedure that +attempts to do the operation assigned, although +the procedure pointers may change and may +point to different procedures to carry out the same operation. +A simple server will leave them all pointing to the same 16 routines, while +a more optimized implementation will switch each from one +procedure to another, depending upon what is most optimal +for the current GC and drawable. + +The sample server contains a considerable chunk of code called the +mi (machine independent) +routines, which serve as drawing primitive routines. +Many server implementations will be able to use these as-is, +because they work for arbitrary depths. +They make no assumptions about the formats of pixmaps +and frame buffers, since they call a set of routines +known as the "Pixblit Routines" (see next section). +They do assume that the way to draw is +through these low-level routines that apply pixel values rows at a time. +If your hardware or firmware gives more performance when +things are done differently, you will want to take this fact into account +and rewrite some or all of the drawing primitives to fit your needs. + +.NH 3 +GC Components +.XS +GC Components +.XE +.LP +This section describes the fields in the GC that affect each drawing primitive. +The only primitive that is not affected is GetImage, which does not use a GC +because its destination is a protocol-style bit image. +Since each drawing primitive mirrors exactly the X protocol request of the +same name, you should refer to the X protocol specification document +for more details. + +ALL of these routines MUST CLIP to the +appropriate regions in the drawable. +Since there are many regions to clip to simultaneously, +your ValidateGC routine should combine these into a unified +clip region to which your drawing routines can quickly refer. +This is exactly what the cfb and mfb routines supplied with the sample server +do. +The mi implementation passes responsibility for clipping while drawing +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 the drawable; +only planes with 1 bits in the mask are affected by any drawing operation. + +All functions except for ImageText calls must obey the alu function. +This is usually Copy, but could be any of the allowable 16 raster-ops. + +All of the functions, except for CopyArea, might use the current +foreground and background pixel values. +Each pixel value is 32 bits. +These correspond to foreground and background colors, but you have +to run them through the colormap 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, cap style, and join style. +Line width is in pixels. +The line style specifies whether it is solid or dashed, and what kind of dash. +The cap style specifies whether Rounded, Butt, etc. +The join style specifies whether joins between joined lines are Miter, Round or Beveled. +When lines cross as part of 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; this is the client's way +of telling you that you can optimize line drawing with little regard to +the end caps and joins. +They are called "thin" lines and are meant to be one pixel wide. +These are frequently done in hardware or in a streamlined assembly language +routine. + +Lines with widths greater than zero, though, must all be drawn with the same +algorithm, because client software assumes that every jag on every +line at an angle will come at the same place. +Two lines that should have +one pixel in the space between them +(because of their distance apart and their widths) should have such a one-pixel line +of space between them if drawn, regardless of angle. + +The solid area fill routines (FillPolygon, PolyFillRect, PolyFillArc) +all use the fill rule, which specifies subtle interpretations of +what points are inside and what are outside of a given polygon. +The PolyFillArc routine also uses the arc mode, which specifies +whether to fill pie segments or single-edge slices of an ellipse. + +The line drawing, area fill, and PolyText routines must all +apply the correct "fill style." +This can be either a solid foreground color, a transparent stipple, +an opaque stipple, or a tile. +Stipples are bitmaps where the 1 bits represent that the foreground color is written, +and 0 bits represent that either the pixel is left alone (transparent) or that +the background color is written (opaque). +A tile is a pixmap of the full depth of the GC that is applied in its full glory to all areas. +The stipple and tile patterns can be any rectangular size, although some implementations +will be faster for certain sizes such as 8x8 or 32x32. +The mi implementation passes this responsibility down to the Pixblit routines. + +See the X protocol document for full details. +The description of the CreateGC request has a very good, detailed description of these +attributes. + +.NH 3 +The Primitives +.XS +The Primitives +.XE +.LP +The Drawing Primitives are as follows: + +.nf + + 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; + +.fi +CopyArea copies a rectangle of pixels from one drawable to another of +the same depth. To effect scrolling, this must be able to copy from +any drawable to itself, overlapped. No squeezing or stretching is done +because the source and destination are the same size. However, +everything is still clipped to the clip regions of the destination +drawable. + +If pGC->graphicsExposures is True, any portions of the destination which +were not valid in the source (either occluded by covering windows, or +outside the bounds of the drawable) should be collected together and +returned as a region (if this resultant region is empty, NULL can be +returned instead). Furthermore, the invalid bits of the source are +not copied to the destination and (when the destination is a window) +are filled with the background tile. The sample routine +miHandleExposures generates the appropriate return value and fills the +invalid area using pScreen->PaintWindowBackground. + +For instance, imagine a window that is partially obscured by other +windows in front of it. As text is scrolled on your window, the pixels +that are scrolled out from under obscuring windows will not be +available on the screen to copy to the right places, and so an exposure +event must be sent for the client to correctly repaint them. Of +course, if you implement some sort of backing store, you could do this +without resorting to exposure events. + +An example implementation is mfbCopyArea() in Xserver/mfb/mfbbitblt.c. +.nf + + 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; + +.fi +CopyPlane must copy one plane of a rectangle from the source drawable +onto the destination drawable. Because this routine only copies one +bit out of each pixel, it can copy between drawables of different +depths. This is the only way of copying between drawables of +different depths, except for copying bitmaps to pixmaps and applying +foreground and background colors to it. All other conditions of +CopyArea apply to CopyPlane too. + +An example implementation is mfbCopyPlane() in +Xserver/mfb/mfbbitblt.c. +.nf + + void pGC->ops->PolyPoint(dst, pGC, mode, n, pPoint) + DrawablePtr dst; + GCPtr pGC; + int mode; + int n; + DDXPointPtr pPoint; + +.fi +PolyPoint draws a set of one-pixel dots (foreground color) +at the locations given in the array. +mode is one of the defined constants Origin (absolute coordinates) or Previous +(each coordinate is relative to the last). +Note that this does not use the background color or any tiles or stipples. + +Example implementations are mfbPolyPoint() in Xserver/mfb/mfbpolypnt.c and +miPolyPoint in Xserver/mi/mipolypnt.c. +.nf + + void pGC->ops->Polylines(dst, pGC, mode, n, pPoint) + DrawablePtr dst; + GCPtr pGC; + int mode; + int n; + DDXPointPtr pPoint; + +.fi +Similar to PolyPoint, Polylines draws lines between the locations given in the array. +Zero-width lines are NOT meant to be really zero width; this is the client's way of +telling you that you can maximally optimize line drawing with little regard to +the end caps and joins. +mode is one of the defined constants Previous or Origin, depending upon +whether the points are each relative to the last or are absolute. + +Example implementations are miWideLine() and miWideDash() in +mi/miwideline.c and miZeroLine() in mi/mizerline.c. +.nf + + void pGC->ops->PolySegment(dst, pGC, n, pPoint) + DrawablePtr dst; + GCPtr pGC; + int n; + xSegment *pSegments; + +.fi +PolySegments draws unconnected +lines between pairs of points in the array; the array must be of +even size; no interconnecting lines are drawn. + +An example implementation is miPolySegment() in mipolyseg.c. +.nf + + void pGC->ops->PolyRectangle(dst, pGC, n, pRect) + DrawablePtr dst; + GCPtr pGC; + int n; + xRectangle *pRect; + +.fi +PolyRectangle draws outlines of rectangles for each rectangle in the array. + +An example implementation is miPolyRectangle() in Xserver/mi/mipolyrect.c. +.nf + + void pGC->ops->PolyArc(dst, pGC, n, pArc) + DrawablePtr dst; + GCPtr pGC; + int n; + xArc*pArc; + +.fi +PolyArc draws connected conic arcs according to the descriptions in the array. +See the protocol specification for more details. + +Example implementations are miZeroPolyArc in Xserver/mi/mizerarc. and +miPolyArc() in Xserver/mi/miarc.c. +.nf + + void pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pPoint) + DrawablePtr dst; + GCPtr pGC; + int shape; + int mode; + int count; + DDXPointPtr pPoint; + +.fi +FillPolygon fills a polygon specified by the points in the array +with the appropriate fill style. +If necessary, an extra border line is assumed between the starting and ending lines. +The shape can be used as a hint +to optimize filling; it indicates whether it is convex (all interior angles +less than 180), nonconvex (some interior angles greater than 180 but +border does not cross itself), or complex (border crosses itself). +You can choose appropriate algorithms or hardware based upon mode. +mode is one of the defined constants Previous or Origin, depending upon +whether the points are each relative to the last or are absolute. + +An example implementation is miFillPolygon() in Xserver/mi/mipoly.c. +.nf + + void pGC->ops->PolyFillRect(dst, pGC, n, pRect) + DrawablePtr dst; + GCPtr pGC; + int n; + xRectangle *pRect; + +.fi +PolyFillRect fills multiple rectangles. + +Example implementations are mfbPolyFillRect() in Xserver/mfb/mfbfillrct.c and +miPolyFillRect() in Xserver/mi/mifillrct.c. +.nf + + void pGC->ops->PolyFillArc(dst, pGC, n, pArc) + DrawablePtr dst; + GCPtr pGC; + int n; + xArc *pArc; + +.fi +PolyFillArc fills a shape for each arc in the +list that is bounded by the arc and one or two +line segments with the current fill style. + +An example implementation is miPolyFillArc() in Xserver/mi/mifillarc.c. +.nf + + 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; + +.fi +PutImage copies a pixmap image into the drawable. The pixmap image +must be in X protocol format (either Bitmap, XYPixmap, or ZPixmap), +and format tells the format. (See the X protocol specification for +details on these formats). You must be able to accept all three +formats, because the client gets to decide which format to send. +Either the drawable and the pixmap image have the same depth, or the +source pixmap image must be a Bitmap. If a Bitmap, the foreground and +background colors will be applied to the destination. + +An example implementation is miPutImage() in Xserver/mfb/mibitblt.c. +.nf + + 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; + +.fi +GetImage copies the bits from the source drawable into +the destination pointer. The bits are written into the buffer +according to the server-defined pixmap padding rules. +pBinImage is guaranteed to be big enough to hold all +the bits that must be written. + +This routine does not correspond exactly to the X protocol GetImage +request, since DIX has to break the reply up into buffers of a size +requested by the transport layer. If format is ZPixmap, the bits are +written in the ZFormat for the depth of the drawable; if there is a 0 +bit in the planeMask for a particular plane, all pixels must have the +bit in that plane equal to 0. If format is XYPixmap, planemask is +guaranteed to have a single bit set; the bits should be written in +Bitmap format, which is the format for a single plane of an XYPixmap. + +An example implementation is miGetImage() in Xserver/mi/mibitblt.c. +.nf + + void pGC->ops->ImageText8(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; + +.fi +ImageText8 draws text. The text is drawn in the foreground color; the +background color fills the remainder of the character rectangles. The +coordinates specify the baseline and start of the text. + +An example implementation is miImageText8() in Xserver/mi/mipolytext.c. +.nf + + int pGC->ops->PolyText8(pDraw, pGC, x, y, count, chars) + DrawablePtr pDraw; + GCPtr pGC; + int x, y; + int count; + char *chars; + +.fi +PolyText8 works like ImageText8, except it draws with +the current fill style for special effects such as +shaded text. +See the X protocol specification for more details. + +An example implementation is miPolyText8() in Xserver/mi/mipolytext.c. +.nf + + 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; + +.fi +These two routines are the same as the "8" versions, +except that they are for 16-bit character codes (useful +for oriental writing systems). + +The primary difference is in the way the character information is +looked up. The 8-bit and the 16-bit versions obviously have different +kinds of character values to look up; the main goal of the lookup is +to provide a pointer to the CharInfo structs for the characters to +draw and to pass these pointers to the Glyph routines. Given a +CharInfo struct, lower-level software can draw the glyph desired with +little concern for other characteristics of the font. + +16-bit character fonts have a row-and-column scheme, where the 2bytes +of the character code constitute the row and column in a square matrix +of CharInfo structs. Each font has row and column minimum and maximum +values; the CharInfo structures form a two-dimensional matrix. + +Example implementations are miPolyText16() and +miImageText16() in Xserver/mi/mipolytext.c. + +See the X protocol specification for more details on these graphic operations. +.LP +There is a hook in the GC ops, called LineHelper, that used to be used in the +sample implementation by the code for wide lines. It no longer servers any +purpose in the sample servers, but still exists, #ifdef'ed by NEED_LINEHELPER, +in case someone needs it. +.NH 2 +Pixblit Procedures +.XS +Pixblit Procedures +.XE +.LP +The Drawing Primitive functions must be defined for your server. +One possible way to do this is to use the mi routines from the sample server. +If you choose to use the mi routines (even part of them!) you must implement +these Pixblit routines. +These routines read and write pixel values +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 as portable as the mi routines. + +The mfb routines only work for monochrome frame buffers, the simplest +type of display. Furthermore, they only work for screens that +organize their bits in rows of pixels on the screen. (See the +Strategies document for more details on porting mfb.) The cfb +routines work for packed-pixel displays from 2 to 32 bits in depth, +although they have a bit of code which has been tuned to run on 8-bit +(1 pixel per byte) displays. + +In other words, if you have a "normal" frame buffer type display, you +can probably use either the mfb or cfb code, and the mi code. If you +have a stranger hardware, you will have to supply your own Pixblit +routines, but you can use the mi routines on top of them. If you have +better ways of doing some of the Drawing Primitive functions, then you +may want to supply some of your own Drawing Primitive routines. (Even +people who write their own Drawing Primitives save at least some of +the mi code for certain special cases that their hardware or library +or fancy algorithm does not handle.) + +The client, DIX, and the machine-independent routines do not carry the +final responsibility of clipping. They all depend upon 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 high level, but +this is only for increased performance and cannot substitute for +bottom-level clipping. For instance, the mi routines, DIX, or the +client may decide to check all character strings to be drawn and chop +off all characters that would not be displayed. If so, it must retain +the character on the edge that is partly displayed so that the Pixblit +routines can clip off precisely at the right place.) + +To make this easier, all of the reasons to clip can be combined into +one region in your ValidateGC procedure. You take this composite clip +region with you into the Pixblit routines. (The sample server does +this.) + +Also, FillSpans() has to apply tile and stipple patterns. The +patterns are all aligned to the window origin so that when two people +write patches that are contiguous, they will merge nicely. (Really, +they are aligned to the patOrg point in the GC. This defaults to (0, +0) but can be set by the client to anything.) + +However, the mi routines can translate (relocate) the points from +window-relative to screen-relative if desired. If you set the +miTranslate field in the GC (set it in the CreateGC or ValidateGC +routine), then the mi output routines will translate all coordinates. +If it is false, then the coordinates will be passed window-relative. +Screens with no hardware translation will probably set miTranslate to +TRUE, so that geometry (e.g. polygons, rectangles) can be translated, +rather than having the resulting list of scanlines translated; this is +good because the list vertices in a drawing request will generally be +much smaller than the list of scanlines it produces. Similarly, +hardware that does translation can set miTranslate to FALSE, and avoid +the extra 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 to be called as often, and +so has different constraints.) The miTranslate field is settable in +each GC, if , for example, you are mixing several kinds of +destinations (offscreen pixmaps, 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 GC to direct +higher code to the correct routine to execute for each function. In +this way, you can optimize for special cases, for example, drawing +solids versus drawing stipples. + +The Pixblit routines are broken up into three sets. The Span routines +simply fill in rows of pixels. The Glyph routines fill in character +glyphs. The PushPixels routine is a three-input bitblt for more +sophisticated image creation. + +It turns out that the Glyph and PushPixels routines actually have a +machine-independent implementation that depends upon the Span +routines. If you are really pressed for time, you can use these +versions, although they are quite slow. + +.NH 3 +Span Routines +.XS +Span Routines +.XE +.LP +For these routines, all graphic operations have been reduced to "spans." +A span is a horizontal row of pixels. +If you can design these routines which write into and read from +rows of pixels at a time, you can use the mi routines. + +Each routine takes +a destination drawable to draw into, a GC to use while drawing, +the number of spans to do, and two pointers to arrays that indicate the list +of starting points and the list of widths of spans. +.nf + + void pGC->ops->FillSpans(dst, pGC, nSpans, pPoints, pWidths, sorted) + DrawablePtr dst; + GCPtr pGC; + int nSpans; + DDXPointPtr pPoints; + int *pWidths; + int sorted; + +.fi +FillSpans should fill horizontal rows of pixels with +the appropriate patterns, stipples, etc., +based on the values in the GC. +The starting points are in the array at pPoints; the widths are in pWidths. +If sorted is true, the scan lines are in increasing y order, in which case +you may be able to make assumptions and optimizations. +.LP +GC components: alu, clipOrg, clientClip, and fillStyle. +.LP +GC mode-dependent components: fgPixel (for fillStyle Solid); tile, patOrg +(for fillStyle Tile); stipple, patOrg, fgPixel (for fillStyle Stipple); +and stipple, patOrg, fgPixel and bgPixel (for fillStyle OpaqueStipple). + +.nf + + 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; + +.fi +For each span, this routine should copy pWidths bits from pSrc to +pDrawable at pPoints using the raster-op from the GC. +If sorted is true, the scan lines are in increasing y order. +The pixels in pSrc are +padded according to the screen's padding rules. +These +can be used to support +interesting extension libraries, for example, shaded primitives. It does not +use the tile and stipple. +.LP +GC components: alu, clipOrg, and clientClip +.LP + +The above functions are expected to handle all modifiers in the current +GC. Therefore, it is expedient to have +different routines to quickly handle common special cases +and reload the procedure pointers +at validate time, as with the other output functions. +.nf + + void pScreen->GetSpans(pDrawable, wMax, pPoints, pWidths, nSpans) + DrawablePtr pDrawable; + int wMax; + DDXPointPtr pPoints; + int *pWidths; + int nSpans; + char *pDst; + +.fi +For each span, GetSpans gets bits from the drawable starting at pPoints +and continuing for pWidths bits. +Each scanline returned will be server-scanline padded. +The routine can return NULL if memory cannot be allocated to hold the +result. + +GetSpans never translates -- for a window, the coordinates are already +screen-relative. Consider the case of hardware that doesn't do +translation: the mi code that calls ddX will translate each shape +(rectangle, polygon,. etc.) before scan-converting it, which requires +many fewer additions that having GetSpans translate each span does. +Conversely, consider hardware that does translate: it can set its +translation point to (0, 0) and get each span, and the only penalty is +the small number of additions required to translate each shape being +scan-converted by the calling code. Contrast the behavior of +FillSpans and SetSpans (discussed above under miTranslate), which are +expected to be used more often. + +Thus, the penalty to hardware that does hardware translation is +negligible, and code that wants to call GetSpans() is greatly +simplified, both for extensions and the machine-independent core +implementation. + +.NH 4 +Glyph Routines +.XS +Glyph Routines +.XE +.LP +The Glyph routines draw individual character glyphs for text drawing requests. + +You have a choice in implementing these routines. You can use the mi +versions; they depend ultimately upon the span routines. Although +text drawing will work, it will be very slow. + +.nf + + 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 */ + +.fi +.LP +GC components: alu, clipOrg, clientClip, font, and fillStyle. +.LP +GC mode-dependent components: fgPixel (for fillStyle Solid); tile, patOrg +(for fillStyle Tile); stipple, patOrg, fgPixel (for fillStyle Stipple); +and stipple, patOrg, fgPixel and bgPixel (for fillStyle OpaqueStipple). +.nf + + 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 */ + +.fi +.LP +GC components: clipOrg, clientClip, font, fgPixel, bgPixel +.LP +These routines must copy the glyphs defined by the bitmaps in +pglyphBase and the font metrics in ppci to the DrawablePtr, pDrawable. +The poly routine follows all fill, stipple, and tile rules. The image +routine simply blasts the glyph onto the glyph's rectangle, in +foreground and background colors. + +More precisely, the Image routine fills the character rectangle with +the background color, and then the glyph is applied in the foreground +color. The glyph can extend outside of the character rectangle. +ImageGlyph() is used for terminal emulators and informal text purposes +such as button labels. + +The exact specification for the Poly routine is that the glyph is +painted with the current fill style. The character rectangle is +irrelevant for this operation. PolyText, at a higher level, includes +facilities for font changes within strings and such; it is to be used +for WYSIWYG word processing and similar systems. + +Both of these routines must clip themselves to the overall clipping region. + +Example implementations in mi are miPolyGlyphBlt() and +miImageGlyphBlt() in Xserver/mi/miglblt.c. + +.NH 4 +PushPixels routine +.XS +PushPixels routine +.XE +.LP +The PushPixels routine writes the current fill style onto the drawable +in a certain shape defined by a bitmap. PushPixels is equivalent to +using a second stipple. You can thing of it as pushing the fillStyle +through a stencil. PushPixels is not used by any of the mi rendering code, +but is used by the mi software cursor code. +.LP +.nf +.ta 1i 3i + Suppose the stencil is: 00111100 + and the stipple is: 10101010 + PushPixels result: 00101000 +.fi +.LP +You have a choice in implementing this routine. +You can use the mi version which depends ultimately upon FillSpans(). +Although it will work, it will be slow. +.LP +.nf + + void pGC->ops->PushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDrawable; + int dx, dy, xOrg, yOrg; + +.fi +.LP +GC components: alu, clipOrg, clientClip, and fillStyle. +.LP +GC mode-dependent components: fgPixel (for fillStyle Solid); tile, patOrg +(for fillStyle Tile); stipple, patOrg, fgPixel (for fillStyle Stipple); +and stipple, patOrg, fgPixel and bgPixel (for fillStyle OpaqueStipple). + +PushPixels applys the foreground color, tile, or stipple from the pGC +through a stencil onto pDrawable. pBitMap points to a stencil (of +which we use an area dx wide by dy high), which is oriented over the +drawable at xOrg, yOrg. Where there is a 1 bit in the bitmap, the +destination is set according to the current fill style. Where there +is a 0 bit in the bitmap, the destination is left the way it is. + +This routine must clip to the overall clipping region. + +An Example implementation is miPushPixels() in Xserver/mi/mipushpxl.c. + +.NH 2 +Shutdown Procedures +.XS +Shutdown Procedures +.XE +.LP +.nf + void AbortDDX() + void ddxGiveUp() +.fi +.LP +Some hardware may require special work to be done before the server +exits so that it is not left in an intermediate state. As explained +in the OS layer, FatalError() will call AbortDDX() just before +terminating the server. In addition, ddxGiveUp() will be called just +before terminating the server on a "clean" death. What AbortDDX() and +ddxGiveUP do is left unspecified, only that stubs must exist in the +ddx layer. It is up to local implementors as to what they should +accomplish before termination. + +.NH 3 +Command Line Procedures +.XS +Command Line Procedures +.XE +.LP +.nf + int ddxProcessArgument(argc, argv, i) + int argc; + char *argv[]; + int i; + + void + ddxUseMsg() + +.fi +.LP +You should write these routines to deal with device-dependent command line +arguments. The routine ddxProcessArgument() is called with the command line, +and the current index into argv; you should return zero if the argument +is not a device-dependent one, and otherwise return a count of the number +of elements of argv that are part of this one argument. For a typical +option (e.g., "-realtime"), you should return the value one. This +routine gets called before checks are made against device-independent +arguments, so it is possible to peek at all arguments or to override +device-independent argument processing. You can document the +device-dependent arguments in ddxUseMsg(), which will be +called from UseMsg() after printing out the device-independent arguments. + +.bp +.NH 2 +Wrappers and devPrivates +.XS +Wrappers and devPrivates +.XE +.LP +Two new extensibility concepts have been developed for release 4, Wrappers +and devPrivates. These replace the R3 GCInterest queues, which were not a +general enough mechanism for many extensions and only provided hooks into a +single data structure. +.NH 3 +devPrivates +.XS +devPrivates +.XE +.LP +devPrivates are arrays of values attached to various data structures +(Screens, GCs, Windows, and Pixmaps currently). These arrays are sized dynamically at +server startup (and reset) time as various modules allocate portions of +them. They can be used for any purpose; each array entry is actually a +union, DevUnion, of common useful types (pointer, long and unsigned long). +devPrivates must be allocated on startup and whenever the server resets. To +make this easier, the global variable "serverGeneration" is incremented each +time devPrivates should be allocated, but before the initialization process +begins, typical usage would be: +.nf +static int privateGeneration = 0; + + if (privateGeneration != serverGeneration) + { + allocate devPrivates here. + + privateGeneration = serverGeneration; + } +.fi +.NH 4 +Screen devPrivates +.XS +Screen devPrivates +.XE +.LP +An index into every screen devPrivates array is allocated with +.nf + int AllocateScreenPrivateIndex() +.fi +This call can occur at any time, each existing devPrivates array is resized +to accommodate the new entry. This routine returns -1 indicating an +allocation failure. Otherwise, the return value can be used to index the +array of devPrivates on any screen: +.nf + private = (PrivatePointer) pScreen->devPrivates[screenPrivateIndex].ptr; +.fi +The pointer in each screen is not initialized by +AllocateScreenPrivateIndex(). +.NH 4 +Window devPrivates +.XS +Window devPrivates +.XE +.LP +An index into every window devPrivates array is allocated with +.nf + int AllocateWindowPrivateIndex () +.fi +AllocateWindowPrivateIndex() never returns an error. This call must be +associated with a call which causes a chunk of memory to be automatically +allocated and attached to the devPrivate entry on every screen which the +module will need to use the index: +.nf + Bool AllocateWindowPrivate (pScreen, index, amount) + ScreenPtr pScreen; + int index; + unsigned amount; +.fi +If this space is not always needed for every object, use 0 as the amount. +In this case, the pointer field of the entry in the devPrivates array is +initialized to NULL. This call exists so that DIX may preallocate all of +the space required for an object with one call; this reduces memory +fragmentation considerably. AllocateWindowPrivate returns FALSE on +allocation failure. Both of these calls must occur before any window +structures are allocated; the server is careful to avoid window creation +until all modules are initialized, but do not call this after +initialization. A typical allocation sequence for WindowPrivates would be: +.nf + privateInitialize (pScreen) + ScreenPtr pScreen; + { + if (privateGeneration != serverGeneration) + { + windowPrivateIndex = AllocateWindowPrivateIndex(); + privateGeneration = serverGeneration; + } + + return (AllocateWindowPrivate(pScreen, windowPrivateIndex, + sizeof(windowPrivateStructure))); + } +.fi +.NH 4 +GC and Pixmap devPrivates +.XS +GC and Pixmap devPrivates +.XE +.LP +The calls for GCs and Pixmaps mirror the Window calls exactly; they have the +same requirements and limitations: +.nf + 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; +.fi +.NH 3 +Wrappers +.XS +Wrappers +.XE +.LP +Wrappers are not a body of code, nor an interface spec. They are, instead, +a technique for hooking a new module into an existing calling sequence. +There are limitations on other portions of the server implementation which +make using wrappers possible; limits on when specific fields of data +structures may be modified. They are intended as a replacement for +GCInterest queues, which were not general enough to support existing +modules; in particular software cursors and backing store both needed more +control over the activity. The general mechanism for using wrappers is: +.nf +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; +} +.fi +Thus the privateWrapperFunction provides hooks for performing work both +before and after the wrapped function has been called; the process of +resetting the functionVector is called "unwrapping" while the process of +fetching the wrapped function and replacing it with the wrapping function +is called "wrapping". It should be clear that GCInterest queues could +be emulated using wrappers. In general, any function vectors contained in +objects can be wrapped, but only vectors in GCs and Screens have been tested. +.LP +Wrapping screen functions is quite easy; each vector is individually +wrapped. Screen functions are not supposed to change after initialization, +so rewrapping is technically not necessary, but causes no problems. +.LP +Wrapping GC functions is a bit more complicated. GC's have two tables of +function vectors, one hanging from gc->ops and the other from gc->funcs, which +should be initially wrapped from a CreateGC wrapper. Wrappers should modify +only table pointers, not the contents of the tables, as they +may be shared by more than one GC (and, in the case of funcs, are probably +shared by all gcs). Your func wrappers may change the GC funcs or ops +pointers, and op wrappers may change the GC op pointers but not the funcs. + +Thus, the rule for GC wrappings is: wrap the funcs from CreateGC and, in each +func wrapper, unwrap the ops and funcs, call down, and re-wrap. In each op +wrapper, unwrap the ops, call down, and rewrap afterwards. Note that in +re-wrapping you must save out the pointer you're replacing again. This way the +chain will be maintained when wrappers adjust the funcs/ops tables they use. +.LP +.NH 2 +Work Queue +.XS +Work Queue +.XE +.LP +To queue work for execution when all clients are in a stable state (i.e. +just before calling select() in WaitForSomething), call: +.nf + Bool QueueWorkProc(function,client,closure) + Bool (*function)(); + ClientPtr client; + pointer closure; +.fi +.LP +When the server is about to suspend itself, the given function will be +executed: +.nf + (*function) (client, closure) +.fi +.LP +Neither client nor closure are actually used inside the work queue routines. +.NH 1 +Extension Interfaces +.XS +Extension Interfaces +.XE +.LP +This section describes the functions which exist in DDX for extension +writers to use. +.NH 2 +Extension initialization +.LP +This function should be called from your extensionInitProc which +should be called by InitExtensions. +.nf + + 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); + +.fi +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). +.NH 2 +Resource type allocation. +.LP +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 +.nf + + RESTYPE CreateNewResourceType(deleteFunc) + +.fi +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 +.nf + + RESTYPE CreateNewResourceClass() + +.fi +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). +.LP +Note that the appropriate class bits must be or'ed into the value returned +by CreateNewResourceType when calling resource lookup functions. +.LP +If you need to create a ``private'' resource ID for internal use, you +can call FakeClientID. +.nf + + XID FakeClientID(client) + int client; + +.fi +This allocates from ID space reserved for the server. +.LP +To associate a resource value with an ID, use AddResource. +.nf + + Bool AddResource(id, type, value) + XID id; + RESTYPE type; + pointer value; + +.fi +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. +.LP +To free a resource, use one of the following. +.nf + + void FreeResource(id, skipDeleteFuncType) + XID id; + RESTYPE skipDeleteFuncType; + + void FreeResourceByType(id, type, skipFree) + XID id; + RESTYPE type; + Bool skipFree; + +.nf +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. +.LP +To look up a resource, use one of the following. +.nf + + pointer LookupIDByType(id, rtype) + XID id; + RESTYPE rtype; + + pointer LookupIDByClass(id, classes) + XID id; + RESTYPE classes; + +.fi +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. +.NH 2 +Macros and Other Helpers +.LP +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. +.bp +.NH 1 +Callback Manager +.XS +Callback Manager +.XE +.LP +To satisfy a growing number of requests for the introduction of ad hoc +notification style hooks in the server, a generic callback manager was +introduced in R6. A callback list object can be introduced for each +new hook that is desired, and other modules in the server can register +interest in the new callback list. The following functions support +these operations. +.LP +Before getting bogged down in the interface details, an typical usage +example should establish the framework. Let's look at the +ClientStateCallback in dix/dispatch.c. The purpose of this particular +callback is to notify intereseted parties when a client's state +(initial, running, gone) changes. The callback is "created" in this +case by simply declaring a variable: + + CallbackListPtr ClientStateCallback; + +Whenever the client's state changes, the following code appears, which notifies +all intereseted parties of the change: + + if (ClientStateCallback) CallCallbacks(&ClientStateCallback, (pointer)client); + +Interested parties subscribe to the ClientStateCallback list by saying: + + AddCallback(&ClientStateCallback, func, data); + +When CallCallbacks is invoked on the list, func will be called thusly: + + (*func)(&ClientStateCallback, data, client) + +Now for the details. +.nf + + Bool CreateCallbackList(pcbl, cbfuncs) + CallbackListPtr *pcbl; + CallbackFuncsPtr cbfuncs; + +.fi +CreateCallbackList creates a callback list. We envision that this +function will be rarely used because the callback list is created +automatically (if it doesn't already exist) when the first call to +AddCallback is made on the list. The only reason to explicitly create +the callback list with this function is if you want to override the +implementation of some of the other operations on the list by passing +your own cbfuncs. You also lose something by explicit creation: you +introduce an order dependency during server startup because the list +must be created before any modules subscribe to it. Returns TRUE if +successful. +.nf + + Bool AddCallback(pcbl, callback, subscriber_data) + CallbackListPtr *pcbl; + CallbackProcPtr callback; + pointer subscriber_data; + +.fi +Adds the (callback, subscriber_data) pair to the given callback list. Creates the callback +list if it doesn't exist. Returns TRUE if successful. +.nf + + Bool DeleteCallback(pcbl, callback, subscriber_data) + CallbackListPtr *pcbl; + CallbackProcPtr callback; + pointer subscriber_data; + +.fi +Removes the (callback, data) pair to the given callback list if present. +Returns TRUE if (callback, data) was found. +.nf + + void CallCallbacks(pcbl, call_data) + CallbackListPtr *pcbl; + pointer call_data; + +.fi +For each callback currently registered on the given callback list, call +it as follows: + + (*callback)(pcbl, subscriber_data, call_data); + +.nf + + void DeleteCallbackList(pcbl) + CallbackListPtr *pcbl; + +.fi +Destroys the given callback list. +.bp +.NH 1 +Summary of Routines +.XS +Summary of Routines +.XE +.LP +This is a summary of the routines discussed in this document. +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 named as shown. +The sample server provides implementations in the following +categories. Notice that many of the graphics routines have both +mi and mfb implementations. +.TS +l l. +dix portable to all systems; do not attempt to rewrite (Xserver/dix) +os routine provided in Xserver/os or Xserver/include/os.h +ddx frame buffer dependent (examples in Xserver/mfb,Xserver/cfb) +mi routine provided in Xserver/mi +hd hardware dependent (examples in many Xserver/hw directories) +none not implemented in sample implementation +.TE +.TS +expand; +c c c +l c l. +Procedure Port Struct +_ +ALLOCATE_LOCAL os +AbortDDX hd +AddCallback dix +AddEnabledDevice os +AddInputDevice dix +AddScreen dix +AdjustWaitForDelay os +Bell hd Device +ChangeClip mi GC func +ChangeGC GC func +ChangeWindowAttributes ddx Screen +ClearToBackground ddx Window +ClientAuthorized os +ClientSignal dix +ClientSleep dix +ClientWakeup dix +ClipNotify ddx Screen +CloseScreen hd +ConstrainCursor hd Screen +CopyArea mi GC op +CopyGCDest ddx GC func +CopyGCSource none GC func +CopyPlane mi GC op +CopyWindow ddx Window +CreateGC ddx Screen +CreateCallbackList dix +CreatePixmap ddx Screen +CreateScreenResources ddx Screen +CreateWellKnowSockets os +CreateWindow ddx Screen +CursorLimits hd Screen +DEALLOCATE_LOCAL os +DeleteCallback dix +DeleteCallbackList dix +DestroyClip ddx GC func +DestroyGC ddx GC func +DestroyPixmap ddx Screen +DestroyWindow ddx Screen +DisplayCursor hd Screen +Error os +.TE +.bp +.TS +expand; +c c c +l c l. +Procedure Port Struct +_ +ErrorF os +FatalError os +FillPolygon mi GC op +FillSpans ddx GC op +FlushAllOutput os +FlushIfCriticalOutputPending os +FreeScratchPixmapHeader dix +GetImage mi Screen +GetMotionEvents hd Device +GetScratchPixmapHeader dix +GetSpans ddx Screen +GetStaticColormap ddx Screen +ImageGlyphBlt mi GC op +ImageText16 mi GC op +ImageText8 mi GC op +InitInput hd +InitKeyboardDeviceStruct dix +InitOutput hd +InitPointerDeviceStruct dix +InsertFakeRequest os +InstallColormap ddx Screen +Intersect mi Screen +Inverse mi Screen +LegalModifier hd +LineHelper mi GC op +ListInstalledColormaps ddx Screen +LookupKeyboardDevice dix +LookupPointerDevice dix +ModifyPixmapheader mi Screen +NextAvailableClient dix +OsInit os +PaintWindowBackground mi Window +PaintWindowBorder mi Window +PointerNonInterestBox hd Screen +PointInRegion mi Screen +PolyArc mi GC op +PolyFillArc mi GC op +PolyFillRect mi GC op +PolyGlyphBlt mi GC op +Polylines mi GC op +PolyPoint mi GC op +PolyRectangle mi GC op +PolySegment mi GC op +PolyText16 mi GC op +PolyText8 mi GC op +PositionWindow ddx Screen +ProcessInputEvents hd +PushPixels mi GC op +PutImage mi GC op +QueryBestSize hd Screen +ReadRequestFromClient os +.TE +.bp +.TS +expand; +c c c +l c l. +Procedure Port Struct +_ +RealizeCursor hd Screen +RealizeFont ddx Screen +RealizeWindow ddx Screen +RecolorCursor hd Screen +RectIn mi Screen +RegionCopy mi Screen +RegionCreate mi Screen +RegionDestroy mi Screen +RegionEmpty mi Screen +RegionExtents mi Screen +RegionNotEmpty mi Screen +RegionReset mi Screen +ResolveColor ddx Screen +RegisterKeyboardDevice dix +RegisterPointerDevice dix +RemoveEnabledDevice os +ResetCurrentRequest os +RestoreAreas none BackingStore +SaveDoomedAreas none BackingStore +SaveScreen ddx Screen +SetCriticalOutputPending os +SetCursorPosition hd Screen +SetInputCheck dix +SetSpans ddx GC op +StoreColors ddx Screen +Subtract mi Screen +TimerCancel os +TimerCheck os +TimerForce os +TimerFree os +TimerInit os +TimerSet os +TimeSinceLastInputEvent hd +TranslateBackingStore none BackingStore +TranslateRegion mi Screen +UninstallColormap ddx Screen +Union mi Screen +UnrealizeCursor hd Screen +UnrealizeFont ddx Screen +UnrealizeWindow ddx Screen +ValidateGC ddx GC func +ValidateTree mi Screen +WaitForSomething os +WindowExposures mi Window +WriteToClient os +Xalloc os +Xfree os +Xrealloc os +.TE + +.TC |