diff options
author | Seemant Kulleen <seemant@gentoo.org> | 2002-04-29 08:29:14 +0000 |
---|---|---|
committer | Seemant Kulleen <seemant@gentoo.org> | 2002-04-29 08:29:14 +0000 |
commit | 180ded2471d136aac347bfb6426aa88db7e06bdd (patch) | |
tree | 10b04f79c867318e12630ec46dce520ae977d753 /media-gfx | |
parent | portage dep fixup (diff) | |
download | historical-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/ChangeLog | 16 | ||||
-rw-r--r-- | media-gfx/xv/files/digest-xv-3.10a-r1 | 1 | ||||
-rw-r--r-- | media-gfx/xv/files/xv-naz-gentoo.patch | 14838 | ||||
-rw-r--r-- | media-gfx/xv/xv-3.10a-r1.ebuild | 45 |
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 +} |