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