[Copyright status: portions of this file are derived from from the X11R4 protocol document, which is Copyright (c) 1986, 1987, 1988 Massachusetts Institute of Technology Permission to use, copy, modify, and distribute this document for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice are retained, and that the name of M.I.T. not be used in advertising or publicity pertaining to this document without specific, written prior permission. M.I.T. makes no representations about the suitability of this document or the protocol defined in this document for any purpose. It is provided ``as is'' without express or implied warranty. Anything herein which is not derived from the X11R4 protocol document is in the public domain.] An X GC, which stands for `graphics context', is a server-side object collecting state used by various graphics requests, such as foreground colour and font. The X requests to create, change, and destroy GCs are fully supported by liblx (a GC, like other server-side objects such as windows and pixmaps, is represented as an LX_XID in the API). Each of these attributes has a default, which is used when a GC is created without specifying that attribute. Function -------- The function specifies how pixels being drawn are combined with pixels already present in the destination drawable. For most calls, the pixels being drawn are the GC's foreground colour, but for some the background colour is used as well, and for a few requests (eg, CopyArea; see lx_CopyArea in core.txt) any pixel value of the relevant depth can occur. There are four possible combinations of a bit from the source and a bit from the destination (both 0, both 1, source 0 and destination 1, and source 1 and destination 0). This then leads to 2<<4, or 16, possible truth tables for the destination bit. Any of the 16 may be used. Each one has a manifest constant for it; unlike most liblx manifest constants, there is some structure specified for them. Bitwise operations on them produce the expected effects, provided that, after doing the bitwise operations, you AND the result with LX_GCFUNCTION__mask and then OR the result of that with LX_GCFUNCTION__base. There are also LX_GCFUNCTION__src and LX_GCFUNCTION__dst, which represent the source and destination values (they are equal to LX_GCFUNCTION_Copy and LX_GCFUNCTION_NoOp). There is a convenience macro LX_GCFUNCTION_norm which performs the normalization AND and OR steps, as in LX_GCFUNCTION_norm(LX_GCFUNCTION__src & ~LX_GCFUNCTION__dst) to compute the correct value to use when you want drawing to produce the source pixels ANDed with the complement of the destination pixels. If we write s for the source and d for the destination, the sixteen manifest constants and the operations they yield are: LX_GCFUNCTION_Clear 0 LX_GCFUNCTION_And s&d LX_GCFUNCTION_AndReverse s&~d LX_GCFUNCTION_Copy s LX_GCFUNCTION_AndInverted d&~s LX_GCFUNCTION_NoOp d LX_GCFUNCTION_Xor s^d LX_GCFUNCTION_Or s|d LX_GCFUNCTION_Nor ~(s|d) LX_GCFUNCTION_Equiv ~(s^d) LX_GCFUNCTION_Invert ~d LX_GCFUNCTION_OrReverse s|~d LX_GCFUNCTION_CopyInverted ~s LX_GCFUNCTION_OrInverted d|~s LX_GCFUNCTION_Nand ~(s&d) LX_GCFUNCTION_Set 1 The default function is Copy. Plane-mask ---------- The plane-mask of a GC is a bitmask with as many bits used as the depth of the destination drawable. Its bits are write-enable bits; bits which are clear in the plane-mask are not affected in the destination drawable. Thus, if we write FUNC() for the operation specified by the GC's function, the resulting pixel value is (FUNC(src,dst) & plane-mask) | (dst & ~ plane-mask) Range checking is not performed on the plane-mask; the value specified is simply truncated to the appropriate number of bits. The default plane-mask is all 1s. Foreground, Background ---------- ---------- These are pixel values. Most drawing operations (points, lines, etc) typically use the GC's foreground colour as the source pixel value, but see the fill-style, which affects this. A few operations (eg, image text, CopyPlane, and some kinds of dashed lines) use the background pixel value as well. Range checking is not performed on the foreground and background pixel values; specified values are simply truncated to the appropriate number of bits. The default foreground is 0; the default background is 1. Line-width ---------- This is an unsigned integer value which controls the width of lines drawn using the GC. It is measured in pixels. If it is set to 0, the resulting lines are called `thin' lines; lines drawn with a GC whose line-width is greater than 0 are called `wide' lines. Wide lines are specified significantly more precisely than thin lines (and thus the graphics results are more precisely predictable), but usually are significantly slower. See the protocol document for the exact specification. The default line-width is 0. Line-style ---------- This specifies how the bodies of lines are drawn. It can be LX_GCLINESTYLE_Solid, LX_GCLINESTYLE_OnOffDash, or LX_GCLINESTYLE_DoubleDash. See the dash, fill-style, and cap-style settings descriptions for some of the terminology used here. Solid draws the whole path of the line. DoubleDash draws the whole path of the line, but even dashes are filled differently from odd dashes, with Butt cap-style used where even and odd dashes meet. OnOffDash draws only the even dashes, with the cap-style applied to all internal ends of individual dashes, except that NotLast is treated as Butt. The default line-style is Solid. Cap-style --------- This specifies how the endpoints of lines are drawn. It can be LX_GCCAPSTYLE_NotLast, LX_GCCAPSTYLE_Butt, LX_GCCAPSTYLE_Round, or LX_GCCAPSTYLE_Projecting. NotLast is equivalent to Butt, except that, for thin lines (see the line-width description), the final endpoint is not drawn. Butt terminates the line square at the endpoint (the termination is perpendicular to the body of the line). Round terminates the line with a circular arc with diameter equal to the line-width, centred on the endpoint. For thin lines, Round is equivalent to Butt. Projecting is like Butt in that the line is terminated with a straight edge perpendicular to the body of the line, but it is placed further out, a distance equal to half the line-width. (It can be thought of as Butt with the line longer than it otherwise would be.) For thin lines, Projecting is equivalent to Butt. The default cap-style is Butt. Join-style ---------- Some graphics requests specify special treatment for line-like objects (lines, arcs, the edges of outlined rectangles) when one object is drawn starting at the same point at which the previous object ended. This treatment is called a `join', and the join-style specifies how such things are handled. It can be LX_GCJOINSTYLE_Miter, LX_GCJOINSTYLE_Round, or LX_GCJOINSTYLE_Bevel. This is used for wide lines only; thin lines are unaffected. Miter extends the outer edges of the lines until they intersect, except that, if the angle between the lines is less than 11 degrees, Bevel is used instead. Round uses a circular cap, as if cap-style Round were used for both line endpoints, with the two resulting circles exactly overlapping. Bevel produces the effect of using Butt cap-style for both endpoints, then filling in the resulting concave triangular notch. The default join-style is Miter. Fill-style ---------- Every graphics operation that draws a set of pixels in a single colour (which is most graphics requests) can be thought of as filling a region of the destination drawwable, that region being the set of affected pixels. The fill-style specifies how this fill operation is performed. It can be LX_GCFILLSTYLE_Solid, LX_GCFILLSTYLE_Tiled, LX_GCFILLSTYLE_Stippled, or LX_GCFILLSTYLE_OpaqueStippled. Solid simply writes using the GC's function, with the GC's foreground setting as the source pixels. Tiled uses the GC's function, with source pixels taken from the tile pixmap. OpaqueStippled is just like Tiled, except that the effective tile is a pixmap of the same size as the stipple bitmap with the GC's foreground pixel value everywhere the stipple has 1 pixels and the background value everywhere it has 0. Stippled is just like Solid, except that the stipple bitmap is tiled over the region and acts as an additional clip-mask ANDed with GC's clip-mask. When using line-style DoubleDash, the fill-style setting affects odd and even dashes differently. The above description applies for even dashes; for Tiled and OpaqueStippled, it also applies for odd dashes. For Solid and Stippled, odd dashes are drawn as described above, except that the GC's background setting is used instead of its foreground setting. The default fill-style is Solid. Fill-rule --------- This controls how the `interior' of a region is defined for FillPoly requests (see lx_FillPoly in core.txt). It can be LX_GCFILLRULE_EvenOdd or LX_GCFILLRULE_Winding. EvenOdd specifies that a point is considered to be inside the region if a half-infinite ray from the point crosses the path an odd number of times. Winding specifies that a point is considered to be inside the region if a half-infinite ray from the point crosses the path unequal numbers of times clockwise and counterclockwise. For either rule, some rays will coincide with path vertices; for some paths, the ray may be collinear with part of the path. These cases are a set of measure zero (since there are a finite number of points involved); almost all rays produce the same result and it is that result which is used. The protocol document specifies that For both fill rules, a point is infinitely small and the path is an infinitely thin line. A pixel is inside if the center point of the pixel is inside and the center point is not on the boundary. If the center point is on the boundary, the pixel is inside if and only if the polygon interior is immediately to its right (x increasing direction). Pixels with centers along a horizontal edge are a special case and are inside if and only if the polygon interior is immediately below (y increasing direction). The default fill-rule is EvenOdd. Tile ---- The tile must be a pixmap on the same screen as, and with the same depth as, the GC. It is used when fill-style is Tiled. Any size pixmap may be specified, though some sizes may be faster than others (see lx_QueryBestSize in core.txt). The default tile is a pixmap of unspecified size filled with the foreground pixel value specified in the creation request, or the default foreground if none was specified. (Subsequent changes to the GC's foreground do not affect this.) Stipple ------- The stipple must be a pixmap on the same screen as the GC and with depth 1. It is used when fill-style is Stippled. Any size pixmap may be specified, though some sizes may be faster than others (see lx_QueryBestSize in core.txt). The default stipple is a pixmap of unspecified size filled with 1s. TileStipXOrigin, TileStipYOrigin --------------- --------------- Tile and stipple pixmaps are, conceptually, tiled to fill an infinite plane, some portion of which is then involved in the graphics request. The tile/stipple X and Y origins allow specifying where the origin of the tile and stipple pixmaps fall on this infinite plane. Specifically, if we call the tile/stipple X and Y origins tsxo and tsyo, then the tile and stipple pixmaps are placed such that the (0,0) pixel of the tile and stipple pixmaps are used for pixel (tsxo,tsyo) of the destination drawable (or, if that pixel is not actually part of the operation, such that they would have been used for it if it were involved). The same values are used for both tile and stipple. The default tile/stipple origins is (0,0). Font ---- The font is used for text-drawing requests. The default font is server-dependent. Subwindow-mode -------------- When graphics are drawn in a window which has viewable inferior InputOutput windows that overlap the operation, the GC's subwindow-mode controls how the overlap is handled. It can be LX_GCSUBWINDOWMODE_ClipByChildren or LX_GCSUBWINDOWMODE_IncludeInferiors. ClipByChildren specifies that viewable inferior windows act as an additional clip-mask. IncludeInferiors specifies that viewable inferior window contents are part of the operation. Using IncludeInferiors when the relevant inferior window has different depth from the window involved in the operation is permitted, but the core protocol does not define the results. The default subwindow-mode is ClipByChildren. Graphics-exposures ------------------ This boolean controls generation of GraphicsExposure and NoExposure events by CopyArea and CopyPlane requests (see lx_CopyArea and lx_CopyPlane in core.txt). The default graphics-exposures is true. ClipXOrigin, ClipYOrigin, Clip-mask ----------- ----------- --------- The clip-mask allows specifying additional clipping of graphics operations. It must be LX_GCCLIPMASK_None or a pixmap of depth 1 on the same screen as the GC. If it is None, there is no additional clipping. Otherwise, a pixel is affected by a graphics operation only when it would be affected if the clip-mask were None and, additionally, the clip-mask has a 1 pixel at the relevant location. The clip-mask pixmap is positioned with its (0,0) pixel at pixel (clip-x-origin,clip-y-origin) in the destination drawable (or where that pixel would be, if those coordinates fall outside the destination). Note that, in contrast to tiles and stipples, clip-masks are not tiled. They are, effectively, padded with an infinite surround of 0 pixels. The clip mask and origin can also be set with the SetClipRectangles request (see lx_SetClipRectangles in core.txt). Setting the clip-mask always overrides any previous clip-mask setting, regardless of which method (ChangeGC or SetClipRectangles) is used for either setting. A clip-mask set as a list of rectangles is semantically equivalent to creating a bitmap large enough to include all the rectangles, filling it with 0s, then filling the rectangles with 1s, then setting that bitmap as a clip-mask (with, if the bitmap's origin doesn't match the rectangles', suitable adjustments to the clip origin). The default clip-mask is None. The default clip origin is (0,0). Dash-offset, Dashes ----------- ------ These provide limited control over line dash settings. (SetDashes provides full control; see lx_SetDashes in core.txt for how to call it.) Setting Dashes to a value N with CreateGC or ChangeGC is equivalent to specifying the list [N, N] to SetDashes. When drawing lines with line-style Solid, the dash settings are ignored. Otherwise, conceptually, an infinite sequence of dashes is overlaid onto the line. The dash lengths are specified as a list of lengths; specifying an odd-length list is equivalent to specifying the same list concatenated with itself, and the list length must be nonzero. Each element of the list must be nonzero and specifies the length of one dash segment. The first such segment is called even, with segments alternating between odd and even after that. The dash-offset specifies how far into this conceptual sequence of dashes the graphics request begins. Dash segment lengths are measured in pixels. Ideally, dash length is measured along the length of the line, but this is required only for horizontal and vertical lines. The default dash-offset is 0. The default Dashes value is 4, which is equivalent to passing the list [4, 4] to SetDashes. Arc-mode -------- The arc-mode setting controls filling of arcs for PolyFillArc. It can be LX_GCARCMODE_Chord or LX_GCARCMODE_PieSlice; see lx_PolyFillArc in core.txt for their meanings. The default arc-mode is PieSlice. ---- When a line is drawn with both endpoints coincident in a way that applies the cap-style to both endpoints, what happens depends on both the line-width and the cap-style. Thin, NotLast Device-dependent, but, ideally, nothing is drawn. Thin, Butt Device-dependent, but, ideally, a single pixel is drawn. Thin, Round Same as Thin/Butt. Thin, Projecting Same as Thin/Butt. Wide, NotLast Equivalent to Wide/Butt, as described under cap-style. Wide, Butt Nothing is drawn. Wide, Round A circle, centred at the endpoint, with diameter equal to the line-width. Wide, Projecting A square, sides parallel to the coordinate axes, centred at the endpoint, with sides equal to the line-width. When a line is drawn with both endpoints coincident in a way that applies a join at at least one end, the effect is as if that line were removed from the path. However, if this reduces the whole path to a single point, the effect is the same as described above, as if the cap-style were applied to both ends of a zero-length line. Setting a pixmap as a GC attribute may or may not result in a copy being made. If the pixmap is later modified, the change may or may not be reflected in graphics requests using the GC. If a pixmap is used simultaneously in a graphics request as both a destination and as a tile or stipple, the results are not defined. The protocol document notes that It is quite likely that some amount of gcontext information will be cached in display hardware and that such hardware can only cache a small number of gcontexts. Given the number and complexity of components, clients should view switching between gcontexts with nearly identical state as significantly more expensive than making minor changes to a single gcontext. When drawing arcs, each arc is specified as an LX_ARC, which is a struct containing six integers, representing a rectangle (x, y, w, h) and two angles (a1, a2). The angles are signed integers in sixty-fourths of degrees; positive indicates counterclockwise and negative indicates clockwise (because X's coordinate system is fourth-quadrant rather than first-quadrant, this is the reverse of the usual mathematician's convention in terms of coordinates, though not in terms of effects on the display). a1 specifies the start position of the arc relative to the increasing X direction. a2 specifies the extent of the arc, relative to the start point; if a2 is greater than 23040 (360 degrees), it is truncated to 23040. The x and y coordinates specify the upper-left corner of the rectangle, relative to the origin of the destination drawable; w and h specify its width and height. The arc is a portion of an ellipse. The ellipse's bounding box is the rectangle. The ellipse centre is at (x+(w/2),y+(h/2)); it intersects the horizontal axis at (x,y+(h/2)) and (x+w,y+(h/2)) and the vertical axis at (x+(w/2),y) and (x+(w/2),y+h). All coordinates in the foregoing may be half-integers. For PolyArc, cap-style and/or join-style are applied as if for a line tangent to the arc in the same direction as the endpoint. If w and h are different, the angles are interpreted as if they applied to a circle, with, after the endpoints are determined, the coordinates scaled to match the actual rectangle. Thus, for example, an a1 value of 2880 (45 * 64) will lead to the start point of the arc being midway between the centre and one corner of the bounding box; unless w and h are equal, this will not be equal distances from the centre in X and Y. Arc drawing always operates in pixel coordinate space; to put it another way, it operates as if pixels were square. If w or h is zero, a vertical or horizontal line results. ---- liblx also supports shadow GCs. It is convenient, in many applications, to keep a client-side copy of the info in a GC, so that (for example) when switching from drawing one thing to drawing another thing, there is no need to change the foreground colour in the GC unless the two colours' pixel values actually differ. Shadow GCs exist to facilitate this. There is a type, LX_SGC, which represents a GC plus a client-side shadow. There are calls on SGCs analogous to CreateGC, ChangeGC, CopyGC, and FreeGC requests, plus a call which converts an SGC into an LX_XID for the underlying GC ID, suitable for passing to requests, such as CopyArea, which need a GC. It is important to note that even *creation* of the underlying GC is done lazily. For example, when creating an SGC, the drawable must be valid at the time the create operation is pushed to the server, which is later than lx_CreateSGC_* time. Similarly, when making a GC setting that uses a server-side resource, such as using a bitmap as a clip-mask, the resource must be valid at push time, not at set time. The SGC calls do not end a batch-in-progrses (see batching.txt) unless they actually generate a protocol request. This means that something like lx_draw_line(...,lx_SGC_GC(gc),...); lx_ChangeSGC_va(...,gc,...,LX_GCV_END); without pushing being requested, or even with it if there are no actual changes to push, will not cause the line to be drawn. See lx_end_batch, in batching.txt, for how to address such cases. By design, LX_SGC is an opaque type. The definition is visible to clients of the library, but this is an accident of the implementation, not because going under its hood is supported. In particular, it is designed to be assignment-incompatible with LX_XID, to produce compile-time errors upon accidentally passing an LX_SGC to an interface expecting a GC's LX_XID. The library does, however, promise that LX_SGC objects (as opposed to the library-internal data structures they conceptually refer to) may be allocated, copied, and deallocated with no particular caution and overhead that would not be equally needed for, for example, ints. Shadow GCs do not work correctly in cases where a different connection (whether from the same client or not) also modifies the underlying GC; they are designed around the assumption that the only client connection that ever modifies the underlying GC is the one that created it. lx_CreateSGC_va, lx_CreateSGC_attr --------------- ----------------- LX_SGC lx_CreateSGC_va(LX_CONN *conn, LX_XID d, ...) LX_SGC lx_CreateSGC_attr(LX_CONN *conn, LX_XID d, unsigned int mask, const LX_GC_ATTRIBUTES *attr) These are just like lx_CreateGC_va and lx_CreateGC_attr except that they return an LX_SGC instead of an LX_XID representing a GC. lx_ChangeSGC_va, lx_ChangeSGC_attr --------------- ----------------- LX_XID lx_ChangeSGC_va(LX_CONN *conn, LX_SGC sgc, ...); LX_XID lx_ChangeSGC_attr(LX_CONN *conn, LX_SGC sgc, unsigned int mask, const LX_GC_ATTRIBUTES *attr) These are just like lx_ChangeGC_va and lx_ChangeGC_attr except for two things: (1) they operate on an LX_SGC instead of an LX_XID representing a GC and (2) they support one additional facility. When changing an SGC, it is often useful to immediately push the changes, if any, because the next thing the application wants to do is a graphics request. Rather than forcing applications to make a separate lx_SGC_GC call each time, lx_ChangeSGC_* support an auto-push facility. If in lx_ChangeSGC_va you terminate the arglist with LX_GCV_PUSH instead of LX_GCV_END, or if in lx_ChangeSGC_attr you also set the LX_GCM_PUSH bit in the mask, the changes will be pushed immediately and the underlying GC's LX_XID will be returned. If you don't enable auto-push, the returned value will be a valid LX_XID from a C perspective but meaningless from an X perspective. lx_SGC_SetDashes ---------------- This is the SGC analog of the core SetDashes request (see lx_SetDashes in core.txt). lx_SGC_SetClipRectangles ------------------------ This is the SGC analog of the core SetClipRectangles request (see lx_SetClipRectangles in core.txt). Unlike most (all, at this writing) other SGC-changing calls, lx_SGC_SetClipRectangles always provokes a push to the server (that is, it is always considered to not match the current state; the actual push is delayed as usual). The SGC shadow could in theory store the exact clip region, but in some cases it would be prohibitively expensive (for example, when it comes from a pixmap created by a different connection, the only way to do this involves reading back the pixmap's contents); in view of the expected use cases for SetClipRectangles, the library is designed to ignore this possible optimization. lx_CopySGCtoGC, lx_CopySGCtoSGC -------------- --------------- extern void lx_CopySGCtoGC(LX_CONN *conn, LX_SGC fsgc, LX_XID tgc, unsigned int mask) extern void lx_CopySGCtoSGC(LX_CONN *conn, LX_SGC fsgc, LX_SGC tsgc, unsigned int mask) These copy from fsgc to tgc (...toGC) or tsgc (...toSGC), under control of the mask, like a CopyGC request except the source (and, for lx_CopySGCtoSGC, the destination as well) is an SGC. There is no lx_CopyGCtoSGC because there is no request which can read back a GC's components. There is no lx_CopyGCtoGC; that's just a plain CopyGC request, for which lx_CopyGC exists. Trying to copy the font out of an SGC which has never had a font set produces undefined behaviour from the library. (The only way to refer to the server default font is as a component of a GC which has never had its font set. But CopyGC requires both GCs be on the same screen, and liblx has no way to tell what screen an SGC is on, making it effectively impossible for liblx to create an internal GC to use as a copy-from source for the server default font. In theory, this could be done, but, because the screen and depth for a GC are specified as a drawable rather than separately, liblx would have to either do a server round-trip to query the screen of the drawable, which would defeat much of the point of using SGCs to begin with, or create a second GC for each SGC, to keep as a copy-from source for the server default font in case the application tries to do this. The round-trip can be avoided if the drawable is a root, or in theory if liblx created it, though the latter would require tracking the screen of all drawables liblx creates. Doubling the GC load is more cost than I think worth paying for a use case this rare, and the server round-trip is incompatible with the API I want SGCs to have. I may make the second GC an option at SGC creation if there's need.) lx_FreeSGC ---------- extern void lx_FreeSGC(LX_CONN *conn, LX_SGC sgc) Analogous to lx_FreeGC, this frees an SGC. lx_SGC_GC --------- LX_XID lx_SGC_GC(LX_CONN *conn, LX_SGC sgc) This returns the underlying GC's LX_XID for an SGC. It also pushes any changes made to the server. If the underlying GC has not yet been created, the creation is pushed. If nothing needs pushing, this is a cheap call which does not generate any protocol requests, just returning the GC's LX_XID.