[comp.windows.x] Usenix paper - corrected version

dshr@SUN.COM (David Rosenthal) (02/06/89)

Here is a shell archive with the source for the "Visualizing X11 Clients"
paper that was presented at Usenix last week.  It corrects the bug in
the version printed in the Proceedings which chooses the largest,
not the smallest,  suitable Visual.

	David.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	vis.nr
#	vis.refs
#	xsd.c
#	xsud.c
# This archive created: Mon Feb  6 09:31:43 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XTEXTFILES = vis.nr
XREFER = refer -e -n -p vis.refs -s
XEQN = eqn
XPIC = pic
XTROFF = psroff -ms -t
X
Xvis.ps:	vis.nr vis.refs xsd.c xsud.c
X	$(REFER) $(TEXTFILES) | $(EQN) | $(PIC) | $(TROFF) >vis.ps
SHAR_EOF
fi
if test -f 'vis.nr'
then
	echo shar: "will not over-write existing file 'vis.nr'"
else
sed 's/^X//' << \SHAR_EOF > 'vis.nr'
X.\"	refer -e -n -p vis.refs -s vis.nr | eqn | pic | psroff -ms
X.EQ
Xdelim $$
X.EN
X.ds CH
X.de Ip
X.IP \(bu 3
X..
X.de Qp
X.nr PS -2
X.nr VS -2
X.QP
X..
X.de Qe
X.nr PS +2
X.nr VS +2
X..
X.de RQ
X.br
X.di
X.nr NF 0
X.if \\n(dn-\\n(.t .nr NF 1
X.if \\n(TC .nr NF 1
X.if !\\n(NF .if \\n(TB .nr TB 0
X.nf
X.rs
X.nr TC 5
X.in 0
X.ls 1
X.if !\\n(TB \{\
X.	ev
X.	br
X.	ev 2
X.	KK
X.\}
X.ls
X.ce 0
X.if !\\n(TB .rm KK
X.if \\n(TB .da KJ
X.if \\n(TB \!.KD \\n(dn
X.if \\n(TB .KK
X.if \\n(TB .di
X.nr TC \\n(TB
X.if \\n(KN .fi
X.in
X.ev
X..
X.\"	These macros should select a typewriter font if you have one.
X.de LS
X.LP
X.KS
X.LD
X.ft L
X.ta .6i 1.2i 1.8i 2.4i 3i 3.6i 4.2i
X..
X.de LE
X.ft P
X.DE
X.KE
X..
X.de Ls
X.nr PS -4
X.nr VS -6
X.LS
X..
X.de Le
X.LE
X.nr PS +4
X.nr VS +6
X.LP
X..
X.nr PO 1.25i
X.TL
XVisualizing X11 Clients
X.AU
XDavid Lemke
XDavid S. H. Rosenthal
X.AI
XSun Microsystems
X2550 Garcia Ave.
XMountain View CA 94043
X.AB
XThe color model of version 11 of the X Window System
Xexposes a number of aspects of the underlying display.
XThe concept it uses to represent these device-dependencies is the
X.I Visual ;
Xthere may be several Visuals available on a given display.
XWe present example programs to illustrate the techniques required if
Xan X client is to operate correctly across the entire range of possible
Xcombinations of Visuals.
X.AE
X.LP
X.DS C
XCopyright \(co 1988 by Sun Microsystems, Inc.\s-2\u*\d\s0
X.DE
X.FS
X*  Permission to use,  copy,  modify and distribute
Xthis document for any purpose and without fee is hereby
Xgranted,  provided that the above copyright notice and this permission
Xnotice appear in all copies,  and that the name of Sun Microsystems,  Inc. not be
Xused in advertising or publicity pertaining to distribution of the software
Xwithout specific,  written prior permission.  Sun Microsystems,  Inc. makes no
Xrepresentations about the suitability of the software described herein for
Xany purpose.  It is provided "as is" without express or implied warranty.
X.br
X\(dg  The X Window System is a trademark of the Massachusetts Institute
Xof Technology.
X.FE
X.Qp
X``The polymorphic visions of the eyes and the spirit are contained in
Xuniform lines of small or capital letters,  periods,  commas,  parentheses \-
Xpages of signs packed as closely together as grains of sand representing
Xthe many-colored spectacle of the world on a surface that is always the
Xsame and always different,  like dunes shifted by the desert wind.''
X.sp
X	Italo Calvino,  \fISix Memos for the Next Millennium\fP
X.sp .25i
X.Qe
X.NH
XIntroduction
X.LP
XA design objective of Version 11 of the X Window System\s-2\u\(dg\d\s0
X.[
Xscheifler gettys transactions graphics 1987
X.]
Xis to make it
Xpossible to write client programs that operate correctly across a wide
Xrange of displays.
XThis objective is often referred to as ``device-independence'',
Xbut this is something of a misnomer.
XX11 abstracts the properties of popular display types into an object
Xcalled a
X.I Visual ,
Xand exposes to the client the existence of a number of
XVisuals.
XVisuals are divided into classes;
Xeach class representing the abstraction of a particular type of display hardware.
X.LP
XThe implementor of an X11 server for a particular display must decide
Xon the appropriate Visual classes to export to its clients.
XMore than one Visual per screen may be exported
Xto allow access to the full set of hardware capabilities.
XWhen a client connects to an X11 server,
Xit must determine the Visuals the server is exporting and their classes,
Xadapting its behavior to suit.
XNormally,  this will involve the client choosing one of the Visuals,  and changing
Xappropriate initializations.
X.LP
XSimply adhering to the X11 protocol does not ensure that a client
Xwill operate correctly on all possible combinations of Visuals.
XThe early X11 server implementations that were made available exported
Xonly a single Visual per screen,
Xand these Visuals were of only two classes.
XAs a result,  many existing X11 clients operate correctly on single-Visual
Xscreens of these two classes,
Xbut not on others.
X.LP
XAmong these not-really-device-independent clients are the
X.B xwd
Xand
X.B xwud
Xprograms in the X11R3 distribution.
XThey ``dump'' to a file,  and ``undump'' from a file,
Xthe image of a window,  but they don't work across all combinations of Visuals.
XIn particular,  they don't work:
X.Ip
Xfor TrueColor or DirectColor Visuals.
X.Ip
Xif there are subwindows that have a different depth,  Visual,
Xor colormap.
X.Ip
Xif the default colormap of the screen being dumped to doesn't
Xmimic the colormap of the window being dumped.
X.LP
XWe first review the Visual concept,  and then present versions of
Xthe screen dump and undump clients that do work correctly across
Xall Visuals.
XThese clients are designed as teaching aids;
Xthey illustrate the techniques needed to make truly device-independent
XX11 clients,  but they:
X.Ip
Xare as simple as possible,  and thus too inefficient for production use,
X.Ip
Xignore all the issues of interacting with window managers and other
Xclients,
X.[
Xrosenthal communication conventions 1988
X.]
Xin the interests of clarity,
X.Ip
Xand ignore our own advice about using a toolkit,
X.[
Xrosenthal hello world 1988
X.]
Xin order to focus on the underlying X11 mechanisms.
X.NH
XVisual Classes
X.LP
XAn X client paints in a
X.I Drawable ,
Xa rectangular array of numbers called
Xpixel values,  using operations that alter the numbers,
Xsuch as CopyArea and PolyLine.
XThe only difference that affects the drawing process between one
Xdrawable and another is the
X.I depth ,
Xthe number of bits in each of the numbers.
XThe Visual concept is irrelevant to this process;
Xa useful model is to think of CPU access to a display bitmap,
Xwith the monitor turned off (see Figure 1).
X.KF
X.DS
X.PS 3.5i 2.5i
Xline from 5.237,4.825 to 6.175,6.325
Xline from 5.237,6.325 to 6.237,4.825
Xline from 2.275,5.788 to 2.175,5.763 to 2.275,5.737
Xline from 2.175,5.763 to 4.175,5.763
Xline from 4.075,5.737 to 4.175,5.763 to 4.075,5.788
Xline from 4.737,7.013 to 6.737,7.013 to 6.737,4.325 to 4.737,4.325 to 4.737,7.013
Xline from 4.175,8.012 to 7.175,8.012 to 7.175,3.325 to 4.175,3.325 to 4.175,8.012
Xline from 0.300,6.325 to 2.175,6.325 to 2.175,5.138 to 0.300,5.138 to 0.300,6.325
X.ps 7
X"Drawable" at 4.925,6.606 ljust
X"Memory" at 4.487,7.668 ljust
X"Pixel Values" at 2.387,5.918 ljust
X"CPU" at 0.925,5.731 ljust
X.PE
X.DE
X.DS C
XFigure 1:  The X11 Drawing Process
X.DE
X.KE
X.LP
XSome Drawables are
X.I Windows ,
Xand these can be made visible by
X.I mapping
Xthem to the screen.
XWhen the client creates a Window,  it must be assigned one of the
Xpossible Visuals for the screen;
Xthis Visual will control the process by which the Window's pixels
Xbecome visible when it is mapped.
XA useful model is to think of video refresh access to a display
Xbitmap,  with the CPU halted (see Figure 2).
X.KF
X.DS
X.PS 3.5i 2.5i
Xline from 6.612,5.763 to 7.112,6.888
Xline from 6.612,6.888 to 7.112,5.763
Xline from 0.988,5.075 to 1.988,7.075
Xline from 0.988,7.075 to 1.988,5.075
Xline from 3.612,7.325 to 4.862,7.325 to 4.862,5.263 to 3.612,5.263 to 3.612,7.325
Xline from 2.550,6.325 to 3.425,6.325
Xline from 3.325,6.300 to 3.425,6.325 to 3.325,6.350
Xline from 0.800,7.763 to 2.300,7.763 to 2.300,4.763 to 0.800,4.763 to 0.800,7.763
Xline from 5.925,6.325 to 6.425,5.575
Xline from 5.925,6.325 to 6.425,7.263
Xline from 6.425,7.263 to 7.237,7.263 to 7.237,5.575 to 6.425,5.575 to 6.425,7.263
Xline from 4.987,6.325 to 5.925,6.325
Xline from 5.825,6.300 to 5.925,6.325 to 5.825,6.350
Xline from 3.487,7.763 to 4.987,7.763 to 4.987,4.825 to 3.487,4.825 to 3.487,7.763
Xline from 0.550,8.075 to 2.550,8.075 to 2.550,4.513 to 0.550,4.513 to 0.550,8.075
X.ps 7
X"Colormap" at 3.737,7.106 ljust
X"Screen" at 6.512,7.106 ljust
X"Values" at 2.675,6.106 ljust
X"Pixel" at 2.675,6.481 ljust
X"RGB" at 5.112,6.418 ljust
X"Visual" at 3.550,7.543 ljust
X"Window" at 1.113,7.543 ljust
X"Memory" at 0.863,7.906 ljust
X.PE
X.DE
X.DS C
XFigure 2:  The X11 Display Process
X.DE
X.KE
X.LP
XConceptually,
Xwhen a screen pixel is to be refreshed the top-most Window's
Xcorresponding pixel value is read,  and used to index into a
X.I Colormap ,
Xan object containing three arrays (red,  green and blue) of
Xintensity values that models a video look-up table.
XThe Visual for the window controls:
X.Ip
XHow this indexing is done.
X.Ip
XWhich of possibly many installed Colormaps is used.
X.Ip
XWhether and how the Colormap can be modified.
X.LP
XVisuals are divided into six classes,  modeling six different types
Xof display hardware.  The classes,  and their effects on the pixel value
Xto visible color mapping,  are:
X.Ip
X.I StaticGray .
XThe pixel value indexes a predefined,  read-only colormap.
XFor each colormap cell,  the red,  green and blue values
Xare the same,  producing a gray image.
X.Ip
X.I StaticColor .
XThe pixel values indexes a predefined,  read-only colormap.
XThe red,  green and blue values for each cell are server-dependent.
X.Ip
X.I TrueColor .
XThe pixel value is divided into sub-fields for red,  green and blue.
XEach sub-field separately indexes the appropriate primary of a
Xpredefined,  read-only colormap.
XThe red,  green and blue values for each cell are server-dependent,
Xand are selected to provide a nearly linear increasing ramp.
X.Ip
X.I GrayScale .
XThe pixel value indexes a colormap which the client can alter,  subject
Xto the restriction that the red,  green and blue values of each cell
Xmust always be the same,  producing a gray image.
X.Ip
X.I PseudoColor .
XThe pixel value indexes a colormap which the client can alter.
XThe red,  green and blue values of each cell can be selected arbitrarily.
X.Ip
X.I DirectColor .
XThe pixel value is divided into sub-fields for red,  green and blue.
XEach sub-field separately indexes the appropriate primary of a
Xcolormap that the client can alter.
X.LP
XThe early X11 server implementations provided two Visuals:
X.Ip
XServers for monochrome displays exported a single StaticGray Visual of depth 1.
X.Ip
XServers for color displays exported a single PseudoColor Visual of varying depth,
Xtypically 4 or 8.
X.LP
XThese are the natural choices for simple workstation hardware,  but they made
Xit easy for initial clients to ignore many of the problems of dealing
Xwith Visuals.
X.LP
XAlready,  servers for common hardware such as the MIT sample
Xserver for the DEC QDSS display
Xand the X11/NeWS
X.[
Xschaufler design overview 1988
X.]
Xserver on Sun color hardware are exporting multiple Visuals.
XThe QDSS server's default Visual is PseudoColor,
Xbut it also exports a StaticColor Visual.
XThe X11/NeWS server's default is a StaticColor Visual,
Xand it also exports a PseudoColor Visual.
XAs X11 becomes available on more complex hardware,  multiple
XVisuals will become increasingly common.
X.LP
XMany current X11 clients make unwarranted assumptions about their Visuals.
XAmong the most common such assumptions\s-2\u\(dg\d\s0
X.FS
X\(dg  The technical term for these erroneous assumptions is
X.I bugs .
X.FE
Xare:
X.Ip
XThat the default Visual is the only available Visual.
XClients making this assumption may fail even though a
XVisual that could have supported them was available.
X.Ip
XThat all Visuals with more than two Colormap cells are
Xcolor.
XClients making this assumption will behave strangely on
Xsome StaticGray and GrayScale Visuals.
X.Ip
XThat all Visuals with more than two Colormap cells have
Xwritable Colormaps.
XClients making this (very common) assumption will fail
Xwith Xlib errors on StaticColor and TrueColor Visuals.
X.Ip
XThat Colormaps (and especially the default Colormap) are
Xinfinitely large,  so that attempts to allocate private cells
Xin them will always succeed.
X.LP
XIn fact,  the only clients that can ignore the question of Visuals
Xare those that use the
X.I BlackPixel()
Xand
X.I WhitePixel()
Xmacros to paint a black and white image in the default Visual;
Xthis will work on all servers though the colors may not actually
Xbe Black or White.
X.I All
Xother clients must pay some attention to the details of the Visual(s)
Xthey are using.
XTo demonstrate how to deal with these details,  we present versions
Xof the screen dump and undump clients.
X.NH
XThe ``dump'' Client
X.LP
XThe objective of the screen dump client is to record the appearance
Xof a specified rectangle of the screen so that it can be restored later,
Xmost likely on some other display device.
XThus,  the stored representation of the rectangle must be device-independent.
XThe simplest possible device-independent representation is the red,  green and
Xblue (RGB) intensities of each pixel.
X.LP
XThe only X11 protocol request that allows a client to read back the contents of
Xa window is GetImage,  so the dump client clearly must be based on it.
XFrom the point of view of the screen dump client,  there are two problems
Xwith the specification of GetImage:
X.Ip
XIt returns pixel values,  not RGB values.
XPixel values are not device-independent,  and so cannot be used directly.
X.Ip
XSome of the values it returns may be garbage.
X.NH 2
XConverting pixel values to RGB
X.LP
XTo transform the returned pixel values to RGB intensities,  the client must
Xuse the QueryColors request to look up the index in a specified Colormap.
XThe Colormap to use will be given by the colormap attribute of the window
Xin question.
X.LP
XThe Visual to be used for this lookup is implicit.
XSince setting a window's colormap attribute to a Colormap that
Xdoes not match the Visual of the window is an error,
Xusing the Colormap attribute of the window
Xfor the pixel value lookup implies using the correct Visual.
X.NH 2
XObtaining Correct Data from GetImage
X.LP
XThe problem of GetImage returning garbage is described in the X11
Xprotocol specification:
X.Qp
X``If the window has a backing store, 
Xthen the backing-store contents are returned for regions of the window 
Xthat are obscured by noninferior windows;
Xotherwise, the returned contents of such obscured regions are undefined.
XAlso undefined are the returned contents of visible
Xregions of inferiors of different depth than the specified window.''
X.[
Xscheifler protocol 1988
X.]
X.Qe
X.LP
XThere are therefore two reasons why some of the returned pixel values may be
Xwrong:
X.Ip
XThey may be obscured by non-inferior windows,  and the server may not
Xbe maintaining backing-store for the window.
XThe backing-store attribute of a window is a hint to the server;
Xthere is no way for a client to discover whether the server is actually
Xmaintaining backing-store for any particular window at any particular time.
X.IP
XThus,  unless it can be determined that a pixel in a window is
X.I not
Xobscured by a non-inferior window,  that pixel value must be regarded as
Xgarbage.
X.Ip
XThey may be in a visible region of an inferior of different depth.
X.IP
XThus,  unless the pixel in question can be shown
X.I not
Xto be in an inferior of different depth,  its value must be regarded as
Xgarbage.
X.LP
XIn both these cases,  at some cost,  we can:
X.Ip
Xunambiguously determine that a pixel value is good,
X.Ip
Xassume that all others are garbage,
X.Ip
Xand use GetImage on other windows to discover the correct values
Xfor these assumed-to-be-garbage pixels.
X.LP
XUnfortunately,  there is a third reason why the pixels may be garbage:
X.Qp
X``When no valid contents are available for regions of a window
Xand the regions are either visible or the server is maintaining backing store,
Xthe server automatically tiles the regions with the window's background
Xunless the window has a background of 
X.B None .
XIf the background is 
X.B None , 
Xthe previous screen contents from other windows of the same depth as the window
Xare simply left in place if the contents come from the parent of the window
Xor an inferior of the parent;
Xotherwise, the initial contents of the exposed regions are undefined.''
X.[
Xscheifler protocol 1988
X.]
X.Qe
X.LP
XIn other words,  the pixels in areas whose top window has background
X.B None
Xmay not have been overwritten by any pixels drawn to the top window,
Xthey may simply have been left there when the window was mapped or
Xexposed.
X.LP
XThere is no way for a client to determine which pixels of a window have
Xbeen updated by operations to that window (or its children).
XThus there is no way to discover which pixels of a top window with
Xbackground
X.B None
Xare garbage,
Xand even if there were there is no way to discover the correct pixel
Xvalue or how to interpret it.
XThe screen dump client simply has to live with the problem;
Xits results cannot be guaranteed correct if any visible windows
Xhave background
X.B None .
X.LP
XThere is one further problem.
XThe protocol specification describes how a Pixmap or a single pixel
Xvalue can be used as the border for a window.
XIt does not specify which Visual and which Colormap are to be used to
Xdisplay these values.
XIt appears that this is an oversight,  and that the Visual and the
XColormap of the window are to be used to display its border.
XThe dump client assumes this.
X.NH 2
XDump Algorithm
X.LP
XWe use the painter's algorithm,  creating an array of pixels to hold the
Xoutput,  and painting the windows into it from the back forwards.
X.LP
XEach pixel in the output may be painted a number of times,  but the last
Xtime it is painted will be by the window on top at that pixel.
XSince this last pixel painted is not overlaid,
Xwe are assured that the pixels returned by GetImage will be good
X(subject to the background
X.B None
Xproblem).
X.LP
XHere is an outline of the algorithm;
Xthe code itself is shown in Appendix A:
X.Ip
XCreate a data structure with one entry per pixel in the specified rectangle,
Xand an empty list whose entries represent Colormaps in use.
XEach entry in the list is itself the head of a list of pixel values in use
Xwith that Colormap.
X.Ip
XGrabServer to prevent changes to the window tree while all this is going on.
X.Ip
XStart at the root,  and:
X.RS
X.Ip
XUse GetGeometry and GetWindowAttributes to find the details of
Xthe current window.
X.Ip
XIf the current window is Viewable:
X.RS
X.Ip
XIf the window's Colormap isn't in the list,  create an entry
Xdescribing it,  and add it to the list.
X.Ip
XUse GetImage on the current window,  and for every pixel in
Xthe returned array:
X.RS
X.Ip
XLabel every corresponding pixel in the data structure with the pixel value
Xreturned by GetImage,  and with this window's Colormap.
X.Ip
XIf this is the first time we've seen this pixel value for this Colormap,
Xuse QueryColor to discover the RGB values that this window's Colormap
Xmaps the pixel value into,  and store the pixel value and RGB in the
Xlist of pixel values in use for this Colormap.
X.RE
X.Ip
XUse QueryTree to find the list of children of the current window and
Xrecurse,  starting with the head (bottom-most) of the list.
X.RE
X.RE
X.Ip
XUngrabServer,  we're finished with it.
X.Ip
XWrite to the output the width and height of the rectangle,
Xand the number of pixel values we've added to the Colormap lists
X(this is an upper bound on the number of the distinct colors
Xin the output).
X.Ip
XFor each pixel in the data structure we built:
X.RS
X.Ip
XFind the list entry for the Colormap the pixel is labelled with.
X.Ip
XIn the list of pixel values in use for that Colormap,
Xfind the pixel value the pixel is labelled with.
X.Ip
XWrite to the output the RGB value stored for its pixel value
Xin the list of pixel values in use for the Colormap.
X.RE
X.NH 2
XAssessment of the Algorithm
X.LP
XThis algorithm is about as simple as it can be while still getting
Xthe job done,  but it causes much more protocol traffic than is
Xstrictly required.
X.LP
XBy making the very pessimistic assumption that a pixel overlaid by
X.I any
Xother window is potentially garbage,
Xit asks the server to return the value of each of these pixels
Xmore often than is essential.
XA more efficient algorithm would only regard pixels overlaid by non-inferiors
Xor inferiors of different depth as potential garbage.
X.LP
XSpace consumption may also be a problem.
XThere are potentially up to $ 2 sup 32 $ different pixel values,
Xand we must retain a list of each pixel value in use for every
XColormap.
XFortunately,
Xthe list of values in use cannot get longer than
Xthe $ [ w ~ times ~ h ] $ of the specified rectangle
X(in the case where every pixel in the rectangle is different),
Xand will normally be much less.
X.NH
XThe ``undump'' Client
X.LP
XThe objective of the screen undump client is to
Xrestore the appearance of the rectangle of the screen that was
Xdumped earlier.
XIt may not in fact be possible to do this,  since the Visuals
Xavailable to the undump program may not be capable of displaying
Xall the colors in the original image.
X.LP
XThe undump client has two main tasks:
X.Ip
XChoose an appropriate Visual and create a Colormap for it.
X.Ip
XBuild an image in memory in which the RGB values have been
Xconverted to pixel values using the Colormap.
X.LP
XFor each of these tasks,  we review the general problem and
Xthen focus on the specific features needed for the undump client.
X.NH 2
XChoosing a Visual
X.LP
XThe server, during the connection handshake,  provides the following
Xinformation for each Visual on each screen:
X.Ip
XThe depth.
X.Ip
XThe Visual class.
X.Ip
XThe masks that identify the red,  green and blue sub-fields of the pixel
Xvalue.
X.Ip
XThe size (number of cells) of the Colormaps of the Visual.
X.Ip
XThe number of bits in a red,  green or blue value that the server
Xwill regard as significant.
X.LP
XThere can be no general rules for choosing a Visual;
Xa particular application might regard any of these pieces of information
Xas the most important factor.
XFor example:
X.Ip
XClients which want to play Colormap tricks,
Xsuch as colormap animation,
Xneed writable Colormap cells,
Xand thus a dynamic Visual.
XFor them,  the class is the most important feature.
X.Ip
XClients which require an exact color need a PseudoColor, DirectColor
Xor TrueColor Visual.
XOther Visuals involve the server making an approximation to the requested
XRGB value.
XFor these clients,  the class is the most important feature.
X.Ip
XClients that
X.I really
Xcare about the exact color will also be interested in the number of
Xsignificant bits,  which will tell them how closely the display can
Xapproximate the RGB value.
X.Ip
XClients that require a certain number of colors to allow for contrast,
Xbut don't care about the exact colors,
Xneed a Visual with a Colormap large enough to hold the colors.
XFor them,  the Colormap size is the most important feature.
X.LP
XXlib
X.[
Xgettys xlib 1988
X.]
Xprovides two utility routines to make selecting a suitable Visual easier,
Xusing the
X.I XVisualInfo
Xstructure shown in Figure 3.
X.KF
X.Ls
X.ta 8n 16n 24n 32n 40n
X	typedef struct {
X		Visual		*visual;
X		VisualID	visualid;
X		int		screen;
X		int		depth;
X		int		class;
X		unsigned long	red_mask;
X		unsigned long	green_mask;
X		unsigned long	blue_mask;
X		int		colormap_size;
X		int		bits_per_rgb;
X	} XVisualInfo;
X.Le
X.DS C
XFigure 3: The XVisualInfo Structure
X.DE
X.KE
X.LP
XA client that simply wants to select a Visual of a given depth and class
Xcan use
X.I XMatchVisualInfo() .
XThe client provides a depth and a Visual class,  and an
X.I XVisualInfo
Xstructure describing one of the possibly many Visuals of that class
Xand depth is returned.
X.LP
XA client that wants more detailed control over the selection of a Visual
Xcan use
X.I XGetVisualInfo() .
XThe client constructs a template
X.I XVisualInfo
Xstructure,  filling in the fields it is interested in.
XAn array of
X.I XVisualInfo
Xstructures is returned,
Xone for each Visual that matches the specified fields.
XFor example,  the code in Figure 4
Xwill find all PseudoColor Visuals with 256-entry
XColormaps.
X.KF
X.Ls
X.ta 8n 16n 24n 32n 40n 48n 56n
X	{
X		XVisualInfo	vinfo_template,
X				*vinfo_list;
X		int		num_matching_visuals;
X	
X		vinfo_template.class = PseudoColor;
X		vinfo_template.colormap_size = 256;
X	
X		vinfo_list = XGetVisualInfo(dpy,
X			VisualClassMask | VisualColormapSizeMask,
X			&vinfo_template, &num_matching_visuals);
X		if (vinfo_list == (VisualInfo *) 0) {
X			/* No such Visuals */
X		} else {
X			/* vinfo_list is an array of matches */
X		}
X	}
X.Le
X.DS C
XFigure 4:  Finding all 256-entry Colormap Visuals
X.DE
X.KE
X.LP
XIn the case of the undump client,  we have a problem that is
Xmore complex than either of these two simple cases.
XWe have a set of RGB values
Xthat we wish to display as well as the available Visuals will let
Xus.
XWe have an upper bound
X.I N
Xon the number of colors,  but no other
Xinformation about the colors\s-2\u\(dd\d\s0.
X.FS
X\(dd  Scanning the RGB values could generate other information,
Xsuch as that all the R, G and B values were equal in a gray image.
XDoing so would make the code,  and the choice of a Visual too
Xcomplex for a paper like this.
X.FE
X.LP
XChoosing a Visual capable of displaying
X.I N
Xdifferent RGB values takes four steps (the actual code is the
Xroutine
X.I FindVisual()
Xin Appendix B):
X.Ip
XRank the Visual classes in descending order of usability for
Xour purposes:
X.RS
X.Ip
XTrueColor.
XA TrueColor Visual with large enough colormaps would be ideal
Xfor the dump client,  since it would not merely represent the
Xrequired RGB values,  but it would not reserve private Colormap
Xcells to do so.
X.Ip
XDirectColor & PseudoColor.
XThese Visuals,  if their Colormaps are big enough,  can represent the
XRGB values we need,  but to do so they have to reserve private
Xcells,  reducing the server resources available for other clients.
X.Ip
XStaticColor.
XA color Visual,  even though we have no control over the color values,
Xis likely to make a better approximation than a GrayScale Visual which
Xcannot display colors at all.
X.Ip
XGrayScale.
XThis Visual,  if its Colormaps were big enough,  could make a monochrome
Xapproximation to the image better than a StaticGray Visual in which
Xwe would have no control over the shades of gray.
X.Ip
XStaticGray.
XIf there's nothing else,  we'll have to make do with this.
X.RE
X.Ip
XScan the list of Visuals returned by the server
Xduring the connection handshake,  and for each Visual class
Xrecord the Visual with the largest Colormaps.
XOf course,  in the normal case,  only a few of the classes will
Xexist,  and the others will be recorded as having a largest Colormap of
Xsize zero.
X.Ip
XIn the rank order,  look for the smallest Visual with
Xcolormaps big enough to display the required number of colors.
XIf one is available,  use it.
X.Ip
XOtherwise,  use the Visual with the largest Colormaps.
XSince none of the maps are big enough to display all the colors,
Xthe server will doing some approximation,
Xand the bigger the map the better the approximation.
X.LP
XNote that we look for the
X.I smallest
XVisual that will do the job.
XThis will ensure that the client uses no more resources than
Xrequired to get its job done.
X.NH 2
XConverting RGB to pixel values
X.LP
XX provides three fundamentally different methods for converting RGB
Xvalues to pixel values.  A client can:
X.Ip
XRequest the server to perform the conversion and return a pixel value.
XThe result is to associate a sharable,  read-only Colormap cell
Xcontaining an approximation to the RGB values with the pixel value.
X.Ip
XRequest the server to assign a writable Colormap cell and corresponding
Xpixel value for the client's private use.
XThe client can then set the Colormap cell to the RGB value.
X.Ip
XThe client can predict the pixel value that will correspond to the
XRGB value,  using its knowledge of the contents of the Colormap.
X.LP
XThe choice of a suitable method depends on the requirements of the
Xapplication and on the class of the Visual it is using.
X.NH 3
XServer does conversion
X.LP
XThe AllocColor request takes an RGB triple and a Colormap as an
Xargument,  and returns a pixel index that points to a
XColormap cell containing the best approximation the server can
Xmake to that RGB value,  and the actual RGB values that the cell
Xcontains.
XIt does so by:
X.Ip
XIf the Visual is static (StaticGray, StaticColor,  or TrueColor),
Xit returns the cell in the map that is closest to the request RGB
Xvalue.
X.Ip
XIf the Visual is dynamic (GrayScale, PseudoColor,  or DirectColor)
Xand the Colormap is full,  it returns the read-only cell with the
Xclosest RGB value to the requested one.
X.Ip
XIf the Visual is dynamic,  and the Colormap has free cells,  the
Xserver will allocate an cell,  mark it read-only,  and set it to
Xthe requested RGB value.
X.LP
XThis technique should be used by all applications except those for
Xwhich the
X.I exact
Xrepresentation of a color is of primary importance,
Xor which use very large numbers of colors.
XThe reasons for preferring this method are that it will work on
Xany Visual,  and that it makes the most efficient use of the
Xserver's resources.
XNote,  however,  that since AllocColor returns a value,  it
Xrequires a round-trip to the server and is therefore slow.
X.NH 3
XClient sets color
X.LP
XIf the Visual is dynamic,
Xclients can use AllocColorCells or AllocColorPlanes to reserve one
Xor more pixel values for their private use.
XIf the allocation succeeds,  the pixel values will point to private,
Xwritable Colormap cells.
XThe client can then use StoreColors to set the RGB values of these
Xcells to exactly the values it desires.
X.LP
XThis technique is more efficient than AllocColor,
Xbecause a round-trip to the server is needed only for the initial allocation
Xrather than every time a color is modified.
XHowever,
Xit should be used only if it essential to the application because
X.Ip
Xit will work only on a dynamic Visual,
X.Ip
Xit consumes server resources that no other client can use until they are released,
X.Ip
Xand unlike the other techniques,
Xit can fail.
X.LP
XIn general,  clients using this technique should create a private Colormap.
XIdeally,  the default Colormap for each Visual should be left for clients using the
Xother techniques to maximize the sharing of resources.
XUnfortunately,  at present a default Colormap is available only for the Visual
Xof the root window.\s-2\u*\d\s0
X.FS
X*  See section 2.2 of the Xlib manual.
XThis problem is being addressed by the X Consortium.
X.FE
X.NH 3
XClient predicts pixel value
X.LP
XThere are two circumstances in which a client can determine the pixel
Xvalue corresponding to a given RGB value
X.I without
Xa round-trip to the server.
XTo do so,  it must have knowledge of the contents of the Colormap:
X.Ip
XIf the Visual is TrueColor,
Xthe Colormap is known to provide linear ramps in each primary color.
XThe R, G and B values can thus be adjusted to the match the corresponding
Xsub-field mask,  and or-ed together to make the pixel value.
X.Ip
XIf the Colormap is one of the set of ``standard'' Colormaps
Xa similar calculation can be performed.
XApplications wishing to use one of these Colormaps look for a property
Xdescribing it on the root window;
Xif the property is not found the application creates a suitable Colormap
Xand a property to describe it.
X.LP
XUnfortunately,  as specified the ``standard colormaps'' mechanism doesn't
Xwork if the server supports multiple Visuals.
XThe properties describe a Colormap,
Xbut not the Visual it belongs to.
XGiven a Colormap,  the protocol does not provide any means to determine
Xthe Visual it belongs to.
XThus,  it must be assumed that the ``standard'' Colormaps belong to the
Xdefault Visual.\s-2\u\(dg\d\s0
X.FS
X\(dg  See section 9.2. of the Xlib manual.
XThis problem is being addressed by the X Consortium.
X.FE
X.NH 2
XThe Undump Algorithm
X.LP
XHere is an outline of the algorithm;
Xthe code itself is shown in Appendix B:
X.Ip
XRead in the width,  height,  number of colors & RGB values.
X.Ip
XChoose an appropriate Visual
X.Ip
XCreate a Colormap for the chosen Visual.
X.Ip
XCreate an image in memory to hold the pixel values that will
Xeventually appear in the window.
X.Ip
XFor each pixel in the data:
X.RS
X.Ip
XConvert the RGB values for the pixel into a pixel value,
Xusing the AllocColor request.
X.Ip
XStore the pixel value into the corresponding location in the
Ximage.
X.RE
X.Ip
XCreate and map a window which uses the Colormap.
X.Ip
XPaint any exposed part of the window with the pixel values
Xfrom the image.
X.NH 2
XAssessment of the Algorithm
X.LP
XOnce again,  this algorithm is about as simple as it can be
Xand still get the job done.
XAs a result,  it is grossly inefficient.
XIt makes the pessimistic assumption that every pixel in the
Ximage is a different color,  and calls AllocColor to convert its RGB
Xvalues into a pixel value.
XOf course,  it is likely that many pixels are the same color,
Xand calling AllocColor only for every distinct color would reduce the
Xtraffic considerably.
X.LP
XOne problem is that this client creates its own Colormap.
XIdeally,  clients should share Colormaps to improve the chance they
Xwill appear in their correct colors.
XIf the ``standard colormaps'' mechanism worked for multiple Visuals,
Xwe could have used the RGB_BEST_MAP property to share a Colormap
Xwith other similar clients.
XIf the default Colormap mechanism worked for multiple Visuals,
Xwe could have used the appropriate default Colormap.
X.LP
XThe client will work on every Visual type,  in most cases providing the
Xbest match available for the colors in the image.
XThere is,  however,  one case in which the match will be less than
Xoptimal.
XIf the Visual is PseudoColor and is too small to accommodate the number
Xof colors in the image,
Xthe first colors encountered in the right-to-left within top-to-bottom
Xscan of the image will get exact colors as new read-only cells
Xare allocated by AllocColor.
XAt some point,  the map will fill up,  and subsequent AllocColor calls
Xwill return existing pre-allocated entries with approximations to
Xthe requested colors.
XThe visual effect will be odd,  as the quality of reproduction changes
Xabruptly part way down the image.
X.LP
XThe Visual selection process has two problems.
XFor the TrueColor and DirectColor cases,
Xit pessimistically assumes that all the distinct colors in the image differ
Xonly in one component,  and will thus overestimate the size of the Colormap
Xrequired.
XFor example,  suppose we have a blue image with 24 distinct colors;
Xall 24 have the same Red and Green values,  differing only in their Blue value.
XWe would need a Colormap with 24 entries for Blue,  but only 1-entry
Xmaps for Red and Green.
XIn practice,  it is likely that the color distribution will be more even and
Xsmaller maps would suffice.
X.LP
XFurther,  it is complicated by the fact that the number of distinct colors
Xis only an upper bound.
XConsider a dump of a screen with an 8-bit PseudoColor Visual and a 1-bit
XStaticGray Visual.
XAssume that the image in the PseudoColor Visual had 256 different colors,
Xtwo of which were white and black.
XThe dump client would not realize that the white and black of the StaticGray
XVisual were the same as the white and black of the PseudoColor Visual
Xand would record the number of colors as 258.
XUndumping to the same display,  it would regard the PseudoColor Visual as
Xinadequate to represent the 258 colors.
X.LP
XBetter analysis of the set of RGB values to be displayed would solve both
Xproblems,  but would make the program too complex for this paper.
X.NH
XVisuals and the Toolkit
X.LP
XThe attention paid by the X Toolkit Intrinsics to the problem
Xof specifying Visuals is evident from the fact that the word Visual
Xdoes not appear in the index to the Intrinsics manual.
X.[
Xtoolkit intrinsics 1988
X.]
XBy reading the code,  it is possible to determine the following
Xinformation.
X.LP
XThe Window for a Widget is created during the process of 
X.I realizing
Xthe Widget,
Xand the Visual to use has to be selected as part of this process.
XDifferent Widget classes will differ as to how they choose a Visual.
XAll Athena Widgets use CopyFromParent as their Visual selection,
Xdeferring the choice to their parent.
XThe root of the Widget tree is a so-called Shell Widget,
Xwhich in the Intrinsics implementation itself inherits its Visual
Xfrom its parent,  in this case the root.
XSo,  all existing Widgets use the Visual of the root.
X.LP
XThe core information,  which all Widgets possess,  includes a Colormap.
XFor the Athena Widgets,  this had better be a Colormap from the root's
XVisual,  or Xlib errors will occur.
XThis Colormap is used to convert RGB values to pixels for the Widget,
Xusing the AllocColor technique.
XOne might think that it would be possible to realize a Widget in a Visual
Xother than the root's by giving it a Colormap from that Visual,  but
Xthis will not work.
X.LP
XA Widget class that needed some Visual other than the root's
Xwould have to implement its own realize procedure,  and make the choice there.
XThe choice algorithm would be the same for all instances of the Widget,
Xbut this does not mean that all instances would have to have the same Visual.
XThis sounds onerous,  but it is in fact the correct approach.
XAs we showed above,
Xthe algorithm for choosing an appropriate Visual is application-specific;
Xit would not be possible to wire-in to the Intrinsics a single algorithm
Xthat would satisfy everyone.
X.NH
XConclusion
X.LP
XThe X11 color model provides powerful access to the capabilities
Xof different types of display hardware.
XUsed carelessly,
Xthis access can lead to programs which run only in the
Xenvironment in which they were developed.
X.LP
XAll but the simplest X11 clients must take care to choose the most
Xsuitable Visual for their purposes,
Xand to adapt their behavior to its capabilities.
XWe have presented the techniques for doing so for a simple
Xapplication,  but more complex applications will require a wider
Xrange of techniques.
XMore work is needed to develop these.
X.SH
XAcknowledgements
X.LP
XThanks are due to James Gosling,  who helped to develop our understanding
Xof these issues,  and who designed the multi-Visual and Colormap capabilities
Xof the X11/NeWS server,
Xto Jeff Vroom,  who spotted the problem of the default colormap,
Xto Bob Scheifler,  who clarified several obscure points,
Xand to the Usenix reviewers.
X.[
X$LIST$
X.]
X.SH
XAppendix A: Dump Program
X.LP
X.Ls
X.ta 8n 16n 24n 32n 40n 48n 56n 64n
X.so xsd.c
X.Le
X.SH
XAppendix B: Undump Program
X.LP
X.Ls
X.ta 8n 16n 24n 32n 40n 48n 56n 64n
X.so xsud.c
X.Le
SHAR_EOF
fi
if test -f 'vis.refs'
then
	echo shar: "will not over-write existing file 'vis.refs'"
else
sed 's/^X//' << \SHAR_EOF > 'vis.refs'
X%A Robert W. Scheifler
X%T X Window System Protocol,  Version 11,  Release 3
X%I Massachusetts Institute of Technology
X%C Cambridge MA
X%D 1988
X
X%A David S. H. Rosenthal
X%T A Simple X11 Client Program
X%I USENIX conference
X%C Dallas,  TX
X%D February 1988
X%K Hello World
X%O Reprinted as \fIGoing for Baroque\fP,  Unix Review \fB6\fP(6), June 1988.
X
X%T Xlib \- C Language X Interface
X%A Jim Gettys
X%A Ron Newman
X%A Robert W. Scheifler
X%I Massachusetts Institute of Technology
X%C Cambridge,  MA
X%D 1988
X
X%T X Toolkit Intrinsics \- C Language X Interface
X%A Joel McCormack
X%A Paul Asente
X%A Ralph R. Swick
X%I Massachusetts Institute of Technology
X%C Cambridge,  MA
X%D 1988
X
X%T X Window System,  Version 11: Inter-Client Communication Conventions Manual
X%A David S. H. Rosenthal
X%I Massachusetts Institute of Technology
X%C Cambridge,  MA
X%D 1988
X%X icccm
X
X%T X11/NeWS Design Overview
X%A Robin Schaufler
X%I USENIX conference
X%C San Francisco,  CA
X%D June 1988
X%P 23-35
X%K X11/NeWS merge
X
X%A Robert W. Scheifler
X%A Jim Gettys
X%T The X Window System
X%J ACM Transactions on Graphics
X%V 5
X%N 2
X%P 79-109
X%D April 1987
SHAR_EOF
fi
if test -f 'xsd.c'
then
	echo shar: "will not over-write existing file 'xsd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xsd.c'
X#include <X11/Xlib.h>
X#include <stdio.h>
X#define	max(a,b)	((a) > (b) ? (a) : (b))
X#define	min(a,b)	((a) < (b) ? (a) : (b))
X
XDisplay	*dpy;		/* X server we're talking to */
Xint dumpw, dumph;	/* Size of the "specified rectangle" */
X
X/*
X *  There will be one of these for each Colormap we find
X */
Xstruct cmp {
X    struct cmp		*next;		/* Link in chain */
X    Colormap		cmap;		/* The Colormap ID */
X    unsigned long	allocated, used;/* Size & usage of inUse */
X    XColor		*inUse;		/* Array of in-use colors */
X};
Xstruct cmp *inUse;	/* The list of Colormaps we found */
Xint numColor = 0;	/* Upper bound on number of distinct RGB values */
X
X/*
X *  There will be one of these for each pixel in the rectangle
X */
Xstruct pxl {
X    struct cmp		*pCmap;		/* The colormap for this pixel */
X    unsigned long	pixel;		/* The pixel value at this pixel */
X};
Xstruct pxl *Map;	/* The map representing the rectangle */
X#define FindPixel(x,y) ((Map+((y)*dumpw))+(x))
X
X/*
X *  Find (and create if necessary) a struct cmp for this Colormap
X */
Xstruct cmp *
XFindColormap(cmap)
X    Colormap	cmap;
X{
X    register struct cmp *pCmap;
X
X    /*  If we've seen this Colormap before,  return its struct cmp */
X    for (pCmap = inUse;  pCmap; pCmap = pCmap->next)
X	if (cmap == pCmap->cmap)
X	    return (pCmap);
X    /* First time, so create a new struct cmp, link it and return it */
X    pCmap = (struct cmp *) calloc(sizeof (struct cmp), 1);
X    pCmap->next = inUse;
X    pCmap->cmap  = cmap;
X    inUse = pCmap;
X    return (pCmap);
X}
X
X/*
X *  Record this pixel value as being in use in its Colormap
X */
Xvoid
XRegisterPixel(pixel, pCmap)
X    unsigned long	pixel;
X    struct cmp		*pCmap;
X{
X    register unsigned long i = pCmap->used;
X
X    /*  If the pixel value is already known,  do nothing */
X    while (i)
X	if (pixel == pCmap->inUse[--i].pixel)
X	    return;
X    /*  This is the first time we've seen this pixel value */
X    if (pCmap->used >= pCmap->allocated) {
X	/*  Need to expand or create the inUse array */
X	pCmap->allocated = (pCmap->allocated * 2) + 10;
X	pCmap->inUse = (XColor *)(pCmap->inUse ?
X			realloc(pCmap->inUse,
X				pCmap->allocated * sizeof (XColor)) :
X			malloc(pCmap->allocated * sizeof (XColor)));
X    }
X    /*  Now we have space to store the XColor, use QueryColor to get RGB */
X    pCmap->inUse[pCmap->used].pixel = pixel;
X    XQueryColor(dpy, pCmap->cmap, &pCmap->inUse[pCmap->used]);
X    numColor++;
X    pCmap->used++;
X}
X
X/*
X *  This gets called once for each window we find as we walk down the tree
X */
XDoWindow(w, xo, yo, x, y, wi, hi)
X    Window	w;
X    int		xo, yo;	/* Parent's origin in root space */
X    int		x, y;	/* Top-left of rectangle in root space */
X    int		wi, hi;	/* Size of rectangle */
X{
X    XWindowAttributes	xwa;	/* Place to return the window's attributes */
X    XImage		*xim;	/* Image to store window's pixels */
X    int			width, height, x1, y1, xi, yi;
X    Window		root, parent, *children;
X    int			nchild, n;
X    struct cmp		*pCmap;
X
X    /*  Get the attributes of this window,  and locate its struct cmp */
X    if (!XGetWindowAttributes(dpy, w, &xwa) || xwa.map_state != IsViewable)
X	return;
X    pCmap = FindColormap(xwa.colormap);
X    /* Compute top-left of image in root space */
X    x1 = max(x, xwa.x+xo);
X    y1 = max(y, xwa.y+yo);
X    width = min(x+wi, xwa.x + xwa.width + 2*xwa.border_width + xo) - x1;
X    height = min(y+hi, xwa.y + xwa.height + 2*xwa.border_width + yo) - y1;
X    if (width <= 0 || height <= 0)
X	return;
X    /*  Use GetImage to get the pixel values for the rectangle */
X    if (!(xim = XGetImage(dpy, w, x1-xwa.border_width-xwa.x-xo,
X			  y1-xwa.border_width-xwa.y-yo, width, height,
X			  (~0), ZPixmap)))
X	return;
X    /*  For each pixel in the returned image */
X    for (yi = 0; yi < height; yi++)
X	for (xi = 0; xi < width; xi++) {
X	    register struct pxl *pPxl = FindPixel(xi+x1, yi+y1);
X
X	    /*  Label the pixel in the map  with this window's Colormap */
X	    pPxl->pCmap = pCmap;
X	    /*  And with its pixel value */
X	    pPxl->pixel = XGetPixel(xim, xi, yi);
X	    RegisterPixel(pPxl->pixel, pCmap);
X	}
X    /*  Free the space for the image */
X    XDestroyImage(xim);
X    /*  Find the children of this window, in back-to-front order */
X    if (XQueryTree(dpy, w, &root, &parent, &children, &nchild)) {
X	for (n = 0; n < nchild; n++) {
X	    /*  Process each of the child windows recursively */
X	    DoWindow(children[n], xo + xwa.x + xwa.border_width,
X		     yo + xwa.y + xwa.border_width, x1, y1, width, height);
X	}
X	/*  Free the list of children */
X	if (nchild > 0)
X	    XFree(children);
X    }
X    return;
X}
X
X/*
X *  Return the XColor structure for the pixel at [x,y] in the map
X */
XXColor *
XFindColor(x, y)
X    int		x, y;
X{
X    struct pxl	*pPxl = FindPixel(x, y);	/* Find the struct pxl */
X    struct cmp	*pCmp = pPxl->pCmap;		/* And the struct cmp */
X    int		i;
X
X    /*  Scan the in-use array for this colormap for the pixel value */
X    for (i = 0; i < pCmp->used; i++)
X	if (pPxl->pixel == pCmp->inUse[i].pixel)
X	    return (&(pCmp->inUse[i]));
X    return (NULL);
X}
X
X/*
X *  Write the representation of the rectangle to stdout
X */
XDoOutput(x, y, w, h)
X    int		x, y, w, h;
X{
X    int		xi, yi;
X
X    /*  Write the width,  height,  and number of colors */
X    fwrite(&w, sizeof (int), 1, stdout);
X    fwrite(&h, sizeof (int), 1, stdout);
X    fwrite(&numColor, sizeof (int), 1, stdout);
X    /*  For each pixel in the image */
X    for (yi = 0; yi < h; yi++)
X	for (xi = 0; xi < w; xi++) {
X	    XColor	*color = FindColor(x + xi, y + yi);
X
X	    /*  Write the R, G & B values for this pixel */
X	    fwrite(&(color->red), sizeof (unsigned short), 1, stdout);
X	    fwrite(&(color->green), sizeof (unsigned short), 1, stdout);
X	    fwrite(&(color->blue), sizeof (unsigned short), 1, stdout);
X	}
X}
X
Xmain(argc, argv)
X    int		argc;
X    char	**argv;
X{
X    int		scrn;
X
X    /*  Try to connect to the server */
X    if ((dpy = XOpenDisplay(NULL)) == (Display *) 0) {
X	fprintf(stderr, "Can't open display\n");
X	exit(1);
X    }
X    /*  Dump the specified part of the default screen */
X    scrn = DefaultScreen(dpy);
X    if (argc > 1)
X	dumpw = atoi(argv[1]);
X    else
X        dumpw = DisplayWidth(dpy, scrn);
X    if (argc > 2)
X	dumph = atoi(argv[2]);
X    else
X        dumph = DisplayHeight(dpy, scrn);
X    /*  Create the map with one struct pxl per pixel */
X    Map = (struct pxl *) calloc(sizeof (struct pxl), dumpw * dumph);
X    /*  Grab the server so things don't change under our feet */
X    XGrabServer(dpy);
X    /*  Recursively build the map */
X    DoWindow(RootWindow(dpy, scrn), 0, 0, 0, 0, dumpw, dumph);
X    /*  Finished reading things from the server - let it go */
X    XUngrabServer(dpy);
X    /*  Write the RGB representation of the rectangle to stdout */
X    DoOutput(0, 0, dumpw, dumph);
X    exit(0);
X}
SHAR_EOF
fi
if test -f 'xsud.c'
then
	echo shar: "will not over-write existing file 'xsud.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xsud.c'
X#include	<X11/Xlib.h>
X#include	<X11/Xutil.h>
X#include	<stdio.h>
X#include	<sys/file.h>
X
XDisplay			*dpy;		/*  X server we're talking to */
XWindow			win;		/*  Window to paint the image in */
XGC			gc;		/*  GC to use for painting */
XVisual			*visual;	/*  Visual to use for the window */
XColormap		cmap;		/*  Colormap to use for painting */
XXEvent			ev;		/*  Event received from the server */
XXImage			*image;		/*  To hold the image to be painted */
Xint			width, height;	/*  Size of the window */
Xint         	        best_size[6];	/*  Largest colormap per Visual class */
XXVisualInfo             *best_vis[6];	/*  Best Visual per Visual class */
Xint                     best_class[] = { TrueColor, DirectColor, PseudoColor,
X                                         StaticColor, GrayScale, StaticGray };
X
X/*
X *  Return the most suitable Visual for representing numcolors colors
X */
XXVisualInfo *
XFindVisual(numcolors)
X    int		numcolors;
X{
X    int			num_vis, i, big_map = 0;
X    XVisualInfo 	vinfo_template, *vlist, *v, *big_vis = NULL;
X
X    /*  Get descriptions of all the visuals */
X    vlist = XGetVisualInfo(dpy, VisualNoMask, &vinfo_template, &num_vis);
X    /* Scan the list examining the colormap size */
X    for (v = vlist; v < vlist + num_vis; v++) {
X        /*  Remember the biggest colormap among all classes */
X	if (v->colormap_size > big_map) {
X	    big_map = v->colormap_size;
X	    big_vis = v;
X	}
X	/*  If the colormap is big enough,  remember it */
X        if (v->colormap_size > numcolors) {
X            if ((best_size[v->class] == 0)
X              || (v->colormap_size < best_size[v->class])) {
X	        /*  Smallest so far that'll do */
X                best_size[v->class] = v->colormap_size;
X                best_vis[v->class] = v;
X            }
X	}
X    }
X    /*  In decreasing order of usability,  look at each class */
X    for (i = 0; i < 6; i++)
X        if (best_size[best_class[i]] > numcolors)
X            /*  This class can represent enough colors */
X            return (best_vis[best_class[i]]);
X    /*  Sigh!  We'll have to make do with a Visual that's too small */
X    return (big_vis);
X}
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X    int         numcolors, num_pxls, num_vis, x, y;
X    unsigned short *rgbvalues;
X    XVisualInfo *vis;
X    XSetWindowAttributes values;
X    XColor      color;
X
X
X    /* Read the size information from stdin */
X    fread((char *) &width, sizeof(int), 1, stdin);
X    fread((char *) &height, sizeof(int), 1, stdin);
X    fread((char *) &numcolors, sizeof(int), 1, stdin);
X    /* Allocate space to hold the RGB data,  and read it in */
X    num_pxls = width * height;
X    rgbvalues = (unsigned short *) malloc(sizeof(unsigned short)
X					  * 3 * num_pxls);
X    fread((char *) rgbvalues, sizeof(unsigned short), 3 * num_pxls, stdin);
X    /* Connect to the server */
X    if ((dpy = XOpenDisplay(NULL)) == (Display *) 0) {
X	fprintf(stderr, "can't open display\n");
X	exit(1);
X    }
X    /* Find a suitable Visual for numcolors */
X    vis = FindVisual(numcolors);
X    /* Create a Colormap in the Visual we found */
X    cmap = XCreateColormap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
X			   vis->visual, AllocNone);
X    /* Create an image the right size */
X    image = XCreateImage(dpy, vis->visual, vis->depth, ZPixmap, 0,
X	      (unsigned long *) malloc(num_pxls * sizeof(unsigned long)),
X			 width, height, 32, 0);
X    /* For each pixel in the image */
X    for (y = 0; y < height; y++)
X	for (x = 0; x < width; x++) {
X	    /* Fill out the RGB fields of the XColor struct */
X	    color.red = *rgbvalues++;
X	    color.green = *rgbvalues++;
X	    color.blue = *rgbvalues++;
X	    color.flags = DoRed | DoGreen | DoBlue;
X	    /* Get the server to convert from RGB to pixel value */
X	    XAllocColor(dpy, cmap, &color);
X	    /* Put the pixel value into the image */
X	    (void) XPutPixel(image, x, y, color.pixel);
X	}
X    /* Create a suitable window using the Colormap, background White */
X    values.colormap = cmap;
X    /* get White from our colormap */
X    XAllocNamedColor(dpy, cmap, "white", &color, &color);
X    values.background_pixel = color.pixel;
X    /* Listen for Expose,  Enter and Leave events */
X    values.event_mask = ExposureMask | EnterWindowMask | LeaveWindowMask;
X    win = XCreateWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)),
X			0, 0, width, height, 0, vis->depth, InputOutput,
X		     vis->visual, CWColormap | CWEventMask | CWBackPixel,
X			&values);
X    /* Create a GC to use for repainting the window */
X    gc = XCreateGC(dpy, win, 0, NULL);
X    /* Map the window,  wait for the Expose events,  and paint */
X    XMapWindow(dpy, win);
X    while (True) {
X	XExposeEvent *e;
X
X	XNextEvent(dpy, &ev);
X	switch (ev.type) {
X	    case Expose:
X		e = (XExposeEvent *) & ev;
X		/* Copy the image to the exposed part of the window */
X		XPutImage(dpy, win, gc, image, e->x, e->y, e->x, e->y,
X		      (e->x + e->width > width ? width - e->x : e->width),
X		      (e->y + e->height > height ? height - e->y : e->height));
X		break;
X	    case EnterNotify:
X		/* Mouse is in the window,  install its Colormap */
X		XInstallColormap(dpy, cmap);
X		break;
X	    case LeaveNotify:
X		/* Mouse has left the window,  uninstall its Colormap */
X		XUninstallColormap(dpy, cmap);
X		break;
X	}
X    }
X}
SHAR_EOF
fi
exit 0
#	End of shell archive