Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!sun-barr!newstop!exodus!appserv!halibut.cis.upenn.edu From: bradley@halibut.cis.upenn.edu (John Bradley) Newsgroups: comp.sources.x Subject: v10i083: xv - display and manipulate images, Part05/10 Message-ID: <321@appserv.Eng.Sun.COM> Date: 27 Nov 90 20:08:23 GMT References: Sender: news@exodus.Eng.Sun.COM Lines: 1886 Approved: argv@sun.com Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley) Posting-number: Volume 10, Issue 83 Archive-name: xv/part05 #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./xvinfo.c` then echo "writting ./xvinfo.c" cat > ./xvinfo.c << '\BARFOO\' /* * xvinfo.c - 'Info' box handling functions * * callable functions: * * CreateInfo(geom) - creates the infoW window. Doesn't map it. * InfoBox(vis) - random processing based on value of 'vis' * maps/unmaps window, etc. * RedrawInfo(x,y,w,h) - called by 'expose' events * SetInfoMode(mode) - changes amount of info Info window shows * SetISTR(st, fmt, args) - sprintf's into ISTR #st. Redraws it in window * char *GetISTR(st) - returns pointer to ISTR #st, or NULL if st bogus */ /* * Copyright 1989, 1990 by the University of Pennsylvania * * Permission to use, copy, and distribute for non-commercial purposes, * is hereby granted without fee, providing that the above copyright * notice appear in all copies and that both the copyright notice and this * permission notice appear in supporting documentation. * * The software may be modified for your own purposes, but modified versions * may not be distributed. * * This software is provided "as is" without any express or implied warranty. */ #define NEEDSVARARGS #include "xv.h" #include "bitmaps.h" /* max length of an Info String */ #define ISTRLEN 80 /* baseline of top line of text */ #define TOPBASE (36 + penn_height/2 + 4 + 8 + ASCENT) #define STLEFT 100 /* left edge of strings */ static Pixmap graspPix, pennPix; static char istrs[NISTR][ISTRLEN]; #ifdef __STDC__ static void DrawStrings(void); static void DrawFieldName(int); static void RedrawString(int); #else static void DrawStrings(), DrawFieldName(), RedrawString(); #endif /***************************************************/ void CreateInfo(geom) char *geom; { infoW = CreateWindow("xv info", geom, INFOWIDE, INFOHIGH, infofg, infobg); if (!infoW) FatalError("can't create info window!"); pennPix = XCreatePixmapFromBitmapData(theDisp, infoW, penn_bits, penn_width, penn_height, infofg, infobg, dispDEEP); graspPix = XCreatePixmapFromBitmapData(theDisp,infoW,grasp_bits,grasp_width, grasp_height, infofg, infobg, dispDEEP); } /***************************************************/ void InfoBox(vis) int vis; { if (vis) XMapRaised(theDisp, infoW); else XUnmapWindow(theDisp, infoW); infoUp = vis; } /***************************************************/ void RedrawInfo(x,y,w,h) int x,y,w,h; { int i; XSetForeground(theDisp, theGC, infofg); XSetBackground(theDisp, theGC, infobg); /* draw the two icons */ XCopyArea(theDisp, pennPix, infoW, theGC, 0, 0, penn_width, penn_height, 36 - penn_width/2, 36 - penn_height/2); XCopyArea(theDisp, graspPix, infoW, theGC, 0, 0, grasp_width, grasp_height, INFOWIDE - 36 - grasp_width/2, 36 - grasp_height/2); /* draw the credits */ sprintf(str,"XV - %s",REVDATE); CenterString(infoW, str, INFOWIDE/2, 36-LINEHIGH); CenterString(infoW, "by John Bradley (bradley@cis.upenn.edu)" , INFOWIDE/2, 36); CenterString(infoW, "(c) 1990, University of Pennsylvania", INFOWIDE/2, 36+LINEHIGH); /* draw the dividing lines */ i = 36 + penn_height/2 + 4; XDrawLine(theDisp, infoW, theGC, 0, i, INFOWIDE, i); XDrawLine(theDisp, infoW, theGC, 0, i+2, INFOWIDE, i+2); XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-20, INFOWIDE, INFOHIGH-20); XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-22, INFOWIDE, INFOHIGH-22); XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-40, INFOWIDE, INFOHIGH-40); XDrawLine(theDisp, infoW, theGC, 0, INFOHIGH-42, INFOWIDE, INFOHIGH-42); DrawStrings(); } /***************************************************/ static void DrawStrings() { int i; for (i=0; i<6; i++) DrawFieldName(i); /* draw the field titles */ for (i=0; i=3) return; XDrawString(theDisp, infoW, theGC, 10, TOPBASE + fnum*LINEHIGH, fname[fnum], strlen(fname[fnum])); } /***************************************************/ static void RedrawString(st) int st; { /* erase area of string, and draw it with new contents */ XSetForeground(theDisp, theGC, infofg); XSetBackground(theDisp, theGC, infobg); if (infoMode == INF_NONE) return; if (infoMode == INF_STR && st > ISTR_WARNING) return; if (infoMode == INF_PART && st > ISTR_RES) return; if (st == ISTR_INFO) { XClearArea(theDisp, infoW, 0, INFOHIGH-19, INFOWIDE, 17, False); CenterString(infoW, istrs[st], INFOWIDE/2, INFOHIGH-10); } else if (st == ISTR_WARNING) { XClearArea(theDisp, infoW, 0, INFOHIGH-39, INFOWIDE, 17, False); CenterString(infoW, istrs[st], INFOWIDE/2, INFOHIGH-30); } else { XClearArea(theDisp,infoW,STLEFT,TOPBASE - ASCENT + (st-ISTR_FILENAME)*LINEHIGH, INFOWIDE-STLEFT, LINEHIGH,False); XDrawString(theDisp, infoW, theGC, STLEFT,TOPBASE + (st-ISTR_FILENAME)*LINEHIGH, istrs[st], strlen(istrs[st])); } } /***************************************************/ void SetInfoMode(mode) int mode; { int y1, y2; infoMode = mode; if (infoUp) { /* only do this if window is mapped */ y1 = TOPBASE - ASCENT; y2 = INFOHIGH-43; XClearArea(theDisp, infoW, 0, y1, INFOWIDE, y2-y1, False); XClearArea(theDisp, infoW, 0, INFOHIGH-39, INFOWIDE, 17, False); XClearArea(theDisp, infoW, 0, INFOHIGH-19, INFOWIDE, 17, False); DrawStrings(); } } /***************************************************/ /*VARARGS0*/ void SetISTR(va_alist) va_dcl { va_list args; char *fmt; int stnum; /* InfoStr( ISTR, format, arg1, arg2, ...) */ va_start(args); stnum = va_arg(args, int); if (stnum<0 || stnum>=NISTR) return; fmt = va_arg(args, char *); vsprintf(istrs[stnum], fmt, args); va_end(args); if (infoUp) { RedrawString(stnum); XFlush(theDisp); } if (ctrlUp && stnum == ISTR_INFO) { DrawCtrlStr(); XFlush(theDisp); } } /***************************************************/ char *GetISTR(stnum) int stnum; { /* returns pointer to ISTR string */ if (stnum < 0 || stnum>=NISTR) return(NULL); return (istrs[stnum]); } \BARFOO\ else echo "will not over write ./xvinfo.c" fi if `test ! -s ./xvmisc.c` then echo "writting ./xvmisc.c" cat > ./xvmisc.c << '\BARFOO\' /* * xvmisc.c - random routines that most of the work involved in putting * a picture on an X display. * * Resize(w,h) - generates epic, new Ximage, * SortColormap() - sorts the desired colormap into a 'most important color * to allocate first' order * AllocColors() - Takes the desired colormap and sees what it can do about * getting it. * DoCrop() - crops the picture * UnCrop() - uncrops the picture (natch) * Rotate() - rotates 'pic' 90-degrees clockwise * FloydDitherize8 - Takes epic, and produces a b/w dithered version of it, * stored in 8-bit per pixel format * FloydDitherize1 - Does the same, but the output is an XYBitmap (1 bit per * pixel, packed 8 pixels to a byte. * CreateXImage - Given epic, generate an ximage of it. Handles displays * of different depths. * CenterString - civilized string drawing routine. uses font 'mfinfo' * ULineString - draws underlined string. uses font 'mfinfo' * StringWidth - civilized XTextWidth width interface, uses font 'mfinfo' * FakeButtonPress - when a keyboard equiv is hit, fakes mouse click in button * Timer - sleeps for a given # of milliseconds */ /* * Copyright 1989, 1990 by the University of Pennsylvania * * Permission to use, copy, and distribute for non-commercial purposes, * is hereby granted without fee, providing that the above copyright * notice appear in all copies and that both the copyright notice and this * permission notice appear in supporting documentation. * * The software may be modified for your own purposes, but modified versions * may not be distributed. * * This software is provided "as is" without any express or implied warranty. */ #define NEEDSTIME #include "xv.h" #include "bitmaps.h" #ifdef __STDC__ static void DoCrop1(int, int, int, int); static void RotatePic(byte *, unsigned int *, unsigned int *, int); static void FloydDitherize8(byte *); static void FloydDitherize1(XImage *); static void FreeMostResources(void); #else static void DoCrop1(), RotatePic(), FloydDitherize8(), FloydDitherize1(); static void FreeMostResources(); #endif /***************************************************/ Window CreateWindow(name,geom,w,h,fg,bg) char *name, *geom; unsigned int w,h; unsigned long fg, bg; { Window win; XSetWindowAttributes xswa; unsigned int xswamask; XWMHints xwmh; XSizeHints hints; int i,x,y; /* note that only x,y are gotten from geom spec. w,h are fixed */ x = y = 1; i = XParseGeometry(geom,&x,&y,&w,&h); if (i&XValue || i&YValue) hints.flags = USPosition; else hints.flags = PPosition; hints.flags |= USSize; if (i&XValue && i&XNegative) x = dispWIDE - w - abs(x); if (i&YValue && i&YNegative) y = dispHIGH - h - abs(y); hints.x = x; hints.y = y; hints.width = w; hints.height = h; hints.min_width = w; hints.min_height = h; hints.max_width = w; hints.max_height = h; hints.flags |= PMaxSize | PMinSize; xswa.background_pixel = bg; xswa.border_pixel = fg; xswamask = CWBackPixel | CWBorderPixel; win = XCreateWindow(theDisp, rootW, x, y, w, h, bwidth, CopyFromParent, CopyFromParent, CopyFromParent, xswamask, &xswa); if (!win) return(win); /* leave immediately if couldn't create */ XSetStandardProperties(theDisp, win, name, name, None, NULL, 0, &hints); xwmh.input = True; xwmh.flags = InputHint; if (iconPix) { xwmh.icon_pixmap = iconPix; xwmh.flags |= IconPixmapHint; } XSetWMHints(theDisp, win, &xwmh); return(win); } /***********************************/ void Resize(w,h) int w,h; { int cy,ex,ey,*cxarr, *cxarrp; byte *clptr,*elptr,*epptr; static char *rstr = "Resizing Image. Please wait..."; clptr = NULL; cxarrp = NULL; cy = 0; /* shut up compiler */ /* force w,h into valid ranges */ RANGE(w,1,dispWIDE); RANGE(h,1,dispHIGH); SetISTR(ISTR_EXPAND, "%.3g x %.3g (%d x %d)", ((float) w) / cWIDE, ((float) h) / cHIGH, w, h); /* if same size, and Ximage created, do nothing */ if (w==eWIDE && h==eHIGH && theImage!=NULL) return; if (DEBUG) fprintf(stderr,"%s: Resize(%d,%d) eSIZE=%d,%d cSIZE=%d,%d\n", cmd,w,h,eWIDE,eHIGH,cWIDE,cHIGH); BTSetActive(&but[BCROP],0); SetCropString(); if (w==cWIDE && h==cHIGH) { /* 1:1 expansion. point epic at cpic */ if (epic != cpic && epic!=NULL) free(epic); epic = cpic; eWIDE = cWIDE; eHIGH = cHIGH; } else { /* have to actually SCALE THE PIC. Drats! */ StartFish(); WaitCursor(); /* if it's a big image, this could take a while. mention it */ if (w*h>(500*500) && !useroot) { XSetForeground(theDisp, theGC, fg); XSetBackground(theDisp, theGC, bg); XClearWindow(theDisp,mainW); XFlush(theDisp); XDrawImageString(theDisp,mainW,theGC,CENTERX(mfinfo,w/2,rstr), CENTERY(mfinfo,h/2),rstr, strlen(rstr)); XFlush(theDisp); } /* first, kill the old epic, if one exists */ if (epic!=NULL && epic!=cpic) { free(epic); epic = NULL; } /* create a new epic of the appropriate size */ eWIDE = w; eHIGH = h; epic = (byte *) malloc(w*h); if (epic==NULL) { sprintf(str,"unable to malloc a %dx%d image\n",w,h); FatalError(str); } /* the scaling routine. not really all that scary after all... */ /* OPTIMIZATON IDEA. Malloc an eWIDE array of ints which will hold the values of the equation px = (pWIDE * ex) / eWIDE. Faster than doing a mul and a div for every point in picture */ cxarr = (int *) malloc(eWIDE * sizeof(int)); if (!cxarr) FatalError("unable to allocate cxarr"); for (ex=0; exuse - a->use); } /***********************************/ void SortColormap() { byte *p; int i, j, k, mdist, entry, mn, d, hist[256], trans[256]; static CMAPENT c[256], c1[256], *cp, *cj, *ck; /* no point doing this if we're on a 1-bit display */ if (ncols == 0) { numcols = 256; return; } /* initialize histogram and compute it */ for (i=0; i<256; i++) hist[i]=0; for (i=pWIDE*pHIGH, p=pic; i; i--, p++) hist[*p]++; if (DEBUG>1) { fprintf(stderr,"%s: Desired colormap\n",cmd); for (i=0; i<256; i++) if (hist[i]) fprintf(stderr,"(%3d %02x,%02x,%02x) ", i,r[i],g[i],b[i]); fprintf(stderr,"\n\n"); } /* put the actually-used colors into the 'c' array in the order they occur */ /* also, while we're at it, calculate numcols */ for (i=numcols=0; i<256; i++) { if (hist[i]) { cp = &c[numcols++]; cp->r = r[i]; cp->g = g[i]; cp->b = b[i]; cp->use = hist[i]; cp->oldindex = i; } } /* find most-used color, put that in c1[0] */ entry = -1; mdist = -1; for (i=0; i mdist) { mdist = c[i].use; entry=i; } } memcpy(&c1[0], &c[entry], sizeof(CMAPENT)); c[entry].use = 0; /* and mark it dealt with */ /* sort rest of colormap, in order of decreasing 'distance' from already allocated elements. FURTHER MODIFICATION of algorithm. The algorithm's performance utterly goes to hell as numcols increases. (Probably on the order of O^3 performance). Since I don't see a clever way of rewriting the algorithm for O^2 performance (which'd be acceptable), I'm going to make a trade-off. I'll only run the algorithm for the first 32 colors (or so). It can do that Real Fast. Then I'll just stick the rest of the unsorted colors (if any), and tack them on the end, in order of amount of use. This should give similar picture quality, with much higher performance. */ for (i=1; iuse) { /* this color has not been marked already */ mn = 10000; for (k=0, ck=c1; kr - ck->r) + abs(cj->g - ck->g) + abs(cj->b - ck->b); if (mn>d) mn=d; } /* mn = minimum distance from c[j] to already used colors */ /* we want to select the unused color that has the greatest mn */ if (mn > mdist) { mdist = mn; entry = j; } } } /* c[entry] is the next color to put in the map. do so */ memcpy(&c1[i], &c[entry], sizeof(CMAPENT)); c[entry].use = 0; } /* tack rest of colors onto colormap in decreasing order of use */ qsort((char *) c,numcols,sizeof(CMAPENT),CMAPcompare); memcpy(&c1[i], c, (numcols - i) * sizeof(CMAPENT)); /* build translation table */ for (i=0; i1) { fprintf(stderr,"%s: result of sorting colormap\n",cmd); for (i=0; i%3d ",i,trans[i]); fprintf(stderr,"\n\n"); } } #define NOPIX 0xffffffff /***********************************/ void AllocColors() { int i, j, unique, p2alloc, p3alloc; Colormap cmap; XColor defs[256]; XColor ctab[256]; int dc; nfcols = unique = p2alloc = p3alloc = 0; rwthistime = 0; if (ncols == 0) { SetISTR(ISTR_COLOR,"no colors allocated. Using black & white."); SetISTR(ISTR_COLOR2,""); return; } /* FIRST PASS COLOR ALLOCATION: for each color in the 'desired colormap', try to get it via XAllocColor(). If for any reason it fails, mark that pixel 'unallocated' and worry about it later. Repeat. */ /* attempt to allocate first ncols entries in colormap note: On displays with less than 8 bits per RGB gun, it's quite possible that different colors in the original picture will be mapped to the same color on the screen. X does this for you silently. However, this is not-desirable for this application, because when I say 'allocate me 32 colors' I want it to allocate 32 different colors, not 32 instances of the same 4 shades... */ for (i=0; i>8)) + abs(gi - (ctab[j].green>>8)) + abs(bi - (ctab[j].blue>>8)); if (d>8)) + abs(gi - (ctab[j].green>>8)) + abs(bi - (ctab[j].blue>>8)); if (d>8)) + abs(gi - (defs[k].green>>8)) + abs(bi - (defs[k].blue>>8)); if (d1) ? "s" : "", p3alloc, (p3alloc>1) ? "s" : ""); else if (p2alloc && !p3alloc) SetISTR(ISTR_COLOR2,"Got %d 'close' color%s.", p2alloc, (p2alloc>1) ? "s" : ""); else if (!p2alloc && p3alloc) SetISTR(ISTR_COLOR2,"'Borrowed' %d color%s.", p3alloc, (p3alloc>1) ? "s" : ""); } /***********************************/ void AllocRWColors() { int i,j; Colormap cmap; XColor defs[256]; nfcols = 0; rwthistime = 1; if (ncols == 0) { SetISTR(ISTR_COLOR,"no colors allocated. Using black & white."); SetISTR(ISTR_COLOR2,""); rwthistime = 0; return; } cmap = theCmap; for (i=0; i>8)) + abs(gi - (defs[k].green>>8)) + abs(bi - (defs[k].blue>>8)); if (dcrx2) { i = crx1; crx1 = crx2; crx2 = i; } if (cry1>cry2) { i = cry1; cry1 = cry2; cry2 = i; } /* see if cropping to same size, in which case do nothing */ if (crx2-crx1 == eWIDE && cry2-cry1 == eHIGH) return; /* figure out what the crop rectangles coordinates are in pic coordinates */ x = cXOFF + (crx1 * cWIDE) / eWIDE; y = cYOFF + (cry1 * cHIGH) / eHIGH; x2 = cXOFF + (crx2 * cWIDE) / eWIDE; y2 = cYOFF + (cry2 * cHIGH) / eHIGH; w = (x2 - x) + 1; h = (y2 - y) + 1; if (w<1) w = 1; if (x+w > pWIDE) w = pWIDE - x; if (h<1) h = 1; if (y+h > pHIGH) h = pHIGH - y; DoCrop1(x,y,w,h); } static void DoCrop1(x,y,w,h) int x,y,w,h; { int i,j; byte *cp, *pp; double expw, exph; /* dispose of old cpic and epic */ if (epic && epic != cpic) free(epic); if (cpic && cpic != pic) free(cpic); epic = cpic = NULL; expw = (double) eWIDE / (double) cWIDE; exph = (double) eHIGH / (double) cHIGH; crx1 = (int) ((x - cXOFF) * expw); cry1 = (int) ((y - cYOFF) * exph); cXOFF = x; cYOFF = y; cWIDE = w; cHIGH = h; if (DEBUG) fprintf(stderr,"%s: cropping to %dx%d rectangle at %d,%d\n", cmd, cWIDE, cHIGH, cXOFF, cYOFF); /* kill old Ximage so that Resize will be forced to generate a new one */ if (theImage != NULL) XDestroyImage(theImage); theImage = NULL; /* at this point, we want to generate cpic, which will contain a cWIDE*cHIGH subsection of 'pic', top-left at cXOFF,cYOFF */ cpic = (byte *) malloc(cWIDE * cHIGH); if (cpic == NULL) { fprintf(stderr,"%s: unable to allocate memory for cropped image\n", cmd); WUnCrop(); cpic = pic; cXOFF = cYOFF = 0; cWIDE = pWIDE; cHIGH = pHIGH; SetCropString(); return; } /* copy relevant pixels from pic to cpic */ cp = cpic; for (i=0; i=0; j--, pix1++, pix-=w) *pix1 = *pix; } else { for (i=w-1; i>=0; i--) /* CCW */ for (j=0, pix=pic+i; j0; i--, p++) { if (*p) *p = white; else *p = black; } } } /************************/ static void FloydDitherize1(ximage) XImage *ximage; { /* same as FloydDitherize8, but output is a 1-bit per pixel XYBitmap, packed 8 pixels per byte */ register short *dp; register byte pix8, bit; short *dithpic; int i, j, err, bperln, order; byte *pp, *image, w, b, w8, b8; image = (byte *) theImage->data; bperln = theImage->bytes_per_line; order = theImage->bitmap_bit_order; if (DEBUG) fprintf(stderr,"Ditherizing1..."); dithpic = (short *) malloc(eWIDE * eHIGH * sizeof(short)); if (dithpic == NULL) FatalError("not enough memory to ditherize"); w = white&0x1; b=black&0x1; w8 = w<<7; b8 = b<<7; /* b/w bit in high bit */ /* copy r[epic] into dithpic so that we can run the algorithm */ pp = epic; dp = dithpic; for (i=eHIGH * eWIDE; i>0; i--) *dp++ = fsgamcr[r[*pp++]]; dp = dithpic; pp = image; for (i=0; i>= 1; bit++; } if (j0) dp[eWIDE-1] += ((err*3)/16); if (j>(7-bit); /* write partial byte at end of line */ } else { /* order==MSBFirst */ bit = pix8 = 0; for (j=0; j0) dp[eWIDE-1] += ((err*3)/16); if (j0; i--) *dp++ = fsgamcr[rgb[*pp++]]; dp = dithpic; pp = outpic; for (i=0; i0) dp[w1] += ((err*3)/16); if (j0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (byte) cols[*pp]; } } theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, eWIDE, eHIGH, 8, 0); if (!theImage) FatalError("couldn't create theImage!"); } break; /*********************************/ case 1: { byte *imagedata; theImage = XCreateImage(theDisp, theVisual, dispDEEP, XYPixmap, 0, NULL, eWIDE, eHIGH, 8, 0); if (!theImage) FatalError("couldn't create theImage!"); imagedata = (byte *) malloc(theImage->bytes_per_line * eHIGH); if (!imagedata) FatalError("couldn't malloc imagedata"); theImage->data = (char *) imagedata; FloydDitherize1(theImage); } break; /*********************************/ case 4: { byte *imagedata, *ip, *pp; byte *lip; int bperline, half, j; theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, eWIDE, eHIGH, 8, 0); if (!theImage) FatalError("couldn't create theImage!"); bperline = theImage->bytes_per_line; imagedata = (byte *) malloc(bperline * eHIGH); if (!imagedata) FatalError("couldn't malloc imagedata"); theImage->data = (char *) imagedata; if (ncols==0) { /* ditherize */ byte *dith; dith = (byte *) malloc(eWIDE * eHIGH); if (!dith) FatalError("can't create dithered image"); FloydDitherize8(dith); if (theImage->bits_per_pixel == 4) { for (i=0, pp=dith, lip=imagedata; ibits_per_pixel == 8) memcpy(imagedata, dith, eWIDE*eHIGH); else FatalError("This display is too bizarre. Can't create XImage."); free(dith); } else { /* don't ditherize */ if (theImage->bits_per_pixel == 4) { for (i=0, pp=epic, lip=imagedata; ibits_per_pixel == 8) { for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (byte) cols[*pp]; } } else FatalError("This display's too bizarre. Can't create XImage."); } } break; /*********************************/ case 6: { byte *imagedata, *ip, *pp; int bperline; theImage = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL, eWIDE, eHIGH, 8, 0); if (!theImage) FatalError("couldn't create theImage!"); if (theImage->bits_per_pixel != 8) FatalError("This display's too bizarre. Can't create XImage."); bperline = theImage->bytes_per_line; imagedata = (byte *) malloc(bperline * eHIGH); if (!imagedata) FatalError("couldn't malloc imagedata"); theImage->data = (char *) imagedata; if (ncols==0) FloydDitherize8(imagedata); else { for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++,ip++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip = (byte) cols[*pp]; } } } break; /*********************************/ case 24: case 32: { byte *imagedata, *ip, *pp; imagedata = (byte *) malloc(4*eWIDE*eHIGH); if (!imagedata) FatalError("couldn't malloc imagedata"); theImage = XCreateImage(theDisp,theVisual,dispDEEP,ZPixmap,0, (char *) imagedata, eWIDE, eHIGH, 32, 0); if (!theImage) FatalError("couldn't create theImage!"); if (theImage->byte_order == MSBFirst) for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip++ = 0; *ip++ = (cols[*pp]>>16) & 0xff; *ip++ = (cols[*pp]>>8) & 0xff; *ip++ = cols[*pp] & 0xff; } else for (i=eWIDE*eHIGH, pp=epic, ip=imagedata; i>0; i--,pp++) { if ((i&0x1ffff) == 0) WaitCursor(); *ip++ = cols[*pp] & 0xff; *ip++ = (cols[*pp]>>8) & 0xff; *ip++ = (cols[*pp]>>16) & 0xff; *ip++ = 0; } } break; /*********************************/ default: sprintf(str,"no code to handle this display type (%d bits deep)", dispDEEP); FatalError(str); break; } } /**************************************************/ void CenterString(win,str,x,y) Window win; char *str; int x,y; { XDrawString(theDisp, win, theGC, CENTERX(mfinfo, x, str), CENTERY(mfinfo, y), str, strlen(str)); } /**************************************************/ void ULineString(win,str,x,y) Window win; char *str; int x,y; { XDrawString(theDisp, win, theGC, x, y, str, strlen(str)); XDrawLine(theDisp, win, theGC, x, y+DESCENT-1, x+StringWidth(str), y+DESCENT-1); } /**************************************************/ int StringWidth(str) char *str; { return(XTextWidth(mfinfo, str, strlen(str))); } /***********************************/ void FakeButtonPress(bp) BUTT *bp; { /* called when a button keyboard equivalent has been pressed. 'fakes' a ButtonPress event in the button, which A) makes the button blink, and B) falls through to ButtonPress command dispatch code */ XButtonEvent ev; ev.type = ButtonPress; ev.send_event = True; ev.display = theDisp; ev.window = bp->win; ev.root = rootW; ev.subwindow = NULL; ev.x = bp->x; ev.y = bp->y; ev.state = 0; ev.button = Button1; XSendEvent(theDisp, bp->win, False, NoEventMask, (XEvent *) &ev); } /**************************************************/ void SetCropString() { /* sets the crop string in the info box to be correct. should be called whenever 'but[BCROP].active', cXOFF,cYOFF,cWIDE,cHIGH are changed */ /* if but[BCROP].active, there's a cropping rectangle drawn on the picture. the string should reflect that. */ if (but[BCROP].active) { /* figure out current cropping rectangle in 'pic' coordinates */ int x,y,x1,y1,w,h; int cx,cy,dx,dy; if (crx1 pWIDE) w = pWIDE - x; if (h<1) h = 1; if (y+h > pHIGH) h = pHIGH - y; SetISTR(ISTR_CROP, "%dx%d rectangle starting at %d,%d", w, h, x, y); } else { /* cropping rectangle is turned off */ if (cpic != pic) SetISTR(ISTR_CROP, "%dx%d rectangle starting at %d,%d", cWIDE, cHIGH, cXOFF, cYOFF); else SetISTR(ISTR_CROP, "none"); } } /***********************************/ void Warning() { char *st; int i; if (infoUp || ctrlUp) { /* give 'em time to read message */ if (!fishrunning) sleep(5); else { for (i=0; i<25; i++) PAUSE_SIG; } } else { st = GetISTR(ISTR_INFO); fprintf(stderr,"%s: %s\n", cmd, st); } } /***********************************/ void FatalError (identifier) char *identifier; { fprintf(stderr, "%s: %s\n",cmd, identifier); Quit(-1); } /***********************************/ void Quit(i) int i; { FreeMostResources(); exit(i); } /***********************************/ static void FreeMostResources() { /* called when the program exits. frees everything explictly created EXCEPT allocated colors. This is used when 'useroot' is in operation, as we have to keep the alloc'd colors around, but we don't want anything else to stay */ if (!theDisp) return; /* called before connection opened */ if (dirW) XDestroyWindow(theDisp, dirW); if (infoW) XDestroyWindow(theDisp, infoW); if (ctrlW) XDestroyWindow(theDisp, ctrlW); if (gamW) XDestroyWindow(theDisp, gamW); XFlush(theDisp); } static Cursor flcurs, fl1curs, fmcurs, fr1curs, frcurs; /***********************************/ void LoadFishCursors() { #define fc_w 16 #define fc_h 16 Pixmap flpix,flmpix,fmpix,fmmpix,frpix,frmpix; Pixmap fl1pix, fl1mpix, fr1pix, fr1mpix; XColor fg, bg; flcurs = fl1curs = fmcurs = fr1curs = frcurs = NULL; flpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left_bits, fc_w, fc_h, 1, 0, 1); flmpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_leftm_bits, fc_w, fc_h, 1, 0, 1); fl1pix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left1_bits, fc_w, fc_h, 1, 0, 1); fl1mpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_left1m_bits, fc_w, fc_h, 1, 0, 1); fmpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_mid_bits, fc_w, fc_h, 1, 0, 1); fmmpix= XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_midm_bits, fc_w, fc_h, 1, 0, 1); fr1pix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right1_bits, fc_w, fc_h, 1, 0, 1); fr1mpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right1m_bits, fc_w, fc_h, 1, 0, 1); frpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_right_bits, fc_w, fc_h, 1, 0, 1); frmpix = XCreatePixmapFromBitmapData(theDisp, ctrlW, fc_rightm_bits, fc_w, fc_h, 1, 0, 1); if (!flpix || !flmpix || !fmpix || !fmmpix || !frpix || !frmpix || !fl1pix || !fl1mpix || !fr1pix || !fr1mpix) return; fg.red = fg.green = fg.blue = 0; bg.red = bg.green = bg.blue = 0xffff; flcurs = XCreatePixmapCursor(theDisp, flpix, flmpix, &fg, &bg, 8,8); fl1curs= XCreatePixmapCursor(theDisp, fl1pix,fl1mpix,&fg, &bg, 8,8); fmcurs = XCreatePixmapCursor(theDisp, fmpix, fmmpix, &fg, &bg, 8,8); fr1curs= XCreatePixmapCursor(theDisp, fr1pix,fr1mpix,&fg, &bg, 8,8); frcurs = XCreatePixmapCursor(theDisp, frpix, frmpix, &fg, &bg, 8,8); if (!flcurs || !fmcurs || !frcurs || !fl1curs || !fr1curs) { flcurs = fmcurs = frcurs = NULL; } } static int fishno=0; /***********************************/ void WaitCursor() { SetCursors(fishno); fishno = (fishno+1) % 8; } /***********************************/ void SetCursors(n) int n; { Cursor c; c = cross; /* if n < 0 sets normal cursor in all windows n = 0..6 cycles through fish cursors */ if (n<0) { if (!useroot && mainW) XDefineCursor(theDisp, mainW, cross); XDefineCursor(theDisp, infoW, arrow); XDefineCursor(theDisp, ctrlW, arrow); XDefineCursor(theDisp, dirW, arrow); XDefineCursor(theDisp, gamW, arrow); fishno = 0; } else if (flcurs) { /* was able to load the cursors */ switch (n%8) { case 0: c = flcurs; break; case 1: c = fl1curs; break; case 2: c = fmcurs; break; case 3: c = fr1curs; break; case 4: c = frcurs; break; case 5: c = fr1curs; break; case 6: c = fmcurs; break; case 7: c = fl1curs; break; } if (!useroot && mainW) XDefineCursor(theDisp, mainW, c); XDefineCursor(theDisp, infoW, c); XDefineCursor(theDisp, ctrlW, c); XDefineCursor(theDisp, dirW, c); XDefineCursor(theDisp, gamW, c); } XFlush(theDisp); } /***************************************************/ static int timerdone; /*******/ static void onalarm() /*******/ { timerdone=1; } /*******/ void Timer(n) /* waits for 'n' milliseconds */ int n; /*******/ { long usec; struct itimerval it; if (!n) return; if (fishrunning) { PAUSE_SIG; return; } #ifdef sco if (!n) return; nap(n); return; #endif /* sco */ #ifdef USLEEP usleep(n); return; #endif #ifdef NOTIMER return; #endif usec = (long) n * 1000; memset(&it, 0, sizeof(it)); if (usec>=1000000L) { /* more than 1 second */ it.it_value.tv_sec = usec / 1000000L; usec %= 1000000L; } it.it_value.tv_usec = usec; timerdone=0; signal(SIGALRM,onalarm); setitimer(ITIMER_REAL, &it, (struct itimerval *)0); while (1) { HOLD_SIG; /* note: have to block, so that ALRM */ if (timerdone) break; /* doesn't occur between 'if (timerdone)' */ else PAUSE_SIG; /* and calling PAUSE_SIG */ } RELEASE_SIG; /* turn ALRM blocking off */ signal(SIGALRM,SIG_DFL); } \BARFOO\ else echo "will not over write ./xvmisc.c" fi echo "Finished archive 5 of 10" exit dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only. -- dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.