bradley@halibut.cis.upenn.edu (John Bradley) (11/28/90)
Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley) Posting-number: Volume 10, Issue 87 Archive-name: xv/part09 #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./xv.c` then echo "writting ./xv.c" cat > ./xv.c << '\BARFOO\' /* * xv.c - main section of xv. X setup, window creation, event loop, etc. * * Author: John Bradley, University of Pennsylvania * (bradley@cis.upenn.edu) */ /* * 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 MAIN #define NEEDSTIME /* for -wait handling in eventloop */ #define NEEDSDIR /* for value of MAXPATHLEN */ #include "xv.h" #include "bitmaps.h" #include <X11/Xatom.h> /* program needs one of the following fonts. Trys them in ascending order */ #define FONT1 "-*-lucida-medium-r-*-*-12-*" #define FONT2 "-*-helvetica-medium-r-*-*-12-*" #define FONT3 "6x13" /* a mono-spaced font needed for the 'pixel value tracking' feature */ #define MFONT1 "-misc-fixed-medium-r-normal-*-13-*" #define MFONT2 "8x13" #define MFONT3 "-*-courier-medium-r-*-*-12-*" /* things EventLoop() can return (0 and above reserved for 'goto pic#') */ #define QUIT -1 /* exit immediately */ #define NEXTPIC -2 /* goto next picture */ #define PREVPIC -3 /* goto prev picture */ #define NEXTQUIT -4 /* goto next picture, quit if none (used by 'wait') */ /* file types that can be read */ #define UNKNOWN 0 #define GIF 1 #define PM 2 #define PBM 3 #define XBM 4 static unsigned long rootbg, rootfg; /* fg/bg for root border */ static int waitsec = -1; /* seconds between pics. -1=wait for event */ static int roottile = 0; /* resize pic to tile evenly on rootW */ static int automax = 0; /* resize pic to dispWIDE, dispHIGH on open */ static int autoquit = 0; /* quit after loading first pic to rootW */ static int autogamma = 0; /* perform gamma correction by default */ static int centerpic = 0; /* center pic on rootW, instead of tiling */ static int rootPattern = 0; /* pattern used for root border */ static char *maingeom = NULL; static char initpath[MAXPATHLEN]; static int rotatesLeft = 0; static Atom __SWM_VROOT = None; /* used in XResource reading... */ static char *def_str; static int def_int; /* function pre-definitions */ static void Syntax(); static int openPic(); static void closePic(); static void OpenFirstPic(); static void OpenNextPic(); static void OpenNextQuit(); static void OpenPrevPic(); static void MainLoop(); static int EventLoop(); static void CreateMainWindow(); static void FixAspect(); static void GetWindowPos(); static void SetWindowPos(); static void TrackCrop(); static void CropKey(); static void TrackPicValues(); static void MakeDispNames(); static int Rect(); static int CheckForConfig(); static Bool IsConfig(); static void SaveRootInfo(); static void KillOldRootInfo(); static int rd_int(); static int rd_str(); static int rd_flag(); /*******************************************/ int main(argc, argv) int argc; char *argv[]; /*******************************************/ { int i, imap, ctrlmap, gmap, clrroot; char *display, *fname, *whitestr, *blackstr, *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom; char *rootfgstr, *rootbgstr; XColor ecdef; Window rootReturn, parentReturn, *children; unsigned int numChildren; /*****************************************************/ /*** variable Initialization ***/ /*****************************************************/ #ifdef SYSV getcwd(initpath, sizeof(initpath)); #else getwd(initpath); #endif /* init internal variables */ display = fname = whitestr = blackstr = NULL; fgstr = bgstr = rootfgstr = rootbgstr = NULL; pic = epic = cpic = NULL; theImage = NULL; LocalCmap = 0; InitFSDTables(); cmd = rindex(argv[0],'/'); if (!cmd) cmd = argv[0]; else cmd++; /* init gamma curve */ ghand[0].x = 0; ghand[0].y = 0; ghand[1].x = 64; ghand[1].y = 64; ghand[2].x = 192; ghand[2].y = 192; ghand[3].x = 255; ghand[3].y = 255; /* init gamma presets */ SetGPreset(0, 255, 64,192, 192, 64, 0); SetGPreset(1, 0, 64,100, 234,255, 255); SetGPreset(2, 0, 80, 38, 210,180, 255); SetGPreset(3, 0, 40, 92, 235,204, 255); /* init command-line options flags */ infogeom = DEFINFOGEOM; ctrlgeom = DEFCTRLGEOM; gamgeom = DEFGAMGEOM; expand = 1; ncols = -1; noglob = 0; revvideo = 0; mono = 0; perfect = 0; ninstall = 0; fixedaspect = 0; DEBUG = 0; bwidth = 2; useroot = clrroot = noqcheck = rwcolor = fishrunning = 0; fish = 0; #ifdef BROKEFREECOLS brokeFreeCols = 1; #else brokeFreeCols = 0; #endif defaspect = normaspect = 1.0; mainW = dirW = infoW = ctrlW = gamW = NULL; imap = ctrlmap = gmap = 0; /* init info box variables */ infoUp = 0; infoMode = INF_STR; for (i=0; i<NISTR; i++) SetISTR(i,""); /* init ctrl box variables */ ctrlUp = 0; curname = 0; gamUp = 0; /*****************************************************/ /*** X Resource Initialization ***/ /*****************************************************/ /* once through the argument list to find the display name, if any */ for (i=1; i<argc-1; i++) { if (!strncmp(argv[i],"-d",2)) { /* display */ display = argv[++i]; break; } } /* open the display */ if ( (theDisp=XOpenDisplay(display)) == NULL) { fprintf(stderr, "%s: Can't open display\n",argv[0]); Quit(1); } if (rd_str ("aspect")) { int n,d; if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1) fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd); else defaspect = (float) n / (float) d; } if (rd_flag("autoGamma")) autogamma = def_int; if (rd_str ("background")) bgstr = def_str; if (rd_str ("black")) blackstr = def_str; if (rd_int ("borderWidth")) bwidth = def_int; if (rd_flag("brokeFreeCols")) brokeFreeCols = def_int; if (rd_flag("centerPic")) centerpic = def_int; if (rd_str ("ctrlGeometry")) ctrlgeom = def_str; if (rd_flag("ctrlMap")) ctrlmap = def_int; if (rd_int ("expand")) expand = def_int; if (rd_flag("fish")) fish = def_int; if (rd_flag("fixed")) fixedaspect = def_int; if (rd_str ("foreground")) fgstr = def_str; if (rd_str ("geometry")) maingeom = def_str; if (rd_str ("gammaGeometry")) gamgeom = def_str; if (rd_flag("gammaMap")) gmap = def_int; if (rd_str("gamma")) { int gry0,grx1,gry1,grx2,gry2,gry3; if (sscanf(def_str,"%d %d %d %d %d %d",&gry0,&grx1,&gry1, &grx2,&gry2,&gry3)!=6) fprintf(stderr,"%s: unable to parse 'gamma' resource\n",cmd); else { ghand[0].y = gry0; ghand[1].x = grx1; ghand[1].y = gry1; ghand[2].x = grx2; ghand[2].y = gry2; ghand[3].y = gry3; } } /* parse 'gamma1' through 'gamma4' resources */ for (i=0; i<4; i++) { char gstr[10]; sprintf(gstr,"gamma%d",i+1); if (rd_str(gstr)) { int y0,x1,y1,x2,y2,y3; if (sscanf(def_str,"%d %d %d %d %d %d",&y0,&x1,&y1,&x2,&y2,&y3)!=6) fprintf(stderr,"%s: unable to parse '%s' resource\n",cmd,gstr); else SetGPreset(i, y0, x1, y1, x2, y2, y3); } } if (rd_str ("infoGeometry")) infogeom = def_str; if (rd_flag("infoMap")) imap = def_int; if (rd_flag("mono")) mono = def_int; if (rd_int ("ncols")) { ncols = def_int; if (ncols>=0) noglob = 1; } if (rd_flag("nglobal")) noglob = def_int; if (rd_flag("ninstall")) ninstall = def_int; if (rd_flag("noqcheck")) noqcheck = def_int; if (rd_flag("perfect")) perfect = def_int; if (rd_flag("reverseVideo")) revvideo = def_int; if (rd_str ("rootBackground")) rootbgstr = def_str; if (rd_str ("rootForeground")) rootfgstr = def_str; if (rd_int ("rootPattern")) rootPattern = def_int; if (rd_flag("rwColor")) rwcolor = def_int; if (rd_flag("slow24")) slow24 = def_int; if (rd_flag("tile")) roottile = def_int; if (rd_str ("white")) whitestr = def_str; /*****************************************************/ /*** Command Line Options ***/ /*****************************************************/ for (i=1, numnames=0; i<argc; i++) { if (argv[i][0] != '-') { /* a file name. put it in list */ if (numnames<MAXNAMES) { namelist[numnames++] = argv[i]; if (numnames==MAXNAMES) { fprintf(stderr,"%s: too many filenames. Only using first %d.\n", cmd, MAXNAMES); } } } else if (!strncmp(argv[i],"-as",2)) { /* default aspect */ int n,d; if (++i<argc) { if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1) fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]); else defaspect = (float) n / (float) d; } } else if (!strncmp(argv[i],"-au",3)) /* autogamma */ autogamma++; else if (!strncmp(argv[i],"-bf",3)) /* brokeFreeCols */ brokeFreeCols = !brokeFreeCols; else if (!strncmp(argv[i],"-bg",3)) /* background color */ { if (++i<argc) bgstr = argv[i]; } else if (!strncmp(argv[i],"-bl",3)) /* black color */ { if (++i<argc) blackstr = argv[i]; } else if (!strncmp(argv[i],"-bw",3)) /* border width */ { if (++i<argc) bwidth=atoi(argv[i]); } else if (!strncmp(argv[i],"-ce",3)) /* centerpic */ centerpic++; else if (!strncmp(argv[i],"-cg",3)) /* ctrlgeom */ { if (++i<argc) ctrlgeom = argv[i]; } else if (!strncmp(argv[i],"-cm",3)) /* ctrlmap */ ctrlmap++; else if (!strncmp(argv[i],"-cl",3)) /* clear */ clrroot++; else if (!strncmp(argv[i],"-d",2)) /* display */ { if (++i<argc) display = argv[i]; } else if (!strncmp(argv[i],"-D",2)) /* debug */ { if (++i<argc) DEBUG = atoi(argv[i]); } else if (!strncmp(argv[i],"-e",2)) /* expand factor */ { if (++i<argc) expand=atoi(argv[i]); } else if (!strncmp(argv[i],"-fis",4)) /* nofish */ fish++; else if (!strncmp(argv[i],"-fix",4)) /* fixed aspect ratio */ fixedaspect++; else if (!strncmp(argv[i],"-fg",3)) /* foreground color */ { if (++i<argc) fgstr = argv[i]; } else if (!strncmp(argv[i],"-ge",3)) /* geometry */ { if (++i<argc) maingeom = argv[i]; } else if (!strncmp(argv[i],"-gg",3)) /* gammageom */ { if (++i<argc) gamgeom = argv[i]; } else if (!strncmp(argv[i],"-gm",3)) /* gmap */ gmap++; else if (!strncmp(argv[i],"-G",2)) /* Gamma */ { if (++i<argc) ghand[0].y=atoi(argv[i]); if (++i<argc) ghand[1].x=atoi(argv[i]); if (++i<argc) ghand[1].y=atoi(argv[i]); if (++i<argc) ghand[2].x=atoi(argv[i]); if (++i<argc) ghand[2].y=atoi(argv[i]); if (++i<argc) ghand[3].y=atoi(argv[i]); } else if (!strncmp(argv[i],"-ig",3)) /* infogeom */ { if (++i<argc) infogeom = argv[i]; } else if (!strncmp(argv[i],"-im",3)) /* imap */ imap++; else if (!strncmp(argv[i],"-ma",3)) /* auto maximize */ automax++; else if (!strncmp(argv[i],"-mo",3)) /* mono */ mono++; else if (!strncmp(argv[i],"-nc",3)) /* ncols */ { if (++i<argc) { ncols=abs(atoi(argv[i])); noglob++; } } else if (!strncmp(argv[i],"-ng",3)) /* no global colors */ noglob++; else if (!strncmp(argv[i],"-ni",3)) /* don't install colormaps by hand */ ninstall=1; else if (!strncmp(argv[i],"-noq",4)) /* noqcheck */ noqcheck++; else if (!strncmp(argv[i],"-p",2)) /* perfect colors */ perfect++; else if (!strncmp(argv[i],"-q",2)) /* auto-quit when using root */ autoquit++; else if (!strncmp(argv[i],"-rb",3)) /* root background color */ { if (++i<argc) rootbgstr = argv[i]; } else if (!strncmp(argv[i],"-rf",3)) /* root foreground color */ { if (++i<argc) rootfgstr = argv[i]; } else if (!strncmp(argv[i],"-ro",3)) /* use root window */ useroot++; else if (!strncmp(argv[i],"-rp",3)) /* root pattern */ { if (++i<argc) rootPattern = abs(atoi(argv[i])); } else if (!strncmp(argv[i],"-rw",3)) /* use r/w color */ rwcolor++; else if (!strcmp(argv[i],"-rv")) /* reverse video */ revvideo++; else if (!strncmp(argv[i],"-s",2)) /* slow 24-to-8 conversion */ slow24++; else if (!strncmp(argv[i],"-t",2)) /* root window tiling */ roottile++; else if (!strncmp(argv[i],"-wa",3)) /* secs to wait between pics */ { if (++i<argc) waitsec = abs(atoi(argv[i])); } else if (!strncmp(argv[i],"-wh",3)) /* white color */ { if (++i<argc) whitestr = argv[i]; } else Syntax(); } if (expand==0) Syntax(); if (DEBUG) XSynchronize(theDisp, True); /* if using root, generally gotta map ctrl window, 'cause there won't be any way to ask for it. (no kbd or mouse events from rootW) */ if (useroot && !autoquit) ctrlmap = 1; /* must not install colormaps on rootW */ if (useroot) { perfect=0; noglob = 1; } /*****************************************************/ /*** X Setup ***/ /*****************************************************/ theScreen = DefaultScreen(theDisp); theCmap = DefaultColormap(theDisp, theScreen); rootW = RootWindow(theDisp,theScreen); theGC = DefaultGC(theDisp,theScreen); theVisual = DefaultVisual(theDisp,theScreen); ncells = DisplayCells(theDisp, theScreen); dispWIDE = DisplayWidth(theDisp,theScreen); dispHIGH = DisplayHeight(theDisp,theScreen); dispDEEP = DisplayPlanes(theDisp,theScreen); /* go look for a virtual root */ __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False); XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children, &numChildren); for (i = 0; i < numChildren; i++) { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; Window *newRoot = NULL; XWindowAttributes xwa; if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0, 1, False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) { rootW = *newRoot; XGetWindowAttributes(theDisp, rootW, &xwa); dispWIDE = xwa.width; dispHIGH = xwa.height; dispDEEP = xwa.depth; break; } } /* have enough info to do a '-clear' now */ if (clrroot || useroot) { KillOldRootInfo(); XSetWindowBackgroundPixmap(theDisp, rootW, None); XClearWindow(theDisp, rootW); XFlush(theDisp); if (clrroot) Quit(0); } arrow = XCreateFontCursor(theDisp,XC_top_left_arrow); /* cross = XCreateFontCursor(theDisp,XC_plus); */ cross = XCreateFontCursor(theDisp,XC_crosshair); /* set up white,black colors */ white = WhitePixel(theDisp,theScreen); black = BlackPixel(theDisp,theScreen); if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) white = ecdef.pixel; if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) black = ecdef.pixel; /* set up fg,bg colors */ fg = black; bg = white; if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) fg = ecdef.pixel; if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) bg = ecdef.pixel; /* set up root fg,bg colors */ rootfg = white; rootbg = black; if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) rootfg = ecdef.pixel; if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) && XAllocColor(theDisp, theCmap, &ecdef)) rootbg = ecdef.pixel; XSetForeground(theDisp,theGC,fg); XSetBackground(theDisp,theGC,bg); /* set up infofg,infobg colors */ infofg = fg; infobg = bg; /* if '-mono' not forced, determine if we're on a b/w or color monitor */ if (!mono) { if (DEBUG) fprintf(stderr,"%s: VisualClass = %d\n",cmd, theVisual->class); if (theVisual->class == StaticGray || theVisual->class == GrayScale) mono = 1; } iconPix = XCreatePixmapFromBitmapData(theDisp, rootW, icon_bits, icon_width, icon_height, 1, 0, 1); /* try to load fonts */ if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL && (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL && (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL) { sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s", FONT1, FONT2, FONT3); FatalError(str); } mfont=mfinfo->fid; XSetFont(theDisp,theGC,mfont); if ( (monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL && (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL && (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL) { sprintf(str,"couldn't open the following fonts:\n\t %s \n\t %s \n\t %s", MFONT1, MFONT2, MFONT3); FatalError(str); } monofont=monofinfo->fid; /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which case ncols = 0; (ncols = max number of colors allocated. on 1-bit displays, no colors are allocated */ if (ncols == -1) { if (dispDEEP>1) ncols = 1<<dispDEEP; else ncols = 0; } else if (ncols>256) ncols = 256; /* so program doesn't blow up */ if (numnames==0) { /* no filenames. build one-name (stdio) list */ namelist[0] = STDINSTR; numnames = 1; } MakeDispNames(); /* create the info box window */ CreateInfo(infogeom); XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask ); InfoBox(imap); /* map it (or not) */ if (imap) { RedrawInfo(0,0,INFOWIDE,INFOHIGH); /* explicit draw if mapped */ XFlush(theDisp); } /* create the control box window */ CreateCtrl(ctrlgeom); XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask); CtrlBox(ctrlmap); /* map it (or not) */ if (ctrlmap) { RedrawCtrl(0,0,CTRLWIDE,CTRLHIGH); /* explicit draw if mapped */ XFlush(theDisp); } /* create the directory window */ CreateDirW(DEFDIRGEOM); XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask); DirBox(0); /* map it (or not) */ /* create the gamma window */ CreateGam(gamgeom); XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask); GamBox(gmap); /* map it (or not) */ GenerateGamma(); GenerateFSGamma(); LoadFishCursors(); SetCursors(-1); /* if we're not on a colormapped display, turn off rwcolor */ if (!(theVisual->class & 1) && rwcolor) { fprintf(stderr,"xv: not a colormapped display. 'rwcolor' turned off.\n"); rwcolor = 0; } /* Do The Thing... */ MainLoop(); Quit(0); return(0); } /***********************************/ static int cpos = 0; printoption(st) char *st; { if (strlen(st) + cpos > 78) { fprintf(stderr,"\n "); cpos = 3; } fprintf(stderr,"%s ",st); cpos = cpos + strlen(st) + 1; } static void Syntax() { fprintf(stderr, "Usage:\n"); printoption(cmd); printoption("[-aspect w:h]"); printoption("[-autogamma]"); printoption("[-bfc]"); printoption("[-bg background]"); printoption("[-black color]"); printoption("[-bw width]"); printoption("[-center]"); printoption("[-cgeom geom]"); printoption("[-clear]"); printoption("[-cmap]"); printoption("[-DEBUG level]"); printoption("[-display disp]"); printoption("[-expand exp]"); printoption("[-fg foreground]"); printoption("[-fish]"); printoption("[-fixed]"); printoption("[-GAMMA y0 x1 y1 x2 y2 y3]"); printoption("[-geometry geom]"); printoption("[-ggeometry geom]"); printoption("[-gmap]"); printoption("[-help]"); printoption("[-igeom geom]"); printoption("[-imap]"); printoption("[-max]"); printoption("[-mono]"); printoption("[-ncols #]"); printoption("[-nglobal]"); printoption("[-ninst]"); printoption("[-noqcheck]"); printoption("[-perfect]"); printoption("[-quit]"); printoption("[-root]"); printoption("[-rw]"); printoption("[-rv]"); printoption("[-rbg color]"); printoption("[-rfg color]"); printoption("[-rpat #]"); printoption("[-slow24]"); printoption("[-tile]"); printoption("[-wait seconds]"); printoption("[-white color]"); printoption("[filename ...]"); fprintf(stderr,"\n\n"); Quit(1); } /***********************************/ static int openPic(filenum) int filenum; { /* tries to load file #filenum (from 'namelist' list) * returns 0 on failure (cleans up after itself) * if successful, returns 1, creates mainW */ int i,filetype,okay,freename, nw, nh; char *tmp; FILE *fp; char *fullname, /* full name of the original file */ filename[256], /* full name of the file to be loaded (could be /tmp) */ basename[128], /* just the name of the original file. No path */ magicno[8]; /* first 8 bytes of file */ normaspect = defaspect; StartFish(); WaitCursor(); curname = filenum; ScrollToCurrent(); /* have scrl/list show current */ XFlush(theDisp); /* update NOW */ /* clear any old error messages */ SetISTR(ISTR_INFO,""); SetISTR(ISTR_WARNING,""); infoMode = INF_STR; okay = 0; /* set up fullname and basename */ fullname = namelist[filenum]; tmp = rindex(fullname,'/'); if (!tmp) tmp = fullname; else tmp++; strcpy(basename,tmp); if (strlen(basename)>2 && strcmp(basename+strlen(basename)-2,".Z")==0) basename[strlen(basename)-2]='\0'; /* chop off .Z, if any */ /* if fullname doesn't start with a '/' (ie, it's a relative path), (and it's not the special case '<stdin>') prepend 'initpath' to it */ freename = 0; if (fullname[0] != '/' && strcmp(fullname,STDINSTR)!=0) { char *tmp; tmp = (char *) malloc(strlen(fullname) + strlen(initpath) + 2); if (!tmp) FatalError("malloc 'filename' failed"); sprintf(tmp,"%s/%s", initpath, fullname); fullname = tmp; freename = 1; } /* uncompress if it's a .Z file */ i = strlen(fullname); if (i>2 && strcmp(fullname+i-2,".Z")==0) { strcpy(filename,"/tmp/xvXXXXXX"); mktemp(filename); sprintf(str,"%s -c %s >%s",UNCOMPRESS,fullname,filename); SetISTR(ISTR_INFO,"Uncompressing '%s'...",basename); if (system(str)) { SetISTR(ISTR_INFO,"Unable to uncompress '%s'.", basename); Warning(); goto FAILED; } WaitCursor(); } else strcpy(filename,fullname); /* if the file is stdio, write it out to a temp file */ if (strcmp(filename,STDINSTR)==0) { FILE *fp; strcpy(filename,"/tmp/xvXXXXXX"); mktemp(filename); fp = fopen(filename,"w"); if (!fp) FatalError("can't write /tmp/xv****** file"); while ( (i=getchar()) != EOF) putc(i,fp); fclose(fp); } /* now, try to determine what type of file we've got by reading the first couple bytes and looking for a Magic Number */ fp=fopen(filename,"r"); if (!fp) { SetISTR(ISTR_INFO,"Can't open '%s' - %s",filename,sys_errlist[errno]); Warning(); goto FAILED; } fread(magicno,8,1,fp); fclose(fp); filetype = UNKNOWN; if (strncmp(magicno,"GIF87",5)==0) filetype = GIF; else if (strncmp(magicno,"VIEW",4)==0 || strncmp(magicno,"WEIV",4)==0) filetype = PM; else if (magicno[0] == 'P' && magicno[1]>='1' && magicno[1]<='6') filetype = PBM; else if (strncmp(magicno,"#define",7)==0) filetype = XBM; if (filetype == UNKNOWN) { SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basename); Warning(); goto FAILED; } SetISTR(ISTR_INFO,"Loading '%s'...",basename); switch (filetype) { case GIF: i = LoadGIF(filename,ncols); break; case PM: i = LoadPM (filename,ncols); break; case PBM: i = LoadPBM(filename,ncols); break; case XBM: i = LoadXBM(filename,ncols); break; } WaitCursor(); if (i) { SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename); Warning(); goto FAILED; } /* successfully read this picture */ /* if we read a /tmp file, delete it. won't be needing it any more */ if (strcmp(fullname,filename)!=0) unlink(filename); SetInfoMode(INF_PART); SetISTR(ISTR_INFO,"Loading '%s'... done.",basename); SetISTR(ISTR_FILENAME,basename); SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH); SetISTR(ISTR_COLOR,""); /* adjust button in/activity */ BTSetActive(&but[BCROP],0); /* new picture, draw no cropping rectangle */ BTSetActive(&but[BUNCROP], 0); BTSetActive(&but[BNEXT], (curname<numnames-1)); BTSetActive(&but[BPREV], (curname>0)); normFact = 1; nw = pWIDE; nh = pHIGH; /* if pic is larger than screen, half picture until it fits on screen */ while (nw > dispWIDE || nh > dispHIGH) { nw = nw / 2; nh = nh / 2; normFact = normFact * 2; } /* expand: if expansion is negative, treat it as a reciprocal */ if (expand<0) { eWIDE = pWIDE/abs(expand); eHIGH = pHIGH/abs(expand); } else { eWIDE = pWIDE * expand; eHIGH = pHIGH * expand; } if (useroot) { int i,x,y; unsigned int w,h; i = XParseGeometry(maingeom,&x,&y,&w,&h); if (i&WidthValue) eWIDE = w; if (i&HeightValue) eHIGH = h; RANGE(eWIDE,1,dispWIDE); RANGE(eHIGH,1,dispHIGH); if (roottile) { /* make picture size a divisor of the rootW size. round down */ i = (dispWIDE + eWIDE-1) / eWIDE; eWIDE = (dispWIDE + i-1) / i; i = (dispHIGH + eHIGH-1) / eHIGH; eHIGH = (dispHIGH + i-1) / i; } } cpic = pic; cWIDE = pWIDE; cHIGH = pHIGH; cXOFF = cYOFF = 0; SetCropString(); if (automax) { eWIDE = dispWIDE; eHIGH = dispHIGH; if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH); } if (useroot) { mainW = rootW; if (theVisual->class & 1) { /* clear old root pixmap before doing the 'alloc colors scene' to avoid annoying 'rainbow' effect as colors are realloced */ XSetWindowBackgroundPixmap(theDisp, rootW, None); XClearWindow(theDisp, rootW); XFlush(theDisp); } } else { CreateMainWindow(maingeom, basename); XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask | StructureNotifyMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask); XMapWindow(theDisp,mainW); } SortColormap(); /* save the desired RGB colormap (before gamma-correcting it) */ for (i=0; i<numcols; i++) { rorg[i] = r[i]; gorg[i] = g[i]; borg[i] = b[i]; } WaitCursor(); DoMonoAndRV(); if (autogamma) GammifyColors(); if (rwcolor) AllocRWColors(); else AllocColors(); WaitCursor(); Resize(eWIDE,eHIGH); WaitCursor(); if (useroot) MakeRootPic(); if (LocalCmap) { XSetWindowAttributes xswa; if (!ninstall) XInstallColormap(theDisp,LocalCmap); xswa.colormap = LocalCmap; XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa); } SetInfoMode(INF_FULL); if (freename) free(fullname); StopFish(); SetCursors(-1); /* put current filename into the 'save-as' filename */ if (strcmp(filename,STDINSTR)==0) SetDirFName("stdin"); else SetDirFName(basename); return 1; FAILED: StopFish(); SetCursors(-1); SetInfoMode(INF_STR); if (strcmp(fullname,filename)!=0) unlink(filename); /* kill /tmp file */ if (freename) free(fullname); return 0; } /***********************************/ static void closePic() { /* kill all resources used for this picture. this would include the window, any allocated colors, pic, epic, theImage, etc. */ int i; static char *st = "Loading..."; if (!useroot) { /* turn off configure events */ XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask); XClearArea(theDisp, mainW, 0,0, eWIDE, eHIGH, True); /* XSetForeground(theDisp, theGC, infofg); XFillRectangle(theDisp,mainW,theGC, 0, 0, StringWidth(st) + 8, CHIGH+4); XSetForeground(theDisp, theGC, infobg); XDrawString(theDisp, mainW, theGC, 4, 2 + ASCENT, st, strlen(st)); XFlush(theDisp); */ } if (LocalCmap) { XFreeColormap(theDisp,LocalCmap); LocalCmap = 0; } else if (!brokeFreeCols) { for (i=0; i<nfcols; i++) XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L); } else { for (i=0; i<nfcols; i++) { int j; for (j=0; j<i; j++) { if (freecols[i] == freecols[j]) /* already been freed once */ break; } if (j==i) /* wasn't found in already-freed list */ XFreeColors(theDisp, theCmap, &freecols[i], 1, 0L); } } if (epic != cpic && epic != NULL) free(epic); if (cpic != pic && cpic != NULL) free(cpic); if (pic != NULL) free(pic); if (theImage != NULL) XDestroyImage(theImage); theImage = NULL; pic = epic = cpic = NULL; SetInfoMode(INF_STR); } /****************/ static void OpenFirstPic() /****************/ { int i; for (i=0; i<numnames; i++) { if (openPic(i)) return; /* success */ } if (numnames>1) FatalError("couldn't open any pictures"); else Quit(-1); } /****************/ static void OpenNextPic() /****************/ { int i,orig; orig = curname; for (i=curname+1; i<numnames; i++) { if (openPic(i)) return; /* success */ } /* couldn't go to next, reopen original */ if (!openPic(orig)) FatalError("couldn't reopen original picture"); } /****************/ static void OpenNextQuit() /****************/ { int i; for (i=curname+1; i<numnames; i++) { if (openPic(i)) return; /* success */ } Quit(0); } /****************/ static void OpenPrevPic() /****************/ { int i,orig; orig = curname; for (i=curname-1; i>=0; i--) { if (openPic(i)) return; /* success */ } /* couldn't go to next, reopen original */ if (!openPic(orig)) FatalError("couldn't reopen original picture"); } /****************/ static void MainLoop() /****************/ { /* search forward until we manage to display a picture, then call EventLoop. EventLoop will eventually return NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */ int i; OpenFirstPic(); /* find first displayable picture, exit if none */ if (useroot && autoquit) Quit(0); while ((i=EventLoop()) != QUIT) { if (i==NEXTPIC && curname<numnames-1) { closePic(); OpenNextPic(); } else if (i==PREVPIC && curname>0) { closePic(); OpenPrevPic(); } else if (i==NEXTQUIT) { closePic(); OpenNextQuit(); } else if (i>=0) { int orig = curname; if (curname != i) { closePic(); if (!openPic(i)) { /* couldn't goto */ if (!openPic(orig)) FatalError("couldn't reopen original picture"); } } } } } /****************/ static int EventLoop() /****************/ { XEvent event; int retval,done; time_t orgtime, curtime; /* note: there's no special event handling if we're using the root window. if we're using the root window, we will recieve NO events for mainW */ time(&orgtime); done = retval = 0; while (!done) { if (waitsec == -1 || XPending(theDisp)>0) { XNextEvent(theDisp, &event); switch (event.type) { case Expose: { XExposeEvent *exp_event = (XExposeEvent *) &event; /* if the window doesn't do intelligent redraw, drop all-1 exposes */ if (exp_event->count>0 && exp_event->window != mainW && exp_event->window != ctrlW && exp_event->window != dirW && exp_event->window != gamW && exp_event->window != graphW) break; if (exp_event->window==mainW) { if (DEBUG) fprintf(stderr,"EXPOSE: "); if (!CheckForConfig()) { if (DEBUG) fprintf(stderr,"No configs pending. Do Expose %d,%d %dx%d\n", exp_event->x, exp_event->y, exp_event->width, exp_event->height); if (DEBUG) XClearArea(theDisp, mainW, exp_event->x, exp_event->y, exp_event->width, exp_event->height, False); DrawWindow(exp_event->x,exp_event->y, exp_event->width, exp_event->height); if (but[BCROP].active) { XRectangle xr; xr.x = exp_event->x; xr.y = exp_event->y; xr.width = exp_event->width; xr.height = exp_event->height; XSetClipRectangles(theDisp,theGC,0,0,&xr,1,Unsorted); InvCropRect(); XSetClipMask(theDisp,theGC,None); } } else if (DEBUG) fprintf(stderr,"Ignoring expose event. Config pending\n"); } else if (exp_event->window==infoW) RedrawInfo(exp_event->x, exp_event->y, exp_event->width, exp_event->height); else if (exp_event->window==ctrlW) RedrawCtrl(exp_event->x, exp_event->y, exp_event->width, exp_event->height); else if (exp_event->window == nList.win) LSRedraw(&nList); else if (exp_event->window == nList.scrl.win) SCRedraw(&nList.scrl); else if (exp_event->window == dirW) RedrawDirW(exp_event->x, exp_event->y, exp_event->width, exp_event->height); else if (exp_event->window == dList.win) LSRedraw(&dList); else if (exp_event->window == dList.scrl.win) SCRedraw(&dList.scrl); else if (exp_event->window == ddirW) RedrawDDirW(); else if (exp_event->window == dnamW) RedrawDNamW(); else if (exp_event->window == gamW) RedrawGam(exp_event->x, exp_event->y, exp_event->width, exp_event->height); else if (exp_event->window == graphW) RedrawGraph(exp_event->x, exp_event->y, exp_event->width, exp_event->height); } break; case ButtonPress: { XButtonEvent *but_event = (XButtonEvent *) &event; int i; switch (but_event->button) { case Button1: if (but_event->window == mainW) TrackPicValues(but_event->x, but_event->y); else if (but_event->window == ctrlW) { int w,h; i=ClickCtrl(but_event->x, but_event->y); if (i>=0) { switch (i) { case BNEXT: retval= NEXTPIC; done=1; break; case BPREV: retval= PREVPIC; done=1; break; case BSAVE: DirBox(1); break; case BQUIT: retval= QUIT; done=1; break; case BCROP: DoCrop(); break; case BUNCROP: UnCrop(); break; case BNORM: WResize(cWIDE/normFact, cHIGH/normFact); break; case BMAX: WResize(dispWIDE, dispHIGH); break; case BUP10: w = (eWIDE*11)/10; h = (eHIGH*11)/10; if (w==eWIDE) w++; if (h==eHIGH) h++; WResize(w,h); break; case BDN10: WResize((eWIDE*9)/10, (eHIGH*9)/10); break; case BUP2: WResize(eWIDE*2, eHIGH*2); break; case BDN2: WResize(eWIDE/2, eHIGH/2); break; case B4BY3: w = eWIDE; h = (w * 3) / 4; if (h>dispHIGH) { h = eHIGH; w = (h*4)/3; } WResize(w,h); break; case BASPECT: FixAspect(1,&w,&h); WResize(w,h); break; case BMAXPECT: { int w1,h1; w1 = eWIDE; h1 = eHIGH; eWIDE = dispWIDE; eHIGH = dispHIGH; FixAspect(0,&w,&h); eWIDE = w1; eHIGH = h1; /* play it safe */ WResize(w,h); } break; case BROTL: Rotate(1); break; case BROTR: Rotate(0); break; case BACROP: AutoCrop(); break; case BINFO: InfoBox(!infoUp); break; case BGAMMA: GamBox(!gamUp); break; } } } else if (but_event->window == nList.win) { i=LSClick(&nList,but_event); if (i>=0) return(i); } else if (but_event->window == nList.scrl.win) SCTrack(&nList.scrl, but_event->x, but_event->y); else if (but_event->window == dirW) { i=ClickDirW(but_event->x, but_event->y); if (i==S_BOPEN) SelectDir(dList.selected); else if (i==S_BCANC) DirBox(0); else if (i==S_BSAVE) DoSave(); else if (i==S_BQUIT) { retval = QUIT; done=1; } } else if (but_event->window == dList.win) { i=LSClick(&dList,but_event); DirOpenActive(); if (i>=0) SelectDir(i); } else if (but_event->window == dList.scrl.win) SCTrack(&dList.scrl, but_event->x, but_event->y); else if (but_event->window == ddirW) TrackDDirW(but_event->x, but_event->y); else if (but_event->window == gamW) ClickGam(but_event->x, but_event->y); else if (but_event->window == graphW) TrackGraph(but_event->x, but_event->y); break; case Button2: if (but_event->window == mainW) TrackCrop(but_event->x, but_event->y); break; case Button3: if (!useroot) /* if using root, MUST NOT get rid of */ CtrlBox(!ctrlUp); /* ctrlbox. can't get it back */ break; default: break; } } break; case KeyPress: { XKeyEvent *key_event = (XKeyEvent *) &event; char buf[128]; KeySym ks; XComposeStatus status; int stlen; stlen = XLookupString(key_event,buf,128,&ks,&status); /* do non-character processing (arrow-keys, that is) */ if (ks==XK_Left) CropKey(-1, 0, key_event->state & ShiftMask); else if (ks==XK_Right) CropKey( 1, 0, key_event->state & ShiftMask); else if (ks==XK_Up) CropKey( 0,-1, key_event->state & ShiftMask); else if (ks==XK_Down) CropKey( 0, 1, key_event->state & ShiftMask); if (!stlen) break; if (key_event->window == dirW) { if (DirKey(buf[0])) XBell(theDisp,0); } else { /* if (isupper(buf[0])) buf[0] = tolower(buf[0]); */ /* commands valid in any window */ switch (buf[0]) { case ' ': case '\r': case '\n': FakeButtonPress(&but[BNEXT]); break; case '\010': case '\177': FakeButtonPress(&but[BPREV]); break; case 's': FakeButtonPress(&but[BSAVE]); break; case 'q': FakeButtonPress(&but[BQUIT]); break; case 'h': case '?': if (!useroot) CtrlBox(!ctrlUp); break; case 'a': FakeButtonPress(&but[BASPECT]); break; case 'A': FakeButtonPress(&but[BACROP]); break; case 'T': FakeButtonPress(&but[BROTL]); break; case 't': FakeButtonPress(&but[BROTR]); break; case '4': FakeButtonPress(&but[B4BY3]); break; case 'c': FakeButtonPress(&but[BCROP]); break; case 'u': FakeButtonPress(&but[BUNCROP]); break; case 'n': FakeButtonPress(&but[BNORM]); break; case 'm': FakeButtonPress(&but[BMAX]); break; case 'M': FakeButtonPress(&but[BMAXPECT]); break; case ',': FakeButtonPress(&but[BDN10]); break; case '.': FakeButtonPress(&but[BUP10]); break; case '<': FakeButtonPress(&but[BDN2]); break; case '>': FakeButtonPress(&but[BUP2]); break; case 'i': FakeButtonPress(&but[BINFO]); break; case 'g': FakeButtonPress(&but[BGAMMA]); break; case 'p': FakeButtonPress(&gbut[G_BAPPLY]); break; default: break; } } } break; case ConfigureNotify: { XConfigureEvent *conf_event = (XConfigureEvent *) &event; if (conf_event->window == mainW && !rotatesLeft) { if (DEBUG) fprintf(stderr,"CONFIG: (%s) ", conf_event->send_event ? "program" : "user"); if (!CheckForConfig()) { XEvent xev; if (DEBUG) fprintf(stderr,"No configs pend. Do full redraw\n"); Resize(conf_event->width, conf_event->height); /* eat pending expose events, as the complete redraw will cover all of them */ while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) { XExposeEvent *exp = (XExposeEvent *) &xev; if (DEBUG) fprintf(stderr, " ate expose (%s) (count=%d) %d,%d %dx%d\n", exp->send_event ? "program" : "user", exp->count, exp->x, exp->y, exp->width, exp->height); } DrawWindow(0,0,conf_event->width, conf_event->height); SetCursors(-1); } else if (DEBUG) fprintf(stderr,"config pending. ignored\n"); } if (rotatesLeft>0) rotatesLeft--; if (!rotatesLeft) SetCursors(-1); } break; case CirculateNotify: case MapNotify: case DestroyNotify: case GravityNotify: case ReparentNotify: case UnmapNotify: break; case EnterNotify: case LeaveNotify: { XCrossingEvent *cross_event = (XCrossingEvent *) &event; if (cross_event->window != mainW) break; if (cross_event->type == EnterNotify && LocalCmap && !ninstall) XInstallColormap(theDisp,LocalCmap); if (cross_event->type == LeaveNotify && LocalCmap && !ninstall) XUninstallColormap(theDisp,LocalCmap); } break; default: break; /* ignore unexpected events */ } /* switch */ } /* if XPending */ else { /* no events. check wait status */ if (waitsec>-1) { time(&curtime); if (curtime - orgtime >= waitsec) return NEXTQUIT; sleep(1); /* so program doesn't loop continuously while 'waiting' */ } } } /* while */ return(retval); } /***********************************/ void DrawWindow(x,y,w,h) int x,y,w,h; { if (theImage) XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y,w,h); else if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NIL\n"); } /***********************************/ static void CreateMainWindow(geom,name) char *geom, *name; { XSetWindowAttributes xswa; unsigned int xswamask; XWindowAttributes xwa; XWMHints xwmh; XSizeHints hints; int i,x,y; unsigned int w,h; char winname[128], iconname[128]; /* * this function mainly deals with parsing the geometry spec correctly. * More trouble than it should be, and probably more trouble than * it has to be, but who can tell these days, what with all those * Widget-usin' Weenies out there... */ x = y = w = h = 1; i = XParseGeometry(geom,&x,&y,&w,&h); if (i&WidthValue) eWIDE = w; if (i&HeightValue) eHIGH = h; if (eWIDE > dispWIDE || eHIGH > dispHIGH) { eWIDE = eWIDE / normFact; eHIGH = eHIGH / normFact; } if (eWIDE < 1) eWIDE = 1; if (eHIGH < 1) eHIGH = 1; if (fixedaspect && i&WidthValue && i&HeightValue) FixAspect(0,&eWIDE,&eHIGH); else if (i&WidthValue && i&HeightValue) { RANGE(eWIDE,1,dispWIDE); RANGE(eHIGH,1,dispHIGH); } else FixAspect(1,&eWIDE,&eHIGH); if (i&XValue || i&YValue) hints.flags = USPosition; else hints.flags = PPosition; hints.flags |= USSize; if (i&XValue && i&XNegative) x = dispWIDE - eWIDE - abs(x); if (i&YValue && i&YNegative) y = dispHIGH - eHIGH - abs(y); if (x+eWIDE > dispWIDE) x = dispWIDE - eWIDE; /* keep on screen */ if (y+eHIGH > dispHIGH) y = dispHIGH - eHIGH; if (eWIDE < 1) eWIDE = 1; if (eHIGH < 1) eHIGH = 1; hints.x = x; hints.y = y; hints.width = eWIDE; hints.height = eHIGH; hints.max_width = dispWIDE; hints.max_height = dispHIGH; hints.flags |= PMaxSize; xswa.background_pixel = bg; xswa.border_pixel = fg; xswamask = CWBackPixel | CWBorderPixel; if (mainW) { GetWindowPos(&xwa); xwa.width = eWIDE; xwa.height = eHIGH; SetWindowPos(&xwa); hints.flags = PSize | PMaxSize; } if (!mainW) mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,bwidth,CopyFromParent, CopyFromParent, CopyFromParent, xswamask, &xswa); sprintf(winname,"xv %s",name); sprintf(iconname,"xv %s",name); XSetStandardProperties(theDisp,mainW,winname,iconname,None, NULL,0,&hints); xwmh.input = True; xwmh.flags = InputHint; if (iconPix) { xwmh.icon_pixmap = iconPix; xwmh.flags |= IconPixmapHint; } XSetWMHints(theDisp, mainW, &xwmh); if (!mainW) FatalError("can't create window!"); } /***********************************/ static void FixAspect(grow,w,h) int grow; int *w, *h; { /* computes new values of eWIDE and eHIGH which will have aspect ratio 'normaspect'. If 'grow' it will preserve aspect by enlarging, otherwise, it will shrink to preserve aspect ratio. Returns these values in 'w' and 'h' */ float xr,yr,curaspect,a,exp; *w = eWIDE; *h = eHIGH; /* xr,yr are expansion factors */ xr = ((float) eWIDE) / cWIDE; yr = ((float) eHIGH) / cHIGH; curaspect = xr / yr; /* if too narrow & shrink, shrink height. too wide and grow, grow height */ if ((curaspect < normaspect && !grow) || (curaspect > normaspect && grow)) { /* modify height */ exp = curaspect / normaspect; *h = (int) (eHIGH * exp + .5); } /* if too narrow & grow, grow width. too wide and shrink, shrink width */ if ((curaspect < normaspect && grow) || (curaspect > normaspect && !grow)) { /* modify width */ exp = normaspect / curaspect; *w = (int) (eWIDE * exp + .5); } /* shrink to fit screen without changing aspect ratio */ if (*w>dispWIDE) { int i; a = (float) *w / dispWIDE; *w = dispWIDE; i = (int) (*h / a + .5); /* avoid freaking some optimizers */ *h = i; } if (*h>dispHIGH) { a = (float) *h / dispHIGH; *h = dispHIGH; *w = (int) (*w / a + .5); } if (*w < 1) *w = 1; if (*h < 1) *h = 1; } /***********************************/ void WResize(w,h) int w,h; { XWindowAttributes xwa; /* force w,h into valid ranges */ RANGE(w,1,dispWIDE); RANGE(h,1,dispHIGH); if (useroot) { Resize(w,h); MakeRootPic(); SetCursors(-1); return; } /* determine if new size goes off edge of screen. if so move window so it doesn't go off screen */ GetWindowPos(&xwa); if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w; if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h; if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n", cmd,w,h,xwa.x,xwa.y); /* resize the window */ xwa.width = w; xwa.height = h; SetWindowPos(&xwa); } /***********************************/ void WRotate() { /* rotate the window and redraw the contents */ if (but[BCROP].active) BTSetActive(&but[BCROP],0); if (useroot) { MakeRootPic(); SetCursors(-1); return; } if (eWIDE == eHIGH) { /* no configure events will be gen'd */ Resize(eWIDE, eHIGH); /* to regen Ximage */ DrawWindow(0, 0, eWIDE, eHIGH); SetCursors(-1); } else { rotatesLeft++; WResize(eWIDE, eHIGH); } } /***********************************/ void WCrop(w,h) int w,h; { XWindowAttributes xwa; /* we want to move window to old x,y + crx1,cry1 */ GetWindowPos(&xwa); xwa.x += crx1; xwa.y += cry1; xwa.width = w; xwa.height = h; SetWindowPos(&xwa); } /***********************************/ void WUnCrop() { int w,h; XWindowAttributes xwa; /* to uncrop, I need to know the old values of cXOFF and cYOFF (cx,cy), and the old values of cWIDE,cHIGH, eWIDE, eHIGH. NOTE that the idea here is to, if possible, uncrop by wrapping the rest of the picture around the currently visible hunk. */ GetWindowPos(&xwa); /* calculate w,h: based on concept of trying to show uncropped picture with same expansion ratios. If this isn't possible (w or h bigger than screen), just go to good ol' 1:1 expansion */ w = (pWIDE * eWIDE) / cWIDE; h = (pHIGH * eHIGH) / cHIGH; if (w>dispWIDE || h>dispHIGH) { w=pWIDE / normFact; h=pHIGH / normFact; if (xwa.x + w > dispWIDE) xwa.x = dispWIDE - w; if (xwa.y + h > dispHIGH) xwa.y = dispHIGH - h; xwa.width = w; xwa.height = h; SetWindowPos(&xwa); } else { xwa.x = xwa.x - (cXOFF*eWIDE)/cWIDE; xwa.y = xwa.y - (cYOFF*eHIGH)/cHIGH; if (xwa.x<0) xwa.x = 0; if (xwa.y<0) xwa.y = 0; xwa.width = w; xwa.height = h; SetWindowPos(&xwa); } } /***********************************/ static void GetWindowPos(xwa) XWindowAttributes *xwa; { Window root,parent,*children,child; unsigned int nchildren; XWindowAttributes pxwa; int ox1,oy1; /* returns the x,y,w,h coords of mainW. x,y are relative to rootW the border is not included (x,y map to top-left pixel in window) */ XGetWindowAttributes(theDisp,mainW,xwa); /* see if mainW has been re-parented by a window manager */ XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren); if (nchildren>0 || children!=NULL) XFree((char *) children); if (parent != rootW) { /* has been reparented */ XGetWindowAttributes(theDisp,parent,&pxwa); XTranslateCoordinates(theDisp,mainW,rootW,0,0, &xwa->x,&xwa->y,&child); XTranslateCoordinates(theDisp,parent,rootW,0,0, &ox1,&oy1,&child); } else { xwa->x += xwa->border_width; xwa->y += xwa->border_width; } } /***********************************/ static void SetWindowPos(xwa) XWindowAttributes *xwa; { /* sets window x,y,w,h values */ /* XSizeHints xsh; */ Window root, parent, *children, child; unsigned int nchildren; XWindowAttributes pxwa; int xoff, yoff, x1, y1, x2, y2; xoff = yoff = 0; /* check for reparented window */ XQueryTree(theDisp,mainW,&root,&parent,&children,&nchildren); if (nchildren>0 || children!=NULL) XFree((char *) children); if (parent != root) { XTranslateCoordinates(theDisp,mainW,rootW,0,0,&x1,&y1,&child); XTranslateCoordinates(theDisp,mainW,parent,0,0,&xoff,&yoff,&child); XTranslateCoordinates(theDisp,parent,rootW,0,0,&x2,&y2,&child); XGetWindowAttributes(theDisp,parent,&pxwa); if (xoff == 0 && yoff == 0) { /* NASTY MOTIF/DXWM KLUDGES */ xoff = pxwa.x; yoff = pxwa.y; if (xwa->x<xoff && (xwa->width + xoff)<dispWIDE) xwa->x = xoff; if (xwa->y<yoff && (xwa->height + yoff)<dispHIGH) xwa->y = yoff; } else { /* NICE, PERFECTLY NORMAL TWM KLUDGES */ xwa->x = xwa->x - xoff; xwa->y = xwa->y - yoff; if (xwa->x<0 && (xwa->width + xoff)<dispWIDE) xwa->x = 0; if (xwa->y<0 && (xwa->height + yoff)<dispHIGH) xwa->y = 0; } } else { xwa->x -= xwa->border_width; xwa->y -= xwa->border_width; if (xwa->x < -(xwa->border_width)) xwa->x = -(xwa->border_width); if (xwa->y < -(xwa->border_width)) xwa->y = -(xwa->border_width); xoff = yoff = xwa->border_width; } XMoveResizeWindow(theDisp, mainW, xwa->x, xwa->y, xwa->width, xwa->height); /* * all this bogus stuff is a work-around for weirdness in * twm where resize was giving 23 extra lines... * should do no harm if this bug is not present. */ XSync(theDisp,False); XGetWindowAttributes(theDisp, mainW, &pxwa); if (pxwa.height != xwa->height) { XEvent xev; /* eat configure event (and any Exposes) if there is one */ if (XCheckTypedWindowEvent(theDisp, mainW, ConfigureNotify, &xev)) { while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)); } XResizeWindow(theDisp, mainW, xwa->width, xwa->height - (pxwa.height - xwa->height)); } } /***********************************/ static void TrackCrop(mx,my) int mx,my; { Window rW,cW; int rx,ry,ox,oy,x,y,active; unsigned int mask; XSetFunction(theDisp,theGC,GXinvert); if (but[BCROP].active) { /* turn off old cropping rectangle */ Rect(crx1,cry1,crx2,cry2); } active = 0; crx1 = ox = mx; cry1 = oy = my; /* nail down one corner */ while (1) { if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button2Mask)) break; /* button released */ if (x!=ox || y!=oy) { /* moved. erase and redraw */ crx2 = x; cry2 = y; Rect(crx1,cry1,ox,oy); active = Rect(crx1,cry1,crx2,cry2); XFlush(theDisp); ox=crx2; oy=cry2; } } } XSetFunction(theDisp,theGC,GXcopy); RANGE(crx1,0,eWIDE); RANGE(cry1,0,eHIGH); RANGE(crx2,0,eWIDE); RANGE(cry2,0,eHIGH); BTSetActive(&but[BCROP],active); SetCropString(); } /***********************************/ static void CropKey(dx,dy,grow) int dx,dy,grow; { int x1,x2,y1,y2; if (!but[BCROP].active) return; /* x1,y1 = top-left, x2,y2 = bot-right */ if (crx1<crx2) { x1=crx1; x2=crx2; } else { x1=crx2; x2=crx1; } if (cry1<cry2) { y1=cry1; y2=cry2; } else { y1=cry2; y2=cry1; } if (!grow) { /* move the rectangle */ x1 += dx; x2 += dx; y1 += dy; y2 += dy; if (x1<0 || x2>eWIDE) { x1 -= dx; x2 -= dx; } if (y1<0 || y2>eHIGH) { y1 -= dy; y2 -= dy; } } else { /* grow the rectangle, pref. keeping top-left anchored */ x2 += dx; y2 += dy; if (x2>eWIDE) { x1 -= dx; x2 -= dx; if (x1<0) x1=0; } if (y2>eHIGH) { y1 -= dy; y2 -= dy; if (y1<0) y1=0; } } InvCropRect(); crx1 = x1; cry1 = y1; crx2 = x2; cry2 = y2; InvCropRect(); SetCropString(); } /***********************************/ static int Rect(x,y,x1,y1) int x,y,x1,y1; { int w,h; /* returns 0 if it didn't draw anything (rect is too small), 1 if it did */ w = abs(x-x1); h = abs(y-y1); if (x>x1) x = x1; if (y>y1) y = y1; if (w<4 || h<4) return 0; /* too small */ /* keep rectangle inside window */ if (x<0) { w+=x; x=0; } if (y<0) { h+=y; y=0; } if (x+w>eWIDE) w=eWIDE-x; if (y+h>eHIGH) h=eHIGH-y; XDrawRectangle(theDisp, mainW, theGC, x, y, w-1, h-1); XDrawRectangle(theDisp, mainW, theGC, x+1, y+1, w-3, h-3); return 1; } /***********************************/ void InvCropRect() { XSetFunction(theDisp,theGC,GXinvert); Rect(crx1,cry1,crx2,cry2); XSetFunction(theDisp,theGC,GXcopy); } /***********************************/ static void TrackPicValues(mx,my) int mx,my; { Window rW,cW; int rx,ry,ox,oy,x,y; unsigned int mask; int ty, w; char foo[64]; unsigned long wh, bl; char *str = "8888,8888 = (123,123,123) <123,123,123>"; wh = infobg; bl = infofg; /* do a colormap search for black and white if LocalCmap and use those colors instead of infobg and infofg */ if (LocalCmap) { XColor ctab[256]; int i; long cval; for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i]; XQueryColors(theDisp,LocalCmap,ctab,nfcols); /* find 'blackest' pixel */ cval = 0x10000 * 3; for (i=0; i<nfcols; i++) if (ctab[i].red + ctab[i].green + ctab[i].blue < cval) { cval = ctab[i].red + ctab[i].green + ctab[i].blue; bl = ctab[i].pixel; } /* find 'whitest' pixel */ cval = -1; for (i=0; i<nfcols; i++) if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) { cval = ctab[i].red + ctab[i].green + ctab[i].blue; wh = ctab[i].pixel; } } XSetFont(theDisp, theGC, monofont); w = XTextWidth(monofinfo,str,strlen(str)); if (my > eHIGH/2) ty = 0; else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4; ox = oy = -1; /* kludge to force redraw first time through */ XSetForeground(theDisp, theGC, bl); XFillRectangle(theDisp, mainW, theGC, 0, ty, w + 8, (monofinfo->ascent+monofinfo->descent) + 4); XSetForeground(theDisp, theGC, wh); XSetBackground(theDisp, theGC, bl); while (1) { int px, py, pix; if (XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) { if (!(mask & Button1Mask)) break; /* button released */ RANGE(x,0,eWIDE-1); RANGE(y,0,eHIGH-1); px = cXOFF + (x * cWIDE) / eWIDE; py = cYOFF + (y * cHIGH) / eHIGH; if (px!=ox || py!=oy) { /* moved. erase and redraw */ pix = pic[py * pWIDE + px]; sprintf(foo,"%4d,%4d = (%3d,%3d,%3d) <%3d,%3d,%3d>", px, py, rorg[pix],gorg[pix],borg[pix], r[pix],g[pix],b[pix]); XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent, foo, strlen(foo)); ox = px; oy = py; } } } XSetFont(theDisp, theGC, mfont); DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4); } /***********************************/ static void MakeDispNames() { int prelen, n, i, done; char *suffix; suffix = namelist[0]; prelen = 0; /* length of prefix to be removed */ n = i = 0; /* shut up pesky compiler warnings */ done = 0; while (!done) { suffix = strchr(suffix,'/'); /* find next '/' in file name */ if (!suffix) break; suffix++; /* go past it */ n = suffix - namelist[0]; for (i=1; i<numnames; i++) { if (strncmp(namelist[0], namelist[i], n)!=0) { done=1; break; } } if (!done) prelen = n; } for (i=0; i<numnames; i++) dispnames[i] = namelist[i] + prelen; } /***********************************/ static int CheckForConfig() { XEvent ev; char foo; /* returns true if there's a config event in which mainW changes size in the event queue */ foo = 0; XCheckIfEvent(theDisp, &ev, IsConfig, &foo); return foo; } static Bool IsConfig(dpy, ev, arg) Display *dpy; XEvent *ev; char *arg; { XConfigureEvent *cev; if (ev->type == ConfigureNotify) { cev = (XConfigureEvent *) ev; if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH)) *arg = 1; } return False; } /***********************************/ void MakeRootPic() { /* called after 'epic' has been generated (if we're using root). creates the XImage and the pixmap, sets the root to the new pixmap, and refreshes the display */ Pixmap tmpPix; int i,j,k,w,h; XSetWindowBackgroundPixmap(theDisp, rootW, None); XClearWindow(theDisp, rootW); XFlush(theDisp); if (((fixedaspect && automax) || centerpic) && (eWIDE != dispWIDE || eHIGH != dispHIGH)) { /* center picture inside a dispWIDE x dispHIGH pixmap */ w = eWIDE; if (w>dispWIDE) w = dispWIDE; h = eHIGH; if (h>dispHIGH) h = dispHIGH; tmpPix = XCreatePixmap(theDisp, mainW, dispWIDE, dispHIGH, dispDEEP); if (!tmpPix) FatalError("couldn't create root pixmap"); /* do some stuff to set up the border around the picture */ XSetForeground(theDisp, theGC, rootbg); XFillRectangle(theDisp, tmpPix, theGC, 0,0, dispWIDE, dispHIGH); switch (rootPattern) { case 0: /* solid color */ break; case 1: /* 'warp' effect */ XSetForeground(theDisp, theGC, rootfg); for (i=0; i<=dispWIDE; i+=8) XDrawLine(theDisp, tmpPix, theGC, i, 0, dispWIDE-i, dispHIGH); for (i=0; i<=dispHIGH; i+=8) XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, dispHIGH-i); break; case 2: /* 'bricks' effect */ XSetForeground(theDisp, theGC, rootfg); for (i=k=0; i<dispHIGH; i+=20,k++) { XDrawLine(theDisp, tmpPix, theGC, 0, i, dispWIDE, i); for (j=(k&1) * 20 + 10; j<dispWIDE; j+=40) XDrawLine(theDisp, tmpPix, theGC, j,i,j,i+20); } break; /* your algorithm here */ default: break; } XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, (dispWIDE-w)/2, (dispHIGH-h)/2, w, h); } else { tmpPix = XCreatePixmap(theDisp, mainW, eWIDE, eHIGH, dispDEEP); if (!tmpPix) FatalError("couldn't create root pixmap"); XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0, eWIDE, eHIGH); } XSetWindowBackgroundPixmap(theDisp, mainW, tmpPix); XFreePixmap(theDisp, tmpPix); SaveRootInfo(); XClearWindow(theDisp, mainW); } /***********************************/ static void SaveRootInfo() { /* called when using root window. stores the pixmap ID used to draw the root window in a property. This will be used later to free all resources allocated by this instantiation of xv (ie, the alloc'd colors). These resources are kept alloc'ed after client exits so that rainbow effect is avoided */ Atom prop; static Pixmap riPix = NULL; if ( !(theVisual->class & 1)) return; /* no colormap to worry about */ if (riPix) return; /* it's already been saved once */ riPix = XCreatePixmap(theDisp, rootW, 1, 1, 1); if (!riPix) return; /* unable to save. thankfully, unlikely to happen */ prop = XInternAtom(theDisp, "_XV_PIXMAP", False); if (!prop) FatalError("couldn't create _XV_PIXMAP atom"); XChangeProperty(theDisp, rootW, prop, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &riPix, 1); XSetCloseDownMode(theDisp, RetainPermanent); } /***********************************/ static void KillOldRootInfo() { /* get the pixmap ID from the _XV_PIXMAP property, and kill it */ Atom prop, type; int format; unsigned long length, after; unsigned char *data; prop = XInternAtom(theDisp, "_XV_PIXMAP", True); if (!prop) return; /* no old pixmap to kill */ if (XGetWindowProperty(theDisp, rootW, prop, 0L, 1L, True, AnyPropertyType, &type, &format, &length, &after, &data) == Success) { if (type==XA_PIXMAP && format==32 && length==1 && after==0 && data) XKillClient(theDisp, *((Pixmap *)data)); } } /************************************************************************/ /* following three rd_* functions swiped from xgraph, by David Harrison */ /************************************************************************/ /***********************************/ static int rd_int(name) char *name; { /* returns '1' if successful. result in def_int */ if (def_str = XGetDefault(theDisp, PROGNAME, name)) { if (sscanf(def_str, "%ld", &def_int) == 1) return 1; else { fprintf(stderr, "%s: couldn't read integer value for %s resource\n", cmd,name); return 0; } } else return 0; } /***********************************/ static int rd_str(name) char *name; { /* returns '1' if successful. result in def_str */ if (def_str = XGetDefault(theDisp, PROGNAME, name)) return 1; else return 0; } /***********************************/ static int rd_flag(name) char *name; { /* returns '1' if successful. result in def_str */ if (def_str = XGetDefault(theDisp, PROGNAME, name)) { def_int = (strcmp(def_str, "on")==0) || (strcmp(def_str, "1")==0) || (strcmp(def_str, "true")==0) || (strcmp(def_str, "yes")==0); return 1; } else return 0; } \BARFOO\ else echo "will not over write ./xv.c" fi echo "Finished archive 9 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.