diff :  xv-3.10a-jumbo-enh-patch-20050410.txt

This is a unified diff.  It should be applied (using Larry Wall's "patch"
program) to the XV 3.10a sources AFTER the jumbo-fixes patch has already
been applied.

diffs below:
   Imakefile
   Makefile
   Makefile.std
   README.pcd
   bits/br_bzip2
   bits/br_pcd
   bits/br_png
   bits/br_zx
   config.h
   xv.c
   xv.h
   xvbmp.c
   xvbrowse.c
   xvctrl.c
   xvdial.c
   xvdir.c
   xvevent.c
   xvgam.c
   xvgif.c
   xvimage.c
   xvjpeg.c
   xvmisc.c
   xvpbm.c
   xvpcd.c
   xvpng.c
   xvpopup.c
   xvps.c
   xvrle.c
   xvroot.c
   xvsmooth.c
   xvtext.c
   xvtiff.c
   xvwbmp.c
   xvzx.c


diff -ruN xv-3.10a-bugfixes/Imakefile xv-3.10a-enhancements/Imakefile
--- xv-3.10a-bugfixes/Imakefile	1995-01-13 12:24:01.000000000 -0800
+++ xv-3.10a-enhancements/Imakefile	2004-05-09 19:48:14.000000000 -0700
@@ -157,7 +157,7 @@
 	xvdial.c xvgraf.c xvsunras.c xvjpeg.c xvps.c xvpopup.c xvdflt.c \
 	xvtiff.c xvtiffwr.c xvpds.c xvrle.c xviris.c xvgrab.c vprintf.c \
 	xvbrowse.c xvtext.c xvpcx.c xviff.c xvtarga.c xvxpm.c xvcut.c \
-	xvxwd.c xvfits.c
+	xvxwd.c xvfits.c xvpng.c xvzx.c xvwbmp.c xvpcd.c
 
 OBJS1 =	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -165,7 +165,7 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o
 
 SRCS2=	bggen.c
 OBJS2=	bggen.o
diff -ruN xv-3.10a-bugfixes/Makefile xv-3.10a-enhancements/Makefile
--- xv-3.10a-bugfixes/Makefile	2005-04-06 08:17:13.000000000 -0700
+++ xv-3.10a-enhancements/Makefile	2005-04-06 08:23:51.000000000 -0700
@@ -59,13 +59,59 @@
 ### on your machine, *COMMENT OUT* the following lines
 ###
 JPEG    = -DDOJPEG
-JPEGDIR = jpeg
-JPEGINC = -I$(JPEGDIR)
-JPEGLIB = $(JPEGDIR)/libjpeg.a
-$(JPEGDIR)/jconfig.h:
-	cd $(JPEGDIR) ; ./configure CC='$(CC)'
-$(JPEGLIB):  $(JPEGDIR)/jconfig.h
-	cd $(JPEGDIR) ; make
+#JPEGDIR = jpeg
+JPEGDIR = /usr
+#JPEGDIR = /usr/local
+#JPEGDIR = ../../libjpeg
+###
+JPEGINC = -I$(JPEGDIR)/include
+#JPEGINC = -I$(JPEGDIR)
+###
+JPEGLIB = -L$(JPEGDIR)/lib -ljpeg
+#JPEGLIB = -L$(JPEGDIR) -ljpeg
+#JPEGLIB = $(JPEGDIR)/libjpeg.a
+###
+### this is intended to build the ancient version (5a) that's included in the
+### "jpeg" subdir of XV, not an arbitrary copy of libjpeg:
+###
+#$(JPEGDIR)/jconfig.h:
+#	cd $(JPEGDIR) ; ./configure CC='$(CC)'
+#$(JPEGLIB):  $(JPEGDIR)/jconfig.h
+#	cd $(JPEGDIR) ; make
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr
+#PNGDIR = /usr/local
+#PNGDIR = ../../libpng
+###
+PNGINC = -I$(PNGDIR)/include
+#PNGINC = -I$(PNGDIR)
+###
+PNGLIB = -L$(PNGDIR)/lib -lpng
+#PNGLIB = -L$(PNGDIR) -lpng
+#PNGLIB = $(PNGDIR)/libpng.a
+
+
+###
+### if, for whatever reason, you're unable to get both the PNG library and
+### (newer versions of) the TIFF library to compile on your machine, *COMMENT
+### OUT* the following lines
+###
+ZLIBDIR = /usr
+#ZLIBDIR = /usr/local
+#ZLIBDIR = ../../zlib
+###
+ZLIBINC = -I$(ZLIBDIR)/include
+#ZLIBINC = -I$(ZLIBDIR)
+###
+ZLIBLIB = -L$(ZLIBDIR)/lib -lz
+#ZLIBLIB = -L$(ZLIBDIR) -lz
+#ZLIBLIB = $(ZLIBDIR)/libz.a
 
 
 ###
@@ -80,17 +126,32 @@
 ###
 #TIFF    = -DDOTIFF
 TIFF    = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX
-TIFFDIR = tiff
-TIFFINC = -I$(TIFFDIR)
-TIFFLIB = $(TIFFDIR)/libtiff.a
-$(TIFFLIB):
-	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
+#TIFFDIR = tiff
+TIFFDIR = /usr
+#TIFFDIR = /usr/local
+#TIFFDIR = ../../libtiff
+###
+TIFFINC = -I$(TIFFDIR)/include
+#TIFFINC = -I$(TIFFDIR)
+###
+### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency
+### is properly handled in LIBS line ~143 lines below
+###
+TIFFLIB = -L$(TIFFDIR)/lib -ltiff
+#TIFFLIB = -L$(TIFFDIR) -ltiff
+#TIFFLIB = $(TIFFDIR)/libtiff.a
+###
+### this is intended to build the ancient version (3.3.016 beta) that's included
+### in the "tiff" subdir of XV, not an arbitrary copy of libtiff:
+###
+#$(TIFFLIB):
+#	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
 
 
 ###
 ### if, for whatever reason, you're unable to get the PDS/VICAR support
 ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line,
-### and also remove 'vdcomp' from the 'all:' dependancy
+### and also remove 'vdcomp' from the 'all:' dependency
 ###
 PDS = -DDOPDS
 
@@ -212,13 +273,13 @@
 
 
 
-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
-	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \
+	$(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \
+	$(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN)
 
 ### remove -lm for BeOS:
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB)
+LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm
+#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -226,7 +287,7 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -236,10 +297,12 @@
 
 
 
-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+all: xv bggen vdcomp xcmap xvpictoppm
 
 
-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+xv: $(OBJS)
 	$(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS)
 
 bggen: bggen.c
@@ -299,7 +362,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:	bits/br_xwd
+xvbrowse.o:	bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -ruN xv-3.10a-bugfixes/Makefile.std xv-3.10a-enhancements/Makefile.std
--- xv-3.10a-bugfixes/Makefile.std	2005-04-06 08:17:13.000000000 -0700
+++ xv-3.10a-enhancements/Makefile.std	2005-04-06 08:23:51.000000000 -0700
@@ -59,13 +59,59 @@
 ### on your machine, *COMMENT OUT* the following lines
 ###
 JPEG    = -DDOJPEG
-JPEGDIR = jpeg
-JPEGINC = -I$(JPEGDIR)
-JPEGLIB = $(JPEGDIR)/libjpeg.a
-$(JPEGDIR)/jconfig.h:
-	cd $(JPEGDIR) ; ./configure CC='$(CC)'
-$(JPEGLIB):  $(JPEGDIR)/jconfig.h
-	cd $(JPEGDIR) ; make
+#JPEGDIR = jpeg
+JPEGDIR = /usr
+#JPEGDIR = /usr/local
+#JPEGDIR = ../../libjpeg
+###
+JPEGINC = -I$(JPEGDIR)/include
+#JPEGINC = -I$(JPEGDIR)
+###
+JPEGLIB = -L$(JPEGDIR)/lib -ljpeg
+#JPEGLIB = -L$(JPEGDIR) -ljpeg
+#JPEGLIB = $(JPEGDIR)/libjpeg.a
+###
+### this is intended to build the ancient version (5a) that's included in the
+### "jpeg" subdir of XV, not an arbitrary copy of libjpeg:
+###
+#$(JPEGDIR)/jconfig.h:
+#	cd $(JPEGDIR) ; ./configure CC='$(CC)'
+#$(JPEGLIB):  $(JPEGDIR)/jconfig.h
+#	cd $(JPEGDIR) ; make
+
+
+###
+### if, for whatever reason, you're unable to get the PNG library to compile
+### on your machine, *COMMENT OUT* the following lines
+###
+PNG    = -DDOPNG
+PNGDIR = /usr
+#PNGDIR = /usr/local
+#PNGDIR = ../../libpng
+###
+PNGINC = -I$(PNGDIR)/include
+#PNGINC = -I$(PNGDIR)
+###
+PNGLIB = -L$(PNGDIR)/lib -lpng
+#PNGLIB = -L$(PNGDIR) -lpng
+#PNGLIB = $(PNGDIR)/libpng.a
+
+
+###
+### if, for whatever reason, you're unable to get both the PNG library and
+### (newer versions of) the TIFF library to compile on your machine, *COMMENT
+### OUT* the following lines
+###
+ZLIBDIR = /usr
+#ZLIBDIR = /usr/local
+#ZLIBDIR = ../../zlib
+###
+ZLIBINC = -I$(ZLIBDIR)/include
+#ZLIBINC = -I$(ZLIBDIR)
+###
+ZLIBLIB = -L$(ZLIBDIR)/lib -lz
+#ZLIBLIB = -L$(ZLIBDIR) -lz
+#ZLIBLIB = $(ZLIBDIR)/libz.a
 
 
 ###
@@ -80,17 +126,32 @@
 ###
 #TIFF    = -DDOTIFF
 TIFF    = -DDOTIFF -DUSE_TILED_TIFF_BOTLEFT_FIX
-TIFFDIR = tiff
-TIFFINC = -I$(TIFFDIR)
-TIFFLIB = $(TIFFDIR)/libtiff.a
-$(TIFFLIB):
-	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
+#TIFFDIR = tiff
+TIFFDIR = /usr
+#TIFFDIR = /usr/local
+#TIFFDIR = ../../libtiff
+###
+TIFFINC = -I$(TIFFDIR)/include
+#TIFFINC = -I$(TIFFDIR)
+###
+### libtiff 3.5 and up may be compiled with zlib and libjpeg, but dependency
+### is properly handled in LIBS line ~143 lines below
+###
+TIFFLIB = -L$(TIFFDIR)/lib -ltiff
+#TIFFLIB = -L$(TIFFDIR) -ltiff
+#TIFFLIB = $(TIFFDIR)/libtiff.a
+###
+### this is intended to build the ancient version (3.3.016 beta) that's included
+### in the "tiff" subdir of XV, not an arbitrary copy of libtiff:
+###
+#$(TIFFLIB):
+#	( cd $(TIFFDIR) ; make CC='$(CC)' COPTS='$(CCOPTS) $(MCHN)' )
 
 
 ###
 ### if, for whatever reason, you're unable to get the PDS/VICAR support
 ### to compile (xvpds.c, and vdcomp.c), *COMMENT OUT* the following line,
-### and also remove 'vdcomp' from the 'all:' dependancy
+### and also remove 'vdcomp' from the 'all:' dependency
 ###
 PDS = -DDOPDS
 
@@ -212,13 +273,13 @@
 
 
 
-CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
-	$(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
-	$(DXWM) $(MCHN)
+CFLAGS = $(CCOPTS) $(PNG) $(PNGINC) $(ZLIBINC) $(JPEG) $(JPEGINC) \
+	$(TIFF) $(TIFFINC) $(PDS) $(NODIRENT) $(VPRINTF) $(TIMERS) \
+	$(UNIX) $(BSDTYPES) $(RAND) $(DXWM) $(MCHN)
 
 ### remove -lm for BeOS:
-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
-#LIBS = -lX11 $(JPEGLIB) $(TIFFLIB)
+LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -L/usr/X11R6/lib -lX11 -lm
+#LIBS = $(TIFFLIB) $(JPEGLIB) $(PNGLIB) $(ZLIBLIB) -lX11
 
 OBJS = 	xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \
 	xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \
@@ -226,7 +287,7 @@
 	xvdial.o xvgraf.o xvsunras.o xvjpeg.o xvps.o xvpopup.o xvdflt.o \
 	xvtiff.o xvtiffwr.o xvpds.o xvrle.o xviris.o xvgrab.o vprintf.o \
 	xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \
-	xvxwd.o xvfits.o
+	xvxwd.o xvfits.o xvpng.o xvzx.o xvwbmp.o xvpcd.o
 
 MISC = README INSTALL CHANGELOG IDEAS
 
@@ -236,10 +297,12 @@
 
 
 
-all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+#all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
+all: xv bggen vdcomp xcmap xvpictoppm
 
 
-xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+#xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
+xv: $(OBJS)
 	$(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS)
 
 bggen: bggen.c
@@ -299,7 +362,7 @@
 xvbrowse.o:	bits/br_pcx bits/br_jfif bits/br_tiff bits/br_pds
 xvbrowse.o:	bits/br_ps bits/br_iff bits/br_targa bits/br_xpm
 xvbrowse.o:	bits/br_trash bits/fcurs bits/fccurs bits/fdcurs bits/fcursm
-xvbrowse.o:	bits/br_xwd
+xvbrowse.o:	bits/br_xwd bits/br_png bits/br_zx bits/br_pcd bits/br_bzip2
 
 xvbutt.o:	bits/cboard50 bits/rb_frame bits/rb_frame1 bits/rb_top
 xvbutt.o:	bits/rb_bot bits/rb_dtop bits/rb_dbot bits/rb_body
diff -ruN xv-3.10a-bugfixes/README.pcd xv-3.10a-enhancements/README.pcd
--- xv-3.10a-bugfixes/README.pcd	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/README.pcd	2001-07-08 11:21:19.000000000 -0700
@@ -0,0 +1,159 @@
+Copyright 1993-2001 David Clunie.
+
+PCD patch for XV 3.10a Release Notes 2001/07/08.
+
+See also the progress notes at the end of this file. Thanks to all those
+contributors who have substantially improved this patch.
+
+These patches allow xv to read Kodak photocd files and choose which of the
+5 available resolutions one wants to view.
+
+When a photocd file is loaded, a dialog box asks which resolution you
+would like. The visual schnauzer builds thumbnails by reading the lowest
+resolution image. The selected resolution can be selected from the
+command line with the -pcd option:
+
+	[-pcd 0|1|2|3|4]
+
+where:
+
+	0=192*128,	base/16 resolution
+	1=384*256,	base/4 resolution
+	2=768*512,	base resolution
+	3=1536*1024,	4base resolution
+	4=3072*2048	16base resolution.
+
+Note that the Pro format is not supported.
+
+The command line option allows loops without the dialog box popping up, eg.:
+
+	xv -pcd 1 -wloop -wait 10 *.pcd
+
+The code is pretty crude and was written quickly for a specific purpose and
+has not really been cleaned up. It is poorly structured, full of debugging
+codes and verbose comments, and there is very little attempt at optimizing
+things. No profiling has been done.
+
+There is not yet support for overview files, nor is there a facility to
+use the higher resolution chroma planes from when viewing lower resolution
+images.
+
+It's only claim to fame is that it works and produces reasonable looking
+images.
+
+The outline of this is shamelessly derived from xvpbm.c to read the
+file, and xvtiffwr.c to handle the popup window and X stuff (X never
+has been my forte !), and the PhotoCD format information (though not
+the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
+program in which he has reverse engineered the format by studying
+hex dumps of PhotoCDs ! The color stuff and Huffman decding were
+extensively revised by Matthew Francey.
+
+Feel free to send me comments or improvements, or even better, more
+information about the photo CD format ... hopefully someone who really
+knows what they are doing will tidy it up or do a neater job.
+
+david (dclunie@dclunie.com)
+
+---------
+
+The trace #define in xvpcd.c is now in the right place, and the ansi
+prototype for the magnify function has been fixed. Colin made me switch to
+xvbcopy() which seems like a good idea for System V victims.
+
+---------
+
+Date: Wed, 22 Dec 1993 16:09:52 --1000
+From: colinc@fitmail.fit.qut.edu.au (Colin Canfield )
+
+I have done some more work using your patch I thought you might be intested in.
+The major change was adding a size parameter to the LoadPCD; either -1 to mean
+the popup or else the size you desired. This allows batch mode processing,
+specifically xv -pcd <size> <filename>, and the visual schnauzer can work in 
+quick mode (ie. you don't have to select each image size when it is building 
+the icons)
+
+I have added an xbm file for the file type but haven't drawn an icon for it,
+this is in bitmaps/br_pcd.xbm. I will just send you the new files.
+
+---------
+
+From: andrew@andrew.triumf.ca (Andrew Daviel)
+Date: 16 Feb 1995 23:32:21 GMT
+
+This is David Clunie's patch for xv-3.00 tuned a bit to work
+on xv-3.10. The code's all the same except for replacing 
+"trace" with "fprintf" in xvpcd.c and adding an "unsigned" qualifier to 
+keep my compiler (gcc) happy. Oh yes, changed RFT_PCD to 20 as
+John Bradley has now used 15 through 19.
+
+---------
+
+From: dclunie@flash.us.com (David A. Clunie)
+Date: Thu Jun 15 14:43:46 GMT+0300 1995
+
+Andrew's patch didn't include Colin's browser changes, so I redid the
+xv-3.10 update from scratch ... it seems pretty much the same as
+Andrew's changes. I also edited the Imakefile and Makefiles in order
+to support the PCD changes, as well as make the install process a
+little more flexible, with options to strip and set modes and so on.
+Also made RFT_PCD 25 so as not to conflict with magpic patch from Japan
+by Ikemoto Masahiro <ikeyan@airlab.cs.ritsumei.ac.jp>, and used his
+bitmap icon for pcd files.
+
+Now there are two versions of the patch, one which should be applied
+to the xv-3.10 distribution.
+
+The other should be applied to xv-3.10 AFTER Ikemoto Masahiro's 
+Patch.magpic2.PhotoCD.XV319a, in order to add the browser features to
+the latter, as well as fixing a Makefile typo (was xcpcd.c not xvpcd.c)
+and including unistd.h for the SEEK_xxx constants in the magicpic
+stuff.
+
+---------
+
+Subject: Re: photo-cd patch for xv 
+From: Matthew Francey <mdf@angoss.com>
+Date: Mon, 26 Mar 2001 15:37:55 +0000
+
+Attached is a revised version of xvpcd.c;  the areas that I have
+re-written or changed are in a different coding style so you can tell
+what has changed.  The GNU 'indent' program can be run against the file
+to enforce a consistent style ..
+
+Here is what I've done though:
+
+a) huffman table reader re-written, because it would fail on some
+   photocd files with "unusual" huffman codes.
+
+b) the huffman-coded corrections are now properly applied
+
+c) the corrections can sometimes over or underflow;  clipping has been
+   introduced and effectively fixes the problem, but I suspect that
+   there is something deeper going on.
+
+d) the "official" YCC->sRGB transform is done.  a "beyond 100% white"
+   mapping table was snarfed from ImageMagick.  an option for using a
+   flat linear LUT was added -- this can make somewhat over-exposed images
+   look alot nicer.
+
+e) there were strange problems where the code wouldn't be able to find
+   the huffman tables and data for the 16base image (the bit-buffering
+   code was starting mid-sector, instead of at a sector boundary).  Looking
+   at a pcd file with a hex editor suggests to me that it is possible to
+   just skip directly to these huffman tables -- no special "+12" and such
+   constants necessary.  But I haven't tried this yet.
+
+The results:  I've been able to read about 50 or 60 .pcd files [scattered
+in age from 6 years old to scans done last week] with this code without
+incident.  Image quality at the high resolution is excellent.  Even the
+trivial amount of LUT control is useful when dealing with over-exposed
+images.
+
+If I get around to it:  finer LUT control to take advantage of the
+slightly extended dynamic range of PhotoCD scans, especially in regards to
+dark or somewhat underexposed scenes.
+
+
+
+
diff -ruN xv-3.10a-bugfixes/bits/br_bzip2 xv-3.10a-enhancements/bits/br_bzip2
--- xv-3.10a-bugfixes/bits/br_bzip2	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_bzip2	1998-04-12 19:23:39.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_bzip2_width 48
+#define br_bzip2_height 48
+static unsigned char br_bzip2_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x7c, 0xbe, 0x3d, 0x0e, 0x02, 0x20, 0xfc, 0xbe, 0x7d, 0x1f, 0x02,
+   0x20, 0xcc, 0xb0, 0x6d, 0x1b, 0x02, 0x20, 0xcc, 0x98, 0x6d, 0x1b, 0x02,
+   0x20, 0xfc, 0x98, 0x6d, 0x18, 0x02, 0x20, 0x7c, 0x8c, 0x7d, 0x0c, 0x02,
+   0x20, 0xcc, 0x8c, 0x3d, 0x0e, 0x02, 0x20, 0xcc, 0x84, 0x0d, 0x06, 0x02,
+   0x20, 0xcc, 0x86, 0x0d, 0x03, 0x02, 0x20, 0xfc, 0xbe, 0x0d, 0x1f, 0x02,
+   0x20, 0x7c, 0xbe, 0x0d, 0x1f, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_pcd xv-3.10a-enhancements/bits/br_pcd
--- xv-3.10a-bugfixes/bits/br_pcd	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_pcd	1995-06-15 21:31:53.000000000 -0700
@@ -0,0 +1,27 @@
+#define br_pcd_width 48
+#define br_pcd_height 48
+static unsigned char br_pcd_bits[] = {
+   0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+   0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x67, 0x00, 0xe0, 0x1c, 0x02,
+   0x20, 0x6f, 0x00, 0xf0, 0x3d, 0x02, 0x20, 0x6b, 0x00, 0xb0, 0x2d, 0x02,
+   0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02, 0x20, 0x6b, 0x00, 0x33, 0x2c, 0x02,
+   0x20, 0xeb, 0x98, 0x37, 0x2c, 0x02, 0x20, 0xef, 0xbd, 0x37, 0x2c, 0x02,
+   0x20, 0x67, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02,
+   0x20, 0x63, 0x2d, 0x33, 0x2c, 0x02, 0x20, 0x63, 0x2d, 0xb3, 0x2d, 0x02,
+   0x20, 0x63, 0x3d, 0xf7, 0x3d, 0x02, 0x20, 0x63, 0x19, 0xe6, 0x1c, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+   0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03};
diff -ruN xv-3.10a-bugfixes/bits/br_png xv-3.10a-enhancements/bits/br_png
--- xv-3.10a-bugfixes/bits/br_png	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_png	1996-06-13 14:32:08.000000000 -0700
@@ -0,0 +1,28 @@
+#define br_png_width 48
+#define br_png_height 48
+static unsigned char br_png_bits[] = {
+  0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0xf8, 0x19, 0xc3, 0x07, 0x02, 0x20, 0x18, 0x3b, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x3b, 0x33, 0x00, 0x02, 0x20, 0x18, 0x5b, 0x33, 0x00, 0x02,
+  0x20, 0xf8, 0x59, 0x33, 0x0f, 0x02, 0x20, 0x18, 0x98, 0x33, 0x0c, 0x02,
+  0x20, 0x18, 0x98, 0x33, 0x0c, 0x02, 0x20, 0x18, 0x18, 0x63, 0x0c, 0x02,
+  0x20, 0x18, 0x18, 0xc3, 0x0b, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  };
diff -ruN xv-3.10a-bugfixes/bits/br_zx xv-3.10a-enhancements/bits/br_zx
--- xv-3.10a-bugfixes/bits/br_zx	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/bits/br_zx	1998-08-06 13:00:03.000000000 -0700
@@ -0,0 +1,28 @@
+#define br_zx_width 48
+#define br_zx_height 48
+static unsigned char br_zx_bits[] = {
+  0xe0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x20, 0x00, 0x00, 0x00, 0x81, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0xff, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0xff, 0xff, 0xff, 0x7f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x61, 0x84, 0x00, 0x11, 0x02,
+  0x20, 0x30, 0x48, 0x00, 0x10, 0x02, 0x20, 0x18, 0x38, 0x10, 0x08, 0x02,
+  0x20, 0x0c, 0x30, 0x10, 0x0e, 0x02, 0x20, 0x06, 0x68, 0x7c, 0x10, 0x02,
+  0x20, 0x03, 0x48, 0x10, 0x10, 0x02, 0x20, 0x41, 0x84, 0x10, 0x11, 0x02,
+  0x20, 0x7f, 0xce, 0x01, 0x0e, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xff, 0xff, 0xff, 0xff, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x40, 0x02, 0x20, 0xff, 0xff, 0xff, 0x3f, 0x02,
+  0x20, 0x00, 0x00, 0x00, 0x10, 0x02, 0x20, 0x00, 0x00, 0x00, 0x08, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0x84, 0x03, 0x20, 0x00, 0x00, 0x00, 0xc2, 0x03,
+  0x20, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x20, 0x00, 0x00, 0x80, 0xf0, 0x02,
+  0x20, 0x00, 0x00, 0x40, 0x78, 0x02, 0x20, 0x00, 0x00, 0x20, 0x3c, 0x02,
+  0x20, 0x00, 0x00, 0x10, 0x1e, 0x02, 0x20, 0x00, 0x00, 0x08, 0x0f, 0x03,
+  0x20, 0x00, 0x00, 0x84, 0x87, 0x03, 0x20, 0x00, 0x00, 0xc2, 0xc3, 0x03,
+  0x20, 0x00, 0x00, 0xe1, 0xe1, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  };
diff -ruN xv-3.10a-bugfixes/config.h xv-3.10a-enhancements/config.h
--- xv-3.10a-bugfixes/config.h	2005-03-21 23:21:31.000000000 -0800
+++ xv-3.10a-enhancements/config.h	2005-03-21 23:21:10.000000000 -0800
@@ -6,14 +6,15 @@
 /***************************************************************************
  * GZIP'd file support
  *
- * if you have the gnu uncompression utility 'gunzip', XV can use it to
- * automatically 'unzip' any gzip'd files.  To enable this feature,
- * change 'undef' to 'define' in the following line.  Needless to say, if
- * your gunzip is installed elsewhere on your machine, change the 'GUNZIP'
- * definition appropriately. (use 'which gunzip' to find if you have gunzip,
- * and where it lives)
+ * if you have the GNU uncompression utility 'gunzip' (or 'gzip' itself,
+ * which is just a link to gunzip), XV can use it to automatically 'unzip'
+ * any gzip'd files.  To enable this feature, change 'undef' to 'define' in
+ * the following line.  Needless to say, if your gunzip is installed elsewhere
+ * on your machine, change the 'GUNZIP' definition appropriately. (use
+ * 'which gunzip' to find if you have gunzip, and where it lives; ditto for
+ * gzip)
  */
-#undef USE_GUNZIP
+#define USE_GUNZIP
 
 #ifdef USE_GUNZIP
 #  ifdef VMS
@@ -26,6 +27,22 @@
 
 
 /***************************************************************************
+ * BZIP2'd file support
+ *
+ * if you have the uncompression utility 'bunzip2' (or 'bzip2' itself, which
+ * is just a link to bunzip2), XV can use it to automatically 'unzip' any
+ * bzip2'd files.  To enable this feature, change 'undef' to 'define' in the
+ * following line (if not already done).  Use 'which bunzip2' or 'which bzip2'
+ * to find if you have bzip2/bunzip2, and where it lives.
+ */
+#define USE_BUNZIP2
+
+#ifdef USE_BUNZIP2
+#  define BUNZIP2 "bunzip2"			/* "bzip2 -d" also OK */
+#endif
+
+
+/***************************************************************************
  * compress'd file support
  *
  * if you have GUNZIP defined above, just ignore this, as 'gunzip' can
@@ -90,6 +107,7 @@
  */
 
 /* #define GS_PATH "/usr/local/bin/gs" */
+#define GS_PATH "/usr/bin/gs"
 /* #define GS_LIB  "."                 */
 /* #define GS_DEV  "ppmraw"            */
 
diff -ruN xv-3.10a-bugfixes/xv.c xv-3.10a-enhancements/xv.c
--- xv-3.10a-bugfixes/xv.c	2005-03-20 22:25:22.000000000 -0800
+++ xv-3.10a-enhancements/xv.c	2005-04-08 08:03:56.000000000 -0700
@@ -78,6 +78,10 @@
 
 static int    force8     = 0;   /* force 8-bit mode */
 static int    force24    = 0;   /* force 24-bit mode */
+static int    PcdSize    = -1;  /* force dialog to ask */
+
+static float  waitsec_nonfinal = -1;  /* "normal" waitsec value */
+static float  waitsec_final = -1;     /* final-image waitsec value */
 
 /* used in DeleteCmd() and Quit() */
 static char  **mainargv;
@@ -120,7 +124,7 @@
 int   imap, ctrlmap, gmap, browmap, cmtmap, clrroot, nopos, limit2x;
 char *display, *whitestr, *blackstr, *histr, *lostr,
      *infogeom, *fgstr, *bgstr, *ctrlgeom, *gamgeom, *browgeom, *tmpstr;
-char *rootfgstr, *rootbgstr, *visualstr, *textgeom, *cmtgeom;
+char *rootfgstr, *rootbgstr, *imagebgstr, *visualstr, *textgeom, *cmtgeom;
 char *monofontname, *flistName;
 int  curstype, stdinflag, browseMode, savenorm, preview, pscomp, preset,
      rmodeset, gamset, cgamset, perfect, owncmap, rwcolor, stdcmap;
@@ -162,7 +166,7 @@
 
   /* init internal variables */
   display = NULL;
-  fgstr = bgstr = rootfgstr = rootbgstr = NULL;
+  fgstr = bgstr = rootfgstr = rootbgstr = imagebgstr = NULL;
   histr = lostr = whitestr = blackstr = NULL;
   visualstr = monofontname = flistName = NULL;
   winTitle = NULL;
@@ -238,7 +242,7 @@
   ninstall = 0;  fixedaspect = 0;  noFreeCols = nodecor = 0;
   DEBUG = 0;  bwidth = 2;
   nolimits = useroot = clrroot = noqcheck = 0;
-  waitsec = -1;  waitloop = 0;  automax = 0;
+  waitsec = waitsec_final = -1.0;  waitloop = 0;  automax = 0;
   rootMode = 0;  hsvmode = 0;
   rmodeset = gamset = cgamset = 0;
   nopos = limit2x = 0;
@@ -251,6 +255,10 @@
   preset = 0;
   viewonly = 0;
 
+#ifdef ENABLE_FIXPIX_SMOOTH
+  do_fixpix_smooth = 0;
+#endif
+
   /* init 'xormasks' array */
   xorMasks[0] = 0x01010101;
   xorMasks[1] = 0x02020203;
@@ -277,6 +285,12 @@
   tiffW = (Window) NULL;  tiffUp = 0;
 #endif
 
+#ifdef HAVE_PNG
+  pngW = (Window) NULL;  pngUp = 0;
+#endif
+
+  pcdW = (Window) NULL;  pcdUp = 0;
+
   imap = ctrlmap = gmap = browmap = cmtmap = 0;
 
   ch_offx = ch_offy = p_offx = p_offy = 0;
@@ -309,7 +323,11 @@
 
   theScreen = DefaultScreen(theDisp);
   theCmap   = DefaultColormap(theDisp, theScreen);
-  rootW     = RootWindow(theDisp,theScreen);
+  if (spec_window) {
+	rootW = spec_window;
+  } else {
+  	rootW = RootWindow(theDisp,theScreen);
+  }
   theGC     = DefaultGC(theDisp,theScreen);
   theVisual = DefaultVisual(theDisp,theScreen);
   ncells    = DisplayCells(theDisp, theScreen);
@@ -320,7 +338,7 @@
 
   rootDEEP = dispDEEP;
 
-  /* things dependant on theVisual:
+  /* things dependent on theVisual:
    *    dispDEEP, theScreen, rootW, ncells, theCmap, theGC,
    *    vrWIDE, dispWIDE, vrHIGH, dispHIGH, maxWIDE, maxHIGH
    */
@@ -575,6 +593,18 @@
       xvAllocColor(theDisp, theCmap, &ecdef))  rootbg = ecdef.pixel;
 
 
+  /* GRR 19980308:  set up image bg color (for transparent images) */
+  have_imagebg = 0;
+  if (imagebgstr && XParseColor(theDisp, theCmap, imagebgstr, &ecdef) &&
+      xvAllocColor(theDisp, theCmap, &ecdef)) {
+    /* imagebg = ecdef.pixel; */
+    have_imagebg = 1;
+    imagebgR = ecdef.red;
+    imagebgG = ecdef.green;
+    imagebgB = ecdef.blue;
+  }
+
+
   /* set up hi/lo colors */
   i=0;
   if (dispDEEP > 1) {   /* only if we're on a reasonable display */
@@ -796,6 +826,14 @@
   XSetTransientForHint(theDisp, tiffW, dirW);
 #endif
 
+#ifdef HAVE_PNG
+  CreatePNGW();
+  XSetTransientForHint(theDisp, pngW, dirW);
+#endif
+
+  CreatePCDW();
+  XSetTransientForHint(theDisp, pcdW, dirW);
+
 
   LoadFishCursors();
   SetCursors(-1);
@@ -964,7 +1002,11 @@
 
   dispDEEP  = vinfo[best].depth;
   theScreen = vinfo[best].screen;
-  rootW     = RootWindow(theDisp, theScreen);
+  if (spec_window) {
+	rootW = spec_window;
+  } else {
+  	rootW = RootWindow(theDisp,theScreen);
+  }
   ncells    = vinfo[best].colormap_size;
   theCmap   = XCreateColormap(theDisp, rootW, theVisual, AllocNone);
 
@@ -1095,6 +1137,9 @@
 
   if (rd_str ("fileList"))       flistName   = def_str;
   if (rd_flag("fixed"))          fixedaspect = def_int;
+#ifdef ENABLE_FIXPIX_SMOOTH
+  if (rd_flag("fixpix"))         do_fixpix_smooth = def_int;
+#endif
   if (rd_flag("force8"))         force8      = def_int;
   if (rd_flag("force24"))        force24     = def_int;
   if (rd_str ("foreground"))     fgstr       = def_str;
@@ -1106,6 +1151,7 @@
   if (rd_str ("highlight"))      histr       = def_str;
   if (rd_str ("iconGeometry"))   icongeom    = def_str;
   if (rd_flag("iconic"))         startIconic = def_int;
+  if (rd_str ("imageBackground")) imagebgstr = def_str;
   if (rd_str ("infoGeometry"))   infogeom    = def_str;
   if (rd_flag("infoMap"))        imap        = def_int;
   if (rd_flag("loadBrowse"))     browseMode  = def_int;
@@ -1198,6 +1244,14 @@
       }
     }
 
+    else if (!argcmp(argv[i],"-windowid",3,0,&pm)) {
+      if (++i<argc) {
+	if (sscanf(argv[i], "%ld", &spec_window) != 1) {
+		fprintf(stderr,"%s: bad argument to -windowid '%s'\n",cmd,argv[i]);
+        }
+      }
+    }
+
     else if (!argcmp(argv[i],"-best24",3,0,&pm))          /* -best */
       conv24 = CONV24_BEST;
 
@@ -1289,7 +1343,11 @@
     else if (!argcmp(argv[i],"-fg",3,0,&pm))              /* fg color */
       { if (++i<argc) fgstr = argv[i]; }
 
-    else if (!argcmp(argv[i],"-fixed",3,1,&fixedaspect)); /* fix asp. ratio */
+    else if (!argcmp(argv[i],"-fixed",5,1,&fixedaspect)); /* fix asp. ratio */
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+    else if (!argcmp(argv[i],"-fixpix",5,1,&do_fixpix_smooth)); /* dithering */
+#endif
 
     else if (!argcmp(argv[i],"-flist",3,0,&pm))           /* file list */
       { if (++i<argc) flistName = argv[i]; }
@@ -1330,6 +1388,10 @@
       { if (++i<argc) infogeom = argv[i]; }
 
     else if (!argcmp(argv[i],"-imap",     3,1,&imap));        /* imap */
+
+    else if (!argcmp(argv[i],"-ibg",3,0,&pm)) /* GRR: image background color */
+      { if (++i<argc) imagebgstr = argv[i]; }
+
     else if (!argcmp(argv[i],"-lbrowse",  3,1,&browseMode));  /* browse mode */
 
     else if (!argcmp(argv[i],"-lo",3,0,&pm))	        /* lowlight */
@@ -1365,16 +1427,18 @@
     else if (!argcmp(argv[i],"-ncols",3,0,&pm))        /* ncols */
       { if (++i<argc) ncols=abs(atoi(argv[i])); }
 
-    else if (!argcmp(argv[i],"-ninstall",  3,1,&ninstall));   /* inst cmaps?*/
+    else if (!argcmp(argv[i],"-ninstall",  3,1,&ninstall));   /* inst cmaps? */
     else if (!argcmp(argv[i],"-nodecor",   4,1,&nodecor));
     else if (!argcmp(argv[i],"-nofreecols",4,1,&noFreeCols));
     else if (!argcmp(argv[i],"-nolimits",  4,1,&nolimits));   /* nolimits */
     else if (!argcmp(argv[i],"-nopos",     4,1,&nopos));      /* nopos */
     else if (!argcmp(argv[i],"-noqcheck",  4,1,&noqcheck));   /* noqcheck */
-    else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root*/
+    else if (!argcmp(argv[i],"-noresetroot",5,1,&resetroot)); /* reset root */
     else if (!argcmp(argv[i],"-norm",      5,1,&autonorm));   /* norm */
     else if (!argcmp(argv[i],"-nostat",    4,1,&nostat));     /* nostat */
     else if (!argcmp(argv[i],"-owncmap",   2,1,&owncmap));    /* own cmap */
+    else if (!argcmp(argv[i],"-pcd",       4,0,&pm))         /* pcd with size */
+      { if (i+1<argc) PcdSize = atoi(argv[++i]); }
     else if (!argcmp(argv[i],"-perfect",   3,1,&perfect));    /* -perfect */
     else if (!argcmp(argv[i],"-pkludge",   3,1,&winCtrPosKludge));
     else if (!argcmp(argv[i],"-poll",      3,1,&polling));    /* chk mod? */
@@ -1440,8 +1504,9 @@
 
     else if (!argcmp(argv[i],"-wait",3,0,&pm)) {        /* secs betwn pics */
       if (++i<argc) {
-	waitsec = abs(atoi(argv[i]));
-	if (waitsec<0) waitsec = 0;
+	char *comma = strchr(argv[i], ',');
+	waitsec_nonfinal = fabs(atof(argv[i]));
+	waitsec_final = comma? fabs(atof(comma+1)) : waitsec_nonfinal;
       }
     }
 
@@ -1514,7 +1579,7 @@
     preset = 0;
   }
 
-  if (waitsec < 0) noFreeCols = 0;   /* disallow nfc if not doing slideshow */
+  if (waitsec < 0.0) noFreeCols = 0;   /* disallow nfc if not doing slideshow */
   if (noFreeCols && perfect) { perfect = 0;  owncmap = 1; }
 
   /* decide what default color allocation stuff we've settled on */
@@ -1556,6 +1621,20 @@
 
 static void cmdSyntax()
 {
+  /* GRR 19980605:  added version info for most common libraries */
+  fprintf(stderr, "XV - %s.\n", REVDATE);
+#ifdef HAVE_JPEG
+  VersionInfoJPEG();
+#endif
+#ifdef HAVE_TIFF
+  VersionInfoTIFF();
+#endif
+#ifdef HAVE_PNG
+  VersionInfoPNG();
+#endif
+  /* pbm/pgm/ppm support is native, not via pbmplus/netpbm libraries */
+  fprintf(stderr, "\n");
+
   fprintf(stderr, "Usage:\n");
   printoption(cmd);
   printoption("[-]");
@@ -1595,6 +1674,9 @@
   printoption("[-expand exp | hexp:vexp]");
   printoption("[-fg color]");
   printoption("[-/+fixed]");
+#ifdef ENABLE_FIXPIX_SMOOTH
+  printoption("[-/+fixpix]");
+#endif
   printoption("[-flist fname]");
   printoption("[-gamma val]");
   printoption("[-geometry geom]");
@@ -1607,6 +1689,7 @@
   printoption("[-hi color]");
   printoption("[-/+hist]");
   printoption("[-/+hsv]");
+  printoption("[-ibg color]");  /* GRR 19980314 */
   printoption("[-icgeometry geom]");
   printoption("[-/+iconic]");
   printoption("[-igeometry geom]");
@@ -1630,6 +1713,7 @@
   printoption("[-/+norm]");
   printoption("[-/+nostat]");
   printoption("[-/+owncmap]");
+  printoption("[-pcd size(0=192*128,1,2,3,4=3072*2048)]");
   printoption("[-/+perfect]");
   printoption("[-/+pkludge]");
   printoption("[-/+poll]");
@@ -1658,8 +1742,9 @@
   printoption("[-vsgeometry geom]");
   printoption("[-/+vsmap]");
   printoption("[-/+vsperfect]");
-  printoption("[-wait seconds]");
+  printoption("[-wait secs[,final_secs]]");
   printoption("[-white color]");
+  printoption("[-windowid windowid]");
   printoption("[-/+wloop]");
   printoption("[filename ...]");
   fprintf(stderr,"\n\n");
@@ -1682,6 +1767,7 @@
   fprintf(stderr,"\t7: centered on a 'brick' background\n");
   fprintf(stderr,"\t8: symmetrical tiling\n");
   fprintf(stderr,"\t9: symmetrical mirrored tiling\n");
+  fprintf(stderr,"\t10: upper left corner\n");
   fprintf(stderr,"\n");
   Quit(1);
 }
@@ -1694,7 +1780,7 @@
      int *plusminus;
 {
   /* does a string compare between a1 and a2.  To return '0', a1 and a2
-     must match to the length of a2, and that length has to
+     must match to the length of a1, and that length has to
      be at least 'minlen'.  Otherwise, return non-zero.  plusminus set to '1'
      if '-option', '0' if '+option' */
 
@@ -1880,6 +1966,7 @@
     basefname[strlen(basefname)-2]='\0';
   else {
 #ifdef GUNZIP
+    /* FIXME: this first test is pointless since it's identical to that above */
     if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0)
       basefname[strlen(basefname)-2]='\0';
 
@@ -1887,6 +1974,10 @@
 	     strcmp(basefname+strlen(basefname)-3,".gz")==0)
       basefname[strlen(basefname)-3]='\0';
 #endif /* GUNZIP */
+#ifdef BUNZIP2
+    if (strlen(basefname)>4 && strcmp(basefname+strlen(basefname)-4,".bz2")==0)
+      basefname[strlen(basefname)-4]='\0';
+#endif /* BUNZIP2 */
   }
 
 
@@ -2006,14 +2097,15 @@
   filetype = ReadFileType(filename);
 
 
-  if (filetype == RFT_COMPRESS) {   /* a compressed file.  uncompress it */
+  /* if it's a compressed file, uncompress it: */
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
     char tmpname[128];
 
     if (
 #ifndef VMS
-	UncompressFile(filename, tmpname)
+	UncompressFile(filename, tmpname, filetype)
 #else
-	UncompressFile(basefname, tmpname)
+	UncompressFile(basefname, tmpname, filetype)
 #endif
 	) {
 
@@ -2424,7 +2516,7 @@
     if (autodither && ncols>0) epicMode = EM_DITH;
 
     /* if in CM_STDCMAP mode, and *not* in '-wait 0', then autodither */
-    if (colorMapMode == CM_STDCMAP && waitsec != 0) epicMode = EM_DITH;
+    if (colorMapMode == CM_STDCMAP && waitsec != 0.0) epicMode = EM_DITH;
 
     /* if -smooth or image has been shrunk to fit screen */
     if (autosmooth || (pWIDE >maxWIDE || pHIGH>maxHIGH)
@@ -2542,6 +2634,9 @@
 }
 
 
+extern byte ZXheader[128];	/* [JCE] Spectrum screen magic number is
+                                  defined in xvzx.c */
+
 
 /********************************/
 int ReadFileType(fname)
@@ -2554,52 +2649,57 @@
 
   FILE *fp;
   byte  magicno[30];    /* first 30 bytes of file */
-  int   rv, n;
+  int   rv=RFT_UNKNOWN, n;
 
   if (!fname) return RFT_ERROR;   /* shouldn't happen */
 
   fp = xv_fopen(fname, "r");
   if (!fp) return RFT_ERROR;
 
+  if (strlen(fname) > 4 &&
+      strcasecmp(fname+strlen(fname)-5, ".wbmp")==0)          rv = RFT_WBMP;
+
   n = fread(magicno, (size_t) 1, (size_t) 30, fp);
   fclose(fp);
 
-  if (n<30) return RFT_UNKNOWN;    /* files less than 30 bytes long... */
-
-  rv = RFT_UNKNOWN;
+  if (n<30) return rv;    /* files less than 30 bytes long... */
 
   if (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 ||
-      strncmp((char *) magicno,"GIF89a", (size_t) 6)==0)        rv = RFT_GIF;
+      strncmp((char *) magicno,"GIF89a", (size_t) 6)==0)      rv = RFT_GIF;
 
   else if (strncmp((char *) magicno,"VIEW", (size_t) 4)==0 ||
-	   strncmp((char *) magicno,"WEIV", (size_t) 4)==0)     rv = RFT_PM;
+	   strncmp((char *) magicno,"WEIV", (size_t) 4)==0)   rv = RFT_PM;
 
   else if (magicno[0] == 'P' && magicno[1]>='1' &&
-	   magicno[1]<='6')                             rv = RFT_PBM;
+	   (magicno[1]<='6' || magicno[1]=='8'))              rv = RFT_PBM;
 
   /* note: have to check XPM before XBM, as first 2 chars are the same */
   else if (strncmp((char *) magicno, "/* XPM */", (size_t) 9)==0) rv = RFT_XPM;
 
   else if (strncmp((char *) magicno,"#define", (size_t) 7)==0 ||
-	   (magicno[0] == '/' && magicno[1] == '*'))    rv = RFT_XBM;
+	   (magicno[0] == '/' && magicno[1] == '*'))          rv = RFT_XBM;
 
   else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
-	   magicno[2]==0x6a && (magicno[3]&0x7f)==0x15) rv = RFT_SUNRAS;
+	   magicno[2]==0x6a && (magicno[3]&0x7f)==0x15)       rv = RFT_SUNRAS;
 
-  else if (magicno[0] == 'B' && magicno[1] == 'M')      rv = RFT_BMP;
+  else if (magicno[0] == 'B' && magicno[1] == 'M')            rv = RFT_BMP;
 
-  else if (magicno[0]==0x52 && magicno[1]==0xcc)        rv = RFT_UTAHRLE;
+  else if (magicno[0]==0x52 && magicno[1]==0xcc)              rv = RFT_UTAHRLE;
 
   else if ((magicno[0]==0x01 && magicno[1]==0xda) ||
-	   (magicno[0]==0xda && magicno[1]==0x01))      rv = RFT_IRIS;
+	   (magicno[0]==0xda && magicno[1]==0x01))            rv = RFT_IRIS;
 
-  else if (magicno[0]==0x1f && magicno[1]==0x9d)        rv = RFT_COMPRESS;
+  else if (magicno[0]==0x1f && magicno[1]==0x9d)              rv = RFT_COMPRESS;
 
 #ifdef GUNZIP
-  else if (magicno[0]==0x1f && magicno[1]==0x8b)        rv = RFT_COMPRESS;
+  else if (magicno[0]==0x1f && magicno[1]==0x8b)              rv = RFT_COMPRESS;
 #endif
 
-  else if (magicno[0]==0x0a && magicno[1] <= 5)         rv = RFT_PCX;
+#ifdef BUNZIP2
+  else if (magicno[0]==0x42 && magicno[1]==0x5a)              rv = RFT_BZIP2;
+#endif
+
+  else if (magicno[0]==0x0a && magicno[1] <= 5)               rv = RFT_PCX;
 
   else if (strncmp((char *) magicno,   "FORM", (size_t) 4)==0 &&
 	   strncmp((char *) magicno+8, "ILBM", (size_t) 4)==0)   rv = RFT_IFF;
@@ -2607,23 +2707,30 @@
   else if (magicno[0]==0 && magicno[1]==0 &&
 	   magicno[2]==2 && magicno[3]==0 &&
 	   magicno[4]==0 && magicno[5]==0 &&
-	   magicno[6]==0 && magicno[7]==0)              rv = RFT_TARGA;
+	   magicno[6]==0 && magicno[7]==0)                    rv = RFT_TARGA;
 
   else if (magicno[4]==0x00 && magicno[5]==0x00 &&
-	   magicno[6]==0x00 && magicno[7]==0x07)        rv = RFT_XWD;
+	   magicno[6]==0x00 && magicno[7]==0x07)              rv = RFT_XWD;
 
   else if (strncmp((char *) magicno,"SIMPLE  ", (size_t) 8)==0 &&
-	   magicno[29] == 'T')                          rv = RFT_FITS;
+	   magicno[29] == 'T')                                rv = RFT_FITS;
 
+  /* [JCE] Spectrum screen */
+  else if (memcmp(magicno, ZXheader, (size_t) 18)==0)         rv = RFT_ZX;
 
 #ifdef HAVE_JPEG
   else if (magicno[0]==0xff && magicno[1]==0xd8 &&
-	   magicno[2]==0xff)                            rv = RFT_JFIF;
+	   magicno[2]==0xff)                                  rv = RFT_JFIF;
 #endif
 
 #ifdef HAVE_TIFF
   else if ((magicno[0]=='M' && magicno[1]=='M') ||
-	   (magicno[0]=='I' && magicno[1]=='I'))        rv = RFT_TIFF;
+	   (magicno[0]=='I' && magicno[1]=='I'))              rv = RFT_TIFF;
+#endif
+
+#ifdef HAVE_PNG
+  else if (magicno[0]==0x89 && magicno[1]=='P' &&
+           magicno[2]=='N'  && magicno[3]=='G')               rv = RFT_PNG;
 #endif
 
 #ifdef HAVE_PDS
@@ -2635,11 +2742,15 @@
       rv = RFT_PDSVICAR;
 #endif
 
-#ifdef GS_PATH
+#ifdef GS_PATH   /* Ghostscript handles both PostScript and PDF */
   else if (strncmp((char *) magicno, "%!",     (size_t) 2)==0 ||
-	   strncmp((char *) magicno, "\004%!", (size_t) 3)==0)   rv = RFT_PS;
+	   strncmp((char *) magicno, "\004%!", (size_t) 3)==0 ||
+           strncmp((char *) magicno, "%PDF",   (size_t) 4)==0)   rv = RFT_PS;
 #endif
 
+  else if (magicno[0]==0xff && magicno[1]==0xff &&
+	   magicno[2]==0xff && magicno[3]==0xff)              rv = RFT_PCD;
+
   return rv;
 }
 
@@ -2652,9 +2763,10 @@
      PICINFO *pinfo;
 {
   /* if quick is set, we're being called to generate icons, or something
-     like that.  We should load the image as quickly as possible.  Currently,
-     this only affects the LoadPS routine, which, if quick is set, only
-     generates the page file for the first page of the document */
+     like that.  We should load the image as quickly as possible.  Previously,
+     this affected only the LoadPS routine, which, if quick is set, only
+     generates the page file for the first page of the document.  Now it
+     also affects PCD, which loads only a thumbnail. */
 
   int rv = 0;
 
@@ -2677,21 +2789,30 @@
   case RFT_XPM:     rv = LoadXPM   (fname, pinfo);         break;
   case RFT_XWD:     rv = LoadXWD   (fname, pinfo);         break;
   case RFT_FITS:    rv = LoadFITS  (fname, pinfo, quick);  break;
+  case RFT_ZX:      rv = LoadZX    (fname, pinfo);         break; /* [JCE] */
+  case RFT_WBMP:    rv = LoadWBMP  (fname, pinfo);         break;
+
+  /* if quick is switched on, use the smallest image size; don't ask the user */
+  case RFT_PCD:     rv = LoadPCD   (fname, pinfo, quick ? 0 : PcdSize);  break;
 
 #ifdef HAVE_JPEG
-  case RFT_JFIF:    rv = LoadJFIF  (fname, pinfo, quick);    break;
+  case RFT_JFIF:    rv = LoadJFIF  (fname, pinfo, quick);  break;
 #endif
 
 #ifdef HAVE_TIFF
-  case RFT_TIFF:    rv = LoadTIFF  (fname, pinfo, quick);    break;
+  case RFT_TIFF:    rv = LoadTIFF  (fname, pinfo, quick);  break;
+#endif
+
+#ifdef HAVE_PNG
+  case RFT_PNG:     rv = LoadPNG   (fname, pinfo);         break;
 #endif
 
 #ifdef HAVE_PDS
-  case RFT_PDSVICAR: rv = LoadPDS  (fname, pinfo);           break;
+  case RFT_PDSVICAR: rv = LoadPDS  (fname, pinfo);         break;
 #endif
 
 #ifdef GS_PATH
-  case RFT_PS:      rv = LoadPS    (fname, pinfo, quick);    break;
+  case RFT_PS:      rv = LoadPS    (fname, pinfo, quick);  break;
 #endif
 
   }
@@ -2700,8 +2821,9 @@
 
 
 /********************************/
-int UncompressFile(name, uncompname)
+int UncompressFile(name, uncompname, filetype)
      char *name, *uncompname;
+     int filetype;
 {
   /* returns '1' on success, with name of uncompressed file in uncompname
      returns '0' on failure */
@@ -2749,7 +2871,12 @@
 #endif
 
 #ifndef VMS
-  sprintf(buf,"%s -c %s >%s", UNCOMPRESS, fname, uncompname);
+  if (filetype == RFT_COMPRESS)
+    sprintf(buf,"%s -c %s >%s", UNCOMPRESS, fname, uncompname);
+# ifdef BUNZIP2
+  else if (filetype == RFT_BZIP2)
+    sprintf(buf,"%s -c %s >%s", BUNZIP2, fname, uncompname);
+# endif
 #else /* it IS VMS */
 # ifdef GUNZIP
   sprintf(buf,"%s %s %s", UNCOMPRESS, fname, uncompname);
@@ -2966,6 +3093,8 @@
 {
   int i;
 
+  waitsec = (numnames <= 1)? waitsec_final : waitsec_nonfinal;
+
   if (!numnames) {  openPic(DFLTPIC);  return; }
 
   i = 0;
@@ -3020,6 +3149,8 @@
       i = nList.selected;
     else i = 0;
 
+    waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal;
+
     while (i<numnames && !openPic(i));
     if (i<numnames) return;    /* success */
   }
@@ -3048,6 +3179,8 @@
 
       if (loop) {  i = 0;   loop = 0; }
 
+      waitsec = (i == numnames-1)? waitsec_final : waitsec_nonfinal;
+
       while (i<numnames && !openPic(i));
       if (i<numnames) return;
     }
@@ -3057,7 +3190,7 @@
     }
 
     loop = 1;        /* back to top of list */
-    if (j) break;                         /* we're in a 'failure loop' */
+    if (j) break;    /* we're in a 'failure loop' */
     j++;
   }
 
@@ -3102,7 +3235,7 @@
   int          k;
   time_t       t;
 
-  /* picks a random name out of the list, and returns it's index.  If there
+  /* picks a random name out of the list and returns its index.  If there
      are no more names to pick, it returns '-1' and resets itself */
 
   if (!loadList || numnames!=listLen) {
@@ -3224,8 +3357,16 @@
   hints.flags = 0;
   if ((i&XValue || i&YValue)) hints.flags = USPosition;
 
-  if (i&XValue && i&XNegative) x = vrWIDE - eWIDE - abs(x);
-  if (i&YValue && i&YNegative) y = vrHIGH - eHIGH - abs(y);
+  hints.win_gravity = NorthWestGravity;
+  if (i&XValue && i&XNegative) {
+    hints.win_gravity = NorthEastGravity;
+    x = vrWIDE - (eWIDE + 2 * bwidth) - abs(x);
+  }
+  if (i&YValue && i&YNegative) {
+    hints.win_gravity = (hints.win_gravity == NorthWestGravity) ?
+      SouthWestGravity : SouthEastGravity;
+    y = vrHIGH - (eHIGH + 2 * bwidth) - abs(y);
+  }
 
   if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE;   /* keep on screen */
   if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH;
@@ -3245,7 +3386,7 @@
   hints.x = x;                  hints.y = y;
   hints.width = eWIDE;          hints.height = eHIGH;
   hints.max_width  = maxWIDE;   hints.max_height = maxHIGH;
-  hints.flags |= USSize | PMaxSize;
+  hints.flags |= USSize | PMaxSize | PWinGravity;
 
   xswa.bit_gravity = StaticGravity;
   xswa.background_pixel = bg;
@@ -3294,10 +3435,6 @@
     }
   }
 
-
-  XSetStandardProperties(theDisp,mainW,"","",None,NULL,0,&hints);
-  setWinIconNames(name);
-
   xwmh.input = True;
   xwmh.flags = InputHint;
 
@@ -3322,12 +3459,13 @@
       }
     }
   }
-  XSetWMHints(theDisp, mainW, &xwmh);
 
   classh.res_name = "xv";
   classh.res_class = "XVroot";
-  XSetClassHint(theDisp, mainW, &classh);
 
+  XmbSetWMProperties(theDisp, mainW, NULL, NULL, NULL, 0, &hints, &xwmh,
+                     &classh);
+  setWinIconNames(name);
 
   if (nodecor) {   /* turn of image window decorations (in MWM) */
     Atom mwm_wm_hints;
@@ -4070,16 +4208,30 @@
       unsigned long nitems, nleft;
       byte *data;
 
-      i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0),
-			     resAtom, 0L, 1L, False,
-			     XA_STRING, &actType, &actFormat, &nitems, &nleft,
-			     (unsigned char **) &data);
+      if (spec_window) {
+        i = XGetWindowProperty(theDisp, spec_window,
+			       resAtom, 0L, 1L, False,
+			       XA_STRING, &actType, &actFormat, &nitems, &nleft,
+			       (unsigned char **) &data);
+      } else {
+        i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0),
+			       resAtom, 0L, 1L, False,
+			       XA_STRING, &actType, &actFormat, &nitems, &nleft,
+			       (unsigned char **) &data);
+      }
       if (i==Success && actType==XA_STRING && actFormat==8) {
 	if (nitems>0 && data) XFree(data);
-	i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L,
-			       (long) ((nleft+4+3)/4),
-			       False, XA_STRING, &actType, &actFormat,
-			       &nitems, &nleft, (unsigned char **) &data);
+        if (spec_window) {
+	  i = XGetWindowProperty(theDisp, spec_window, resAtom, 0L,
+			         (long) ((nleft+4+3)/4),
+			         False, XA_STRING, &actType, &actFormat,
+			         &nitems, &nleft, (unsigned char **) &data);
+        } else {
+	  i = XGetWindowProperty(theDisp, RootWindow(theDisp, 0), resAtom, 0L,
+			         (long) ((nleft+4+3)/4),
+			         False, XA_STRING, &actType, &actFormat,
+			         &nitems, &nleft, (unsigned char **) &data);
+        }
 	if (i==Success && actType==XA_STRING && actFormat==8 && data) {
 	  def_resource = XrmGetStringDatabase((char *) data);
 	  XFree(data);
diff -ruN xv-3.10a-bugfixes/xv.h xv-3.10a-enhancements/xv.h
--- xv-3.10a-bugfixes/xv.h	2005-04-10 09:37:18.000000000 -0700
+++ xv-3.10a-enhancements/xv.h	2005-04-10 16:59:14.000000000 -0700
@@ -14,7 +14,7 @@
 /* GRR orig jumbo enhancements patch:	20000220 */
 /* GRR 1st public jumbo F+E patches:	20040531 */
 /* GRR 2nd public jumbo F+E patches:	20050410 */
-#define REVDATE   "version 3.10a-jumboFix of 20050410"
+#define REVDATE   "version 3.10a-jumboFix+Enh of 20050410"
 #define VERSTR    "3.10a-20050410"
 
 /*
@@ -49,6 +49,10 @@
 /* START OF MACHINE-DEPENDENT CONFIGURATION INFO */
 /*************************************************/
 
+
+#define ENABLE_FIXPIX_SMOOTH	/* GRR 19980607 */
+
+
 /* Things to make xv more likely to just build, without the user tweaking
    the makefile */
 
@@ -134,7 +138,7 @@
 #  include <errno.h>
    extern int   errno;             /* SHOULD be in errno.h, but often isn't */
 #  if !defined(__NetBSD__) && !(defined(__linux__) && defined(__USE_BSD))
-     extern char *sys_errlist[];     /* this too... */
+     extern char *sys_errlist[];   /* this too... */
 #  endif
 #endif
 
@@ -351,6 +355,21 @@
 #endif
 
 
+/* GRR 20040503:  This is new and so far tested only under Linux.  But it
+ *                allows -wait to work with subsecond values as long as
+ *                times() exists and clock_t is a long int (latter matters
+ *                only if/when clocks wrap, which for Linux is multiples of
+ *                497.11 days since the last reboot). */
+#if defined(__linux__)
+#  define USE_TICKS             /* use times()/Timer(), not time()/sleep() */
+#  include <limits.h>           /* LONG_MAX (really want CLOCK_T_MAX) */
+#  include <sys/times.h>        /* times() */
+#  ifndef CLK_TCK               /* can be undefined in strict-ANSI mode */
+#    define CLK_TCK CLOCKS_PER_SEC   /* claimed to be same thing in time.h */
+#  endif
+#endif
+
+
 /*****************************/
 /* END OF CONFIGURATION INFO */
 /*****************************/
@@ -363,17 +382,21 @@
 #  define HAVE_TIFF
 #endif
 
+#ifdef DOPNG
+#  define HAVE_PNG
+#endif
+
 #ifdef DOPDS
 #  define HAVE_PDS
 #endif
 
 
 
-#define PROGNAME  "xv"             /* used in resource database */
+#define PROGNAME   "xv"            /* used in resource database */
 
-#define MAXNAMES 4096              /* max # of files in ctrlW list */
+#define MAXNAMES   32768           /* max # of files in ctrlW list */
 
-#define MAXBRWIN   4               /* max # of vis browser windows */
+#define MAXBRWIN   16              /* max # of vis browser windows */
 
 /* strings in the INFOBOX (used in SetISTR and GetISTR) */
 #define NISTR         10    /* number of ISTRs */
@@ -494,24 +517,33 @@
 #define F_TIFINC  0
 #endif
 
+#ifdef HAVE_PNG
+#define F_PNGINC  1
+#else
+#define F_PNGINC  0
+#endif
+
 
 #define F_GIF         0
 #define F_JPEG      ( 0 + F_JPGINC)
 #define F_TIFF      ( 0 + F_JPGINC + F_TIFINC)
-#define F_PS        ( 1 + F_JPGINC + F_TIFINC)
-#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC)
-#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC)
-#define F_XBM       ( 4 + F_JPGINC + F_TIFINC)
-#define F_XPM       ( 5 + F_JPGINC + F_TIFINC)
-#define F_BMP       ( 6 + F_JPGINC + F_TIFINC)
-#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC)
-#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC)
-#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC)
-#define F_FITS      (10 + F_JPGINC + F_TIFINC)
-#define F_PM        (11 + F_JPGINC + F_TIFINC)
-#define F_DELIM1    (12 + F_JPGINC + F_TIFINC)     /* ----- */
-#define F_FILELIST  (13 + F_JPGINC + F_TIFINC)
-#define F_MAXFMTS   (14 + F_JPGINC + F_TIFINC)     /* 15, normally */
+#define F_PNG       ( 0 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PS        ( 1 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMRAW    ( 2 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PBMASCII  ( 3 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XBM       ( 4 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_XPM       ( 5 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_BMP       ( 6 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_SUNRAS    ( 7 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_IRIS      ( 8 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_TARGA     ( 9 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_FITS      (10 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_PM        (11 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_ZX        (12 + F_JPGINC + F_TIFINC + F_PNGINC)   /* [JCE] */
+#define F_WBMP      (13 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_DELIM1    (14 + F_JPGINC + F_TIFINC + F_PNGINC)   /* ----- */
+#define F_FILELIST  (15 + F_JPGINC + F_TIFINC + F_PNGINC)
+#define F_MAXFMTS   (16 + F_JPGINC + F_TIFINC + F_PNGINC)   /* 19, normally */
 
 
 
@@ -541,6 +573,11 @@
 #define RFT_XPM      17
 #define RFT_XWD      18
 #define RFT_FITS     19
+#define RFT_PNG      20
+#define RFT_ZX       21    /* [JCE] */
+#define RFT_WBMP     22
+#define RFT_PCD      23
+#define RFT_BZIP2    24
 
 /* definitions for page up/down, arrow up/down list control */
 #define LS_PAGEUP   0
@@ -599,7 +636,8 @@
 #define RM_CBRICK  7     /* centered on a 'brick' bg */
 #define RM_ECENTER 8     /* symmetrical tiled */
 #define RM_ECMIRR  9     /* symmetrical mirror tiled */
-#define RM_MAX     RM_ECMIRR
+#define RM_UPLEFT 10     /* just in upper left corner */
+#define RM_MAX     RM_UPLEFT
 
 
 /* values of colorMapMode */
@@ -649,7 +687,8 @@
 #define RMB_CBRICK   8
 #define RMB_ECENTER  9
 #define RMB_ECMIRR   10
-#define RMB_MAX      11
+#define RMB_UPLEFT   11
+#define RMB_MAX      12
 
 
 /* indicies into conv24MB */
@@ -801,9 +840,10 @@
 typedef struct { Window win;            /* window ID */
 		 int x,y,w,h;           /* window coords in parent */
 		 int active;            /* true if can do anything*/
-		 int min,max;           /* min/max values 'pos' can take */
-		 int val;               /* 'value' of dial */
-		 int page;              /* amt val change on pageup/pagedown */
+		 double min,max;        /* min/max values 'pos' can take */
+		 double val;            /* 'value' of dial */
+		 double inc;            /* amt val change on up/down */
+		 double page;           /* amt val change on pageup/pagedown */
 		 char *title;           /* title for this guage */
 		 char *units;           /* string appended to value */
 		 u_long fg,bg,hi,lo;    /* colors */
@@ -971,7 +1011,7 @@
 WHERE unsigned int  ncells, dispWIDE, dispHIGH, dispDEEP;
 WHERE unsigned int  vrWIDE, vrHIGH, maxWIDE, maxHIGH;
 WHERE Colormap      theCmap, LocalCmap;
-WHERE Window        rootW, mainW, vrootW;
+WHERE Window        spec_window, rootW, mainW, vrootW;
 WHERE GC            theGC;
 WHERE u_long        black, white, fg, bg, infofg, infobg;
 WHERE u_long        hicol, locol;
@@ -1090,35 +1130,39 @@
 WHERE float         defaspect,     /* default aspect ratio to use */
                     normaspect;    /* normal aspect ratio of this picture */
 
-WHERE unsigned long rootbg, rootfg;   /* fg/bg for root border */
-WHERE int           waitsec;          /* secs btwn pics. -1=wait for event */
-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 u_long        rootbg, rootfg; /* fg/bg for root border */
+WHERE u_short       imagebgR;
+WHERE u_short       imagebgG;      /* GRR 19980308:  bg for transpar. images */
+WHERE u_short       imagebgB;
+WHERE int           have_imagebg;
+WHERE double        waitsec;       /* secs btwn pics. -1.0=wait for event */
+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           nostat;           /* if true, don't stat() in LdCurDir */
+WHERE int           nostat;        /* if true, don't stat() in LdCurDir */
 
-WHERE int           ctrlColor;        /* whether or not to use colored butts */
+WHERE int           ctrlColor;     /* whether or not to use colored butts */
 
-WHERE char         *def_str;          /* used by rd_*() routines */
+WHERE char         *def_str;       /* used by rd_*() routines */
 WHERE int           def_int;
-WHERE char         *tmpdir;           /* equal to "/tmp" or $TMPDIR env var */
-WHERE Pixmap        gray25Tile,       /* used for 3d effect on 1-bit disp's */
+WHERE char         *tmpdir;        /* equal to "/tmp" or $TMPDIR env var */
+WHERE Pixmap        gray25Tile,    /* used for 3d effect on 1-bit disp's */
                     gray50Tile;
-WHERE int           autoDelete;       /* delete cmd-line files on exit? */
+WHERE int           autoDelete;    /* delete cmd-line files on exit? */
 
 #define PRINTCMDLEN 256
 WHERE char          printCmd[PRINTCMDLEN];
 
 /* stuff used for 'info' box */
 WHERE Window        infoW;
-WHERE int           infoUp;       /* boolean:  whether infobox is visible */
+WHERE int           infoUp;        /* boolean:  whether infobox is visible */
 WHERE int           infoMode;
 
 
 /* stuff used for 'ctrl' box */
 WHERE Window        ctrlW;
-WHERE int           ctrlUp;       /* boolean:  whether ctrlbox is visible */
+WHERE int           ctrlUp;        /* boolean:  whether ctrlbox is visible */
 WHERE char         *namelist[MAXNAMES];  /* list of file names from argv */
 WHERE char         *origlist[MAXNAMES];  /* only names from argv (autoDelete)*/
 WHERE int           orignumnames;
@@ -1157,25 +1201,30 @@
 
 
 /* stuff used for 'browse' box */
-WHERE int           anyBrowUp;            /* whether *any* browser visible */
+WHERE int           anyBrowUp;              /* whether *any* browser visible */
 
 /* stuff used for textview windows */
-WHERE int           anyTextUp;            /* are any text windows visible? */
-WHERE int           commentUp;            /* comment window up? */
+WHERE int           anyTextUp;              /* are any text windows visible? */
+WHERE int           commentUp;              /* comment window up? */
 
 /* stuff used for xvcut.c */
-WHERE int           forceClipFile;        /* don't use property clipboard */
-WHERE int           clearR, clearG, clearB;  /* clear color in 24-bit mode */
+WHERE int           forceClipFile;          /* don't use property clipboard */
+WHERE int           clearR, clearG, clearB; /* clear color in 24-bit mode */
 
 
 /* stuff used for 'ps' box */
 WHERE Window        psW;
-WHERE int           psUp;       /* is psW mapped, or what? */
+WHERE int           psUp;         /* is psW mapped, or what? */
 WHERE CBUTT         encapsCB, pscompCB;
 WHERE char         *gsDev, *gsGeomStr;
 WHERE int           gsRes;
 
 
+/* stuff used for 'pcd' box */
+WHERE Window        pcdW;
+WHERE int           pcdUp;        /* is pcdW mapped, or what? */
+
+
 #ifdef HAVE_JPEG
 /* stuff used for 'jpeg' box */
 WHERE Window        jpegW;
@@ -1190,6 +1239,18 @@
 #endif
 
 
+#ifdef HAVE_PNG
+/* stuff used for 'png' box */
+WHERE Window        pngW;
+WHERE int           pngUp;        /* is pngW mapped, or what? */
+#endif
+
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+WHERE int           do_fixpix_smooth;  /* GRR 19980607: runtime FS dithering */
+#endif
+
+
 #undef WHERE
 
 
@@ -1199,7 +1260,7 @@
 /****************************** XV.C ****************************/
 int   ReadFileType      PARM((char *));
 int   ReadPicFile       PARM((char *, int, PICINFO *, int));
-int   UncompressFile    PARM((char *, char *));
+int   UncompressFile    PARM((char *, char *, int));
 void  KillPageFiles     PARM((char *, int));
 
 void NewPicGetColors    PARM((int, int));
@@ -1502,12 +1563,12 @@
 
 
 /*************************** XVDIAL.C ***************************/
-void DCreate               PARM((DIAL *, Window, int, int, int, int, int,
-				 int, int, int, u_long, u_long, u_long,
-				 u_long, char *, char *));
+void DCreate               PARM((DIAL *, Window, int, int, int, int, double,
+                                 double, double, double, double, u_long,
+                                 u_long, u_long, u_long, char *, char *));
 
-void DSetRange             PARM((DIAL *, int, int, int, int));
-void DSetVal               PARM((DIAL *, int));
+void DSetRange             PARM((DIAL *, double,double,double,double,double));
+void DSetVal               PARM((DIAL *, double));
 void DSetActive            PARM((DIAL *, int));
 void DRedraw               PARM((DIAL *));
 int  DTrack                PARM((DIAL *, int, int));
@@ -1604,6 +1665,11 @@
 int WriteBMP               PARM((FILE *, byte *, int, int, int, byte *,
 				 byte *, byte *, int, int));
 
+/**************************** XVWBMP.C ***************************/
+int LoadWBMP               PARM((char *, PICINFO *));
+int WriteWBMP              PARM((FILE *, byte *, int, int, int, byte *,
+				 byte *, byte *, int, int));
+
 /**************************** XVRLE.C ***************************/
 int LoadRLE                PARM((char *, PICINFO *));
 
@@ -1642,6 +1708,7 @@
 void JPEGDialog            PARM((int));
 int  JPEGCheckEvent        PARM((XEvent *));
 void JPEGSaveParams        PARM((char *, int));
+void VersionInfoJPEG       PARM((void));		/* GRR 19980605 */
 
 /**************************** XVTIFF.C ***************************/
 int   LoadTIFF             PARM((char *, PICINFO *, int));
@@ -1649,6 +1716,15 @@
 void  TIFFDialog           PARM((int));
 int   TIFFCheckEvent       PARM((XEvent *));
 void  TIFFSaveParams       PARM((char *, int));
+void  VersionInfoTIFF      PARM((void));		/* GRR 19980605 */
+
+/**************************** XVPNG.C ***************************/
+int  LoadPNG               PARM((char *, PICINFO *));
+void CreatePNGW            PARM((void));
+void PNGDialog             PARM((int));
+int  PNGCheckEvent         PARM((XEvent *));
+void PNGSaveParams         PARM((char *, int));
+void VersionInfoPNG        PARM((void));		/* GRR 19980605 */
 
 /**************************** XVPDS.C ***************************/
 int LoadPDS                PARM((char *, PICINFO *));
@@ -1661,6 +1737,19 @@
 void  PSResize             PARM((void));
 int   LoadPS               PARM((char *, PICINFO *, int));
 
+/************************ [JCE] XVZX.C ***************************/
+
+int LoadZX                 PARM((char *, PICINFO *));
+int WriteZX                PARM((FILE *, byte *, int, int, int, byte *,
+				 byte *, byte *, int, int, char *));
+
+/**************************** XVPCD.C ***************************/
+int   LoadPCD              PARM((char *, PICINFO *, int));
+void  CreatePCDW           PARM((void));
+void  PCDDialog            PARM((int));
+int   PCDCheckEvent        PARM((XEvent *));
+void  PCDSetParamOptions   PARM((char *));
+
 /*************************** XVPOPUP.C ***************************/
 void  CenterMapWindow      PARM((Window, int, int, int, int));
 int   PopUp                PARM((char *, char **, int));
diff -ruN xv-3.10a-bugfixes/xvbmp.c xv-3.10a-enhancements/xvbmp.c
--- xv-3.10a-bugfixes/xvbmp.c	2005-03-27 18:12:17.000000000 -0800
+++ xv-3.10a-enhancements/xvbmp.c	2005-04-08 22:59:13.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * xvbmp.c - i/o routines for .BMP files (MS Windows 3.x)
+ * xvbmp.c - I/O routines for .BMP files (MS Windows 3.x and later; OS/2)
  *
  * LoadBMP(fname, numcols)
  * WriteBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
@@ -9,30 +9,39 @@
 
 #include "xv.h"
 
-/* comments on error handling:
-   a truncated file is not considered a Major Error.  The file is loaded, the
-   rest of the pic is filled with 0's.
-
-   a file with garbage characters in it is an unloadable file.  All allocated
-   stuff is tossed, and LoadBMP returns non-zero
-
-   not being able to malloc is a Fatal Error.  The program is aborted. */
-
-
-#define BI_RGB  0
-#define BI_RLE8 1
-#define BI_RLE4 2
+/* Comments on error-handling:
+   A truncated file is not considered a Major Error.  The file is loaded,
+   and the rest of the pic is filled with 0's.
+
+   A file with garbage characters in it is an unloadable file.  All allocated
+   stuff is tossed, and LoadBMP returns non-zero.
+
+   Not being able to malloc is a Fatal Error.  The program is aborted. */
+
+
+#define BI_RGB       0   /* a.k.a. uncompressed */
+#define BI_RLE8      1
+#define BI_RLE4      2
+#define BI_BITFIELDS 3   /* BMP version 4 */
+#define BI_JPEG      4   /* BMP version 5 (not yet supported) */
+#define BI_PNG       5   /* BMP version 5 (not yet supported) */
 
 #define WIN_OS2_OLD 12
 #define WIN_NEW     40
 #define OS2_NEW     64
 
+#if (defined(UINT_MAX) && UINT_MAX != 0xffffffffU)
+#  error XV's BMP code requires 32-bit unsigned integer type, but u_int isn't
+#endif
+
 static long filesize;
 
 static int   loadBMP1   PARM((FILE *, byte *, u_int, u_int));
 static int   loadBMP4   PARM((FILE *, byte *, u_int, u_int, u_int));
 static int   loadBMP8   PARM((FILE *, byte *, u_int, u_int, u_int));
-static int   loadBMP24  PARM((FILE *, byte *, u_int, u_int));
+static int   loadBMP16  PARM((FILE *, byte *, u_int, u_int, u_int *));
+static int   loadBMP24  PARM((FILE *, byte *, u_int, u_int, u_int));
+static int   loadBMP32  PARM((FILE *, byte *, u_int, u_int, u_int *));
 static u_int getshort   PARM((FILE *));
 static u_int getint     PARM((FILE *));
 static void  putshort   PARM((FILE *, int));
@@ -52,15 +61,14 @@
      PICINFO *pinfo;
 /*******************************************/
 {
-  FILE         *fp;
-  int          i, c, c1, rv;
-  u_int        bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
-  u_int        biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
-  u_int        biYPelsPerMeter, biClrUsed, biClrImportant;
-  int bPad;
-  char         *cmpstr;
-  byte         *pic24, *pic8;
-  char          buf[512], *bname;
+  FILE    *fp;
+  int     i, c, c1, rv, bPad;
+  u_int   bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
+  u_int   biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
+  u_int   biYPelsPerMeter, biClrUsed, biClrImportant;
+  u_int   colormask[3];
+  char    buf[512], *bname, *cmpstr, rgb_bits[16];
+  byte    *pic24, *pic8;
 
   /* returns '1' on success */
 
@@ -98,14 +106,13 @@
     biClrUsed       = getint(fp);
     biClrImportant  = getint(fp);
   }
-
   else {    /* old bitmap format */
     biWidth         = getshort(fp);          /* Types have changed ! */
     biHeight        = getshort(fp);
     biPlanes        = getshort(fp);
     biBitCount      = getshort(fp);
 
-    /* Not in old versions so have to compute them*/
+    /* not in old versions, so have to compute them */
     biSizeImage = (((biPlanes * biBitCount*biWidth)+31)/32)*4*biHeight;
 
     biCompression   = BI_RGB;
@@ -126,25 +133,39 @@
   if (FERROR(fp)) { bmpError(bname,"EOF reached in file header"); goto ERROR; }
 
 
-  /* error checking */
-  if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && biBitCount!=24) ||
-      biPlanes!=1 || biCompression>BI_RLE4 ||
+  /* error-checking */
+  if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 &&
+       biBitCount!=16 && biBitCount!=24 && biBitCount!=32) ||
+      biPlanes!=1 || biCompression>BI_PNG ||
       biWidth<=0 || biHeight<=0 ||
       (biClrUsed && biClrUsed > (1 << biBitCount))) {
 
     sprintf(buf,
-	    "Bogus BMP File!  (%dx%d, Bits=%d, Colors=%d, Planes=%d, Compr=%d)",
+	    "Unsupported BMP type (%dx%d, Bits=%d, Colors=%d, Planes=%d, "
+	    "Compr=%d)",
 	    biWidth, biHeight, biBitCount, biClrUsed, biPlanes, biCompression);
 
     bmpError(bname, buf);
     goto ERROR;
   }
 
+  if (biCompression>BI_BITFIELDS) {
+    sprintf(buf, "Unsupported BMP compression method (%s)",
+	    biCompression == BI_JPEG? "JPEG" :
+	    biCompression == BI_PNG? "PNG" :
+	    "internal logic error");
+
+    bmpError(bname, buf);
+    goto ERROR;
+  }
+
   if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) ||
-      (biBitCount==4 && biCompression==BI_RLE8) ||
-      (biBitCount==8 && biCompression==BI_RLE4)) {
+      (biBitCount==4 && biCompression!=BI_RGB && biCompression!=BI_RLE4) ||
+      (biBitCount==8 && biCompression!=BI_RGB && biCompression!=BI_RLE8) ||
+      ((biBitCount==16 || biBitCount==32) &&
+       biCompression!=BI_RGB && biCompression!=BI_BITFIELDS)) {
 
-    sprintf(buf,"Bogus BMP File!  (bitCount=%d, Compression=%d)",
+    sprintf(buf,"Unsupported BMP type (bitCount=%d, Compression=%d)",
 	    biBitCount, biCompression);
 
     bmpError(bname, buf);
@@ -156,13 +177,21 @@
   if (biSize != WIN_OS2_OLD) {
     /* skip ahead to colormap, using biSize */
     c = biSize - 40;    /* 40 bytes read from biSize to biClrImportant */
-    for (i=0; i<c; i++) getc(fp);
-
+    for (i=0; i<c; i++)
+      getc(fp);
     bPad = bfOffBits - (biSize + 14);
   }
 
+  /* 16-bit, 32-bit color mask */
+  if (biCompression==BI_BITFIELDS) {
+    colormask[0] = getint(fp);
+    colormask[1] = getint(fp);
+    colormask[2] = getint(fp);
+    bPad -= 12;
+  }
+
   /* load up colormap, if any */
-  if (biBitCount!=24) {
+  if (biBitCount==1 || biBitCount==4 || biBitCount==8) {
     int i, cmaplen;
 
 /* this is superfluous; see identical test in "error checking" block above
@@ -205,7 +234,7 @@
 
   /* create pic8 or pic24 */
 
-  if (biBitCount==24) {
+  if (biBitCount==16 || biBitCount==24 || biBitCount==32) {
     u_int npixels = biWidth * biHeight;
     u_int count = 3 * npixels;
 
@@ -227,19 +256,35 @@
   WaitCursor();
 
   /* load up the image */
-  if      (biBitCount == 1) rv = loadBMP1(fp,pic8,biWidth,biHeight);
-  else if (biBitCount == 4) rv = loadBMP4(fp,pic8,biWidth,biHeight,
-					  biCompression);
-  else if (biBitCount == 8) rv = loadBMP8(fp,pic8,biWidth,biHeight,
-					  biCompression);
-  else                      rv = loadBMP24(fp,pic24,biWidth,biHeight);
+  switch (biBitCount) {
+  case 1:
+    rv = loadBMP1(fp, pic8, biWidth, biHeight);
+    break;
+  case 4:
+    rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression);
+    break;
+  case 8:
+    rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression);
+    break;
+  case 16:
+    rv = loadBMP16(fp, pic24, biWidth, biHeight,           /*  v-- BI_RGB */
+                   biCompression == BI_BITFIELDS? colormask : NULL);
+    break;
+  default:
+    if (biBitCount == 32 && biCompression == BI_BITFIELDS)
+      rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask);
+    else /* 24 or (32 and BI_RGB) */
+      rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount);
+    break;
+  }
 
   if (rv) bmpError(bname, "File appears truncated.  Winging it.");
 
+
   fclose(fp);
 
 
-  if (biBitCount == 24) {
+  if (biBitCount > 8) {
     pinfo->pic  = pic24;
     pinfo->type = PIC24;
   }
@@ -251,6 +296,22 @@
   cmpstr = "";
   if      (biCompression == BI_RLE4) cmpstr = ", RLE4 compressed";
   else if (biCompression == BI_RLE8) cmpstr = ", RLE8 compressed";
+  else if (biCompression == BI_BITFIELDS) {
+    int    bit, c[3], i;
+    u_int  mask;
+
+    for (i = 0; i < 3; ++i) {
+      mask = colormask[i];
+      c[i] = 0;
+      for (bit = 0; bit < 32; ++bit) {
+        if (mask & 1)
+          ++c[i];
+        mask >>= 1;
+      }
+    }
+    sprintf(rgb_bits, ", RGB%d%d%d", c[0], c[1], c[2]);
+    cmpstr = rgb_bits;
+  }
 
   pinfo->w = biWidth;  pinfo->h = biHeight;
   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
@@ -402,10 +463,12 @@
      u_int  w,h,comp;
 {
   int   i,j,c,c1,padw,x,y,rv;
-  byte *pp;
+  byte *pp, *pend;
 
   rv = 0;
 
+  pend = pic8 + w * h;
+
   if (comp == BI_RGB) {   /* read uncompressed data */
     padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
 
@@ -425,12 +488,12 @@
     x = y = 0;
     pp = pic8 + x + (h-y-1)*w;
 
-    while (y<h) {
+    while (y<h && pp<=pend) {
       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
 
       if (c) {                                   /* encoded mode */
 	c1 = getc(fp);
-	for (i=0; i<c; i++,x++,pp++) *pp = c1;
+	for (i=0; i<c && pp<=pend; i++,x++,pp++) *pp = c1;
       }
 
       else {    /* c==0x00  :  escape codes */
@@ -449,7 +512,7 @@
 	}
 
 	else {                                   /* absolute mode */
-	  for (i=0; i<c; i++, x++, pp++) {
+	  for (i=0; i<c && pp<=pend; i++, x++, pp++) {
 	    c1 = getc(fp);
 	    *pp = c1;
 	  }
@@ -472,10 +535,113 @@
 
 
 /*******************************************/
-static int loadBMP24(fp, pic24, w, h)
+static int loadBMP16(fp, pic24, w, h, mask)
+     FILE  *fp;
+     byte  *pic24;
+     u_int w, h, *mask;
+{
+  int	 x, y;
+  byte	*pp;
+  u_int	 buf, colormask[6];
+  int	 i, bit, bitshift[6], colorbits[6], bitshift2[6];
+
+  if (mask == NULL) {  /* RGB555 */
+    colormask[0] = 0x00007c00;
+    colormask[1] = 0x000003e0;
+    colormask[2] = 0x0000001f;
+    colormask[3] = 0x7c000000;
+    colormask[4] = 0x03e00000;
+    colormask[5] = 0x001f0000;
+    bitshift[0] =  7;	bitshift2[0] = 0;
+    bitshift[1] =  2;	bitshift2[1] = 0;
+    bitshift[2] =  0;	bitshift2[2] = 3;
+    bitshift[3] = 23;	bitshift2[3] = 0;
+    bitshift[4] = 18;	bitshift2[4] = 0;
+    bitshift[5] = 13;	bitshift2[5] = 0;
+  } else {
+    colormask[0] = mask[0];
+    colormask[1] = mask[1];
+    colormask[2] = mask[2];
+    colormask[3] = (mask[0] & 0xffff) << 16;
+    colormask[4] = (mask[1] & 0xffff) << 16;
+    colormask[5] = (mask[2] & 0xffff) << 16;
+
+    for (i = 0; i < 3; ++i) {
+      buf = colormask[i];
+
+      bitshift[i] = 0;
+      for (bit = 0; bit < 32; ++bit) {
+	if (buf & 1)
+	  break;
+	else
+	  ++bitshift[i];
+	buf >>= 1;
+      }
+      bitshift[i+3] = bitshift[i] + 16;
+
+      colorbits[i] = 0;
+      for (; bit < 32; ++bit) {
+	if (buf & 1)
+	  ++colorbits[i];
+	else
+	  break;
+	buf >>= 1;
+      }
+      if (colorbits[i] > 8) { /* over 8-bit depth */
+	bitshift[i] += (colorbits[i] - 8);
+	bitshift[i+3] = bitshift[i] + 16;
+	bitshift2[i] = bitshift2[i+3] = 0;
+      } else
+	bitshift2[i] = bitshift2[i+3] = 8 - colorbits[i];
+    }
+  }
+
+  if (DEBUG > 1)
+    fprintf(stderr, "loadBMP16: bitfields\n"
+	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
+	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
+	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n",
+	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
+	    colormask[3], bitshift[3], bitshift2[3],
+	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
+	    colormask[4], bitshift[4], bitshift2[4],
+	    colorbits[2], colormask[2], bitshift[2], bitshift2[2],
+	    colormask[5], bitshift[5], bitshift2[5]);
+
+  for (y = h-1; y >= 0; y--) {
+    pp = pic24 + (3 * w * y);
+    if ((y&0x3f)==0) WaitCursor();
+
+    for (x = w; x > 1; x -= 2) {
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
+      *(pp++) = (buf & colormask[3]) >> bitshift[3] << bitshift2[3];
+      *(pp++) = (buf & colormask[4]) >> bitshift[4] << bitshift2[4];
+      *(pp++) = (buf & colormask[5]) >> bitshift[5] << bitshift2[5];
+    }
+    if (w & 1) { /* padded to 2 pix */
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2];
+    }
+  }
+
+  return FERROR(fp)? 1 : 0;
+}
+
+
+
+/*******************************************/
+static int loadBMP24(fp, pic24, w, h, bits)   /* also handles 32-bit BI_RGB */
      FILE *fp;
      byte *pic24;
-     u_int  w,h;
+     u_int  w,h, bits;
 {
   int   i,j,padb,rv;
   byte *pp;
@@ -483,6 +649,7 @@
   rv = 0;
 
   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to read at EOscanline */
+  if (bits==32) padb = 0;
 
   for (i=h-1; i>=0; i--) {
     pp = pic24 + (i * w * 3);
@@ -492,6 +659,7 @@
       pp[2] = getc(fp);   /* blue */
       pp[1] = getc(fp);   /* green */
       pp[0] = getc(fp);   /* red */
+      if (bits==32) getc(fp);
       pp += 3;
     }
 
@@ -507,6 +675,70 @@
 
 
 /*******************************************/
+static int loadBMP32(fp, pic24, w, h, colormask) /* 32-bit BI_BITFIELDS only */
+     FILE  *fp;
+     byte  *pic24;
+     u_int w, h, *colormask;
+{
+  int	 x, y;
+  byte	*pp;
+  u_int	 buf;
+  int	 i, bit, bitshift[3], colorbits[3], bitshift2[3];
+
+  for (i = 0; i < 3; ++i) {
+    buf = colormask[i];
+
+    bitshift[i] = 0;
+    for (bit = 0; bit < 32; ++bit) {
+      if (buf & 1)
+	break;
+      else
+	++bitshift[i];
+      buf >>= 1;
+    }
+
+    colorbits[i] = 0;
+    for (; bit < 32; ++bit) {
+      if (buf & 1)
+	++colorbits[i];
+      else
+	break;
+      buf >>= 1;
+    }
+    if (colorbits[i] > 8) {  /* over 8-bit depth */
+      bitshift[i] += (colorbits[i] - 8);
+      bitshift2[i] = 0;
+    } else
+      bitshift2[i] = 8 - colorbits[i];
+  }
+
+  if (DEBUG > 1)
+    fprintf(stderr, "loadBMP32: bitfields\n"
+	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
+	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n",
+	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
+	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
+	    colorbits[2], colormask[2], bitshift[2], bitshift2[2]);
+
+  for (y = h-1; y >= 0; y--) {
+    pp = pic24 + (3 * w * y);
+    if ((y&0x3f)==0) WaitCursor();
+
+    for(x = w; x > 0; x --) {
+      buf = getint(fp);
+      *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
+      *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
+      *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
+    }
+  }
+
+  return FERROR(fp)? 1 : 0;
+}
+
+
+
+/*******************************************/
 static u_int getshort(fp)
      FILE *fp;
 {
@@ -523,7 +755,7 @@
   int c, c1, c2, c3;
   c = getc(fp);  c1 = getc(fp);  c2 = getc(fp);  c3 = getc(fp);
   return  ((u_int) c) +
-         (((u_int) c1) << 8) +
+	 (((u_int) c1) << 8) +
 	 (((u_int) c2) << 16) +
 	 (((u_int) c3) << 24);
 }
diff -ruN xv-3.10a-bugfixes/xvbrowse.c xv-3.10a-enhancements/xvbrowse.c
--- xv-3.10a-bugfixes/xvbrowse.c	2004-05-16 18:01:25.000000000 -0700
+++ xv-3.10a-enhancements/xvbrowse.c	2005-04-10 18:46:24.000000000 -0700
@@ -24,6 +24,10 @@
 typedef unsigned int mode_t;  /* file mode bits */
 #endif
 
+#ifndef MAX
+#  define MAX(a,b) (((a)>(b))?(a):(b))   /* used only for wheelmouse support */
+#endif
+
 
 /* load up built-in icons */
 #include "bits/br_file"
@@ -36,6 +40,7 @@
 #include "bits/br_error"
 /* #include "bits/br_unknown"	commented out (near line 492) */
 #include "bits/br_cmpres"
+#include "bits/br_bzip2"
 
 #include "bits/br_gif"
 #include "bits/br_pm"
@@ -50,11 +55,14 @@
 #include "bits/br_tiff"
 #include "bits/br_pds"
 #include "bits/br_ps"
+#include "bits/br_pcd"
 #include "bits/br_iff"
 #include "bits/br_targa"
 #include "bits/br_xpm"
 #include "bits/br_xwd"
 #include "bits/br_fits"
+#include "bits/br_png"
+#include "bits/br_zx"	/* [JCE] The Spectrum+3 icon */
 
 #include "bits/br_trash"
 #include "bits/fcurs"
@@ -94,14 +102,15 @@
 #define BF_XPM      25
 #define BF_XWD      26
 #define BF_FITS     27
-#define BF_MAX      28    /* # of built-in icons */
+#define BF_PNG      28
+#define BF_ZX       29    /* [JCE] Spectrum SCREEN$ */
+#define BF_PCD      30
+#define BF_BZIP2    31
+#define BF_MAX      32    /* # of built-in icons */
 
 #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
-
 #define SCROLLVERT  8      /* height of scroll region at top/bottom of iconw */
 #define PAGEVERT    40     /* during rect drag, if further than this, page */
 
@@ -113,10 +122,27 @@
 #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
+/* some people like bigger icons; 4:3 aspect ratio is recommended
+ * (NOTE:  standard XV binaries will not be able to read larger icons!) */
+#ifndef ISIZE_WIDE
+#  define ISIZE_WIDE 80    /* maximum size of an icon */
+#endif
+#ifndef ISIZE_HIGH
+#  define ISIZE_HIGH 60
+#endif
+
+#ifndef ISIZE_WPAD
+#  define ISIZE_WPAD 16    /* extra horizontal padding between icons */
+#endif
+
+#ifndef INUM_WIDE
+#  define INUM_WIDE 6      /* size initial window to hold this many icons */
+#endif
+#ifndef INUM_HIGH
+#  define INUM_HIGH 3
+#endif
 
-#define ISPACE_WIDE (ISIZE_WIDE+16)   /* icon spacing */
+#define ISPACE_WIDE (ISIZE_WIDE+ISIZE_WPAD)   /* 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)
@@ -146,6 +172,11 @@
 #define BUTTW 80
 #define BUTTH 24
 
+/* original size of window was 615 x 356 (for 80x60 thumbnails in 6x3 array) */
+#define DEF_BROWWIDE  (ISPACE_WIDE * INUM_WIDE + LRMARGINS * 2 + 29)
+#define DEF_BROWHIGH  (ISPACE_HIGH * INUM_HIGH + BUTTH * 2 + 16 + 28)
+/* last number is a fudge--e.g., extra spaces, borders, etc. -----^  */
+
 static char *showHstr = "Show hidden files";
 static char *hideHstr = "Hide 'hidden' files";
 
@@ -209,6 +240,13 @@
 		} BROWINFO;
 
 
+/* keep track of last icon visible in each path */
+typedef struct IVIS IVIS;
+    struct IVIS { IVIS   *next;
+                  char   *name;
+                  int    icon;
+                };
+
 static Cursor   movecurs, copycurs, delcurs;
 static BROWINFO binfo[MAXBRWIN];
 static Pixmap   bfIcons[BF_MAX], trashPix;
@@ -298,6 +336,8 @@
 
 static int  selmatch         PARM((char *, char *));
 static int  selmatch1        PARM((char *, char *));
+static void recIconVisible   PARM((char *, int));
+static void restIconVisible  PARM((BROWINFO *));
 
 
 
@@ -511,9 +551,10 @@
   bfIcons[BF_JFIF]=MakePix1(br->win,br_jfif_bits,br_jfif_width,br_jfif_height);
   bfIcons[BF_TIFF]=MakePix1(br->win,br_tiff_bits,br_tiff_width,br_tiff_height);
   bfIcons[BF_PDS] =MakePix1(br->win,br_pds_bits, br_pds_width, br_pds_height);
-
-  bfIcons[BF_COMPRESS]= MakePix1(br->win, br_cmpres_bits,
-				 br_cmpres_width, br_cmpres_height);
+  bfIcons[BF_COMPRESS] = MakePix1(br->win, br_cmpres_bits,
+				  br_cmpres_width, br_cmpres_height);
+  bfIcons[BF_BZIP2] = MakePix1(br->win, br_bzip2_bits,
+			       br_bzip2_width, br_bzip2_height);
 
   bfIcons[BF_PS]  =MakePix1(br->win,br_ps_bits,  br_ps_width,  br_ps_height);
   bfIcons[BF_IFF] =MakePix1(br->win,br_iff_bits, br_iff_width, br_iff_height);
@@ -524,6 +565,9 @@
   bfIcons[BF_XPM] =MakePix1(br->win,br_xpm_bits, br_xpm_width, br_xpm_height);
   bfIcons[BF_XWD] =MakePix1(br->win,br_xwd_bits, br_xwd_width, br_xwd_height);
   bfIcons[BF_FITS]=MakePix1(br->win,br_fits_bits,br_fits_width,br_fits_height);
+  bfIcons[BF_PNG] =MakePix1(br->win,br_png_bits, br_png_width, br_png_height);
+  bfIcons[BF_ZX]  =MakePix1(br->win,br_zx_bits,  br_zx_width,  br_zx_height);
+  bfIcons[BF_PCD] =MakePix1(br->win,br_pcd_bits, br_pcd_width, br_pcd_height);
 
 
   /* check that they all got built */
@@ -812,7 +856,38 @@
       else if (e->window == br->iconW) {
 	i = clickIconWin(br, x,y,(unsigned long) e->time,
 			 (e->state&ControlMask) || (e->state&ShiftMask));
-
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button4) {   /* note min vs. max, + vs. - */
+      /* scroll regardless of where we are in the browser window */
+      if (e->window == br->win ||
+	  e->window == br->scrl.win ||
+	  e->window == br->iconW)
+      {
+	SCRL *sp=&(br->scrl);
+	int  halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button5) {   /* note max vs. min, - vs. + */
+      /* scroll regardless of where we are in the browser window */
+      if (e->window == br->win ||
+	  e->window == br->scrl.win ||
+	  e->window == br->iconW)
+      {
+	SCRL *sp=&(br->scrl);
+	int  halfpage=MAX(1,sp->page/2); /* user resize to 1 line? */
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
       }
       else rv = 0;
     }
@@ -1598,6 +1673,10 @@
 {
   int sval, first, numvis;
 
+  /* if we know what path we have, remember last visible icon for this path */
+  if (br->path)
+    recIconVisible(br->path, num);
+
   /* if icon #i isn't visible, adjust scrollbar so it *is* */
 
   sval = br->scrl.val;
@@ -1649,29 +1728,14 @@
   return;
 }
 
-
 /***************************************************************/
-static int clickIconWin(br, mx, my, mtime, multi)
-     BROWINFO *br;
-     int mx,my,multi;
-     unsigned long mtime;
+static int updateSel(br, sel, multi, mtime)
+  BROWINFO *br;
+  int sel, multi;
+  unsigned long mtime;
 {
-  /* returns '-1' normally, returns an index into bfList[] if the user
-     double-clicks an icon */
-
-  int       i,j, rv, sel, cpymode, dodel;
-  BROWINFO *destBr;
-  BFIL     *bf;
-  char      buf[256], *destFolderName;
-
-  rv = -1;     /* default return value */
-  if (!br->bfList || !br->bfLen) return rv;
-
-  destBr = br;  destFolderName = ".";
-
-  sel = mouseInWhichIcon(br, mx, my);
-
-  dodel = 0;
+  int i;
+  BFIL *bf;
 
   if (sel == -1) {  /* clicked on nothing */
     if (!multi) {   /* deselect all */
@@ -1728,11 +1792,12 @@
 
 
     /* see if we've double-clicked something */
-    if (sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) {
+    if (mtime &&
+        sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) {
       br->lastIconClicked = -1;    /* YES */
 
       doubleClick(br, sel);
-      return rv;
+      return -1;
     }
 
     else {
@@ -1741,9 +1806,36 @@
     }
   }
 
-
   changedNumLit(br, -1, 0);
+  return 0;
+}
+
+
+/***************************************************************/
+static int clickIconWin(br, mx, my, mtime, multi)
+     BROWINFO *br;
+     int mx,my,multi;
+     unsigned long mtime;
+{
+  /* returns '-1' normally, returns an index into bfList[] if the user
+     double-clicks an icon */
+
+  int       i,j, sel, cpymode, dodel;
+  BROWINFO *destBr;
+  BFIL     *bf;
+  char      buf[256], *destFolderName;
+
+  if (!br->bfList || !br->bfLen) return -1;
 
+  destBr = br;  destFolderName = ".";
+
+  sel = mouseInWhichIcon(br, mx, my);
+  dodel = 0;
+
+  recIconVisible(br->path, sel);
+
+  if (updateSel(br, sel, multi, mtime))
+    return -1;
 
 
   {    /* track mouse until button1 is released */
@@ -2098,7 +2190,7 @@
     }
   }      /* end of 'tracking' sub-function */
 
-  return rv;
+  return -1;
 }
 
 /*******************************************/
@@ -2173,6 +2265,7 @@
     else {
       scanDir(br);
       SCSetVal(&(br->scrl), 0);  /* reset to top on a chdir */
+      restIconVisible(br);
     }
   }
 
@@ -2563,6 +2656,7 @@
     else {
       scanDir(br);
       SCSetVal(&br->scrl, 0);  /* reset to top of window on a chdir */
+      restIconVisible(br);
     }
   }
 }
@@ -2589,6 +2683,7 @@
     XBell(theDisp, 50);
   }
 
+  restIconVisible(br);
   strcat(br->path, "/");   /* put trailing '/' back on */
   return rv;
 }
@@ -3006,6 +3101,7 @@
     case RFT_XBM:      bf->ftype = BF_XBM;      break;
     case RFT_SUNRAS:   bf->ftype = BF_SUNRAS;   break;
     case RFT_BMP:      bf->ftype = BF_BMP;      break;
+    case RFT_WBMP:     bf->ftype = BF_BMP;      break;
     case RFT_UTAHRLE:  bf->ftype = BF_UTAHRLE;  break;
     case RFT_IRIS:     bf->ftype = BF_IRIS;     break;
     case RFT_PCX:      bf->ftype = BF_PCX;      break;
@@ -3013,12 +3109,16 @@
     case RFT_TIFF:     bf->ftype = BF_TIFF;     break;
     case RFT_PDSVICAR: bf->ftype = BF_PDS;      break;
     case RFT_COMPRESS: bf->ftype = BF_COMPRESS; break;
+    case RFT_BZIP2:    bf->ftype = BF_BZIP2;    break;
     case RFT_PS:       bf->ftype = BF_PS;       break;
     case RFT_IFF:      bf->ftype = BF_IFF;      break;
     case RFT_TARGA:    bf->ftype = BF_TARGA;    break;
     case RFT_XPM:      bf->ftype = BF_XPM;      break;
     case RFT_XWD:      bf->ftype = BF_XWD;      break;
     case RFT_FITS:     bf->ftype = BF_FITS;     break;
+    case RFT_PNG:      bf->ftype = BF_PNG;      break;
+    case RFT_ZX:       bf->ftype = BF_ZX;       break;	/* [JCE] */
+    case RFT_PCD:      bf->ftype = BF_PCD;      break;
     }
   }
 }
@@ -3431,7 +3531,7 @@
 
   filetype = ReadFileType(bf->name);
 
-  if (filetype == RFT_COMPRESS) {
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
 #if (defined(VMS) && !defined(GUNZIP))
     /* VMS decompress doesn't like the file to have a trailing .Z in fname
        however, GUnZip is OK with it, which we are calling UnCompress */
@@ -3442,7 +3542,7 @@
     uncName = bf->name;
 #endif
 
-    if (UncompressFile(uncName, uncompname)) {
+    if (UncompressFile(uncName, uncompname, filetype)) {
       filetype = ReadFileType(uncompname);
       readname = uncompname;
     }
@@ -3566,6 +3666,9 @@
   case RFT_XPM:      strcat(str,"XPM file");              break;
   case RFT_XWD:      strcat(str,"XWD file");              break;
   case RFT_FITS:     strcat(str,"FITS file");             break;
+  case RFT_PNG:      strcat(str,"PNG file");              break;
+  case RFT_ZX:       strcat(str,"Spectrum SCREEN$");      break; /* [JCE] */
+  case RFT_PCD:      strcat(str,"PhotoCD file");          break;
   default:           strcat(str,"file of unknown type");  break;
   }
 
@@ -4205,6 +4308,7 @@
   else {
     scanDir(br);
     SCSetVal(&(br->scrl), 0);	/* reset to top on a chdir */
+    restIconVisible(br);
   }
 }
 
@@ -4453,6 +4557,7 @@
   for (i=0; i<dirStackLen && strcmp(curDir, dirStack[i]); i++);
   if (i<dirStackLen) {   /* YES */
     chdir(orgDir);
+    restIconVisible(br);
     return;
   }
 
@@ -4460,6 +4565,7 @@
   if (!sp) {
     setBrowStr(br, "malloc() error in recurseUpdate()\n");
     chdir(orgDir);
+    restIconVisible(br);
     return;
   }
 
@@ -4495,6 +4601,7 @@
   xv_getwd(curDir, sizeof(curDir));
   if (strcmp(orgDir, curDir)) {   /* change back to orgdir */
     chdir(orgDir);
+    restIconVisible(br);
     scanDir(br);
   }
 }
@@ -4748,6 +4855,15 @@
   }
 
 
+  if (!cpymode) {
+    /* clear all lit files in the source folder (as they've been moved)
+       note:  this won't be the optimal behavior if any files failed to
+       move, but screw it, that's not going to happen too often... */
+    for (i=0; i<srcBr->bfLen; i++) srcBr->bfList[i].lit = 0;
+    srcBr->numlit = 0;
+  }
+
+
   /* clear all files in the destination folder */
   for (i=0; i<dstBr->bfLen; i++) {
     dstBr->bfList[i].lit = 0;
@@ -5418,4 +5534,56 @@
 }
 
 
+static IVIS *icon_vis_list = NULL;
+
+/***************************************************************/
+static void recIconVisible(name, icon)
+  char *name;
+  int   icon;
+{
+  IVIS *ptr, *prev = NULL;
+
+  for (ptr = icon_vis_list; ptr; prev = ptr, ptr = ptr->next) {
+    if (!strcmp(ptr->name, name)) {
+      ptr->icon = icon;
+      return;
+    }
+  }
+
+  ptr = calloc(sizeof(IVIS), 1);
+  if (!ptr)
+    return;
+
+  ptr->name = strdup(name);
+
+  if (!ptr->name) {
+    free(ptr);
+    return;
+  }
+
+  if (!prev) {
+    icon_vis_list = ptr;
+  } else {
+    prev->next = ptr;
+  }
+
+  ptr->next = NULL;
+  ptr->icon = icon;
+}
+
+/***************************************************************/
+static void restIconVisible(br)
+  BROWINFO *br;
+{
+  IVIS *ptr;
 
+  for (ptr = icon_vis_list; ptr; ptr = ptr->next) {
+    if (!strcmp(ptr->name, br->path)) {
+      if (ptr->icon >= 0) {
+        makeIconVisible(br, ptr->icon);
+        updateSel(br, ptr->icon, 0, 0);
+      }
+      return;
+    }
+  }
+}
diff -ruN xv-3.10a-bugfixes/xvctrl.c xv-3.10a-enhancements/xvctrl.c
--- xv-3.10a-bugfixes/xvctrl.c	2004-05-23 11:56:37.000000000 -0700
+++ xv-3.10a-enhancements/xvctrl.c	2004-05-23 12:15:18.000000000 -0700
@@ -104,7 +104,8 @@
 			     "Root: centered, warp",
 			     "Root: centered, brick",
     		             "Root: symmetrical tiled",
-			     "Root: symmetrical mirrored" };
+			     "Root: symmetrical mirrored",
+			     "Root: upper left corner" };
 
 static char *conv24MList[] = { "8-bit mode\t\2448",
 			       "24-bit mode\t\2448",
diff -ruN xv-3.10a-bugfixes/xvdial.c xv-3.10a-enhancements/xvdial.c
--- xv-3.10a-bugfixes/xvdial.c	2004-05-16 18:01:57.000000000 -0700
+++ xv-3.10a-enhancements/xvdial.c	2004-05-16 18:06:38.000000000 -0700
@@ -41,20 +41,21 @@
 
 
 /* local functions */
-static int  whereInDial     PARM((DIAL *, int, int));
-static void drawArrow       PARM((DIAL *));
-static void drawValStr      PARM((DIAL *));
-static void drawButt        PARM((DIAL *, int, int));
-static int  computeDialVal  PARM((DIAL *, int, int));
-static void dimDial         PARM((DIAL *));
+static int    whereInDial     PARM((DIAL *, int, int));
+static void   drawArrow       PARM((DIAL *));
+static void   drawValStr      PARM((DIAL *));
+static void   drawButt        PARM((DIAL *, int, int));
+static double computeDialVal  PARM((DIAL *, int, int));
+static void   dimDial         PARM((DIAL *));
 
 
 /***************************************************/
-void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, page,
+void DCreate(dp, parent, x, y, w, h, minv, maxv, curv, inc, page,
 	          fg, bg, hi, lo, title, units)
 DIAL         *dp;
 Window        parent;
-int           x,y,w,h,minv,maxv,curv,page;
+int           x,y,w,h;
+double        minv,maxv,curv,inc,page;
 unsigned long fg,bg,hi,lo;
 char         *title, *units;
 {
@@ -98,18 +99,18 @@
 				1,fg,bg);
   if (!dp->win) FatalError("can't create dial window");
 
-  DSetRange(dp, minv, maxv, curv, page);
+  DSetRange(dp, minv, maxv, curv, inc, page);
   XSelectInput(theDisp, dp->win, ExposureMask | ButtonPressMask);
 }
 
 
 /***************************************************/
-void DSetRange(dp, minv, maxv, curv, page)
-DIAL *dp;
-int   minv, maxv, curv, page;
+void DSetRange(dp, minv, maxv, curv, inc, page)
+DIAL   *dp;
+double  minv, maxv, curv, inc, page;
 {
   if (maxv<minv) maxv=minv;
-  dp->min = minv;    dp->max = maxv;    dp->page = page;
+  dp->min = minv; dp->max = maxv; dp->inc = inc; dp->page = page;
   dp->active =  (minv < maxv);
 
   DSetVal(dp, curv);
@@ -118,8 +119,8 @@
 
 /***************************************************/
 void DSetVal(dp, curv)
-DIAL *dp;
-int   curv;
+DIAL  *dp;
+double curv;
 {
   RANGE(curv, dp->min, dp->max);   /* make sure curv is in-range */
 
@@ -129,7 +130,7 @@
   XSetForeground(theDisp, theGC, dp->bg);
   drawArrow(dp);
 
-  dp->val = curv;
+  dp->val = (double)((int)(curv / dp->inc + (curv > 0 ? 0.5 : -0.5))) * dp->inc;
 
   /* draw new arrow and string */
   XSetForeground(theDisp, theGC, dp->fg);
@@ -202,7 +203,8 @@
 int mx,my;
 {
   Window       rW,cW;
-  int          rx,ry, x,y, ipos, pos, lit, i, origval;
+  int          rx, ry, x, y, ipos, pos, lit;
+  double       origval;
   unsigned int mask;
 
   lit = 0;
@@ -224,9 +226,9 @@
   if (ipos != INDIAL) {
     drawButt(dp, ipos, 1);
     switch (ipos) {
-    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1); break;
+    case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc);  break;
     case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page); break;
-    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1); break;
+    case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);  break;
     case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page); break;
     }
     if (dp->drawobj != NULL) (dp->drawobj)();
@@ -235,8 +237,9 @@
   }
 
   else {
-    i = computeDialVal(dp, mx, my);
-    DSetVal(dp, i);
+    double v;
+    v = computeDialVal(dp, mx, my);
+    DSetVal(dp, v);
     if (dp->drawobj != NULL) (dp->drawobj)();
   }
 
@@ -246,11 +249,11 @@
     if (!(mask & Button1Mask)) break;    /* button released */
 
     if (ipos == INDIAL) {
-      int j;
-      i = computeDialVal(dp, x, y);
-      j = dp->val;
-      DSetVal(dp, i);
-      if (j != dp->val) {
+      double v, w;
+      v = computeDialVal(dp, x, y);
+      w = dp->val;
+      DSetVal(dp, v);
+      if (w != dp->val) {
 	/* track whatever dial controls */
 	if (dp->drawobj != NULL) (dp->drawobj)();
       }
@@ -266,11 +269,11 @@
 
       if (lit) {
 	switch (ipos) {
-	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+1);
+	case INCW1:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->inc);
 	             break;
 	case INCW2:  if (dp->val < dp->max) DSetVal(dp, dp->val+dp->page);
                      break;
-	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-1);
+	case INCCW1: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->inc);
                      break;
 	case INCCW2: if (dp->val > dp->min) DSetVal(dp, dp->val-dp->page);
                      break;
@@ -320,19 +323,20 @@
 static void drawArrow(dp)
 DIAL *dp;
 {
-  int i, rad, cx, cy;
+  int rad, cx, cy;
+  double v;
   XPoint arrow[4];
 
   rad = dp->rad;  cx = dp->cx;  cy = dp->cy;
 
   /* map pos (range minv..maxv) into degrees (range 240..-60) */
-  i = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
-  arrow[0].x = cx + (int) ((double) rad * .80 * cos(i * DEG2RAD));
-  arrow[0].y = cy - (int) ((double) rad * .80 * sin(i * DEG2RAD));
-  arrow[1].x = cx + (int) ((double) rad * .33 * cos((i+160) * DEG2RAD));
-  arrow[1].y = cy - (int) ((double) rad * .33 * sin((i+160) * DEG2RAD));
-  arrow[2].x = cx + (int) ((double) rad * .33 * cos((i-160) * DEG2RAD));
-  arrow[2].y = cy - (int) ((double) rad * .33 * sin((i-160) * DEG2RAD));
+  v = 240 + (-300 * (dp->val - dp->min)) / (dp->max - dp->min);
+  arrow[0].x = cx + (int) ((double) rad * .80 * cos(v * DEG2RAD));
+  arrow[0].y = cy - (int) ((double) rad * .80 * sin(v * DEG2RAD));
+  arrow[1].x = cx + (int) ((double) rad * .33 * cos((v+160) * DEG2RAD));
+  arrow[1].y = cy - (int) ((double) rad * .33 * sin((v+160) * DEG2RAD));
+  arrow[2].x = cx + (int) ((double) rad * .33 * cos((v-160) * DEG2RAD));
+  arrow[2].y = cy - (int) ((double) rad * .33 * sin((v-160) * DEG2RAD));
   arrow[3].x = arrow[0].x;
   arrow[3].y = arrow[0].y;
   XDrawLines(theDisp, dp->win, theGC, arrow, 4, CoordModeOrigin);
@@ -343,23 +347,37 @@
 static void drawValStr(dp)
 DIAL *dp;
 {
-  int  i, x1, x2;
+  int  tot, i, x1, x2;
   char foo[60], foo1[60];
 
   /* compute longest string necessary so we can right-align this thing */
-  sprintf(foo,"%d",dp->min);    x1 = strlen(foo);
-  sprintf(foo,"%d",dp->max);    x2 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->min);    x1 = strlen(foo);
+  sprintf(foo,"%d",(int)dp->max);    x2 = strlen(foo);
   if (dp->min < 0 && dp->max > 0) x2++;   /* put '+' at beginning */
   i = x1;  if (x2>x1) i = x2;
   if (dp->units) i += strlen(dp->units);
 
-  if (dp->min < 0 && dp->max > 0) sprintf(foo,"%+d", dp->val);
-  else sprintf(foo,"%d", dp->val);
+  sprintf(foo,"%g",dp->inc);   /* space for decimal values */
+  tot = i + strlen(foo) - 1;   /* Take away the 0 from the beginning */
+
+  if (dp->min < 0.0 && dp->max > 0.0) sprintf(foo,"%+g", dp->val);
+  else sprintf(foo,"%g", dp->val);
+
+  if (dp->inc < 1.0)
+  {
+    int j;
+
+    if (dp->val == (double)((int)dp->val))
+      strcat(foo,".");
+
+    for (j = strlen(foo); j < tot; j++)
+      strcat(foo,"0");
+  }
 
   if (dp->units) strcat(foo,dp->units);
   foo1[0] = '\0';
   if (strlen(foo) < (size_t) i) {
-    for (i = i - strlen(foo); i>0; i--) strcat(foo1," ");
+    for (i-=strlen(foo);i>0;i--) strcat(foo1," ");
   }
   strcat(foo1, foo);
 
@@ -411,12 +429,13 @@
 
 
 /***************************************************/
-static int computeDialVal(dp, x, y)
+static double computeDialVal(dp, x, y)
 DIAL *dp;
 int x, y;
 {
-  int dx, dy, val;
-  double angle;
+  int dx, dy;
+
+  double angle, val;
 
   /* compute dx, dy (distance from cx, cy).  Note: +dy is *up* */
   dx = x - dp->cx;  dy = dp->cy - y;
@@ -436,8 +455,10 @@
   if (angle > 270.0) angle -= 360.0;
   if (angle < -90.0) angle += 360.0;
 
-  val = (int) ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
+  val = ((dp->max - dp->min) * (240.0 - angle) / 300.0) + dp->min;
 
+  /* round value to be an even multiple of dp->inc */
+  val = (double)((int)(val / dp->inc + 0.5)) * dp->inc;
   return val;
 }
 
diff -ruN xv-3.10a-bugfixes/xvdir.c xv-3.10a-enhancements/xvdir.c
--- xv-3.10a-bugfixes/xvdir.c	2005-03-20 18:38:30.000000000 -0800
+++ xv-3.10a-enhancements/xvdir.c	2005-04-10 09:52:19.000000000 -0700
@@ -62,6 +62,9 @@
 #ifdef HAVE_TIFF
 			       "TIFF",
 #endif
+#ifdef HAVE_PNG
+			       "PNG",
+#endif
 			       "PostScript",
 			       "PBM/PGM/PPM (raw)",
 			       "PBM/PGM/PPM (ascii)",
@@ -73,6 +76,8 @@
 			       "Targa (24-bit)",
 			       "FITS",
 			       "PM",
+			       "Spectrum SCREEN$",	/* [JCE] */
+			       "WBMP",
 			       MBSEP,
 			       "Filename List"};
 
@@ -847,7 +852,7 @@
     scrollToFileName();
   }
 
-  else if (c=='\010' || c=='\177') {    /* BS or DEL */
+  else if (c=='\010') {                 /* BS */
     if (curPos==0) return(-1);          /* at beginning of str */
     xvbcopy(&filename[curPos], &filename[curPos-1], (size_t) (len-curPos+1));
     curPos--;
@@ -872,7 +877,7 @@
     curPos = len;
   }
 
-  else if (c=='\004') {                 /* ^D: delete character at curPos */
+  else if (c=='\004' || c=='\177') {    /* ^D or DEL: delete character at curPos */
     if (curPos==len) return(-1);
     xvbcopy(&filename[curPos+1], &filename[curPos], (size_t) (len-curPos));
   }
@@ -1116,6 +1121,15 @@
   }
 #endif
 
+#ifdef HAVE_PNG
+  else if (fmt == F_PNG) {   /* PNG */
+    PNGSaveParams(fullname, col);
+    PNGDialog(1);                   /* open PNG Dialog box */
+    dbut[S_BOK].lit = 0;  BTRedraw(&dbut[S_BOK]);
+    return 0;                      /* always 'succeeds' */
+  }
+#endif
+
 
 
 
@@ -1164,6 +1178,10 @@
     rv = WriteBMP   (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
     break;
 
+  case F_WBMP:
+    rv = WriteWBMP  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
+    break;
+
   case F_IRIS:
     rv = WriteIRIS  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col);
     break;
@@ -1181,6 +1199,11 @@
     rv = WriteFITS  (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
 		     picComments);
     break;
+
+  case F_ZX:		/* [JCE] Spectrum SCREEN$ */
+    rv = WriteZX    (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,picComments);
+    break;
+
   }
 
 
@@ -1310,7 +1333,8 @@
 
   else if (group == F_FORMAT) {
     MBSelect(&fmtMB, bnum);
-    if (MBWhich(&fmtMB) == F_XBM) { /* turn off all but B/W */
+    if (MBWhich(&fmtMB) == F_XBM ||
+	MBWhich(&fmtMB) == F_WBMP) { /* turn off all but B/W */
       colMB.dim[F_FULLCOLOR] = 1;
       colMB.dim[F_GREYSCALE] = 1;
       colMB.dim[F_BWDITHER]  = 0;
@@ -1389,14 +1413,22 @@
       (strcmp(lowsuf,"eps" )==0) ||
       (strcmp(lowsuf,"rgb" )==0) ||
       (strcmp(lowsuf,"tga" )==0) ||
-      (strcmp(lowsuf,"xpm" )==0) ||
       (strcmp(lowsuf,"fits")==0) ||
       (strcmp(lowsuf,"fts" )==0) ||
+#ifdef HAVE_JPEG
       (strcmp(lowsuf,"jpg" )==0) ||
       (strcmp(lowsuf,"jpeg")==0) ||
       (strcmp(lowsuf,"jfif")==0) ||
+#endif
+#ifdef HAVE_TIFF
       (strcmp(lowsuf,"tif" )==0) ||
-      (strcmp(lowsuf,"tiff")==0)) {
+      (strcmp(lowsuf,"tiff")==0) ||
+#endif
+#ifdef HAVE_PNG
+      (strcmp(lowsuf,"png" )==0) ||
+#endif
+      (strcmp(lowsuf,"wbmp")==0) ||
+      (strcmp(lowsuf,"xpm" )==0)) {
 
     /* found one.  set lowsuf = to the new suffix, and tack on to filename */
 
@@ -1419,6 +1451,7 @@
     case F_XBM:      strcpy(lowsuf,"xbm");  break;
     case F_SUNRAS:   strcpy(lowsuf,"ras");  break;
     case F_BMP:      strcpy(lowsuf,"bmp");  break;
+    case F_WBMP:     strcpy(lowsuf,"wbmp"); break;
     case F_PS:       strcpy(lowsuf,"ps");   break;
     case F_IRIS:     strcpy(lowsuf,"rgb");  break;
     case F_TARGA:    strcpy(lowsuf,"tga");  break;
@@ -1432,6 +1465,10 @@
 #ifdef HAVE_TIFF
     case F_TIFF:     strcpy(lowsuf,"tif");  break;
 #endif
+
+#ifdef HAVE_PNG
+    case F_PNG:      strcpy(lowsuf,"png");  break;
+#endif
     }
 
     if (allcaps) {  /* upper-caseify lowsuf */
diff -ruN xv-3.10a-bugfixes/xvevent.c xv-3.10a-enhancements/xvevent.c
--- xv-3.10a-bugfixes/xvevent.c	2004-05-16 18:02:03.000000000 -0700
+++ xv-3.10a-enhancements/xvevent.c	2005-04-10 09:52:19.000000000 -0700
@@ -71,7 +71,12 @@
 {
   XEvent event;
   int    retval,done,waiting;
-  time_t orgtime, curtime;
+#ifdef USE_TICKS
+  clock_t waitsec_ticks=0L, orgtime_ticks=0L, curtime_ticks;
+  clock_t elapsed_ticks=0L, remaining_interval;
+#else
+  time_t orgtime=0L, curtime;
+#endif
 
 
 #ifndef NOSIGNAL
@@ -100,18 +105,24 @@
 
   while (!done) {
 
-    if (waitsec > -1 && canstartwait && !waiting && XPending(theDisp)==0) {
+    if (waitsec >= 0.0 && canstartwait && !waiting && XPending(theDisp)==0) {
       /* we wanna wait, we can wait, we haven't started waiting yet, and
 	 all pending events (ie, drawing the image the first time)
 	 have been dealt with:  START WAITING */
-      time((time_t *) &orgtime);
+#ifdef USE_TICKS
+      waitsec_ticks = (clock_t)(waitsec * CLK_TCK);
+      orgtime_ticks = times(NULL);  /* unclear if NULL valid, but OK on Linux */
+#else
+      orgtime = time(NULL);
+#endif
       waiting = 1;
     }
 
 
     /* if there's an XEvent pending *or* we're not doing anything
        in real-time (polling, flashing the selection, etc.) get next event */
-    if ((waitsec==-1 && !polling && !HaveSelection()) || XPending(theDisp)>0) {
+    if ((waitsec<0.0 && !polling && !HaveSelection()) || XPending(theDisp)>0)
+    {
       XNextEvent(theDisp, &event);
       retval = HandleEvent(&event,&done);
     }
@@ -121,7 +132,7 @@
 	DrawSelection(0);
 	DrawSelection(1);
 	XFlush(theDisp);
-	Timer(200);
+	Timer(200);             /* milliseconds */
       }
 
       if (polling) {
@@ -129,13 +140,32 @@
 	else if (!XPending(theDisp)) sleep(1);
       }
 
-      if (waitsec>-1 && waiting) {
-	time((time_t *) &curtime);
-	if (curtime - orgtime < waitsec) sleep(1);
-	else {
-	  if (waitloop) return NEXTLOOP;
-	  else return NEXTQUIT;
-	}
+      if (waitsec>=0.0 && waiting) {
+#ifdef USE_TICKS
+        curtime_ticks = times(NULL);   /* value in ticks */
+        if (curtime_ticks < orgtime_ticks) {
+          /* clock ticks rolled over:  need to correct for that (i.e.,
+           *  curtime_ticks is presumably quite small, while orgtime_ticks
+           *  should be close to LONG_MAX, so do math accordingly--any way
+           *  to check whether clock_t is *not* a signed long?) */
+          elapsed_ticks = curtime_ticks + (LONG_MAX - orgtime_ticks);
+        } else
+          elapsed_ticks = curtime_ticks - orgtime_ticks;
+        remaining_interval = waitsec_ticks - elapsed_ticks;
+        if (remaining_interval >= (clock_t)(1 * CLK_TCK))
+          sleep(1);
+        else {
+          /* less than one second remaining:  do delay in msec, then return */
+          Timer((remaining_interval * 1000L) / CLK_TCK);  /* can't overflow */
+          return waitloop? NEXTLOOP : NEXTQUIT;
+        }
+#else
+        curtime = time(NULL);          /* value in seconds */
+	if (curtime - orgtime < (time_t)waitsec)
+          sleep(1);
+	else
+          return waitloop? NEXTLOOP : NEXTQUIT;
+#endif
       }
     }
   }  /* while (!done) */
@@ -154,7 +184,7 @@
      int    *donep;
 {
   static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
-  static int wasJpegUp=0, wasTiffUp=0;
+  static int wasJpegUp=0, wasTiffUp=0, wasPngUp=0, wasPcdUp=0;
 
   static int mainWKludge=0;  /* force first mainW expose after a mainW config
 				to redraw all of mainW */
@@ -233,6 +263,12 @@
     if (TIFFCheckEvent(event)) break;   /* event has been processed */
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;   /* event has been processed */
+#endif
+
+    if (PCDCheckEvent(event)) break;    /* event has been processed */
+
     if (GamCheckEvent (event)) break;   /* event has been processed */
     if (BrowseCheckEvent (event, &retval, &done)) break;   /* event eaten */
     if (TextCheckEvent   (event, &retval, &done)) break;   /* event eaten */
@@ -359,6 +395,12 @@
       else if (client_event->window == tiffW) TIFFDialog(0);
 #endif
 
+#ifdef HAVE_PNG
+      else if (client_event->window == pngW)  PNGDialog(0);
+#endif
+
+      else if (client_event->window == pcdW)  PCDDialog(0);
+
       else if (client_event->window == mainW) Quit(0);
     }
   }
@@ -534,10 +576,13 @@
 #ifdef HAVE_JPEG
 	if (wasJpegUp) { JPEGDialog(wasJpegUp);  wasJpegUp=0; }
 #endif
-
 #ifdef HAVE_TIFF
 	if (wasTiffUp) { TIFFDialog(wasTiffUp);  wasTiffUp=0; }
 #endif
+#ifdef HAVE_PNG
+	if (wasPngUp)  { PNGDialog(wasJpegUp);   wasPngUp=0; }
+#endif
+	if (wasPcdUp)  { PCDDialog(wasPcdUp);    wasPcdUp=0; }
       }
     }
   }
@@ -572,10 +617,13 @@
 #ifdef HAVE_JPEG
 	  if (jpegUp) { wasJpegUp = jpegUp;  JPEGDialog(0); }
 #endif
-
 #ifdef HAVE_TIFF
 	  if (tiffUp) { wasTiffUp = tiffUp;  TIFFDialog(0); }
 #endif
+#ifdef HAVE_PNG
+	  if (pngUp)  { wasPngUp  = pngUp;   PNGDialog(0); }
+#endif
+	  if (pcdUp)  { wasPcdUp = pcdUp;    PCDDialog(0); }
 	}
       }
     }
@@ -1147,6 +1195,12 @@
     if (TIFFCheckEvent(event)) break;
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+
+    if (PCDCheckEvent (event)) break;	/* event has been processed */
+
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
@@ -1276,6 +1330,48 @@
       else if (shift) BlurPaint();
       break;
 
+    case Button4:   /* note min vs. max, + vs. - */
+      if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
+	SCRL *sp=&nList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else if (win ==  dirW || win == dList.win || win == dList.scrl.win) {
+	SCRL *sp=&dList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      break;
+
+    case Button5:   /* note max vs. min, - vs. + */
+      if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
+	SCRL *sp=&nList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      else if (win ==  dirW || win == dList.win || win == dList.scrl.win) {
+	SCRL *sp=&dList.scrl;
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      break;
+
     default:       break;
     }
   }
@@ -1364,6 +1460,12 @@
     if (TIFFCheckEvent(event)) break;
 #endif
 
+#ifdef HAVE_PNG
+    if (PNGCheckEvent (event)) break;
+#endif
+
+    if (PCDCheckEvent (event)) break;
+
     if (GamCheckEvent (event)) break;
     if (BrowseCheckEvent (event, &retval, &done)) break;
     if (TextCheckEvent   (event, &retval, &done)) break;
@@ -1578,13 +1680,13 @@
 	}
 	break;
 
-      case '\010':
-      case '\177': FakeButtonPress(&but[BPREV]);    break;
+      case '\010': FakeButtonPress(&but[BPREV]);    break;
 
 
       case '\014': FakeButtonPress(&but[BLOAD]);    break;  /* ^L */
       case '\023': FakeButtonPress(&but[BSAVE]);    break;  /* ^S */
       case '\020': FakeButtonPress(&but[BPRINT]);   break;  /* ^P */
+      case '\177':
       case '\004': FakeButtonPress(&but[BDELETE]);  break;  /* ^D */
 
 	/* BCOPY, BCUT, BPASTE, BCLEAR handled in 'meta' case */
@@ -2370,6 +2472,12 @@
   if (tiffUp) TIFFDialog(0);  /* close tiff window */
 #endif
 
+#ifdef HAVE_PNG
+  if (pngUp) PNGDialog(0);    /* close png window */
+#endif
+
+  if (pcdUp) PCDDialog(0);    /* close pcd window */
+
   ClosePopUp();
 
   /* make the interrupt signal look like a '\n' keypress in ctrlW */
diff -ruN xv-3.10a-bugfixes/xvgam.c xv-3.10a-enhancements/xvgam.c
--- xv-3.10a-bugfixes/xvgam.c	2004-05-16 18:02:11.000000000 -0700
+++ xv-3.10a-enhancements/xvgam.c	2004-05-16 18:06:48.000000000 -0700
@@ -265,11 +265,11 @@
   BTCreate(&gbut[G_BRNDCOL], cmapF,  5 + 66 + 67 + 2, 189, 66, BUTTH,
 	   "Random", infofg, infobg, hicol, locol);
 
-  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0,360,180, 5,
+  DCreate(&rhDial, cmapF, 5, 215, 66, 100,   0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Hue", NULL);
-  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0,360,180, 5,
+  DCreate(&gsDial, cmapF, 72, 215, 66, 100,  0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Sat.", NULL);
-  DCreate(&bvDial, cmapF, 139, 215, 66, 100,   0,360,180, 5,
+  DCreate(&bvDial, cmapF, 139, 215, 66, 100, 0.0, 360.0, 180.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Value", NULL);
 
   rhDial.drawobj = gsDial.drawobj = bvDial.drawobj = dragEditColor;
@@ -359,7 +359,7 @@
 
   srcHD.drawobj = dstHD.drawobj = whtHD.drawobj = dragHueDial;
 
-  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100, 100, 0, 5,
+  DCreate(&satDial, hsvF, 100, 199, 100, 121, -100.0, 100.0, 0.0, 1.0, 5.0,
 	   infofg, infobg,hicol,locol, "Saturation", "%");
 
   hueRB = RBCreate(NULL, hsvF,  7, 153, "1",
@@ -722,7 +722,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvnonlinear++;
 
-  if (satDial.val != 0) hsvnonlinear++;
+  if (satDial.val != 0.0) hsvnonlinear++;
 
   /* check intensity graf */
   for (i=0; i<256 && intGraf.func[i]==i; i++);
@@ -1291,14 +1291,14 @@
     rgb2hsv(rcmap[editColor], gcmap[editColor], bcmap[editColor], &h, &s, &v);
     if (h<0) h = 0;
 
-    DSetVal(&rhDial, (int) h);
-    DSetVal(&gsDial, (int) (s*100));
-    DSetVal(&bvDial, (int) (v*100));
+    DSetVal(&rhDial, h);
+    DSetVal(&gsDial, s*100);
+    DSetVal(&bvDial, v*100);
   }
   else {
-    DSetVal(&rhDial, rcmap[editColor]);
-    DSetVal(&gsDial, gcmap[editColor]);
-    DSetVal(&bvDial, bcmap[editColor]);
+    DSetVal(&rhDial, (double)rcmap[editColor]);
+    DSetVal(&gsDial, (double)gcmap[editColor]);
+    DSetVal(&bvDial, (double)bcmap[editColor]);
   }
 }
 
@@ -1310,16 +1310,15 @@
 
   if (hsvmode) {
     int rv, gv, bv;
-    hsv2rgb((double) rhDial.val, ((double) gsDial.val) / 100.0,
-	    ((double) bvDial.val) / 100.0, &rv, &gv, &bv);
+    hsv2rgb(rhDial.val, gsDial.val / 100.0, bvDial.val / 100.0, &rv, &gv, &bv);
     rcmap[editColor] = rv;
     gcmap[editColor] = gv;
     bcmap[editColor] = bv;
   }
   else {
-    rcmap[editColor] = rhDial.val;
-    gcmap[editColor] = gsDial.val;
-    bcmap[editColor] = bvDial.val;
+    rcmap[editColor] = (int)rhDial.val;
+    gcmap[editColor] = (int)gsDial.val;
+    bcmap[editColor] = (int)bvDial.val;
   }
 }
 
@@ -1561,9 +1560,9 @@
     gsDial.title = "Green";
     bvDial.title = "Blue";
 
-    DSetRange(&rhDial, 0, 255, rcmap[editColor], 16);
-    DSetRange(&gsDial, 0, 255, gcmap[editColor], 16);
-    DSetRange(&bvDial, 0, 255, bcmap[editColor], 16);
+    DSetRange(&rhDial, 0.0, 255.0, (double)rcmap[editColor], 1.0, 16.0);
+    DSetRange(&gsDial, 0.0, 255.0, (double)gcmap[editColor], 1.0, 16.0);
+    DSetRange(&bvDial, 0.0, 255.0, (double)bcmap[editColor], 1.0, 16.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1581,9 +1580,9 @@
 	    &h, &s, &v);
 
     if (h<0.0) h = 0.0;
-    DSetRange(&rhDial, 0, 360, (int) h, 5);
-    DSetRange(&gsDial, 0, 100, (int) (s*100), 5);
-    DSetRange(&bvDial, 0, 100, (int) (v*100), 5);
+    DSetRange(&rhDial, 0.0, 360.0,     h, 1.0, 5.0);
+    DSetRange(&gsDial, 0.0, 100.0, s*100, 1.0, 5.0);
+    DSetRange(&bvDial, 0.0, 100.0, v*100, 1.0, 5.0);
 
     XClearWindow(theDisp, rhDial.win);    DRedraw(&rhDial);
     XClearWindow(theDisp, gsDial.win);    DRedraw(&gsDial);
@@ -1891,7 +1890,7 @@
     }
 
     /* apply satDial value to s */
-    s = s + ((double) satDial.val) / 100.0;
+    s = s + satDial.val / 100.0;
     if (s<0.0) s = 0.0;
     if (s>1.0) s = 1.0;
 
@@ -2007,7 +2006,7 @@
 
   gs->hueRBnum = RBWhich(hueRB);
 
-  gs->satval = satDial.val;
+  gs->satval = (int)satDial.val;
   GetGrafState(&intGraf,&gs->istate);
   GetGrafState(&rGraf,  &gs->rstate);
   GetGrafState(&gGraf,  &gs->gstate);
@@ -2064,8 +2063,8 @@
     changed++;
   }
 
-  if (gs->satval != satDial.val) {
-    DSetVal(&satDial,gs->satval);
+  if (gs->satval != (int)satDial.val) {
+    DSetVal(&satDial,(double)gs->satval);
     changed++;
   }
 
@@ -3200,7 +3199,7 @@
 
   if (whtHD.enabCB.val && whtHD.satval) hsvmod++;
 
-  if (satDial.val != 0) hsvmod++;
+  if (satDial.val != 0.0) hsvmod++;
 
   /* check intensity graf */
   for (i=0; i<256; i++) {
@@ -3284,7 +3283,7 @@
       }
 
       /* apply satDial value to s */
-      s = s + satDial.val;
+      s = s + (int)satDial.val;
       if (s<  0) s =   0;
       if (s>100) s = 100;
 
diff -ruN xv-3.10a-bugfixes/xvgif.c xv-3.10a-enhancements/xvgif.c
--- xv-3.10a-bugfixes/xvgif.c	2005-04-03 11:53:13.000000000 -0700
+++ xv-3.10a-enhancements/xvgif.c	2005-04-03 11:53:54.000000000 -0700
@@ -50,6 +50,7 @@
     BytesPerScanline,		/* bytes per scanline in output raster */
     ColorMapSize,		/* number of colors */
     Background,			/* background color */
+    Transparent,		/* transparent color (GRR 19980314) */
     CodeSize,			/* Code size, read from GIF header */
     InitCodeSize,		/* Starting code size, used during Clear */
     Code,			/* Value returned by ReadCode */
@@ -118,6 +119,7 @@
   Pass = -1;
   RawGIF = Raster = pic8 = NULL;
   gif89 = 0;
+  Transparent = -1;
 
   pinfo->pic     = (byte *) NULL;
   pinfo->comment = (char *) NULL;
@@ -336,10 +338,26 @@
 	SetISTR(ISTR_INFO, "%s:  %s", bname,
 		"Graphic Control Extension in GIF file.  Ignored.");
 
-	/* read (and ignore) data sub-blocks */
+	/* read (and ignore) data sub-blocks, unless compositing with
+         * user-defined background */
 	do {
-	  j = 0; sbsize = NEXTBYTE;
-	  while (j<sbsize) { SKIPBYTE;  j++; }
+	  j = 0;
+	  sbsize = NEXTBYTE;
+	  /* GRR 19980314:  get transparent index out of block */
+	  if (have_imagebg && sbsize == 4 && Transparent < 0) {
+	    byte packed_fields = NEXTBYTE;
+
+	    j++;
+	    SKIPBYTE;  j++;
+	    SKIPBYTE;  j++;
+	    if (packed_fields & 1) {
+	      Transparent = NEXTBYTE;
+	      j++;
+	    }
+	  }
+	  while (j<sbsize) {
+	    SKIPBYTE;  j++;
+	  }
 	} while (sbsize);
       }
 
@@ -484,6 +502,17 @@
   }
 
 
+  /* GRR 19980314 */
+  /* need not worry about size of EGA palette:  full 256 colors */
+  if (have_imagebg && Transparent >= 0 &&
+      Transparent < ((Misc&0x80)? (1 << ((Misc&7)+1)) : ColorMapSize) )
+  {
+    pinfo->r[Transparent] = (imagebgR >> 8);
+    pinfo->g[Transparent] = (imagebgG >> 8);
+    pinfo->b[Transparent] = (imagebgB >> 8);
+  }
+
+
 
   /* Start reading the raster data. First we get the intial code size
    * and compute decompressor constant values, based on this code size.
diff -ruN xv-3.10a-bugfixes/xvimage.c xv-3.10a-enhancements/xvimage.c
--- xv-3.10a-bugfixes/xvimage.c	2005-03-31 07:23:39.000000000 -0800
+++ xv-3.10a-enhancements/xvimage.c	2005-04-08 07:35:35.000000000 -0700
@@ -21,6 +21,15 @@
  *            int  LoadPad(pinfo, fname);
  */
 
+/* The following switch should better be provided at runtime for
+ * comparison purposes.
+ * At the moment it's only compile time, unfortunately.
+ * Who can make adaptions for use as a runtime switch by a menu option?
+ * [GRR 19980607:  now via do_fixpix_smooth global; macro renamed to ENABLE_]
+ * [see http://sylvana.net/fixpix/ for home page, further info]
+ */
+/* #define ENABLE_FIXPIX_SMOOTH */   /* GRR 19980607:  moved into xv.h */
+
 #include "copyright.h"
 
 #include "xv.h"
@@ -36,7 +45,9 @@
 static int  doAutoCrop24      PARM((void));
 static void floydDitherize1   PARM((XImage *, byte *, int, int, int,
 				    byte *, byte *,byte *));
+#if 0 /* NOTUSED */
 static int  highbit           PARM((unsigned long));
+#endif
 
 static int  doPadSolid        PARM((char *, int, int, int, int));
 static int  doPadBggen        PARM((char *, int, int, int, int));
@@ -46,6 +57,267 @@
 static int  ReadImageFile1    PARM((char *, PICINFO *));
 
 
+/* The following array represents the pixel values for each shade
+ * of the primary color components.
+ * If 'p' is a pointer to a source image rgb-byte-triplet, we can
+ * construct the output pixel value simply by 'oring' together
+ * the corresponding components:
+ *
+ *	unsigned char *p;
+ *	unsigned long pixval;
+ *
+ *	pixval  = screen_rgb[0][*p++];
+ *	pixval |= screen_rgb[1][*p++];
+ *	pixval |= screen_rgb[2][*p++];
+ *
+ * This is both efficient and generic, since the only assumption
+ * is that the primary color components have separate bits.
+ * The order and distribution of bits does not matter, and we
+ * don't need additional variables and shifting/masking code.
+ * The array size is 3 KBytes total and thus very reasonable.
+ */
+
+static unsigned long screen_rgb[3][256];
+
+/* The following array holds the exact color representations
+ * reported by the system.
+ * This is useful for less than 24 bit deep displays as a base
+ * for additional dithering to get smoother output.
+ */
+
+static byte screen_set[3][256];
+
+/* The following routine initializes the screen_rgb and screen_set
+ * arrays.
+ * Since it is executed only once per program run, it does not need
+ * to be super-efficient.
+ *
+ * The method is to draw points in a pixmap with the specified shades
+ * of primary colors and then get the corresponding XImage pixel
+ * representation.
+ * Thus we can get away with any Bit-order/Byte-order dependencies.
+ *
+ * The routine uses some global X variables: theDisp, theScreen,
+ * and dispDEEP. Adapt these to your application as necessary.
+ * I've not passed them in as parameters, since for other platforms
+ * than X these may be different (see vfixpix.c), and so the
+ * screen_init() interface is unique.
+ *
+ * BUG: I've read in the "Xlib Programming Manual" from O'Reilly &
+ * Associates, that the DefaultColormap in TrueColor might not
+ * provide the full shade representation in XAllocColor.
+ * In this case one had to provide a 'best' colormap instead.
+ * However, my tests with Xaccel on a Linux-Box with a Mach64
+ * card were fully successful, so I leave that potential problem
+ * to you at the moment and would appreciate any suggestions...
+ */
+
+static void screen_init()
+{
+  static int init_flag; /* assume auto-init as 0 */
+  Pixmap check_map;
+  GC check_gc;
+  XColor check_col;
+  XImage *check_image;
+  int ci, i;
+
+  if (init_flag) return;
+  init_flag = 1;
+
+  check_map = XCreatePixmap(theDisp, RootWindow(theDisp,theScreen),
+			    1, 1, dispDEEP);
+  check_gc = XCreateGC(theDisp, check_map, 0, NULL);
+  for (ci = 0; ci < 3; ci++) {
+    for (i = 0; i < 256; i++) {
+      check_col.red = 0;
+      check_col.green = 0;
+      check_col.blue = 0;
+      /* Do proper upscaling from unsigned 8 bit (image data values)
+	 to unsigned 16 bit (X color representation). */
+      ((unsigned short *)&check_col.red)[ci] = (unsigned short)((i << 8) | i);
+      if (theVisual->class == TrueColor)
+	XAllocColor(theDisp, theCmap, &check_col);
+      else
+	xvAllocColor(theDisp, theCmap, &check_col);
+      screen_set[ci][i] =
+	(((unsigned short *)&check_col.red)[ci] >> 8) & 0xff;
+      XSetForeground(theDisp, check_gc, check_col.pixel);
+      XDrawPoint(theDisp, check_map, check_gc, 0, 0);
+      check_image = XGetImage(theDisp, check_map, 0, 0, 1, 1,
+			      AllPlanes, ZPixmap);
+      if (check_image) {
+	switch (check_image->bits_per_pixel) {
+	case 8:
+	  screen_rgb[ci][i] = *(CARD8 *)check_image->data;
+	  break;
+	case 16:
+	  screen_rgb[ci][i] = *(CARD16 *)check_image->data;
+	  break;
+	case 24:
+	  screen_rgb[ci][i] =
+	    ((unsigned long)*(CARD8 *)check_image->data << 16) |
+	    ((unsigned long)*(CARD8 *)(check_image->data + 1) << 8) |
+	    (unsigned long)*(CARD8 *)(check_image->data + 2);
+	  break;
+	case 32:
+	  screen_rgb[ci][i] = *(CARD32 *)check_image->data;
+	  break;
+	}
+	XDestroyImage(check_image);
+      }
+    }
+  }
+  XFreeGC(theDisp, check_gc);
+  XFreePixmap(theDisp, check_map);
+}
+
+
+#ifdef ENABLE_FIXPIX_SMOOTH
+
+/* The following code is based in part on:
+ *
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values.  Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count.  The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ *		...	(here)	7/16
+ *		3/16	5/16	1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed.  We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column.  (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ */
+
+typedef INT16 FSERROR;		/* 16 bits should be enough */
+typedef int LOCFSERROR;		/* use 'int' for calculation temps */
+
+typedef struct { byte    *colorset;
+		 FSERROR *fserrors;
+	       } FSBUF;
+
+/* Floyd-Steinberg initialization function.
+ *
+ * It is called 'fs2_init' since it's specialized for our purpose and
+ * could be embedded in a more general FS-package.
+ *
+ * Returns a malloced FSBUF pointer which has to be passed as first
+ * parameter to subsequent 'fs2_dither' calls.
+ * The FSBUF structure does not need to be referenced by the calling
+ * application, it can be treated from the app like a void pointer.
+ *
+ * The current implementation does only require to free() this returned
+ * pointer after processing.
+ *
+ * Returns NULL if malloc fails.
+ *
+ * NOTE: The FSBUF structure is designed to allow the 'fs2_dither'
+ * function to work with an *arbitrary* number of color components
+ * at runtime! This is an enhancement over the IJG code base :-).
+ * Only fs2_init() specifies the (maximum) number of components.
+ */
+
+static FSBUF *fs2_init(width)
+int width;
+{
+  FSBUF *fs;
+  FSERROR *p;
+
+  fs = (FSBUF *)
+    malloc(sizeof(FSBUF) * 3 + ((size_t)width + 2) * sizeof(FSERROR) * 3);
+  if (fs == 0) return fs;
+
+  fs[0].colorset = screen_set[0];
+  fs[1].colorset = screen_set[1];
+  fs[2].colorset = screen_set[2];
+
+  p = (FSERROR *)(fs + 3);
+  memset(p, 0, ((size_t)width + 2) * sizeof(FSERROR) * 3);
+
+  fs[0].fserrors = p;
+  fs[1].fserrors = p + 1;
+  fs[2].fserrors = p + 2;
+
+  return fs;
+}
+
+/* Floyd-Steinberg dithering function.
+ *
+ * NOTE:
+ * (1) The image data referenced by 'ptr' is *overwritten* (input *and*
+ *     output) to allow more efficient implementation.
+ * (2) Alternate FS dithering is provided by the sign of 'nc'. Pass in
+ *     a negative value for right-to-left processing. The return value
+ *     provides the right-signed value for subsequent calls!
+ * (3) This particular implementation assumes *no* padding between lines!
+ *     Adapt this if necessary.
+ */
+
+static int fs2_dither(fs, ptr, nc, num_rows, num_cols)
+FSBUF *fs;
+byte *ptr;
+int nc, num_rows, num_cols;
+{
+  int abs_nc, ci, row, col;
+  LOCFSERROR delta, cur, belowerr, bpreverr;
+  byte *dataptr, *colsetptr;
+  FSERROR *errorptr;
+
+  if ((abs_nc = nc) < 0) abs_nc = -abs_nc;
+  for (row = 0; row < num_rows; row++) {
+    for (ci = 0; ci < abs_nc; ci++, ptr++) {
+      dataptr = ptr;
+      colsetptr = fs[ci].colorset;
+      errorptr = fs[ci].fserrors;
+      if (nc < 0) {
+	dataptr += (num_cols - 1) * abs_nc;
+	errorptr += (num_cols + 1) * abs_nc;
+      }
+      cur = belowerr = bpreverr = 0;
+      for (col = 0; col < num_cols; col++) {
+	cur += errorptr[nc];
+	cur += 8; cur >>= 4;
+	if ((cur += *dataptr) < 0) cur = 0;
+	else if (cur > 255) cur = 255;
+	*dataptr = cur & 0xff;
+	cur -= colsetptr[cur];
+	delta = cur << 1; cur += delta;
+	bpreverr += cur; cur += delta;
+	belowerr += cur; cur += delta;
+	errorptr[0] = (FSERROR)bpreverr;
+	bpreverr = belowerr;
+	belowerr = delta >> 1;
+	dataptr += nc;
+	errorptr += nc;
+      }
+      errorptr[0] = (FSERROR)bpreverr;
+    }
+    ptr += (num_cols - 1) * abs_nc;
+    nc = -nc;
+  }
+  return nc;
+}
+
+#endif /* ENABLE_FIXPIX_SMOOTH */
+
 
 #define DO_CROP 0
 #define DO_ZOOM 1
@@ -1838,7 +2110,7 @@
      unsigned int   wide, high;
 {
   /*
-   * this has to do the none-to-simple bit of converting the data in 'pic24'
+   * This has to do the none-too-simple bit of converting the data in 'pic24'
    * into something usable by X.
    *
    * There are two major approaches:  if we're displaying on a TrueColor
@@ -1852,7 +2124,7 @@
    * mode.  (In that by this point, a 3/3/2 standard colormap has been
    * created for our use (though all 256 colors may not be unique...), and
    * we're just going to display the 24-bit picture by dithering with those
-   * colors
+   * colors.)
    *
    */
 
@@ -1890,33 +2162,17 @@
     /* Non-ColorMapped Visuals:  TrueColor, DirectColor                     */
     /************************************************************************/
 
-    unsigned long r, g, b, rmask, gmask, bmask, xcol;
-    int           rshift, gshift, bshift, bperpix, bperline, border, cshift;
-    int           maplen;
+    unsigned long xcol;
+    int           bperpix, bperline;
     byte         *imagedata, *lip, *ip, *pp;
 
 
-    /* compute various shifting constants that we'll need... */
-
-    rmask = theVisual->red_mask;
-    gmask = theVisual->green_mask;
-    bmask = theVisual->blue_mask;
-
-    rshift = 7 - highbit(rmask);
-    gshift = 7 - highbit(gmask);
-    bshift = 7 - highbit(bmask);
-
-    maplen = theVisual->map_entries;
-    if (maplen>256) maplen=256;
-    cshift = 7 - highbit((u_long) (maplen-1));
-
     xim = XCreateImage(theDisp, theVisual, dispDEEP, ZPixmap, 0, NULL,
 		        wide,  high, 32, 0);
     if (!xim) FatalError("couldn't create X image!");
 
     bperline = xim->bytes_per_line;
     bperpix  = xim->bits_per_pixel;
-    border   = xim->byte_order;
 
     imagedata = (byte *) malloc((size_t) (high * bperline));
     if (!imagedata) FatalError("couldn't malloc imagedata");
@@ -1930,85 +2186,141 @@
       FatalError(buf);
     }
 
+    screen_init();
 
-    lip = imagedata;  pp = pic24;
-    for (i=0; i<high; i++, lip+=bperline) {
-      for (j=0, ip=lip; j<wide; j++) {
-	r = *pp++;  g = *pp++;  b = *pp++;
-
-	/* shift r,g,b so that high bit of 8-bit color specification is
-	 * aligned with high bit of r,g,b-mask in visual,
-	 * AND each component with its mask,
-	 * and OR the three components together
-	 */
-
-	if (theVisual->class == DirectColor) {
-	  r = (u_long) directConv[(r>>cshift) & 0xff] << cshift;
-	  g = (u_long) directConv[(g>>cshift) & 0xff] << cshift;
-	  b = (u_long) directConv[(b>>cshift) & 0xff] << cshift;
-	}
-
-
-	/* shift the bits around */
-	if (rshift<0) r = r << (-rshift);
-	         else r = r >> rshift;
-
-	if (gshift<0) g = g << (-gshift);
-	         else g = g >> gshift;
-
-	if (bshift<0) b = b << (-bshift);
-	         else b = b >> bshift;
-
-	r = r & rmask;
-	g = g & gmask;
-	b = b & bmask;
-
-	xcol = r | g | b;
-
-	if (bperpix == 32) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>24) & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>24) & 0xff;
-	  }
-	}
-
-	else if (bperpix == 24) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>16) & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ = (xcol>>16) & 0xff;
-	  }
-	}
+#ifdef ENABLE_FIXPIX_SMOOTH
+    if (do_fixpix_smooth) {
+#if 0
+      /* If we wouldn't have to save the original pic24 image data,
+       * the following code would do the dither job by overwriting
+       * the image data, and the normal render code would then work
+       * without any change on that data.
+       * Unfortunately, this approach would hurt the xv assumptions...
+       */
+      if (bperpix < 24) {
+        FSBUF *fs = fs2_init(wide);
+        if (fs) {
+	  fs2_dither(fs, pic24, 3, high, wide);
+	  free(fs);
+        }
+      }
+#else
+      /* ...so we have to take a different approach with linewise
+       * dithering/rendering in a loop using a temporary line buffer.
+       */
+      if (bperpix < 24) {
+        FSBUF *fs = fs2_init(wide);
+        if (fs) {
+	  byte *row_buf = malloc((size_t)wide * 3);
+	  if (row_buf) {
+	    int nc = 3;
+	    byte *picp = pic24;  lip = imagedata;
+
+	    switch (bperpix) {
+	      case 8:
+	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
+	          memcpy(row_buf, picp, (size_t)wide * 3);
+	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
+	          for (j=0, ip=lip, pp=row_buf; j<wide; j++) {
+	            xcol  = screen_rgb[0][*pp++];
+	            xcol |= screen_rgb[1][*pp++];
+	            xcol |= screen_rgb[2][*pp++];
+		    *ip++ = xcol & 0xff;
+	          }
+	        }
+		break;
+
+	      case 16:
+	        for (i=0; i<high; i++, lip+=bperline, picp+=(size_t)wide*3) {
+	          CARD16 *ip16 = (CARD16 *)lip;
+	          memcpy(row_buf, picp, (size_t)wide * 3);
+	          nc = fs2_dither(fs, row_buf, nc, 1, wide);
+	          for (j=0, pp=row_buf; j<wide; j++) {
+	            xcol  = screen_rgb[0][*pp++];
+	            xcol |= screen_rgb[1][*pp++];
+	            xcol |= screen_rgb[2][*pp++];
+		    *ip16++ = (CARD16)xcol;
+	          }
+	        }
+		break;
+	    } /* end switch */
+
+	    free(row_buf);
+	    free(fs);
 
-	else if (bperpix == 16) {
-	  if (border == MSBFirst) {
-	    *ip++ = (xcol>>8)  & 0xff;
-	    *ip++ =  xcol      & 0xff;
-	  }
-	  else {  /* LSBFirst */
-	    *ip++ =  xcol      & 0xff;
-	    *ip++ = (xcol>>8)  & 0xff;
+	    return xim;
 	  }
-	}
-
-	else if (bperpix == 8) {
-	  *ip++ =  xcol      & 0xff;
-	}
+	  free(fs);
+        }
       }
+#endif /* 0? */
     }
+#endif /* ENABLE_FIXPIX_SMOOTH */
+
+    lip = imagedata;  pp = pic24;
+
+    switch (bperpix) {
+      case 8:
+        for (i=0; i<high; i++, lip+=bperline) {
+          for (j=0, ip=lip; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip++ = xcol & 0xff;
+          }
+        }
+        break;
+
+      case 16:
+        for (i=0; i<high; i++, lip+=bperline) {
+          CARD16 *ip16 = (CARD16 *)lip;
+          for (j=0; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip16++ = (CARD16)xcol;
+          }
+        }
+        break;
+
+      case 24:
+        for (i=0; i<high; i++, lip+=bperline) {
+          for (j=0, ip=lip; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+#ifdef USE_24BIT_ENDIAN_FIX
+	    if (border == MSBFirst) {
+	      *ip++ = (xcol>>16) & 0xff;
+	      *ip++ = (xcol>>8)  & 0xff;
+	      *ip++ =  xcol      & 0xff;
+	    }
+	    else {  /* LSBFirst */
+	      *ip++ =  xcol      & 0xff;
+	      *ip++ = (xcol>>8)  & 0xff;
+	      *ip++ = (xcol>>16) & 0xff;
+	    }
+#else /* GRR:  this came with the FixPix patch, but I don't think it's right */
+	    *ip++ = (xcol >> 16) & 0xff;    /* (no way to test, however, so  */
+	    *ip++ = (xcol >> 8)  & 0xff;    /* it's left enabled by default) */
+	    *ip++ =  xcol        & 0xff;
+#endif
+          }
+        }
+        break;
+
+      case 32:
+        for (i=0; i<high; i++, lip+=bperline) {
+          CARD32 *ip32 = (CARD32 *)lip;
+          for (j=0; j<wide; j++) {
+	    xcol  = screen_rgb[0][*pp++];
+	    xcol |= screen_rgb[1][*pp++];
+	    xcol |= screen_rgb[2][*pp++];
+	    *ip32++ = (CARD32)xcol;
+          }
+        }
+        break;
+    } /* end switch */
   }
 
   else {
@@ -2458,6 +2770,7 @@
 
 
 /***********************/
+#if 0 /* NOTUSED */
 static int highbit(ul)
 unsigned long ul;
 {
@@ -2470,6 +2783,7 @@
   for (i=31; ((ul & hb) == 0) && i>=0;  i--, ul<<=1);
   return i;
 }
+#endif /* 0 - NOTUSED */
 
 
 
@@ -2978,7 +3292,7 @@
 
   ftype = ReadFileType(name);
 
-  if (ftype == RFT_COMPRESS) {    /* handle compressed/gzipped files */
+  if ((ftype == RFT_COMPRESS) || (ftype == RFT_BZIP2)) {  /* handle .Z,gz,bz2 */
 #ifdef VMS
     basefname[0] = '\0';
     strcpy(basefname, name);     /* remove trailing .Z */
@@ -2988,7 +3302,7 @@
     uncName = name;
 #endif
 
-    if (UncompressFile(uncName, uncompname)) {
+    if (UncompressFile(uncName, uncompname, ftype)) {
       ftype = ReadFileType(uncompname);
       readname = uncompname;
     }
@@ -3029,9 +3343,3 @@
 
   return 1;
 }
-
-
-
-
-
-
diff -ruN xv-3.10a-bugfixes/xvjpeg.c xv-3.10a-enhancements/xvjpeg.c
--- xv-3.10a-bugfixes/xvjpeg.c	2005-03-27 16:23:06.000000000 -0800
+++ xv-3.10a-enhancements/xvjpeg.c	2005-03-27 17:24:04.000000000 -0800
@@ -51,11 +51,11 @@
 static    void         clickJD            PARM((int, int));
 static    void         doCmd              PARM((int));
 static    void         writeJPEG          PARM((void));
-METHODDEF void         xv_error_exit      PARM((j_common_ptr));
-METHODDEF void         xv_error_output    PARM((j_common_ptr));
-METHODDEF void         xv_prog_meter      PARM((j_common_ptr));
+METHODDEF(void)        xv_error_exit      PARM((j_common_ptr));
+METHODDEF(void)        xv_error_output    PARM((j_common_ptr));
+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_comment PARM((j_decompress_ptr));
 static    int          writeJFIF          PARM((FILE *, byte *, int,int,int));
 
 
@@ -85,10 +85,10 @@
 
   XSelectInput(theDisp, jpegW, ExposureMask | ButtonPressMask | KeyPressMask);
 
-  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1, 100, 75, 5,
+  DCreate(&qDial, jpegW, 10, 10, 80, 100, 1.0, 100.0, 75.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Quality", "%");
 
-  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0, 100, 0, 5,
+  DCreate(&smDial, jpegW, 120, 10, 80, 100, 0.0, 100.0, 0.0, 1.0, 5.0,
 	  infofg, infobg, hicol, locol, "Smoothing", "%");
 
   BTCreate(&jbut[J_BOK], jpegW, JWIDE-180-1, JHIGH-10-BUTTH-1, 80, BUTTH,
@@ -415,7 +415,7 @@
 
 
 /**************************************************/
-METHODDEF void xv_error_exit(cinfo)
+METHODDEF(void) xv_error_exit(cinfo)
      j_common_ptr cinfo;
 {
   my_error_ptr myerr;
@@ -427,7 +427,7 @@
 
 
 /**************************************************/
-METHODDEF void xv_error_output(cinfo)
+METHODDEF(void) xv_error_output(cinfo)
      j_common_ptr cinfo;
 {
   my_error_ptr myerr;
@@ -441,7 +441,7 @@
 
 
 /**************************************************/
-METHODDEF void xv_prog_meter(cinfo)
+METHODDEF(void) xv_prog_meter(cinfo)
      j_common_ptr cinfo;
 {
   struct jpeg_progress_mgr *prog;
@@ -706,7 +706,7 @@
 
 
 /**************************************************/
-METHODDEF boolean xv_process_comment(cinfo)
+METHODDEF(boolean) xv_process_comment(cinfo)
      j_decompress_ptr cinfo;
 {
   int          length, hasnull;
@@ -794,8 +794,8 @@
 
 
   jpeg_set_defaults(&cinfo);
-  jpeg_set_quality(&cinfo, qDial.val, TRUE);
-  cinfo.smoothing_factor = smDial.val;
+  jpeg_set_quality(&cinfo, (int)qDial.val, TRUE);
+  cinfo.smoothing_factor = (int)smDial.val;
 
 
   jpeg_start_compress(&cinfo, TRUE);
@@ -804,7 +804,7 @@
   /*** COMMENT HANDLING ***/
 
   sprintf(xvcmt, "%sXV %s  Quality = %d, Smoothing = %d\n",
-	  CREATOR_STR, REVDATE, qDial.val, smDial.val);
+	  CREATOR_STR, REVDATE, (int)qDial.val, (int)smDial.val);
 
   if (picComments) {   /* append XV comment */
     char *sp, *sp1;  int done;
@@ -866,4 +866,27 @@
 
 
 
+
+/*******************************************/
+void
+VersionInfoJPEG()	/* GRR 19980605, 19980607 */
+{
+  int major = JPEG_LIB_VERSION / 10;
+  int minor = JPEG_LIB_VERSION % 10;
+  char minoralpha[2];
+
+  if (minor) {
+    minoralpha[0] = (char)(minor - 1 + 'a');
+    minoralpha[1] = '\0';
+  } else
+    minoralpha[0] = '\0';
+
+/* fprintf(stderr, "   Compiled with libjpeg %d.%d.\n", major, minor); */
+  fprintf(stderr, "   Compiled with libjpeg %d%s.\n", major, minoralpha);
+}
+
+
+
+
+
 #endif  /* HAVE_JPEG */
diff -ruN xv-3.10a-bugfixes/xvmisc.c xv-3.10a-enhancements/xvmisc.c
--- xv-3.10a-bugfixes/xvmisc.c	2005-03-20 22:47:06.000000000 -0800
+++ xv-3.10a-enhancements/xvmisc.c	2005-04-10 09:52:10.000000000 -0700
@@ -103,10 +103,18 @@
   if (!usesize || !(i&WidthValue))  w = defw;
   if (!usesize || !(i&HeightValue)) h = defh;
 
-  hints.flags |= USSize;
+  hints.flags |= USSize | PWinGravity;
 
-  if (i&XValue && i&XNegative) x = dispWIDE - w - abs(x);
-  if (i&YValue && i&YNegative) y = dispHIGH - h - abs(y);
+  hints.win_gravity = NorthWestGravity;
+  if (i&XValue && i&XNegative) {
+    hints.win_gravity = NorthEastGravity;
+    x = dispWIDE - (w + 2 * bwidth) - abs(x);
+  }
+  if (i&YValue && i&YNegative) {
+    hints.win_gravity = (hints.win_gravity == NorthWestGravity) ?
+      SouthWestGravity : SouthEastGravity;
+    y = dispHIGH - (h + 2 * bwidth) - abs(y);
+  }
 
 
 #define VROOT_TRANS
@@ -142,20 +150,19 @@
   if (!win) return(win);   /* leave immediately if couldn't create */
 
 
-  XSetStandardProperties(theDisp, win, name, name, None, NULL, 0, &hints);
-
   xwmh.input = True;
   xwmh.flags = InputHint;
   if (iconPix) { xwmh.icon_pixmap = iconPix;  xwmh.flags |= IconPixmapHint; }
-  XSetWMHints(theDisp, win, &xwmh);
 
   if (clname && strlen(clname)) {
     classh.res_name = "xv";
     classh.res_class = clname;
-    XSetClassHint(theDisp, win, &classh);
     StoreDeleteWindowProp(win);
   }
 
+  XmbSetWMProperties(theDisp, win, name, name, NULL, 0, &hints, &xwmh,
+      clname ? &classh : NULL);
+
   return(win);
 }
 
@@ -232,28 +239,28 @@
   int  i = CK_NONE;
 
   if      (ks==XK_Up    || ks==XK_KP_Up    ||
-	   ks==XK_KP_8  || ks==XK_F28)             i=CK_UP;
+			   ks==XK_F28)             i=CK_UP;
 
   else if (ks==XK_Down  || ks==XK_KP_Down  ||
-	   ks==XK_KP_2  || ks==XK_F34)             i=CK_DOWN;
+			   ks==XK_F34)             i=CK_DOWN;
 
   else if (ks==XK_Left  || ks==XK_KP_Left  ||
-	   ks==XK_KP_4  || ks==XK_F30)             i=CK_LEFT;
+			   ks==XK_F30)             i=CK_LEFT;
 
   else if (ks==XK_Right || ks==XK_KP_Right ||
-	   ks==XK_KP_6  || ks==XK_F32)             i=CK_RIGHT;
+			   ks==XK_F32)             i=CK_RIGHT;
 
   else if (ks==XK_Prior || ks==XK_KP_Prior ||
-	   ks==XK_KP_9  || ks==XK_F29)             i=CK_PAGEUP;
+			   ks==XK_F29)             i=CK_PAGEUP;
 
   else if (ks==XK_Next  || ks==XK_KP_Next  ||
-	   ks==XK_KP_3  || ks==XK_F35)             i=CK_PAGEDOWN;
+			   ks==XK_F35)             i=CK_PAGEDOWN;
 
   else if (ks==XK_Home  || ks==XK_KP_Home  ||
-	   ks==XK_KP_7  || ks==XK_F27)             i=CK_HOME;
+			   ks==XK_F27)             i=CK_HOME;
 
   else if (ks==XK_End   || ks==XK_KP_End   ||
-	   ks==XK_KP_1  || ks==XK_F33)             i=CK_END;
+			   ks==XK_F33)             i=CK_END;
 
   else i = CK_NONE;
 
@@ -526,6 +533,12 @@
     if (tiffW) XDestroyWindow(theDisp, tiffW);
 #endif
 
+#ifdef HAVE_PNG
+    if (pngW)  XDestroyWindow(theDisp, pngW);
+#endif
+
+    if (pcdW)  XDestroyWindow(theDisp, pcdW);
+
     /* if NOT using stdcmap for images, free stdcmap */
     if (colorMapMode != CM_STDCMAP) {
       int j;
@@ -722,6 +735,12 @@
 #ifdef HAVE_TIFF
   if (tiffW) XDefineCursor(theDisp, tiffW, otherc);
 #endif
+
+#ifdef HAVE_PNG
+  if (pngW)  XDefineCursor(theDisp, pngW, otherc);
+#endif
+
+  if (pcdW)  XDefineCursor(theDisp, pcdW, otherc);
 }
 
 
@@ -921,7 +940,7 @@
 void XVCreatedFile(fullname)
      char *fullname;
 {
-  /* called whenever a file has been deleted.  Updates browser & dir windows,
+  /* called whenever a file has been created.  Updates browser & dir windows,
      if necessary */
 
   BRCreatedFile(fullname);
diff -ruN xv-3.10a-bugfixes/xvpbm.c xv-3.10a-enhancements/xvpbm.c
--- xv-3.10a-bugfixes/xvpbm.c	2005-04-03 14:25:28.000000000 -0700
+++ xv-3.10a-enhancements/xvpbm.c	2005-04-03 14:21:14.000000000 -0700
@@ -23,6 +23,15 @@
  */
 
 
+typedef unsigned short  ush;
+typedef unsigned char   uch;
+
+#define alpha_composite(composite, fg, alpha, bg) {               \
+    ush temp = ((ush)(fg)*(ush)(alpha) +                          \
+                (ush)(bg)*(ush)(255 - (ush)(alpha)) + (ush)128);  \
+    (composite) = (uch)((temp + (temp >> 8)) >> 8);               \
+}
+
 #define TRUNCSTR "File appears to be truncated."
 
 static int garbage;
@@ -31,6 +40,7 @@
 static int loadpbm  PARM((FILE *, PICINFO *, int));
 static int loadpgm  PARM((FILE *, PICINFO *, int, int));
 static int loadppm  PARM((FILE *, PICINFO *, int, int));
+static int loadpam  PARM((FILE *, PICINFO *, int, int));
 static int getint   PARM((FILE *, PICINFO *));
 static int getbit   PARM((FILE *, PICINFO *));
 static int getshort PARM((FILE *));
@@ -73,7 +83,8 @@
      "P6" = raw pixmap */
 
   c = getc(fp);  c1 = getc(fp);
-  if (c!='P' || c1<'1' || c1>'6') return(pbmError(bname, "unknown format"));
+  if (c!='P' || c1<'1' || (c1>'6' && c1!='8'))	/* GRR alpha */
+    return(pbmError(bname, "unknown format"));
 
   /* read in header information */
   pinfo->w = getint(fp, pinfo);  pinfo->h = getint(fp, pinfo);
@@ -104,6 +115,7 @@
   if      (c1=='1' || c1=='4') rv = loadpbm(fp, pinfo, c1=='4' ? 1 : 0);
   else if (c1=='2' || c1=='5') rv = loadpgm(fp, pinfo, c1=='5' ? 1 : 0, maxv);
   else if (c1=='3' || c1=='6') rv = loadppm(fp, pinfo, c1=='6' ? 1 : 0, maxv);
+  else if            (c1=='8') rv = loadpam(fp, pinfo,           1    , maxv);
 
   fclose(fp);
 
@@ -341,6 +353,122 @@
 }
 
 
+/*******************************************/
+static int loadpam(fp, pinfo, raw, maxv)	/* unofficial RGBA extension */
+     FILE    *fp;
+     PICINFO *pinfo;
+     int      raw, maxv;
+{
+  byte *p, *pix, *pic24, *linebuf, scale[256], bgR, bgG, bgB, r, g, b, a;
+  int   i, j, bitshift, w, h, npixels, bufsize, linebufsize, holdmaxv;
+
+  w = pinfo->w;
+  h = pinfo->h;
+
+  npixels = w * h;
+  bufsize = 3*npixels;
+  linebufsize = 4*w;
+  if (w <= 0 || h <= 0 || npixels/w != h || bufsize/3 != npixels ||
+      linebufsize/4 != w)
+    return pbmError(bname, "image dimensions too large");
+
+  /* allocate 24-bit image */
+  pic24 = (byte *) calloc((size_t) bufsize, (size_t) 1);
+  if (!pic24) FatalError("couldn't malloc 'pic24' for PAM");
+
+  /* allocate line buffer for pre-composited RGBA data */
+  linebuf = (byte *) malloc((size_t) linebufsize);
+  if (!linebuf) {
+    free(pic24);
+    FatalError("couldn't malloc 'linebuf' for PAM");
+  }
+
+  pinfo->pic  = pic24;
+  pinfo->type = PIC24;
+  sprintf(pinfo->fullInfo, "PAM, %s format.  (%ld bytes)",
+	  (raw) ? "raw" : "ascii", filesize);
+  sprintf(pinfo->shrtInfo, "%dx%d PAM.", w, h);
+  pinfo->colType = F_FULLCOLOR;
+
+
+  /* if maxv>255, keep dropping bits until it's reasonable */
+  holdmaxv = maxv;
+  bitshift = 0;
+  while (maxv>255) { maxv = maxv>>1;  bitshift++; }
+
+
+  numgot = 0;
+
+  if (!raw) {					/* GRR:  not alpha-ready */
+    return pbmError(bname, "can't handle non-raw PAM image");
+/*
+    for (i=0, pix=pic24; i<h; i++) {
+      if ((i&0x3f)==0) WaitCursor();
+      for (j=0; j<w*3; j++, pix++)
+	*pix = (byte) (getint(fp, pinfo) >> bitshift);
+    }
+ */
+  }
+  else { /* raw */
+    if (holdmaxv>255) {				/* GRR:  not alpha-ready */
+      return pbmError(bname, "can't handle PAM image with maxval > 255");
+/*
+      for (i=0, pix=pic24; i<h; i++) {
+	if ((i&0x3f)==0) WaitCursor();
+	for (j=0; j<w*3; j++,pix++)
+	  *pix = (byte) (getshort(fp) >> bitshift);
+      }
+ */
+    }
+    else {
+      if (have_imagebg) {			/* GRR:  alpha-ready */
+        bgR = (imagebgR >> 8);
+        bgG = (imagebgG >> 8);
+        bgB = (imagebgB >> 8);
+      } else {
+        bgR = bgG = bgB = 0;
+      }
+      for (i=0, pix=pic24; i<h; i++) {
+        numgot += fread(linebuf, (size_t) 1, (size_t) linebufsize, fp);  /* read data */
+	if ((i&0x3f)==0) WaitCursor();
+	for (j=0, p=linebuf; j<w; j++) {
+          r = *p++;
+          g = *p++;
+          b = *p++;
+          a = *p++;
+          alpha_composite(*pix++, r, a, bgR)
+          alpha_composite(*pix++, g, a, bgG)
+          alpha_composite(*pix++, b, a, bgB)
+	}
+      }
+    }
+  }
+
+  free(linebuf);
+
+  /* in principle this could overflow, but not critical */
+  if (numgot != w*h*4) pbmError(bname, TRUNCSTR);
+
+  if (garbage)
+    return(pbmError(bname, "Garbage characters in image data."));
+
+
+  /* have to scale up all RGB values (Conv24to8 expects RGB values to
+     range from 0-255) */
+
+  if (maxv<255) {
+    for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv;
+
+    for (i=0, pix=pic24; i<h; i++) {
+      if ((i&0x3f)==0) WaitCursor();
+      for (j=0; j<w*3; j++, pix++) *pix = scale[*pix];
+    }
+  }
+
+  return 1;
+}
+
+
 
 /*******************************************/
 static int getint(fp, pinfo)
diff -ruN xv-3.10a-bugfixes/xvpcd.c xv-3.10a-enhancements/xvpcd.c
--- xv-3.10a-bugfixes/xvpcd.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpcd.c	2005-04-03 15:06:11.000000000 -0700
@@ -0,0 +1,1303 @@
+/*
+ * xvpcd.c - load routine for 'PhotoCD' format pictures
+ *
+ * LoadPCD(fname, pinfo, size)  -  loads a PhotoCD file
+ *
+ * This routine will popup a choice of which of the 5 available resolutions
+ * the user wants to choose, then load it as a 24 bit image.
+ *
+ * Copyright 1993 David Clunie, Melbourne, Australia.
+ *
+ * The outline of this is shamelessly derived from xvpbm.c to read the
+ * file, and xvtiffwr.c to handle the popup window and X stuff (X never
+ * has been my forte !), and the PhotoCD format information (though not
+ * the code) was found in Hadmut Danisch's (danisch@ira.uka.de) hpcdtoppm
+ * program in which he has reverse engineered the format by studying
+ * hex dumps of PhotoCDs ! After all who can afford the Kodak developer's
+ * kit, which none of us have seen yet ? Am I even allowed to mention these
+ * words (Kodak, PhotoCD) ? I presume they are registered trade marks.
+ *
+ * PS. I have no idea how Halmut worked out the YCC <-> RGB conversion
+ * factors, but I have calculated them from his tables and the results
+ * look good enough to me.
+ *
+ * Added size parameter to allow the schnautzer to create thumnails
+ * without requesting the size every time.
+ */
+#define	TRACE	0
+#if TRACE
+#  define trace(x) fprintf x
+#else
+#  define trace(x)
+#endif
+
+#include "xv.h"
+#include <memory.h>
+
+/* Comments on error-handling:
+   A truncated file is not considered a Major Error.  The file is loaded,
+   and the rest of the pic is filled with 0's.
+
+   Not being able to malloc is a Fatal Error.  The program is aborted. */
+
+
+#ifdef __STDC__
+static void magnify(int, int, int, int, int, byte *);
+static int pcdError(char *, char *);
+static int gethuffdata(byte *, byte *, byte *, int, int);
+#else
+static void magnify();
+static int pcdError();
+static int gethuffdata();
+#endif
+
+#define wcurfactor 16	/* Call WaitCursor() every n rows */
+
+static int	size;	  /* Set by window routines */
+static int	leaveitup;/* Cleared by docmd() when OK or CANCEL pressed */
+static int	goforit;  /* Set to 1 if OK or 0 if CANCEL */
+static FILE	*fp;
+static CBUTT  lutCB;
+
+/*
+ * This "beyond 100%" table is taken from ImageMagick (gamma 2.2).
+ * Why there are 351 entries and not 346 as per Kodak documentation
+ * is a mystery.
+ */
+static	double	rscale = 1.00,
+		gscale = 1.00,
+		bscale = 1.00;
+
+static	byte	Y[351] = {
+	  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+	 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
+	 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+	 30,  32,  33,  34,  35,  36,  37,  38,  39,  40,
+	 41,  42,  43,  45,  46,  47,  48,  49,  50,  51,
+	 52,  53,  54,  56,  57,  58,  59,  60,  61,  62,
+	 63,  64,  66,  67,  68,  69,  70,  71,  72,  73,
+	 74,  76,  77,  78,  79,  80,  81,  82,  83,  84,
+	 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
+	 97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+	107, 108, 110, 111, 112, 113, 114, 115, 116, 117,
+	118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+	129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+	139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
+	149, 150, 151, 152, 153, 154, 155, 156, 157, 158,
+	159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+	169, 170, 171, 172, 173, 174, 175, 176, 176, 177,
+	178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
+	188, 189, 190, 191, 192, 193, 193, 194, 195, 196,
+	197, 198, 199, 200, 201, 201, 202, 203, 204, 205,
+	206, 207, 207, 208, 209, 210, 211, 211, 212, 213,
+	214, 215, 215, 216, 217, 218, 218, 219, 220, 221,
+	221, 222, 223, 224, 224, 225, 226, 226, 227, 228,
+	228, 229, 230, 230, 231, 232, 232, 233, 234, 234,
+	235, 236, 236, 237, 237, 238, 238, 239, 240, 240,
+	241, 241, 242, 242, 243, 243, 244, 244, 245, 245,
+	245, 246, 246, 247, 247, 247, 248, 248, 248, 249,
+	249, 249, 249, 250, 250, 250, 250, 251, 251, 251,
+	251, 251, 252, 252, 252, 252, 252, 253, 253, 253,
+	253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+	254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
+	254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255
+};
+
+/*******************************************/
+/* The size should be -1 for the popup to ask otherwise fast is assumed */
+/* returns '1' on success */
+/*******************************************/
+int
+LoadPCD(char *fname, PICINFO *pinfo, int theSize)
+{
+  long   offset;
+  int    mag;
+  int	 rotate;
+  byte	 header[3*0x800];
+  byte	*pic24, *luma, *chroma1, *chroma2, *ptr, *lptr, *c1ptr, *c2ptr;
+  int   w, h, npixels, bufsize;
+  int   row, col;
+	int	huffplanes;
+	char	*bname;
+
+	bname		= BaseName(fname);
+	pinfo->pic	= NULL;
+	pinfo->comment	= NULL;
+
+
+	/*
+	 *  open the file
+	 */
+	if((fp=fopen(fname,"r")) == NULL)
+		return pcdError(bname, "can't open file");
+
+	/*
+	 * inspect the header
+	 */
+	if(fread(&header[0], 1, sizeof(header), fp) != sizeof(header))
+		return pcdError(bname, "could not load PCD header");
+	if(strncmp(&header[0x800], "PCD_", 4) != 0)
+		return pcdError(bname, "not a PCD file");
+	rotate = header[0x0E02] & 0x03;
+
+/* base/16
+	- plain data starts at sector 1+2+1=4
+	  (numbered from 0, ie. the 5th sector)
+	- luma 192*128 = 24576 bytes (12 sectors)
+	  + chroma1 96*64 = 6144 bytes (3 sectors)
+	  + chroma2 96*64 = 6144 bytes (3 sectors)
+	  = total 18 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 192 wide,
+	  then 1 of each of the chroma rows 96 wide !
+
+   base/4
+	- plain data starts at sector 1+2+1+18+1=23
+	- luma 384*256 = 98304 bytes (48 sectors)
+	  + chroma1 192*128 = 24576 bytes (12 sectors)
+	  + chroma2 192*128 = 24576 bytes (12 sectors)
+	  = total 72 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 384 wide,
+	  then 1 of each of the chroma rows 192 wide !
+
+   base
+	- plain data starts at sector 1+2+1+18+1+72+1=96
+
+	- luma 768*512 = 393216 bytes (192 sectors)
+	  + chroma1 384*256 = 98304 bytes (48 sectors)
+	  + chroma2 384*256 = 98304 bytes (48 sectors)
+	  = total 288 sectors
+
+	- NB. "Plain" data is interleaved - 2 luma rows 768 wide,
+	  then 1 of each of the chroma rows 384 wide !
+
+   4base
+	- plain data for base is read
+	- luma data interpolated *2
+	- chroma data interpolated *4
+
+	- cd_offset is 1+2+1+18+1+72+1+288=384
+	- at cd_offset+4 (388) is huffman table
+	- at cd_offset+5 (389) is 4base luma plane
+
+	(the sector at cd_offset+3 seems to contain 256 words each of
+	which is an offset presumably to the sector containing certain
+	rows ? rows/4 given 1024 possible rows. The rest of this sector
+	is filled with zeroes)
+
+
+   16base
+	- plain data for base is read
+	- luma data interpolated *2
+	- chroma data interpolated *4
+
+	- cd_offset is 1+2+1+18+1+72+1+288=384
+	- at cd_offset+4 (388) is huffman table for 4 base
+	- at cd_offset+5 (389) is 4base luma plane
+	- luma plane interpolated *2
+
+	- cd_offset is set to current position (should be start of sector)
+	- at cd_offset+12 is huffman table for 16 base
+	- at cd_offset+14 is 16 base luma & 2 chroma planes which are read
+          (note that the luma plane comes first, with a sync pattern
+           announcing each row from 0 to 2047, then the two chroma planes
+           are interleaved by row, the row # being even from 0 to 2046, with
+           each row containing 1536 values, the chroma1 row coming first,
+           finally followed by a sync pattern with a row of 2048 announcing
+           the end (its plane seems to be set to 3, ie. chroma2)
+	- chroma planes interpolated *2
+
+	(the sector at cd_offset+10 & 11 seem to contain 1024 pairs of words
+        the first for luma and the second for chroma, each of
+	which is an offset presumably to the sector containing certain
+	rows ? rows/2 given 2048 possible rows)
+
+Not yet implemented:
+
+In order to do overskip for base and 4base, one has to reach the chroma
+data for 16 base:
+
+	- for 4base, after reading the 4base luma plane (and presumably
+	  skipping the chroma planes) one sets cd_offset to the start of
+	  the "current" sector
+
+	- for base, one has to skip the 4base data first:
+	- cd_offset is set to 384
+	- at (cd_offset+3 sectors)[510] is a 16 bit word high byte 1st
+	  containing an offset to the beginning of the 16base stuff
+	  though there is then a loop until >30 0xff's start a sector !
+
+	- being now positioned after the end of the 4base stuff,
+	- at (cd_offset+10 sectors)[2] is a 16 bit word high byte 1st
+	  containing an offset to the chroma planes.
+	- at cd_offset+12 is the set of huffman tables
+
+	- for base, the 16base chroma planes are then halved
+*/
+
+  PCDSetParamOptions(bname);
+  if (theSize == -1)
+  {
+    PCDDialog(1);                   /* Open PCD Dialog box */
+    SetCursors(-1);                 /* Somebody has already set it to wait :( */
+    leaveitup=1;
+    goforit=0;
+	size = 1;
+    /* block until the popup window gets closed */
+    while (leaveitup) {
+      int i;
+      XEvent event;
+      XNextEvent(theDisp, &event);
+      HandleEvent(&event, &i);
+    }
+    /* At this point goforit and size will have been set */
+    if (!goforit) {
+      /* nothing allocated so nothing needs freeing */
+      return 0;
+    }
+    WaitCursor();
+  }
+  else
+  {
+    size = theSize;
+    goforit = 1;
+  }
+
+	if(lutCB.val)
+		rscale = gscale = bscale = 255.0/346.0;
+	else
+		rscale = gscale = bscale = 1.0;
+
+	switch (size) {
+	case 0:
+		pinfo->w = 192;
+		pinfo->h = 128;
+		offset=4*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base/16 resolution");
+		break;
+
+	case 1:
+		pinfo->w = 384;
+		pinfo->h = 256;
+		offset=23*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base/4 resolution");
+		break;
+
+	case 2:
+	default:
+		pinfo->w = 768;
+		pinfo->h = 512;
+		offset=96*0x800;
+		mag=1;
+		huffplanes=0;
+		sprintf(pinfo->fullInfo, "PhotoCD, base resolution");
+		break;
+
+	case 3:
+		pinfo->w = 1536;
+		pinfo->h = 1024;
+		offset=96*0x800;
+		mag=2;
+		huffplanes=1;
+		sprintf(pinfo->fullInfo, "PhotoCD, 4base resolution");
+		break;
+
+	case 4:
+		pinfo->w=3072;
+		pinfo->h=2048;
+		offset=96*0x800;
+		mag=4;
+		huffplanes=2;
+		sprintf(pinfo->fullInfo, "PhotoCD, 16base resolution");
+		break;
+	}
+
+	/*
+	 * rotate?
+	 */
+	w = pinfo->w;
+	h = pinfo->h;
+	switch(rotate) {
+	case	0:
+		break;
+
+	case	1:
+	case	3:
+		pinfo->w = h;
+		pinfo->h = w;
+		break;
+
+	default:
+		fprintf(stderr, "unknown image rotate %d; assuming none\n",
+			rotate);
+		rotate = 0;
+	}
+
+	/*
+	 * allocate 24-bit image
+	 */
+	npixels = pinfo->w * pinfo->h;
+	bufsize = 3 * npixels;
+	if (pinfo->w <= 0 || pinfo->h <= 0 || npixels/pinfo->w != pinfo->h ||
+	    bufsize/3 != npixels)
+		FatalError("image dimensions out of range");
+
+	pinfo->pic = (byte *)malloc((size_t) bufsize);
+	if(!pinfo->pic)
+		FatalError("couldn't malloc '24-bit RGB plane'");
+
+	pinfo->type = PIC24;
+	sprintf(pinfo->shrtInfo, "%dx%d PhotoCD.", pinfo->w, pinfo->h);
+	pinfo->colType = F_FULLCOLOR;
+	pinfo->frmType = -1;
+
+	if(fseek(fp, offset, SEEK_SET) == -1) {
+		free(pinfo->pic);
+		return pcdError(bname,"Can't find start of data.");
+	}
+
+	pic24 = pinfo->pic;
+
+	luma=(byte *)calloc(npixels,1);
+	if(!luma) {
+		free(pinfo->pic);
+		FatalError("couldn't malloc 'luma plane'");
+	}
+
+	chroma1=(byte *)calloc(npixels/4,1);
+	if(!chroma1) {
+		free(pinfo->pic);
+		free(luma);
+		FatalError("couldn't malloc 'chroma1 plane'");
+	}
+
+	chroma2=(byte *)calloc(npixels/4,1);
+	if(!chroma2) {
+		free(pinfo->pic);
+		free(luma);
+		free(chroma1);
+		FatalError("couldn't malloc 'chroma2 plane'");
+	}
+
+	/* Read 2 luma rows length w, then one of each chroma rows w/2 */
+	/* If a mag factor is active, the small image is read into the */
+	/* top right hand corner of the larger allocated image */
+
+	trace((stderr, "base image: start @ 0x%08lx (sector %ld.%ld)\n",
+				ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+	for(row=0,lptr=luma,c1ptr=chroma1,c2ptr=chroma2; row <h/mag;
+				row+=2,lptr+=w*2,c1ptr+=w/2,c2ptr+=w/2) {
+		if(fread(lptr, 1, w/mag, fp) != w/mag) {
+			pcdError(bname, "Luma plane too short.");
+			break;
+		}
+		if(fread(lptr+w, 1, w/mag, fp) != w/mag) {
+			pcdError(bname, "Luma plane too short.");
+			break;
+		}
+		if(fread(c1ptr, 1, w/2/mag, fp) != w/2/mag) {
+			pcdError(bname, "Chroma1 plane too short.");
+			break;
+		}
+		if(fread(c2ptr, 1, w/2/mag, fp) != w/2/mag) {
+			pcdError(bname, "Chroma2 plane too short.");
+			break;
+		}
+		if(row%wcurfactor == 0)
+			WaitCursor();
+	}
+	trace((stderr, "base image: done @ 0x%08lx (sector %ld.%ld)\n",
+				ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+
+	if(huffplanes) {
+		if(fseek(fp, 388*0x800, SEEK_SET) == -1)
+			return pcdError(bname,
+					"Can't find start of huffman tables.");
+
+		magnify(2, h/mag, w/mag, h, w, luma);
+		magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma1);
+		magnify(2, h/2/mag, w/2/mag, h/2, w/2, chroma2);
+
+		/*
+		 * doesn't really touch the chroma planes which aren't
+		 * present in 4base
+		 */
+		gethuffdata(luma, chroma1, chroma2, w, h/mag*2);
+
+		/*
+		 * if only doing 4base should probably fetch 16bases
+		 * chroma planes here
+		 */
+		if(huffplanes == 2) {
+			/*
+			 * This depends on gethuffdata() having grabbed
+			 * things in 0x800 sectors AND still being
+			 * positioned in the "last" sector of the data
+			 * (cf. Hadmut's code which is positioned at start
+			 * of the next sector)
+			 */
+			long	offset = ftell(fp)/0x800+12;
+
+			if(fseek(fp, offset*0x800, SEEK_SET) == 0) {
+				magnify(2,h/2,w/2,h,w,luma);
+				magnify(2,h/4,w/4,h/2,w/2,chroma1);
+				magnify(2,h/4,w/4,h/2,w/2,chroma2);
+				gethuffdata(luma,chroma1,chroma2,w,h);
+			} else
+				fprintf(stderr, "can't seek to 2nd huffman tables\n");
+		}
+	}
+	fclose(fp);
+
+	/*
+	 * YCC -> R'G'B' and image rotate
+	 */
+	ptr=pic24;
+	lptr=luma; c1ptr=chroma1; c2ptr=chroma2;
+	for(row = 0; row < h; ++row) {
+		byte	*rowc1ptr = c1ptr,
+			*rowc2ptr = c2ptr;
+		int	k = 0;
+
+		switch(rotate) {
+		case	1:
+			ptr = &pic24[row*3 + (w - 1)*h*3];
+			  k = -3*(h + 1);
+			break;
+
+		case	3:
+			ptr = &pic24[(h - 1 - row)*3];
+			  k =  3*(h - 1);
+			break;
+
+		default:
+			ptr = &pic24[row*w*3];
+			  k = 0;
+			break;
+		}
+		for(col = 0; col < w; ++col) {
+			double	L	= 1.3584*(double) *lptr++,
+				C1	= 2.2179*(double) (*c1ptr - 156),
+				C2	= 1.8215*(double) (*c2ptr - 137);
+			int	r	= rscale*(L + C2),
+				g	= gscale*(L - 0.194*C1 - 0.509*C2),
+				b	= bscale*(L + C1);
+
+			if(lutCB.val) {
+				if(r < 0) r = 0; else if(r >= 255) r = 255;
+				if(g < 0) g = 0; else if(g >= 255) g = 255;
+				if(b < 0) b = 0; else if(b >= 255) b = 255;
+			} else {
+				if(r < 0) r = 0; else if(r >= 351) r = 350;
+				if(g < 0) g = 0; else if(g >= 351) g = 350;
+				if(b < 0) b = 0; else if(b >= 351) b = 350;
+				r = Y[r]; g = Y[g]; b = Y[b];
+			}
+			*ptr++ = r;
+			*ptr++ = g;
+			*ptr++ = b;
+			ptr   += k;
+			if(col & 1) {
+				++c1ptr;
+				++c2ptr;
+			}
+		}
+		if((row & 1) == 0) {
+			c1ptr = rowc1ptr;
+			c2ptr = rowc2ptr;
+		}
+		if(row%wcurfactor == 0)
+			WaitCursor();
+	}
+	free(luma); free(chroma1); free(chroma2);
+	return 1;
+}
+
+/*
+ * derived from Hadmut Danisch's interpolate()
+ */
+static void
+magnify(int mag,	/* power of 2 by which to magnify in place */
+	int h, int w,	/* the "start" unmag'd dimensions of the array */
+	int mh, int mw,	/* the real (maximum) dimensions of the array */
+	byte *p)	/* pointer to the data */
+{
+  int x,y,yi;
+  byte *optr,*nptr,*uptr;  /* MUST be unsigned, else averaging fails */
+
+  while (mag > 1) {
+
+    /* create every 2nd new row from 0 */
+    /*  even pixels being equal to the old, odd ones averaged with successor */
+    /*  special case being the last column which is just set equal to the */
+    /*  second last) ... */
+
+    for(y=0;y<h;y++) {
+      yi=h-1-y;
+      optr=p+  yi*mw + (w-1);	          /* last pixel of an old row */
+      nptr=p+2*yi*mw + (2*w - 2);         /* last pixel of a new row */
+
+      nptr[0]=nptr[1]=optr[0];            /* special cases */
+
+      for(x=1;x<w;x++) {
+        optr--; nptr-=2;                  /* next lower pixel(s) */
+        nptr[0]=optr[0];                  /* even pixels duped */
+        nptr[1]=(((int)optr[0])+
+                 ((int)optr[1])+1)>>1;    /* odd averaged */
+      }
+    }
+
+    /* Fill in odd rows, as average of prior & succeeding rows, with */
+    /* even pixels average of one column, odd pixels average of two */
+
+    for(y=0;y<h-1;y++) {                  /* all but the last old row */
+      optr=p + 2*y*mw;                    /* start of the new "even" rows */
+      nptr=optr+mw;                       /* start of the next empty row */
+      uptr=nptr+mw;                       /* start of the next again (even) */
+
+      for(x=0;x<w-1;x++) {                /* for all cols except the last */
+        nptr[0]=(((int)optr[0])+
+                 ((int)uptr[0])+1)>>1;    /* even pixels */
+        nptr[1]=(((int)optr[0])+
+                 ((int)optr[2])+
+                 ((int)uptr[0])+
+                 ((int)uptr[2])+2)>>2;    /* odd pixels */
+        nptr+=2; optr+=2; uptr+=2;
+      }
+      *(nptr++)=(((int)*(optr++))+
+                 ((int)*(uptr++))+1)>>1;  /* 2nd last pixel */
+      *(nptr++)=(((int)*(optr++))+
+                 ((int)*(uptr++))+1)>>1;  /* last pixel */
+    }
+
+    xvbcopy(p + (2*h-2)*mw,                 /* 2nd last row */
+          p + (2*h-1)*mw,                 /* the last row */
+          2*w);                           /* length of a new row */
+
+    h*=2; w*=2;
+    mag>>=1;	/* Obviously mag must be a power of 2 ! */
+  }
+}
+
+/*******************************************/
+static int
+pcdError(char *fname, char *st)
+{
+  SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
+  return 0;
+}
+
+
+/**** Stuff for PCDDialog box ****/
+
+#define TWIDE 380
+#define THIGH 160
+#define T_NBUTTS 2
+#define T_BOK    0
+#define T_BCANC  1
+#define BUTTH    24
+
+static void drawTD    PARM((int, int, int, int));
+static void clickTD   PARM((int, int));
+static void doCmd     PARM((int));
+static void PCDSetParams PARM((void));
+
+/* local variables */
+static BUTT  tbut[T_NBUTTS];
+static RBUTT *resnRB;
+
+
+
+/***************************************************/
+void CreatePCDW()
+{
+  int	     y;
+
+  pcdW = CreateWindow("xv pcd", "XVpcd", NULL,
+		       TWIDE, THIGH, infofg, infobg, 0);
+  if (!pcdW) FatalError("can't create pcd window!");
+
+  XSelectInput(theDisp, pcdW, ExposureMask | ButtonPressMask | KeyPressMask);
+
+  BTCreate(&tbut[T_BOK], pcdW, TWIDE-140-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	   "Ok", infofg, infobg, hicol, locol);
+
+  BTCreate(&tbut[T_BCANC], pcdW, TWIDE-70-1, THIGH-10-BUTTH-1, 60, BUTTH,
+	   "Cancel", infofg, infobg, hicol, locol);
+
+  y = 55;
+  resnRB = RBCreate(NULL, pcdW, 36, y,   "192*128   Base/16",
+           infofg, infobg,hicol,locol);
+  RBCreate(resnRB, pcdW, 36, y+18,       "384*256   Base/4",
+           infofg, infobg,hicol,locol);
+  RBCreate(resnRB, pcdW, 36, y+36,       "768*512   Base",
+           infofg, infobg, hicol, locol);
+  RBCreate(resnRB, pcdW, TWIDE/2, y,     "1536*1024 4Base",
+           infofg, infobg, hicol, locol);
+  RBCreate(resnRB, pcdW, TWIDE/2, y+18,  "3072*2048 16Base",
+           infofg, infobg, hicol, locol);
+
+  CBCreate(&lutCB, pcdW, TWIDE/2, y+36,  "Linear LUT",
+           infofg, infobg, hicol, locol);
+
+  RBSelect(resnRB, 2);
+
+  XMapSubwindows(theDisp, pcdW);
+}
+
+
+/***************************************************/
+void PCDDialog(vis)
+int vis;
+{
+  if (vis) {
+    CenterMapWindow(pcdW, tbut[T_BOK].x + tbut[T_BOK].w/2,
+		    tbut[T_BOK].y + tbut[T_BOK].h/2, TWIDE, THIGH);
+  }
+  else     XUnmapWindow(theDisp, pcdW);
+  pcdUp = vis;
+}
+
+
+/***************************************************/
+int PCDCheckEvent(xev)
+XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!pcdUp) return 0;
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x;  y = e->y;  w = e->width;  h = e->height;
+
+    if (e->window == pcdW)       drawTD(x, y, w, h);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+
+    if (e->button == Button1) {
+      if      (e->window == pcdW)     clickTD(x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;  XComposeStatus status;
+    int stlen;
+
+    stlen = XLookupString(e,buf,128,&ks,&status);
+    buf[stlen] = '\0';
+
+    RemapKeyCheck(ks, buf, &stlen);
+
+    if (e->window == pcdW) {
+      if (stlen) {
+	if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+	  FakeButtonPress(&tbut[T_BOK]);
+	}
+	else if (buf[0] == '\033') {            /* ESC */
+	  FakeButtonPress(&tbut[T_BCANC]);
+	}
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return rv;
+}
+
+
+/***************************************************/
+void
+PCDSetParamOptions(char *fname)
+{
+  int cur;
+  cur = RBWhich(resnRB);
+
+  RBSetActive(resnRB,0,1);
+  RBSetActive(resnRB,1,1);
+  RBSetActive(resnRB,2,1);
+  RBSetActive(resnRB,3,1);
+  RBSetActive(resnRB,4,1);
+  CBSetActive(&lutCB,1);
+}
+
+
+/***************************************************/
+static void
+drawTD(int x, int y, int w, int h)
+{
+  char *title  = "Load PhotoCD file...";
+  int  i;
+  XRectangle xr;
+
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i=0; i<T_NBUTTS; i++) BTRedraw(&tbut[i]);
+
+  ULineString(pcdW, resnRB->x-16, resnRB->y-10-DESCENT, "Resolution");
+  RBRedraw(resnRB, -1);
+  CBRedraw(&lutCB);
+
+  XDrawString(theDisp, pcdW, theGC, 20, 19, title, strlen(title));
+
+  XSetClipMask(theDisp, theGC, None);
+}
+
+
+/***************************************************/
+static void clickTD(x,y)
+int x,y;
+{
+  int i;
+  BUTT *bp;
+
+  /* check BUTTs */
+
+  /* check the RBUTTS first, since they don't DO anything */
+  if ( (i=RBClick(resnRB, x,y)) >= 0) {
+    (void) RBTrack(resnRB, i);
+    return;
+  }
+
+  if(CBClick(&lutCB, x, y)) {
+    (void) CBTrack(&lutCB);
+    return;
+  }
+
+  for (i=0; i<T_NBUTTS; i++) {
+    bp = &tbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
+  }
+
+  if (i<T_NBUTTS) {  /* found one */
+    if (BTTrack(bp)) doCmd(i);
+  }
+}
+
+
+
+/***************************************************/
+static void doCmd(cmd)
+int cmd;
+{
+  leaveitup=0;
+  goforit=0;
+  switch (cmd) {
+  case T_BOK:  	PCDSetParams();
+                goforit=1;
+  case T_BCANC:	PCDDialog(0);
+                break;
+
+  default:	break;
+  }
+}
+
+
+/*******************************************/
+static void PCDSetParams()
+{
+  switch (RBWhich(resnRB)) {
+  case 0: size = 0;      break;
+  case 1: size = 1;      break;
+  case 2: size = 2;      break;
+  case 3: size = 3;      break;
+  case 4: size = 4;      break;
+  case 5: size = 0;      break;
+  default: size = 0;     break;
+  }
+}
+
+/*
+ * Read the Huffman tables which consist of an unsigned byte # of entries
+ * (less 1) followed by up to 256 entries, each of which is a series of 4
+ * unsigned bytes - length, highseq, lowseq, and key.
+ *
+ * Store the huffman table into tree type structure:
+ *
+ * 	int int[n of entries*2]
+ *
+ * Each entry consists of two words (the 1st for zero and the 2nd for one).
+ *
+ * If the word is negative, then subtract it from the current pointer to
+ * get the next entry (ie. it is the negative offset from the current
+ * position*2 in order to skip entries not words) with which to
+ * make a decision.
+ *
+ * If the word is not negative, then the low 8 bits contain the value (which
+ * is supposed to be a signed char) and the rest of the word is zero.
+ */
+static void
+dumphufftab(int n, const byte *h, int m, const int *t)
+{
+	int	j;
+
+	for(j = 0; j < n || j < m; ++j) {
+		if(j < m)
+			fprintf(stderr, "%04x %04x ::", 0xffff & t[2*j + 0],
+							 0xffff & t[2*j + 1]);
+		else
+			fprintf(stderr, "%s %s ::", "    ", "    ");
+		if(j < n) {
+			int	 k;
+			unsigned l = (h[4*j + 1] << 8) | h[4*j + 2];
+
+			fprintf(stderr, " %02x %2d ", h[4*j + 3], h[4*j + 0]);
+			for(k = 0; k <= h[4*j + 0]; ++k, l *= 2)
+				fprintf(stderr, "%c", '0'+((l & 0x8000) != 0));
+		}
+		fprintf(stderr, "\n");
+	}
+}
+
+static int *
+gethufftable(void)
+{
+	int	*hufftab, *h, i, j, N, num, bufsize, huffptr, hufftop;
+	byte	*huf;
+
+	/*
+	 * absorb the entirety of the table in one chunk (for better
+	 * dumps in case of error)
+	 */
+	trace((stderr, "hufftab 0x%08lx ", ftell(fp)));
+	num = 1 + fgetc(fp);   /* 256 max */
+	huf = (byte *)alloca(4*num*sizeof(byte));
+	if((i = fread(huf, 1, 4*num, fp)) != 4*num) {
+		fprintf(stderr, "unexpected EOF: got %d bytes, wanted %d\n",
+								i, 4*num);
+		return NULL;
+	}
+
+	/*
+	 * guess an initial size and prepare the initial entry
+	 */
+	trace((stderr, "length %u\n", num));
+	N = 2*num;   /* 512 max */
+	bufsize = N * sizeof(int);
+/*	this case can't happen, but added for symmetry with loop below
+	if (N/2 != num || bufsize/N != sizeof(int)) {
+		SetISTR(ISTR_WARNING, "Huffman table size out of range");
+		return NULL;
+	}
+ */
+	if((hufftab = (int *)malloc(bufsize)) == NULL)
+		FatalError("couldn't malloc initial Huffman table");
+	hufftab[0] = hufftab[1] = 0;
+
+	/*
+	 * we check the table for reasonableness;  there is a lack of detailed
+	 * documentation on this format.  in particular, for the base16,
+	 * the position of the huffman tables is uncertain to within one
+	 * "sector", and we have to detect his before trying to read
+	 * bogusness.
+	 */
+	hufftop = 0;
+	for(i = 0; i < num; ++i) {
+		unsigned length   =  huf[4*i + 0],
+			 codeword = (huf[4*i + 1] << 8) | huf[4*i + 2];
+
+		/*
+		 * some sanity checks
+		 */
+		if(length >= 16) {
+			fprintf(stderr,
+				"gethufftable: improbable length @ %d/%d\n",
+					i, num);
+			dumphufftab(num, huf, hufftop/2, hufftab);
+			free(hufftab);
+			return NULL;
+		}
+
+		/*
+		 * walk the whole set of codes
+		 */
+		huffptr = 0;
+		for(j = 0; j < 16; ++j, codeword *= 2) {
+			/*
+			 * choose the child node
+			 */
+			if(codeword & 0x8000)
+				++huffptr;
+
+			/*
+			 * store value at end-of-code
+			 */
+			if(j == length) {
+				/*
+				 * more sanity
+				 */
+				if((codeword *= 2) & 0xffff) {
+					fprintf(stderr,
+						"gethufftable: "
+						":probable invalid code @ %d\n",
+							i);
+					dumphufftab(num, huf,
+							hufftop/2, hufftab);
+					free(hufftab);
+					return NULL;
+				}
+				hufftab[huffptr] = 1 + (int) huf[4*i + 3];
+				break;
+			}
+
+			/*
+			 * otherwise, follow the tree to date
+			 */
+			if(hufftab[huffptr] < 0) {
+				huffptr -= hufftab[huffptr];
+				continue;
+			} else if(hufftab[huffptr] > 0) {
+				fprintf(stderr, "duplicate code %d %d/%d\n",
+					huffptr, i, num);
+				dumphufftab(num, huf, hufftop/2, hufftab);
+				free(hufftab);
+				return NULL;
+			}
+
+			/*
+			 * and if necessary, make the tree bigger
+			 */
+			if((hufftop += 2) >= N) {
+				int oldN = N;
+#if TRACE
+				dumphufftab(num, huf, hufftop/2, hufftab);
+#endif
+				N *= 2;
+				bufsize = N*sizeof(int);
+				if (N/2 != oldN || bufsize/N != sizeof(int)) {
+					SetISTR(ISTR_WARNING,
+					  "new Huffman table is too large");
+					free(hufftab);
+					return NULL;
+				}
+				h = (int *)realloc(hufftab, bufsize);
+				if(h == NULL) {
+					fprintf(stderr,
+						"Table overflow %d/%d\n",
+								 i, num);
+					dumphufftab(num, huf,
+							hufftop/2, hufftab);
+					free(hufftab);
+					FatalError(
+					  "couldn't realloc Huffman table");
+				}
+				hufftab = h;
+			}
+
+			/*
+			 * then add new ptr
+			 */
+			hufftab[huffptr] = huffptr - hufftop;
+			huffptr = hufftop;
+			hufftab[huffptr + 0] =
+			hufftab[huffptr + 1] = 0;
+		}
+	}
+	return hufftab;
+}
+
+/* WORDTYPE & char buffer must be unsigned else */
+/* fills with sign bit not 0 on right shifts */
+typedef unsigned int WORDTYPE;
+typedef int SWORDTYPE;
+#define WORDSIZE sizeof(WORDTYPE)
+#define NBYTESINBUF 0x800
+
+static byte buffer[NBYTESINBUF];
+static int bitsleft=0;
+static int bytesleft=0;
+static byte *bufptr;
+static WORDTYPE word;
+
+#if 0
+static void
+dumpbuffer(void)
+{
+  int i,left;
+  byte *ptr=buffer;
+
+  fprintf(stderr,"dumpbuffer: bytesleft=%d bitsleft= %d word=0x%08lx\n",
+    bytesleft,bitsleft,(unsigned long)word);
+  for (left=NBYTESINBUF; left>0; left-=16) {
+    fprintf(stderr,"%05d  ",left);
+    for (i=0; i<8; i++) {
+      fprintf(stderr,"%02x",*ptr++);
+      fprintf(stderr,"%02x ",*ptr++);
+    }
+    fprintf(stderr,"\n");
+  }
+}
+#endif /* 0 */
+
+static void
+loadbuffer(void)
+{
+  if ((bytesleft=fread(buffer,1,NBYTESINBUF,fp)) == 0) {
+    fprintf(stderr,"Truncation error\n");
+    exit(1);
+  }
+  bufptr=buffer;
+  /* dumpbuffer(); */
+}
+
+static void
+loadbyte(void)
+{
+  if (bytesleft <= 0) loadbuffer();
+  --bytesleft;
+  word|=(WORDTYPE)(*bufptr++)<<(sizeof(WORDTYPE)*8-8-bitsleft);
+  bitsleft+=8;
+}
+
+static int
+getbit(void)
+{
+  int bit;
+
+  while (bitsleft <= 0) loadbyte();
+  --bitsleft;
+  bit=(SWORDTYPE)(word)<0;  /* assumes word is signed */
+  /* bit=word>>(sizeof(WORDTYPE)*8-1); */
+  word<<=1;
+  return bit;
+}
+
+static WORDTYPE
+getnn(int nn)
+{
+  WORDTYPE value;
+
+  while (bitsleft <= nn) loadbyte();
+  bitsleft-=nn;
+  value=word>>(sizeof(WORDTYPE)*8-nn);
+  word<<=nn;
+  return value;
+}
+
+static WORDTYPE
+isnn(int nn)
+{
+  WORDTYPE value;
+
+  while (bitsleft <= nn) loadbyte();
+  value=word>>(sizeof(WORDTYPE)*8-nn);
+  return value;
+}
+
+static void
+skipnn(int nn)
+{
+  while (bitsleft <= nn) loadbyte();
+  bitsleft-=nn;
+  word<<=nn;
+}
+
+#define get1()    (getbit())
+#define get2()    (getnn(2))
+#define get8()    (getnn(8))
+#define get13()    (getnn(13))
+#define get16()    (getnn(16))
+#define get24()    (getnn(24))
+
+#define is24()    (isnn(24))
+
+#define skip1()    (skipnn(1))
+#define skip24()  (skipnn(24))
+
+static int
+gethuffdata(	byte *luma,
+		byte *chroma1,
+		byte *chroma2,
+		int realrowwidth,
+		int maxrownumber)
+{
+static	byte	clip[3*256];
+	int	*hufftable[3], *huffstart = NULL, *huffptr = NULL;
+	int	row, col, plane, i, result = 1;
+#if TRACE
+	int	uflow = 0, oflow = 0;
+#endif
+	byte	*pixelptr = NULL;
+
+	trace((stderr,"gethuffdata: start @ 0x%08lx (sector %ld.%ld)\n",
+			ftell(fp), ftell(fp)/0x800, ftell(fp) % 0x800));
+
+	/*
+	 * correction clipping
+	 */
+	if(clip[256+255] == 0) {
+		for(i = 0; i < 256; ++i)
+			clip[i +   0] = 0x00,
+			clip[i + 256] = (byte) i,
+			clip[i + 512] = 0xff;
+	}
+
+	/*
+	 * should really only look for luma plane for 4base, but the
+	 * there are zeroes in the rest of the sector that give both
+	 * chroma tables 0 length
+	 */
+	for(i = 0; i < 3; ++i)
+		hufftable[i] = NULL;
+	for(i = 0; i < 3; ++i) {
+		if((hufftable[i] = gethufftable()) == NULL) {
+			result = 0;
+			break;
+		}
+	}
+	if(result == 0)
+		goto oops;
+
+	/*
+	 * skip remainder of current sector
+	 */
+	i = (ftell(fp) | 0x7ff) + 1;
+	if(fseek(fp, i, SEEK_SET) < 0) {
+		fprintf(stderr, "gethuffdata: sector skip failed\n");
+		return 0;
+	}
+
+	/*
+	 * skip remainder of "sector"
+	 */
+	i = 0;
+	while (is24() != 0xfffffe) {
+		(void)get24();
+		if(++i == 1)
+			trace((stderr,"gethuffdata: skipping for sync ..."));
+	}
+	if(i != 0)
+		trace((stderr, " %d times\n", i));
+
+	while(result) {
+		if(is24() == 0xfffffe) {
+			skip24();
+			plane = get2();
+			row = get13(); col = 0;
+			skip1();
+			if(row >= maxrownumber) {
+				trace((stderr,
+					"gethuffdata: stopping at row %d\n",
+								row));
+				break;
+			}
+			switch (plane) {
+			case	0:
+				huffstart = hufftable[0];
+				pixelptr  = luma + row*realrowwidth;
+				break;
+
+			case	2:
+				huffstart = hufftable[1];
+				pixelptr  = chroma1 + row/2*realrowwidth/2;
+				break;
+
+			case	3:
+				huffstart = hufftable[2];
+				pixelptr  = chroma2 + row/2*realrowwidth/2;
+				break;
+
+			default:
+				fprintf(stderr, "gethuffdata: bad plane %d\n",
+									plane);
+				result = 0;
+				break;
+			}
+			WaitCursor();
+			continue;
+		}
+
+		/*
+		 * locate correction in huffman tree
+		 */
+		for(huffptr = huffstart;;) {
+			huffptr += get1();
+			if(*huffptr < 0) {
+				huffptr -= *huffptr;
+			} else if(*huffptr == 0) {
+				fprintf(stderr,
+					"gethuffdata: invalid code: "
+						"image quality reduced\n");
+				result = 0;
+				break;
+			} else
+				break;
+		}
+		if(!result)
+			break;
+
+		/*
+		 * apply correction to the pixel
+		 *
+		 * eeeek!!  the corrections can sometimes over or underflow!
+		 * this strongly suggested that the 'magnify' method was in
+		 * some way wrong.  however, experiments showed that the
+		 * over/under flows even occured for the pixels that are
+		 * copied through magnify without change (ie, the even
+		 * row/even column case).  curiously, though, the odd
+		 * column and odd row cases were about 3x more likely to have
+		 * the over/underflow, and the odd row/odd column case was
+		 * about 5x higher, so maybe the use of a bi-linear
+		 * interpolation is not correct -- just *close*?
+		 *
+		 * the other clue in this area is that the overflows are
+		 * by far most frequenct along edges of very bright
+		 * areas -- rarely in the interior of such regions.
+		 */
+		i = (int) *pixelptr + (signed char) (*huffptr - 1);
+#if TRACE
+		if(i > 255)
+			++oflow;
+/*			trace((stderr,
+			  "gethuffdata: oflow %d %d %d\n", row, col, i));*/
+		else if(i < 0)
+			++uflow;
+/*			trace((stderr,
+			  "gethuffdata: uflow %d %d %d\n", row, col, i));*/
+		++col;
+#endif
+		*pixelptr++ = clip[i + 256];
+	}
+
+oops:
+	for(i = 0; i < 3; ++i)
+		free(hufftable[i]);
+	trace((stderr, "gethuffdata: uflow=%d oflow=%d\n", uflow, oflow));
+	trace((stderr, "gethuffdata: done @ 0x%08lx (sector %ld.%d)\n",
+				ftell(fp), ftell(fp)/0x800, 0x800 - bytesleft));
+	return result;
+}
+
diff -ruN xv-3.10a-bugfixes/xvpng.c xv-3.10a-enhancements/xvpng.c
--- xv-3.10a-bugfixes/xvpng.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvpng.c	2005-03-27 21:15:54.000000000 -0800
@@ -0,0 +1,1081 @@
+/*
+ * xvpng.c - load and write routines for 'PNG' format pictures
+ *
+ * callable functions
+ *
+ *    CreatePNGW()
+ *    PNGDialog(vis)
+ *    PNGCheckEvent(xev)
+ *    PNGSaveParams(fname, col)
+ *    LoadPNG(fname, pinfo)
+ *    VersionInfoPNG()
+ */
+
+/*#include "copyright.h"*/
+/* (c) 1995 by Alexander Lehmann <lehmann@mathematik.th-darmstadt.de>
+ *   This file is a suplement to xv and is supplied under the same copying
+ *   conditions (except the shareware part).
+ * Modified by Andreas Dilger <adilger@enel.ucalgary.ca> to fix
+ *   error handling for bad PNGs, add dialogs for interlacing and
+ *   compression selection, and upgrade to libpng-0.89.
+ * Modified by Greg Roelofs, TenThumbs and others to fix bugs and add
+ *   features.
+ * The copyright will be passed on to JB at some future point if he
+ * so desires.
+ */
+
+#include "xv.h"
+
+#ifdef HAVE_PNG
+
+#include "png.h"
+
+/*** Stuff for PNG Dialog box ***/
+#define PWIDE 318
+#define PHIGH 215
+
+#define DISPLAY_GAMMA 2.20  /* default display gamma */
+#define COMPRESSION   6     /* default zlib compression level, not max
+                               (Z_BEST_COMPRESSION) */
+
+#define HAVE_tRNS     (info_ptr->valid & PNG_INFO_tRNS)
+
+#define DWIDE     86
+#define DHIGH    104
+#define PFX PWIDE-93
+#define PFY       44
+#define PFH       20
+
+#define P_BOK    0
+#define P_BCANC  1
+#define P_NBUTTS 2
+
+#define BUTTH    24
+
+#define LF       10   /* a.k.a. '\n' on ASCII machines */
+#define CR       13   /* a.k.a. '\r' on ASCII machines */
+
+/*** local functions ***/
+static    void drawPD         PARM((int, int, int, int));
+static    void clickPD        PARM((int, int));
+static    void doCmd          PARM((int));
+static    void writePNG       PARM((void));
+static    int  WritePNG       PARM((FILE *, byte *, int, int, int,
+                                    byte *, byte *, byte *, int));
+
+static    void png_xv_error   PARM((png_structp png_ptr,
+                                    png_const_charp message));
+static    void png_xv_warning PARM((png_structp png_ptr,
+                                    png_const_charp message));
+
+/*** local variables ***/
+static char *filename;
+static char *fbasename;
+static int   colorType;
+static int   read_anything;
+static double Display_Gamma = DISPLAY_GAMMA;
+
+static DIAL  cDial, gDial;
+static BUTT  pbut[P_NBUTTS];
+static CBUTT interCB;
+static CBUTT FdefCB, FnoneCB, FsubCB, FupCB, FavgCB, FPaethCB;
+
+/**************************************************************************/
+/* PNG SAVE DIALOG ROUTINES ***********************************************/
+/**************************************************************************/
+
+
+/*******************************************/
+void CreatePNGW()
+{
+  pngW = CreateWindow("xv png", "XVPNG", NULL,
+                      PWIDE, PHIGH, infofg, infobg, 0);
+  if (!pngW) FatalError("can't create PNG window!");
+
+  XSelectInput(theDisp, pngW, ExposureMask | ButtonPressMask | KeyPressMask);
+
+  DCreate(&cDial, pngW,  12, 25, DWIDE, DHIGH, (double)Z_NO_COMPRESSION,
+          (double)Z_BEST_COMPRESSION, COMPRESSION, 1.0, 3.0,
+          infofg, infobg, hicol, locol, "Compression", NULL);
+
+  DCreate(&gDial, pngW, DWIDE+27, 25, DWIDE, DHIGH, 1.0, 3.5,DISPLAY_GAMMA,0.01,0.2,
+          infofg, infobg, hicol, locol, "Disp. Gamma", NULL);
+
+  CBCreate(&interCB, pngW,  DWIDE+30, DHIGH+3*LINEHIGH+2, "interlace",
+           infofg, infobg, hicol, locol);
+
+  CBCreate(&FdefCB,   pngW, PFX, PFY, "Default",
+           infofg, infobg, hicol, locol);
+  FdefCB.val = 1;
+
+  CBCreate(&FnoneCB,  pngW, PFX, FdefCB.y + PFH + 4, "none",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FsubCB,   pngW, PFX, FnoneCB.y + PFH, "sub",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FupCB,    pngW, PFX, FsubCB.y  + PFH, "up",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FavgCB,   pngW, PFX, FupCB.y   + PFH, "average",
+           infofg, infobg, hicol, locol);
+  CBCreate(&FPaethCB, pngW, PFX, FavgCB.y  + PFH, "Paeth",
+           infofg, infobg, hicol, locol);
+
+  FnoneCB.val = FsubCB.val = FupCB.val = FavgCB.val = FPaethCB.val = 1;
+  CBSetActive(&FnoneCB, !FdefCB.val);
+  CBSetActive(&FsubCB, !FdefCB.val);
+  CBSetActive(&FupCB, !FdefCB.val);
+  CBSetActive(&FavgCB, !FdefCB.val);
+  CBSetActive(&FPaethCB, !FdefCB.val);
+
+  BTCreate(&pbut[P_BOK], pngW, PWIDE-180-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Ok", infofg, infobg, hicol, locol);
+  BTCreate(&pbut[P_BCANC], pngW, PWIDE-90-1, PHIGH-10-BUTTH-1, 80, BUTTH,
+          "Cancel", infofg, infobg, hicol, locol);
+
+  XMapSubwindows(theDisp, pngW);
+}
+
+
+/*******************************************/
+void PNGDialog(vis)
+     int vis;
+{
+  if (vis) {
+    CenterMapWindow(pngW, pbut[P_BOK].x + (int) pbut[P_BOK].w/2,
+                          pbut[P_BOK].y + (int) pbut[P_BOK].h/2,
+                    PWIDE, PHIGH);
+  }
+  else XUnmapWindow(theDisp, pngW);
+  pngUp = vis;
+}
+
+
+/*******************************************/
+int PNGCheckEvent(xev)
+     XEvent *xev;
+{
+  /* check event to see if it's for one of our subwindows.  If it is,
+     deal accordingly, and return '1'.  Otherwise, return '0' */
+
+  int rv;
+  rv = 1;
+
+  if (!pngUp) return 0;
+
+  if (xev->type == Expose) {
+    int x,y,w,h;
+    XExposeEvent *e = (XExposeEvent *) xev;
+    x = e->x; y = e->y; w = e->width; h = e->height;
+
+    /* throw away excess expose events for 'dumb' windows */
+    if (e->count > 0 && (e->window == cDial.win)) {}
+
+    else if (e->window == pngW)        drawPD(x, y, w, h);
+    else if (e->window == cDial.win)   DRedraw(&cDial);
+    else if (e->window == gDial.win)   DRedraw(&gDial);
+    else rv = 0;
+  }
+
+  else if (xev->type == ButtonPress) {
+    XButtonEvent *e = (XButtonEvent *) xev;
+    int x,y;
+    x = e->x;  y = e->y;
+
+    if (e->button == Button1) {
+      if      (e->window == pngW)       clickPD(x,y);
+      else if (e->window == cDial.win)  DTrack(&cDial,x,y);
+      else if (e->window == gDial.win)  DTrack(&gDial,x,y);
+      else rv = 0;
+    }  /* button1 */
+    else rv = 0;
+  }  /* button press */
+
+  else if (xev->type == KeyPress) {
+    XKeyEvent *e = (XKeyEvent *) xev;
+    char buf[128];  KeySym ks;
+    int stlen;
+
+    stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
+    buf[stlen] = '\0';
+
+    RemapKeyCheck(ks, buf, &stlen);
+
+    if (e->window == pngW) {
+      if (stlen) {
+        if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
+          FakeButtonPress(&pbut[P_BOK]);
+        }
+        else if (buf[0] == '\033') {            /* ESC */
+          FakeButtonPress(&pbut[P_BCANC]);
+        }
+      }
+    }
+    else rv = 0;
+  }
+  else rv = 0;
+
+  if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
+    XBell(theDisp, 50);
+    rv = 1;   /* eat it */
+  }
+
+  return rv;
+}
+
+
+/*******************************************/
+void PNGSaveParams(fname, col)
+     char *fname;
+     int col;
+{
+  filename = fname;
+  colorType = col;
+}
+
+
+/*******************************************/
+static void drawPD(x, y, w, h)
+     int x, y, w, h;
+{
+  char *title   = "Save PNG file...";
+
+  char ctitle1[20];
+  char *ctitle2 = "Useful range";
+  char *ctitle3 = "is 2 - 7.";
+  char *ctitle4 = "Uncompressed = 0";
+
+  char *ftitle  = "Row Filters:";
+
+  char gtitle[20];
+
+  int i;
+  XRectangle xr;
+
+  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
+  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
+
+  XSetForeground(theDisp, theGC, infofg);
+  XSetBackground(theDisp, theGC, infobg);
+
+  for (i=0; i<P_NBUTTS; i++) BTRedraw(&pbut[i]);
+
+  DrawString(pngW,       15,  6+ASCENT,                          title);
+
+  sprintf(ctitle1, "Default = %d", COMPRESSION);
+  DrawString(pngW,       18,  6+DHIGH+cDial.y+ASCENT,            ctitle1);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+LINEHIGH,   ctitle2);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+2*LINEHIGH, ctitle3);
+  DrawString(pngW,       17,  6+DHIGH+cDial.y+ASCENT+3*LINEHIGH, ctitle4);
+
+  sprintf(gtitle, "Default = %g", DISPLAY_GAMMA);
+  DrawString(pngW, DWIDE+30,  6+DHIGH+gDial.y+ASCENT,            gtitle);
+
+  ULineString(pngW, FdefCB.x, FdefCB.y-3-DESCENT, ftitle);
+  XDrawRectangle(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y-LINEHIGH-3,
+                                       93, 8*LINEHIGH+15);
+  CBRedraw(&FdefCB);
+  XDrawLine(theDisp, pngW, theGC, FdefCB.x-11, FdefCB.y+LINEHIGH+4,
+                                  FdefCB.x+82, FdefCB.y+LINEHIGH+4);
+
+  CBRedraw(&FnoneCB);
+  CBRedraw(&FupCB);
+  CBRedraw(&FsubCB);
+  CBRedraw(&FavgCB);
+  CBRedraw(&FPaethCB);
+
+  CBRedraw(&interCB);
+
+  XSetClipMask(theDisp, theGC, None);
+}
+
+
+/*******************************************/
+static void clickPD(x,y)
+     int x,y;
+{
+  int i;
+  BUTT *bp;
+
+  /* check BUTTs */
+
+  for (i=0; i<P_NBUTTS; i++) {
+    bp = &pbut[i];
+    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
+  }
+
+  if (i<P_NBUTTS) {  /* found one */
+    if (BTTrack(bp)) doCmd(i);
+  }
+
+  /* check CBUTTs */
+
+  else if (CBClick(&FdefCB,x,y)) {
+    int oldval = FdefCB.val;
+
+    CBTrack(&FdefCB);
+
+    if (oldval != FdefCB.val)
+    {
+      CBSetActive(&FnoneCB, !FdefCB.val);
+      CBSetActive(&FsubCB, !FdefCB.val);
+      CBSetActive(&FupCB, !FdefCB.val);
+      CBSetActive(&FavgCB, !FdefCB.val);
+      CBSetActive(&FPaethCB, !FdefCB.val);
+
+      CBRedraw(&FnoneCB);
+      CBRedraw(&FupCB);
+      CBRedraw(&FsubCB);
+      CBRedraw(&FavgCB);
+      CBRedraw(&FPaethCB);
+    }
+  }
+  else if (CBClick(&FnoneCB,x,y))  CBTrack(&FnoneCB);
+  else if (CBClick(&FsubCB,x,y))   CBTrack(&FsubCB);
+  else if (CBClick(&FupCB,x,y))    CBTrack(&FupCB);
+  else if (CBClick(&FavgCB,x,y))   CBTrack(&FavgCB);
+  else if (CBClick(&FPaethCB,x,y)) CBTrack(&FPaethCB);
+  else if (CBClick(&interCB,x,y))  CBTrack(&interCB);
+}
+
+
+/*******************************************/
+static void doCmd(cmd)
+     int cmd;
+{
+  switch (cmd) {
+    case P_BOK:
+      {
+        char *fullname;
+
+        writePNG();
+        PNGDialog(0);
+
+        fullname = GetDirFullName();
+        if (!ISPIPE(fullname[0])) {
+          XVCreatedFile(fullname);
+          StickInCtrlList(0);
+        }
+      }
+      break;
+
+    case P_BCANC:
+      PNGDialog(0);
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+/*******************************************/
+static void writePNG()
+{
+  FILE       *fp;
+  int         w, h, nc, rv, ptype, pfree;
+  byte       *inpix, *rmap, *gmap, *bmap;
+
+  fp = OpenOutFile(filename);
+  if (!fp) return;
+
+  fbasename = BaseName(filename);
+
+  WaitCursor();
+  inpix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap);
+
+  rv = WritePNG(fp, inpix, ptype, w, h, rmap, gmap, bmap, nc);
+
+  SetCursors(-1);
+
+  if (CloseOutFile(fp, filename, rv) == 0) DirBox(0);
+
+  if (pfree) free(inpix);
+}
+
+
+/*******************************************/
+int WritePNG(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols)
+     FILE *fp;
+     byte *pic;
+     int   ptype, w, h;
+     byte *rmap, *gmap, *bmap;
+     int   numcols;
+{
+  png_struct *png_ptr;
+  png_info   *info_ptr;
+  png_color   palette[256];
+  png_textp   text;
+  byte        remap[256];
+  int         i, filter, linesize, pass;
+  byte       *p, *png_line;
+  char        software[256];
+  char       *savecmnt;
+
+  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+       png_xv_error, png_xv_warning)) == NULL) {
+    sprintf(software, "png_create_write_struct() failure in WritePNG (ver. %s)",
+      PNG_LIBPNG_VER_STRING);
+    FatalError(software);
+  }
+
+  if ((info_ptr = png_create_info_struct(png_ptr)) == NULL)
+  {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    sprintf(software, "png_create_info_struct() failure in WritePNG");
+    FatalError(software);
+  }
+
+  if (setjmp(png_ptr->jmpbuf)) {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  png_init_io(png_ptr, fp);
+
+  png_set_compression_level(png_ptr, (int)cDial.val);
+
+  /* Don't bother filtering if we aren't compressing the image */
+  if (FdefCB.val)
+  {
+    if ((int)cDial.val == 0)
+      png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+  }
+  else
+  {
+    filter  = FnoneCB.val  ? PNG_FILTER_NONE  : 0;
+    filter |= FsubCB.val   ? PNG_FILTER_SUB   : 0;
+    filter |= FupCB.val    ? PNG_FILTER_UP    : 0;
+    filter |= FavgCB.val   ? PNG_FILTER_AVG   : 0;
+    filter |= FPaethCB.val ? PNG_FILTER_PAETH : 0;
+
+    png_set_filter(png_ptr, 0, filter);
+  }
+
+  info_ptr->width = w;
+  info_ptr->height = h;
+  if (w <= 0 || h <= 0) {
+    SetISTR(ISTR_WARNING, "%s:  image dimensions out of range (%dx%d)",
+      fbasename, w, h);
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return -1;
+  }
+
+  info_ptr->interlace_type = interCB.val ? 1 : 0;
+
+  linesize = 0;   /* quiet a compiler warning */
+
+  if (colorType == F_FULLCOLOR || colorType == F_REDUCED) {
+    if(ptype == PIC24) {
+      linesize = 3*w;
+      if (linesize/3 < w) {
+        SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+          fbasename, w, h);
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        return -1;
+      }
+      info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+      info_ptr->bit_depth = 8;
+    } else {
+      linesize = w;
+      info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+      if(numcols <= 2)
+        info_ptr->bit_depth = 1;
+      else
+      if(numcols <= 4)
+        info_ptr->bit_depth = 2;
+      else
+      if(numcols <= 16)
+        info_ptr->bit_depth = 4;
+      else
+        info_ptr->bit_depth = 8;
+
+      for(i = 0; i < numcols; i++) {
+        palette[i].red   = rmap[i];
+        palette[i].green = gmap[i];
+        palette[i].blue  = bmap[i];
+      }
+      info_ptr->num_palette = numcols;
+      info_ptr->palette = palette;
+      info_ptr->valid |= PNG_INFO_PLTE;
+    }
+  }
+
+  else if(colorType == F_GREYSCALE || colorType == F_BWDITHER) {
+    info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
+    if(colorType == F_BWDITHER) {
+      /* shouldn't happen */
+      if (ptype == PIC24) FatalError("PIC24 and B/W Stipple in WritePNG()");
+
+      info_ptr->bit_depth = 1;
+      if(MONO(rmap[0], gmap[0], bmap[0]) > MONO(rmap[1], gmap[1], bmap[1])) {
+        remap[0] = 1;
+        remap[1] = 0;
+      }
+      else {
+        remap[0] = 0;
+        remap[1] = 1;
+      }
+      linesize = w;
+    }
+    else {
+      if(ptype == PIC24) {
+        linesize = 3*w;
+        if (linesize/3 < w) {
+          SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+            fbasename, w, h);
+          png_destroy_write_struct(&png_ptr, &info_ptr);
+          return -1;
+        }
+        info_ptr->bit_depth = 8;
+      }
+      else {
+        int low_precision;
+
+        linesize = w;
+
+        for(i = 0; i < numcols; i++)
+          remap[i] = MONO(rmap[i], gmap[i], bmap[i]);
+
+        for(; i < 256; i++)
+          remap[i]=0;
+
+        info_ptr->bit_depth = 8;
+
+        /* Note that this fails most of the time because of gamma */
+        /* try to adjust to 4-bit precision grayscale */
+
+        low_precision=1;
+
+        for(i = 0; i < numcols; i++) {
+          if((remap[i] & 0x0f) * 0x11 != remap[i]) {
+            low_precision = 0;
+            break;
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 0xf;
+          }
+          info_ptr->bit_depth = 4;
+
+          /* try to adjust to 2-bit precision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x03) * 0x05 != remap[i]) {
+              low_precision = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 3;
+          }
+          info_ptr->bit_depth = 2;
+
+          /* try to adjust to 1-bit precision grayscale */
+
+          for(i = 0; i < numcols; i++) {
+            if((remap[i] & 0x01) * 0x03 != remap[i]) {
+              low_precision = 0;
+              break;
+            }
+          }
+        }
+
+        if(low_precision) {
+          for(i = 0; i < numcols; i++) {
+            remap[i] &= 1;
+          }
+          info_ptr->bit_depth = 1;
+        }
+      }
+    }
+  }
+
+  else
+    png_error(png_ptr, "Unknown colorstyle in WritePNG");
+
+  if ((text = (png_textp)malloc(sizeof(png_text)))) {
+    sprintf(software, "XV %s", REVDATE);
+
+    text->compression = -1;
+    text->key = "Software";
+    text->text = software;
+    text->text_length = strlen(text->text);
+
+    info_ptr->max_text = 1;
+    info_ptr->num_text = 1;
+    info_ptr->text = text;
+  }
+
+  Display_Gamma = gDial.val;  /* Save the current gamma for loading */
+
+  info_ptr->gamma = 1.0/gDial.val;
+  info_ptr->valid |= PNG_INFO_gAMA;
+
+  png_write_info(png_ptr, info_ptr);
+
+  if(info_ptr->bit_depth < 8)
+    png_set_packing(png_ptr);
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  if((png_line = malloc(linesize)) == NULL)
+    png_error(png_ptr, "cannot allocate temp image line");
+
+  for(i = 0; i < pass; i++) {
+    int j;
+    p = pic;
+    for(j = 0; j < h; j++) {
+      if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
+        int k;
+        for(k = 0; k < w; k++)
+          png_line[k] = ptype==PIC24 ? MONO(p[k*3], p[k*3+1], p[k*3+2]) :
+                                       remap[p[k]];
+        png_write_row(png_ptr, png_line);
+      } else  /* RGB or palette */
+        png_write_row(png_ptr, p);
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  free(png_line);
+
+  savecmnt = NULL;   /* quiet a compiler warning */
+
+  if (text)
+  {
+    if (picComments && strlen(picComments) &&
+        (savecmnt = (char *)malloc((strlen(picComments) + 1)*sizeof(char)))) {
+      png_textp tp;
+      char *comment, *key;
+
+      strcpy(savecmnt, picComments);
+      key = savecmnt;
+      tp = text;
+      info_ptr->num_text = 0;
+
+      comment = strchr(key, ':');
+
+      do  {
+        /* Allocate a larger structure for comments if necessary */
+        if (info_ptr->num_text >= info_ptr->max_text)
+        {
+          if ((tp =
+              realloc(text, (info_ptr->num_text + 2)*sizeof(png_text))) == NULL)
+          {
+            break;
+          }
+          else
+          {
+            text = tp;
+            tp = &text[info_ptr->num_text];
+            info_ptr->max_text += 2;
+          }
+        }
+
+        /* See if it looks like a PNG keyword from LoadPNG */
+        /* GRR: should test for strictly < 80, right? (key = 1-79 chars only) */
+        if(comment && comment[1] == ':' && comment - key <= 80) {
+          *(comment++) = '\0';
+          *(comment++) = '\0';
+
+          /* If the comment is the 'Software' chunk XV writes, we remove it,
+             since we have already stored one */
+          if (strcmp(key, "Software") == 0 && strncmp(comment, "XV", 2) == 0) {
+            key = strchr(comment, '\n');
+            if(key)
+              key++; /* skip \n */
+            comment = strchr(key, ':');
+          }
+          /* We have another keyword and/or comment to write out */
+          else {
+            tp->key = key;
+            tp->text = comment;
+
+            /* We have to find the end of this comment, and the next keyword
+               if there is one */
+            for (; NULL != (key = comment = strchr(comment, ':')); comment++)
+              if (key[1] == ':')
+                break;
+
+            /* It looks like another keyword, go backward to the beginning */
+            if (key) {
+              while(key > tp->text && *key != '\n')
+                key--;
+
+              if (key > tp->text && comment - key <= 80) {
+                *key = '\0';
+                key++;
+              }
+            }
+
+            tp->text_length = strlen(tp->text);
+
+            /* We don't have another keyword, so remove the last newline */
+            if (!key && tp->text[tp->text_length - 1] == '\n')
+            {
+              tp->text[tp->text_length] = '\0';
+              tp->text_length--;
+            }
+
+            tp->compression = tp->text_length > 640 ? 0 : -1;
+            info_ptr->num_text++;
+            tp++;
+          }
+        }
+        /* Just a generic comment:  make sure line-endings are valid for PNG */
+        else {
+          char *p=key, *q=key;     /* only deleting chars, not adding any */
+
+          while (*p) {
+            if (*p == CR) {        /* lone CR or CR/LF:  EOL either way */
+              *q++ = LF;           /* LF is the only allowed PNG line-ending */
+              if (p[1] == LF)      /* get rid of any original LF */
+                ++p;
+            } else if (*p == LF)   /* lone LF */
+              *q++ = LF;
+            else
+              *q++ = *p;
+            ++p;
+          }
+          *q = '\0';               /* unnecessary...but what the heck */
+          tp->key = "Comment";
+          tp->text = key;
+          tp->text_length = q - key;
+          tp->compression = tp->text_length > 750 ? 0 : -1;
+          info_ptr->num_text++;
+          key = NULL;
+        }
+      } while (key && *key);
+    }
+    else
+    {
+      info_ptr->num_text = 0;
+    }
+  }
+  info_ptr->text = text;
+
+  png_convert_from_time_t(&(info_ptr->mod_time), time(NULL));
+  info_ptr->valid |= PNG_INFO_tIME;
+
+  png_write_end(png_ptr, info_ptr);
+  fflush(fp);   /* just in case we core-dump before finishing... */
+
+  if (text)
+  {
+    free(text);
+    /* must do this or png_destroy_write_struct() 0.97+ will free text again: */
+    info_ptr->text = (png_textp)NULL;
+    if (savecmnt)
+    {
+      free(savecmnt);
+      savecmnt = (char *)NULL;
+    }
+  }
+
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+
+  return 0;
+}
+
+
+/*******************************************/
+int LoadPNG(fname, pinfo)
+     char    *fname;
+     PICINFO *pinfo;
+/*******************************************/
+{
+  /* returns '1' on success */
+
+  FILE  *fp;
+  png_struct *png_ptr;
+  png_info *info_ptr;
+  png_color_16 my_background;
+  int i,j;
+  int linesize, bufsize;
+  int filesize;
+  int pass;
+  int gray_to_rgb;
+  size_t commentsize;
+
+  fbasename = BaseName(fname);
+
+  pinfo->pic     = (byte *) NULL;
+  pinfo->comment = (char *) NULL;
+
+  read_anything=0;
+
+  /* open the file */
+  fp = xv_fopen(fname,"r");
+  if (!fp) {
+    SetISTR(ISTR_WARNING,"%s:  can't open file", fname);
+    return 0;
+  }
+
+  /* find the size of the file */
+  fseek(fp, 0L, 2);
+  filesize = ftell(fp);
+  fseek(fp, 0L, 0);
+
+  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                   png_xv_error, png_xv_warning);
+  if(!png_ptr) {
+    fclose(fp);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  info_ptr = png_create_info_struct(png_ptr);
+
+  if(!info_ptr) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+    FatalError("malloc failure in LoadPNG");
+  }
+
+  if(setjmp(png_ptr->jmpbuf)) {
+    fclose(fp);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    if(!read_anything) {
+      if(pinfo->pic) {
+        free(pinfo->pic);
+        pinfo->pic = NULL;
+      }
+      if(pinfo->comment) {
+        free(pinfo->comment);
+        pinfo->comment = NULL;
+      }
+    }
+    return read_anything;
+  }
+
+  png_init_io(png_ptr, fp);
+  png_read_info(png_ptr, info_ptr);
+
+  pinfo->w = pinfo->normw = info_ptr->width;
+  pinfo->h = pinfo->normh = info_ptr->height;
+  if (pinfo->w <= 0 || pinfo->h <= 0) {
+    SetISTR(ISTR_WARNING, "%s:  image dimensions out of range (%dx%d)",
+      fbasename, pinfo->w, pinfo->h);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return read_anything;
+  }
+
+  pinfo->frmType = F_PNG;
+
+  sprintf(pinfo->fullInfo, "PNG, %d bit ",
+          info_ptr->bit_depth * info_ptr->channels);
+
+  switch(info_ptr->color_type) {
+    case PNG_COLOR_TYPE_PALETTE:
+      strcat(pinfo->fullInfo, "palette color");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY:
+      strcat(pinfo->fullInfo, "grayscale");
+      break;
+
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+      strcat(pinfo->fullInfo, "grayscale+alpha");
+      break;
+
+    case PNG_COLOR_TYPE_RGB:
+      strcat(pinfo->fullInfo, "truecolor");
+      break;
+
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+      strcat(pinfo->fullInfo, "truecolor+alpha");
+      break;
+  }
+
+  sprintf(pinfo->fullInfo + strlen(pinfo->fullInfo),
+	  ", %sinterlaced. (%d bytes)",
+	  info_ptr->interlace_type ? "" : "non-", filesize);
+
+  sprintf(pinfo->shrtInfo, "%ldx%ld PNG", info_ptr->width, info_ptr->height);
+
+  if (info_ptr->bit_depth < 8)
+      png_set_packing(png_ptr);
+
+  if (info_ptr->valid & PNG_INFO_gAMA)
+    png_set_gamma(png_ptr, Display_Gamma, info_ptr->gamma);
+  else
+    png_set_gamma(png_ptr, Display_Gamma, 0.45);
+
+  gray_to_rgb = 0;   /* quiet a compiler warning */
+
+  if (have_imagebg) {
+    if (info_ptr->bit_depth == 16) {
+      my_background.red   = imagebgR;
+      my_background.green = imagebgG;
+      my_background.blue  = imagebgB;
+      my_background.gray = imagebgG;   /* only used if all three equal... */
+    } else {
+      my_background.red   = (imagebgR >> 8);
+      my_background.green = (imagebgG >> 8);
+      my_background.blue  = (imagebgB >> 8);
+      my_background.gray = my_background.green;
+    }
+    png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
+                       0, Display_Gamma);
+    if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+         (info_ptr->color_type == PNG_COLOR_TYPE_GRAY && HAVE_tRNS)) &&
+        (imagebgR != imagebgG || imagebgR != imagebgB))  /* i.e., colored bg */
+    {
+      png_set_gray_to_rgb(png_ptr);
+      png_set_expand(png_ptr);
+      gray_to_rgb = 1;
+    }
+  } else {
+    if (info_ptr->valid & PNG_INFO_bKGD) {
+      png_set_background(png_ptr, &info_ptr->background,
+                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+    } else {
+      my_background.red = my_background.green = my_background.blue =
+        my_background.gray = 0;
+      png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN,
+                         0, Display_Gamma);
+    }
+  }
+
+  if (info_ptr->bit_depth == 16)
+    png_set_strip_16(png_ptr);
+
+  if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+      info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+  {
+    if (info_ptr->bit_depth == 1)
+      pinfo->colType = F_BWDITHER;
+    else
+      pinfo->colType = F_GREYSCALE;
+    png_set_expand(png_ptr);
+  }
+
+  pass=png_set_interlace_handling(png_ptr);
+
+  png_read_update_info(png_ptr, info_ptr);
+
+  if(info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+     info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || gray_to_rgb)
+  {
+    linesize = 3 * pinfo->w;
+    if (linesize/3 < pinfo->w) {   /* know pinfo->w > 0 (see above) */
+      SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+        fbasename, pinfo->w, pinfo->h);
+      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+      return read_anything;
+    }
+    pinfo->colType = F_FULLCOLOR;
+    pinfo->type = PIC24;
+  } else {
+    linesize = pinfo->w;
+    pinfo->type = PIC8;
+    if(info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+       info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+      for(i = 0; i < 256; i++)
+        pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i;
+    } else {
+      pinfo->colType = F_FULLCOLOR;
+      for(i = 0; i < info_ptr->num_palette; i++) {
+        pinfo->r[i] = info_ptr->palette[i].red;
+        pinfo->g[i] = info_ptr->palette[i].green;
+        pinfo->b[i] = info_ptr->palette[i].blue;
+      }
+    }
+  }
+
+  bufsize = linesize * pinfo->h;
+  if (bufsize/linesize < pinfo->h) {  /* know linesize, pinfo->h > 0 (above) */
+    SetISTR(ISTR_WARNING, "%s:  image dimensions too large (%dx%d)",
+      fbasename, pinfo->w, pinfo->h);
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return read_anything;
+  }
+  pinfo->pic = calloc((size_t)bufsize, (size_t)1);
+
+  if(!pinfo->pic) {
+    png_error(png_ptr, "can't allocate space for PNG image");
+  }
+
+  png_start_read_image(png_ptr);
+
+  for(i = 0; i < pass; i++) {
+    byte *p = pinfo->pic;
+    for(j = 0; j < pinfo->h; j++) {
+      png_read_row(png_ptr, p, NULL);
+      read_anything = 1;
+      if((j & 0x1f) == 0) WaitCursor();
+      p += linesize;
+    }
+  }
+
+  png_read_end(png_ptr, info_ptr);
+
+  if(info_ptr->num_text > 0) {
+    commentsize = 1;
+
+    for(i = 0; i < info_ptr->num_text; i++)
+      commentsize += strlen(info_ptr->text[i].key) + 1 +
+                     info_ptr->text[i].text_length + 2;
+
+    if((pinfo->comment = malloc(commentsize)) == NULL) {
+      png_warning(png_ptr,"can't allocate comment string");
+    }
+    else {
+      pinfo->comment[0] = '\0';
+      for(i = 0; i < info_ptr->num_text; i++) {
+        strcat(pinfo->comment, info_ptr->text[i].key);
+        strcat(pinfo->comment, "::");
+        strcat(pinfo->comment, info_ptr->text[i].text);
+        strcat(pinfo->comment, "\n");
+      }
+    }
+  }
+
+  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+  fclose(fp);
+
+  return 1;
+}
+
+
+/*******************************************/
+static void
+png_xv_error(png_ptr, message)
+     png_structp png_ptr;
+     png_const_charp message;
+{
+  SetISTR(ISTR_WARNING,"%s:  libpng error: %s", fbasename, message);
+
+  longjmp(png_ptr->jmpbuf, 1);
+}
+
+
+/*******************************************/
+static void
+png_xv_warning(png_ptr, message)
+     png_structp png_ptr;
+     png_const_charp message;
+{
+  if (!png_ptr)
+    return;
+
+  SetISTR(ISTR_WARNING,"%s:  libpng warning: %s", fbasename, message);
+}
+
+
+/*******************************************/
+void
+VersionInfoPNG()	/* GRR 19980605 */
+{
+  fprintf(stderr, "   Compiled with libpng %s; using libpng %s.\n",
+    PNG_LIBPNG_VER_STRING, png_libpng_ver);
+  fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
+    ZLIB_VERSION, zlib_version);
+}
+
+#endif /* HAVE_PNG */
diff -ruN xv-3.10a-bugfixes/xvpopup.c xv-3.10a-enhancements/xvpopup.c
--- xv-3.10a-bugfixes/xvpopup.c	2004-05-16 18:04:13.000000000 -0700
+++ xv-3.10a-enhancements/xvpopup.c	2005-04-10 09:52:19.000000000 -0700
@@ -201,14 +201,14 @@
 
     if (!padHaveDooDads) {
       DCreate(&padWDial, popW, 16,      puhigh-16-100-1,75,100,
-	      1, 2048, pWIDE, 10,
+	      1.0, 2048.0, (double)pWIDE, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Width", NULL);
       DCreate(&padHDial, popW, 16+1+75, puhigh-16-100-1,75,100,
-	      1, 2048, pHIGH, 10,
+	      1.0, 2048.0, (double)pHIGH, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Height", NULL);
 
       DCreate(&padODial, popW, 16+1+75+75+9, puhigh-16-100-1,75,100,
-	      0, 100, 100, 10,
+	      0.0, 100.0, 100.0, 1.0, 10.0,
 	      infofg, infobg, hicol, locol, "Opaque", NULL);
 
       MBCreate(&padMthdMB, popW, 100-2+44, 10, 140, 19, NULL,
@@ -259,9 +259,9 @@
   else if (poptyp == ISPAD) {
     BTSetActive(&bts[0], (int) strlen(gsBuf));
     i = pWIDE * 3;  RANGE(i,2048,9999);
-    DSetRange(&padWDial, 1, i, padWDial.val, 10);
+    DSetRange(&padWDial, 1.0, (double)i, padWDial.val, 1.0, 10.0);
     i = pHIGH * 3;  RANGE(i,2048,9999);
-    DSetRange(&padHDial, 1, i, padHDial.val, 10);
+    DSetRange(&padHDial, 1.0, (double)i, padHDial.val, 1.0, 10.0);
 
     DSetActive(&padWDial, (padMode!=PAD_LOAD));  /* DSetRange activates dial */
     DSetActive(&padHDial, (padMode!=PAD_LOAD));
@@ -466,9 +466,9 @@
   changedGSBuf();      /* careful!  popW doesn't exist yet! */
 
   if (padHaveDooDads) {
-    oldW = padWDial.val;
-    oldH = padHDial.val;
-    oldO = padODial.val;
+    oldW = (int)padWDial.val;
+    oldH = (int)padHDial.val;
+    oldO = (int)padODial.val;
   }
   else { oldW = pWIDE;  oldH = pHIGH;  oldO = 100; }
 
@@ -487,9 +487,9 @@
   }
 
   if (rv == 1) {   /* cancelled:  restore normal values */
-    DSetVal(&padWDial, oldW);
-    DSetVal(&padHDial, oldH);
-    DSetVal(&padODial, oldO);
+    DSetVal(&padWDial, (double)oldW);
+    DSetVal(&padHDial, (double)oldH);
+    DSetVal(&padODial, (double)oldO);
   }
 
   XUnmapWindow(theDisp, padWDial.win);
@@ -499,9 +499,9 @@
   /* load up return values */
   *pMode   = padMode;
   *pStr    = padBuf;
-  *pWide   = padWDial.val;
-  *pHigh   = padHDial.val;
-  *pOpaque = padODial.val;
+  *pWide   = (int)padWDial.val;
+  *pHigh   = (int)padHDial.val;
+  *pOpaque = (int)padODial.val;
   *pOmode  = padOMode;
 
   return rv;
@@ -972,8 +972,8 @@
   else if (popUp == ISPAD) {
     if (PTINRECT(x, y, padDButt.x, padDButt.y, padDButt.w, padDButt.h)) {
       if (BTTrack(&padDButt)) {
-	DSetVal(&padWDial, pWIDE);
-	DSetVal(&padHDial, pHIGH);
+	DSetVal(&padWDial, (double)pWIDE);
+	DSetVal(&padHDial, (double)pHIGH);
       }
     }
 
@@ -1105,7 +1105,7 @@
   }
 
 
-  else if (c=='\010' || c=='\177') {    /* BS or DEL */
+  else if (c=='\010') {                 /* BS */
     if (gsCurPos==0) return 1;                     /* at beginning of str */
     xvbcopy(&gsBuf[gsCurPos], &gsBuf[gsCurPos-1], (size_t) len-gsCurPos+1);
     gsCurPos--;
@@ -1128,7 +1128,7 @@
     gsCurPos = len;
   }
 
-  else if (c=='\004') {                 /* ^D: delete character at gsCurPos */
+  else if (c=='\004' || c=='\177') {    /* ^D or DEL: delete character at gsCurPos */
     if (gsCurPos==len) return 1;
     xvbcopy(&gsBuf[gsCurPos+1], &gsBuf[gsCurPos], (size_t) len-gsCurPos);
   }
diff -ruN xv-3.10a-bugfixes/xvps.c xv-3.10a-enhancements/xvps.c
--- xv-3.10a-bugfixes/xvps.c	2005-03-30 08:18:17.000000000 -0800
+++ xv-3.10a-enhancements/xvps.c	2005-03-30 08:19:00.000000000 -0800
@@ -142,9 +142,9 @@
   CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg, hicol, locol);
   CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg, hicol, locol);
 
-  DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5,
+  DCreate(&xsDial, psW, 240, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0,
 	  infofg, infobg, hicol, locol, "Width", "%");
-  DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5,
+  DCreate(&ysDial, psW, 331, 30, 80, 100, 10.0, 800.0, 100.0, 0.5, 5.0,
 	  infofg, infobg, hicol, locol, "Height", "%");
   xsDial.drawobj = changedScale;
   ysDial.drawobj = changedScale;
@@ -239,10 +239,10 @@
 
   if (rd_int("psres")) {             /* xv.psres:  default paper resolution */
     if (def_int >= 10 && def_int <= 720) {
-      int i = (int) ((PIX2INCH * 100) / def_int);
+      double v = (PIX2INCH * 100) / def_int;
 
-      DSetVal(&xsDial, i);
-      DSetVal(&ysDial, i);
+      DSetVal(&xsDial, v);
+      DSetVal(&ysDial, v);
     }
   }
 
@@ -839,7 +839,7 @@
   if (scx < scy) { sz_iny = h * scx; }
             else { sz_inx = w * scy; }
 
-  DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5));
+  DSetVal(&xsDial, 100 * (sz_inx * PIX2INCH) / w);
   DSetVal(&ysDial, xsDial.val);
 
   sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);
@@ -1563,7 +1563,6 @@
 #ifdef GS_PATH
   char tmp[512], gscmd[512], cmdstr[512], tmpname[64];
   int  gsresult, nump, i, filetype, doalert, epsf;
-  char *rld;
 #endif
 
   pinfo->pic     = (byte *) NULL;
diff -ruN xv-3.10a-bugfixes/xvrle.c xv-3.10a-enhancements/xvrle.c
--- xv-3.10a-bugfixes/xvrle.c	2005-03-29 23:29:14.000000000 -0800
+++ xv-3.10a-enhancements/xvrle.c	2004-05-16 18:07:46.000000000 -0700
@@ -43,7 +43,7 @@
   byte   bgcol[256];
   byte   maps[3][256];
   int    xpos, ypos, w, h, flags, ncolors, pixelbits, ncmap, cmaplen;
-  int    cmtlen, npixels, bufsize=0;
+  int    cmtlen;
   byte  *img;
   long filesize;
   char  *bname, *errstr;
@@ -176,44 +176,32 @@
 
   errstr = NULL;
   if (ncolors == 0 || ncolors == 2)
-    errstr = "Unsupported number of channels in RLE file";
+    errstr = "Unsupt. # of channels in RLE file.\n";
 
   if (pixelbits != 8)
-    errstr = "Only 8-bit pixels supported in RLE files";
+    errstr = "Only 8-bit pixels supported in RLE files.\n";
 
   if (ncmap==0 || ncmap==1 || ncmap == 3 || ncmap == ncolors) { /* ok */ }
-  else errstr = "Invalid number of colormap channels in RLE file";
+  else errstr = "Invalid # of colormap channels in RLE file.\n";
 
-  npixels = w * h;
-  if (w <= 0 || h <= 0 || npixels/w != h)
-    errstr = "RLE image dimensions out of range";
+  if (w<1 || h<1)
+    errstr = "Bogus size in RLE header.\n";
 
 
   if (errstr) {
     fclose(fp);
-    if (pinfo->comment)
-      free(pinfo->comment);
-    pinfo->comment = (char *) NULL;
+    if (pinfo->comment) free(pinfo->comment);  pinfo->comment = (char *) NULL;
     return rleError(bname, errstr);
   }
 
 
   /* allocate image memory */
-  if (ncolors == 1)
-    img = (byte *) calloc((size_t) npixels, (size_t) 1);
-  else {
-    bufsize = 3*npixels;
-    if (bufsize/3 != npixels)
-      return rleError(bname, "RLE image dimensions out of range");
-    img = (byte *) calloc((size_t) bufsize, (size_t) 1);
-  }
-
+  if (ncolors == 1) img = (byte *) calloc((size_t) w * h,     (size_t) 1);
+               else img = (byte *) calloc((size_t) w * h * 3, (size_t) 1);
   if (!img) {
     fclose(fp);
-    if (pinfo->comment)
-      free(pinfo->comment);
-    pinfo->comment = (char *) NULL;
-    return rleError(bname, "Unable to allocate RLE image data");
+    if (pinfo->comment) free(pinfo->comment);  pinfo->comment = (char *) NULL;
+    return rleError(bname, "unable to allocate image data.\n");
   }
 
 
@@ -221,10 +209,10 @@
   if ((flags & H_CLEARFIRST) && !(flags & H_NO_BACKGROUND)) {
     byte *ip;
     if (ncolors == 1) {
-      for (i=0, ip=img; i<npixels; i++, ip++) *ip = bgcol[0];
+      for (i=0, ip=img; i<w*h; i++, ip++) *ip = bgcol[0];
     }
     else {
-      for (i=0, ip=img; i<npixels; i++)
+      for (i=0, ip=img; i<w*h; i++)
 	for (j=0; j<3; j++, ip++) *ip = bgcol[j];
     }
   }
@@ -242,7 +230,7 @@
   if (ncmap) {
     byte *ip;
     int   imagelen, cmask;
-    imagelen = (ncolors==1) ? npixels : bufsize;
+    imagelen = (ncolors==1) ? w*h : w*h*3;
     cmask = (cmaplen-1);
 
     if (ncmap == 1) {   /* single gamma curve */
@@ -250,7 +238,7 @@
     }
 
     else if (ncmap >= 3 && ncolors >=3) {   /* one curve per band */
-      for (i=0, ip=img; i<npixels; i++) {
+      for (i=0, ip=img; i<w*h; i++) {
 	*ip = maps[0][*ip & cmask];   ip++;
 	*ip = maps[1][*ip & cmask];   ip++;
 	*ip = maps[2][*ip & cmask];   ip++;
diff -ruN xv-3.10a-bugfixes/xvroot.c xv-3.10a-enhancements/xvroot.c
--- xv-3.10a-bugfixes/xvroot.c	2004-05-16 18:04:21.000000000 -0700
+++ xv-3.10a-enhancements/xvroot.c	2004-05-16 18:07:52.000000000 -0700
@@ -44,6 +44,7 @@
   case RM_MIRROR:
   case RM_IMIRROR: rpixw = 2*eWIDE;  rpixh = 2*eHIGH;  break;
   case RM_CSOLID:
+  case RM_UPLEFT:
   case RM_CWARP:
   case RM_CBRICK:  rpixw = dispWIDE; rpixh = dispHIGH; break;
 
@@ -101,7 +102,7 @@
 
 
   else if (rmode == RM_CENTER || rmode == RM_CENTILE || rmode == RM_CSOLID ||
-	   rmode == RM_CWARP || rmode == RM_CBRICK) {
+	   rmode == RM_CWARP || rmode == RM_CBRICK || rmode == RM_UPLEFT) {
     /* do some stuff to set up the border around the picture */
 
     if (rmode != RM_CENTILE) {
@@ -138,6 +139,12 @@
 
     else if (rmode == RM_CSOLID) { }
 
+    else if (rmode == RM_UPLEFT) {
+
+      XPutImage(theDisp, tmpPix, theGC, theImage, 0,0, 0,0,
+		(u_int) eWIDE, (u_int) eHIGH);
+    }
+
     else if (rmode == RM_CWARP) {          /* warp effect */
       XSetForeground(theDisp, theGC, rootfg);
       for (i=0; i<=dispWIDE; i+=8)
@@ -157,7 +164,7 @@
 
 
     /* draw the image centered on top of the background */
-    if (rmode != RM_CENTILE)
+    if ((rmode != RM_CENTILE) && (rmode != RM_UPLEFT))
       XPutImage(theDisp, tmpPix, theGC, theImage, 0,0,
 		((int) dispWIDE-eWIDE)/2, ((int) dispHIGH-eHIGH)/2,
 		(u_int) eWIDE, (u_int) eHIGH);
diff -ruN xv-3.10a-bugfixes/xvsmooth.c xv-3.10a-enhancements/xvsmooth.c
--- xv-3.10a-bugfixes/xvsmooth.c	2004-05-16 18:04:28.000000000 -0700
+++ xv-3.10a-enhancements/xvsmooth.c	2004-05-16 18:07:59.000000000 -0700
@@ -105,7 +105,7 @@
     /* we can save a lot of time by precomputing cxtab[] and pxtab[], both
        dwide arrays of ints that contain values for the equations:
          cx = (ex * swide) / dwide;
-         px = ((ex * swide * 100) / dwide) - (cx * 100) - 50; */
+         px = ((ex * swide * 128) / dwide) - (cx * 128) - 64; */
 
     cxtab = (int *) malloc(dwide * sizeof(int));
     if (!cxtab) { free(pic24);  return NULL; }
@@ -115,8 +115,8 @@
 
     for (ex=0; ex<dwide; ex++) {
       cxtab[ex] = (ex * swide) / dwide;
-      pxtab[ex] = (((ex * swide)* 100) / dwide)
-	           - (cxtab[ex] * 100) - 50;
+      pxtab[ex] = (((ex * swide)* 128) / dwide)
+	           - (cxtab[ex] * 128) - 64;
     }
 
     for (ey=0; ey<dhigh; ey++) {
@@ -125,7 +125,7 @@
       ProgressMeter(0, (dhigh)-1, ey, "Smooth");
 
       cy = (ey * shigh) / dhigh;
-      py = (((ey * shigh) * 100) / dhigh) - (cy * 100) - 50;
+      py = (((ey * shigh) * 128) / dhigh) - (cy * 128) - 64;
       if (py<0) { y1 = cy-1;  if (y1<0) y1=0; }
            else { y1 = cy+1;  if (y1>shigh-1) y1=shigh-1; }
 
@@ -172,30 +172,30 @@
 	else {
 	  /* compute weighting factors */
 	  apx = abs(px);  apy = abs(py);
-	  pA = (apx * apy) / 100;
-	  pB = (apy * (100 - apx)) / 100;
-	  pC = (apx * (100 - apy)) / 100;
-	  pD = 100 - (pA + pB + pC);
+	  pA = (apx * apy) >> 7; /* div 128 */
+	  pB = (apy * (128 - apx)) >> 7; /* div 128 */
+	  pC = (apx * (128 - apy)) >> 7; /* div 128 */
+	  pD = 128 - (pA + pB + pC);
 
 	  if (is24) {
-	    *pp++ = ((int) (pA * rA))/100 + ((int) (pB * rB))/100 +
-	            ((int) (pC * rC))/100 + ((int) (pD * rD))/100;
+	    *pp++ = (((int) (pA * rA))>>7) + (((int) (pB * rB))>>7) +
+	            (((int) (pC * rC))>>7) + (((int) (pD * rD))>>7);
 
-	    *pp++ = ((int) (pA * gA))/100 + ((int) (pB * gB))/100 +
-	            ((int) (pC * gC))/100 + ((int) (pD * gD))/100;
+	    *pp++ = (((int) (pA * gA))>>7) + (((int) (pB * gB))>>7) +
+	            (((int) (pC * gC))>>7) + (((int) (pD * gD))>>7);
 
-	    *pp++ = ((int) (pA * bA))/100 + ((int) (pB * bB))/100 +
-	            ((int) (pC * bC))/100 + ((int) (pD * bD))/100;
+	    *pp++ = (((int) (pA * bA))>>7) + (((int) (pB * bB))>>7) +
+	            (((int) (pC * bC))>>7) + (((int) (pD * bD))>>7);
 	  }
 	  else {  /* 8-bit pic */
-	    *pp++ = ((int) (pA * rmap[cA]))/100 + ((int)(pB * rmap[cB]))/100 +
-	            ((int) (pC * rmap[cC]))/100 + ((int)(pD * rmap[cD]))/100;
+	    *pp++ = (((int)(pA * rmap[cA]))>>7) + (((int)(pB * rmap[cB]))>>7) +
+	            (((int)(pC * rmap[cC]))>>7) + (((int)(pD * rmap[cD]))>>7);
 
-	    *pp++ = ((int) (pA * gmap[cA]))/100 + ((int)(pB * gmap[cB]))/100 +
-	            ((int) (pC * gmap[cC]))/100 + ((int)(pD * gmap[cD]))/100;
+	    *pp++ = (((int)(pA * gmap[cA]))>>7) + (((int)(pB * gmap[cB]))>>7) +
+	            (((int)(pC * gmap[cC]))>>7) + (((int)(pD * gmap[cD]))>>7);
 
-	    *pp++ = ((int)(pA * bmap[cA]))/100 + ((int)(pB * bmap[cB]))/100 +
-  	            ((int)(pC * bmap[cC]))/100 + ((int)(pD * bmap[cD]))/100;
+	    *pp++ = (((int)(pA * bmap[cA]))>>7) + (((int)(pB * bmap[cB]))>>7) +
+  	            (((int)(pC * bmap[cC]))>>7) + (((int)(pD * bmap[cD]))>>7);
 	  }
 	}
       }
diff -ruN xv-3.10a-bugfixes/xvtext.c xv-3.10a-enhancements/xvtext.c
--- xv-3.10a-bugfixes/xvtext.c	2004-05-16 18:04:38.000000000 -0700
+++ xv-3.10a-enhancements/xvtext.c	2004-05-16 18:08:10.000000000 -0700
@@ -199,6 +199,7 @@
 {
   /* given a filename, attempts to read in the file and open a textview win */
 
+  int   filetype;
   long  textlen;
   char *text, buf[512], title[128], rfname[MAXPATHLEN+1];
   char *basefname[128];  /* just current fname, no path */
@@ -210,14 +211,15 @@
   /* see if this file is compressed.  if it is, uncompress it, and view
      the uncompressed version */
 
-  if (ReadFileType(fname) == RFT_COMPRESS) {
+  filetype = ReadFileType(fname);
+  if ((filetype == RFT_COMPRESS) || (filetype == RFT_BZIP2)) {
 #ifndef VMS
-    if (!UncompressFile(fname, rfname)) return;    /* failed to uncompress */
+    if (!UncompressFile(fname, rfname, filetype)) return;     /* failed */
 #else
     /* chop off trailing '.Z' from friendly displayed basefname, if any */
     strcpy (basefname, fname);
     *rindex (basefname, '.') = '\0';
-    if (!UncompressFile(basefname, rfname)) return;/* failed to uncompress */
+    if (!UncompressFile(basefname, rfname, filetype)) return; /* failed */
 #endif
   }
 
@@ -591,6 +593,40 @@
       else if (e->window == tv->textW) { }
       else rv = 0;
     }
+    else if (e->button == Button4) {   /* note min vs. max, + vs. - */
+      /* scroll regardless of where we are in the text window */
+      if (e->window == tv->win ||
+	 e->window == tv->vscrl.win ||
+	 e->window == tv->hscrl.win ||
+	 e->window == tv->textW)
+      {
+	SCRL *sp=&(tv->vscrl);
+	int  halfpage=sp->page/2;
+
+	if (sp->val > sp->min+halfpage)
+	  SCSetVal(sp,sp->val-halfpage);
+	else
+	  SCSetVal(sp,sp->min);
+      }
+      else rv = 0;
+    }
+    else if (e->button == Button5) {   /* note max vs. min, - vs. + */
+      /* scroll regardless of where we are in the text window */
+      if (e->window == tv->win ||
+	 e->window == tv->vscrl.win ||
+	 e->window == tv->hscrl.win ||
+	 e->window == tv->textW)
+      {
+	SCRL *sp=&(tv->vscrl);
+	int  halfpage=sp->page/2;
+
+	if (sp->val < sp->max-halfpage)
+	  SCSetVal(sp,sp->val+halfpage);
+	else
+	  SCSetVal(sp,sp->max);
+      }
+      else rv = 0;
+    }
     else rv = 0;
   }
 
diff -ruN xv-3.10a-bugfixes/xvtiff.c xv-3.10a-enhancements/xvtiff.c
--- xv-3.10a-bugfixes/xvtiff.c	2005-03-27 17:25:31.000000000 -0800
+++ xv-3.10a-enhancements/xvtiff.c	2005-03-27 17:24:11.000000000 -0800
@@ -564,6 +564,10 @@
 static	byte **BWmap;
 static	byte **PALmap;
 
+/* XXXX Work around some collisions with the new library. */
+#define tileContigRoutine _tileContigRoutine
+#define tileSeparateRoutine _tileSeparateRoutine
+
 typedef void (*tileContigRoutine)   PARM((byte*, u_char*, RGBvalue*,
 					  uint32, uint32, int, int));
 
@@ -603,7 +607,7 @@
 					     uint32, uint32, int, int));
 static void   put4bitbwtile            PARM((byte *, u_char *, RGBvalue *,
 					     uint32, uint32, int, int));
-static void   put16bitbwtile           PARM((byte *, u_char *, RGBvalue *,
+static void   put16bitbwtile           PARM((byte *, u_short *, RGBvalue *,
 					     uint32, uint32, int, int));
 
 static void   putRGBcontig8bittile     PARM((byte *, u_char *, RGBvalue *,
@@ -653,7 +657,7 @@
 
   default:
     TIFFError(TIFFFileName(tif),
-	      "Sorry, can not handle %d-bit pictures", bitspersample);
+	      "Sorry, cannot handle %d-bit pictures", bitspersample);
     return (0);
   }
 
@@ -666,7 +670,7 @@
 
   default:
     TIFFError(TIFFFileName(tif),
-	      "Sorry, can not handle %d-channel images", samplesperpixel);
+	      "Sorry, cannot handle %d-channel images", samplesperpixel);
     return (0);
   }
 
@@ -1157,7 +1161,7 @@
   b = g + stripsize;
   put = pickTileSeparateCase(Map);
   if (put == 0) {
-    TIFFError(filename, "Can not handle format");
+    TIFFError(filename, "Cannot handle format");
     return (0);
   }
   y = setorientation(tif, h);
@@ -1197,7 +1201,7 @@
 /*
  * Greyscale images with less than 8 bits/sample are handled
  * with a table to avoid lots of shifts and masks.  The table
- * is setup so that put*bwtile (below) can retrieve 8/bitspersample
+ * is set up so that put*bwtile (below) can retrieve 8/bitspersample
  * pixel values simply by indexing into the table with one
  * number.
  */
@@ -1249,11 +1253,11 @@
 
 
 /*
- * Palette images with <= 8 bits/sample are handled
- * with a table to avoid lots of shifts and masks.  The table
- * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
- * pixel values simply by indexing into the table with one
- * number.
+ * Palette images with <= 8 bits/sample are handled with
+ * a table to avoid lots of shifts and masks.  The table
+ * is set up so that put*cmaptile (below) can retrieve
+ * (8/bitspersample) pixel-values simply by indexing into
+ * the table with one number.
  */
 static int makecmap()
 {
@@ -1305,7 +1309,7 @@
 /*
  * The following routines move decoded data returned
  * from the TIFF library into rasters filled with packed
- * ABGR pixels (i.e. suitable for passing to lrecwrite.)
+ * ABGR pixels (i.e., suitable for passing to lrecwrite.)
  *
  * The routines have been created according to the most
  * important cases and optimized.  pickTileContigCase and
@@ -1376,7 +1380,7 @@
      int fromskew, toskew;
 {
   while (h-- > 0) {
-    UNROLL8(w, , *cp++ = PALmap[*pp++][0])
+    UNROLL8(w, , *cp++ = PALmap[*pp++][0]);
     cp += toskew;
     pp += fromskew;
   }
@@ -1529,7 +1533,7 @@
  */
 static void put16bitbwtile(cp, pp, Map, w, h, fromskew, toskew)
      byte  *cp;
-     u_char *pp;
+     u_short *pp;
      RGBvalue *Map;
      uint32 w, h;
      int fromskew, toskew;
@@ -1538,8 +1542,7 @@
 
   while (h-- > 0) {
     for (x=w; x>0; x--) {
-      *cp++ = Map[(pp[0] << 8) + pp[1]];
-      pp += 2;
+      *cp++ = Map[*pp++];
     }
     cp += toskew;
     pp += fromskew;
@@ -1577,7 +1580,7 @@
 	      *cp++ = pp[0];
 	      *cp++ = pp[1];
 	      *cp++ = pp[2];
-	      pp += samplesperpixel)
+	      pp += samplesperpixel);
       cp += toskew;
       pp += fromskew;
     }
@@ -1650,7 +1653,7 @@
 	      *cp++ = *r++;
 	      *cp++ = *g++;
 	      *cp++ = *b++;
-	      )
+	      );
       SKEW(r, g, b, fromskew);
       cp += toskew;
     }
@@ -1857,7 +1860,7 @@
   case PHOTOMETRIC_MINISWHITE:
   case PHOTOMETRIC_MINISBLACK:
     switch (bitspersample) {
-    case 16: put = put16bitbwtile; break;
+    case 16: put = (tileContigRoutine) put16bitbwtile; break;
     case 8:  put = putgreytile;    break;
     case 4:  put = put4bitbwtile;  break;
     case 2:  put = put2bitbwtile;  break;
@@ -1872,7 +1875,7 @@
     break;
   }
 
-  if (put==0) TIFFError(filename, "Can not handle format");
+  if (put==0) TIFFError(filename, "Cannot handle format");
   return (put);
 }
 
@@ -1880,8 +1883,8 @@
 /*
  * Select the appropriate conversion routine for unpacked data.
  *
- * NB: we assume that unpacked single channel data is directed
- *	 to the "packed routines.
+ * NB: we assume that unpacked single-channel data is directed
+ *	 to the "packed" routines.
  */
 static tileSeparateRoutine pickTileSeparateCase(Map)
      RGBvalue* Map;
@@ -1897,10 +1900,32 @@
     break;
   }
 
-  if (put==0) TIFFError(filename, "Can not handle format");
+  if (put==0) TIFFError(filename, "Cannot handle format");
   return (put);
 }
 
 
 
+/*******************************************/
+void
+VersionInfoTIFF()      /* GRR 19980605 */
+{
+  char temp[1024], *p, *q;
+
+  strcpy(temp, TIFFGetVersion());
+  p = temp;
+  while (!isdigit(*p))
+    ++p;
+  if ((q = strchr(p, '\n')) != NULL)
+    *q = '\0';
+
+  fprintf(stderr, "   Compiled with libtiff %s", p);
+#ifdef TIFFLIB_VERSION
+  fprintf(stderr, " of %d", TIFFLIB_VERSION);    /* e.g., 19960307 */
+#endif
+  fprintf(stderr, ".\n");
+}
+
+
+
 #endif /* HAVE_TIFF */
diff -ruN xv-3.10a-bugfixes/xvwbmp.c xv-3.10a-enhancements/xvwbmp.c
--- xv-3.10a-bugfixes/xvwbmp.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvwbmp.c	2005-04-03 14:02:18.000000000 -0700
@@ -0,0 +1,323 @@
+/*
+ * xvwbmp.c - i/o routings for WBMP files
+ * defined by OMA (http://www.openmobilealliance.com)
+ * as a standard for images for micro devices.
+ *
+ * exports :
+ *
+ * LoadWBMP(fname, numcols);
+ * WriteWBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
+ *
+ * author: Pawel S. Veselov <vps@manticore.2y.net>
+ *	      http://manticore.2y.net/
+ *
+ */
+
+#include "xv.h"
+
+typedef	short int16;
+typedef unsigned char uint8;
+typedef	unsigned short uint16;	/* sizeof (uint16) must == 2 */
+#if defined(__alpha) || _MIPS_SZLONG == 64
+typedef	int int32;
+typedef	unsigned int uint32;	/* sizeof (uint32) must == 4 */
+#else
+typedef	long int32;
+typedef	unsigned long uint32;	/* sizeof (uint32) must == 4 */
+#endif
+
+#define MUST(a)	            if (!(a)) {\
+				return fail(st_fname, st_err);\
+				close(fd); \
+			    }
+#define READU8(fd,u)	    if ((read(fd, &u, 1)<1)) {\
+				myfree(); \
+				close(fd); \
+				return fail(st_fname, err_ueof); }
+#define SREADU8(fd, u)	    if ((read(fd, &u, 1,)<1)) {\
+				{ st_err = err_ueof; return 0; }
+
+#define SREADC(fd, str, l)  {	\
+    str = (char*)mymalloc(l);	\
+    if (!str) {			\
+	myfree();		\
+	FatalError("LoadWBMP: can't malloc extension buffer");	\
+    }				\
+    if (read(fd, str, l)<l) {	\
+	st_err = err_ueof;	\
+	return 0;		\
+    }
+
+static char * err_ueof = "Unexpected EOF";
+static char * err_unst = "Unsupported image type";
+static char * err_extf = "Extensions are forbidden";
+static char * err_inmb = "Invalid multibyte integer";
+
+static char * st_fname;
+static char * st_err;
+
+static int fail	    PARM((char *, char *));
+static int read_mb  PARM((int *, int));
+static void write_mb PARM((uint32, FILE *));
+static int read_ext PARM((int, uint8));
+static void * mymalloc PARM((int));
+static void myfree   PARM((void));
+static uint8 * render1 PARM((uint8 *, int, int));
+
+void ** mymem = NULL;
+int mymems = 0;
+
+int LoadWBMP(char * fname, PICINFO * pinfo)
+{
+    int fd;
+    int im_type;	/* image type (only type 0 supported) */
+    uint8 fix_header;	/* fixed header field */
+    int width, height;
+    int npixels, raw_size, aux;
+    uint8 * raw;
+
+    st_fname = fname;
+
+    fd = open(fname, O_RDONLY);
+    if (fd < 0) {
+	return fail(fname, "Couldn't open the file");
+    }
+
+    MUST(read_mb(&im_type, fd));
+    if (im_type) {
+	return fail(fname, err_unst);
+    }
+
+    READU8(fd, fix_header);
+
+    MUST(read_ext(fd, fix_header));
+
+    MUST(read_mb(&width, fd));
+    MUST(read_mb(&height, fd));
+
+    npixels = width * height;
+    raw_size = (npixels+7) / 8;
+    if (width <= 0 || height <= 0 || npixels/width != height ||
+        npixels+7 < npixels)
+    {
+	return fail(fname, "image dimensions out of range");
+    }
+
+    raw = mymalloc(raw_size);
+    if (!raw) {
+	myfree();
+	FatalError("LoadWBMP: can't malloc image buffer");
+    }
+
+    aux = read(fd, raw, raw_size);
+    if (aux < raw_size) {
+	fail(fname, "Image size shrank");
+	raw_size = aux;
+    }
+
+    pinfo->r[0] = 0;
+    pinfo->g[0] = 0;
+    pinfo->b[0] = 0;
+    pinfo->r[1] = 255;
+    pinfo->g[1] = 255;
+    pinfo->b[1] = 255;
+
+    pinfo->pic = render1(raw, raw_size, npixels);
+    pinfo->type = PIC8;
+
+    pinfo->w = pinfo->normw = width;
+    pinfo->h = pinfo->normh = height;
+    pinfo->frmType = F_BWDITHER;
+
+    sprintf(pinfo->fullInfo, "WBMP, 1 bit per pixel, %d bytes", raw_size);
+    sprintf(pinfo->shrtInfo, "%dx%d WBMP (WAP/OMA).", width, height);
+    pinfo->comment = (char*)NULL;
+
+    close(fd);
+
+    myfree();
+    return 1;
+}
+
+int WriteWBMP(FILE * fp, byte * pic, int ptype, int w, int h,
+	byte * rmap, byte *gmap, byte *bmap,
+	int numcols, int colorstyle)
+{
+    int count = 0;
+    uint8 bit = 0;
+    int i;
+
+    write_mb(0, fp);	/* type : always 0 */
+    putc(0, fp);	/* fixed header : always 0 for type 0 */
+    write_mb((uint32)w, fp);
+    write_mb((uint32)h, fp);
+
+    /* ready to write data */
+
+    for (i=0; i<w*h; i++) {
+	bit |= (((pic[i]&1)<<(7-(count++))));
+	if (count == 8) {
+	    putc(bit, fp);
+	    count = 0;
+	}
+    }
+
+    if (!count) {
+	putc(bit, fp);
+    }
+
+    return 0;
+}
+
+int fail(char * name, char * msg)
+{
+    SetISTR(ISTR_WARNING, "%s : %s", name, msg);
+    return 0;
+}
+
+void write_mb(uint32 data, FILE * f)
+{
+    int i = 32;
+    uint32 aux = data;
+    int no;
+
+    if (!aux) {
+	i = 1;
+    } else {
+	while (!(aux & 0x80000000)) {
+	    aux <<= 1;
+	    i--;
+	}
+    }
+
+    /* i tells us how many bits are left to encode */
+
+    no = (i / 7 + ((i % 7)?1:0))-1;
+
+    /*
+    fprintf(stderr, "writing %x, bits to write=%d, passes=%d\n",
+	    data, i, no);
+    */
+
+    do {
+	uint8 value = no?0x80:0x0;
+	value |= ((data >> (no*7)) & 0x7f);
+	putc(value, f);
+    } while ((no--)>0);
+
+}
+
+int read_mb(int * dst, int fd)
+{
+    int ac = 0;
+    int ct = 0;
+
+    while (1) {
+	uint8 bt;
+	if ((ct++)==6) {
+	    st_err = err_inmb;
+	    return 0;
+	}
+
+	if ((read(fd, &bt, 1)) < 1) {
+	    st_err = err_ueof;
+	    return 0;
+	}
+	ac = (ac << 7) | (bt & 0x7f);   /* accumulates up to 42 bits?? FIXME */
+	if (!(bt & 0x80))
+	    break;
+    }
+    *dst = ac;
+    return 1;
+}
+
+int read_ext(int fd, uint8 fixed)
+{
+    if (!(fixed&0x7f)) {    /* no extensions */
+	return 1;
+    }
+
+    /*
+     * The only described type is WBMP 0, that must not
+     * have extensions.
+     */
+
+    st_err = err_extf;
+    return 0;
+
+    /*
+
+    fixed = (fixed >> 5)&0x3;
+
+    switch (fixed) {
+    case 0:
+	while (true) {
+	    SREADU8(fd, fixed);
+	    if (!(fixed & 0x7f)) { break; }
+	}
+	break;
+    case 0x3:
+	{
+	    char * par;
+	    char * val;
+	    SREADU8(fd, fixed);
+	    SREADC(fd, par, (fixed>>4)&0x6);
+	    SREADC(fd, val, fixed&0xf);
+	}
+	break;
+    }
+    */
+}
+
+void * mymalloc(int l)
+{
+    mymem = (void**)realloc(mymem, mymems+1);
+    if (!mymem)
+	FatalError("LoadWBMP: can't realloc buffer");
+    return (mymem[mymems++] = malloc(l));
+}
+
+void myfree()
+{
+    int i;
+
+    if (mymem) {
+	for (i=0; i<mymems; i++) {
+	    if (mymem[i])
+	        free(mymem[i]);
+	}
+	free(mymem);
+    }
+    mymem = (void**)NULL;
+    mymems = 0;
+}
+
+uint8 * render1(uint8 * data, int size, int npixels)
+{
+    byte * pic;
+    int i;
+    int cnt = 0;
+    uint8 cb = *data;
+
+    pic = calloc(npixels,1);   /* checked for overflow by caller */
+    if (!pic) {
+	myfree();
+	FatalError("LoadWBMP: can't allocate 'pic' buffer");
+    }
+
+    /* expand bits into bytes */
+    /* memset(pic, 0, npixels); */
+
+    for (i=0; i<npixels; i++) {
+
+	pic[i] = (cb>>7)&1;
+
+	if ((++cnt)==8) {
+	    cb = *(++data);
+	    cnt = 0;
+	} else {
+	    cb <<=1;
+	}
+    }
+    return pic;
+}
diff -ruN xv-3.10a-bugfixes/xvzx.c xv-3.10a-enhancements/xvzx.c
--- xv-3.10a-bugfixes/xvzx.c	1969-12-31 16:00:00.000000000 -0800
+++ xv-3.10a-enhancements/xvzx.c	2004-05-16 18:08:33.000000000 -0700
@@ -0,0 +1,349 @@
+/*
+ * xvzx.c - load routine for Spectrum screen$
+ *
+ * John Elliott, 7 August 1998
+ *
+ * LoadZX(fname, pinfo)  -  load file
+ * WriteZX(fp,pic,ptype,w,h,r,g,b,numcols,style,cmt,comment) - convert to
+ *                          256x192 SCREEN$ and save.
+ */
+
+#include "copyright.h"
+
+#include "xv.h"
+
+
+
+/*
+ * comments on error handling:
+ * a file with a bad header checksum is a warning error.
+ *
+ * not being able to malloc is a Fatal Error.  The program is aborted.
+ */
+
+
+#define TRUNCSTR "File appears to be truncated."
+
+static int zxError PARM((char *, char *));
+
+static char *bname;
+
+/*******************************************/
+int LoadZX(fname, pinfo)
+     char    *fname;
+     PICINFO *pinfo;
+/*******************************************/
+{
+  /* returns '1' on success */
+
+  FILE  *fp;
+  unsigned int    c, c1;
+  int   x,y, trunc;
+  byte  *zxfile;
+
+  bname = BaseName(fname);
+
+  pinfo->pic     = (byte *) NULL;
+  pinfo->comment = (char *) NULL;
+
+  /* Allocate memory for a 256x192x8bit image */
+
+  pinfo->pic     = (byte *)malloc(256*192);
+  if (!pinfo->pic) FatalError("malloc failure in xvzx.c LoadZX");
+
+  /* Allocate 1B80h bytes and slurp the whole file into memory */
+
+  zxfile         = (byte *)malloc(7040);
+  if (!zxfile)     FatalError("malloc failure in xvzx.c LoadZX");
+
+  /* open the file */
+  fp = xv_fopen(fname,"r");
+  if (!fp) return (zxError(bname, "can't open file"));
+
+  /* Load it in en bloc */
+  memset(zxfile, 0, 7040);
+  if (fread(zxfile, 1, 7040, fp) < 7040) trunc = 1;
+
+  /* Transform to 8-bit */
+
+  for (y = 0; y < 192; y++) for (x = 0; x < 256; x++)
+  {
+     /* Spectrum screen layout: three 2k segments at y=0, y=64, y=128 */
+     /* In each segment: Scan lines 0,8,16,...,56,1,9,...,57 etc.  Each
+        scanline is 32 bytes, so line 1 is 256 bytes after line 0
+
+        So address of line start is ((y>>6) * 2048) + ((y & 7) * 256)
+        + ((y & 0x38) * 4)
+
+       The colour byte for a cell is at screen + 6k + (y >> 3)*32 + (x>>3)
+
+       */
+
+     int offset;
+     byte *dst  = pinfo->pic + 256*y + x;
+     byte attr, pt, mask;
+
+     offset  = (y >> 6)   * 2048;
+     offset += (y & 7)    * 256;
+     offset += (y & 0x38) * 4;
+     offset += (x >> 3);
+
+     pt = zxfile[offset + 128];	/* Ink/paper map */
+
+     offset = 0x1880;
+     offset += (y >> 3) * 32;
+     offset += (x >> 3);
+
+     attr = zxfile[offset]; 	/* Colours for cell */
+
+     mask = 0x80;
+
+     if (x & 7) mask >>= (x & 7);
+
+     if (pt & mask)  *dst = attr & 7;        /* Ink */
+     else            *dst = (attr >> 3) & 7; /* Paper */
+
+     if (attr & 0x40) *dst |= 8; /* High intensity */
+  }
+
+  /* Picture bytes converted; now build the colour maps */
+
+  pinfo->normw = pinfo->w = 256;
+  pinfo->normh = pinfo->h = 192;
+  pinfo->type = PIC8;
+
+  for (c = 0; c < 16; c++)
+  {
+    if (c < 8) c1 = 192; else c1 = 255;	/* low-intensity colours use 192 */
+					/* high-intensity colours use 255 */
+    pinfo->b[c] = (c & 1 ? c1 : 0);
+    pinfo->r[c] = (c & 2 ? c1 : 0);
+    pinfo->g[c] = (c & 4 ? c1 : 0);
+  }
+
+  pinfo->colType = F_FULLCOLOR;
+  pinfo->frmType = F_ZX;		/* Save as SCREEN$ */
+  sprintf(pinfo->fullInfo, "Spectrum SCREEN$, load address %04x",
+                                 zxfile[16]+256*zxfile[17]);
+  strcpy(pinfo->shrtInfo, "Spectrum SCREEN$.");
+
+  /* Almost as an afterthought, check that the +3DOS header is valid.
+
+     If it isn't, then odds are that the file isn't a graphic. But it
+     had the right magic number, so it might be. Let them see it anyway.
+
+     The check is: Byte 127 of the header should be the 8-bit sum of bytes
+                   0-126 of the header. The header should also have the
+                   +3DOS magic number, but we know it does or we wouldn't
+                   have got this far.
+  */
+
+  c1 = 0;
+  for (c1 = c = 0; c < 127; c++) c1 = ((c1 + zxfile[c]) & 0xFF);
+  if (c1 != zxfile[127]) zxError(bname, "Bad header checksum.");
+
+  fclose(fp);
+  free(zxfile);
+  return 1;
+}
+
+
+
+
+
+/*******************************************/
+static int zxError(fname, st)
+     char *fname, *st;
+{
+  SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
+  return 0;
+}
+
+
+/* Spectrum screen file header. The first 18 bytes are used in the magic
+   number test */
+
+byte ZXheader[128] =
+{
+        'P', 'L', 'U', 'S', '3', 'D', 'O', 'S', 26,  /* Spectrum +3DOS file */
+	  1,   0, 				     /* Header type 1.0 */
+	128,  27,  0,   0,			     /* 7040 bytes */
+	  3,	                                     /* Binary format */
+          0, 27,   				     /* 6912 data bytes */
+	  0, 64					     /* load address 0x4000 */
+};
+
+
+
+/* Get the Spectrum colour/bright byte (0-15) from a pixel */
+
+static int PointZX(pic, w, h, rmap, gmap, bmap, x, y)
+	byte *pic;
+	int w,h;
+	byte *rmap, *gmap, *bmap;
+	int x,y;
+{
+	int index, r, g, b, zxc;
+
+	/* If the picture is smaller than the screen, pad out the edges
+           with "bright black" - a colour not otherwise returned */
+
+	if (x >= w || y >= h) return 8;
+
+	/* Get colour index */
+
+	index = pic[y*w + x];
+
+	/* Convert to rgb */
+
+	r = rmap[index];
+	g = gmap[index];
+	b = bmap[index];
+	zxc = 0;
+
+	/* Work out Spectrum colour by a simplistic "nearest colour" method */
+
+	if (b >= 160) zxc |= 1;	/* Blue */
+	if (r >= 160) zxc |= 2;	/* Red */
+	if (g >= 160) zxc |= 4;	/* Green */
+	if (r > 208 || g >= 208 || b >= 208) zxc |= 8; /* High intensity */
+
+	return zxc;
+}
+
+
+/* Work out what colours should be used in a cell */
+
+static void CellZX(pic, w, h, rmap, gmap, bmap, cx, cy, zxfile)
+        byte *pic;
+        int w,h;
+        byte *rmap, *gmap, *bmap;
+        int cx,cy;
+	byte *zxfile;
+{
+	byte counts[16];	/* Count of no. of colours */
+	int offset, ink, paper, n, m, x, y, x0, y0, di, dp;
+
+	x0 = cx * 8;		/* Convert from cell to pixel coords */
+	y0 = cy * 8;
+
+	for (n = 0; n < 16; n++) counts[n] = 0;	 /* Reset all counts */
+
+	/* Count no. of pixels of various colours */
+
+	for (y = y0; y < y0+8; y++) for (x = x0; x < x0+8; x++)
+	{
+		m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
+
+		counts[m]++;
+	}
+	counts[8] = 0;	/* Discard Bright Black (pixels not in the picture area)
+                         */
+
+	/* Assign the most popular colour as ink */
+	for (n = m = ink = 0; n < 16; n++) if (counts[n] > m)
+	{
+		ink = n;
+		m   = counts[n];
+	}
+	counts[ink] = 0;
+
+	/* Assign the next most popular colour as paper */
+	for (n = m = paper = 0; n < 16; n++) if (counts[n] > m)
+	{
+		paper = n;
+		m     = counts[n];
+	}
+	/* We have ink and paper. Set cell's attributes */
+
+	offset = cy*32 + cx + 0x1880;
+
+	/* Set the high-intensity bit if ink is high-intensity */
+	if (ink & 8) zxfile[offset] = 0x40; else zxfile[offset] = 0;
+	zxfile[offset] |= ((paper & 7) << 3);
+	zxfile[offset] |=  (ink & 7);
+
+	/* Plot the points */
+	for (y = y0; y < y0+8; y++)
+	{
+	     byte mask = 0x80;
+
+	     offset  = (y >> 6)   * 2048;
+	     offset += (y & 7)    * 256;
+	     offset += (y & 0x38) * 4;
+	     offset += (x0 >> 3);
+
+	     for (x = x0; x < x0+8; x++)
+	     {
+		/* Work out whether the point should be plotted as ink or
+                   paper */
+		m = PointZX(pic, w, h, rmap, gmap, bmap, x, y);
+
+		di = (ink & 7)   - (m & 7);	/* "Difference" from ink */
+		dp = (paper & 7) - (m & 7);	/* "Difference" from paper */
+
+		if (di < 0) di = -di;
+		if (dp < 0) dp = -dp;
+
+		if (di < dp)	/* Point is more like ink */
+			zxfile[offset+128] |= mask;
+
+		mask = (mask >> 1);
+             }
+	}
+
+}
+
+
+
+/*******************************************/
+int WriteZX(fp,pic,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle,comment)
+     FILE *fp;
+     byte *pic;
+     int   ptype, w,h;
+     byte *rmap, *gmap, *bmap;
+     int   numcols, colorstyle;
+     char *comment;
+{
+	int rv, x, y;
+	byte *zxfile;
+	byte *pic8;
+	byte  rtemp[256],gtemp[256],btemp[256];
+
+	/* To simplify matters, reduce 24-bit to 8-bit. Since the Spectrum
+           screen is 3.5-bit anyway, it doesn't make much difference */
+
+	if (ptype == PIC24)
+	{
+		pic8 = Conv24to8(pic, w, h, 256, rtemp,gtemp,btemp);
+		if (!pic8) FatalError("Unable to malloc in WriteZX()");
+		rmap = rtemp;  gmap = gtemp;  bmap = btemp;  numcols=256;
+  	}
+	else pic8 = pic;
+
+	ZXheader[127] = 0x71;	/* The correct checksum. */
+
+	/* Create a memory image of the SCREEN$ */
+
+	zxfile         = (byte *)malloc(7040);
+	if (!zxfile)     FatalError("malloc failure in xvzx.c WriteZX");
+
+	memset(zxfile, 0, 7040);	/* Reset all points to black */
+	memcpy(zxfile, ZXheader, 128);	/* Create +3DOS header */
+
+        /* Convert the image, character cell by character cell */
+        for (y = 0; y < 24; y++) for (x = 0; x < 32; x++)
+        {
+                CellZX(pic8, w, h, rmap, gmap, bmap, x, y, zxfile);
+        }
+	rv = 0;
+	if (fwrite(zxfile, 1, 7040, fp) < 7040) rv = -1;
+
+	if (ptype == PIC24) free(pic8);
+	free(zxfile);
+
+	if (ferror(fp)) rv = -1;
+
+	return rv;
+}
+
