
X11 implementation notes
------------------------

(0) Errors.

On the first call to connect to a server, I call XSetErrorHandler to
install a non-fatal error handler.  This handler calls the on_error
function set by p_handler, reporting a priority 1 error with an error
message that begins with "Xlib: ".

A more severe problem is the XSetIOErrorHandler routine, which must
not return.  Such an error will result in the on_panic routine set by
p_panic being called for each screen of the display.

Status returns in Xlib are 0 on failure, non-0 on success.  Anything
returning Status bypasses the error handler set by XSetErrorHandler,
and must therefore be checked.

(1) Fonts.

-----------------------------

At connect time, XListFonts is used to find as many fonts matching
"courier", "times", "helvetica", "symbol", and "new century
schoolbook" as possible.  Specifically, in the font list, an attempt
is made to find medium, bold, italic (or oblique), and bold italic
versions of all five fonts (this will never succeed with symbol), for
a total of 20 possible typefaces.  For each typeface, I catalog all
the sizes - in pixels! - the server can provide, sorted according to
size.  For each available size, I store a copy of the font name that
will retrieve that font later.  In the case of a scalable font, this
name will have wildcard characters for the sizes.  (If more than one
font matches, I take the first in the XListFonts list.)  After this
search, I have recorded all the fonts of interest that exist on this
server, with the means to retrieve them.  For scalable fonts, a call
to XListFonts will still be necessary in order to get a specific size
which is not prebuilt.

If a requested typeface is not available, I first check if the
non-bold, non-italic basic version is present.  If not, I check for
any bold, italic, or bold-italic versions.  If none of these is
available, I try first times, then new century, then helvetica, then
courier in the requested face, and finally that same sequence in the
basic face.  If this search comes up empty, I fall back to the GUI
font (see below).  Once the typeface is found, I choose the pixel size
closest to the request, or, if a scalable version is available, I
construct the exact pixel size requested.

I cache up to 6 fonts to allow switching among several fonts without
loading and unloading.  When the cache is full, the least recently
used font is unloaded.

Additionally, there is a GUI font which I load at connect time.  If
nothing better can be found, this will be the default font for the
server (guaranteed to be loaded according to O'Reilly 6.2.2 volume
one).

-----------------------------

The "standard" pixel sizes are:

points            pixels
            75 dpi       100 dpi
   8           8           11
  10          10           14
  12          12           17
  14          14           20
  18          18           25
  24          24           34

The two 14 pixel fonts sometimes differ by one pixel in average width
between the 75 and 100 dpi resolutions; I don't distinguish them, and
use whichever happens to come first in XListFonts.  Therefore, a full
installation of these standard fonts involves 11 sizes for each of 17
fonts (no bold or italic symbol fonts), for a total of 187 typefaces.
When scalable fonts are also available, this will be 204 font names to
be catalogued.  X font names have 14 components:

-foundry-family-wgt-slant-wid--pixels-pts-hres-vres-spacing-avgwid-char-set

For the five fonts I care about, I have seen these variants:

 adobe|bitstream-courier-medium|bold-o|i|r-normal--    m iso8859-1
 adobe-times-medium|bold-i|r-normal--                  p iso8859-1
 adobe-helvetica-medium|bold-o|r-normal--              p iso8859-1
 adobe-symbol-medium|medium-r|r-normal--               p adobe-fontspecific
 adobe-new century schoolbook-medium|bold-i|r-normal-- p iso8859-1

-----------------------------

Font rotation is painful.  The basic idea is to create an offscreen
bitmap, draw to the bitmap, read the bitmap back as an XImage, rotate
the XImage bitmap, then write the bitmap back to a second offscreen
bitmap.  The weird part begins now: You can specify a "stipple"
pattern when you fill an area; the bitmap containing the rotated text
can be used as a stipple, so that a call to XFillRectangle actually
paints the rotated text.  This actually perfectly simulates all the
drawing options available for painting text -- except, of course, you
can't stipple it (actually you could, by using a counter-rotated
stipple pattern while drawing the text into the first bitmap).

The hitch is that the XImage interface is botched.  The XFree86 source
(and I suspect vendor X's as well) has a reasonably efficient
XPutImage call to convert from the myriad image formats to the one
required by the server.  However, XGetImage does not perform any
conversion, so you get images back in whatever format the server uses
- making efficient rotation a huge chore.  (XGetSubImage looks like it
would perform the required format conversion, but it turns out to be
implemented very inefficiently using XGetPixel and XPutPixel -- it's
not obvious to me why the very same efficient routines used by
XPutImage could not be used to make XGetSubImage just as efficient.
It turns out the server doesn't translate either Get or Put requests
-- this is just a client side issue.)  I decided this was an X
problem, not a Gist problem, and assume that someday, efficient
versions of XGetSubImage will become the norm.  My compromise was to
use the same image format as the XCreateBitmapFromData functions --
namely the format used in all the bitmap files supplied with the X
distribution.  Presumably, this particular format will come early on
any prioritization of optimizations.

Note that X11 "default" bitmap is

format=      XYPixmap
bit_order=   LSBFirst
byte_order=  LSBFirst (unused)
bitmap_unit= 8
bitmap_pad=  8
xoffset=     0
no extra bytes per line

(This is what is required for input to XCreateBitmapFromData, and
handled by XReadBitmapFile and XWriteBitmapFile.)

-----------------------------


(2) Colors.

I support three color models: standard colors, palette colors, and rgb
colors.  Palettes are restricted to 240 colors, which leaves room for
up to 16 standard colors within a 256 color colormap.

A huge amount of work is required to intelligently handle the case of
the PseudoColor visual; the other visuals (StaticGray, GrayScale,
StaticColor, TrueColor, and DirectColor) are relatively simple.

First, for DirectColor or GrayScale, I create a single colormap (256
r=g=b=index colors) at p_connect time, and arrange for it to be
installed on every window.  This effectively reduces the case of
DirectColor to TrueColor, and the case of GrayScale to StaticGray.  I
do not support color table animation; therefore the TrueColor and
StaticGray visuals are functionally equivalent to DirectColor and
GrayScale, respectively.

Now, for any visual other than PseudoColor, XAllocColor immediately
gives the closest match possible to any rgb value on the display.

For PseudoColor, I support two modes of operation for every toplevel
window -- shared and private colormaps -- controlled by the P_PRIVMAP
hint passed to the p_window function.  Shared colormap windows always
use the default colormap for the screen; each private colormap window
has its own colormap (they can't share each others maps).  In the case
of private colormaps, I take care to reduce colormap flashing by
allocating all the standard colors at the same pixel they have in the
default colormap for the screen, and by allocating palette colors from
the top down (since most X servers seem to allocate them from the
bottom up).

At the first reference to an rgb-model color in a PseudoColor window,
I install a 5-9-5 (5 reds, 9 greens, 5 blues) colormap.  All
subsequent palette-model or rgb-model colors are approximated as well
as possible from within this 595 colormap.  (This matches Mesa's
strategy for 8-bit deep screens.)  Once this 595 colormap is
installed, it will persist, with p_palette calls allocating
palette-model colors from this 595 map instead of changing colormap
colors.  Destroying the window is the only way to return to a "normal"
colormap in which an attempt is made to get the exact rgb values
requested for palette-model colors.

One final complexity is that offscreen pixmaps cannot have their own
colormaps under X.  Thus, an offscreen uses the colormap of its parent
window, and calls to p_palette or references to rgb-model colors when
drawing to an offscreen pixmap will change the colormap of the parent
window as a side effect.



-----------------------------

(3) Events.

The x11_create function creates a new window, and attaches its p_win
struct to the window via a hashtab for later retrieval.  There is one
hashtab per display; the effect is the same as the XContext mechanism.
The x11_create function also calls XSelectInput to determine which X
events the window will receive.

Toplevel windows additionally may require setting window properties to
communicate with the window manager (WM_DELETE_WINDOW is the most
important).  And menus require both the override_redirect property and
save_under property.

All button press events are selected with OwnerGrabButtonMask, and
pointer grabs are made with owner_events True.  This forces the X
server to do the geometry calculation.  However, I intend that the
higher level platform independent event handlers will allow for some
variation in the details of event delivery semantics.

One "event" in the sense of the basic input event manager consists of
all the data readable on the X socket, which may be several or many X
events.  Callbacks for all of these occur without polling for any new
input in between.

-----------------------------

(4) X Resources.

Window class names for all resources is "Gist".  (Toplevel windows
will have class "Gist", unless created with the P_DIALOG hint, in
which case they have class "GistDialog".)  All resources can be
overridden by setting external program variables before making a
connection (via p_connect or, for the colors, p_multihead).

X resources are:
            X resource                     program override variable
  --------------------------------------   -------------------------
  boldfont (preferred) or font (or Font)          x_xfont
  foreground (or Foreground)                      x_foreground
  background (or Background)                      x_background
  guifg                                           x_guifg
  guibg                                           x_guibg
  guihi                                           x_guihi
  guilo                                           x_guilo

defaults:
  font: 9x15
        fixed
        <font in default GC on root window>
  foreground: black
  background: white  <if foreground closer to black than white>
              black  <if foreground closer to white than black>
  guifg: foreground
  guibg: background
  guihi: <none>
  guilo: <none>
    if the hilight or lolight color is not specified, use a 2x2
      gray bitmap with FillOpaqueStipple to draw hi or lo regions
    the fg color of the hi stipple is always white; the foreground
      color of the lo stipple is always black
    the bg color of the stipple (for either hi or lo) is the
      "background" color, unless that is too close to white or black,
      in which case the stipple bg is the "foreground" color

A 3d effect is generated by drawing the top and left sides of boxes
hi, and the bottom and right sides of boxes lo.
