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; i<MAXBRWIN; i++) {
-    resizeBrowse(&binfo[i], DEF_BROWWIDE, DEF_BROWHIGH);
+    resizeBrowse(&binfo[i], DEF_BROWWIDE(br), DEF_BROWHIGH(br));
 
     XSelectInput(theDisp, binfo[i].win, ExposureMask | ButtonPressMask | 
 		 KeyPressMask | StructureNotifyMask);
@@ -544,26 +592,29 @@
     FatalError("unable to create all built-in icons for schnauzer");
 
 
-  /* create movecurs and copycurs cursors */
+  /* create movecurs, linkcurs, and copycurs cursors */
   mcpix = MakePix1(rootW, filecurs_bits,  filecurs_width,  filecurs_height);
   ccpix = MakePix1(rootW, fileccurs_bits, fileccurs_width, fileccurs_height);
+  lcpix = MakePix1(rootW, filelcurs_bits, filelcurs_width, filelcurs_height);
   dcpix = MakePix1(rootW, fdcurs_bits,    fdcurs_width,    fdcurs_height);
   fcmpix= MakePix1(rootW, filecursm_bits, filecursm_width, filecursm_height);
 
-  if (mcpix && ccpix && fcmpix && dcpix) {
+  if (mcpix && ccpix && lcpix && fcmpix && dcpix) {
     cursfg.red = cursfg.green = cursfg.blue = 0;
     cursbg.red = cursbg.green = cursbg.blue = 0xffff;
 
     movecurs = XCreatePixmapCursor(theDisp,mcpix,fcmpix,&cursfg,&cursbg,13,13);
     copycurs = XCreatePixmapCursor(theDisp,ccpix,fcmpix,&cursfg,&cursbg,13,13);
+    linkcurs = XCreatePixmapCursor(theDisp,lcpix,fcmpix,&cursfg,&cursbg,13,13);
     delcurs  = XCreatePixmapCursor(theDisp,dcpix,fcmpix,&cursbg,&cursfg,13,13);
-    if (!movecurs || !copycurs || !delcurs) 
+    if (!movecurs || !copycurs || !linkcurs || !delcurs) 
       FatalError("unable to create schnauzer cursors...");
   }
   else FatalError("unable to create schnauzer cursors...");
 
   XFreePixmap(theDisp, mcpix);
   XFreePixmap(theDisp, ccpix);
+  XFreePixmap(theDisp, lcpix);
   XFreePixmap(theDisp, dcpix);
   XFreePixmap(theDisp, fcmpix);
     
@@ -882,9 +933,25 @@
   if (br->wide == 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 <BF_MAX) {  /* built-in icon */
     XCopyPlane(theDisp, bfIcons[bf->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; i<MAXBRWIN; i++) 
-		  XDefineCursor(theDisp,binfo[i].iconW, curs);
+	      curs = (cmod == CM_LINK) ? linkcurs
+		     : (cmod == CM_COPY) ? copycurs : movecurs;
+	      for (i=0; i<MAXBRWIN; i++) 
+		XDefineCursor(theDisp,binfo[i].iconW, curs);
 	    }
 	    cpymode = cmod;
 	    
@@ -1807,7 +1891,8 @@
 	    
 	    if (dodel && i==MAXBRWIN) {        /* moved out */
 	      dodel = 0;
-	      curs = (cpymode) ? copycurs : movecurs;
+	      curs = (cpymode == CM_LINK) ? linkcurs
+		     : (cpymode == CM_COPY) ? copycurs : movecurs;
 	      for (i=0; i<MAXBRWIN; i++) 
 		XDefineCursor(theDisp,binfo[i].iconW, curs);
 	    }
@@ -1916,7 +2001,7 @@
 	      RANGE(y, 0, br->iwHigh-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; i<br->bfLen; 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 && sel<br->bfLen) {
       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<MAXBRWIN; i++) {
+    if (binfo[i].isizeWide > 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; i<nlen; i++) {
@@ -4706,10 +4873,12 @@
     sprintf(src,"%s%s", srcpath, names[i]);
     sprintf(dst,"%s%s", dstp,    names[i]);
 
-    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 (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<argc) autorotate = atoi(argv[i]); }
     
     else if (!argcmp(argv[i],"-rv",3,1,&revvideo));   /* reverse video */
     else if (!argcmp(argv[i],"-rw",3,1,&rwcolor));    /* use r/w color */
 
-    else if (!argcmp(argv[i],"-slow24",3,0,&pm))      /* slow 24->-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 <errno.h>
    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 */
 

