[comp.sources.x] v03i008: display the default colormap, Part01/01

mikew@wyse.wyse.com (Mike Wexler) (02/03/89)

Submitted-by: bradley@scotty.dccs.upenn.edu (John Bradley)
Posting-number: Volume 3, Issue 8
Archive-name: xcmap/part01



xcmap is a program that displays the contents of the default colormap on 
4-, 6-, and 8-bit X11 displays.  It displays the colormap both as a grid of
colored rectangles, and as RGB components.

This is a very useful thing to anybody who's trying to do color-intensive
programs (such as displaying GIF pictures...) on X.

It's also kind of neat to watch.

John Bradley  -  bradley@cis.upenn.edu

-------------------------(cut here)--------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./xcmap`
then
  mkdir ./xcmap
  echo "mkdir ./xcmap"
fi
if `test ! -s ./xcmap/README`
then
echo "writing ./xcmap/README"
cat > ./xcmap/README << '\Rogue\Monster\'
xcmap is a program that displays the contents of the default colormap on 
4-, 6-, and 8-bit X11 displays.  It displays the colormap both as a grid of
colored rectangles, and as RGB components.
\Rogue\Monster\
else
  echo "will not over write ./xcmap/README"
fi
if `test ! -s ./xcmap/xcmap.man`
then
echo "writing ./xcmap/xcmap.man"
cat > ./xcmap/xcmap.man << '\Rogue\Monster\'
.TH xcmap 1X
.SH NAME
xcmap \- displays the default colormap on X11 displays
.SH SYNTAX
\fBxcmap\fP [ [-d] \fIdisplay\fP] [ [-g] \fIgeometry\fP]
.SH DESCRIPTION
\fBxcmap\fP is an X11 program that displays the contents of the colormap
on 4-, 6-, and 8-bit color (or greyscale) displays.  It displays a grid 
of squares, (4x4, 8x8, or 16x16 grid, depending on the number of planes)
that correspond to entries in the colormap.  The squares are (of course)
drawn in their corresponding color.
.PP
You may click (with the left button) on any of these squares.  Doing so
will display the pixel number corresponding to that square, and its red,
green, and blue components (as 4-digit hex numbers).  It will continue to do
this as long as you hold the button down.
.PP
Note:  This program points out a bug in the X11R2 server for the IBM RT
Megapel display.  Essentially, the problem is a discrepancy between what the 
server THINKS the colormap is, and what the colormap in the hardware 
ACTUALLY is.
.PP
.SH AUTHOR
John Bradley  -  bradley@cis.upenn.edu
\Rogue\Monster\
else
  echo "will not over write ./xcmap/xcmap.man"
fi
if `test ! -s ./xcmap/Makefile`
then
echo "writing ./xcmap/Makefile"
cat > ./xcmap/Makefile << '\Rogue\Monster\'
XLIB = -lX11
CFLAGS = -O

OBJS = xcmap.o

all: xcmap

xcmap: $(OBJS)
	cc $(CFLAGS) -o xcmap $(OBJS) $(XLIB) $(CLIBS)

clean:
	rm -f $(OBJS)


\Rogue\Monster\
else
  echo "will not over write ./xcmap/Makefile"
fi
if `test ! -s ./xcmap/xcmap.c`
then
echo "writing ./xcmap/xcmap.c"
cat > ./xcmap/xcmap.c << '\Rogue\Monster\'
/*
 * xcmap.c - shows the contents of the colormap on 4, 6, or 8-bit X11 displays
 *
 *  Author:    John Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 */

#define REVDATE   "Rev: 2/1/89"

/* include files */
#include <stdio.h>
#include <strings.h>
#include <ctype.h>

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>

typedef unsigned char byte;

/* text centering macros for X11 */
#define CENTERX(f,x,str) ((x)-XTextWidth(f,str,strlen(str))/2)
#define CENTERY(f,y) ((y)-((f->ascent+f->descent)/2)+f->ascent)

#define FONT "8x13"

/* X stuff */
Display       *theDisp;
int           theScreen, dispcells;
Colormap      theCmap;
Window        rootW, mainW;
GC            theGC;
unsigned long fcol,bcol;
Font          mfont;
XFontStruct   *mfinfo;
Visual        *theVisual;


/* global vars */
int            WIDE,HIGH,cWIDE,cHIGH,nxcells,nycells, pvalup;
XColor         defs[256];
char          *cmd, tmpstr[128];



/*******************************************/
main(argc, argv)
    int   argc;
    char *argv[];
/*******************************************/
{
    int        i;
    char      *display, *geom;
    XEvent     event;

    cmd = argv[0];
    display = geom = NULL;


    /*********************Options*********************/

    for (i = 1; i < argc; i++) {
        char *strind;

        if (!strncmp(argv[i],"-g",2)) {		/* geometry */
            i++;
            geom = argv[i];
            continue;
            }

        if (argv[i][0] == '=') {		/* old-style geometry */
            geom = argv[i];
            continue;
            }

        if (!strncmp(argv[i],"-d",2)) {		/* display */
            i++;
            display = argv[i];
            continue;
            }

        strind = index(argv[i], ':');		/* old-style display */
        if(strind != NULL) {
            display = argv[i];
            continue;
            }

        Syntax(cmd);
    }


    /*****************************************************/

    /* Open up the display. */

    if ( (theDisp=XOpenDisplay(display)) == NULL)
        FatalError("can't open display");

    theScreen = DefaultScreen(theDisp);
    theCmap   = DefaultColormap(theDisp, theScreen);
    rootW     = RootWindow(theDisp,theScreen);
    theGC     = DefaultGC(theDisp,theScreen);
    fcol      = WhitePixel(theDisp,theScreen);
    bcol      = BlackPixel(theDisp,theScreen);
    theVisual = DefaultVisual(theDisp,theScreen);

    dispcells = DisplayCells(theDisp, theScreen);
    if (dispcells!=16 && dispcells!=64 && dispcells != 256) {
        sprintf(tmpstr,"dispcells = %d.  This program can only deal with 4, 6, and 8-bit displays.",dispcells);
        FatalError(tmpstr);
        }

    switch (dispcells) {
	case  16:  nxcells = nycells =  4;  break;
	case  64:  nxcells = nycells =  8;  break;
	case 256:  nxcells = nycells = 16;  break;
        }
    

    /**************** Create/Open X Resources ***************/
    if ((mfinfo = XLoadQueryFont(theDisp,FONT))==NULL) {
       sprintf(tmpstr,"couldn't open '%s' font",FONT);
       FatalError(tmpstr);
       }

    mfont=mfinfo->fid;
    XSetFont(theDisp,theGC,mfont);
    XSetForeground(theDisp,theGC,fcol);
    XSetBackground(theDisp,theGC,bcol);

    CreateMainWindow(cmd,geom,argc,argv);
    Resize(WIDE,HIGH);

    XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
                               | StructureNotifyMask | ButtonPressMask);
    XMapWindow(theDisp,mainW);

    /**************** Main loop *****************/
    while (1) {
        XNextEvent(theDisp, &event);
        HandleEvent(&event);
        }
}



/****************/
HandleEvent(event)
    XEvent *event;
/****************/
{
    switch (event->type) {
        case Expose: {
            XExposeEvent *exp_event = (XExposeEvent *) event;

            if (exp_event->window==mainW) 
                DrawWindow(exp_event->x,exp_event->y,
                           exp_event->width, exp_event->height);
            }
            break;

        case ButtonPress: {
            XButtonEvent *but_event = (XButtonEvent *) event;

            if (but_event->window == mainW && but_event->button == Button1) 
                TrackMouse(but_event->x, but_event->y);
            }
            break;

        case KeyPress: {
            XKeyEvent *key_event = (XKeyEvent *) event;
            KeySym ks;
            XComposeStatus status;

            XLookupString(key_event,tmpstr,128,&ks,&status);
            if (tmpstr[0]=='q' || tmpstr[0]=='Q') Quit();
            }
            break;

        case ConfigureNotify: {
            XConfigureEvent *conf_event = (XConfigureEvent *) event;

            if (conf_event->window == mainW && 
                 (conf_event->width != WIDE || conf_event->height != HIGH))
                Resize(conf_event->width, conf_event->height);
            }
            break;


        case CirculateNotify:
        case MapNotify:
        case DestroyNotify:
        case GravityNotify:
        case ReparentNotify:
        case UnmapNotify:       break;

        default:
            printf("event type=%ld\n",event->type); 
            FatalError("Unexpected X_Event");

        }  /* end of switch */
}


/***********************************/
Syntax()
{
    printf("Usage: %s filename [=geometry | -geometry geom] [ [-display] display]\n",cmd);
    exit(1);
}


/***********************************/
FatalError (identifier)
       char *identifier;
{
    fprintf(stderr, "%s: %s\n",cmd, identifier);
    exit(-1);
}


/***********************************/
Quit()
{
    exit(0);
}


/***********************************/
CreateMainWindow(name,geom,argc,argv)
    char *name,*geom,**argv;
    int   argc;
{
    XSetWindowAttributes xswa;
    unsigned int xswamask;
    XSizeHints hints;
    int i,x,y,w,h;

    WIDE = HIGH = 256;			/* default window size */

    x=y=w=h=1;
    i=XParseGeometry(geom,&x,&y,&w,&h);
    if (i&WidthValue)  WIDE = w;
    if (i&HeightValue) HIGH = h;

    if (i&XValue || i&YValue) hints.flags = USPosition;  
                         else hints.flags = PPosition;

    hints.flags |= USSize;

    if (i&XValue && i&XNegative) 
        x = XDisplayWidth(theDisp,theScreen)-WIDE-abs(x);
    if (i&YValue && i&YNegative) 
        y = XDisplayHeight(theDisp,theScreen)-HIGH-abs(y);

    hints.x=x;             hints.y=y;
    hints.width  = WIDE;   hints.height = HIGH;
    hints.max_width  = DisplayWidth(theDisp,theScreen);
    hints.max_height = DisplayHeight(theDisp,theScreen);
    hints.min_width  = 16;
    hints.min_height = 16;
    hints.width_inc = hints.height_inc = 16;
    hints.flags |= PMaxSize | PMinSize | PResizeInc;

    xswa.background_pixel = bcol;
    xswa.border_pixel     = fcol;
    xswa.cursor = XCreateFontCursor (theDisp, XC_top_left_arrow);
    xswamask = CWBackPixel | CWBorderPixel | CWCursor;

    mainW = XCreateWindow(theDisp,rootW,x,y,WIDE,HIGH,2,0,CopyFromParent,
                          CopyFromParent, xswamask, &xswa);

    XSetStandardProperties(theDisp,mainW,"xcmap","xcmap",None,
                            argv,argc,&hints);

    if (!mainW) FatalError("Can't open main window");

}


/***********************************/
DrawWindow(x,y,w,h)
       int x,y,w,h;
{
    int i,j,x1,y1,x2,y2;

    x1 = x / cWIDE;      y1 = y / cHIGH;	/* (x1,y1) (x2,y2): bounding */
    x2 = ((x+w) + cWIDE - 1) / cWIDE;		/*       rect in cell coords */
    y2 = ((y+h) + cHIGH - 1) / cHIGH;

    for (i=y1; i<y2; i++) {
        for (j=x1; j<x2; j++) {
            XSetForeground(theDisp,theGC,(unsigned long) (i*nycells+j) );
            XFillRectangle(theDisp,mainW,theGC,j*cWIDE,i*cHIGH,cWIDE,cHIGH);
            }
        }
}


/***********************************/
Resize(w,h)
int w,h;
{
    cWIDE = (w + nxcells - 1) / nxcells;
    cHIGH = (h + nycells - 1) / nycells;
    WIDE = w;  HIGH = h;
}
                

/***********************************/
TrackMouse(mx,my)
       int mx,my;
{
    /* called when there's a button press in the window.  draws the pixel
       value, and loops until button is released */

    Window        rootW,childW;
    int           rx,ry,x,y;
    unsigned int  mask;

    pvalup = 0;
    DrawPixValue(mx,my);

    while (1) {
        if (XQueryPointer(theDisp,mainW,&rootW,&childW,&rx,&ry,&x,&y,&mask)) {
            if (!(mask & Button1Mask)) break;    /* button released */
            
            DrawPixValue(x,y);
            }
        }
}

                    
/***********************************/
DrawPixValue(x,y)
         int x,y;
{
    static unsigned long pix, lastpix;
    static int           pvaly;

    if (!pvalup) {	/* it's not up.  make it so */
        if (y >= HIGH/2) pvaly = 0;  else pvaly = HIGH - 12;
        pvalup = 1;
        lastpix = 0xffff;		/* kludge to force redraw on first */
	XClearArea(theDisp,mainW,0,pvaly,WIDE,13,True);
        }

    x /= cWIDE;  y /= cHIGH;

    pix = y * nxcells + x;

    if (pix != lastpix) {
        XColor def;
        char  *sp;

	XSetForeground(theDisp,theGC,fcol);
        lastpix = def.pixel = pix;
        XQueryColor(theDisp, theCmap, &def);
        sprintf(tmpstr, "Pix %3ld = ($%04x, $%04x, $%04x)",
                         pix, def.red, def.green, def.blue);

        /* make the hex uppercase */        
        for (sp=tmpstr+4; *sp; sp++) 
            if (islower(*sp)) *sp = toupper(*sp);

        XDrawImageString(theDisp,mainW,theGC,5,pvaly+10,tmpstr,strlen(tmpstr));
        }
}

\Rogue\Monster\
else
  echo "will not over write ./xcmap/xcmap.c"
fi
if `test ! -s ./xcmap/patchlevel.h`
then
echo "writing ./xcmap/patchlevel.h"
cat > ./xcmap/patchlevel.h << '\Rogue\Monster\'
#define PATCHLEVEL 0
\Rogue\Monster\
else
  echo "will not over write ./xcmap/patchlevel.h"
fi
if `test ! -s ./xcmap/AUTHOR`
then
echo "writing ./xcmap/AUTHOR"
cat > ./xcmap/AUTHOR << '\Rogue\Monster\'
Written by John Bradley (bradley@cis.upenn.edu), one of the fine folks at 
the University of Pennsylvania.

Do whatever you want with this program, though it *would* be nice if my name
remained on it somewhere...  Other than that, it may be freely modified,
distributed, and used to fill up disk space.

--jhb
\Rogue\Monster\
else
  echo "will not over write ./xcmap/AUTHOR"
fi
if `test ! -s ./xcmap/Imakefile`
then
echo "writing ./xcmap/Imakefile"
cat > ./xcmap/Imakefile << '\Rogue\Monster\'
LOCAL_LIBRARIES = $(XLIB)

OBJS = \
        xcmap.o

SRCS = \
        xcmap.c

ComplexProgramTarget(xcmap)

\Rogue\Monster\
else
  echo "will not over write ./xcmap/Imakefile"
fi
echo "Finished archive 1 of 1"
exit


-- 
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
Moderator of comp.sources.x