5284 lines
186 KiB
Plaintext
5284 lines
186 KiB
Plaintext
.\" $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
|