In Chapter 2 and Chapter 3 you learned the basic concepts and tasks you need to write simple applications using XDPS. To write more complex applications, however, you need the additional concepts and tasks described in this chapter.
In XDPS, PostScript language code can be sent to a context in three encodings: as a binary object sequence, as binary-encoded tokens, or as ASCII text. Each PostScript context has two encoding parameters: DPSProgramEncoding and DPSNameEncoding.
XDPS uses default values for the encoding parameters, so application programmers can usually ignore encoding. Table 4-1 shows the default values for the encoding parameters.
Context Type | Encoding Parameter | Default Value |
execution | DPSProgramEncoding | Binary object sequence (dps_binObjSeq) |
execution | DPSNameEncoding | User name index (dps_indexed) |
text | DPSProgramEncoding | ASCII characters (dps_ascii) |
text | DPSNameEncoding | User name string (dps_string) |
XDPS lets you change the encoding parameters of a context to any of the three possible encodings. To change the encoding parameters, use the Client Library routine DPSChangeEncoding, described in Chapter 5.
In most implementations of the Display PostScript system, the Client Library buffers its communications with the Display PostScript server. But in XDPS, the Client Library communicates with the server by way of Xlib, which buffers its own communication. To avoid duplicate buffering, the XDPS Client Library performs no internal buffering. Instead, all buffering of Client Library communication occurs in Xlib. As a result, the XDPS Client Library routine DPSFlushContext performs the same tasks as the Xlib procedure XFlush.
To preserve security on servers, XDPS lets applications access only certain files stored on the server. Specifically, XDPS lets applications access only files stored in two directories referred to here as tempdir and permdir.
The tempdir directory is temporary: its contents are deleted each time the XDPS server is started or reset, such as when the user logs out. In contrast, permdir is a permanent directory: resetting and restarting does not affect its contents. Applications can both read from tempdir and write to it. Applications can only read from permdir; they cannot write to it.
To specify a file stored in tempdir, an application must prefix the filename with %temp%. To specify a file in permdir, an application must use the prefix %perm%. If a filename is preceded by neither %temp% nor %perm%, XDPS searches for the file first in tempdir and then in permdir. XDPS does not let applications access file names that include a slash (/), a bracket ([), or a colon (:).
By default, tempdir is the directory /usr/lib/DPS/tempdir; permdir is /usr/lib/DPS/permdir. You can, however, assign other directory names. To do so, specify those names in the XDPS server startup command.
The X Window System and the PostScript language use different coordinate systems to specify points within the drawing area. As a result, XDPS applications sometimes need to convert user space coordinates (used by the PostScript language) into X coordinates, and vice versa.
Before converting coordinates, an application should create a context and perform the following steps:
The application can then perform coordinate conversions for the context.
To get the CTM, its inverse, and the X coordinates of the current user space origin, an application can call a custom wrap such as PSWGetTransform, whose pswrap source file is shown in Example 4-1.
defineps PSWGetTransform(DPSContext ctxt | float ctm[6], invctm[6]; int *xOffset, *yOffset) matrix currentmatrix dup ctm matrix invertmatrix invctm currentXoffset exch xOffset yOffset endps
The following C language code calls PSWGetTransform:
DPSContext ctxt; float ctm[6], invctm[6]; int xOffset, yOffset; PSWGetTransform(ctxt, ctm, invctm, &xOffset, &yOffset);
To convert an X coordinate into a user space coordinate, an application can execute the following C language code:
#define A_COEFF 0 #define B_COEFF 1 #define C_COEFF 2 #define D_COEFF 3 #define TX_CONS 4 #define TY_CONS 5 int x,y; /* X coordinate */ float ux, uy; /* user space coordinate */
x -= xOffset; y -= yOffset; ux = invctm[A_COEFF] * x + invctm[C_COEFF] * y + invctm[TX_CONS]; uy = invctm[B_COEFF] * x + invctm[D_COEFF] * y + invctm[TY_CONS];
To convert a user space coordinate into an X coordinate, an application can execute the following C language code:
x = ctm[A_COEFF] * ux + ctm[C_COEFF] * uy + ctm[TX_CONS] + xOffset; y = ctm[B_COEFF] * ux + ctm[D_COEFF] * uy + ctm[TY_CONS] + yOffset;
An application or user can resize the window in which XDPS paints. Resizing can affect two PostScript language settings, the clipping path and the user space origin, as described in the following sections.
PostScript language painting occurs only within the area known as the clipping path. When initializing a context, XDPS sets the clipping path equal to the size of the window. If the window is resized, however, XDPS does not reset the clipping path. Instead, each time the window is resized, the application should execute the PostScript language operator initclip, which reinitializes the clipping path to match the window's new size. The application can then reexecute any code that performs further clipping.
When an application resizes the window of a context, the user space origin moves according to the bit gravity of the window. Bit gravity is an X window attribute that governs how partial window contents are preserved when a window is resized. (Bit gravity is not to be confused with window gravity, an X attribute that does not affect the user space origin.) In X, specifying the bit gravity of a window is optional: the default value is ForgetGravity. XDPS treats ForgetGravity as NorthWest gravity.
Because a window's user space origin moves according to the window's bit gravity, resizing does not change the distance between the user space origin and any PostScript language images already displayed. Because this distance is unchanged, future PostScript language images align with those already displayed.
Compare Figure 4-1 and Figure 4-2. The left side of Figure 4-1 shows a window displaying the text "NorthWest." As shown, the user space origin is the window's lower left corner, and the bit gravity is NorthWest.
The right side of the figure shows the same window after resizing. Notice that the user space origin (and hence the displayed text) remains a constant distance from the window's upper left corner: its "NorthWest" corner.
In Figure 4-2, the size of the window on the left and the position of its text are the same as in Figure 4-1. Also the same is the user space origin: the lower left corner. In Figure 4-2, however, the bit gravity is SouthWest. Therefore, when the window is resized, the user space origin and displayed text remain a constant distance from the window's lower left corner: its "SouthWest" corner.
The user space origin is typically the lower left corner of the drawing space. For this reason, typical XDPS applications should explicitly set the bit gravity of windows to SouthWest.
X imaging calls complete atomically. Therefore, XDPS applications need not take special precautions when issuing X imaging calls before PostScript language imaging calls. PostScript contexts, however, complete nonatomically and asynchronously within the X server. Thus, when an application issues X imaging calls immediately after issuing PostScript language calls, the X calls can sometimes execute before the PostScript language calls. That is, it is possible for X and the Display PostScript system to become unsynchronized.
Few applications need to synchronize the Display PostScript system and X explicitly. To do so, an application can call the Client Library routine DPSWaitContext before issuing the X imaging calls that follow PostScript language calls. DPSWaitContext forces the PostScript language calls to complete before the X calls. Note that DPSWaitContext causes a round trip to the server. Such trips impair performance, so call DPSWaitContext only when needed.
Applications, or clients, sometimes need to pause the execution of a context. Pausing a context lets an application take control when the PostScript interpreter reaches certain points within a PostScript language procedure.
To pause a context, an application sends the system-specific PostScript language operator clientsync. The clientsync operator causes a context to enter the FROZEN state. The context remains in that state until the application calls the Client Library routine XDPSUnfreezeContext. (For more information on clientsync, see its description in Chapter 6. For a description of XDPSUnfreezeContext, see Chapter 5.)
Although the XDPS Client Library lets applications share contexts and spaces, it does not coordinate the sharing. Instead, the applications themselves must coordinate any sharing of resources.
The sharing applications must avoid race conditions and deadlocks. In addition, if one application obtains the XID of a resource created by another, the application that obtained the XID must create records and handles to access the shared resource through the Client Library.
A context or space cannot be destroyed while shared. If such a resource is shared, the routines DPSDestroyContext and DPSDestroySpace destroy the client data structures created to access the shared resource but do not destroy the resource itself. After a resource is no longer shared, an application can destroy it by calling DPSDestroyContext or DPSDestroySpace.
In XDPS, the Display PostScript system paints colors and gray shades on an X server. An X server can render only a finite number of exact colors and shades simultaneously; it represents each as a pixel value. In contrast, the PostScript language represents colors and shades not as pixel values but as "pure" colors and "pure" shades, without regard for whether the output device can render them exactly. As a result, to paint on an X display, a PostScript context must first find whether there is a pixel value that matches the pure color or shade specified by the PostScript language.
To find the pixel value that matches a particular color or shade, a context searches the color cube or gray ramp. The color cube and gray ramp specify pixel values that correspond to a subset of all possible pure colors and shades.
The color cube defines a set of colormap cells whose values form a series of color ramps (progressive changes in color). Each axis of the color cube represents one of three hues: red, green, or blue (r/g/b); all displayed colors are composites of these hues. Values along the axes of the cube represent intensity of hue and increase from 0% to 100% of the displayed color. Note that the color cube is not a cube in the strict sense of the word: the axes need not have the same "length," that is, the same number of values.
The gray ramp defines a set of colormap cells whose values form a single color ramp of gray shades. Values along the gray ramp represent comparative intensities of black and white. Along the ramp, the intensity of white increases from 0% to 100%.
If the color cube or gray ramp contains a pixel value that exactly matches the specified pure color or shade, the context uses the pixel value to paint the pure color or shade. Otherwise, the context approximates the color or shade by dithering, by painting a pattern of colors or gray shades from its color cube or gray ramp.
When creating a context, an application must allocate and define a color cube and gray ramp. If the application defines no color cube, the context renders colors by dithering from the gray ramp. If the application defines neither a color cube nor a gray ramp, the context cannot paint.
Typically, applications create contexts by calling XDPSCreateSimpleContext. This routine allocates and defines a color cube and gray ramp using the XStandardColormap structures RGB_DEFAULT_MAP and RGB_GRAY_MAP. If these structures do not exist, XDPSCreateSimpleContext allocates them. To allocate and define a different color cube and gray ramp, an application can use either of two methods:
To allocate and define a color cube and gray ramp, an application performs the following steps:
The following sections describe how XDPS uses the color cube and gray ramp, referring to the following elements of the color cube and gray ramp:
maxred | redmult |
maxgreen | greenmult |
maxblue | bluemult |
maxgrays | graymult |
firstgray | firstcolor |
colormapid |
These names are the same as those used for elements of the colorinfo array, which is accessed by the X-specific operators setXgcdrawablecolor and currentXgcdrawablecolor. (For more information, see the description of these operators in Chapter 6.)
To render an exact color, XDPS searches the colormap for the pixel value matching the r/g/b value specified in the color cube. Conceptually, the color cube is three-dimensional; the colormap, however, is conceptually one-dimensional. Thus, to find the pixel value that matches an r/g/b value, XDPS uses the following formula:
PixelValue = r * redmult + g * greenmult + b * bluemult + firstcolor
In this formula,
r,
b,
and
g
are integers. The integer
r
is in the range
[0;
maxred];
g
is in the range
[0;
maxgreen];
and
b
is in the range
[0;
maxblue].
A color cube must start at pixel firstcolor in the X colormap colormapid. Along the red, green and blue axes of the cube, values should increase from zero to the maximum values for each axis. For example, one common color allocation is 3/3/2 (three reds, three greens, and two blues). This allocation results in the following maximum value for each hue:
maxred = 2
maxgreen = 2
maxblue = 1
In the colorinfo array, the elements redmult, greenmult, and bluemult are the scale factors that determine the spacing of the cube in the linear colormap. For the 3/3/2 color cube mentioned earlier, appropriate values might be:
redmult = 32
greenmult = 4
bluemult = 1
Note
In an empty color cube, maxred, maxgreen, and maxblue each equal -1, not zero.
The gray ramp must start at pixel firstgray in XStandardColormap colormapid. To find the pixel value that matches a gray value, XDPS uses the following formula, where gray is an integer in the range [0; maxgrays]:
PixelValue = gray * graymult + firstgray
For example, suppose you want to define a 5-cell gray ramp whose values increase from 0% to 100% in steps of 20%. If the corresponding five colormap entries are contiguous, you can describe the map by setting maxgray to 4 and graymult to 1.
A gray ramp must consist of at least two cells: one for black, one for white. If the colormap is associated with the default visual type, you can use the following values to form a 2-cell gray ramp consisting of BlackPixel and WhitePixel:
maxgrays = 1
graymult =
WhitePixel-
BlackPixel
firstgray =
BlackPixel
By default, XDPS dithers to render any color not in the color cube. To render such an additional color exactly, an application must cause the X server to allocate a colormap cell for the additional color.
To control whether additional colors are rendered exactly or by dithering, an application can set the actual element of the colorinfo array. The actual element specifies the maximum number of additional colormap cells that the server attempts to allocate. Thus, it limits the number of additional colors that the server attempts to render exactly.
If actual is nonzero, the server attempts to allocate a colormap cell for each additional color until it has allocated actual cells. After actual cells have been allocated, the server renders any future additional colors by dithering. If actual equals zero, the server dithers to render all colors not found in the color cube.
To override the maximum set by actual, an application can use the X-specific operator setrgbXactual.
Note
XDPS does not limit the number of colormap cells that one context or one application can allocate.
The color cube and gray ramp are passed to XDPSCreateContext as XStandardColormap structures. Table 4-2 and Table 4-3 show how the entries in these XStandardColormap structures correspond to elements in the colorinfo array.
colorinfo Element | XStandardColormap Element |
maxred | red_max |
redmult | red_mult |
maxgreen | green_max |
greenmult | green_mult |
maxblue | blue_max |
bluemult | blue_mult |
firstcolor | base_pixel |
colorinfo Element | XStandardColormap Element |
maxgrays | red_max |
graymult | red_mult |
firstgray | base_pixel |
colormapid | colormap |