home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume10 / xv / part09 < prev    next >
Encoding:
Text File  |  1990-12-09  |  62.4 KB  |  2,274 lines

  1. Path: uunet!lll-winken!sun-barr!newstop!exodus!appserv!halibut.cis.upenn.edu
  2. From: bradley@halibut.cis.upenn.edu (John Bradley)
  3. Newsgroups: comp.sources.x
  4. Subject: v10i087: xv - display and manipulate images, Part09/10
  5. Message-ID: <325@appserv.Eng.Sun.COM>
  6. Date: 27 Nov 90 20:08:46 GMT
  7. References: <csx-10i079:xv@uunet.UU.NET>
  8. Sender: news@exodus.Eng.Sun.COM
  9. Lines: 2257
  10. Approved: argv@sun.com
  11.  
  12. Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
  13. Posting-number: Volume 10, Issue 87
  14. Archive-name: xv/part09
  15.  
  16. #!/bin/sh
  17. # to extract, remove the header and type "sh filename"
  18. if `test ! -s ./xv.c`
  19. then
  20. echo "writting ./xv.c"
  21. cat > ./xv.c << '\BARFOO\'
  22. /*
  23.  * xv.c - main section of xv.  X setup, window creation, event loop, etc.
  24.  *
  25.  *  Author:    John Bradley, University of Pennsylvania
  26.  *                (bradley@cis.upenn.edu)
  27.  */
  28.  
  29.  
  30. /*
  31.  * Copyright 1989, 1990 by the University of Pennsylvania
  32.  *
  33.  * Permission to use, copy, and distribute for non-commercial purposes,
  34.  * is hereby granted without fee, providing that the above copyright
  35.  * notice appear in all copies and that both the copyright notice and this
  36.  * permission notice appear in supporting documentation. 
  37.  *
  38.  * The software may be modified for your own purposes, but modified versions
  39.  * may not be distributed.
  40.  *
  41.  * This software is provided "as is" without any express or implied warranty.
  42.  */
  43.  
  44.  
  45. #define MAIN
  46. #define NEEDSTIME    /* for -wait handling in eventloop */
  47. #define NEEDSDIR     /* for value of MAXPATHLEN */
  48.  
  49. #include "xv.h"
  50. #include "bitmaps.h"
  51.  
  52. #include <X11/Xatom.h>
  53.  
  54. /* program needs one of the following fonts.  Trys them in ascending order */
  55. #define FONT1 "-*-lucida-medium-r-*-*-12-*"
  56. #define FONT2 "-*-helvetica-medium-r-*-*-12-*"
  57. #define FONT3 "6x13"
  58.  
  59. /* a mono-spaced font needed for the 'pixel value tracking' feature */
  60. #define MFONT1 "-misc-fixed-medium-r-normal-*-13-*"
  61. #define MFONT2 "8x13"   
  62. #define MFONT3 "-*-courier-medium-r-*-*-12-*"
  63.  
  64. /* things EventLoop() can return (0 and above reserved for 'goto pic#') */
  65. #define QUIT     -1    /* exit immediately  */
  66. #define NEXTPIC  -2    /* goto next picture */
  67. #define PREVPIC  -3    /* goto prev picture */
  68. #define NEXTQUIT -4    /* goto next picture, quit if none (used by 'wait') */
  69.  
  70.  
  71. /* file types that can be read */
  72. #define UNKNOWN 0
  73. #define GIF     1
  74. #define PM      2
  75. #define PBM     3
  76. #define XBM     4
  77.  
  78. static unsigned long rootbg, rootfg;  /* fg/bg for root border */
  79. static int    waitsec = -1;     /* seconds between pics. -1=wait for event */
  80. static int    roottile = 0;     /* resize pic to tile evenly on rootW */
  81. static int    automax  = 0;     /* resize pic to dispWIDE, dispHIGH on open */
  82. static int    autoquit = 0;     /* quit after loading first pic to rootW */
  83. static int    autogamma = 0;    /* perform gamma correction by default */
  84. static int    centerpic = 0;    /* center pic on rootW, instead of tiling */
  85. static int    rootPattern = 0;  /* pattern used for root border */
  86. static char  *maingeom = NULL;
  87. static char   initpath[MAXPATHLEN];
  88. static int    rotatesLeft = 0;
  89. static Atom   __SWM_VROOT = None;
  90.  
  91. /* used in XResource reading... */
  92. static char *def_str;
  93. static int   def_int;
  94.  
  95. /* function pre-definitions */
  96. static void Syntax();
  97. static int  openPic();
  98. static void closePic();
  99. static void OpenFirstPic();
  100. static void OpenNextPic();
  101. static void OpenNextQuit();
  102. static void OpenPrevPic();
  103. static void MainLoop();
  104. static int  EventLoop();
  105. static void CreateMainWindow();
  106. static void FixAspect();
  107. static void GetWindowPos();
  108. static void SetWindowPos();
  109. static void TrackCrop();
  110. static void CropKey();
  111. static void TrackPicValues();
  112. static void MakeDispNames();
  113. static int  Rect();
  114. static int  CheckForConfig();
  115. static Bool IsConfig();
  116. static void SaveRootInfo();
  117. static void KillOldRootInfo();
  118. static int  rd_int();
  119. static int  rd_str();
  120. static int  rd_flag();
  121.  
  122.  
  123.  
  124.  
  125. /*******************************************/
  126. int main(argc, argv)
  127. int   argc;
  128. char *argv[];
  129. /*******************************************/
  130. {
  131.   int   i, imap, ctrlmap, gmap, clrroot;
  132.   char *display, *fname, *whitestr, *blackstr, 
  133.        *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom;
  134.   char *rootfgstr, *rootbgstr;
  135.  
  136.   XColor ecdef;
  137.   Window rootReturn, parentReturn, *children;
  138.   unsigned int numChildren;
  139.  
  140.  
  141.   /*****************************************************/
  142.   /*** variable Initialization                       ***/
  143.   /*****************************************************/
  144.  
  145. #ifdef SYSV
  146.   getcwd(initpath, sizeof(initpath));
  147. #else
  148.   getwd(initpath);
  149. #endif
  150.  
  151.   /* init internal variables */
  152.   display = fname = whitestr = blackstr = NULL;
  153.   fgstr = bgstr = rootfgstr = rootbgstr = NULL;
  154.   pic = epic = cpic = NULL;
  155.   theImage = NULL;
  156.   LocalCmap = 0;
  157.   InitFSDTables();
  158.   cmd = rindex(argv[0],'/');
  159.   if (!cmd) cmd = argv[0]; else cmd++;
  160.  
  161.  
  162.   /* init gamma curve */
  163.   ghand[0].x =   0;  ghand[0].y =   0;
  164.   ghand[1].x =  64;  ghand[1].y =  64;
  165.   ghand[2].x = 192;  ghand[2].y = 192;
  166.   ghand[3].x = 255;  ghand[3].y = 255;
  167.  
  168.   /* init gamma presets */
  169.   SetGPreset(0, 255, 64,192, 192, 64,   0);
  170.   SetGPreset(1,   0, 64,100, 234,255, 255);
  171.   SetGPreset(2,   0, 80, 38, 210,180, 255);
  172.   SetGPreset(3,   0, 40, 92, 235,204, 255);
  173.  
  174.   /* init command-line options flags */
  175.   infogeom = DEFINFOGEOM;  ctrlgeom = DEFCTRLGEOM;  gamgeom = DEFGAMGEOM;
  176.   expand = 1;  ncols = -1;  noglob = 0;  revvideo = 0;  mono = 0;  
  177.   perfect = 0;  ninstall = 0;  fixedaspect = 0;  
  178.   DEBUG = 0;  bwidth = 2;
  179.   useroot = clrroot = noqcheck = rwcolor = fishrunning = 0;
  180.   fish = 0;
  181.  
  182. #ifdef BROKEFREECOLS
  183.   brokeFreeCols = 1;
  184. #else
  185.   brokeFreeCols = 0;
  186. #endif
  187.  
  188.   defaspect = normaspect = 1.0;
  189.  
  190.   mainW = dirW = infoW = ctrlW = gamW = NULL;
  191.   imap = ctrlmap = gmap = 0;
  192.  
  193.   /* init info box variables */
  194.   infoUp = 0;
  195.   infoMode = INF_STR;
  196.   for (i=0; i<NISTR; i++) SetISTR(i,"");
  197.  
  198.   /* init ctrl box variables */
  199.   ctrlUp = 0;
  200.   curname = 0;
  201.  
  202.   gamUp = 0;
  203.  
  204.  
  205.   /*****************************************************/
  206.   /*** X Resource Initialization                     ***/
  207.   /*****************************************************/
  208.  
  209.   /* once through the argument list to find the display name, if any */
  210.   for (i=1; i<argc-1; i++) {
  211.     if (!strncmp(argv[i],"-d",2)) {    /* display */
  212.       display = argv[++i];
  213.       break;
  214.     }
  215.   }
  216.  
  217.   /* open the display */
  218.   if ( (theDisp=XOpenDisplay(display)) == NULL) {
  219.     fprintf(stderr, "%s: Can't open display\n",argv[0]);
  220.     Quit(1);
  221.   }
  222.  
  223.   if (rd_str ("aspect")) {
  224.     int n,d;
  225.     if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1)
  226.       fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd);
  227.     else defaspect = (float) n / (float) d;
  228.   }
  229.       
  230.   if (rd_flag("autoGamma"))     autogamma   = def_int;
  231.   if (rd_str ("background"))    bgstr       = def_str;
  232.   if (rd_str ("black"))         blackstr    = def_str;
  233.   if (rd_int ("borderWidth"))   bwidth      = def_int;
  234.   if (rd_flag("brokeFreeCols")) brokeFreeCols = def_int;
  235.   if (rd_flag("centerPic"))     centerpic   = def_int;
  236.   if (rd_str ("ctrlGeometry"))  ctrlgeom    = def_str;
  237.   if (rd_flag("ctrlMap"))       ctrlmap     = def_int;
  238.   if (rd_int ("expand"))        expand      = def_int;
  239.   if (rd_flag("fish"))          fish        = def_int;
  240.   if (rd_flag("fixed"))         fixedaspect = def_int;
  241.   if (rd_str ("foreground"))    fgstr       = def_str;
  242.   if (rd_str ("geometry"))      maingeom    = def_str;
  243.   if (rd_str ("gammaGeometry")) gamgeom     = def_str;
  244.   if (rd_flag("gammaMap"))      gmap        = def_int;
  245.  
  246.   if (rd_str("gamma")) {
  247.     int gry0,grx1,gry1,grx2,gry2,gry3;
  248.     if (sscanf(def_str,"%d %d %d %d %d %d",&gry0,&grx1,&gry1,
  249.            &grx2,&gry2,&gry3)!=6) 
  250.       fprintf(stderr,"%s: unable to parse 'gamma' resource\n",cmd);
  251.     else { 
  252.       ghand[0].y = gry0;
  253.       ghand[1].x = grx1;  ghand[1].y = gry1;
  254.       ghand[2].x = grx2;  ghand[2].y = gry2;
  255.       ghand[3].y = gry3;
  256.     }
  257.   }
  258.  
  259.   /* parse 'gamma1' through 'gamma4' resources */
  260.   for (i=0; i<4; i++) {
  261.     char gstr[10];
  262.     sprintf(gstr,"gamma%d",i+1);
  263.  
  264.     if (rd_str(gstr)) {
  265.       int y0,x1,y1,x2,y2,y3;
  266.       if (sscanf(def_str,"%d %d %d %d %d %d",&y0,&x1,&y1,&x2,&y2,&y3)!=6) 
  267.     fprintf(stderr,"%s: unable to parse '%s' resource\n",cmd,gstr);
  268.       else
  269.     SetGPreset(i, y0, x1, y1, x2, y2, y3);
  270.     }
  271.   }
  272.  
  273.   if (rd_str ("infoGeometry"))  infogeom = def_str;
  274.   if (rd_flag("infoMap"))       imap     = def_int;
  275.   if (rd_flag("mono"))          mono     = def_int;
  276.   if (rd_int ("ncols"))         { ncols  = def_int; if (ncols>=0) noglob = 1; }
  277.   if (rd_flag("nglobal"))       noglob   = def_int;
  278.   if (rd_flag("ninstall"))      ninstall = def_int;
  279.   if (rd_flag("noqcheck"))      noqcheck = def_int;
  280.   if (rd_flag("perfect"))       perfect  = def_int;
  281.   if (rd_flag("reverseVideo"))  revvideo = def_int;
  282.   if (rd_str ("rootBackground")) rootbgstr = def_str;
  283.   if (rd_str ("rootForeground")) rootfgstr = def_str;
  284.   if (rd_int ("rootPattern"))    rootPattern = def_int;
  285.   if (rd_flag("rwColor"))       rwcolor  = def_int;
  286.   if (rd_flag("slow24"))        slow24   = def_int;
  287.   if (rd_flag("tile"))          roottile = def_int;
  288.   if (rd_str ("white"))         whitestr = def_str;
  289.       
  290.  
  291.   /*****************************************************/
  292.   /*** Command Line Options                          ***/
  293.   /*****************************************************/
  294.   
  295.   for (i=1, numnames=0; i<argc; i++) {
  296.     if (argv[i][0] != '-') {           /* a file name.  put it in list */
  297.       if (numnames<MAXNAMES) {
  298.     namelist[numnames++] = argv[i];
  299.     if (numnames==MAXNAMES) {
  300.       fprintf(stderr,"%s: too many filenames.  Only using first %d.\n",
  301.           cmd, MAXNAMES);
  302.     }
  303.       }
  304.     }
  305.     
  306.     else if (!strncmp(argv[i],"-as",2)) { /* default aspect */
  307.       int n,d;
  308.       if (++i<argc) {
  309.     if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1)
  310.       fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]);
  311.     else defaspect = (float) n / (float) d;
  312.       }
  313.     }
  314.  
  315.     else if (!strncmp(argv[i],"-au",3))  /* autogamma */
  316.       autogamma++;
  317.  
  318.     else if (!strncmp(argv[i],"-bf",3))  /* brokeFreeCols */
  319.       brokeFreeCols = !brokeFreeCols;
  320.  
  321.     else if (!strncmp(argv[i],"-bg",3)) /* background color */
  322.       { if (++i<argc) bgstr = argv[i]; }
  323.  
  324.     else if (!strncmp(argv[i],"-bl",3))    /* black color */
  325.       { if (++i<argc) blackstr = argv[i]; }
  326.     
  327.     else if (!strncmp(argv[i],"-bw",3)) /* border width */
  328.       { if (++i<argc) bwidth=atoi(argv[i]); }
  329.  
  330.     else if (!strncmp(argv[i],"-ce",3))    /* centerpic */
  331.       centerpic++;
  332.     
  333.     else if (!strncmp(argv[i],"-cg",3))    /* ctrlgeom */
  334.       { if (++i<argc) ctrlgeom = argv[i]; }
  335.     
  336.     else if (!strncmp(argv[i],"-cm",3))    /* ctrlmap */
  337.       ctrlmap++;
  338.     
  339.     else if (!strncmp(argv[i],"-cl",3))    /* clear */
  340.       clrroot++;
  341.     
  342.     else if (!strncmp(argv[i],"-d",2))  /* display */
  343.       { if (++i<argc) display = argv[i]; }
  344.  
  345.     else if (!strncmp(argv[i],"-D",2))     /* debug */
  346.       { if (++i<argc) DEBUG = atoi(argv[i]); }
  347.  
  348.     else if (!strncmp(argv[i],"-e",2))     /* expand factor */
  349.       { if (++i<argc) expand=atoi(argv[i]); }
  350.  
  351.     else if (!strncmp(argv[i],"-fis",4)) /* nofish */
  352.       fish++;
  353.  
  354.     else if (!strncmp(argv[i],"-fix",4)) /* fixed aspect ratio */
  355.       fixedaspect++;
  356.     
  357.     else if (!strncmp(argv[i],"-fg",3)) /* foreground color */
  358.       { if (++i<argc) fgstr = argv[i]; }
  359.     
  360.     else if (!strncmp(argv[i],"-ge",3))    /* geometry */
  361.       { if (++i<argc) maingeom = argv[i]; }
  362.     
  363.     else if (!strncmp(argv[i],"-gg",3))    /* gammageom */
  364.       { if (++i<argc) gamgeom = argv[i]; }
  365.     
  366.     else if (!strncmp(argv[i],"-gm",3))    /* gmap */
  367.       gmap++;
  368.     
  369.     else if (!strncmp(argv[i],"-G",2))    /* Gamma */
  370.       { if (++i<argc) ghand[0].y=atoi(argv[i]);
  371.     if (++i<argc) ghand[1].x=atoi(argv[i]);
  372.     if (++i<argc) ghand[1].y=atoi(argv[i]);
  373.         if (++i<argc) ghand[2].x=atoi(argv[i]);
  374.     if (++i<argc) ghand[2].y=atoi(argv[i]);
  375.         if (++i<argc) ghand[3].y=atoi(argv[i]); }
  376.     
  377.     else if (!strncmp(argv[i],"-ig",3))    /* infogeom */
  378.       { if (++i<argc) infogeom = argv[i]; }
  379.     
  380.     else if (!strncmp(argv[i],"-im",3))    /* imap */
  381.       imap++;
  382.     
  383.     else if (!strncmp(argv[i],"-ma",3))    /* auto maximize */
  384.       automax++;
  385.     
  386.     else if (!strncmp(argv[i],"-mo",3))    /* mono */
  387.       mono++;
  388.     
  389.     else if (!strncmp(argv[i],"-nc",3)) /* ncols */
  390.       { if (++i<argc) { ncols=abs(atoi(argv[i])); noglob++; } }
  391.     
  392.     else if (!strncmp(argv[i],"-ng",3)) /* no global colors */
  393.       noglob++;
  394.     
  395.     else if (!strncmp(argv[i],"-ni",3))    /* don't install colormaps by hand */
  396.       ninstall=1;
  397.  
  398.     else if (!strncmp(argv[i],"-noq",4)) /* noqcheck */
  399.       noqcheck++;
  400.  
  401.     else if (!strncmp(argv[i],"-p",2))  /* perfect colors */
  402.       perfect++;  
  403.     
  404.     else if (!strncmp(argv[i],"-q",2))  /* auto-quit when using root */
  405.       autoquit++;
  406.     
  407.     else if (!strncmp(argv[i],"-rb",3)) /* root background color */
  408.       { if (++i<argc) rootbgstr = argv[i]; }
  409.     
  410.     else if (!strncmp(argv[i],"-rf",3)) /* root foreground color */
  411.       { if (++i<argc) rootfgstr = argv[i]; }
  412.     
  413.     else if (!strncmp(argv[i],"-ro",3)) /* use root window */
  414.       useroot++;
  415.     
  416.     else if (!strncmp(argv[i],"-rp",3))    /* root pattern */
  417.       { if (++i<argc) rootPattern = abs(atoi(argv[i])); }
  418.     
  419.     else if (!strncmp(argv[i],"-rw",3)) /* use r/w color */
  420.       rwcolor++;
  421.     
  422.     else if (!strcmp(argv[i],"-rv"))    /* reverse video */
  423.       revvideo++;
  424.     
  425.     else if (!strncmp(argv[i],"-s",2))  /* slow 24-to-8 conversion */
  426.       slow24++;
  427.     
  428.     else if (!strncmp(argv[i],"-t",2))  /* root window tiling */
  429.       roottile++;
  430.     
  431.     else if (!strncmp(argv[i],"-wa",3))    /* secs to wait between pics */
  432.       { if (++i<argc) waitsec = abs(atoi(argv[i])); }
  433.     
  434.     else if (!strncmp(argv[i],"-wh",3))    /* white color */
  435.       { if (++i<argc) whitestr = argv[i]; }
  436.     
  437.     else Syntax();
  438.   }
  439.   
  440.   if (expand==0) Syntax();
  441.  
  442.   if (DEBUG) XSynchronize(theDisp, True);
  443.  
  444.   /* if using root, generally gotta map ctrl window, 'cause there won't be
  445.      any way to ask for it.  (no kbd or mouse events from rootW) */
  446.   if (useroot && !autoquit) 
  447.     ctrlmap = 1;    
  448.  
  449.   /* must not install colormaps on rootW */
  450.   if (useroot) { perfect=0;  noglob = 1; } 
  451.  
  452.  
  453.  
  454.   /*****************************************************/
  455.   /*** X Setup                                       ***/
  456.   /*****************************************************/
  457.   
  458.   theScreen = DefaultScreen(theDisp);
  459.   theCmap   = DefaultColormap(theDisp, theScreen);
  460.   rootW     = RootWindow(theDisp,theScreen);
  461.   theGC     = DefaultGC(theDisp,theScreen);
  462.   theVisual = DefaultVisual(theDisp,theScreen);
  463.   ncells    = DisplayCells(theDisp, theScreen);
  464.   dispWIDE  = DisplayWidth(theDisp,theScreen);
  465.   dispHIGH  = DisplayHeight(theDisp,theScreen);
  466.   dispDEEP  = DisplayPlanes(theDisp,theScreen);
  467.  
  468.  
  469.   /* go look for a virtual root */
  470.   __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False);
  471.   XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children,
  472.          &numChildren);
  473.   for (i = 0; i < numChildren; i++) {
  474.     Atom actual_type;
  475.     int actual_format;
  476.     unsigned long nitems, bytesafter;
  477.     Window *newRoot = NULL;
  478.     XWindowAttributes xwa;
  479.     if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0, 1,
  480.           False, XA_WINDOW, &actual_type, &actual_format, &nitems,
  481.       &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) {
  482.       rootW = *newRoot;
  483.       XGetWindowAttributes(theDisp, rootW, &xwa);
  484.       dispWIDE = xwa.width;  dispHIGH = xwa.height;
  485.       dispDEEP = xwa.depth;
  486.       break;
  487.     }
  488.   }
  489.  
  490.   /* have enough info to do a '-clear' now */
  491.   if (clrroot || useroot) {
  492.     KillOldRootInfo();
  493.     XSetWindowBackgroundPixmap(theDisp, rootW, None);
  494.     XClearWindow(theDisp, rootW);
  495.     XFlush(theDisp);
  496.     if (clrroot) Quit(0);
  497.   }
  498.  
  499.  
  500.   arrow     = XCreateFontCursor(theDisp,XC_top_left_arrow);
  501. /*  cross     = XCreateFontCursor(theDisp,XC_plus); */
  502.   cross     = XCreateFontCursor(theDisp,XC_crosshair);
  503.  
  504.   /* set up white,black colors */
  505.   white = WhitePixel(theDisp,theScreen);
  506.   black = BlackPixel(theDisp,theScreen);
  507.   if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
  508.       XAllocColor(theDisp, theCmap, &ecdef))  white = ecdef.pixel;
  509.   if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
  510.       XAllocColor(theDisp, theCmap, &ecdef))  black = ecdef.pixel;
  511.  
  512.   /* set up fg,bg colors */
  513.   fg = black;   bg = white;
  514.   if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
  515.       XAllocColor(theDisp, theCmap, &ecdef))  fg = ecdef.pixel;
  516.   if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
  517.       XAllocColor(theDisp, theCmap, &ecdef))  bg = ecdef.pixel;
  518.  
  519.   /* set up root fg,bg colors */
  520.   rootfg = white;   rootbg = black;
  521.   if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
  522.       XAllocColor(theDisp, theCmap, &ecdef))  rootfg = ecdef.pixel;
  523.   if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
  524.       XAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
  525.  
  526.   XSetForeground(theDisp,theGC,fg);
  527.   XSetBackground(theDisp,theGC,bg);
  528.  
  529.   /* set up infofg,infobg colors */
  530.   infofg = fg;   infobg = bg;
  531.  
  532.  
  533.   /* if '-mono' not forced, determine if we're on a b/w or color monitor */
  534.   if (!mono) {
  535.     if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class);
  536.     if (theVisual->class == StaticGray || theVisual->class == GrayScale)
  537.       mono = 1;
  538.   }
  539.   
  540.   iconPix = XCreatePixmapFromBitmapData(theDisp, rootW, icon_bits,
  541.          icon_width, icon_height, 1, 0, 1);
  542.  
  543.   /* try to load fonts */
  544.   if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL && 
  545.        (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL && 
  546.        (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL) {
  547.     sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s",
  548.         FONT1, FONT2, FONT3);
  549.     FatalError(str);
  550.   }
  551.   mfont=mfinfo->fid;
  552.   XSetFont(theDisp,theGC,mfont);
  553.   
  554.   if ( (monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL && 
  555.        (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL && 
  556.        (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL) {
  557.     sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s",
  558.         MFONT1, MFONT2, MFONT3);
  559.     FatalError(str);
  560.   }
  561.   monofont=monofinfo->fid;
  562.   
  563.  
  564.   /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
  565.      case ncols = 0;  (ncols = max number of colors allocated.  on 1-bit
  566.      displays, no colors are allocated */
  567.  
  568.   if (ncols == -1) {
  569.     if (dispDEEP>1) ncols = 1<<dispDEEP;
  570.     else ncols = 0;
  571.   }
  572.   else if (ncols>256) ncols = 256;       /* so program doesn't blow up */
  573.  
  574.   if (numnames==0) {       /* no filenames.  build one-name (stdio) list */
  575.     namelist[0] = STDINSTR;
  576.     numnames = 1;
  577.     }
  578.  
  579.   MakeDispNames();
  580.  
  581.   /* create the info box window */
  582.   CreateInfo(infogeom);
  583.   XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask );
  584.   InfoBox(imap);     /* map it (or not) */
  585.   if (imap) {
  586.     RedrawInfo(0,0,INFOWIDE,INFOHIGH);  /* explicit draw if mapped */
  587.     XFlush(theDisp);
  588.   }
  589.  
  590.  
  591.   /* create the control box window */
  592.   CreateCtrl(ctrlgeom);
  593.   XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask);
  594.   CtrlBox(ctrlmap);     /* map it (or not) */
  595.   if (ctrlmap) {
  596.     RedrawCtrl(0,0,CTRLWIDE,CTRLHIGH);   /* explicit draw if mapped */
  597.     XFlush(theDisp);
  598.   }
  599.  
  600.  
  601.   /* create the directory window */
  602.   CreateDirW(DEFDIRGEOM);
  603.   XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask);
  604.   DirBox(0);     /* map it (or not) */
  605.  
  606.  
  607.   /* create the gamma window */
  608.   CreateGam(gamgeom);
  609.   XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask);
  610.   GamBox(gmap);     /* map it (or not) */
  611.  
  612.   GenerateGamma();
  613.   GenerateFSGamma();
  614.  
  615.   LoadFishCursors();
  616.   SetCursors(-1);
  617.  
  618.   /* if we're not on a colormapped display, turn off rwcolor */
  619.   if (!(theVisual->class & 1) && rwcolor) {
  620.     fprintf(stderr,"xv: not a colormapped display.  'rwcolor' turned off.\n");
  621.     rwcolor = 0;
  622.   }
  623.  
  624.   /* Do The Thing... */
  625.   MainLoop();
  626.   Quit(0);
  627.   return(0);
  628. }
  629.  
  630.  
  631.  
  632.  
  633. /***********************************/
  634. static int cpos = 0;
  635. printoption(st)
  636. char *st;
  637. {
  638.   if (strlen(st) + cpos > 78) {
  639.     fprintf(stderr,"\n   ");
  640.     cpos = 3;
  641.   }
  642.  
  643.   fprintf(stderr,"%s ",st);
  644.   cpos = cpos + strlen(st) + 1;
  645. }
  646.  
  647. static void Syntax()
  648. {
  649.   fprintf(stderr, "Usage:\n");
  650.   printoption(cmd);
  651.   printoption("[-aspect w:h]");
  652.   printoption("[-autogamma]");
  653.   printoption("[-bfc]");
  654.   printoption("[-bg background]");
  655.   printoption("[-black color]");
  656.   printoption("[-bw width]");
  657.   printoption("[-center]");
  658.   printoption("[-cgeom geom]");
  659.   printoption("[-clear]");
  660.   printoption("[-cmap]");
  661.   printoption("[-DEBUG level]");
  662.   printoption("[-display disp]");
  663.   printoption("[-expand exp]");
  664.   printoption("[-fg foreground]");
  665.   printoption("[-fish]");
  666.   printoption("[-fixed]");
  667.   printoption("[-GAMMA y0 x1 y1 x2 y2 y3]");
  668.   printoption("[-geometry geom]");
  669.   printoption("[-ggeometry geom]");
  670.   printoption("[-gmap]");
  671.   printoption("[-help]");
  672.   printoption("[-igeom geom]");
  673.   printoption("[-imap]");
  674.   printoption("[-max]");
  675.   printoption("[-mono]");
  676.   printoption("[-ncols #]");
  677.   printoption("[-nglobal]");
  678.   printoption("[-ninst]");
  679.   printoption("[-noqcheck]");
  680.   printoption("[-perfect]");
  681.   printoption("[-quit]");
  682.   printoption("[-root]");
  683.   printoption("[-rw]");
  684.   printoption("[-rv]");
  685.   printoption("[-rbg color]");
  686.   printoption("[-rfg color]");
  687.   printoption("[-rpat #]");
  688.   printoption("[-slow24]");
  689.   printoption("[-tile]");
  690.   printoption("[-wait seconds]");
  691.   printoption("[-white color]");
  692.   printoption("[filename ...]");
  693.   fprintf(stderr,"\n\n");
  694.   Quit(1);
  695. }
  696.  
  697.  
  698. /***********************************/
  699. static int openPic(filenum)
  700. int filenum;
  701. {
  702.   /* tries to load file #filenum (from 'namelist' list)
  703.    * returns 0 on failure (cleans up after itself)
  704.    * if successful, returns 1, creates mainW
  705.    */
  706.  
  707.   int   i,filetype,okay,freename, nw, nh;
  708.   char *tmp;
  709.   FILE *fp;
  710.   char *fullname,      /* full name of the original file */
  711.         filename[256], /* full name of the file to be loaded (could be /tmp) */
  712.         basename[128], /* just the name of the original file. No path */
  713.         magicno[8];    /* first 8 bytes of file */
  714.  
  715.   
  716.   normaspect = defaspect;
  717.  
  718.   StartFish();
  719.   WaitCursor();
  720.  
  721.   curname = filenum;
  722.   ScrollToCurrent();  /* have scrl/list show current */
  723.   XFlush(theDisp);    /* update NOW */
  724.  
  725.   /* clear any old error messages */
  726.  
  727.   SetISTR(ISTR_INFO,"");
  728.   SetISTR(ISTR_WARNING,"");
  729.   infoMode = INF_STR;
  730.   okay = 0;
  731.  
  732.   /* set up fullname and basename */
  733.  
  734.   fullname = namelist[filenum];
  735.   tmp = rindex(fullname,'/');
  736.   if (!tmp) tmp = fullname; else tmp++;
  737.   strcpy(basename,tmp);
  738.   if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0) 
  739.     basename[strlen(basename)-2]='\0';     /* chop off .Z, if any */
  740.  
  741.   /* if fullname doesn't start with a '/' (ie, it's a relative path), 
  742.      (and it's not the special case '<stdin>') prepend 'initpath' to it */
  743.   freename = 0;
  744.   if (fullname[0] != '/' && strcmp(fullname,STDINSTR)!=0) {
  745.     char *tmp;
  746.     tmp = (char *) malloc(strlen(fullname) + strlen(initpath) + 2);
  747.     if (!tmp) FatalError("malloc 'filename' failed");
  748.     sprintf(tmp,"%s/%s", initpath, fullname);
  749.     fullname = tmp;
  750.     freename = 1;
  751.   }
  752.     
  753.  
  754.   /* uncompress if it's a .Z file */
  755.  
  756.   i = strlen(fullname);
  757.   if (i>2 && strcmp(fullname+i-2,".Z")==0) {
  758.     strcpy(filename,"/tmp/xvXXXXXX");
  759.     mktemp(filename);
  760.     sprintf(str,"%s -c %s >%s",UNCOMPRESS,fullname,filename);
  761.     SetISTR(ISTR_INFO,"Uncompressing '%s'...",basename);
  762.     if (system(str)) {
  763.       SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basename);
  764.       Warning();
  765.       goto FAILED;
  766.     }
  767.   WaitCursor();
  768.   }
  769.   else strcpy(filename,fullname);
  770.     
  771.  
  772.   /* if the file is stdio, write it out to a temp file */
  773.   if (strcmp(filename,STDINSTR)==0) {
  774.     FILE *fp;
  775.  
  776.     strcpy(filename,"/tmp/xvXXXXXX");
  777.     mktemp(filename);
  778.  
  779.     fp = fopen(filename,"w");
  780.     if (!fp) FatalError("can't write /tmp/xv****** file");
  781.     
  782.     while ( (i=getchar()) != EOF) putc(i,fp);
  783.     fclose(fp);
  784.   }
  785.  
  786.  
  787.   /* now, try to determine what type of file we've got by reading the
  788.      first couple bytes and looking for a Magic Number */
  789.  
  790.   fp=fopen(filename,"r");
  791.   if (!fp) {
  792.     SetISTR(ISTR_INFO,"Can't open '%s' -  %s",filename,sys_errlist[errno]);
  793.     Warning();
  794.     goto FAILED;
  795.   }
  796.  
  797.   fread(magicno,8,1,fp);  
  798.   fclose(fp);
  799.  
  800.   filetype = UNKNOWN;
  801.   if (strncmp(magicno,"GIF87",5)==0) filetype = GIF;
  802.  
  803.   else if (strncmp(magicno,"VIEW",4)==0 ||
  804.        strncmp(magicno,"WEIV",4)==0) filetype = PM;
  805.  
  806.   else if (magicno[0] == 'P' && magicno[1]>='1' && 
  807.        magicno[1]<='6') filetype = PBM;
  808.  
  809.   else if (strncmp(magicno,"#define",7)==0) filetype = XBM;
  810.  
  811.   if (filetype == UNKNOWN) {
  812.     SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basename);
  813.     Warning();
  814.     goto FAILED;
  815.   }
  816.  
  817.   SetISTR(ISTR_INFO,"Loading '%s'...",basename);
  818.  
  819.   switch (filetype) {
  820.   case GIF: i = LoadGIF(filename,ncols); break;
  821.   case PM:  i = LoadPM (filename,ncols); break;
  822.   case PBM: i = LoadPBM(filename,ncols); break;
  823.   case XBM: i = LoadXBM(filename,ncols); break;
  824.   }
  825.   WaitCursor();
  826.  
  827.   if (i) {
  828.     SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename);
  829.     Warning();
  830.     goto FAILED;
  831.   }
  832.  
  833.   /* successfully read this picture */
  834.  
  835.   /* if we read a /tmp file, delete it.  won't be needing it any more */
  836.   if (strcmp(fullname,filename)!=0) unlink(filename);
  837.  
  838.   SetInfoMode(INF_PART);
  839.   SetISTR(ISTR_INFO,"Loading '%s'...  done.",basename);
  840.   SetISTR(ISTR_FILENAME,basename);
  841.   SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
  842.   SetISTR(ISTR_COLOR,"");
  843.  
  844.   /* adjust button in/activity */
  845.   BTSetActive(&but[BCROP],0);  /* new picture, draw no cropping rectangle */
  846.   BTSetActive(&but[BUNCROP], 0);
  847.   BTSetActive(&but[BNEXT], (curname<numnames-1));
  848.   BTSetActive(&but[BPREV], (curname>0));
  849.  
  850.   normFact = 1;  nw = pWIDE;  nh = pHIGH;
  851.   /* if pic is larger than screen, half picture until it fits on screen */
  852.   while (nw > dispWIDE || nh > dispHIGH) {
  853.     nw = nw / 2;  
  854.     nh = nh / 2;
  855.     normFact = normFact * 2;
  856.   }
  857.  
  858.   /* expand:  if expansion is negative, treat it as a reciprocal */
  859.   if (expand<0) { eWIDE = pWIDE/abs(expand);  eHIGH = pHIGH/abs(expand); }
  860.            else { eWIDE = pWIDE * expand;     eHIGH = pHIGH * expand; }
  861.  
  862.   if (useroot) {
  863.     int i,x,y;  unsigned int w,h;
  864.     i = XParseGeometry(maingeom,&x,&y,&w,&h);
  865.     if (i&WidthValue)  eWIDE = w;
  866.     if (i&HeightValue) eHIGH = h;
  867.     RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH);
  868.  
  869.     if (roottile) {
  870.       /* make picture size a divisor of the rootW size.  round down */
  871.       i = (dispWIDE + eWIDE-1) / eWIDE;   eWIDE = (dispWIDE + i-1) / i;
  872.       i = (dispHIGH + eHIGH-1) / eHIGH;   eHIGH = (dispHIGH + i-1) / i;
  873.     }
  874.   }
  875.  
  876.   cpic = pic;  cWIDE = pWIDE;  cHIGH = pHIGH;  cXOFF = cYOFF = 0;
  877.   SetCropString();
  878.  
  879.   if (automax) { 
  880.     eWIDE = dispWIDE;  eHIGH = dispHIGH;
  881.     if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
  882.   }
  883.  
  884.   if (useroot) {
  885.     mainW = rootW;
  886.  
  887.     if (theVisual->class & 1) {
  888.       /* clear old root pixmap before doing the 'alloc colors scene' 
  889.      to avoid annoying 'rainbow' effect as colors are realloced */
  890.       XSetWindowBackgroundPixmap(theDisp, rootW, None);
  891.       XClearWindow(theDisp, rootW);
  892.       XFlush(theDisp);
  893.     }
  894.   }
  895.   else {
  896.     CreateMainWindow(maingeom, basename);
  897.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  898.          | StructureNotifyMask | ButtonPressMask
  899.          | EnterWindowMask | LeaveWindowMask);
  900.     XMapWindow(theDisp,mainW);
  901.   }
  902.  
  903.   SortColormap();
  904.  
  905.   /* save the desired RGB colormap (before gamma-correcting it) */
  906.   for (i=0; i<numcols; i++)
  907.     { rorg[i] = r[i];  gorg[i] = g[i];  borg[i] = b[i]; }
  908.  
  909.   WaitCursor();
  910.   DoMonoAndRV();
  911.   if (autogamma) GammifyColors();
  912.  
  913.   if (rwcolor) AllocRWColors();
  914.           else AllocColors();
  915.  
  916.   WaitCursor();
  917.   Resize(eWIDE,eHIGH);
  918.  
  919.   WaitCursor();
  920.   if (useroot) MakeRootPic();
  921.     
  922.   if (LocalCmap) {
  923.     XSetWindowAttributes xswa;
  924.     if (!ninstall) XInstallColormap(theDisp,LocalCmap);
  925.     xswa.colormap = LocalCmap;
  926.     XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
  927.   }
  928.     
  929.   SetInfoMode(INF_FULL);
  930.   if (freename) free(fullname);
  931.  
  932.   StopFish();
  933.   SetCursors(-1);
  934.  
  935.   /* put current filename into the 'save-as' filename */
  936.   if (strcmp(filename,STDINSTR)==0) SetDirFName("stdin");
  937.   else SetDirFName(basename);
  938.     
  939.   return 1;
  940.  
  941.   
  942.  FAILED:
  943.   StopFish();
  944.   SetCursors(-1);
  945.   SetInfoMode(INF_STR);
  946.   if (strcmp(fullname,filename)!=0) unlink(filename);   /* kill /tmp file */
  947.   if (freename) free(fullname);
  948.   return 0;
  949. }
  950.  
  951.  
  952.  
  953.  
  954. /***********************************/
  955. static void closePic()
  956. {
  957.   /* kill all resources used for this picture.
  958.      this would include the window, any allocated colors, pic, epic, 
  959.      theImage, etc. */
  960.  
  961.   int i;
  962.   static char *st = "Loading...";
  963.  
  964.   if (!useroot) {
  965.     /* turn off configure events */
  966.     XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
  967.          | ButtonPressMask
  968.          | EnterWindowMask | LeaveWindowMask);
  969.     XClearArea(theDisp, mainW, 0,0, eWIDE, eHIGH, True);
  970.  
  971.     /* 
  972.       XSetForeground(theDisp, theGC, infofg);
  973.       XFillRectangle(theDisp,mainW,theGC, 0, 0, StringWidth(st) + 8, CHIGH+4);
  974.       XSetForeground(theDisp, theGC, infobg);
  975.       XDrawString(theDisp, mainW, theGC, 4, 2 + ASCENT, st, strlen(st));
  976.       XFlush(theDisp);  
  977.     */
  978.   }
  979.   
  980.   if (LocalCmap) {
  981.     XFreeColormap(theDisp,LocalCmap);
  982.     LocalCmap = 0;
  983.   }
  984.   else if (!brokeFreeCols) {
  985.     for (i=0; i<nfcols; i++) 
  986.       XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
  987.   }
  988.   else {
  989.     for (i=0; i<nfcols; i++) {
  990.       int j;
  991.       for (j=0; j<i; j++) {
  992.         if (freecols[i] == freecols[j])   /* already been freed once */
  993.       break;
  994.       }
  995.       if (j==i)      /* wasn't found in already-freed list */
  996.         XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L);
  997.     }
  998.   }
  999.  
  1000.   if (epic != cpic && epic != NULL) free(epic);
  1001.   if (cpic !=  pic && cpic != NULL) free(cpic);
  1002.   if (pic != NULL) free(pic);
  1003.   if (theImage != NULL) XDestroyImage(theImage);
  1004.   theImage = NULL;
  1005.   pic = epic = cpic = NULL;
  1006.  
  1007.   SetInfoMode(INF_STR);
  1008. }
  1009.  
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016. /****************/
  1017. static void OpenFirstPic()
  1018. /****************/
  1019. {
  1020.   int i;
  1021.  
  1022.   for (i=0; i<numnames; i++) {
  1023.     if (openPic(i)) return;    /* success */
  1024.   }
  1025.  
  1026.   if (numnames>1) FatalError("couldn't open any pictures");
  1027.   else Quit(-1);
  1028. }
  1029.  
  1030.  
  1031. /****************/
  1032. static void OpenNextPic()
  1033. /****************/
  1034. {
  1035.   int i,orig;
  1036.  
  1037.   orig = curname;
  1038.   for (i=curname+1; i<numnames; i++) {
  1039.     if (openPic(i)) return;    /* success */
  1040.   }
  1041.  
  1042.   /* couldn't go to next, reopen original */
  1043.   if (!openPic(orig)) FatalError("couldn't reopen original picture");
  1044. }
  1045.  
  1046.  
  1047. /****************/
  1048. static void OpenNextQuit()
  1049. /****************/
  1050. {
  1051.   int i;
  1052.  
  1053.   for (i=curname+1; i<numnames; i++) {
  1054.     if (openPic(i)) return;    /* success */
  1055.   }
  1056.  
  1057.   Quit(0);
  1058. }
  1059.  
  1060.  
  1061. /****************/
  1062. static void OpenPrevPic()
  1063. /****************/
  1064. {
  1065.   int i,orig;
  1066.  
  1067.   orig = curname;
  1068.   for (i=curname-1; i>=0; i--) {
  1069.     if (openPic(i)) return;    /* success */
  1070.   }
  1071.  
  1072.   /* couldn't go to next, reopen original */
  1073.   if (!openPic(orig)) FatalError("couldn't reopen original picture");
  1074. }
  1075.  
  1076.  
  1077. /****************/
  1078. static void MainLoop()
  1079. /****************/
  1080. {
  1081.   /* search forward until we manage to display a picture, 
  1082.      then call EventLoop.  EventLoop will eventually return 
  1083.      NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */
  1084.  
  1085.   int i;
  1086.  
  1087.   OpenFirstPic();   /* find first displayable picture, exit if none */
  1088.  
  1089.   if (useroot && autoquit) Quit(0);
  1090.  
  1091.   while ((i=EventLoop()) != QUIT) {
  1092.     if      (i==NEXTPIC && curname<numnames-1)  { closePic(); OpenNextPic(); }
  1093.     else if (i==PREVPIC && curname>0)  { closePic(); OpenPrevPic(); }
  1094.     else if (i==NEXTQUIT) { closePic(); OpenNextQuit(); }
  1095.     else if (i>=0) {
  1096.       int orig = curname;
  1097.       if (curname != i) {
  1098.     closePic();
  1099.     if (!openPic(i)) {  /* couldn't goto */
  1100.       if (!openPic(orig)) FatalError("couldn't reopen original picture");
  1101.     }
  1102.       }
  1103.     }
  1104.   }
  1105. }
  1106.  
  1107.  
  1108.  
  1109. /****************/
  1110. static int EventLoop()
  1111. /****************/
  1112. {
  1113.   XEvent event;
  1114.   int    retval,done;
  1115.   time_t orgtime, curtime;
  1116.  
  1117.  
  1118.   /* note: there's no special event handling if we're using the root window.
  1119.      if we're using the root window, we will recieve NO events for mainW */
  1120.  
  1121.   time(&orgtime);
  1122.  
  1123.   done = retval = 0;
  1124.   while (!done) {
  1125.  
  1126.     if (waitsec == -1 || XPending(theDisp)>0) {
  1127.       XNextEvent(theDisp, &event);
  1128.       
  1129.       switch (event.type) {
  1130.       case Expose: {
  1131.         XExposeEvent *exp_event = (XExposeEvent *) &event;
  1132.  
  1133.     /* if the window doesn't do intelligent redraw, drop all-1 exposes */
  1134.     if (exp_event->count>0 && exp_event->window != mainW 
  1135.                            && exp_event->window != ctrlW
  1136.                            && exp_event->window != dirW
  1137.                                && exp_event->window != gamW
  1138.                                && exp_event->window != graphW) break;
  1139.  
  1140.         if (exp_event->window==mainW) {
  1141.       if (DEBUG) fprintf(stderr,"EXPOSE:  ");
  1142.       if (!CheckForConfig()) {
  1143.         if (DEBUG)
  1144.           fprintf(stderr,"No configs pending.   Do Expose %d,%d %dx%d\n",
  1145.               exp_event->x, exp_event->y, 
  1146.               exp_event->width, exp_event->height);
  1147.  
  1148.         if (DEBUG) 
  1149.           XClearArea(theDisp, mainW, exp_event->x, exp_event->y,
  1150.              exp_event->width, exp_event->height, False);
  1151.  
  1152.         DrawWindow(exp_event->x,exp_event->y,
  1153.                exp_event->width, exp_event->height);
  1154.         
  1155.         if (but[BCROP].active) {
  1156.           XRectangle xr;
  1157.           xr.x = exp_event->x;  xr.y = exp_event->y;
  1158.           xr.width = exp_event->width;  xr.height = exp_event->height;
  1159.       
  1160.           XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted);
  1161.           InvCropRect();
  1162.           XSetClipMask(theDisp,theGC,None);
  1163.         }
  1164.       }
  1165.       else
  1166.         if (DEBUG) 
  1167.           fprintf(stderr,"Ignoring expose event.  Config pending\n");
  1168.     }
  1169.  
  1170.     else if (exp_event->window==infoW) 
  1171.       RedrawInfo(exp_event->x, exp_event->y, 
  1172.               exp_event->width, exp_event->height);
  1173.  
  1174.  
  1175.     else if (exp_event->window==ctrlW) 
  1176.       RedrawCtrl(exp_event->x, exp_event->y, 
  1177.               exp_event->width, exp_event->height);
  1178.  
  1179.     else if (exp_event->window == nList.win)
  1180.       LSRedraw(&nList);
  1181.  
  1182.     else if (exp_event->window == nList.scrl.win)
  1183.       SCRedraw(&nList.scrl);
  1184.  
  1185.  
  1186.  
  1187.     else if (exp_event->window == dirW) 
  1188.       RedrawDirW(exp_event->x, exp_event->y, 
  1189.               exp_event->width, exp_event->height);
  1190.  
  1191.  
  1192.     else if (exp_event->window == dList.win)
  1193.       LSRedraw(&dList);
  1194.  
  1195.     else if (exp_event->window == dList.scrl.win)
  1196.       SCRedraw(&dList.scrl);
  1197.  
  1198.     else if (exp_event->window == ddirW) 
  1199.       RedrawDDirW();
  1200.  
  1201.     else if (exp_event->window == dnamW) 
  1202.       RedrawDNamW();
  1203.  
  1204.  
  1205.     else if (exp_event->window == gamW) 
  1206.       RedrawGam(exp_event->x, exp_event->y, 
  1207.               exp_event->width, exp_event->height);
  1208.  
  1209.     else if (exp_event->window == graphW) 
  1210.       RedrawGraph(exp_event->x, exp_event->y, 
  1211.               exp_event->width, exp_event->height);
  1212.  
  1213.       }      
  1214.       break;
  1215.     
  1216.       case ButtonPress: {
  1217.     XButtonEvent *but_event = (XButtonEvent *) &event;
  1218.     int i;
  1219.  
  1220.     switch (but_event->button) {
  1221.     case Button1:  
  1222.       if (but_event->window == mainW)
  1223.         TrackPicValues(but_event->x, but_event->y);
  1224.  
  1225.       else if (but_event->window == ctrlW) {
  1226.         int   w,h;
  1227.  
  1228.         i=ClickCtrl(but_event->x, but_event->y);
  1229.         if (i>=0) {
  1230.           switch (i) {
  1231.           case BNEXT:   retval= NEXTPIC;  done=1;  break;
  1232.           case BPREV:   retval= PREVPIC;  done=1;  break;
  1233.           case BSAVE:   DirBox(1); break;
  1234.           case BQUIT:   retval= QUIT;     done=1;  break;
  1235.  
  1236.           case BCROP:   DoCrop();  break;
  1237.           case BUNCROP: UnCrop();  break;
  1238.           case BNORM:   WResize(cWIDE/normFact, cHIGH/normFact);  break;
  1239.           case BMAX:    WResize(dispWIDE, dispHIGH);  break;
  1240.           case BUP10:   w = (eWIDE*11)/10;  h = (eHIGH*11)/10;
  1241.                             if (w==eWIDE) w++;
  1242.                             if (h==eHIGH) h++;
  1243.                             WResize(w,h);
  1244.                             break;
  1245.               case BDN10:   WResize((eWIDE*9)/10, (eHIGH*9)/10);  break;
  1246.           case BUP2:    WResize(eWIDE*2, eHIGH*2);  break;
  1247.           case BDN2:    WResize(eWIDE/2, eHIGH/2);  break;
  1248.               case B4BY3:   w = eWIDE;  h = (w * 3) / 4;
  1249.                             if (h>dispHIGH) { h = eHIGH;  w = (h*4)/3; }
  1250.                             WResize(w,h);
  1251.                             break;
  1252.  
  1253.           case BASPECT: FixAspect(1,&w,&h);  WResize(w,h);  break;
  1254.           case BMAXPECT: { int w1,h1;
  1255.                              w1 = eWIDE;  h1 = eHIGH;
  1256.                      eWIDE = dispWIDE;  eHIGH = dispHIGH;
  1257.                      FixAspect(0,&w,&h);
  1258.                  eWIDE = w1;  eHIGH = h1;  /* play it safe */
  1259.                              WResize(w,h);
  1260.                              }   break;
  1261.  
  1262.           case BROTL:   Rotate(1);  break;
  1263.           case BROTR:   Rotate(0);  break;
  1264.           case BACROP:  AutoCrop();  break;
  1265.  
  1266.           case BINFO:   InfoBox(!infoUp); break;
  1267.           case BGAMMA:  GamBox(!gamUp);   break;
  1268.           }
  1269.         }
  1270.       }
  1271.  
  1272.       else if (but_event->window == nList.win) {
  1273.         i=LSClick(&nList,but_event);
  1274.         if (i>=0) return(i);
  1275.       }
  1276.  
  1277.       else if (but_event->window == nList.scrl.win) 
  1278.         SCTrack(&nList.scrl, but_event->x, but_event->y);
  1279.  
  1280.  
  1281.       else if (but_event->window == dirW) {
  1282.         i=ClickDirW(but_event->x, but_event->y);
  1283.         
  1284.         if      (i==S_BOPEN) SelectDir(dList.selected);
  1285.         else if (i==S_BCANC) DirBox(0);
  1286.         else if (i==S_BSAVE) DoSave();
  1287.         else if (i==S_BQUIT) { retval = QUIT;  done=1; }
  1288.       }
  1289.  
  1290.       else if (but_event->window == dList.win) {
  1291.         i=LSClick(&dList,but_event);
  1292.         DirOpenActive();
  1293.         if (i>=0) SelectDir(i);
  1294.       }
  1295.  
  1296.       else if (but_event->window == dList.scrl.win) 
  1297.         SCTrack(&dList.scrl, but_event->x, but_event->y);
  1298.  
  1299.       else if (but_event->window == ddirW) 
  1300.         TrackDDirW(but_event->x, but_event->y);
  1301.  
  1302.  
  1303.       else if (but_event->window == gamW)
  1304.         ClickGam(but_event->x, but_event->y);
  1305.  
  1306.       else if (but_event->window == graphW)
  1307.         TrackGraph(but_event->x, but_event->y);
  1308.  
  1309.       break;
  1310.  
  1311.     case Button2:  if (but_event->window == mainW)
  1312.                      TrackCrop(but_event->x, but_event->y);
  1313.                        break;
  1314.  
  1315.     case Button3:  if (!useroot)   /* if using root, MUST NOT get rid of */
  1316.                      CtrlBox(!ctrlUp);   /* ctrlbox.  can't get it back */
  1317.                        break;
  1318.     default:       break;
  1319.     }
  1320.       }
  1321.       break;
  1322.     
  1323.       case KeyPress: {
  1324.     XKeyEvent *key_event = (XKeyEvent *) &event;
  1325.     char buf[128];     KeySym ks;  XComposeStatus status;  int stlen;
  1326.     
  1327.     stlen = XLookupString(key_event,buf,128,&ks,&status);
  1328.  
  1329.     /* do non-character processing (arrow-keys, that is) */
  1330.     if      (ks==XK_Left)  CropKey(-1, 0, key_event->state & ShiftMask);
  1331.     else if (ks==XK_Right) CropKey( 1, 0, key_event->state & ShiftMask);
  1332.     else if (ks==XK_Up)    CropKey( 0,-1, key_event->state & ShiftMask);
  1333.     else if (ks==XK_Down)  CropKey( 0, 1, key_event->state & ShiftMask);
  1334.  
  1335.     if (!stlen) break;
  1336.  
  1337.     if (key_event->window == dirW) {
  1338.       if (DirKey(buf[0])) XBell(theDisp,0);
  1339.     }
  1340.  
  1341.     else {
  1342.       /* if (isupper(buf[0])) buf[0] = tolower(buf[0]); */
  1343.  
  1344.       /* commands valid in any window */
  1345.       
  1346.       switch (buf[0]) {
  1347.       case ' ':
  1348.       case '\r':
  1349.       case '\n':   FakeButtonPress(&but[BNEXT]);    break;
  1350.  
  1351.       case '\010':
  1352.       case '\177': FakeButtonPress(&but[BPREV]);    break;
  1353.  
  1354.       case 's':    FakeButtonPress(&but[BSAVE]);    break;
  1355.       case 'q':    FakeButtonPress(&but[BQUIT]);    break;
  1356.  
  1357.       case 'h':
  1358.       case '?':    if (!useroot) CtrlBox(!ctrlUp);  break;
  1359.  
  1360.       case 'a':    FakeButtonPress(&but[BASPECT]);  break;
  1361.       case 'A':    FakeButtonPress(&but[BACROP]);   break;
  1362.  
  1363.       case 'T':    FakeButtonPress(&but[BROTL]);    break;
  1364.       case 't':    FakeButtonPress(&but[BROTR]);    break;
  1365.       case '4':    FakeButtonPress(&but[B4BY3]);    break;
  1366.       case 'c':    FakeButtonPress(&but[BCROP]);    break;
  1367.       case 'u':    FakeButtonPress(&but[BUNCROP]);  break;
  1368.       case 'n':    FakeButtonPress(&but[BNORM]);    break;
  1369.       case 'm':    FakeButtonPress(&but[BMAX]);     break;
  1370.       case 'M':    FakeButtonPress(&but[BMAXPECT]); break;
  1371.       case ',':    FakeButtonPress(&but[BDN10]);    break;
  1372.       case '.':    FakeButtonPress(&but[BUP10]);    break;
  1373.       case '<':    FakeButtonPress(&but[BDN2]);     break;
  1374.       case '>':    FakeButtonPress(&but[BUP2]);     break;
  1375.  
  1376.       case 'i':    FakeButtonPress(&but[BINFO]);    break;
  1377.       case 'g':    FakeButtonPress(&but[BGAMMA]);   break;
  1378.  
  1379.       case 'p':    FakeButtonPress(&gbut[G_BAPPLY]);    break;
  1380.  
  1381.       default:     break;
  1382.       }
  1383.     }
  1384.       }
  1385.       break;
  1386.     
  1387.       case ConfigureNotify: {
  1388.     XConfigureEvent *conf_event = (XConfigureEvent *) &event;
  1389.  
  1390.     if (conf_event->window == mainW && !rotatesLeft) {
  1391.       if (DEBUG) fprintf(stderr,"CONFIG: (%s) ", 
  1392.                  conf_event->send_event ? "program" : "user");
  1393.       if (!CheckForConfig()) {
  1394.         XEvent xev;
  1395.         if (DEBUG) fprintf(stderr,"No configs pend.  Do full redraw\n");
  1396.         Resize(conf_event->width, conf_event->height);
  1397.  
  1398.         /* eat pending expose events, as the complete redraw will 
  1399.            cover all of them */
  1400.         while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
  1401.           XExposeEvent *exp = (XExposeEvent *) &xev;
  1402.           if (DEBUG) 
  1403.         fprintf(stderr, "  ate expose (%s) (count=%d) %d,%d  %dx%d\n",
  1404.             exp->send_event ? "program" : "user", exp->count,
  1405.             exp->x, exp->y, exp->width, exp->height);
  1406.         }
  1407.  
  1408.         DrawWindow(0,0,conf_event->width, conf_event->height);
  1409.         SetCursors(-1);
  1410.  
  1411.       }
  1412.       else 
  1413.         if (DEBUG) fprintf(stderr,"config pending.  ignored\n");
  1414.     }
  1415.     if (rotatesLeft>0) rotatesLeft--;
  1416.     if (!rotatesLeft) SetCursors(-1);
  1417.       }
  1418.       break;
  1419.     
  1420.     
  1421.       case CirculateNotify:
  1422.       case MapNotify:
  1423.       case DestroyNotify:
  1424.       case GravityNotify:
  1425.       case ReparentNotify:
  1426.       case UnmapNotify:         break;
  1427.  
  1428.       case EnterNotify:
  1429.       case LeaveNotify: {
  1430.     XCrossingEvent *cross_event = (XCrossingEvent *) &event;
  1431.  
  1432.      if (cross_event->window != mainW) break;
  1433.  
  1434.     if (cross_event->type == EnterNotify && LocalCmap && !ninstall) 
  1435.       XInstallColormap(theDisp,LocalCmap);
  1436.  
  1437.     if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) 
  1438.       XUninstallColormap(theDisp,LocalCmap);
  1439.       }
  1440.       break;
  1441.     
  1442.     
  1443.       default: break;        /* ignore unexpected events */
  1444.       }  /* switch */
  1445.     }  /* if XPending */
  1446.     
  1447.  
  1448.     else {                      /* no events.  check wait status */
  1449.       if (waitsec>-1) {
  1450.     time(&curtime);
  1451.     if (curtime - orgtime >= waitsec) return NEXTQUIT;
  1452.     sleep(1);   /* so program doesn't loop continuously while 'waiting' */
  1453.       }
  1454.     }
  1455.  
  1456.   }  /* while */
  1457.   return(retval);
  1458. }
  1459.  
  1460.  
  1461.  
  1462. /***********************************/
  1463. void DrawWindow(x,y,w,h)
  1464. int x,y,w,h;
  1465. {
  1466.   if (theImage)
  1467.     XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h);
  1468.   else 
  1469.     if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n");
  1470. }
  1471.  
  1472.  
  1473. /***********************************/
  1474. static void CreateMainWindow(geom,name)
  1475.      char *geom, *name;
  1476. {
  1477.   XSetWindowAttributes xswa;
  1478.   unsigned int         xswamask;
  1479.   XWindowAttributes    xwa;
  1480.   XWMHints             xwmh;
  1481.   XSizeHints           hints;
  1482.   int                  i,x,y;
  1483.   unsigned int         w,h;
  1484.   char                 winname[128], iconname[128];
  1485.  
  1486.   /*
  1487.    * this function mainly deals with parsing the geometry spec correctly.
  1488.    * More trouble than it should be, and probably more trouble than
  1489.    * it has to be, but who can tell these days, what with all those
  1490.    * Widget-usin' Weenies out there...
  1491.    */
  1492.  
  1493.   x = y = w = h = 1;
  1494.   i = XParseGeometry(geom,&x,&y,&w,&h);
  1495.   if (i&WidthValue)  eWIDE = w;
  1496.   if (i&HeightValue) eHIGH = h;
  1497.  
  1498.   if (eWIDE > dispWIDE || eHIGH > dispHIGH) {
  1499.     eWIDE = eWIDE / normFact;
  1500.     eHIGH = eHIGH / normFact;
  1501.   }
  1502.   if (eWIDE < 1) eWIDE = 1;
  1503.   if (eHIGH < 1) eHIGH = 1;
  1504.  
  1505.   if (fixedaspect && i&WidthValue && i&HeightValue) FixAspect(0,&eWIDE,&eHIGH);
  1506.   else if (i&WidthValue && i&HeightValue) 
  1507.     { RANGE(eWIDE,1,dispWIDE);  RANGE(eHIGH,1,dispHIGH); }
  1508.   else FixAspect(1,&eWIDE,&eHIGH);
  1509.  
  1510.   if (i&XValue || i&YValue) hints.flags = USPosition;  
  1511.                        else hints.flags = PPosition;
  1512.  
  1513.   hints.flags |= USSize;
  1514.  
  1515.   if (i&XValue && i&XNegative) x = dispWIDE - eWIDE - abs(x);
  1516.   if (i&YValue && i&YNegative) y = dispHIGH - eHIGH - abs(y);
  1517.  
  1518.   if (x+eWIDE > dispWIDE) x = dispWIDE - eWIDE;   /* keep on screen */
  1519.   if (y+eHIGH > dispHIGH) y = dispHIGH - eHIGH;
  1520.  
  1521.   if (eWIDE < 1) eWIDE = 1;
  1522.   if (eHIGH < 1) eHIGH = 1;
  1523.  
  1524.   hints.x = x;                  hints.y = y;
  1525.   hints.width = eWIDE;          hints.height = eHIGH;
  1526.   hints.max_width  = dispWIDE;  hints.max_height = dispHIGH;
  1527.   hints.flags |= PMaxSize;
  1528.  
  1529.   xswa.background_pixel = bg;
  1530.   xswa.border_pixel     = fg;
  1531.   xswamask = CWBackPixel | CWBorderPixel;
  1532.  
  1533.   if (mainW) {
  1534.     GetWindowPos(&xwa);
  1535.     xwa.width = eWIDE;  xwa.height = eHIGH;
  1536.     SetWindowPos(&xwa);
  1537.     hints.flags = PSize | PMaxSize;
  1538.   }
  1539.  
  1540.   if (!mainW)
  1541.     mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,bwidth,CopyFromParent,
  1542.               CopyFromParent, CopyFromParent, xswamask, &xswa);
  1543.  
  1544.   sprintf(winname,"xv %s",name);
  1545.   sprintf(iconname,"xv %s",name);
  1546.   XSetStandardProperties(theDisp,mainW,winname,iconname,None,
  1547.              NULL,0,&hints);
  1548.  
  1549.   xwmh.input = True;
  1550.   xwmh.flags = InputHint;
  1551.   if (iconPix) { xwmh.icon_pixmap = iconPix;  xwmh.flags |= IconPixmapHint; }
  1552.   XSetWMHints(theDisp, mainW, &xwmh);
  1553.  
  1554.   if (!mainW) FatalError("can't create window!");
  1555. }
  1556.  
  1557.  
  1558. /***********************************/
  1559. static void FixAspect(grow,w,h)
  1560. int   grow;
  1561. int   *w, *h;
  1562. {
  1563.   /* computes new values of eWIDE and eHIGH which will have aspect ratio
  1564.      'normaspect'.  If 'grow' it will preserve aspect by enlarging, 
  1565.      otherwise, it will shrink to preserve aspect ratio.  
  1566.      Returns these values in 'w' and 'h' */
  1567.  
  1568.   float xr,yr,curaspect,a,exp;
  1569.  
  1570.   *w = eWIDE;  *h = eHIGH;
  1571.  
  1572.   /* xr,yr are expansion factors */
  1573.   xr = ((float) eWIDE) / cWIDE;
  1574.   yr = ((float) eHIGH) / cHIGH;
  1575.   curaspect  = xr / yr;
  1576.  
  1577.   /* if too narrow & shrink, shrink height.  too wide and grow, grow height */
  1578.   if ((curaspect < normaspect && !grow) || 
  1579.       (curaspect > normaspect &&  grow)) {    /* modify height */
  1580.     exp = curaspect / normaspect;
  1581.     *h = (int) (eHIGH * exp + .5);
  1582.   }
  1583.  
  1584.   /* if too narrow & grow, grow width.  too wide and shrink, shrink width */
  1585.   if ((curaspect < normaspect &&  grow) || 
  1586.       (curaspect > normaspect && !grow)) {    /* modify width */
  1587.     exp = normaspect / curaspect;
  1588.     *w = (int) (eWIDE * exp + .5);
  1589.   }
  1590.  
  1591.  
  1592.   /* shrink to fit screen without changing aspect ratio */
  1593.   if (*w>dispWIDE) {
  1594.     int i;
  1595.     a = (float) *w / dispWIDE;
  1596.     *w = dispWIDE;
  1597.     i = (int) (*h / a + .5);        /* avoid freaking some optimizers */
  1598.     *h = i;
  1599.   }
  1600.  
  1601.   if (*h>dispHIGH) {
  1602.     a = (float) *h / dispHIGH;
  1603.     *h = dispHIGH;
  1604.     *w = (int) (*w / a + .5);
  1605.   }
  1606.  
  1607.   if (*w < 1) *w = 1;
  1608.   if (*h < 1) *h = 1;
  1609. }
  1610.  
  1611.  
  1612. /***********************************/
  1613. void WResize(w,h)
  1614. int w,h;
  1615. {
  1616.   XWindowAttributes xwa;
  1617.  
  1618.   /* force w,h into valid ranges */
  1619.   RANGE(w,1,dispWIDE);  RANGE(h,1,dispHIGH);
  1620.  
  1621.   if (useroot) {
  1622.     Resize(w,h);
  1623.     MakeRootPic();
  1624.     SetCursors(-1);
  1625.     return;
  1626.   }
  1627.  
  1628.   /* determine if new size goes off edge of screen.  if so move window so it
  1629.      doesn't go off screen */
  1630.  
  1631.   GetWindowPos(&xwa);
  1632.   if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w;
  1633.   if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h;
  1634.  
  1635.   if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
  1636.              cmd,w,h,xwa.x,xwa.y);
  1637.  
  1638.   /* resize the window */
  1639.   xwa.width = w;  xwa.height = h;
  1640.  
  1641.   SetWindowPos(&xwa);
  1642. }
  1643.  
  1644.  
  1645.  
  1646.  
  1647. /***********************************/
  1648. void WRotate()
  1649. {
  1650.   /* rotate the window and redraw the contents  */
  1651.  
  1652.   if (but[BCROP].active) BTSetActive(&but[BCROP],0);
  1653.   if (useroot) {
  1654.     MakeRootPic();
  1655.     SetCursors(-1);
  1656.     return;
  1657.   }
  1658.  
  1659.   if (eWIDE == eHIGH) {     /* no configure events will be gen'd */
  1660.     Resize(eWIDE, eHIGH);   /* to regen Ximage */
  1661.     DrawWindow(0, 0, eWIDE, eHIGH);
  1662.     SetCursors(-1);
  1663.   }
  1664.   else {
  1665.     rotatesLeft++;
  1666.     WResize(eWIDE, eHIGH);
  1667.   }
  1668. }
  1669.  
  1670.  
  1671.  
  1672.  
  1673. /***********************************/
  1674. void WCrop(w,h)
  1675. int w,h;
  1676. {
  1677.   XWindowAttributes xwa;
  1678.  
  1679.   /* we want to move window to old x,y + crx1,cry1 */
  1680.   GetWindowPos(&xwa);
  1681.   xwa.x += crx1;  xwa.y += cry1;
  1682.   xwa.width = w;  xwa.height = h;
  1683.   SetWindowPos(&xwa);
  1684. }
  1685.  
  1686.  
  1687. /***********************************/
  1688. void WUnCrop()
  1689. {
  1690.   int w,h;
  1691.   XWindowAttributes xwa;
  1692.  
  1693.   /* to uncrop, I need to know the old values of cXOFF and cYOFF (cx,cy), and
  1694.      the old values of cWIDE,cHIGH, eWIDE, eHIGH.  NOTE that the idea here
  1695.      is to, if possible, uncrop by wrapping the rest of the picture around
  1696.      the currently visible hunk.  */
  1697.  
  1698.   GetWindowPos(&xwa);
  1699.  
  1700.   /* calculate w,h:  based on concept of trying to show uncropped picture
  1701.      with same expansion ratios.  If this isn't possible (w or h bigger
  1702.      than screen), just go to good ol' 1:1 expansion */
  1703.  
  1704.   w = (pWIDE * eWIDE) / cWIDE;  h = (pHIGH * eHIGH) / cHIGH;
  1705.  
  1706.   if (w>dispWIDE || h>dispHIGH) {
  1707.     w=pWIDE / normFact;  h=pHIGH / normFact;
  1708.     if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w;
  1709.     if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h;
  1710.     xwa.width = w;  xwa.height = h;
  1711.     SetWindowPos(&xwa);
  1712.   }
  1713.  
  1714.   else {
  1715.     xwa.x = xwa.x - (cXOFF*eWIDE)/cWIDE;   xwa.y = xwa.y - (cYOFF*eHIGH)/cHIGH;
  1716.     if (xwa.x<0) xwa.x = 0;
  1717.     if (xwa.y<0) xwa.y = 0;
  1718.     xwa.width = w;  xwa.height = h;
  1719.     SetWindowPos(&xwa);
  1720.   }
  1721. }
  1722.  
  1723.  
  1724.  
  1725. /***********************************/
  1726. static void GetWindowPos(xwa)
  1727. XWindowAttributes *xwa;
  1728. {
  1729.   Window            root,parent,*children,child;
  1730.   unsigned int      nchildren;
  1731.   XWindowAttributes pxwa;
  1732.   int ox1,oy1;
  1733.  
  1734.   /* returns the x,y,w,h coords of mainW.  x,y are relative to rootW 
  1735.      the border is not included (x,y map to top-left pixel in window) */
  1736.  
  1737.   XGetWindowAttributes(theDisp,mainW,xwa);
  1738.  
  1739.   /* see if mainW has been re-parented by a window manager */
  1740.   XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren);
  1741.   if (nchildren>0 || children!=NULL) XFree((char *) children);
  1742.  
  1743.   if (parent != rootW) {     /* has been reparented */
  1744.     XGetWindowAttributes(theDisp,parent,&pxwa);
  1745.  
  1746.     XTranslateCoordinates(theDisp,mainW,rootW,0,0,
  1747.               &xwa->x,&xwa->y,&child);
  1748.  
  1749.     XTranslateCoordinates(theDisp,parent,rootW,0,0,
  1750.               &ox1,&oy1,&child);
  1751.   }
  1752.  
  1753.   else {
  1754.     xwa->x += xwa->border_width;
  1755.     xwa->y += xwa->border_width;
  1756.   }
  1757. }
  1758.  
  1759.  
  1760. /***********************************/
  1761. static void SetWindowPos(xwa)
  1762. XWindowAttributes *xwa;
  1763. {
  1764.   /* sets window x,y,w,h values */
  1765.   /*  XSizeHints        xsh; */
  1766.   Window            root, parent, *children, child;
  1767.   unsigned int      nchildren;
  1768.   XWindowAttributes pxwa;
  1769.   int               xoff, yoff, x1, y1, x2, y2;
  1770.  
  1771.   xoff = yoff = 0;
  1772.   /* check for reparented window */
  1773.   XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren);
  1774.   if (nchildren>0 || children!=NULL) XFree((char *) children);
  1775.   if (parent != root) {
  1776.     XTranslateCoordinates(theDisp,mainW,rootW,0,0,&x1,&y1,&child);
  1777.     XTranslateCoordinates(theDisp,mainW,parent,0,0,&xoff,&yoff,&child);
  1778.     XTranslateCoordinates(theDisp,parent,rootW,0,0,&x2,&y2,&child);
  1779.     XGetWindowAttributes(theDisp,parent,&pxwa);
  1780.  
  1781.     if (xoff == 0 && yoff == 0) {
  1782.       /* NASTY MOTIF/DXWM KLUDGES */
  1783.       xoff = pxwa.x;  yoff = pxwa.y;
  1784.       if (xwa->x<xoff && (xwa->width + xoff)<dispWIDE) xwa->x = xoff;
  1785.       if (xwa->y<yoff && (xwa->height + yoff)<dispHIGH) xwa->y = yoff;
  1786.     }
  1787.     else {
  1788.       /* NICE, PERFECTLY NORMAL TWM KLUDGES */
  1789.       xwa->x = xwa->x - xoff;
  1790.       xwa->y = xwa->y - yoff;
  1791.       if (xwa->x<0 && (xwa->width + xoff)<dispWIDE) xwa->x = 0;
  1792.       if (xwa->y<0 && (xwa->height + yoff)<dispHIGH) xwa->y = 0;
  1793.     }
  1794.   }
  1795.   else {
  1796.     xwa->x -= xwa->border_width;
  1797.     xwa->y -= xwa->border_width;
  1798.  
  1799.     if (xwa->x < -(xwa->border_width)) xwa->x = -(xwa->border_width);
  1800.     if (xwa->y < -(xwa->border_width)) xwa->y = -(xwa->border_width);
  1801.     xoff = yoff = xwa->border_width;
  1802.   }
  1803.     
  1804.   XMoveResizeWindow(theDisp, mainW, xwa->x, xwa->y, xwa->width, xwa->height);
  1805.  
  1806.   /*
  1807.    * all this bogus stuff is a work-around for weirdness in
  1808.    * twm where resize was giving 23 extra lines...
  1809.    * should do no harm if this bug is not present.
  1810.    */
  1811.   XSync(theDisp,False);
  1812.   XGetWindowAttributes(theDisp, mainW, &pxwa);
  1813.   if (pxwa.height != xwa->height) {
  1814.     XEvent xev;
  1815.     /* eat configure event (and any Exposes) if there is one */
  1816.     if (XCheckTypedWindowEvent(theDisp, mainW, ConfigureNotify, &xev)) {
  1817.       while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev));
  1818.     }
  1819.  
  1820.     XResizeWindow(theDisp, mainW, xwa->width, 
  1821.           xwa->height - (pxwa.height - xwa->height));
  1822.   }
  1823.  
  1824. }
  1825.  
  1826.  
  1827. /***********************************/
  1828. static void TrackCrop(mx,my)
  1829. int mx,my;
  1830. {
  1831.   Window       rW,cW;
  1832.   int          rx,ry,ox,oy,x,y,active;
  1833.   unsigned int mask;
  1834.  
  1835.   XSetFunction(theDisp,theGC,GXinvert);
  1836.  
  1837.   if (but[BCROP].active) {             /* turn off old cropping rectangle */
  1838.     Rect(crx1,cry1,crx2,cry2);
  1839.   }
  1840.  active = 0;
  1841.  
  1842.   crx1 = ox = mx;  cry1 = oy = my;         /* nail down one corner */
  1843.  
  1844.   while (1) {
  1845.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  1846.       if (!(mask & Button2Mask)) break;    /* button released */
  1847.  
  1848.       if (x!=ox || y!=oy) {                /* moved.  erase and redraw */
  1849.     crx2 = x;  cry2 = y;
  1850.     Rect(crx1,cry1,ox,oy);
  1851.     active = Rect(crx1,cry1,crx2,cry2);
  1852.     XFlush(theDisp);
  1853.     ox=crx2;  oy=cry2;
  1854.       }
  1855.     }
  1856.   }
  1857.  
  1858.   XSetFunction(theDisp,theGC,GXcopy);
  1859.   RANGE(crx1,0,eWIDE);  RANGE(cry1,0,eHIGH);
  1860.   RANGE(crx2,0,eWIDE);  RANGE(cry2,0,eHIGH);
  1861.   BTSetActive(&but[BCROP],active);
  1862.   SetCropString();
  1863. }
  1864.  
  1865.  
  1866. /***********************************/
  1867. static void CropKey(dx,dy,grow)
  1868. int dx,dy,grow;
  1869. {
  1870.   int x1,x2,y1,y2;
  1871.  
  1872.   if (!but[BCROP].active) return;
  1873.  
  1874.   /* x1,y1 = top-left,  x2,y2 = bot-right */
  1875.   if (crx1<crx2) { x1=crx1;  x2=crx2; }   else { x1=crx2;  x2=crx1; }
  1876.   if (cry1<cry2) { y1=cry1;  y2=cry2; }   else { y1=cry2;  y2=cry1; }
  1877.  
  1878.   if (!grow) {    /* move the rectangle */
  1879.     x1 += dx;  x2 += dx;  y1 += dy;  y2 += dy;
  1880.     if (x1<0 || x2>eWIDE) { x1 -= dx;  x2 -= dx; }
  1881.     if (y1<0 || y2>eHIGH) { y1 -= dy;  y2 -= dy; }
  1882.   }
  1883.   else {          /* grow the rectangle, pref. keeping top-left anchored */
  1884.     x2 += dx;  y2 += dy;
  1885.     if (x2>eWIDE) { 
  1886.       x1 -= dx;  x2 -= dx;
  1887.       if (x1<0) x1=0;
  1888.     }
  1889.  
  1890.     if (y2>eHIGH) { 
  1891.       y1 -= dy;  y2 -= dy;
  1892.       if (y1<0) y1=0;
  1893.     }
  1894.   }
  1895.     
  1896.   InvCropRect();
  1897.   crx1 = x1;  cry1 = y1;  crx2 = x2;  cry2 = y2;
  1898.   InvCropRect();
  1899.   SetCropString();
  1900. }
  1901.  
  1902.   
  1903. /***********************************/
  1904. static int Rect(x,y,x1,y1)
  1905. int x,y,x1,y1;
  1906. {
  1907.   int w,h;
  1908.  
  1909.   /* returns 0 if it didn't draw anything (rect is too small), 1 if it did */
  1910.   w = abs(x-x1);  h = abs(y-y1);
  1911.   if (x>x1) x = x1;
  1912.   if (y>y1) y = y1;
  1913.  
  1914.   if (w<4 || h<4) return 0;   /* too small */
  1915.  
  1916.   /* keep rectangle inside window */  
  1917.   if (x<0) { w+=x; x=0; }
  1918.   if (y<0) { h+=y; y=0; }
  1919.   if (x+w>eWIDE) w=eWIDE-x;  
  1920.   if (y+h>eHIGH) h=eHIGH-y;
  1921.  
  1922.   XDrawRectangle(theDisp, mainW, theGC, x, y, w-1, h-1);
  1923.   XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-3, h-3);
  1924.   return 1;
  1925. }
  1926.  
  1927.  
  1928. /***********************************/
  1929. void InvCropRect()
  1930. {
  1931.   XSetFunction(theDisp,theGC,GXinvert);
  1932.   Rect(crx1,cry1,crx2,cry2);
  1933.   XSetFunction(theDisp,theGC,GXcopy);
  1934. }
  1935.  
  1936.  
  1937. /***********************************/
  1938. static void TrackPicValues(mx,my)
  1939. int mx,my;
  1940. {
  1941.   Window       rW,cW;
  1942.   int          rx,ry,ox,oy,x,y;
  1943.   unsigned int mask;
  1944.   int          ty, w;
  1945.   char         foo[64];
  1946.   unsigned long wh, bl;
  1947.   char         *str = "8888,8888 = (123,123,123)  <123,123,123>";
  1948.  
  1949.   wh = infobg;  bl = infofg;
  1950.  
  1951.   /* do a colormap search for black and white if LocalCmap 
  1952.      and use those colors instead of infobg and infofg */
  1953.   if (LocalCmap) {
  1954.     XColor ctab[256];
  1955.     int  i;
  1956.     long cval;
  1957.  
  1958.     for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
  1959.     XQueryColors(theDisp,LocalCmap,ctab,nfcols);
  1960.     
  1961.     /* find 'blackest' pixel */
  1962.     cval = 0x10000 * 3;
  1963.     for (i=0; i<nfcols; i++)
  1964.       if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) {
  1965.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  1966.     bl = ctab[i].pixel;
  1967.       }
  1968.  
  1969.     /* find 'whitest' pixel */
  1970.     cval = -1;
  1971.     for (i=0; i<nfcols; i++)
  1972.       if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
  1973.     cval = ctab[i].red + ctab[i].green + ctab[i].blue;
  1974.     wh = ctab[i].pixel;
  1975.       }
  1976.   }
  1977.  
  1978.   XSetFont(theDisp, theGC, monofont);
  1979.   w = XTextWidth(monofinfo,str,strlen(str));
  1980.  
  1981.   if (my > eHIGH/2) ty = 0;
  1982.                else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
  1983.  
  1984.   ox = oy = -1;  /* kludge to force redraw first time through */
  1985.  
  1986.   XSetForeground(theDisp, theGC, bl);
  1987.   XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8, 
  1988.          (monofinfo->ascent+monofinfo->descent) + 4);
  1989.   XSetForeground(theDisp, theGC, wh);
  1990.   XSetBackground(theDisp, theGC, bl);
  1991.  
  1992.   while (1) {
  1993.     int px, py, pix;
  1994.  
  1995.     if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  1996.       if (!(mask & Button1Mask)) break;    /* button released */
  1997.  
  1998.       RANGE(x,0,eWIDE-1);  
  1999.       RANGE(y,0,eHIGH-1);
  2000.  
  2001.       px = cXOFF + (x * cWIDE) / eWIDE;
  2002.       py = cYOFF + (y * cHIGH) / eHIGH;
  2003.  
  2004.       if (px!=ox || py!=oy) {                /* moved.  erase and redraw */
  2005.     pix = pic[py * pWIDE + px];
  2006.  
  2007.     sprintf(foo,"%4d,%4d = (%3d,%3d,%3d)  <%3d,%3d,%3d>", 
  2008.         px, py, rorg[pix],gorg[pix],borg[pix], r[pix],g[pix],b[pix]);
  2009.     XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, 
  2010.             foo, strlen(foo));
  2011.     ox = px;  oy = py;
  2012.       }
  2013.     }
  2014.   }
  2015.  
  2016.   XSetFont(theDisp, theGC, mfont);
  2017.   DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
  2018. }
  2019.  
  2020.  
  2021. /***********************************/
  2022. static void MakeDispNames()
  2023. {
  2024.   int   prelen, n, i, done;
  2025.   char *suffix;
  2026.  
  2027.   suffix = namelist[0];
  2028.   prelen = 0;   /* length of prefix to be removed */
  2029.   n = i = 0;    /* shut up pesky compiler warnings */
  2030.  
  2031.   done = 0;
  2032.   while (!done) {
  2033.     suffix = strchr(suffix,'/');    /* find next '/' in file name */
  2034.     if (!suffix) break;
  2035.  
  2036.     suffix++;                       /* go past it */
  2037.     n = suffix - namelist[0];
  2038.     for (i=1; i<numnames; i++) {
  2039.       if (strncmp(namelist[0], namelist[i], n)!=0) { done=1; break; }
  2040.     }
  2041.  
  2042.     if (!done) prelen = n;
  2043.   }
  2044.  
  2045.   for (i=0; i<numnames; i++)
  2046.     dispnames[i] = namelist[i] + prelen;
  2047. }
  2048.  
  2049.  
  2050. /***********************************/
  2051. static int CheckForConfig()
  2052. {
  2053.   XEvent ev;
  2054.   char   foo;
  2055.  
  2056.   /* returns true if there's a config event in which mainW changes size
  2057.      in the event queue */
  2058.  
  2059.   foo = 0;
  2060.   XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
  2061.   return foo;
  2062. }
  2063.  
  2064. static Bool IsConfig(dpy, ev, arg)
  2065. Display *dpy;
  2066. XEvent  *ev;
  2067. char    *arg;
  2068. {
  2069.   XConfigureEvent *cev;
  2070.  
  2071.   if (ev->type == ConfigureNotify) {
  2072.     cev = (XConfigureEvent *) ev;
  2073.     if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
  2074.       *arg = 1;
  2075.   }
  2076.   return False;
  2077. }
  2078.  
  2079.  
  2080. /***********************************/
  2081. void MakeRootPic()
  2082. {
  2083.   /* called after 'epic' has been generated (if we're using root).  
  2084.      creates the XImage and the pixmap, sets the root to the new
  2085.      pixmap, and refreshes the display */
  2086.  
  2087.   Pixmap tmpPix;
  2088.   int    i,j,k,w,h;
  2089.  
  2090.   XSetWindowBackgroundPixmap(theDisp, rootW, None);
  2091.   XClearWindow(theDisp, rootW);
  2092.   XFlush(theDisp);
  2093.  
  2094.   if (((fixedaspect && automax) || centerpic)
  2095.       && (eWIDE != dispWIDE || eHIGH != dispHIGH)) {
  2096.  
  2097.     /* center picture inside a dispWIDE x dispHIGH pixmap */
  2098.     w = eWIDE;  if (w>dispWIDE) w = dispWIDE;
  2099.     h = eHIGH;  if (h>dispHIGH) h = dispHIGH;
  2100.     tmpPix = XCreatePixmap(theDisp, mainW, dispWIDE, dispHIGH, dispDEEP);
  2101.     if (!tmpPix) FatalError("couldn't create root pixmap");
  2102.  
  2103.     /* do some stuff to set up the border around the picture */
  2104.  
  2105.     XSetForeground(theDisp, theGC, rootbg);
  2106.     XFillRectangle(theDisp, tmpPix, theGC, 0,0, dispWIDE, dispHIGH);
  2107.  
  2108.     switch (rootPattern) {
  2109.     case 0: /* solid color */ break;
  2110.  
  2111.     case 1: /* 'warp' effect */
  2112.             XSetForeground(theDisp, theGC, rootfg);
  2113.             for (i=0; i<=dispWIDE; i+=8) 
  2114.               XDrawLine(theDisp, tmpPix, theGC, i, 0, dispWIDE-i, dispHIGH);
  2115.             for (i=0; i<=dispHIGH; i+=8)
  2116.               XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, dispHIGH-i);
  2117.             break;
  2118.  
  2119.     case 2: /* 'bricks' effect */
  2120.             XSetForeground(theDisp, theGC, rootfg);
  2121.             for (i=k=0; i<dispHIGH; i+=20,k++) {
  2122.               XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, i);
  2123.           for (j=(k&1) * 20 + 10; j<dispWIDE; j+=40) 
  2124.         XDrawLine(theDisp, tmpPix, theGC, j,i,j,i+20);
  2125.         }
  2126.             break;
  2127.  
  2128.     /* your algorithm here */
  2129.  
  2130.     default: break;
  2131.     }
  2132.       
  2133.  
  2134.     XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 
  2135.           (dispWIDE-w)/2, (dispHIGH-h)/2, w, h);
  2136.   }
  2137.   else {
  2138.     tmpPix = XCreatePixmap(theDisp, mainW, eWIDE, eHIGH, dispDEEP);
  2139.     if (!tmpPix) FatalError("couldn't create root pixmap");
  2140.     XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0, eWIDE, eHIGH);
  2141.   }
  2142.  
  2143.   XSetWindowBackgroundPixmap(theDisp, mainW, tmpPix);
  2144.   XFreePixmap(theDisp, tmpPix);
  2145.  
  2146.   SaveRootInfo();
  2147.   XClearWindow(theDisp, mainW);
  2148. }
  2149.  
  2150.  
  2151.  
  2152. /***********************************/
  2153. static void SaveRootInfo()
  2154. {
  2155.   /* called when using root window.  stores the pixmap ID used to draw the
  2156.      root window in a property.  This will be used later to free all resources
  2157.      allocated by this instantiation of xv (ie, the alloc'd colors).  These
  2158.      resources are kept alloc'ed after client exits so that rainbow effect
  2159.      is avoided */
  2160.  
  2161.   Atom          prop;
  2162.   static Pixmap riPix = NULL;
  2163.  
  2164.   if ( !(theVisual->class & 1)) return;  /* no colormap to worry about */
  2165.  
  2166.   if (riPix) return;                     /* it's already been saved once */
  2167.  
  2168.   riPix = XCreatePixmap(theDisp, rootW, 1, 1, 1);
  2169.   if (!riPix) return;   /* unable to save.  thankfully, unlikely to happen */
  2170.  
  2171.   prop = XInternAtom(theDisp, "_XV_PIXMAP", False);
  2172.   if (!prop) FatalError("couldn't create _XV_PIXMAP atom");
  2173.  
  2174.   XChangeProperty(theDisp, rootW, prop, XA_PIXMAP, 32, PropModeReplace,
  2175.           (unsigned char *) &riPix, 1);
  2176.  
  2177.   XSetCloseDownMode(theDisp, RetainPermanent);
  2178. }
  2179.  
  2180.  
  2181. /***********************************/
  2182. static void KillOldRootInfo()
  2183. {
  2184.   /* get the pixmap ID from the _XV_PIXMAP property, and kill it */
  2185.  
  2186.   Atom           prop, type;
  2187.   int            format;
  2188.   unsigned long  length, after;
  2189.   unsigned char *data;
  2190.  
  2191.   prop = XInternAtom(theDisp, "_XV_PIXMAP", True);
  2192.   if (!prop) return;    /* no old pixmap to kill */
  2193.  
  2194.   if (XGetWindowProperty(theDisp, rootW, prop, 0L, 1L, True, AnyPropertyType,
  2195.              &type, &format, &length, &after, &data) == Success) {
  2196.  
  2197.     if (type==XA_PIXMAP && format==32 && length==1 && after==0 && data)
  2198.       XKillClient(theDisp, *((Pixmap *)data));
  2199.   }
  2200.  
  2201. }
  2202.  
  2203.  
  2204. /************************************************************************/
  2205. /* following three rd_* functions swiped from xgraph, by David Harrison */
  2206. /************************************************************************/
  2207.  
  2208. /***********************************/
  2209. static int rd_int(name)
  2210. char *name;
  2211. {
  2212.   /* returns '1' if successful.  result in def_int */
  2213.  
  2214.   if (def_str = XGetDefault(theDisp, PROGNAME, name)) {
  2215.     if (sscanf(def_str, "%ld", &def_int) == 1) return 1;
  2216.     else {
  2217.       fprintf(stderr, "%s: couldn't read integer value for %s resource\n", 
  2218.           cmd,name);
  2219.       return 0;
  2220.     }
  2221.   }
  2222.   else return 0;
  2223.  
  2224. }
  2225.  
  2226. /***********************************/
  2227. static int rd_str(name)
  2228. char *name;
  2229. {
  2230.   /* returns '1' if successful.  result in def_str */
  2231.   
  2232.   if (def_str = XGetDefault(theDisp, PROGNAME, name)) return 1;
  2233.   else return 0;
  2234.  
  2235. }
  2236.  
  2237. /***********************************/
  2238. static int rd_flag(name)
  2239. char *name;
  2240. {
  2241.   /* returns '1' if successful.  result in def_str */
  2242.   
  2243.   if (def_str = XGetDefault(theDisp, PROGNAME, name)) {
  2244.     def_int = (strcmp(def_str, "on")==0) || 
  2245.               (strcmp(def_str, "1")==0) ||
  2246.           (strcmp(def_str, "true")==0) ||
  2247.           (strcmp(def_str, "yes")==0);
  2248.     return 1;
  2249.     }
  2250.  
  2251.   else return 0;
  2252. }
  2253.     
  2254.  
  2255.  
  2256.  
  2257.  
  2258. \BARFOO\
  2259. else
  2260.   echo "will not over write ./xv.c"
  2261. fi
  2262. echo "Finished archive 9 of 10"
  2263. exit
  2264.  
  2265. dan
  2266. ----------------------------------------------------
  2267. O'Reilly && Associates   argv@sun.com / argv@ora.com
  2268. Opinions expressed reflect those of the author only.
  2269. --
  2270. dan
  2271. ----------------------------------------------------
  2272. O'Reilly && Associates   argv@sun.com / argv@ora.com
  2273. Opinions expressed reflect those of the author only.
  2274.