summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeemant Kulleen <seemant@gentoo.org>2002-04-29 08:29:14 +0000
committerSeemant Kulleen <seemant@gentoo.org>2002-04-29 08:29:14 +0000
commit180ded2471d136aac347bfb6426aa88db7e06bdd (patch)
tree10b04f79c867318e12630ec46dce520ae977d753 /media-gfx
parentportage dep fixup (diff)
downloadhistorical-180ded2471d136aac347bfb6426aa88db7e06bdd.tar.gz
historical-180ded2471d136aac347bfb6426aa88db7e06bdd.tar.bz2
historical-180ded2471d136aac347bfb6426aa88db7e06bdd.zip
naz strikes again with a brilliant patch
Diffstat (limited to 'media-gfx')
-rw-r--r--media-gfx/xv/ChangeLog16
-rw-r--r--media-gfx/xv/files/digest-xv-3.10a-r11
-rw-r--r--media-gfx/xv/files/xv-naz-gentoo.patch14838
-rw-r--r--media-gfx/xv/xv-3.10a-r1.ebuild45
4 files changed, 14899 insertions, 1 deletions
diff --git a/media-gfx/xv/ChangeLog b/media-gfx/xv/ChangeLog
index 9d85a98ca53d..42ec95fff37a 100644
--- a/media-gfx/xv/ChangeLog
+++ b/media-gfx/xv/ChangeLog
@@ -1,6 +1,20 @@
# ChangeLog for media-gfx/xv
# Copyright 2002 Gentoo Technologies, Inc.; Distributed under the GPL
-# $Header: /var/cvsroot/gentoo-x86/media-gfx/xv/ChangeLog,v 1.2 2002/04/25 21:38:42 bangert Exp $
+# $Header: /var/cvsroot/gentoo-x86/media-gfx/xv/ChangeLog,v 1.3 2002/04/29 08:29:14 seemant Exp $
+
+*xv-3.10a-r1 (29 Apr 2002)
+
+ 29 Apr 2002; Seemant Kulleen <seemant@gentoo.org> xv-3.10a-r1.ebuild
+ files/digest-xv-3.10a.ebuild files/xv-naz-gentoo.patch :
+
+ This patch, submitted by NAZ (from #gentoo) now brings in png, jpeg and tiff
+ support. The only issue is that, if you want support for one of those, you
+ get to have support for all of them. While unfortunate, this unavoidable, due
+ to the manner in which xv's Makefiles are laid out. To think, there actually
+ is a configure script. And also, it's been more than half a decade since
+ this package came out -- you'd think the author would issue an upgrade.
+ </rant>
+
25 Apr 2002; Thilo Bangert <bangert@gentoo.org> :
diff --git a/media-gfx/xv/files/digest-xv-3.10a-r1 b/media-gfx/xv/files/digest-xv-3.10a-r1
index f6f83423ac38..48d744cce2ec 100644
--- a/media-gfx/xv/files/digest-xv-3.10a-r1
+++ b/media-gfx/xv/files/digest-xv-3.10a-r1
@@ -1 +1,2 @@
MD5 2d4fbeec1561304362781cc8e2f7f72d xv-3.10a.tar.gz 2259124
+MD5 c8cbe14db6e2104ed4eb5330cdaba420 xv-3.10a-png-1.2d.tar.gz 20971
diff --git a/media-gfx/xv/files/xv-naz-gentoo.patch b/media-gfx/xv/files/xv-naz-gentoo.patch
new file mode 100644
index 000000000000..3c0edcc83d4c
--- /dev/null
+++ b/media-gfx/xv/files/xv-naz-gentoo.patch
@@ -0,0 +1,14838 @@
+diff -urN xv-3.10a/Makefile xv-3.10apatched/Makefile
+--- xv-3.10a/Makefile Mon Jan 23 12:20:54 1995
++++ xv-3.10apatched/Makefile Tue Apr 30 00:12:54 2002
+@@ -1,8 +1,8 @@
+ # Makefile for xv
+
+ # your C compiler (and options) of choice
+-CC = cc
+-# CC = gcc -ansi
++#CC = cc
++CC = gcc -ansi
+
+ # use this if you're using 'cc' on a DEC Alpha (OSF/1) or MIPS (Ultrix) system:
+ # CC = cc -std1 -Olimit 750
+@@ -14,7 +14,7 @@
+ # -Wuninitialized -Wparentheses
+
+
+-CCOPTS = -O
++CCOPTS = -O -L/usr/X11R6/lib -D_BSD_SOURCE
+
+
+ ### NOTE: Sun running OpenWindows:
+@@ -28,10 +28,10 @@
+
+
+ ### Installation locations
+-BINDIR = /usr/local/bin
+-MANDIR = /usr/local/man/man1
++BINDIR = /usr/X11R6/bin
++MANDIR = /usr/man/man1
+ MANSUF = 1
+-LIBDIR = /usr/local/lib
++LIBDIR = /usr/lib
+
+
+ buildit: all
+@@ -46,13 +46,28 @@
+ ### 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
++#JPEGINC = -I$(JPEGDIR)
++JPEGLIB = -ljpeg
++#$(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
++PNGLIB = -lpng
++
++
++###
++### if, for whatever reason, you're unable to get the PNG library to compile
++### on your machine, *COMMENT OUT* the following lines
++###
++ZLIBLIB = -lz
+
+
+ ###
+@@ -102,7 +117,7 @@
+
+
+ ### for LINUX, uncomment the following line
+-#MCHN = -DLINUX
++MCHN = -DLINUX
+
+
+ # For SCO 1.1 (UNIX 3.2v2) machines, uncomment the following:
+@@ -144,7 +159,7 @@
+
+ # if your machine has the usleep() function, uncomment the following line:
+ # if it doesn't, or you're not sure, leave this line alone.
+-#TIMERS = -DUSLEEP
++TIMERS = -DUSLEEP
+
+
+ # if XV locks up whenever you click on *any* of the buttons, the Timer()
+@@ -186,9 +201,9 @@
+
+ CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
+ $(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
+- $(DXWM) $(MCHN)
++ $(DXWM) $(MCHN) $(PNG) $(PNGINC) $(ZLIBINC)
+
+-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
++LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) $(PNGLIB) $(ZLIBLIB) -lm
+
+ 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 \
+@@ -196,7 +211,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
+
+ MISC = README INSTALL CHANGELOG IDEAS
+
+@@ -267,7 +282,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
+
+ 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 -urN xv-3.10a/Makefile.std xv-3.10apatched/Makefile.std
+--- xv-3.10a/Makefile.std Mon Jan 23 17:06:26 1995
++++ xv-3.10apatched/Makefile.std Tue Apr 30 00:10:16 2002
+@@ -56,6 +56,25 @@
+
+
+ ###
++### 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/local/src/libpng
++PNGINC = -I$(PNGDIR)
++PNGLIB = -L$(PNGDIR) -lpng
++
++
++###
++### if, for whatever reason, you're unable to get the PNG library to compile
++### on your machine, *COMMENT OUT* the following lines
++###
++ZLIBDIR = /usr/local/src/zlib
++ZLIBINC = -I$(ZLIBDIR)
++ZLIBLIB = -L$(ZLIBDIR) -lz
++
++
++###
+ ### if, for whatever reason, you're unable to get the TIFF library to compile
+ ### on your machine, *COMMENT OUT* the following lines
+ ###
+@@ -186,9 +205,9 @@
+
+ CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
+ $(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
+- $(DXWM) $(MCHN)
++ $(DXWM) $(MCHN) $(PNG) $(PNGINC) $(ZLIBINC)
+
+-LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) -lm
++LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) $(PNGLIB) $(ZLIBLIB) -lm
+
+ 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 \
+@@ -196,7 +215,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
+
+ MISC = README INSTALL CHANGELOG IDEAS
+
+@@ -267,7 +286,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
+
+ 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 -urN xv-3.10a/Makefile~ xv-3.10apatched/Makefile~
+--- xv-3.10a/Makefile~ Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/Makefile~ Tue Apr 30 00:10:16 2002
+@@ -0,0 +1,338 @@
++# Makefile for xv
++
++# your C compiler (and options) of choice
++CC = cc
++# CC = gcc -ansi
++
++# use this if you're using 'cc' on a DEC Alpha (OSF/1) or MIPS (Ultrix) system:
++# CC = cc -std1 -Olimit 750
++
++# this is what I personally use on an OSF Alpha. Not that I recommend it.
++# CC = gcc -g -ansi -pedantic -W -Wreturn-type -Wmissing-prototypes \
++# -Wstrict-prototypes -Waggregate-return -Wconversion \
++# -Wpointer-arith -Wcomment -Wformat -Wchar-subscripts \
++# -Wuninitialized -Wparentheses
++
++
++CCOPTS = -O
++
++
++### NOTE: Sun running OpenWindows:
++### if you're using a SUN running OPENWINDOWS, you need to add these two
++### options to the CCOPTS line, so it finds the libs and include files
++### -L/usr/openwin/lib -I/usr/openwin/include
++###
++### In general, if your X11 include files and libX11.a library aren't in the
++### 'standard' places in which the C compiler looks, you should add '-L' and
++### '-I' options on the CCOPTS line to tell the compiler where said files are.
++
++
++### Installation locations
++BINDIR = /usr/local/bin
++MANDIR = /usr/local/man/man1
++MANSUF = 1
++LIBDIR = /usr/local/lib
++
++
++buildit: all
++
++
++########################### CONFIGURATION OPTIONS ############################
++### NOTE: be sure to check 'config.h', for a few other configuration options
++##############################################################################
++
++###
++### if, for whatever reason, you're unable to get the JPEG library to compile
++### 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
++
++
++###
++### 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/local/src/libpng
++PNGINC = -I$(PNGDIR)
++PNGLIB = -L$(PNGDIR) -lpng
++
++
++###
++### if, for whatever reason, you're unable to get the PNG library to compile
++### on your machine, *COMMENT OUT* the following lines
++###
++ZLIBDIR = /usr/local/src/zlib
++ZLIBINC = -I$(ZLIBDIR)
++ZLIBLIB = -L$(ZLIBDIR) -lz
++
++
++###
++### if, for whatever reason, you're unable to get the TIFF library to compile
++### on your machine, *COMMENT OUT* the following lines
++###
++TIFF = -DDOTIFF
++TIFFDIR = tiff
++TIFFINC = -I$(TIFFDIR)
++TIFFLIB = $(TIFFDIR)/libtiff.a
++$(TIFFLIB):
++ ( cd $(TIFFDIR) ; make CC='$(CC)' )
++
++
++###
++### 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
++###
++PDS = -DDOPDS
++
++
++#----------System V----------
++
++# if you are running on a SysV-based machine, such as HP, Silicon Graphics,
++# Solaris, etc., uncomment the following line to get mostly there.
++#UNIX = -DSVR4
++
++
++#----------Machine Specific Configurations----------
++
++### If you are using an SGI system, uncomment the following line
++#MCHN = -Dsgi
++
++
++### For HP-UX, uncomment the following line:
++#MCHN= -Dhpux -D_HPUX_SOURCE
++# To use old HP compilers (HPUX 7.0 or so), you may need
++#MCHN= -Dhpux -D_HPUX_SOURCE +Ns4000
++#
++# also, if you're using HP's compiler, add '-Aa' to whichever of those
++# two lines you're using, to turn on ANSI C mode. Or so I'm told.
++#
++# note: You may need to add '-I/usr/include/X11R5' (or R6, or whatever)
++# to whichever of those lines you used, as HP tends to store their X11
++# include files in a non-standard place...
++
++
++### for LINUX, uncomment the following line
++#MCHN = -DLINUX
++
++
++# For SCO 1.1 (UNIX 3.2v2) machines, uncomment the following:
++#MCHN = -Dsco -DPOSIX
++#
++# For ODT 2.0 (UNIX 3.2v4) machines, uncomment the following:
++#MCHN= -Dsco -DPOSIX -DNO_RANDOM
++#
++# Also, you should add '-lc -lx' to the end of the LIBS def below
++# -lx must be after -lc so you get the right directory routines.
++
++
++# for UMAX V by Encore Computers uncomment the following line for
++# the portable c compiler, system specific definitions and
++# location of local X11 library(if site specific, modify -L option)
++# No other switches should be necessary, or so I'm told...
++#
++#MCHN = -q extensions=pcc_c -D__UMAXV__ -L/usr2/usr/lib/X11 -DSVR4
++
++# For Interactive/SunSoft Unix ISC 4.0 (whatever *that* is!)
++#MCHN = -DSVR4 -DBSDTYPES
++
++
++#----------'Roll Your Own' Options----------
++
++
++# if your machine doesn't have 'random()', but does have 'rand()',
++# uncomment the following line:
++#
++#RAND = -DNO_RANDOM
++
++
++# if your system *doesn't* have /usr/include/dirent.h, (ie, isn't POSIX
++# compliant, then you may have to uncomment the following line to use the
++# 'old-style' directory-handling structures
++#
++#NODIRENT = -DNODIRENT
++
++
++# if your machine has the usleep() function, uncomment the following line:
++# if it doesn't, or you're not sure, leave this line alone.
++#TIMERS = -DUSLEEP
++
++
++# if XV locks up whenever you click on *any* of the buttons, the Timer()
++# function in xvmisc.c is going out to lunch. A simple workaround is to
++# uncomment the following line:
++#TIMERS = -DNOTIMER
++
++
++# if you are running under DXWM, I pity you. XV doesn't work correctly
++# under DXWM. You should probably be running MWM. However, if such is
++# not an option for you, try uncommenting the following line. The
++# behavior won't be 'right', but it will be less 'wrong'.
++#DXWM = -DDXWM
++
++
++# if, during compilation, your system complains about the types
++# 'u_long', 'u_short', 'u_int', etc. as being undefined, uncomment the
++# following line:
++#BSDTYPES = -DBSDTYPES
++
++
++# if your machine doesn't have 'vprintf()' or 'vsprintf()'
++# (see vprintf.c for more information, if needed)
++#
++# (for BSD 4.3 VAX, uncomment the following line)
++#VPRINTF = -DNEED_VPRINTF -DINTSPRINTF -DLONGINT -DNOVOID
++# (for (stock) IBM RT AOS 4.3, uncomment the following line)
++#VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS
++# (for Sequent running DYNIX 3.1.4, uncomment the following line)
++#VPRINTF = -DNEED_VPRINTF -DLONGINT -DNOSTDHDRS
++
++
++
++
++################ END OF CONFIGURATION OPTIONS #################
++
++
++
++
++CFLAGS = $(CCOPTS) $(JPEG) $(JPEGINC) $(TIFF) $(TIFFINC) $(PDS) \
++ $(NODIRENT) $(VPRINTF) $(TIMERS) $(UNIX) $(BSDTYPES) $(RAND) \
++ $(DXWM) $(MCHN) $(PNG) $(PNGINC) $(ZLIBINC)
++
++LIBS = -lX11 $(JPEGLIB) $(TIFFLIB) $(PNGLIB) $(ZLIBLIB) -lm
++
++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 \
++ xvgifwr.o xvdir.o xvbutt.o xvpbm.o xvxbm.o xvgam.o xvbmp.o \
++ 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 xvpng.o
++
++MISC = README INSTALL CHANGELOG IDEAS
++
++
++
++.c.o: ; $(CC) $(CFLAGS) -c $*.c
++
++
++
++all: $(JPEGLIB) $(TIFFLIB) xv bggen vdcomp xcmap xvpictoppm
++
++
++xv: $(OBJS) $(JPEGLIB) $(TIFFLIB)
++ $(CC) -o xv $(CFLAGS) $(OBJS) $(LIBS)
++
++bggen: bggen.c
++ $(CC) $(CFLAGS) -o bggen bggen.c $(LIBS)
++
++vdcomp: vdcomp.c
++ $(CC) $(CFLAGS) -o vdcomp vdcomp.c
++
++xcmap: xcmap.c
++ $(CC) $(CFLAGS) -o xcmap xcmap.c $(LIBS)
++
++xvpictoppm: xvpictoppm.c
++ $(CC) $(CFLAGS) -o xvpictoppm xvpictoppm.c
++
++
++
++xvclean:
++ rm -f $(OBJS) xv
++
++clean: xvclean
++ rm -f bggen vdcomp xcmap xvpictoppm
++ ./cleandir $(JPEGDIR)
++ rm -f $(JPEGDIR)/jconfig.h $(JPEGDIR)/Makefile
++ ./cleandir $(TIFFDIR)
++
++
++install: all
++ cp xv bggen vdcomp xcmap xvpictoppm $(BINDIR)
++ cp docs/xv.man $(MANDIR)/xv.$(MANSUF)
++ cp docs/bggen.man $(MANDIR)/bggen.$(MANSUF)
++ cp docs/xcmap.man $(MANDIR)/xcmap.$(MANSUF)
++ cp docs/xvp2p.man $(MANDIR)/xvpictoppm.$(MANSUF)
++ cp docs/vdcomp.man $(MANDIR)/vdcomp.$(MANSUF)
++ cp docs/xvdocs.ps* $(LIBDIR)
++
++tar:
++ tar cvf xv.tar Makefile* Imakefile *.c *.h bits \
++ docs unsupt vms $(JPEGDIR) $(TIFFDIR) $(MISC)
++
++xvtar:
++ tar cvf xv.tar Makefile* Imakefile *.c *.h bits
++
++$(OBJS): xv.h config.h
++
++
++################# bitmap dependencies ####################
++
++xv.o: bits/icon bits/iconmask bits/runicon bits/runiconm
++xv.o: bits/cboard50 bits/gray25
++
++xvbrowse.o: bits/br_file bits/br_dir bits/br_exe bits/br_chr bits/br_blk
++xvbrowse.o: bits/br_sock bits/br_fifo bits/br_error bits/br_unknown
++xvbrowse.o: bits/br_cmpres bits/br_gif bits/br_pm bits/br_pbm
++xvbrowse.o: bits/br_sunras bits/br_bmp bits/br_utah bits/br_iris
++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 bits/br_png
++
++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
++xvbutt.o: bits/rb_dot bits/cb_check bits/mb_chk
++
++xvctrl.o: bits/gray25 bits/gray50 bits/i_fifo bits/i_chr bits/i_dir
++xvctrl.o: bits/i_blk bits/i_lnk bits/i_sock bits/i_exe bits/i_reg
++xvctrl.o: bits/h_rotl bits/h_rotr bits/fliph bits/flipv bits/p10
++xvctrl.o: bits/m10 bits/cut bits/copy bits/paste bits/clear
++xvctrl.o: bits/uicon bits/oicon1 bits/oicon2 bits/icon
++xvctrl.o: bits/padimg bits/annot
++
++xvcut.o: bits/cut bits/cutm bits/copy bits/copym
++
++xvdflt.o: bits/logo_top bits/logo_bot bits/logo_out bits/xv_jhb
++xvdflt.o: bits/xv_cpyrt bits/xv_rev bits/xv_ver
++xvdflt.o: bits/xf_left bits/xf_right bits/font5x9.h
++xvdflt.o: xvdflt.h
++
++xvdial.o: bits/dial_cw1 bits/dial_ccw1 bits/dial_cw2 bits/dial_ccw2
++
++xvdir.o: bits/d_load bits/d_save
++
++xvevent.o: bits/dropper bits/dropperm bits/pen bits/penm
++xvevent.o: bits/blur bits/blurm
++
++xvgam.o: bits/h_rotl bits/h_rotr bits/h_flip bits/h_sinc bits/h_sdec
++xvgam.o: bits/h_sat bits/h_desat
++
++xvgraf.o: bits/gf1_addh bits/gf1_delh bits/gf1_line bits/gf1_spln
++xvgraf.o: bits/gf1_rst bits/gf1_gamma
++
++xvinfo.o: bits/penn bits/pennnet
++
++xvmisc.o: bits/fc_left bits/fc_leftm bits/fc_left1 bits/fc_left1m
++xvmisc.o: bits/fc_mid bits/fc_midm bits/fc_right1 bits/fc_right1m
++xvmisc.o: bits/fc_right bits/fc_rightm
++
++xvpopup.o: bits/icon
++
++xvroot.o: bits/root_weave
++
++xvscrl.o: bits/up bits/down bits/up1 bits/down1 bits/uph bits/downh
++xvscrl.o: bits/uph1 bits/downh1 bits/scrlgray
++
++################# end bitmap dependencies ####################
++
++
++
+diff -urN xv-3.10a/bits/br_png xv-3.10apatched/bits/br_png
+--- xv-3.10a/bits/br_png Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/bits/br_png Tue Apr 30 00:23:33 2002
+@@ -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 -urN xv-3.10a/config.h xv-3.10apatched/config.h
+--- xv-3.10a/config.h Thu Jan 5 10:49:21 1995
++++ xv-3.10apatched/config.h Tue Apr 30 00:11:18 2002
+@@ -13,14 +13,14 @@
+ * definition appropriately. (use 'which gunzip' to find if you have gunzip,
+ * and where it lives)
+ */
+-#undef USE_GUNZIP
++#define USE_GUNZIP
+
+ #ifdef USE_GUNZIP
+-# ifdef VMS
+-# define GUNZIP "UNCOMPRESS"
+-# else
+-# define GUNZIP "/usr/local/bin/gunzip -q"
+-# endif
++#ifdef VMS
++#define GUNZIP "UNCOMPRESS"
++#else
++#define GUNZIP "/bin/gunzip -q"
++#endif
+ #endif
+
+
+@@ -88,9 +88,9 @@
+ * should not need to be changed
+ */
+
+-/* #define GS_PATH "/usr/local/bin/gs" */
+-/* #define GS_LIB "." */
+-/* #define GS_DEV "ppmraw" */
++#define GS_PATH "/usr/bin/gs"
++#define GS_LIB "."
++#define GS_DEV "ppmraw"
+
+
+ /***************************************************************************
+@@ -103,7 +103,7 @@
+ * change 'undef' to 'define' in the following line
+ */
+
+-#undef USEOLDPIC
++#define USEOLDPIC
+
+
+ /***************************************************************************
+diff -urN xv-3.10a/tiff/Makefile xv-3.10apatched/tiff/Makefile
+--- xv-3.10a/tiff/Makefile Thu Dec 22 14:35:12 1994
++++ xv-3.10apatched/tiff/Makefile Tue Apr 30 00:12:54 2002
+@@ -36,7 +36,7 @@
+ IPATH= -I.
+
+ COPTS= -O
+-CFLAGS= ${COPTS} ${IPATH}
++CFLAGS= ${COPTS} ${IPATH} -D_BSD_SOURCE
+
+ INCS= tiff.h tiffio.h
+
+diff -urN xv-3.10a/xv.c xv-3.10apatched/xv.c
+--- xv-3.10a/xv.c Thu Jan 19 10:08:43 1995
++++ xv-3.10apatched/xv.c Tue Apr 30 00:20:19 2002
+@@ -277,6 +277,10 @@
+ tiffW = (Window) NULL; tiffUp = 0;
+ #endif
+
++#ifdef HAVE_PNG
++ pngW = (Window) NULL; pngUp = 0;
++#endif
++
+ imap = ctrlmap = gmap = browmap = cmtmap = 0;
+
+ ch_offx = ch_offy = p_offx = p_offy = 0;
+@@ -309,7 +313,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);
+@@ -782,6 +790,10 @@
+ XSetTransientForHint(theDisp, tiffW, dirW);
+ #endif
+
++#ifdef HAVE_PNG
++ CreatePNGW();
++ XSetTransientForHint(theDisp, pngW, dirW);
++#endif
+
+ LoadFishCursors();
+ SetCursors(-1);
+@@ -950,7 +962,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);
+
+@@ -1184,6 +1200,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;
+
+@@ -1646,6 +1670,7 @@
+ printoption("[-/+vsperfect]");
+ printoption("[-wait seconds]");
+ printoption("[-white color]");
++ printoption("[-windowid windowid]");
+ printoption("[-/+wloop]");
+ printoption("[filename ...]");
+ fprintf(stderr,"\n\n");
+@@ -1668,6 +1693,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);
+ }
+@@ -2611,6 +2637,11 @@
+ (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
+ else if (strncmp((char *) magicno, "NJPL1I00", (size_t) 8)==0 ||
+ strncmp((char *) magicno+2,"NJPL1I", (size_t) 6)==0 ||
+@@ -2625,6 +2656,10 @@
+ strncmp((char *) magicno, "\004%!", (size_t) 3)==0) rv = RFT_PS;
+ #endif
+
++#ifdef GS_PATH
++ else if (strncmp((char *) magicno, "%PDF", (size_t) 4)==0) rv = RFT_PS;
++#endif
++
+ return rv;
+ }
+
+@@ -2671,6 +2706,10 @@
+ case RFT_TIFF: rv = LoadTIFF (fname, pinfo); 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;
+ #endif
+@@ -4043,16 +4082,30 @@
+ unsigned long nitems, nleft;
+ byte *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);
++ 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 -urN xv-3.10a/xv.c~ xv-3.10apatched/xv.c~
+--- xv-3.10a/xv.c~ Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/xv.c~ Tue Apr 30 00:19:26 2002
+@@ -0,0 +1,4156 @@
++/*
++ * xv.c - main section of xv. X setup, window creation, etc.
++ */
++
++#include "copyright.h"
++
++#define MAIN
++#define NEEDSTIME
++#define NEEDSDIR /* for value of MAXPATHLEN */
++
++#include "xv.h"
++
++#include "bits/icon"
++#include "bits/iconmask"
++#include "bits/runicon"
++#include "bits/runiconm"
++#include "bits/cboard50"
++#include "bits/gray25"
++
++#include <X11/Xatom.h>
++
++#ifdef VMS
++ extern Window pseudo_root();
++#endif
++
++
++/* program needs one of the following fonts. Trys them in ascending order */
++#define FONT1 "-*-lucida-medium-r-*-*-12-*-*-*-*-*-*-*"
++#define FONT2 "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*"
++#define FONT3 "-*-helvetica-medium-r-*-*-11-*-*-*-*-*-*-*"
++#define FONT4 "6x13"
++#define FONT5 "fixed"
++
++/* a mono-spaced font needed for the 'pixel value tracking' feature */
++#define MFONT1 "-misc-fixed-medium-r-normal-*-13-*"
++#define MFONT2 "6x13"
++#define MFONT3 "-*-courier-medium-r-*-*-12-*"
++#define MFONT4 "fixed"
++
++
++/* default positions for various windows */
++#define DEFINFOGEOM "-10+10" /* default position of info window */
++#define DEFCTRLGEOM "+170+380" /* default position of ctrl window */
++#define DEFGAMGEOM "+10-10" /* default position of gamma window */
++#define DEFBROWGEOM "-10-10" /* default position of browse window */
++#define DEFTEXTGEOM "-10+320" /* default position of text window */
++#define DEFCMTGEOM "-10+300" /* default position of comment window */
++
++
++
++static int revvideo = 0; /* true if we should reverse video */
++static int dfltkludge = 0; /* true if we want dfltpic dithered */
++static int clearonload; /* clear window/root (on colormap visuals) */
++static int randomShow = 0; /* do a 'random' slideshow */
++static int startIconic = 0; /* '-iconic' option */
++static int defaultVis = 0; /* true if using DefaultVisual */
++static double hexpand = 1.0; /* '-expand' argument */
++static double vexpand = 1.0; /* '-expand' argument */
++static char *maingeom = NULL;
++static char *icongeom = NULL;
++static Atom __SWM_VROOT = None;
++
++static char basefname[128]; /* just the current fname, no path */
++
++/* things to do upon successfully loading an image */
++static int autoraw = 0; /* force raw if using stdcmap */
++static int autodither = 0; /* dither */
++static int autosmooth = 0; /* smooth */
++static int auto4x3 = 0; /* do a 4x3 */
++static int autorotate = 0; /* rotate 0, +-90, +-180, +-270 */
++static int autohflip = 0; /* Flip Horizontally */
++static int autovflip = 0; /* Flip Vertically */
++static int autocrop = 0; /* do an 'AutoCrop' command */
++static int acrop = 0; /* automatically do a 'Crop' */
++static int acropX, acropY, acropW, acropH;
++static int autonorm = 0; /* normalize */
++static int autohisteq = 0; /* Histogram equalization */
++
++static int force8 = 0; /* force 8-bit mode */
++static int force24 = 0; /* force 24-bit mode */
++
++/* used in DeleteCmd() and Quit() */
++static char **mainargv;
++static int mainargc;
++
++
++/* local function pre-definitions */
++ int main PARM((int, char **));
++static int highbit PARM((unsigned long));
++static void makeDirectCmap PARM((void));
++static void useOtherVisual PARM((XVisualInfo *, int));
++static void parseResources PARM((int, char **));
++static void parseCmdLine PARM((int, char **));
++static void verifyArgs PARM((void));
++static void printoption PARM((char *));
++static void cmdSyntax PARM((void));
++static void rmodeSyntax PARM((void));
++static int openPic PARM((int));
++static int readpipe PARM((char *, char *));
++static void openFirstPic PARM((void));
++static void openNextPic PARM((void));
++static void openNextQuit PARM((void));
++static void openNextLoop PARM((void));
++static void openPrevPic PARM((void));
++static void openNamedPic PARM((void));
++static int findRandomPic PARM((void));
++static void mainLoop PARM((void));
++static void createMainWindow PARM((char *, char *));
++static void setWinIconNames PARM((char *));
++static void makeDispNames PARM((void));
++static void fixDispNames PARM((void));
++static void deleteFromList PARM((int));
++static int argcmp PARM((char *, char *, int, int, int *));
++static void add_filelist_to_namelist PARM((char *, char **, int *, int));
++
++
++/* formerly local vars in main, made local to this module when
++ parseResources() and parseCmdLine() were split out of main() */
++
++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 *monofontname, *flistName;
++int curstype, stdinflag, browseMode, savenorm, preview, pscomp, preset,
++ rmodeset, gamset, cgamset, perfect, owncmap, rwcolor, stdcmap;
++int nodecor;
++double gamval, rgamval, ggamval, bgamval;
++
++
++
++
++/*******************************************/
++int main(argc, argv)
++ int argc;
++ char **argv;
++/*******************************************/
++{
++ int i;
++ XColor ecdef;
++ Window rootReturn, parentReturn, *children;
++ unsigned int numChildren, rootDEEP;
++
++
++#ifdef VMS
++ /* convert VMS-style arguments to unix names and glob */
++ do_vms_wildcard(&argc, &argv);
++ getredirection(&argc, &argv);
++#endif
++
++
++ /*****************************************************/
++ /*** variable Initialization ***/
++ /*****************************************************/
++
++ xv_getwd(initdir, sizeof(initdir));
++ searchdir[0] = '\0';
++ fullfname[0] = '\0';
++
++ mainargv = argv;
++ mainargc = argc;
++
++ /* init internal variables */
++ display = NULL;
++ fgstr = bgstr = rootfgstr = rootbgstr = NULL;
++ histr = lostr = whitestr = blackstr = NULL;
++ visualstr = monofontname = flistName = NULL;
++ winTitle = NULL;
++
++ pic = egampic = epic = cpic = NULL;
++ theImage = NULL;
++
++ picComments = (char *) NULL;
++
++ numPages = 1; curPage = 0;
++ pageBaseName[0] = '\0';
++
++ LocalCmap = browCmap = 0;
++ stdinflag = 0;
++ autoclose = autoDelete = 0;
++ cmapInGam = 0;
++ grabDelay = 0;
++ showzoomcursor = 0;
++ perfect = owncmap = stdcmap = rwcolor = 0;
++
++ ignoreConfigs = 0;
++ browPerfect = 1;
++ gamval = rgamval = ggamval = bgamval = 1.0;
++
++ picType = -1; /* gets set once file is loaded */
++ colorMapMode = CM_NORMAL;
++ haveStdCmap = STD_NONE;
++ allocMode = AM_READONLY;
++ novbrowse = 0;
++
++#ifndef VMS
++ strcpy(printCmd, "lpr");
++#else
++ strcpy(printCmd, "Print /Queue = XV_Queue");
++#endif
++
++ forceClipFile = 0;
++ clearR = clearG = clearB = 0;
++ InitSelection();
++
++
++ /* default Ghostscript parameters */
++ gsDev = "ppmraw";
++#ifdef GS_DEV
++ gsDev = GS_DEV;
++#endif
++
++ gsRes = 72;
++ gsGeomStr = NULL;
++
++
++ /* init default colors */
++ fgstr = "#000000"; bgstr = "#B2C0DC";
++ histr = "#C6D5E2"; lostr = "#8B99B5";
++
++ cmd = (char *) rindex(argv[0],'/');
++ if (!cmd) cmd = argv[0]; else cmd++;
++
++ tmpstr = (char *) getenv("TMPDIR");
++ if (!tmpstr) tmpdir = "/tmp";
++ else {
++ tmpdir = (char *) malloc(strlen(tmpstr) + 1);
++ if (!tmpdir) FatalError("can't malloc 'tmpdir'\n");
++ strcpy(tmpdir, tmpstr);
++ }
++
++ /* init command-line options flags */
++ infogeom = DEFINFOGEOM; ctrlgeom = DEFCTRLGEOM;
++ gamgeom = DEFGAMGEOM; browgeom = DEFBROWGEOM;
++ textgeom = DEFTEXTGEOM; cmtgeom = DEFCMTGEOM;
++
++ ncols = -1; mono = 0;
++ ninstall = 0; fixedaspect = 0; noFreeCols = nodecor = 0;
++ DEBUG = 0; bwidth = 2;
++ nolimits = useroot = clrroot = noqcheck = 0;
++ waitsec = -1; waitloop = 0; automax = 0;
++ rootMode = 0; hsvmode = 0;
++ rmodeset = gamset = cgamset = 0;
++ nopos = limit2x = 0;
++ resetroot = 1;
++ clearonload = 0;
++ curstype = XC_top_left_arrow;
++ browseMode = savenorm = nostat = 0;
++ preview = 0;
++ pscomp = 0;
++ preset = 0;
++ viewonly = 0;
++
++ /* init 'xormasks' array */
++ xorMasks[0] = 0x01010101;
++ xorMasks[1] = 0x02020203;
++ xorMasks[2] = 0x84848485;
++ xorMasks[3] = 0x88888889;
++ xorMasks[4] = 0x10101011;
++ xorMasks[5] = 0x20202023;
++ xorMasks[6] = 0xc4c4c4c5;
++ xorMasks[7] = 0xffffffff;
++
++ kludge_offx = kludge_offy = winCtrPosKludge = 0;
++
++ conv24 = CONV24_SLOW; /* use 'slow' algorithm by default */
++
++ defaspect = normaspect = 1.0;
++ mainW = dirW = infoW = ctrlW = gamW = psW = (Window) NULL;
++ anyBrowUp = 0;
++
++#ifdef HAVE_JPEG
++ jpegW = (Window) NULL; jpegUp = 0;
++#endif
++
++#ifdef HAVE_TIFF
++ tiffW = (Window) NULL; tiffUp = 0;
++#endif
++
++#ifdef HAVE_PNG
++ pngW = (Window) NULL; pngUp = 0;
++#endif
++
++ imap = ctrlmap = gmap = browmap = cmtmap = 0;
++
++ ch_offx = ch_offy = p_offx = p_offy = 0;
++
++ /* init info box variables */
++ infoUp = 0;
++ infoMode = INF_STR;
++ for (i=0; i<NISTR; i++) SetISTR(i,"");
++
++ /* init ctrl box variables */
++ ctrlUp = 0;
++ curname = -1;
++ formatStr[0] ='\0';
++
++ gamUp = 0;
++ psUp = 0;
++
++ Init24to8();
++
++
++ /* handle user-specified resources and cmd-line arguments */
++ parseResources(argc,argv);
++ parseCmdLine(argc, argv);
++ verifyArgs();
++
++
++ /*****************************************************/
++ /*** X Setup ***/
++ /*****************************************************/
++
++ theScreen = DefaultScreen(theDisp);
++ theCmap = DefaultColormap(theDisp, theScreen);
++ rootW = RootWindow(theDisp,theScreen);
++ theGC = DefaultGC(theDisp,theScreen);
++ theVisual = DefaultVisual(theDisp,theScreen);
++ ncells = DisplayCells(theDisp, theScreen);
++ dispDEEP = DisplayPlanes(theDisp,theScreen);
++ maxWIDE = vrWIDE = dispWIDE = DisplayWidth(theDisp,theScreen);
++ maxHIGH = vrHIGH = dispHIGH = DisplayHeight(theDisp,theScreen);
++
++
++ rootDEEP = dispDEEP;
++
++ /* things dependant on theVisual:
++ * dispDEEP, theScreen, rootW, ncells, theCmap, theGC,
++ * vrWIDE, dispWIDE, vrHIGH, dispHIGH, maxWIDE, maxHIGH
++ */
++
++
++
++ /* if we *haven't* had a non-default visual specified,
++ see if we have a TrueColor or DirectColor visual of 24 or 32 bits,
++ and if so, use that as the default visual (prefer TrueColor) */
++
++ if (!visualstr && !useroot) {
++ XVisualInfo *vinfo, rvinfo;
++ int best, numvis;
++ long flags;
++
++ best = -1;
++ rvinfo.class = TrueColor;
++ rvinfo.screen = theScreen;
++ flags = VisualClassMask | VisualScreenMask;
++
++ vinfo = XGetVisualInfo(theDisp, flags, &rvinfo, &numvis);
++ if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */
++ for (i=0, best = -1; i<numvis; i++) {
++ if (vinfo[i].depth == 24) best = i;
++ else if (vinfo[i].depth>24 && best<0) best = i;
++ }
++ }
++
++ if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */
++ rvinfo.class = DirectColor;
++ if (vinfo) XFree((char *) vinfo);
++ vinfo = XGetVisualInfo(theDisp, flags, &rvinfo, &numvis);
++ if (vinfo) {
++ for (i=0, best = -1; i<numvis; i++) {
++ if (vinfo[i].depth == 24) best = i;
++ else if (vinfo[i].depth>24 && best<0) best = i;
++ }
++ }
++ }
++
++ if (best>=0 && best<numvis) useOtherVisual(vinfo, best);
++ if (vinfo) XFree((char *) vinfo);
++ }
++
++
++
++ if (visualstr && useroot) {
++ fprintf(stderr, "%s: %sUsing default visual.\n",
++ cmd, "Warning: Can't use specified visual on root. ");
++ visualstr = NULL;
++ }
++
++ if (visualstr && !useroot) { /* handle non-default visual */
++ int vclass = -1;
++ int vid = -1;
++
++ lower_str(visualstr);
++ if (!strcmp(visualstr,"staticgray")) vclass = StaticGray;
++ else if (!strcmp(visualstr,"staticcolor")) vclass = StaticColor;
++ else if (!strcmp(visualstr,"truecolor")) vclass = TrueColor;
++ else if (!strcmp(visualstr,"grayscale")) vclass = GrayScale;
++ else if (!strcmp(visualstr,"pseudocolor")) vclass = PseudoColor;
++ else if (!strcmp(visualstr,"directcolor")) vclass = DirectColor;
++ else if (!strcmp(visualstr,"default")) {} /* recognize it as valid */
++ else if (!strncmp(visualstr,"0x",(size_t) 2)) { /* specified visual id */
++ if (sscanf(visualstr, "0x%x", &vid) != 1) vid = -1;
++ }
++ else {
++ fprintf(stderr,"%s: Unrecognized visual type '%s'. %s\n",
++ cmd, visualstr, "Using server default.");
++ }
++
++
++ /* if 'default', vclass and vid will both be '-1' */
++
++ if (vclass >= 0 || vid >= 0) { /* try to find asked-for visual type */
++ XVisualInfo *vinfo, rvinfo;
++ long vinfomask;
++ int numvis, best;
++
++ if (vclass >= 0) {
++ rvinfo.class = vclass; vinfomask = VisualClassMask;
++ }
++ else { rvinfo.visualid = vid; vinfomask = VisualIDMask; }
++
++ rvinfo.screen = theScreen;
++ vinfomask |= VisualScreenMask;
++
++ vinfo = XGetVisualInfo(theDisp, vinfomask, &rvinfo, &numvis);
++
++ if (vinfo) { /* choose the 'best' one, if multiple */
++ for (i=0, best = 0; i<numvis; i++) {
++ if (vinfo[i].depth > vinfo[best].depth) best = i;
++ }
++
++ useOtherVisual(vinfo, best);
++ XFree((char *) vinfo);
++ }
++ else fprintf(stderr,"%s: Visual type '%s' not available. %s\n",
++ cmd, visualstr, "Using server default.");
++ }
++ }
++
++
++
++ /* make linear colormap for DirectColor visual */
++ if (theVisual->class == DirectColor) makeDirectCmap();
++
++ defaultVis = (XVisualIDFromVisual(theVisual) ==
++ XVisualIDFromVisual(DefaultVisual(theDisp, DefaultScreen(theDisp))));
++
++
++ /* turn GraphicsExposures OFF in the default GC */
++ {
++ XGCValues xgcv;
++ xgcv.graphics_exposures = False;
++ XChangeGC(theDisp, theGC, GCGraphicsExposures, &xgcv);
++ }
++
++
++ if (!useroot && limit2x) { maxWIDE *= 2; maxHIGH *= 2; }
++ if (nolimits) { maxWIDE = 65000; maxHIGH = 65000; }
++
++ XSetErrorHandler(xvErrorHandler);
++
++ /* always search for virtual root window */
++ vrootW = rootW;
++#ifndef VMS
++ __SWM_VROOT = XInternAtom(theDisp, "__SWM_VROOT", False);
++ XQueryTree(theDisp, rootW, &rootReturn, &parentReturn, &children,
++ &numChildren);
++ for (i = 0; i < numChildren; i++) {
++ Atom actual_type;
++ int actual_format;
++ unsigned long nitems, bytesafter;
++ Window *newRoot = NULL;
++ XWindowAttributes xwa;
++ if (XGetWindowProperty (theDisp, children[i], __SWM_VROOT, 0L, 1L,
++ False, XA_WINDOW, &actual_type, &actual_format, &nitems,
++ &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) {
++ vrootW = *newRoot;
++ XGetWindowAttributes(theDisp, vrootW, &xwa);
++ vrWIDE = xwa.width; vrHIGH = xwa.height;
++ dispDEEP = xwa.depth;
++ break;
++ }
++ }
++#else /* VMS */
++ vrootW = pseudo_root(theDisp, theScreen);
++#endif
++
++
++
++
++ if (clrroot || useroot) {
++ /* have enough info to do a '-clear' now */
++ KillOldRootInfo(); /* if any */
++ if (resetroot || clrroot) ClearRoot(); /* don't clear on '-noresetroot' */
++ if (clrroot) Quit(0);
++ }
++
++
++ arrow = XCreateFontCursor(theDisp,(u_int) curstype);
++ cross = XCreateFontCursor(theDisp,XC_crosshair);
++ tcross = XCreateFontCursor(theDisp,XC_tcross);
++ zoom = XCreateFontCursor(theDisp,XC_sizing);
++
++ {
++ XColor fc, bc;
++ fc.red = fc.green = fc.blue = 0xffff;
++ bc.red = bc.green = bc.blue = 0x0000;
++
++ XRecolorCursor(theDisp, zoom, &fc, &bc);
++ }
++
++ { /* create inviso cursor */
++ Pixmap pix;
++ static char bits[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
++ XColor cfg;
++
++ cfg.red = cfg.green = cfg.blue = 0;
++ pix = XCreateBitmapFromData(theDisp, rootW, bits, 8, 8);
++ inviso = XCreatePixmapCursor(theDisp, pix, pix, &cfg, &cfg, 0,0);
++ XFreePixmap(theDisp, pix);
++ }
++
++
++
++ /* set up white,black colors */
++ whtRGB = 0xffffff; blkRGB = 0x000000;
++
++ if (defaultVis) {
++ white = WhitePixel(theDisp,theScreen);
++ black = BlackPixel(theDisp,theScreen);
++ }
++ else {
++ ecdef.flags = DoRed | DoGreen | DoBlue;
++ ecdef.red = ecdef.green = ecdef.blue = 0xffff;
++ if (xvAllocColor(theDisp, theCmap, &ecdef)) white = ecdef.pixel;
++ else white = 0xffffffff; /* probably evil... */
++
++ ecdef.red = ecdef.green = ecdef.blue = 0x0000;
++ if (xvAllocColor(theDisp, theCmap, &ecdef)) black = ecdef.pixel;
++ else black = 0x00000000; /* probably evil... */
++ }
++
++ if (whitestr && XParseColor(theDisp, theCmap, whitestr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) {
++ white = ecdef.pixel;
++ whtRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
++ }
++
++ if (blackstr && XParseColor(theDisp, theCmap, blackstr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) {
++ black = ecdef.pixel;
++ blkRGB = ((ecdef.red>>8)<<16) | (ecdef.green&0xff00) | (ecdef.blue>>8);
++ }
++
++
++ /* set up fg,bg colors */
++ fg = black; bg = white;
++ if (fgstr && XParseColor(theDisp, theCmap, fgstr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) {
++ fg = ecdef.pixel;
++ }
++
++ if (bgstr && XParseColor(theDisp, theCmap, bgstr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) {
++ bg = ecdef.pixel;
++ }
++
++
++ /* set up root fg,bg colors */
++ rootfg = white; rootbg = black;
++ if (rootfgstr && XParseColor(theDisp, theCmap, rootfgstr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) rootfg = ecdef.pixel;
++ if (rootbgstr && XParseColor(theDisp, theCmap, rootbgstr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) rootbg = ecdef.pixel;
++
++
++ /* set up hi/lo colors */
++ i=0;
++ if (dispDEEP > 1) { /* only if we're on a reasonable display */
++ if (histr && XParseColor(theDisp, theCmap, histr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) { hicol = ecdef.pixel; i|=1; }
++ if (lostr && XParseColor(theDisp, theCmap, lostr, &ecdef) &&
++ xvAllocColor(theDisp, theCmap, &ecdef)) { locol = ecdef.pixel; i|=2; }
++ }
++
++ if (i==0) ctrlColor = 0;
++ else if (i==3) ctrlColor = 1;
++ else { /* only got some of them */
++ if (i&1) xvFreeColors(theDisp, theCmap, &hicol, 1, 0L);
++ if (i&2) xvFreeColors(theDisp, theCmap, &locol, 1, 0L);
++ ctrlColor = 0;
++ }
++
++ if (!ctrlColor) { hicol = bg; locol = fg; }
++
++ XSetForeground(theDisp,theGC,fg);
++ XSetBackground(theDisp,theGC,bg);
++
++ infofg = fg; infobg = bg;
++
++ /* if '-mono' not forced, determine if we're on a grey or color monitor */
++ if (!mono) {
++ if (theVisual->class == StaticGray || theVisual->class == GrayScale)
++ mono = 1;
++ }
++
++
++
++ iconPix = MakePix1(rootW, icon_bits, icon_width, icon_height);
++ iconmask = MakePix1(rootW, iconmask_bits, icon_width, icon_height);
++ riconPix = MakePix1(rootW, runicon_bits, runicon_width, runicon_height);
++ riconmask= MakePix1(rootW, runiconm_bits, runiconm_width,runiconm_height);
++
++ if (!iconPix || !iconmask || !riconPix || !riconmask)
++ FatalError("Unable to create icon pixmaps\n");
++
++ gray50Tile = XCreatePixmapFromBitmapData(theDisp, rootW,
++ (char *) cboard50_bits,
++ cboard50_width, cboard50_height,
++ infofg, infobg, dispDEEP);
++ if (!gray50Tile) FatalError("Unable to create gray50Tile bitmap\n");
++
++ gray25Tile = XCreatePixmapFromBitmapData(theDisp, rootW,
++ (char *) gray25_bits,
++ gray25_width, gray25_height,
++ infofg, infobg, dispDEEP);
++ if (!gray25Tile) FatalError("Unable to create gray25Tile bitmap\n");
++
++
++ /* try to load fonts */
++ if ( (mfinfo = XLoadQueryFont(theDisp,FONT1))==NULL &&
++ (mfinfo = XLoadQueryFont(theDisp,FONT2))==NULL &&
++ (mfinfo = XLoadQueryFont(theDisp,FONT3))==NULL &&
++ (mfinfo = XLoadQueryFont(theDisp,FONT4))==NULL &&
++ (mfinfo = XLoadQueryFont(theDisp,FONT5))==NULL) {
++ sprintf(str,
++ "couldn't open the following fonts:\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s",
++ FONT1, FONT2, FONT3, FONT4, FONT5);
++ FatalError(str);
++ }
++ mfont=mfinfo->fid;
++ XSetFont(theDisp,theGC,mfont);
++
++ monofinfo = (XFontStruct *) NULL;
++
++ if (monofontname) {
++ monofinfo = XLoadQueryFont(theDisp, monofontname);
++ if (!monofinfo) fprintf(stderr,"xv: unable to load font '%s'\n",
++ monofontname);
++ }
++
++ if (!monofinfo) {
++ if ((monofinfo = XLoadQueryFont(theDisp,MFONT1))==NULL &&
++ (monofinfo = XLoadQueryFont(theDisp,MFONT2))==NULL &&
++ (monofinfo = XLoadQueryFont(theDisp,MFONT3))==NULL &&
++ (monofinfo = XLoadQueryFont(theDisp,MFONT4))==NULL) {
++ sprintf(str,"couldn't open %s fonts:\n\t%s\n\t%s\n\t%s\n\t%s",
++ "any of the following",
++ MFONT1, MFONT2, MFONT3, MFONT4);
++ FatalError(str);
++ }
++ }
++
++ monofont=monofinfo->fid;
++
++
++
++
++ /* if ncols wasn't set, set it to 2^dispDEEP, unless dispDEEP=1, in which
++ case ncols = 0; (ncols = max number of colors allocated. on 1-bit
++ displays, no colors are allocated */
++
++ if (ncols == -1) {
++ if (dispDEEP>1) ncols = 1 << ((dispDEEP>8) ? 8 : dispDEEP);
++ else ncols = 0;
++ }
++ else if (ncols>256) ncols = 256; /* so program doesn't blow up */
++
++
++ GenerateFSGamma(); /* has to be done before 'OpenBrowse()' is called */
++
++
++
++ /* no filenames. build one-name (stdio) list (if stdinflag) */
++ if (numnames==0) {
++ if (stdinflag) {
++ /* have to malloc namelist[0] so we can free it in deleteFromList() */
++ namelist[0] = (char *) malloc(strlen(STDINSTR) + 1);
++ if (!namelist[0]) FatalError("unable to to build namelist[0]");
++ strcpy(namelist[0], STDINSTR);
++ numnames = 1;
++ }
++ else namelist[0] = NULL;
++ }
++
++ if (numnames) makeDispNames();
++
++
++ if (viewonly || autoquit) {
++ imap = ctrlmap = gmap = browmap = cmtmap = 0;
++ novbrowse = 1;
++ }
++
++
++ /* create the info box window */
++ CreateInfo(infogeom);
++ XSelectInput(theDisp, infoW, ExposureMask | ButtonPressMask | KeyPressMask
++ | StructureNotifyMask);
++ InfoBox(imap); /* map it (or not) */
++ if (imap) {
++ RedrawInfo(0,0,1000,1000); /* explicit draw if mapped */
++ XFlush(theDisp);
++ }
++
++
++ /* create the control box window */
++ CreateCtrl(ctrlgeom);
++ epicMode = EM_RAW; SetEpicMode();
++
++ XSelectInput(theDisp, ctrlW, ExposureMask | ButtonPressMask | KeyPressMask
++ | StructureNotifyMask);
++ if (ctrlmap < 0) { /* map iconified */
++ XWMHints xwmh;
++ xwmh.input = True;
++ xwmh.initial_state = IconicState;
++ xwmh.flags = (InputHint | StateHint);
++ XSetWMHints(theDisp, ctrlW, &xwmh);
++ ctrlmap = 1;
++ }
++ CtrlBox(ctrlmap); /* map it (or not) */
++ if (ctrlmap) {
++ RedrawCtrl(0,0,1000,1000); /* explicit draw if mapped */
++ XFlush(theDisp);
++ }
++
++ fixDispNames();
++ ChangedCtrlList();
++
++ /* disable root modes if using non-default visual */
++ if (!defaultVis) {
++ for (i=RMB_ROOT; i<RMB_MAX; i++) rootMB.dim[i] = 1;
++ }
++
++
++ /* create the directory window */
++ CreateDirW(NULL);
++ XSelectInput(theDisp, dirW, ExposureMask | ButtonPressMask | KeyPressMask);
++ browseCB.val = browseMode;
++ savenormCB.val = savenorm;
++
++ /* create the gamma window */
++ CreateGam(gamgeom, (gamset) ? gamval : -1.0,
++ (cgamset) ? rgamval : -1.0,
++ (cgamset) ? ggamval : -1.0,
++ (cgamset) ? bgamval : -1.0,
++ preset);
++ XSelectInput(theDisp, gamW, ExposureMask | ButtonPressMask | KeyPressMask
++ | StructureNotifyMask
++ | (cmapInGam ? ColormapChangeMask : 0));
++
++ GamBox(gmap); /* map it (or not) */
++
++
++
++ stdnfcols = 0; /* so we don't try to free any if we don't create any */
++
++ if (!novbrowse) {
++ MakeBrowCmap();
++ /* create the visual browser window */
++ CreateBrowse(browgeom, fgstr, bgstr, histr, lostr);
++
++ if (browmap) OpenBrowse();
++ }
++ else windowMB.dim[WMB_BROWSE] = 1; /* disable visual schnauzer */
++
++
++ CreateTextWins(textgeom, cmtgeom);
++ if (cmtmap) OpenCommentText();
++
++
++ /* create the ps window */
++ CreatePSD(NULL);
++ XSetTransientForHint(theDisp, psW, dirW);
++ encapsCB.val = preview;
++ pscompCB.val = pscomp;
++
++
++#ifdef HAVE_JPEG
++ CreateJPEGW();
++ XSetTransientForHint(theDisp, jpegW, dirW);
++#endif
++
++#ifdef HAVE_TIFF
++ CreateTIFFW();
++ XSetTransientForHint(theDisp, tiffW, dirW);
++#endif
++
++#ifdef HAVE_PNG
++ CreatePNGW();
++ XSetTransientForHint(theDisp, pngW, dirW);
++#endif
++
++ LoadFishCursors();
++ SetCursors(-1);
++
++
++ /* if we're not on a colormapped display, turn off rwcolor */
++ if (!CMAPVIS(theVisual)) {
++ if (rwcolor) fprintf(stderr, "xv: not a colormapped display. %s\n",
++ "'rwcolor' turned off.");
++
++ allocMode = AM_READONLY;
++ dispMB.flags[DMB_COLRW] = 0; /* de-'check' */
++ dispMB.dim[DMB_COLRW] = 1; /* and dim it */
++ }
++
++
++ if (force24) {
++ Set824Menus(PIC24);
++ conv24MB.flags[CONV24_LOCK] = 1;
++ picType = PIC24;
++ }
++ else if (force8) {
++ Set824Menus(PIC8);
++ conv24MB.flags[CONV24_LOCK] = 1;
++ picType = PIC8;
++ }
++ else {
++ Set824Menus(PIC8); /* default mode */
++ picType = PIC8;
++ }
++
++
++
++ /* make std colormap, maybe */
++ ChangeCmapMode(colorMapMode, 0, 0);
++
++
++
++
++ /* Do The Thing... */
++ mainLoop();
++ Quit(0);
++ return(0);
++}
++
++
++
++/*****************************************************/
++static void makeDirectCmap()
++{
++ int i, j, cmaplen, numgot;
++ byte origgot[256];
++ XColor c;
++ u_long rmask, gmask, bmask;
++ int rshift, gshift, bshift;
++
++
++ rmask = theVisual->red_mask;
++ gmask = theVisual->green_mask;
++ bmask = theVisual->blue_mask;
++
++ rshift = highbit(rmask) - 15;
++ gshift = highbit(gmask) - 15;
++ bshift = highbit(bmask) - 15;
++
++ if (rshift<0) rmask = rmask << (-rshift);
++ else rmask = rmask >> rshift;
++
++ if (gshift<0) gmask = gmask << (-gshift);
++ else gmask = gmask >> gshift;
++
++ if (bshift<0) bmask = bmask << (-bshift);
++ else bmask = bmask >> bshift;
++
++
++ cmaplen = theVisual->map_entries;
++ if (cmaplen>256) cmaplen=256;
++
++
++ /* try to alloc a 'cmaplen' long grayscale colormap. May not get all
++ entries for whatever reason. Build table 'directConv[]' that
++ maps range [0..(cmaplen-1)] into set of colors we did get */
++
++ for (i=0; i<256; i++) { origgot[i] = 0; directConv[i] = 0; }
++
++ for (i=numgot=0; i<cmaplen; i++) {
++ c.red = c.green = c.blue = (i * 0xffff) / (cmaplen - 1);
++ c.red = c.red & rmask;
++ c.green = c.green & gmask;
++ c.blue = c.blue & bmask;
++ c.flags = DoRed | DoGreen | DoBlue;
++
++ if (XAllocColor(theDisp, theCmap, &c)) {
++ /* fprintf(stderr,"%3d: %4x,%4x,%4x\n", i, c.red,c.green,c.blue); */
++ directConv[i] = i;
++ origgot[i] = 1;
++ numgot++;
++ }
++ }
++
++
++ if (numgot == 0) FatalError("Got no entries in DirectColor cmap!\n");
++
++ /* directConv may or may not have holes in it. */
++ for (i=0; i<cmaplen; i++) {
++ if (!origgot[i]) {
++ int numbak, numfwd;
++ numbak = numfwd = 0;
++ while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++;
++ while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++;
++
++ if (i-numbak<0 || !origgot[i-numbak]) numbak = 999;
++ if (i+numfwd>=cmaplen || !origgot[i+numfwd]) numfwd = 999;
++
++ if (numbak<numfwd) directConv[i] = directConv[i-numbak];
++ else if (numfwd<999) directConv[i] = directConv[i+numfwd];
++ else FatalError("DirectColor cmap: can't happen!");
++ }
++ }
++}
++
++
++static int highbit(ul)
++ unsigned long ul;
++{
++ /* returns position of highest set bit in 'ul' as an integer (0-31),
++ or -1 if none */
++
++ int i; unsigned long hb;
++ hb = 0x8000; hb = (hb<<16); /* hb = 0x80000000UL */
++ for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1);
++ return i;
++}
++
++
++
++
++/*****************************************************/
++static void useOtherVisual(vinfo, best)
++ XVisualInfo *vinfo;
++ int best;
++{
++ if (!vinfo || best<0) return;
++
++ if (vinfo[best].visualid ==
++ XVisualIDFromVisual(DefaultVisual(theDisp, theScreen))) return;
++
++ theVisual = vinfo[best].visual;
++
++ if (DEBUG) {
++ fprintf(stderr,"%s: using %s visual (0x%0x), depth = %d, screen = %d\n",
++ cmd,
++ (vinfo[best].class==StaticGray) ? "StaticGray" :
++ (vinfo[best].class==StaticColor) ? "StaticColor" :
++ (vinfo[best].class==TrueColor) ? "TrueColor" :
++ (vinfo[best].class==GrayScale) ? "GrayScale" :
++ (vinfo[best].class==PseudoColor) ? "PseudoColor" :
++ (vinfo[best].class==DirectColor) ? "DirectColor" : "<unknown>",
++ (int) vinfo[best].visualid,
++ vinfo[best].depth, vinfo[best].screen);
++
++ fprintf(stderr,"\tmasks: (0x%x,0x%x,0x%x), bits_per_rgb=%d\n",
++ (int) vinfo[best].red_mask, (int) vinfo[best].green_mask,
++ (int) vinfo[best].blue_mask, vinfo[best].bits_per_rgb);
++ }
++
++ dispDEEP = vinfo[best].depth;
++ theScreen = vinfo[best].screen;
++ rootW = RootWindow(theDisp, theScreen);
++ ncells = vinfo[best].colormap_size;
++ theCmap = XCreateColormap(theDisp, rootW, theVisual, AllocNone);
++
++ {
++ /* create a temporary window using this visual so we can
++ create a GC for this visual */
++
++ Window win;
++ XSetWindowAttributes xswa;
++ XGCValues xgcv;
++ unsigned long xswamask;
++
++ XFlush(theDisp);
++ XSync(theDisp, False);
++
++ xswa.background_pixel = 0;
++ xswa.border_pixel = 1;
++ xswa.colormap = theCmap;
++ xswamask = CWBackPixel | CWBorderPixel | CWColormap;
++
++ win = XCreateWindow(theDisp, rootW, 0, 0, 100, 100, 2, (int) dispDEEP,
++ InputOutput, theVisual, xswamask, &xswa);
++
++ XFlush(theDisp);
++ XSync(theDisp, False);
++
++ theGC = XCreateGC(theDisp, win, 0L, &xgcv);
++
++ XDestroyWindow(theDisp, win);
++ }
++
++ vrWIDE = dispWIDE = DisplayWidth(theDisp,theScreen);
++ vrHIGH = dispHIGH = DisplayHeight(theDisp,theScreen);
++ maxWIDE = dispWIDE; maxHIGH = dispHIGH;
++}
++
++
++
++
++/*****************************************************/
++static void parseResources(argc, argv)
++ int argc;
++ char **argv;
++{
++ int i, pm;
++
++ /* once through the argument list to find the display name
++ and DEBUG level, if any */
++
++ for (i=1; i<argc; i++) {
++ if (!strncmp(argv[i],"-help", (size_t) 5)) { /* help */
++ cmdSyntax();
++ exit(0);
++ }
++
++ else if (!argcmp(argv[i],"-display",4,0,&pm)) {
++ i++;
++ if (i<argc) display = argv[i];
++ break;
++ }
++
++#ifdef VMS /* in VMS, cmd-line-opts are in lower case */
++ else if (!argcmp(argv[i],"-debug",3,0,&pm)) {
++ { if (++i<argc) DEBUG = atoi(argv[i]); }
++ }
++#else
++ else if (!argcmp(argv[i],"-DEBUG",2,0,&pm)) {
++ { if (++i<argc) DEBUG = atoi(argv[i]); }
++ }
++#endif
++ }
++
++ /* open the display */
++ if ( (theDisp=XOpenDisplay(display)) == NULL) {
++ fprintf(stderr, "%s: Can't open display\n",argv[0]);
++ exit(1);
++ }
++
++
++
++ if (rd_str ("aspect")) {
++ int n,d;
++ if (sscanf(def_str,"%d:%d",&n,&d)!=2 || n<1 || d<1)
++ fprintf(stderr,"%s: unable to parse 'aspect' resource\n",cmd);
++ else defaspect = (float) n / (float) d;
++ }
++
++ if (rd_flag("2xlimit")) limit2x = def_int;
++ if (rd_flag("auto4x3")) auto4x3 = def_int;
++ if (rd_flag("autoClose")) autoclose = def_int;
++ if (rd_flag("autoCrop")) autocrop = def_int;
++ if (rd_flag("autoDither")) autodither = def_int;
++ if (rd_flag("autoHFlip")) autohflip = def_int;
++ if (rd_flag("autoHistEq")) autohisteq = def_int;
++ if (rd_flag("autoNorm")) autonorm = def_int;
++ if (rd_flag("autoRaw")) autoraw = def_int;
++ if (rd_int ("autoRotate")) autorotate = def_int;
++ if (rd_flag("autoSmooth")) autosmooth = def_int;
++ if (rd_flag("autoVFlip")) autovflip = def_int;
++ if (rd_str ("background")) bgstr = def_str;
++ if (rd_flag("best24") && def_int) conv24 = CONV24_BEST;
++ if (rd_str ("black")) blackstr = def_str;
++ if (rd_int ("borderWidth")) bwidth = def_int;
++ if (rd_str ("ceditGeometry")) gamgeom = def_str;
++ if (rd_flag("ceditMap")) gmap = def_int;
++ if (rd_flag("ceditColorMap")) cmapInGam = def_int;
++ if (rd_flag("clearOnLoad")) clearonload = def_int;
++ if (rd_str ("commentGeometry")) cmtgeom = def_str;
++ if (rd_flag("commentMap")) cmtmap = def_int;
++ if (rd_str ("ctrlGeometry")) ctrlgeom = def_str;
++ if (rd_flag("ctrlMap")) ctrlmap = def_int;
++ if (rd_int ("cursor")) curstype = def_int;
++ if (rd_int ("defaultPreset")) preset = def_int;
++
++ if (rd_str ("driftKludge")) {
++ if (sscanf(def_str,"%d %d", &kludge_offx, &kludge_offy) != 2) {
++ kludge_offx = kludge_offy = 0;
++ }
++ }
++
++ if (rd_str ("expand")) {
++ if (index(def_str, ':')) {
++ if (sscanf(def_str, "%lf:%lf", &hexpand, &vexpand)!=2)
++ { hexpand = vexpand = 1.0; }
++ }
++ else hexpand = vexpand = atof(def_str);
++ }
++
++ if (rd_str ("fileList")) flistName = def_str;
++ if (rd_flag("fixed")) fixedaspect = def_int;
++ if (rd_flag("force8")) force8 = def_int;
++ if (rd_flag("force24")) force24 = def_int;
++ if (rd_str ("foreground")) fgstr = def_str;
++ if (rd_str ("geometry")) maingeom = def_str;
++ if (rd_str ("gsDevice")) gsDev = def_str;
++ if (rd_str ("gsGeometry")) gsGeomStr = def_str;
++ if (rd_int ("gsResolution")) gsRes = def_int;
++ if (rd_flag("hsvMode")) hsvmode = def_int;
++ if (rd_str ("highlight")) histr = def_str;
++ if (rd_str ("iconGeometry")) icongeom = def_str;
++ if (rd_flag("iconic")) startIconic = def_int;
++ if (rd_str ("infoGeometry")) infogeom = def_str;
++ if (rd_flag("infoMap")) imap = def_int;
++ if (rd_flag("loadBrowse")) browseMode = def_int;
++ if (rd_str ("lowlight")) lostr = def_str;
++ if (rd_flag("mono")) mono = def_int;
++ if (rd_str ("monofont")) monofontname = def_str;
++ if (rd_int ("ncols")) ncols = def_int;
++ if (rd_flag("ninstall")) ninstall = def_int;
++ if (rd_flag("nodecor")) nodecor = def_int;
++ if (rd_flag("nolimits")) nolimits = def_int;
++ if (rd_flag("nopos")) nopos = def_int;
++ if (rd_flag("noqcheck")) noqcheck = def_int;
++ if (rd_flag("nostat")) nostat = def_int;
++ if (rd_flag("ownCmap")) owncmap = def_int;
++ if (rd_flag("perfect")) perfect = def_int;
++ if (rd_flag("popupKludge")) winCtrPosKludge = def_int;
++ if (rd_str ("print")) strncpy(printCmd, def_str,
++ (size_t) PRINTCMDLEN);
++ if (rd_flag("pscompress")) pscomp = def_int;
++ if (rd_flag("pspreview")) preview = def_int;
++ if (rd_flag("quick24") && def_int) conv24 = CONV24_FAST;
++ if (rd_flag("resetroot")) resetroot = def_int;
++ if (rd_flag("reverse")) revvideo = def_int;
++ if (rd_str ("rootBackground")) rootbgstr = def_str;
++ if (rd_str ("rootForeground")) rootfgstr = def_str;
++ if (rd_int ("rootMode")) { rootMode = def_int; rmodeset++; }
++ if (rd_flag("rwColor")) rwcolor = def_int;
++ if (rd_flag("saveNormal")) savenorm = def_int;
++ if (rd_str ("searchDirectory")) strcpy(searchdir, def_str);
++ if (rd_str ("textviewGeometry")) textgeom = def_str;
++ if (rd_flag("useStdCmap")) stdcmap = def_int;
++ if (rd_str ("visual")) visualstr = def_str;
++ if (rd_flag("vsDisable")) novbrowse = def_int;
++ if (rd_str ("vsGeometry")) browgeom = def_str;
++ if (rd_flag("vsMap")) browmap = def_int;
++ if (rd_flag("vsPerfect")) browPerfect = def_int;
++ if (rd_str ("white")) whitestr = def_str;
++}
++
++
++
++/*****************************************************/
++static void parseCmdLine(argc, argv)
++ int argc; char **argv;
++{
++ int i, oldi, not_in_first_half, pm;
++
++ orignumnames = 0;
++
++ for (i=1, numnames=0; i<argc; i++) {
++ oldi = i;
++
++ not_in_first_half = 0;
++
++ if (argv[i][0] != '-' && argv[i][0] != '+') {
++ /* a file name. put it in list */
++
++ if (!nostat) {
++ struct stat st; int ftype;
++ if (stat(argv[i], &st) == 0) {
++ ftype = st.st_mode;
++ if (!S_ISREG(ftype)) continue; /* stat'd & isn't file. skip it */
++ }
++ }
++
++ if (numnames<MAXNAMES) {
++ namelist[numnames++] = argv[i];
++ if (numnames==MAXNAMES) {
++ fprintf(stderr,"%s: too many filenames. Only using first %d.\n",
++ cmd, MAXNAMES);
++ }
++ }
++ }
++
++ else if (!strcmp(argv[i], "-")) /* stdin flag */
++ stdinflag++;
++
++ else if (!argcmp(argv[i],"-24", 3,1,&force24 )); /* force24 */
++ else if (!argcmp(argv[i],"-2xlimit",3,1,&limit2x )); /* 2xlimit */
++ else if (!argcmp(argv[i],"-4x3", 2,1,&auto4x3 )); /* 4x3 */
++ else if (!argcmp(argv[i],"-8", 2,1,&force8 )); /* force8 */
++ else if (!argcmp(argv[i],"-acrop", 3,1,&autocrop)); /* autocrop */
++
++ else if (!argcmp(argv[i],"-aspect",3,0,&pm)) { /* def. aspect */
++ int n,d;
++ if (++i<argc) {
++ if (sscanf(argv[i],"%d:%d",&n,&d)!=2 || n<1 || d<1)
++ fprintf(stderr,"%s: bad aspect ratio '%s'\n",cmd,argv[i]);
++ else defaspect = (float) n / (float) d;
++ }
++ }
++
++ else if (!argcmp(argv[i],"-best24",3,0,&pm)) /* -best */
++ conv24 = CONV24_BEST;
++
++ else if (!argcmp(argv[i],"-bg",3,0,&pm)) /* bg color */
++ { if (++i<argc) bgstr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-black",3,0,&pm)) /* black color */
++ { if (++i<argc) blackstr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-bw",3,0,&pm)) /* border width */
++ { if (++i<argc) bwidth=atoi(argv[i]); }
++
++ else if (!argcmp(argv[i],"-cecmap",4,1,&cmapInGam)); /* cmapInGam */
++
++ else if (!argcmp(argv[i],"-cegeometry",4,0,&pm)) /* gammageom */
++ { if (++i<argc) gamgeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-cemap",4,1,&gmap)); /* gmap */
++
++ else if (!argcmp(argv[i],"-cgamma",4,0,&pm)) { /* color gamma */
++ if (i+3<argc) {
++ rgamval = atof(argv[++i]);
++ ggamval = atof(argv[++i]);
++ bgamval = atof(argv[++i]);
++ }
++ cgamset++;
++ }
++
++ else if (!argcmp(argv[i],"-cgeometry",4,0,&pm)) /* ctrlgeom */
++ { if (++i<argc) ctrlgeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-clear",4,1,&clrroot)); /* clear */
++ else if (!argcmp(argv[i],"-close",4,1,&autoclose)); /* close */
++ else if (!argcmp(argv[i],"-cmap", 3,1,&ctrlmap)); /* ctrlmap */
++
++ else if (!argcmp(argv[i],"-cmtgeometry",5,0,&pm)) /* comment geom */
++ { if (++i<argc) cmtgeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-cmtmap",5,1,&cmtmap)); /* map cmt window */
++
++ else if (!argcmp(argv[i],"-crop",3,0,&pm)) { /* crop */
++ if (i+4<argc) {
++ acropX = atoi(argv[++i]);
++ acropY = atoi(argv[++i]);
++ acropW = atoi(argv[++i]);
++ acropH = atoi(argv[++i]);
++ }
++ acrop++;
++ }
++
++ else if (!argcmp(argv[i],"-cursor",3,0,&pm)) /* cursor */
++ { if (++i<argc) curstype = atoi(argv[i]); }
++
++#ifdef VMS /* in VMS, cmd-line-opts are in lower case */
++ else if (!argcmp(argv[i],"-debug",3,0,&pm)) {
++ { if (++i<argc) DEBUG = atoi(argv[i]); }
++ }
++#else
++ else if (!argcmp(argv[i],"-DEBUG",2,0,&pm)) {
++ { if (++i<argc) DEBUG = atoi(argv[i]); }
++ }
++#endif
++
++ else if (!argcmp(argv[i],"-dir",4,0,&pm)) /* search dir */
++ { if (++i<argc) strcpy(searchdir, argv[i]); }
++
++ else if (!argcmp(argv[i],"-display",4,0,&pm)) /* display */
++ { if (++i<argc) display = argv[i]; }
++
++ else if (!argcmp(argv[i],"-dither",4,1,&autodither)); /* autodither */
++
++ else if (!argcmp(argv[i],"-drift",3,0,&pm)) { /* drift kludge */
++ if (i<argc-2) {
++ kludge_offx = atoi(argv[++i]);
++ kludge_offy = atoi(argv[++i]);
++ }
++ }
++
++ else if (!argcmp(argv[i],"-expand",2,0,&pm)) { /* expand factor */
++ if (++i<argc) {
++ if (index(argv[i], ':')) {
++ if (sscanf(argv[i], "%lf:%lf", &hexpand, &vexpand)!=2)
++ { hexpand = vexpand = 1.0; }
++ }
++ else hexpand = vexpand = atof(argv[i]);
++ }
++ }
++
++ 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],"-flist",3,0,&pm)) /* file list */
++ { if (++i<argc) flistName = argv[i]; }
++
++ else if (!argcmp(argv[i],"-gamma",3,0,&pm)) /* gamma */
++ { if (++i<argc) gamval = atof(argv[i]); gamset++; }
++
++ else if (!argcmp(argv[i],"-geometry",3,0,&pm)) /* geometry */
++ { if (++i<argc) maingeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-grabdelay",3,0,&pm)) /* grabDelay */
++ { if (++i<argc) grabDelay = atoi(argv[i]); }
++
++ else if (!argcmp(argv[i],"-gsdev",4,0,&pm)) /* gsDevice */
++ { if (++i<argc) gsDev = argv[i]; }
++
++ else if (!argcmp(argv[i],"-gsgeom",4,0,&pm)) /* gsGeometry */
++ { if (++i<argc) gsGeomStr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-gsres",4,0,&pm)) /* gsResolution */
++ { if (++i<argc) gsRes=abs(atoi(argv[i])); }
++
++ else if (!argcmp(argv[i],"-hflip",3,1,&autohflip)); /* hflip */
++
++ else if (!argcmp(argv[i],"-hi",3,0,&pm)) /* highlight */
++ { if (++i<argc) histr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-hist", 4,1,&autohisteq)); /* hist eq */
++
++ else if (!argcmp(argv[i],"-hsv", 3,1,&hsvmode)); /* hsvmode */
++
++ else if (!argcmp(argv[i],"-icgeometry",4,0,&pm)) /* icon geometry */
++ { if (++i<argc) icongeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-iconic",4,1,&startIconic)); /* iconic */
++
++ else if (!argcmp(argv[i],"-igeometry",3,0,&pm)) /* infogeom */
++ { if (++i<argc) infogeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-imap", 3,1,&imap)); /* imap */
++ else if (!argcmp(argv[i],"-lbrowse", 3,1,&browseMode)); /* browse mode */
++
++ else if (!argcmp(argv[i],"-lo",3,0,&pm)) /* lowlight */
++ { if (++i<argc) lostr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-loadclear",4,1,&clearonload)); /* clearonload */
++
++
++ else not_in_first_half = 1;
++
++
++
++ if (i != oldi) continue; /* parsed something... */
++
++
++
++ /* split huge else-if group into two halves, as it breaks some compilers */
++
++
++
++ if (!argcmp(argv[i],"-max",4,1,&automax)); /* auto maximize */
++ else if (!argcmp(argv[i],"-maxpect",5,1,&pm)) /* auto maximize */
++ { automax=pm; fixedaspect=pm; }
++
++ else if (!argcmp(argv[i],"-mfn",3,0,&pm)) /* mono font name */
++ { if (++i<argc) monofontname = argv[i]; }
++
++ else if (!argcmp(argv[i],"-mono",3,1,&mono)); /* mono */
++
++ else if (!argcmp(argv[i],"-name",3,0,&pm)) /* name */
++ { if (++i<argc) winTitle = argv[i]; }
++
++ 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],"-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],"-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],"-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? */
++
++ else if (!argcmp(argv[i],"-preset",3,0,&pm)) /* preset */
++ { if (++i<argc) preset=abs(atoi(argv[i])); }
++
++ else if (!argcmp(argv[i],"-quick24",5,0,&pm)) /* quick 24-to-8 conv */
++ conv24 = CONV24_FAST;
++
++ else if (!argcmp(argv[i],"-quit", 2,1,&autoquit)); /* auto-quit */
++ else if (!argcmp(argv[i],"-random", 4,1,&randomShow)); /* random */
++ else if (!argcmp(argv[i],"-raw", 4,1,&autoraw)); /* force raw */
++
++ else if (!argcmp(argv[i],"-rbg",3,0,&pm)) /* root background color */
++ { if (++i<argc) rootbgstr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-rfg",3,0,&pm)) /* root foreground color */
++ { if (++i<argc) rootfgstr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-rgb",4,1,&pm)) /* rgb mode */
++ hsvmode = !pm;
++
++ else if (!argcmp(argv[i],"-RM",3,0,&pm)) /* auto-delete */
++ autoDelete = 1;
++
++ else if (!argcmp(argv[i],"-rmode",3,0,&pm)) /* root pattern */
++ { if (++i<argc) rootMode = atoi(argv[i]);
++ useroot++; rmodeset++;
++ }
++
++ else if (!argcmp(argv[i],"-root",4,1,&useroot)); /* use root window */
++
++ else if (!argcmp(argv[i],"-rotate",4,0,&pm)) /* rotate */
++ { if (++i<argc) autorotate = atoi(argv[i]); }
++
++ else if (!argcmp(argv[i],"-rv",3,1,&revvideo)); /* reverse video */
++ else if (!argcmp(argv[i],"-rw",3,1,&rwcolor)); /* use r/w color */
++
++ else if (!argcmp(argv[i],"-slow24",3,0,&pm)) /* slow 24->-8 conv.*/
++ conv24 = CONV24_SLOW;
++
++ else if (!argcmp(argv[i],"-smooth",3,1,&autosmooth)); /* autosmooth */
++ else if (!argcmp(argv[i],"-stdcmap",3,1,&stdcmap)); /* use stdcmap */
++
++ else if (!argcmp(argv[i],"-tgeometry",2,0,&pm)) /* textview geom */
++ { if (++i<argc) textgeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-vflip",3,1,&autovflip)); /* vflip */
++ else if (!argcmp(argv[i],"-viewonly",4,1,&viewonly)); /* viewonly */
++
++ else if (!argcmp(argv[i],"-visual",4,0,&pm)) /* visual */
++ { if (++i<argc) visualstr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-vsdisable",4,1,&novbrowse)); /* disable sch? */
++
++ else if (!argcmp(argv[i],"-vsgeometry",4,0,&pm)) /* visSchnauzer geom */
++ { if (++i<argc) browgeom = argv[i]; }
++
++ else if (!argcmp(argv[i],"-vsmap",4,1,&browmap)); /* visSchnauzer map */
++
++ else if (!argcmp(argv[i],"-vsperfect",3,1,&browPerfect)); /* vs perf. */
++
++ 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;
++ }
++ }
++
++ else if (!argcmp(argv[i],"-white",3,0,&pm)) /* white color */
++ { if (++i<argc) whitestr = argv[i]; }
++
++ else if (!argcmp(argv[i],"-wloop",3,1,&waitloop)); /* waitloop */
++
++ else if (not_in_first_half) cmdSyntax();
++ }
++
++
++ /* build origlist[], a copy of namelist that remains unmodified, for
++ use with the 'autoDelete' option */
++ orignumnames = numnames;
++ xvbcopy( (char *) namelist, (char *) origlist, sizeof(origlist));
++}
++
++
++/*****************************************************************/
++static void verifyArgs()
++{
++ /* check options for validity */
++
++ if (strlen(searchdir)) { /* got a search directory */
++ if (chdir(searchdir)) {
++ fprintf(stderr,"xv: unable to cd to directory '%s'.\n",searchdir);
++ fprintf(stderr,
++ " Ignoring '-dir' option and/or 'xv.searchDirectory' resource\n");
++ searchdir[0] = '\0';
++ }
++ }
++
++
++ if (flistName)
++ add_filelist_to_namelist(flistName, namelist, &numnames, MAXNAMES);
++
++ RANGE(curstype,0,254);
++ curstype = curstype & 0xfe; /* clear low bit to make curstype even */
++
++ if (hexpand == 0.0 || vexpand == 0.0) cmdSyntax();
++ if (rootMode < 0 || rootMode > RM_MAX) rmodeSyntax();
++
++ if (DEBUG) XSynchronize(theDisp, True);
++
++ /* if using root, generally gotta map ctrl window, 'cause there won't be
++ any way to ask for it. (no kbd or mouse events from rootW) */
++ if (useroot && !autoquit) ctrlmap = -1;
++
++
++ if (abs(autorotate) != 0 && abs(autorotate) != 90 &&
++ abs(autorotate) != 180 && abs(autorotate) != 270) {
++ fprintf(stderr,"Invalid auto rotation value (%d) ignored.\n", autorotate);
++ fprintf(stderr," (Valid values: 0, +-90, +-180, +-270)\n");
++
++ autorotate = 0;
++ }
++
++
++ if (grabDelay < 0 || grabDelay > 15) {
++ fprintf(stderr,
++ "Invalid '-grabdelay' value ignored. Valid range is 0-15 seconds.\n");
++ grabDelay = 0;
++ }
++
++ if (preset<0 || preset>4) {
++ fprintf(stderr,"Invalid default preset value (%d) ignored.\n", preset);
++ fprintf(stderr," (Valid values: 1, 2, 3, 4)\n");
++
++ preset = 0;
++ }
++
++ if (waitsec < 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 */
++ if (rwcolor) allocMode = AM_READWRITE;
++
++ if (perfect) colorMapMode = CM_PERFECT;
++ if (owncmap) colorMapMode = CM_OWNCMAP;
++ if (stdcmap) colorMapMode = CM_STDCMAP;
++
++ defaultCmapMode = colorMapMode; /* default mode for 8-bit images */
++
++ if (nopos) {
++ maingeom = infogeom = ctrlgeom = gamgeom = browgeom = textgeom = NULL;
++ cmtgeom = NULL;
++ }
++
++ /* if -root and -maxp, disallow 'integer' tiling modes */
++ if (useroot && fixedaspect && automax && !rmodeset &&
++ (rootMode == RM_TILE || rootMode == RM_IMIRROR))
++ rootMode = RM_CSOLID;
++}
++
++
++
++
++/***********************************/
++static int cpos = 0;
++static void printoption(st)
++ char *st;
++{
++ if (strlen(st) + cpos > 78) {
++ fprintf(stderr,"\n ");
++ cpos = 3;
++ }
++
++ fprintf(stderr,"%s ",st);
++ cpos = cpos + strlen(st) + 1;
++}
++
++static void cmdSyntax()
++{
++ fprintf(stderr, "Usage:\n");
++ printoption(cmd);
++ printoption("[-]");
++ printoption("[-/+24]");
++ printoption("[-/+2xlimit]");
++ printoption("[-/+4x3]");
++ printoption("[-/+8]");
++ printoption("[-/+acrop]");
++ printoption("[-aspect w:h]");
++ printoption("[-best24]");
++ printoption("[-bg color]");
++ printoption("[-black color]");
++ printoption("[-bw width]");
++ printoption("[-/+cecmap]");
++ printoption("[-cegeometry geom]");
++ printoption("[-/+cemap]");
++ printoption("[-cgamma rval gval bval]");
++ printoption("[-cgeometry geom]");
++ printoption("[-/+clear]");
++ printoption("[-/+close]");
++ printoption("[-/+cmap]");
++ printoption("[-cmtgeometry geom]");
++ printoption("[-/+cmtmap]");
++ printoption("[-crop x y w h]");
++ printoption("[-cursor char#]");
++
++#ifndef VMS
++ printoption("[-DEBUG level]");
++#else
++ printoption("[-debug level]");
++#endif
++
++ printoption("[-dir directory]");
++ printoption("[-display disp]");
++ printoption("[-/+dither]");
++ printoption("[-drift dx dy]");
++ printoption("[-expand exp | hexp:vexp]");
++ printoption("[-fg color]");
++ printoption("[-/+fixed]");
++ printoption("[-flist fname]");
++ printoption("[-gamma val]");
++ printoption("[-geometry geom]");
++ printoption("[-grabdelay seconds]");
++ printoption("[-gsdev str]");
++ printoption("[-gsgeom geom]");
++ printoption("[-gsres int]");
++ printoption("[-help]");
++ printoption("[-/+hflip]");
++ printoption("[-hi color]");
++ printoption("[-/+hist]");
++ printoption("[-/+hsv]");
++ printoption("[-icgeometry geom]");
++ printoption("[-/+iconic]");
++ printoption("[-igeometry geom]");
++ printoption("[-/+imap]");
++ printoption("[-/+lbrowse]");
++ printoption("[-lo color]");
++ printoption("[-/+loadclear]");
++ printoption("[-/+max]");
++ printoption("[-/+maxpect]");
++ printoption("[-mfn font]");
++ printoption("[-/+mono]");
++ printoption("[-name str]");
++ printoption("[-ncols #]");
++ printoption("[-/+ninstall]");
++ printoption("[-/+nodecor]");
++ printoption("[-/+nofreecols]");
++ printoption("[-/+nolimits]");
++ printoption("[-/+nopos]");
++ printoption("[-/+noqcheck]");
++ printoption("[-/+noresetroot]");
++ printoption("[-/+norm]");
++ printoption("[-/+nostat]");
++ printoption("[-/+owncmap]");
++ printoption("[-/+perfect]");
++ printoption("[-/+pkludge]");
++ printoption("[-/+poll]");
++ printoption("[-preset #]");
++ printoption("[-quick24]");
++ printoption("[-/+quit]");
++ printoption("[-/+random]");
++ printoption("[-/+raw]");
++ printoption("[-rbg color]");
++ printoption("[-rfg color]");
++ printoption("[-/+rgb]");
++ printoption("[-RM]");
++ printoption("[-rmode #]");
++ printoption("[-/+root]");
++ printoption("[-rotate deg]");
++ printoption("[-/+rv]");
++ printoption("[-/+rw]");
++ printoption("[-slow24]");
++ printoption("[-/+smooth]");
++ printoption("[-/+stdcmap]");
++ printoption("[-tgeometry geom]");
++ printoption("[-/+vflip]");
++ printoption("[-/+viewonly]");
++ printoption("[-visual type]");
++ printoption("[-/+vsdisable]");
++ printoption("[-vsgeometry geom]");
++ printoption("[-/+vsmap]");
++ printoption("[-/+vsperfect]");
++ printoption("[-wait seconds]");
++ printoption("[-white color]");
++ printoption("[-/+wloop]");
++ printoption("[filename ...]");
++ fprintf(stderr,"\n\n");
++ Quit(1);
++}
++
++
++/***********************************/
++static void rmodeSyntax()
++{
++ fprintf(stderr,"%s: unknown root mode '%d'. Valid modes are:\n",
++ cmd, rootMode);
++ fprintf(stderr,"\t0: tiling\n");
++ fprintf(stderr,"\t1: integer tiling\n");
++ fprintf(stderr,"\t2: mirrored tiling\n");
++ fprintf(stderr,"\t3: integer mirrored tiling\n");
++ fprintf(stderr,"\t4: centered tiling\n");
++ fprintf(stderr,"\t5: centered on a solid background\n");
++ fprintf(stderr,"\t6: centered on a 'warp' background\n");
++ fprintf(stderr,"\t7: centered on a 'brick' background\n");
++ fprintf(stderr,"\t8: symmetrical tiling\n");
++ fprintf(stderr,"\t9: symmetrical mirrored tiling\n");
++ fprintf(stderr,"\n");
++ Quit(1);
++}
++
++
++/***********************************/
++static int argcmp(a1, a2, minlen, plusallowed, plusminus)
++ char *a1, *a2;
++ int minlen, plusallowed;
++ 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
++ be at least 'minlen'. Otherwise, return non-zero. plusminus set to '1'
++ if '-option', '0' if '+option' */
++
++ int i;
++
++ if ((strlen(a1) < (size_t) minlen) || (strlen(a2) < (size_t) minlen))
++ return 1;
++ if (strlen(a1) > strlen(a2)) return 1;
++
++ if (strncmp(a1+1, a2+1, strlen(a1)-1)) return 1;
++
++ if (a1[0]=='-' || (plusallowed && a1[0]=='+')) {
++ /* only set if we match */
++ *plusminus = (a1[0] == '-');
++ return 0;
++ }
++
++ return 1;
++}
++
++
++/***********************************/
++static int openPic(filenum)
++ int filenum;
++{
++ /* tries to load file #filenum (from 'namelist' list)
++ * returns 0 on failure (cleans up after itself)
++ * returns '-1' if caller should display DFLTPIC (shown as text)
++ * if successful, returns 1, creates mainW
++ *
++ * By the way, I'd just like to point out that this procedure has gotten
++ * *way* out of hand...
++ */
++
++ PICINFO pinfo;
++ int i,filetype,freename, frompipe, frompoll, fromint, killpage;
++ int oldeWIDE, oldeHIGH, oldpWIDE, oldpHIGH;
++ int oldCXOFF, oldCYOFF, oldCWIDE, oldCHIGH, wascropped;
++ char *tmp;
++ char *fullname, /* full name of the original file */
++ filename[512], /* full name of file to load (could be /tmp/xxx)*/
++ globnm[512]; /* globbed version of fullname of orig file */
++
++ xvbzero((char *) &pinfo, sizeof(PICINFO));
++
++ /* init important fields of pinfo */
++ pinfo.pic = (byte *) NULL;
++ pinfo.comment = (char *) NULL;
++ pinfo.numpages = 1;
++ pinfo.pagebname[0] = '\0';
++
++
++ normaspect = defaspect;
++ freename = dfltkludge = frompipe = frompoll = fromint = wascropped = 0;
++ oldpWIDE = oldpHIGH = oldCXOFF = oldCYOFF = oldCWIDE = oldCHIGH = 0;
++ oldeWIDE = eWIDE; oldeHIGH = eHIGH;
++ fullname = NULL;
++ killpage = 0;
++
++ WaitCursor();
++
++ SetISTR(ISTR_INFO,"");
++ SetISTR(ISTR_WARNING,"");
++
++
++ /* if we're not loading next or prev page in a multi-page doc, kill off
++ page files */
++ if (strlen(pageBaseName) && filenum!=OP_PAGEDN && filenum!=OP_PAGEUP)
++ killpage = 1;
++
++
++ if (strlen(pageBaseName) && (filenum==OP_PAGEDN || filenum==OP_PAGEUP)) {
++ if (filenum==OP_PAGEUP && curPage>0) curPage--;
++ else if (filenum==OP_PAGEDN && curPage<numPages-1) curPage++;
++ else {
++ XBell(theDisp, 0); /* hit either end */
++ SetCursors(-1);
++ return 0;
++ }
++
++ sprintf(filename, "%s%d", pageBaseName, curPage+1);
++ fullname = filename;
++ goto HAVE_FILENAME;
++ }
++
++
++ if (filenum == DFLTPIC) {
++ filename[0] = '\0'; basefname[0] = '\0'; fullfname[0] = '\0';
++ fullname = "";
++ curname = -1; /* ??? */
++ LoadDfltPic(&pinfo);
++
++ if (killpage) { /* kill old page files, if any */
++ KillPageFiles(pageBaseName, numPages);
++ pageBaseName[0] = '\0';
++ numPages = 1;
++ curPage = 0;
++ }
++
++ goto GOTIMAGE;
++ }
++ else if (filenum == GRABBED) {
++ filename[0] = '\0'; basefname[0] = '\0'; fullfname[0] = '\0';
++ fullname = "";
++ i = LoadGrab(&pinfo);
++ if (!i) goto FAILED; /* shouldn't happen */
++
++ if (killpage) { /* kill old page files, if any */
++ KillPageFiles(pageBaseName, numPages);
++ pageBaseName[0] = '\0';
++ numPages = 1;
++ curPage = 0;
++ }
++
++ goto GOTIMAGE;
++ }
++
++ else if (filenum == PADDED) {
++ /* need fullfname (used for window/icon name),
++ basefname(compute from fullfname) */
++
++ i = LoadPad(&pinfo, fullfname);
++ fullname = fullfname;
++ strcpy(filename, fullfname);
++ tmp = BaseName(fullfname);
++ strcpy(basefname, tmp);
++
++ if (!i) goto FAILED; /* shouldn't happen */
++
++ if (killpage) { /* kill old page files, if any */
++ KillPageFiles(pageBaseName, numPages);
++ pageBaseName[0] = '\0';
++ numPages = 1;
++ curPage = 0;
++ }
++
++ goto GOTIMAGE;
++ }
++
++
++ if (filenum == POLLED) {
++ frompoll = 1;
++ oldpWIDE = pWIDE; oldpHIGH = pHIGH;
++ wascropped = (cWIDE!=pWIDE || cHIGH!=pHIGH);
++ oldCXOFF = cXOFF; oldCYOFF = cYOFF; oldCWIDE = cWIDE; oldCHIGH = cHIGH;
++ filenum = curname;
++ }
++
++ if (filenum == RELOAD) {
++ fromint = 1;
++ filenum = nList.selected;
++ }
++
++ if (filenum != LOADPIC) {
++ if (filenum >= nList.nstr || filenum < 0) goto FAILED;
++ curname = filenum;
++ nList.selected = curname;
++ ScrollToCurrent(&nList); /* have scrl/list show current */
++ XFlush(theDisp); /* update NOW */
++ }
++
++
++
++ /* set up fullname and basefname */
++
++ if (filenum == LOADPIC) {
++ fullname = GetDirFullName();
++
++ if (ISPIPE(fullname[0])) { /* read from a pipe. */
++ strcpy(filename, fullname);
++ if (readpipe(fullname, filename)) goto FAILED;
++ frompipe = 1;
++ }
++ }
++ else fullname = namelist[filenum];
++
++
++ strcpy(fullfname, fullname);
++ tmp = BaseName(fullname);
++ strcpy(basefname, tmp);
++
++
++ /* chop off trailing ".Z", ".z", or ".gz" from displayed basefname, if any */
++ if (strlen(basefname) > (size_t) 2 &&
++ strcmp(basefname+strlen(basefname)-2,".Z")==0)
++ basefname[strlen(basefname)-2]='\0';
++ else {
++#ifdef GUNZIP
++ if (strlen(basefname)>2 && strcmp(basefname+strlen(basefname)-2,".Z")==0)
++ basefname[strlen(basefname)-2]='\0';
++
++ else if (strlen(basefname)>3 &&
++ strcmp(basefname+strlen(basefname)-3,".gz")==0)
++ basefname[strlen(basefname)-3]='\0';
++#endif /* GUNZIP */
++ }
++
++
++ if (filenum == LOADPIC && ISPIPE(fullname[0])) {
++ /* if we're reading from a pipe, 'filename' will have the /tmp/xvXXXXXX
++ filename, and we can skip a lot of stuff: (such as prepending
++ 'initdir' to relative paths, dealing with reading from stdin, etc. */
++
++ /* at this point, fullname = "! do some commands",
++ filename = "/tmp/xv123456",
++ and basefname= "xv123456" */
++ }
++
++ else { /* NOT reading from a PIPE */
++
++ /* if fullname doesn't start with a '/' (ie, it's a relative path),
++ (and it's not LOADPIC and it's not the special case '<stdin>')
++ then we need to prepend a directory name to it:
++
++ prepend 'initdir',
++ if we have a searchdir (ie, we have multiple places to look),
++ see if such a file exists (via fopen()),
++ if it does, we're done.
++ if it doesn't, and we have a searchdir, try prepending searchdir
++ and see if file exists.
++ if it does, we're done.
++ if it doesn't, remove all prepended directories, and fall through
++ to error code below. */
++
++ if (filenum!=LOADPIC && fullname[0]!='/' && strcmp(fullname,STDINSTR)!=0) {
++ char *tmp1;
++
++ /* stick 'initdir ' onto front of filename */
++
++#ifndef VMS
++ tmp1 = (char *) malloc(strlen(fullname) + strlen(initdir) + 2);
++ if (!tmp1) FatalError("malloc 'filename' failed");
++ sprintf(tmp1,"%s/%s", initdir, fullname);
++#else /* it is VMS */
++ tmp1 = (char *) malloc(strlen(fullname) + 2);
++ if (!tmp1) FatalError("malloc 'filename' failed");
++ sprintf(tmp1,"%s", fullname);
++#endif
++
++ if (!strlen(searchdir)) { /* no searchdir, don't check */
++ fullname = tmp1;
++ freename = 1;
++ }
++ else { /* see if said file exists */
++ FILE *fp;
++ fp = fopen(tmp1, "r");
++ if (fp) { /* initpath/fullname exists */
++ fclose(fp);
++ fullname = tmp1;
++ freename = 1;
++ }
++ else { /* doesn't: try searchdir */
++ free(tmp1);
++#ifndef VMS
++ tmp1 = (char *) malloc(strlen(fullname) + strlen(searchdir) + 2);
++ if (!tmp1) FatalError("malloc 'filename' failed");
++ sprintf(tmp1,"%s/%s", searchdir, fullname);
++#else /* it is VMS */
++ tmp1 = (char *) malloc(strlen(fullname) + 2);
++ if (!tmp1) FatalError("malloc 'filename' failed");
++ sprintf(tmp1,"%s", fullname);
++#endif
++
++ fp = fopen(tmp1, "r");
++ if (fp) { /* searchpath/fullname exists */
++ fclose(fp);
++ fullname = tmp1;
++ freename = 1;
++ }
++ else free(tmp1); /* doesn't exist either... */
++ }
++ }
++ }
++
++ strcpy(filename, fullname);
++
++
++ /* if the file is STDIN, write it out to a temp file */
++
++ if (strcmp(filename,STDINSTR)==0) {
++ FILE *fp;
++
++#ifndef VMS
++ sprintf(filename,"%s/xvXXXXXX",tmpdir);
++#else /* it is VMS */
++ sprintf(filename, "[]xvXXXXXX");
++#endif
++ mktemp(filename);
++
++ clearerr(stdin);
++ fp = fopen(filename,"w");
++ if (!fp) FatalError("openPic(): can't write temporary file");
++
++ while ( (i=getchar()) != EOF) putc(i,fp);
++ fclose(fp);
++
++ /* and remove it from list, since we can never reload from stdin */
++ if (strcmp(namelist[0], STDINSTR)==0) deleteFromList(0);
++ }
++ }
++
++
++
++ HAVE_FILENAME:
++
++ /******* AT THIS POINT 'filename' is the name of an actual data file
++ (no pipes or stdin, though it could be compressed) to be loaded */
++ filetype = ReadFileType(filename);
++
++
++ if (filetype == RFT_COMPRESS) { /* a compressed file. uncompress it */
++ char tmpname[128];
++
++ if (
++#ifndef VMS
++ UncompressFile(filename, tmpname)
++#else
++ UncompressFile(basefname, tmpname)
++#endif
++ ) {
++
++ filetype = ReadFileType(tmpname); /* and try again */
++
++ /* if we made a /tmp file (from stdin, etc.) won't need it any more */
++ if (strcmp(fullname,filename)!=0) unlink(filename);
++
++ strcpy(filename, tmpname);
++ }
++ else filetype = RFT_ERROR;
++
++ WaitCursor();
++ }
++
++
++ if (filetype == RFT_ERROR) {
++ char foostr[512];
++ sprintf(foostr,"Can't open file '%s'\n\n %s.",filename, ERRSTR(errno));
++
++ if (!polling) ErrPopUp(foostr, "\nBummer!");
++
++ goto FAILED; /* couldn't get magic#, screw it! */
++ }
++
++
++ if (filetype == RFT_UNKNOWN) {
++ /* view as a text/hex file */
++ TextView(filename);
++ SetISTR(ISTR_INFO,"'%s' not in a recognized format.", basefname);
++ /* Warning(); */
++ goto SHOWN_AS_TEXT;
++ }
++
++ if (filetype < RFT_ERROR) {
++ SetISTR(ISTR_INFO,"'%s' not in a readable format.", basefname);
++ Warning();
++ goto FAILED;
++ }
++
++
++ /****** AT THIS POINT: the filetype is a known, readable format */
++
++ /* kill old page files, if any */
++ if (killpage) {
++ KillPageFiles(pageBaseName, numPages);
++ pageBaseName[0] = '\0';
++ numPages = 1;
++ curPage = 0;
++ }
++
++
++ SetISTR(ISTR_INFO,"Loading...");
++
++ i = ReadPicFile(filename, filetype, &pinfo, 0);
++
++ if (filetype == RFT_XBM && (!i || pinfo.w==0 || pinfo.h==0)) {
++ /* probably just a '.h' file or something... */
++ SetISTR(ISTR_INFO," ");
++ TextView(filename);
++ goto SHOWN_AS_TEXT;
++ }
++
++ if (!i) {
++ SetISTR(ISTR_INFO,"Couldn't load file '%s'.",filename);
++ Warning();
++ goto FAILED;
++ }
++
++
++
++ WaitCursor();
++
++ if (pinfo.w==0 || pinfo.h==0) { /* shouldn't happen, but let's be safe */
++ SetISTR(ISTR_INFO,"Image size '0x0' not allowed.");
++ Warning();
++ if (pinfo.pic) free(pinfo.pic); pinfo.pic = (byte *) NULL;
++ if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL;
++ goto FAILED;
++ }
++
++
++ /**************/
++ /* SUCCESS!!! */
++ /**************/
++
++
++ GOTIMAGE:
++ /* successfully read this picture. No failures from here on out
++ (well, once the pic has been converted if we're locked in a mode) */
++
++
++ state824 = 0;
++
++ /* if we're locked into a mode, do appropriate conversion */
++ if (conv24MB.flags[CONV24_LOCK]) { /* locked */
++ if (pinfo.type==PIC24 && picType==PIC8) { /* 24 -> 8 bit */
++ byte *pic8;
++ pic8 = Conv24to8(pinfo.pic, pinfo.w, pinfo.h, ncols,
++ pinfo.r, pinfo.g, pinfo.b);
++ free(pinfo.pic);
++ pinfo.pic = pic8;
++ pinfo.type = PIC8;
++
++ state824 = 1;
++ }
++
++ else if (pinfo.type!=PIC24 && picType==PIC24) { /* 8 -> 24 bit */
++ byte *pic24;
++ pic24 = Conv8to24(pinfo.pic, pinfo.w, pinfo.h,
++ pinfo.r, pinfo.g, pinfo.b);
++ free(pinfo.pic);
++ pinfo.pic = pic24;
++ pinfo.type = PIC24;
++ }
++ }
++ else { /* not locked. switch 8/24 mode */
++ picType = pinfo.type;
++ Set824Menus(picType);
++ }
++
++
++ if (!pinfo.pic) { /* must've failed in the 8-24 or 24-8 conversion */
++ SetISTR(ISTR_INFO,"Couldn't do %s conversion.",
++ (picType==PIC24) ? "8->24" : "24->8");
++ if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL;
++ Warning();
++ goto FAILED;
++ }
++
++
++
++ /* ABSOLUTELY no failures from here on out... */
++
++
++ if (strlen(pinfo.pagebname)) {
++ strcpy(pageBaseName, pinfo.pagebname);
++ numPages = pinfo.numpages;
++ curPage = 0;
++ }
++
++ ignoreConfigs = 1;
++
++ if (mainW && !useroot) {
++ /* avoid generating excess configure events while we resize the window */
++ XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
++ | StructureNotifyMask
++ | ButtonPressMask | KeyReleaseMask
++ | EnterWindowMask | LeaveWindowMask);
++ XFlush(theDisp);
++ }
++
++ /* kill off OLD picture, now that we've succesfully loaded a new one */
++ KillOldPics();
++ SetInfoMode(INF_STR);
++
++
++ /* get info out of the PICINFO struct */
++ pic = pinfo.pic;
++ pWIDE = pinfo.w;
++ pHIGH = pinfo.h;
++ if (pinfo.frmType >=0) SetDirSaveMode(F_FORMAT, pinfo.frmType);
++ if (pinfo.colType >=0) SetDirSaveMode(F_COLORS, pinfo.colType);
++
++ SetISTR(ISTR_FORMAT, pinfo.fullInfo);
++ strcpy(formatStr, pinfo.shrtInfo);
++ picComments = pinfo.comment;
++ ChangeCommentText();
++
++ for (i=0; i<256; i++) {
++ rMap[i] = pinfo.r[i];
++ gMap[i] = pinfo.g[i];
++ bMap[i] = pinfo.b[i];
++ }
++
++
++
++ AlgInit();
++
++ /* stick this file in the 'ctrlW' name list */
++ if (filenum == LOADPIC && !frompipe) StickInCtrlList(1);
++
++ if (polling && !frompoll) InitPoll();
++
++ /* turn off 'frompoll' if the pic has changed size */
++ if (frompoll && (pWIDE != oldpWIDE || pHIGH != oldpHIGH)) frompoll = 0;
++
++
++ if (!browseCB.val && filenum == LOADPIC) DirBox(0); /* close the DirBox */
++
++
++ /* if we read a /tmp file, delete it. won't be needing it any more */
++ if (fullname && strcmp(fullname,filename)!=0) unlink(filename);
++
++
++ SetISTR(ISTR_INFO,formatStr);
++
++ SetInfoMode(INF_PART);
++ SetISTR(ISTR_FILENAME,
++ (filenum==DFLTPIC || filenum==GRABBED || frompipe)
++ ? "<none>" : basefname);
++
++ SetISTR(ISTR_RES,"%d x %d",pWIDE,pHIGH);
++ SetISTR(ISTR_COLOR, "");
++ SetISTR(ISTR_COLOR2,"");
++
++ /* adjust button in/activity */
++ if (HaveSelection()) EnableSelection(0);
++ SetSelectionString();
++ BTSetActive(&but[BCROP], 0);
++ BTSetActive(&but[BUNCROP], 0);
++ BTSetActive(&but[BCUT], 0);
++ BTSetActive(&but[BCOPY], 0);
++ BTSetActive(&but[BCLEAR], 0);
++
++ ActivePrevNext();
++
++
++
++ /* handle various 'auto-whatever' command line options
++ Note that if 'frompoll' is set, things that have to do with
++ setting the expansion factor are skipped, as we'll want it to
++ display in the (already-existing) window at the same size */
++
++
++ if (frompoll) {
++ cpic = pic; cWIDE = pWIDE; cHIGH = pHIGH; cXOFF = cYOFF = 0;
++ FreeEpic();
++ if (wascropped) DoCrop(oldCXOFF, oldCYOFF, oldCWIDE, oldCHIGH);
++ FreeEpic(); eWIDE = oldeWIDE; eHIGH = oldeHIGH;
++ SetCropString();
++ }
++ else {
++ int w,h,aspWIDE,aspHIGH,oldemode;
++
++ oldemode = epicMode;
++ epicMode = EM_RAW; /* be in raw mode for all intermediate conversions */
++ cpic = pic; cWIDE = pWIDE; cHIGH = pHIGH; cXOFF = cYOFF = 0;
++ epic = cpic; eWIDE = cWIDE; eHIGH = cHIGH;
++
++ SetCropString();
++
++ /*****************************************/
++ /* handle aspect options: -aspect, -4x3 */
++ /*****************************************/
++
++ if (normaspect != 1.0) { /* -aspect */
++ FixAspect(1, &w, &h);
++ eWIDE = w; eHIGH = h;
++ }
++
++ if (auto4x3) {
++ w = eWIDE; h = (w*3) / 4;
++ eWIDE = w; eHIGH = h;
++ }
++
++
++ if (eWIDE != cWIDE || eHIGH != cHIGH) epic = (byte *) NULL;
++
++ /**************************************/
++ /* handle cropping (-acrop and -crop) */
++ /**************************************/
++
++ if (autocrop) DoAutoCrop();
++ if (acrop) DoCrop(acropX, acropY, acropW, acropH);
++
++ if (eWIDE != cWIDE || eHIGH != cHIGH) epic = (byte *) NULL;
++
++ /********************************/
++ /* handle rotation and flipping */
++ /********************************/
++
++ if (autorotate) {
++ /* figure out optimal rotation. (ie, instead of +270, do -90) */
++ if (autorotate == 270) autorotate = -90;
++ else if (autorotate == -270) autorotate = 90;
++
++ i = autorotate;
++ while (i) {
++ if (i < 0) { /* rotate CW */
++ DoRotate(0);
++ i += 90;
++ }
++ else { /* rotate CCW */
++ DoRotate(1);
++ i -= 90;
++ }
++ }
++ }
++
++ if (autohflip) Flip(0); /* horizontal flip */
++ if (autovflip) Flip(1); /* vertical flip */
++
++
++ /********************************************/
++ /* handle expansion options: */
++ /* -expand, -max, -maxpect, -fixed, -geom */
++ /********************************************/
++
++ /* at this point, treat whatever eWIDE,eHIGH is as 1x1 expansion,
++ (due to earlier aspect-ratio option handling). Note that
++ all that goes on here is that eWIDE/eHIGH are modified. No
++ images are generated. */
++
++ aspWIDE = eWIDE; aspHIGH = eHIGH; /* aspect-corrected eWIDE,eHIGH */
++
++ if (hexpand < 0.0) eWIDE=(int)(aspWIDE / -hexpand); /* neg: reciprocal */
++ else eWIDE=(int)(aspWIDE * hexpand);
++ if (vexpand < 0.0) eHIGH=(int)(aspHIGH / -vexpand); /* neg: reciprocal */
++ else eHIGH=(int)(aspHIGH * vexpand);
++
++ if (maingeom) {
++ /* deal with geometry spec. Note, they shouldn't have given us
++ *both* an expansion factor and a geomsize. The geomsize wins out */
++
++ int i,x,y,gewide,gehigh; u_int w,h;
++
++ gewide = eWIDE; gehigh = eHIGH;
++ i = XParseGeometry(maingeom,&x,&y,&w,&h);
++
++ if (i&WidthValue) gewide = (int) w;
++ if (i&HeightValue) gehigh = (int) h;
++
++ /* handle case where the pinheads only specified width *or * height */
++ if (( i&WidthValue && ~i&HeightValue) ||
++ (~i&WidthValue && i&HeightValue)) {
++
++ if (i&WidthValue) { gehigh = (aspHIGH * gewide) / pWIDE; }
++ else { gewide = (aspWIDE * gehigh) / pHIGH; }
++ }
++
++ /* specified a 'maximum size, but please keep your aspect ratio */
++ if (fixedaspect && i&WidthValue && i&HeightValue) {
++ if (aspWIDE > gewide || aspHIGH > gehigh) {
++ /* shrink aspWIDE,HIGH accordingly... */
++ double r,wr,hr;
++
++ wr = ((double) aspWIDE) / gewide;
++ hr = ((double) aspHIGH) / gehigh;
++
++ r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */
++ aspWIDE = (int) ((aspWIDE / r) + 0.5);
++ aspHIGH = (int) ((aspHIGH / r) + 0.5);
++ }
++
++ /* image is now definitely no larger than gewide,gehigh */
++ /* should now expand it so that one axis is of specified size */
++
++ if (aspWIDE != gewide && aspHIGH != gehigh) { /* is smaller */
++ /* grow aspWIDE,HIGH accordingly... */
++ double r,wr,hr;
++
++ wr = ((double) aspWIDE) / gewide;
++ hr = ((double) aspHIGH) / gehigh;
++
++ r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */
++ aspWIDE = (int) ((aspWIDE / r) + 0.5);
++ aspHIGH = (int) ((aspHIGH / r) + 0.5);
++
++ }
++
++ eWIDE = aspWIDE; eHIGH = aspHIGH;
++ }
++ else { eWIDE = gewide; eHIGH = gehigh; }
++ }
++
++
++ if (automax) { /* -max and -maxpect */
++ eWIDE = dispWIDE; eHIGH = dispHIGH;
++ if (fixedaspect) FixAspect(0,&eWIDE,&eHIGH);
++ }
++
++
++ /* now, just make sure that eWIDE/eHIGH aren't too big... */
++ /* shrink eWIDE,eHIGH preserving aspect ratio, if so... */
++ if (eWIDE>maxWIDE || eHIGH>maxHIGH) {
++ /* the numbers here can get big. use floats */
++ double r,wr,hr;
++
++ wr = ((double) eWIDE) / maxWIDE;
++ hr = ((double) eHIGH) / maxHIGH;
++
++ r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */
++ eWIDE = (int) ((eWIDE / r) + 0.5);
++ eHIGH = (int) ((eHIGH / r) + 0.5);
++ }
++
++ if (eWIDE < 1) eWIDE = 1; /* just to be safe... */
++ if (eHIGH < 1) eHIGH = 1;
++
++ /* if we're using an integer tiled root mode, truncate eWIDE/eHIGH to
++ be an integer divisor of the display size */
++
++ if (useroot && (rootMode == RM_TILE || rootMode == RM_IMIRROR)) {
++ /* make picture size a divisor of the rootW size. round down */
++ i = (dispWIDE + eWIDE-1) / eWIDE; eWIDE = (dispWIDE + i-1) / i;
++ i = (dispHIGH + eHIGH-1) / eHIGH; eHIGH = (dispHIGH + i-1) / i;
++ }
++
++
++ if (eWIDE != cWIDE || eHIGH != cHIGH) epic = (byte *) NULL;
++
++ /********************************************/
++ /* handle epic generation options: */
++ /* -raw, -dith, -smooth */
++ /********************************************/
++
++ 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 -smooth or image has been shrunk to fit screen */
++ if (autosmooth || (pWIDE >maxWIDE || pHIGH>maxHIGH)
++ || (cWIDE != eWIDE || cHIGH != eHIGH)) epicMode = EM_SMOOTH;
++
++ if (autoraw) epicMode = EM_RAW;
++
++ /* 'dithering' makes no sense in 24-bit mode */
++ if (picType == PIC24 && epicMode == EM_DITH) epicMode = EM_RAW;
++
++ SetEpicMode();
++ } /* end of !frompoll */
++
++
++
++ /* at this point eWIDE,eHIGH are correct, but a proper epic (particularly
++ if in DITH or SMOOTH mode) doesn't exist yet. Will be made once the
++ colors have been picked. */
++
++
++
++ /* clear old image (window/root) before we start changing colors... */
++ if (CMAPVIS(theVisual) && clearonload && picType == PIC8 &&
++ colorMapMode != CM_STDCMAP) {
++
++ if (mainW && !useroot) {
++ XClearArea(theDisp, mainW, 0,0, (u_int)oldeWIDE, (u_int)oldeHIGH, True);
++ XFlush(theDisp);
++ }
++
++ if (useroot) {
++ mainW = vrootW;
++ ClearRoot();
++ }
++ }
++
++
++ if (useroot) mainW = vrootW;
++ if (eWIDE != cWIDE || eHIGH != cHIGH) epic = (byte *) NULL;
++
++ NewPicGetColors(autonorm, autohisteq);
++
++ GenerateEpic(eWIDE, eHIGH); /* want to dither *after* color allocs */
++ CreateXImage();
++
++ WaitCursor();
++ HandleDispMode(); /* create root pic, or mainW, depending... */
++
++
++ if (LocalCmap) {
++ XSetWindowAttributes xswa;
++ xswa.colormap = LocalCmap;
++
++ if (!ninstall) XInstallColormap(theDisp,LocalCmap);
++ XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
++ if (cmapInGam) XChangeWindowAttributes(theDisp,gamW,CWColormap,&xswa);
++ }
++
++
++
++ tmp = GetISTR(ISTR_COLOR);
++ SetISTR(ISTR_INFO,"%s %s %s", formatStr,
++ (picType==PIC8) ? "8-bit mode." : "24-bit mode.",
++ tmp);
++
++ SetInfoMode(INF_FULL);
++ if (freename) free(fullname);
++
++
++ SetCursors(-1);
++
++
++ if (dirUp!=BLOAD) {
++ /* put current filename into the 'save-as' filename */
++ if (strcmp(filename,STDINSTR)==0) SetDirFName("stdin");
++ else if (frompipe || filenum == LOADPIC || filenum == GRABBED ||
++ filenum == DFLTPIC || filenum == PADDED) {} /* leave it alone */
++ else SetDirFName(basefname);
++ }
++
++
++ /* force a redraw of the whole window, as I can't quite trust Config's
++ to generate the correct exposes (particularly with 'BitGravity' turned
++ on */
++
++ if (mainW && !useroot) GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
++
++ return 1;
++
++
++ FAILED:
++ SetCursors(-1);
++ KillPageFiles(pinfo.pagebname, pinfo.numpages);
++
++ if (fullname && strcmp(fullname,filename)!=0)
++ unlink(filename); /* kill /tmp file */
++ if (freename) free(fullname);
++
++ if (!fromint && !polling && filenum>=0 && filenum<nList.nstr)
++ deleteFromList(filenum);
++
++ if (polling) sleep(1);
++
++ return 0;
++
++
++ SHOWN_AS_TEXT: /* file wasn't in recognized format... */
++ SetCursors(-1);
++
++ if (strcmp(fullname,filename)!=0) unlink(filename); /* kill /tmp file */
++ if (freename) free(fullname);
++
++ ActivePrevNext();
++ return 1; /* we've displayed the file 'ok' */
++}
++
++
++
++/********************************/
++int ReadFileType(fname)
++ char *fname;
++{
++ /* opens fname (which *better* be an actual file by this point!) and
++ reads the first couple o' bytes. Figures out what the file's likely
++ to be, and returns the appropriate RFT_*** code */
++
++
++ FILE *fp;
++ byte magicno[30]; /* first 30 bytes of file */
++ int rv, n;
++
++ if (!fname) return RFT_ERROR; /* shouldn't happen */
++
++ fp = xv_fopen(fname, "r");
++ if (!fp) return RFT_ERROR;
++
++ 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 (strncmp((char *) magicno,"GIF87a", (size_t) 6)==0 ||
++ 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;
++
++ else if (magicno[0] == 'P' && magicno[1]>='1' &&
++ magicno[1]<='6') 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;
++
++ else if (magicno[0]==0x59 && (magicno[1]&0x7f)==0x26 &&
++ 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]==0x52 && magicno[1]==0xcc) rv = RFT_UTAHRLE;
++
++ else if ((magicno[0]==0x01 && magicno[1]==0xda) ||
++ (magicno[0]==0xda && magicno[1]==0x01)) rv = RFT_IRIS;
++
++ else if (magicno[0]==0x1f && magicno[1]==0x9d) rv = RFT_COMPRESS;
++
++#ifdef GUNZIP
++ else if (magicno[0]==0x1f && magicno[1]==0x8b) rv = RFT_COMPRESS;
++#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;
++
++ 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;
++
++ else if (magicno[4]==0x00 && magicno[5]==0x00 &&
++ 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;
++
++
++#ifdef HAVE_JPEG
++ else if (magicno[0]==0xff && magicno[1]==0xd8 &&
++ 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;
++#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
++ else if (strncmp((char *) magicno, "NJPL1I00", (size_t) 8)==0 ||
++ strncmp((char *) magicno+2,"NJPL1I", (size_t) 6)==0 ||
++ strncmp((char *) magicno, "CCSD3ZF", (size_t) 7)==0 ||
++ strncmp((char *) magicno+2,"CCSD3Z", (size_t) 6)==0 ||
++ strncmp((char *) magicno, "LBLSIZE=", (size_t) 8)==0)
++ rv = RFT_PDSVICAR;
++#endif
++
++#ifdef GS_PATH
++ else if (strncmp((char *) magicno, "%!", (size_t) 2)==0 ||
++ strncmp((char *) magicno, "\004%!", (size_t) 3)==0) rv = RFT_PS;
++#endif
++
++#ifdef GS_PATH
++ else if (strncmp((char *) magicno, "%PDF", (size_t) 4)==0) rv = RFT_PS;
++#endif
++
++ return rv;
++}
++
++
++
++/********************************/
++int ReadPicFile(fname, ftype, pinfo, quick)
++ char *fname;
++ int ftype, quick;
++ 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 */
++
++ int rv = 0;
++
++ /* by default, most formats aren't multi-page */
++ pinfo->numpages = 1;
++ pinfo->pagebname[0] = '\0';
++
++ switch (ftype) {
++ case RFT_GIF: rv = LoadGIF (fname, pinfo); break;
++ case RFT_PM: rv = LoadPM (fname, pinfo); break;
++ case RFT_PBM: rv = LoadPBM (fname, pinfo); break;
++ case RFT_XBM: rv = LoadXBM (fname, pinfo); break;
++ case RFT_SUNRAS: rv = LoadSunRas(fname, pinfo); break;
++ case RFT_BMP: rv = LoadBMP (fname, pinfo); break;
++ case RFT_UTAHRLE: rv = LoadRLE (fname, pinfo); break;
++ case RFT_IRIS: rv = LoadIRIS (fname, pinfo); break;
++ case RFT_PCX: rv = LoadPCX (fname, pinfo); break;
++ case RFT_IFF: rv = LoadIFF (fname, pinfo); break;
++ case RFT_TARGA: rv = LoadTarga (fname, pinfo); break;
++ 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;
++
++#ifdef HAVE_JPEG
++ case RFT_JFIF: rv = LoadJFIF (fname, pinfo, quick); break;
++#endif
++
++#ifdef HAVE_TIFF
++ case RFT_TIFF: rv = LoadTIFF (fname, pinfo); 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;
++#endif
++
++#ifdef GS_PATH
++ case RFT_PS: rv = LoadPS (fname, pinfo, quick); break;
++#endif
++
++ }
++ return rv;
++}
++
++
++/********************************/
++int UncompressFile(name, uncompname)
++ char *name, *uncompname;
++{
++ /* returns '1' on success, with name of uncompressed file in uncompname
++ returns '0' on failure */
++
++ char namez[128], *fname, buf[512];
++
++ fname = name;
++ namez[0] = '\0';
++
++
++#if !defined(VMS) && !defined(GUNZIP)
++ /* see if compressed file name ends with '.Z'. If it *doesn't* we need
++ temporarily rename it so it *does*, uncompress it, and rename *back*
++ to what it was. necessary because uncompress doesn't handle files
++ that don't end with '.Z' */
++
++ if (strlen(name) >= (size_t) 2 &&
++ strcmp(name + strlen(name)-2,".Z")!=0 &&
++ strcmp(name + strlen(name)-2,".z")!=0) {
++ strcpy(namez, name);
++ strcat(namez,".Z");
++
++ if (rename(name, namez) < 0) {
++ sprintf(buf, "Error renaming '%s' to '%s': %s",
++ name, namez, ERRSTR(errno));
++ ErrPopUp(buf, "\nBummer!");
++ return 0;
++ }
++
++ fname = namez;
++ }
++#endif /* not VMS and not GUNZIP */
++
++
++
++#ifndef VMS
++ sprintf(uncompname, "%s/xvuXXXXXX", tmpdir);
++ mktemp(uncompname);
++ sprintf(buf,"%s -c %s >%s", UNCOMPRESS, fname, uncompname);
++#else /* it IS VMS */
++ strcpy(uncompname, "[]xvuXXXXXX");
++ mktemp(uncompname);
++# ifdef GUNZIP
++ sprintf(buf,"%s %s %s", UNCOMPRESS, fname, uncompname);
++# else
++ sprintf(buf,"%s %s", UNCOMPRESS, fname);
++# endif
++#endif
++
++ SetISTR(ISTR_INFO, "Uncompressing '%s'...", BaseName(fname));
++#ifndef VMS
++ if (system(buf)) {
++#else
++ if (!system(buf)) {
++#endif
++ SetISTR(ISTR_INFO, "Unable to uncompress '%s'.", BaseName(fname));
++ Warning();
++ return 0;
++ }
++
++#ifndef VMS
++ /* if we renamed the file to end with a .Z for the sake of 'uncompress',
++ rename it back to what it once was... */
++
++ if (strlen(namez)) {
++ if (rename(namez, name) < 0) {
++ sprintf(buf, "Error renaming '%s' to '%s': %s",
++ namez, name, ERRSTR(errno));
++ ErrPopUp(buf, "\nBummer!");
++ }
++ }
++#else
++ /*
++ sprintf(buf,"Rename %s %s", fname, uncompname);
++ SetISTR(ISTR_INFO,"Renaming '%s'...", fname);
++ if (!system(buf)) {
++ SetISTR(ISTR_INFO,"Unable to rename '%s'.", fname);
++ Warning();
++ return 0;
++ }
++ */
++#endif /* not VMS */
++
++ return 1;
++}
++
++
++/********************************/
++void KillPageFiles(bname, numpages)
++ char *bname;
++ int numpages;
++{
++ /* deletes any page files (numbered 1 through numpages) that might exist */
++ char tmp[128];
++ int i;
++
++ if (strlen(bname) == 0) return; /* no page files */
++
++ for (i=1; i<=numpages; i++) {
++ sprintf(tmp, "%s%d", bname, i);
++ unlink(tmp);
++ }
++}
++
++
++/********************************/
++void NewPicGetColors(donorm, dohist)
++ int donorm, dohist;
++{
++ int i;
++
++ /* some stuff that necessary whenever running an algorithm or
++ installing a new 'pic' (or switching 824 modes) */
++
++ numcols = 0; /* gets set by SortColormap: set to 0 for PIC24 images */
++ for (i=0; i<256; i++) cols[i]=infobg;
++
++ if (picType == PIC8) {
++ byte trans[256];
++ SortColormap(pic,pWIDE,pHIGH,&numcols,rMap,gMap,bMap,colAllocOrder,trans);
++ ColorCompress8(trans);
++ }
++
++ if (picType == PIC8) {
++ /* see if image is a b/w bitmap.
++ If so, use '-black' and '-white' colors */
++ if (numcols == 2) {
++ if ((rMap[0] == gMap[0] && rMap[0] == bMap[0] && rMap[0] == 255) &&
++ (rMap[1] == gMap[1] && rMap[1] == bMap[1] && rMap[1] == 0)) {
++ /* 0=wht, 1=blk */
++ rMap[0] = (whtRGB>>16)&0xff;
++ gMap[0] = (whtRGB>>8)&0xff;
++ bMap[0] = whtRGB&0xff;
++
++ rMap[1] = (blkRGB>>16)&0xff;
++ gMap[1] = (blkRGB>>8)&0xff;
++ bMap[1] = blkRGB&0xff;
++ }
++
++ else if ((rMap[0] == gMap[0] && rMap[0] == bMap[0] && rMap[0] == 0) &&
++ (rMap[1] == gMap[1] && rMap[1] == bMap[1] && rMap[1] == 255)) {
++ /*0=blk,1=wht*/
++ rMap[0] = (blkRGB>>16)&0xff;
++ gMap[0] = (blkRGB>>8)&0xff;
++ bMap[0] = blkRGB&0xff;
++
++ rMap[1] = (whtRGB>>16)&0xff;
++ gMap[1] = (whtRGB>>8)&0xff;
++ bMap[1]=whtRGB&0xff;
++ }
++ }
++ }
++
++
++ if (picType == PIC8) {
++ /* reverse image, if desired */
++ if (revvideo) {
++ for (i=0; i<numcols; i++) {
++ rMap[i] = 255 - rMap[i];
++ gMap[i] = 255 - gMap[i];
++ bMap[i] = 255 - bMap[i];
++ }
++ }
++
++ /* save the desired RGB colormap (before dicking with it) */
++ for (i=0; i<numcols; i++) {
++ rorg[i] = rcmap[i] = rMap[i];
++ gorg[i] = gcmap[i] = gMap[i];
++ borg[i] = bcmap[i] = bMap[i];
++ }
++ }
++
++ else if (picType == PIC24 && revvideo) {
++ if (pic) InvertPic24(pic, pWIDE, pHIGH);
++ if (cpic && cpic!=pic) InvertPic24(cpic, cWIDE, cHIGH);
++ if (epic && epic!=cpic) InvertPic24(epic, eWIDE, eHIGH);
++ if (egampic && egampic != epic) InvertPic24(egampic, eWIDE, eHIGH);
++ }
++
++
++ NewCMap();
++
++ if (donorm) DoNorm();
++ if (dohist) DoHistEq();
++
++ GammifyColors();
++
++ if (picType == PIC24) ChangeCmapMode(CM_STDCMAP, 0, 1);
++ else ChangeCmapMode(defaultCmapMode, 0, 1);
++
++ ChangeEC(0);
++}
++
++
++
++/***********************************/
++static int readpipe(cmd, fname)
++ char *cmd, *fname;
++{
++ /* cmd is something like: "! bggen 100 0 0"
++ *
++ * runs command (with "> /tmp/xv******" appended).
++ * returns "/tmp/xv******" in fname
++ * returns '0' if everything's cool, '1' on error
++ */
++
++ char fullcmd[512], tmpname[64], str[512];
++ int i;
++
++ if (!cmd || (strlen(cmd) < (size_t) 2)) return 1;
++
++ sprintf(tmpname,"%s/xvXXXXXX", tmpdir);
++ mktemp(tmpname);
++ if (tmpname[0] == '\0') { /* mktemp() blew up */
++ sprintf(str,"Unable to create temporary filename.");
++ ErrPopUp(str, "\nHow unlikely!");
++ return 1;
++ }
++
++ /* build command */
++ strcpy(fullcmd, cmd+1); /* skip the leading '!' character in cmd */
++ strcat(fullcmd, " > ");
++ strcat(fullcmd, tmpname);
++
++ /* execute the command */
++ sprintf(str, "Doing command: '%s'", fullcmd);
++ OpenAlert(str);
++ i = system(fullcmd);
++ if (i) {
++ sprintf(str, "Unable to complete command:\n %s\n\n exit status: %d",
++ fullcmd, i);
++ CloseAlert();
++ ErrPopUp(str, "\nThat Sucks!");
++ unlink(tmpname); /* just in case it was created */
++ return 1;
++ }
++
++ CloseAlert();
++ strcpy(fname, tmpname);
++ return 0;
++}
++
++
++
++
++
++
++/****************/
++static void openFirstPic()
++{
++ int i;
++
++ if (!numnames) { openPic(DFLTPIC); return; }
++
++ i = 0;
++ if (!randomShow) {
++ while (numnames>0) {
++ if (openPic(0)) return; /* success */
++ else {
++ if (polling && !i)
++ fprintf(stderr,"%s: POLLING: Waiting for file '%s' \n\tto %s\n",
++ cmd, namelist[0], "be created, or whatever...");
++ i = 1;
++ }
++ }
++ }
++
++ else { /* pick random first picture */
++ for (i=findRandomPic(); i>=0; i=findRandomPic())
++ if (openPic(i)) return; /* success */
++ }
++
++ if (numnames>1) FatalError("couldn't open any pictures");
++ else Quit(-1);
++}
++
++
++/****************/
++static void openNextPic()
++{
++ int i;
++
++ if (curname>=0) i = curname+1;
++ else if (nList.selected >= 0 && nList.selected < numnames)
++ i = nList.selected;
++ else i = 0;
++
++
++ while (i<numnames && !openPic(i));
++ if (i<numnames) return; /* success */
++
++ openPic(DFLTPIC);
++}
++
++
++/****************/
++static void openNextQuit()
++{
++ int i;
++
++ if (!randomShow) {
++ if (curname>=0) i = curname+1;
++ else if (nList.selected >= 0 && nList.selected < numnames)
++ i = nList.selected;
++ else i = 0;
++
++ while (i<numnames && !openPic(i));
++ if (i<numnames) return; /* success */
++ }
++ else {
++ for (i=findRandomPic(); i>=0; i=findRandomPic())
++ if (openPic(i)) return;
++ }
++
++ Quit(0);
++}
++
++
++/****************/
++static void openNextLoop()
++{
++ int i,j,loop;
++
++ j = loop = 0;
++ while (1) {
++ if (!randomShow) {
++
++ if (curname>=0) i = curname+1;
++ else if (nList.selected >= 0 && nList.selected < numnames)
++ i = nList.selected;
++ else i = 0;
++
++ if (loop) { i = 0; loop = 0; }
++
++ while (i<numnames && !openPic(i));
++ if (i<numnames) return;
++ }
++ else {
++ for (i=findRandomPic(); i>=0; i=findRandomPic())
++ if (openPic(i)) return;
++ }
++
++ loop = 1; /* back to top of list */
++ if (j) break; /* we're in a 'failure loop' */
++ j++;
++ }
++
++ openPic(DFLTPIC);
++}
++
++
++/****************/
++static void openPrevPic()
++{
++ int i;
++
++ if (curname>0) i = curname-1;
++ else if (nList.selected>0 && nList.selected < numnames)
++ i = nList.selected - 1;
++ else i = numnames-1;
++
++ for ( ; i>=0; i--) {
++ if (openPic(i)) return; /* success */
++ }
++
++ openPic(DFLTPIC);
++}
++
++
++/****************/
++static void openNamedPic()
++{
++ /* if (!openPic(LOADPIC)) openPic(DFLTPIC); */
++ openPic(LOADPIC);
++}
++
++
++
++
++/****************/
++static int findRandomPic()
++/****************/
++{
++ static byte *loadList;
++ static int left_to_load, listLen = -1;
++ int k;
++ time_t t;
++
++ /* picks a random name out of the list, and returns it's index. If there
++ are no more names to pick, it returns '-1' and resets itself */
++
++ if (!loadList || numnames!=listLen) {
++ if (loadList) free(loadList);
++ else {
++ time(&t);
++ srandom((unsigned int) t); /* seed the random */
++ }
++
++ left_to_load = listLen = numnames;
++ loadList = (byte *) malloc((size_t) listLen);
++ for (k=0; k<listLen; k++) loadList[k] = 0;
++ }
++
++ if (left_to_load <= 0) { /* we've loaded all the pics */
++ for (k=0; k<listLen; k++) loadList[k] = 0; /* clear flags */
++ left_to_load = listLen;
++ return -1; /* 'done' return */
++ }
++
++ for (k=abs(random()) % listLen; loadList[k]; k = (k+1) % listLen);
++
++ left_to_load--;
++ loadList[k] = TRUE;
++
++ return k;
++}
++
++/****************/
++static void mainLoop()
++{
++ /* search forward until we manage to display a picture,
++ then call EventLoop. EventLoop will eventually return
++ NEXTPIC, PREVPIC, NEXTQUIT, QUIT, or, if >= 0, a filenum to GOTO */
++
++ int i;
++
++ /* if curname<0 (there is no 'current' file), 'Next' means view the
++ selected file (or the 0th file, if no selection either), and 'Prev' means
++ view the one right before the selected file */
++
++ openFirstPic(); /* find first displayable picture, exit if none */
++
++ if (!pic) { /* must've opened a text file... display dflt pic */
++ openPic(DFLTPIC);
++ if (mainW && !useroot) RaiseTextWindows();
++ }
++
++ if (useroot && autoquit) Quit(0);
++
++ while ((i=EventLoop()) != QUIT) {
++ if (i==NEXTPIC) {
++ if ((curname<0 && numnames>0) ||
++ (curname<numnames-1)) openNextPic();
++ }
++
++ else if (i==PREVPIC) {
++ if (curname>0 || (curname<0 && nList.selected>0))
++ openPrevPic();
++ }
++
++ else if (i==NEXTQUIT) openNextQuit();
++ else if (i==NEXTLOOP) openNextLoop();
++ else if (i==LOADPIC) openNamedPic();
++
++ else if (i==DELETE) { /* deleted currently-viewed image */
++ curname = -1;
++ ActivePrevNext();
++ if (but[BNEXT].active)
++ FakeButtonPress(&but[BNEXT]);
++ else openPic(DFLTPIC);
++ }
++
++ else if (i==THISNEXT) { /* open current sel, 'next' until success */
++ int j;
++ j = nList.selected;
++ if (j<0) j = 0;
++ while (j<numnames && !openPic(j));
++ if (!pic) openPic(DFLTPIC);
++ }
++
++ else if (i>=0 || i==GRABBED || i==POLLED || i==RELOAD ||
++ i==OP_PAGEUP || i==OP_PAGEDN || i==DFLTPIC || i==PADDED) {
++ openPic(i);
++ /* if (!openPic(i)) openPic(DFLTPIC); */
++ }
++ }
++}
++
++
++
++/***********************************/
++static void createMainWindow(geom, name)
++ char *geom, *name;
++{
++ XSetWindowAttributes xswa;
++ unsigned long xswamask;
++ XWindowAttributes xwa;
++ XWMHints xwmh;
++ XSizeHints hints;
++ XClassHint classh;
++ int i,x,y;
++ unsigned int w,h;
++ static int firstTime = 1;
++
++ /*
++ * this function mainly deals with parsing the geometry spec correctly.
++ * More trouble than it should be, and probably more trouble than
++ * it has to be, but who can tell these days, what with all those
++ * Widget-usin' Weenies out there...
++ *
++ * Note: eWIDE,eHIGH have the correct, desired window size. Ignore the
++ * w,h fields in the geometry spec, as they've already been dealt with
++ */
++
++ x = y = w = h = 1;
++ i = XParseGeometry(geom,&x,&y,&w,&h);
++
++ 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);
++
++ if (x+eWIDE > vrWIDE) x = vrWIDE - eWIDE; /* keep on screen */
++ if (y+eHIGH > vrHIGH) y = vrHIGH - eHIGH;
++
++
++#define VROOT_TRANS
++#ifdef VROOT_TRANS
++ if (vrootW != rootW) { /* virtual window manager running */
++ int x1,y1;
++ Window child;
++ XTranslateCoordinates(theDisp, rootW, vrootW, x, y, &x1, &y1, &child);
++ if (DEBUG) fprintf(stderr,"translate: %d,%d -> %d,%d\n",x,y,x1,y1);
++ x = x1; y = y1;
++ }
++#endif
++
++ hints.x = x; hints.y = y;
++ hints.width = eWIDE; hints.height = eHIGH;
++ hints.max_width = maxWIDE; hints.max_height = maxHIGH;
++ hints.flags |= USSize | PMaxSize;
++
++ xswa.bit_gravity = StaticGravity;
++ xswa.background_pixel = bg;
++ xswa.border_pixel = fg;
++ xswa.colormap = theCmap;
++
++ xswa.backing_store = WhenMapped;
++
++ /* NOTE: I've turned 'backing-store' off on the image window, as some
++ servers (HP 9000/300 series running X11R4) don't properly deal with
++ things when the image window changes size. It isn't a big performance
++ improvement anyway (for the image window), unless you're on a slow
++ network. In any event, I'm not *turning off* backing store, I'm
++ just not explicitly turning it *on*. If your X server is set up
++ that windows, by default, have backing-store turned on, then the
++ image window will, too */
++
++ xswamask = CWBackPixel | CWBorderPixel | CWColormap /* | CWBackingStore */;
++ if (!clearonload) xswamask |= CWBitGravity;
++
++ if (mainW) {
++ GetWindowPos(&xwa);
++ xwa.width = eWIDE; xwa.height = eHIGH;
++
++ /* try to keep the damned thing on-screen, if possible */
++ if (xwa.x + xwa.width > dispWIDE) xwa.x = dispWIDE - xwa.width;
++ if (xwa.y + xwa.height > dispHIGH) xwa.y = dispHIGH - xwa.height;
++ if (xwa.x < 0) xwa.x = 0;
++ if (xwa.y < 0) xwa.y = 0;
++
++ SetWindowPos(&xwa);
++ hints.flags = PSize | PMaxSize;
++ }
++
++ else {
++ mainW = XCreateWindow(theDisp,rootW,x,y, (u_int) eWIDE, (u_int) eHIGH,
++ (u_int) bwidth, (int) dispDEEP, InputOutput,
++ theVisual, xswamask, &xswa);
++ if (!mainW) FatalError("can't create window!");
++
++ XSetCommand(theDisp, mainW, mainargv, mainargc);
++
++ if (LocalCmap) {
++ xswa.colormap = LocalCmap;
++ XChangeWindowAttributes(theDisp,mainW,CWColormap,&xswa);
++ }
++ }
++
++
++ XSetStandardProperties(theDisp,mainW,"","",None,NULL,0,&hints);
++ setWinIconNames(name);
++
++ xwmh.input = True;
++ xwmh.flags = InputHint;
++
++ xwmh.icon_pixmap = iconPix;
++ xwmh.icon_mask = iconmask;
++ xwmh.flags |= (IconPixmapHint | IconMaskHint);
++
++
++ if (startIconic && firstTime) {
++ xwmh.initial_state = IconicState;
++ xwmh.flags |= StateHint;
++
++ if (icongeom) {
++ int i,x,y; unsigned int w,h;
++ i = XParseGeometry(icongeom, &x, &y, &w, &h); /* ignore w,h */
++ if (i&XValue && i&YValue) {
++ if (i&XValue && i&XNegative) x = vrWIDE - icon_width - abs(x);
++ if (i&YValue && i&YNegative) y = vrHIGH - icon_height - abs(y);
++
++ xwmh.icon_x = x; xwmh.icon_y = y;
++ xwmh.flags |= (IconPositionHint);
++ }
++ }
++ }
++ XSetWMHints(theDisp, mainW, &xwmh);
++
++ classh.res_name = "xv";
++ classh.res_class = "XVroot";
++ XSetClassHint(theDisp, mainW, &classh);
++
++
++ if (nodecor) { /* turn of image window decorations (in MWM) */
++ Atom mwm_wm_hints;
++ struct s_mwmhints {
++ long flags;
++ long functions;
++ long decorations;
++ u_long input_mode;
++ long status;
++ } mwmhints;
++
++ mwm_wm_hints = XInternAtom(theDisp, "_MOTIF_WM_HINTS", False);
++ if (mwm_wm_hints != None) {
++ xvbzero((char *) &mwmhints, sizeof(mwmhints));
++ mwmhints.flags = 2;
++ mwmhints.decorations = 4;
++
++ XChangeProperty(theDisp, mainW, mwm_wm_hints, mwm_wm_hints, 32,
++ PropModeReplace, (byte *) &mwmhints,
++ (int) (sizeof(mwmhints))/4);
++ XSync(theDisp, False);
++ }
++ }
++
++
++ firstTime = 0;
++}
++
++
++/***********************************/
++static void setWinIconNames(name)
++ char *name;
++{
++ char winname[256], iconname[256];
++
++ if (winTitle) {
++ strcpy(winname, winTitle);
++ strcpy(iconname, winTitle);
++ }
++ else if (name[0] == '\0') {
++ sprintf(winname, "xv %s",VERSTR);
++ sprintf(iconname,"xv");
++ }
++ else {
++ sprintf(winname,"xv %s: %s", VERSTR, name);
++ sprintf(iconname,"%s",name);
++ }
++
++#ifndef REGSTR
++ strcat(winname, " <unregistered>");
++#endif
++
++ if (mainW) {
++ XStoreName(theDisp, mainW, winname);
++ XSetIconName(theDisp, mainW, iconname);
++ }
++}
++
++
++/***********************************/
++void FixAspect(grow,w,h)
++int grow;
++int *w, *h;
++{
++ /* computes new values of eWIDE and eHIGH which will have aspect ratio
++ 'normaspect'. If 'grow' it will preserve aspect by enlarging,
++ otherwise, it will shrink to preserve aspect ratio.
++ Returns these values in 'w' and 'h' */
++
++ float xr,yr,curaspect,a,exp;
++
++ *w = eWIDE; *h = eHIGH;
++
++ /* xr,yr are expansion factors */
++ xr = ((float) eWIDE) / cWIDE;
++ yr = ((float) eHIGH) / cHIGH;
++ curaspect = xr / yr;
++
++ /* if too narrow & shrink, shrink height. too wide and grow, grow height */
++ if ((curaspect < normaspect && !grow) ||
++ (curaspect > normaspect && grow)) { /* modify height */
++ exp = curaspect / normaspect;
++ *h = (int) (eHIGH * exp + .5);
++ }
++
++ /* if too narrow & grow, grow width. too wide and shrink, shrink width */
++ if ((curaspect < normaspect && grow) ||
++ (curaspect > normaspect && !grow)) { /* modify width */
++ exp = normaspect / curaspect;
++ *w = (int) (eWIDE * exp + .5);
++ }
++
++
++ /* shrink to fit screen without changing aspect ratio */
++ if (*w>maxWIDE) {
++ int i;
++ a = (float) *w / maxWIDE;
++ *w = maxWIDE;
++ i = (int) (*h / a + .5); /* avoid freaking some optimizers */
++ *h = i;
++ }
++
++ if (*h>maxHIGH) {
++ a = (float) *h / maxHIGH;
++ *h = maxHIGH;
++ *w = (int) (*w / a + .5);
++ }
++
++ if (*w < 1) *w = 1;
++ if (*h < 1) *h = 1;
++}
++
++
++/***********************************/
++static void makeDispNames()
++{
++ int prelen, n, i, done;
++ char *suffix;
++
++ suffix = namelist[0];
++ prelen = 0; /* length of prefix to be removed */
++ n = i = 0; /* shut up pesky compiler warnings */
++
++ done = 0;
++ while (!done) {
++ suffix = (char *) index(suffix,'/'); /* find next '/' in file name */
++ if (!suffix) break;
++
++ suffix++; /* go past it */
++ n = suffix - namelist[0];
++ for (i=1; i<numnames; i++) {
++ if (strncmp(namelist[0], namelist[i], (size_t) n)!=0) { done=1; break; }
++ }
++
++ if (!done) prelen = n;
++ }
++
++ for (i=0; i<numnames; i++)
++ dispnames[i] = namelist[i] + prelen;
++}
++
++
++/***********************************/
++static void fixDispNames()
++{
++ /* fix dispnames array so that names don't go off right edge */
++
++ int i,j;
++ char *tmp;
++
++ for (i=j=0; i<numnames; i++) {
++ char *dname;
++
++ dname = dispnames[i];
++ if (StringWidth(dname) > (nList.w-10-16)) { /* have to trunc. */
++ tmp = dname;
++ while (1) {
++ tmp = (char *) index(tmp,'/'); /* find next '/' in filename */
++ if (!tmp) { tmp = dname; break; }
++
++ tmp++; /* move to char following the '/' */
++ if (StringWidth(tmp) <= (nList.w-10-16)) { /* is cool now */
++ j++; break;
++ }
++ }
++ dispnames[i] = tmp;
++ }
++ }
++}
++
++
++/***********************************/
++void StickInCtrlList(select)
++ int select;
++{
++ /* stick current name (from 'load/save' box) and current working directory
++ into 'namelist'. Does redraw list. */
++
++ char *name;
++ char cwd[MAXPATHLEN];
++
++ name = GetDirFName();
++ GetDirPath(cwd);
++
++ AddFNameToCtrlList(cwd, name);
++
++ if (select) {
++ nList.selected = numnames-1;
++ curname = numnames - 1;
++ }
++
++ ChangedCtrlList();
++}
++
++
++/***********************************/
++void AddFNameToCtrlList(fpath,fname)
++ char *fpath, *fname;
++{
++ /* stick given path/name into 'namelist'. Doesn't redraw list */
++
++ char *fullname, *dname;
++ char cwd[MAXPATHLEN], globnm[MAXPATHLEN+100];
++ int i;
++
++ if (!fpath) fpath = ""; /* bulletproofing... */
++ if (!fname) fname = "";
++
++ if (numnames == MAXNAMES) return; /* full up */
++
++ /* handle globbing */
++ if (fname[0] == '~') {
++ strcpy(globnm, fname);
++ Globify(globnm);
++ fname = globnm;
++ }
++
++ if (fname[0] != '/') { /* prepend path */
++ strcpy(cwd, fpath); /* copy it to a modifiable place */
++
++ /* make sure fpath has a trailing '/' char */
++ if (strlen(cwd)==0 || cwd[strlen(cwd)-1]!='/') strcat(cwd, "/");
++
++ fullname = (char *) malloc(strlen(cwd) + strlen(fname) + 2);
++ if (!fullname) FatalError("couldn't alloc name in AddFNameToCtrlList()\n");
++
++ sprintf(fullname, "%s%s", cwd, fname);
++ }
++ else { /* copy name to fullname */
++ fullname = (char *) malloc(strlen(fname) + 1);
++ if (!fullname) FatalError("couldn't alloc name in AddFNameToCtrlList()\n");
++ strcpy(fullname, fname);
++ }
++
++
++ /* see if this name is a duplicate. Don't add it if it is. */
++ for (i=0; i<numnames; i++)
++ if (strcmp(fullname, namelist[i]) == 0) {
++ free(fullname);
++ return;
++ }
++
++ namelist[numnames] = fullname;
++ numnames++;
++ makeDispNames();
++ fixDispNames();
++}
++
++
++/***********************************/
++void ChangedCtrlList()
++{
++ /* called when the namelist/dispnames arrays have changed, and list needs
++ to be re-displayed */
++
++ int cname, lsel;
++
++ if (numnames>0) BTSetActive(&but[BDELETE],1);
++ windowMB.dim[WMB_TEXTVIEW] = (numnames==0);
++
++ cname = curname; lsel = nList.selected; /* get blown away in LSNewData */
++ LSChangeData(&nList, dispnames, numnames);
++ curname = cname; nList.selected = lsel; /* restore prev values */
++
++ ActivePrevNext();
++
++ ScrollToCurrent(&nList);
++ DrawCtrlNumFiles();
++}
++
++
++/***********************************/
++void ActivePrevNext()
++{
++ /* called to enable/disable the Prev/Next buttons whenever curname and/or
++ numnames and/or nList.selected change */
++
++ /* if curname<0 (there is no 'current' file), 'Next' means view the
++ selected file (or the 0th file, if no selection either), and 'Prev' means
++ view the one right before the selected file */
++
++ if (curname<0) { /* light things based on nList.selected, instead */
++ BTSetActive(&but[BNEXT], (numnames>0));
++ BTSetActive(&but[BPREV], (nList.selected>0));
++ }
++ else {
++ BTSetActive(&but[BNEXT], (curname<numnames-1));
++ BTSetActive(&but[BPREV], (curname>0));
++ }
++}
++
++
++/***********************************/
++int DeleteCmd()
++{
++ /* 'delete' button was pressed. Pop up a dialog box to determine
++ what should be deleted, then do it.
++ returns '1' if THE CURRENTLY VIEWED entry was deleted from the list,
++ in which case the 'selected' filename on the ctrl list is now
++ different, and should be auto-loaded, or something */
++
++ static char *bnames[] = { "\004Disk File", "\nList Entry", "\033Cancel" };
++ char str[512];
++ int del, i, delnum, rv;
++
++ /* failsafe */
++ delnum = nList.selected;
++ if (delnum < 0 || delnum >= numnames) return 0;
++
++ sprintf(str,"Delete '%s'?\n\n%s%s",
++ namelist[delnum],
++ "'List Entry' deletes selection from list.\n",
++ "'Disk File' deletes file associated with selection.");
++
++ del = PopUp(str, bnames, 3);
++
++ if (del == 2) return 0; /* cancel */
++
++ if (del == 0) { /* 'Disk File' */
++ char *name;
++ if (namelist[delnum][0] != '/') { /* prepend 'initdir' */
++ name = (char *) malloc(strlen(namelist[delnum]) + strlen(initdir) + 2);
++ if (!name) FatalError("malloc in DeleteCmd failed\n");
++ sprintf(name,"%s/%s", initdir, namelist[delnum]);
++ }
++ else name = namelist[delnum];
++
++ i = unlink(name);
++ if (i) {
++ sprintf(str,"Can't delete file '%s'\n\n %s.", name, ERRSTR(errno));
++ ErrPopUp(str, "\nPity");
++ if (name != namelist[delnum]) free(name);
++ return 0;
++ }
++
++ XVDeletedFile(name);
++ if (name != namelist[delnum]) free(name);
++ }
++
++ deleteFromList(delnum);
++
++ rv = 0;
++ if (delnum == curname) { /* deleted the viewed file */
++ curname = nList.selected;
++ rv = 1; /* auto-load currently 'selected' filename */
++ }
++ else if (delnum < curname) curname = (curname > 0) ? curname-1 : 0;
++
++ return rv;
++}
++
++
++/********************************************/
++static void deleteFromList(delnum)
++ int delnum;
++{
++ int i;
++
++ /* remove from list on either 'List Entry' or (successful) 'Disk File' */
++
++ /* determine if namelist[delnum] needs to be freed or not */
++ for (i=0; i<mainargc && mainargv[i] != namelist[delnum]; i++) ;
++ if (i == mainargc) { /* not found. free it */
++ free(namelist[delnum]);
++ }
++
++ if (delnum != numnames-1) {
++ /* snip out of namelist and dispnames lists */
++ xvbcopy((char *) &namelist[delnum+1], (char *) &namelist[delnum],
++ (numnames - delnum - 1) * sizeof(namelist[0]));
++
++ xvbcopy((char *) &dispnames[delnum+1], (char *) &dispnames[delnum],
++ (numnames - delnum - 1) * sizeof(dispnames[0]));
++ }
++
++ numnames--;
++ if (numnames==0) BTSetActive(&but[BDELETE],0);
++ windowMB.dim[WMB_TEXTVIEW] = (numnames==0);
++
++ nList.nstr = numnames;
++ nList.selected = delnum;
++
++ if (nList.selected >= numnames) nList.selected = numnames-1;
++ if (nList.selected < 0) nList.selected = 0;
++
++ SCSetRange(&nList.scrl, 0, numnames - nList.nlines,
++ nList.scrl.val, nList.nlines-1);
++ ScrollToCurrent(&nList);
++ DrawCtrlNumFiles();
++
++ ActivePrevNext();
++}
++
++
++/***********************************/
++void HandleDispMode()
++{
++ /* handles a change in the display mode (windowed/root).
++ Also, called to do the 'right' thing when opening a picture
++ displays epic, in current size, UNLESS we've selected an 'integer'
++ root tiling thingy, in which case we resize epic appropriately */
++
++ static int haveoldinfo = 0;
++ static Window oldMainW;
++ static int oldCmapMode;
++ static XSizeHints oldHints;
++ static XWindowAttributes oldXwa;
++ int i;
++
++
++ WaitCursor();
++
++ /****************************************************************/
++ /*** RMB_WINDOW windowed mode */
++ /****************************************************************/
++
++
++ if (dispMode == RMB_WINDOW) { /* windowed */
++ char fnam[256];
++
++ BTSetActive(&but[BANNOT], 1);
++
++ if (fullfname[0] == '\0') fnam[0] = '\0';
++ else {
++ char *tmp;
++ int i, state;
++
++ /* find beginning of next-to-last pathname component, ie,
++ if fullfname is "/foo/bar/snausage", we'd like "bar/snausage" */
++
++ state = 0;
++ for (i=strlen(fullfname); i>0 && state!=2; i--) {
++ if (fullfname[i] == '/') state++;
++ }
++
++ if (state==2) tmp = fullfname + i + 2;
++ else tmp = fullfname;
++
++ strcpy(fnam, tmp);
++
++ /* if we're viewing a multi-page doc, add page # to title */
++ if (strlen(pageBaseName) && numPages>1) {
++ char foo[64];
++ sprintf(foo, " Page %d of %d", curPage+1, numPages);
++ strcat(fnam, foo);
++ }
++
++ }
++
++ if (useroot && resetroot) ClearRoot();
++
++ if (mainW == (Window) NULL || useroot) { /* window not visible */
++ useroot = 0;
++
++ if (haveoldinfo) { /* just remap mainW and resize it */
++ XWMHints xwmh;
++
++ mainW = oldMainW;
++
++ /* enable 'perfect' and 'owncmap' options */
++ dispMB.dim[DMB_COLPERF] = (picType == PIC8) ? 0 : 1;
++ dispMB.dim[DMB_COLOWNC] = (picType == PIC8) ? 0 : 1;
++
++ XSetStandardProperties(theDisp,mainW,"","",None,NULL,0,&oldHints);
++ setWinIconNames(fnam);
++
++ xwmh.initial_state = NormalState;
++ xwmh.input = True;
++ xwmh.flags = InputHint;
++
++ xwmh.icon_pixmap = iconPix;
++ xwmh.icon_mask = iconmask;
++ xwmh.flags |= ( IconPixmapHint | IconMaskHint) ;
++
++ xwmh.flags |= StateHint;
++ XSetWMHints(theDisp, mainW, &xwmh);
++
++ oldXwa.width = eWIDE; oldXwa.height = eHIGH;
++ SetWindowPos(&oldXwa);
++ XResizeWindow(theDisp, mainW, (u_int) eWIDE, (u_int) eHIGH);
++ XMapWindow(theDisp, mainW);
++ }
++
++ else { /* first time. need to create mainW */
++ mainW = (Window) NULL;
++ createMainWindow(maingeom, fnam);
++ XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
++ | StructureNotifyMask | ButtonPressMask
++ | KeyReleaseMask | ColormapChangeMask
++ | EnterWindowMask | LeaveWindowMask );
++
++ StoreDeleteWindowProp(mainW);
++ XFlush(theDisp);
++ XMapWindow(theDisp,mainW);
++ XFlush(theDisp);
++ if (startIconic) sleep(2); /* give it time to get the window up...*/
++ }
++ }
++
++ else { /* mainW already visible */
++ createMainWindow(maingeom, fnam);
++ XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
++ | StructureNotifyMask | ButtonPressMask
++ | KeyReleaseMask | ColormapChangeMask
++ | EnterWindowMask | LeaveWindowMask );
++
++ if (LocalCmap) { /* AllocColors created local colormap */
++ XSetWindowColormap(theDisp, mainW, LocalCmap);
++ }
++ }
++
++
++
++ useroot = 0;
++ }
++
++
++ /****************************************************************/
++ /*** ROOT mode */
++ /****************************************************************/
++
++
++ else if (dispMode > RMB_WINDOW && dispMode < RMB_MAX) {
++ int ew, eh, regen;
++
++ BTSetActive(&but[BANNOT], 0);
++
++ regen = 0;
++ if (!useroot) { /* have to hide mainW, etc. */
++ dispMB.dim[DMB_COLPERF] = 1; /* no perfect or owncmap in root mode */
++ dispMB.dim[DMB_COLOWNC] = 1;
++
++ /* save current window stuff */
++ haveoldinfo = 1;
++ oldMainW = mainW;
++ oldCmapMode = colorMapMode;
++
++ GetWindowPos(&oldXwa);
++ if (!XGetNormalHints(theDisp, mainW, &oldHints)) oldHints.flags = 0;
++ oldHints.x=oldXwa.x; oldHints.y=oldXwa.y; oldHints.flags|=USPosition;
++
++ if (LocalCmap) regen=1;
++
++ /* this reallocs the colors */
++ if (colorMapMode==CM_PERFECT || colorMapMode==CM_OWNCMAP)
++ ChangeCmapMode(CM_NORMAL, 0, 0);
++
++
++ XUnmapWindow(theDisp, mainW);
++ mainW = vrootW;
++
++ if (!ctrlUp) { /* make sure ctrl is up when going to 'root' mode */
++ XWMHints xwmh;
++ xwmh.input = True;
++ xwmh.initial_state = IconicState;
++ xwmh.flags = (InputHint | StateHint);
++ XSetWMHints(theDisp, ctrlW, &xwmh);
++ CtrlBox(1);
++ }
++ }
++
++ useroot = 1;
++ rootMode = dispMode - RMB_ROOT;
++ ew = eWIDE; eh = eHIGH;
++
++ RANGE(ew,1,maxWIDE); RANGE(eh,1,maxHIGH);
++
++ if (rootMode == RM_TILE || rootMode == RM_IMIRROR) {
++ i = (dispWIDE + ew-1) / ew; ew = (dispWIDE + i-1) / i;
++ i = (dispHIGH + eh-1) / eh; eh = (dispHIGH + i-1) / i;
++ }
++
++ if (ew != eWIDE || eh != eHIGH) { /* changed size... */
++ GenerateEpic(ew, eh);
++ CreateXImage();
++ }
++ else if (regen) CreateXImage();
++
++ KillOldRootInfo();
++ MakeRootPic();
++ SetCursors(-1);
++ }
++
++ else {
++ fprintf(stderr,"unknown dispMB value '%d' in HandleDispMode()\n",
++ dispMode);
++ }
++
++ SetCursors(-1);
++}
++
++
++/*******************************************************/
++static void add_filelist_to_namelist(flist, nlist, numn, maxn)
++ char *flist;
++ char **nlist;
++ int *numn, maxn;
++{
++ /* written by Brian Gregory (bgregory@megatest.com) */
++
++ FILE *fp;
++
++ fp = fopen(flist,"r");
++ if (!fp) {
++ fprintf(stderr,"Can't open filelist '%s': %s\n", flist, ERRSTR(errno));
++ return;
++ }
++
++ while (*numn < maxn) {
++ char *s, *nlp, fbuf[MAXPATHLEN];
++ if (!fgets(fbuf, MAXPATHLEN, fp) ||
++ !(s = (char *) malloc(strlen(fbuf)))) break;
++
++ nlp = (char *) rindex(fbuf, '\n');
++ if (nlp) *nlp = '\0';
++ strcpy(s, fbuf);
++
++ namelist[*numn] = s; (*numn)++;
++ }
++
++
++ if (*numn == maxn) {
++ fprintf(stderr, "%s: too many filenames. Only using first %d.\n",
++ flist, maxn);
++ }
++
++ fclose(fp);
++}
++
++
++
++
++/************************************************************************/
++
++/***********************************/
++char *lower_str(str)
++ char *str;
++{
++ char *p;
++ for (p=str; *p; p++) if (isupper(*p)) *p = tolower(*p);
++ return str;
++}
++
++
++/***********************************/
++int rd_int(name)
++ char *name;
++{
++ /* returns '1' if successful. result in def_int */
++
++ if (rd_str_cl(name, "", 0)) { /* sets def_str */
++ if (sscanf(def_str, "%d", &def_int) == 1) return 1;
++ else {
++ fprintf(stderr, "%s: couldn't read integer value for %s resource\n",
++ cmd, name);
++ return 0;
++ }
++ }
++ else return 0;
++}
++
++
++/***********************************/
++int rd_str(name)
++ char *name;
++{
++ return rd_str_cl(name, "", 0);
++}
++
++
++/***********************************/
++int rd_flag(name)
++char *name;
++{
++ /* returns '1' if successful. result in def_int */
++
++ char buf[256];
++
++ if (rd_str_cl(name, "", 0)) { /* sets def_str */
++ strcpy(buf, def_str);
++ lower_str(buf);
++
++ def_int = (strcmp(buf, "on")==0) ||
++ (strcmp(buf, "1")==0) ||
++ (strcmp(buf, "true")==0) ||
++ (strcmp(buf, "yes")==0);
++ return 1;
++ }
++
++ else return 0;
++}
++
++
++
++
++static int xrm_initted = 0;
++
++/***********************************/
++int rd_str_cl (name_str, class_str, reinit)
++ char *name_str;
++ char *class_str;
++ int reinit;
++{
++ /* note: *all* X resource reading goes through this routine... */
++
++ /* returns '1' if successful, result in def_str */
++
++ char q_name[BUFSIZ], q_class[BUFSIZ];
++ char *type;
++ XrmValue result;
++ int gotit;
++ static XrmDatabase def_resource;
++
++
++ if (reinit) {
++#ifndef vax11c
++ if (xrm_initted && def_resource) XrmDestroyDatabase(def_resource);
++#endif
++ xrm_initted = 0;
++ }
++
++ if (!xrm_initted) {
++ Atom resAtom;
++ char *xrm_str;
++
++ XrmInitialize();
++ xrm_initted = 1;
++ def_resource = (XrmDatabase) 0;
++
++ gotit = 0;
++
++
++ /* don't use XResourceManagerString, as it is a snapshot of the
++ string when theDisp was opened, and doesn't change */
++
++ resAtom = XInternAtom(theDisp, "RESOURCE_MANAGER", True);
++ if (resAtom != None) {
++ Atom actType;
++ int i, actFormat;
++ 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 (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 (i==Success && actType==XA_STRING && actFormat==8 && data) {
++ def_resource = XrmGetStringDatabase((char *) data);
++ XFree(data);
++ gotit = 1;
++ }
++ }
++ }
++
++
++
++ if (!gotit) {
++ xrm_str = XResourceManagerString(theDisp);
++
++ if (xrm_str) {
++ def_resource = XrmGetStringDatabase(xrm_str);
++ if (DEBUG) fprintf(stderr,"rd_str_cl: Using RESOURCE_MANAGER prop.\n");
++ }
++ else { /* no RESOURCE_MANAGER prop. read from 'likely' file */
++ char foo[256], *homedir, *xenviron;
++ XrmDatabase res1;
++
++#ifdef VMS
++ strcpy(foo, "SYS$LOGIN:DECW$XDEFAULTS.DAT");
++#else
++ homedir = (char *) getenv("HOME");
++ if (!homedir) homedir = ".";
++ sprintf(foo,"%s/.Xdefaults", homedir);
++#endif
++
++ def_resource = XrmGetFileDatabase(foo);
++
++ if (DEBUG) {
++ fprintf(stderr,"rd_str_cl: No RESOURCE_MANAGER prop.\n");
++ fprintf(stderr,"rd_str_cl: Using file '%s' (%s) ",
++ foo, (def_resource) ? "success" : "failure");
++ }
++
++
++ /* merge file pointed to by XENVIRONMENT */
++ xenviron = (char *) getenv("XENVIRONMENT");
++ if (xenviron) {
++ res1 = XrmGetFileDatabase(xenviron);
++
++ if (DEBUG) {
++ fprintf(stderr,"merging XENVIRONMENT='%s' (%s) ",
++ xenviron, (res1) ? "success" : "failure");
++ }
++
++ if (res1) { /* merge databases */
++ if (!def_resource) def_resource = res1;
++ else XrmMergeDatabases(res1, &def_resource);
++ }
++ }
++
++
++ if (DEBUG) fprintf(stderr,"\n\n");
++ }
++ }
++ }
++
++
++ if (!def_resource) return 0; /* no resource database to search! */
++
++
++ strcpy (q_name, PROGNAME);
++ strcat (q_name, ".");
++ strcat (q_name, name_str);
++
++ strcpy (q_class, "Program");
++ strcat (q_class, ".");
++ strcat (q_class, class_str);
++
++ (void) XrmGetResource(def_resource, q_name, q_class, &type, &result);
++
++ def_str = result.addr;
++ if (def_str) return (1);
++ else return (0);
++}
++
++
+diff -urN xv-3.10a/xv.h xv-3.10apatched/xv.h
+--- xv-3.10a/xv.h Mon Jan 23 12:22:23 1995
++++ xv-3.10apatched/xv.h Tue Apr 30 00:20:19 2002
+@@ -8,8 +8,8 @@
+ #include "config.h"
+
+
+-#define REVDATE "Version 3.10a Rev: 12/29/94"
+-#define VERSTR "3.10a"
++#define REVDATE "Version 3.10a Rev: 12/29/94 (PNG patch 1.2)"
++#define VERSTR "3.10a(PNG)"
+
+ /*
+ * uncomment the following, and modify for your site, but only if you've
+@@ -114,8 +114,8 @@
+
+ #ifndef VMS
+ # include <errno.h>
+- extern int errno; /* SHOULD be in errno.h, but often isn't */
+-# ifndef __NetBSD__
++# if !defined(__NetBSD__) && !defined(__GNU_LIBRARY__)
++ extern int errno; /* SHOULD be in errno.h, but often isn't */
+ extern char *sys_errlist[]; /* this too... */
+ # endif
+ #endif
+@@ -327,6 +327,10 @@
+ #define HAVE_TIFF
+ #endif
+
++#ifdef DOPNG
++#define HAVE_PNG
++#endif
++
+ #ifdef DOPDS
+ #define HAVE_PDS
+ #endif
+@@ -458,24 +462,31 @@
+ #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_DELIM1 (12 + F_JPGINC + F_TIFINC + F_PNGINC) /* ----- */
++#define F_FILELIST (13 + F_JPGINC + F_TIFINC + F_PNGINC)
++#define F_MAXFMTS (14 + F_JPGINC + F_TIFINC + F_PNGINC) /* 17, normally */
+
+
+
+@@ -505,6 +516,7 @@
+ #define RFT_XPM 17
+ #define RFT_XWD 18
+ #define RFT_FITS 19
++#define RFT_PNG 20
+
+ /* definitions for page up/down, arrow up/down list control */
+ #define LS_PAGEUP 0
+@@ -563,7 +575,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 */
+@@ -613,7 +626,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 */
+@@ -765,9 +779,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 */
+@@ -935,7 +950,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;
+@@ -1154,6 +1169,13 @@
+ #endif
+
+
++#ifdef HAVE_PNG
++/* stuff used for 'png' box */
++WHERE Window pngW;
++WHERE int pngUp; /* is pngW mapped, or what? */
++#endif
++
++
+ #undef WHERE
+
+
+@@ -1465,12 +1487,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));
+@@ -1613,6 +1635,13 @@
+ int TIFFCheckEvent PARM((XEvent *));
+ void TIFFSaveParams PARM((char *, int));
+
++/**************************** XVPNG.C ***************************/
++int LoadPNG PARM((char *, PICINFO *));
++void CreatePNGW PARM((void));
++void PNGDialog PARM((int));
++int PNGCheckEvent PARM((XEvent *));
++void PNGSaveParams PARM((char *, int));
++
+ /**************************** XVPDS.C ***************************/
+ int LoadPDS PARM((char *, PICINFO *));
+
+diff -urN xv-3.10a/xvbmp.c xv-3.10apatched/xvbmp.c
+--- xv-3.10a/xvbmp.c Thu Dec 22 14:34:42 1994
++++ xv-3.10apatched/xvbmp.c Tue Apr 30 00:20:27 2002
+@@ -32,7 +32,7 @@
+ 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 loadBMP24 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));
+@@ -127,7 +127,8 @@
+
+
+ /* error checking */
+- if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && biBitCount!=24) ||
++ if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 &&
++ biBitCount!=24 && biBitCount!=32) ||
+ biPlanes!=1 || biCompression>BI_RLE4) {
+
+ sprintf(buf,"Bogus BMP File! (bitCount=%d, Planes=%d, Compression=%d)",
+@@ -137,7 +138,8 @@
+ goto ERROR;
+ }
+
+- if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) ||
++ if (((biBitCount==1 || biBitCount==24 || biBitCount==32)
++ && biCompression != BI_RGB) ||
+ (biBitCount==4 && biCompression==BI_RLE8) ||
+ (biBitCount==8 && biCompression==BI_RLE4)) {
+
+@@ -159,7 +161,7 @@
+ }
+
+ /* load up colormap, if any */
+- if (biBitCount!=24) {
++ if (biBitCount!=24 && biBitCount!=32) {
+ int i, cmaplen;
+
+ cmaplen = (biClrUsed) ? biClrUsed : 1 << biBitCount;
+@@ -197,7 +199,7 @@
+
+ /* create pic8 or pic24 */
+
+- if (biBitCount==24) {
++ if (biBitCount==24 || biBitCount==32) {
+ pic24 = (byte *) calloc((size_t) biWidth * biHeight * 3, (size_t) 1);
+ if (!pic24) return (bmpError(bname, "couldn't malloc 'pic24'"));
+ }
+@@ -212,16 +214,18 @@
+ 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,
++ else if (biBitCount == 8) rv = loadBMP8(fp,pic8,biWidth,biHeight,
+ biCompression);
+- else rv = loadBMP24(fp,pic24,biWidth,biHeight);
++ else rv = loadBMP24(fp,pic24,biWidth,biHeight,
++ biBitCount);
++
+
+ if (rv) bmpError(bname, "File appears truncated. Winging it.\n");
+
+ fclose(fp);
+
+
+- if (biBitCount == 24) {
++ if (biBitCount == 24 || biBitCount == 32) {
+ pinfo->pic = pic24;
+ pinfo->type = PIC24;
+ }
+@@ -384,10 +388,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) */
+
+@@ -407,12 +413,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 */
+@@ -431,7 +437,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;
+ }
+@@ -454,10 +460,10 @@
+
+
+ /*******************************************/
+-static int loadBMP24(fp, pic24, w, h)
++static int loadBMP24(fp, pic24, w, h, bits)
+ FILE *fp;
+ byte *pic24;
+- u_int w,h;
++ u_int w,h, bits;
+ {
+ int i,j,padb,rv;
+ byte *pp;
+@@ -465,6 +471,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);
+@@ -474,6 +481,7 @@
+ pp[2] = getc(fp); /* blue */
+ pp[1] = getc(fp); /* green */
+ pp[0] = getc(fp); /* red */
++ if (bits==32) getc(fp);
+ pp += 3;
+ }
+
+diff -urN xv-3.10a/xvbrowse.c xv-3.10apatched/xvbrowse.c
+--- xv-3.10a/xvbrowse.c Thu Jan 19 09:49:17 1995
++++ xv-3.10apatched/xvbrowse.c Tue Apr 30 00:19:13 2002
+@@ -55,6 +55,7 @@
+ #include "bits/br_xpm"
+ #include "bits/br_xwd"
+ #include "bits/br_fits"
++#include "bits/br_png"
+
+ #include "bits/br_trash"
+ #include "bits/fcurs"
+@@ -94,7 +95,8 @@
+ #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_MAX 29 /* # of built-in icons */
+
+ #define ISLOADABLE(ftyp) (ftyp!=BF_DIR && ftyp!=BF_CHR && ftyp!=BF_BLK && \
+ ftyp!=BF_SOCK && ftyp!=BF_FIFO)
+@@ -524,6 +526,7 @@
+ 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);
+
+
+ /* check that they all got built */
+@@ -956,6 +959,7 @@
+ char *str;
+ {
+ strncpy(br->dispstr, str, (size_t) 256);
++ br->dispstr[255] = '\0';
+ drawBrowStr(br);
+ XFlush(theDisp);
+ }
+@@ -1490,6 +1494,7 @@
+ if (StringWidth(str) > ISPACE_WIDE-6) {
+ int dotpos;
+ strncpy(tmpstr, str, (size_t) 56);
++ tmpstr[56] = '\0'; /* MR: otherwise it dies on long file names */
+ dotpos = strlen(tmpstr);
+ strcat(tmpstr,"...");
+
+@@ -1505,7 +1510,7 @@
+ nstr = tmpstr;
+ }
+ else nstr = str;
+-
++
+
+ /* draw the title */
+ sw = StringWidth(nstr);
+@@ -3020,6 +3025,7 @@
+ 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;
+ }
+ }
+ }
+@@ -3567,6 +3573,7 @@
+ 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;
+ default: strcat(str,"file of unknown type"); break;
+ }
+
+diff -urN xv-3.10a/xvbrowse.c~ xv-3.10apatched/xvbrowse.c~
+--- xv-3.10a/xvbrowse.c~ Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/xvbrowse.c~ Tue Apr 30 00:10:16 2002
+@@ -0,0 +1,5427 @@
++/*
++ * xvbrowse.c - visual schnauzer routines
++ *
++ * includes:
++ * void CreateBrowse(char *, char *, char *, char *, char *);
++ * void OpenBrowse();
++ * void HideBrowseWindows();
++ * void UnHideBrowseWindows();
++ * void SetBrowseCursor(Cursor);
++ * void KillBrowseWindows();
++ * int BrowseCheckEvent(evt, int *retval, int *done);
++ * int BrowseDelWin(Window);
++ * void SetBrowStr(char *);
++ * void RegenBrowseIcons();
++ *
++ */
++
++#include "copyright.h"
++
++#define NEEDSDIR
++#include "xv.h"
++
++#if defined(VMS) || defined(isc)
++typedef unsigned int mode_t; /* file mode bits */
++#endif
++
++
++/* load up built-in icons */
++#include "bits/br_file"
++#include "bits/br_dir"
++#include "bits/br_exe"
++#include "bits/br_chr"
++#include "bits/br_blk"
++#include "bits/br_sock"
++#include "bits/br_fifo"
++#include "bits/br_error"
++#include "bits/br_unknown"
++#include "bits/br_cmpres"
++
++#include "bits/br_gif"
++#include "bits/br_pm"
++#include "bits/br_pbm"
++#include "bits/br_xbm"
++#include "bits/br_sunras"
++#include "bits/br_bmp"
++#include "bits/br_utah"
++#include "bits/br_iris"
++#include "bits/br_pcx"
++#include "bits/br_jfif"
++#include "bits/br_tiff"
++#include "bits/br_pds"
++#include "bits/br_ps"
++#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_trash"
++#include "bits/fcurs"
++#include "bits/fccurs"
++#include "bits/fdcurs"
++#include "bits/fcursm"
++
++
++
++/* FileTypes */
++#define BF_HAVEIMG -1 /* should use 'pimage' and 'ximage' fields */
++#define BF_FILE 0
++#define BF_DIR 1
++#define BF_EXE 2
++#define BF_CHR 3
++#define BF_BLK 4
++#define BF_SOCK 5
++#define BF_FIFO 6
++#define BF_ERROR 7
++#define BF_UNKNOWN 8
++#define BF_GIF 9
++#define BF_PM 10
++#define BF_PBM 11
++#define BF_XBM 12
++#define BF_SUNRAS 13
++#define BF_BMP 14
++#define BF_UTAHRLE 15
++#define BF_IRIS 16
++#define BF_PCX 17
++#define BF_JFIF 18
++#define BF_TIFF 19
++#define BF_PDS 20
++#define BF_COMPRESS 21
++#define BF_PS 22
++#define BF_IFF 23
++#define BF_TARGA 24
++#define BF_XPM 25
++#define BF_XWD 26
++#define BF_FITS 27
++#define BF_PNG 28
++#define BF_MAX 29 /* # 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 */
++
++#define ICON_ONLY 2 /* if 'lit' field ==, invert icon only, not title */
++#define TEMP_LIT 3 /* temporarily selected, normally off */
++#define TEMP_LIT1 4 /* temporarily selected, normally on */
++
++#define TOPMARGIN 30 /* from top of window to top of iconwindow */
++#define BOTMARGIN 58 /* room for a row of buttons and a line of text */
++#define LRMARGINS 5 /* left and right margins */
++
++#define ISIZE_WIDE 80 /* maximum size of an icon */
++#define ISIZE_HIGH 60
++
++#define ISPACE_WIDE (ISIZE_WIDE+16) /* icon spacing */
++#define ISPACE_TOP 4 /* dist btwn top of ISPACE and ISIZE */
++#define ISPACE_TTOP 4 /* dist btwn bot of icon and title */
++#define ISPACE_HIGH (ISIZE_HIGH+ISPACE_TOP+ISPACE_TTOP+16+4)
++
++#define DBLCLICKTIME 300 /* milliseconds */
++
++/* button/menu indicies */
++#define BR_CHDIR 0
++#define BR_DELETE 1
++#define BR_MKDIR 2
++#define BR_RENAME 3
++#define BR_RESCAN 4
++#define BR_UPDATE 5
++#define BR_NEWWIN 6
++#define BR_GENICON 7
++#define BR_SELALL 8
++#define BR_TEXTVIEW 9
++#define BR_RECURSUP 10
++#define BR_QUIT 11
++#define BR_CLOSE 12
++#define BR_NBUTTS 13 /* # of command buttons */
++#define BR_SEP1 13 /* separator */
++#define BR_HIDDEN 14
++#define BR_SELFILES 15
++#define BR_NCMDS 16 /* # of menu commands */
++
++#define BUTTW 80
++#define BUTTH 24
++
++static char *showHstr = "Show hidden files";
++static char *hideHstr = "Hide 'hidden' files";
++
++static char *cmdMList[] = { "Change directory...\t^c",
++ "Delete file(s)\t^d",
++ "New directory...\t^n",
++ "Rename file...\t^r",
++ "Rescan directory\t^s",
++ "Update icons\t^u",
++ "Open new window\t^w",
++ "Generate icon(s)\t^g",
++ "Select all files\t^a",
++ "Text view\t^t",
++ "Recursive Update\t^e",
++ "Quit xv\t^q",
++ "Close window\t^c",
++ MBSEP,
++ "Show hidden files", /* no equiv */
++ "Select files...\t^f"
++ };
++
++
++#define MAXDEEP 30 /* maximum directory depth */
++
++#define BOGUSPATH "NO SUCH PATH"
++
++
++typedef struct { char *name; /* name of file */
++ char *imginfo; /* info on the real image */
++ int ftype; /* BF_EXE, BF_DIR, BF_FILE, etc... */
++ byte *pimage; /* normal, 8-bit-per image */
++ XImage *ximage; /* X version of pimage */
++ int w,h; /* size of icon */
++ int lit; /* true if 'selected' */
++ } BFIL;
++
++/* data needed per schnauzer window */
++typedef struct { Window win, iconW;
++ int vis, wasvis;
++
++ int wide, high;
++ int iwWide, iwHigh;
++ int numWide, numHigh, visHigh;
++
++ SCRL scrl;
++ BUTT but[BR_NBUTTS];
++ MBUTT dirMB, cmdMB;
++ char dispstr[256];
++ int numbutshown;
++ int showhidden;
++
++ int numlit;
++ BFIL *bfList;
++ int bfLen;
++ int lastIconClicked;
++ unsigned long lastClickTime;
++
++ int ndirs;
++ char *mblist[MAXDEEP];
++ char path[MAXPATHLEN+2]; /* '/' terminated */
++ } BROWINFO;
++
++
++static Cursor movecurs, copycurs, delcurs;
++static BROWINFO binfo[MAXBRWIN];
++static Pixmap bfIcons[BF_MAX], trashPix;
++static int hasBeenSized = 0;
++static int haveWindows = 0;
++
++static unsigned long browfg, browbg, browhi, browlo;
++
++static void closeBrowse PARM((BROWINFO *));
++static int brChkEvent PARM((BROWINFO *, XEvent *));
++static void resizeBrowse PARM((BROWINFO *, int, int));
++static void setBrowStr PARM((BROWINFO *, char *));
++static void doCmd PARM((BROWINFO *, int));
++static void drawBrow PARM((BROWINFO *));
++static void drawNumfiles PARM((BROWINFO *));
++static void eraseNumfiles PARM((BROWINFO *, int));
++static void drawTrash PARM((BROWINFO *));
++static int inTrash PARM((BROWINFO *, int, int));
++static void drawBrowStr PARM((BROWINFO *));
++static void changedNumLit PARM((BROWINFO *, int, int));
++static void setSelInfoStr PARM((BROWINFO *, int));
++static void exposeIconWin PARM((BROWINFO *, int, int, int, int));
++static void drawIconWin PARM((int, SCRL *));
++static void eraseIcon PARM((BROWINFO *, int));
++static void eraseIconTitle PARM((BROWINFO *, int));
++static void drawIcon PARM((BROWINFO *, int));
++static void makeIconVisible PARM((BROWINFO *, int));
++static void clickBrow PARM((BROWINFO *, int, int));
++static int clickIconWin PARM((BROWINFO *, int, int, unsigned long, int));
++static void doubleClick PARM((BROWINFO *, int));
++static int mouseInWhichIcon PARM((BROWINFO *, int, int));
++static void invertSelRect PARM((BROWINFO *, int, int, int, int));
++static void keyIconWin PARM((BROWINFO *, XKeyEvent *));
++static void browKey PARM((BROWINFO *, int));
++static void browAlpha PARM((BROWINFO *, int));
++static void changedBrDirMB PARM((BROWINFO *, int));
++static int cdBrow PARM((BROWINFO *));
++static void scanDir PARM((BROWINFO *));
++static void copyDirInfo PARM((BROWINFO *, BROWINFO *));
++static void endScan PARM((BROWINFO *, int));
++static void scanFile PARM((BROWINFO *, BFIL *, char *));
++static void sortBFList PARM((BROWINFO *));
++static int bfnamCmp PARM((const void *, const void *));
++static void rescanDir PARM((BROWINFO *));
++static int namcmp PARM((const void *, const void *));
++static void freeBfList PARM((BROWINFO *br));
++static char **getDirEntries PARM((char *, int *, int));
++static void computeScrlVals PARM((BROWINFO *, int *, int *));
++static void genSelectedIcons PARM((BROWINFO *));
++static void genIcon PARM((BROWINFO *, BFIL *));
++static void loadThumbFile PARM((BROWINFO *, BFIL *));
++static void writeThumbFile PARM((BROWINFO *, BFIL *, byte *, int,
++ int, char *));
++
++static void makeThumbDir PARM((BROWINFO *));
++static void updateIcons PARM((BROWINFO *));
++
++static void drawTemp PARM((BROWINFO *, int, int));
++static void clearTemp PARM((BROWINFO *));
++
++static void doTextCmd PARM((BROWINFO *));
++static void doRenameCmd PARM((BROWINFO *));
++static void doMkdirCmd PARM((BROWINFO *));
++
++static void doChdirCmd PARM((BROWINFO *));
++static void doDeleteCmd PARM((BROWINFO *));
++static void doSelFilesCmd PARM((BROWINFO *));
++
++static void doRecurseCmd PARM((BROWINFO *));
++static void recurseUpdate PARM((BROWINFO *, char *));
++
++static void rm_file PARM((BROWINFO *, char *));
++static void rm_dir PARM((BROWINFO *, char *));
++static void rm_dir1 PARM((BROWINFO *));
++
++static void dragFiles PARM((BROWINFO *, BROWINFO *, char *, char *,
++ char *, char **, int, int));
++static int moveFile PARM((char *, char *));
++static int copyFile PARM((char *, char *));
++static void cp PARM((void));
++static void cp_dir PARM((void));
++static void cp_file PARM((struct stat *, int));
++static void cp_special PARM((struct stat *, int));
++static void cp_fifo PARM((struct stat *, int));
++
++static int stat2bf PARM((u_int));
++
++static int selmatch PARM((char *, char *));
++static int selmatch1 PARM((char *, char *));
++
++
++
++/***************************************************************/
++void CreateBrowse(geom, fgstr, bgstr, histr, lostr)
++ char *geom, *fgstr, *bgstr, *histr, *lostr;
++{
++ int i;
++ XSizeHints hints;
++ XSetWindowAttributes xswa;
++ BROWINFO *br;
++ XColor ecdef, cursfg, cursbg;
++ Pixmap mcpix, ccpix, dcpix, fcmpix;
++ int gx, gy, gw, gh, gset, gx1, gy1;
++ unsigned int uw, uh;
++ char wgeom[64];
++
++ if (!geom) geom = "";
++
++ /* map color spec strings into browCmap, if we're in browPerfect mode */
++ if (browPerfect && browCmap) {
++ browfg = 0; browbg = 255; /* black text on white bg, by default */
++ if (fgstr && XParseColor(theDisp, browCmap, fgstr, &ecdef)) {
++ browfg = browcols[((ecdef.red >> 8) & 0xe0) |
++ ((ecdef.green >> 11) & 0x1c) |
++ ((ecdef.blue >> 14) & 0x03)];
++ }
++
++ if (bgstr && XParseColor(theDisp, browCmap, bgstr, &ecdef)) {
++ browbg = browcols[((ecdef.red >> 8) & 0xe0) |
++ ((ecdef.green >> 11) & 0x1c) |
++ ((ecdef.blue >> 14) & 0x03)];
++ }
++
++ browhi = browbg; browlo = browfg;
++ if (histr && XParseColor(theDisp, browCmap, histr, &ecdef)) {
++ browhi = browcols[((ecdef.red >> 8) & 0xe0) |
++ ((ecdef.green >> 11) & 0x1c) |
++ ((ecdef.blue >> 14) & 0x03)];
++ }
++
++ if (lostr && XParseColor(theDisp, browCmap, lostr, &ecdef)) {
++ browlo = browcols[((ecdef.red >> 8) & 0xe0) |
++ ((ecdef.green >> 11) & 0x1c) |
++ ((ecdef.blue >> 14) & 0x03)];
++ }
++ }
++ else {
++ browfg = infofg; browbg = infobg; browhi = hicol; browlo = locol;
++ }
++
++
++
++ gset = XParseGeometry(geom, &gx, &gy, &uw, &uh);
++ gw = (int) uw; gh = (int) uh;
++
++ /* creates *all* schnauzer windows at once */
++
++ for (i=0; i<MAXBRWIN; i++) binfo[i].win = (Window) NULL;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ char wname[64];
++
++ /* create a slightly offset geometry, so the windows stack nicely */
++ if ((gset & XValue) && (gset & YValue)) {
++ if (gset & XNegative) gx1 = gx - i * 20;
++ else gx1 = gx + i * 20;
++
++ if (gset & YNegative) gy1 = gy - i * 20;
++ else gy1 = gy + i * 20;
++
++ if ((gset & WidthValue) && (gset & HeightValue))
++ sprintf(wgeom, "%dx%d%s%d%s%d", gw, gh,
++ (gset & XNegative) ? "-" : "+", abs(gx1),
++ (gset & YNegative) ? "-" : "+", abs(gy1));
++ else
++ sprintf(wgeom, "%s%d%s%d",
++ (gset & XNegative) ? "-" : "+", abs(gx1),
++ (gset & YNegative) ? "-" : "+", abs(gy1));
++ }
++ else strcpy(wgeom, geom);
++
++ br = &binfo[i];
++
++ if (i) sprintf(wname, "xv visual schnauzer (%d)", i);
++ else sprintf(wname, "xv visual schnauzer");
++
++ br->win = CreateWindow(wname, "XVschnauze", wgeom,
++ DEF_BROWWIDE, DEF_BROWHIGH, browfg, browbg, 1);
++ if (!br->win) FatalError("can't create schnauzer window!");
++
++ haveWindows = 1;
++ br->vis = br->wasvis = 0;
++
++ if (browPerfect && browCmap) {
++ xswa.colormap = browCmap;
++ XChangeWindowAttributes(theDisp, br->win, CWColormap, &xswa);
++ }
++
++ if (ctrlColor) XSetWindowBackground(theDisp, br->win, browlo);
++ else XSetWindowBackgroundPixmap(theDisp, br->win, grayTile);
++
++ /* note: everything is sized and positioned in ResizeBrowse() */
++
++ br->iconW = XCreateSimpleWindow(theDisp, br->win, 1,1, 100,100,
++ 1,browfg,browbg);
++ if (!br->iconW) FatalError("can't create schnauzer icon window!");
++
++ SCCreate(&(br->scrl), br->win, 0,0, 1,100, 0,0,0,0,
++ browfg, browbg, browhi, browlo, drawIconWin);
++
++
++ if (XGetNormalHints(theDisp, br->win, &hints)) {
++ hints.min_width = 325 + 96;
++ hints.min_height = 180;
++ hints.flags |= PMinSize;
++ XSetNormalHints(theDisp, br->win, &hints);
++ }
++
++#ifdef BACKING_STORE
++ xswa.backing_store = WhenMapped;
++ XChangeWindowAttributes(theDisp, br->iconW, CWBackingStore, &xswa);
++#endif
++
++ XSelectInput(theDisp, br->iconW, ExposureMask | ButtonPressMask);
++
++
++
++ BTCreate(&(br->but[BR_CHDIR]), br->win, 0,0,BUTTW,BUTTH,
++ "Change Dir",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_DELETE]), br->win, 0,0,BUTTW,BUTTH,
++ "Delete",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_MKDIR]), br->win, 0,0,BUTTW,BUTTH,
++ "New Dir",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_RENAME]), br->win, 0,0,BUTTW,BUTTH,
++ "Rename",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_RESCAN]), br->win, 0,0,BUTTW,BUTTH,
++ "ReScan",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_UPDATE]), br->win, 0,0,BUTTW,BUTTH,
++ "Update",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_NEWWIN]), br->win, 0,0,BUTTW,BUTTH,
++ "Open Win",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_GENICON]),br->win, 0,0,BUTTW,BUTTH,
++ "GenIcon",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_SELALL]), br->win, 0,0,BUTTW,BUTTH,
++ "Select All",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_TEXTVIEW]), br->win, 0,0,BUTTW,BUTTH,
++ "Text view",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_RECURSUP]), br->win, 0,0,BUTTW,BUTTH,
++ "RecursUpd",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_QUIT]), br->win, 0,0,BUTTW,BUTTH,
++ "Quit xv",browfg,browbg,browhi,browlo);
++ BTCreate(&(br->but[BR_CLOSE]), br->win, 0,0,BUTTW,BUTTH,
++ "Close",browfg,browbg,browhi,browlo);
++
++ XMapSubwindows(theDisp, br->win);
++
++ MBCreate(&(br->dirMB), br->win, 0,0,100,19, NULL,NULL,0,
++ browfg,browbg,browhi,browlo);
++
++ MBCreate(&(br->cmdMB), br->win, 0,0,160,19, "Misc. Commands",
++ cmdMList, BR_NCMDS, browfg,browbg,browhi,browlo);
++
++ br->showhidden = 0;
++ br->cmdMB.list[BR_HIDDEN] = showHstr;
++
++ br->numbutshown = 0;
++ br->numlit = 0;
++ br->bfList = NULL;
++ br->bfLen = 0;
++ br->dispstr[0] = '\0';
++ br->ndirs = 0;
++ sprintf(br->path, BOGUSPATH);
++
++ br->lastIconClicked = -1;
++ br->lastClickTime = 0;
++ }
++
++
++ /* create built-in icon pixmaps */
++ bfIcons[BF_FILE]=MakePix1(br->win,br_file_bits,br_file_width,br_file_height);
++ bfIcons[BF_DIR] =MakePix1(br->win,br_dir_bits, br_dir_width, br_dir_height);
++ bfIcons[BF_EXE] =MakePix1(br->win,br_exe_bits, br_exe_width, br_exe_height);
++ bfIcons[BF_CHR] =MakePix1(br->win,br_chr_bits, br_chr_width, br_chr_height);
++ bfIcons[BF_BLK] =MakePix1(br->win,br_blk_bits, br_blk_width, br_blk_height);
++ bfIcons[BF_SOCK]=MakePix1(br->win,br_sock_bits,br_sock_width,br_sock_height);
++ bfIcons[BF_FIFO]=MakePix1(br->win,br_fifo_bits,br_fifo_width,br_fifo_height);
++
++ bfIcons[BF_ERROR] = MakePix1(br->win, br_error_bits,
++ br_error_width, br_error_height);
++
++/* bfIcons[BF_UNKNOWN] = MakePix1(br->win, br_unknown_bits,
++ br_unknown_width, br_unknown_height); */
++
++ bfIcons[BF_UNKNOWN] = bfIcons[BF_FILE];
++
++ bfIcons[BF_GIF] =MakePix1(br->win,br_gif_bits, br_gif_width, br_gif_height);
++ bfIcons[BF_PM] =MakePix1(br->win,br_pm_bits, br_pm_width, br_pm_height);
++ bfIcons[BF_PBM] =MakePix1(br->win,br_pbm_bits, br_pbm_width, br_pbm_height);
++ bfIcons[BF_XBM] =MakePix1(br->win,br_xbm_bits, br_xbm_width, br_xbm_height);
++
++ bfIcons[BF_SUNRAS] = MakePix1(br->win, br_sunras_bits,
++ br_sunras_width, br_sunras_height);
++ bfIcons[BF_BMP] = MakePix1(br->win,br_bmp_bits,
++ br_bmp_width, br_bmp_height);
++ bfIcons[BF_UTAHRLE] = MakePix1(br->win, br_utahrle_bits,
++ br_utahrle_width, br_utahrle_height);
++
++ bfIcons[BF_IRIS]=MakePix1(br->win,br_iris_bits,br_iris_width,br_iris_height);
++ bfIcons[BF_PCX] =MakePix1(br->win,br_pcx_bits, br_pcx_width, br_pcx_height);
++ 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_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);
++
++ bfIcons[BF_TARGA] = MakePix1(br->win, br_targa_bits,
++ br_targa_width, br_targa_height);
++
++ 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);
++
++
++ /* check that they all got built */
++ for (i=0; i<BF_MAX && bfIcons[i]; i++);
++ if (i<BF_MAX)
++ FatalError("unable to create all built-in icons for schnauzer");
++
++ for (i=0; i<MAXBRWIN; i++) {
++ resizeBrowse(&binfo[i], DEF_BROWWIDE, DEF_BROWHIGH);
++
++ XSelectInput(theDisp, binfo[i].win, ExposureMask | ButtonPressMask |
++ KeyPressMask | StructureNotifyMask);
++ }
++
++
++ trashPix = MakePix1(br->win, br_trash_bits, br_trash_width, br_trash_height);
++ if (!trashPix)
++ FatalError("unable to create all built-in icons for schnauzer");
++
++
++ /* create movecurs and copycurs cursors */
++ mcpix = MakePix1(rootW, filecurs_bits, filecurs_width, filecurs_height);
++ ccpix = MakePix1(rootW, fileccurs_bits, fileccurs_width, fileccurs_height);
++ dcpix = MakePix1(rootW, fdcurs_bits, fdcurs_width, fdcurs_height);
++ fcmpix= MakePix1(rootW, filecursm_bits, filecursm_width, filecursm_height);
++
++ if (mcpix && ccpix && fcmpix && dcpix) {
++ cursfg.red = cursfg.green = cursfg.blue = 0;
++ cursbg.red = cursbg.green = cursbg.blue = 0xffff;
++
++ movecurs = XCreatePixmapCursor(theDisp,mcpix,fcmpix,&cursfg,&cursbg,13,13);
++ copycurs = XCreatePixmapCursor(theDisp,ccpix,fcmpix,&cursfg,&cursbg,13,13);
++ delcurs = XCreatePixmapCursor(theDisp,dcpix,fcmpix,&cursbg,&cursfg,13,13);
++ if (!movecurs || !copycurs || !delcurs)
++ FatalError("unable to create schnauzer cursors...");
++ }
++ else FatalError("unable to create schnauzer cursors...");
++
++ XFreePixmap(theDisp, mcpix);
++ XFreePixmap(theDisp, ccpix);
++ XFreePixmap(theDisp, dcpix);
++ XFreePixmap(theDisp, fcmpix);
++
++
++ hasBeenSized = 1; /* we can now start looking at browse events */
++}
++
++
++/***************************************************************/
++void OpenBrowse()
++{
++ /* opens up a single browser window */
++ int i;
++ BROWINFO *br;
++ char path[MAXPATHLEN+1];
++
++ /* find next browser to be opened */
++ for (i=0; i<MAXBRWIN; i++) {
++ br = &binfo[i];
++ if (!br->vis) break;
++ }
++ if (i==MAXBRWIN) return; /* full up: shouldn't happen */
++
++ anyBrowUp = 1;
++ XMapRaised(theDisp, br->win);
++ br->vis = 1;
++
++ freeBfList(br);
++
++ /* see if some browser is pointing to the same path as CWD. If so,
++ copy the info, rather than reading the directory */
++ xv_getwd(path, sizeof(path));
++ if (path[strlen(path)-1] != '/') strcat(path,"/"); /* add trailing '/' */
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (strcmp(binfo[i].path,path)==0) break;
++ }
++
++ if (i<MAXBRWIN && &binfo[i] != br) copyDirInfo(&binfo[i], br);
++ else scanDir(br);
++
++ SCSetVal(&(br->scrl), 0);
++
++
++ /* see if that was the last one */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (!binfo[i].vis) break;
++ }
++ if (i==MAXBRWIN) { /* can't open any more */
++ windowMB.dim[WMB_BROWSE] = 1;
++ for (i=0; i<MAXBRWIN; i++) {
++ BTSetActive(&(binfo[i].but[BR_NEWWIN]), 0);
++ binfo[i].cmdMB.dim[BR_NEWWIN] = 1;
++ }
++ }
++
++
++ changedNumLit(br, -1, 0);
++}
++
++
++/***************************************************************/
++static void closeBrowse(br)
++ BROWINFO *br;
++{
++ int i;
++
++ WaitCursor();
++
++ /* closes a specified browse window */
++ XUnmapWindow(theDisp, br->win);
++ br->vis = 0;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (binfo[i].vis) break;
++ }
++ if (i==MAXBRWIN) anyBrowUp = 0;
++
++ /* free all info for this browse window */
++ freeBfList(br);
++ sprintf(br->path, BOGUSPATH);
++
++ /* turn on 'open new window' command doodads */
++ windowMB.dim[WMB_BROWSE] = 0;
++ for (i=0; i<MAXBRWIN; i++) {
++ BTSetActive(&(binfo[i].but[BR_NEWWIN]), 1);
++ binfo[i].cmdMB.dim[BR_NEWWIN] = 0;
++ }
++
++ SetCursors(-1);
++}
++
++
++/***************************************************************/
++void HideBrowseWindows()
++{
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (binfo[i].vis) {
++ XUnmapWindow(theDisp, binfo[i].win);
++ binfo[i].wasvis = 1;
++ binfo[i].vis = 0;
++ }
++ }
++}
++
++
++/***************************************************************/
++void UnHideBrowseWindows()
++{
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (binfo[i].wasvis) {
++ XMapRaised(theDisp, binfo[i].win);
++ binfo[i].wasvis = 0;
++ binfo[i].vis = 1;
++ }
++ }
++}
++
++
++/***************************************************************/
++void SetBrowseCursor(c)
++ Cursor c;
++{
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (haveWindows && binfo[i].win) XDefineCursor(theDisp, binfo[i].win, c);
++ }
++}
++
++
++/***************************************************************/
++void KillBrowseWindows()
++{
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (haveWindows && binfo[i].win) XDestroyWindow(theDisp, binfo[i].win);
++ }
++}
++
++
++static int *event_retP, *event_doneP;
++
++/***************************************************************/
++int BrowseCheckEvent(xev, retP, doneP)
++ XEvent *xev;
++ int *retP, *doneP;
++{
++ int i;
++
++ event_retP = retP; /* so don't have to pass these all over the place */
++ event_doneP = doneP;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (brChkEvent(&binfo[i], xev)) break;
++ }
++
++ if (i<MAXBRWIN) return 1;
++ return 0;
++}
++
++
++/***************************************************************/
++static int brChkEvent(br, xev)
++ BROWINFO *br;
++ XEvent *xev;
++{
++ /* checks event to see if it's a browse-window related thing. If it
++ is, it eats the event and returns '1', otherwise '0'. */
++
++ int i, rv;
++ char buf[1024];
++
++ rv = 1;
++
++ if (!hasBeenSized) return 0; /* ignore evrythng until we get 1st Resize */
++
++ 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 redraws for 'dumb' windows */
++ if (e->count > 0 && (e->window == br->scrl.win)) {}
++
++ else if (e->window == br->scrl.win) SCRedraw(&(br->scrl));
++
++ else if (e->window == br->win || e->window == br->iconW) { /* smart wins */
++ /* group individual expose rects into a single expose region */
++ int count;
++ Region reg;
++ XRectangle rect;
++ XEvent evt;
++
++ XSync(theDisp, False);
++
++ xvbcopy((char *) e, (char *) &evt, sizeof(XEvent));
++ reg = XCreateRegion();
++ count = 0;
++ do {
++ rect.x = evt.xexpose.x;
++ rect.y = evt.xexpose.y;
++ rect.width = evt.xexpose.width;
++ rect.height = evt.xexpose.height;
++
++ XUnionRectWithRegion(&rect, reg, reg);
++ count++;
++ } while (XCheckWindowEvent(theDisp, evt.xexpose.window,
++ ExposureMask, &evt));
++
++ XClipBox(reg, &rect); /* bounding box of region */
++ XSetRegion(theDisp, theGC, reg);
++
++ if (DEBUG) {
++ fprintf(stderr,"win = %lx, br->win = %lx, iconW = %lx\n",
++ e->window, br->win, br->iconW);
++ fprintf(stderr,"grouped %d expose events into %d,%d %dx%d rect\n",
++ count, rect.x, rect.y, rect.width, rect.height);
++ }
++
++ if (e->window == br->win) drawBrow(br);
++
++ else if (e->window == br->iconW)
++ exposeIconWin(br, rect.x, rect.y, rect.width, rect.height);
++
++ XSetClipMask(theDisp, theGC, None);
++ XDestroyRegion(reg);
++ }
++
++ else rv = 0;
++ }
++
++
++ else if (xev->type == ButtonPress) {
++ XButtonEvent *e = (XButtonEvent *) xev;
++ int i,x,y;
++ x = e->x; y = e->y;
++
++ if (e->button == Button1) {
++ if (e->window == br->win) clickBrow(br,x,y);
++ else if (e->window == br->scrl.win) SCTrack(&(br->scrl),x,y);
++ 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 rv = 0;
++ }
++
++
++ else if (xev->type == KeyPress) {
++ XKeyEvent *e = (XKeyEvent *) xev;
++ if (e->window == br->win) keyIconWin(br, e);
++ else rv = 0;
++ }
++
++
++ else if (xev->type == ConfigureNotify) {
++ XConfigureEvent *e = (XConfigureEvent *) xev;
++
++ if (e->window == br->win) {
++ if (DEBUG) fprintf(stderr,"browW got a configure event (%dx%d)\n",
++ e->width, e->height);
++
++ if (br->wide != e->width || br->high != e->height) {
++ if (DEBUG) fprintf(stderr,"Forcing a redraw! (from configure)\n");
++ XClearArea(theDisp, br->win, 0, 0,
++ (u_int) e->width, (u_int) e->height, True);
++ resizeBrowse(br, e->width, e->height);
++ }
++ }
++ else rv = 0;
++ }
++
++ else rv = 0;
++
++ return rv;
++}
++
++
++/***************************************************************/
++int BrowseDelWin(win)
++ Window win;
++{
++ /* got a delete window request. see if the window is a browser window,
++ and close accordingly. Return 1 if event was eaten */
++
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (binfo[i].win == win) {
++ closeBrowse(&binfo[i]);
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++
++/***************************************************************/
++static void resizeBrowse(br,w,h)
++ BROWINFO *br;
++ int w,h;
++{
++ XSizeHints hints;
++ int i, minv, maxv, curv, page, maxh;
++
++ if (br->wide == w && br->high == h) return; /* no change in size */
++
++ if (XGetNormalHints(theDisp, br->win, &hints)) {
++ hints.width = w;
++ hints.height = h;
++ hints.flags |= USSize;
++ XSetNormalHints(theDisp, br->win, &hints);
++ }
++
++ br->wide = w; br->high = h;
++ br->iwWide = br->wide - (2*LRMARGINS) - (br->scrl.tsize+1) - 2;
++ maxh = br->high - (TOPMARGIN + BOTMARGIN);
++
++ br->iwHigh = (maxh / ISPACE_HIGH) * ISPACE_HIGH;
++ if (br->iwHigh < ISPACE_HIGH) br->iwHigh = ISPACE_HIGH;
++
++ XMoveResizeWindow(theDisp, br->iconW, LRMARGINS, TOPMARGIN,
++ (u_int) br->iwWide, (u_int) br->iwHigh);
++
++
++ /* move the buttons around */
++ br->numbutshown = (br->wide / (BUTTW + 5));
++ RANGE(br->numbutshown, 1, BR_NBUTTS);
++ br->numbutshown--;
++
++ for (i=0; i<BR_NBUTTS; i++) {
++ /* 'close' always goes on right-most edge */
++
++ if (i<br->numbutshown)
++ br->but[i].x = br->wide - (1+br->numbutshown-i) * (BUTTW+5);
++ else if (i==BR_CLOSE)
++ br->but[i].x = br->wide - (BUTTW+5);
++ else
++ br->but[i].x = br->wide + 10; /* offscreen */
++
++ br->but[i].y = br->high - BUTTH - 5;
++ }
++
++ br->dirMB.x = br->wide/2 - br->dirMB.w/2;
++ br->dirMB.x = br->dirMB.x - br->cmdMB.w/2 + (StringWidth("123 files") + 6)/2;
++
++ br->dirMB.y = 5;
++
++ br->cmdMB.x = br->wide - LRMARGINS - br->cmdMB.w - 2;
++ br->cmdMB.y = 5;
++
++ br->numWide = br->iwWide / ISPACE_WIDE;
++ br->visHigh = br->iwHigh / ISPACE_HIGH;
++
++ /* compute minv,maxv,curv,page values based on new current size */
++ computeScrlVals(br, &maxv, &page);
++ if (br->scrl.val>maxv) br->scrl.val = maxv;
++
++ SCChange(&br->scrl, LRMARGINS+br->iwWide+1, TOPMARGIN,
++ 1, br->iwHigh, 0, maxv, br->scrl.val, page);
++}
++
++
++
++/***************************************************************/
++void SetBrowStr(str)
++ char *str;
++{
++ /* put string in *all* browse windows */
++ int i;
++
++ for (i=0; i<MAXBRWIN; i++)
++ setBrowStr(&binfo[i], str);
++}
++
++
++/***************************************************************/
++static void setBrowStr(br, str)
++ BROWINFO *br;
++ char *str;
++{
++ strncpy(br->dispstr, str, (size_t) 256);
++ drawBrowStr(br);
++ XFlush(theDisp);
++}
++
++
++/***************************************************************/
++void RegenBrowseIcons()
++{
++ /* called whenever colormaps have changed, and icons need to be rebuilt */
++
++ int i, j, iconcount;
++ BFIL *bf;
++ BROWINFO *br;
++
++ for (j=0; j<MAXBRWIN; j++) {
++ br = &binfo[j];
++
++ iconcount = 0;
++
++ for (i=0; i<br->bfLen; i++) {
++ bf = &(br->bfList[i]);
++
++ drawTemp(br, i, br->bfLen);
++
++ if (bf->pimage && bf->ftype == BF_HAVEIMG) {
++ xvDestroyImage(bf->ximage);
++ bf->ximage = Pic8ToXImage(bf->pimage, (u_int) bf->w, (u_int) bf->h,
++ browcols, browR, browG, browB);
++ iconcount++;
++ }
++
++ if ((i && (i %100)==0) ||
++ (iconcount && (iconcount% 20)==0)) { /* mention progress */
++
++ char tmp[64];
++
++ sprintf(tmp, "Re-coloring icons: processed %d out of %d...",
++ i+1, br->bfLen);
++ setBrowStr(br, tmp);
++ }
++ }
++
++ clearTemp(br);
++ setBrowStr(br, "");
++ drawIconWin(0, &(br->scrl)); /* redraw new icons */
++ }
++}
++
++
++/***************************************************************/
++void BRDeletedFile(name)
++ char *name;
++{
++ /* called when file 'name' has been deleted. If any of the browsers
++ were showing the directory that the file was in, does a rescan() */
++
++ int i;
++ char buf[MAXPATHLEN + 2], *tmp;
++
++ strcpy(buf, name);
++ tmp = BaseName(buf);
++ *tmp = '\0'; /* truncate after last '/' */
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (strcmp(binfo[i].path, buf)==0) rescanDir(&binfo[i]);
++ }
++}
++
++
++/***************************************************************/
++void BRCreatedFile(name)
++ char *name;
++{
++ BRDeletedFile(name);
++}
++
++
++/**************************************************************/
++/*** INTERNAL FUNCTIONS ***/
++/**************************************************************/
++
++
++/***************************************************************/
++static void doCmd(br, cmd)
++ BROWINFO *br;
++ int cmd;
++{
++ switch (cmd) {
++ case BR_CHDIR: doChdirCmd(br);
++ break;
++
++ case BR_DELETE: doDeleteCmd(br);
++ break;
++
++ case BR_MKDIR: doMkdirCmd(br);
++ break;
++
++ case BR_RENAME: doRenameCmd(br);
++ break;
++
++ case BR_RESCAN: rescanDir(br);
++ break;
++
++ case BR_UPDATE: rescanDir(br);
++ updateIcons(br);
++ break;
++
++ case BR_NEWWIN: cdBrow(br); /* try to open current dir */
++ OpenBrowse();
++ break;
++
++ case BR_GENICON: genSelectedIcons(br); break;
++
++ case BR_SELALL: {
++ int i; char buf[128];
++
++ for (i=0; i<br->bfLen; i++)
++ br->bfList[i].lit = 1;
++ br->numlit = br->bfLen;
++
++ /* EXCEPT for parent directory */
++ if (br->bfLen>0 && strcmp(br->bfList[0].name,"..")==0) {
++ br->numlit--; br->bfList[0].lit = 0;
++ }
++
++ changedNumLit(br, -1, 0);
++ drawIconWin(0, &(br->scrl));
++ }
++ break;
++
++ case BR_TEXTVIEW: doTextCmd(br); break;
++
++ case BR_QUIT: Quit(0); break;
++
++ case BR_CLOSE: closeBrowse(br); break;
++
++ case BR_HIDDEN: br->showhidden = !br->showhidden;
++ br->cmdMB.list[cmd] = (br->showhidden)
++ ? hideHstr : showHstr;
++ rescanDir(br);
++ break;
++
++ case BR_SELFILES: doSelFilesCmd(br); break;
++
++ case BR_RECURSUP: doRecurseCmd(br); break;
++ }
++}
++
++
++
++/***************************************************************/
++static void drawBrow(br)
++ BROWINFO *br;
++{
++ int i;
++
++ drawNumfiles(br);
++ drawTrash(br);
++ drawBrowStr(br);
++
++ for (i=0; i<BR_NBUTTS; i++) {
++ if (i<br->numbutshown || i == BR_CLOSE) BTRedraw(&(br->but[i]));
++ }
++
++ MBRedraw(&(br->dirMB));
++ MBRedraw(&(br->cmdMB));
++}
++
++
++/***************************************************************/
++static void drawNumfiles(br)
++ BROWINFO *br;
++{
++ char foo[40];
++ int x, y;
++
++ x = 30;
++ y = br->dirMB.y;
++
++ if (br->bfLen != 1) sprintf(foo, "%d files", br->bfLen);
++ else strcpy(foo, "1 file");
++
++ XSetForeground(theDisp, theGC, browbg);
++ XFillRectangle(theDisp,br->win, theGC, x+1,y+1,
++ (u_int) StringWidth(foo)+6, (u_int) br->dirMB.h-1);
++
++ XSetForeground(theDisp,theGC,browfg);
++ XDrawRectangle(theDisp,br->win, theGC, x,y,
++ (u_int) StringWidth(foo)+7, (u_int) br->dirMB.h);
++
++ Draw3dRect(br->win, x+1, y+1, (u_int) StringWidth(foo)+5,
++ (u_int) br->dirMB.h-2, R3D_IN, 2, browhi, browlo, browbg);
++
++ XSetForeground(theDisp,theGC,browfg);
++ DrawString(br->win, x+3, (int) CENTERY(mfinfo, y + br->dirMB.h/2), foo);
++}
++
++
++/***************************************************************/
++static void eraseNumfiles(br,nf)
++ BROWINFO *br;
++ int nf;
++{
++ char foo[40];
++
++ if (nf != 1) sprintf(foo,"%d files",nf);
++ else strcpy(foo,"1 file");
++
++ XClearArea(theDisp,br->win, 30, br->dirMB.y,
++ (u_int) StringWidth(foo)+8, (u_int) br->dirMB.h+1, False);
++}
++
++
++/***************************************************************/
++static void drawTrash(br)
++ BROWINFO *br;
++{
++ int x, y, w, h;
++
++ x = 5;
++ y = br->dirMB.y;
++ w = 20;
++ h = br->dirMB.h;
++
++ XSetForeground(theDisp, theGC, browbg);
++ XFillRectangle(theDisp,br->win, theGC, x+1,y+1, (u_int) w-1, (u_int) h-1);
++
++ XSetForeground(theDisp,theGC,browfg);
++ XDrawRectangle(theDisp,br->win, theGC, x,y, (u_int) w, (u_int) h);
++ Draw3dRect(br->win, x+1, y+1, (u_int) w-2, (u_int) h-2,
++ R3D_IN, 2, browhi, browlo, browbg);
++
++ XSetForeground(theDisp,theGC,browfg);
++ XSetBackground(theDisp,theGC,browbg);
++ XCopyPlane(theDisp, trashPix, br->win, theGC,
++ 0,0,(u_int) br_trash_width, (u_int) br_trash_height,
++ x+(w-br_trash_width)/2, y+(h-br_trash_height)/2,
++ 1L);
++}
++
++
++/***************************************************************/
++static int inTrash(br, mx,my)
++ BROWINFO *br;
++ int mx,my;
++{
++ int x, y, w, h;
++
++ x = 5;
++ y = br->dirMB.y;
++ w = 20;
++ h = br->dirMB.h;
++
++ return PTINRECT(mx, my, x,y,w,h);
++}
++
++
++/***************************************************************/
++static void drawBrowStr(br)
++ BROWINFO *br;
++{
++ int y;
++
++ y = br->high - (BUTTH+10) - (CHIGH + 6);
++
++ XSetForeground(theDisp, theGC, browbg);
++ XFillRectangle(theDisp, br->win, theGC, 0, y+3,
++ (u_int) br->wide, (u_int) CHIGH+1);
++
++ XSetForeground(theDisp, theGC, browfg);
++ XDrawLine(theDisp, br->win, theGC, 0, y, br->wide, y);
++ XDrawLine(theDisp, br->win, theGC, 0, y+CHIGH+4, br->wide, y+CHIGH+4);
++
++ XSetForeground(theDisp, theGC, (ctrlColor) ? browlo : browbg);
++ XDrawLine(theDisp, br->win, theGC, 0, y+1, br->wide, y+1);
++ XDrawLine(theDisp, br->win, theGC, 0, y+CHIGH+5, br->wide, y+CHIGH+5);
++
++ XSetForeground(theDisp, theGC, (ctrlColor) ? browhi : browfg);
++ XDrawLine(theDisp, br->win, theGC, 0, y+2, br->wide, y+2);
++ XDrawLine(theDisp, br->win, theGC, 0, y+CHIGH+6, br->wide, y+CHIGH+6);
++
++ XSetForeground(theDisp, theGC, browfg);
++ DrawString(br->win, 5, y+ASCENT+3, br->dispstr);
++}
++
++
++/***************************************************************/
++static void changedNumLit(br, sel, nostr)
++ BROWINFO *br;
++ int sel, nostr;
++{
++ int i, allowtext;
++
++ if (!nostr) setSelInfoStr(br, sel);
++ BTSetActive(&br->but[BR_DELETE], br->numlit>0);
++ br->cmdMB.dim[BR_DELETE] = !(br->numlit>0);
++
++ BTSetActive(&br->but[BR_RENAME], br->numlit==1);
++ br->cmdMB.dim[BR_RENAME] = !(br->numlit==1);
++
++ BTSetActive(&br->but[BR_GENICON], br->numlit>0);
++ br->cmdMB.dim[BR_GENICON] = !(br->numlit>0);
++
++ /* turn on 'text view' cmd if exactly one non-dir is lit */
++ allowtext = 0;
++ if (br->numlit == 1) {
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);
++ if (i<br->bfLen && br->bfList[i].ftype != BF_DIR) allowtext = 1;
++ }
++ BTSetActive(&br->but[BR_TEXTVIEW], allowtext);
++ br->cmdMB.dim[BR_TEXTVIEW] = !allowtext;
++}
++
++
++/***************************************************************/
++static void setSelInfoStr(br, sel)
++ BROWINFO *br;
++ int sel;
++{
++ /* sets the '# files selected' string in the brow window appropriately */
++
++ /* criteria:
++ * if no files are lit, display ''
++ * if 1 file is lit, pretend it was selected, fall through...
++ * if 1 or more files are lit
++ * if >1 files are lit, and clicked on nothing, disp '# files selected'
++ * otherwise, display info on selected file
++ */
++
++ int i;
++ char buf[256], buf1[256];
++ BFIL *bf;
++
++
++ /* default case if no special info */
++ if (br->numlit>0) sprintf(buf, "%d file%s selected", br->numlit,
++ (br->numlit>1) ? "s" : "");
++ else buf[0] = '\0';
++
++
++ if (br->numlit > 0) { /* one or more files lit */
++ if (br->numlit == 1) { /* pretend it was selected */
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);
++ sel = i;
++ }
++
++ if (sel >= 0 && sel < br->bfLen) { /* display info on selected file */
++ bf = &(br->bfList[sel]);
++
++ if (bf->lit) {
++ if (br->numlit>1) sprintf(buf1," (%d files selected)", br->numlit);
++ else buf1[0] = '\0';
++
++ if (bf->ftype==BF_HAVEIMG && bf->imginfo) {
++ sprintf(buf,"%s: %s", bf->name, bf->imginfo);
++ strcat(buf, buf1);
++ }
++
++ else if (bf->ftype != BF_DIR) { /* no info. display file size */
++ struct stat st;
++
++ sprintf(buf, "%s%s", br->path, bf->name); /* build filename */
++ if (stat(buf, &st) == 0) {
++ sprintf(buf, "%s: %ld bytes", bf->name, st.st_size);
++ strcat(buf, buf1);
++ }
++ }
++ }
++ }
++ }
++
++ setBrowStr(br, buf);
++}
++
++
++/***************************************************************/
++static void exposeIconWin(br, x,y,w,h)
++ BROWINFO *br;
++ int x,y,w,h;
++{
++ int i, j, cnt;
++
++ if (!hasBeenSized || !br->bfList || !br->bfLen) return;
++
++ /* figure out what icons intersect the clip rect, and only redraw those,
++ as drawing entirely clipped-out images *still* requires transmitting
++ the image */
++
++ cnt = (1 + br->visHigh) * br->numWide; /* # of icons to check */
++
++ for (i=0, j=br->scrl.val * br->numWide; i<cnt; i++,j++) {
++ int ix,iy,iw,ih;
++
++ /* figure out if this icon region is in the clip region */
++
++ ix = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */
++ iy = (i/br->numWide) * ISPACE_HIGH;
++ iw = ISPACE_WIDE;
++ ih = ISPACE_HIGH;
++
++ if ((ix+iw >= x) && (ix < x+w) && (iy+ih >= y) && (iy < y+h)) {
++ if (j>=0 && j < br->bfLen) drawIcon(br,j);
++ }
++ }
++
++ Draw3dRect(br->iconW, 0, 0, (u_int) br->iwWide-1, (u_int) br->iwHigh-1,
++ R3D_IN, 2, browhi, browlo, browbg);
++}
++
++
++/***************************************************************/
++static void drawIconWin(delta, sptr)
++ int delta;
++ SCRL *sptr;
++{
++ int i,indx, x,y, ix,iy, num;
++ BFIL *bf;
++ BROWINFO *br;
++ char tmpstr[64], *nstr;
++
++ /* figure out BROWINFO pointer from SCRL pointer */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (&(binfo[i].scrl) == sptr) break;
++ }
++ if (i==MAXBRWIN) return; /* didn't find one */
++
++ br = &binfo[i];
++
++ /* make sure we've been sized. Necessary, as creating/modifying the
++ scrollbar calls this routine directly, rather than through
++ BrowseCheckEvent() */
++
++ if (!hasBeenSized) return;
++
++ XSetForeground(theDisp, theGC, browfg);
++ XSetBackground(theDisp, theGC, browbg);
++
++ if (br->bfList && br->bfLen) {
++ num = br->visHigh * br->numWide;
++
++ for (i=0, indx=br->scrl.val * br->numWide; i<num; i++,indx++) {
++ int x,y,w,h;
++
++ /* erase old icon + string */
++ x = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */
++ y = (i/br->numWide) * ISPACE_HIGH;
++ w = ISPACE_WIDE;
++ h = ISPACE_HIGH;
++
++ XSetForeground(theDisp, theGC, browbg);
++ if (ctrlColor) { /* keep from erasing borders */
++ if (x<2) x = 2;
++ if (y<2) y = 2;
++ if (x+w > br->iwWide-4) w = (br->iwWide-4)-x + 2;
++ if (y+h > br->iwHigh-4) h = (br->iwHigh-4)-y + 2;
++ }
++ XFillRectangle(theDisp, br->iconW, theGC, x, y, ISPACE_WIDE, (u_int) h);
++
++ if (indx>=0 && indx < br->bfLen) drawIcon(br, indx);
++ }
++ }
++
++ Draw3dRect(br->iconW, 0, 0, (u_int) br->iwWide-1, (u_int) br->iwHigh-1,
++ R3D_IN, 2, browhi, browlo, browbg);
++}
++
++
++
++/***************************************/
++static void drawIcon(br, num)
++ BROWINFO *br;
++ int num;
++{
++ int i,x,y,ix,iy,sw,sh,sx,sy;
++ BFIL *bf;
++ char tmpstr[64], fixedname[64], *nstr, *str;
++
++
++ if (num<0 || num >= br->bfLen) return;
++ bf = &(br->bfList[num]);
++
++ i = num - (br->scrl.val * br->numWide);
++ if (i<0 || i>(br->visHigh+1)*br->numWide) return; /* not visible */
++
++ if (bf->lit) {
++ XSetForeground(theDisp, theGC, browbg);
++ XSetBackground(theDisp, theGC, browfg);
++ }
++ else {
++ XSetForeground(theDisp, theGC, browfg);
++ XSetBackground(theDisp, theGC, browbg);
++ }
++
++ x = (i%br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */
++ y = (i/br->numWide) * ISPACE_HIGH;
++
++ /* draw the icon */
++ ix = x + ISPACE_WIDE/2 - bf->w/2; /* center align */
++ iy = y + ISPACE_TOP + ISIZE_HIGH - bf->h; /* bottom align */
++
++
++ if (bf->ftype >= 0 && bf->ftype <BF_MAX) { /* built-in icon */
++ XCopyPlane(theDisp, bfIcons[bf->ftype], br->iconW, theGC,
++ 0, 0, (u_int) bf->w, (u_int) bf->h, ix, iy, 1L);
++ }
++
++ else if (bf->ftype == BF_HAVEIMG && bf->ximage) {
++ XPutImage(theDisp, br->iconW, theGC, bf->ximage, 0,0, ix,iy,
++ (u_int) bf->w, (u_int) bf->h);
++ }
++
++ else { /* shouldn't happen */
++ XDrawRectangle(theDisp, br->iconW, theGC, ix, iy,
++ (u_int) bf->w, (u_int) bf->h);
++ }
++
++
++ str = bf->name;
++#ifdef VMS
++ if (bf->ftype == BF_DIR) {
++ strcpy(fixedname, bf->name);
++ str = rindex(fixedname, '.'); /* lop off '.DIR' suffix, if any */
++ if (str) *str = '\0';
++ str = fixedname;
++ }
++#endif /* VMS */
++
++ if (!strcmp(bf->name,"..")) str = "<parent>";
++
++
++ /* decide if the title is too big, and shorten if neccesary */
++ if (StringWidth(str) > ISPACE_WIDE-6) {
++ int dotpos;
++ strncpy(tmpstr, str, (size_t) 56);
++ dotpos = strlen(tmpstr);
++ strcat(tmpstr,"...");
++
++ while(StringWidth(tmpstr) > ISPACE_WIDE-6 && dotpos>0) {
++ /* change last non-dot char in tmpstr to a dot, and lop off
++ last dot */
++
++ dotpos--;
++ tmpstr[dotpos] = '.';
++ tmpstr[dotpos+3] = '\0';
++ }
++
++ nstr = tmpstr;
++ }
++ else nstr = str;
++
++
++ /* draw the title */
++ sw = StringWidth(nstr);
++ sh = CHIGH;
++
++ sx = x + ISPACE_WIDE/2 - sw/2 - 2;
++ sy = y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP - 1;
++
++ XSetForeground(theDisp, theGC,
++ (bf->lit && bf->lit!=ICON_ONLY) ? browfg : browbg);
++ XFillRectangle(theDisp, br->iconW, theGC, sx, sy,
++ (u_int) sw + 4, (u_int) sh + 2);
++
++ XSetForeground(theDisp, theGC,
++ (bf->lit && bf->lit!=ICON_ONLY) ? browbg : browfg);
++ CenterString(br->iconW, x + ISPACE_WIDE/2,
++ y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP + CHIGH/2, nstr);
++}
++
++
++/***************************************/
++static void eraseIcon(br, num)
++ BROWINFO *br;
++ int num;
++{
++ /* note: doesn't erase the icon's title, just the icon itself */
++
++ int i,x,y,ix,iy,w,h;
++ BFIL *bf;
++ char tmpstr[64], *nstr;
++
++ if (num<0 || num >= br->bfLen) return;
++ bf = &(br->bfList[num]);
++
++ i = num - (br->scrl.val * br->numWide);
++
++ XSetForeground(theDisp, theGC, browbg);
++
++ x = (i % br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */
++ y = (i / br->numWide) * ISPACE_HIGH;
++ w = bf->w;
++ h = bf->h;
++
++ ix = x + ISPACE_WIDE/2 - w/2; /* center align */
++ iy = y + ISPACE_TOP + ISIZE_HIGH - h; /* bottom align */
++
++ if (ctrlColor) { /* keep from erasing borders */
++ if (ix<2) ix = 2;
++ if (iy<2) iy = 2;
++ if (ix+w > br->iwWide-2) w = (br->iwWide-2) - ix;
++ if (iy+h > br->iwHigh-2) h = (br->iwHigh-2) - iy;
++ }
++
++ XFillRectangle(theDisp, br->iconW, theGC, ix, iy, (u_int) w+1, (u_int) h+1);
++}
++
++
++/***************************************/
++static void eraseIconTitle(br, num)
++ BROWINFO *br;
++ int num;
++{
++ /* note: doesn't erase the icon, just the icon's title */
++
++ int i,x,y;
++
++ if (num<0 || num >= br->bfLen) return;
++ i = num - (br->scrl.val * br->numWide);
++
++ x = (i % br->numWide) * ISPACE_WIDE; /* x,y = top-left of icon region */
++ y = (i / br->numWide) * ISPACE_HIGH;
++
++ XSetForeground(theDisp, theGC, browbg);
++ XFillRectangle(theDisp, br->iconW, theGC,
++ x, y + ISPACE_TOP + ISIZE_HIGH + ISPACE_TTOP - 1,
++ (u_int) ISPACE_WIDE, (u_int) LINEHIGH);
++
++ if (ctrlColor)
++ Draw3dRect(br->iconW, 0, 0, (u_int) br->iwWide-1, (u_int) br->iwHigh-1,
++ R3D_IN, 2, browhi, browlo, browbg);
++}
++
++
++
++/***************************************/
++static void makeIconVisible(br, num)
++ BROWINFO *br;
++ int num;
++{
++ int sval, first, numvis;
++
++ /* if icon #i isn't visible, adjust scrollbar so it *is* */
++
++ sval = br->scrl.val;
++ first = sval * br->numWide;
++ numvis = br->visHigh * br->numWide;
++
++ while (num<first) { sval--; first = sval * br->numWide; }
++ if (num>= (first+numvis)) {
++ /* get #num into top row, to reduce future scrolling */
++ while (num>=(first+br->numWide) && sval<br->scrl.max) {
++ sval++; first = sval * br->numWide;
++ }
++ }
++ SCSetVal(&br->scrl, sval);
++}
++
++
++
++/***************************************************************/
++static void clickBrow(br, x,y)
++ BROWINFO *br;
++ int x,y;
++{
++ int i;
++ BUTT *bp;
++
++ for (i=0; i<BR_NBUTTS; i++) {
++ bp = &(br->but[i]);
++ if (PTINRECT(x,y,bp->x,bp->y,bp->w,bp->h)) break;
++ }
++
++ if (i<BR_NBUTTS) {
++ if (BTTrack(bp)) doCmd(br, i);
++ return;
++ }
++
++ if (MBClick(&(br->dirMB), x,y)) {
++ i = MBTrack(&(br->dirMB));
++ if (i >= 0) changedBrDirMB(br, i);
++ return;
++ }
++
++ if (MBClick(&(br->cmdMB), x,y)) {
++ i = MBTrack(&(br->cmdMB));
++ if (i >= 0) doCmd(br, i);
++ return;
++ }
++
++ return;
++}
++
++
++/***************************************************************/
++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, base, num, x,y,ix,iy, 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;
++
++ if (sel == -1) { /* clicked on nothing */
++ if (!multi) { /* deselect all */
++ for (i=0; i<br->bfLen; i++) {
++ if (br->bfList[i].lit) { br->bfList[i].lit = 0; drawIcon(br,i); }
++ br->numlit = 0;
++ }
++ }
++
++ changedNumLit(br, sel, 0);
++ br->lastIconClicked = -1;
++ }
++
++
++ else if (multi) { /* clicked on something, while 'multi' key down */
++ bf = &(br->bfList[sel]);
++
++ bf->lit = !bf->lit;
++ br->lastIconClicked = -1;
++
++ if (!bf->lit) br->numlit--;
++ else br->numlit++;
++
++ drawIcon(br, sel);
++
++ changedNumLit(br, sel, 0);
++ }
++
++
++ else { /* clicked on something, and not in 'multi' mode */
++ /* if there are some lit, and we *didn't* click one of them, turn
++ all others off */
++ if (br->numlit && !br->bfList[sel].lit) {
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit && i!=sel) {
++ bf->lit = 0;
++ drawIcon(br, i);
++ br->numlit--;
++ }
++ }
++ }
++
++
++ bf = &br->bfList[sel];
++
++ if (!bf->lit) {
++ bf->lit = 1;
++ drawIcon(br, sel);
++ br->numlit = 1;
++ }
++
++
++ changedNumLit(br, sel, 0);
++
++
++ /* see if we've double-clicked something */
++ if (sel==br->lastIconClicked && mtime-br->lastClickTime < DBLCLICKTIME) {
++ int k;
++ br->lastIconClicked = -1; /* YES */
++
++ doubleClick(br, sel);
++ return rv;
++ }
++
++ else {
++ br->lastIconClicked = sel;
++ br->lastClickTime = mtime;
++ }
++ }
++
++
++ changedNumLit(br, -1, 0);
++
++
++
++ { /* track mouse until button1 is released */
++
++ Window rW, win, cW;
++ int x, y, rootx, rooty, iwx, iwy, bwx, bwy;
++ unsigned int mask;
++ Cursor curs;
++ int samepos, oldx, oldy, oldbrnum, destic, origsval, first;
++ int hasrect, rx, ry, rw, rh;
++
++ rx = ry = rw = rh = 0;
++ first = 1; hasrect = 0; cpymode = 0;
++ origsval = br->scrl.val;
++
++ if ( (sel>=0 && !multi) || sel==-1) {
++ /* clicked on an icon, or clicked on nothing... */
++
++ while (!XQueryPointer(theDisp, rootW, &rW, &cW, &rootx, &rooty,
++ &x,&y,&mask));
++ if (mask & Button1Mask) { /* still held down */
++
++ if (sel == -1) curs = tcross;
++ else if ((mask & ControlMask) || (mask & ShiftMask)) {
++ curs = copycurs; cpymode = 1;
++ }
++ else curs = movecurs;
++
++ /* change cursors */
++ for (i=0; i<MAXBRWIN; i++)
++ XDefineCursor(theDisp,binfo[i].iconW, curs);
++
++ samepos = oldx = oldy = oldbrnum = 0;
++
++ while (1) { /* wait for button 1 to be released */
++ while (!XQueryPointer(theDisp,rootW,&rW,&win,&rootx,&rooty,
++ &x,&y,&mask));
++ if (!(mask & Button1Mask)) break;
++
++ if (sel>=0) { /* see if changed copy/move status (and cursor) */
++ int cmod;
++
++ cmod = (mask&ControlMask || mask&ShiftMask) ? 1 : 0;
++
++ if (cmod != cpymode && !dodel) {
++ curs = (cmod) ? copycurs : movecurs;
++ for (i=0; i<MAXBRWIN; i++)
++ XDefineCursor(theDisp,binfo[i].iconW, curs);
++ }
++ cpymode = cmod;
++
++
++ /* see if cursor is in any of the trash can areas */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (binfo[i].vis) {
++ XTranslateCoordinates(theDisp, rW, binfo[i].win, rootx,rooty,
++ &bwx,&bwy, &cW);
++ if (inTrash(&binfo[i], bwx, bwy)) break;
++ }
++ }
++
++ if (dodel && i==MAXBRWIN) { /* moved out */
++ dodel = 0;
++ curs = (cpymode) ? copycurs : movecurs;
++ for (i=0; i<MAXBRWIN; i++)
++ XDefineCursor(theDisp,binfo[i].iconW, curs);
++ }
++
++ else if (!dodel && i<MAXBRWIN) { /* moved in */
++ dodel = 1;
++ for (i=0; i<MAXBRWIN; i++)
++ XDefineCursor(theDisp,binfo[i].iconW, delcurs);
++ }
++ }
++
++
++
++ XTranslateCoordinates(theDisp, rW, br->iconW, rootx,rooty,
++ &iwx,&iwy, &cW);
++
++ /* find deepest child that the mouse is in */
++ while (win!=None) {
++ XTranslateCoordinates(theDisp, rW, win, rootx, rooty, &x, &y, &cW);
++ if (cW == None) break;
++ else win = cW;
++ }
++
++ for (i=0; i<MAXBRWIN && win!=binfo[i].iconW; i++);
++ if (i==MAXBRWIN) { destBr=(BROWINFO *) NULL; destFolderName = ""; }
++
++ /* if it's in any icon window, and we're doing icon-dragging
++ OR we're doing a rectangle-drag */
++
++ if (i<MAXBRWIN || sel == -1) {
++ if (i<MAXBRWIN) destBr = &binfo[i];
++ if (sel == -1) destBr = br;
++
++ /* AUTO-SCROLLING: scroll any icon window if we're doing an
++ icon-drag. Only scroll the original window if we're doing
++ a rect drag */
++
++ if (sel>=0 && (oldx!=x || oldy!=y || oldbrnum!=i)) { /* moved */
++ samepos = 0; oldx = x; oldy = y; oldbrnum = i;
++ }
++ else {
++ int scamt = 0;
++ if (sel == -1) { /* rectangle dragging */
++ if (iwy < SCROLLVERT) scamt = -1;
++ if (iwy < -PAGEVERT) scamt = -destBr->visHigh;
++ if (iwy > destBr->iwHigh-SCROLLVERT) scamt = 1;
++ if (iwy > destBr->iwHigh+PAGEVERT) scamt = destBr->visHigh;
++ }
++ else { /* file dragging */
++ if (y >= 0 && y < SCROLLVERT) scamt = -1;
++ if (y <= destBr->iwHigh && y > destBr->iwHigh-SCROLLVERT)
++ scamt = 1;
++ }
++
++ if ((scamt < 0 && destBr->scrl.val > 0) ||
++ (scamt > 0 && destBr->scrl.val < destBr->scrl.max)) {
++
++ if (hasrect) invertSelRect(br,rx,ry,rw,rh);
++ hasrect = 0;
++
++ SCSetVal(&(destBr->scrl), destBr->scrl.val + scamt);
++ Timer(150);
++ }
++ }
++
++
++ /* if we clicked on an icon (originally), and therefore are
++ showing the 'move files' cursor, see if the cursor is within
++ the icon region of any folders. If so, light up *the icon
++ only* of the selected folder, by setting it's 'lit' field to
++ ICON_ONLY, and clearing any other folders that might have
++ that set (only one dest folder can be lit at a time) */
++
++ if (sel>=0) {
++ destic = mouseInWhichIcon(destBr, x, y);
++
++ bf = (destic>=0) ? &(destBr->bfList[destic]) : (BFIL *) NULL;
++ if (!bf || (bf && bf->ftype == BF_DIR && bf->lit!=ICON_ONLY)) {
++ for (i=0; i<destBr->bfLen; i++) { /* clear prev dest */
++ if (destBr->bfList[i].lit == ICON_ONLY) {
++ destBr->bfList[i].lit = 0;
++ drawIcon(destBr, i);
++ }
++ }
++ destFolderName = ".";
++ }
++
++ if (bf && bf->ftype == BF_DIR && !bf->lit) {
++ bf->lit = ICON_ONLY;
++ drawIcon(destBr, destic);
++ destFolderName = bf->name;
++ }
++ }
++
++ /* Dragging a selection rectangle. */
++
++ else {
++ static int prevx, prevy, prevcnt;
++ int origy, top, left, wide, high, cnt;
++
++ if (first) { prevx = mx; prevy = my; first=0; prevcnt = -1; }
++
++ /* set x,y to iconW coordinate system, clipped... */
++ x = iwx; y = iwy;
++ RANGE(x, 0, br->iwWide-1);
++ RANGE(y, 0, br->iwHigh-1);
++
++ if (x != prevx || y != prevy || !hasrect) { /* cursor moved */
++ origy = my - (br->scrl.val - origsval) * ISPACE_HIGH;
++
++ if (hasrect) invertSelRect(br, rx, ry, rw, rh); /* turn off */
++
++ rx = (mx < x) ? mx : x;
++ ry = (origy < y) ? origy : y;
++ rw = abs(mx - x);
++ rh = abs(origy - y);
++
++ /* figure out which icons need to be lit/unlit. Only
++ redraw those that have changed state */
++
++ for (i=0,cnt=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ int ix, iy, isin, light;
++
++ ix = ((i%br->numWide) * ISPACE_WIDE)
++ + ISPACE_WIDE/2 - bf->w/2;
++ iy = ((i/br->numWide) * ISPACE_HIGH)
++ + ISPACE_TOP + ISIZE_HIGH - bf->h;
++
++ iy = iy - br->scrl.val * ISPACE_HIGH;
++
++ /* is the icon rectangle of this beastie inside the
++ dragging rectangle ? */
++
++ isin = (ix+bf->w >= rx && ix < rx+rw &&
++ iy+bf->h >= ry && iy < ry+rh);
++
++ if (isin) {
++ if (bf->lit==0) {
++ bf->lit = TEMP_LIT; drawIcon(br, i);
++ }
++ else if (bf->lit==1) {
++ bf->lit = TEMP_LIT1; drawIcon(br, i);
++ }
++ }
++ else {
++ if (bf->lit == TEMP_LIT) {
++ bf->lit = 0; drawIcon(br, i);
++ }
++ else if (bf->lit == TEMP_LIT1) {
++ bf->lit = 1; drawIcon(br, i);
++ }
++ }
++
++ if (bf->lit) cnt++;
++ }
++
++ invertSelRect(br, rx, ry, rw, rh); /* turn on */
++ hasrect = 1;
++
++ if (cnt != prevcnt) {
++ if (cnt) sprintf(buf, "%d file%s selected", cnt,
++ (cnt>1) ? "s" : "");
++ else buf[0]='\0';
++ setBrowStr(br, buf);
++ prevcnt = cnt;
++ }
++
++ prevx = x; prevy = y;
++ }
++ }
++ }
++
++ else { /* NOT in an icon window... */
++ /* turn off ALL ICON_ONLY icons in ALL icon windows... */
++ for (i=0; i<MAXBRWIN; i++) {
++ for (j=0, bf=binfo[i].bfList; j<binfo[i].bfLen; j++,bf++) {
++ if (bf->lit == ICON_ONLY) {
++ bf->lit = 0;
++ drawIcon(&binfo[i], j);
++ }
++ }
++ }
++ }
++ }
++
++ /* RELEASED BUTTON: back to normal arrow cursor */
++ for (i=0; i<MAXBRWIN; i++)
++ XDefineCursor(theDisp, binfo[i].iconW, None);
++
++ if (sel == -1) { /* was dragging rectangle */
++ if (hasrect) invertSelRect(br, rx, ry, rw, rh);
++
++ br->numlit = 0;
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (!multi && bf->lit == 1) { bf->lit = 0; drawIcon(br, i); }
++
++ if (bf->lit == TEMP_LIT || bf->lit == TEMP_LIT1) {
++ bf->lit = 1; drawIcon(br, i);
++ }
++
++ if (bf->lit) br->numlit++;
++ }
++
++ changedNumLit(br, -1, 0);
++ }
++ }
++ }
++ }
++
++
++ /* if doing a copy or a move, do the thing to the files */
++ if (sel >= 0) {
++ char *destFolder;
++
++ if (DEBUG) {
++ fprintf(stderr,"---------------\n");
++ fprintf(stderr,"Source Dir: '%s'\n", br->path);
++ fprintf(stderr,"Dest Dir: '%s'\n", destBr ? destBr->path : "<null>");
++ fprintf(stderr,"Dest Folder: '%s'\n", destFolderName);
++ }
++
++
++ if (!br->numlit) {
++ if (DEBUG) fprintf(stderr, "no selected files. Nothing to do!\n");
++ }
++
++ else if (dodel) {
++ doDeleteCmd(br);
++ }
++
++ else if (!destBr || strlen(destFolderName) == 0) {
++ if (DEBUG) fprintf(stderr, "no destination. Nothing to do!\n");
++ }
++
++ else if (strcmp(destFolderName,".") == 0 &&
++ strcmp(br->path, destBr->path) == 0) {
++ if (DEBUG) fprintf(stderr,"source == destination. Nothing to do!\n");
++ }
++
++ else { /* have to do some copying/moving */
++ char **nlist; int ncnt;
++
++ if (DEBUG) fprintf(stderr,"Files to %s: ", cpymode ? "copy" : "move");
++
++ nlist = (char **) malloc(br->numlit * sizeof(char *));
++ if (!nlist) FatalError("clickIconWin: couldn't malloc nlist");
++
++ /* copy names to nlist */
++ for (i=ncnt=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit == 1 && ncnt < br->numlit) {
++ nlist[ncnt] = (char *) malloc(strlen(bf->name)+1);
++ if (!nlist[ncnt]) FatalError("out of memory building namelist");
++
++ strcpy(nlist[ncnt], bf->name);
++ ncnt++;
++ if (DEBUG) fprintf(stderr, "%s ", bf->name);
++ }
++ }
++ if (DEBUG) fprintf(stderr,"\n\n");
++
++#ifdef VMS
++ /*
++ * For VMS, our directory file names are identifed by the
++ * special filename extension, ".DIR". Unfortunately, this
++ * needs to be stripped before we ever actually use the name
++ * in a copy command... :( RLD 26-FEB-1993
++ */
++
++ *rindex ( destFolderName, '.' ) = '\0';
++#endif
++
++
++ dragFiles(br, destBr, br->path, destBr->path, destFolderName, nlist,
++ ncnt, cpymode);
++
++ /* free namelist */
++ for (i=0; i<ncnt; i++) if (nlist[i]) free(nlist[i]);
++ free(nlist);
++ }
++
++
++ if (destBr) { /* turn off any ICON_ONLY folders */
++ for (i=0, bf=destBr->bfList; i<destBr->bfLen; i++,bf++) {
++ if (bf->lit == ICON_ONLY) {
++ bf->lit = 0;
++ drawIcon(destBr, i);
++ }
++ }
++ }
++ } /* end of 'tracking' sub-function */
++
++ return rv;
++}
++
++/*******************************************/
++static void doubleClick(br, sel)
++ BROWINFO *br;
++ int sel;
++{
++ int i, j, k;
++ char buf[512];
++ BFIL *bf;
++
++ /* called to 'open' icon #sel, which could be a file or a dir */
++
++ /* if sel == -1, then called via RETURN key. just use first lit item
++ as thing that was double clicked on */
++
++ if (sel < 0) {
++ for (sel=0; sel<br->bfLen && br->bfList[sel].lit==0; sel++);
++ }
++
++ j = 0;
++ k = numnames;
++ if (sel < 0 || sel >= br->bfLen) return; /* no selection */
++
++ /* if this isn't a dir, copy it, and all other selected non-dir
++ filenames into the ctrl list */
++ if (ISLOADABLE(br->bfList[sel].ftype)) {
++ AddFNameToCtrlList(br->path, br->bfList[sel].name);
++ j++;
++ }
++
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit && ISLOADABLE(bf->ftype) && i!=sel) {
++ AddFNameToCtrlList(br->path, bf->name);
++ j++;
++ }
++ }
++
++ /* clear all 'other' selections */
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit && i!=sel) {
++ bf->lit = 0;
++ drawIcon(br, i);
++ }
++ }
++ br->numlit = 1;
++ changedNumLit(br, sel, 0);
++
++
++ if (j && k<numnames) { /* stuff was *actually* added to the list */
++ curname = nList.selected = k;
++ ChangedCtrlList(); /* added something to list */
++ }
++
++
++
++ /* double-clicked something. We should do something about it */
++ if (br->bfList[sel].ftype == BF_DIR) { /* try to cd */
++#ifndef VMS
++ sprintf(buf, "%s%s", br->path, br->bfList[sel].name);
++#else
++ if (strcmp(br->bfList[sel].name,"..")==0) sprintf(buf,"[-]");
++ else sprintf(buf, "%s%s", br->path, br->bfList[sel].name);
++#endif
++
++ if (chdir(buf)) {
++ char str[512];
++ sprintf(str,"Unable to cd to '%s'\n", br->bfList[sel].name);
++ setBrowStr(br, str);
++ XBell(theDisp, 50);
++ }
++ else {
++ scanDir(br);
++ SCSetVal(&(br->scrl), 0); /* reset to top on a chdir */
++ }
++ }
++
++ else { /* not a directory. Try to open it as a file */
++ int j;
++
++ sprintf(buf, "%s%s", br->path, br->bfList[sel].name);
++
++ /* if name is already in namelist, make it the current selection */
++ for (j=0; j<numnames && strcmp(namelist[j],buf); j++);
++
++ if (j<numnames) {
++ if (nList.selected != j) {
++ curname = nList.selected = j;
++ ChangedCtrlList();
++ }
++ *event_retP = THISNEXT;
++ }
++ else { *event_retP = LOADPIC; SetDirFName(buf); }
++
++ *event_doneP = 1; /* make MainLoop load image */
++ }
++}
++
++/*******************************************/
++static int mouseInWhichIcon(br, mx, my)
++ BROWINFO *br;
++ int mx, my;
++{
++ /* mx,my are mouse position in iconW coordinates. Returns '-1' if the
++ mouse is not in any icon */
++
++ int i, x, y, ix, iy, sel, base, num;
++ BFIL *bf;
++
++ /* figure out what was clicked... */
++ base = br->scrl.val * br->numWide;
++ num = (1+br->visHigh) * br->numWide;
++
++ for (i=0, sel=base; i<num; i++,sel++) {
++ if (sel>=0 && sel<br->bfLen) {
++ bf = &(br->bfList[sel]);
++
++ x = (i%br->numWide) * ISPACE_WIDE; /* x,y=top-left of icon region */
++ y = (i/br->numWide) * ISPACE_HIGH;
++
++ ix = x + ISPACE_WIDE/2 - bf->w/2; /* center align */
++ iy = y + ISPACE_TOP + ISIZE_HIGH - bf->h; /* bottom align */
++
++ if (PTINRECT(mx,my, ix, iy, bf->w, bf->h)) break;
++ }
++ }
++
++ if (i==num) return -1;
++ return sel;
++}
++
++
++/*******************************************/
++static void invertSelRect(br, x, y, w, h)
++ BROWINFO *br;
++ int x,y,w,h;
++{
++ if (w>1 && h>1) {
++ XSetState(theDisp,theGC, browfg, browbg, GXinvert, browfg^browbg);
++ XDrawRectangle(theDisp, br->iconW, theGC, x,y, (u_int) w, (u_int) h);
++ XSetState(theDisp,theGC, browfg, browbg, GXcopy, AllPlanes);
++ }
++}
++
++
++
++
++/***************************************************************/
++static void keyIconWin(br, kevt)
++ BROWINFO *br;
++ XKeyEvent *kevt;
++{
++ char buf[128];
++ KeySym ks;
++ int stlen, shift, dealt, ck;
++
++ stlen = XLookupString(kevt, buf, 128, &ks, (XComposeStatus *) NULL);
++ shift = kevt->state & ShiftMask;
++ ck = CursorKey(ks, shift, 1);
++ dealt = 1;
++
++ RemapKeyCheck(ks, buf, &stlen);
++
++ /* check for arrow keys, Home, End, PgUp, PgDown, etc. */
++ if (ck!=CK_NONE) browKey(br,ck);
++ else dealt = 0;
++
++ /* fake tab and backtab to be same as 'space' and 'backspace' */
++ if (ks==XK_Tab && shift) { buf[0] = '\010'; stlen = 1; }
++ if (ks==XK_Tab && !shift) { buf[0] = ' '; stlen = 1; }
++
++ if (dealt || !stlen) return;
++
++ /* keyboard equivalents */
++ switch (buf[0]) {
++ case '\003': doCmd(br, BR_CHDIR); break; /* ^C = Chdir */
++ case '\004': doCmd(br, BR_DELETE); break; /* ^D = Delete Files */
++ case '\016': doCmd(br, BR_MKDIR); break; /* ^N = New Directory */
++ case '\022': doCmd(br, BR_RENAME); break; /* ^R = Rename */
++ case '\023': doCmd(br, BR_RESCAN); break; /* ^S = reScan */
++ case '\025': doCmd(br, BR_UPDATE); break; /* ^U = Update icons */
++ case '\027': doCmd(br, BR_NEWWIN); break; /* ^W = open new Window */
++ case '\007': doCmd(br, BR_GENICON); break; /* ^G = Generate icons */
++ case '\001': doCmd(br, BR_SELALL); break; /* ^A = select All */
++ case '\024': doCmd(br, BR_TEXTVIEW); break; /* ^T = Textview */
++ case '\005': doCmd(br, BR_RECURSUP); break; /* ^E = rEcursive update */
++ case '\021': doCmd(br, BR_QUIT); break; /* ^Q = Quit xv */
++
++ case '\006': doCmd(br, BR_SELFILES); break; /* ^F = Select Files */
++
++
++ /* case '\003': FakeButtonPress(&but[BCMTVIEW]); break; */ /* ^C */
++
++ case '\033': doCmd(br, BR_CLOSE); break; /* ESC = Close window */
++
++ case '\r':
++ case '\n': doubleClick(br, -1); break; /* RETURN = load selected */
++
++ case ' ':
++ case '\010':
++ case '\177': /* SPACE = load next, BS/DEL = load prev */
++ if (br->bfLen && br->numlit >= 1) {
++ int i, j, viewsel;
++ char fname[MAXPATHLEN];
++
++ /* if 'shift-space' find last lit icon, select the next one after it,
++ and load it. If 'space' do the same, but lose prior lit. These
++ are the only cases where br->numlit >1 allowed */
++
++ if (br->numlit>1 && buf[0] != ' ') return;
++
++ if (buf[0]==' ' && (br->numlit>1 || (br->numlit==1 && shift))) {
++ for (i=br->bfLen-1; i>=0 && !br->bfList[i].lit; i--); /* i=last lit */
++ if (i==br->bfLen-1) return;
++
++ i++;
++ if (!shift) {
++ for (j=0; j<br->bfLen; j++) {
++ if (br->bfList[j].lit && j!=i) {
++ br->bfList[j].lit = 0;
++ drawIcon(br, j);
++ }
++ }
++ }
++
++ br->bfList[i].lit = 1;
++
++ for (j=0, br->numlit=0; j<br->bfLen; j++)
++ if (br->bfList[j].lit) br->numlit++;
++
++ makeIconVisible(br, i);
++ drawIcon(br, i);
++ setSelInfoStr(br, i);
++
++ /* load this file, stick it in ctrlList, etc. */
++
++ if (ISLOADABLE(br->bfList[i].ftype)) {
++ char foo[256];
++
++ j = numnames;
++ AddFNameToCtrlList(br->path, br->bfList[i].name);
++ if (j<numnames) { /* actually added it */
++ curname = nList.selected = j;
++ ChangedCtrlList();
++ }
++
++ /* try to open this file */
++ sprintf(foo, "%s%s", br->path, br->bfList[i].name);
++ for (j=0; j<numnames && strcmp(namelist[j],foo); j++);
++ if (j<numnames) {
++ curname = nList.selected = j;
++ ChangedCtrlList();
++ *event_retP = THISNEXT;
++ }
++ else { *event_retP = LOADPIC; SetDirFName(foo); }
++
++ *event_doneP = 1;
++ }
++ }
++
++ else { /* not SPACE, or SPACE and lit=1 and not shift */
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++); /* find lit one */
++ sprintf(fname, "%s%s", br->path, br->bfList[i].name);
++ viewsel = !(strcmp(fname, fullfname));
++
++ if (viewsel) {
++ if (buf[0]==' ') browKey(br, CK_RIGHT);
++ else browKey(br, CK_LEFT);
++ }
++
++ if (!br->bfList[i].lit || !viewsel) { /* changed selection */
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++); /* find it */
++ if (br->bfList[i].ftype != BF_DIR)
++ doubleClick(br, -1);
++ }
++ }
++ }
++ break;
++
++
++ default: /* unknown character. Take it as an alpha accelerator */
++ if (buf[0] > 32) browAlpha(br, buf[0]);
++ else XBell(theDisp, 0);
++ break;
++ }
++
++}
++
++
++/***************************************************/
++static void browKey(br, key)
++ BROWINFO *br;
++ int key;
++{
++ int i,j;
++
++ if (!br->bfLen) return;
++
++ /* an arrow key (or something like that) was pressed in icon window.
++ change selection/scrollbar accordingly */
++
++ /* handle easy keys */
++ if (key == CK_PAGEUP) SCSetVal(&br->scrl, br->scrl.val - br->scrl.page);
++ if (key == CK_PAGEDOWN) SCSetVal(&br->scrl, br->scrl.val + br->scrl.page);
++ if (key == CK_HOME) SCSetVal(&br->scrl, br->scrl.min);
++ if (key == CK_END) SCSetVal(&br->scrl, br->scrl.max);
++
++ /* handle up/down/left/right keys
++ *
++ * if precisely *one* item is lit, than the up/down/left/right keys move
++ * the selection.
++ *
++ * if NO items are lit, then left/right select the first/last fully-displayed
++ * icon, and up/down simply scroll window up or down, without selecting
++ * anything
++ *
++ * if more than one item is lit, up/down/left/right keys BEEP
++ */
++
++ if (key==CK_UP || key==CK_DOWN || key==CK_LEFT || key==CK_RIGHT) {
++
++ if (br->numlit > 1) XBell(theDisp, 50);
++ else if (br->numlit == 1) {
++ /* find it */
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);
++
++ /* if it's not visible, lose it */
++ if ((i < br->scrl.val * br->numWide) ||
++ (i >= (br->scrl.val + br->visHigh) * br->numWide)) {
++ br->numlit = 0;
++ br->bfList[i].lit = 0;
++ drawIcon(br, i);
++ }
++ else {
++ /* make it visible */
++ makeIconVisible(br, i);
++
++ j = i;
++
++ if (key == CK_UP) j = i - br->numWide;
++ if (key == CK_DOWN) j = i + br->numWide;
++ if (key == CK_LEFT) j = i - 1;
++ if (key == CK_RIGHT) j = i + 1;
++
++ if (j >= 0 && j < br->bfLen) {
++ br->bfList[i].lit = 0;
++ br->bfList[j].lit = 1;
++ makeIconVisible(br,j);
++ drawIcon(br,i);
++ drawIcon(br,j);
++ setSelInfoStr(br, j);
++ }
++ }
++ }
++
++
++ if (br->numlit == 0) { /* no current selection */
++ if (key == CK_UP) SCSetVal(&br->scrl, br->scrl.val - 1);
++ if (key == CK_DOWN) SCSetVal(&br->scrl, br->scrl.val + 1);
++ if (key == CK_LEFT || key == CK_RIGHT) {
++ if (key == CK_LEFT) i = (br->scrl.val+br->visHigh) * br->numWide - 1;
++ else i = (br->scrl.val * br->numWide);
++ RANGE(i, 0, br->bfLen-1);
++ br->bfList[i].lit = 1;
++ br->numlit = 1;
++ changedNumLit(br, i, 0);
++ drawIcon(br, i);
++ }
++ }
++ }
++}
++
++
++
++/***************************************************/
++static void browAlpha(br, ch)
++ BROWINFO *br;
++ int ch;
++{
++ /* find first 'plain' file that is lexically >= than the given ch */
++
++ int i,j;
++
++ if (!br->bfLen) return;
++ if (ch <= ' ' || ch > '\177') return; /* ignore 'funny' keys */
++
++ for (i=0; i<br->bfLen && br->bfList[i].ftype==BF_DIR; i++);
++ if (i==br->bfLen) return; /* only directories in this dir */
++
++ for ( ; i<br->bfLen; i++) {
++ if (br->bfList[i].name[0] >= ch) break;
++ }
++
++ if (i==br->bfLen) i--;
++
++ for (j=0; j<br->bfLen; j++) {
++ if (br->bfList[j].lit) {
++ br->bfList[j].lit = 0;
++ drawIcon(br, j);
++ }
++ }
++
++ br->bfList[i].lit = 1;
++ drawIcon(br, i);
++ br->numlit = 1;
++
++ makeIconVisible(br, i);
++ changedNumLit(br, i, 0);
++}
++
++
++
++/***************************************************/
++static void changedBrDirMB(br, sel)
++ BROWINFO *br;
++ int sel;
++{
++
++ if (sel != 0) { /* changed directories */
++ char tmppath[MAXPATHLEN+1];
++ int i;
++
++ /* build 'tmppath' */
++ tmppath[0] = '\0';
++ for (i = br->ndirs-1; i>=sel; i--)
++ strcat(tmppath, br->mblist[i]);
++
++ if (tmppath[0] == '\0') {
++ /* special case: if cd to '/', fix path (it's currently "") */
++#ifdef apollo /*** Apollo DomainOS uses // as the network root ***/
++ strcpy(tmppath,"//");
++#else
++ strcpy(tmppath,"/");
++#endif
++ }
++#ifdef VMS
++ else {
++ /*
++ * The VMS chdir always needs 2 components (device and directory),
++ * so convert "/device" to "/device/000000" and convert
++ * "/" to "/XV_Root_Device/000000" (XV_RootDevice will need to be
++ * a special concealed device setup to provide list of available
++ * disks).
++ *
++ * End 'tmppath' by changing trailing '/' (of dir name) to a '\0'
++ */
++ *rindex ( tmppath, '/') = '\0';
++ if ( ((br->ndirs-sel) == 2) && (strlen(tmppath) > 1) )
++ strcat ( tmppath, "/000000" ); /* add root dir for device */
++ else if ((br->ndirs-sel) == 1 )
++ strcpy ( tmppath, "/XV_Root_Device/000000" ); /* fake top level */
++ }
++#endif
++
++ if (chdir(tmppath)) {
++ char str[512];
++ sprintf(str,"Unable to cd to '%s'\n", tmppath);
++ MBRedraw(&(br->dirMB));
++ setBrowStr(br,str);
++ XBell(theDisp, 50);
++ }
++ else {
++ scanDir(br);
++ SCSetVal(&br->scrl, 0); /* reset to top of window on a chdir */
++ }
++ }
++}
++
++
++
++/***************************************************************/
++static int cdBrow(br)
++ BROWINFO *br;
++{
++ /* returns non-zero on failure */
++
++ int rv;
++
++ /* temporarily excise trailing '/' char from br->path */
++ if ((strlen(br->path) > (size_t) 2) && br->path[strlen(br->path)-1] == '/')
++ br->path[strlen(br->path)-1] = '\0';
++
++ rv = chdir(br->path);
++ if (rv) {
++ char str[512];
++ sprintf(str, "Unable to cd to '%s'\n", br->path);
++ setBrowStr(br, str);
++ XBell(theDisp, 50);
++ }
++
++ strcat(br->path, "/"); /* put trailing '/' back on */
++ return rv;
++}
++
++
++/***************************************************************/
++static void copyDirInfo(srcbr, dstbr)
++ BROWINFO *srcbr, *dstbr;
++{
++ /* copies br info from an already existing browser window
++ (ie, one that is already showing the same directory) */
++
++ int i, oldnum, maxv, page;
++
++ oldnum = dstbr->bfLen;
++ dstbr->lastIconClicked = -1;
++ setBrowStr(dstbr,"");
++
++ /* copy mblist */
++ dstbr->ndirs = srcbr->ndirs;
++ for (i=0; i<dstbr->ndirs; i++) {
++ dstbr->mblist[i] = (char *) malloc(strlen(srcbr->mblist[i]) + 1);
++ if (!dstbr->mblist[i]) FatalError("unable to malloc brMBlist[]");
++ strcpy(dstbr->mblist[i], srcbr->mblist[i]);
++ }
++
++ dstbr->dirMB.list = srcbr->mblist;
++ dstbr->dirMB.nlist = srcbr->ndirs;
++
++ XClearArea(theDisp, dstbr->dirMB.win, dstbr->dirMB.x, dstbr->dirMB.y,
++ dstbr->dirMB.w+3, dstbr->dirMB.h+3, False);
++
++ i = StringWidth(dstbr->mblist[0]) + 10;
++ dstbr->dirMB.x = dstbr->dirMB.x + dstbr->dirMB.w/2 - i/2;
++ dstbr->dirMB.w = i;
++ MBRedraw(&dstbr->dirMB);
++
++ strcpy(dstbr->path, srcbr->path);
++
++ WaitCursor();
++ freeBfList(dstbr); /* just to be safe */
++
++ /* copy the bfList info */
++ dstbr->numlit = 0;
++ dstbr->bfLen = srcbr->bfLen;
++
++ dstbr->bfList = (BFIL *) calloc((size_t) dstbr->bfLen, sizeof(BFIL));
++ if (!dstbr->bfList) FatalError("can't create bfList!");
++
++ for (i=0; i<dstbr->bfLen; i++) {
++ BFIL *sbf, *dbf;
++
++ if ((i&0x03) == 0) drawTemp(dstbr, i, dstbr->bfLen);
++ if ((i & 0x3f) == 0) WaitCursor();
++
++ sbf = &(srcbr->bfList[i]);
++ dbf = &(dstbr->bfList[i]);
++
++ if (sbf->name) {
++ dbf->name = (char *) malloc(strlen(sbf->name) + 1);
++ if (!dbf->name) FatalError("ran out of memory for dbf->name");
++ strcpy(dbf->name, sbf->name);
++ }
++ else dbf->name = (char *) NULL;
++
++ if (sbf->imginfo) {
++ dbf->imginfo = (char *) malloc(strlen(sbf->imginfo) + 1);
++ if (!dbf->imginfo) FatalError("ran out of memory for dbf->imginfo");
++ strcpy(dbf->imginfo, sbf->imginfo);
++ }
++ else dbf->imginfo = (char *) NULL;
++
++ dbf->ftype = sbf->ftype;
++ dbf->lit = 0;
++ dbf->w = sbf->w;
++ dbf->h = sbf->h;
++
++ if (sbf->pimage) {
++ dbf->pimage = (byte *) malloc((size_t) dbf->w * dbf->h);
++ if (!dbf->pimage) FatalError("ran out of memory for dbf->pimage");
++ xvbcopy((char *) sbf->pimage, (char *) dbf->pimage,
++ (size_t) (dbf->w * dbf->h));
++ }
++ else dbf->pimage = (byte *) NULL;
++
++ if (sbf->ximage) {
++ dbf->ximage = (XImage *) malloc(sizeof(XImage));
++ if (!dbf->ximage) FatalError("ran out of memory for dbf->ximage");
++ xvbcopy((char *) sbf->ximage, (char *) dbf->ximage, sizeof(XImage));
++
++ if (sbf->ximage->data) {
++ dbf->ximage->data = (char *) malloc((size_t) dbf->ximage->height *
++ dbf->ximage->bytes_per_line);
++ if (!dbf->ximage->data) FatalError("ran out of memory for ximg data");
++ xvbcopy((char *) sbf->ximage->data, (char *) dbf->ximage->data,
++ (size_t) dbf->ximage->height * dbf->ximage->bytes_per_line);
++ }
++ }
++ else dbf->ximage = (XImage *) NULL;
++
++ }
++
++ clearTemp(dstbr);
++
++ /* misc setup (similar to endScan(), but without unnecessary stuff) */
++ eraseNumfiles(dstbr, oldnum);
++ drawNumfiles(dstbr);
++ drawTrash(dstbr);
++ computeScrlVals(dstbr, &maxv, &page);
++ if (dstbr->scrl.val > maxv) dstbr->scrl.val = maxv;
++
++ XClearArea(theDisp, dstbr->iconW, 0, 0, (u_int) dstbr->iwWide,
++ (u_int) dstbr->iwHigh, True);
++ SCSetRange(&dstbr->scrl, 0, maxv, dstbr->scrl.val, page);
++
++ SetCursors(-1);
++}
++
++
++
++
++/***************************************************************/
++static void scanDir(br)
++ BROWINFO *br;
++{
++ /* loads contents of current working directory into BFIL structures...
++ * and also loads up the MB list
++ *
++ * note: when actually doing the code, in addition to stat'ing files, we
++ * might want to try reading the first couple of bytes out of them, to see
++ * what magicno they have, and putting up an appropriate icon for different
++ * types of standard files. Make this mechanism fairly clean and easily
++ * extensible, as different machines will have different types of files,
++ * and it's reasonable to expect folks to want to add their own bitmaps
++ */
++
++ int i,j,k,oldbflen,vmsparent;
++ BFIL *bf;
++
++ DIR *dirp;
++ char *dbeg, *dend;
++ char *dirnames[MAXDEEP];
++ static char path[MAXPATHLEN + 2] = { '\0' };
++
++#ifdef NODIRENT
++ struct direct *dp;
++#else
++ struct dirent *dp;
++#endif
++
++
++ br->lastIconClicked = -1; /* turn off possibility of seeing a dblclick */
++ setBrowStr(br,"");
++
++
++ /********************************************************************/
++ /*** LOAD UP the brdirMB information to reflect the new directory ***/
++ /********************************************************************/
++
++
++ xv_getwd(path, sizeof(path));
++ if (path[strlen(path)-1] != '/') strcat(path,"/"); /* add trailing '/' */
++
++ for (i=0; i<br->ndirs; i++) free(br->mblist[i]); /* clear old dir names */
++
++ /* path will be something like: "/u3/bradley/src/weiner/whatever/" */
++
++ dbeg = dend = path;
++ for (i=0; i<MAXDEEP && dend; i++) {
++ dend = (char *) index(dbeg,'/'); /* find next '/' char */
++
++#ifdef apollo
++ /** On Apollos the path will be something like //machine/users/foo/ **/
++ /** handle the initial // **/
++ if ((dend == dbeg ) && (dbeg[0] == '/') && (dbeg[1] == '/')) dend += 1;
++#endif
++
++ dirnames[i] = dbeg;
++ dbeg = dend+1;
++ }
++ br->ndirs = i-1;
++
++
++ /* build brMBlist */
++ for (i = br->ndirs-1,j=0; i>=0; i--,j++) {
++ size_t stlen = (i<(br->ndirs-1)) ? dirnames[i+1] - dirnames[i]
++ : strlen(dirnames[i]);
++
++ br->mblist[j] = (char *) malloc(stlen+1);
++ if (!br->mblist[j]) FatalError("unable to malloc brMBlist[]");
++
++ strncpy(br->mblist[j], dirnames[i], stlen);
++ br->mblist[j][stlen] = '\0';
++ }
++
++
++ /* refresh the brdirMB button */
++ br->dirMB.list = br->mblist;
++ br->dirMB.nlist = br->ndirs;
++
++ XClearArea(theDisp, br->dirMB.win, br->dirMB.x, br->dirMB.y,
++ br->dirMB.w+3, br->dirMB.h+3, False);
++
++ i = StringWidth(br->mblist[0]) + 10;
++ br->dirMB.x = br->dirMB.x + br->dirMB.w/2 - i/2;
++ br->dirMB.w = i;
++ MBRedraw(&br->dirMB);
++
++ strcpy(br->path, path); /* will have a trailing '/' character */
++
++
++ /********************************************************************/
++ /*** read the directory (load up bfList) ***/
++ /********************************************************************/
++
++
++ WaitCursor();
++
++ oldbflen = br->bfLen;
++
++ freeBfList(br); /* free all memory currently used by bfList structure */
++
++ /* count how many files are in the list */
++
++ dirp = opendir(".");
++ if (!dirp) {
++ endScan(br, oldbflen);
++ setBrowStr(br, "Couldn't read current directory.");
++ SetCursors(-1);
++ return;
++ }
++
++#ifdef VMS
++ br->bfLen = 1; /* always have a parent directory */
++#endif
++
++ while ( (dp = readdir(dirp)) != NULL) {
++ if (strcmp(dp->d_name, ".") &&
++ strcmp(dp->d_name, THUMBDIR)) {
++ if (!br->showhidden && dp->d_name[0] == '.' &&
++ strcmp(dp->d_name,"..")!=0) continue;
++ else
++ br->bfLen++;
++ }
++ if ((br->bfLen & 0x3f) == 0) WaitCursor();
++ }
++
++
++ if (br->bfLen) {
++ int readcount, iconcount, statcount;
++
++ br->bfList = (BFIL *) calloc((size_t) br->bfLen, sizeof(BFIL));
++
++ if (!br->bfList) FatalError("can't create bfList! (malloc failed)\n");
++
++ rewinddir(dirp); /* back to beginning of directory */
++
++ vmsparent = 0;
++#ifdef VMS
++ vmsparent = 1;
++#endif
++
++ /* get info for each file in directory */
++
++ readcount = 0; iconcount = 0; statcount = 0;
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++
++ drawTemp(br, i, br->bfLen);
++
++ if ((i & 0x1f) == 0) WaitCursor();
++
++ /* get next directory entry that isn't '.' or THUMBDIR or
++ '..' in root directory, or a hidden file if !showhidden */
++
++ if (vmsparent) { /* first time: make bogus parent for VMS */
++ bf->name = (char *) malloc(strlen("..") + 1);
++ if (!bf->name) FatalError("out of memory in scanDir()");
++ strcpy(bf->name, "..");
++ bf->ftype = BF_DIR;
++ bf->w = br_dir_width;
++ bf->h = br_chr_width;
++ bf->pimage = (byte *) NULL;
++ bf->ximage = (XImage *) NULL;
++ bf->lit = 0;
++ }
++ else {
++ do { dp = readdir(dirp); }
++ while (dp && (strcmp(dp->d_name, ".")==0 ||
++ strcmp(dp->d_name, THUMBDIR)==0 ||
++ strcmp(dp->d_name, THUMBDIRNAME)==0 ||
++ (br->ndirs==1 && strcmp(dp->d_name,"..")==0) ||
++ (!br->showhidden && dp->d_name[0] == '.' &&
++ strcmp(dp->d_name,"..")!=0)));
++
++ if (!dp) { br->bfLen = i; break; } /* dir got shorter... */
++ }
++
++ if (!vmsparent) scanFile(br, bf, dp->d_name);
++ vmsparent = 0;
++
++ statcount++;
++ if (bf->ftype == BF_HAVEIMG) iconcount++;
++ if (bf->ftype == BF_FILE) readcount++;
++
++ if ((statcount && (statcount%100)==0) ||
++ (iconcount && (iconcount% 20)==0) ||
++ (readcount && (readcount% 20)==0)) { /* mention progress */
++
++ char tmp[64];
++
++ sprintf(tmp, "Processed %d out of %d...", i+1, br->bfLen);
++ setBrowStr(br, tmp);
++ }
++ }
++
++ clearTemp(br);
++ }
++
++ closedir(dirp);
++
++ endScan(br, oldbflen);
++}
++
++
++/***************************************************************/
++static void endScan(br, oldnum)
++ BROWINFO *br;
++ int oldnum;
++{
++ /* called at end of scanDir() and rescanDir() */
++
++ int maxv, page;
++ int w,h;
++
++ setBrowStr(br,"");
++ sortBFList(br);
++
++ eraseNumfiles(br, oldnum);
++ drawNumfiles(br);
++ drawTrash(br);
++
++ computeScrlVals(br, &maxv, &page);
++ if (br->scrl.val>maxv) br->scrl.val = maxv;
++
++ /* have to clear window as # of icons may have changed */
++ w = br->iwWide; h = br->iwHigh;
++ if (ctrlColor) { w -= 4; h -= 4; }
++ if (w<1) w = 1;
++ if (h<1) h = 1;
++
++ XClearArea(theDisp, br->iconW, (ctrlColor) ? 2 : 0, (ctrlColor) ? 2 : 0,
++ (u_int) w, (u_int) h, False);
++
++ SCSetRange(&br->scrl, 0, maxv, br->scrl.val, page);
++
++ SetCursors(-1);
++}
++
++
++/***************************************************************/
++static void scanFile(br, bf, name)
++ BROWINFO *br;
++ BFIL *bf;
++ char *name;
++{
++ /* given a pointer to an empty BFIL structure, and a filename,
++ loads up the BFIL structure appropriately */
++
++ struct stat st;
++
++ /* copy name */
++ bf->name = (char *) malloc(strlen(name) + 1);
++
++ if (!bf->name) FatalError("ran out of memory for bf->name");
++ strcpy(bf->name, name);
++
++ /* default icon values. (in case 'stat' doesn't work) */
++ bf->ftype = BF_FILE;
++ bf->w = br_file_width; bf->h = br_file_height;
++ bf->pimage = (byte *) NULL;
++ bf->ximage = (XImage *) NULL;
++ bf->lit = 0;
++
++
++ if (stat(bf->name, &st)==0) {
++ bf->ftype = stat2bf((u_int) st.st_mode);
++ if (bf->ftype == BF_FILE && (st.st_mode & 0111)) bf->ftype = BF_EXE;
++
++ switch (bf->ftype) {
++ case BF_DIR: bf->w = br_dir_width; bf->h = br_dir_height; break;
++ case BF_CHR: bf->w = br_chr_width; bf->h = br_chr_height; break;
++ case BF_BLK: bf->w = br_blk_width; bf->h = br_blk_height; break;
++ case BF_SOCK: bf->w = br_sock_width; bf->h = br_sock_height; break;
++ case BF_FIFO: bf->w = br_fifo_width; bf->h = br_fifo_height; break;
++ case BF_EXE: bf->w = br_exe_width; bf->h = br_exe_height; break;
++ }
++ }
++
++
++ loadThumbFile(br, bf);
++
++
++ if (bf->ftype == BF_FILE || bf->ftype == BF_EXE) {
++ /* if it's a regular file, with no thumbnail, try to determine what
++ type of file it is */
++
++ int filetype;
++
++ filetype = ReadFileType(bf->name);
++
++ switch (filetype) {
++ case RFT_GIF: bf->ftype = BF_GIF; break;
++ case RFT_PM: bf->ftype = BF_PM; break;
++ case RFT_PBM: bf->ftype = BF_PBM; break;
++ 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_UTAHRLE: bf->ftype = BF_UTAHRLE; break;
++ case RFT_IRIS: bf->ftype = BF_IRIS; break;
++ case RFT_PCX: bf->ftype = BF_PCX; break;
++ case RFT_JFIF: bf->ftype = BF_JFIF; break;
++ 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_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;
++ }
++ }
++}
++
++
++
++/***************************************************************/
++static unsigned long bfcompares;
++
++static void sortBFList(br)
++ BROWINFO *br;
++{
++ bfcompares = 0;
++ qsort((char *) br->bfList, (size_t) br->bfLen, sizeof(BFIL), bfnamCmp);
++}
++
++
++static int bfnamCmp(p1, p2)
++ const void *p1, *p2;
++{
++ BFIL *b1, *b2;
++
++ b1 = (BFIL *) p1;
++ b2 = (BFIL *) p2;
++
++ bfcompares++;
++ if ((bfcompares & 0x7f)==0) WaitCursor();
++
++ /* sort critera: directories first, in alphabetical order,
++ followed by everything else, in alphabetical order */
++
++ if ((b1->ftype == BF_DIR && b2->ftype == BF_DIR) ||
++ (b1->ftype != BF_DIR && b2->ftype != BF_DIR))
++ return strcmp(b1->name, b2->name);
++
++ else if (b1->ftype == BF_DIR && b2->ftype != BF_DIR) return -1;
++ else return 1;
++}
++
++
++/***************************************************************/
++static void rescanDir(br)
++ BROWINFO *br;
++{
++ /* chdir to br->path
++ * build two name-lists, one holding the names of all files in the bfList,
++ * and the second holding the names of all files in this directory
++ * (ignore . and .. and THUMBDIR in both)
++ *
++ * include directories in both lists, but filter files (in the second list)
++ * by br->showhidden
++ *
++ * sort the two namelists in pure-alpha order.
++ * for each item in the first list, see if it has an entry in the second
++ * list. If it does, remove the entry from *both* lists
++ *
++ * once that's done, we'll have a list of files that have been deleted
++ * (are in bfList, but not in directory)
++ * and a list of files that have been created
++ * (aren't in bfList, are in directory)
++ *
++ * malloc a new temp bfList that has room for (bfLen - #del'd + #created)
++ * entries, copy all entries from the old bfList (that aren't on the
++ * deleted list) into the new list. for each entry on the created list,
++ * copy it to the new bfList and load its icon (not that it's likely to
++ * have one, in which case fall back to the generic file-type icon).
++ *
++ * free data used by any remaining (deleted) entries in the old bfList
++ *
++ * call sortBfList to put the new bflist into the right order
++ */
++
++ int i, j, bflen, dirlen, dnum, cmpval, newlen, n, oldlen;
++ char **bfnames, **dirnames;
++ BFIL *newbflist, *bf;
++
++ if (cdBrow(br)) return;
++
++ WaitCursor();
++
++ /* build 'bfnames' array */
++ bflen = oldlen = br->bfLen; bfnames = (char **) NULL;
++ if (bflen) {
++ bfnames = (char **) malloc(bflen * sizeof(char *));
++ if (!bfnames) FatalError("couldn't alloc bfnames in rescanDir()");
++ for (i=0; i<bflen; i++) {
++ bfnames[i] = (char *) malloc(strlen(br->bfList[i].name) + 1);
++ if (!bfnames[i]) FatalError("couldn't alloc bfnames in rescanDir()");
++
++ strcpy(bfnames[i], br->bfList[i].name);
++ }
++ }
++
++ WaitCursor();
++
++ dirnames = getDirEntries(".", &dirlen, br->showhidden);
++
++ WaitCursor();
++
++ /* note, either (or both) dirnames/bfnames can be NULL, in which case
++ their respective 'len's will be zero */
++
++ /* sort the two name lists */
++ if (bflen) qsort((char *) bfnames, (size_t) bflen, sizeof(char *),namcmp);
++ if (dirlen) qsort((char *) dirnames, (size_t) dirlen,sizeof(char *),namcmp);
++
++ /* run through the bflist, and delete entries common to both lists */
++ for (i=0, dnum=0; i<bflen && dnum<dirlen; i++) {
++ cmpval = strcmp(bfnames[i], dirnames[dnum]);
++ if (cmpval < 0) continue;
++ else if (cmpval > 0) { /* advance dnum, and try again */
++ dnum++;
++ i--;
++ }
++ else /* cmpval == 0 */ { /* remove from both lists */
++ free(bfnames[i]); free(dirnames[dnum]);
++ bfnames[i] = dirnames[dnum] = (char *) NULL;
++ dnum++;
++ }
++ }
++
++
++ WaitCursor();
++
++ /* compress the lists, removing NULL entries, . .. and THUMBDIR */
++
++ for (i=j=0; i<bflen; i++) {
++ if (bfnames[i] && strcmp(bfnames[i],".") && strcmp(bfnames[i],"..") &&
++ strcmp(bfnames[i],THUMBDIR) && strcmp(bfnames[i],THUMBDIRNAME)) {
++ bfnames[j++] = bfnames[i];
++ }
++ }
++ bflen = j;
++
++
++ for (i=j=0; i<dirlen; i++) {
++ if (dirnames[i] && strcmp(dirnames[i],".") && strcmp(dirnames[i],"..") &&
++ strcmp(dirnames[i],THUMBDIR) && strcmp(dirnames[i],THUMBDIRNAME)) {
++ dirnames[j++] = dirnames[i];
++ }
++ }
++ dirlen = j;
++
++
++ if (DEBUG) {
++ fprintf(stderr,"%d files seem to have gone away: ", bflen);
++ for (i=0; i<bflen; i++)
++ fprintf(stderr,"%s ", bfnames[i]);
++ fprintf(stderr,"\n\n");
++
++ fprintf(stderr,"%d files seem to have appeared: ", dirlen);
++ for (i=0; i<dirlen; i++)
++ fprintf(stderr,"%s ", dirnames[i]);
++ fprintf(stderr,"\n\n");
++ }
++
++
++ /* create a new bfList */
++ newlen = br->bfLen - bflen + dirlen; /* oldlen - #del'd + #created */
++ if (newlen>0) {
++ newbflist = (BFIL *) calloc((size_t) newlen, sizeof(BFIL));
++ if (!newbflist) FatalError("couldn't malloc newbflist in rescanDir()");
++
++ /* copy all entries from old bflist that aren't on deleted list into new */
++ for (i=n=0, bf=br->bfList; i<br->bfLen && n<newlen; i++, bf++) {
++ for (j=0; j<bflen; j++) {
++ if (strcmp(bf->name, bfnames[j])==0) break;
++ }
++ if (j == bflen) { /* not in del list. copy to new list */
++ xvbcopy((char *) bf, (char *) &(newbflist[n++]), sizeof(BFIL));
++ }
++ else { /* in deleted list. free all data for this entry */
++ if (bf->name) free(bf->name);
++ if (bf->imginfo) free(bf->imginfo);
++ if (bf->pimage) free(bf->pimage);
++ if (bf->ximage) xvDestroyImage(bf->ximage);
++ }
++ }
++
++
++ /* add all entries in the 'created' list */
++ for (i=0; i<dirlen && n<newlen; i++) {
++ scanFile(br, &newbflist[n++], dirnames[i]);
++ }
++
++
++ if (br->bfList) free(br->bfList);
++
++ br->bfList = newbflist;
++ br->bfLen = (n < newlen) ? n : newlen;
++ }
++ else freeBfList(br); /* dir is now empty */
++
++ WaitCursor();
++
++
++ /* free memory still in use by bfnames and dirnames arrays */
++ for (i=0; i<bflen; i++) { if (bfnames[i]) free(bfnames[i]); }
++ for (i=0; i<dirlen; i++) { if (dirnames[i]) free(dirnames[i]); }
++ if (bfnames) free(bfnames);
++ if (dirnames) free(dirnames);
++
++ endScan(br, oldlen);
++}
++
++/***************************************************************/
++static void freeBfList(br)
++ BROWINFO *br;
++{
++ int i;
++ BFIL *bf;
++
++ if (br->bfList) {
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if ((i & 0x3f) == 0) WaitCursor();
++
++ if (bf->name) free(bf->name);
++ if (bf->imginfo) free(bf->imginfo);
++ if (bf->pimage) free(bf->pimage);
++ if (bf->ximage) xvDestroyImage(bf->ximage);
++ }
++
++ free(br->bfList);
++ }
++
++ br->bfList = (BFIL *) NULL;
++ br->bfLen = 0;
++ br->numlit = 0;
++}
++
++
++static int namcmp(p1, p2)
++ const void *p1, *p2;
++{
++ char **s1, **s2;
++ s1 = (char **) p1;
++ s2 = (char **) p2;
++
++ return strcmp(*s1,*s2);
++}
++
++/***************************************************************/
++static char **getDirEntries(dir, lenP, dohidden)
++ char *dir;
++ int *lenP;
++ int dohidden;
++{
++ /* loads up all directory entries into an array. This *isn't* a great
++ way to do it, but I can't count on 'scandir()' existing on
++ every system. Returns 'NULL' on failure, or pointer to array of
++ 'lenP' strings on success. '.' and '..' ARE included in list
++ if !dohidden, all '.*' files are skipped (except . and ..) */
++
++ int i, j, dirlen;
++ DIR *dirp;
++ char **names;
++#ifdef NODIRENT
++ struct direct *dp;
++#else
++ struct dirent *dp;
++#endif
++
++
++ dirp = opendir(dir);
++ if (!dirp) {
++ SetISTR(ISTR_WARNING, "%s: %s", dir, ERRSTR(errno));
++ *lenP = 0;
++ return (char **) NULL;
++ }
++
++
++ /* count # of entries in dir (worst case) */
++ for (dirlen=0; (dp = readdir(dirp)) != NULL; dirlen++);
++ if (!dirlen) {
++ closedir(dirp);
++ *lenP = dirlen;
++ return (char **) NULL;
++ }
++
++
++ /* load up the entries, now that we know how many to make */
++ names = (char **) malloc(dirlen * sizeof(char *));
++ if (!names) FatalError("malloc failure in getDirEntries()");
++
++
++ rewinddir(dirp);
++ for (i=0; i<dirlen; ) {
++ dp = readdir(dirp);
++ if (!dp) break;
++
++ if (!dohidden) {
++#ifndef VMS
++ if (dp->d_name[0] == '.' &&
++ strcmp(dp->d_name,"." )!=0 &&
++ strcmp(dp->d_name,"..")!=0) continue;
++#endif
++ }
++
++ names[i] = (char *) malloc(strlen(dp->d_name) + 1);
++ if (!names[i]) FatalError("malloc failure in getDirEntries()");
++
++ strcpy(names[i], dp->d_name);
++ i++;
++ }
++
++ if (i<dirlen) dirlen = i; /* dir got shorter... */
++
++ closedir(dirp);
++
++ *lenP = dirlen;
++ return names;
++}
++
++
++
++/***************************************************************/
++static void computeScrlVals(br, max, page)
++ BROWINFO *br;
++ int *max, *page;
++{
++ /* called whenever bfList or size of icon window has changed */
++
++ if (br->numWide<1) br->numWide = 1; /* safety */
++
++ br->numHigh = (br->bfLen + br->numWide-1) / br->numWide; /* # icons high */
++
++ *page = br->visHigh;
++ *max = br->numHigh - *page;
++}
++
++
++
++
++
++
++/***************************************************************/
++static void genSelectedIcons(br)
++ BROWINFO *br;
++{
++ int i, sval, first, numvis, cnt;
++
++ setBrowStr(br, "");
++
++ if (!br->bfList || !br->bfLen) return;
++
++ if (cdBrow(br)) return;
++
++ WaitCursor();
++
++ for (i=cnt=0; i<br->bfLen; i++) {
++ if (br->bfList[i].lit) {
++ if (br->numlit) drawTemp(br, cnt, br->numlit);
++ cnt++;
++ makeIconVisible(br, i);
++ eraseIcon(br, i);
++ genIcon(br, &(br->bfList[i]));
++ br->bfList[i].lit = 0;
++ drawIcon(br, i);
++ }
++ }
++
++ if (br->numlit) clearTemp(br);
++ br->numlit = 0;
++ changedNumLit(br, -1, 1);
++
++ SetCursors(-1);
++}
++
++
++/***************************************************************/
++static void genIcon(br, bf)
++ BROWINFO *br;
++ BFIL *bf;
++{
++ /* given a BFIL entry, load up the file.
++ * if we succeeded in loading up the file,
++ * generate an aspect-correct 8-bit image using brow Cmap
++ * otherwise
++ * replace this icon with the BF_UNKNOWN, or BF_ERR icons
++ */
++
++ PICINFO pinfo;
++ int i, filetype;
++ double wexpand,hexpand;
++ int iwide, ihigh;
++ byte *icon24, *icon8;
++ char str[256], str1[256], *readname, uncompname[128];
++ char basefname[128], *uncName;
++
++
++ if (!bf || !bf->name || bf->name[0] == '\0') return; /* shouldn't happen */
++ str[0] = '\0';
++ basefname[0] = '\0';
++ pinfo.pic = (byte *) NULL;
++ pinfo.comment = (char *) NULL;
++ readname = bf->name;
++
++ /* free any old info in 'bf' */
++ if (bf->imginfo) free (bf->imginfo);
++ if (bf->pimage) free (bf->pimage);
++ if (bf->ximage) xvDestroyImage(bf->ximage);
++
++ bf->imginfo = (char *) NULL;
++ bf->pimage = (byte *) NULL;
++ bf->ximage = (XImage *) NULL;
++
++
++ /* skip all 'special' files */
++ if (!ISLOADABLE(bf->ftype)) return;
++
++ filetype = ReadFileType(bf->name);
++
++ if (filetype == RFT_COMPRESS) {
++#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 */
++ strcpy (basefname, bf->name);
++ *rindex (basefname, '.') = '\0';
++ uncName = basefname;
++#else
++ uncName = bf->name;
++#endif
++
++ if (UncompressFile(uncName, uncompname)) {
++ filetype = ReadFileType(uncompname);
++ readname = uncompname;
++ }
++ else {
++ sprintf(str, "Couldn't uncompress file '%s'", bf->name);
++ setBrowStr(br, str);
++ bf->ftype = BF_ERROR;
++ }
++ }
++
++ /* get rid of comments. don't need 'em */
++ if (pinfo.comment) free(pinfo.comment); pinfo.comment = (char *) NULL;
++
++ if (filetype == RFT_ERROR) {
++ sprintf(str,"Couldn't open file '%s'", bf->name);
++ setBrowStr(br, str);
++ bf->ftype = BF_ERROR;
++ }
++
++ else if (filetype == RFT_UNKNOWN) {
++ /* if it *was* an 'exe', leave it that way */
++ if (bf->ftype != BF_EXE) bf->ftype = BF_UNKNOWN;
++ }
++
++ else {
++ /* otherwise it's a known filetype... do the *hard* part now... */
++
++ i = ReadPicFile(readname, filetype, &pinfo, 1);
++ KillPageFiles(pinfo.pagebname, pinfo.numpages);
++
++ if (!i) bf->ftype = BF_ERROR;
++
++ if (i && (pinfo.w<=0 || pinfo.h<=0)) { /* bogus size */
++ bf->ftype = BF_ERROR;
++ free(pinfo.pic); pinfo.pic = (byte *) NULL;
++ }
++
++ if (bf->ftype==BF_ERROR && filetype==RFT_XBM) bf->ftype = BF_UNKNOWN;
++ }
++
++ /* get rid of comment, as we don't need it */
++ if (pinfo.comment) {
++ free(pinfo.comment); pinfo.comment = (char *) NULL;
++ }
++
++ /* if we made an uncompressed file, we can rm it now */
++ if (readname != bf->name) unlink(readname);
++
++
++ /* at this point either BF_ERROR, BF_UNKNOWN, BF_EXE or pic */
++
++ if (!pinfo.pic) {
++ if (bf->ftype == BF_EXE) return; /* don't write thumbfiles for exe's */
++
++ bf->w = br_file_width; bf->h = br_file_height;
++ writeThumbFile(br, bf, NULL, 0, 0, NULL); /* BF_ERROR, BF_UNKNOWN */
++ return;
++ }
++
++ /* at this point, we have a pic, so it must be an image file */
++
++
++ /* compute size of icon (iwide,ihigh) */
++
++ wexpand = (double) pinfo.w / (double) ISIZE_WIDE;
++ hexpand = (double) pinfo.h / (double) ISIZE_HIGH;
++
++ if (wexpand >= 1.0 || hexpand >= 1.0) { /* don't expand small icons */
++ if (wexpand>hexpand) {
++ iwide = (int) (pinfo.w / wexpand + 0.5);
++ ihigh = (int) (pinfo.h / wexpand + 0.5);
++ }
++ else {
++ iwide = (int) (pinfo.w / hexpand + 0.5);
++ ihigh = (int) (pinfo.h / hexpand + 0.5);
++ }
++ }
++ else { /* smaller than ISIZE. Leave it that way. */
++ iwide = pinfo.w; ihigh = pinfo.h;
++ }
++
++
++ /* generate icon */
++ icon24 = Smooth24(pinfo.pic, pinfo.type==PIC24, pinfo.w, pinfo.h,
++ iwide, ihigh, pinfo.r,pinfo.g,pinfo.b);
++ if (!icon24) { bf->ftype = BF_FILE; free(pinfo.pic); return; }
++
++ sprintf(str, "%dx%d ", pinfo.normw, pinfo.normh);
++ switch (filetype) {
++ case RFT_GIF: if (xv_strstr(pinfo.shrtInfo, "GIF89"))
++ strcat(str,"GIF89 file");
++ else
++ strcat(str,"GIF87 file");
++ break;
++
++ case RFT_PM: strcat(str,"PM file"); break;
++
++ case RFT_PBM: if (xv_strstr(pinfo.fullInfo, "raw")) strcat(str,"Raw ");
++ else strcat(str,"Ascii ");
++
++ for (i=0; i<3 && (strlen(pinfo.fullInfo)>(size_t)3); i++){
++ str1[0] = pinfo.fullInfo[i]; str1[1] = '\0';
++ strcat(str, str1);
++ }
++
++ strcat(str," file");
++ break;
++
++ case RFT_XBM: strcat(str,"X11 bitmap file"); break;
++ case RFT_SUNRAS: strcat(str,"Sun rasterfile"); break;
++ case RFT_BMP: strcat(str,"BMP file"); break;
++ case RFT_UTAHRLE: strcat(str,"Utah RLE file"); break;
++ case RFT_IRIS: strcat(str,"Iris RGB file"); break;
++ case RFT_PCX: strcat(str,"PCX file"); break;
++ case RFT_JFIF: strcat(str,"JPEG file"); break;
++ case RFT_TIFF: strcat(str,"TIFF file"); break;
++ case RFT_PDSVICAR: strcat(str,"PDS/VICAR file"); break;
++ case RFT_PS: strcat(str,"PostScript file"); break;
++ case RFT_IFF: strcat(str,"ILBM file"); break;
++ case RFT_TARGA: strcat(str,"Targa file"); break;
++ 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;
++ default: strcat(str,"file of unknown type"); break;
++ }
++
++
++ /* find out length of original file */
++ { FILE *fp;
++ long filesize;
++ char buf[64];
++
++ fp = fopen(bf->name, "r");
++ if (fp) {
++ fseek(fp, 0L, 2);
++ filesize = ftell(fp);
++ fclose(fp);
++
++ sprintf(buf," (%ld bytes)", filesize);
++ strcat(str, buf);
++ }
++ }
++
++
++ sprintf(str1, "%s: %s", bf->name, str);
++ setBrowStr(br, str1);
++
++ /* dither 24-bit icon into 8-bit icon (using 3/3/2 cmap) */
++ icon8 = DoColorDither(icon24, NULL, iwide, ihigh, NULL, NULL, NULL,
++ browR, browG, browB, 256);
++ if (!icon8) { bf->ftype = BF_FILE; free(icon24); free(pinfo.pic); return; }
++
++ writeThumbFile(br, bf, icon8, iwide, ihigh, str);
++
++ /* have to make a *copy* of str */
++ if (strlen(str)) {
++ bf->imginfo = (char *) malloc(strlen(str)+1);
++ if (bf->imginfo) strcpy(bf->imginfo, str);
++ }
++ else bf->imginfo = (char *) NULL;
++
++ bf->pimage = icon8;
++ bf->w = iwide;
++ bf->h = ihigh;
++ bf->ftype = BF_HAVEIMG;
++
++ bf->ximage = Pic8ToXImage(icon8, (u_int) iwide, (u_int) ihigh, browcols,
++ browR, browG, browB);
++
++ free(icon24);
++ free(pinfo.pic);
++}
++
++
++
++
++
++
++/*
++ * THUMBNAIL FILE FORMAT:
++ *
++ * <magic number 'P7 332' >
++ * <comment identifying version of XV that wrote this file>
++ * <comment identifying type & size of the full-size image>
++ * <OPTIONAL comment identifying this as a BUILT-IN icon, in which case
++ * there is no width,height,maxval info, nor any 8-bit data>
++ * <comment signifying end of comments>
++ * <width, height, and maxval of this file >
++ * <raw binary 8-bit data, in 3/3/2 Truecolor format>
++ *
++ * Example:
++ * P7 332
++ * #XVVERSION:Version 2.28 Rev: 9/26/92
++ * #IMGINFO:512x440 Color JPEG
++ * #END_OF_COMMENTS
++ * 48 40 255
++ * <binary data>
++ *
++ * alternately:
++ * P7 332
++ * #XVVERSION:Version 2.28 Rev: 9/26/92
++ * #BUILTIN:UNKNOWN
++ * #IMGINFO:
++ * #END_OF_COMMENTS
++ */
++
++
++
++/***************************************************************/
++static void loadThumbFile(br, bf)
++ BROWINFO *br;
++ BFIL *bf;
++{
++ /* determine if bf has an associated thumbnail file. If so, load it up,
++ and create the ximage, and such */
++
++ FILE *fp;
++ char thFname[512];
++ char buf[256], *st, *info;
++ int w,h,mv,i,builtin;
++ byte *icon8;
++
++ info = NULL; icon8 = NULL; builtin = 0;
++
++ sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name);
++
++ fp = fopen(thFname, "r");
++ if (!fp) return; /* nope, it doesn't have one */
++
++ /* read in the file */
++ if (!fgets(buf, 256, fp)) goto errexit;
++
++ if (strncmp(buf, "P7 332", (size_t) 6)) goto errexit;
++
++
++ /* read comments until we see '#END_OF_COMMENTS', or hit EOF */
++ while (1) {
++ if (!fgets(buf, 256, fp)) goto errexit;
++
++ if (!strncmp(buf, "#END_OF_COMMENTS", strlen("#END_OF_COMMENTS")))
++ break;
++
++ else if (!strncmp(buf, "#XVVERSION:", strlen("#XVVERSION:"))) {
++ /* probably should check for compatibility, or something... */
++ }
++
++ else if (!strncmp(buf, "#BUILTIN:", strlen("#BUILTIN:"))) {
++ builtin = 1;
++ st = (char *) index(buf, ':') + 1;
++ if (strcmp(st, "ERROR")==0) bf->ftype = BF_ERROR;
++ else bf->ftype = BF_UNKNOWN;
++ }
++
++ else if (!strncmp(buf, "#IMGINFO:", strlen("#IMGINFO:"))) {
++ st = (char *) index(buf, ':') + 1;
++ info = (char *) malloc(strlen(st) + 1);
++ if (info) strcpy(info, st);
++ }
++ }
++
++
++ if (builtin) {
++ bf->imginfo = info;
++ fclose(fp);
++ return;
++ }
++
++
++
++ /* read width, height, maxval */
++ if (!fgets(buf, 256, fp) || sscanf(buf, "%d %d %d", &w, &h, &mv) != 3)
++ goto errexit;
++
++
++ if (w>ISIZE_WIDE || h>ISIZE_HIGH || w<1 || h<1 || mv != 255) {
++ sprintf(buf,"Bogus thumbnail file for '%s'. Skipping.", bf->name);
++ setBrowStr(br, buf);
++ goto errexit;
++ }
++
++
++ /* read binary data */
++ icon8 = (byte *) malloc((size_t) w * h);
++ if (!icon8) goto errexit;
++
++ i = fread(icon8, (size_t) 1, (size_t) w*h, fp);
++ if (i != w*h) goto errexit;
++
++ if (icon8) {
++ bf->pimage = icon8;
++ bf->w = w;
++ bf->h = h;
++ bf->ftype = BF_HAVEIMG;
++ bf->imginfo = info;
++
++ bf->ximage = Pic8ToXImage(icon8, (u_int) w, (u_int) h, browcols,
++ browR, browG, browB);
++ }
++ else {
++ if (info) free(info);
++ }
++
++ fclose(fp);
++ return;
++
++
++ errexit:
++ fclose(fp);
++ if (info) free(info);
++ if (icon8) free(icon8);
++}
++
++
++
++/***************************************************************/
++static void writeThumbFile(br, bf, icon8, w, h, info)
++ BROWINFO *br;
++ BFIL *bf;
++ byte *icon8;
++ int w,h;
++ char *info;
++{
++ FILE *fp;
++ char thFname[512], buf[256];
++ int i, perm;
++ struct stat st;
++
++
++ makeThumbDir(br);
++
++
++ /* stat the original file, get permissions for thumbfile */
++ sprintf(thFname, "%s%s", br->path, bf->name);
++ i = stat(thFname, &st);
++ if (!i) perm = st.st_mode & 07777;
++ else perm = 0755;
++
++
++
++ sprintf(thFname, "%s%s/%s", br->path, THUMBDIR, bf->name);
++
++ fp = fopen(thFname, "w");
++ if (!fp) {
++ sprintf(buf, "Can't create thumbnail file '%s': %s", thFname,
++ ERRSTR(errno));
++ setBrowStr(br, buf);
++ return; /* can't write... */
++ }
++
++
++ /* write the file */
++ fprintf(fp, "P7 332\n");
++ fprintf(fp, "#XVVERSION:%s\n", REVDATE);
++
++ if (icon8) {
++ fprintf(fp, "#IMGINFO:%s\n", (info) ? info : "");
++ }
++ else {
++ fprintf(fp, "#BUILTIN:");
++ switch (bf->ftype) {
++ case BF_ERROR: fprintf(fp,"ERROR\n"); break;
++ case BF_UNKNOWN: fprintf(fp,"UNKNOWN\n"); break;
++ default: fprintf(fp,"UNKNOWN\n"); break;
++ }
++
++ fprintf(fp, "#IMGINFO:%s\n", (info) ? info : "");
++ }
++
++ fprintf(fp, "#END_OF_COMMENTS\n");
++
++ if (icon8) {
++ fprintf(fp, "%d %d %d\n", w, h, 255);
++
++ /* write the raw data */
++ fwrite(icon8, (size_t) 1, (size_t) w*h, fp);
++ }
++
++ if (ferror(fp)) { /* error occurred */
++ fclose(fp);
++ unlink(thFname); /* delete it */
++ sprintf(buf, "Can't write thumbnail file '%s': %s", thFname,
++ ERRSTR(errno));
++ setBrowStr(br, buf);
++ return; /* can't write... */
++ }
++
++ fclose(fp);
++
++ chmod(thFname, (mode_t) perm);
++}
++
++
++/***************************************************************/
++static void makeThumbDir(br)
++ BROWINFO *br;
++{
++ char thFname[512];
++ int i, perm;
++ struct stat st;
++
++ /* stat the THUMBDIR directory: if it doesn't exist, and we are not
++ already in a THUMBDIR, create it */
++
++ sprintf(thFname, "%s%s", br->path, THUMBDIRNAME);
++
++ i = stat(thFname, &st);
++ if (i) { /* failed, let's create it */
++ sprintf(thFname, "%s.", br->path);
++ i = stat(thFname, &st); /* get permissions of parent dir */
++ if (!i) perm = st.st_mode & 07777;
++ else perm = 0755;
++
++ sprintf(thFname, "%s%s", br->path, THUMBDIRNAME);
++ mkdir(thFname, (mode_t) perm);
++ }
++}
++
++
++
++/***************************************************************/
++static void updateIcons(br)
++ BROWINFO *br;
++{
++ /* for each file in the bfList, see if it has an icon file.
++ * if it doesn't, generate one
++ * if it does, check the dates. If the pic file is newer, regen icon
++ *
++ * for each file in the current directory's thumbnail directory,
++ * see if there's a corresponding pic file. If not, delete the
++ * icon file
++ */
++
++ int i, iconsBuilt, iconsKilled, statcount;
++ char tmpstr[128];
++ BFIL *bf;
++ DIR *dirp;
++#ifdef NODIRENT
++ struct direct *dp;
++#else
++ struct dirent *dp;
++#endif
++
++
++ iconsBuilt = iconsKilled = statcount = 0;
++
++ makeThumbDir(br);
++
++ /* okay, we're in the right directory. run through the bfList, and look
++ for corresponding thumbnail files */
++
++ WaitCursor();
++
++ for (i=0, bf=br->bfList; i<br->bfLen; i++, bf++) {
++ if (bf->ftype <= BF_FILE || bf->ftype >= BF_ERROR || bf->ftype==BF_EXE) {
++
++ /* ie, not a 'special' file */
++
++ int s1, s2;
++ char thfname[256];
++ struct stat filest, thumbst;
++
++ drawTemp(br, i, br->bfLen);
++
++ s1 = stat(bf->name, &filest);
++
++ /* see if this file has an associated thumbnail file */
++ sprintf(thfname, "%s/%s", THUMBDIR, bf->name);
++ s2 = stat(thfname, &thumbst);
++
++ if (s1 || s2 || filest.st_mtime > thumbst.st_mtime ||
++ filest.st_ctime > thumbst.st_ctime) {
++ /* either stat'ing the file or the thumbfile failed, or
++ both stat's succeeded and the file has a newer mod or creation
++ time than the thumbnail file */
++
++ makeIconVisible(br, i);
++ eraseIcon(br, i);
++ genIcon(br, bf);
++ drawIcon(br, i);
++
++ if (bf->ftype != BF_EXE) {
++ iconsBuilt++;
++ if (DEBUG)
++ fprintf(stderr,"icon made:fname='%s' thfname='%s' %d,%d,%d,%d\n",
++ bf->name, thfname, s1,s2,filest.st_mtime,thumbst.st_mtime);
++ }
++ }
++ }
++ statcount++;
++
++ if ((statcount % 30)==0) WaitCursor();
++
++ if ((statcount && (statcount % 100)==0) ||
++ (iconsBuilt && (iconsBuilt % 20)==0)) {
++
++ sprintf(tmpstr, "Processed %d out of %d...", i+1, br->bfLen);
++ setBrowStr(br, tmpstr);
++ }
++ }
++
++ clearTemp(br);
++
++
++
++ /* search the THUMBDIR directory, looking for thumbfiles that don't have
++ corresponding pic files. Delete those. */
++
++ setBrowStr(br, "Scanning for excess icon files...");
++
++ statcount = 0;
++ dirp = opendir(THUMBDIR);
++ if (dirp) {
++ while ( (dp = readdir(dirp)) != NULL) {
++ char thfname[256];
++ struct stat filest, thumbst;
++
++ /* stat this directory entry to make sure it's a plain file */
++ sprintf(thfname, "%s/%s", THUMBDIR, dp->d_name);
++ if (stat(thfname, &thumbst)==0) { /* success */
++ int tmp;
++ tmp = stat2bf((u_int) thumbst.st_mode);
++
++ if (tmp == BF_FILE) { /* a plain file */
++ /* see if this thumbfile has an associated pic file */
++ if (stat(dp->d_name, &filest)) { /* failed!: guess it doesn't */
++ if (unlink(thfname)==0) iconsKilled++;
++ }
++ }
++ }
++ statcount++;
++
++ if ((statcount % 30)==0) WaitCursor();
++ }
++ closedir(dirp);
++ }
++
++ SetCursors(-1);
++
++ sprintf(tmpstr, "Update finished: %d icon%s created, %d icon%s deleted.",
++ iconsBuilt, (iconsBuilt ==1) ? "" : "s",
++ iconsKilled, (iconsKilled==1) ? "" : "s");
++ setBrowStr(br, tmpstr);
++
++ drawIconWin(0, &(br->scrl)); /* redraw icon window */
++}
++
++
++/*******************************************/
++static void drawTemp(br, cnt, maxcnt)
++ BROWINFO *br;
++ int cnt, maxcnt;
++{
++ if (maxcnt<1) return; /* none of that naughty ol' divide by zero stuff */
++
++ DrawTempGauge(br->win, 5, br->dirMB.y,
++ (int) br->dirMB.x-10, (int) br->dirMB.h,
++ (double) cnt / (double) maxcnt,
++ browfg, browbg, browhi, browlo, "");
++}
++
++static void clearTemp(br)
++ BROWINFO *br;
++{
++ XClearArea(theDisp, br->win, 5, br->dirMB.y,
++ (u_int) br->dirMB.x-10+1, (u_int) br->dirMB.h + 1, True);
++}
++
++
++
++
++/*******************************************/
++static void doTextCmd(br)
++ BROWINFO *br;
++{
++ int i;
++
++ if (!br->bfLen || !br->bfList || !br->numlit) return;
++
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);
++ if (i==br->bfLen) return; /* shouldn't happen */
++
++ if (cdBrow(br)) return;
++ TextView(br->bfList[i].name);
++}
++
++
++/*******************************************/
++static void doRenameCmd(br)
++ BROWINFO *br;
++{
++ /* called when one (and *only* one!) item is lit in the current br.
++ pops up a 'what do you want to rename it to' box, and attempts to
++ do the trick... */
++
++ int i, num;
++ char buf[128], txt[256], *origname, txt1[256];
++ static char *labels[] = { "\nOk", "\033Cancel" };
++ struct stat st;
++
++ if (cdBrow(br)) return;
++
++ /* find the selected file */
++ for (i=0; i<br->bfLen && !br->bfList[i].lit; i++);
++ if (i==br->bfLen) return; /* shouldn't happen */
++
++ origname = br->bfList[i].name; num = i;
++
++ if (strcmp(origname, "..")==0) {
++ sprintf(buf,"Sorry, you can't rename the parent directory, %s",
++ "for semi-obvious reasons.");
++ ErrPopUp(buf, "\nRight.");
++ return;
++ }
++
++ sprintf(txt, "Enter a new name for the %s '%s':",
++ (br->bfList[i].ftype==BF_DIR) ? "directory" : "file",
++ origname);
++
++ strcpy(buf, origname);
++ i = GetStrPopUp(txt, labels, 2, buf, 128, "/ |\'\"<>,", 0);
++ if (i) return; /* cancelled */
++
++
++ if (strcmp(origname, buf)==0) return;
++
++
++ /* see if the desired file exists, and attempt to do the rename if
++ it doesn't. On success, free bfList[].name, realloc with the new name,
++ and redraw that icon. If any other br's are pointed to same dir,
++ do rescan's in them */
++
++ /* this will also pick up mucking around with '.' and '..' */
++ if (stat(buf, &st) == 0) { /* successful stat: new name already exists */
++ sprintf(txt,"Sorry, a file or directory named '%s' already exists.",buf);
++ ErrPopUp(txt, "\nOh!");
++ return;
++ }
++
++ /* try to rename the file */
++ if (rename(origname, buf) < 0) {
++ sprintf(txt, "Error renaming '%s' to '%s': %s",
++ origname, buf, ERRSTR(errno));
++ ErrPopUp(txt, "\nSo what!");
++ return;
++ }
++
++
++ /* try to rename it's thumbnail file, if any. Ignore errors */
++ sprintf(txt, "%s/%s", THUMBDIR, origname);
++ sprintf(txt1, "%s/%s", THUMBDIR, buf);
++ rename(txt, txt1);
++
++
++
++ free(br->bfList[num].name);
++ br->bfList[num].name = (char *) malloc(strlen(buf) + 1);
++ if (br->bfList[num].name) strcpy(br->bfList[num].name, buf);
++ else FatalError("out of memory in doRenameCmd");
++
++ eraseIconTitle(br, num);
++ drawIcon(br, num);
++
++ for (i=0; i<MAXBRWIN; i++) {
++ if (&binfo[i] != br && strcmp(binfo[i].path, br->path)==0)
++ rescanDir(&binfo[i]);
++ }
++
++ DIRCreatedFile(br->path);
++}
++
++
++
++
++/*******************************************/
++static void doMkdirCmd(br)
++ BROWINFO *br;
++{
++ /* called at any time (doesn't have anything to do with current selection)
++ pops up a 'what do you want to call it' box, and attempts to
++ do the trick... */
++
++ int i;
++ char buf[128], txt[256];
++ static char *labels[] = { "\nOk", "\033Cancel" };
++ struct stat st;
++
++ if (cdBrow(br)) return;
++
++ buf[0] = '\0';
++ i = GetStrPopUp("Enter name for new directory:", labels, 2,
++ buf, 128, "/ |\'\"<>,", 0);
++ if (i) return; /* cancelled */
++
++ if (strlen(buf)==0) return; /* no name entered */
++
++ /* make sure they haven't tried to create '.' or '..' (can't be filtered) */
++ /* see if the file exists already, complain and abort if it does */
++
++ if (strcmp(buf,".")==0 || strcmp(buf,"..")==0 ||
++ stat(buf, &st)==0) {
++ sprintf(txt,"Sorry, a file or directory named '%s' already exists.",buf);
++ ErrPopUp(txt, "\nZoinks!");
++ return;
++ }
++
++
++ /* if it doesn't, do the mkdir(). On success, need to do a rescan of
++ cwd, and any other br's pointing at same directory */
++ if (mkdir(buf, 0755) < 0) {
++ sprintf(txt, "Error creating directory '%s': %s", buf, ERRSTR(errno));
++ ErrPopUp(txt, "\nEat me!");
++ return;
++ }
++
++
++ /* rescan current br, and all other br's pointing to same directory */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (strcmp(binfo[i].path, br->path)==0)
++ rescanDir(&binfo[i]);
++ }
++
++ DIRCreatedFile(br->path);
++}
++
++
++
++
++
++/*******************************************/
++static void doChdirCmd(br)
++ BROWINFO *br;
++{
++ int i;
++ static char buf[MAXPATHLEN+100];
++ static char *labels[] = { "\nOk", "\033Cancel" };
++ char str[512];
++
++ buf[0] = '\0';
++ i = GetStrPopUp("Change to directory:", labels, 2, buf, MAXPATHLEN, " ", 0);
++ if (i) return; /* cancelled */
++
++#ifndef VMS
++ if (Globify(buf)) { /* do ~ expansion if necessary */
++ sprintf(str,"Unable to expand '%s' (unknown uid)\n", buf);
++ setBrowStr(br, str);
++ XBell(theDisp, 50);
++ return;
++ }
++#endif
++
++ if (buf[0] == '.') { /* chdir to relative dir */
++ if (cdBrow(br)) return; /* prints its own error message */
++ }
++
++ if (chdir(buf)) {
++ sprintf(str,"Unable to cd to '%s'\n", buf);
++ setBrowStr(br, str);
++ XBell(theDisp, 50);
++ }
++ else {
++ scanDir(br);
++ SCSetVal(&(br->scrl), 0); /* reset to top on a chdir */
++ }
++}
++
++
++
++/*******************************************/
++static void doDeleteCmd(br)
++ BROWINFO *br;
++{
++ /* if '..' is lit, turn it off and mention that you can't delete it.
++ *
++ * count # of lit files and lit directories. Prompt with an
++ * appropriate 'Are you sure?' box
++ *
++ * if we're proceeding, delete the non-dir files, and their thumbnail
++ * buddies, if any (by calling rm_file() )
++ * call 'rm_dir()' for each of the directories
++ */
++
++ BFIL *bf;
++ int i, j, numdirs, numfiles, slen, firstdel;
++ char buf[512];
++ static char *yesno[] = { "\004Delete", "\033Cancel" };
++
++ if (!br->bfLen || !br->bfList || !br->numlit) return;
++
++ if (cdBrow(br)) return; /* can't cd to this directory. screw it! */
++
++ if (br->bfList[0].lit && strcmp(br->bfList[0].name,"..")==0) {
++ br->numlit--;
++ br->bfList[0].lit = 0;
++ changedNumLit(br, -1, 0);
++
++ sprintf(buf,"Sorry, but you can't delete the parent directory, %s",
++ "for semi-obvious reasons.");
++ ErrPopUp(buf, "\nRight.");
++ if (!br->numlit) { /* turned off only lit file. return */
++ drawIcon(br, 0);
++ return;
++ }
++ }
++
++ numdirs = numfiles = 0; firstdel = -1;
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit) {
++ if (firstdel == -1) firstdel = i;
++ if (bf->ftype == BF_DIR) numdirs++;
++ else numfiles++;
++ }
++ }
++
++
++ /* if any plain files are being toasted, bring up the low-key
++ confirmation box */
++
++ if (numfiles) {
++ sprintf(buf,"Delete file%s: ", numfiles>1 ? "s" : "");
++ slen = strlen(buf);
++
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit && bf->ftype != BF_DIR) {
++ if ( (slen + strlen(bf->name) + 1) > 256) {
++ strcat(buf,"...");
++ break;
++ }
++ else {
++ strcat(buf, bf->name); slen += strlen(bf->name);
++ strcat(buf, " "); slen++;
++ }
++ }
++ }
++
++ i = PopUp(buf, yesno, 2);
++ if (i) return; /* cancelled */
++ }
++
++
++ /* if any directories are being toasted, bring up the are you REALLY sure
++ confirmation box */
++
++ if (numdirs) {
++ sprintf(buf,"Recursively delete director%s: ", numdirs>1 ? "ies" : "y");
++ slen = strlen(buf);
++
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit && bf->ftype == BF_DIR) {
++ if ( (slen + strlen(bf->name) + 1) > 256) {
++ strcat(buf,"...");
++ break;
++ }
++ else {
++ strcat(buf, bf->name); slen += strlen(bf->name);
++ strcat(buf, " "); slen++;
++ }
++ }
++ }
++
++ i = PopUp(buf, yesno, 2);
++ if (i) return; /* cancelled */
++ }
++
++
++ /* okay, at this point they've been warned. do the deletion */
++
++ for (i=0, bf=br->bfList; i<br->bfLen; i++,bf++) {
++ if (bf->lit) {
++ if (bf->ftype == BF_DIR) rm_dir (br, bf->name);
++ else rm_file(br, bf->name);
++ }
++ }
++
++ /* rescan br, as it's probably changed */
++ rescanDir(br);
++
++ /* recompute br->numlit */
++ for (i=br->numlit=0; i<br->bfLen; i++) {
++ if (br->bfList[i].lit) br->numlit++;
++ }
++ changedNumLit(br, -1, 0);
++
++
++ /* if deleted a single file, select the icon that's in the same position */
++ if (numfiles + numdirs >= 1) {
++ if (!br->bfList[firstdel].lit) {
++ br->bfList[firstdel].lit = 1;
++ br->numlit++;
++ drawIcon(br, firstdel);
++ makeIconVisible(br, firstdel);
++ changedNumLit(br, firstdel, 0);
++ }
++ }
++
++ /* rescan other br's that are looking at this directory */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (&binfo[i] != br && strcmp(binfo[i].path, br->path)==0)
++ rescanDir(&binfo[i]);
++ }
++
++ DIRDeletedFile(br->path);
++}
++
++
++
++/*******************************************/
++static void doSelFilesCmd(br)
++ BROWINFO *br;
++{
++ int i;
++ static char buf[MAXPATHLEN+100];
++ static char *labels[] = { "\nOk", "\033Cancel" };
++ char str[512];
++
++ buf[0] = '\0';
++ strcpy(str,"Select file name(s). Wildcard '*' is allowed. ");
++ strcat(str,"Previously selected files will remain selected.");
++
++ i = GetStrPopUp(str, labels, 2, buf, MAXPATHLEN, "", 0);
++ if (i) return; /* cancelled */
++
++ for (i=0; i<br->bfLen; i++) {
++ if (strcmp(br->bfList[i].name, "..")==0) continue; /* skip '..' */
++
++ if (selmatch(br->bfList[i].name, buf)) {
++ br->bfList[i].lit = 1;
++ drawIcon(br,i);
++ }
++ }
++
++ /* recount numlit */
++ br->numlit = 0;
++ for (i=0; i<br->bfLen; i++) {
++ if (br->bfList[i].lit) br->numlit++;
++ }
++ changedNumLit(br, -1, 0);
++}
++
++
++
++/*******************************************/
++
++static char *dirStack[128];
++static int dirStackLen;
++
++
++/*******************************************/
++static void doRecurseCmd(br)
++ BROWINFO *br;
++{
++ int i;
++ static char *labels[] = { "\nOk", "\033Cancel" };
++ char str[512];
++
++ strcpy(str,"Recursive Update: This could take *quite* a while.\n");
++ strcat(str,"Are you sure?");
++
++ i = PopUp(str, labels, 2);
++ if (i) return; /* cancelled */
++
++
++ /* initialize dirname list */
++ dirStackLen = 0;
++
++ cdBrow(br);
++ SCSetVal(&(br->scrl),0);
++ recurseUpdate(br, ".");
++}
++
++
++/*******************************************/
++static void recurseUpdate(br, subdir)
++ BROWINFO *br;
++ char *subdir;
++{
++ /* note: 'br->path + subdir' is the full path to recurse down from */
++
++ /* save current directory, so we can restore upon exit
++ *
++ * build new dest directory, cd there, get working directory (which
++ * shouldn't have symlink names in it). If this dir is in dirstack,
++ * we've looped: cd to orig dir and return
++ * otherwise: load 'br' to reflect new dir, do an Update(),
++ * and for each subdir in this dir, recurse
++ *
++ * if cur dir != orig dir, cd back to orig dir and reload 'br'
++ */
++
++ int i;
++ char orgDir[MAXPATHLEN + 2];
++ char curDir[MAXPATHLEN + 2];
++ char *sp;
++ BFIL *bf;
++
++ xv_getwd(orgDir, sizeof(orgDir));
++
++ sprintf(curDir, "%s%s", br->path, subdir);
++ if (chdir(curDir)) {
++ char str[512];
++ sprintf(str, "Unable to cd to '%s'\n", curDir);
++ setBrowStr(br, str);
++ return;
++ }
++
++ xv_getwd(curDir, sizeof(curDir));
++
++ /* have we looped? */
++ for (i=0; i<dirStackLen && strcmp(curDir, dirStack[i]); i++);
++ if (i<dirStackLen) { /* YES */
++ chdir(orgDir);
++ return;
++ }
++
++ sp = (char *) malloc((size_t) strlen(curDir) + 1);
++ if (!sp) {
++ setBrowStr(br, "malloc() error in recurseUpdate()\n");
++ chdir(orgDir);
++ return;
++ }
++
++ strcpy(sp, curDir);
++ dirStack[dirStackLen++] = sp;
++
++ if (DEBUG) {
++ fprintf(stderr,"------\n");
++ for (i=dirStackLen-1; i>=0; i--) fprintf(stderr," %s\n", dirStack[i]);
++ fprintf(stderr,"------\n");
++ }
++
++
++ /* do this directory */
++ scanDir(br);
++ updateIcons(br);
++
++ /* do subdirectories of this directory, not counting . .. and .xvpics */
++ for (i=0; i<br->bfLen; i++) {
++ bf = &(br->bfList[i]);
++ if (bf &&
++ bf->ftype == BF_DIR &&
++ strcmp(bf->name, ".") &&
++ strcmp(bf->name, "..") &&
++ strcmp(bf->name, THUMBDIRNAME) ) {
++ recurseUpdate(br, bf->name);
++ }
++ }
++
++ /* remove this directory from the stack */
++ free(dirStack[--dirStackLen]);
++
++ xv_getwd(curDir, sizeof(curDir));
++ if (strcmp(orgDir, curDir)) { /* change back to orgdir */
++ chdir(orgDir);
++ scanDir(br);
++ }
++}
++
++
++/*******************************************/
++static void rm_file(br, name)
++ BROWINFO *br;
++ char *name;
++{
++ /* unlinks specified file. br only needed to display potential err msg */
++
++ int i;
++ char buf[512], buf1[512], *tmp;
++
++ if (DEBUG) fprintf(stderr,"rm %s", name);
++
++ i = unlink(name);
++ if (i) {
++ sprintf(buf, "rm %s: %s", name, ERRSTR(errno));
++ setBrowStr(br, buf);
++ }
++
++ /* try to delete a thumbnail file, as well. ignore errors */
++ strcpy(buf1, name); /* tmp1 = leading path of name */
++ tmp = (char *) rindex(buf1, '/');
++ if (!tmp) strcpy(buf1,".");
++ else *tmp = '\0';
++
++ sprintf(buf, "%s/%s/%s", buf1, THUMBDIR, BaseName(name));
++ if (DEBUG) fprintf(stderr," (%s)\n", buf);
++
++ unlink(buf);
++}
++
++static char rmdirPath[MAXPATHLEN+1];
++
++/*******************************************/
++static void rm_dir(br, dname)
++ BROWINFO *br;
++ char *dname;
++{
++ /* called to remove top-level dir. All subdirs are handled by rm_dir1() */
++
++ strcpy(rmdirPath, dname);
++ rm_dir1(br);
++}
++
++static void rm_dir1(br)
++ BROWINFO *br;
++{
++ /* recursively delete this directory, and all things under it */
++
++ int i, dirlen, longpath, oldpathlen;
++ char **names, *name, buf[512];
++ struct stat st;
++
++ if (DEBUG) fprintf(stderr,"rm %s\n", rmdirPath);
++
++ longpath = 0;
++ oldpathlen = strlen(rmdirPath);
++
++ /* delete all plain files under this directory */
++ names = getDirEntries(rmdirPath, &dirlen, 1);
++
++ if (names && dirlen) {
++ /* we've got the names of all files & dirs in this directory. rm the
++ non-subdirectories first */
++
++ for (i=0; i<dirlen; i++) {
++ name = names[i];
++
++ /* skip . and .. (not that we should ever see them... */
++ if (name[0] == '.' && (name[1]=='\0' ||
++ (name[1]=='.' && name[2]=='\0'))) goto done;
++
++ if (strlen(name) + oldpathlen >= (MAXPATHLEN-3)) {
++ longpath = 1;
++ goto done;
++ }
++
++ strcat(rmdirPath, "/");
++ strcat(rmdirPath, name);
++
++ if (stat(rmdirPath, &st) < 0) {
++ sprintf(buf, "%s: %s", name, ERRSTR(errno));
++ setBrowStr(br, buf);
++ rmdirPath[oldpathlen] = '\0';
++ goto done;
++ }
++
++ if (stat2bf((u_int) st.st_mode) == BF_DIR) { /* skip, for now */
++ rmdirPath[oldpathlen] = '\0';
++ continue; /* don't remove from list */
++ }
++
++ rm_file(br, rmdirPath);
++ rmdirPath[oldpathlen] = '\0';
++
++ done: /* remove name from list */
++ free(name);
++ names[i] = (char *) NULL;
++ }
++
++
++ /* rm subdirectories, the only things left in the list */
++ for (i=0; i<dirlen; i++) {
++ if (!names[i]) continue; /* loop until next name found */
++ name = names[i];
++
++ if (strlen(name) + oldpathlen >= (MAXPATHLEN-3)) {
++ longpath = 1;
++ continue;
++ }
++
++ strcat(rmdirPath, "/");
++ strcat(rmdirPath, name);
++
++ rm_dir1(br); /* RECURSE! */
++
++ rmdirPath[oldpathlen] = '\0';
++ }
++
++ /* empty rest of namelist */
++ for (i=0; i<dirlen; i++) {
++ if (names[i]) free(names[i]);
++ }
++ free(names);
++ }
++
++ if (longpath) setBrowStr(br, "Path too long error!");
++
++ i = rmdir(rmdirPath);
++ if (i < 0) {
++ sprintf(buf, "rm %s: %s", rmdirPath, ERRSTR(errno));
++ setBrowStr(br, buf);
++ }
++}
++
++
++
++
++static int overwrite;
++#define OWRT_ASK 0
++#define OWRT_NOASK 1
++#define OWRT_CANCEL 2
++
++
++/*******************************************/
++static void dragFiles(srcBr, dstBr, srcpath, dstpath, dstdir,
++ names, nlen, cpymode)
++ BROWINFO *srcBr, *dstBr;
++ char *srcpath, *dstpath, *dstdir, **names;
++ int nlen, cpymode;
++{
++ /* move or copy file(s) and their associated thumbnail files.
++ srcpath and dstpath will have trailing '/'s. dstdir is name of
++ folder in dstpath (or "." or "..") to write to. names is an nlen
++ long array of strings (the simple filenames of the files to move)
++ if 'cpymode' copy files, otherwise move them */
++
++ int i, j, k, dothumbs, fail;
++ char dstp[MAXPATHLEN + 1];
++ char src[MAXPATHLEN+1], dst[MAXPATHLEN+1];
++ char buf[128];
++ struct stat st;
++
++
++ /* build real destination dir */
++ strcpy(dstp, dstpath);
++
++ /* note dstpath of "/" and dstdir of ".." will never happen, as there's
++ no parent folder shown when in the root directory */
++
++ if (strcmp(dstdir,"..")==0) { /* lop off last pathname component */
++ for (i=strlen(dstp)-2; i>0 && dstp[i]!='/'; i--);
++ i++;
++ dstp[i] = '\0';
++ }
++ else if (strcmp(dstdir,".")!=0) sprintf(dstp, "%s%s/", dstpath, dstdir);
++
++
++
++ /* if there is a thumbnail directory in 'srcpath', make one for dstpath */
++ sprintf(src,"%s%s", srcpath, THUMBDIR);
++ dothumbs = 0;
++ if (stat(src, &st)==0) {
++ sprintf(dst,"%s%s", dstp, THUMBDIR);
++ mkdir(dst, st.st_mode & 07777);
++ dothumbs = 1;
++ }
++
++
++ overwrite = OWRT_ASK;
++
++ if (nlen>1) {
++ if (cpymode) setBrowStr(srcBr, "Copying files...");
++ else setBrowStr(srcBr, "Moving files...");
++ }
++
++ for (i=fail=0; i<nlen; i++) {
++ WaitCursor();
++ /* progress report */
++ if (nlen>1) drawTemp(srcBr, i, nlen);
++
++ if (strcmp(names[i], "..")==0) continue; /* don't move parent */
++
++ sprintf(src,"%s%s", srcpath, names[i]);
++ sprintf(dst,"%s%s", dstp, names[i]);
++
++ if (cpymode) j = copyFile(src,dst);
++ else j = moveFile(src,dst);
++
++ if (overwrite == OWRT_CANCEL) break; /* abort move */
++ if (j==1) fail++;
++
++ if (dothumbs && j==0) {
++ sprintf(src,"%s%s/%s", srcpath, THUMBDIR, names[i]);
++ sprintf(dst,"%s%s/%s", dstp, THUMBDIR, names[i]);
++
++ /* delete destination thumbfile to avoid 'overwrite' warnings */
++ unlink(dst);
++
++ if (cpymode) j = copyFile(src,dst);
++ else j = moveFile(src,dst);
++ }
++ }
++
++ if (nlen>1) clearTemp(srcBr);
++
++
++ /* update icon windows appropriately */
++ for (i=0; i<MAXBRWIN; i++) {
++ if (strcmp(binfo[i].path, srcpath)==0 ||
++ strcmp(binfo[i].path, dstp)==0) {
++ rescanDir(&binfo[i]);
++ }
++ }
++
++ /* update directory window (load/save) */
++ sprintf(src, "%sbozo", srcpath);
++ DIRDeletedFile(src);
++ sprintf(src, "%sbozo", dstp);
++ DIRCreatedFile(src);
++
++ if (dothumbs) {
++ sprintf(src, "%s%s/bozo", srcpath, THUMBDIR);
++ DIRDeletedFile(src);
++ sprintf(src, "%s%s/bozo", dstp, THUMBDIR);
++ DIRCreatedFile(src);
++ }
++
++
++ /* clear all files in the destination folder */
++ for (i=0; i<dstBr->bfLen; i++) {
++ dstBr->bfList[i].lit = 0;
++ }
++ dstBr->numlit = 0;
++
++
++ /* light all named files in the destination folder */
++ for (i=0; i<nlen; i++) {
++ char *name; BFIL *bf;
++ name = names[i];
++ for (j=0, bf=dstBr->bfList;
++ j<dstBr->bfLen && strcmp(name, bf->name)!=0; j++, bf++);
++ if (j<dstBr->bfLen) {
++ bf->lit = 1; dstBr->numlit++;
++ }
++ }
++
++
++ /* scroll so first lit file is visible */
++ for (i=0; i<dstBr->bfLen && !dstBr->bfList[i].lit; i++);
++ if (i<dstBr->bfLen) makeIconVisible(dstBr, i);
++
++ drawIconWin(0, &(dstBr->scrl)); /* redraw dst window */
++ changedNumLit(dstBr, -1, 0);
++
++
++ /* adjust srcBr */
++ for (i=srcBr->numlit=0; i<srcBr->bfLen; i++) {
++ if (srcBr->bfList[i].lit) srcBr->numlit++;
++ }
++ changedNumLit(srcBr, -1, 0);
++
++
++ if (fail) sprintf(buf, "Some files were not %s because of errors.",
++ cpymode ? "copied" : "moved");
++
++ else if (nlen>1) sprintf(buf, "%d files %s", nlen,
++ (cpymode) ? "copied" : "moved");
++ else buf[0] = '\0';
++ setBrowStr(srcBr, buf);
++
++ SetCursors(-1);
++}
++
++
++
++/*************************************************/
++static int moveFile(src,dst)
++ char *src, *dst;
++{
++ /* essentially the same as the 'mv' command. src and dst are full
++ pathnames. It's semi-quiet about errors. a non-existant src file is
++ *not* considered an error (as we don't check for thumbfiles to exist
++ before calling this function). Returns '1' on error, '0' if ok.
++ Returns '-1' on 'skip this'
++
++ One bit of noise: if destination file exists, pop up a Overwrite?
++ warning box. */
++
++ int i, srcdir, dstdir;
++ struct stat st;
++ char buf[512];
++ static char *owbuts[4] = { "\nOk", "dDon't ask", "nNo", "\033Cancel" };
++
++ if (DEBUG) fprintf(stderr,"moveFile %s %s\n", src, dst);
++
++ if (stat(src, &st)) return 0; /* src doesn't exist, it would seem */
++ srcdir = (stat2bf((u_int) st.st_mode) == BF_DIR);
++
++ /* see if destination exists */
++ if (stat(dst, &st)==0) {
++ dstdir = (stat2bf((u_int) st.st_mode) == BF_DIR);
++
++ if (overwrite==OWRT_ASK) {
++ sprintf(buf, "%s '%s' exists.\n\nOverwrite?",
++ dstdir ? "Directory" : "File", dst);
++ i = PopUp(buf, owbuts, 4);
++
++ if (i==1) overwrite = OWRT_NOASK;
++ else if (i==2) return -1;
++ else if (i==3) { overwrite = OWRT_CANCEL; return 1; }
++ }
++
++ if (dstdir) {
++#ifndef VMS /* we don't delete directories in VMS */
++ sprintf(buf, "rm -rf %s", dst);
++ if (system(buf)) { /* okay, so it's cheating... */
++ SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst);
++ return 1;
++ }
++#endif /* VMS */
++ }
++ else if (unlink(dst)) {
++ SetISTR(ISTR_WARNING, "unlink %s: %s", dst, ERRSTR(errno));
++ return 1;
++ }
++ }
++
++
++ if (!rename(src, dst)) return 0; /* Ok */
++ if (errno != EXDEV) return 1; /* failure, of some sort */
++
++ /* We're crossing filesystem boundaries. Copy the file and rm the
++ original */
++
++ i = copyFile(src, dst);
++ if (i == 0) { /* copied okay, kill the original */
++ if (srcdir) {
++#ifndef VMS /* we don't delete directories in VMS */
++ sprintf(buf, "rm -rf %s", src);
++ if (system(buf)) { /* okay, so it's cheating... */
++ SetISTR(ISTR_WARNING, "Unable to remove directory %s", dst);
++ return 1;
++ }
++#endif /* VMS */
++ }
++ else if (unlink(src)) {
++ SetISTR(ISTR_WARNING, "unlink %s: %s", src, ERRSTR(errno));
++ return 1;
++ }
++ }
++
++ return i;
++}
++
++
++/* needed to recursively copy directories */
++static int userMask, copyerr;
++static char cpSrcPath[MAXPATHLEN], cpDstPath[MAXPATHLEN];
++
++
++/*************************************************/
++static int copyFile(src,dst)
++ char *src, *dst;
++{
++ /* src and dst are full
++ pathnames. It's semi-quiet about errors. a non-existant src file is
++ *not* considered an error (as we don't check for thumbfiles to exist
++ before calling this function). Returns '1' on error, '0' if ok.
++
++ Will be called with full filenames of source and destination, as in:
++ src="/usr/bozo/foobie" and dst="/somewhere/else/foobie" */
++
++ /* possible cases: source is either a file or a directory, or doesn't exist,
++ destination is either a file, a directory, or doesn't exist.
++
++ if source doesn't exist, nothing to do.
++ if source is a file:
++ if dest is a file, popup 'overwriting' question, delete file if ok
++ if dest is a dir, popup 'overwriting dir' question, delete dir if ok
++ fall through: if dest doesn't exist, copy the file
++ if source is a dir:
++ if dest is a file, popup 'overwriting' question, delete file if ok
++ if dest is a dir, popup 'overwriting dir' question, delete dir if ok
++ fall through: if dest doesn't exist, copy the directory, recurs */
++
++
++ int i, dstExists, srcdir, dstdir;
++ struct stat srcSt, dstSt;
++ char buf[1024];
++ static char *owdiff[3] = { "\nOk", "nNo", "\033Cancel" };
++ static char *owsame[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" };
++
++ if (DEBUG) fprintf(stderr,"copyFile %s %s\n", src, dst);
++
++ if (stat(src,&srcSt)) return 0; /* source doesn't exist, it would seem */
++
++ dstExists = (stat(dst, &dstSt)==0);
++
++ if (dstExists) { /* ask about overwriting... */
++ srcdir = (stat2bf((u_int) srcSt.st_mode) == BF_DIR);
++ dstdir = (stat2bf((u_int) dstSt.st_mode) == BF_DIR);
++
++ sprintf(buf, "%s '%s' already exists. Replace it with %s '%s'?",
++ (dstdir) ? "Directory" : "File", dst,
++ (srcdir) ? "contents of directory" : "file", src);
++
++ if (srcdir == dstdir) {
++ if (overwrite==OWRT_ASK) {
++ i = PopUp(buf, owsame, 4);
++ if (i==1) overwrite = OWRT_NOASK;
++ if (i==2) return -1;
++ else if (i==3) { overwrite = OWRT_CANCEL; return 1; }
++ }
++ }
++ else { /* one's a dir, the other's a file. *ALWAYS* ask! */
++ i = PopUp(buf, owdiff, 3);
++ if (i==1) return -1;
++ else if (i==2) { overwrite = OWRT_CANCEL; return 1; }
++ }
++
++
++ /* it's okay... rm the destination */
++ if (dstdir) {
++ if (rmdir(dst)) return 1; /* failed to remove */
++ }
++ else {
++ if (unlink(dst)) return 1; /* failed to remove */
++ }
++
++ dstExists = 0;
++ }
++
++
++ /* destination doesn't exist no more, if it ever did... */
++ userMask = umask(0); /* grab the umask */
++ umask((mode_t) userMask); /* put it back... */
++
++
++ strcpy(cpSrcPath, src);
++ strcpy(cpDstPath, dst);
++
++ copyerr = 0;
++ cp();
++
++ return (copyerr>0) ? 1 : 0;
++}
++
++
++/* The following cp() and cp_* functions are derived from the source
++ to 'cp' from the BSD sources */
++
++/*
++ * Copyright (c) 1988 The Regents of the University of California.
++ * All rights reserved.
++ *
++ * This code is derived from software contributed to Berkeley by
++ * David Hitz of Auspex Systems Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. All advertising materials mentioning features or use of this software
++ * must display the following acknowledgement:
++ * This product includes software developed by the University of
++ * California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++
++/************************/
++static void cp()
++/************************/
++{
++ /* copies 'thing' at cpSrcPath to cpDstPath. Since this function is
++ called recursively by cp_dir, there are *no* guarantees that either file
++ exists or not */
++
++ int i, havedst;
++ struct stat srcSt, dstSt;
++
++ if (stat(cpSrcPath, &srcSt)) { /* src doesn't exist, usefully... */
++ SetISTR(ISTR_WARNING, "%s: %s", cpSrcPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++
++ if (stat(cpDstPath, &dstSt)) { /* dst doesn't exist. not really a prob */
++ havedst = 0;
++ }
++ else {
++ if (srcSt.st_dev == dstSt.st_dev && srcSt.st_ino == dstSt.st_ino) {
++ return; /* identical files: nothing to do */
++ }
++ havedst = 1;
++ }
++
++
++ switch(stat2bf((u_int) srcSt.st_mode)) {
++ /* determine how to copy, by filetype */
++
++ /* NOTE: There is no S_IFLNK case here, since we're using 'stat()' and
++ * not lstat(). As such we'll never see symbolic links, only that which
++ * they point to
++ */
++
++ case BF_DIR: if (!havedst) { /* create destination directory */
++ if (mkdir(cpDstPath, srcSt.st_mode | 0700) < 0) {
++ SetISTR(ISTR_WARNING,"%s: %s",cpDstPath,ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++ }
++ else {
++ if (stat2bf((u_int) dstSt.st_mode) != BF_DIR) {
++ SetISTR(ISTR_WARNING,"%s: not a directory", cpDstPath);
++ copyerr++;
++ return;
++ }
++ }
++
++ cp_dir();
++ if (!havedst) chmod(cpDstPath, srcSt.st_mode);
++
++ break;
++
++
++ case BF_CHR:
++ case BF_BLK: cp_special(&srcSt, havedst); break;
++
++ case BF_FIFO: cp_fifo(&srcSt, havedst); break;
++
++ case BF_SOCK: SetISTR(ISTR_WARNING,"Socket file '%s' not copied.",
++ cpSrcPath);
++ copyerr++;
++ break;
++
++ default: cp_file(&srcSt, havedst);
++ }
++
++ return;
++}
++
++
++/********************/
++static void cp_dir()
++/********************/
++{
++ int i, dirlen, oldsrclen, olddstlen, longpath;
++ char **names, *name;
++ struct stat srcSt, dstSt;
++
++
++ /* src and dst directories both exists now. copy entries */
++
++ if (DEBUG) fprintf(stderr,"cp_dir: src='%s', dst='%s'\n",
++ cpSrcPath, cpDstPath);
++
++ longpath = 0;
++ oldsrclen = strlen(cpSrcPath);
++ olddstlen = strlen(cpDstPath);
++
++ names = getDirEntries(cpSrcPath, &dirlen, 1);
++ if (!names || !dirlen) return; /* nothing to copy */
++
++
++ /* now, we've got a list of entry names. Copy the non-subdirs first, for
++ performance reasons... */
++
++ for (i=0; i<dirlen && overwrite!=OWRT_CANCEL; i++) {
++ name = names[i];
++ if (name[0] == '.' && (name[1]=='\0' ||
++ (name[1]=='.' && name[2]=='\0'))) goto done;
++
++ /* add name to src and dst paths */
++ if ((strlen(name) + oldsrclen >= (MAXPATHLEN-3)) ||
++ (strlen(name) + olddstlen >= (MAXPATHLEN-3))) {
++ copyerr++; /* path too long */
++ longpath = 1;
++ goto done;
++ }
++
++ strcat(cpSrcPath, "/");
++ strcat(cpSrcPath, name);
++
++ if (stat(cpSrcPath, &srcSt) < 0) {
++ SetISTR(ISTR_WARNING,"%s: %s",cpSrcPath,ERRSTR(errno));
++ copyerr++;
++ cpSrcPath[oldsrclen] = '\0';
++ goto done;
++ }
++
++ if (stat2bf((u_int) srcSt.st_mode) == BF_DIR) {
++ cpSrcPath[oldsrclen] = '\0';
++ continue; /* don't remove from list, just skip */
++ }
++
++ strcat(cpDstPath, "/");
++ strcat(cpDstPath, name);
++ cp(); /* RECURSE */
++
++ cpSrcPath[oldsrclen] = '\0';
++ cpDstPath[olddstlen] = '\0';
++
++ done: /* remove name from list */
++ free(name);
++ names[i] = (char *) NULL;
++ }
++
++
++ /* copy subdirectories, which are the only things left in the list */
++ for (i=0; i<dirlen && overwrite!=OWRT_CANCEL; i++) {
++ if (!names[i]) continue; /* loop until next name found */
++ name = names[i];
++
++ /* add name to src and dst paths */
++ if ((strlen(name) + oldsrclen >= (MAXPATHLEN-3)) ||
++ (strlen(name) + olddstlen >= (MAXPATHLEN-3))) {
++ copyerr++;
++ longpath = 1;
++ continue;
++ }
++
++ strcat(cpSrcPath, "/");
++ strcat(cpSrcPath, name);
++
++ strcat(cpDstPath, "/");
++ strcat(cpDstPath, name);
++
++ cp(); /* RECURSE */
++
++ cpSrcPath[oldsrclen] = '\0';
++ cpDstPath[olddstlen] = '\0';
++ }
++
++ /* free all memory still in use */
++ for (i=0; i<dirlen; i++) {
++ if (names[i]) free(names[i]);
++ }
++ free(names);
++
++ if (longpath) SetISTR(ISTR_WARNING, "Path too long error!");
++}
++
++
++/*****************************/
++static void cp_file(st, exists)
++ struct stat *st;
++ int exists;
++/*****************************/
++{
++ register int srcFd, dstFd, rcount, wcount, i;
++ char str[512], buf[8192];
++ static char *owbuts[4] = { "\nOk", "dDon't Ask", "nNo", "\033Cancel" };
++
++ if (DEBUG) fprintf(stderr,"cp_file: src='%s', dst='%s'\n",
++ cpSrcPath, cpDstPath);
++
++ if ((srcFd = open(cpSrcPath, O_RDONLY, 0)) == -1) {
++ SetISTR(ISTR_WARNING, "%s: %s", cpSrcPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++
++ if (exists) {
++ if (overwrite==OWRT_ASK) {
++ sprintf(buf, "File '%s' exists.\n\nOverwrite?", cpDstPath);
++ i = PopUp(buf, owbuts, 4);
++
++ if (i==1) overwrite = OWRT_NOASK;
++ else if (i==2) return;
++ else if (i==3) { overwrite = OWRT_CANCEL; return; }
++ }
++ dstFd = open(cpDstPath, O_WRONLY|O_TRUNC, 0);
++ }
++ else
++ dstFd = open(cpDstPath, O_WRONLY|O_CREAT|O_TRUNC,
++ (st->st_mode & 0777) & (~userMask));
++
++ if (dstFd == -1) {
++ SetISTR(ISTR_WARNING, "%s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++
++ WaitCursor();
++
++ /* copy the file contents */
++ while ((rcount = read(srcFd, buf, (size_t) 8192)) > 0) {
++ wcount = write(dstFd, buf, (size_t) rcount);
++ if (rcount != wcount || wcount == -1) {
++ SetISTR(ISTR_WARNING, "%s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ break;
++ }
++ }
++ if (rcount < 0) {
++ SetISTR(ISTR_WARNING, "%s: %s", cpSrcPath, ERRSTR(errno));
++ copyerr++;
++ }
++
++ close(srcFd);
++ if (close(dstFd)) {
++ SetISTR(ISTR_WARNING, "%s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ }
++}
++
++
++
++/*********************************/
++static void cp_special(st, exists)
++ struct stat *st;
++ int exists;
++/*********************************/
++{
++ if (DEBUG) fprintf(stderr,"cp_spec: src='%s', dst='%s'\n",
++ cpSrcPath, cpDstPath);
++
++ if (exists && unlink(cpDstPath)) {
++ SetISTR(ISTR_WARNING, "unlink %s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++
++#ifndef VMS /* VMS doesn't have a mknod command */
++ if (mknod(cpDstPath, st->st_mode, st->st_rdev)) {
++ SetISTR(ISTR_WARNING, "mknod %s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++#endif
++
++}
++
++
++/*********************************/
++static void cp_fifo(st, exists)
++ struct stat *st;
++ int exists;
++/*********************************/
++{
++ if (DEBUG) fprintf(stderr,"cp_fifo: src='%s', dst='%s'\n",
++ cpSrcPath, cpDstPath);
++
++#ifdef S_IFIFO
++ if (exists && unlink(cpDstPath)) {
++ SetISTR(ISTR_WARNING, "unlink %s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++
++ if (mknod(cpDstPath, (st->st_mode & 07777) | S_IFIFO, 0)) {
++ /* was: mkfifo(cpDstPath, st->st_mode) */
++ SetISTR(ISTR_WARNING, "mkfifo %s: %s", cpDstPath, ERRSTR(errno));
++ copyerr++;
++ return;
++ }
++#endif
++}
++
++
++
++
++/*********************************/
++static int stat2bf(uistmode)
++ u_int uistmode;
++{
++ /* given the 'st.st_mode' field from a successful stat(), returns
++ BF_FILE, BF_DIR, BF_BLK, BF_CHR, BF_FIFO, or BF_SOCK. Does *NOT*
++ return BF_EXE */
++
++ int rv;
++ mode_t stmode = (mode_t) uistmode;
++
++ if (S_ISDIR(stmode)) rv = BF_DIR;
++ else if (S_ISCHR(stmode)) rv = BF_CHR;
++ else if (S_ISBLK(stmode)) rv = BF_BLK;
++ else if (S_ISFIFO(stmode)) rv = BF_FIFO;
++ else if (S_ISSOCK(stmode)) rv = BF_SOCK;
++ else rv = BF_FILE;
++
++ return rv;
++}
++
++
++
++/*********************************/
++static int selmatch(name, line)
++ char *name, *line;
++{
++ /* returns non-zero if 'name' is found in 'line'. Line can be sequence of
++ words separated by whitespace, in which case 'name' is compared to each
++ word in the line */
++
++ char *arg;
++ int ch, rv;
++
++ rv = 0;
++
++ while (*line && !rv) {
++ while (*line && isspace(*line)) line++; /* to begin of next word */
++ arg = line;
++ while (*line && !isspace(*line)) line++; /* end of this word */
++
++ ch = *line; *line = '\0'; /* null-terminate 'arg' */
++ rv = selmatch1(name, arg);
++ *line = ch;
++ }
++
++ return rv;
++}
++
++
++/*********************************/
++static int selmatch1(name, arg)
++ char *name, *arg;
++{
++ /* returns non-zero if 'name' matches 'arg'. Any '*' chars found in arg
++ are considered wildcards that match any number of characters,
++ including zero. */
++
++ char *sp, *oldnp;
++
++ while (*arg && *name) {
++ if (*arg != '*') {
++ if (*arg != *name) return 0;
++ arg++; name++;
++ }
++
++ else { /* hit a '*' ... */
++ for (sp=arg+1; *sp && *sp!='*'; sp++); /* any other '*'s in arg? */
++ if (!*sp) {
++ /* this is the last '*'. Advance name, arg to end of their strings,
++ and match backwards until we hit the '*' character */
++
++ oldnp = name;
++ while (*name) name++;
++ while (*arg ) arg++;
++ name--; arg--;
++
++ while (*arg != '*') {
++ if (*arg != *name || name<oldnp) return 0;
++ arg--; name--;
++ }
++ return 1; /* success! */
++ }
++
++ else { /* there are more '*'s in arg... */
++ /* find the first occurrence of the string between the two '*'s.
++ if the '*'s are next to each other, just throw away the first one */
++
++ arg++; /* points to char after first '*' */
++ sp--; /* points to char before second '*' */
++
++ if (arg<=sp) { /* find string arg..sp in name */
++ int i;
++ int sslen = (sp-arg) + 1;
++
++ while (*name) {
++ for (i=0; i<sslen && name[i] && name[i]==arg[i]; i++);
++ if (i==sslen) break;
++ else name++;
++ }
++ if (!*name) return 0;
++
++ /* found substring in name */
++ name += sslen;
++ arg = sp+1;
++ }
++ }
++ }
++ }
++
++ if (!*arg && !*name) return 1;
++
++ return 0;
++}
++
++
++
+diff -urN xv-3.10a/xvctrl.c xv-3.10apatched/xvctrl.c
+--- xv-3.10a/xvctrl.c Thu Dec 22 14:34:41 1994
++++ xv-3.10apatched/xvctrl.c Tue Apr 30 00:20:19 2002
+@@ -101,7 +101,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 -urN xv-3.10a/xvdial.c xv-3.10apatched/xvdial.c
+--- xv-3.10a/xvdial.c Tue Jan 3 13:20:31 1995
++++ xv-3.10apatched/xvdial.c Tue Apr 30 00:10:16 2002
+@@ -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 -urN xv-3.10a/xvdir.c xv-3.10apatched/xvdir.c
+--- xv-3.10a/xvdir.c Tue Jan 3 13:21:39 1995
++++ xv-3.10apatched/xvdir.c Tue Apr 30 00:19:13 2002
+@@ -62,6 +62,9 @@
+ #ifdef HAVE_TIFF
+ "TIFF",
+ #endif
++#ifdef HAVE_PNG
++ "PNG",
++#endif
+ "PostScript",
+ "PBM/PGM/PPM (raw)",
+ "PBM/PGM/PPM (ascii)",
+@@ -1115,6 +1118,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
++
+
+
+
+@@ -1168,7 +1180,8 @@
+
+ case F_XPM:
+ rv = WriteXPM (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+- fullname, picComments);
++ fullname, picComments);
++ break;
+ case F_FITS:
+ rv = WriteFITS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
+ picComments);
+@@ -1200,6 +1213,7 @@
+ char *st;
+ {
+ strncpy(deffname, st, (size_t) MAXFNLEN-1);
++ deffname[MAXFNLEN-1] = '\0';
+ setFName(st);
+ }
+
+@@ -1380,14 +1394,21 @@
+ (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,"xpm" )==0)) {
+
+ /* found one. set lowsuf = to the new suffix, and tack on to filename */
+
+@@ -1423,6 +1444,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 -urN xv-3.10a/xvdir.c~ xv-3.10apatched/xvdir.c~
+--- xv-3.10a/xvdir.c~ Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/xvdir.c~ Tue Apr 30 00:10:16 2002
+@@ -0,0 +1,2088 @@
++/*
++ * xvdir.c - Directory changin', file i/o dialog box
++ *
++ * callable functions:
++ *
++ * CreateDirW(geom,bwidth)- creates the dirW window. Doesn't map it.
++ * DirBox(vis) - random processing based on value of 'vis'
++ * maps/unmaps window, etc.
++ * ClickDirW() - handles mouse clicks in DirW
++ * LoadCurrentDirectory() - loads up current dir information for dirW
++ * GetDirPath() - returns path that 'dirW' is looking at
++ * DoSave() - calls appropriate save routines
++ * SetDirFName() - sets the 'load/save-as' filename and default
++ * GetDirFName() - gets the 'load/save-as' filename (no path)
++ * SetDirSaveMode() - sets default format/color settings
++ *
++ * InitPoll() - called whenever a file is first loaded
++ * CheckPoll(int) - checks to see whether we should reload
++ */
++
++#include "copyright.h"
++
++#define NEEDSTIME /* for CheckPoll */
++#define NEEDSDIR
++#include "xv.h"
++
++#include "bits/d_load"
++#include "bits/d_save"
++
++#ifndef VMS
++#include <pwd.h> /* for getpwnam() prototype and passwd struct */
++#endif
++
++
++#define DIRWIDE 350 /* (fixed) size of directory window */
++#define DIRHIGH 400
++
++#define NLINES 15 /* # of lines in list control (keep odd) */
++#define LISTWIDE 237 /* width of list window */
++#define BUTTW 60 /* width of buttons */
++#define BUTTH 24 /* height of buttons */
++#define DDWIDE (LISTWIDE-80+15) /* max width of dirMB */
++#define DNAMWIDE 252 /* width of 'file name' entry window */
++#define MAXDEEP 30 /* max num of directories in cwd path */
++#define MAXFNLEN 256 /* max len of filename being entered */
++
++#define FMTLABEL "Format:" /* label shown next to fmtMB */
++#define COLLABEL "Colors:" /* label shown next to colMB */
++#define FMTWIDE 150 /* width of fmtMB */
++#define COLWIDE 150 /* width of colMB */
++
++/* NOTE: make sure these match up with F_* definitions in xv.h */
++static char *saveColors[] = { "Full Color",
++ "Greyscale",
++ "B/W Dithered",
++ "Reduced Color" };
++
++static char *saveFormats[] = { "GIF",
++#ifdef HAVE_JPEG
++ "JPEG",
++#endif
++#ifdef HAVE_TIFF
++ "TIFF",
++#endif
++#ifdef HAVE_PNG
++ "PNG",
++#endif
++ "PostScript",
++ "PBM/PGM/PPM (raw)",
++ "PBM/PGM/PPM (ascii)",
++ "X11 Bitmap",
++ "XPM",
++ "BMP",
++ "Sun Rasterfile",
++ "IRIS RGB",
++ "Targa (24-bit)",
++ "FITS",
++ "PM",
++ MBSEP,
++ "Filename List"};
++
++
++static void arrangeButts PARM((int));
++static void RedrawDList PARM((int, SCRL *));
++static void changedDirMB PARM((int));
++static int dnamcmp PARM((const void *, const void *));
++static int FNameCdable PARM((void));
++static void loadCWD PARM((void));
++static int cd_able PARM((char *));
++static void scrollToFileName PARM((void));
++static void setFName PARM((char *));
++static void showFName PARM((void));
++static void changeSuffix PARM((void));
++static int autoComplete PARM((void));
++
++static byte *handleBWandReduced PARM((byte *, int,int,int, int, int *,
++ byte **, byte **, byte **));
++static byte *handleNormSel PARM((int *, int *, int *, int *));
++
++
++static char *fnames[MAXNAMES];
++static int numfnames = 0, ndirs = 0;
++static char path[MAXPATHLEN+1]; /* '/' terminated */
++static char loadpath[MAXPATHLEN+1]; /* '/' terminated */
++static char savepath[MAXPATHLEN+1]; /* '/' terminated */
++static char *dirs[MAXDEEP]; /* list of directory names */
++static char *dirMBlist[MAXDEEP]; /* list of dir names in right order */
++static char *lastdir; /* name of the directory we're in */
++static char filename[MAXFNLEN+100]; /* filename being entered */
++static char deffname[MAXFNLEN+100]; /* default filename */
++
++static int savemode; /* if 0 'load box', if 1 'save box' */
++static int curPos, stPos, enPos; /* filename textedit stuff */
++static MBUTT dirMB; /* popup path menu */
++static MBUTT fmtMB; /* 'format' menu button (Save only) */
++static MBUTT colMB; /* 'colors' menu button (Save only) */
++
++static Pixmap d_loadPix, d_savePix;
++
++static int haveoldinfo = 0;
++static int oldformat, oldcolors;
++static char oldfname[MAXFNLEN+100];
++
++/* the name of the file actually opened. (the temp file if we are piping) */
++static char outFName[256];
++static int dopipe;
++
++
++/***************************************************/
++void CreateDirW(geom)
++ char *geom;
++{
++ int w, y;
++
++ path[0] = '\0';
++
++ xv_getwd(loadpath, sizeof(loadpath));
++ xv_getwd(savepath, sizeof(savepath));
++
++
++ dirW = CreateWindow("","XVdir", geom, DIRWIDE, DIRHIGH, infofg, infobg, 0);
++ if (!dirW) FatalError("couldn't create 'directory' window!");
++
++ LSCreate(&dList, dirW, 10, 5 + 3*(6+LINEHIGH) + 6, LISTWIDE,
++ LINEHIGH*NLINES, NLINES, fnames, numfnames, infofg, infobg,
++ hicol, locol, RedrawDList, 1, 0);
++
++ dnamW = XCreateSimpleWindow(theDisp, dirW, 80, dList.y + (int) dList.h + 30,
++ (u_int) DNAMWIDE+6, (u_int) LINEHIGH+5,
++ 1, infofg, infobg);
++ if (!dnamW) FatalError("can't create name window");
++ XSelectInput(theDisp, dnamW, ExposureMask);
++
++
++ CBCreate(&browseCB, dirW, DIRWIDE/2, dList.y + (int) dList.h + 6,
++ "Browse", infofg, infobg, hicol,locol);
++
++ CBCreate(&savenormCB, dirW, 220, dList.y + (int) dList.h + 6,
++ "Normal Size", infofg, infobg,hicol,locol);
++
++ CBCreate(&saveselCB, dirW, 80, dList.y + (int) dList.h + 6,
++ "Selected Area", infofg, infobg,hicol,locol);
++
++
++ /* y-coordinates get filled in when window is opened */
++ BTCreate(&dbut[S_BOK], dirW, 259, 0, 80, BUTTH,
++ "Ok", infofg, infobg,hicol,locol);
++ BTCreate(&dbut[S_BCANC], dirW, 259, 0, 80, BUTTH,
++ "Cancel", infofg,infobg,hicol,locol);
++ BTCreate(&dbut[S_BRESCAN], dirW, 259, 0, 80, BUTTH,
++ "Rescan", infofg,infobg,hicol,locol);
++ BTCreate(&dbut[S_BOLDSET], dirW, 259, 0, 80, BUTTH,
++ "Prev Set", infofg,infobg,hicol,locol);
++ BTCreate(&dbut[S_BOLDNAM], dirW, 259, 0, 80, BUTTH,
++ "Prev Name", infofg,infobg,hicol,locol);
++
++ SetDirFName("");
++ XMapSubwindows(theDisp, dirW);
++ numfnames = 0;
++
++
++ /*
++ * create MBUTTs *after* calling XMapSubWindows() to keep popup unmapped
++ */
++
++ MBCreate(&dirMB, dirW, 50, dList.y -(LINEHIGH+6),
++ (u_int) DDWIDE, (u_int) LINEHIGH, NULL, NULL, 0,
++ infofg,infobg,hicol,locol);
++
++ MBCreate(&fmtMB, dirW, DIRWIDE-FMTWIDE-10, 5,
++ (u_int) FMTWIDE, (u_int) LINEHIGH, NULL, saveFormats, F_MAXFMTS,
++ infofg,infobg,hicol,locol);
++ fmtMB.hascheck = 1;
++ MBSelect(&fmtMB, 0);
++
++ MBCreate(&colMB, dirW, DIRWIDE-COLWIDE-10, 5+LINEHIGH+6,
++ (u_int) COLWIDE, (u_int) LINEHIGH, NULL, saveColors, F_MAXCOLORS,
++ infofg,infobg,hicol,locol);
++ colMB.hascheck = 1;
++ MBSelect(&colMB, 0);
++
++
++ d_loadPix = XCreatePixmapFromBitmapData(theDisp, dirW,
++ (char *) d_load_bits, d_load_width, d_load_height,
++ infofg, infobg, dispDEEP);
++
++ d_savePix = XCreatePixmapFromBitmapData(theDisp, dirW,
++ (char *) d_save_bits, d_save_width, d_save_height,
++ infofg, infobg, dispDEEP);
++
++}
++
++
++/***************************************************/
++void DirBox(mode)
++ int mode;
++{
++ static int firstclose = 1;
++
++ if (!mode) {
++ if (savemode) strcpy(savepath, path);
++ else strcpy(loadpath, path);
++
++ if (firstclose) {
++ strcpy(loadpath, path);
++ strcpy(savepath, path);
++ firstclose = 0;
++ }
++
++ XUnmapWindow(theDisp, dirW); /* close */
++ }
++
++ else if (mode == BLOAD) {
++ strcpy(path, loadpath);
++ WaitCursor(); LoadCurrentDirectory(); SetCursors(-1);
++
++ XStoreName(theDisp, dirW, "xv load");
++ XSetIconName(theDisp, dirW, "xv load");
++
++ dbut[S_BLOADALL].str = "Load All";
++ BTSetActive(&dbut[S_BLOADALL], 1);
++
++ arrangeButts(mode);
++
++ MBSetActive(&fmtMB, 0);
++ MBSetActive(&colMB, 0);
++
++ CenterMapWindow(dirW, dbut[S_BOK].x+30, dbut[S_BOK].y + BUTTH/2,
++ DIRWIDE, DIRHIGH);
++
++ savemode = 0;
++ }
++
++ else if (mode == BSAVE) {
++ strcpy(path, savepath);
++ WaitCursor(); LoadCurrentDirectory(); SetCursors(-1);
++
++ XStoreName(theDisp, dirW, "xv save");
++ XSetIconName(theDisp, dirW, "xv save");
++
++ dbut[S_BOLDSET].str = "Prev Set";
++
++ arrangeButts(mode);
++
++ BTSetActive(&dbut[S_BOLDSET], haveoldinfo);
++ BTSetActive(&dbut[S_BOLDNAM], haveoldinfo);
++
++ CBSetActive(&saveselCB, HaveSelection());
++
++ MBSetActive(&fmtMB, 1);
++ if (MBWhich(&fmtMB) == F_FILELIST) {
++ MBSetActive(&colMB, 0);
++ CBSetActive(&savenormCB, 0);
++ }
++ else {
++ MBSetActive(&colMB, 1);
++ CBSetActive(&savenormCB, 1);
++ }
++
++ CenterMapWindow(dirW, dbut[S_BOK].x+30, dbut[S_BOK].y + BUTTH/2,
++ DIRWIDE, DIRHIGH);
++
++ savemode = 1;
++ }
++
++ scrollToFileName();
++
++ dirUp = mode;
++ BTSetActive(&but[BLOAD], !dirUp);
++ BTSetActive(&but[BSAVE], !dirUp);
++}
++
++
++/***************************************************/
++static void arrangeButts(mode)
++ int mode;
++{
++ int i, nbts, ngaps, szdiff, top, gap;
++
++ nbts = (mode==BLOAD) ? S_LOAD_NBUTTS : S_NBUTTS;
++ ngaps = nbts-1;
++
++ szdiff = dList.h - (nbts * BUTTH);
++ gap = szdiff / ngaps;
++
++ if (gap>16) {
++ gap = 16;
++ top = dList.y + (dList.h - (nbts*BUTTH) - (ngaps*gap))/2;
++
++ for (i=0; i<nbts; i++) dbut[i].y = top + i*(BUTTH+gap);
++ }
++ else {
++ for (i=0; i<nbts; i++)
++ dbut[i].y = dList.y + ((dList.h-BUTTH)*i) / ngaps;
++ }
++}
++
++
++
++/***************************************************/
++void RedrawDirW(x,y,w,h)
++ int x,y,w,h;
++{
++ int i, ypos, txtw;
++ char foo[30], *str;
++ XRectangle xr;
++
++ if (dList.nstr==1) strcpy(foo,"1 file");
++ else sprintf(foo,"%d files",dList.nstr);
++
++ ypos = dList.y + dList.h + 8 + ASCENT;
++ XSetForeground(theDisp, theGC, infobg);
++ XFillRectangle(theDisp, dirW, theGC, 10, ypos-ASCENT,
++ (u_int) DIRWIDE, (u_int) CHIGH);
++ XSetForeground(theDisp, theGC, infofg);
++ DrawString(dirW, 10, ypos, foo);
++
++
++ if (dirUp == BLOAD) str = "Load file:";
++ else str = "Save file:";
++ DrawString(dirW, 10, dList.y + (int) dList.h + 30 + 4 + ASCENT, str);
++
++ /* draw dividing line */
++ XSetForeground(theDisp, theGC, infofg);
++ XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-6, DIRWIDE, dirMB.y-6);
++ if (ctrlColor) {
++ XSetForeground(theDisp, theGC, locol);
++ XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-5, DIRWIDE, dirMB.y-5);
++ XSetForeground(theDisp, theGC, hicol);
++ }
++ XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-4, DIRWIDE, dirMB.y-4);
++
++
++
++ for (i=0; i<(savemode ? S_NBUTTS : S_LOAD_NBUTTS); i++) BTRedraw(&dbut[i]);
++
++ MBRedraw(&dirMB);
++ MBRedraw(&fmtMB);
++ MBRedraw(&colMB);
++
++ XSetForeground(theDisp, theGC, infofg);
++ XSetBackground(theDisp, theGC, infobg);
++
++ txtw = StringWidth(FMTLABEL);
++ if (StringWidth(COLLABEL) > txtw) txtw = StringWidth(COLLABEL);
++
++ if (!savemode) {
++ XCopyArea(theDisp, d_loadPix, dirW, theGC, 0,0,d_load_width,d_load_height,
++ 10, (dirMB.y-6)/2 - d_load_height/2);
++
++ XSetFillStyle(theDisp, theGC, FillStippled);
++ XSetStipple(theDisp, theGC, dimStip);
++ DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT, FMTLABEL);
++ DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT + (LINEHIGH+6), COLLABEL);
++ XSetFillStyle(theDisp,theGC,FillSolid);
++
++ CBRedraw(&browseCB);
++ }
++ else {
++ XCopyArea(theDisp, d_savePix, dirW, theGC, 0,0,d_save_width,d_save_height,
++ 10, (dirMB.y-6)/2 - d_save_height/2);
++
++ XSetForeground(theDisp, theGC, infofg);
++ DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT, FMTLABEL);
++ DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT + (LINEHIGH+6), COLLABEL);
++
++ CBRedraw(&savenormCB);
++ CBRedraw(&saveselCB);
++ }
++}
++
++
++/***************************************************/
++int ClickDirW(x,y)
++int x,y;
++{
++ BUTT *bp;
++ int bnum,i,maxbut,v;
++ char buf[1024];
++
++ if (savemode) { /* check format/colors MBUTTS */
++ i = v = 0;
++ if (MBClick(&fmtMB, x,y) && (v=MBTrack(&fmtMB))>=0) i=1;
++ else if (MBClick(&colMB, x,y) && (v=MBTrack(&colMB))>=0) i=2;
++
++ if (i) { /* changed one of them */
++ if (i==1) SetDirSaveMode(F_FORMAT, v);
++ else SetDirSaveMode(F_COLORS, v);
++ changeSuffix();
++ }
++ }
++
++
++ if (!savemode) { /* LOAD */
++ if (CBClick(&browseCB,x,y)) CBTrack(&browseCB);
++ }
++ else { /* SAVE */
++ if (CBClick(&savenormCB,x,y)) CBTrack(&savenormCB);
++ else if (CBClick(&saveselCB,x,y)) CBTrack(&saveselCB);
++ }
++
++
++ maxbut = (savemode) ? S_NBUTTS : S_LOAD_NBUTTS;
++
++ for (bnum=0; bnum<maxbut; bnum++) {
++ bp = &dbut[bnum];
++ if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
++ }
++
++ if (bnum<maxbut && BTTrack(bp)) { /* found one */
++ if (bnum<S_BOLDSET) return bnum; /* do Ok,Cancel,Rescan in xvevent.c */
++
++ if (bnum == S_BOLDSET && savemode && haveoldinfo) {
++ MBSelect(&fmtMB, oldformat);
++ MBSelect(&colMB, oldcolors);
++ changeSuffix();
++ }
++
++ else if (bnum == S_BOLDNAM && savemode && haveoldinfo) {
++ setFName(oldfname);
++ }
++
++ else if (bnum == S_BLOADALL && !savemode) {
++ int j, oldnumnames;
++ char *dname;
++
++ oldnumnames = numnames;
++
++ for (i=0; i<numfnames && numnames<MAXNAMES; i++) {
++ if (fnames[i][0] == C_REG || fnames[i][0] == C_EXE) {
++ sprintf(buf,"%s%s", path, fnames[i]+1);
++
++ /* check for dups. Don't add it if it is. */
++ for (j=0; j<numnames && strcmp(buf,namelist[j]); j++);
++
++ if (j==numnames) { /* add to list */
++ namelist[numnames] = (char *) malloc(strlen(buf)+1);
++ if (!namelist[numnames]) FatalError("out of memory!\n");
++ strcpy(namelist[numnames],buf);
++
++ dname = namelist[numnames];
++
++ /* figure out how much of name can be shown */
++ if (StringWidth(dname) > (nList.w-10-16)) { /* truncate */
++ char *tmp;
++ int prelen = 0;
++
++ tmp = dname;
++ while (1) {
++ tmp = (char *) index(tmp,'/'); /* find next '/' in buf */
++ if (!tmp) break;
++
++ tmp++; /* move to char following the '/' */
++ prelen = tmp - dname;
++ if (StringWidth(tmp) <= (nList.w-10-16)) break; /* cool now */
++ }
++
++ dispnames[numnames] = dname + prelen;
++ }
++ else dispnames[numnames] = dname;
++
++ numnames++;
++ }
++ }
++ }
++
++ if (oldnumnames != numnames) { /* added some */
++ if (numnames>0) BTSetActive(&but[BDELETE],1);
++ windowMB.dim[WMB_TEXTVIEW] = (numnames==0);
++
++ LSNewData(&nList, dispnames, numnames);
++ nList.selected = oldnumnames;
++ curname = oldnumnames - 1;
++
++ ActivePrevNext();
++
++ ScrollToCurrent(&nList);
++ DrawCtrlNumFiles();
++
++ if (!browseCB.val) DirBox(0);
++ }
++
++ }
++ }
++
++
++
++ if (MBClick(&dirMB, x, y)) {
++ i = MBTrack(&dirMB);
++ if (i >= 0) changedDirMB(i);
++ }
++
++ return -1;
++}
++
++
++/***************************************************/
++void SelectDir(n)
++int n;
++{
++ /* called when entry #n in the dir list was selected/double-clicked */
++
++ /* if n<0, nothing was double-clicked, but perhaps the selection
++ has changed. Copy the selection to the filename if a) we're in
++ the 'load' box, and b) it's not a directory name */
++
++ if (n<0) {
++ if (dList.selected>=0)
++ setFName(dList.str[dList.selected]+1);
++ return;
++ }
++
++ /* can just pretend 'enter' was hit on a double click, as the original
++ click would've copied the string to filename */
++
++ if (!DirCheckCD()) FakeButtonPress(&dbut[S_BOK]);
++}
++
++
++
++/***************************************************/
++static void changedDirMB(sel)
++ int sel;
++{
++ if (sel != 0) { /* changed directories */
++ char tmppath[MAXPATHLEN+1], *trunc_point;
++
++ /* end 'path' by changing trailing '/' (of dir name) to a '\0' */
++ trunc_point = (dirs[(ndirs-1)-sel + 1] - 1);
++ *trunc_point = '\0';
++
++ if (path[0] == '\0') {
++ /* special case: if cd to '/', fix path (it's currently "") */
++#ifdef apollo /*** Apollo DomainOS uses // as the network root ***/
++ strcpy(tmppath,"//");
++#else
++ strcpy(tmppath,"/");
++#endif
++ }
++ else strcpy(tmppath, path);
++
++#ifdef VMS
++ /*
++ * The VMS chdir always needs 2 components (device and directory),
++ * so convert "/device" to "/device/000000" and convert
++ * "/" to "/XV_Root_Device/000000" (XV_Root_Device will need to be
++ * a special concealed device setup to provide a list of available
++ * disks).
++ */
++ if ( ((ndirs-sel) == 2) && (strlen(tmppath) > 1) )
++ strcat ( tmppath, "/000000" ); /* add root dir for device */
++ else if ((ndirs-sel) == 1 ) {
++ strcpy ( tmppath, "/XV_Root_Device/000000" ); /* fake top level */
++ }
++#endif
++
++ if (chdir(tmppath)) {
++ char str[512];
++ sprintf(str,"Unable to cd to '%s'\n", tmppath);
++ *trunc_point = '/'; /* restore the path */
++ MBRedraw(&dirMB);
++ ErrPopUp(str, "\nWhatever");
++ }
++ else {
++ loadCWD();
++ }
++ }
++}
++
++
++/***************************************************/
++static void RedrawDList(delta, sptr)
++ int delta;
++ SCRL *sptr;
++{
++ LSRedraw(&dList,delta);
++}
++
++
++/***************************************************/
++static void loadCWD()
++{
++ /* loads up current-working-directory into load/save list */
++
++ xv_getwd(path, sizeof(path));
++ LoadCurrentDirectory();
++}
++
++
++
++/***************************************************/
++void LoadCurrentDirectory()
++{
++ /* rescans current load/save directory */
++
++ DIR *dirp;
++ int i, j, ftype, mode, changedDir;
++ struct stat st;
++ char *dbeg, *dend;
++ static char oldpath[MAXPATHLEN + 2] = { '\0' };
++
++#ifdef NODIRENT
++ struct direct *dp;
++#else
++ struct dirent *dp;
++#endif
++
++
++ /* get rid of previous file names */
++ for (i=0; i<numfnames; i++) free(fnames[i]);
++ numfnames = 0;
++
++ /* get rid of old dirMBlist */
++ for (i=0; i<ndirs; i++) free(dirMBlist[i]);
++
++#ifndef VMS
++ if (strlen(path) == 0) xv_getwd(path, sizeof(path)); /* no dir, use cwd */
++#else
++ xv_getwd(path, sizeof(path));
++#endif
++
++ if (chdir(path)) {
++ ErrPopUp("Current load/save directory seems to have gone away!",
++ "\nYikes!");
++#ifdef apollo
++ strcpy(path,"//");
++#else
++ strcpy(path,"/");
++#endif
++ chdir(path);
++ }
++
++ changedDir = strcmp(path, oldpath);
++ strcpy(oldpath, path);
++
++ if ((strlen(path) > (size_t) 1) && path[strlen(path)-1] != '/')
++ strcat(path,"/"); /* tack on a trailing '/' to make path consistent */
++
++ /* path will be something like: "/u3/bradley/src/weiner/whatever/" */
++ /* parse path into individual directory names */
++ dbeg = dend = path;
++ for (i=0; i<MAXDEEP && dend; i++) {
++ dend = (char *) index(dbeg,'/'); /* find next '/' char */
++
++#ifdef apollo
++ /** On apollos the path will be something like //machine/users/foo/ **/
++ /** handle the initial // **/
++ if ((dend == dbeg ) && (dbeg[0] == '/') && (dbeg[1] == '/')) dend += 1;
++#endif
++
++ dirs[i] = dbeg;
++ dbeg = dend+1;
++ }
++ ndirs = i-1;
++
++
++ /* build dirMBlist */
++ for (i=ndirs-1,j=0; i>=0; i--,j++) {
++ size_t stlen = (i<(ndirs-1)) ? dirs[i+1] - dirs[i] : strlen(dirs[i]);
++ dirMBlist[j] = (char *) malloc(stlen+1);
++ if (!dirMBlist[j]) FatalError("unable to malloc dirMBlist[]");
++
++ strncpy(dirMBlist[j], dirs[i], stlen);
++ dirMBlist[j][stlen] = '\0';
++ }
++
++
++ lastdir = dirs[ndirs-1];
++ dirMB.list = dirMBlist;
++ dirMB.nlist = ndirs;
++ XClearArea(theDisp, dirMB.win, dirMB.x, dirMB.y,
++ (u_int) dirMB.w+3, (u_int) dirMB.h+3, False);
++ i = StringWidth(dirMBlist[0]) + 10;
++ dirMB.x = dirMB.x + dirMB.w/2 - i/2;
++ dirMB.w = i;
++ MBRedraw(&dirMB);
++
++
++ dirp = opendir(".");
++ if (!dirp) {
++ LSNewData(&dList, fnames, 0);
++ RedrawDirW(0,0,DIRWIDE,DIRHIGH);
++ return;
++ }
++
++ WaitCursor();
++
++ i=0;
++ while ( (dp = readdir(dirp)) != NULL) {
++ if (strcmp(dp->d_name, ".")==0 ||
++ (strcmp(dp->d_name, "..")==0 &&
++ (strcmp(path,"/")==0 || strcmp(path,"//")==0)) ||
++ strcmp(dp->d_name, THUMBDIR)==0) {
++ /* skip over '.' and '..' and THUMBDIR */
++ }
++ else {
++
++ if (i == MAXNAMES) {
++ fprintf(stderr,
++ "%s: too many directory entries. Only using first %d.\n",
++ cmd, MAXNAMES);
++ break;
++ }
++
++ if ((i&31)==0) WaitCursor();
++
++ fnames[i] = (char *) malloc(strlen(dp->d_name)+2); /* +2=ftype + '\0' */
++
++ if (!fnames[i]) FatalError("malloc error while reading directory");
++ strcpy(fnames[i]+1, dp->d_name);
++
++ /* figure out what type of file the beastie is */
++ fnames[i][0] = C_REG; /* default to normal file, if stat fails */
++
++#ifdef VMS
++ /* For VMS we will default all files EXCEPT directories to avoid
++ the high cost of the VAX C implementation of the stat function.
++ Suggested by Kevin Oberman (OBERMAN@icdc.llnl.gov) */
++
++ if (xv_strstr (fnames[i]+1, ".DIR") != NULL) fnames[i][0] = C_DIR;
++ if (xv_strstr (fnames[i]+1, ".EXE") != NULL) fnames[i][0] = C_EXE;
++ if (xv_strstr (fnames[i]+1, ".OBJ") != NULL) fnames[i][0] = C_BLK;
++#else
++ if (!nostat && (stat(fnames[i]+1, &st)==0)) {
++ mode = st.st_mode & 0777; /* rwx modes */
++
++ ftype = st.st_mode;
++ if (S_ISDIR(ftype)) fnames[i][0] = C_DIR;
++ else if (S_ISCHR(ftype)) fnames[i][0] = C_CHR;
++ else if (S_ISBLK(ftype)) fnames[i][0] = C_BLK;
++ else if (S_ISLINK(ftype)) fnames[i][0] = C_LNK;
++ else if (S_ISFIFO(ftype)) fnames[i][0] = C_FIFO;
++ else if (S_ISSOCK(ftype)) fnames[i][0] = C_SOCK;
++ else if (fnames[i][0] == C_REG && (mode&0111)) fnames[i][0] = C_EXE;
++ }
++ else {
++ /* fprintf(stderr,"problems 'stat-ing' files\n");*/
++ fnames[i][0] = C_REG;
++ }
++#endif /* VMS */
++
++ i++;
++ }
++ }
++
++ closedir(dirp);
++
++ numfnames = i;
++
++ qsort((char *) fnames, (size_t) numfnames, sizeof(char *), dnamcmp);
++
++ if (changedDir) LSNewData(&dList, fnames, numfnames);
++ else LSChangeData(&dList, fnames, numfnames);
++ RedrawDirW(0,0,DIRWIDE,DIRHIGH);
++ SetCursors(-1);
++}
++
++
++/***************************************************/
++void GetDirPath(buf)
++ char *buf;
++{
++ /* returns current 'dirW' path. buf should be MAXPATHLEN long */
++
++ strcpy(buf, path);
++}
++
++
++/***************************************************/
++static int cd_able(str)
++char *str;
++{
++ return ((str[0] == C_DIR || str[0] == C_LNK));
++}
++
++
++/***************************************************/
++static int dnamcmp(p1,p2)
++ const void *p1, *p2;
++{
++ char **s1, **s2;
++
++ s1 = (char **) p1;
++ s2 = (char **) p2;
++
++#ifdef FOO
++ /* sort so that directories are at beginning of list */
++
++ /* if both dir/lnk or both NOT dir/lnk, sort on name */
++
++ if ( ( cd_able(*s1) && cd_able(*s2)) ||
++ (!cd_able(*s1) && !cd_able(*s2)))
++ return (strcmp((*s1)+1, (*s2)+1));
++
++ else if (cd_able(*s1)) return -1; /* s1 is first */
++ else return 1; /* s2 is first */
++#else
++ /* sort in pure alpha order */
++ return(strcmp((*s1)+1, (*s2)+1));
++#endif
++}
++
++
++
++
++
++/***************************************************/
++int DirKey(c)
++ int c;
++{
++ /* got keypress in dirW. stick on end of filename */
++ int len;
++
++ len = strlen(filename);
++
++ if (c>=' ' && c<'\177') { /* printable characters */
++ /* note: only allow 'piped commands' in savemode... */
++
++ /* only allow spaces in 'piped commands', not filenames */
++ if (c==' ' && (!ISPIPE(filename[0]) || curPos==0)) return (-1);
++
++ /* only allow vertbars in 'piped commands', not filenames */
++ if (c=='|' && curPos!=0 && !ISPIPE(filename[0])) return(-1);
++
++ if (len >= MAXFNLEN-1) return(-1); /* max length of string */
++ xvbcopy(&filename[curPos], &filename[curPos+1], (size_t) (len-curPos+1));
++ filename[curPos]=c; curPos++;
++
++ scrollToFileName();
++ }
++
++ else if (c=='\010' || c=='\177') { /* BS or DEL */
++ if (curPos==0) return(-1); /* at beginning of str */
++ xvbcopy(&filename[curPos], &filename[curPos-1], (size_t) (len-curPos+1));
++ curPos--;
++
++ if (strlen(filename) > (size_t) 0) scrollToFileName();
++ }
++
++ else if (c=='\025') { /* ^U: clear entire line */
++ filename[0] = '\0';
++ curPos = 0;
++ }
++
++ else if (c=='\013') { /* ^K: clear to end of line */
++ filename[curPos] = '\0';
++ }
++
++ else if (c=='\001') { /* ^A: move to beginning */
++ curPos = 0;
++ }
++
++ else if (c=='\005') { /* ^E: move to end */
++ curPos = len;
++ }
++
++ else if (c=='\004') { /* ^D: delete character at curPos */
++ if (curPos==len) return(-1);
++ xvbcopy(&filename[curPos+1], &filename[curPos], (size_t) (len-curPos));
++ }
++
++ else if (c=='\002') { /* ^B: move backwards char */
++ if (curPos==0) return(-1);
++ curPos--;
++ }
++
++ else if (c=='\006') { /* ^F: move forwards char */
++ if (curPos==len) return(-1);
++ curPos++;
++ }
++
++ else if (c=='\012' || c=='\015') { /* CR or LF */
++ if (!DirCheckCD()) FakeButtonPress(&dbut[S_BOK]);
++ }
++
++ else if (c=='\033') { /* ESC = Cancel */
++ FakeButtonPress(&dbut[S_BCANC]);
++ }
++
++ else if (c=='\011') { /* tab = filename expansion */
++ if (!autoComplete()) XBell(theDisp, 0);
++ else {
++ curPos = strlen(filename);
++ scrollToFileName();
++ }
++ }
++
++ else return(-1); /* unhandled character */
++
++ showFName();
++
++ /* if we cleared out filename, clear out deffname as well */
++ if (!filename[0]) deffname[0] = '\0';
++
++ return(0);
++}
++
++
++/***************************************************/
++static int autoComplete()
++{
++ /* called to 'auto complete' a filename being entered. If the name that
++ has been entered so far is anything but a simple filename (ie, has
++ spaces, pipe char, '/', etc) fails. If it is a simple filename,
++ looks through the name list to find something that matches what's already
++ been typed. If nothing matches, it fails. If more than one thing
++ matches, it sets the name to the longest string that the multiple
++ matches have in common, and succeeds (and beeps).
++ If only one matches, sets the string to the match and succeeds.
++
++ returns zero on failure, non-zero on success */
++
++ int i, firstmatch, slen, nummatch, cnt;
++
++ /* is filename a simple filename? */
++ if (strlen(filename)==0 ||
++ ISPIPE(filename[0]) ||
++ index(filename, '/') ||
++ filename[0]=='~' ) return 0;
++
++ slen = strlen(filename);
++ for (i=0; i<dList.nstr; i++) {
++ if (strncmp(filename, dList.str[i]+1, (size_t) slen) <= 0) break;
++ }
++ if (i==dList.nstr) return 0;
++ if (strncmp(filename, dList.str[i]+1, (size_t) slen) < 0) return 0;
++
++ /* there's a match of some sort... */
++ firstmatch = i;
++
++ /* count # of matches */
++ for (i=firstmatch, nummatch=0;
++ i<dList.nstr && strncmp(filename, dList.str[i]+1, (size_t) slen)==0;
++ i++, nummatch++);
++
++ if (nummatch == 1) { /* only one match */
++ strcpy(filename, dList.str[firstmatch]+1);
++ return 1;
++ }
++
++
++ /* compute longest common prefix among the matches */
++ while (dList.str[firstmatch][slen+1]!='\0') {
++ filename[slen] = dList.str[firstmatch][slen+1];
++ slen++; filename[slen] = '\0';
++
++ for (i=firstmatch, cnt=0;
++ i<dList.nstr && strncmp(filename, dList.str[i]+1, (size_t) slen)==0;
++ i++, cnt++);
++
++ if (cnt != nummatch) { slen--; filename[slen] = '\0'; break; }
++ }
++
++ XBell(theDisp, 0);
++
++ return 1;
++}
++
++/***************************************************/
++static void scrollToFileName()
++{
++ int i, hi, lo, pos, cmp;
++
++ /* called when 'fname' changes. Tries to scroll the directory list
++ so that fname would be centered in it */
++
++ /* nothing to do if scrlbar not enabled ( <= NLINES names in list) */
++ if (dList.scrl.max <= 0) return;
++
++ /* find the position in the namelist that the current name should be at
++ (binary search) */
++
++ pos = 0; lo = 0; hi = dList.nstr-1;
++ i = strlen(filename);
++ if (!i) { SCSetVal(&dList.scrl, 0); return; }
++
++ while ((hi-lo)>=0) {
++ pos = lo + (hi-lo)/2;
++ cmp = strcmp(filename, dList.str[pos]+1);
++ if (cmp<0) hi = pos-1;
++ else if (cmp>0) lo = pos+1;
++ else break; /* found it! */
++ }
++
++ /* set scroll position so that 'pos' will be centered in the list */
++ i = pos - (NLINES/2);
++ SCSetVal(&dList.scrl, i);
++}
++
++
++/***************************************************/
++void RedrawDNamW()
++{
++ int cpos;
++
++ /* draw substring filename[stPos:enPos] and cursor */
++
++ Draw3dRect(dnamW, 0, 0, (u_int) DNAMWIDE+5, (u_int) LINEHIGH+4, R3D_IN, 2,
++ hicol, locol, infobg);
++
++ XSetForeground(theDisp, theGC, infofg);
++
++ if (stPos>0) { /* draw a "there's more over here" doowah */
++ XDrawLine(theDisp, dnamW, theGC, 0,0,0,LINEHIGH+5);
++ XDrawLine(theDisp, dnamW, theGC, 1,0,1,LINEHIGH+5);
++ XDrawLine(theDisp, dnamW, theGC, 2,0,2,LINEHIGH+5);
++ }
++
++ if ((size_t) enPos < strlen(filename)) {
++ /* draw a "there's more over here" doowah */
++ XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+5,0,DNAMWIDE+5,LINEHIGH+5);
++ XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+4,0,DNAMWIDE+4,LINEHIGH+5);
++ XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+3,0,DNAMWIDE+3,LINEHIGH+5);
++ }
++
++ XDrawString(theDisp, dnamW, theGC,3,ASCENT+3,filename+stPos, enPos-stPos);
++
++ cpos = XTextWidth(mfinfo, &filename[stPos], curPos-stPos);
++ XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2, 3+cpos, 2+CHIGH+1);
++ XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2+CHIGH+1, 5+cpos, 2+CHIGH+3);
++ XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2+CHIGH+1, 1+cpos, 2+CHIGH+3);
++}
++
++
++/***************************************************/
++int DoSave()
++{
++ FILE *fp;
++ byte *thepic, *rp, *gp, *bp;
++ int i, w, h, rv, fmt, col, nc, ptype, pfree;
++ char *fullname;
++
++ /* opens file, does appropriate color pre-processing, calls save routine
++ based on chosen format. Returns '0' if successful */
++
++ dbut[S_BOK].lit = 1; BTRedraw(&dbut[S_BOK]);
++
++ fullname = GetDirFullName();
++
++ fmt = MBWhich(&fmtMB);
++ col = MBWhich(&colMB);
++
++ if (fmt<0 || col<0)
++ FatalError("xv: no 'checked' format or color. shouldn't happen!\n");
++
++
++ if (fmt == F_FILELIST) { /* write filename list */
++ fp = OpenOutFile(fullname);
++ if (!fp) {
++ SetCursors(-1);
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return -1;
++ }
++
++ for (i=0; i<numnames; i++) {
++ if ((i&0x3f)==0) WaitCursor();
++ if (namelist[i][0] != '/') fprintf(fp, "%s/%s\n", initdir, namelist[i]);
++ else fprintf(fp, "%s\n", namelist[i]);
++ }
++
++ i = (ferror(fp)) ? 1 : 0;
++ if (CloseOutFile(fp, fullname, i) == 0) {
++ DirBox(0);
++ XVCreatedFile(fullname);
++ }
++
++ SetCursors(-1);
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return i;
++ } /* FILELIST */
++
++
++ /* handle formats that pop up 'how do you want to save this' boxes */
++
++
++ if (fmt == F_PS) { /* PostScript */
++ PSSaveParams(fullname, col);
++ PSDialog(1); /* open PSDialog box */
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return 0; /* always 'succeeds' */
++ }
++
++#ifdef HAVE_JPEG
++ else if (fmt == F_JPEG) { /* JPEG */
++ JPEGSaveParams(fullname, col);
++ JPEGDialog(1); /* open JPEGDialog box */
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return 0; /* always 'succeeds' */
++ }
++#endif
++
++#ifdef HAVE_TIFF
++ else if (fmt == F_TIFF) { /* TIFF */
++ TIFFSaveParams(fullname, col);
++ TIFFDialog(1); /* open TIFF Dialog box */
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return 0; /* always 'succeeds' */
++ }
++#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
++
++
++
++
++ WaitCursor();
++
++ thepic = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rp, &gp, &bp);
++
++ fp = OpenOutFile(fullname);
++ if (!fp) {
++ if (pfree) free(thepic);
++ SetCursors(-1);
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++ return -1;
++ }
++
++
++ if (col == F_REDUCED) col = F_FULLCOLOR;
++ rv = 0;
++
++ switch (fmt) {
++ case F_GIF:
++ rv = WriteGIF (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,picComments);
++ break;
++
++ case F_PM:
++ rv = WritePM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,picComments);
++ break;
++
++ case F_PBMRAW:
++ rv = WritePBM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,1,picComments);
++ break;
++
++ case F_PBMASCII:
++ rv = WritePBM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,0,picComments);
++ break;
++
++ case F_XBM:
++ rv = WriteXBM (fp, thepic, w, h, rp, gp, bp, fullname); break;
++
++ case F_SUNRAS:
++ rv = WriteSunRas(fp, thepic, ptype, w, h, rp, gp, bp, nc, col,0); break;
++
++ case F_BMP:
++ rv = WriteBMP (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;
++
++ case F_TARGA:
++ rv = WriteTarga (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); break;
++
++ case F_XPM:
++ rv = WriteXPM (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
++ fullname, picComments);
++ break;
++ case F_FITS:
++ rv = WriteFITS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
++ picComments);
++ break;
++ }
++
++
++ if (CloseOutFile(fp, fullname, rv) == 0) {
++ DirBox(0);
++ if (!dopipe) {
++ XVCreatedFile(fullname);
++ StickInCtrlList(0);
++ }
++ }
++
++
++ if (pfree) free(thepic);
++
++ SetCursors(-1);
++ dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
++
++ return rv;
++}
++
++
++
++/***************************************************/
++void SetDirFName(st)
++ char *st;
++{
++ strncpy(deffname, st, (size_t) MAXFNLEN-1);
++ setFName(st);
++}
++
++
++/***************************************************/
++static void setFName(st)
++ char *st;
++{
++ strncpy(filename, st, (size_t) MAXFNLEN-1);
++ filename[MAXFNLEN-1] = '\0'; /* make sure it's terminated */
++ curPos = strlen(st);
++ stPos = 0; enPos = curPos;
++
++ showFName();
++}
++
++
++/***************************************************/
++static void showFName()
++{
++ int len;
++
++ len = strlen(filename);
++
++ if (curPos<stPos) stPos = curPos;
++ if (curPos>enPos) enPos = curPos;
++
++ if (stPos>len) stPos = (len>0) ? len-1 : 0;
++ if (enPos>len) enPos = (len>0) ? len-1 : 0;
++
++ /* while substring is shorter than window, inc enPos */
++
++ while (XTextWidth(mfinfo, &filename[stPos], enPos-stPos) < DNAMWIDE
++ && enPos<len) { enPos++; }
++
++ /* while substring is longer than window, dec enpos, unless enpos==curpos,
++ in which case, inc stpos */
++
++ while (XTextWidth(mfinfo, &filename[stPos], enPos-stPos) > DNAMWIDE) {
++ if (enPos != curPos) enPos--;
++ else stPos++;
++ }
++
++
++ if (ctrlColor) XClearArea(theDisp, dnamW, 2,2, (u_int) DNAMWIDE+5-3,
++ (u_int) LINEHIGH+4-3, False);
++ else XClearWindow(theDisp, dnamW);
++
++ RedrawDNamW();
++ BTSetActive(&dbut[S_BOK], strlen(filename)!=0);
++}
++
++
++/***************************************************/
++char *GetDirFName()
++{
++ return (filename);
++}
++
++
++/***************************************************/
++char *GetDirFullName()
++{
++ static char globname[MAXFNLEN+100]; /* the +100 is for ~ expansion */
++ static char fullname[MAXPATHLEN+2];
++
++ if (ISPIPE(filename[0])) strcpy(fullname, filename);
++ else {
++ strcpy(globname, filename);
++ if (globname[0] == '~') Globify(globname);
++
++ if (globname[0] != '/') sprintf(fullname, "%s%s", path, globname);
++ else strcpy(fullname, globname);
++ }
++
++ return (fullname);
++}
++
++
++/***************************************************/
++void SetDirSaveMode(group, bnum)
++ int group, bnum;
++{
++ if (group == F_COLORS) {
++ if (picType == PIC24) { /* disable REDUCED COLOR */
++ colMB.dim[F_REDUCED] = 1;
++ if (MBWhich(&colMB) == F_REDUCED) MBSelect(&colMB, F_FULLCOLOR);
++ }
++ else { /* PIC8 - turn on REDUCED COLOR, if not XBM */
++ if (MBWhich(&fmtMB) != F_XBM) {
++ colMB.dim[F_REDUCED] = 0;
++ MBRedraw(&fmtMB);
++ }
++ }
++
++ if (bnum>=0) MBSelect(&colMB, bnum);
++ }
++
++
++ else if (group == F_FORMAT) {
++ MBSelect(&fmtMB, bnum);
++ if (MBWhich(&fmtMB) == F_XBM) { /* turn off all but B/W */
++ colMB.dim[F_FULLCOLOR] = 1;
++ colMB.dim[F_GREYSCALE] = 1;
++ colMB.dim[F_BWDITHER] = 0;
++ colMB.dim[F_REDUCED] = 1;
++ MBSelect(&colMB, F_BWDITHER);
++ }
++
++ else if (MBWhich(&fmtMB) == F_FITS) { /* turn off 'color' modes */
++ colMB.dim[F_FULLCOLOR] = 1;
++ colMB.dim[F_GREYSCALE] = 0;
++ colMB.dim[F_BWDITHER] = 0;
++ colMB.dim[F_REDUCED] = 1;
++ MBSelect(&colMB, F_GREYSCALE);
++ }
++
++ else { /* turn on all */
++ colMB.dim[F_FULLCOLOR] = 0;
++ colMB.dim[F_GREYSCALE] = 0;
++ colMB.dim[F_BWDITHER] = 0;
++ colMB.dim[F_REDUCED] = (picType==PIC8) ? 0 : 1;
++ if (picType!=PIC8 && MBWhich(&colMB)==F_REDUCED)
++ MBSelect(&colMB, F_FULLCOLOR);
++ }
++
++ if (MBWhich(&fmtMB) == F_FILELIST) {
++ MBSetActive(&colMB, 0);
++ CBSetActive(&savenormCB, 0);
++ }
++ else {
++ MBSetActive(&colMB, 1);
++ CBSetActive(&savenormCB, 1);
++ }
++ }
++}
++
++
++
++/***************************************/
++static void changeSuffix()
++{
++ /* see if there's a common suffix at the end of the filename.
++ if there is, remember what case it was (all caps or all lower), lop
++ it off, and replace it with a new appropriate suffix, in the
++ same case */
++
++ int allcaps;
++ char *suffix, *sp, *dp, lowsuf[512];
++
++ /* find the last '.' in the filename */
++ suffix = (char *) rindex(filename, '.');
++ if (!suffix) return;
++ suffix++; /* point to first letter of the suffix */
++
++ /* check for all-caposity */
++ for (sp = suffix, allcaps=1; *sp; sp++)
++ if (islower(*sp)) allcaps = 0;
++
++ /* copy the suffix into an all-lower-case buffer */
++ for (sp=suffix, dp=lowsuf; *sp; sp++, dp++) {
++ *dp = (isupper(*sp)) ? tolower(*sp) : *sp;
++ }
++ *dp = '\0';
++
++ /* compare for common suffixes */
++ if ((strcmp(lowsuf,"gif" )==0) ||
++ (strcmp(lowsuf,"pm" )==0) ||
++ (strcmp(lowsuf,"pbm" )==0) ||
++ (strcmp(lowsuf,"pgm" )==0) ||
++ (strcmp(lowsuf,"ppm" )==0) ||
++ (strcmp(lowsuf,"pnm" )==0) ||
++ (strcmp(lowsuf,"bm" )==0) ||
++ (strcmp(lowsuf,"xbm" )==0) ||
++ (strcmp(lowsuf,"ras" )==0) ||
++ (strcmp(lowsuf,"bmp" )==0) ||
++ (strcmp(lowsuf,"ps" )==0) ||
++ (strcmp(lowsuf,"eps" )==0) ||
++ (strcmp(lowsuf,"rgb" )==0) ||
++ (strcmp(lowsuf,"tga" )==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) ||
++#endif
++#ifdef HAVE_PNG
++ (strcmp(lowsuf,"png" )==0) ||
++#endif
++ (strcmp(lowsuf,"xpm" )==0)) {
++
++ /* found one. set lowsuf = to the new suffix, and tack on to filename */
++
++ int fmt, col;
++ fmt = MBWhich(&fmtMB);
++ col = MBWhich(&colMB);
++
++ if (fmt<0 || col<0) return; /* shouldn't happen */
++
++ switch (fmt) {
++ case F_GIF: strcpy(lowsuf,"gif"); break;
++ case F_PM: strcpy(lowsuf,"pm"); break;
++ case F_PBMRAW:
++ case F_PBMASCII: if (col == F_FULLCOLOR || col == F_REDUCED)
++ strcpy(lowsuf,"ppm");
++ else if (col == F_GREYSCALE) strcpy(lowsuf,"pgm");
++ else if (col == F_BWDITHER) strcpy(lowsuf,"pbm");
++ break;
++
++ case F_XBM: strcpy(lowsuf,"xbm"); break;
++ case F_SUNRAS: strcpy(lowsuf,"ras"); break;
++ case F_BMP: strcpy(lowsuf,"bmp"); break;
++ case F_PS: strcpy(lowsuf,"ps"); break;
++ case F_IRIS: strcpy(lowsuf,"rgb"); break;
++ case F_TARGA: strcpy(lowsuf,"tga"); break;
++ case F_XPM: strcpy(lowsuf,"xpm"); break;
++ case F_FITS: strcpy(lowsuf,"fts"); break;
++
++#ifdef HAVE_JPEG
++ case F_JPEG: strcpy(lowsuf,"jpg"); break;
++#endif
++
++#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 */
++ for (sp=lowsuf; *sp; sp++)
++ *sp = (islower(*sp)) ? toupper(*sp) : *sp;
++ }
++
++ /* one other case: if the original suffix started with a single
++ capital letter, make the new suffix start with a single cap */
++ if (isupper(suffix[0])) lowsuf[0] = toupper(lowsuf[0]);
++
++ strcpy(suffix, lowsuf); /* tack onto filename */
++ SetDirFName(filename);
++ }
++
++}
++
++
++/***************************************************/
++int DirCheckCD()
++{
++ /* checks if the current filename is a directory. If so,
++ cd's there, resets the filename to 'deffname', and returns '1'
++
++ otherwise, does nothing and returns '0' */
++
++ if (FNameCdable()) {
++ setFName(deffname);
++ return 1;
++ }
++
++ return 0;
++}
++
++
++/***************************************************/
++static int FNameCdable()
++{
++ /* returns '1' if filename is a directory, and goes there */
++
++ char newpath[1024];
++ struct stat st;
++ int retval = 0;
++
++ newpath[0] = '\0'; /* start out empty */
++
++ if (ISPIPE(filename[0]) || strlen(filename)==0) return 0;
++
++ if (filename[0] == '/' || filename[0] == '~') { /* absolute path */
++ strcpy(newpath, filename);
++ }
++ else { /* not an absolute pathname */
++ strcpy(newpath,path);
++ strcat(newpath,filename);
++ }
++
++ if (newpath[0]=='~') { /* handle globbing */
++ Globify(newpath);
++ }
++
++#ifdef VMS
++ /* Convert names of form "/device.dir" to "/device/000000.DIR" */
++ if ( rindex ( newpath, '/' ) == newpath ) {
++ strcpy ( rindex ( newpath, '.' ), "/000000.DIR" );
++ }
++#endif
++
++ if (stat(newpath, &st)==0) {
++ int isdir;
++
++ isdir = S_ISDIR(st.st_mode);
++
++ if (isdir) {
++#ifdef VMS
++ /* remove .DIR from the path so that false 000000 directories work */
++ char *dirext;
++ dirext = rindex ( newpath, '/' );
++ if ( dirext == NULL ) dirext = newpath; else dirext++;
++ dirext = xv_strstr ( dirext, "." );
++ *dirext = '\0';
++#endif
++
++ if (chdir(newpath)==0) {
++ loadCWD(); /* success! */
++ }
++
++ else {
++ char str[512];
++
++ sprintf(str,"Can't chdir to '%s'.\n\n %s.",filename, ERRSTR(errno));
++ ErrPopUp(str, "\nPity");
++ }
++ retval = 1;
++ }
++ }
++
++ return retval;
++}
++
++
++/**************************************************************************/
++int Globify(fname)
++ char *fname;
++{
++ /* expands ~s in file names. Returns the name inplace 'name'.
++ returns 0 if okay, 1 if error occurred (user name not found) */
++
++ struct passwd *entry;
++ char *cp, *sp, *up, uname[64], tmp[MAXFNLEN+100];
++
++#ifdef VMS
++ return 1;
++#else
++ if (*fname != '~') return 0; /* doesn't start with a tilde, don't expand */
++
++ /* look for the first '/' after the tilde */
++ sp = (char *) index(fname,'/');
++ if (sp == 0) { /* no '/' after the tilde */
++ sp = fname+strlen(fname); /* sp = end of string */
++ }
++
++ /* uname equals the string between the ~ and the / */
++ for (cp=fname+1,up=uname; cp<sp; *up++ = *cp++);
++ *up='\0';
++
++ if (*uname=='\0') { /* no name. substitute ~ with $HOME */
++ char *homedir;
++ homedir = (char *) getenv("HOME");
++ if (homedir == NULL) homedir = ".";
++ strcpy(tmp,homedir);
++ strcat(tmp,sp);
++ }
++
++ else { /* get password entry for uname */
++ entry = getpwnam(uname);
++ if (entry==0) return 1; /* name not found */
++ strcpy(tmp,entry->pw_dir);
++ strcat(tmp,sp);
++ endpwent();
++ }
++
++ strcpy(fname,tmp); /* return expanded file name */
++ return 0;
++#endif /* !VMS */
++}
++
++
++
++
++/***************************************/
++FILE *OpenOutFile(filename)
++ char *filename;
++{
++ /* opens file for output. does various error handling bits. Returns
++ an open file pointer if success, NULL if failure */
++
++ FILE *fp;
++ struct stat st;
++
++ if (!filename || filename[0] == '\0') return NULL;
++ strcpy(outFName, filename);
++ dopipe = 0;
++
++ /* make sure we're in the correct directory */
++ if (strlen(path)) chdir(path);
++
++ if (ISPIPE(filename[0])) { /* do piping */
++ /* make up some bogus temp file to put this in */
++#ifndef VMS
++ sprintf(outFName, "%s/xvXXXXXX", tmpdir);
++#else
++ strcpy(outFName, "[]xvXXXXXX.lis");
++#endif
++ mktemp(outFName);
++ dopipe = 1;
++ }
++
++
++ /* see if file exists (ie, we're overwriting) */
++ if (stat(outFName, &st)==0) { /* stat succeeded, file must exist */
++ static char *foo[] = { "\nOk", "\033Cancel" };
++ char str[512];
++
++ sprintf(str,"Overwrite existing file '%s'?", outFName);
++ if (PopUp(str, foo, 2)) return NULL;
++ }
++
++
++ /* Open file */
++ fp = fopen(outFName, "w");
++ if (!fp) {
++ char str[512];
++ sprintf(str,"Can't write file '%s'\n\n %s.",outFName, ERRSTR(errno));
++ ErrPopUp(str, "\nBummer");
++ return NULL;
++ }
++
++ return fp;
++}
++
++
++/***************************************/
++int CloseOutFile(fp, filename, failed)
++ FILE *fp;
++ char *filename;
++ int failed;
++{
++ char buf[64];
++
++ /* close output file, and if piping, deal... Returns '0' if everything OK */
++
++ if (failed) { /* failure during format-specific output routine */
++ char str[512];
++ sprintf(str,"Couldn't write file '%s'.", outFName);
++ ErrPopUp(str, "\nBummer!");
++ unlink(outFName); /* couldn't properly write file: delete it */
++ return 1;
++ }
++
++
++ if (fclose(fp) == EOF) {
++ static char *foo[] = { "\nWeird!" };
++ char str[512];
++ sprintf(str,"Can't close file '%s'\n\n %s.",outFName, ERRSTR(errno));
++ ErrPopUp(str, "\nWeird!");
++ return 1;
++ }
++
++ buf[0]= '\0'; /* empty buffer */
++ { /* compute size of written file */
++ FILE *fp;
++ long filesize;
++ fp = fopen(outFName,"r");
++ if (fp) {
++ fseek(fp, 0L, 2);
++ filesize = ftell(fp);
++ fclose(fp);
++
++ sprintf(buf," (%ld bytes)", filesize);
++ }
++ }
++
++ SetISTR(ISTR_INFO,"Successfully wrote '%s'%s", outFName, buf);
++
++ if (dopipe) {
++ char cmd[512], str[1024];
++ int i;
++
++#ifndef VMS
++ sprintf(cmd, "cat %s |%s", outFName, filename+1); /* lose pipe char */
++#else
++ sprintf(cmd, "Print /Queue = XV_Queue /Delete %s", outFName);
++#endif
++ sprintf(str,"Doing command: '%s'", cmd);
++ OpenAlert(str);
++ i = system(cmd);
++
++#ifdef VMS
++ i = !i;
++#endif
++
++ if (i) {
++ sprintf(str, "Unable to complete command:\n %s", cmd);
++ CloseAlert();
++ ErrPopUp(str, "\nThat Sucks!");
++ unlink(outFName);
++ return 1;
++ }
++ else {
++ CloseAlert();
++ SetISTR(ISTR_INFO,"Successfully completed command.");
++#ifndef VMS
++ unlink(outFName);
++#endif
++ }
++ }
++
++ /* save old info */
++ haveoldinfo = 1;
++ oldformat = MBWhich(&fmtMB);
++ oldcolors = MBWhich(&colMB);
++ strcpy(oldfname, filename);
++
++ return 0;
++}
++
++
++
++
++static byte rBW[2], gBW[2], bBW[2];
++static byte gray[256];
++
++/***************************************/
++static byte *handleBWandReduced(pic, ptype, pw, ph, color, nc, rpp, gpp, bpp)
++ byte *pic;
++ int ptype, pw, ph, color, *nc;
++ byte **rpp, **gpp, **bpp;
++{
++ /* given 'color mode' (F_FULLCOLOR, etc.), we may have to dither
++ and/or use different colormaps. Returns 'nc', rpp, gpp, bpp (the
++ colormap to use). Also, if the function returns non-NULL, it generated
++ a new (dithered) image to use. */
++
++ int i;
++ byte *bwpic;
++
++ bwpic = (byte *) NULL;
++ *nc = numcols; *rpp = rMap; *gpp = gMap; *bpp = bMap;
++
++ /* quick check: if we're saving a 24-bit image, then none of this
++ complicated 'reduced'/dithered/smoothed business comes into play.
++ 'reduced' is disabled, for semi-obvious reasons, in 24-bit mode,
++ as is 'dithered'. If 'smoothed', and we're saving at current
++ size, no problem. Otherwise, if we're saving at original size,
++ smoothing should have no effect, so there's no reason to smooth
++ the original pic...
++
++ In any event: in 24-bit mode, all we have to do here is determine
++ if we're saving B/W DITHERED, and deal accordingly */
++
++
++ if (ptype == PIC24) {
++ if (color != F_BWDITHER) return NULL;
++ else { /* generate a bw-dithered version */
++ byte *p24, *thepic;
++
++ thepic = pic;
++ p24 = GammifyPic24(thepic, pw, ph);
++ if (p24) thepic = p24;
++
++ /* generate a FSDithered 1-byte per pixel image */
++ bwpic = FSDither(thepic, PIC24, pw, ph, NULL,NULL,NULL, 0, 1);
++ if (!bwpic) FatalError("unable to malloc dithered picture (DoSave)");
++
++ if (p24) free(p24); /* won't need it any more */
++
++ /* build a BW colormap */
++ rBW[0] = gBW[0] = bBW[0] = 0;
++ rBW[1] = gBW[1] = bBW[1] = 255;
++
++ *rpp = rBW; *gpp = gBW; *bpp = bBW;
++ *nc = 2;
++
++ return bwpic;
++ }
++ }
++
++
++
++ /* ptype == PIC8 ... */
++
++ *nc = numcols; *rpp = rMap; *gpp = gMap; *bpp = bMap;
++ if (color==F_REDUCED) { *rpp = rdisp; *gpp = gdisp; *bpp = bdisp; }
++
++ /* if DITHER or SMOOTH, and color==FULLCOLOR or GREY,
++ make color=REDUCED, so it will be written with the correct colortable */
++
++ if ((epicMode == EM_DITH || epicMode == EM_SMOOTH) && color != F_REDUCED) {
++ if (color == F_FULLCOLOR) {
++ *rpp = rdisp; *gpp = gdisp; *bpp = bdisp;
++ }
++ else if (color == F_GREYSCALE) {
++ for (i=0; i<256; i++) gray[i] = MONO(rdisp[i], gdisp[i], bdisp[i]);
++ *rpp = gray; *gpp = gray; *bpp = gray;
++ }
++ }
++
++
++
++
++ if (color==F_BWDITHER || (ncols==0 && color==F_REDUCED) ) {
++ /* if we're saving as 'dithered', or we're viewing as dithered
++ and we're saving 'reduced' then generate a dithered image */
++
++ if (numcols==2) return NULL; /* already dithered */
++
++ /* generate a dithered 1-byte per pixel image */
++ bwpic = FSDither(pic, PIC8, pw, ph, rMap,gMap,bMap, 0, 1);
++ if (!bwpic) FatalError("unable to malloc dithered picture (DoSave)");
++
++ /* put a BW colormap */
++ rBW[0] = (blkRGB>>16)&0xff; rBW[1] = (whtRGB>>16)&0xff;
++ gBW[0] = (blkRGB>>8)&0xff; gBW[1] = (whtRGB>>8)&0xff;
++ bBW[0] = blkRGB&0xff; bBW[1] = whtRGB&0xff;
++ *rpp = rBW; *gpp = gBW; *bpp = bBW;
++ *nc = 2;
++ }
++
++ return bwpic;
++}
++
++
++/***************************************/
++static byte *handleNormSel(pptype, pwide, phigh, pfree)
++ int *pptype, *pwide, *phigh, *pfree;
++{
++ /* called to return a pointer to a 'pic', its type, its width & height,
++ * and whether or not it should be freed when we're done with it. The 'pic'
++ * returned is the desired portion of 'cpic' or 'epic' if there is a
++ * selection, and the saveselCB is enabled, or alternately, it's the
++ * whole cpic or epic.
++ *
++ * if selection does not intersect cpic/epic, returns cpic/epic
++ * NEVER RETURNS NULL
++ */
++
++ byte *thepic;
++ int pw, ph, slx, sly, slw, slh;
++
++ *pfree = 0; *pptype = picType;
++
++ if (savenormCB.val) { thepic = cpic; pw = cWIDE; ph = cHIGH; }
++ else { thepic = epic; pw = eWIDE; ph = eHIGH; }
++
++ *pwide = pw; *phigh = ph;
++
++
++ if (saveselCB.active && saveselCB.val && HaveSelection()) {
++ GetSelRCoords(&slx, &sly, &slw, &slh); /* in 'pic' coords */
++
++ if (savenormCB.val) {
++ CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pWIDE,pHIGH);
++
++ if (slw<1 || slh<1) { slx = sly = 0; slw=pWIDE; slh=pHIGH; }
++
++ if (slx==0 && sly==0 && slw==pWIDE && slh==pHIGH) thepic = pic;
++ else {
++ thepic = XVGetSubImage(pic, *pptype, pWIDE,pHIGH, slx, sly, slw, slh);
++ *pfree = 1;
++ }
++ }
++ else { /* convert sel -> epic coords */
++ int x1,x2,y1,y2;
++ x1 = slx; y1 = sly;
++ x2 = slx + slw; y2 = sly + slh;
++ CoordP2E(x1,y1, &x1, &y1);
++ CoordP2E(x2,y2, &x2, &y2);
++ slx = x1; sly = y1; slw = x2-x1; slh = y2-y1;
++ CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pw,ph);
++
++ if (slw<1 || slh<1) { slx = sly = 0; slw=pw; slh=ph; }
++
++ if (slx!=0 || sly!=0 || slw!=pw || slh!=ph) {
++ thepic = XVGetSubImage(thepic, *pptype, pw, ph, slx, sly, slw, slh);
++ *pfree = 1;
++ }
++ }
++
++ *pwide = slw; *phigh = slh;
++ }
++
++ return thepic;
++}
++
++
++/***************************************/
++byte *GenSavePic(ptypeP, wP, hP, freeP, ncP, rmapP, gmapP, bmapP)
++ int *ptypeP, *wP, *hP, *freeP, *ncP;
++ byte **rmapP, **gmapP, **bmapP;
++{
++ /* handles the whole ugly mess of the various save options.
++ * returns an image, of type 'ptypeP', size 'wP,hP'.
++ * if (*ptypeP == PIC8), also returns numcols 'ncP', and the r,g,b map
++ * to use rmapP, gmapP, bmapP.
++ *
++ * if freeP is set, image can safely be freed after it is saved
++ */
++
++ byte *pic1, *pic2;
++ int ptype, w, h, pfree;
++
++ pic1 = handleNormSel(&ptype, &w, &h, &pfree);
++
++ pic2 = handleBWandReduced(pic1, ptype, w,h, MBWhich(&colMB),
++ ncP, rmapP, gmapP, bmapP);
++ if (pic2) {
++ if (pfree) free(pic1);
++ pic1 = pic2;
++ pfree = 1;
++ ptype = PIC8;
++ }
++
++
++ if (ptype == PIC24) {
++ pic2 = GammifyPic24(pic1, w, h);
++ if (pic2) {
++ if (pfree) free(pic1);
++ pic1 = pic2;
++ pfree = 1;
++ }
++ }
++
++ *ptypeP = ptype; *wP = w; *hP = h; *freeP = pfree;
++
++ return pic1;
++}
++
++
++/***************************************/
++void GetSaveSize(wP, hP)
++ int *wP, *hP;
++{
++ /* returns the size (in pixels) of the save image. Takes 'normal size'
++ and 'save selection' checkboxes into account */
++
++ int slx,sly,slw,slh;
++
++ if (savenormCB.val) { slw = cWIDE; slh = cHIGH; }
++ else { slw = eWIDE; slh = eHIGH; }
++
++ if (saveselCB.active && saveselCB.val && HaveSelection()) {
++ GetSelRCoords(&slx, &sly, &slw, &slh); /* pic coord */
++ if (savenormCB.val) {
++ CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pWIDE,pHIGH);
++ if (slw<1 || slh<1) { slx = sly = 0; slw=pWIDE; slh=pHIGH; }
++ }
++ else { /* -> epic coord */
++ int x1,x2,y1,y2;
++ x1 = slx; y1 = sly;
++ x2 = slx + slw; y2 = sly + slh;
++ CoordP2E(x1,y1, &x1, &y1);
++ CoordP2E(x2,y2, &x2, &y2);
++ slx = x1; sly = y1; slw = x2-x1; slh = y2-y1;
++ CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,eWIDE,eHIGH);
++
++ if (slw<1 || slh<1) { slx = sly = 0; slw=eWIDE; slh=eHIGH; }
++ }
++ }
++
++ *wP = slw; *hP = slh;
++}
++
++
++
++
++/*************************************************************/
++/* POLLING ROUTINES */
++/*************************************************************/
++
++
++static struct stat origStat, lastStat;
++static int haveStat = 0, haveLastStat = 0;
++static time_t lastchgtime;
++
++/****************************/
++void InitPoll()
++{
++ /* called whenever a file is initially loaded. stat's the file and puts
++ the results in origStat */
++
++ haveStat = haveLastStat = 0;
++ lastchgtime = (time_t) 0;
++
++ /* only do stat() if curname is a valid index, and it's not '<stdin>' */
++ if (curname>=0 && curname<numnames &&
++ (strcmp(namelist[curname], STDINSTR)!=0)) {
++
++ if (stat(namelist[curname], &origStat)==0) {
++ haveStat = 1;
++ if (DEBUG) fprintf(stderr," origStat.size=%ld, origStat.mtime=%d\n",
++ origStat.st_size, origStat.st_mtime);
++ }
++ }
++}
++
++
++/****************************/
++int CheckPoll(del)
++ int del;
++{
++ /* returns '1' if the file has been modified, and either
++ A) the file has stabilized (st = lastStat), or
++ B) 'del' seconds have gone by since the file last changed size
++ */
++
++ struct stat st;
++ time_t nowT;
++
++ time(&nowT);
++
++ if (haveStat && curname>=0 && curname<numnames &&
++ (strcmp(namelist[curname], STDINSTR)!=0)) {
++
++ if (stat(namelist[curname], &st)==0) {
++ if (DEBUG) fprintf(stderr," st.size=%ld, st.mtime=%d\n",
++ st.st_size, st.st_mtime);
++
++ if ((st.st_size == origStat.st_size) &&
++ (st.st_mtime == origStat.st_mtime)) return 0; /* no change */
++
++ /* if it's changed since last looked ... */
++ if (!haveLastStat ||
++ st.st_size != lastStat.st_size ||
++ st.st_mtime != lastStat.st_mtime) {
++ xvbcopy((char *) &st, (char *) &lastStat, sizeof(struct stat));
++ haveLastStat = 1;
++ lastchgtime = nowT;
++ return 0;
++ }
++
++ /* if it hasn't changed in a while... */
++ if (haveLastStat && st.st_size > 0 && (nowT - lastchgtime) > del) {
++ xvbcopy((char *) &st, (char *) &origStat, sizeof(struct stat));
++ haveLastStat = 0; lastchgtime = 0;
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++
++/***************************************************************/
++void DIRDeletedFile(name)
++ char *name;
++{
++ /* called when file 'name' has been deleted. If any of the browsers
++ were showing the directory that the file was in, does a rescan() */
++
++ int i;
++ char buf[MAXPATHLEN + 2], *tmp;
++
++ strcpy(buf, name);
++ tmp = BaseName(buf);
++ *tmp = '\0'; /* truncate after last '/' */
++
++ if (strcmp(path, buf)==0) LoadCurrentDirectory();
++}
++
++
++/***************************************************************/
++void DIRCreatedFile(name)
++ char *name;
++{
++ DIRDeletedFile(name);
++}
++
++
+diff -urN xv-3.10a/xvevent.c xv-3.10apatched/xvevent.c
+--- xv-3.10a/xvevent.c Mon Jan 23 15:20:24 1995
++++ xv-3.10apatched/xvevent.c Tue Apr 30 00:10:16 2002
+@@ -154,7 +154,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;
+
+ static int mainWKludge=0; /* force first mainW expose after a mainW config
+ to redraw all of mainW */
+@@ -233,6 +233,10 @@
+ if (TIFFCheckEvent(event)) break; /* event has been processed */
+ #endif
+
++#ifdef HAVE_PNG
++ if (PNGCheckEvent (event)) break; /* event has been processed */
++#endif
++
+ 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 +363,10 @@
+ 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 == mainW) Quit(0);
+ }
+ }
+@@ -538,6 +546,10 @@
+ #ifdef HAVE_TIFF
+ if (wasTiffUp) { TIFFDialog(wasTiffUp); wasTiffUp=0; }
+ #endif
++
++#ifdef HAVE_PNG
++ if (wasPngUp) { PNGDialog(wasJpegUp); wasPngUp=0; }
++#endif
+ }
+ }
+ }
+@@ -576,6 +588,10 @@
+ #ifdef HAVE_TIFF
+ if (tiffUp) { wasTiffUp = tiffUp; TIFFDialog(0); }
+ #endif
++
++#ifdef HAVE_PNG
++ if (pngUp) { wasPngUp = pngUp; PNGDialog(0); }
++#endif
+ }
+ }
+ }
+@@ -1147,6 +1163,10 @@
+ if (TIFFCheckEvent(event)) break;
+ #endif
+
++#ifdef HAVE_PNG
++ if (PNGCheckEvent (event)) break;
++#endif
++
+ if (GamCheckEvent (event)) break;
+ if (BrowseCheckEvent (event, &retval, &done)) break;
+ if (TextCheckEvent (event, &retval, &done)) break;
+@@ -1366,6 +1386,10 @@
+ if (TIFFCheckEvent(event)) break;
+ #endif
+
++#ifdef HAVE_PNG
++ if (PNGCheckEvent (event)) break;
++#endif
++
+ if (GamCheckEvent (event)) break;
+ if (BrowseCheckEvent (event, &retval, &done)) break;
+ if (TextCheckEvent (event, &retval, &done)) break;
+@@ -2372,6 +2396,10 @@
+ if (tiffUp) TIFFDialog(0); /* close tiff window */
+ #endif
+
++#ifdef HAVE_PNG
++ if (pngUp) PNGDialog(0); /* close png window */
++#endif
++
+ ClosePopUp();
+
+ /* make the interrupt signal look like a '\n' keypress in ctrlW */
+diff -urN xv-3.10a/xvgam.c xv-3.10apatched/xvgam.c
+--- xv-3.10a/xvgam.c Fri Jan 13 11:51:14 1995
++++ xv-3.10apatched/xvgam.c Tue Apr 30 00:10:16 2002
+@@ -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 -urN xv-3.10a/xvgif.c xv-3.10apatched/xvgif.c
+--- xv-3.10a/xvgif.c Tue Jan 10 11:54:41 1995
++++ xv-3.10apatched/xvgif.c Tue Apr 30 00:19:00 2002
+@@ -113,7 +113,8 @@
+ int aspect, gotimage;
+
+ /* initialize variables */
+- BitOffset = XC = YC = Pass = OutCount = gotimage = 0;
++ BitOffset = XC = YC = OutCount = gotimage = 0;
++ Pass = -1;
+ RawGIF = Raster = pic8 = NULL;
+ gif89 = 0;
+
+@@ -692,7 +693,12 @@
+ {
+ static byte *ptr = NULL;
+ static int oldYC = -1;
+-
++
++ if (Pass == -1) { /* first time through - init stuff */
++ oldYC = -1;
++ Pass = 0;
++ }
++
+ if (oldYC != YC) { ptr = pic8 + YC * Width; oldYC = YC; }
+
+ if (YC<Height)
+diff -urN xv-3.10a/xvgrab.c xv-3.10apatched/xvgrab.c
+--- xv-3.10a/xvgrab.c Thu Dec 22 14:34:47 1994
++++ xv-3.10apatched/xvgrab.c Tue Apr 30 00:13:18 2002
+@@ -341,16 +341,16 @@
+ ConfigureNotify on mainW */
+
+ state = 0;
+- while (1) {
++ while (state != 3) {
+ XEvent event;
+ XNextEvent(theDisp, &event);
+ HandleEvent(&event, &i);
+
+- if (state==0 && event.type == MapNotify &&
+- event.xmap.window == mainW) state = 1;
++ if (!(state&1) && event.type == MapNotify &&
++ event.xmap.window == mainW) state |= 1;
+
+- if (state==1 && event.type == ConfigureNotify &&
+- event.xconfigure.window == mainW) break;
++ if (!(state&2) && event.type == ConfigureNotify &&
++ event.xconfigure.window == mainW) state |= 2;
+ }
+
+ if (DEBUG) fprintf(stderr,"==after remapping mainW, GOT Config.\n");
+diff -urN xv-3.10a/xvimage.c xv-3.10apatched/xvimage.c
+--- xv-3.10a/xvimage.c Fri Jan 13 16:11:36 1995
++++ xv-3.10apatched/xvimage.c Tue Apr 30 00:18:50 2002
+@@ -1736,10 +1736,12 @@
+ if (xim->byte_order == MSBFirst) {
+ for (i=wide*high, ip=imagedata; i>0; i--,pp++) {
+ if (((i+1)&0x1ffff) == 0) WaitCursor();
+- if (dithpic) {
+- *ip++ = ((*pp) ? white : black) & 0xffff;
+- }
+- else *ip++ = xcolors[*pp] & 0xffff;
++
++ if (dithpic) xcol = ((*pp) ? white : black) & 0xffff;
++ else xcol = xcolors[*pp] & 0xffff;
++
++ *((unsigned char *)ip)++ = (xcol>>8) & 0xff;
++ *((unsigned char *)ip)++ = (xcol) & 0xff;
+ }
+ }
+ else { /* LSBFirst */
+@@ -1749,8 +1751,8 @@
+ if (dithpic) xcol = ((*pp) ? white : black) & 0xffff;
+ else xcol = xcolors[*pp];
+
+- /* WAS *ip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8); */
+- *ip++ = (unsigned short) (xcol);
++ *((unsigned char *)ip)++ = (xcol) & 0xff;
++ *((unsigned char *)ip)++ = (xcol>>8) & 0xff;
+ }
+ }
+ }
+diff -urN xv-3.10a/xvjpeg.c xv-3.10apatched/xvjpeg.c
+--- xv-3.10a/xvjpeg.c Thu Jan 5 00:17:13 1995
++++ xv-3.10apatched/xvjpeg.c Tue Apr 30 00:12:38 2002
+@@ -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));
+
+
+@@ -87,10 +87,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,
+@@ -400,7 +400,7 @@
+
+
+ /**************************************************/
+-METHODDEF void xv_error_exit(cinfo)
++METHODDEF(void) xv_error_exit(cinfo)
+ j_common_ptr cinfo;
+ {
+ my_error_ptr myerr;
+@@ -412,7 +412,7 @@
+
+
+ /**************************************************/
+-METHODDEF void xv_error_output(cinfo)
++METHODDEF(void) xv_error_output(cinfo)
+ j_common_ptr cinfo;
+ {
+ my_error_ptr myerr;
+@@ -426,7 +426,7 @@
+
+
+ /**************************************************/
+-METHODDEF void xv_prog_meter(cinfo)
++METHODDEF(void) xv_prog_meter(cinfo)
+ j_common_ptr cinfo;
+ {
+ struct jpeg_progress_mgr *prog;
+@@ -671,7 +671,7 @@
+
+
+ /**************************************************/
+-METHODDEF boolean xv_process_comment(cinfo)
++METHODDEF(boolean) xv_process_comment(cinfo)
+ j_decompress_ptr cinfo;
+ {
+ int length, hasnull;
+@@ -759,8 +759,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);
+@@ -769,7 +769,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;
+diff -urN xv-3.10a/xvmisc.c xv-3.10apatched/xvmisc.c
+--- xv-3.10a/xvmisc.c Fri Jan 13 15:41:34 1995
++++ xv-3.10apatched/xvmisc.c Tue Apr 30 00:10:16 2002
+@@ -520,6 +520,10 @@
+ if (tiffW) XDestroyWindow(theDisp, tiffW);
+ #endif
+
++#ifdef HAVE_PNG
++ if (pngW) XDestroyWindow(theDisp, pngW);
++#endif
++
+ /* if NOT using stdcmap for images, free stdcmap */
+ if (colorMapMode != CM_STDCMAP) {
+ int j;
+@@ -716,6 +720,10 @@
+ #ifdef HAVE_TIFF
+ if (tiffW) XDefineCursor(theDisp, tiffW, otherc);
+ #endif
++
++#ifdef HAVE_PNG
++ if (pngW) XDefineCursor(theDisp, pngW, otherc);
++#endif
+ }
+
+
+diff -urN xv-3.10a/xvpng.c xv-3.10apatched/xvpng.c
+--- xv-3.10a/xvpng.c Wed Dec 31 16:00:00 1969
++++ xv-3.10apatched/xvpng.c Tue Apr 30 00:24:17 2002
+@@ -0,0 +1,965 @@
++/*
++ * xvpng.c - load and write routines for 'PNG' format pictures
++ *
++ * callable functions
++ *
++ * CreatePNGW()
++ * PNGDialog(vis)
++ * PNGCheckEvent(xev)
++ * PNGSaveParams(fname, col)
++ * LoadPNG(fname, pinfo)
++ */
++
++/*#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
++ * 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 */
++/* Default zlib compression level
++#define COMPRESSION Z_BEST_COMPRESSION
++*/
++#define COMPRESSION 6
++
++#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
++
++/*** 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_struct *png_ptr, char *message));
++static void png_xv_warning PARM((png_struct *png_ptr, char *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, 2.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 = 0, pass;
++ byte *p, *png_line;
++ char software[256];
++ char *savecmnt = NULL;
++
++ if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
++ png_xv_error, png_xv_warning)) == NULL) {
++ FatalError("malloc failure in WritePNG");
++ }
++
++ if ((info_ptr = png_create_info_struct(png_ptr)) == NULL)
++ {
++ png_destroy_write_struct(&png_ptr, &info_ptr);
++ FatalError("malloc failure in WritePNG");
++ }
++
++ 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;
++
++ info_ptr->interlace_type = interCB.val ? 1 : 0;
++
++ if (colorType == F_FULLCOLOR || colorType == F_REDUCED) {
++ if(ptype == PIC24) {
++ linesize = 3*w;
++ 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 = w*3;
++ info_ptr->bit_depth = 8;
++ }
++ else {
++ int low_presc;
++
++ 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 prescision grayscale */
++
++ low_presc=1;
++
++ for(i = 0; i < numcols; i++) {
++ if((remap[i] & 0x0f) * 0x11 != remap[i]) {
++ low_presc = 0;
++ break;
++ }
++ }
++
++ if(low_presc) {
++ for(i = 0; i < numcols; i++) {
++ remap[i] &= 0xf;
++ }
++ info_ptr->bit_depth = 4;
++
++ /* try to adjust to 2 bit prescision grayscale */
++
++ for(i = 0; i < numcols; i++) {
++ if((remap[i] & 0x03) * 0x05 != remap[i]) {
++ low_presc = 0;
++ break;
++ }
++ }
++ }
++
++ if(low_presc) {
++ for(i = 0; i < numcols; i++) {
++ remap[i] &= 3;
++ }
++ info_ptr->bit_depth = 2;
++
++ /* try to adjust to 1 bit prescision grayscale */
++
++ for(i = 0; i < numcols; i++) {
++ if((remap[i] & 0x01) * 0x03 != remap[i]) {
++ low_presc = 0;
++ break;
++ }
++ }
++ }
++
++ if(low_presc) {
++ 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++) {
++ fflush(stdout);
++ 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 /* rbg or palette */
++ png_write_row(png_ptr, p);
++ if((j & 0x1f) == 0) WaitCursor();
++ p += linesize;
++ }
++ }
++
++ free(png_line);
++
++ 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 */
++ 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 */
++ do {
++ key = comment = strchr(comment, ':');
++ } while (key && key[1] != ':');
++
++ /* 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++;
++ }
++ }
++ /* It is just a generic comment */
++ else {
++ tp->key = "Comment";
++ tp->text = key;
++ tp->text_length = strlen(tp->text);
++ 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);
++ png_destroy_write_struct(&png_ptr, &info_ptr);
++
++ if (text)
++ {
++ free(text);
++ if (savecmnt)
++ free(savecmnt);
++ }
++
++ 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;
++ int filesize;
++ int pass;
++ 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;
++
++ 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, "%dx%d 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);
++
++ 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) {
++ linesize = pinfo->w * 3;
++ 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;
++ }
++ }
++ }
++ pinfo->pic = calloc((size_t)(linesize*pinfo->h), (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_struct *png_ptr;
++ char *message;
++{
++ SetISTR(ISTR_WARNING,"%s: libpng error: %s", fbasename, message);
++
++ longjmp(png_ptr->jmpbuf, 1);
++}
++
++
++/*******************************************/
++static void
++png_xv_warning(png_ptr, message)
++ png_struct *png_ptr;
++ char *message;
++{
++ if (!png_ptr)
++ return;
++
++ SetISTR(ISTR_WARNING,"%s: libpng warning: %s", fbasename, message);
++}
++
++#endif
+diff -urN xv-3.10a/xvpopup.c xv-3.10apatched/xvpopup.c
+--- xv-3.10a/xvpopup.c Thu Jan 19 10:09:31 1995
++++ xv-3.10apatched/xvpopup.c Tue Apr 30 00:19:13 2002
+@@ -200,14 +200,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,
+@@ -258,9 +258,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));
+@@ -465,9 +465,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; }
+
+@@ -486,9 +486,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);
+@@ -498,9 +498,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;
+@@ -560,6 +560,7 @@
+ nams[*lenp] = (char *) malloc((size_t) 32);
+ if (!nams[*lenp]) { free(vals[*lenp]); continue; }
+ strncpy(nams[*lenp], vals[*lenp], (size_t) 31);
++ nams[*lenp][31] = '\0';
+ }
+
+ if (strlen(nams[*lenp]) > (size_t) 20) { /* fix long names */
+@@ -972,8 +973,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);
+ }
+ }
+
+diff -urN xv-3.10a/xvps.c xv-3.10apatched/xvps.c
+--- xv-3.10a/xvps.c Thu Dec 22 14:34:42 1994
++++ xv-3.10apatched/xvps.c Tue Apr 30 00:20:13 2002
+@@ -139,9 +139,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;
+@@ -236,10 +236,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);
+ }
+ }
+
+@@ -836,7 +836,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);
+@@ -1564,7 +1564,7 @@
+ /* build command string */
+
+ #ifndef VMS /* VMS needs quotes around mixed case command lines */
+- sprintf(tmp, "%s -sDEVICE=%s -r%d -q -dNOPAUSE -sOutputFile=%s%%d ",
++ sprintf(tmp, "%s -sDEVICE=%s -r%d -q -dSAFER -dNOPAUSE -sOutputFile=%s%%d ",
+ GS_PATH, gsDev, gsRes, tmpname);
+ #else
+ sprintf(tmp,
+@@ -1577,11 +1577,20 @@
+ # ifndef VMS
+ sprintf(tmp1, "-I%s ", GS_LIB);
+ # else
+- sprintf(tmp1, "\"-I%s\"", GS_LIB);
++ sprintf(tmp1, "\"-I%s\" ", GS_LIB);
+ # endif
+ strcat(tmp, tmp1);
+ #endif
+
++
++ /* prevent some potential naughtiness... */
++#ifndef VMS
++ strcat(tmp, "-dSAFER ");
++#else
++ strcat(tmp, "\"-dSAFER\" ");
++#endif
++
++
+ if (gsGeomStr) {
+ sprintf(tmp1, "-g%s ", gsGeomStr);
+ strcat(tmp, tmp1);
+diff -urN xv-3.10a/xvroot.c xv-3.10apatched/xvroot.c
+--- xv-3.10a/xvroot.c Thu Dec 22 14:34:42 1994
++++ xv-3.10apatched/xvroot.c Tue Apr 30 00:20:19 2002
+@@ -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 -urN xv-3.10a/xvtext.c xv-3.10apatched/xvtext.c
+--- xv-3.10a/xvtext.c Fri Jan 13 15:46:28 1995
++++ xv-3.10apatched/xvtext.c Tue Apr 30 00:19:13 2002
+@@ -293,6 +293,7 @@
+ tv->textlen = len;
+ tv->freeonclose = freeonclose;
+ strncpy(tv->title, title, (size_t) TITLELEN-1);
++ tv->title[TITLELEN-1] = '\0';
+
+ computeText(tv); /* compute # lines and linestarts array */
+
+diff -urN xv-3.10a/xvtiff.c xv-3.10apatched/xvtiff.c
+--- xv-3.10a/xvtiff.c Fri Jan 13 11:53:34 1995
++++ xv-3.10apatched/xvtiff.c Tue Apr 30 00:20:00 2002
+@@ -301,6 +301,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));
+
+@@ -340,7 +344,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 *,
+@@ -1218,7 +1222,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;
+@@ -1227,8 +1231,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;
+@@ -1514,7 +1517,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;
diff --git a/media-gfx/xv/xv-3.10a-r1.ebuild b/media-gfx/xv/xv-3.10a-r1.ebuild
new file mode 100644
index 000000000000..7acb9e67821f
--- /dev/null
+++ b/media-gfx/xv/xv-3.10a-r1.ebuild
@@ -0,0 +1,45 @@
+# Copyright 1999-2002 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author Ben Lutgens <lamer@gentoo.org>
+# $Header: /var/cvsroot/gentoo-x86/media-gfx/xv/xv-3.10a-r1.ebuild,v 1.1 2002/04/29 08:29:14 seemant Exp $
+
+S=${WORKDIR}/${P}
+DESCRIPTION="An interactive image manipulation program for X which can
+deal with a wide variety of image formats"
+SRC_URI="ftp://ftp.cis.upenn.edu/pub/xv/${P}.tar.gz"
+HOMEPAGE="http://www.trilon.com/xv/index.html"
+
+DEPEND="virtual/x11
+ png? ( media-libs/jpeg
+ media-libs/tiff
+ media-libs/libpng
+ >=sys-libs/zlib-1.1.4 )"
+
+PATCHDIR=${WORKDIR}/patches
+
+src_unpack() {
+ unpack ${P}.tar.gz
+
+ cd ${S}
+ patch -p1 < ${FILESDIR}/${PN}-naz-gentoo.patch
+}
+
+src_compile() {
+
+ make || die
+}
+
+src_install () {
+
+ dodir /usr/bin
+ dodir /usr/share/man/man1
+
+ make \
+ DESTDIR=${D} \
+ BINDIR=${D}/usr/bin \
+ MANDIR=${D}/usr/share/man/man1 \
+ LIBDIR=${D}/usr/lib \
+ install || die
+
+ dodoc README INSTALL CHANGELOG BUGS IDEAS
+}