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

  1. Path: wuarchive!cs.utexas.edu!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: v10i083: xv - display and manipulate images, Part05/10
  5. Message-ID: <321@appserv.Eng.Sun.COM>
  6. Date: 27 Nov 90 20:08:23 GMT
  7. References: <csx-10i079:xv@uunet.UU.NET>
  8. Sender: news@exodus.Eng.Sun.COM
  9. Lines: 1886
  10. Approved: argv@sun.com
  11.  
  12. Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
  13. Posting-number: Volume 10, Issue 83
  14. Archive-name: xv/part05
  15.  
  16. #!/bin/sh
  17. # to extract, remove the header and type "sh filename"
  18. if `test ! -s ./xvinfo.c`
  19. then
  20. echo "writting ./xvinfo.c"
  21. cat > ./xvinfo.c << '\BARFOO\'
  22. /* 
  23.  * xvinfo.c - 'Info' box handling functions
  24.  *
  25.  * callable functions:
  26.  *
  27.  *   CreateInfo(geom)       -  creates the infoW window.  Doesn't map it.
  28.  *   InfoBox(vis)           -  random processing based on value of 'vis'
  29.  *                             maps/unmaps window, etc.
  30.  *   RedrawInfo(x,y,w,h)    -  called by 'expose' events
  31.  *   SetInfoMode(mode)      -  changes amount of info Info window shows
  32.  *   SetISTR(st, fmt, args) - sprintf's into ISTR #st.  Redraws it in window 
  33.  *   char *GetISTR(st)      - returns pointer to ISTR #st, or NULL if st bogus
  34.  */
  35.  
  36. /*
  37.  * Copyright 1989, 1990 by the University of Pennsylvania
  38.  *
  39.  * Permission to use, copy, and distribute for non-commercial purposes,
  40.  * is hereby granted without fee, providing that the above copyright
  41.  * notice appear in all copies and that both the copyright notice and this
  42.  * permission notice appear in supporting documentation.
  43.  *
  44.  * The software may be modified for your own purposes, but modified versions
  45.  * may not be distributed.
  46.  *
  47.  * This software is provided "as is" without any express or implied warranty.
  48.  */
  49.  
  50.  
  51. #define  NEEDSVARARGS
  52.  
  53. #include "xv.h"
  54. #include "bitmaps.h"
  55.  
  56. /* max length of an Info String */
  57. #define ISTRLEN 80
  58.  
  59. /* baseline of top line of text */
  60. #define TOPBASE (36 + penn_height/2 + 4 + 8 + ASCENT)
  61. #define STLEFT  100   /* left edge of strings */
  62.  
  63. static Pixmap graspPix, pennPix;
  64. static char istrs[NISTR][ISTRLEN];
  65.  
  66. #ifdef __STDC__
  67. static void DrawStrings(void);
  68. static void DrawFieldName(int);
  69. static void RedrawString(int);
  70. #else
  71. static void DrawStrings(), DrawFieldName(), RedrawString();
  72. #endif
  73.  
  74.  
  75.  
  76. /***************************************************/
  77. void CreateInfo(geom)
  78. char *geom;
  79. {
  80.   infoW = CreateWindow("xv info", geom, INFOWIDE, INFOHIGH, infofg, infobg);
  81.   if (!infoW) FatalError("can't create info window!");
  82.  
  83.   pennPix = XCreatePixmapFromBitmapData(theDisp, infoW, penn_bits, penn_width, 
  84.                   penn_height, infofg, infobg, dispDEEP);
  85.   graspPix = XCreatePixmapFromBitmapData(theDisp,infoW,grasp_bits,grasp_width, 
  86.                   grasp_height, infofg, infobg, dispDEEP);
  87. }
  88.   
  89.  
  90. /***************************************************/
  91. void InfoBox(vis)
  92. int vis;
  93. {
  94.   if (vis) XMapRaised(theDisp, infoW);
  95.   else     XUnmapWindow(theDisp, infoW);
  96.  
  97.   infoUp = vis;
  98. }
  99.  
  100.  
  101. /***************************************************/
  102. void RedrawInfo(x,y,w,h)
  103. int x,y,w,h;
  104. {
  105.   int  i;
  106.  
  107.   XSetForeground(theDisp, theGC, infofg);
  108.   XSetBackground(theDisp, theGC, infobg);
  109.  
  110.   /* draw the two icons */
  111.   XCopyArea(theDisp, pennPix, infoW, theGC, 0, 0, penn_width, penn_height,
  112.         36 - penn_width/2, 36 - penn_height/2);
  113.   XCopyArea(theDisp, graspPix, infoW, theGC, 0, 0, grasp_width, grasp_height,
  114.         INFOWIDE - 36 - grasp_width/2, 36 - grasp_height/2);
  115.  
  116.   /* draw the credits */
  117.   sprintf(str,"XV   -   %s",REVDATE);
  118.   CenterString(infoW, str, INFOWIDE/2, 36-LINEHIGH);
  119.   CenterString(infoW, "by John Bradley  (bradley@cis.upenn.edu)"
  120.            , INFOWIDE/2, 36);
  121.   CenterString(infoW, "(c) 1990, University of Pennsylvania",
  122.            INFOWIDE/2, 36+LINEHIGH);
  123.  
  124.   /* draw the dividing lines */
  125.   i = 36 + penn_height/2 + 4;
  126.   XDrawLine(theDisp, infoW, theGC, 0, i, INFOWIDE, i);
  127.   XDrawLine(theDisp, infoW, theGC, 0, i+2, INFOWIDE, i+2);
  128.  
  129.   XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-20, INFOWIDE, INFOHIGH-20);
  130.   XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-22, INFOWIDE, INFOHIGH-22);
  131.  
  132.   XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-40, INFOWIDE, INFOHIGH-40);
  133.   XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-42, INFOWIDE, INFOHIGH-42);
  134.  
  135.   DrawStrings();
  136. }
  137.  
  138.  
  139. /***************************************************/
  140. static void DrawStrings()
  141. {
  142.   int i;
  143.   for (i=0; i<6; i++) DrawFieldName(i);     /* draw the field titles */
  144.   for (i=0; i<NISTR; i++) RedrawString(i);  /* draw the field values */
  145.   XFlush(theDisp);
  146. }
  147.  
  148.  
  149. /***************************************************/
  150. static void DrawFieldName(fnum)
  151. int fnum;
  152. {
  153.   static char *fname[6] = {  "Filename:", "Format:", "Resolution:", 
  154.                  "Cropping:", "Expansion:", "Colors:" };
  155.  
  156.   XSetForeground(theDisp, theGC, infofg);
  157.   XSetBackground(theDisp, theGC, infobg);
  158.  
  159.   if (infoMode == INF_NONE || infoMode == INF_STR) return;
  160.   if (infoMode == INF_PART && fnum>=3) return;
  161.  
  162.   XDrawString(theDisp, infoW, theGC, 10, TOPBASE + fnum*LINEHIGH, 
  163.         fname[fnum], strlen(fname[fnum]));
  164. }
  165.  
  166.  
  167. /***************************************************/
  168. static void RedrawString(st)
  169. int st;
  170. {
  171.   /* erase area of string, and draw it with new contents */
  172.   
  173.   XSetForeground(theDisp, theGC, infofg);
  174.   XSetBackground(theDisp, theGC, infobg);
  175.  
  176.   if (infoMode == INF_NONE) return;
  177.   if (infoMode == INF_STR && st > ISTR_WARNING) return;
  178.   if (infoMode == INF_PART && st > ISTR_RES) return;
  179.  
  180.  
  181.   if (st == ISTR_INFO) {
  182.     XClearArea(theDisp, infoW, 0, INFOHIGH-19, INFOWIDE, 17, False);
  183.     CenterString(infoW, istrs[st], INFOWIDE/2, INFOHIGH-10);
  184.   }
  185.   else if (st == ISTR_WARNING) {
  186.     XClearArea(theDisp, infoW, 0, INFOHIGH-39, INFOWIDE, 17, False);
  187.     CenterString(infoW, istrs[st], INFOWIDE/2, INFOHIGH-30);
  188.   }
  189.   else {
  190.     XClearArea(theDisp,infoW,STLEFT,TOPBASE - ASCENT
  191.            + (st-ISTR_FILENAME)*LINEHIGH, INFOWIDE-STLEFT, LINEHIGH,False);
  192.     XDrawString(theDisp, infoW, theGC, STLEFT,TOPBASE
  193.         + (st-ISTR_FILENAME)*LINEHIGH,    istrs[st], strlen(istrs[st]));
  194.   }
  195. }
  196.  
  197.  
  198.  
  199. /***************************************************/
  200. void SetInfoMode(mode)
  201. int mode;
  202. {
  203.   int y1, y2;
  204.  
  205.   infoMode = mode;
  206.   if (infoUp) {   /* only do this if window is mapped */
  207.     y1 = TOPBASE - ASCENT;
  208.     y2 = INFOHIGH-43;
  209.  
  210.     XClearArea(theDisp, infoW, 0, y1, INFOWIDE, y2-y1, False);
  211.     XClearArea(theDisp, infoW, 0, INFOHIGH-39, INFOWIDE, 17, False);
  212.     XClearArea(theDisp, infoW, 0, INFOHIGH-19, INFOWIDE, 17, False);
  213.  
  214.     DrawStrings();
  215.   }
  216. }
  217.  
  218.  
  219. /***************************************************/
  220. /*VARARGS0*/
  221. void SetISTR(va_alist)
  222. va_dcl
  223. {
  224.   va_list args;
  225.   char    *fmt;
  226.   int     stnum;
  227.  
  228.   /* InfoStr( ISTR, format, arg1, arg2, ...) */
  229.  
  230.   va_start(args);
  231.  
  232.   stnum = va_arg(args, int);
  233.   if (stnum<0 || stnum>=NISTR) return;
  234.  
  235.   fmt = va_arg(args, char *);
  236.   vsprintf(istrs[stnum], fmt, args);
  237.   va_end(args);
  238.   
  239.   if (infoUp) {
  240.     RedrawString(stnum);
  241.     XFlush(theDisp);
  242.   }
  243.  
  244.   if (ctrlUp && stnum == ISTR_INFO) {
  245.     DrawCtrlStr();
  246.     XFlush(theDisp);
  247.   }
  248. }
  249.  
  250.  
  251. /***************************************************/
  252. char *GetISTR(stnum)
  253. int stnum;
  254. {
  255.   /* returns pointer to ISTR string */
  256.   if (stnum < 0 || stnum>=NISTR) return(NULL);
  257.   return (istrs[stnum]);
  258. }
  259.  
  260.  
  261. \BARFOO\
  262. else
  263.   echo "will not over write ./xvinfo.c"
  264. fi
  265. if `test ! -s ./xvmisc.c`
  266. then
  267. echo "writting ./xvmisc.c"
  268. cat > ./xvmisc.c << '\BARFOO\'
  269. /*
  270.  * xvmisc.c - random routines that most of the work involved in putting
  271.  *            a picture on an X display.
  272.  *
  273.  *  Resize(w,h)    -  generates epic, new Ximage,
  274.  *  SortColormap() -  sorts the desired colormap into a 'most important color
  275.  *                    to allocate first' order
  276.  *  AllocColors()  -  Takes the desired colormap and sees what it can do about
  277.  *                    getting it.
  278.  *  DoCrop()       -  crops the picture
  279.  *  UnCrop()       -  uncrops the picture (natch)
  280.  *  Rotate()       -  rotates 'pic' 90-degrees clockwise
  281.  *  FloydDitherize8 - Takes epic, and produces a b/w dithered version of it,
  282.  *                    stored in 8-bit per pixel format
  283.  *  FloydDitherize1 - Does the same, but the output is an XYBitmap (1 bit per
  284.  *                    pixel, packed 8 pixels to a byte.
  285.  *  CreateXImage    - Given epic, generate an ximage of it.  Handles displays
  286.  *                    of different depths.
  287.  *  CenterString    - civilized string drawing routine.  uses font 'mfinfo'
  288.  *  ULineString     - draws underlined string.  uses font 'mfinfo'
  289.  *  StringWidth     - civilized XTextWidth width interface, uses font 'mfinfo'
  290.  *  FakeButtonPress - when a keyboard equiv is hit, fakes mouse click in button
  291.  *  Timer           - sleeps for a given # of milliseconds
  292.  */
  293.  
  294. /*
  295.  * Copyright 1989, 1990 by the University of Pennsylvania
  296.  *
  297.  * Permission to use, copy, and distribute for non-commercial purposes,
  298.  * is hereby granted without fee, providing that the above copyright
  299.  * notice appear in all copies and that both the copyright notice and this
  300.  * permission notice appear in supporting documentation.
  301.  *
  302.  * The software may be modified for your own purposes, but modified versions
  303.  * may not be distributed.
  304.  *
  305.  * This software is provided "as is" without any express or implied warranty.
  306.  */
  307.  
  308.  
  309. #define NEEDSTIME
  310. #include "xv.h"
  311. #include "bitmaps.h"
  312.  
  313. #ifdef __STDC__
  314. static void DoCrop1(int, int, int, int);
  315. static void RotatePic(byte *, unsigned int *, unsigned int *, int);
  316. static void FloydDitherize8(byte *);
  317. static void FloydDitherize1(XImage *);
  318. static void FreeMostResources(void);
  319. #else
  320. static void DoCrop1(), RotatePic(), FloydDitherize8(), FloydDitherize1();
  321. static void FreeMostResources();
  322. #endif
  323.  
  324.  
  325. /***************************************************/
  326. Window CreateWindow(name,geom,w,h,fg,bg)
  327. char         *name, *geom;
  328. unsigned int  w,h;
  329. unsigned long fg, bg;
  330. {
  331.   Window               win;
  332.   XSetWindowAttributes xswa;
  333.   unsigned int         xswamask;
  334.   XWMHints             xwmh;
  335.   XSizeHints           hints;
  336.   int                  i,x,y;
  337.  
  338.   /* note that only x,y are gotten from geom spec.  w,h are fixed */
  339.   x = y = 1;
  340.   i = XParseGeometry(geom,&x,&y,&w,&h);
  341.  
  342.   if (i&XValue || i&YValue) hints.flags = USPosition;  
  343.                        else hints.flags = PPosition;
  344.  
  345.   hints.flags |= USSize;
  346.  
  347.   if (i&XValue && i&XNegative) x = dispWIDE - w - abs(x);
  348.   if (i&YValue && i&YNegative) y = dispHIGH - h - abs(y);
  349.  
  350.   hints.x = x;                  hints.y = y;
  351.   hints.width = w;              hints.height = h;
  352.   hints.min_width  = w;         hints.min_height = h;
  353.   hints.max_width  = w;         hints.max_height = h;
  354.   hints.flags |= PMaxSize | PMinSize;
  355.  
  356.   xswa.background_pixel = bg;
  357.   xswa.border_pixel     = fg;
  358.   xswamask = CWBackPixel | CWBorderPixel;
  359.  
  360.   win = XCreateWindow(theDisp, rootW, x, y, w, h, 
  361.             bwidth, CopyFromParent, CopyFromParent,
  362.             CopyFromParent, xswamask, &xswa);
  363.   if (!win) return(win);   /* leave immediately if couldn't create */
  364.  
  365.   XSetStandardProperties(theDisp, win, name, name, None, NULL, 0, &hints);
  366.  
  367.   xwmh.input = True;
  368.   xwmh.flags = InputHint;
  369.   if (iconPix) { xwmh.icon_pixmap = iconPix;  xwmh.flags |= IconPixmapHint; }
  370.   XSetWMHints(theDisp, win, &xwmh);
  371.  
  372.   return(win);
  373. }
  374.   
  375.  
  376.  
  377. /***********************************/
  378. void Resize(w,h)
  379. int w,h;
  380. {
  381.   int          cy,ex,ey,*cxarr, *cxarrp;
  382.   byte        *clptr,*elptr,*epptr;
  383.   static char *rstr = "Resizing Image.  Please wait...";
  384.  
  385.   clptr = NULL;  cxarrp = NULL;  cy = 0;  /* shut up compiler */
  386.   /* force w,h into valid ranges */
  387.   RANGE(w,1,dispWIDE);  RANGE(h,1,dispHIGH);
  388.  
  389.   SetISTR(ISTR_EXPAND, "%.3g x %.3g  (%d x %d)",
  390.       ((float) w) / cWIDE, ((float) h) / cHIGH, w, h);
  391.  
  392.   /* if same size, and Ximage created, do nothing */
  393.   if (w==eWIDE && h==eHIGH && theImage!=NULL) return;
  394.  
  395.   if (DEBUG) fprintf(stderr,"%s: Resize(%d,%d)  eSIZE=%d,%d  cSIZE=%d,%d\n",
  396.              cmd,w,h,eWIDE,eHIGH,cWIDE,cHIGH);
  397.  
  398.   BTSetActive(&but[BCROP],0);
  399.   SetCropString();
  400.  
  401.   if (w==cWIDE && h==cHIGH) {  /* 1:1 expansion.  point epic at cpic */
  402.     if (epic != cpic && epic!=NULL) free(epic);
  403.     epic = cpic;  eWIDE = cWIDE;  eHIGH = cHIGH;
  404.   }
  405.  
  406.   else {  /* have to actually SCALE THE PIC.  Drats! */
  407.     StartFish();
  408.     WaitCursor();
  409.  
  410.     /* if it's a big image, this could take a while.  mention it */
  411.     if (w*h>(500*500) && !useroot) {
  412.       XSetForeground(theDisp, theGC, fg);
  413.       XSetBackground(theDisp, theGC, bg);
  414.       XClearWindow(theDisp,mainW);
  415.       XFlush(theDisp);
  416.       XDrawImageString(theDisp,mainW,theGC,CENTERX(mfinfo,w/2,rstr),
  417.                CENTERY(mfinfo,h/2),rstr, strlen(rstr));
  418.       XFlush(theDisp);
  419.     }
  420.  
  421.     /* first, kill the old epic, if one exists */
  422.     if (epic!=NULL && epic!=cpic) {
  423.       free(epic);  epic = NULL;
  424.     }
  425.  
  426.     /* create a new epic of the appropriate size */
  427.     eWIDE = w;  eHIGH = h;
  428.     epic = (byte *) malloc(w*h);
  429.     if (epic==NULL) {
  430.       sprintf(str,"unable to malloc a %dx%d image\n",w,h);
  431.       FatalError(str);
  432.     }
  433.  
  434.     /* the scaling routine.  not really all that scary after all... */
  435.  
  436.     /* OPTIMIZATON IDEA.  Malloc an eWIDE array of ints which will hold the
  437.        values of the equation px = (pWIDE * ex) / eWIDE.  Faster than doing 
  438.        a mul and a div for every point in picture */
  439.  
  440.     cxarr = (int *) malloc(eWIDE * sizeof(int));
  441.     if (!cxarr) FatalError("unable to allocate cxarr");
  442.     for (ex=0; ex<eWIDE; ex++) cxarr[ex] = (cWIDE * ex) / eWIDE;
  443.  
  444.     elptr = epptr = epic;
  445.     for (ey=0;  ey<eHIGH;  ey++, elptr+=eWIDE) {
  446.       if ((ey&127) == 0) WaitCursor();
  447.       cy = (cHIGH * ey) / eHIGH;
  448.       epptr = elptr;
  449.       clptr = cpic + (cy * cWIDE);
  450.       for (ex=0, cxarrp = cxarr;  ex<eWIDE;  ex++, epptr++) 
  451.     *epptr = clptr[*cxarrp++];
  452.     }
  453.     free(cxarr);
  454.   }
  455.  
  456.   /* now make something displayable out of epic */
  457.   CreateXImage();
  458.   StopFish();
  459. }
  460.                 
  461.  
  462.  
  463.  
  464. /************************************************/
  465. /* structure and routine used in SortColormap() */
  466. /************************************************/
  467.  
  468. typedef struct thing 
  469.     { byte r,g,b; 
  470.       int oldindex; 
  471.       int use; } CMAPENT;
  472.  
  473.  
  474. static int CMAPcompare(a,b)
  475. CMAPENT *a,*b;
  476. {
  477.   return (b->use - a->use);
  478. }
  479.  
  480.  
  481. /***********************************/
  482. void SortColormap()
  483. {
  484.   byte *p;
  485.   int   i, j, k, mdist, entry, mn, d, hist[256], trans[256];
  486.   static CMAPENT c[256], c1[256], *cp, *cj, *ck;
  487.  
  488.  
  489.   /* no point doing this if we're on a 1-bit display */
  490.   if (ncols == 0) { numcols = 256; return; }
  491.   
  492.   /* initialize histogram and compute it */
  493.   for (i=0; i<256; i++) hist[i]=0;
  494.   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) hist[*p]++;
  495.   
  496.   if (DEBUG>1) {
  497.     fprintf(stderr,"%s: Desired colormap\n",cmd);
  498.     for (i=0; i<256; i++) 
  499.       if (hist[i]) fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",
  500.                i,r[i],g[i],b[i]);
  501.     fprintf(stderr,"\n\n");
  502.   }
  503.   
  504.   
  505.   /* put the actually-used colors into the 'c' array in the order they occur */
  506.   /* also, while we're at it, calculate numcols */
  507.   for (i=numcols=0; i<256; i++) {
  508.     if (hist[i]) { 
  509.       cp = &c[numcols++];
  510.       cp->r = r[i];  cp->g = g[i];  cp->b = b[i];
  511.       cp->use = hist[i];  cp->oldindex = i;
  512.     }
  513.   }
  514.  
  515.  
  516.   /* find most-used color, put that in c1[0] */
  517.   entry = -1;  mdist = -1;
  518.   for (i=0; i<numcols; i++) {
  519.     if (c[i].use > mdist) { mdist = c[i].use;  entry=i; }
  520.   }
  521.   memcpy(&c1[0], &c[entry], sizeof(CMAPENT));
  522.   c[entry].use = 0;   /* and mark it dealt with */
  523.   
  524.   
  525.   /* sort rest of colormap, in order of decreasing 'distance' from already
  526.      allocated elements.
  527.   
  528.      FURTHER MODIFICATION of algorithm.  The algorithm's performance
  529.      utterly goes to hell as numcols increases.  (Probably on the order
  530.      of O^3 performance).  Since I don't see a clever way of rewriting
  531.      the algorithm for O^2 performance (which'd be acceptable), I'm going
  532.      to make a trade-off.  I'll only run the algorithm for the first 32 colors
  533.      (or so).  It can do that Real Fast.  Then I'll just stick the rest of
  534.      the unsorted colors (if any), and tack them on the end, in order of
  535.      amount of use.  This should give similar picture quality, with 
  536.      much higher performance. */
  537.  
  538.   for (i=1; i<numcols && i<32; i++) {
  539.     /* find the i'th most different color */
  540.     entry = -1;  mdist = -1;
  541.     for (j=0, cj=c; j<numcols; j++,cj++) {
  542.       if (cj->use) {  /* this color has not been marked already */
  543.     mn = 10000;
  544.     for (k=0, ck=c1; k<i; k++,ck++) {
  545.       d = abs(cj->r - ck->r) + abs(cj->g - ck->g) + abs(cj->b - ck->b);
  546.       if (mn>d) mn=d;
  547.     }
  548.     /* mn = minimum distance from c[j] to already used colors */
  549.     /* we want to select the unused color that has the greatest mn */
  550.     if (mn > mdist) { mdist = mn;  entry = j; }
  551.       }
  552.     }
  553.     
  554.     /* c[entry] is the next color to put in the map.  do so */
  555.     memcpy(&c1[i], &c[entry], sizeof(CMAPENT));
  556.     c[entry].use = 0;
  557.   }
  558.   
  559.   /* tack rest of colors onto colormap in decreasing order of use */
  560.   qsort((char *) c,numcols,sizeof(CMAPENT),CMAPcompare);
  561.   memcpy(&c1[i], c, (numcols - i) * sizeof(CMAPENT));
  562.  
  563.  
  564.   /* build translation table */
  565.   for (i=0; i<numcols; i++) trans[ c1[i].oldindex ] = i;
  566.   
  567.   /* modify 'pic' to reflect the new colormap */
  568.   for (i=pWIDE*pHIGH, p=pic; i; i--, p++) *p = trans[*p];
  569.   
  570.   /* and copy the new colormap into *the* colormap */
  571.   for (i=0; i<numcols; i++) {
  572.     r[i] = c1[i].r;  g[i] = c1[i].g;  b[i] = c1[i].b;
  573.   }
  574.   
  575.   if (DEBUG>1) {
  576.     fprintf(stderr,"%s: result of sorting colormap\n",cmd);
  577.     for (i=0; i<numcols; i++) 
  578.       fprintf(stderr,"(%3d  %02x,%02x,%02x)     ",i,r[i],g[i],b[i]);
  579.     fprintf(stderr,"\n\n");
  580.     
  581.     fprintf(stderr,"%s: translate table\n",cmd);
  582.     for (i=0; i<numcols; i++) 
  583.       fprintf(stderr,"%3d->%3d  ",i,trans[i]);
  584.     fprintf(stderr,"\n\n");
  585.   }
  586.   
  587. }
  588.  
  589.  
  590.  
  591. #define NOPIX 0xffffffff    
  592.  
  593. /***********************************/
  594. void AllocColors()
  595. {
  596.   int      i, j, unique, p2alloc, p3alloc;
  597.   Colormap cmap;
  598.   XColor   defs[256];
  599.   XColor   ctab[256];
  600.   int      dc;
  601.  
  602.  
  603.   nfcols = unique = p2alloc = p3alloc = 0;
  604.   rwthistime = 0;
  605.  
  606.  
  607.   if (ncols == 0) {
  608.     SetISTR(ISTR_COLOR,"no colors allocated.  Using black & white.");
  609.     SetISTR(ISTR_COLOR2,"");
  610.     return;
  611.   }
  612.  
  613.  
  614.   /* FIRST PASS COLOR ALLOCATION:  
  615.      for each color in the 'desired colormap', try to get it via
  616.      XAllocColor().  If for any reason it fails, mark that pixel
  617.      'unallocated' and worry about it later.  Repeat. */
  618.  
  619.   /* attempt to allocate first ncols entries in colormap 
  620.      note: On displays with less than 8 bits per RGB gun, it's quite
  621.      possible that different colors in the original picture will be
  622.      mapped to the same color on the screen.  X does this for you
  623.      silently.  However, this is not-desirable for this application, 
  624.      because when I say 'allocate me 32 colors' I want it to allocate
  625.      32 different colors, not 32 instances of the same 4 shades... */
  626.   
  627.   for (i=0; i<numcols; i++) cols[i] = NOPIX;
  628.   
  629.   cmap = theCmap;
  630.   for (i=0; i<numcols && unique<ncols; i++) {
  631.     defs[i].red   = r[i]<<8;
  632.     defs[i].green = g[i]<<8;
  633.     defs[i].blue  = b[i]<<8;
  634.     defs[i].flags = DoRed | DoGreen | DoBlue;
  635.     
  636.     if (XAllocColor(theDisp, cmap, &defs[i])) { 
  637.       unsigned long pixel, *fcptr;
  638.       
  639.       pixel = cols[i] = defs[i].pixel;
  640.       
  641.       /* see if the newly allocated color is new and different */
  642.       for (j=0, fcptr=freecols; j<nfcols && *fcptr!=pixel; j++,fcptr++);
  643.       if (j==nfcols) unique++;
  644.       
  645.       fc2pcol[nfcols] = i;
  646.       freecols[nfcols++] = pixel;
  647.     }
  648.  
  649.     else {
  650.       /* the allocation failed.  If we want 'perfect' color, and we haven't 
  651.      already created our own colormap, we'll want to do so */
  652.       if (perfect && !LocalCmap) {
  653.     LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
  654.     XSetWindowColormap(theDisp,mainW, LocalCmap);
  655.     cmap = LocalCmap;
  656.     i--;      /* redo the allocation request */
  657.       }
  658.  
  659.       else
  660.     /* either we don't care about perfect color, or we do care, have
  661.        allocated our own colormap, and have STILL run out of colors
  662.        (possible, even on an 8 bit display), just mark pixel as
  663.        unallocated.  We'll deal with it later */
  664.     cols[i] = NOPIX;
  665.     }
  666.   }  /* FIRST PASS */
  667.   
  668.   
  669.   
  670.   if (nfcols==numcols) {
  671.     if (numcols != unique)
  672.       SetISTR(ISTR_COLOR,"Got all %d desired colors.  (%d unique)", numcols,
  673.           unique);
  674.     else
  675.       SetISTR(ISTR_COLOR,"Got all %d desired colors.", numcols);
  676.  
  677.     SetISTR(ISTR_COLOR2,"");
  678.     return;
  679.   }
  680.   
  681.  
  682.  
  683.   /* SECOND PASS COLOR ALLOCATION:
  684.      Allocating 'exact' colors failed.  Now try to allocate 'closest'
  685.      colors.
  686.  
  687.      Read entire X colormap (or first 256 entries) in from display.
  688.      for each unallocated pixel, find the closest color that actually
  689.      is in the X colormap.  Try to allocate that color (read only).
  690.      If that fails, the THIRD PASS will deal with it */
  691.  
  692.   SetISTR(ISTR_COLOR,"Got %d out of %d colors.  (%d unique)", 
  693.       nfcols,numcols,unique);
  694.  
  695.  
  696.   /* read entire colormap (or first 256 entries) into 'ctab' */
  697.   dc = (ncells<256) ? ncells : 256;
  698.   for (i=0; i<dc; i++) ctab[i].pixel = (unsigned long) i;
  699.  
  700.   XQueryColors(theDisp, cmap, ctab, dc);
  701.  
  702.   for (i=0; i<numcols && unique<ncols; i++)
  703.     if (cols[i]==NOPIX) {  /* an unallocated pixel */
  704.       int           d, mdist, close;
  705.       unsigned long ri,gi,bi;
  706.  
  707.       mdist = 100000;   close = -1;
  708.       ri = r[i];  gi = g[i];  bi = b[i];
  709.       
  710.       for (j=0; j<dc; j++) {
  711.     d = abs(ri - (ctab[j].red>>8)) +
  712.         abs(gi - (ctab[j].green>>8)) +
  713.         abs(bi - (ctab[j].blue>>8));
  714.     if (d<mdist) { mdist=d; close=j; }
  715.       }
  716.  
  717.       if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  718.       if (XAllocColor(theDisp, cmap, &ctab[close])) { 
  719.     memcpy(&defs[i], &ctab[close], sizeof(XColor));
  720.     cols[i] = ctab[close].pixel;
  721.     fc2pcol[nfcols] = i;
  722.     freecols[nfcols++] = cols[i];
  723.     p2alloc++;
  724.     unique++;
  725.       }
  726.     }
  727.  
  728.  
  729.  
  730.   /* THIRD PASS COLOR ALLOCATION:
  731.      We've alloc'ed all the colors we can.  Now, we have to map any
  732.      remaining unalloced pixels into either A) the colors that we DID get
  733.      (noglob), or B) the colors found in the X colormap */
  734.  
  735.   for (i=0; i<numcols; i++) {
  736.     if (cols[i] == NOPIX) {  /* an unallocated pixel */
  737.       int           d, k, mdist, close;
  738.       unsigned long ri,gi,bi;
  739.  
  740.       mdist = 100000;   close = -1;
  741.       ri = r[i];  gi = g[i];  bi = b[i];
  742.       
  743.       if (!noglob) {   /* search the entire X colormap */
  744.     for (j=0; j<dc; j++) {
  745.       d = abs(ri - (ctab[j].red>>8)) +
  746.           abs(gi - (ctab[j].green>>8)) +
  747.           abs(bi - (ctab[j].blue>>8));
  748.       if (d<mdist) { mdist=d; close=j; }
  749.     }
  750.     if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  751.     memcpy(&defs[i], &ctab[close], sizeof(XColor));
  752.     cols[i] = defs[i].pixel;
  753.     p3alloc++;
  754.       }
  755.       
  756.       else {                     /* only search the alloc'd colors */
  757.     for (j=0; j<nfcols; j++) {
  758.       k = fc2pcol[j];
  759.       d = abs(ri - (defs[k].red>>8)) +
  760.           abs(gi - (defs[k].green>>8)) +
  761.           abs(bi - (defs[k].blue>>8));
  762.       if (d<mdist) { mdist=d;  close=k; }
  763.     }
  764.     if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  765.     memcpy(&defs[i], &defs[close], sizeof(XColor));
  766.     cols[i] = defs[i].pixel;
  767.       }
  768.     }
  769.   }  /* THIRD PASS */
  770.  
  771.  
  772.   if (p2alloc && p3alloc)
  773.     SetISTR(ISTR_COLOR2,"Got %d 'close' color%s.  'Borrowed' %d color%s.",
  774.         p2alloc, (p2alloc>1) ? "s" : "", 
  775.         p3alloc, (p3alloc>1) ? "s" : "");
  776.  
  777.   else if (p2alloc && !p3alloc) 
  778.     SetISTR(ISTR_COLOR2,"Got %d 'close' color%s.",
  779.         p2alloc, (p2alloc>1) ? "s" : "");
  780.  
  781.   else if (!p2alloc && p3alloc) 
  782.     SetISTR(ISTR_COLOR2,"'Borrowed' %d color%s.",
  783.         p3alloc, (p3alloc>1) ? "s" : "");
  784. }
  785.  
  786.  
  787.  
  788. /***********************************/
  789. void AllocRWColors()
  790. {
  791.   int i,j;
  792.   Colormap cmap;
  793.   XColor   defs[256];
  794.  
  795.   nfcols = 0;   rwthistime = 1;
  796.  
  797.   if (ncols == 0) {
  798.     SetISTR(ISTR_COLOR,"no colors allocated.  Using black & white.");
  799.     SetISTR(ISTR_COLOR2,"");
  800.     rwthistime = 0;
  801.     return;
  802.   }
  803.  
  804.  
  805.   cmap = theCmap;
  806.  
  807.   for (i=0; i<numcols; i++) cols[i] = NOPIX;
  808.  
  809.   for (i=0; i<numcols && i<ncols; i++) {
  810.     unsigned long pmr[1], pix[1];
  811.     if (XAllocColorCells(theDisp, cmap, False, pmr, 0, pix, 1)) {
  812.       defs[i].pixel = cols[i] = pix[0];
  813.       defs[i].red   = r[i]<<8;
  814.       defs[i].green = g[i]<<8;
  815.       defs[i].blue  = b[i]<<8;
  816.       defs[i].flags = DoRed | DoGreen | DoBlue;
  817.  
  818.       fc2pcol[nfcols]    = i;
  819.       freecols[nfcols++] = pix[0];
  820.       }
  821.  
  822.     else {
  823.       if (perfect && !LocalCmap) {
  824.     LocalCmap = XCopyColormapAndFree(theDisp,theCmap);
  825.     XSetWindowColormap(theDisp,mainW, LocalCmap);
  826.     cmap = LocalCmap;
  827.     i--;      /* redo the allocation request */
  828.       }
  829.  
  830.       else cols[i] = NOPIX;
  831.     }
  832.   }  /* for (i=0; ... */
  833.  
  834.  
  835.  
  836.   if (nfcols==numcols) {
  837.     SetISTR(ISTR_COLOR,"Got all %d desired colors.", numcols);
  838.     SetISTR(ISTR_COLOR2,"");
  839.   }
  840.  
  841.   else {
  842.     /* Failed to allocate all colors in picture.  Map remaining desired 
  843.        colors into closest allocated desired colors */
  844.  
  845.       if (nfcols==0) {
  846.     SetISTR(ISTR_COLOR,"No r/w cells available.  Using r/o color.");
  847.     AllocColors();
  848.     return;
  849.       }
  850.     
  851.       SetISTR(ISTR_COLOR,"Got %d out of %d colors.",  nfcols,numcols);
  852.  
  853.       for (i=0; i<numcols; i++)
  854.     if (cols[i]==NOPIX) {  /* an unallocated pixel */
  855.       int           k, d, mdist, close;
  856.       unsigned long ri,gi,bi;
  857.  
  858.       mdist = 100000;   close = -1;
  859.       ri = r[i];  gi = g[i];  bi = b[i];
  860.  
  861.       for (j=0; j<nfcols; j++) {
  862.         k = fc2pcol[j];
  863.         d = abs(ri - (defs[k].red>>8)) + abs(gi - (defs[k].green>>8)) +
  864.             abs(bi - (defs[k].blue>>8));
  865.         if (d<mdist) { mdist=d; close=k; }
  866.       }
  867.  
  868.       if (close<0) FatalError("This Can't Happen! (How reassuring.)");
  869.       cols[i] = defs[close].pixel;
  870.     }
  871.     }
  872.  
  873.   /* load up the allocated colorcells */
  874.   for (i=0; i<nfcols; i++) {
  875.     j = fc2pcol[i];
  876.     defs[i].pixel = freecols[i];
  877.     defs[i].red   = r[j]<<8;
  878.     defs[i].green = g[j]<<8;
  879.     defs[i].blue  = b[j]<<8;
  880.     defs[i].flags = DoRed | DoGreen | DoBlue;
  881.     /* fprintf(stderr,"StoreColors: %3d = %3d,%3d,%3d\n",
  882.        defs[i].pixel,r[j],g[j],b[j]); */
  883.   }
  884.   XStoreColors(theDisp, cmap, defs, nfcols);
  885.   XStoreColor(theDisp, cmap, &defs[0]);   /* bug in XStoreColors call */
  886. }
  887.  
  888.  
  889.  
  890. /***********************************/
  891. void DoMonoAndRV()
  892. {
  893.   int i;
  894.  
  895.   /* operate on original colors, before any gamma correction */
  896.   for (i=0; i<numcols; i++) {
  897.     r[i] = rorg[i];  g[i] = gorg[i];  b[i] = borg[i];
  898.   }
  899.  
  900.   if (mono || ncols==0)  /* if monochrome, mono-ify the desired colormap */
  901.     for (i=0; i<numcols; i++)
  902.       r[i] = g[i] = b[i] = MONO(r[i],g[i],b[i]);
  903.  
  904.   if (revvideo)  /* reverse the desired colormaps */
  905.     for (i=0; i<numcols; i++) {
  906.       r[i] = 255-r[i];  g[i] = 255-g[i];  b[i] = 255-b[i];
  907.     }
  908. }
  909.  
  910.  
  911. /***********************************/
  912. void DoCrop()
  913. {
  914.   int i, x, y, x2, y2, w, h;
  915.  
  916.   if (!but[BCROP].active) return;
  917.  
  918.   /* turn off the cropping rectangle */
  919.   InvCropRect();  BTSetActive(&but[BCROP],0);
  920.  
  921.   /* sort crx1,crx2,cry1,cry2 so that crx1,cry1 are top left corner */
  922.   if (crx1>crx2) { i = crx1; crx1 = crx2; crx2 = i; }
  923.   if (cry1>cry2) { i = cry1; cry1 = cry2; cry2 = i; }
  924.  
  925.   /* see if cropping to same size, in which case do nothing */
  926.   if (crx2-crx1 == eWIDE && cry2-cry1 == eHIGH) return;
  927.  
  928.   /* figure out what the crop rectangles coordinates are in pic coordinates */
  929.   x = cXOFF + (crx1 * cWIDE) / eWIDE;
  930.   y = cYOFF + (cry1 * cHIGH) / eHIGH;
  931.   x2 = cXOFF + (crx2 * cWIDE) / eWIDE;
  932.   y2 = cYOFF + (cry2 * cHIGH) / eHIGH;
  933.   w = (x2 - x) + 1;
  934.   h = (y2 - y) + 1;
  935.  
  936.   if (w<1) w = 1;
  937.   if (x+w > pWIDE) w = pWIDE - x;
  938.   if (h<1) h = 1;
  939.   if (y+h > pHIGH) h = pHIGH - y;
  940.  
  941.   DoCrop1(x,y,w,h);
  942. }
  943.  
  944.  
  945. static void DoCrop1(x,y,w,h)
  946. int x,y,w,h;
  947. {
  948.   int   i,j;
  949.   byte *cp, *pp;
  950.   double expw, exph;
  951.  
  952.   /* dispose of old cpic and epic */
  953.   if (epic && epic != cpic) free(epic);
  954.   if (cpic && cpic !=  pic) free(cpic);
  955.   epic = cpic = NULL;
  956.  
  957.   expw = (double) eWIDE / (double) cWIDE;
  958.   exph = (double) eHIGH / (double) cHIGH;
  959.  
  960.   crx1 = (int) ((x - cXOFF) * expw);
  961.   cry1 = (int) ((y - cYOFF) * exph);
  962.  
  963.   cXOFF = x;  cYOFF = y;  cWIDE = w;  cHIGH = h;
  964.   if (DEBUG) fprintf(stderr,"%s: cropping to %dx%d rectangle at %d,%d\n",
  965.              cmd, cWIDE, cHIGH, cXOFF, cYOFF);
  966.  
  967.   /* kill old Ximage so that Resize will be forced to generate a new one */
  968.   if (theImage != NULL) XDestroyImage(theImage);
  969.   theImage = NULL;
  970.  
  971.   /* at this point, we want to generate cpic, which will contain a
  972.      cWIDE*cHIGH subsection of 'pic', top-left at cXOFF,cYOFF */
  973.  
  974.   cpic = (byte *) malloc(cWIDE * cHIGH);
  975.   if (cpic == NULL) {
  976.     fprintf(stderr,"%s: unable to allocate memory for cropped image\n", cmd);
  977.     WUnCrop();
  978.     cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
  979.     SetCropString();
  980.     return;
  981.   }
  982.  
  983.   /* copy relevant pixels from pic to cpic */
  984.   cp = cpic;
  985.   for (i=0; i<cHIGH; i++) {
  986.     pp = pic + (i+cYOFF) * pWIDE + cXOFF;
  987.     for (j=0; j<cWIDE; j++) 
  988.       *cp++ = *pp++;
  989.   }
  990.  
  991.   SetCropString();
  992.   BTSetActive(&but[BUNCROP],1);
  993.  
  994.   /* shrink window */
  995.  
  996.   WCrop((int) (cWIDE * expw), (int) (cHIGH * exph));
  997. }
  998.  
  999.  
  1000.  
  1001. /***********************************/
  1002. void UnCrop()
  1003. {
  1004.   int w,h;
  1005.  
  1006.   if (cpic == pic) return;     /* not cropped */
  1007.  
  1008.   BTSetActive(&but[BUNCROP],0);
  1009.  
  1010.   /* dispose of old cpic and epic */
  1011.   if (epic && epic != cpic) free(epic);
  1012.   if (cpic && cpic !=  pic) free(cpic);
  1013.   epic = cpic = NULL;
  1014.   
  1015.   /* kill old Ximage so that Resize will be forced to generate a new one */
  1016.   if (theImage != NULL) XDestroyImage(theImage);
  1017.   theImage = NULL;
  1018.  
  1019.   w = (pWIDE * eWIDE) / cWIDE;
  1020.   h = (pHIGH * eHIGH) / cHIGH;
  1021.   RANGE(w,1,dispWIDE);  RANGE(h,1,dispHIGH);
  1022.  
  1023.   WUnCrop();
  1024.   cpic = pic;  cXOFF = cYOFF = 0;  cWIDE = pWIDE;  cHIGH = pHIGH;
  1025.   SetCropString();
  1026. }
  1027.   
  1028.  
  1029. /***********************************/
  1030. void AutoCrop()
  1031. {
  1032.   byte *cp, *cp1;
  1033.   int  i, ctop, cbot, cleft, cright;
  1034.   byte bgcol;
  1035.  
  1036.   ctop = cbot = cleft = cright = 0;
  1037.  
  1038.   /* crop the top */
  1039.   cp = cpic;
  1040.   bgcol = cp[0];
  1041.  
  1042.   while (ctop+1 < cHIGH) {
  1043.     /* see if we can delete this line */
  1044.     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++, cp1++);
  1045.     if (i==cWIDE) { cp += cWIDE;  ctop++; }
  1046.     else break;
  1047.   }
  1048.  
  1049.  
  1050.   /* crop the bottom */
  1051.   cp = cpic + (cHIGH-1) * cWIDE;
  1052.   bgcol = cp[0];
  1053.  
  1054.   while (ctop + cbot + 1 < cHIGH) {
  1055.     /* see if we can delete this line */
  1056.     for (i=0, cp1=cp; i<cWIDE && *cp1==bgcol; i++,cp1++);
  1057.     if (i==cWIDE) { cp -= cWIDE;  cbot++; }
  1058.     else break;
  1059.   }
  1060.  
  1061.  
  1062.   /* crop the left side */
  1063.   cp = cpic;
  1064.   bgcol = cp[0];
  1065.  
  1066.   while (cleft + 1 < cWIDE) {
  1067.     /* see if we can delete this line */
  1068.     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
  1069.     if (i==cHIGH) { cp++; cleft++; }
  1070.     else break;
  1071.   }
  1072.  
  1073.  
  1074.   /* crop the right side */
  1075.   cp = cpic + cWIDE-1;
  1076.   bgcol = cp[0];
  1077.  
  1078.   while (cleft + cright + 1 < cWIDE) {
  1079.     /* see if we can delete this line */
  1080.     for (i=0, cp1=cp; i<cHIGH && *cp1==bgcol; i++, cp1 += cWIDE);
  1081.     if (i==cHIGH) { cp--; cright++; }
  1082.     else break;
  1083.   }
  1084.  
  1085.  
  1086.   /* do the actual cropping */
  1087.   if (cleft || ctop || cbot || cright)
  1088.     DoCrop1(cXOFF+cleft, cYOFF+ctop, cWIDE-(cleft+cright), cHIGH-(ctop+cbot));
  1089. }
  1090.  
  1091.  
  1092. /***********************************/
  1093. void Rotate(dir)
  1094. int dir;
  1095. {
  1096.   int i;
  1097.  
  1098.   /* dir=0: clockwise, else counter-clockwise */
  1099.  
  1100.   RotatePic(pic, &pWIDE, &pHIGH, dir);
  1101.  
  1102.   /* rotate clipped version and modify 'clip' coords */
  1103.   if (cpic != pic && cpic != NULL) {
  1104.     if (!dir) {
  1105.       i = pWIDE - (cYOFF + cHIGH);      /* have to rotate offsets */
  1106.       cYOFF = cXOFF;
  1107.       cXOFF = i;
  1108.     }
  1109.     else {
  1110.       i = pHIGH - (cXOFF + cWIDE);
  1111.       cXOFF = cYOFF;
  1112.       cYOFF = i;
  1113.     }
  1114.     RotatePic(cpic, &cWIDE, &cHIGH,dir);
  1115.   }
  1116.   else { cWIDE = pWIDE;  cHIGH = pHIGH; }
  1117.  
  1118.   /* rotate expanded version */
  1119.   if (epic != cpic && epic != NULL) {
  1120.     RotatePic(epic, &eWIDE, &eHIGH,dir);
  1121.   }
  1122.   else { eWIDE = cWIDE;  eHIGH = cHIGH; }
  1123.  
  1124.   CreateXImage();
  1125.   WRotate();
  1126. }
  1127.  
  1128.  
  1129. /************************/
  1130. static void RotatePic(pic, wp, hp, dir)
  1131. byte *pic;
  1132. unsigned int *wp, *hp;
  1133. int dir;
  1134. {
  1135.   /* rotates a w*h array of bytes 90 deg clockwise (dir=0) 
  1136.      or counter-clockwise (dir != 0).  swaps w and h */
  1137.  
  1138.   byte *pic1, *pix1, *pix;
  1139.   int          i,j;
  1140.   unsigned int w,h;
  1141.  
  1142.   w = *wp;  h = *hp;  
  1143.   pix1 = pic1 = (byte *) malloc(w*h);
  1144.   if (!pic1) FatalError("Not enough memory to rotate!");
  1145.  
  1146.   /* do the rotation */
  1147.   if (dir==0) {
  1148.     for (i=0; i<w; i++)        /* CW */
  1149.       for (j=h-1, pix=pic+(h-1)*w + i; j>=0; j--, pix1++, pix-=w) 
  1150.     *pix1 = *pix;
  1151.   }
  1152.   else {
  1153.     for (i=w-1; i>=0; i--)     /* CCW */
  1154.       for (j=0, pix=pic+i; j<h; j++, pix1++, pix+=w) 
  1155.     *pix1 = *pix;
  1156.   }
  1157.  
  1158.  
  1159.   /* copy the rotated buffer into the original buffer */
  1160.   memcpy(pic, pic1, w*h);
  1161.  
  1162.   free(pic1);
  1163.  
  1164.   /* swap w and h */
  1165.   *wp = h;  *hp = w;
  1166. }
  1167.  
  1168.   
  1169.  
  1170. /************************/
  1171. static void FloydDitherize8(image)
  1172.      byte *image;
  1173. {
  1174.   /* takes epic, and builds a black&white dithered version of it.
  1175.      stores result in 8bit Pixmap format in 'image' */
  1176.  
  1177.   int i;
  1178.   byte *p;
  1179.  
  1180.   FSDither(epic, eWIDE, eHIGH, image);
  1181.  
  1182.   /* set to 'black' and 'white' instead of '0' and '1' */
  1183.   if (black != 0 || white != 1) {
  1184.     for (i=eWIDE*eHIGH, p=image; i>0; i--, p++) {
  1185.       if (*p) *p = white;  else *p = black;
  1186.     }
  1187.   }
  1188. }
  1189.  
  1190.  
  1191.  
  1192. /************************/
  1193. static void FloydDitherize1(ximage)
  1194.      XImage *ximage;
  1195. {
  1196.   /* same as FloydDitherize8, but output is a 1-bit per pixel XYBitmap,
  1197.      packed 8 pixels per byte */
  1198.  
  1199.   register short *dp;
  1200.   register byte   pix8, bit;
  1201.   short          *dithpic;
  1202.   int             i, j, err, bperln, order;
  1203.   byte           *pp, *image, w, b, w8, b8;
  1204.  
  1205.  
  1206.   image  = (byte *) theImage->data;
  1207.   bperln = theImage->bytes_per_line;
  1208.   order  = theImage->bitmap_bit_order;
  1209.  
  1210.   if (DEBUG) fprintf(stderr,"Ditherizing1...");
  1211.  
  1212.   dithpic = (short *) malloc(eWIDE * eHIGH * sizeof(short));
  1213.   if (dithpic == NULL) FatalError("not enough memory to ditherize");
  1214.  
  1215.   w = white&0x1;  b=black&0x1;
  1216.   w8 = w<<7;  b8 = b<<7;        /* b/w bit in high bit */
  1217.   
  1218.   /* copy r[epic] into dithpic so that we can run the algorithm */
  1219.   pp = epic;  dp = dithpic;
  1220.   for (i=eHIGH * eWIDE; i>0; i--) *dp++ = fsgamcr[r[*pp++]];
  1221.  
  1222.   dp = dithpic;
  1223.   pp = image;
  1224.  
  1225.   for (i=0; i<eHIGH; i++) {
  1226.     pp = image + i*bperln;
  1227.  
  1228.     if (order==LSBFirst) {
  1229.       bit = pix8 = 0;
  1230.       for (j=0; j<eWIDE; j++,dp++) {
  1231.     if (*dp<128) { err = *dp;     pix8 |= b8; }
  1232.             else { err = *dp-255; pix8 |= w8; }
  1233.  
  1234.     if (bit==7) {
  1235.       *pp++ = pix8;  bit=pix8=0;
  1236.     }
  1237.     else { pix8 >>= 1;  bit++; }
  1238.  
  1239.     if (j<eWIDE-1) dp[1] += ((err*7)/16);
  1240.  
  1241.     if (i<eHIGH-1) {
  1242.       dp[eWIDE] += ((err*5)/16);
  1243.       if (j>0)       dp[eWIDE-1] += ((err*3)/16);
  1244.       if (j<eWIDE-1) dp[eWIDE+1] += (err/16);
  1245.     }
  1246.       }
  1247.       if (bit) *pp++ = pix8>>(7-bit);  /* write partial byte at end of line */
  1248.     }
  1249.  
  1250.     else {   /* order==MSBFirst */
  1251.       bit = pix8 = 0;
  1252.       for (j=0; j<eWIDE; j++,dp++) {
  1253.     if (*dp<128) { err = *dp;     pix8 |= b; }
  1254.             else { err = *dp-255; pix8 |= w; }
  1255.  
  1256.     if (bit==7) {
  1257.       *pp++ = pix8;  bit=pix8=0;
  1258.     }
  1259.     else { pix8 <<= 1; bit++; }
  1260.  
  1261.     if (j<eWIDE-1) dp[1] += ((err*7)/16);
  1262.  
  1263.     if (i<eHIGH-1) {
  1264.       dp[eWIDE] += ((err*5)/16);
  1265.       if (j>0)       dp[eWIDE-1] += ((err*3)/16);
  1266.       if (j<eWIDE-1) dp[eWIDE+1] += (err/16);
  1267.     }
  1268.       }
  1269.       if (bit) *pp++ = pix8<<(7-bit);  /* write partial byte at end of line */
  1270.     }
  1271.   }
  1272.  
  1273.   if (DEBUG) fprintf(stderr,"done\n");
  1274.  
  1275.   free(dithpic);
  1276. }
  1277.  
  1278.  
  1279.  
  1280. /************************/
  1281. void FSDither(inpic, w, h, outpic)
  1282. byte *inpic, *outpic;
  1283. int   w,h;
  1284. {
  1285.   /* takes inpic, and builds a black&white dithered version of it.
  1286.      stores result as 1 byte per pixel format in 'image'
  1287.      black = 0;  white = 1;
  1288.      temporarily mallocs a w*h array of SHORTS.
  1289.      (need to be signed, also to avoid overflow problems.)  */
  1290.  
  1291.   /* floyd-steinberg dithering.
  1292.    *
  1293.    * ----   x    7/16
  1294.    * 3/16  5/16  1/16
  1295.    *
  1296.    */
  1297.  
  1298.   short *dp, *dithpic;
  1299.   int    i, j, err, w1, h1;
  1300.   byte  *pp, rgb[256];
  1301.  
  1302.   if (DEBUG) fprintf(stderr,"Ditherizing...");
  1303.  
  1304.   /* first thing to do is build rgb[], which will hold the B/W intensity
  1305.      of the colors in the r,g,b arrays */
  1306.   for (i=0; i<256; i++)
  1307.     rgb[i] = MONO(r[i], g[i], b[i]);
  1308.  
  1309.  
  1310.   dithpic = (short *) malloc(w*h * sizeof(short));
  1311.   if (dithpic == NULL) FatalError("not enough memory to ditherize");
  1312.  
  1313.   w1 = w-1;  h1 = h-1;
  1314.  
  1315.   /* copy rgb[inpic] into dithpic so that we can run the algorithm */
  1316.   pp = inpic;  dp = dithpic;
  1317.   for (i=w*h; i>0; i--) *dp++ = fsgamcr[rgb[*pp++]];
  1318.  
  1319.   dp = dithpic;  pp = outpic;
  1320.   for (i=0; i<h; i++) {
  1321.     if ((i&15) == 0) WaitCursor();
  1322.     for (j=0; j<w; j++,dp++,pp++) {
  1323.       if (*dp<128) { err = *dp;     *pp = 0; }
  1324.               else { err = *dp-255; *pp = 1; }
  1325.  
  1326.       if (j<w1) dp[1] += ((err*7)/16);
  1327.  
  1328.       if (i<h1) {
  1329.         dp[w] += ((err*5)/16);
  1330.         if (j>0)  dp[w1] += ((err*3)/16);
  1331.         if (j<w1) dp[w+1] += (err/16);
  1332.       }
  1333.     }
  1334.   }
  1335.  
  1336.   if (DEBUG) fprintf(stderr,"done\n");
  1337.  
  1338.   free(dithpic);
  1339. }
  1340.  
  1341.  
  1342.  
  1343.  
  1344.  
  1345.  
  1346. /***********************************/
  1347. void CreateXImage()
  1348. {
  1349.   int    i;
  1350.  
  1351.  
  1352.   /*
  1353.    * this has to do the tricky bit of converting the data in 'epic'
  1354.    * into something usable for X.
  1355.    *
  1356.    * Algorithm notes:
  1357.    *   if dispDEEP is 8, nothing has to be done other than create an
  1358.    *      Ximage (ZPixmap, depth=8) and point it at the 'epic' data.
  1359.    *
  1360.    *   if dispDEEP is 1, format'll be an XYBitmap, special case code
  1361.    *   
  1362.    *   if dispDEEP is 4, format'll be a ZPixmap, 4 or 8 bits per pixel
  1363.    *
  1364.    *   if dispDEEP is 6, format'll be a ZPixmap, 8 bits per pixel
  1365.    *
  1366.    *   if dispDEEP is 24 or 32, format'll be a ZPixmap.  32 bits per pixel
  1367.    *
  1368.    *   any other value of dispDEEP will use a XYPixmap of the appropriate
  1369.    *   depth, and some slug-like general-case code  DOESN'T YET!!
  1370.    */
  1371.  
  1372.   if (DEBUG) 
  1373.     fprintf(stderr,"%s: creating a %dx%d Ximage, %d bits deep\n",
  1374.         cmd, eWIDE, eHIGH, dispDEEP);
  1375.  
  1376.   /* destroy old image and imagedata, if there is one */
  1377.   if (theImage) XDestroyImage(theImage);
  1378.   theImage = NULL;
  1379.  
  1380.   if (!epic) {
  1381.     /* fprintf(stderr,"CreateXImage called while epic was null\n"); */
  1382.     Resize(eWIDE,eHIGH);
  1383.     return;
  1384.   }
  1385.  
  1386.   switch (dispDEEP) 
  1387.     {
  1388.  
  1389.     case 8:
  1390.       {
  1391.       byte  *imagedata, *ip, *pp;
  1392.  
  1393.       imagedata = (byte *) malloc(eWIDE*eHIGH);
  1394.       if (!imagedata) FatalError("couldn't malloc imagedata");
  1395.       
  1396.       if (ncols==0) FloydDitherize8(imagedata);
  1397.       else {
  1398.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  1399.       if ((i&0x1ffff) == 0) WaitCursor();
  1400.       *ip = (byte) cols[*pp];
  1401.     }
  1402.       }
  1403.  
  1404.       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  1405.                   (char *) imagedata, eWIDE, eHIGH, 8, 0);
  1406.       if (!theImage) FatalError("couldn't create theImage!");
  1407.       }
  1408.       break;
  1409.  
  1410.     /*********************************/
  1411.  
  1412.     case 1:
  1413.       {
  1414.       byte  *imagedata;
  1415.  
  1416.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, 
  1417.                   eWIDE, eHIGH, 8, 0);
  1418.       if (!theImage) FatalError("couldn't create theImage!");
  1419.       imagedata = (byte *) malloc(theImage->bytes_per_line * eHIGH);
  1420.       if (!imagedata) FatalError("couldn't malloc imagedata");
  1421.       theImage->data = (char *) imagedata;
  1422.       FloydDitherize1(theImage);
  1423.       }
  1424.       break;
  1425.       
  1426.     /*********************************/
  1427.       
  1428.     case 4: {
  1429.       byte  *imagedata, *ip, *pp;
  1430.       byte *lip;
  1431.       int  bperline, half, j;
  1432.  
  1433.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  1434.                   eWIDE, eHIGH, 8, 0);
  1435.       if (!theImage) FatalError("couldn't create theImage!");
  1436.  
  1437.       bperline = theImage->bytes_per_line;
  1438.       imagedata = (byte *) malloc(bperline * eHIGH);
  1439.       if (!imagedata) FatalError("couldn't malloc imagedata");
  1440.       theImage->data = (char *) imagedata;
  1441.  
  1442.       if (ncols==0) {            /* ditherize */
  1443.     byte *dith;
  1444.     dith = (byte *) malloc(eWIDE * eHIGH);
  1445.     if (!dith) FatalError("can't create dithered image");
  1446.     FloydDitherize8(dith);
  1447.  
  1448.     if (theImage->bits_per_pixel == 4) {
  1449.       for (i=0, pp=dith, lip=imagedata; i<eHIGH; i++, lip+=bperline)
  1450.         for (j=0, ip=lip, half=0; j<eWIDE; j++,pp++,half++) {
  1451.           if (half&1) { *ip = *ip + ((*pp&0x0f)<<4);  ip++; }
  1452.           else *ip = *pp&0x0f;
  1453.         }
  1454.     }
  1455.     else if (theImage->bits_per_pixel == 8)
  1456.       memcpy(imagedata, dith, eWIDE*eHIGH);
  1457.     
  1458.     else FatalError("This display is too bizarre.  Can't create XImage.");
  1459.  
  1460.     free(dith);
  1461.       }
  1462.  
  1463.       else {     /* don't ditherize */
  1464.     if (theImage->bits_per_pixel == 4) {
  1465.       for (i=0, pp=epic, lip=imagedata; i<eHIGH; i++, lip+=bperline) {
  1466.         if ((i&127) == 0) WaitCursor();
  1467.         for (j=0, ip=lip, half=0; j<eWIDE; j++,pp++,half++) {
  1468.           if (half&1) { *ip = *ip + ((cols[*pp]&0x0f)<<4);  ip++; }
  1469.           else *ip = cols[*pp]&0x0f;
  1470.         }
  1471.       }
  1472.     }
  1473.     else if (theImage->bits_per_pixel == 8) {
  1474.       for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  1475.         if ((i&0x1ffff) == 0) WaitCursor();
  1476.         *ip = (byte) cols[*pp];
  1477.       }
  1478.     }
  1479.     else FatalError("This display's too bizarre.  Can't create XImage.");
  1480.       }
  1481.       
  1482.       }
  1483.       break;
  1484.       
  1485.     /*********************************/
  1486.       
  1487.     case 6: {
  1488.       byte  *imagedata, *ip, *pp;
  1489.       int  bperline;
  1490.  
  1491.       theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, 
  1492.                   eWIDE, eHIGH, 8, 0);
  1493.       if (!theImage) FatalError("couldn't create theImage!");
  1494.  
  1495.       if (theImage->bits_per_pixel != 8)
  1496.     FatalError("This display's too bizarre.  Can't create XImage.");
  1497.  
  1498.       bperline = theImage->bytes_per_line;
  1499.       imagedata = (byte *) malloc(bperline * eHIGH);
  1500.       if (!imagedata) FatalError("couldn't malloc imagedata");
  1501.       theImage->data = (char *) imagedata;
  1502.  
  1503.       if (ncols==0) FloydDitherize8(imagedata);
  1504.       else {
  1505.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) {
  1506.       if ((i&0x1ffff) == 0) WaitCursor();
  1507.       *ip = (byte) cols[*pp];
  1508.     }
  1509.       }
  1510.       
  1511.       }
  1512.       break;
  1513.       
  1514.     /*********************************/
  1515.       
  1516.     case 24:
  1517.     case 32:
  1518.       {
  1519.       byte  *imagedata, *ip, *pp;
  1520.       imagedata = (byte *) malloc(4*eWIDE*eHIGH);
  1521.       if (!imagedata) FatalError("couldn't malloc imagedata");
  1522.       
  1523.       theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0,
  1524.                   (char *) imagedata, eWIDE, eHIGH, 32, 0);
  1525.       if (!theImage) FatalError("couldn't create theImage!");
  1526.       
  1527.       if (theImage->byte_order == MSBFirst) 
  1528.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  1529.       if ((i&0x1ffff) == 0) WaitCursor();
  1530.       *ip++ = 0;
  1531.       *ip++ = (cols[*pp]>>16) & 0xff;
  1532.       *ip++ = (cols[*pp]>>8) & 0xff;
  1533.       *ip++ =  cols[*pp] & 0xff;
  1534.     }
  1535.       else 
  1536.     for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) {
  1537.       if ((i&0x1ffff) == 0) WaitCursor();
  1538.       *ip++ =  cols[*pp] & 0xff;
  1539.       *ip++ = (cols[*pp]>>8) & 0xff;
  1540.       *ip++ = (cols[*pp]>>16) & 0xff;
  1541.       *ip++ = 0;
  1542.     }
  1543.       }      
  1544.       break;
  1545.  
  1546.     /*********************************/
  1547.  
  1548.     default: 
  1549.       sprintf(str,"no code to handle this display type (%d bits deep)",
  1550.           dispDEEP);
  1551.       FatalError(str);
  1552.       break;
  1553.     }
  1554. }
  1555.  
  1556.  
  1557.  
  1558.  
  1559. /**************************************************/
  1560. void CenterString(win,str,x,y)
  1561. Window win;
  1562. char *str;
  1563. int x,y;
  1564. {
  1565.   XDrawString(theDisp, win, theGC, CENTERX(mfinfo, x, str),
  1566.         CENTERY(mfinfo, y), str, strlen(str));
  1567. }
  1568.  
  1569.   
  1570. /**************************************************/
  1571. void ULineString(win,str,x,y)
  1572. Window win;
  1573. char *str;
  1574. int x,y;
  1575. {
  1576.   XDrawString(theDisp, win, theGC, x, y, str, strlen(str));
  1577.   XDrawLine(theDisp, win, theGC, x, y+DESCENT-1, 
  1578.         x+StringWidth(str), y+DESCENT-1);
  1579. }
  1580.  
  1581.   
  1582. /**************************************************/
  1583. int StringWidth(str)
  1584. char *str;
  1585. {
  1586.   return(XTextWidth(mfinfo, str, strlen(str)));
  1587. }
  1588.  
  1589.   
  1590. /***********************************/
  1591. void FakeButtonPress(bp)
  1592. BUTT *bp;
  1593. {
  1594.   /* called when a button keyboard equivalent has been pressed.
  1595.      'fakes' a ButtonPress event in the button, which A) makes the button
  1596.      blink, and B) falls through to ButtonPress command dispatch code */
  1597.  
  1598.   XButtonEvent ev;
  1599.  
  1600.   ev.type = ButtonPress;
  1601.   ev.send_event = True;
  1602.   ev.display = theDisp;
  1603.   ev.window = bp->win;
  1604.   ev.root = rootW;
  1605.   ev.subwindow = NULL;
  1606.   ev.x = bp->x;
  1607.   ev.y = bp->y;
  1608.   ev.state = 0;
  1609.   ev.button = Button1;
  1610.   XSendEvent(theDisp, bp->win, False, NoEventMask, (XEvent *) &ev);
  1611. }
  1612.  
  1613. /**************************************************/
  1614. void SetCropString()
  1615. {
  1616.   /* sets the crop string in the info box to be correct.  should
  1617.      be called whenever 'but[BCROP].active', cXOFF,cYOFF,cWIDE,cHIGH 
  1618.      are changed */
  1619.  
  1620.   /* if but[BCROP].active, there's a cropping rectangle drawn on the picture.
  1621.      the string should reflect that.  */
  1622.  
  1623.   if (but[BCROP].active) {
  1624.     /* figure out current cropping rectangle in 'pic' coordinates */
  1625.     int x,y,x1,y1,w,h;
  1626.     int cx,cy,dx,dy;
  1627.     
  1628.     if (crx1<crx2) cx=crx1; else cx=crx2;
  1629.     if (cry1<cry2) cy=cry1; else cy=cry2;
  1630.     dx = abs(crx1-crx2);  dy = abs(cry1-cry2);
  1631.  
  1632.     x = cXOFF + (cx * cWIDE) / eWIDE;
  1633.     y = cYOFF + (cy * cHIGH) / eHIGH;
  1634.     x1 = cXOFF + ((cx+dx) * cWIDE) / eWIDE;
  1635.     y1 = cYOFF + ((cy+dy) * cHIGH) / eHIGH;
  1636.     w = (x1 - x) + 1;
  1637.     h = (y1 - y) + 1;
  1638.  
  1639.     if (w<1) w = 1;
  1640.     if (x+w > pWIDE) w = pWIDE - x;
  1641.     if (h<1) h = 1;
  1642.     if (y+h > pHIGH) h = pHIGH - y;
  1643.  
  1644.     SetISTR(ISTR_CROP, "%dx%d rectangle starting at %d,%d", w, h, x, y);
  1645.   }
  1646.  
  1647.   else {   /* cropping rectangle is turned off */
  1648.     if (cpic != pic)
  1649.       SetISTR(ISTR_CROP, "%dx%d rectangle starting at %d,%d", 
  1650.           cWIDE, cHIGH, cXOFF, cYOFF);
  1651.     else
  1652.       SetISTR(ISTR_CROP, "none");
  1653.   }
  1654. }
  1655.  
  1656.  
  1657. /***********************************/
  1658. void Warning()
  1659. {
  1660.   char *st;
  1661.   int i;
  1662.  
  1663.   if (infoUp || ctrlUp) {   /* give 'em time to read message */
  1664.     if (!fishrunning) sleep(5);  
  1665.     else {
  1666.       for (i=0; i<25; i++) PAUSE_SIG;
  1667.     }
  1668.   }
  1669.   else {
  1670.     st = GetISTR(ISTR_INFO);
  1671.     fprintf(stderr,"%s: %s\n", cmd, st);
  1672.   }
  1673. }
  1674.     
  1675.  
  1676. /***********************************/
  1677. void FatalError (identifier)
  1678.       char *identifier;
  1679. {
  1680.   fprintf(stderr, "%s: %s\n",cmd, identifier);
  1681.   Quit(-1);
  1682. }
  1683.  
  1684.  
  1685. /***********************************/
  1686. void Quit(i)
  1687. int i;
  1688.   FreeMostResources();
  1689.   exit(i);
  1690. }
  1691.  
  1692.  
  1693. /***********************************/
  1694. static void FreeMostResources()
  1695. {
  1696.   /* called when the program exits.  frees everything explictly created
  1697.      EXCEPT allocated colors.  This is used when 'useroot' is in operation,
  1698.      as we have to keep the alloc'd colors around, but we don't want anything
  1699.      else to stay */
  1700.  
  1701.   if (!theDisp) return;   /* called before connection opened */
  1702.  
  1703.   if (dirW)  XDestroyWindow(theDisp, dirW);
  1704.   if (infoW) XDestroyWindow(theDisp, infoW);
  1705.   if (ctrlW) XDestroyWindow(theDisp, ctrlW);
  1706.   if (gamW)  XDestroyWindow(theDisp, gamW);
  1707.  
  1708.   XFlush(theDisp);
  1709. }
  1710.  
  1711. static Cursor flcurs, fl1curs, fmcurs, fr1curs, frcurs;
  1712.  
  1713. /***********************************/
  1714. void LoadFishCursors()
  1715. {
  1716. #define fc_w 16
  1717. #define fc_h 16 
  1718.  
  1719.   Pixmap flpix,flmpix,fmpix,fmmpix,frpix,frmpix;
  1720.   Pixmap fl1pix, fl1mpix, fr1pix, fr1mpix;
  1721.   XColor fg, bg;
  1722.  
  1723.   flcurs = fl1curs = fmcurs = fr1curs = frcurs = NULL;
  1724.  
  1725.   flpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left_bits,
  1726.          fc_w, fc_h, 1, 0, 1);
  1727.   flmpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_leftm_bits,
  1728.          fc_w, fc_h, 1, 0, 1);
  1729.  
  1730.   fl1pix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left1_bits,
  1731.          fc_w, fc_h, 1, 0, 1);
  1732.   fl1mpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left1m_bits,
  1733.          fc_w, fc_h, 1, 0, 1);
  1734.  
  1735.   fmpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_mid_bits,
  1736.          fc_w, fc_h, 1, 0, 1);
  1737.   fmmpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_midm_bits,
  1738.          fc_w, fc_h, 1, 0, 1);
  1739.  
  1740.   fr1pix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right1_bits,
  1741.          fc_w, fc_h, 1, 0, 1);
  1742.   fr1mpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right1m_bits,
  1743.          fc_w, fc_h, 1, 0, 1);
  1744.  
  1745.   frpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right_bits,
  1746.          fc_w, fc_h, 1, 0, 1);
  1747.   frmpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_rightm_bits,
  1748.          fc_w, fc_h, 1, 0, 1);
  1749.  
  1750.   if (!flpix || !flmpix || !fmpix || !fmmpix || !frpix || !frmpix
  1751.       || !fl1pix || !fl1mpix || !fr1pix || !fr1mpix) return;
  1752.  
  1753.   fg.red = fg.green = fg.blue = 0;
  1754.   bg.red = bg.green = bg.blue = 0xffff;
  1755.  
  1756.   flcurs = XCreatePixmapCursor(theDisp, flpix, flmpix, &fg, &bg, 8,8);
  1757.   fl1curs= XCreatePixmapCursor(theDisp, fl1pix,fl1mpix,&fg, &bg, 8,8);
  1758.   fmcurs = XCreatePixmapCursor(theDisp, fmpix, fmmpix, &fg, &bg, 8,8);
  1759.   fr1curs= XCreatePixmapCursor(theDisp, fr1pix,fr1mpix,&fg, &bg, 8,8);
  1760.   frcurs = XCreatePixmapCursor(theDisp, frpix, frmpix, &fg, &bg, 8,8);
  1761.  
  1762.   if (!flcurs || !fmcurs || !frcurs || !fl1curs || !fr1curs) 
  1763.     { flcurs = fmcurs = frcurs = NULL; }
  1764. }
  1765.  
  1766. static int fishno=0;
  1767.  
  1768.  
  1769. /***********************************/
  1770. void WaitCursor()
  1771. {
  1772.   SetCursors(fishno);
  1773.   fishno = (fishno+1) % 8;
  1774. }
  1775.  
  1776.  
  1777. /***********************************/
  1778. void SetCursors(n)
  1779. int n;
  1780. {
  1781.   Cursor c;
  1782.  
  1783.   c = cross;
  1784.   /* if n < 0   sets normal cursor in all windows
  1785.      n = 0..6   cycles through fish cursors */
  1786.  
  1787.   if (n<0) {
  1788.     if (!useroot && mainW) XDefineCursor(theDisp, mainW, cross);
  1789.     XDefineCursor(theDisp, infoW, arrow);
  1790.     XDefineCursor(theDisp, ctrlW, arrow);
  1791.     XDefineCursor(theDisp, dirW, arrow);
  1792.     XDefineCursor(theDisp, gamW, arrow);
  1793.     fishno = 0;
  1794.   }
  1795.  
  1796.   else if (flcurs) {    /* was able to load the cursors */
  1797.     switch (n%8) {
  1798.     case 0: c = flcurs;   break;
  1799.     case 1: c = fl1curs;  break;
  1800.     case 2: c = fmcurs;   break;
  1801.     case 3: c = fr1curs;  break;
  1802.     case 4: c = frcurs;   break;
  1803.     case 5: c = fr1curs;  break;
  1804.     case 6: c = fmcurs;   break;
  1805.     case 7: c = fl1curs;  break;
  1806.     }
  1807.  
  1808.     if (!useroot && mainW) XDefineCursor(theDisp, mainW, c);
  1809.     XDefineCursor(theDisp, infoW, c);
  1810.     XDefineCursor(theDisp, ctrlW, c);
  1811.     XDefineCursor(theDisp, dirW, c);
  1812.     XDefineCursor(theDisp, gamW, c);
  1813.   }
  1814.  
  1815.   XFlush(theDisp);
  1816. }
  1817.   
  1818.     
  1819.  
  1820.  
  1821. /***************************************************/
  1822.  
  1823. static int timerdone;
  1824.  
  1825. /*******/
  1826. static void onalarm()
  1827. /*******/
  1828. {
  1829.   timerdone=1;
  1830. }
  1831.  
  1832.  
  1833. /*******/
  1834. void Timer(n)   /* waits for 'n' milliseconds */
  1835.  int  n;
  1836. /*******/
  1837. {
  1838.   long usec;
  1839.   struct itimerval it;
  1840.  
  1841.   if (!n) return;
  1842.   if (fishrunning) { PAUSE_SIG; return; }
  1843.  
  1844. #ifdef sco
  1845.   if (!n) return;
  1846.   nap(n);
  1847.   return;
  1848. #endif /* sco */
  1849.  
  1850. #ifdef USLEEP
  1851.   usleep(n);
  1852.   return;
  1853. #endif
  1854.  
  1855. #ifdef NOTIMER
  1856.   return;
  1857. #endif
  1858.  
  1859.   usec = (long) n * 1000;
  1860.   
  1861.   memset(&it, 0, sizeof(it));
  1862.   if (usec>=1000000L) {  /* more than 1 second */
  1863.     it.it_value.tv_sec = usec / 1000000L;
  1864.     usec %= 1000000L;
  1865.   }
  1866.  
  1867.   it.it_value.tv_usec = usec;
  1868.   timerdone=0;
  1869.   signal(SIGALRM,onalarm);
  1870.   setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
  1871.   while (1) {
  1872.     HOLD_SIG;                    /* note:  have to block, so that ALRM */
  1873.     if (timerdone) break;        /* doesn't occur between 'if (timerdone)' */
  1874.     else PAUSE_SIG;              /* and calling PAUSE_SIG */
  1875.   }
  1876.  
  1877.   RELEASE_SIG;                   /* turn ALRM blocking off */
  1878.   signal(SIGALRM,SIG_DFL);
  1879. }
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886. \BARFOO\
  1887. else
  1888.   echo "will not over write ./xvmisc.c"
  1889. fi
  1890. echo "Finished archive 5 of 10"
  1891. exit
  1892.  
  1893. dan
  1894. ----------------------------------------------------
  1895. O'Reilly && Associates   argv@sun.com / argv@ora.com
  1896. Opinions expressed reflect those of the author only.
  1897. --
  1898. dan
  1899. ----------------------------------------------------
  1900. O'Reilly && Associates   argv@sun.com / argv@ora.com
  1901. Opinions expressed reflect those of the author only.
  1902.