home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xv310a / xvgrab.c < prev    next >
C/C++ Source or Header  |  1995-06-12  |  26KB  |  953 lines

  1. /*
  2.  * xvgrab.c - image grabbing (from the display) functions for XV
  3.  *
  4.  *  Author:    John Bradley, University of Pennsylvania
  5.  *
  6.  *  Contains:
  7.  *     int Grab()             - handles the GRAB command
  8.  *     int LoadGrab();        - 'loads' the pic from the last succesful Grab
  9.  *            
  10.  */
  11.  
  12. #include "copyright.h"
  13.  
  14. #define NEEDSTIME
  15. #include "xv.h"
  16.  
  17. static byte *grabPic = (byte *) NULL;
  18. static int  gbits;                              /* either '8' or '24' */
  19. static byte grabmapR[256], grabmapG[256], grabmapB[256];  /* colormap */
  20. static int  gWIDE,gHIGH;
  21. static int  grabInProgress=0;
  22. static int  hidewins = 0;
  23. static GC   rootGC;
  24.  
  25. static void   flashrect       PARM((int, int, int, int, int));
  26. static void   startflash      PARM((void));
  27. static void   endflash        PARM((void));
  28. static int    grabImage       PARM((Window, int, int, int, int));
  29. static void   ungrabX         PARM((void));
  30. static int    convertImage    PARM((XImage *, XColor *, int, 
  31.                     XWindowAttributes *));
  32.  
  33. static int    lowbitnum       PARM((unsigned long));
  34. static int    getxcolors      PARM((XWindowAttributes *, XColor **));
  35. static Window xvClientWindow  PARM((Display *, Window));
  36.  
  37.  
  38.  
  39.  
  40. /***********************************/
  41. int Grab()
  42. {
  43.   /* does UI part of Grab command.  returns '1' if a new image was grabbed,
  44.      0 if cancelled */
  45.  
  46.   int          i, x, y, x1, y1, x2, y2, ix, iy, iw, ih, rv;
  47.   int          rx, ry, pretendGotB1, autograb;
  48.   int          oldaclose;
  49.   Window       rW, cW, clickWin, tmpwin;
  50.   unsigned int mask;
  51.   XColor       fc, bc;
  52.  
  53.   pretendGotB1 = 0;
  54.  
  55.   if (grabInProgress) return 0;      /* avoid recursive grabs during delay */
  56.  
  57.   /* do the dialog box thing */
  58.   i = GrabPopUp(&hidewins, &grabDelay);
  59.   if (i==2) return 0;    /* cancelled */
  60.   autograb = (i==1);
  61.  
  62.   if (hidewins) {                   /* unmap all XV windows */
  63.     autoclose += 2;                 /* force it on once */
  64.     if (mainW && dispMode==RMB_WINDOW) XUnmapWindow(theDisp, mainW);
  65.     else if (ctrlW) CtrlBox(0);
  66.   }
  67.  
  68.  
  69.   XSync(theDisp, False);
  70.  
  71.   if (grabDelay>0) {    /* instead of sleep(), handle events while waiting */
  72.     time_t startT, t;
  73.     int  done;
  74.  
  75.     grabInProgress = 1; /* guard against recursive grabs during delay */
  76.     time(&startT);
  77.     while (1) {
  78.       time(&t);  
  79.       if (t >= startT + grabDelay) break;
  80.       if (XPending(theDisp)>0) {
  81.     XEvent evt;
  82.     XNextEvent(theDisp, &evt);
  83.     i = HandleEvent(&evt, &done);
  84.     if (done) {                    /* only 'new image' cmd accepted=quit */
  85.       if (i==QUIT) Quit(0);
  86.       else XBell(theDisp, 0);
  87.     }
  88.       }
  89.       Timer(100);
  90.     }
  91.     grabInProgress = 0;
  92.   }
  93.  
  94.   
  95.   rootGC   = DefaultGC(theDisp, theScreen);
  96.   
  97.   if (grabPic) {  /* throw away previous 'grabbed' pic, if there is one */
  98.     free(grabPic);  grabPic = (byte *) NULL;
  99.   }
  100.  
  101.  
  102.   fc.flags = bc.flags = DoRed | DoGreen | DoBlue;
  103.   fc.red = fc.green = fc.blue = 0xffff;  
  104.   bc.red = bc.green = bc.blue = 0x0000;
  105.   XRecolorCursor(theDisp, tcross, &fc, &bc);
  106.  
  107.  
  108.   XBell(theDisp, 0);        /* beep once at start of grab */
  109.  
  110.   if (!autograb) XGrabButton(theDisp, (u_int) AnyButton, 0, rootW, False, 0, 
  111.                  GrabModeAsync, GrabModeSync, None, tcross);
  112.   
  113.   if (autograb) {
  114.     XGrabServer(theDisp);     /* until we've done the grabImage */
  115.     if (!XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
  116.       fprintf(stderr, "xv: XQueryPointer failed!\n");
  117.       XUngrabServer(theDisp);
  118.       rv = 0;
  119.       goto exit;
  120.     }
  121.     else { pretendGotB1 = 1;  mask = Button1Mask; }
  122.   }
  123.  
  124.   else {   /* !autograb */
  125.     /* wait for a button press */
  126.     while (1) {
  127.       XEvent evt;  int done;
  128.  
  129.       /* recolor cursor to indicate that grabbing is active? */
  130.  
  131.       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
  132.     if (mask & (Button1Mask | Button2Mask | Button3Mask)) break;
  133.       }
  134.  
  135.       /* continue to handle events while waiting... */
  136.       XNextEvent(theDisp, &evt);
  137.       i = HandleEvent(&evt, &done);
  138.       if (done) {                    /* only 'new image' cmd accepted=quit */
  139.     if (i==QUIT) { 
  140.       XUngrabButton(theDisp, (u_int) AnyButton, 0, rootW);
  141.       Quit(0);
  142.     }
  143.     else XBell(theDisp, 0);
  144.       }
  145.  
  146.     }
  147.   }
  148.   
  149.   
  150.   /***
  151.    ***  got button click (or pretending we did, if autograb)
  152.    ***/
  153.   
  154.  
  155.   if (mask & Button3Mask || rW!=rootW) {        /* Button3: CANCEL GRAB */
  156.     while (1) {      /* wait for button to be released */
  157.       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
  158.     if (!(mask & Button3Mask)) break;
  159.       }
  160.     }
  161.     
  162.     XUngrabButton(theDisp, (u_int) AnyButton, 0, rootW);
  163.     XBell(theDisp, 0);
  164.     XBell(theDisp, 0);
  165.     rv = 0;
  166.     goto exit;
  167.   }
  168.  
  169.  
  170.  
  171.   if (mask & Button1Mask) {  /* Button1:  GRAB WINDOW (& FRAME, maybe)     */
  172.     while (!pretendGotB1) {  /* wait for button to be released, if clicked */
  173.       int rx,ry,x1,y1;  Window rW, cW;
  174.       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x1,&y1,&mask)) {
  175.     if (!(mask & Button1Mask)) break;
  176.       }
  177.     }
  178.     
  179.     if (!cW || cW == rootW) clickWin = rootW;
  180.     else {
  181.       int xr, yr;    Window chwin;
  182.       XTranslateCoordinates(theDisp, rW, cW, rx, ry, &xr, &yr, &chwin);
  183.       if (chwin != None) {
  184.     XWindowAttributes clickxwa, parentxwa;
  185.  
  186.     clickWin = xvClientWindow(theDisp, chwin);
  187.  
  188.     /* decide if we want to just grab clickWin, or cW.
  189.        basically, if they're different in any important way 
  190.        (depth, visual, colormap), grab 'clickWin' only, 
  191.        as it's the important part */
  192.  
  193.     if (!clickWin || 
  194.         (XGetWindowAttributes(theDisp, clickWin, &clickxwa)  &&
  195.          XGetWindowAttributes(theDisp, cW,       &parentxwa) &&
  196.          clickxwa.visual->class == parentxwa.visual->class   &&
  197.          clickxwa.colormap      == parentxwa.colormap        &&
  198.          clickxwa.depth         == parentxwa.depth)
  199.         )
  200.       clickWin = cW;         /* close enough! */
  201.       }
  202.       else clickWin = cW;
  203.       
  204.       if (DEBUG) 
  205.     fprintf(stderr, "rW = %x, cW = %x, chwin = %x, clickWin = %x\n",
  206.         (u_int) rW, (u_int) cW, (u_int) chwin, (u_int) clickWin);
  207.     }
  208.     
  209.     
  210.     if (clickWin == rootW) {   /* grab entire screen */
  211.       if (DEBUG) fprintf(stderr,"Grab: clicked on root window.\n");
  212.       ix = iy = 0;  iw = dispWIDE;  ih = dispHIGH;
  213.     }
  214.     else {
  215.       int x,y;  Window win;   unsigned int rw,rh,rb,rd;
  216.       
  217.       if (XGetGeometry(theDisp,clickWin,&rW, &x, &y, &rw, &rh, &rb, &rd)) {
  218.     iw = (int) rw;  ih = (int) rh;
  219.     
  220.     XTranslateCoordinates(theDisp, clickWin, rootW, 0, 0, &ix,&iy, &win);
  221.     
  222.     if (DEBUG) fprintf(stderr,"clickWin=0x%x: %d,%d %dx%d depth=%ud\n", 
  223.                (u_int) clickWin, ix, iy, iw, ih, rd);    
  224.       }
  225.       else {
  226.     ix = iy = 0;  iw = dispWIDE;  ih = dispHIGH;  clickWin = rootW;
  227.     if (DEBUG) fprintf(stderr,"XGetGeometry failed? (using root win)\n");
  228.       }
  229.     }
  230.     
  231.     
  232.     /* range checking:  keep rectangle fully on-screen */
  233.     if (ix<0) { iw += ix;  ix = 0; }
  234.     if (iy<0) { ih += iy;  iy = 0; }
  235.     if (ix+iw>dispWIDE) iw = dispWIDE-ix;
  236.     if (iy+ih>dispHIGH) ih = dispHIGH-iy;
  237.     
  238.     
  239.     if (DEBUG) fprintf(stderr,"using %d,%d (%dx%d)\n", ix, iy, iw, ih);
  240.     
  241.     /* flash the rectangle a bit... */
  242.     startflash();
  243.     for (i=0; i<5; i++) {
  244.       flashrect(ix, iy, iw, ih, 1);
  245.       XFlush(theDisp);  Timer(100);
  246.       flashrect(ix, iy, iw, ih, 0);
  247.       XFlush(theDisp);  Timer(100);
  248.     }
  249.     endflash();
  250.   }
  251.  
  252.  
  253.   else {  /* Button2:  TRACK A RECTANGLE */
  254.     int    origrx, origry;
  255.     Window origcW;
  256.  
  257.     clickWin = rootW;  origcW = cW;
  258.     origrx = ix = x2 = rx;
  259.     origry = iy = y2 = ry;
  260.     iw = ih = 0;
  261.     
  262.     XGrabServer(theDisp);
  263.     startflash();
  264.  
  265.     /* Wait for button release while tracking rectangle on screen */
  266.     while (1) {
  267.       if (XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  268.     if (!(mask & Button2Mask)) break;
  269.       }
  270.  
  271.       flashrect(ix, iy, iw, ih, 0);                /* turn off rect */
  272.  
  273.       if (rx!=x2 || ry!=y2) {                      /* resize rectangle */
  274.     ix = (x1<rx) ? x1 : rx;
  275.     iy = (y1<ry) ? y1 : ry;
  276.     iw = abs(rx - x1);  ih = abs(ry - y1);
  277.     x2 = rx;  y2 = ry;
  278.       }
  279.       
  280.       if (iw>1 && ih>1) flashrect(ix,iy,iw,ih,1);  /* turn on rect */
  281.     }
  282.  
  283.     flashrect(ix, iy, iw, ih, 0);                  /* turn off rect */
  284.     endflash();
  285.     
  286.     XUngrabServer(theDisp);
  287.     
  288.     
  289.     if (origcW == cW) {  /* maybe it's entirely in one window??? */
  290.       if (cW) {    /* will be 0 if clicked in rootW */
  291.     Window stwin, enwin, stwin1, enwin1;
  292.     if (DEBUG) fprintf(stderr,"origcW=%x cW=%x   ", 
  293.                (u_int) origcW, (u_int) cW);
  294.     XTranslateCoordinates(theDisp,rootW,cW, origrx,origry,&x,&y,&stwin);
  295.     XTranslateCoordinates(theDisp,rootW,cW, rx,    ry,    &x,&y,&enwin);
  296.     
  297.     if (DEBUG) fprintf(stderr,"stwin=%x enwin=%x   ", 
  298.                (u_int) stwin, (u_int) enwin);
  299.     if (stwin == enwin && stwin != None) {
  300.       stwin1 = xvClientWindow(theDisp, stwin);
  301.       enwin1 = xvClientWindow(theDisp, enwin);
  302.       if (DEBUG) fprintf(stderr,"stwin1=%x enwin1=%x   ", 
  303.                  (u_int) stwin1, (u_int) enwin1);
  304.       
  305.       if (stwin1 == enwin1 && stwin1) clickWin = stwin1;
  306.       else clickWin = stwin;
  307.     }
  308.     if (DEBUG) fprintf(stderr,"\n");
  309.       }
  310.       else clickWin = rootW;
  311.     }
  312.   }
  313.   
  314.  
  315.   /***
  316.    ***  now that clickWin,ix,iy,iw,ih are known, try to grab the bits...
  317.    ***/
  318.  
  319.  
  320.   WaitCursor();
  321.  
  322.   if (!autograb) XGrabServer(theDisp);     /* until we've done the grabImage */
  323.   rv = grabImage(clickWin,ix,iy,iw,ih);  /* ungrabs the server & button */
  324.  
  325.   SetCursors(-1);
  326.  
  327.  
  328.  exit:
  329.  
  330.   if (hidewins) {                   /* remap XV windows */
  331.     autoclose += 2;                 /* force it on once */
  332.     if (mainW && dispMode == RMB_WINDOW) {
  333.       int state;
  334.  
  335.       XMapRaised(theDisp, mainW);
  336.       XSync(theDisp, False);        /* get that damned window on screen */
  337.  
  338.       if (DEBUG) fprintf(stderr,"==remapped mainW.  waiting for Config.\n");
  339.  
  340.       /* sit here until we see a MapNotify on mainW followed by a 
  341.      ConfigureNotify on mainW */
  342.  
  343.       state = 0;
  344.       while (1) {
  345.     XEvent event;
  346.     XNextEvent(theDisp, &event);
  347.     HandleEvent(&event, &i);
  348.  
  349.     if (state==0 && event.type == MapNotify &&
  350.         event.xmap.window == mainW) state = 1;
  351.  
  352.     if (state==1 && event.type == ConfigureNotify && 
  353.         event.xconfigure.window == mainW) break;
  354.       }
  355.  
  356.       if (DEBUG) fprintf(stderr,"==after remapping mainW, GOT Config.\n");
  357.     }
  358.       
  359.     else if (ctrlW) CtrlBox(1);
  360.   }
  361.  
  362.   return rv;
  363. }
  364.  
  365.  
  366. /***********************************/
  367. static void flashrect(x,y,w,h,show)
  368.      int x,y,w,h,show;
  369. {
  370.   static int isvis  = 0;
  371.   static int maskno = 0;
  372.  
  373.   XSetPlaneMask(theDisp, rootGC, xorMasks[maskno]);
  374.  
  375.   if (!show) {     /* turn off rectangle */
  376.     if (isvis) 
  377.       XDrawRectangle(theDisp, rootW, rootGC, x, y, (u_int) w-1, (u_int) h-1);
  378.  
  379.     isvis = 0;
  380.   }
  381.   else {           /* show rectangle */
  382.     if (!isvis && w>1 && h>1) {
  383.       maskno = (maskno + 1) & 7;
  384.       XSetPlaneMask(theDisp, rootGC, xorMasks[maskno]);
  385.       XDrawRectangle(theDisp, rootW, rootGC, x, y, (u_int) w-1, (u_int) h-1);
  386.       isvis = 1;
  387.     }
  388.   }
  389. }
  390.  
  391.  
  392. /***********************************/
  393. static void startflash()
  394. {  
  395.   /* set up for drawing a flashing rectangle */
  396.   XSetFunction(theDisp, rootGC, GXinvert);
  397.   XSetSubwindowMode(theDisp, rootGC, IncludeInferiors);
  398. }
  399.  
  400. /***********************************/
  401. static void endflash()
  402. {  
  403.   XSetFunction(theDisp, rootGC, GXcopy);
  404.   XSetSubwindowMode(theDisp, rootGC, ClipByChildren);
  405.   XSetPlaneMask(theDisp, rootGC, AllPlanes);
  406.   XSync(theDisp, False);
  407. }
  408.  
  409.  
  410. /***********************************/
  411. static int grabImage(clickWin, x, y, w, h)
  412.      Window clickWin;
  413.      int    x, y, w, h;
  414. {
  415.   /* attempts to grab the specified rectangle of the root window
  416.      returns '1' on success.  clickWin is used to figure out the depth
  417.      and colormap to use */
  418.  
  419.   XImage *image;
  420.   XWindowAttributes xwa;
  421.   XColor *colors;
  422.   int ncolors, i, ix, iy;
  423.   char str[256];
  424.   Window win;
  425.  
  426.  
  427.   /* range checking */
  428.   if (x<0) { w += x;  x = 0; }
  429.   if (y<0) { h += y;  y = 0; }
  430.   if (x+w>dispWIDE) w = dispWIDE-x;
  431.   if (y+h>dispHIGH) h = dispHIGH-y;
  432.  
  433.   if (w==0 || h==0) {  /* selected nothing */
  434.     ungrabX();
  435.     return 0;
  436.   }
  437.  
  438.   if (!XGetWindowAttributes(theDisp, clickWin, &xwa)) {
  439.     sprintf(str,"Unable to get window attributes for clicked-on window\n");
  440.     ungrabX();
  441.     ErrPopUp(str, "\nThat Sucks!");
  442.     return 0;
  443.   }
  444.  
  445.  
  446.   XTranslateCoordinates(theDisp, rootW, clickWin, x, y, &ix, &iy, &win);
  447.  
  448.   xerrcode = 0;
  449.   image = XGetImage(theDisp, clickWin, ix, iy, (u_int) w, (u_int) h, 
  450.             AllPlanes, ZPixmap);
  451.   if (xerrcode || !image || !image->data) {
  452.     sprintf(str, "Unable to get image (%d,%d %dx%d) from display", ix,iy,w,h);
  453.     ungrabX();
  454.     ErrPopUp(str, "\nThat Sucks!");
  455.     return 0;
  456.   }
  457.  
  458.   ncolors = getxcolors(&xwa, &colors);
  459.  
  460.   ungrabX();
  461.  
  462.   if (ncolors && DEBUG) {
  463.     fprintf(stderr, "Colormap:\n");
  464.     for (i=0; i<ncolors; i++)
  465.       fprintf(stderr,"%02x%02x%02x  ",colors[i].red>>8, colors[i].green>>8,
  466.           colors[i].blue>>8);
  467.     fprintf(stderr,"\n");
  468.   }
  469.  
  470.  
  471.   XBell(theDisp, 0);    /* beep twice at end of grab */
  472.   XBell(theDisp, 0);
  473.  
  474.   i = convertImage(image, colors, ncolors, &xwa);
  475.  
  476.   /* DO *NOT* use xvDestroyImage(), as the 'data' field was alloc'd by X, not
  477.      necessarily through 'malloc() / free()' */
  478.   XDestroyImage(image);   
  479.   
  480.   if (colors) free((char *) colors);
  481.  
  482.   return i;
  483. }
  484.  
  485.  
  486. static void ungrabX()
  487. {
  488.   XUngrabServer(theDisp);
  489.   XUngrabButton(theDisp, (u_int) AnyButton, 0, rootW);
  490. }
  491.  
  492.  
  493.  
  494.  
  495.  
  496. union swapun {
  497.   CARD32 l;
  498.   CARD16 s;
  499.   CARD8  b[sizeof(CARD32)];
  500. };
  501.  
  502.  
  503. /**************************************/
  504. static int convertImage(image, colors, ncolors, xwap)
  505.      XImage *image;
  506.      XColor *colors;
  507.      int     ncolors;
  508.      XWindowAttributes *xwap;
  509. {
  510.   /* attempts to conver the image from whatever weird-ass format it might
  511.      be in into something E-Z to deal with (either an 8-bit colormapped
  512.      image, or a 24-bit image).  Returns '1' on success. */
  513.  
  514.   /* this code owes a lot to 'xwdtopnm.c', part of the pbmplus package,
  515.      written by Jef Poskanzer */
  516.  
  517.   int             i, j;
  518.   CARD8          *bptr, tmpbyte;
  519.   CARD16         *sptr, sval;
  520.   CARD32         *lptr, lval;
  521.   CARD8          *pptr, *lineptr;
  522.   int            bits_used, bits_per_item, bit_shift, bit_order;
  523.   int            bits_per_pixel, byte_order;
  524.   CARD32         pixvalue, pixmask, rmask, gmask, bmask;
  525.   int            rshift, gshift, bshift, r8shift, g8shift, b8shift;
  526.   CARD32         rval, gval, bval;
  527.   union swapun   sw;
  528.   int            isLsbMachine, flipBytes;
  529.   Visual         *visual;
  530.   char            errstr[256];
  531.   static char    *foo[] = { "\nThat Sucks!" };
  532.  
  533.  
  534.   /* quiet compiler warnings */
  535.   sval = 0;
  536.   lval = 0;
  537.   bit_shift = 0;
  538.   pixvalue  = 0;
  539.   rmask  = gmask  = bmask = 0;
  540.   rshift = gshift = bshift = 0;
  541.  
  542.  
  543.   /* determine byte order of the machine we're running on */
  544.   sw.l = 1;
  545.   isLsbMachine = (sw.b[0]) ? 1 : 0;
  546.  
  547.   if (xwap && xwap->visual) visual = xwap->visual;
  548.                        else visual = theVisual;
  549.  
  550.   if (DEBUG) {
  551.     fprintf(stderr,"convertImage:\n");
  552.     fprintf(stderr,"  %dx%d (offset %d), %s\n",
  553.         image->width, image->height, image->xoffset, 
  554.         (image->format == XYBitmap || image->format == XYPixmap) 
  555.         ? "XYPixmap" : "ZPixmap");
  556.  
  557.     fprintf(stderr,"byte_order = %s, bitmap_bit_order = %s, unit=%d, pad=%d\n",
  558.         (image->byte_order == LSBFirst) ? "LSBFirst" : "MSBFirst",
  559.         (image->bitmap_bit_order == LSBFirst) ? "LSBFirst" : "MSBFirst",
  560.         image->bitmap_unit, image->bitmap_pad);
  561.  
  562.     fprintf(stderr,"depth = %d, bperline = %d, bits_per_pixel = %d\n",
  563.         image->depth, image->bytes_per_line, image->bits_per_pixel);
  564.  
  565.     fprintf(stderr,"masks:  red %lx  green %lx  blue %lx\n",
  566.         image->red_mask, image->green_mask, image->blue_mask);
  567.  
  568.     if (isLsbMachine) fprintf(stderr,"This looks like an lsbfirst machine\n");
  569.                  else fprintf(stderr,"This looks like an msbfirst machine\n");
  570.   }
  571.  
  572.  
  573.   if (image->bitmap_unit != 8 && image->bitmap_unit != 16 &&
  574.       image->bitmap_unit != 32) {
  575.     sprintf(errstr, "%s\nReturned image bitmap_unit (%d) non-standard.",
  576.         "Can't deal with this display.", image->bitmap_unit);
  577.     ErrPopUp(errstr, "\nThat Sucks!");
  578.     return 0;
  579.   }
  580.  
  581.   if (!ncolors && visual->class != TrueColor) {
  582.     sprintf(errstr, "%s\nOnly TrueColor displays can have no colormap.",
  583.         "Can't deal with this display.");
  584.     ErrPopUp(errstr, "\nThat Sucks!");
  585.     return 0;
  586.   }
  587.  
  588.  
  589.   /* build the 'global' grabPic stuff */
  590.   gWIDE = image->width;  gHIGH = image->height;
  591.  
  592.   if (visual->class == TrueColor || visual->class == DirectColor ||
  593.       ncolors > 256) {
  594.     grabPic = (byte *) malloc((size_t) gWIDE * gHIGH * 3);
  595.     gbits = 24;
  596.   }
  597.   else {
  598.     grabPic = (byte *) malloc((size_t) gWIDE * gHIGH);
  599.     gbits = 8;
  600.  
  601.     /* load up the colormap */
  602.     for (i=0; i<ncolors; i++) {
  603.       grabmapR[i] = colors[i].red   >> 8;
  604.       grabmapG[i] = colors[i].green >> 8;
  605.       grabmapB[i] = colors[i].blue  >> 8;
  606.     }
  607.   }
  608.   
  609.   if (!grabPic) FatalError("unable to malloc grabPic in convertImage()");
  610.   pptr = grabPic;
  611.  
  612.  
  613.   if (visual->class == TrueColor || visual->class == DirectColor) {
  614.     unsigned int tmp;
  615.  
  616.     /* compute various shifty constants we'll need */
  617.     rmask = image->red_mask;
  618.     gmask = image->green_mask;
  619.     bmask = image->blue_mask;
  620.  
  621.     rshift = lowbitnum((unsigned long) rmask);
  622.     gshift = lowbitnum((unsigned long) gmask);
  623.     bshift = lowbitnum((unsigned long) bmask);
  624.  
  625.     r8shift = 0;  tmp = rmask >> rshift;
  626.     while (tmp >= 256) { tmp >>= 1;  r8shift -= 1; }
  627.     while (tmp < 128)  { tmp <<= 1;  r8shift += 1; }
  628.  
  629.     g8shift = 0;  tmp = gmask >> gshift;
  630.     while (tmp >= 256) { tmp >>= 1;  g8shift -= 1; }
  631.     while (tmp < 128)  { tmp <<= 1;  g8shift += 1; }
  632.  
  633.     b8shift = 0;  tmp = bmask >> bshift;
  634.     while (tmp >= 256) { tmp >>= 1;  b8shift -= 1; }
  635.     while (tmp < 128)  { tmp <<= 1;  b8shift += 1; }
  636.  
  637.     if (DEBUG)
  638.       fprintf(stderr,"True/DirectColor: shifts=%d,%d,%d  8shifts=%d,%d,%d\n",
  639.           rshift, gshift, bshift, r8shift, g8shift, b8shift);
  640.   }
  641.  
  642.  
  643.   bits_per_item = image->bitmap_unit;
  644.   bits_used = bits_per_item;
  645.   bits_per_pixel = image->bits_per_pixel;
  646.  
  647.   if (bits_per_pixel == 32) pixmask = 0xffffffff;
  648.   else pixmask = (((CARD32) 1) << bits_per_pixel) - 1;
  649.  
  650.   bit_order = image->bitmap_bit_order;
  651.   byte_order = image->byte_order;
  652.  
  653.   /* if we're on an lsbfirst machine, or the image came from an lsbfirst
  654.      machine, we should flip the bytes around.  NOTE:  if we're on an
  655.      lsbfirst machine *and* the image came from an lsbfirst machine, 
  656.      *don't* flip bytes, as it should work out */
  657.  
  658.   /* pity we don't have a logical exclusive-or */
  659.   flipBytes = ( isLsbMachine && byte_order != LSBFirst) ||
  660.               (!isLsbMachine && byte_order == LSBFirst);
  661.  
  662.   for (i=0; i<image->height; i++) {
  663.     lineptr = (byte *) image->data + (i * image->bytes_per_line);
  664.     bptr = ((CARD8  *) lineptr) - 1;
  665.     sptr = ((CARD16 *) lineptr) - 1;
  666.     lptr = ((CARD32 *) lineptr) - 1;
  667.     bits_used = bits_per_item;
  668.  
  669.     for (j=0; j<image->width; j++) {
  670.       
  671.       /* get the next pixel value from the image data */
  672.  
  673.       if (bits_used == bits_per_item) {  /* time to move on to next b/s/l */
  674.     switch (bits_per_item) {
  675.     case 8:  bptr++;  break;
  676.     case 16: sptr++;  sval = *sptr;
  677.              if (flipBytes) {   /* swap CARD16 */
  678.            sw.s = sval;
  679.            tmpbyte = sw.b[0];
  680.            sw.b[0] = sw.b[1];
  681.            sw.b[1] = tmpbyte;
  682.            sval = sw.s;
  683.          }
  684.              break;
  685.     case 32: lptr++;  lval = *lptr;
  686.              if (flipBytes) {   /* swap CARD32 */
  687.            sw.l = lval;
  688.            tmpbyte = sw.b[0];
  689.            sw.b[0] = sw.b[3];
  690.            sw.b[3] = tmpbyte;
  691.            tmpbyte = sw.b[1];
  692.            sw.b[1] = sw.b[2];
  693.            sw.b[2] = tmpbyte;
  694.            lval = sw.l;
  695.          }
  696.              break;
  697.     }
  698.            
  699.     bits_used = 0;
  700.     if (bit_order == MSBFirst) bit_shift = bits_per_item - bits_per_pixel;
  701.                           else bit_shift = 0;
  702.       }
  703.  
  704.       switch (bits_per_item) {
  705.       case 8:  pixvalue = (*bptr >> bit_shift) & pixmask;  break;
  706.       case 16: pixvalue = ( sval >> bit_shift) & pixmask;  break;
  707.       case 32: pixvalue = ( lval >> bit_shift) & pixmask;  break;
  708.       }
  709.  
  710.       if (bit_order == MSBFirst) bit_shift -= bits_per_pixel;
  711.                             else bit_shift += bits_per_pixel;
  712.       bits_used += bits_per_pixel;
  713.  
  714.       
  715.       /* okay, we've got the next pixel value in 'pixvalue' */
  716.       
  717.       if (visual->class == TrueColor || visual->class == DirectColor) {
  718.     /* in either case, we have to take the pixvalue and 
  719.        break it out into individual r,g,b components */
  720.     rval = (pixvalue & rmask) >> rshift;
  721.     gval = (pixvalue & gmask) >> gshift;
  722.     bval = (pixvalue & bmask) >> bshift;
  723.  
  724.     if (visual->class == DirectColor) {
  725.       /* use rval, gval, bval as indicies into colors array */
  726.  
  727.       *pptr++ = (rval < ncolors) ? (colors[rval].red   >> 8) : 0;
  728.       *pptr++ = (gval < ncolors) ? (colors[gval].green >> 8) : 0;
  729.       *pptr++ = (bval < ncolors) ? (colors[bval].blue  >> 8) : 0;
  730.     }
  731.  
  732.     else {   /* TrueColor */
  733.       /* have to map rval,gval,bval into 0-255 range */
  734.       *pptr++ = (r8shift >= 0) ? (rval << r8shift) : (rval >> (-r8shift));
  735.       *pptr++ = (g8shift >= 0) ? (gval << g8shift) : (gval >> (-g8shift));
  736.       *pptr++ = (b8shift >= 0) ? (bval << b8shift) : (bval >> (-b8shift));
  737.     }
  738.       }
  739.  
  740.       else { /* all others: StaticGray, StaticColor, GrayScale, PseudoColor */
  741.     /* use pixel value as an index into colors array */
  742.  
  743.     if (pixvalue >= ncolors) {
  744.       FatalError("convertImage(): pixvalue >= ncolors");
  745.     }
  746.  
  747.     if (gbits == 24) {   /* too many colors for 8-bit colormap */
  748.       *pptr++ = (colors[pixvalue].red)   >> 8;
  749.       *pptr++ = (colors[pixvalue].green) >> 8;
  750.       *pptr++ = (colors[pixvalue].blue)  >> 8;
  751.     }
  752.     else *pptr++ = pixvalue & 0xff;
  753.  
  754.       }
  755.     }
  756.   }
  757.  
  758.   return 1;
  759. }
  760.  
  761.  
  762.  
  763. /**************************************/
  764. static int lowbitnum(ul)
  765.      unsigned long ul;
  766. {
  767.   /* returns position of lowest set bit in 'ul' as an integer (0-31),
  768.    or -1 if none */
  769.  
  770.   int i;
  771.   for (i=0; ((ul&1) == 0) && i<32;  i++, ul>>=1);
  772.   if (i==32) i = -1;
  773.   return i;
  774. }
  775.  
  776.  
  777.  
  778. /**************************************/
  779. /* following code snarfed from 'xwd.c' */
  780. /**************************************/
  781.  
  782. #define lowbit(x) ((x) & (~(x) + 1))
  783.  
  784.  
  785. static int getxcolors(win_info, colors)
  786.      XWindowAttributes *win_info;
  787.      XColor **colors;
  788. {
  789.   int i, ncolors;
  790.   Colormap cmap;
  791.  
  792.   *colors = (XColor *) NULL;
  793.  
  794.   if (win_info->visual->class == TrueColor) {
  795.     if (DEBUG) fprintf(stderr,"TrueColor visual:  no colormap needed\n");
  796.     return 0;
  797.   }
  798.  
  799.   else if (!win_info->colormap) {
  800.     if (DEBUG) fprintf(stderr,"no colormap associated with window\n");
  801.     return 0;
  802.   }
  803.  
  804.   ncolors = win_info->visual->map_entries;
  805.   if (DEBUG) fprintf(stderr,"%d entries in colormap\n", ncolors);
  806.  
  807.   if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors)))
  808.     FatalError("malloc failed in getxcolors()");
  809.  
  810.  
  811.   if (win_info->visual->class == DirectColor) {
  812.     Pixel red, green, blue, red1, green1, blue1;
  813.  
  814.     if (DEBUG) fprintf(stderr,"DirectColor visual\n");
  815.  
  816.     red = green = blue = 0;
  817.     red1   = lowbit(win_info->visual->red_mask);
  818.     green1 = lowbit(win_info->visual->green_mask);
  819.     blue1  = lowbit(win_info->visual->blue_mask);
  820.     for (i=0; i<ncolors; i++) {
  821.       (*colors)[i].pixel = red|green|blue;
  822.       (*colors)[i].pad = 0;
  823.       red += red1;
  824.       if (red > win_info->visual->red_mask)     red = 0;
  825.       green += green1;
  826.       if (green > win_info->visual->green_mask) green = 0;
  827.       blue += blue1;
  828.       if (blue > win_info->visual->blue_mask)   blue = 0;
  829.     }
  830.   }
  831.   else {
  832.     for (i=0; i<ncolors; i++) {
  833.       (*colors)[i].pixel = i;
  834.       (*colors)[i].pad = 0;
  835.     }
  836.   }
  837.  
  838.   XQueryColors(theDisp, win_info->colormap, *colors, ncolors);
  839.  
  840.   return(ncolors);
  841. }
  842.     
  843.  
  844.  
  845.  
  846.  
  847. /***********************************/
  848. int LoadGrab(pinfo)
  849.      PICINFO *pinfo;
  850. {
  851.   /* loads up (into XV structures) last image successfully grabbed.
  852.      returns '0' on failure, '1' on success */
  853.  
  854.   int   i;
  855.  
  856.   if (!grabPic) return 0;   /* no image to use */
  857.  
  858.   if (gbits == 24) pinfo->type = PIC24;
  859.   else {
  860.     pinfo->type = PIC8;
  861.  
  862.     for (i=0; i<256; i++) {
  863.       pinfo->r[i] = grabmapR[i];
  864.       pinfo->g[i] = grabmapG[i];
  865.       pinfo->b[i] = grabmapB[i];
  866.     }
  867.   }
  868.  
  869.   pinfo->pic     = grabPic;
  870.   pinfo->normw   = pinfo->w   = gWIDE;
  871.   pinfo->normh   = pinfo->h   = gHIGH;
  872.   pinfo->frmType = -1;
  873.   pinfo->colType = -1;
  874.  
  875.   sprintf(pinfo->fullInfo,"<%s internal>", 
  876.       (pinfo->type == PIC8) ? "8-bit" : "24-bit");
  877.   
  878.   sprintf(pinfo->shrtInfo,"%dx%d image.",gWIDE, gHIGH);
  879.   
  880.   pinfo->comment = (char *) NULL;
  881.  
  882.   grabPic = (byte *) NULL;
  883.  
  884.   return 1;
  885. }
  886.  
  887.  
  888.  
  889.  
  890.  
  891. #include <X11/Xlib.h>
  892. #include <X11/Xatom.h>
  893.  
  894. static Window TryChildren PARM((Display *, Window, Atom));
  895.  
  896. /* Find a window with WM_STATE, else return '0' */
  897.  
  898. static Window xvClientWindow (dpy, win)
  899.     Display *dpy;
  900.     Window win;
  901. {
  902.     Atom WM_STATE;
  903.     Atom type = None;
  904.     int format;
  905.     unsigned long nitems, after;
  906.     unsigned char *data;
  907.     Window inf;
  908.  
  909.     WM_STATE = XInternAtom(dpy, "WM_STATE", True);
  910.     if (!WM_STATE) return win;
  911.  
  912.     XGetWindowProperty(dpy, win, WM_STATE, 0L, 0L, False, AnyPropertyType,
  913.                &type, &format, &nitems, &after, &data);
  914.     if (type) return win;
  915.  
  916.     inf = TryChildren(dpy, win, WM_STATE);
  917.  
  918.     return inf;
  919. }
  920.  
  921. static Window TryChildren (dpy, win, WM_STATE)
  922.     Display *dpy;
  923.     Window win;
  924.     Atom WM_STATE;
  925. {
  926.     Window root, parent;
  927.     Window *children;
  928.     unsigned int nchildren;
  929.     unsigned int i;
  930.     Atom type = None;
  931.     int format;
  932.     unsigned long nitems, after;
  933.     unsigned char *data;
  934.     Window inf = 0;
  935.  
  936.     if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
  937.     return 0;
  938.  
  939.     for (i = 0; !inf && (i < nchildren); i++) {
  940.     XGetWindowProperty(dpy, children[i], WM_STATE, 0L, 0L, False,
  941.                AnyPropertyType, &type, &format, &nitems,
  942.                &after, &data);
  943.     if (type)
  944.       inf = children[i];
  945.     }
  946.  
  947.     for (i = 0; !inf && (i < nchildren); i++)
  948.       inf = TryChildren(dpy, children[i], WM_STATE);
  949.  
  950.     if (children) XFree((char *)children);
  951.     return inf;
  952. }
  953.