home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / xv221src / xv.c < prev    next >
C/C++ Source or Header  |  1992-09-24  |  73KB  |  2,485 lines

  1. /*
  2.  * xv.c - main section of xv.  X setup, window creation, etc.
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *                (bradley@cis.upenn.edu)
  6.  *
  7.  *  Modified for VMS by:
  8.  *              David Jones, the Ohio State University
  9.  *           (jonesd@kcgl1.eng.ohio-state.edu)
  10.  *          and Rick Dyson, the University of Iowa
  11.  *                 (dyson@IowaSP.Physics.UIowa.EDU)
  12.  *
  13.  *  Contains:
  14.  *            int  main(argc,argv)
  15.  *     static void Syntax()
  16.  *     static int  openPic(filenum)
  17.  *     static void closePic()
  18.  *     static void OpenFirstPic()
  19.  *     static void OpenNextPic()
  20.  *     static void OpenNextQuit()
  21.  *     static void OpenNextLoop()
  22.  *     static void OpenPrevPic()
  23.  *     static void OpenNamedPic()
  24.  *     static void MainLoop()
  25.  *     static void CreateMainWindow(geom, name)
  26.  *            void FixAspect(grow, w, h)
  27.  *     static void MakeDispNames()
  28.  *     static void stickInList();
  29.  *            void DeleteCmd();
  30.  *            int  rd_int(name)
  31.  *            int  rd_str(name)
  32.  *            int  rd_str_cl(name_str, class_str)
  33.  *            int  rd_flag(name)
  34.  */
  35.  
  36.  
  37. /*
  38.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  39.  *                       The University of Pennsylvania
  40.  *
  41.  * Permission to use, copy, and distribute for non-commercial purposes,
  42.  * is hereby granted without fee, providing that the above copyright
  43.  * notice appear in all copies and that both the copyright notice and this
  44.  * permission notice appear in supporting documentation. 
  45.  *
  46.  * The software may be modified for your own purposes, but modified versions
  47.  * may not be distributed.
  48.  *
  49.  * This software is provided "as is" without any expressed or implied warranty.
  50.  *
  51.  * The author may be contacted via:
  52.  *    US Mail:   John Bradley
  53.  *               GRASP Lab, Room 301C
  54.  *               3401 Walnut St.  
  55.  *               Philadelphia, PA  19104
  56.  *
  57.  *    Phone:     (215) 898-8813
  58.  *    EMail:     bradley@cis.upenn.edu       
  59.  */
  60.  
  61.  
  62. #define MAIN
  63. #define NEEDSTIME
  64. #define NEEDSDIR     /* for value of MAXPATHLEN */
  65.  
  66. #include "xv.h"
  67. #include "bitmaps.h"
  68. #include "sunras.h"
  69.  
  70. #include <X11/Xatom.h>
  71.  
  72. #ifdef VMS
  73. extern Window pseudo_root();
  74. #endif
  75.  
  76.  
  77. /* program needs one of the following fonts.  Trys them in ascending order */
  78.  
  79. #define FONT1 "-*-lucida-medium-r-*-*-12-*"
  80. #define FONT2 "-*-helvetica-medium-r-*-*-12-*"
  81. #define FONT3 "-*-helvetica-medium-r-*-*-11-*"
  82. #define FONT4 "6x13"
  83. #define FONT5 "fixed"
  84.  
  85. /* a mono-spaced font needed for the 'pixel value tracking' feature */
  86. #define MFONT1 "-misc-fixed-medium-r-normal-*-13-*"
  87. #define MFONT2 "6x13"   
  88. #define MFONT3 "-*-courier-medium-r-*-*-12-*"
  89. #define MFONT4 "fixed"   
  90.  
  91.  
  92. /* file types that can be read */
  93. #define UNKNOWN 0
  94. #define GIF     1
  95. #define PM      2
  96. #define PBM     3
  97. #define XBM     4
  98. #define SUNRAS  5
  99. #define UTAHRLE 6
  100.  
  101.  
  102. #ifdef HAVE_JPEG
  103. # define JFIF 7
  104. #endif
  105.  
  106. #ifdef HAVE_TIFF
  107. # ifdef HAVE_JPEG
  108. #  define TIFF 8
  109. # else
  110. #  define TIFF 7
  111. # endif
  112. #endif
  113.  
  114. #ifdef HAVE_PDS
  115. # if (defined(HAVE_TIFF) && defined(HAVE_JPEG))
  116. #  define PDSVICAR 9
  117. # else
  118. #  if (defined(HAVE_TIFF) || defined(HAVE_JPEG))
  119. #   define PDSVICAR 8
  120. #  else
  121. #   define PDSVICAR 7
  122. #  endif
  123. # endif
  124. #endif
  125.  
  126. /* yech! */
  127.  
  128.  
  129.  
  130.  
  131. static int    revvideo   = 0;   /* true if we should reverse video */
  132. static int    dfltkludge = 0;   /* true if we're viewing dfltpic */
  133. static int    keeparound = 1;   /* if true, don't quit after del. last image */
  134. static int    autoquit = 0;     /* quit after loading first pic to rootW */
  135. static int    autosmooth = 0;   /* smooth picture upon loading */
  136. static int    autodither = 0;   /* colordither picture upon loading */
  137. static int    autocrop   = 0;   /* autocrop picture upon loading */
  138. static int    clearonload;      /* clear window/root (on colormap visuals) */
  139. static float  expand = 1.0;     /* '-expand' argument */
  140. static char  *maingeom = NULL;
  141. static char   initpath[MAXPATHLEN];
  142. static Atom   __SWM_VROOT = None;
  143.  
  144. /* used in DeleteCmd() */
  145. static char  **mainargv;
  146. static int     mainargc;
  147.  
  148.  
  149. /* local function pre-definitions */
  150. #ifdef __STDC__
  151. static void Syntax(void);
  152. static void RmodeSyntax(void);
  153. static int  openPic(int);
  154. static int  readpipe(char *, char *);
  155. static void closePic(void);
  156. static void OpenFirstPic(void);
  157. static void OpenNextPic(void);
  158. static void OpenNextQuit(void);
  159. static void OpenNextLoop(void);
  160. static void OpenPrevPic(void);
  161. static void OpenNamedPic(void);
  162. static void MainLoop(void);
  163. static void CreateMainWindow(char *, char *);
  164. static void smoothResize(int, int);
  165. static void MakeDispNames(void);
  166. static void stickInList(void);
  167. static int  argcmp(char *, char *, int);
  168. #else
  169. static void Syntax(), RmodeSyntax(), closePic(), OpenFirstPic(), OpenNextPic();
  170. static void OpenNextQuit(), OpenNextLoop(), OpenPrevPic(), OpenNamedPic();
  171. static void MainLoop(), CreateMainWindow(), MakeDispNames(), stickInList();
  172. static int  openPic(), argcmp(), readpipe();
  173. static void smoothResize();
  174. #endif
  175.  
  176.  
  177. /*******************************************/
  178. int main(argc, argv)
  179. int   argc;
  180. char *argv[];
  181. /*******************************************/
  182. {
  183.   int   i, imap, ctrlmap, gmap, clrroot, nopos, limit2x;
  184.   char *display, *whitestr, *blackstr, *histr, *lostr,
  185.        *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom;
  186.   char *rootfgstr, *rootbgstr, *visualstr;
  187.   int  curstype, stdinflag, browseMode, savenorm, preview, pscomp;
  188.  
  189.   XColor ecdef;
  190.   Window rootReturn, parentReturn, *children;
  191.   unsigned int numChildren;
  192.  
  193. #ifdef VMS
  194.   /* convert VMS-style arguments to unix names and glob */
  195.   do_vms_wildcard(&argc, &argv);
  196.   getredirection(&argc, &argv);
  197. #endif
  198.  
  199.   /*****************************************************/
  200.   /*** variable Initialization                       ***/
  201.   /*****************************************************/
  202.  
  203.   GETWD(initpath);
  204.   mainargv = argv;
  205.   mainargc = argc;
  206.  
  207.   /* init internal variables */
  208.   display = NULL;
  209.   fgstr = bgstr = rootfgstr = rootbgstr = NULL;
  210.   histr = lostr = whitestr = blackstr = NULL;
  211.   visualstr = NULL;
  212.   pic = epic = cpic = NULL;
  213.   theImage = NULL;
  214.   LocalCmap = 0;
  215.   stdinflag = 0;
  216.   autoclose = 1; 
  217.   cmapInGam = 1;
  218.   cmapinstalled = showzoomcursor = 0;
  219.  
  220.   /* init default colors */
  221.   fgstr = "#000000";  bgstr = "#B2C0DC";
  222.   histr = "#C6D5E2";  lostr = "#8B99B5";
  223.  
  224.   cmd = rindex(argv[0],'/');
  225.   if (!cmd) cmd = argv[0]; else cmd++;
  226.  
  227.   tmpdir = (char *) getenv("TMPDIR");
  228.   if (!tmpdir) tmpdir = "/tmp";
  229.  
  230.   /* init command-line options flags */
  231.   infogeom = DEFINFOGEOM;  ctrlgeom = DEFCTRLGEOM;  
  232.   gamgeom  = DEFGAMGEOM;
  233.  
  234.   ncols = -1;  noglob = 0;  mono = 0;  
  235.   perfect = 0;  ninstall = 0;  fixedaspect = 0;
  236.   DEBUG = 0;  bwidth = 2;
  237.   nolimits = useroot = clrroot = noqcheck = rwcolor = owncmap = 0;
  238.   waitsec = -1;  waitloop = 0;  automax = 0;
  239.   rootMode = 0;  hsvmode = 0;
  240.   nopos = limit2x = 0;
  241.   resetroot = 1;
  242.   clearonload = 0;
  243.   curstype = XC_crosshair;
  244.   browseMode = savenorm = nostat = 0;
  245.   preview = 0;
  246.   pscomp = 0;
  247.  
  248.   conv24 = CONV24_SLOW;  /* use 'slow' algorithm by default */
  249.  
  250.   defaspect = normaspect = 1.0;
  251.   mainW = dirW = infoW = ctrlW = gamW = psW = (Window) NULL;
  252.  
  253. #ifdef HAVE_JPEG
  254.   jpegW = (Window) NULL;
  255. #endif
  256.  
  257. #ifdef HAVE_TIFF
  258.   tiffW = (Window) NULL;
  259. #endif
  260.  
  261.   imap = ctrlmap = gmap = 0;
  262.  
  263.   ch_offx = ch_offy = p_offx = p_offy = 0;
  264.  
  265.   /* init info box variables */
  266.   infoUp = 0;
  267.   infoMode = INF_STR;
  268.   for (i=0; i<NISTR; i++) SetISTR(i,"");
  269.  
  270.   /* init ctrl box variables */
  271.   ctrlUp = 0;
  272.   curname = 0;
  273.   formatStr[0] ='\0';
  274.  
  275.   gamUp = 0;
  276.  
  277.   Init24to8();
  278.  
  279.   /*****************************************************/
  280.   /*** X Resource Initialization                     ***/
  281.   /*****************************************************/
  282.  
  283.   /* once through the argument list to find the display name, if any */
  284.   for (i=1; i<argc; i++) {
  285.     if (!strncmp(argv[i],"-help",5)) {     /* help */
  286.       Syntax();
  287.       exit(0);
  288.     }
  289.  
  290.     else if (!argcmp(argv[i],"-display",4)) {  /* display */
  291.       i++;
  292.       if (i<argc) display = argv[i];
  293.       break;
  294.     }
  295.   }
  296.  
  297.   /* open the display */
  298.   if ( (theDisp=XOpenDisplay(display)) == NULL) {
  299.     fprintf(stderr, "%s: Can't open display\n",argv[0]);
  300.     exit(1);
  301.   }
  302.  
  303.  
  304.  
  305.   if (rd_str ("aspect")) {
  306.     int n,d;
  307.     if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1)
  308.       fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd);
  309.     else defaspect = (float) n / (float) d;
  310.   }
  311.       
  312.   if (rd_flag("2xlimit"))        limit2x     = def_int;      
  313.   if (rd_flag("autoClose"))      autoclose   = def_int;
  314.   if (rd_flag("autoCrop"))       autocrop    = def_int;
  315.   if (rd_flag("autoDither"))     autodither  = def_int;
  316.   if (rd_flag("autoSmooth"))     autosmooth  = def_int;
  317.   if (rd_str ("background"))     bgstr       = def_str;
  318.   if (rd_flag("best24") && def_int)  conv24  = CONV24_BEST;
  319.   if (rd_str ("black"))          blackstr    = def_str;
  320.   if (rd_int ("borderWidth"))    bwidth      = def_int;
  321.   if (rd_flag("browseMode"))     browseMode  = def_int;
  322.   if (rd_str ("ctrlGeometry"))   ctrlgeom    = def_str;
  323.   if (rd_flag("ctrlMap"))        ctrlmap     = def_int;
  324.   if (rd_int ("cursor"))         curstype    = def_int;
  325.   if (rd_str ("expand"))         expand      = atof(def_str);
  326.   if (rd_flag("fixed"))          fixedaspect = def_int;
  327.   if (rd_str ("foreground"))     fgstr       = def_str;
  328.   if (rd_str ("geometry"))       maingeom    = def_str;
  329.   if (rd_str ("ceditGeometry"))  gamgeom     = def_str;
  330.   if (rd_flag("ceditMap"))       gmap        = def_int;
  331.   if (rd_flag("ceditColorMap"))  cmapInGam   = def_int;
  332.   if (rd_flag("clearOnLoad"))    clearonload = def_int;
  333.   if (rd_flag("hsvMode"))        hsvmode     = def_int;
  334.   if (rd_str ("highlight"))      histr       = def_str;
  335.   if (rd_str ("infoGeometry"))   infogeom    = def_str;
  336.   if (rd_flag("infoMap"))        imap        = def_int;
  337.   if (rd_flag("keepAround"))     keeparound  = def_int;
  338.   if (rd_str ("lowlight"))       lostr       = def_str;
  339.   if (rd_flag("mono"))           mono        = def_int;
  340.   if (rd_int ("ncols"))        { ncols = def_int; if (ncols>=0) noglob = 1; }
  341.   if (rd_flag("nglobal"))        noglob      = def_int;
  342.   if (rd_flag("ninstall"))       ninstall    = def_int;
  343.   if (rd_flag("nolimits"))       nolimits    = def_int;
  344.   if (rd_flag("nopos"))          nopos       = def_int;
  345.   if (rd_flag("noqcheck"))       noqcheck    = def_int;
  346.   if (rd_flag("nostat"))         nostat      = def_int;
  347.   if (rd_flag("ownCmap"))        owncmap     = def_int;
  348.   if (rd_flag("perfect"))        perfect     = def_int;
  349.   if (rd_flag("pscompress"))     pscomp      = def_int;
  350.   if (rd_flag("pspreview"))      preview     = def_int;
  351.   if (rd_flag("quick24") && def_int)  conv24 = CONV24_FAST;
  352.   if (rd_flag("resetroot"))      resetroot   = def_int;
  353.   if (rd_flag("reverse"))        revvideo    = def_int;
  354.   if (rd_str ("rootBackground")) rootbgstr   = def_str;
  355.   if (rd_str ("rootForeground")) rootfgstr   = def_str;
  356.   if (rd_int ("rootMode"))       rootMode    = def_int;
  357.   if (rd_flag("rwColor"))        rwcolor     = def_int;
  358.   if (rd_flag("saveNormal"))     savenorm    = def_int;
  359.   if (rd_str ("visual"))         visualstr   = def_str;
  360.   if (rd_str ("white"))          whitestr    = def_str;
  361.       
  362.  
  363.   /*****************************************************/
  364.   /*** Command Line Options                          ***/
  365.   /*****************************************************/
  366.   
  367.   for (i=1, numnames=0; i<argc; i++) {
  368.     if (argv[i][0] != '-') {           /* a file name.  put it in list */
  369.       if (numnames<MAXNAMES) {
  370.     namelist[numnames++] = argv[i];
  371.     if (numnames==MAXNAMES) {
  372.       fprintf(stderr,"%s: too many filenames.  Only using first %d.\n",
  373.           cmd, MAXNAMES);
  374.     }
  375.       }
  376.     }
  377.  
  378.     else if (!strcmp(argv[i],  "-"))           /* stdin flag */
  379.       stdinflag++;
  380.  
  381.     else if (!argcmp(argv[i],"-2xlimit",2))    /* 2xlimit */
  382.       limit2x = !limit2x;
  383.  
  384.     else if (!argcmp(argv[i],"-aspect",2)) {   /* default aspect */
  385.       int n,d;
  386.       if (++i<argc) {
  387.     if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1)
  388.       fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]);
  389.     else defaspect = (float) n / (float) d;
  390.       }
  391.     }
  392.  
  393.     else if (!argcmp(argv[i],"-best24",3))     /* ppmquant 24->8 conversion */
  394.       conv24 = CONV24_BEST;
  395.     
  396.     else if (!argcmp(argv[i],"-bg",3))        /* background color */
  397.       { if (++i<argc) bgstr = argv[i]; }
  398.  
  399.     else if (!argcmp(argv[i],"-black",3))     /* black color */
  400.       { if (++i<argc) blackstr = argv[i]; }
  401.     
  402.     else if (!argcmp(argv[i],"-browse",3))    /* browse mode */
  403.       browseMode = !browseMode;
  404.  
  405.     else if (!argcmp(argv[i],"-bw",3))        /* border width */
  406.       { if (++i<argc) bwidth=atoi(argv[i]); }
  407.  
  408.     else if (!argcmp(argv[i],"-cecmap",4))    /* cmapInGam */
  409.       cmapInGam = !cmapInGam;
  410.     
  411.     else if (!argcmp(argv[i],"-cegeometry",4))    /* gammageom */
  412.       { if (++i<argc) gamgeom = argv[i]; }
  413.     
  414.     else if (!argcmp(argv[i],"-cemap",4))    /* gmap */
  415.       gmap++;
  416.     
  417.     else if (!argcmp(argv[i],"-cgeometry",3))    /* ctrlgeom */
  418.       { if (++i<argc) ctrlgeom = argv[i]; }
  419.     
  420.     else if (!argcmp(argv[i],"-clear",4))    /* clear */
  421.       clrroot++;
  422.     
  423.     else if (!argcmp(argv[i],"-close",4))    /* close */
  424.       autoclose = !autoclose;
  425.     
  426.     else if (!argcmp(argv[i],"-cmap",3))    /* ctrlmap */
  427.       ctrlmap++;
  428.     
  429.     else if (!argcmp(argv[i],"-crop",3))        /* autocrop */
  430.       autocrop = !autocrop;
  431.  
  432.     else if (!argcmp(argv[i],"-cursor",3))    /* cursor */
  433.       { if (++i<argc) curstype = atoi(argv[i]); }
  434.  
  435.     else if (!argcmp(argv[i],"-DEBUG",2))     /* debug */
  436.       { if (++i<argc) DEBUG = atoi(argv[i]); }
  437.  
  438.     else if (!argcmp(argv[i],"-display",4))     /* display */
  439.       { if (++i<argc) display = argv[i]; }
  440.  
  441.     else if (!argcmp(argv[i],"-dither",4))      /* autodither */
  442.       autodither = !autodither;
  443.  
  444.     else if (!argcmp(argv[i],"-expand",2))     /* expand factor */
  445.       { if (++i<argc) expand=atof(argv[i]); }
  446.  
  447.     else if (!argcmp(argv[i],"-fg",3))          /* foreground color */
  448.       { if (++i<argc) fgstr = argv[i]; }
  449.     
  450.     else if (!argcmp(argv[i],"-fixed",3))       /* fixed aspect ratio */
  451.       fixedaspect++;
  452.     
  453.     else if (!argcmp(argv[i],"-geometry",2))    /* geometry */
  454.       { if (++i<argc) maingeom = argv[i]; }
  455.     
  456.     else if (!argcmp(argv[i],"-hi",3))            /* highlight */
  457.       { if (++i<argc) histr = argv[i]; }
  458.     
  459.     else if (!argcmp(argv[i],"-hsv",3))         /* hsvmode */
  460.       hsvmode = 1;
  461.     
  462.     else if (!argcmp(argv[i],"-igeometry",3))    /* infogeom */
  463.       { if (++i<argc) infogeom = argv[i]; }
  464.     
  465.     else if (!argcmp(argv[i],"-imap",3))    /* imap */
  466.       imap++;
  467.     
  468.     else if (!argcmp(argv[i],"-keeparound",2))  /* keeparound */
  469.       keeparound = !keeparound;
  470.     
  471.     else if (!argcmp(argv[i],"-loadclear",4))   /* toggle clearonload */
  472.       clearonload = !clearonload;
  473.  
  474.     else if (!argcmp(argv[i],"-lo",3))            /* lowlight */
  475.       { if (++i<argc) lostr = argv[i]; }
  476.     
  477.     else if (!argcmp(argv[i],"-max",4))            /* auto maximize */
  478.       automax++;
  479.     
  480.     else if (!argcmp(argv[i],"-maxpect",5))     /* auto maximize */
  481.       { automax++; fixedaspect++; }
  482.     
  483.     else if (!argcmp(argv[i],"-mono",3))    /* mono */
  484.       mono++;
  485.     
  486.     else if (!argcmp(argv[i],"-ncols",3))       /* ncols */
  487.       { if (++i<argc) { ncols=abs(atoi(argv[i])); noglob++; } }
  488.     
  489.     else if (!argcmp(argv[i],"-nglobal",3))     /* no global colors */
  490.       noglob++;
  491.     
  492.     else if (!argcmp(argv[i],"-ninstall",3))    /* don't install colormaps */
  493.       ninstall=1;
  494.  
  495.     else if (!argcmp(argv[i],"-nolimits",4))    /* nolimits */
  496.       nolimits = !nolimits;
  497.  
  498.     else if (!argcmp(argv[i],"-nopos",4))       /* nopos */
  499.       nopos++;
  500.  
  501.     else if (!argcmp(argv[i],"-noqcheck",4))    /* noqcheck */
  502.       noqcheck++;
  503.  
  504.     else if (!argcmp(argv[i],"-nostat",4))      /* nostat */
  505.       nostat = !nostat;
  506.  
  507.     else if (!argcmp(argv[i],"-owncmap",2))     /* own colormap */
  508.       owncmap++;
  509.  
  510.     else if (!argcmp(argv[i],"-perfect",2))     /* perfect colors */
  511.       perfect++;  
  512.  
  513.     else if (!argcmp(argv[i],"-noresetroot",2)) /* reset root in window mode */
  514.       resetroot = !resetroot;  
  515.     
  516.     else if (!argcmp(argv[i],"-quick24",5))     /* quick 24-to-8 conversion */
  517.       conv24 = CONV24_FAST;
  518.     
  519.     else if (!argcmp(argv[i],"-quit",2))        /* auto-quit if -root */
  520.       autoquit++;
  521.     
  522.     else if (!argcmp(argv[i],"-rbg",3))         /* root background color */
  523.       { if (++i<argc) rootbgstr = argv[i]; }
  524.     
  525.     else if (!argcmp(argv[i],"-rfg",3))         /* root foreground color */
  526.       { if (++i<argc) rootfgstr = argv[i]; }
  527.     
  528.     else if (!argcmp(argv[i],"-rgb",4))         /* rgb mode */
  529.       hsvmode = 0;
  530.     
  531.     else if (!argcmp(argv[i],"-rmode",3))    /* root pattern */
  532.       { if (++i<argc) rootMode = abs(atoi(argv[i])); useroot++; }
  533.     
  534.     else if (!argcmp(argv[i],"-root",3))        /* use root window */
  535.       useroot++;
  536.     
  537.     else if (!argcmp(argv[i],"-rv",3))          /* reverse video */
  538.       revvideo = !revvideo;
  539.     
  540.     else if (!argcmp(argv[i],"-rw",3))          /* use r/w color */
  541.       rwcolor = !rwcolor;
  542.     
  543.     else if (!argcmp(argv[i],"-slow24",3))      /* slow 24-to-8 conversion */
  544.       conv24 = CONV24_SLOW;
  545.     
  546.     else if (!argcmp(argv[i],"-smooth",3))      /* autosmooth */
  547.       autosmooth = !autosmooth;
  548.  
  549.     else if (!argcmp(argv[i],"-visual",2))    /* visual */
  550.       { if (++i<argc) visualstr = argv[i]; }
  551.     
  552.     else if (!argcmp(argv[i],"-wait",3)) {      /* secs to wait between pics */
  553.       if (++i<argc) {
  554.     waitsec = abs(atoi(argv[i]));
  555.     if (waitsec<0) waitsec = 0;
  556.       }
  557.     }
  558.     
  559.     else if (!argcmp(argv[i],"-white",3))    /* white color */
  560.       { if (++i<argc) whitestr = argv[i]; }
  561.     
  562.     else if (!argcmp(argv[i],"-wloop",3))    /* waitloop */
  563.       waitloop++;
  564.     
  565.     else if (!argcmp(argv[i],"-nolimits",3))    /* waitloop */
  566.       nolimits++;
  567.     
  568.     else Syntax();
  569.   }
  570.  
  571.   RANGE(curstype,0,254);
  572.   curstype = curstype & 0xfe;   /* clear low bit to make curstype even */
  573.  
  574.   if (expand == 0.0) Syntax();
  575.   if (rootMode < 0 || rootMode > RM_MAX) RmodeSyntax();
  576.  
  577.   if (DEBUG) XSynchronize(theDisp, True);
  578.  
  579.   /* if using root, generally gotta map ctrl window, 'cause there won't be
  580.      any way to ask for it.  (no kbd or mouse events from rootW) */
  581.   if (useroot && !autoquit) ctrlmap = -1;    
  582.  
  583.   /* must not install colormaps on rootW */
  584.   if (useroot) { owncmap = perfect=0;  noglob = 1; } 
  585.  
  586.   if (owncmap) perfect = 1;
  587.  
  588.   if (nopos) { maingeom = infogeom = ctrlgeom = gamgeom = NULL; }
  589.  
  590.   /* if -root and -maxp, make sure we're using a 'centered' mode */
  591.   if (useroot && fixedaspect && automax && rootMode < RM_CENTER)
  592.     rootMode = RM_CSOLID;
  593.  
  594.  
  595.   /*****************************************************/
  596.   /*** X Setup                                       ***/
  597.   /*****************************************************/
  598.   
  599.   theScreen = DefaultScreen(theDisp);
  600.   theCmap   = DefaultColormap(theDisp, theScreen);
  601.   rootW     = RootWindow(theDisp,theScreen);
  602.   theGC     = DefaultGC(theDisp,theScreen);
  603.   theVisual = DefaultVisual(theDisp,theScreen);
  604.   ncells    = DisplayCells(theDisp, theScreen);
  605.   dispDEEP  = DisplayPlanes(theDisp,theScreen);
  606.   vrWIDE = dispWIDE  = DisplayWidth(theDisp,theScreen);
  607.   vrHIGH = dispHIGH  = DisplayHeight(theDisp,theScreen);
  608.   maxWIDE = dispWIDE;  maxHIGH = dispHIGH;
  609.  
  610.   if (visualstr) {     /* handle non-default visual */
  611.     int vclass = -1;
  612.     lower_str(visualstr);
  613.     if      (!strcmp(visualstr,"staticgray"))  vclass = StaticGray;
  614.     else if (!strcmp(visualstr,"staticcolor")) vclass = StaticColor;
  615.     else if (!strcmp(visualstr,"truecolor"))   vclass = TrueColor;
  616.     else if (!strcmp(visualstr,"grayscale"))   vclass = GrayScale;
  617.     else if (!strcmp(visualstr,"pseudocolor")) vclass = PseudoColor;
  618.     else if (!strcmp(visualstr,"directcolor")) vclass = DirectColor;
  619.     else {
  620.       fprintf(stderr,"%s: Unrecognized visual type '%s'.  %s\n",
  621.           cmd, visualstr, "Using server default.");
  622.     }
  623.  
  624.     if (vclass >= 0) {   /* try to find asked-for visual type */
  625.       XVisualInfo *vinfo, rvinfo;
  626.       int numvis, best;
  627.  
  628.       rvinfo.class = vclass;
  629.       vinfo = XGetVisualInfo(theDisp, VisualClassMask, &rvinfo, &numvis);
  630.       if (vinfo) {       /* choose the 'best' one, if multiple */
  631.     for (i=0, best=0; i<numvis; i++) {
  632.       if (vinfo[i].depth > vinfo[best].depth) best = i;
  633.     }
  634.     theVisual = vinfo[best].visual;
  635.     if (DEBUG) {
  636.       fprintf(stderr,"%s: using %s visual, depth = %d, screen = %d\n",
  637.           cmd, visualstr, vinfo[best].depth, vinfo[best].screen);
  638.       fprintf(stderr,"\tmasks: (0x%x,0x%x,0x%x), bits_per_rgb=%d\n",
  639.           vinfo[best].red_mask, vinfo[best].green_mask,
  640.           vinfo[best].blue_mask, vinfo[best].bits_per_rgb);
  641.     }
  642.  
  643.     dispDEEP = vinfo[best].depth;
  644.     theScreen = vinfo[best].screen;
  645.     rootW = RootWindow(theDisp, theScreen);
  646.     ncells = vinfo[best].colormap_size;
  647.     theGC = DefaultGC(theDisp, theScreen);
  648.     vrWIDE = dispWIDE  = DisplayWidth(theDisp,theScreen);
  649.     vrHIGH = dispHIGH  = DisplayHeight(theDisp,theScreen);
  650.     maxWIDE = dispWIDE;  maxHIGH = dispHIGH;
  651.     theCmap = XCreateColormap(theDisp, rootW, theVisual, AllocNone);
  652. #ifdef FOO
  653.     theCmap = DefaultColormap(theDisp, theScreen);
  654. #endif
  655.  
  656.     XFree((char *) vinfo);
  657.       }
  658.       else fprintf(stderr,"%s: Visual type '%s' not available.  %s\n",
  659.            cmd, visualstr, "Using server default.");
  660.     }
  661.   }
  662.     
  663.  
  664.   if (!useroot && limit2x) { maxWIDE *= 2;  maxHIGH *= 2; }
  665.   if (nolimits) { maxWIDE = 65000; maxHIGH = 65000; }
  666.  
  667.   XSetErrorHandler(xvErrorHandler);
  668.  
  669.   /* always search for virtual root window */
  670.   vrootW = rootW;
  671. #ifndef VMS
  672.   __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False);
  673.   XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children,
  674.          &numChildren);
  675.   for (i = 0; i < numChildren; i++) {
  676.     Atom actual_type;
  677.     int actual_format;
  678.     unsigned long nitems, bytesafter;
  679.     Window *newRoot = NULL;
  680.     XWindowAttributes xwa;
  681.     if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0, 1,
  682.       False, XA_WINDOW, &actual_type, &actual_format, &nitems,
  683.       &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) {
  684.       vrootW = *newRoot;
  685.       XGetWindowAttributes(theDisp, vrootW, &xwa);
  686.       vrWIDE = xwa.width;  vrHIGH = xwa.height;
  687.       dispDEEP = xwa.depth;
  688.       break;
  689.     }
  690.   }
  691. #else  /* VMS */
  692.   vrootW = pseudo_root(theDisp, theScreen);
  693. #endif
  694.  
  695.   if (clrroot || useroot) {
  696.     /* have enough info to do a '-clear' now */
  697.     KillOldRootInfo();   /* if any */
  698.     if (resetroot || clrroot) ClearRoot();  /* don't clear on '-noresetroot' */
  699.     if (clrroot) Quit(0);
  700.   }
  701.  
  702.  
  703.   arrow     = XCreateFontCursor(theDisp,XC_top_left_arrow);
  704.   cross     = XCreateFontCursor(theDisp,curstype);
  705.   tcross    = XCreateFontCursor(theDisp,XC_tcross);
  706.   zoom      = XCreateFontCursor(theDisp,XC_sizing);
  707.  
  708.   {
  709.     XColor fc, bc;
  710.     fc.red = fc.green = fc.blue = 0xffff;
  711.     bc.red = bc.green = bc.blue = 0x0000;
  712.     
  713.     XRecolorCursor(theDisp, zoom, &fc, &bc);
  714.   }
  715.  
  716.   { /* create invisible cursor */
  717.     Pixmap pix;
  718.     static char bits[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  719.     XColor col;
  720.  
  721.     col.red = col.green = col.blue = 0;
  722.  
  723.     pix = XCreateBitmapFromData(theDisp, rootW, bits, 8, 8);
  724.     inviso = XCreatePixmapCursor(theDisp, pix, pix, &col, &col, 0,0);
  725.     XFreePixmap(theDisp, pix);
  726.   }
  727.  
  728.  
  729.  
  730.   /* set up white,black colors */
  731.   white = WhitePixel(theDisp,theScreen);  whtRGB = 0xffffff;
  732.   black = BlackPixel(theDisp,theScreen);  blkRGB = 0x000000;
  733.  
  734.   if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
  735.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  736.     white = ecdef.pixel;
  737.     whtRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  738.   }
  739.  
  740.   if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
  741.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  742.     black = ecdef.pixel;
  743.     blkRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
  744.   }
  745.  
  746.  
  747.   /* set up fg,bg colors */
  748.   fg = black;   bg = white;  
  749.   if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
  750.       xvAllocColor(theDisp, theCmap, &ecdef)) {
  751.     fg = ecdef.pixel;
  752.   }
  753.  
  754.   if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
  755.       xvAllocColor(theDisp, theCmap, &ecdef))  {
  756.     bg = ecdef.pixel;
  757.   }
  758.  
  759.  
  760.   /* set up root fg,bg colors */
  761.   rootfg = white;   rootbg = black;
  762.   if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
  763.       xvAllocColor(theDisp, theCmap, &ecdef))  rootfg = ecdef.pixel;
  764.   if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
  765.       xvAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
  766.  
  767.  
  768.   /* set up hi/lo colors */
  769.   i=0;
  770.   if (dispDEEP > 1) {   /* only if we're on a reasonable display */
  771.     if (histr && XParseColor(theDisp, theCmap, histr, &ecdef) &&
  772.     xvAllocColor(theDisp, theCmap, &ecdef))  { hicol = ecdef.pixel; i|=1; }
  773.     if (lostr && XParseColor(theDisp, theCmap, lostr, &ecdef) &&
  774.     xvAllocColor(theDisp, theCmap, &ecdef))  { locol = ecdef.pixel; i|=2; }
  775.   }
  776.  
  777.   if      (i==0) ctrlColor = 0;
  778.   else if (i==3) ctrlColor = 1;
  779.   else {  /* only got some of them */
  780.     if (i&1) xvFreeColors(theDisp, theCmap, &hicol, 1, 0L);
  781.     if (i&2) xvFreeColors(theDisp, theCmap, &locol, 1, 0L);
  782.     ctrlColor = 0;
  783.   }
  784.  
  785.   XSetForeground(theDisp,theGC,fg);
  786.   XSetBackground(theDisp,theGC,bg);
  787.  
  788.   infofg = fg;  infobg = bg;
  789.  
  790.   /* if '-mono' not forced, determine if we're on a grey or color monitor */
  791.   if (!mono) {
  792.     if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
  793.     if (theVisual->class == StaticGray || theVisual->class == GrayScale)
  794.       mono = 1;
  795.   }
  796.   
  797.  
  798.  
  799.   iconPix = XCreatePixmapFromBitmapData(theDisp, rootW, icon_bits,
  800.          icon_width, icon_height, 1, 0, 1);
  801.  
  802.   iconmask = XCreatePixmapFromBitmapData(theDisp, rootW, iconmask_bits,
  803.          icon_width, icon_height, 1, 0, 1);
  804.  
  805.  
  806.  
  807.   /* try to load fonts */
  808.   if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL && 
  809.        (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL && 
  810.        (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL && 
  811.        (mfinfo = XLoadQueryFont(theDisp,FONT4))==NULL && 
  812.        (mfinfo = XLoadQueryFont(theDisp,FONT5))==NULL) {
  813.     sprintf(str,
  814.         "couldn't open the following fonts:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s",
  815.         FONT1, FONT2, FONT3, FONT4, FONT5);
  816.     FatalError(str);
  817.   }
  818.   mfont=mfinfo->fid;
  819.   XSetFont(theDisp,theGC,mfont);
  820.   
  821.   if ( (monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL && 
  822.        (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL && 
  823.        (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL && 
  824.        (monofinfo = XLoadQueryFont(theDisp,MFONT4))==NULL) {
  825.     sprintf(str,"couldn't open the following fonts:\n\t%s\n\t%s\n\t%s\n\t%s",
  826.         MFONT1, MFONT2, MFONT3, MFONT4);
  827.     FatalError(str);
  828.   }
  829.   monofont=monofinfo->fid;
  830.   
  831.  
  832.  
  833.  
  834.   /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
  835.      case ncols = 0;  (ncols = max number of colors allocated.  on 1-bit
  836.      displays, no colors are allocated */
  837.  
  838.   if (ncols == -1) {
  839.     if (dispDEEP>1) ncols = 1 << ((dispDEEP>8) ? 8 : dispDEEP);
  840.     else ncols = 0;
  841.   }
  842.   else if (ncols>256) ncols = 256;       /* so program doesn't blow up */
  843.  
  844.  
  845.  
  846.   /* no filenames.  build one-name (stdio) list (if stdinflag) */
  847.   if (numnames==0) {
  848.     if (stdinflag) {  namelist[0] = STDINSTR; numnames = 1; }
  849.     else           {  namelist[0] = NULL;     numnames = 0; }
  850.   }
  851.  
  852.   if (numnames) MakeDispNames();
  853.  
  854.  
  855.  
  856.   /* create the info box window */
  857.   CreateInfo(infogeom);
  858.   XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask
  859.            | StructureNotifyMask);
  860.   InfoBox(imap);     /* map it (or not) */
  861.   if (imap) {
  862.     RedrawInfo(0,0,INFOWIDE,INFOHIGH);  /* explicit draw if mapped */
  863.     XFlush(theDisp);
  864.   }
  865.  
  866.  
  867.   /* create the control box window */
  868.   CreateCtrl(ctrlgeom);
  869.   epicmode = EM_RAW;   SetEpicMode();
  870.   XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask
  871.            | StructureNotifyMask);
  872.   if (ctrlmap < 0) {    /* map iconified */
  873.     XWMHints xwmh;
  874.     xwmh.initial_state = IconicState;
  875.     xwmh.flags = StateHint;
  876.     XSetWMHints(theDisp, ctrlW, &xwmh);
  877.     ctrlmap = 1;
  878.   }
  879.   CtrlBox(ctrlmap);     /* map it (or not) */
  880.   if (ctrlmap) {
  881.     RedrawCtrl(0,0,CTRLWIDE,CTRLHIGH);   /* explicit draw if mapped */
  882.     XFlush(theDisp);
  883.   }
  884.  
  885.  
  886.   /* create the directory window */
  887.   CreateDirW(NULL);
  888.   XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask);
  889.   browseCB.val = browseMode;
  890.   savenormCB.val = savenorm;
  891.  
  892.  
  893.   /* create the gamma window */
  894.   CreateGam(gamgeom);
  895.   XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask
  896.            | StructureNotifyMask
  897.            | (cmapInGam ? ColormapChangeMask : 0));
  898.  
  899.   GamBox(gmap);     /* map it (or not) */
  900.  
  901.  
  902.   /* create the ps window */
  903.   CreatePSD(NULL);
  904.   encapsCB.val = preview;
  905.   pscompCB.val = pscomp;
  906.  
  907. #ifdef HAVE_JPEG
  908.   CreateJPEGW();
  909. #endif
  910.  
  911. #ifdef HAVE_TIFF
  912.   CreateTIFFW();
  913. #endif
  914.  
  915.   GenerateFSGamma();
  916.  
  917.   LoadFishCursors();
  918.   SetCursors(-1);
  919.  
  920.   /* if we're not on a colormapped display, turn off rwcolor */
  921.   if (theVisual->class != PseudoColor && 
  922.       theVisual->class != GrayScale && rwcolor) {
  923.     fprintf(stderr,"xv: not a colormapped display.  'rwcolor' turned off.\n");
  924.     rwcolor = 0;
  925.   }
  926.  
  927.   XSelectInput(theDisp, rootW, ColormapChangeMask);
  928.  
  929.   /* Do The Thing... */
  930.   MainLoop();
  931.   Quit(0);
  932.   return(0);
  933. }
  934.  
  935.  
  936.  
  937.  
  938. /***********************************/
  939. static int cpos = 0;
  940. void printoption(st)
  941. char *st;
  942. {
  943.   if (strlen(st) + cpos > 78) {
  944.     fprintf(stderr,"\n   ");
  945.     cpos = 3;
  946.   }
  947.  
  948.   fprintf(stderr,"%s ",st);
  949.   cpos = cpos + strlen(st) + 1;
  950. }
  951.  
  952. static void Syntax()
  953. {
  954.   fprintf(stderr, "Usage:\n");
  955.   printoption(cmd);
  956.   printoption("[-]");
  957.   printoption("[-2xlimit]");
  958.   printoption("[-aspect w:h]");
  959.   printoption("[-best24]");
  960.   printoption("[-bg color]");
  961.   printoption("[-black color]");
  962.   printoption("[-browse]");
  963.   printoption("[-bw width]");
  964.   printoption("[-cecmap]");
  965.   printoption("[-cegeometry geom]");
  966.   printoption("[-cemap]");
  967.   printoption("[-cgeometry geom]");
  968.   printoption("[-clear]");
  969.   printoption("[-close]");
  970.   printoption("[-cmap]");
  971.   printoption("[-crop]");
  972.   printoption("[-cursor char#]");
  973.   printoption("[-DEBUG level]");
  974.   printoption("[-display disp]");
  975.   printoption("[-dither]");
  976.   printoption("[-expand exp]");
  977.   printoption("[-fg color]");
  978.   printoption("[-fixed]");
  979.   printoption("[-geometry geom]");
  980.   printoption("[-help]");
  981.   printoption("[-hi color]");
  982.   printoption("[-hsv]");
  983.   printoption("[-igeometry geom]");
  984.   printoption("[-imap]");
  985.   printoption("[-keeparound]");
  986.   printoption("[-lo color]");
  987.   printoption("[-loadclear]");
  988.   printoption("[-max]");
  989.   printoption("[-maxpect]");
  990.   printoption("[-mono]");
  991.   printoption("[-ncols #]");
  992.   printoption("[-nglobal]");
  993.   printoption("[-ninstall]");
  994.   printoption("[-nolimits]");
  995.   printoption("[-nopos]");
  996.   printoption("[-noqcheck]");
  997.   printoption("[-noresetroot]");
  998.   printoption("[-nostat]");
  999.   printoption("[-owncmap]");
  1000.   printoption("[-perfect]");
  1001.   printoption("[-quick24]");
  1002.   printoption("[-quit]");
  1003.   printoption("[-rbg color]");
  1004.   printoption("[-rfg color]");
  1005.   printoption("[-rgb]");
  1006.   printoption("[-rmode #]");
  1007.   printoption("[-root]");
  1008.   printoption("[-rv]");
  1009.   printoption("[-rw]");
  1010.   printoption("[-slow24]");
  1011.   printoption("[-smooth]");
  1012.   printoption("[-visual type]");
  1013.   printoption("[-wait seconds]");
  1014.   printoption("[-white color]");
  1015.   printoption("[-wloop]");
  1016.   printoption("[filename ...]");
  1017.   fprintf(stderr,"\n\n");
  1018.   Quit(1);
  1019. }
  1020.  
  1021.  
  1022. /***********************************/
  1023. static void RmodeSyntax()
  1024. {
  1025.   fprintf(stderr,"%s: unknown root mode '%d'.  Valid modes are:\n", 
  1026.       cmd, rootMode);
  1027.   fprintf(stderr,"\t0: tiling\n");
  1028.   fprintf(stderr,"\t1: integer tiling\n");
  1029.   fprintf(stderr,"\t2: mirrored tiling\n");
  1030.   fprintf(stderr,"\t3: integer mirrored tiling\n");
  1031.   fprintf(stderr,"\t4: centered tiling\n");
  1032.   fprintf(stderr,"\t5: centered on a solid background\n");
  1033.   fprintf(stderr,"\t6: centered on a 'warp' background\n");
  1034.   fprintf(stderr,"\t7: centered on a 'brick' background\n");
  1035.   fprintf(stderr,"\n");
  1036.   Quit(1);
  1037. }
  1038.  
  1039.  
  1040. /***********************************/
  1041. static int argcmp(a1, a2, minlen)
  1042. char *a1, *a2;
  1043. int minlen;
  1044. {
  1045.   /* does a string compare between a1 and a2.  To return '0', a1 and a2 
  1046.      must match to the length of a2, and that length has to
  1047.      be at least 'minlen'.  Otherwise, return non-zero */
  1048.  
  1049.   if (strlen(a1) < minlen || strlen(a2) < minlen) return 1;
  1050.   if (strlen(a1) > strlen(a2)) return 1;
  1051.  
  1052.   return (strncmp(a1, a2, strlen(a1)));
  1053. }
  1054.  
  1055.  
  1056. /***********************************/
  1057. static int openPic(filenum)
  1058. int filenum;
  1059. {
  1060.   /* tries to load file #filenum (from 'namelist' list)
  1061.    * returns 0 on failure (cleans up after itself)
  1062.    * if successful, returns 1, creates mainW
  1063.    *
  1064.    * By the way, I'd just like to point out that this procedure has gotten
  1065.    * *way* out of hand...
  1066.    */
  1067.  
  1068.   int   i,filetype,freename, nw, nh, frompipe;
  1069.   int   oldeWIDE, oldeHIGH;
  1070.   char *tmp;
  1071.   FILE *fp;
  1072.   char *fullname,      /* full name of the original file */
  1073.         filename[256], /* full name of the file to be loaded (could be /tmp) */
  1074.         globnm[512];   /* globbed version of fullname of orig file */
  1075.   byte  magicno[8];    /* first 8 bytes of file */
  1076.  
  1077.   normaspect = defaspect;
  1078.   freename = dfltkludge = frompipe = 0;
  1079.   oldeWIDE = eWIDE;  oldeHIGH = eHIGH;
  1080.  
  1081.   WaitCursor();
  1082.  
  1083.   if (filenum == DFLTPIC) {
  1084.     filename[0] = '\0';  basefname[0] = '\0';  fullname = "";
  1085.     dfltkludge = 1;
  1086.     LoadDfltPic();
  1087.     goto GOTIMAGE;
  1088.   }
  1089.  
  1090.  
  1091.   if (filenum == GRABBED) {
  1092.     filename[0] = '\0';  basefname[0] = '\0';  fullname = "";
  1093.     LoadGrab();
  1094.     goto GOTIMAGE;
  1095.   }
  1096.  
  1097.  
  1098.   if (filenum != LOADPIC) {
  1099.     if (filenum >= nList.nstr && filenum < 0) goto FAILED;
  1100.     curname = filenum;
  1101.     nList.selected = curname;
  1102.     ScrollToCurrent(&nList);  /* have scrl/list show current */
  1103.     XFlush(theDisp);    /* update NOW */
  1104.   }
  1105.  
  1106.   /* clear any old error messages */
  1107.  
  1108.   formatStr[0] = '\0';
  1109.   SetISTR(ISTR_INFO,"");
  1110.   SetISTR(ISTR_WARNING,"");
  1111.   infoMode = INF_STR;
  1112.  
  1113.   /* set up fullname and basefname */
  1114.  
  1115.   if (filenum == LOADPIC) {
  1116.     fullname = GetDirFName();
  1117.     if (fullname[0] == '~') {
  1118.       strcpy(globnm, fullname);
  1119.       Globify(globnm);
  1120.       fullname = globnm;
  1121.     }
  1122.     else if (ISPIPE(fullname[0])) {    /* read from a pipe. */
  1123.       strcpy(filename, fullname);
  1124.       if (readpipe(fullname, filename)) goto FAILED;
  1125.       frompipe = 1;
  1126.     }
  1127.   }
  1128.   else fullname = namelist[filenum];
  1129.  
  1130.  
  1131.   /* compute basefname */
  1132.   tmp = rindex(fullname,'/');
  1133.   if (!tmp) tmp = fullname; else tmp++;
  1134.   strcpy(basefname,tmp);
  1135.  
  1136.  
  1137.   if (filenum == LOADPIC && ISPIPE(fullname[0])) {
  1138.     /* if we're reading from a pipe, 'filename' will have the /tmp/xvXXXXXX
  1139.        filename, and we can skip a lot of stuff:  (such as dealing with
  1140.        compressed files, prepending 'initpath' to relative paths, dealing
  1141.        with reading from stdin */
  1142.  
  1143.     /* at this point, fullname = "! do some commands",
  1144.                       filename = "/tmp/xv123456",
  1145.           and basefname= "xv123456" */
  1146.   }
  1147.  
  1148.   else {
  1149. #ifndef VMS
  1150.     if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0) 
  1151.       basefname[strlen(basefname)-2]='\0';     /* chop off .Z, if any */
  1152. #endif
  1153.  
  1154.     /* if fullname doesn't start with a '/' (ie, it's a relative path), 
  1155.        (and it's not LOADPIC and it's not the special case '<stdin>') 
  1156.        prepend 'initpath' to it */
  1157.     
  1158.     if (filenum != LOADPIC && fullname[0] != '/' && 
  1159.     strcmp(fullname,STDINSTR)!=0) {
  1160.       char *tmp;
  1161.  
  1162. #ifndef VMS
  1163.       tmp = (char *) malloc(strlen(fullname) + strlen(initpath) + 2);
  1164.       if (!tmp) FatalError("malloc 'filename' failed");
  1165.       sprintf(tmp,"%s/%s", initpath, fullname);
  1166. #else  /* it is VMS */
  1167.       tmp = (char *) malloc(strlen(fullname) + 2);
  1168.       if (!tmp) FatalError("malloc 'filename' failed");
  1169.       sprintf(tmp,"%s", fullname);
  1170. #endif
  1171.  
  1172.       fullname = tmp;
  1173.       freename = 1;
  1174.     }
  1175.     
  1176.  
  1177.     /* uncompress if it's a .Z file */
  1178.  
  1179.     i = strlen(fullname);
  1180. #ifndef VMS
  1181.     if (i>2 && strcmp(fullname+i-2,".Z")==0) {
  1182.       sprintf(filename,"%s/xvXXXXXX",tmpdir);
  1183.       mktemp(filename);
  1184.       sprintf(str,"%s -c %s >%s",UNCOMPRESS,fullname,filename);
  1185.       SetISTR(ISTR_INFO,"Uncompressing '%s'...",basefname);
  1186.       if (system(str)) {
  1187.     SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basefname);
  1188.     Warning();
  1189.     goto FAILED;
  1190.       }
  1191.       WaitCursor();
  1192.     }
  1193.     else strcpy(filename,fullname);
  1194.  
  1195. #else  /* it is VMS */
  1196.  
  1197.     tmp = strstr(basefname,".Z");
  1198.     if (!tmp) tmp = strstr(basefname,".z");
  1199.  
  1200. #ifdef HAVE_LZW
  1201.     if (!tmp) tmp = strstr(basefname,"_Z");
  1202.     if (!tmp) tmp = strstr(basefname,"_z");
  1203. #else
  1204.     if (tmp) *tmp = '\0';
  1205. #endif
  1206.  
  1207.     if (i>2 && tmp) {
  1208.       strcpy(filename,"Sys$Disk:[]xvXXXXXX");
  1209.       mktemp(filename);
  1210.  
  1211. #ifdef HAVE_LZW
  1212.       sprintf(str,"%s %s %s", UNCOMPRESS, basefname, filename);
  1213. #else
  1214.       sprintf(str,"%s %s", UNCOMPRESS, basefname);
  1215. #endif
  1216.  
  1217.       if (!system(str)) {
  1218.     SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basefname);
  1219.     Warning();
  1220.     goto FAILED;
  1221.       }
  1222.  
  1223. #ifndef HAVE_LZW
  1224.       sprintf(str,"Rename %s %s", basefname, filename);
  1225.       SetISTR(ISTR_INFO,"Renaming '%s'...",fullname);
  1226.       if (!system(str)) {
  1227.     SetISTR(ISTR_INFO,"Unable to rename '%s'.", fullname);
  1228.     Warning();
  1229.     goto FAILED;
  1230.       }
  1231. #endif /* HAVE_LZW */
  1232.  
  1233.       WaitCursor();
  1234.     }
  1235.     else strcpy(filename,fullname);
  1236.  
  1237. #endif /* not VMS */
  1238.  
  1239.     
  1240.     
  1241.     /* if the file is stdio, write it out to a temp file */
  1242.     if (strcmp(filename,STDINSTR)==0) {
  1243.       FILE *fp;
  1244.  
  1245. #ifndef VMS      
  1246.       sprintf(filename,"%s/xvXXXXXX",tmpdir);
  1247. #else /* it is VMS */
  1248.       sprintf(filename, "Sys$Disk:[]xvXXXXXX");
  1249. #endif
  1250.       mktemp(filename);
  1251.       
  1252.       fp = fopen(filename,WRITE_BINARY);
  1253.       if (!fp) FatalError("openPic(): can't write temporary file");
  1254.     
  1255.       while ( (i=getchar()) != EOF) putc(i,fp);
  1256.       fclose(fp);
  1257.     }
  1258.   }
  1259.  
  1260.  
  1261.   /* now, try to determine what type of file we've got by reading the
  1262.      first couple bytes and looking for a Magic Number */
  1263.  
  1264. #ifndef VMS
  1265.   fp=fopen(filename,READ_BINARY);
  1266. #else   /* it is VMS */
  1267.   /* Open with optional arguments to force stream access in order to
  1268.      get around problems with stream_CR created by pathworks (mac) */ 
  1269.   fp=fopen (filename,"rb","ctx=stm");
  1270. #endif
  1271.  
  1272.   if (!fp) {
  1273.     static char *foo[] = { "\nBummer!" };
  1274.     char  str[512];
  1275.     sprintf(str,"Can't open file '%s'\n\n  %s.",filename,
  1276. #ifndef VMS
  1277.         sys_errlist[errno]
  1278. #else
  1279.     strerror(errno, vaxc$errno)
  1280. #endif
  1281.         );
  1282.  
  1283.     PopUp(str, foo, 1);
  1284.     goto FAILED;
  1285.   }
  1286.  
  1287.   fread(magicno,8,1,fp);  
  1288.   fclose(fp);
  1289.  
  1290.   filetype = UNKNOWN;
  1291.   if (strncmp((char *) magicno,"GIF87a",6)==0 ||
  1292.       strncmp((char *) magicno,"GIF89a",6)==0) filetype = GIF;
  1293.  
  1294.   else if (strncmp((char *) magicno,"VIEW",4)==0 ||
  1295.        strncmp((char *) magicno,"WEIV",4)==0) filetype = PM;
  1296.  
  1297.   else if (magicno[0] == 'P' && magicno[1]>='1' && 
  1298.        magicno[1]<='6') filetype = PBM;
  1299.  
  1300.   else if (strncmp((char *) magicno,"#define",7)==0) filetype = XBM;
  1301.  
  1302.   else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
  1303.        magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) filetype = SUNRAS;
  1304.  
  1305.   else if (magicno[0]==0x52 && magicno[1]==0xcc) filetype = UTAHRLE;
  1306.  
  1307. #ifdef HAVE_JPEG
  1308.   else if (magicno[0]==0xff && magicno[1]==0xd8 && 
  1309.        magicno[2]==0xff) filetype = JFIF;
  1310. #endif
  1311.  
  1312. #ifdef HAVE_TIFF
  1313.   else if ((magicno[0]=='M' && magicno[1]=='M') ||
  1314.        (magicno[0]=='I' && magicno[1]=='I')) filetype = TIFF;
  1315. #endif
  1316.  
  1317. #ifdef HAVE_PDS
  1318.   else if (strncmp((char *) magicno,  "NJPL1I00",8)==0 || /* fixed-len pds */
  1319.        strncmp((char *) magicno+2,"NJPL1I",  6)==0 || /* vger+other pds */
  1320.            strncmp((char *) magicno,  "CCSD3ZF", 7)==0 || /* vikng pds browse*/
  1321.        strncmp((char *) magicno+2,"CCSD3Z",  6)==0 || /* vik. huffman pds*/
  1322.        strncmp((char *) magicno,  "LBLSIZE=",8)==0)   /* vicar */
  1323.       filetype = PDSVICAR;
  1324. #endif
  1325.  
  1326.  
  1327.   if (filetype == UNKNOWN) {
  1328.     SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basefname);
  1329.     Warning();
  1330.     goto FAILED;
  1331.   }
  1332.  
  1333.  
  1334.   SetISTR(ISTR_INFO,"Loading...");
  1335.  
  1336.   switch (filetype) {
  1337.   case GIF:         i = LoadGIF(filename,ncols);     break;
  1338.   case PM:          i = LoadPM (filename,ncols);     break;
  1339.   case PBM:         i = LoadPBM(filename,ncols);     break;
  1340.   case XBM:         i = LoadXBM(filename,ncols);     break;
  1341.   case SUNRAS:      i = LoadSunRas(filename, ncols); break;
  1342.   case UTAHRLE:     i = LoadRLE(filename, ncols);    break;
  1343.  
  1344. #ifdef HAVE_JPEG
  1345.   case JFIF:        i = LoadJFIF(filename, ncols);   break;
  1346. #endif
  1347.  
  1348. #ifdef HAVE_TIFF
  1349.   case TIFF:        i = LoadTIFF(filename, ncols);   break;
  1350. #endif
  1351.  
  1352. #ifdef HAVE_PDS
  1353.   case PDSVICAR:    i = LoadPDS(filename, ncols);    break;
  1354. #endif
  1355.   }
  1356.  
  1357.  
  1358.   WaitCursor();
  1359.  
  1360.   if (i) {
  1361.     SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename);
  1362.     Warning();
  1363.     goto FAILED;
  1364.   }
  1365.  
  1366.   if (pWIDE==0 || pHIGH==0) {  /* shouldn't happen, but let's be safe */
  1367.     SetISTR(ISTR_INFO,"Image size '0x0' not allowed.");
  1368.     Warning();
  1369.     goto FAILED;
  1370.   }
  1371.  
  1372.     
  1373.  GOTIMAGE:
  1374.   /* successfully read this picture.  No failures from here on out */
  1375.  
  1376.   /* stick this file in the 'ctrlW' name list */
  1377.   if (filenum == LOADPIC && !frompipe) stickInList();
  1378.  
  1379.   /* clear old image WINDOW before we start dicking with colors... */
  1380.   if (mainW && !useroot && clearonload &&
  1381.       (theVisual->class == PseudoColor || theVisual->class == GrayScale)) {
  1382.     XClearArea(theDisp, mainW, 0, 0, eWIDE, eHIGH, True);
  1383.     XFlush(theDisp);
  1384.   }
  1385.  
  1386.   if (!browseCB.val && filenum == LOADPIC) DirBox(0);   /* close the DirBox */
  1387.  
  1388.  
  1389.   /* if we read a /tmp file, delete it.  won't be needing it any more */
  1390.   if (strcmp(fullname,filename)!=0) unlink(filename);
  1391.  
  1392.  
  1393.   SetISTR(ISTR_INFO,formatStr);
  1394.     
  1395.   SetInfoMode(INF_PART);
  1396.   SetISTR(ISTR_FILENAME, (filenum==DFLTPIC || filenum==GRABBED || frompipe)
  1397.                        ? "<none>" : basefname);
  1398.  
  1399.   SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
  1400.   SetISTR(ISTR_COLOR,"");
  1401.  
  1402.   /* adjust button in/activity */
  1403.   BTSetActive(&but[BCROP],0);  /* new picture, draw no cropping rectangle */
  1404.   BTSetActive(&but[BUNCROP], 0);
  1405.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  1406.   BTSetActive(&but[BPREV], (curname>0));
  1407.  
  1408.  
  1409.   normFact = 1;  nw = pWIDE;  nh = pHIGH;
  1410.   /* if pic is larger than screen, half picture until it fits on screen */
  1411.   while (nw > maxWIDE || nh > maxHIGH) {
  1412.     nw = nw / 2;  
  1413.     nh = nh / 2;
  1414.     normFact = normFact * 2;
  1415.   }
  1416.  
  1417.   if (normFact != 1) {
  1418.     char tstr[128];
  1419.     tmp = GetISTR(ISTR_WARNING);
  1420.     if (strlen(tmp)>0) sprintf(tstr, "%s  Shrunk %dX.", tmp, normFact);
  1421.                   else sprintf(tstr, "Shrunk %dX.", normFact);
  1422.     SetISTR(ISTR_WARNING,tstr);
  1423.   }
  1424.  
  1425.   /* expand:  if expansion is negative, treat it as a reciprocal */
  1426.   if (expand < 0.0) { eWIDE=(int)(pWIDE/-expand);  eHIGH=(int)(pHIGH/-expand); }
  1427.                else { eWIDE=(int)(pWIDE* expand);  eHIGH=(int)(pHIGH* expand); }
  1428.  
  1429.   if (eWIDE>maxWIDE || eHIGH>maxHIGH) {
  1430.     eWIDE = eWIDE / normFact;  eHIGH = eHIGH / normFact;
  1431.   }
  1432.  
  1433.  
  1434.   if (useroot) {
  1435.     int i,x,y;  unsigned int w,h;
  1436.     i = XParseGeometry(maingeom,&x,&y,&w,&h);
  1437.     if (i&WidthValue)  eWIDE = w;
  1438.     if (i&HeightValue) eHIGH = h;
  1439.     RANGE(eWIDE,1,maxWIDE);  RANGE(eHIGH,1,maxHIGH);
  1440.  
  1441.     /* handle case where they only specified width *or* height */
  1442.     if (( i&WidthValue && ~i&HeightValue) ||
  1443.     (~i&WidthValue &&  i&HeightValue)) {
  1444.  
  1445.       if (i&WidthValue) { eHIGH = (pHIGH * eWIDE) / pWIDE; }
  1446.                    else { eWIDE = (pWIDE * eHIGH) / pHIGH; }
  1447.  
  1448.       RANGE(eWIDE,1,maxWIDE);  RANGE(eHIGH,1,maxHIGH);
  1449.     }
  1450.  
  1451.     if (rootMode == RM_TILE || rootMode == RM_IMIRROR) {
  1452.       /* make picture size a divisor of the rootW size.  round down */
  1453.       i = (dispWIDE + eWIDE-1) / eWIDE;   eWIDE = (dispWIDE + i-1) / i;
  1454.       i = (dispHIGH + eHIGH-1) / eHIGH;   eHIGH = (dispHIGH + i-1) / i;
  1455.     }
  1456.   }
  1457.  
  1458.   cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;  cXOFF = cYOFF = 0;
  1459.   SetCropString(but[BCROP].active);
  1460.  
  1461.   if (automax) { 
  1462.     eWIDE = dispWIDE;  eHIGH = dispHIGH;
  1463.     if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  1464.   }
  1465.  
  1466.   if (useroot) {
  1467.     mainW = vrootW;
  1468.  
  1469.     if ((theVisual->class == PseudoColor || theVisual->class == GrayScale)
  1470.     && clearonload) {
  1471.       /* clear old root pixmap before doing the 'alloc colors scene' 
  1472.      to avoid annoying 'rainbow' effect as colors are realloced
  1473.      (unless we said '-noresetroot') */
  1474.       ClearRoot();
  1475.     }
  1476.   }
  1477.  
  1478.  
  1479.   SortColormap();
  1480.  
  1481.   /* see if image is a b/w bitmap.  If so, use '-black' and '-white' colors */
  1482.   if (numcols == 2) {
  1483.     if ((r[0] == g[0] && r[0] == b[0] && r[0] == 255) &&
  1484.     (r[1] == g[1] && r[1] == b[1] && r[1] ==   0)) {  /* 0=wht, 1=blk */
  1485.       r[0] = (whtRGB>>16)&0xff;  g[0] = (whtRGB>>8)&0xff;  b[0] = whtRGB&0xff;
  1486.       r[1] = (blkRGB>>16)&0xff;  g[1] = (blkRGB>>8)&0xff;  b[1] = blkRGB&0xff;
  1487.     }
  1488.     else if ((r[0] == g[0] && r[0] == b[0] && r[0] ==   0) &&
  1489.          (r[1] == g[1] && r[1] == b[1] && r[1] == 255)) { /*0=blk, 1=wht*/
  1490.       r[0] = (blkRGB>>16)&0xff;  g[0] = (blkRGB>>8)&0xff;  b[0] = blkRGB&0xff;
  1491.       r[1] = (whtRGB>>16)&0xff;  g[1] = (whtRGB>>8)&0xff;  b[1] = whtRGB&0xff;
  1492.     }
  1493.   }
  1494.       
  1495.  
  1496.   /* reverse image, if desired */
  1497.   if (revvideo) {
  1498.     for (i=0; i<numcols; i++) {
  1499.       r[i] = 255 - r[i];
  1500.       g[i] = 255 - g[i];
  1501.       b[i] = 255 - b[i];
  1502.     }
  1503.   }
  1504.  
  1505.   /* save the desired RGB colormap (before dicking with it) */
  1506.   for (i=0; i<numcols; i++) { 
  1507.     rorg[i] = rcmap[i] = r[i];  
  1508.     gorg[i] = gcmap[i] = g[i];  
  1509.     borg[i] = bcmap[i] = b[i];  
  1510.   }
  1511.  
  1512.   NewCMap();
  1513.   GammifyColors();
  1514.  
  1515.   WaitCursor();
  1516.   if (rwcolor) AllocRWColors();  else AllocColors();
  1517.   ChangeEC(0);
  1518.  
  1519.   WaitCursor();
  1520.   smoothResize(eWIDE, eHIGH);
  1521.  
  1522.   WaitCursor();
  1523.   HandleDispMode();   /* create root pic, or mainW, depending... */
  1524.     
  1525.   if (LocalCmap) {
  1526.     XSetWindowAttributes xswa;
  1527.     if (!ninstall) XInstallColormap(theDisp,LocalCmap);
  1528.     xswa.colormap = LocalCmap;
  1529.     XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
  1530.     if (cmapInGam) XChangeWindowAttributes(theDisp,gamW,CWColormap,&xswa);
  1531.   }
  1532.  
  1533.   tmp = GetISTR(ISTR_COLOR);
  1534.   SetISTR(ISTR_INFO,"%s  %s",formatStr, tmp);
  1535.     
  1536.   SetInfoMode(INF_FULL);
  1537.   if (freename) free(fullname);
  1538.  
  1539.   if (autocrop) AutoCrop();
  1540.  
  1541.   SetCursors(-1);
  1542.  
  1543.   if (dirUp!=BLOAD) {
  1544.     /* put current filename into the 'save-as' filename */
  1545.     if      (strcmp(filename,STDINSTR)==0)   SetDirFName("stdin");
  1546.     else if (frompipe || filenum == LOADPIC || filenum == GRABBED ||
  1547.          filenum == DFLTPIC) {}             /* leave it alone */
  1548.     else SetDirFName(basefname);
  1549.   }
  1550.  
  1551.  
  1552.   /* since we're now using BitGravity to keep parts of the image window
  1553.      valid when the window is resized, we have to force an expose event
  1554.      on the *previous* size of the window, as this portion of the new
  1555.      window will *not* be given an expose event
  1556.  
  1557.      UNLESS the window hasn't changed size at all, in which case an
  1558.      appropriate expose event will be generated by CreateMainWindow().
  1559.  
  1560.      Yech! */
  1561.  
  1562.   if (mainW && !useroot && !clearonload && oldeWIDE>0 && oldeHIGH>0 &&
  1563.       (oldeWIDE != eWIDE || oldeHIGH != eHIGH) )
  1564.     GenExpose(mainW, 0, 0, oldeWIDE, oldeHIGH);
  1565.  
  1566.   return 1;
  1567.  
  1568.   
  1569.  FAILED:
  1570.   SetCursors(-1);
  1571.   SetInfoMode(INF_STR);
  1572.   if (strcmp(fullname,filename)!=0) unlink(filename);   /* kill /tmp file */
  1573.   if (freename) free(fullname);
  1574.   return 0;
  1575. }
  1576.  
  1577.  
  1578. /***********************************/
  1579. static int readpipe(cmd, fname)
  1580.      char *cmd, *fname;
  1581. {
  1582.   /* cmd is something like: "! bggen 100 0 0"
  1583.    *
  1584.    * runs command (with "> /tmp/xv******" appended).  
  1585.    * returns "/tmp/xv******" in fname
  1586.    * returns '0' if everything's cool, '1' on error
  1587.    */
  1588.  
  1589.   char fullcmd[512], tmpname[20], str[512];
  1590.   int i;
  1591.  
  1592.   if (!cmd || strlen(cmd)<2) return 1;
  1593.  
  1594.   sprintf(tmpname,"%s/xvXXXXXX", tmpdir);
  1595.   mktemp(tmpname);
  1596.   if (tmpname[0] == '\0') {   /* mktemp() blew up */
  1597.     static char *foo[] = {"\nHow unlikely!"};
  1598.     sprintf(str,"Unable to create temporary filename.");
  1599.     PopUp(str, foo, 1);
  1600.     return 1;
  1601.   }
  1602.  
  1603.   /* build command */
  1604.   strcpy(fullcmd, cmd+1);  /* skip the leading '!' character in cmd */
  1605.   strcat(fullcmd, " > ");
  1606.   strcat(fullcmd, tmpname);
  1607.  
  1608.   /* execute the command */
  1609.   sprintf(str, "Doing command: '%s'", fullcmd);
  1610.   OpenAlert(str);
  1611.   i = system(fullcmd);
  1612.   if (i) {
  1613.     static char *foo[] = { "\nThat Sucks!" };
  1614.     sprintf(str, "Unable to complete command:\n  %s\n\n  exit status: %d",
  1615.         fullcmd, i);
  1616.     CloseAlert();
  1617.     PopUp(str, foo, 1);
  1618.     unlink(tmpname);      /* just in case it was created */
  1619.     return 1;
  1620.   }
  1621.  
  1622.   CloseAlert();
  1623.   strcpy(fname, tmpname);
  1624.   return 0;
  1625. }
  1626.  
  1627.  
  1628. /***********************************/
  1629. static void closePic()
  1630. {
  1631.   /* kill all resources used for this picture.
  1632.      this would include the window, any allocated colors, pic, epic, 
  1633.      theImage, etc. */
  1634.  
  1635.   if (!useroot) {
  1636.     /* turn off configure events */
  1637.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  1638.          | ButtonPressMask | KeyReleaseMask
  1639.          | EnterWindowMask | LeaveWindowMask);
  1640.   }
  1641.  
  1642.  
  1643.   FreeAllColors();
  1644.  
  1645.  
  1646.   if (epic != cpic && epic != NULL) free(epic);
  1647.   if (cpic !=  pic && cpic != NULL) free(cpic);
  1648.   if (pic != NULL) free(pic);
  1649.   xvDestroyImage(theImage);   theImage = NULL;
  1650.   pic = epic = cpic = NULL;
  1651.  
  1652.   SetInfoMode(INF_STR);
  1653. }
  1654.  
  1655.  
  1656.  
  1657.  
  1658.  
  1659.  
  1660.  
  1661. /****************/
  1662. static void OpenFirstPic()
  1663. /****************/
  1664. {
  1665.   int i;
  1666.  
  1667.   if (!numnames) {  openPic(DFLTPIC);  return; }
  1668.  
  1669.   for (i=0; i<numnames; i++) {
  1670.     if (openPic(i)) return;    /* success */
  1671.   }
  1672.  
  1673.   if (numnames>1) FatalError("couldn't open any pictures");
  1674.   else Quit(-1);
  1675. }
  1676.  
  1677.  
  1678. /****************/
  1679. static void OpenNextPic()
  1680. /****************/
  1681. {
  1682.   int i;
  1683.  
  1684.   for (i=curname+1; i<numnames; i++) {
  1685.     if (openPic(i)) return;    /* success */
  1686.   }
  1687.  
  1688.   openPic(DFLTPIC);
  1689. }
  1690.  
  1691.  
  1692. /****************/
  1693. static void OpenNextQuit()
  1694. /****************/
  1695. {
  1696.   int i;
  1697.  
  1698.   for (i=curname+1; i<numnames; i++) {
  1699.     if (openPic(i)) return;    /* success */
  1700.   }
  1701.  
  1702.   Quit(0);
  1703. }
  1704.  
  1705.  
  1706. /****************/
  1707. static void OpenNextLoop()
  1708. /****************/
  1709. {
  1710.   int i,j;
  1711.  
  1712.   j = 0;
  1713.   while (1) {
  1714.     for (i=curname+1; i<numnames; i++) {  /* load next picture */
  1715.       if (openPic(i)) return;
  1716.     }
  1717.     curname = -1;                         /* back to first in list */
  1718.     if (j) break;                         /* we're in a 'failure loop' */
  1719.     j++;
  1720.   }
  1721.  
  1722.   openPic(DFLTPIC);
  1723. }
  1724.  
  1725.  
  1726. /****************/
  1727. static void OpenPrevPic()
  1728. /****************/
  1729. {
  1730.   int i;
  1731.  
  1732.   for (i=curname-1; i>=0; i--) {
  1733.     if (openPic(i)) return;    /* success */
  1734.   }
  1735.  
  1736.   openPic(DFLTPIC);
  1737. }
  1738.  
  1739.  
  1740. /****************/
  1741. static void OpenNamedPic()
  1742. /****************/
  1743. {
  1744.   if (!openPic(LOADPIC)) openPic(DFLTPIC);
  1745. }
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751. /****************/
  1752. static void MainLoop()
  1753. /****************/
  1754. {
  1755.   /* search forward until we manage to display a picture, 
  1756.      then call EventLoop.  EventLoop will eventually return 
  1757.      NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */
  1758.  
  1759.   int i;
  1760.  
  1761.   OpenFirstPic();   /* find first displayable picture, exit if none */
  1762.  
  1763.   if (useroot && autoquit) Quit(0);
  1764.  
  1765.   while ((i=EventLoop()) != QUIT) {
  1766.     if      (i==NEXTPIC && curname<numnames-1)  { closePic(); OpenNextPic(); }
  1767.     else if (i==PREVPIC && curname>0)  { closePic(); OpenPrevPic(); }
  1768.     else if (i==NEXTQUIT) { closePic(); OpenNextQuit(); }
  1769.     else if (i==NEXTLOOP) { closePic(); OpenNextLoop(); }
  1770.     else if (i==LOADPIC)  { closePic(); OpenNamedPic(); }
  1771.  
  1772.     else if (i==DELETE)   {
  1773.       closePic();
  1774.       if (nList.nstr == 0 && !keeparound) Quit(0);
  1775.  
  1776.       if (curname >= 0 && curname < numnames) {   /* there's a selection */
  1777.     if (!openPic(curname)) openPic(DFLTPIC);
  1778.       }
  1779.       else openPic(DFLTPIC);
  1780.     }
  1781.  
  1782.     else if (i==GRABBED)   {
  1783.       closePic();
  1784.       if (!openPic(GRABBED)) openPic(DFLTPIC);
  1785.     }
  1786.  
  1787.     else if (i>=0) {
  1788.       closePic();
  1789.       if (!openPic(i)) openPic(DFLTPIC);
  1790.     }
  1791.  
  1792.   }
  1793. }
  1794.  
  1795.  
  1796.  
  1797. /***********************************/
  1798. static void CreateMainWindow(geom,name)
  1799.      char *geom, *name;
  1800. {
  1801.   XSetWindowAttributes xswa;
  1802.   unsigned int         xswamask;
  1803.   XWindowAttributes    xwa;
  1804.   XWMHints             xwmh;
  1805.   XSizeHints           hints;
  1806.   XClassHint           classh;
  1807.   int                  i,x,y,ew,eh;
  1808.   unsigned int         w,h;
  1809.   char                 winname[128], iconname[128];
  1810.  
  1811.   /*
  1812.    * this function mainly deals with parsing the geometry spec correctly.
  1813.    * More trouble than it should be, and probably more trouble than
  1814.    * it has to be, but who can tell these days, what with all those
  1815.    * Widget-usin' Weenies out there...
  1816.    */
  1817.  
  1818.   ew = eWIDE;  eh = eHIGH;
  1819.   x = y = w = h = 1;
  1820.   i = XParseGeometry(geom,&x,&y,&w,&h);
  1821.  
  1822.   if (i&WidthValue)  eWIDE = w;
  1823.   if (i&HeightValue) eHIGH = h;
  1824.  
  1825.   /* handle case where they only specified width *or* height */
  1826.   if (( i&WidthValue && ~i&HeightValue) ||
  1827.       (~i&WidthValue &&  i&HeightValue)) {
  1828.     
  1829.     if (i&WidthValue) { eHIGH = (pHIGH * eWIDE) / pWIDE; }
  1830.                  else { eWIDE = (pWIDE * eHIGH) / pHIGH; }
  1831.   }
  1832.  
  1833.   if (eWIDE > maxWIDE || eHIGH > maxHIGH) {
  1834.     eWIDE = eWIDE / normFact;
  1835.     eHIGH = eHIGH / normFact;
  1836.   }
  1837.   if (eWIDE < 1) eWIDE = 1;
  1838.   if (eHIGH < 1) eHIGH = 1;
  1839.  
  1840.   if (fixedaspect && i&WidthValue && i&HeightValue) 
  1841.     FixAspect(0,&eWIDE,&eHIGH);
  1842.   else if (i&WidthValue && i&HeightValue) 
  1843.     { RANGE(eWIDE,1,maxWIDE);  RANGE(eHIGH,1,maxHIGH); }
  1844.   else FixAspect(1,&eWIDE,&eHIGH);
  1845.  
  1846.  
  1847.   hints.flags = 0;
  1848.   if ((i&XValue || i&YValue)) hints.flags = USPosition;
  1849.  
  1850.   if (i&XValue && i&XNegative) x = vrWIDE - eWIDE - abs(x);
  1851.   if (i&YValue && i&YNegative) y = vrHIGH - eHIGH - abs(y);
  1852.  
  1853.   if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE;   /* keep on screen */
  1854.   if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH;
  1855.  
  1856.   if (eWIDE < 1) eWIDE = 1;
  1857.   if (eHIGH < 1) eHIGH = 1;
  1858.  
  1859. #define VROOT_TRANS
  1860. #ifdef VROOT_TRANS
  1861.   if (vrootW != rootW) { /* virtual window manager running */
  1862.     int x1,y1;
  1863.     Window child;
  1864.     XTranslateCoordinates(theDisp, rootW, vrootW, x, y, &x1, &y1, &child);
  1865.     if (DEBUG) fprintf(stderr,"translate:  %d,%d -> %d,%d\n",x,y,x1,y1);
  1866.     x = x1;  y = y1;
  1867.   }
  1868. #endif
  1869.  
  1870.   hints.x = x;                  hints.y = y;
  1871.   hints.width = eWIDE;          hints.height = eHIGH;
  1872.   hints.max_width  = maxWIDE;   hints.max_height = maxHIGH;
  1873.   hints.flags |= USSize | PMaxSize;
  1874.  
  1875.   xswa.bit_gravity = StaticGravity;
  1876.   xswa.background_pixel = bg;
  1877.   xswa.border_pixel     = fg;
  1878.   xswa.colormap         = theCmap;
  1879.   xswamask = CWBackPixel | CWBorderPixel | CWColormap;
  1880.   if (!clearonload) xswamask |= CWBitGravity;
  1881.  
  1882.   if (mainW) {
  1883.     GetWindowPos(&xwa);
  1884.  
  1885.     /* generate an expose event if window hasn't changed size */
  1886.     if (xwa.width == eWIDE && xwa.height == eHIGH) 
  1887.       GenExpose(mainW, 0,0, eWIDE, eHIGH);  
  1888.  
  1889.     xwa.width = eWIDE;  xwa.height = eHIGH;
  1890.     SetWindowPos(&xwa);
  1891.     hints.flags = PSize | PMaxSize;
  1892.   } 
  1893.  
  1894.   else {
  1895.     mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,bwidth,dispDEEP,
  1896.               InputOutput, theVisual, xswamask, &xswa);
  1897.     if (!mainW) FatalError("can't create window!");
  1898.  
  1899.     XSetTransientForHint(theDisp, psW, mainW);
  1900.  
  1901. #ifdef HAVE_JPEG
  1902.     XSetTransientForHint(theDisp, jpegW, mainW);
  1903. #endif
  1904.  
  1905. #ifdef HAVE_TIFF
  1906.     XSetTransientForHint(theDisp, tiffW, mainW);
  1907. #endif
  1908.   }
  1909.  
  1910.  
  1911.   if (name[0] == '\0') {
  1912.     sprintf(winname, "xv");
  1913.     sprintf(iconname,"xv");
  1914.   }
  1915.   else {
  1916.     sprintf(winname,"xv %s",name);
  1917.     sprintf(iconname,"%s",name);
  1918.   }
  1919.  
  1920.   XSetStandardProperties(theDisp,mainW,winname,iconname,None,NULL,0,&hints);
  1921.  
  1922.   xwmh.input = True;
  1923.   xwmh.flags = InputHint;
  1924.  
  1925.   if (iconPix) { 
  1926.     xwmh.icon_pixmap = iconPix;  
  1927.     xwmh.icon_mask   = iconmask;  
  1928.     xwmh.flags |= ( IconPixmapHint | IconMaskHint) ;
  1929.   }
  1930.   XSetWMHints(theDisp, mainW, &xwmh);
  1931.  
  1932.   classh.res_name = "xv";
  1933.   classh.res_class = "XVroot";
  1934.   XSetClassHint(theDisp, mainW, &classh);
  1935. }
  1936.  
  1937.  
  1938. /***********************************/
  1939. void FixAspect(grow,w,h)
  1940. int   grow;
  1941. int   *w, *h;
  1942. {
  1943.   /* computes new values of eWIDE and eHIGH which will have aspect ratio
  1944.      'normaspect'.  If 'grow' it will preserve aspect by enlarging, 
  1945.      otherwise, it will shrink to preserve aspect ratio.  
  1946.      Returns these values in 'w' and 'h' */
  1947.  
  1948.   float xr,yr,curaspect,a,exp;
  1949.  
  1950.   *w = eWIDE;  *h = eHIGH;
  1951.  
  1952.   /* xr,yr are expansion factors */
  1953.   xr = ((float) eWIDE) / cWIDE;
  1954.   yr = ((float) eHIGH) / cHIGH;
  1955.   curaspect  = xr / yr;
  1956.  
  1957.   /* if too narrow & shrink, shrink height.  too wide and grow, grow height */
  1958.   if ((curaspect < normaspect && !grow) || 
  1959.       (curaspect > normaspect &&  grow)) {    /* modify height */
  1960.     exp = curaspect / normaspect;
  1961.     *h = (int) (eHIGH * exp + .5);
  1962.   }
  1963.  
  1964.   /* if too narrow & grow, grow width.  too wide and shrink, shrink width */
  1965.   if ((curaspect < normaspect &&  grow) || 
  1966.       (curaspect > normaspect && !grow)) {    /* modify width */
  1967.     exp = normaspect / curaspect;
  1968.     *w = (int) (eWIDE * exp + .5);
  1969.   }
  1970.  
  1971.  
  1972.   /* shrink to fit screen without changing aspect ratio */
  1973.   if (*w>maxWIDE) {
  1974.     int i;
  1975.     a = (float) *w / maxWIDE;
  1976.     *w = maxWIDE;
  1977.     i = (int) (*h / a + .5);        /* avoid freaking some optimizers */
  1978.     *h = i;
  1979.   }
  1980.  
  1981.   if (*h>maxHIGH) {
  1982.     a = (float) *h / maxHIGH;
  1983.     *h = maxHIGH;
  1984.     *w = (int) (*w / a + .5);
  1985.   }
  1986.  
  1987.   if (*w < 1) *w = 1;
  1988.   if (*h < 1) *h = 1;
  1989. }
  1990.  
  1991.  
  1992. /***********************************/
  1993. static void MakeDispNames()
  1994. {
  1995.   int   prelen, n, i, done;
  1996.   char *suffix;
  1997.  
  1998.   suffix = namelist[0];
  1999.   prelen = 0;   /* length of prefix to be removed */
  2000.   n = i = 0;    /* shut up pesky compiler warnings */
  2001.  
  2002.   done = 0;
  2003.   while (!done) {
  2004.     suffix = (char *) strchr(suffix,'/');    /* find next '/' in file name */
  2005.     if (!suffix) break;
  2006.  
  2007.     suffix++;                       /* go past it */
  2008.     n = suffix - namelist[0];
  2009.     for (i=1; i<numnames; i++) {
  2010.       if (strncmp(namelist[0], namelist[i], n)!=0) { done=1; break; }
  2011.     }
  2012.  
  2013.     if (!done) prelen = n;
  2014.   }
  2015.  
  2016.   for (i=0; i<numnames; i++)
  2017.     dispnames[i] = namelist[i] + prelen;
  2018. }
  2019.  
  2020.  
  2021. /***********************************/
  2022. static void stickInList()
  2023. {
  2024.   /* stick current name (from 'load' box) and current working directory
  2025.      into 'namelist' */
  2026.  
  2027.   char *name, *fullname;
  2028.   char cwd[MAXPATHLEN];
  2029.  
  2030.   if (numnames == MAXNAMES) return;  /* full up */
  2031.  
  2032.   name = GetDirFName();
  2033.   if (name[0] != '/') {  /* prepend current working path */
  2034.     GETWD(cwd);
  2035.  
  2036.     fullname = (char *) malloc(strlen(cwd) + strlen(name) + 2);
  2037.     if (!fullname) FatalError("couldn't alloc 'fullname' in stickInList()\n");
  2038.  
  2039.     sprintf(fullname, "%s/%s", cwd, name);
  2040.   }
  2041.  
  2042.   else {                 /* copy name to fullname */
  2043.     fullname = (char *) malloc(strlen(name) + 1);
  2044.     if (!fullname) FatalError("couldn't alloc 'fullname' in stickInList()\n");
  2045.     strcpy(fullname, name);
  2046.   }
  2047.  
  2048.   namelist[numnames] = fullname;
  2049.  
  2050.   /* figure out how much of name can be shown */
  2051.   if (StringWidth(fullname) > (CTRL_LISTW-10)) {   /* has to be truncated */
  2052.     char *tmp;
  2053.     int   prelen = 0;
  2054.  
  2055.     tmp = fullname;
  2056.     while (1) {
  2057.       tmp = (char *) strchr(tmp,'/'); /* find next (forward) '/' in filename */
  2058.       if (!tmp) break;
  2059.  
  2060.       tmp++;                   /* move to char following the '/' */
  2061.       prelen = tmp - fullname;
  2062.       if (StringWidth(tmp) <= (CTRL_LISTW-10)) break;   /* we're cool now */
  2063.     }
  2064.  
  2065.     dispnames[numnames] = fullname + prelen;
  2066.   }
  2067.   else dispnames[numnames] = fullname;
  2068.  
  2069.   numnames++;
  2070.   if (numnames>0) BTSetActive(&but[BDELETE],1);
  2071.  
  2072.  
  2073.   LSNewData(&nList, dispnames, numnames);
  2074.   nList.selected = numnames-1;
  2075.   curname = numnames - 1;
  2076.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  2077.   BTSetActive(&but[BPREV], (curname>0));
  2078.  
  2079.   ScrollToCurrent(&nList);
  2080.   XClearArea(theDisp, ctrlW, 0, 0, 200, 40, True);  /* redraw part of ctrlW */
  2081. }
  2082.  
  2083.  
  2084. /***********************************/
  2085. int DeleteCmd()
  2086. {
  2087.   /* 'delete' button was pressed.  Pop up a dialog box to determine
  2088.      what should be deleted, then do it.
  2089.      returns '1' if THE CURRENTLY VIEWED entry was deleted from the list, 
  2090.      in which case the 'selected' filename on the ctrl list is now 
  2091.      different, and should be auto-loaded, or something */
  2092.  
  2093.   static char *bnames[] = { "\004Disk File", "\nList Entry", "\033Cancel" };
  2094.   char str[512];
  2095.   int  del, i, delnum, rv;
  2096.  
  2097.   /* failsafe */
  2098.   delnum = nList.selected;
  2099.   if (delnum < 0 || delnum >= numnames) return 0;
  2100.  
  2101.   sprintf(str,"What do you wish to delete?\n\n%s%s",
  2102.       "'List Entry' deletes selection from list.\n",
  2103.       "'Disk File' deletes file associated with selection.");
  2104.  
  2105.   del = PopUp(str, bnames, 3);
  2106.   
  2107.   if (del == 2) return 0;   /* cancel */
  2108.   
  2109.   if (del == 0) {           /* 'Disk File' */
  2110.     char *name;
  2111.     if (namelist[delnum][0] != '/') {    /* prepend 'initpath' */
  2112.       name = (char *) malloc(strlen(namelist[delnum]) + strlen(initpath) + 2);
  2113.       if (!name) FatalError("malloc in DeleteCmd failed\n");
  2114.       sprintf(name,"%s/%s", initpath, namelist[delnum]);
  2115.     }
  2116.     else name = namelist[delnum];
  2117.     i = unlink(name);
  2118.     if (i) {
  2119.       static char *foo[] = { "\nPity!" };
  2120.       sprintf(str,"Can't delete file '%s'\n\n  %s.", name, sys_errlist[errno]);
  2121.       PopUp(str, foo, 1);
  2122.       return 0;
  2123.     }
  2124.     LoadCurrentDirectory();   /* just in case we deleted a file in the cwd */
  2125.   }
  2126.  
  2127.  
  2128.   /* remove from list on either 'List Entry' or (successful) 'Disk File' */
  2129.  
  2130.   /* determine if namelist[delnum] needs to be freed or not */
  2131.   for (i=0; i<mainargc && mainargv[i] != namelist[delnum]; i++) ;
  2132.   if (i == mainargc) {  /* not found.  free it */
  2133.     free(namelist[delnum]);
  2134.   }
  2135.  
  2136.   if (delnum != numnames-1) {
  2137.     /* snip out of namelist and dispnames lists */
  2138.     bcopy(&namelist[delnum+1], &namelist[delnum], 
  2139.       (numnames - delnum - 1) * sizeof(namelist[0]));
  2140.  
  2141.     bcopy(&dispnames[delnum+1], &dispnames[delnum], 
  2142.       (numnames - delnum - 1) * sizeof(dispnames[0]));
  2143.   }
  2144.   
  2145.   numnames--;
  2146.   if (numnames==0) BTSetActive(&but[BDELETE],0);
  2147.  
  2148.   nList.nstr = numnames;
  2149.   nList.selected = delnum;
  2150.  
  2151.   if (nList.selected >= numnames) nList.selected = numnames-1;
  2152.   if (nList.selected < 0) nList.selected = 0;
  2153.  
  2154.   SCSetRange(&nList.scrl, 0, numnames - nList.nlines, 
  2155.          nList.scrl.val, nList.nlines-1);
  2156.   ScrollToCurrent(&nList);
  2157.   XClearArea(theDisp, ctrlW, 0, 0, 200, 40, True);  /* redraw part of ctrlW */
  2158.  
  2159.   rv = 0;
  2160.   if (delnum == curname) {      /* deleted the viewed file */
  2161.     curname = nList.selected;
  2162.     rv = 1;                     /* auto-load currently 'selected' filename */
  2163.   }
  2164.   else if (delnum < curname) curname = (curname > 0) ? curname-1 : 0;
  2165.   else if (delnum > curname);
  2166.  
  2167.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  2168.   BTSetActive(&but[BPREV], (curname>0));
  2169.   return rv;
  2170. }
  2171.  
  2172.  
  2173.  
  2174. /***********************************/
  2175. static void smoothResize(w,h)
  2176. {
  2177.   if (autosmooth || normFact != 1) 
  2178.     { eWIDE = w;  eHIGH = h; Smooth(); }
  2179.   else Resize(w,h);
  2180.  
  2181.   if ((autodither || dfltkludge) && !autosmooth && ncols>0)
  2182.     ColorDither(NULL, w,h);
  2183. }
  2184.  
  2185.  
  2186. /***********************************/
  2187. void HandleDispMode()
  2188. {
  2189.   /* handles a change in the display mode (windowed/root).
  2190.      Also, called to do the 'right' thing when opening a picture
  2191.      displays epic, in current size, UNLESS we've selected an 'integer'
  2192.      root tiling thingy, in which case we resize epic appropriately */
  2193.  
  2194.   static int haveoldinfo = 0;
  2195.   static Window            oldMainW;
  2196.   static int               oldPerfect, oldNoglob, oldOwnCmap;
  2197.   static int               hadLocalCmap;
  2198.   static XSizeHints        oldHints;
  2199.   static XWindowAttributes oldXwa;
  2200.   int i;
  2201.   char wnam[128], inam[128];
  2202.  
  2203.   if (dispMB.selected == 0) {        /* windowed */
  2204.     if (useroot && resetroot) ClearRoot();
  2205.  
  2206.     if (mainW == (Window) NULL || useroot) {  /* window not visible */
  2207.       useroot = 0;  
  2208.  
  2209.       if (haveoldinfo) {             /* just remap mainW and resize it */
  2210.     mainW = oldMainW;
  2211.  
  2212.     perfect = oldPerfect;
  2213.     noglob  = oldNoglob;
  2214.     owncmap = oldOwnCmap;
  2215.     if (hadLocalCmap) {          /* use 'perfect' again */
  2216.       FreeAllColors();
  2217.       if (rwcolor) AllocRWColors();  else AllocColors();
  2218.       CreateXImage();
  2219.     }
  2220.  
  2221.     sprintf(wnam,"xv %s",basefname);
  2222.     sprintf(inam,"%s",basefname);
  2223.     XSetStandardProperties(theDisp,mainW,wnam,inam,None,NULL,0,&oldHints);
  2224.  
  2225.     oldXwa.width = eWIDE;  oldXwa.height = eHIGH;
  2226.     SetWindowPos(&oldXwa);
  2227.     XMapWindow(theDisp, mainW);
  2228.       }
  2229.  
  2230.       else {                         /* first time.  need to create mainW */
  2231.     int ew, eh;
  2232.     mainW = (Window) NULL;  ew = eWIDE;  eh = eHIGH;
  2233.     CreateMainWindow(maingeom, basefname);
  2234.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2235.              | StructureNotifyMask | ButtonPressMask
  2236.              | KeyReleaseMask | ColormapChangeMask
  2237.              | EnterWindowMask | LeaveWindowMask );
  2238.  
  2239.     StoreDeleteWindowProp(mainW);
  2240.     XMapWindow(theDisp,mainW);
  2241.  
  2242.     if (ew != eWIDE || eh != eHIGH) smoothResize(ew, eh);
  2243.       }
  2244.     }
  2245.  
  2246.     else {                            /* mainW already visible */
  2247.       int ew, eh;
  2248.       ew = eWIDE;  eh = eHIGH;
  2249.       CreateMainWindow(maingeom, basefname);
  2250.       XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  2251.            | StructureNotifyMask | ButtonPressMask
  2252.            | KeyReleaseMask | ColormapChangeMask
  2253.            | EnterWindowMask | LeaveWindowMask );
  2254.  
  2255.       if (LocalCmap) {                /* AllocColors created local colormap */
  2256.     XSetWindowColormap(theDisp, mainW, LocalCmap);
  2257.       }
  2258.       if (ew != eWIDE || eh != eHIGH) smoothResize(ew, eh);
  2259.     }
  2260.  
  2261.     useroot = 0;
  2262.   }
  2263.  
  2264.  
  2265.  
  2266.   else if (dispMB.selected > 0 && (dispMB.selected <= RM_MAX+1)) {
  2267.     /* a 'root' mode */
  2268.     int ew, eh, regen;
  2269.  
  2270.     regen = 0;
  2271.     if (!useroot) {                  /* have to kill mainW, etc. */
  2272.       /* save current window position */
  2273.       haveoldinfo = 1;
  2274.       oldMainW = mainW;
  2275.       oldPerfect = perfect;
  2276.       oldNoglob = noglob;
  2277.       oldOwnCmap = owncmap;
  2278.  
  2279.       hadLocalCmap = LocalCmap;
  2280.  
  2281.       GetWindowPos(&oldXwa);
  2282.       if (!XGetNormalHints(theDisp, mainW, &oldHints)) oldHints.flags = 0;
  2283.       oldHints.x=oldXwa.x;  oldHints.y=oldXwa.y;  oldHints.flags|=USPosition;
  2284.  
  2285.  
  2286.       perfect = owncmap = 0;         /* can't do -perfect on a root window */
  2287.       noglob = 1;                    /* Phase 3 color alloc's a bad idea too */
  2288.       XUnmapWindow(theDisp, mainW);
  2289.       mainW = vrootW;
  2290.  
  2291.       if (!ctrlUp) {    /* make sure ctrl is up when going to 'root' mode */
  2292.     XWMHints xwmh;
  2293.     xwmh.initial_state = IconicState;
  2294.     xwmh.flags = StateHint;
  2295.     XSetWMHints(theDisp, ctrlW, &xwmh);
  2296.     CtrlBox(1);
  2297.       }
  2298.     }
  2299.       
  2300.     if (LocalCmap) {                 /* we *were* using -perfect */
  2301.       FreeAllColors();
  2302.       if (rwcolor) AllocRWColors();  else AllocColors();
  2303.       regen = 1;
  2304.     }
  2305.     
  2306.  
  2307.     useroot = 1;
  2308.     rootMode = dispMB.selected - 1;
  2309.     ew = eWIDE;  eh = eHIGH;
  2310.  
  2311.     RANGE(ew,1,maxWIDE);  RANGE(eh,1,maxHIGH);
  2312.  
  2313.     if (rootMode == RM_TILE || rootMode == RM_IMIRROR) {
  2314.       /* make picture size a divisor of the rootW size.  round down */
  2315.       i = (dispWIDE + ew-1) / ew;   ew = (dispWIDE + i-1) / i;
  2316.       i = (dispHIGH + eh-1) / eh;   eh = (dispHIGH + i-1) / i;
  2317.     }
  2318.  
  2319.     if (ew != eWIDE || eh != eHIGH) smoothResize(ew, eh);  /* changed size */
  2320.     else {
  2321.       /* didn't regen XImage.  If we were using LocalCmap we have to */
  2322.       if (regen) CreateXImage();                    
  2323.     }
  2324.  
  2325.     KillOldRootInfo();
  2326.     MakeRootPic();
  2327.     SetCursors(-1);
  2328.   }
  2329.  
  2330.   else {
  2331.     fprintf(stderr,"%s:  unknown dispMB value '%d' in HandleDispMode()\n",
  2332.         dispMB.selected);
  2333.   }
  2334. }
  2335.  
  2336. /************************************************************************/
  2337. /* following three rd_* functions swiped from xgraph, by David Harrison */
  2338. /************************************************************************/
  2339.  
  2340. /***********************************/
  2341. /* weikart, Mon Sep  2 18:26:36 1991; convert to lower-care for comparisons: */
  2342. char *lower_str(string)
  2343. char *string;
  2344. {
  2345.   char *p;
  2346.   for (p = string; *p != '\0'; p++)
  2347.     if (isupper(*p)) *p = tolower(*p);
  2348.   return string;
  2349. }
  2350.  
  2351.  
  2352. /***********************************
  2353.  * If XGetDefault finds a DECW$XDEFAULTS.DAT file, it reads it once and saves
  2354.  * the contents for subsequent calls.  It doesn't remember when a lookup
  2355.  * fails, however, and will try to lookup the file again for every XGetDefault
  2356.  * call.  Replace the XGetDefault calls with rd_getdefault, which is more 
  2357.  * intelligent about handling missing DECW$XDEFAULTS.DAT (i.e. most users).
  2358.  */
  2359.  
  2360. static XrmDatabase def_resource;
  2361. static int xrm_initted = 0;
  2362.  
  2363. char *rd_getdefault ( name )
  2364.      char *name;
  2365. {
  2366. #ifndef VMS
  2367.   return XGetDefault (theDisp, PROGNAME, name);
  2368. #else /* it is VMS */
  2369.   char namelist[512], *type;
  2370.   XrmValue value;
  2371.   
  2372.   if ( !xrm_initted ) {
  2373.     xrm_initted = 1;
  2374.     XrmInitialize();
  2375.     def_resource = XrmGetFileDatabase ( "SYS$LOGIN:DECW$XDEFAULTS.DAT" );
  2376.   }
  2377.  
  2378.   if ( def_resource != NULL ) {
  2379.     sprintf ( namelist, "%s.%s", PROGNAME, name );
  2380.     XrmGetResource ( def_resource, namelist, "", &type, &value );
  2381.     return value.addr;
  2382.   }
  2383.   else return NULL;    /* no database */
  2384.   
  2385. #endif
  2386. }
  2387.  
  2388.  
  2389. /***********************************/
  2390. int rd_int(name)
  2391. char *name;
  2392. {
  2393.   /* returns '1' if successful.  result in def_int */
  2394.  
  2395.   def_str = rd_getdefault(name);
  2396.   if (def_str) {
  2397.     if (sscanf(def_str, "%ld", &def_int) == 1) return 1;
  2398.     else {
  2399.       fprintf(stderr, "%s: couldn't read integer value for %s resource\n", 
  2400.           cmd,name);
  2401.       return 0;
  2402.     }
  2403.   }
  2404.   else return 0;
  2405.  
  2406. }
  2407.  
  2408. /***********************************/
  2409. int rd_str(name)
  2410. char *name;
  2411. {
  2412.   /* returns '1' if successful.  result in def_str */
  2413.   
  2414.   def_str = rd_getdefault(name);
  2415.   if (def_str) return 1;
  2416.           else return 0;
  2417.  
  2418. }
  2419.  
  2420.  
  2421. /***********************************/
  2422. int rd_flag(name)
  2423. char *name;
  2424. {
  2425.   /* returns '1' if successful.  result in def_int */
  2426.   
  2427.   char buf[256];
  2428.  
  2429.   def_str = rd_getdefault(name);
  2430.   if (def_str) {
  2431.     strcpy(buf, def_str);
  2432.     lower_str(buf);
  2433.  
  2434.     def_int = (strcmp(buf, "on")==0) || 
  2435.               (strcmp(buf, "1")==0) ||
  2436.           (strcmp(buf, "true")==0) ||
  2437.           (strcmp(buf, "yes")==0);
  2438.     return 1;
  2439.     }
  2440.  
  2441.   else return 0;
  2442. }
  2443.     
  2444.  
  2445. /************************************************************************/
  2446. /* rd_str_cl() written by Dean Elhard  (elhard@system-m.az05.bull.com)  */
  2447. /************************************************************************/
  2448.  
  2449. /* Author's note:
  2450.  *
  2451.  * I build another routine to go along with rd_str, rd_int, and rd_flag, called
  2452.  * rd_str_cl which takes a name and a class string and works with multi-part
  2453.  * names.  The code is not really great because it depends on the resource
  2454.  * database field in the display structure (which is the one XGetResource uses
  2455.  * in X11R5 at least).  It also depends on XGetResource being called first to
  2456.  * initialize the database.  I should have probably rewritten rd_str, rd_int,
  2457.  * and rd_flag to all call XrmGetResource, but I wanted to keep the change as
  2458.  * minimal as possible.  If you want to implement a better fix, I leave that
  2459.  * to you.  Context diffs for the two changed files (xv.c and xvgam.c) follow.
  2460.  */
  2461.  
  2462. int rd_str_cl (name_str, class_str)
  2463.      char *name_str;
  2464.      char *class_str;
  2465. {
  2466.   char     q_name[BUFSIZ];
  2467.   char     q_class[BUFSIZ];
  2468.   char    *type;
  2469.   XrmValue result;
  2470.  
  2471.   strcpy (q_name, PROGNAME);
  2472.   strcat (q_name, ".");
  2473.   strcat (q_name, name_str);
  2474.   
  2475.   strcpy (q_class, "Program");
  2476.   strcat (q_class, ".");
  2477.   strcat (q_class, class_str);
  2478.   
  2479.   (void) XrmGetResource(theDisp->db, q_name, q_class, &type, &result);
  2480.   
  2481.   def_str = result.addr;
  2482.   if (def_str) return (1);
  2483.   else return (0);
  2484. }
  2485.