[comp.sources.x] v10i087: xv - display and manipulate images, Part09/10

bradley@halibut.cis.upenn.edu (John Bradley) (11/28/90)

Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
Posting-number: Volume 10, Issue 87
Archive-name: xv/part09

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xv.c`
then
echo "writting ./xv.c"
cat > ./xv.c << '\BARFOO\'
/*
 * xv.c - main section of xv.  X setup, window creation, event loop, etc.
 *
 *  Author:    John Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 */


/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation. 
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#define MAIN
#define NEEDSTIME    /* for -wait handling in eventloop */
#define NEEDSDIR     /* for value of MAXPATHLEN */

#include "xv.h"
#include "bitmaps.h"

#include <X11/Xatom.h>

/* program needs one of the following fonts.  Trys them in ascending order */
#define FONT1 "-*-lucida-medium-r-*-*-12-*"
#define FONT2 "-*-helvetica-medium-r-*-*-12-*"
#define FONT3 "6x13"

/* a mono-spaced font needed for the 'pixel value tracking' feature */
#define MFONT1 "-misc-fixed-medium-r-normal-*-13-*"
#define MFONT2 "8x13"   
#define MFONT3 "-*-courier-medium-r-*-*-12-*"

/* things EventLoop() can return (0 and above reserved for 'goto pic#') */
#define QUIT     -1    /* exit immediately  */
#define NEXTPIC  -2    /* goto next picture */
#define PREVPIC  -3    /* goto prev picture */
#define NEXTQUIT -4    /* goto next picture, quit if none (used by 'wait') */


/* file types that can be read */
#define UNKNOWN 0
#define GIF     1
#define PM      2
#define PBM     3
#define XBM     4

static unsigned long rootbg, rootfg;  /* fg/bg for root border */
static int    waitsec = -1;     /* seconds between pics. -1=wait for event */
static int    roottile = 0;     /* resize pic to tile evenly on rootW */
static int    automax  = 0;     /* resize pic to dispWIDE, dispHIGH on open */
static int    autoquit = 0;     /* quit after loading first pic to rootW */
static int    autogamma = 0;    /* perform gamma correction by default */
static int    centerpic = 0;    /* center pic on rootW, instead of tiling */
static int    rootPattern = 0;  /* pattern used for root border */
static char  *maingeom = NULL;
static char   initpath[MAXPATHLEN];
static int    rotatesLeft = 0;
static Atom   __SWM_VROOT = None;

/* used in XResource reading... */
static char *def_str;
static int   def_int;

/* function pre-definitions */
static void Syntax();
static int  openPic();
static void closePic();
static void OpenFirstPic();
static void OpenNextPic();
static void OpenNextQuit();
static void OpenPrevPic();
static void MainLoop();
static int  EventLoop();
static void CreateMainWindow();
static void FixAspect();
static void GetWindowPos();
static void SetWindowPos();
static void TrackCrop();
static void CropKey();
static void TrackPicValues();
static void MakeDispNames();
static int  Rect();
static int  CheckForConfig();
static Bool IsConfig();
static void SaveRootInfo();
static void KillOldRootInfo();
static int  rd_int();
static int  rd_str();
static int  rd_flag();




/*******************************************/
int main(argc, argv)
int   argc;
char *argv[];
/*******************************************/
{
  int   i, imap, ctrlmap, gmap, clrroot;
  char *display, *fname, *whitestr, *blackstr, 
       *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom;
  char *rootfgstr, *rootbgstr;

  XColor ecdef;
  Window rootReturn, parentReturn, *children;
  unsigned int numChildren;


  /*****************************************************/
  /*** variable Initialization                       ***/
  /*****************************************************/

#ifdef SYSV
  getcwd(initpath, sizeof(initpath));
#else
  getwd(initpath);
#endif

  /* init internal variables */
  display = fname = whitestr = blackstr = NULL;
  fgstr = bgstr = rootfgstr = rootbgstr = NULL;
  pic = epic = cpic = NULL;
  theImage = NULL;
  LocalCmap = 0;
  InitFSDTables();
  cmd = rindex(argv[0],'/');
  if (!cmd) cmd = argv[0]; else cmd++;


  /* init gamma curve */
  ghand[0].x =   0;  ghand[0].y =   0;
  ghand[1].x =  64;  ghand[1].y =  64;
  ghand[2].x = 192;  ghand[2].y = 192;
  ghand[3].x = 255;  ghand[3].y = 255;

  /* init gamma presets */
  SetGPreset(0, 255, 64,192, 192, 64,   0);
  SetGPreset(1,   0, 64,100, 234,255, 255);
  SetGPreset(2,   0, 80, 38, 210,180, 255);
  SetGPreset(3,   0, 40, 92, 235,204, 255);

  /* init command-line options flags */
  infogeom = DEFINFOGEOM;  ctrlgeom = DEFCTRLGEOM;  gamgeom = DEFGAMGEOM;
  expand = 1;  ncols = -1;  noglob = 0;  revvideo = 0;  mono = 0;  
  perfect = 0;  ninstall = 0;  fixedaspect = 0;  
  DEBUG = 0;  bwidth = 2;
  useroot = clrroot = noqcheck = rwcolor = fishrunning = 0;
  fish = 0;

#ifdef BROKEFREECOLS
  brokeFreeCols = 1;
#else
  brokeFreeCols = 0;
#endif

  defaspect = normaspect = 1.0;

  mainW = dirW = infoW = ctrlW = gamW = NULL;
  imap = ctrlmap = gmap = 0;

  /* init info box variables */
  infoUp = 0;
  infoMode = INF_STR;
  for (i=0; i<NISTR; i++) SetISTR(i,"");

  /* init ctrl box variables */
  ctrlUp = 0;
  curname = 0;

  gamUp = 0;


  /*****************************************************/
  /*** X Resource Initialization                     ***/
  /*****************************************************/

  /* once through the argument list to find the display name, if any */
  for (i=1; i<argc-1; i++) {
    if (!strncmp(argv[i],"-d",2)) {	/* display */
      display = argv[++i];
      break;
    }
  }

  /* open the display */
  if ( (theDisp=XOpenDisplay(display)) == NULL) {
    fprintf(stderr, "%s: Can't open display\n",argv[0]);
    Quit(1);
  }

  if (rd_str ("aspect")) {
    int n,d;
    if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1)
      fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd);
    else defaspect = (float) n / (float) d;
  }
      
  if (rd_flag("autoGamma"))     autogamma   = def_int;
  if (rd_str ("background"))    bgstr       = def_str;
  if (rd_str ("black"))         blackstr    = def_str;
  if (rd_int ("borderWidth"))   bwidth      = def_int;
  if (rd_flag("brokeFreeCols")) brokeFreeCols = def_int;
  if (rd_flag("centerPic"))     centerpic   = def_int;
  if (rd_str ("ctrlGeometry"))  ctrlgeom    = def_str;
  if (rd_flag("ctrlMap"))       ctrlmap     = def_int;
  if (rd_int ("expand"))        expand      = def_int;
  if (rd_flag("fish"))          fish        = def_int;
  if (rd_flag("fixed"))         fixedaspect = def_int;
  if (rd_str ("foreground"))    fgstr       = def_str;
  if (rd_str ("geometry"))      maingeom    = def_str;
  if (rd_str ("gammaGeometry")) gamgeom     = def_str;
  if (rd_flag("gammaMap"))      gmap        = def_int;

  if (rd_str("gamma")) {
    int gry0,grx1,gry1,grx2,gry2,gry3;
    if (sscanf(def_str,"%d %d %d %d %d %d",&gry0,&grx1,&gry1,
	       &grx2,&gry2,&gry3)!=6) 
      fprintf(stderr,"%s: unable to parse 'gamma' resource\n",cmd);
    else { 
      ghand[0].y = gry0;
      ghand[1].x = grx1;  ghand[1].y = gry1;
      ghand[2].x = grx2;  ghand[2].y = gry2;
      ghand[3].y = gry3;
    }
  }

  /* parse 'gamma1' through 'gamma4' resources */
  for (i=0; i<4; i++) {
    char gstr[10];
    sprintf(gstr,"gamma%d",i+1);

    if (rd_str(gstr)) {
      int y0,x1,y1,x2,y2,y3;
      if (sscanf(def_str,"%d %d %d %d %d %d",&y0,&x1,&y1,&x2,&y2,&y3)!=6) 
	fprintf(stderr,"%s: unable to parse '%s' resource\n",cmd,gstr);
      else
	SetGPreset(i, y0, x1, y1, x2, y2, y3);
    }
  }

  if (rd_str ("infoGeometry"))  infogeom = def_str;
  if (rd_flag("infoMap"))       imap     = def_int;
  if (rd_flag("mono"))          mono     = def_int;
  if (rd_int ("ncols"))         { ncols  = def_int; if (ncols>=0) noglob = 1; }
  if (rd_flag("nglobal"))       noglob   = def_int;
  if (rd_flag("ninstall"))      ninstall = def_int;
  if (rd_flag("noqcheck"))      noqcheck = def_int;
  if (rd_flag("perfect"))       perfect  = def_int;
  if (rd_flag("reverseVideo"))  revvideo = def_int;
  if (rd_str ("rootBackground")) rootbgstr = def_str;
  if (rd_str ("rootForeground")) rootfgstr = def_str;
  if (rd_int ("rootPattern"))    rootPattern = def_int;
  if (rd_flag("rwColor"))       rwcolor  = def_int;
  if (rd_flag("slow24"))        slow24   = def_int;
  if (rd_flag("tile"))          roottile = def_int;
  if (rd_str ("white"))         whitestr = def_str;
      

  /*****************************************************/
  /*** Command Line Options                          ***/
  /*****************************************************/
  
  for (i=1, numnames=0; i<argc; i++) {
    if (argv[i][0] != '-') {   		/* a file name.  put it in list */
      if (numnames<MAXNAMES) {
	namelist[numnames++] = argv[i];
	if (numnames==MAXNAMES) {
	  fprintf(stderr,"%s: too many filenames.  Only using first %d.\n",
		  cmd, MAXNAMES);
	}
      }
    }
    
    else if (!strncmp(argv[i],"-as",2)) { /* default aspect */
      int n,d;
      if (++i<argc) {
	if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1)
	  fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]);
	else defaspect = (float) n / (float) d;
      }
    }

    else if (!strncmp(argv[i],"-au",3))  /* autogamma */
      autogamma++;

    else if (!strncmp(argv[i],"-bf",3))  /* brokeFreeCols */
      brokeFreeCols = !brokeFreeCols;

    else if (!strncmp(argv[i],"-bg",3)) /* background color */
      { if (++i<argc) bgstr = argv[i]; }

    else if (!strncmp(argv[i],"-bl",3))	/* black color */
      { if (++i<argc) blackstr = argv[i]; }
    
    else if (!strncmp(argv[i],"-bw",3)) /* border width */
      { if (++i<argc) bwidth=atoi(argv[i]); }

    else if (!strncmp(argv[i],"-ce",3))	/* centerpic */
      centerpic++;
    
    else if (!strncmp(argv[i],"-cg",3))	/* ctrlgeom */
      { if (++i<argc) ctrlgeom = argv[i]; }
    
    else if (!strncmp(argv[i],"-cm",3))	/* ctrlmap */
      ctrlmap++;
    
    else if (!strncmp(argv[i],"-cl",3))	/* clear */
      clrroot++;
    
    else if (!strncmp(argv[i],"-d",2))  /* display */
      { if (++i<argc) display = argv[i]; }

    else if (!strncmp(argv[i],"-D",2)) 	/* debug */
      { if (++i<argc) DEBUG = atoi(argv[i]); }

    else if (!strncmp(argv[i],"-e",2)) 	/* expand factor */
      { if (++i<argc) expand=atoi(argv[i]); }

    else if (!strncmp(argv[i],"-fis",4)) /* nofish */
      fish++;

    else if (!strncmp(argv[i],"-fix",4)) /* fixed aspect ratio */
      fixedaspect++;
    
    else if (!strncmp(argv[i],"-fg",3)) /* foreground color */
      { if (++i<argc) fgstr = argv[i]; }
    
    else if (!strncmp(argv[i],"-ge",3))	/* geometry */
      { if (++i<argc) maingeom = argv[i]; }
    
    else if (!strncmp(argv[i],"-gg",3))	/* gammageom */
      { if (++i<argc) gamgeom = argv[i]; }
    
    else if (!strncmp(argv[i],"-gm",3))	/* gmap */
      gmap++;
    
    else if (!strncmp(argv[i],"-G",2))	/* Gamma */
      { if (++i<argc) ghand[0].y=atoi(argv[i]);
	if (++i<argc) ghand[1].x=atoi(argv[i]);
	if (++i<argc) ghand[1].y=atoi(argv[i]);
        if (++i<argc) ghand[2].x=atoi(argv[i]);
	if (++i<argc) ghand[2].y=atoi(argv[i]);
        if (++i<argc) ghand[3].y=atoi(argv[i]); }
    
    else if (!strncmp(argv[i],"-ig",3))	/* infogeom */
      { if (++i<argc) infogeom = argv[i]; }
    
    else if (!strncmp(argv[i],"-im",3))	/* imap */
      imap++;
    
    else if (!strncmp(argv[i],"-ma",3))	/* auto maximize */
      automax++;
    
    else if (!strncmp(argv[i],"-mo",3))	/* mono */
      mono++;
    
    else if (!strncmp(argv[i],"-nc",3)) /* ncols */
      { if (++i<argc) { ncols=abs(atoi(argv[i])); noglob++; } }
    
    else if (!strncmp(argv[i],"-ng",3)) /* no global colors */
      noglob++;
    
    else if (!strncmp(argv[i],"-ni",3))	/* don't install colormaps by hand */
      ninstall=1;

    else if (!strncmp(argv[i],"-noq",4)) /* noqcheck */
      noqcheck++;

    else if (!strncmp(argv[i],"-p",2))  /* perfect colors */
      perfect++;  
    
    else if (!strncmp(argv[i],"-q",2))  /* auto-quit when using root */
      autoquit++;
    
    else if (!strncmp(argv[i],"-rb",3)) /* root background color */
      { if (++i<argc) rootbgstr = argv[i]; }
    
    else if (!strncmp(argv[i],"-rf",3)) /* root foreground color */
      { if (++i<argc) rootfgstr = argv[i]; }
    
    else if (!strncmp(argv[i],"-ro",3)) /* use root window */
      useroot++;
    
    else if (!strncmp(argv[i],"-rp",3))	/* root pattern */
      { if (++i<argc) rootPattern = abs(atoi(argv[i])); }
    
    else if (!strncmp(argv[i],"-rw",3)) /* use r/w color */
      rwcolor++;
    
    else if (!strcmp(argv[i],"-rv"))    /* reverse video */
      revvideo++;
    
    else if (!strncmp(argv[i],"-s",2))  /* slow 24-to-8 conversion */
      slow24++;
    
    else if (!strncmp(argv[i],"-t",2))  /* root window tiling */
      roottile++;
    
    else if (!strncmp(argv[i],"-wa",3))	/* secs to wait between pics */
      { if (++i<argc) waitsec = abs(atoi(argv[i])); }
    
    else if (!strncmp(argv[i],"-wh",3))	/* white color */
      { if (++i<argc) whitestr = argv[i]; }
    
    else Syntax();
  }
  
  if (expand==0) Syntax();

  if (DEBUG) XSynchronize(theDisp, True);

  /* if using root, generally gotta map ctrl window, 'cause there won't be
     any way to ask for it.  (no kbd or mouse events from rootW) */
  if (useroot && !autoquit) 
    ctrlmap = 1;    

  /* must not install colormaps on rootW */
  if (useroot) { perfect=0;  noglob = 1; } 



  /*****************************************************/
  /*** X Setup                                       ***/
  /*****************************************************/
  
  theScreen = DefaultScreen(theDisp);
  theCmap   = DefaultColormap(theDisp, theScreen);
  rootW     = RootWindow(theDisp,theScreen);
  theGC     = DefaultGC(theDisp,theScreen);
  theVisual = DefaultVisual(theDisp,theScreen);
  ncells    = DisplayCells(theDisp, theScreen);
  dispWIDE  = DisplayWidth(theDisp,theScreen);
  dispHIGH  = DisplayHeight(theDisp,theScreen);
  dispDEEP  = DisplayPlanes(theDisp,theScreen);


  /* go look for a virtual root */
  __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False);
  XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children,
	     &numChildren);
  for (i = 0; i < numChildren; i++) {
    Atom actual_type;
    int actual_format;
    unsigned long nitems, bytesafter;
    Window *newRoot = NULL;
    XWindowAttributes xwa;
    if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0, 1,
          False, XA_WINDOW, &actual_type, &actual_format, &nitems,
	  &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) {
      rootW = *newRoot;
      XGetWindowAttributes(theDisp, rootW, &xwa);
      dispWIDE = xwa.width;  dispHIGH = xwa.height;
      dispDEEP = xwa.depth;
      break;
    }
  }

  /* have enough info to do a '-clear' now */
  if (clrroot || useroot) {
    KillOldRootInfo();
    XSetWindowBackgroundPixmap(theDisp, rootW, None);
    XClearWindow(theDisp, rootW);
    XFlush(theDisp);
    if (clrroot) Quit(0);
  }


  arrow     = XCreateFontCursor(theDisp,XC_top_left_arrow);
/*  cross     = XCreateFontCursor(theDisp,XC_plus); */
  cross     = XCreateFontCursor(theDisp,XC_crosshair);

  /* set up white,black colors */
  white = WhitePixel(theDisp,theScreen);
  black = BlackPixel(theDisp,theScreen);
  if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  white = ecdef.pixel;
  if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  black = ecdef.pixel;

  /* set up fg,bg colors */
  fg = black;   bg = white;
  if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  fg = ecdef.pixel;
  if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  bg = ecdef.pixel;

  /* set up root fg,bg colors */
  rootfg = white;   rootbg = black;
  if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  rootfg = ecdef.pixel;
  if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
      XAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;

  XSetForeground(theDisp,theGC,fg);
  XSetBackground(theDisp,theGC,bg);

  /* set up infofg,infobg colors */
  infofg = fg;   infobg = bg;


  /* if '-mono' not forced, determine if we're on a b/w or color monitor */
  if (!mono) {
    if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
    if (theVisual->class == StaticGray || theVisual->class == GrayScale)
      mono = 1;
  }
  
  iconPix = XCreatePixmapFromBitmapData(theDisp, rootW, icon_bits,
	     icon_width, icon_height, 1, 0, 1);

  /* try to load fonts */
  if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL && 
       (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL && 
       (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL) {
    sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s",
	    FONT1, FONT2, FONT3);
    FatalError(str);
  }
  mfont=mfinfo->fid;
  XSetFont(theDisp,theGC,mfont);
  
  if ( (monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL && 
       (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL && 
       (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL) {
    sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s",
	    MFONT1, MFONT2, MFONT3);
    FatalError(str);
  }
  monofont=monofinfo->fid;
  

  /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
     case ncols = 0;  (ncols = max number of colors allocated.  on 1-bit
     displays, no colors are allocated */

  if (ncols == -1) {
    if (dispDEEP>1) ncols = 1<<dispDEEP;
    else ncols = 0;
  }
  else if (ncols>256) ncols = 256;       /* so program doesn't blow up */

  if (numnames==0) {       /* no filenames.  build one-name (stdio) list */
    namelist[0] = STDINSTR;
    numnames = 1;
    }

  MakeDispNames();

  /* create the info box window */
  CreateInfo(infogeom);
  XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask );
  InfoBox(imap);     /* map it (or not) */
  if (imap) {
    RedrawInfo(0,0,INFOWIDE,INFOHIGH);  /* explicit draw if mapped */
    XFlush(theDisp);
  }


  /* create the control box window */
  CreateCtrl(ctrlgeom);
  XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask);
  CtrlBox(ctrlmap);     /* map it (or not) */
  if (ctrlmap) {
    RedrawCtrl(0,0,CTRLWIDE,CTRLHIGH);   /* explicit draw if mapped */
    XFlush(theDisp);
  }


  /* create the directory window */
  CreateDirW(DEFDIRGEOM);
  XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask);
  DirBox(0);     /* map it (or not) */


  /* create the gamma window */
  CreateGam(gamgeom);
  XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask);
  GamBox(gmap);     /* map it (or not) */

  GenerateGamma();
  GenerateFSGamma();

  LoadFishCursors();
  SetCursors(-1);

  /* if we're not on a colormapped display, turn off rwcolor */
  if (!(theVisual->class & 1) && rwcolor) {
    fprintf(stderr,"xv: not a colormapped display.  'rwcolor' turned off.\n");
    rwcolor = 0;
  }

  /* Do The Thing... */
  MainLoop();
  Quit(0);
  return(0);
}




/***********************************/
static int cpos = 0;
printoption(st)
char *st;
{
  if (strlen(st) + cpos > 78) {
    fprintf(stderr,"\n   ");
    cpos = 3;
  }

  fprintf(stderr,"%s ",st);
  cpos = cpos + strlen(st) + 1;
}

static void Syntax()
{
  fprintf(stderr, "Usage:\n");
  printoption(cmd);
  printoption("[-aspect w:h]");
  printoption("[-autogamma]");
  printoption("[-bfc]");
  printoption("[-bg background]");
  printoption("[-black color]");
  printoption("[-bw width]");
  printoption("[-center]");
  printoption("[-cgeom geom]");
  printoption("[-clear]");
  printoption("[-cmap]");
  printoption("[-DEBUG level]");
  printoption("[-display disp]");
  printoption("[-expand exp]");
  printoption("[-fg foreground]");
  printoption("[-fish]");
  printoption("[-fixed]");
  printoption("[-GAMMA y0 x1 y1 x2 y2 y3]");
  printoption("[-geometry geom]");
  printoption("[-ggeometry geom]");
  printoption("[-gmap]");
  printoption("[-help]");
  printoption("[-igeom geom]");
  printoption("[-imap]");
  printoption("[-max]");
  printoption("[-mono]");
  printoption("[-ncols #]");
  printoption("[-nglobal]");
  printoption("[-ninst]");
  printoption("[-noqcheck]");
  printoption("[-perfect]");
  printoption("[-quit]");
  printoption("[-root]");
  printoption("[-rw]");
  printoption("[-rv]");
  printoption("[-rbg color]");
  printoption("[-rfg color]");
  printoption("[-rpat #]");
  printoption("[-slow24]");
  printoption("[-tile]");
  printoption("[-wait seconds]");
  printoption("[-white color]");
  printoption("[filename ...]");
  fprintf(stderr,"\n\n");
  Quit(1);
}


/***********************************/
static int openPic(filenum)
int filenum;
{
  /* tries to load file #filenum (from 'namelist' list)
   * returns 0 on failure (cleans up after itself)
   * if successful, returns 1, creates mainW
   */

  int   i,filetype,okay,freename, nw, nh;
  char *tmp;
  FILE *fp;
  char *fullname,      /* full name of the original file */
        filename[256], /* full name of the file to be loaded (could be /tmp) */
        basename[128], /* just the name of the original file. No path */
        magicno[8];    /* first 8 bytes of file */

  
  normaspect = defaspect;

  StartFish();
  WaitCursor();

  curname = filenum;
  ScrollToCurrent();  /* have scrl/list show current */
  XFlush(theDisp);    /* update NOW */

  /* clear any old error messages */

  SetISTR(ISTR_INFO,"");
  SetISTR(ISTR_WARNING,"");
  infoMode = INF_STR;
  okay = 0;

  /* set up fullname and basename */

  fullname = namelist[filenum];
  tmp = rindex(fullname,'/');
  if (!tmp) tmp = fullname; else tmp++;
  strcpy(basename,tmp);
  if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0) 
    basename[strlen(basename)-2]='\0';     /* chop off .Z, if any */

  /* if fullname doesn't start with a '/' (ie, it's a relative path), 
     (and it's not the special case '<stdin>') prepend 'initpath' to it */
  freename = 0;
  if (fullname[0] != '/' && strcmp(fullname,STDINSTR)!=0) {
    char *tmp;
    tmp = (char *) malloc(strlen(fullname) + strlen(initpath) + 2);
    if (!tmp) FatalError("malloc 'filename' failed");
    sprintf(tmp,"%s/%s", initpath, fullname);
    fullname = tmp;
    freename = 1;
  }
    

  /* uncompress if it's a .Z file */

  i = strlen(fullname);
  if (i>2 && strcmp(fullname+i-2,".Z")==0) {
    strcpy(filename,"/tmp/xvXXXXXX");
    mktemp(filename);
    sprintf(str,"%s -c %s >%s",UNCOMPRESS,fullname,filename);
    SetISTR(ISTR_INFO,"Uncompressing '%s'...",basename);
    if (system(str)) {
      SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basename);
      Warning();
      goto FAILED;
    }
  WaitCursor();
  }
  else strcpy(filename,fullname);
    

  /* if the file is stdio, write it out to a temp file */
  if (strcmp(filename,STDINSTR)==0) {
    FILE *fp;

    strcpy(filename,"/tmp/xvXXXXXX");
    mktemp(filename);

    fp = fopen(filename,"w");
    if (!fp) FatalError("can't write /tmp/xv****** file");
    
    while ( (i=getchar()) != EOF) putc(i,fp);
    fclose(fp);
  }


  /* now, try to determine what type of file we've got by reading the
     first couple bytes and looking for a Magic Number */

  fp=fopen(filename,"r");
  if (!fp) {
    SetISTR(ISTR_INFO,"Can't open '%s' -  %s",filename,sys_errlist[errno]);
    Warning();
    goto FAILED;
  }

  fread(magicno,8,1,fp);  
  fclose(fp);

  filetype = UNKNOWN;
  if (strncmp(magicno,"GIF87",5)==0) filetype = GIF;

  else if (strncmp(magicno,"VIEW",4)==0 ||
	   strncmp(magicno,"WEIV",4)==0) filetype = PM;

  else if (magicno[0] == 'P' && magicno[1]>='1' && 
	   magicno[1]<='6') filetype = PBM;

  else if (strncmp(magicno,"#define",7)==0) filetype = XBM;

  if (filetype == UNKNOWN) {
    SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basename);
    Warning();
    goto FAILED;
  }

  SetISTR(ISTR_INFO,"Loading '%s'...",basename);

  switch (filetype) {
  case GIF: i = LoadGIF(filename,ncols); break;
  case PM:  i = LoadPM (filename,ncols); break;
  case PBM: i = LoadPBM(filename,ncols); break;
  case XBM: i = LoadXBM(filename,ncols); break;
  }
  WaitCursor();

  if (i) {
    SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename);
    Warning();
    goto FAILED;
  }

  /* successfully read this picture */

  /* if we read a /tmp file, delete it.  won't be needing it any more */
  if (strcmp(fullname,filename)!=0) unlink(filename);

  SetInfoMode(INF_PART);
  SetISTR(ISTR_INFO,"Loading '%s'...  done.",basename);
  SetISTR(ISTR_FILENAME,basename);
  SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
  SetISTR(ISTR_COLOR,"");

  /* adjust button in/activity */
  BTSetActive(&but[BCROP],0);  /* new picture, draw no cropping rectangle */
  BTSetActive(&but[BUNCROP], 0);
  BTSetActive(&but[BNEXT], (curname<numnames-1));
  BTSetActive(&but[BPREV], (curname>0));

  normFact = 1;  nw = pWIDE;  nh = pHIGH;
  /* if pic is larger than screen, half picture until it fits on screen */
  while (nw > dispWIDE || nh > dispHIGH) {
    nw = nw / 2;  
    nh = nh / 2;
    normFact = normFact * 2;
  }

  /* expand:  if expansion is negative, treat it as a reciprocal */
  if (expand<0) { eWIDE = pWIDE/abs(expand);  eHIGH = pHIGH/abs(expand); }
           else { eWIDE = pWIDE * expand;     eHIGH = pHIGH * expand; }

  if (useroot) {
    int i,x,y;  unsigned int w,h;
    i = XParseGeometry(maingeom,&x,&y,&w,&h);
    if (i&WidthValue)  eWIDE = w;
    if (i&HeightValue) eHIGH = h;
    RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH);

    if (roottile) {
      /* make picture size a divisor of the rootW size.  round down */
      i = (dispWIDE + eWIDE-1) / eWIDE;   eWIDE = (dispWIDE + i-1) / i;
      i = (dispHIGH + eHIGH-1) / eHIGH;   eHIGH = (dispHIGH + i-1) / i;
    }
  }

  cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;  cXOFF = cYOFF = 0;
  SetCropString();

  if (automax) { 
    eWIDE = dispWIDE;  eHIGH = dispHIGH;
    if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  }

  if (useroot) {
    mainW = rootW;

    if (theVisual->class & 1) {
      /* clear old root pixmap before doing the 'alloc colors scene' 
	 to avoid annoying 'rainbow' effect as colors are realloced */
      XSetWindowBackgroundPixmap(theDisp, rootW, None);
      XClearWindow(theDisp, rootW);
      XFlush(theDisp);
    }
  }
  else {
    CreateMainWindow(maingeom, basename);
    XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
		 | StructureNotifyMask | ButtonPressMask
		 | EnterWindowMask | LeaveWindowMask);
    XMapWindow(theDisp,mainW);
  }

  SortColormap();

  /* save the desired RGB colormap (before gamma-correcting it) */
  for (i=0; i<numcols; i++)
    { rorg[i] = r[i];  gorg[i] = g[i];  borg[i] = b[i]; }

  WaitCursor();
  DoMonoAndRV();
  if (autogamma) GammifyColors();

  if (rwcolor) AllocRWColors();
          else AllocColors();

  WaitCursor();
  Resize(eWIDE,eHIGH);

  WaitCursor();
  if (useroot) MakeRootPic();
    
  if (LocalCmap) {
    XSetWindowAttributes xswa;
    if (!ninstall) XInstallColormap(theDisp,LocalCmap);
    xswa.colormap = LocalCmap;
    XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
  }
	
  SetInfoMode(INF_FULL);
  if (freename) free(fullname);

  StopFish();
  SetCursors(-1);

  /* put current filename into the 'save-as' filename */
  if (strcmp(filename,STDINSTR)==0) SetDirFName("stdin");
  else SetDirFName(basename);
    
  return 1;

  
 FAILED:
  StopFish();
  SetCursors(-1);
  SetInfoMode(INF_STR);
  if (strcmp(fullname,filename)!=0) unlink(filename);   /* kill /tmp file */
  if (freename) free(fullname);
  return 0;
}




/***********************************/
static void closePic()
{
  /* kill all resources used for this picture.
     this would include the window, any allocated colors, pic, epic, 
     theImage, etc. */

  int i;
  static char *st = "Loading...";

  if (!useroot) {
    /* turn off configure events */
    XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
		 | ButtonPressMask
		 | EnterWindowMask | LeaveWindowMask);
    XClearArea(theDisp, mainW, 0,0, eWIDE, eHIGH, True);

    /* 
      XSetForeground(theDisp, theGC, infofg);
      XFillRectangle(theDisp,mainW,theGC, 0, 0, StringWidth(st) + 8, CHIGH+4);
      XSetForeground(theDisp, theGC, infobg);
      XDrawString(theDisp, mainW, theGC, 4, 2 + ASCENT, st, strlen(st));
      XFlush(theDisp);  
    */
  }
  
  if (LocalCmap) {
    XFreeColormap(theDisp,LocalCmap);
    LocalCmap = 0;
  }
  else if (!brokeFreeCols) {
    for (i=0; i<nfcols; i++) 
      XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
  }
  else {
    for (i=0; i<nfcols; i++) {
      int j;
      for (j=0; j<i; j++) {
        if (freecols[i] == freecols[j])   /* already been freed once */
	  break;
      }
      if (j==i)      /* wasn't found in already-freed list */
        XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
    }
  }

  if (epic != cpic && epic != NULL) free(epic);
  if (cpic !=  pic && cpic != NULL) free(cpic);
  if (pic != NULL) free(pic);
  if (theImage != NULL) XDestroyImage(theImage);
  theImage = NULL;
  pic = epic = cpic = NULL;

  SetInfoMode(INF_STR);
}







/****************/
static void OpenFirstPic()
/****************/
{
  int i;

  for (i=0; i<numnames; i++) {
    if (openPic(i)) return;    /* success */
  }

  if (numnames>1) FatalError("couldn't open any pictures");
  else Quit(-1);
}


/****************/
static void OpenNextPic()
/****************/
{
  int i,orig;

  orig = curname;
  for (i=curname+1; i<numnames; i++) {
    if (openPic(i)) return;    /* success */
  }

  /* couldn't go to next, reopen original */
  if (!openPic(orig)) FatalError("couldn't reopen original picture");
}


/****************/
static void OpenNextQuit()
/****************/
{
  int i;

  for (i=curname+1; i<numnames; i++) {
    if (openPic(i)) return;    /* success */
  }

  Quit(0);
}


/****************/
static void OpenPrevPic()
/****************/
{
  int i,orig;

  orig = curname;
  for (i=curname-1; i>=0; i--) {
    if (openPic(i)) return;    /* success */
  }

  /* couldn't go to next, reopen original */
  if (!openPic(orig)) FatalError("couldn't reopen original picture");
}


/****************/
static void MainLoop()
/****************/
{
  /* search forward until we manage to display a picture, 
     then call EventLoop.  EventLoop will eventually return 
     NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */

  int i;

  OpenFirstPic();   /* find first displayable picture, exit if none */

  if (useroot && autoquit) Quit(0);

  while ((i=EventLoop()) != QUIT) {
    if      (i==NEXTPIC && curname<numnames-1)  { closePic(); OpenNextPic(); }
    else if (i==PREVPIC && curname>0)  { closePic(); OpenPrevPic(); }
    else if (i==NEXTQUIT) { closePic(); OpenNextQuit(); }
    else if (i>=0) {
      int orig = curname;
      if (curname != i) {
	closePic();
	if (!openPic(i)) {  /* couldn't goto */
	  if (!openPic(orig)) FatalError("couldn't reopen original picture");
	}
      }
    }
  }
}



/****************/
static int EventLoop()
/****************/
{
  XEvent event;
  int    retval,done;
  time_t orgtime, curtime;


  /* note: there's no special event handling if we're using the root window.
     if we're using the root window, we will recieve NO events for mainW */

  time(&orgtime);

  done = retval = 0;
  while (!done) {

    if (waitsec == -1 || XPending(theDisp)>0) {
      XNextEvent(theDisp, &event);
      
      switch (event.type) {
      case Expose: {
        XExposeEvent *exp_event = (XExposeEvent *) &event;

	/* if the window doesn't do intelligent redraw, drop all-1 exposes */
	if (exp_event->count>0 && exp_event->window != mainW 
	                       && exp_event->window != ctrlW
	                       && exp_event->window != dirW
                               && exp_event->window != gamW
                               && exp_event->window != graphW) break;

        if (exp_event->window==mainW) {
	  if (DEBUG) fprintf(stderr,"EXPOSE:  ");
	  if (!CheckForConfig()) {
	    if (DEBUG)
	      fprintf(stderr,"No configs pending.   Do Expose %d,%d %dx%d\n",
		      exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);

	    if (DEBUG) 
	      XClearArea(theDisp, mainW, exp_event->x, exp_event->y,
			 exp_event->width, exp_event->height, False);

	    DrawWindow(exp_event->x,exp_event->y,
		       exp_event->width, exp_event->height);
	    
	    if (but[BCROP].active) {
	      XRectangle xr;
	      xr.x = exp_event->x;  xr.y = exp_event->y;
	      xr.width = exp_event->width;  xr.height = exp_event->height;
	  
	      XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted);
	      InvCropRect();
	      XSetClipMask(theDisp,theGC,None);
	    }
	  }
	  else
	    if (DEBUG) 
	      fprintf(stderr,"Ignoring expose event.  Config pending\n");
	}

	else if (exp_event->window==infoW) 
	  RedrawInfo(exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);


	else if (exp_event->window==ctrlW) 
	  RedrawCtrl(exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);

	else if (exp_event->window == nList.win)
	  LSRedraw(&nList);

	else if (exp_event->window == nList.scrl.win)
	  SCRedraw(&nList.scrl);



	else if (exp_event->window == dirW) 
	  RedrawDirW(exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);


	else if (exp_event->window == dList.win)
	  LSRedraw(&dList);

	else if (exp_event->window == dList.scrl.win)
	  SCRedraw(&dList.scrl);

	else if (exp_event->window == ddirW) 
	  RedrawDDirW();

	else if (exp_event->window == dnamW) 
	  RedrawDNamW();


	else if (exp_event->window == gamW) 
	  RedrawGam(exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);

	else if (exp_event->window == graphW) 
	  RedrawGraph(exp_event->x, exp_event->y, 
		      exp_event->width, exp_event->height);

      }      
      break;
	
      case ButtonPress: {
	XButtonEvent *but_event = (XButtonEvent *) &event;
	int i;

	switch (but_event->button) {
	case Button1:  
	  if (but_event->window == mainW)
	    TrackPicValues(but_event->x, but_event->y);

	  else if (but_event->window == ctrlW) {
	    int   w,h;

	    i=ClickCtrl(but_event->x, but_event->y);
	    if (i>=0) {
	      switch (i) {
	      case BNEXT:   retval= NEXTPIC;  done=1;  break;
	      case BPREV:   retval= PREVPIC;  done=1;  break;
	      case BSAVE:   DirBox(1); break;
	      case BQUIT:   retval= QUIT;     done=1;  break;

	      case BCROP:   DoCrop();  break;
	      case BUNCROP: UnCrop();  break;
	      case BNORM:   WResize(cWIDE/normFact, cHIGH/normFact);  break;
	      case BMAX:    WResize(dispWIDE, dispHIGH);  break;
	      case BUP10:   w = (eWIDE*11)/10;  h = (eHIGH*11)/10;
                            if (w==eWIDE) w++;
                            if (h==eHIGH) h++;
                            WResize(w,h);
                            break;
              case BDN10:   WResize((eWIDE*9)/10, (eHIGH*9)/10);  break;
	      case BUP2:    WResize(eWIDE*2, eHIGH*2);  break;
	      case BDN2:    WResize(eWIDE/2, eHIGH/2);  break;
              case B4BY3:   w = eWIDE;  h = (w * 3) / 4;
                            if (h>dispHIGH) { h = eHIGH;  w = (h*4)/3; }
                            WResize(w,h);
                            break;

	      case BASPECT: FixAspect(1,&w,&h);  WResize(w,h);  break;
	      case BMAXPECT: { int w1,h1;
                             w1 = eWIDE;  h1 = eHIGH;
		             eWIDE = dispWIDE;  eHIGH = dispHIGH;
		             FixAspect(0,&w,&h);
			     eWIDE = w1;  eHIGH = h1;  /* play it safe */
                             WResize(w,h);
                             }   break;

	      case BROTL:   Rotate(1);  break;
	      case BROTR:   Rotate(0);  break;
	      case BACROP:  AutoCrop();  break;

	      case BINFO:   InfoBox(!infoUp); break;
	      case BGAMMA:  GamBox(!gamUp);   break;
	      }
	    }
	  }

	  else if (but_event->window == nList.win) {
	    i=LSClick(&nList,but_event);
	    if (i>=0) return(i);
	  }

	  else if (but_event->window == nList.scrl.win) 
	    SCTrack(&nList.scrl, but_event->x, but_event->y);


	  else if (but_event->window == dirW) {
	    i=ClickDirW(but_event->x, but_event->y);
	    
	    if      (i==S_BOPEN) SelectDir(dList.selected);
	    else if (i==S_BCANC) DirBox(0);
	    else if (i==S_BSAVE) DoSave();
	    else if (i==S_BQUIT) { retval = QUIT;  done=1; }
	  }

	  else if (but_event->window == dList.win) {
	    i=LSClick(&dList,but_event);
	    DirOpenActive();
	    if (i>=0) SelectDir(i);
	  }

	  else if (but_event->window == dList.scrl.win) 
	    SCTrack(&dList.scrl, but_event->x, but_event->y);

	  else if (but_event->window == ddirW) 
	    TrackDDirW(but_event->x, but_event->y);


	  else if (but_event->window == gamW)
	    ClickGam(but_event->x, but_event->y);

	  else if (but_event->window == graphW)
	    TrackGraph(but_event->x, but_event->y);

	  break;

	case Button2:  if (but_event->window == mainW)
	                 TrackCrop(but_event->x, but_event->y);
                       break;

	case Button3:  if (!useroot)   /* if using root, MUST NOT get rid of */
	                 CtrlBox(!ctrlUp);   /* ctrlbox.  can't get it back */
                       break;
	default:       break;
	}
      }
      break;
	
      case KeyPress: {
	XKeyEvent *key_event = (XKeyEvent *) &event;
	char buf[128]; 	KeySym ks;  XComposeStatus status;  int stlen;
	
	stlen = XLookupString(key_event,buf,128,&ks,&status);

	/* do non-character processing (arrow-keys, that is) */
	if      (ks==XK_Left)  CropKey(-1, 0, key_event->state & ShiftMask);
	else if (ks==XK_Right) CropKey( 1, 0, key_event->state & ShiftMask);
	else if (ks==XK_Up)    CropKey( 0,-1, key_event->state & ShiftMask);
	else if (ks==XK_Down)  CropKey( 0, 1, key_event->state & ShiftMask);

	if (!stlen) break;

	if (key_event->window == dirW) {
	  if (DirKey(buf[0])) XBell(theDisp,0);
	}

	else {
	  /* if (isupper(buf[0])) buf[0] = tolower(buf[0]); */

	  /* commands valid in any window */
	  
	  switch (buf[0]) {
	  case ' ':
	  case '\r':
	  case '\n':   FakeButtonPress(&but[BNEXT]);    break;

	  case '\010':
	  case '\177': FakeButtonPress(&but[BPREV]);    break;

	  case 's':    FakeButtonPress(&but[BSAVE]);    break;
	  case 'q':    FakeButtonPress(&but[BQUIT]);    break;

	  case 'h':
	  case '?':    if (!useroot) CtrlBox(!ctrlUp);  break;

	  case 'a':    FakeButtonPress(&but[BASPECT]);  break;
	  case 'A':    FakeButtonPress(&but[BACROP]);   break;

	  case 'T':    FakeButtonPress(&but[BROTL]);    break;
	  case 't':    FakeButtonPress(&but[BROTR]);    break;
	  case '4':    FakeButtonPress(&but[B4BY3]);    break;
	  case 'c':    FakeButtonPress(&but[BCROP]);    break;
	  case 'u':    FakeButtonPress(&but[BUNCROP]);  break;
	  case 'n':    FakeButtonPress(&but[BNORM]);    break;
	  case 'm':    FakeButtonPress(&but[BMAX]);     break;
	  case 'M':    FakeButtonPress(&but[BMAXPECT]); break;
	  case ',':    FakeButtonPress(&but[BDN10]);    break;
	  case '.':    FakeButtonPress(&but[BUP10]);    break;
	  case '<':    FakeButtonPress(&but[BDN2]);     break;
	  case '>':    FakeButtonPress(&but[BUP2]);     break;

	  case 'i':    FakeButtonPress(&but[BINFO]);    break;
	  case 'g':    FakeButtonPress(&but[BGAMMA]);   break;

	  case 'p':    FakeButtonPress(&gbut[G_BAPPLY]);    break;

	  default:     break;
	  }
	}
      }
      break;
	
      case ConfigureNotify: {
	XConfigureEvent *conf_event = (XConfigureEvent *) &event;

	if (conf_event->window == mainW && !rotatesLeft) {
	  if (DEBUG) fprintf(stderr,"CONFIG: (%s) ", 
			     conf_event->send_event ? "program" : "user");
	  if (!CheckForConfig()) {
	    XEvent xev;
	    if (DEBUG) fprintf(stderr,"No configs pend.  Do full redraw\n");
	    Resize(conf_event->width, conf_event->height);

	    /* eat pending expose events, as the complete redraw will 
	       cover all of them */
	    while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
	      XExposeEvent *exp = (XExposeEvent *) &xev;
	      if (DEBUG) 
		fprintf(stderr, "  ate expose (%s) (count=%d) %d,%d  %dx%d\n",
			exp->send_event ? "program" : "user", exp->count,
			exp->x, exp->y, exp->width, exp->height);
	    }

	    DrawWindow(0,0,conf_event->width, conf_event->height);
	    SetCursors(-1);

	  }
	  else 
	    if (DEBUG) fprintf(stderr,"config pending.  ignored\n");
	}
	if (rotatesLeft>0) rotatesLeft--;
	if (!rotatesLeft) SetCursors(-1);
      }
      break;
	
	
      case CirculateNotify:
      case MapNotify:
      case DestroyNotify:
      case GravityNotify:
      case ReparentNotify:
      case UnmapNotify:         break;

      case EnterNotify:
      case LeaveNotify: {
	XCrossingEvent *cross_event = (XCrossingEvent *) &event;

 	if (cross_event->window != mainW) break;

	if (cross_event->type == EnterNotify && LocalCmap && !ninstall) 
	  XInstallColormap(theDisp,LocalCmap);

	if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) 
	  XUninstallColormap(theDisp,LocalCmap);
      }
      break;
	
	
      default: break;		/* ignore unexpected events */
      }  /* switch */
    }  /* if XPending */
    

    else {                      /* no events.  check wait status */
      if (waitsec>-1) {
	time(&curtime);
	if (curtime - orgtime >= waitsec) return NEXTQUIT;
	sleep(1);   /* so program doesn't loop continuously while 'waiting' */
      }
    }

  }  /* while */
  return(retval);
}



/***********************************/
void DrawWindow(x,y,w,h)
int x,y,w,h;
{
  if (theImage)
    XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h);
  else 
    if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n");
}


/***********************************/
static void CreateMainWindow(geom,name)
     char *geom, *name;
{
  XSetWindowAttributes xswa;
  unsigned int         xswamask;
  XWindowAttributes    xwa;
  XWMHints             xwmh;
  XSizeHints           hints;
  int                  i,x,y;
  unsigned int         w,h;
  char                 winname[128], iconname[128];

  /*
   * this function mainly deals with parsing the geometry spec correctly.
   * More trouble than it should be, and probably more trouble than
   * it has to be, but who can tell these days, what with all those
   * Widget-usin' Weenies out there...
   */

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

  if (eWIDE > dispWIDE || eHIGH > dispHIGH) {
    eWIDE = eWIDE / normFact;
    eHIGH = eHIGH / normFact;
  }
  if (eWIDE < 1) eWIDE = 1;
  if (eHIGH < 1) eHIGH = 1;

  if (fixedaspect && i&WidthValue && i&HeightValue) FixAspect(0,&eWIDE,&eHIGH);
  else if (i&WidthValue && i&HeightValue) 
    { RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH); }
  else FixAspect(1,&eWIDE,&eHIGH);

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

  hints.flags |= USSize;

  if (i&XValue && i&XNegative) x = dispWIDE - eWIDE - abs(x);
  if (i&YValue && i&YNegative) y = dispHIGH - eHIGH - abs(y);

  if (x+eWIDE > dispWIDE) x = dispWIDE - eWIDE;   /* keep on screen */
  if (y+eHIGH > dispHIGH) y = dispHIGH - eHIGH;

  if (eWIDE < 1) eWIDE = 1;
  if (eHIGH < 1) eHIGH = 1;

  hints.x = x;                  hints.y = y;
  hints.width = eWIDE;          hints.height = eHIGH;
  hints.max_width  = dispWIDE;  hints.max_height = dispHIGH;
  hints.flags |= PMaxSize;

  xswa.background_pixel = bg;
  xswa.border_pixel     = fg;
  xswamask = CWBackPixel | CWBorderPixel;

  if (mainW) {
    GetWindowPos(&xwa);
    xwa.width = eWIDE;  xwa.height = eHIGH;
    SetWindowPos(&xwa);
    hints.flags = PSize | PMaxSize;
  }

  if (!mainW)
    mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,bwidth,CopyFromParent,
			  CopyFromParent, CopyFromParent, xswamask, &xswa);

  sprintf(winname,"xv %s",name);
  sprintf(iconname,"xv %s",name);
  XSetStandardProperties(theDisp,mainW,winname,iconname,None,
			 NULL,0,&hints);

  xwmh.input = True;
  xwmh.flags = InputHint;
  if (iconPix) { xwmh.icon_pixmap = iconPix;  xwmh.flags |= IconPixmapHint; }
  XSetWMHints(theDisp, mainW, &xwmh);

  if (!mainW) FatalError("can't create window!");
}


/***********************************/
static void FixAspect(grow,w,h)
int   grow;
int   *w, *h;
{
  /* computes new values of eWIDE and eHIGH which will have aspect ratio
     'normaspect'.  If 'grow' it will preserve aspect by enlarging, 
     otherwise, it will shrink to preserve aspect ratio.  
     Returns these values in 'w' and 'h' */

  float xr,yr,curaspect,a,exp;

  *w = eWIDE;  *h = eHIGH;

  /* xr,yr are expansion factors */
  xr = ((float) eWIDE) / cWIDE;
  yr = ((float) eHIGH) / cHIGH;
  curaspect  = xr / yr;

  /* if too narrow & shrink, shrink height.  too wide and grow, grow height */
  if ((curaspect < normaspect && !grow) || 
      (curaspect > normaspect &&  grow)) {    /* modify height */
    exp = curaspect / normaspect;
    *h = (int) (eHIGH * exp + .5);
  }

  /* if too narrow & grow, grow width.  too wide and shrink, shrink width */
  if ((curaspect < normaspect &&  grow) || 
      (curaspect > normaspect && !grow)) {    /* modify width */
    exp = normaspect / curaspect;
    *w = (int) (eWIDE * exp + .5);
  }


  /* shrink to fit screen without changing aspect ratio */
  if (*w>dispWIDE) {
    int i;
    a = (float) *w / dispWIDE;
    *w = dispWIDE;
    i = (int) (*h / a + .5);        /* avoid freaking some optimizers */
    *h = i;
  }

  if (*h>dispHIGH) {
    a = (float) *h / dispHIGH;
    *h = dispHIGH;
    *w = (int) (*w / a + .5);
  }

  if (*w < 1) *w = 1;
  if (*h < 1) *h = 1;
}


/***********************************/
void WResize(w,h)
int w,h;
{
  XWindowAttributes xwa;

  /* force w,h into valid ranges */
  RANGE(w,1,dispWIDE);  RANGE(h,1,dispHIGH);

  if (useroot) {
    Resize(w,h);
    MakeRootPic();
    SetCursors(-1);
    return;
  }

  /* determine if new size goes off edge of screen.  if so move window so it
     doesn't go off screen */

  GetWindowPos(&xwa);
  if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w;
  if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h;

  if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
		     cmd,w,h,xwa.x,xwa.y);

  /* resize the window */
  xwa.width = w;  xwa.height = h;

  SetWindowPos(&xwa);
}




/***********************************/
void WRotate()
{
  /* rotate the window and redraw the contents  */

  if (but[BCROP].active) BTSetActive(&but[BCROP],0);
  if (useroot) {
    MakeRootPic();
    SetCursors(-1);
    return;
  }

  if (eWIDE == eHIGH) {     /* no configure events will be gen'd */
    Resize(eWIDE, eHIGH);   /* to regen Ximage */
    DrawWindow(0, 0, eWIDE, eHIGH);
    SetCursors(-1);
  }
  else {
    rotatesLeft++;
    WResize(eWIDE, eHIGH);
  }
}




/***********************************/
void WCrop(w,h)
int w,h;
{
  XWindowAttributes xwa;

  /* we want to move window to old x,y + crx1,cry1 */
  GetWindowPos(&xwa);
  xwa.x += crx1;  xwa.y += cry1;
  xwa.width = w;  xwa.height = h;
  SetWindowPos(&xwa);
}


/***********************************/
void WUnCrop()
{
  int w,h;
  XWindowAttributes xwa;

  /* to uncrop, I need to know the old values of cXOFF and cYOFF (cx,cy), and
     the old values of cWIDE,cHIGH, eWIDE, eHIGH.  NOTE that the idea here
     is to, if possible, uncrop by wrapping the rest of the picture around
     the currently visible hunk.  */

  GetWindowPos(&xwa);

  /* calculate w,h:  based on concept of trying to show uncropped picture
     with same expansion ratios.  If this isn't possible (w or h bigger
     than screen), just go to good ol' 1:1 expansion */

  w = (pWIDE * eWIDE) / cWIDE;  h = (pHIGH * eHIGH) / cHIGH;

  if (w>dispWIDE || h>dispHIGH) {
    w=pWIDE / normFact;  h=pHIGH / normFact;
    if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w;
    if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h;
    xwa.width = w;  xwa.height = h;
    SetWindowPos(&xwa);
  }

  else {
    xwa.x = xwa.x - (cXOFF*eWIDE)/cWIDE;   xwa.y = xwa.y - (cYOFF*eHIGH)/cHIGH;
    if (xwa.x<0) xwa.x = 0;
    if (xwa.y<0) xwa.y = 0;
    xwa.width = w;  xwa.height = h;
    SetWindowPos(&xwa);
  }
}



/***********************************/
static void GetWindowPos(xwa)
XWindowAttributes *xwa;
{
  Window            root,parent,*children,child;
  unsigned int      nchildren;
  XWindowAttributes pxwa;
  int ox1,oy1;

  /* returns the x,y,w,h coords of mainW.  x,y are relative to rootW 
     the border is not included (x,y map to top-left pixel in window) */

  XGetWindowAttributes(theDisp,mainW,xwa);

  /* see if mainW has been re-parented by a window manager */
  XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren);
  if (nchildren>0 || children!=NULL) XFree((char *) children);

  if (parent != rootW) {     /* has been reparented */
    XGetWindowAttributes(theDisp,parent,&pxwa);

    XTranslateCoordinates(theDisp,mainW,rootW,0,0,
			  &xwa->x,&xwa->y,&child);

    XTranslateCoordinates(theDisp,parent,rootW,0,0,
			  &ox1,&oy1,&child);
  }

  else {
    xwa->x += xwa->border_width;
    xwa->y += xwa->border_width;
  }
}


/***********************************/
static void SetWindowPos(xwa)
XWindowAttributes *xwa;
{
  /* sets window x,y,w,h values */
  /*  XSizeHints        xsh; */
  Window            root, parent, *children, child;
  unsigned int      nchildren;
  XWindowAttributes pxwa;
  int               xoff, yoff, x1, y1, x2, y2;

  xoff = yoff = 0;
  /* check for reparented window */
  XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren);
  if (nchildren>0 || children!=NULL) XFree((char *) children);
  if (parent != root) {
    XTranslateCoordinates(theDisp,mainW,rootW,0,0,&x1,&y1,&child);
    XTranslateCoordinates(theDisp,mainW,parent,0,0,&xoff,&yoff,&child);
    XTranslateCoordinates(theDisp,parent,rootW,0,0,&x2,&y2,&child);
    XGetWindowAttributes(theDisp,parent,&pxwa);

    if (xoff == 0 && yoff == 0) {
      /* NASTY MOTIF/DXWM KLUDGES */
      xoff = pxwa.x;  yoff = pxwa.y;
      if (xwa->x<xoff && (xwa->width + xoff)<dispWIDE) xwa->x = xoff;
      if (xwa->y<yoff && (xwa->height + yoff)<dispHIGH) xwa->y = yoff;
    }
    else {
      /* NICE, PERFECTLY NORMAL TWM KLUDGES */
      xwa->x = xwa->x - xoff;
      xwa->y = xwa->y - yoff;
      if (xwa->x<0 && (xwa->width + xoff)<dispWIDE) xwa->x = 0;
      if (xwa->y<0 && (xwa->height + yoff)<dispHIGH) xwa->y = 0;
    }
  }
  else {
    xwa->x -= xwa->border_width;
    xwa->y -= xwa->border_width;

    if (xwa->x < -(xwa->border_width)) xwa->x = -(xwa->border_width);
    if (xwa->y < -(xwa->border_width)) xwa->y = -(xwa->border_width);
    xoff = yoff = xwa->border_width;
  }
    
  XMoveResizeWindow(theDisp, mainW, xwa->x, xwa->y, xwa->width, xwa->height);

  /*
   * all this bogus stuff is a work-around for weirdness in
   * twm where resize was giving 23 extra lines...
   * should do no harm if this bug is not present.
   */
  XSync(theDisp,False);
  XGetWindowAttributes(theDisp, mainW, &pxwa);
  if (pxwa.height != xwa->height) {
    XEvent xev;
    /* eat configure event (and any Exposes) if there is one */
    if (XCheckTypedWindowEvent(theDisp, mainW, ConfigureNotify, &xev)) {
      while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev));
    }

    XResizeWindow(theDisp, mainW, xwa->width, 
		  xwa->height - (pxwa.height - xwa->height));
  }

}


/***********************************/
static void TrackCrop(mx,my)
int mx,my;
{
  Window       rW,cW;
  int          rx,ry,ox,oy,x,y,active;
  unsigned int mask;

  XSetFunction(theDisp,theGC,GXinvert);

  if (but[BCROP].active) {             /* turn off old cropping rectangle */
    Rect(crx1,cry1,crx2,cry2);
  }
 active = 0;

  crx1 = ox = mx;  cry1 = oy = my;         /* nail down one corner */

  while (1) {
    if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
      if (!(mask & Button2Mask)) break;    /* button released */

      if (x!=ox || y!=oy) {                /* moved.  erase and redraw */
	crx2 = x;  cry2 = y;
	Rect(crx1,cry1,ox,oy);
	active = Rect(crx1,cry1,crx2,cry2);
	XFlush(theDisp);
	ox=crx2;  oy=cry2;
      }
    }
  }

  XSetFunction(theDisp,theGC,GXcopy);
  RANGE(crx1,0,eWIDE);  RANGE(cry1,0,eHIGH);
  RANGE(crx2,0,eWIDE);  RANGE(cry2,0,eHIGH);
  BTSetActive(&but[BCROP],active);
  SetCropString();
}


/***********************************/
static void CropKey(dx,dy,grow)
int dx,dy,grow;
{
  int x1,x2,y1,y2;

  if (!but[BCROP].active) return;

  /* x1,y1 = top-left,  x2,y2 = bot-right */
  if (crx1<crx2) { x1=crx1;  x2=crx2; }   else { x1=crx2;  x2=crx1; }
  if (cry1<cry2) { y1=cry1;  y2=cry2; }   else { y1=cry2;  y2=cry1; }

  if (!grow) {    /* move the rectangle */
    x1 += dx;  x2 += dx;  y1 += dy;  y2 += dy;
    if (x1<0 || x2>eWIDE) { x1 -= dx;  x2 -= dx; }
    if (y1<0 || y2>eHIGH) { y1 -= dy;  y2 -= dy; }
  }
  else {          /* grow the rectangle, pref. keeping top-left anchored */
    x2 += dx;  y2 += dy;
    if (x2>eWIDE) { 
      x1 -= dx;  x2 -= dx;
      if (x1<0) x1=0;
    }

    if (y2>eHIGH) { 
      y1 -= dy;  y2 -= dy;
      if (y1<0) y1=0;
    }
  }
    
  InvCropRect();
  crx1 = x1;  cry1 = y1;  crx2 = x2;  cry2 = y2;
  InvCropRect();
  SetCropString();
}

  
/***********************************/
static int Rect(x,y,x1,y1)
int x,y,x1,y1;
{
  int w,h;

  /* returns 0 if it didn't draw anything (rect is too small), 1 if it did */
  w = abs(x-x1);  h = abs(y-y1);
  if (x>x1) x = x1;
  if (y>y1) y = y1;

  if (w<4 || h<4) return 0;   /* too small */

  /* keep rectangle inside window */  
  if (x<0) { w+=x; x=0; }
  if (y<0) { h+=y; y=0; }
  if (x+w>eWIDE) w=eWIDE-x;  
  if (y+h>eHIGH) h=eHIGH-y;

  XDrawRectangle(theDisp, mainW, theGC, x, y, w-1, h-1);
  XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-3, h-3);
  return 1;
}


/***********************************/
void InvCropRect()
{
  XSetFunction(theDisp,theGC,GXinvert);
  Rect(crx1,cry1,crx2,cry2);
  XSetFunction(theDisp,theGC,GXcopy);
}


/***********************************/
static void TrackPicValues(mx,my)
int mx,my;
{
  Window       rW,cW;
  int          rx,ry,ox,oy,x,y;
  unsigned int mask;
  int          ty, w;
  char         foo[64];
  unsigned long wh, bl;
  char         *str = "8888,8888 = (123,123,123)  <123,123,123>";

  wh = infobg;  bl = infofg;

  /* do a colormap search for black and white if LocalCmap 
     and use those colors instead of infobg and infofg */
  if (LocalCmap) {
    XColor ctab[256];
    int  i;
    long cval;

    for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
    XQueryColors(theDisp,LocalCmap,ctab,nfcols);
    
    /* find 'blackest' pixel */
    cval = 0x10000 * 3;
    for (i=0; i<nfcols; i++)
      if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) {
	cval = ctab[i].red + ctab[i].green + ctab[i].blue;
	bl = ctab[i].pixel;
      }

    /* find 'whitest' pixel */
    cval = -1;
    for (i=0; i<nfcols; i++)
      if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
	cval = ctab[i].red + ctab[i].green + ctab[i].blue;
	wh = ctab[i].pixel;
      }
  }

  XSetFont(theDisp, theGC, monofont);
  w = XTextWidth(monofinfo,str,strlen(str));

  if (my > eHIGH/2) ty = 0;
               else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;

  ox = oy = -1;  /* kludge to force redraw first time through */

  XSetForeground(theDisp, theGC, bl);
  XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8, 
		 (monofinfo->ascent+monofinfo->descent) + 4);
  XSetForeground(theDisp, theGC, wh);
  XSetBackground(theDisp, theGC, bl);

  while (1) {
    int px, py, pix;

    if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
      if (!(mask & Button1Mask)) break;    /* button released */

      RANGE(x,0,eWIDE-1);  
      RANGE(y,0,eHIGH-1);

      px = cXOFF + (x * cWIDE) / eWIDE;
      py = cYOFF + (y * cHIGH) / eHIGH;

      if (px!=ox || py!=oy) {                /* moved.  erase and redraw */
	pix = pic[py * pWIDE + px];

	sprintf(foo,"%4d,%4d = (%3d,%3d,%3d)  <%3d,%3d,%3d>", 
		px, py, rorg[pix],gorg[pix],borg[pix], r[pix],g[pix],b[pix]);
	XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, 
		    foo, strlen(foo));
	ox = px;  oy = py;
      }
    }
  }

  XSetFont(theDisp, theGC, mfont);
  DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
}


/***********************************/
static void MakeDispNames()
{
  int   prelen, n, i, done;
  char *suffix;

  suffix = namelist[0];
  prelen = 0;   /* length of prefix to be removed */
  n = i = 0;    /* shut up pesky compiler warnings */

  done = 0;
  while (!done) {
    suffix = strchr(suffix,'/');    /* find next '/' in file name */
    if (!suffix) break;

    suffix++;                       /* go past it */
    n = suffix - namelist[0];
    for (i=1; i<numnames; i++) {
      if (strncmp(namelist[0], namelist[i], n)!=0) { done=1; break; }
    }

    if (!done) prelen = n;
  }

  for (i=0; i<numnames; i++)
    dispnames[i] = namelist[i] + prelen;
}


/***********************************/
static int CheckForConfig()
{
  XEvent ev;
  char   foo;

  /* returns true if there's a config event in which mainW changes size
     in the event queue */

  foo = 0;
  XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
  return foo;
}

static Bool IsConfig(dpy, ev, arg)
Display *dpy;
XEvent  *ev;
char    *arg;
{
  XConfigureEvent *cev;

  if (ev->type == ConfigureNotify) {
    cev = (XConfigureEvent *) ev;
    if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
      *arg = 1;
  }
  return False;
}


/***********************************/
void MakeRootPic()
{
  /* called after 'epic' has been generated (if we're using root).  
     creates the XImage and the pixmap, sets the root to the new
     pixmap, and refreshes the display */

  Pixmap tmpPix;
  int    i,j,k,w,h;

  XSetWindowBackgroundPixmap(theDisp, rootW, None);
  XClearWindow(theDisp, rootW);
  XFlush(theDisp);

  if (((fixedaspect && automax) || centerpic)
      && (eWIDE != dispWIDE || eHIGH != dispHIGH)) {

    /* center picture inside a dispWIDE x dispHIGH pixmap */
    w = eWIDE;  if (w>dispWIDE) w = dispWIDE;
    h = eHIGH;  if (h>dispHIGH) h = dispHIGH;
    tmpPix = XCreatePixmap(theDisp, mainW, dispWIDE, dispHIGH, dispDEEP);
    if (!tmpPix) FatalError("couldn't create root pixmap");

    /* do some stuff to set up the border around the picture */

    XSetForeground(theDisp, theGC, rootbg);
    XFillRectangle(theDisp, tmpPix, theGC, 0,0, dispWIDE, dispHIGH);

    switch (rootPattern) {
    case 0: /* solid color */ break;

    case 1: /* 'warp' effect */
            XSetForeground(theDisp, theGC, rootfg);
            for (i=0; i<=dispWIDE; i+=8) 
              XDrawLine(theDisp, tmpPix, theGC, i, 0, dispWIDE-i, dispHIGH);
            for (i=0; i<=dispHIGH; i+=8)
              XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, dispHIGH-i);
            break;

    case 2: /* 'bricks' effect */
            XSetForeground(theDisp, theGC, rootfg);
            for (i=k=0; i<dispHIGH; i+=20,k++) {
              XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, i);
	      for (j=(k&1) * 20 + 10; j<dispWIDE; j+=40) 
		XDrawLine(theDisp, tmpPix, theGC, j,i,j,i+20);
	    }
            break;

    /* your algorithm here */

    default: break;
    }
      

    XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 
	      (dispWIDE-w)/2, (dispHIGH-h)/2, w, h);
  }
  else {
    tmpPix = XCreatePixmap(theDisp, mainW, eWIDE, eHIGH, dispDEEP);
    if (!tmpPix) FatalError("couldn't create root pixmap");
    XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0, eWIDE, eHIGH);
  }

  XSetWindowBackgroundPixmap(theDisp, mainW, tmpPix);
  XFreePixmap(theDisp, tmpPix);

  SaveRootInfo();
  XClearWindow(theDisp, mainW);
}



/***********************************/
static void SaveRootInfo()
{
  /* called when using root window.  stores the pixmap ID used to draw the
     root window in a property.  This will be used later to free all resources
     allocated by this instantiation of xv (ie, the alloc'd colors).  These
     resources are kept alloc'ed after client exits so that rainbow effect
     is avoided */

  Atom          prop;
  static Pixmap riPix = NULL;

  if ( !(theVisual->class & 1)) return;  /* no colormap to worry about */

  if (riPix) return;                     /* it's already been saved once */

  riPix = XCreatePixmap(theDisp, rootW, 1, 1, 1);
  if (!riPix) return;   /* unable to save.  thankfully, unlikely to happen */

  prop = XInternAtom(theDisp, "_XV_PIXMAP", False);
  if (!prop) FatalError("couldn't create _XV_PIXMAP atom");

  XChangeProperty(theDisp, rootW, prop, XA_PIXMAP, 32, PropModeReplace,
		  (unsigned char *) &riPix, 1);

  XSetCloseDownMode(theDisp, RetainPermanent);
}


/***********************************/
static void KillOldRootInfo()
{
  /* get the pixmap ID from the _XV_PIXMAP property, and kill it */

  Atom           prop, type;
  int            format;
  unsigned long  length, after;
  unsigned char *data;

  prop = XInternAtom(theDisp, "_XV_PIXMAP", True);
  if (!prop) return;    /* no old pixmap to kill */

  if (XGetWindowProperty(theDisp, rootW, prop, 0L, 1L, True, AnyPropertyType,
		     &type, &format, &length, &after, &data) == Success) {

    if (type==XA_PIXMAP && format==32 && length==1 && after==0 && data)
      XKillClient(theDisp, *((Pixmap *)data));
  }

}


/************************************************************************/
/* following three rd_* functions swiped from xgraph, by David Harrison */
/************************************************************************/

/***********************************/
static int rd_int(name)
char *name;
{
  /* returns '1' if successful.  result in def_int */

  if (def_str = XGetDefault(theDisp, PROGNAME, name)) {
    if (sscanf(def_str, "%ld", &def_int) == 1) return 1;
    else {
      fprintf(stderr, "%s: couldn't read integer value for %s resource\n", 
	      cmd,name);
      return 0;
    }
  }
  else return 0;

}

/***********************************/
static int rd_str(name)
char *name;
{
  /* returns '1' if successful.  result in def_str */
  
  if (def_str = XGetDefault(theDisp, PROGNAME, name)) return 1;
  else return 0;

}

/***********************************/
static int rd_flag(name)
char *name;
{
  /* returns '1' if successful.  result in def_str */
  
  if (def_str = XGetDefault(theDisp, PROGNAME, name)) {
    def_int = (strcmp(def_str, "on")==0) || 
              (strcmp(def_str, "1")==0) ||
	      (strcmp(def_str, "true")==0) ||
	      (strcmp(def_str, "yes")==0);
    return 1;
    }

  else return 0;
}
    




\BARFOO\
else
  echo "will not over write ./xv.c"
fi
echo "Finished archive 9 of 10"
exit

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.
--
dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.