Index: xvjpeg.c =================================================================== RCS file: RCS/xvjpeg.c,v retrieving revision 1.1 diff -u -r1.1 xvjpeg.c --- xvjpeg.c 2001/11/20 08:39:17 1.1 +++ xvjpeg.c 2001/11/20 09:35:38 @@ -21,6 +21,7 @@ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ #endif +#define JPEG_APP1 (JPEG_APP0 + 1) /*** Stuff for JPEG Dialog box ***/ #define JWIDE 400 @@ -35,8 +36,15 @@ This is currently hardcoded to be twice the size of a schnauzer icon, as the schnauzer's the only thing that does a quick load... */ +#if 0 #define QUICKWIDE 160 #define QUICKHIGH 120 +#else /* 0 */ +extern int maxIsizeWide; +extern int maxIsizeHigh; +#define QUICKWIDE (maxIsizeWide*2) +#define QUICKHIGH (maxIsizeHigh*2) +#endif /* 0 */ struct my_error_mgr { struct jpeg_error_mgr pub; @@ -56,6 +64,7 @@ METHODDEF void xv_prog_meter PARM((j_common_ptr)); static unsigned int j_getc PARM((j_decompress_ptr)); METHODDEF boolean xv_process_comment PARM((j_decompress_ptr)); +METHODDEF boolean xv_process_app1 PARM((j_decompress_ptr)); static int writeJFIF PARM((FILE *, byte *, int,int,int)); @@ -65,6 +74,8 @@ static char *fbasename; static char *comment; static int colorType; +static char *imageInfo; +static int imageInfoSize; static DIAL qDial, smDial; static BUTT jbut[J_NBUTTS]; @@ -470,6 +481,7 @@ fbasename = BaseName(fname); pic = (byte *) NULL; comment = (char *) NULL; + imageInfo = (char *) NULL; pinfo->type = PIC8; @@ -488,11 +500,14 @@ /* if we're here, it blowed up... */ jpeg_destroy_decompress(&cinfo); fclose(fp); - if (pic) free(pic); - if (comment) free(comment); + if (pic) free(pic); + if (comment) free(comment); + if (imageInfo) free(imageInfo); pinfo->pic = (byte *) NULL; pinfo->comment = (char *) NULL; + pinfo->imageInfo = (char *) NULL; + pinfo->imageInfoSize = 0; return 0; } @@ -500,6 +515,7 @@ jpeg_create_decompress(&cinfo); jpeg_set_marker_processor(&cinfo, JPEG_COM, xv_process_comment); + jpeg_set_marker_processor(&cinfo, JPEG_APP1, xv_process_app1); /* hook up progress meter */ prog.progress_monitor = xv_prog_meter; @@ -587,6 +603,9 @@ jpeg_destroy_decompress(&cinfo); fclose(fp); if (comment) free(comment); + if (imageInfo) free(imageInfo); + comment = NULL; + imageInfo = NULL; return 0; } @@ -601,6 +620,9 @@ jpeg_destroy_decompress(&cinfo); fclose(fp); if (comment) free(comment); + if (imageInfo) free(imageInfo); + comment = NULL; + imageInfo = NULL; return 0; } @@ -642,13 +664,17 @@ sprintf(pinfo->shrtInfo, "%dx%d %s JPEG. ", w,h, (cinfo.out_color_space == JCS_GRAYSCALE) ? "Greyscale " : "Color "); - pinfo->comment = comment; + pinfo->comment = comment; + pinfo->imageInfo = imageInfo; + pinfo->imageInfoSize = imageInfoSize; jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(fp); - comment = (char *) NULL; + comment = (char *) NULL; + imageInfo = (char *) NULL; + imageInfoSize = 0; return 1; } @@ -704,6 +730,36 @@ return TRUE; } +/**************************************************/ +METHODDEF boolean xv_process_app1(cinfo) + j_decompress_ptr cinfo; +{ + int length, hasnull; + unsigned int ch; + char *sp; + + length = j_getc(cinfo) << 8; + length += j_getc(cinfo); + length -= 2; /* discount the length word itself */ + + if (!imageInfo) { + imageInfo = (char *) malloc((size_t) length); + imageInfoSize = 0; + } + else imageInfo = (char *) realloc(imageInfo, imageInfoSize + length); + if (!imageInfo) FatalError("out of memory in xv_process_imageInfo"); + + sp = imageInfo + imageInfoSize; + imageInfoSize += length; + + while (length-- > 0) { + ch = j_getc(cinfo); + *sp++ = (char) ch; + } + + return TRUE; +} + @@ -723,7 +779,7 @@ int i, bperpix; char xvcmt[256]; - comment = (char *) NULL; + comment = (char *) NULL; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = xv_error_exit; @@ -818,6 +874,10 @@ jpeg_write_marker(&cinfo,JPEG_COM,(byte *) comment,(u_int) strlen(comment)); + if (picImageInfo) + jpeg_write_marker(&cinfo, JPEG_APP1, + (byte *) picImageInfo,(u_int) picImageInfoSize); + while (cinfo.next_scanline < cinfo.image_height) { rowptr[0] = (JSAMPROW) &pic[cinfo.next_scanline * w * bperpix]; (void) jpeg_write_scanlines(&cinfo, rowptr, (JDIMENSION) 1); Index: xvbrowse.c =================================================================== RCS file: RCS/xvbrowse.c,v retrieving revision 1.1 diff -u -r1.1 xvbrowse.c --- xvbrowse.c 2001/11/20 08:39:17 1.1 +++ xvbrowse.c 2001/11/24 12:17:24 @@ -59,6 +59,7 @@ #include "bits/br_trash" #include "bits/fcurs" #include "bits/fccurs" +#include "bits/flcurs" #include "bits/fdcurs" #include "bits/fcursm" @@ -99,8 +100,10 @@ #define ISLOADABLE(ftyp) (ftyp!=BF_DIR && ftyp!=BF_CHR && ftyp!=BF_BLK && \ ftyp!=BF_SOCK && ftyp!=BF_FIFO) -#define DEF_BROWWIDE 615 /* default size of window */ -#define DEF_BROWHIGH 356 +/* Default size of window -- roughly 600x350, but flexible. + The added constant at the end is pure magic. */ +#define DEF_BROWWIDE(br) ((550+br->isizeWide-1)/ISPACE_WIDE(br)*ISPACE_WIDE(br)-(ISPACE_WIDE(br)-br->isizeWide)+2*LRMARGINS+40) +#define DEF_BROWHIGH(br) ((250+br->isizeHigh-1)/ISPACE_HIGH(br)*ISPACE_HIGH(br)-(ISPACE_HIGH(br)-br->isizeHigh)+TOPMARGIN+BOTMARGIN+32) #define SCROLLVERT 8 /* height of scroll region at top/bottom of iconw */ #define PAGEVERT 40 /* during rect drag, if further than this, page */ @@ -113,13 +116,13 @@ #define BOTMARGIN 58 /* room for a row of buttons and a line of text */ #define LRMARGINS 5 /* left and right margins */ -#define ISIZE_WIDE 80 /* maximum size of an icon */ -#define ISIZE_HIGH 60 +#define DEF_ISIZE_WIDE 160 /* default size of an icon */ +#define DEF_ISIZE_HIGH 120 -#define ISPACE_WIDE (ISIZE_WIDE+16) /* icon spacing */ +#define ISPACE_WIDE(br) (br->isizeWide+16) /* icon spacing */ #define ISPACE_TOP 4 /* dist btwn top of ISPACE and ISIZE */ #define ISPACE_TTOP 4 /* dist btwn bot of icon and title */ -#define ISPACE_HIGH (ISIZE_HIGH+ISPACE_TOP+ISPACE_TTOP+16+4) +#define ISPACE_HIGH(br) (br->isizeHigh+ISPACE_TOP+ISPACE_TTOP+16+4) #define DBLCLICKTIME 300 /* milliseconds */ @@ -140,14 +143,26 @@ #define BR_NBUTTS 13 /* # of command buttons */ #define BR_SEP1 13 /* separator */ #define BR_HIDDEN 14 -#define BR_SELFILES 15 -#define BR_NCMDS 16 /* # of menu commands */ +#define BR_LINK 15 /* type of links to use */ +#define BR_SELFILES 16 +#define BR_ICONSIZE 17 /* choose icon size */ +#define BR_NCMDS 18 /* # of menu commands */ #define BUTTW 80 #define BUTTH 24 +/* copy modes */ +#define CM_MOVE 0 /* Move files */ +#define CM_COPY 1 /* Copy files */ +#define CM_LINK 2 /* Symlink files */ + +int maxIsizeWide = DEF_ISIZE_WIDE; +int maxIsizeHigh = DEF_ISIZE_HIGH; + static char *showHstr = "Show hidden files"; static char *hideHstr = "Hide 'hidden' files"; +static char *symLstr = "Use symbolic links"; +static char *hardLstr = "Use hard links"; static char *cmdMList[] = { "Change directory...\t^c", "Delete file(s)\t^d", @@ -161,10 +176,12 @@ "Text view\t^t", "Recursive Update\t^e", "Quit xv\t^q", - "Close window\t^c", + "Close window\tESC", MBSEP, "Show hidden files", /* no equiv */ - "Select files...\t^f" + "Use symbolic links", /* no equiv */ + "Select files...\t^f", + "Choose icon size...", /* no equiv */ }; @@ -189,6 +206,7 @@ int wide, high; int iwWide, iwHigh; int numWide, numHigh, visHigh; + int isizeWide, isizeHigh; SCRL scrl; BUTT but[BR_NBUTTS]; @@ -196,6 +214,7 @@ char dispstr[256]; int numbutshown; int showhidden; + int hardlink; int numlit; BFIL *bfList; @@ -209,7 +228,7 @@ } BROWINFO; -static Cursor movecurs, copycurs, delcurs; +static Cursor movecurs, copycurs, linkcurs, delcurs; static BROWINFO binfo[MAXBRWIN]; static Pixmap bfIcons[BF_MAX], trashPix; static int hasBeenSized = 0; @@ -277,6 +296,8 @@ static void doDeleteCmd PARM((BROWINFO *)); static void doSelFilesCmd PARM((BROWINFO *)); +static void doIconSizeCmd PARM((BROWINFO *)); + static void doRecurseCmd PARM((BROWINFO *)); static void recurseUpdate PARM((BROWINFO *, char *)); @@ -288,6 +309,7 @@ char *, char **, int, int)); static int moveFile PARM((char *, char *)); static int copyFile PARM((char *, char *)); +static int linkFile PARM((char *, char *, int)); static void cp PARM((void)); static void cp_dir PARM((void)); static void cp_file PARM((struct stat *, int)); @@ -310,7 +332,7 @@ XSetWindowAttributes xswa; BROWINFO *br; XColor ecdef, cursfg, cursbg; - Pixmap mcpix, ccpix, dcpix, fcmpix; + Pixmap mcpix, ccpix, lcpix, dcpix, fcmpix; int gx, gy, gw, gh, gset, gx1, gy1; unsigned int uw, uh; char wgeom[64]; @@ -385,8 +407,12 @@ if (i) sprintf(wname, "xv visual schnauzer (%d)", i); else sprintf(wname, "xv visual schnauzer"); + br->isizeWide = DEF_ISIZE_WIDE; + br->isizeHigh = DEF_ISIZE_HIGH; + br->win = CreateWindow(wname, "XVschnauze", wgeom, - DEF_BROWWIDE, DEF_BROWHIGH, browfg, browbg, 1); + DEF_BROWWIDE(br), DEF_BROWHIGH(br), + browfg, browbg, 1); if (!br->win) FatalError("can't create schnauzer window!"); haveWindows = 1; @@ -411,9 +437,25 @@ if (XGetNormalHints(theDisp, br->win, &hints)) { - hints.min_width = 325 + 96; - hints.min_height = 180; - hints.flags |= PMinSize; + /* The constants here are pure magic, derived by experimentation */ + hints.base_width = 2 * LRMARGINS + 24; + hints.base_height = TOPMARGIN + BOTMARGIN; + hints.width_inc = ISPACE_WIDE(br); + hints.height_inc = ISPACE_HIGH(br); + /* For some reason, my window manager insists on using the minimum + size as the base size even when PBaseSize is specified. + Until I figure out the cause, I'm going to disable the + setting of the base size because it messes up the resizing + display. GHK 11-24-01 */ +#if 0 + hints.min_width = hints.width_inc + hints.base_width; + hints.min_height = hints.height_inc + hints.base_height; + hints.flags |= PMinSize | PResizeInc | PBaseSize; +#else /* 0 */ + hints.min_width = hints.base_width; + hints.min_height = hints.base_height; + hints.flags |= PMinSize | PResizeInc; +#endif /* 0 */ XSetNormalHints(theDisp, br->win, &hints); } @@ -462,7 +504,13 @@ cmdMList, BR_NCMDS, browfg,browbg,browhi,browlo); br->showhidden = 0; - br->cmdMB.list[BR_HIDDEN] = showHstr; + br->hardlink = 0; + + if (rd_flag("showHidden")) br->showhidden = def_int; + if (rd_flag("hardLink")) br->hardlink = def_int; + + br->cmdMB.list[BR_HIDDEN] = br->showhidden ? hideHstr : showHstr; + br->cmdMB.list[BR_LINK] = br->hardlink ? symLstr : hardLstr; br->numbutshown = 0; br->numlit = 0; @@ -532,7 +580,7 @@ FatalError("unable to create all built-in icons for schnauzer"); for (i=0; iwide == w && br->high == h) return; /* no change in size */ if (XGetNormalHints(theDisp, br->win, &hints)) { - hints.width = w; - hints.height = h; - hints.flags |= USSize; + /* The constants here are pure magic, derived by experimentation */ + hints.base_width = 2 * LRMARGINS + 24; + hints.base_height = TOPMARGIN + BOTMARGIN; + hints.width_inc = ISPACE_WIDE(br); + hints.height_inc = ISPACE_HIGH(br); + /* For some reason, my window manager insists on using the minimum + size as the base size even when PBaseSize is specified. + Until I figure out the cause, I'm going to disable the + setting of the base size because it messes up the resizing + display. GHK 11-24-01 */ +#if 0 + hints.min_width = hints.width_inc + hints.base_width; + hints.min_height = hints.height_inc + hints.base_height; + hints.flags |= USSize | PMinSize | PResizeInc | PBaseSize; +#else /* 0 */ + hints.min_width = hints.base_width; + hints.min_height = hints.base_height; + hints.flags |= USSize | PMinSize | PResizeInc; +#endif /* 0 */ XSetNormalHints(theDisp, br->win, &hints); } @@ -892,8 +959,8 @@ br->iwWide = br->wide - (2*LRMARGINS) - (br->scrl.tsize+1) - 2; maxh = br->high - (TOPMARGIN + BOTMARGIN); - br->iwHigh = (maxh / ISPACE_HIGH) * ISPACE_HIGH; - if (br->iwHigh < ISPACE_HIGH) br->iwHigh = ISPACE_HIGH; + br->iwHigh = (maxh / ISPACE_HIGH(br)) * ISPACE_HIGH(br); + if (br->iwHigh < ISPACE_HIGH(br)) br->iwHigh = ISPACE_HIGH(br); XMoveResizeWindow(theDisp, br->iconW, LRMARGINS, TOPMARGIN, (u_int) br->iwWide, (u_int) br->iwHigh); @@ -925,8 +992,8 @@ br->cmdMB.x = br->wide - LRMARGINS - br->cmdMB.w - 2; br->cmdMB.y = 5; - br->numWide = br->iwWide / ISPACE_WIDE; - br->visHigh = br->iwHigh / ISPACE_HIGH; + br->numWide = br->iwWide / ISPACE_WIDE(br); + br->visHigh = br->iwHigh / ISPACE_HIGH(br); /* compute minv,maxv,curv,page values based on new current size */ computeScrlVals(br, &maxv, &page); @@ -1098,8 +1165,16 @@ rescanDir(br); break; + case BR_LINK: br->hardlink = !br->hardlink; + br->cmdMB.list[cmd] = (br->hardlink) + ? symLstr : hardLstr; + rescanDir(br); + break; + case BR_SELFILES: doSelFilesCmd(br); break; + case BR_ICONSIZE: doIconSizeCmd(br); break; + case BR_RECURSUP: doRecurseCmd(br); break; } } @@ -1351,10 +1426,10 @@ /* figure out if this icon region is in the clip region */ - ix = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */ - iy = (i/br->numWide) * ISPACE_HIGH; - iw = ISPACE_WIDE; - ih = ISPACE_HIGH; + ix = (i%br->numWide) * ISPACE_WIDE(br); /* x,y = top-left of icon region */ + iy = (i/br->numWide) * ISPACE_HIGH(br); + iw = ISPACE_WIDE(br); + ih = ISPACE_HIGH(br); if ((ix+iw >= x) && (ix < x+w) && (iy+ih >= y) && (iy < y+h)) { if (j>=0 && j < br->bfLen) drawIcon(br,j); @@ -1400,10 +1475,10 @@ int x,y,w,h; /* erase old icon + string */ - x = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */ - y = (i/br->numWide) * ISPACE_HIGH; - w = ISPACE_WIDE; - h = ISPACE_HIGH; + x = (i%br->numWide) * ISPACE_WIDE(br); /* x,y = top-left of icon regn */ + y = (i/br->numWide) * ISPACE_HIGH(br); + w = ISPACE_WIDE(br); + h = ISPACE_HIGH(br); XSetForeground(theDisp, theGC, browbg); if (ctrlColor) { /* keep from erasing borders */ @@ -1412,7 +1487,8 @@ if (x+w > br->iwWide-4) w = (br->iwWide-4)-x + 2; if (y+h > br->iwHigh-4) h = (br->iwHigh-4)-y + 2; } - XFillRectangle(theDisp, br->iconW, theGC, x, y, ISPACE_WIDE, (u_int) h); + XFillRectangle(theDisp, br->iconW, theGC, + x, y, ISPACE_WIDE(br), (u_int) h); if (indx>=0 && indx < br->bfLen) drawIcon(br, indx); } @@ -1429,7 +1505,7 @@ BROWINFO *br; int num; { - int i,x,y,ix,iy,sw,sh,sx,sy; + int i,x,y,ix,iy,iw,ih,sw,sh,sx,sy; BFIL *bf; char tmpstr[64], fixedname[64], *nstr, *str; @@ -1449,27 +1525,30 @@ XSetBackground(theDisp, theGC, browbg); } - x = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */ - y = (i/br->numWide) * ISPACE_HIGH; + x = (i%br->numWide) * ISPACE_WIDE(br); /* x,y = top-left of icon region */ + y = (i/br->numWide) * ISPACE_HIGH(br); + + iw = bf->w < br->isizeWide ? bf->w : br->isizeWide; + ih = bf->h < br->isizeHigh ? bf->h : br->isizeHigh; /* draw the icon */ - ix = x + ISPACE_WIDE/2 - bf->w/2; /* center align */ - iy = y + ISPACE_TOP + ISIZE_HIGH - bf->h; /* bottom align */ + ix = x + ISPACE_WIDE(br)/2 - iw/2; /* center align */ + iy = y + ISPACE_TOP + br->isizeHigh - ih; /* bottom align */ if (bf->ftype >= 0 && bf->ftype ftype], br->iconW, theGC, - 0, 0, (u_int) bf->w, (u_int) bf->h, ix, iy, 1L); + 0, 0, (u_int) iw, (u_int) ih, ix, iy, 1L); } else if (bf->ftype == BF_HAVEIMG && bf->ximage) { XPutImage(theDisp, br->iconW, theGC, bf->ximage, 0,0, ix,iy, - (u_int) bf->w, (u_int) bf->h); + (u_int) iw, (u_int) ih); } else { /* shouldn't happen */ XDrawRectangle(theDisp, br->iconW, theGC, ix, iy, - (u_int) bf->w, (u_int) bf->h); + (u_int) iw, (u_int) ih); } @@ -1487,13 +1566,13 @@ /* decide if the title is too big, and shorten if neccesary */ - if (StringWidth(str) > ISPACE_WIDE-6) { + if (StringWidth(str) > ISPACE_WIDE(br)-6) { int dotpos; strncpy(tmpstr, str, (size_t) 56); dotpos = strlen(tmpstr); strcat(tmpstr,"..."); - while(StringWidth(tmpstr) > ISPACE_WIDE-6 && dotpos>0) { + while(StringWidth(tmpstr) > ISPACE_WIDE(br)-6 && dotpos>0) { /* change last non-dot char in tmpstr to a dot, and lop off last dot */ @@ -1511,8 +1590,8 @@ sw = StringWidth(nstr); sh = CHIGH; - sx = x + ISPACE_WIDE/2 - sw/2 - 2; - sy = y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP - 1; + sx = x + ISPACE_WIDE(br)/2 - sw/2 - 2; + sy = y + ISPACE_TOP + br->isizeHigh + ISPACE_TTOP - 1; XSetForeground(theDisp, theGC, (bf->lit && bf->lit!=ICON_ONLY) ? browfg : browbg); @@ -1521,8 +1600,8 @@ XSetForeground(theDisp, theGC, (bf->lit && bf->lit!=ICON_ONLY) ? browbg : browfg); - CenterString(br->iconW, x + ISPACE_WIDE/2, - y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP + CHIGH/2, nstr); + CenterString(br->iconW, x + ISPACE_WIDE(br)/2, + y + ISPACE_TOP + br->isizeHigh + ISPACE_TTOP + CHIGH/2, nstr); } @@ -1544,13 +1623,13 @@ XSetForeground(theDisp, theGC, browbg); - x = (i % br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */ - y = (i / br->numWide) * ISPACE_HIGH; + x = (i % br->numWide) * ISPACE_WIDE(br); /* x,y = top-left of icon region */ + y = (i / br->numWide) * ISPACE_HIGH(br); w = bf->w; h = bf->h; - ix = x + ISPACE_WIDE/2 - w/2; /* center align */ - iy = y + ISPACE_TOP + ISIZE_HIGH - h; /* bottom align */ + ix = x + ISPACE_WIDE(br)/2 - w/2; /* center align */ + iy = y + ISPACE_TOP + br->isizeHigh - h; /* bottom align */ if (ctrlColor) { /* keep from erasing borders */ if (ix<2) ix = 2; @@ -1575,13 +1654,13 @@ if (num<0 || num >= br->bfLen) return; i = num - (br->scrl.val * br->numWide); - x = (i % br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */ - y = (i / br->numWide) * ISPACE_HIGH; + x = (i % br->numWide) * ISPACE_WIDE(br); /* x,y = top-left of icon region */ + y = (i / br->numWide) * ISPACE_HIGH(br); XSetForeground(theDisp, theGC, browbg); XFillRectangle(theDisp, br->iconW, theGC, - x, y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP - 1, - (u_int) ISPACE_WIDE, (u_int) LINEHIGH); + x, y + ISPACE_TOP + br->isizeHigh + ISPACE_TTOP - 1, + (u_int) ISPACE_WIDE(br), (u_int) LINEHIGH); if (ctrlColor) Draw3dRect(br->iconW, 0, 0, (u_int) br->iwWide-1, (u_int) br->iwHigh-1, @@ -1756,7 +1835,7 @@ int hasrect, rx, ry, rw, rh; rx = ry = rw = rh = 0; - first = 1; hasrect = 0; cpymode = 0; + first = 1; hasrect = 0; cpymode = CM_MOVE; origsval = br->scrl.val; if ( (sel>=0 && !multi) || sel==-1) { @@ -1767,8 +1846,11 @@ if (mask & Button1Mask) { /* still held down */ if (sel == -1) curs = tcross; - else if ((mask & ControlMask) || (mask & ShiftMask)) { - curs = copycurs; cpymode = 1; + else if (mask & ControlMask) { + curs = copycurs; cpymode = CM_COPY; + } + else if (mask & ShiftMask) { + curs = linkcurs; cpymode = CM_LINK; } else curs = movecurs; @@ -1786,12 +1868,14 @@ if (sel>=0) { /* see if changed copy/move status (and cursor) */ int cmod; - cmod = (mask&ControlMask || mask&ShiftMask) ? 1 : 0; + cmod = (mask&ControlMask) ? CM_COPY + : (mask&ShiftMask) ? CM_LINK : CM_MOVE; if (cmod != cpymode && !dodel) { - curs = (cmod) ? copycurs : movecurs; - for (i=0; iiwHigh-1); if (x != prevx || y != prevy || !hasrect) { /* cursor moved */ - origy = my - (br->scrl.val - origsval) * ISPACE_HIGH; + origy = my - (br->scrl.val - origsval) * ISPACE_HIGH(br); if (hasrect) invertSelRect(br, rx, ry, rw, rh); /* turn off */ @@ -1929,20 +2014,23 @@ redraw those that have changed state */ for (i=0,cnt=0, bf=br->bfList; ibfLen; i++,bf++) { - int ix, iy, isin, light; + int ix, iy, w, h, isin, light; - ix = ((i%br->numWide) * ISPACE_WIDE) - + ISPACE_WIDE/2 - bf->w/2; - iy = ((i/br->numWide) * ISPACE_HIGH) - + ISPACE_TOP + ISIZE_HIGH - bf->h; + w = bf->w < br->isizeWide ? bf->w : br->isizeWide; + h = bf->h < br->isizeHigh ? bf->h : br->isizeHigh; - iy = iy - br->scrl.val * ISPACE_HIGH; + ix = ((i%br->numWide) * ISPACE_WIDE(br)) + + ISPACE_WIDE(br)/2 - w/2; + iy = ((i/br->numWide) * ISPACE_HIGH(br)) + + ISPACE_TOP + br->isizeHigh - h; + + iy = iy - br->scrl.val * ISPACE_HIGH(br); /* is the icon rectangle of this beastie inside the dragging rectangle ? */ - isin = (ix+bf->w >= rx && ix < rx+rw && - iy+bf->h >= ry && iy < ry+rh); + isin = (ix+w >= rx && ix < rx+rw && + iy+h >= ry && iy < ry+rh); if (isin) { if (bf->lit==0) { @@ -2050,7 +2138,10 @@ else { /* have to do some copying/moving */ char **nlist; int ncnt; - if (DEBUG) fprintf(stderr,"Files to %s: ", cpymode ? "copy" : "move"); + if (DEBUG) + fprintf(stderr,"Files to %s: ", + (cpymode == CM_COPY) ? "copy" + : (cpymode == CM_LINK) ? "link" : "move"); nlist = (char **) malloc(br->numlit * sizeof(char *)); if (!nlist) FatalError("clickIconWin: couldn't malloc nlist"); @@ -2206,7 +2297,7 @@ /* mx,my are mouse position in iconW coordinates. Returns '-1' if the mouse is not in any icon */ - int i, x, y, ix, iy, sel, base, num; + int i, x, y, w, h, ix, iy, sel, base, num; BFIL *bf; /* figure out what was clicked... */ @@ -2217,13 +2308,16 @@ if (sel>=0 && selbfLen) { bf = &(br->bfList[sel]); - x = (i%br->numWide) * ISPACE_WIDE; /* x,y=top-left of icon region */ - y = (i/br->numWide) * ISPACE_HIGH; + x = (i%br->numWide) * ISPACE_WIDE(br); /* x,y=top-left of icon region */ + y = (i/br->numWide) * ISPACE_HIGH(br); + + w = bf->w < br->isizeWide ? bf->w : br->isizeWide; + h = bf->h < br->isizeHigh ? bf->h : br->isizeHigh; - ix = x + ISPACE_WIDE/2 - bf->w/2; /* center align */ - iy = y + ISPACE_TOP + ISIZE_HIGH - bf->h; /* bottom align */ + ix = x + ISPACE_WIDE(br)/2 - w/2; /* center align */ + iy = y + ISPACE_TOP + br->isizeHigh - h; /* bottom align */ - if (PTINRECT(mx,my, ix, iy, bf->w, bf->h)) break; + if (PTINRECT(mx,my, ix, iy, w, h)) break; } } @@ -3408,6 +3502,7 @@ byte *icon24, *icon8; char str[256], str1[256], *readname, uncompname[128]; char basefname[128], *uncName; + struct stat st; if (!bf || !bf->name || bf->name[0] == '\0') return; /* shouldn't happen */ @@ -3508,8 +3603,8 @@ /* compute size of icon (iwide,ihigh) */ - wexpand = (double) pinfo.w / (double) ISIZE_WIDE; - hexpand = (double) pinfo.h / (double) ISIZE_HIGH; + wexpand = (double) pinfo.w / (double) br->isizeWide; + hexpand = (double) pinfo.h / (double) br->isizeHigh; if (wexpand >= 1.0 || hexpand >= 1.0) { /* don't expand small icons */ if (wexpand>hexpand) { @@ -3598,6 +3693,13 @@ writeThumbFile(br, bf, icon8, iwide, ihigh, str); + /* Find out if it's a link. */ + if (lstat(bf->name, &st)==0 && S_ISLNK(st.st_mode)) { + strcpy(str1, str); + strcpy(str, "Link to "); + strcat(str, str1); + } + /* have to make a *copy* of str */ if (strlen(str)) { bf->imginfo = (char *) malloc(strlen(str)+1); @@ -3665,6 +3767,7 @@ char buf[256], *st, *info; int w,h,mv,i,builtin; byte *icon8; + struct stat lst; info = NULL; icon8 = NULL; builtin = 0; @@ -3699,8 +3802,18 @@ else if (!strncmp(buf, "#IMGINFO:", strlen("#IMGINFO:"))) { st = (char *) index(buf, ':') + 1; - info = (char *) malloc(strlen(st) + 1); - if (info) strcpy(info, st); + /* Find out if it's a link. */ + if (lstat(bf->name, &lst)==0 && S_ISLNK(lst.st_mode)) { + info = (char *) malloc(strlen(st) + 1 + sizeof "Link to " - 1); + if (info) { + strcpy(info, "Link to "); + strcat(info, st); + } + } + else { + info = (char *) malloc(strlen(st) + 1); + if (info) strcpy(info, st); + } } } @@ -3718,7 +3831,7 @@ goto errexit; - if (w>ISIZE_WIDE || h>ISIZE_HIGH || w<1 || h<1 || mv != 255) { + if (w<1 || h<1 || mv != 255) { sprintf(buf,"Bogus thumbnail file for '%s'. Skipping.", bf->name); setBrowStr(br, buf); goto errexit; @@ -4229,6 +4342,7 @@ int i, j, numdirs, numfiles, slen, firstdel; char buf[512]; static char *yesno[] = { "\004Delete", "\033Cancel" }; + static char *noyes[] = { "\033Cancel", "\004Delete" }; if (!br->bfLen || !br->bfList || !br->numlit) return; @@ -4284,7 +4398,8 @@ /* if any directories are being toasted, bring up the are you REALLY sure - confirmation box */ + confirmation box. We use noyes instead of yesno so that they have to + do more than just click fast without realizing what's up. */ if (numdirs) { sprintf(buf,"Recursively delete director%s: ", numdirs>1 ? "ies" : "y"); @@ -4303,8 +4418,8 @@ } } - i = PopUp(buf, yesno, 2); - if (i) return; /* cancelled */ + i = PopUp(buf, noyes, 2); + if (i == 0) return; /* cancelled */ } @@ -4385,6 +4500,50 @@ /*******************************************/ +static void doIconSizeCmd(br) + BROWINFO *br; +{ + int i; + static char buf[MAXPATHLEN+100]; + static char *labels[] = { "\nOk", "\033Cancel" }; + char str[512]; + + buf[0] = '\0'; + sprintf(str, + "Icons are currently %dx%d. Choose new icon width (default %d).", + br->isizeWide, br->isizeHigh, br->isizeWide); + strcat(str," Icon height is calculated automatically as 0.75*width."); + strcat(str," Icons larger than the chosen size will display only"); + strcat(str," the upper-left corner"); + + i = GetStrPopUp(str, labels, 2, buf, MAXPATHLEN, "", 0); + if (i) return; /* cancelled */ + + i = atoi(buf); + if (i <= 0) return; + + /* force width to be a multiple of 4 and height to be 3/4 of width */ + br->isizeWide = i & ~3; + br->isizeHigh = (br->isizeWide / 4) * 3; + + /* save browser width, then change it so that resizeBrowse will run */ + i = br->wide; + br->wide++; + resizeBrowse(br, i, br->high); + + maxIsizeWide = 0; + maxIsizeHigh = 0; + for (i=0; i maxIsizeWide) + maxIsizeWide = binfo[i].isizeWide; + if (binfo[i].isizeHigh > maxIsizeHigh) + maxIsizeHigh = binfo[i].isizeHigh; + } +} + + + +/*******************************************/ static char *dirStack[128]; static int dirStackLen; @@ -4643,6 +4802,11 @@ #define OWRT_NOASK 1 #define OWRT_CANCEL 2 +static int cantlink; +#define CLNK_ASK 0 +#define CLNK_COPY 1 +#define CLNK_SYM 2 +#define CLNK_CANCEL 3 /*******************************************/ static void dragFiles(srcBr, dstBr, srcpath, dstpath, dstdir, @@ -4655,7 +4819,8 @@ srcpath and dstpath will have trailing '/'s. dstdir is name of folder in dstpath (or "." or "..") to write to. names is an nlen long array of strings (the simple filenames of the files to move) - if 'cpymode' copy files, otherwise move them */ + if 'cpymode' is CM_COPY copy files, if it's CM_LINK symlink them, + otherwise move them */ int i, j, k, dothumbs, fail; char dstp[MAXPATHLEN + 1]; @@ -4690,10 +4855,12 @@ overwrite = OWRT_ASK; + cantlink = CLNK_ASK; if (nlen>1) { - if (cpymode) setBrowStr(srcBr, "Copying files..."); - else setBrowStr(srcBr, "Moving files..."); + if (cpymode == CM_COPY) setBrowStr(srcBr, "Copying files..."); + else if (cpymode == CM_LINK) setBrowStr(srcBr, "Linking files..."); + else setBrowStr(srcBr, "Moving files..."); } for (i=fail=0; ihardlink); + else j = moveFile(src,dst); if (overwrite == OWRT_CANCEL) break; /* abort move */ + if (cantlink == CLNK_CANCEL) break; /* abort move */ if (j==1) fail++; if (dothumbs && j==0) { @@ -4719,8 +4888,11 @@ /* delete destination thumbfile to avoid 'overwrite' warnings */ unlink(dst); - if (cpymode) j = copyFile(src,dst); - else j = moveFile(src,dst); + if (cpymode == CM_COPY) j = copyFile(src,dst); + else if (cpymode == CM_LINK) j = linkFile(src,dst,srcBr->hardlink); + else j = moveFile(src,dst); + + if (cantlink == CLNK_CANCEL) break; /* abort move */ } } @@ -4784,10 +4956,12 @@ if (fail) sprintf(buf, "Some files were not %s because of errors.", - cpymode ? "copied" : "moved"); + (cpymode == CM_COPY) ? "copied" + : (cpymode == CM_LINK) ? "linked" : "moved"); else if (nlen>1) sprintf(buf, "%d files %s", nlen, - (cpymode) ? "copied" : "moved"); + (cpymode == CM_COPY) ? "copied" + : (cpymode == CM_LINK) ? "linked" : "moved"); else buf[0] = '\0'; setBrowStr(srcBr, buf); @@ -4968,6 +5142,112 @@ return (copyerr>0) ? 1 : 0; } +/*************************************************/ +static int linkFile(src,dst,hard) + char *src, *dst; + int hard; +{ + /* essentially the same as the 'ln' or 'ln -s' command. src and dst are + full pathnames. It's semi-quiet about errors. a non-existant + src file is *not* considered an error (as we don't check for + thumbfiles to exist before calling this function). Returns '1' + on error, '0' if ok. Returns '-1' on 'skip this'.; + + To enhance portability, the common prefix of src and dst is stripped + and replaced by an appropriate number of "../" sequences when symlinks + are used. + + One bit of noise: if destination file exists, pop up an Overwrite? + warning box. */ + + int i, match, dstdir; + struct stat st; + char buf[512]; + char correctedsrc[MAXPATHLEN+1]; + static char *owbuts[4] = { "\nOk", "dDon't ask", "nNo", "\033Cancel" }; + static char *clbuts[3] = { "\nSymlink", "cCopy", "\033Cancel" }; + + if (DEBUG) fprintf(stderr,"linkFile %s %s\n", src, dst); + + if (stat(src, &st)) return 0; /* src doesn't exist, it would seem */ + + /* see if destination exists */ + if (stat(dst, &st)==0) { + dstdir = (stat2bf((u_int) st.st_mode) == BF_DIR); + + if (overwrite==OWRT_ASK) { + sprintf(buf, "%s '%s' exists.\n\nOverwrite?", + dstdir ? "Directory" : "File", dst); + i = PopUp(buf, owbuts, 4); + + if (i==1) overwrite = OWRT_NOASK; + else if (i==2) return -1; + else if (i==3) { overwrite = OWRT_CANCEL; return 1; } + } + + if (dstdir) { +#ifndef VMS /* we don't delete directories in VMS */ + sprintf(buf, "rm -rf %s", dst); + if (system(buf)) { /* okay, so it's cheating... */ + SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst); + return 1; + } +#endif /* VMS */ + } + else if (unlink(dst)) { + SetISTR(ISTR_WARNING, "unlink %s: %s", dst, ERRSTR(errno)); + return 1; + } + } + + + if (hard) { + if (!link(src, dst)) return 0; /* Ok */ + if (errno != EXDEV) return 1; /* failure, of some sort */ + + /* Can't link (due to cross-device linking). */ + if (cantlink==CLNK_ASK) { + sprintf(buf, "Attempt to link across directories.\n\nCopy or symlink?", + dst); + i = PopUp(buf, clbuts, 3); + + if (i==0) cantlink = CLNK_SYM; + else if (i==1) cantlink = CLNK_COPY; + else if (i==2) { cantlink = CLNK_CANCEL; return 1; } + } + + if (cantlink==CLNK_COPY) return copyFile(src, dst); + + /* fall through to do symlink (cantlink==CLNK_SYM) */ + } + + /* Fix the source directory path. */ + for (match=0; src[match]!='\0'; match++) { + if (src[match]!=dst[match]) + break; + } + while (--match>0) { + if (src[match]=='/') + break; + } + if (match==0) + strcpy(correctedsrc, src); + else { + match++; + /* match now points to the beginning of the first non-matching component */ + correctedsrc[0] = '\0'; + for (i=match; dst[i]!='\0'; i++) { + if (dst[i] == '/') + strcat(correctedsrc, "../"); + } + strcat(correctedsrc, src+match); + } + + if (!symlink(correctedsrc, dst)) return 0; /* Ok */ + + return errno != 0; +} + /* The following cp() and cp_* functions are derived from the source to 'cp' from the BSD sources */ Index: xvmisc.c =================================================================== RCS file: RCS/xvmisc.c,v retrieving revision 1.1 diff -u -r1.1 xvmisc.c --- xvmisc.c 2001/11/20 08:39:17 1.1 +++ xvmisc.c 2002/08/12 04:05:38 @@ -333,6 +333,10 @@ ev.display = theDisp; ev.window = win; ev.x = x; ev.y = y; ev.width = w; ev.height = h; + if (slideshow) { + ev.x += (dispWIDE - eWIDE) / 2; + ev.y += (dispHIGH - eHIGH) / 2; + } ev.count = 0; XSendEvent(theDisp, win, False, NoEventMask, (XEvent *) &ev); Index: xvevent.c =================================================================== RCS file: RCS/xvevent.c,v retrieving revision 1.1 diff -u -r1.1 xvevent.c --- xvevent.c 2001/11/20 08:39:17 1.1 +++ xvevent.c 2002/08/12 03:57:41 @@ -477,7 +477,8 @@ else { if (DEBUG) fprintf(stderr,"Do full redraw\n"); - Resize(cevt->width, cevt->height); + if (!slideshow) + Resize(cevt->width, cevt->height); /* eat any pending expose events and do a full redraw */ while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) { @@ -646,7 +647,12 @@ { XWindowAttributes xwa; GetWindowPos(&xwa); - xwa.width = eWIDE; xwa.height = eHIGH; + if (slideshow) { + xwa.width = dispWIDE; xwa.height = dispHIGH; + } + else { + xwa.width = eWIDE; xwa.height = eHIGH; + } /* try to keep the damned thing on-screen, if possible */ if (xwa.x + xwa.width > dispWIDE) xwa.x = dispWIDE - xwa.width; @@ -1823,8 +1829,32 @@ if (x+w < eWIDE) w++; /* add one for broken servers (?) */ if (y+h < eHIGH) h++; - if (theImage) - XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y, (u_int) w, (u_int) h); + if (theImage) { + if (slideshow) { + static int oldeWIDE = 0, oldeHIGH = 0; + int offx, offy; + offx = (dispWIDE - eWIDE) / 2; + offy = (dispHIGH - eHIGH) / 2; + if (oldeWIDE != eWIDE || oldeHIGH != eHIGH) + XClearArea(theDisp, mainW, 0, 0, dispWIDE, dispHIGH, False); + oldeWIDE = eWIDE; + oldeHIGH = eHIGH; + if (x < offx) { + w -= offx - x; + x = offx; + } + if (y < offy) { + h -= offy - y; + y = offy; + } + if (w > eWIDE) w = eWIDE; + if (h > eHIGH) h = eHIGH; + XPutImage(theDisp,mainW,theGC,theImage,x - offx,y - offy,x,y, + (u_int) w, (u_int) h); + } + else + XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y, (u_int) w, (u_int) h); + } else if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NULL\n"); } Index: xv.c =================================================================== RCS file: RCS/xv.c,v retrieving revision 1.1 diff -u -r1.1 xv.c --- xv.c 2001/11/20 08:39:17 1.1 +++ xv.c 2002/08/12 04:17:41 @@ -172,6 +172,10 @@ picComments = (char *) NULL; + if (picImageInfo) free(picImageInfo); + picImageInfo = (char *) NULL; + picImageInfoSize = 0; + numPages = 1; curPage = 0; pageBaseName[0] = '\0'; @@ -241,6 +245,7 @@ waitsec = -1; waitloop = 0; automax = 0; rootMode = 0; hsvmode = 0; rmodeset = gamset = cgamset = 0; + slideshow = 0; nopos = limit2x = 0; resetroot = 1; clearonload = 0; @@ -1394,13 +1399,15 @@ else if (!argcmp(argv[i],"-root",4,1,&useroot)); /* use root window */ + else if (!argcmp(argv[i],"-slideshow",4,1,&slideshow)); /* slide show */ + else if (!argcmp(argv[i],"-rotate",4,0,&pm)) /* rotate */ { if (++i-8 conv.*/ + else if (!argcmp(argv[i],"-slow24",4,0,&pm)) /* slow 24->-8 conv.*/ conv24 = CONV24_SLOW; else if (!argcmp(argv[i],"-smooth",3,1,&autosmooth)); /* autosmooth */ @@ -1633,6 +1640,7 @@ printoption("[-rotate deg]"); printoption("[-/+rv]"); printoption("[-/+rw]"); + printoption("[-/+slideshow]"); printoption("[-slow24]"); printoption("[-/+smooth]"); printoption("[-/+stdcmap]"); @@ -2167,6 +2175,8 @@ strcpy(formatStr, pinfo.shrtInfo); picComments = pinfo.comment; ChangeCommentText(); + picImageInfo = pinfo.imageInfo; + picImageInfoSize = pinfo.imageInfoSize; for (i=0; i<256; i++) { rMap[i] = pinfo.r[i]; @@ -3216,12 +3226,17 @@ #endif hints.x = x; hints.y = y; - hints.width = eWIDE; hints.height = eHIGH; + if (slideshow) { + hints.width = dispWIDE; hints.height = dispHIGH; + } + else { + hints.width = eWIDE; hints.height = eHIGH; + } hints.max_width = maxWIDE; hints.max_height = maxHIGH; hints.flags |= USSize | PMaxSize; xswa.bit_gravity = StaticGravity; - xswa.background_pixel = bg; + xswa.background_pixel = slideshow ? rootbg : bg; xswa.border_pixel = fg; xswa.colormap = theCmap; @@ -3241,7 +3256,9 @@ if (mainW) { GetWindowPos(&xwa); - xwa.width = eWIDE; xwa.height = eHIGH; + if (!slideshow) { + xwa.width = eWIDE; xwa.height = eHIGH; + } /* try to keep the damned thing on-screen, if possible */ if (xwa.x + xwa.width > dispWIDE) xwa.x = dispWIDE - xwa.width; @@ -3254,7 +3271,9 @@ } else { - mainW = XCreateWindow(theDisp,rootW,x,y, (u_int) eWIDE, (u_int) eHIGH, + mainW = XCreateWindow(theDisp,rootW,x,y, + slideshow ? (u_int) dispWIDE : (u_int) eWIDE, + slideshow ? (u_int) dispHIGH : (u_int) eHIGH, (u_int) bwidth, (int) dispDEEP, InputOutput, theVisual, xswamask, &xswa); if (!mainW) FatalError("can't create window!"); Index: config.h =================================================================== RCS file: RCS/config.h,v retrieving revision 1.1 diff -u -r1.1 config.h --- config.h 2001/11/20 08:39:17 1.1 +++ config.h 2002/08/11 16:29:06 @@ -13,13 +13,13 @@ * definition appropriately. (use 'which gunzip' to find if you have gunzip, * and where it lives) */ -#undef USE_GUNZIP +#define USE_GUNZIP #ifdef USE_GUNZIP # ifdef VMS # define GUNZIP "UNCOMPRESS" # else -# define GUNZIP "/usr/local/bin/gunzip -q" +# define GUNZIP "/usr/bin/gunzip -q" # endif #endif @@ -88,7 +88,7 @@ * should not need to be changed */ -/* #define GS_PATH "/usr/local/bin/gs" */ +#define GS_PATH "/usr/bin/gs" /* #define GS_LIB "." */ /* #define GS_DEV "ppmraw" */ Index: xv.h =================================================================== RCS file: RCS/xv.h,v retrieving revision 1.1 diff -u -r1.1 xv.h --- xv.h 2001/11/20 08:39:17 1.1 +++ xv.h 2002/08/11 23:32:18 @@ -8,8 +8,8 @@ #include "config.h" -#define REVDATE "Version 3.10a Rev: 12/29/94" -#define VERSTR "3.10a" +#define REVDATE "Version 3.10a.ghk Rev: 08/17/02" +#define VERSTR "3.10a.ghk" /* * uncomment the following, and modify for your site, but only if you've @@ -116,7 +116,9 @@ # include extern int errno; /* SHOULD be in errno.h, but often isn't */ # ifndef __NetBSD__ +# ifndef LINUX extern char *sys_errlist[]; /* this too... */ +# endif # endif #endif @@ -865,6 +867,8 @@ char shrtInfo[128]; /* short format info */ char *comment; /* comment text */ + byte *imageInfo; /* image info from digicam */ + int imageInfoSize; /* size of image info */ int numpages; /* # of page files, if >1 */ char pagebname[64]; /* basename of page files */ } PICINFO; @@ -959,6 +963,8 @@ WHERE char formatStr[80]; /* short-form 'file format' */ WHERE int picType; /* CONV24_8BIT,CONV24_24BIT,etc.*/ WHERE char *picComments; /* text comments on current pic */ +WHERE byte *picImageInfo; /* image info from digicam */ +WHERE int picImageInfoSize; /* size of image info */ WHERE int numPages, curPage; /* for multi-page files */ WHERE char pageBaseName[64]; /* basename for multi-page files */ @@ -1059,6 +1065,7 @@ WHERE int waitloop; /* loop at end of slide show? */ WHERE int automax; /* maximize pic on open */ WHERE int rootMode; /* mode used for -root images */ +WHERE int slideshow; /* slide show mode (full-size window) */ WHERE int nostat; /* if true, don't stat() in LdCurDir */