diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /other/pamx | |
download | netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip |
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'other/pamx')
-rw-r--r-- | other/pamx/COPYRIGHT | 72 | ||||
-rw-r--r-- | other/pamx/Makefile | 43 | ||||
-rw-r--r-- | other/pamx/Makefile2 | 51 | ||||
-rw-r--r-- | other/pamx/fill.c | 82 | ||||
-rw-r--r-- | other/pamx/fill.h | 16 | ||||
-rw-r--r-- | other/pamx/image.c | 331 | ||||
-rw-r--r-- | other/pamx/image.h | 90 | ||||
-rw-r--r-- | other/pamx/pamx.c | 364 | ||||
-rw-r--r-- | other/pamx/send.c | 872 | ||||
-rw-r--r-- | other/pamx/send.h | 38 | ||||
-rw-r--r-- | other/pamx/valtomem.h | 65 | ||||
-rw-r--r-- | other/pamx/window.c | 1209 | ||||
-rw-r--r-- | other/pamx/window.h | 38 | ||||
-rw-r--r-- | other/pamx/ximageinfo.h | 25 |
14 files changed, 3296 insertions, 0 deletions
diff --git a/other/pamx/COPYRIGHT b/other/pamx/COPYRIGHT new file mode 100644 index 00000000..3ad3b675 --- /dev/null +++ b/other/pamx/COPYRIGHT @@ -0,0 +1,72 @@ +Many of the source files for Pamx contain code written by or derived +from code written by Jim Frost for his program Xloadimage. The files +in which Frost has copyright contain Frost's name at the top. Frost +licenses his copyright to the public as follows: + + Copyright 1989, 1993 Jim Frost + + Permission to use, copy, modify, distribute, and sell this software + and its documentation for any purpose is hereby granted without fee, + provided that the above copyright notice appear in all copies and + that both that copyright notice and this permission notice appear + in supporting documentation. The author makes no representations + about the suitability of this software for any purpose. It is + provided "as is" without express or implied warranty. + + THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + USE OR PERFORMANCE OF THIS SOFTWARE. + + +The rest of the code was primarily written by Bryan Henderson, +starting in 2006. Bryan and other authors have contributed their work +to the public domain. + + +Here is a more or less complete list of people who contributed to +the Xloadimage from which Pamx was derived. The list is from the README +file in the Xloadimage source code: + +Special thanks to the crew at the Boston University Graphics Lab for +their assistance and sample images, and to bzs@std.com for his simple +dithering algorithm (or what's left of it). Real special thanks to +Kirk L. Johnson (tuna@athena.mit.edu) for a very nice GIF loader and +dithering routine, to Mark Snitily (zok!mark@apple.com) for 386/ix +compatibility work, to Andreas Stolcke (stolcke@icsib12.berkeley.edu) +for miscellaneous bug fixes, to Anthony A. Datri (datri@convex.com) +for a number of things, to Mark Moraes (moraes@cs.toronto.edu) for +the slideshow colormap fix, to Gregg Townsend (gmt@cs.arizona.edu) for +a suggested dithering routine and other fixes, to Brian Frost +(B1F5814@RIGEL.TAMU.EDU) for changes for VMS, to Chip Horstman for G3 +FAX support, to Deron Dann Johnson (dj@eng.sun.com) for fixing the +RetainTemporary bug, to Tom Tatlow (tatlow@dash.enet.dec.com) for +image rotation code, to Mark A. Horstman (mhorstm@sarek.sbc.com) for +tilde expansion in .xloadimagerc files and virtual-root support in +root.c, to Tim Roper (timr@labtam.labtam.oz.au), Graeme Gill +(graeme@labtam.oz.au) for gamma correction and Utah RLE image support, +Mark Majhor (uunet!sequent!markm) for FBM and MacPaint support, Ian +MacPhedran (macphed@dvinci.usask.ca) for PGM and PPM support, Per +Fogelstrom (pf@diab.se) for a fix to send.c, Hans J. Albertsson +(hans@Sweden.Sun.COM) for cleaning up GIF aborting, Graham Hudspith +(gwh@inmos.com) for a geometry patch, Glenn P. Davis +(davis@unidata.ucar.edu) for McIDAS areafile support, Keith S. Pickens +(maxwell.nde.swri.edu!ksp) for fixing the RLE loader to work with the +updated zio package, Mike Douglas (douglas@wilbur.coyote.trw.com) for +normalization, Rod Johnson (johnson@wrl.epi.com) for speedup +suggestions, Hal Peterson (hrp@cray.com) for his Imakefile fix, Matt +Caprile (Matthew.Caprile@ec.bull.fr) for slideshow delay code, Bob +Deroy (rwd@bucrsb.bu.edu) for mondo 24-bit Sun Rasterfile images that +broke everything, Christos S. Zoulas (christo@ee.cornell.edu) for a +first-cut 24-bit implementation, Gerald James Barnes +(gjb@oasis.icl.stc.co.uk) for a first-cut forced-visual +implementation, Michael Campanella (campanella@cvg.enet.dec.com) for +more VMS changes, Kee Hinckley (nazgul@alfalfa.com) for robustness +changes to the g3 and MacPaint loaders and the ZIO package, Tim +Northrup (tim@brspyr1.brs.com) for PC Paintbrush and GEM image +formats, Richard Weidner (richard@elroy.jpl.nasa.gov) for lots of +24-bit testing, Eckhard Rueggeberg (erueg@cfgauss.uni-math.gwdg.de) +for a better PCX loader, and any others whose names I've missed. diff --git a/other/pamx/Makefile b/other/pamx/Makefile new file mode 100644 index 00000000..a86a3331 --- /dev/null +++ b/other/pamx/Makefile @@ -0,0 +1,43 @@ +ifeq ($(SRCDIR)x,x) + SRCDIR = $(CURDIR)/../.. + BUILDDIR = $(SRCDIR) +endif +SUBDIR = other/pamx +VPATH=.:$(SRCDIR)/$(SUBDIR) + +include $(BUILDDIR)/Makefile.config + +ifneq ($(X11LIB),NONE) + ifneq ($(X11HDR_DIR),) + INCLUDES += -I$(X11HDR_DIR) + endif +endif + +ifneq ($(X11LIB),NONE) + BINARIES += pamx +endif + +PAMX_OBJECTS = \ + pamx.o \ + image.o \ + send.o \ + window.o \ + +MERGE_OBJECTS = \ + pamx.o2 \ + image.o \ + send.o \ + window.o \ + +OBJECTS = $(PAMX_OBJECTS) + +MERGEBINARIES = $(BINARIES) + +all: $(BINARIES) + +include $(SRCDIR)/Makefile.common + +pamx: $(PAMX_OBJECTS) $(NETPBMLIB) $(LIBOPT) + $(LD) $(LDFLAGS) -o $@ $(PAMX_OBJECTS) \ + $(shell $(LIBOPT) $(NETPBMLIB) $(X11LIB)) \ + $(LDLIBS) $(MATHLIB) $(RPATH) $(LADD) diff --git a/other/pamx/Makefile2 b/other/pamx/Makefile2 new file mode 100644 index 00000000..f69e103f --- /dev/null +++ b/other/pamx/Makefile2 @@ -0,0 +1,51 @@ +# C compiler to use, including special flags. +CC=gcc + +WARNINGS = -Wall -Wmissing-declarations -Wundef -Wimplicit -Wwrite-strings \ + -Winline \ + -Wstrict-prototypes -Wmissing-prototypes \ + -Werror + +CFLAGS = $(WARNINGS) -fno-common -g +INCLUDES = -I /home/bryanh/netpbm/other/importinc + +# X11 include and library information. +X11_LIB_DIR=-L/subsysx/X11R6/lib +X11_LIB_NAME=-lX11 +NETPBMLIB = /home/bryanh/netpbm/lib/libnetpbm.so + +LIBS=$(X11_LIB_DIR) $(X11_LIB_NAME) -lm + +default: pamx + +# files for the image library +IMAGE_SRCS= image.c +IMAGE_OBJS= ${IMAGE_SRCS:.c=.o} + +# files for the image processing library +PROCESS_HDRS= +# no image processing. +PROCESS_SRCS= fill.c +PROCESS_OBJS= ${PROCESS_SRCS:.c=.o} + +X_SRCS= send.c window.c pamx.c +X_OBJS= ${X_SRCS:.c=.o} + +OBJS= $(IMAGE_OBJS) $(PROCESS_OBJS) $(X_OBJS) $(NETPBMLIB) + +.c.o: $*.c + $(CC) -c $(CFLAGS) $(INCLUDES) $*.c $(CADD) + +pamx: $(OBJS) $(OPTIONAL_LIBS) + $(CC) -o $@ $(OBJS) $(OPTIONAL_LIBS) $(LIBS) + +clean:: + rm -f *.o pamx + +dep: + $(CC) -MM -MG $(INCLUDES) *.c >Makefile.depend + +include Makefile.depend + +Makefile.depend: + >$@ diff --git a/other/pamx/fill.c b/other/pamx/fill.c new file mode 100644 index 00000000..13a2b21e --- /dev/null +++ b/other/pamx/fill.c @@ -0,0 +1,82 @@ +/* + fill an image area with a particular pixel value + + By Jim Frost 1989.10.02, Bryan Henderson 2006.03.25. + + See COPYRIGHT file for copyright information. +*/ + +#include "pm.h" +#include "image.h" +#include "valtomem.h" +#include "fill.h" + +void +fill(Image * const imageP, + unsigned int const fx, + unsigned int const fy, + unsigned int const fw, + unsigned int const fh, + Pixel const pixval) { + + assertGoodImage(imageP); + switch(imageP->type) { + case IBITMAP: { + unsigned int const linelen = (imageP->width +7)/ 8; + unsigned int const start = (fx +7) / 8; + unsigned char const startmask = 0x80 >> (fx % 8); + + unsigned int y; + unsigned char * lineptr; + + for (y = fy, lineptr = imageP->data + linelen * fy; + y < fy + fh; + ++y, lineptr += linelen) { + + unsigned int x; + unsigned char mask; + unsigned char * pixptr; + + mask = startmask; + pixptr = lineptr + start; + + for (x = fx; x < fw; ++x) { + if (pixval) + *pixptr |= mask; + else + *pixptr &= ~mask; + if (!(mask >>= 1)) { + mask = 0x80; + ++pixptr; + } + } + } + } break; + + case IRGB: + case ITRUE: { + unsigned int const linelen= imageP->width * imageP->pixlen; + unsigned int const start = imageP->pixlen * fx; + + unsigned int y; + unsigned char * lineptr; + + for (y = fy, lineptr = imageP->data + (linelen * fy); + y < fy + fh; + ++y, lineptr += linelen) { + + unsigned int x; + unsigned char * pixptr; + + pixptr = lineptr + start; + for (x = fx, pixptr = lineptr + start; + x < fw; + ++x, pixptr += imageP->pixlen) { + valToMem(pixval, pixptr, imageP->pixlen); + } + } + } break; + default: + pm_error("INTERNAL ERROR: Impossible image type %u", imageP->type); + } +} diff --git a/other/pamx/fill.h b/other/pamx/fill.h new file mode 100644 index 00000000..1f316d0b --- /dev/null +++ b/other/pamx/fill.h @@ -0,0 +1,16 @@ +#ifndef FILL_H_INCLUDED +#define FILL_H_INCLUDED + +#include "ximageinfo.h" + +struct Image; + +void +fill(struct Image * const imageP, + unsigned int const fx, + unsigned int const fy, + unsigned int const fw, + unsigned int const fh, + Pixel const pixval); + +#endif diff --git a/other/pamx/image.c b/other/pamx/image.c new file mode 100644 index 00000000..3aaa8478 --- /dev/null +++ b/other/pamx/image.c @@ -0,0 +1,331 @@ +/* + Functions to allocate and deallocate structures and structure data + + By Jim Frost 1989.09.29, Bryan Henderson 2006.03.25. + + See COPYRIGHT file for copyright information. +*/ + +#include <assert.h> + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "pam.h" +#include "image.h" + + + +/* this table is useful for quick conversions between depth and ncolors */ + +static unsigned long const DepthToColorsTable[] = { + /* 0 */ 1, + /* 1 */ 2, + /* 2 */ 4, + /* 3 */ 8, + /* 4 */ 16, + /* 5 */ 32, + /* 6 */ 64, + /* 7 */ 128, + /* 8 */ 256, + /* 9 */ 512, + /* 10 */ 1024, + /* 11 */ 2048, + /* 12 */ 4096, + /* 13 */ 8192, + /* 14 */ 16384, + /* 15 */ 32768, + /* 16 */ 65536, + /* 17 */ 131072, + /* 18 */ 262144, + /* 19 */ 524288, + /* 20 */ 1048576, + /* 21 */ 2097152, + /* 22 */ 4194304, + /* 23 */ 8388608, + /* 24 */ 16777216, + /* 25 */ 33554432, + /* 26 */ 67108864, + /* 27 */ 134217728, + /* 28 */ 268435456, + /* 29 */ 536870912, + /* 30 */ 1073741824, + /* 31 */ 2147483648u, + /* 32 */ 2147483648u /* bigger than unsigned int; this is good enough */ +}; + + + +unsigned int +depthToColors(unsigned int const depth) { + return DepthToColorsTable[MIN(depth,32)]; +} + + + +unsigned long +colorsToDepth(unsigned long const ncolors) { + + unsigned long a; + + for (a = 0; (a < 32) && (DepthToColorsTable[a] < ncolors); ++a) + /* EMPTY */ + ; + return a ; +} + + + +void +assertGoodImage(Image * const imageP) { + + assert(imageP != NULL); + + switch (imageP->type) { + case IBITMAP: + case IRGB: + case ITRUE: + break; + default: + assert(FALSE); /* can't be */ + } +} + + + +static void +newRGBMapData(RGBMap * const rgbP, + unsigned int const size) { + + rgbP->used = 0; + rgbP->size = size; + rgbP->compressed = FALSE; + MALLOCARRAY(rgbP->red, size); + MALLOCARRAY(rgbP->grn, size); + MALLOCARRAY(rgbP->blu, size); + + if (rgbP->red == NULL || rgbP->grn == NULL || rgbP->blu == NULL) + pm_error("Out of memory allocating %u pixels", size); +} + + + +static void +freeRGBMapData(RGBMap * const rgbP) { + + free(rgbP->red); + free(rgbP->grn); + free(rgbP->blu); +} + + + +Image * +newBitImage(unsigned int const width, + unsigned int const height) { + + unsigned int const linelen = (width + 7) / 8; + + Image * imageP; + + MALLOCVAR_NOFAIL(imageP); + + imageP->type = IBITMAP; + newRGBMapData(&imageP->rgb, 2); + imageP->rgb.red[0] = imageP->rgb.grn[0] = imageP->rgb.blu[0] = 65535; + imageP->rgb.red[1] = imageP->rgb.grn[1] = imageP->rgb.blu[1] = 0; + imageP->rgb.used = 2; + imageP->width = width; + imageP->height = height; + imageP->depth = 1; + + if (UINT_MAX / linelen < height) + pm_error("Image dimensions too big to compute: %u x %u", + linelen, height); + MALLOCARRAY(imageP->data, linelen * height); + + if (imageP->data == NULL) + pm_error("Out of memory allocating array of %u x %u", linelen, height); + + return imageP; +} + + + +Image * +newRGBImage(unsigned int const width, + unsigned int const height, + unsigned int const depth) { + + unsigned int const pixlen = pixlen > 0 ? (depth + 7) / 8 : 1; + /* Special case for "zero" depth image, which is sometimes + interpreted as "one color" + */ + unsigned int const numcolors = depthToColors(depth); + + Image * imageP; + + MALLOCVAR_NOFAIL(imageP); + imageP->type = IRGB; + newRGBMapData(&imageP->rgb, numcolors); + imageP->width = width; + imageP->height = height; + imageP->depth = depth; + imageP->pixlen = pixlen; + + if (UINT_MAX / width / height < pixlen) + pm_error("Image dimensions %u x %u x %u are too big to compute.", + width, height, pixlen); + MALLOCARRAY(imageP->data, width * height * pixlen); + if (imageP->data == NULL) + pm_error("Unable to allocate %u x %u x %u raster array", + width, height, pixlen); + + return imageP; +} + + + +Image * +newTrueImage(unsigned int const width, + unsigned int const height) { + + unsigned int const pixlen = 3; + + Image * imageP; + + MALLOCVAR_NOFAIL(imageP); + imageP->type = ITRUE; + imageP->rgb.used = 0; + imageP->rgb.size = 0; + imageP->width = width; + imageP->height = height; + imageP->depth = 24; + imageP->pixlen = 3; + + if (UINT_MAX / width / height < pixlen) + pm_error("Image dimensions %u x %u x %u are too big to compute.", + width, height, pixlen); + MALLOCARRAY(imageP->data, width * height * pixlen); + if (imageP->data == NULL) + pm_error("Unable to allocate %u x %u x %u raster array", + width, height, pixlen); + + return imageP; +} + + + +static void +freeImageData(Image * const imageP) { + + if (!TRUEP(imageP)) + freeRGBMapData(&imageP->rgb); + free(imageP->data); +} + + + +void +freeImage(Image * const imageP) { + + assertGoodImage(imageP); + + freeImageData(imageP); + + imageP->type = IBAD; + + free(imageP); +} + + + + +static void +fillRow1(struct pam * const pamP, + tuple * const tuplerow, + unsigned char ** const pP) { + + unsigned int col; + + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + *(*pP)++ = + pnm_scalesample(tuplerow[col][0], pamP->maxval, 255); + } +} + + + +static void +fillRow3(struct pam * const pamP, + tuple * const tuplerow, + unsigned char ** const pP) { + + unsigned int col; + + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + *(*pP)++ = + pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255); + } +} + + + +Image * +pbmLoad(const char * const fullname, + const char * const name, + bool const verbose) { + + FILE * ifP; + struct pam pam; + Image * imageP; + unsigned int row; + const char * filename; + tuple * tuplerow; + unsigned char * p; + enum {DEPTH_1, DEPTH_3} depth; + + if (STREQ(fullname, "stdin")) + filename = "-"; + else + filename = fullname; + + ifP = pm_openr(filename); + + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + if (strncmp(pam.tuple_type, "RGB", 3) == 0) { + depth = DEPTH_3; + if (pam.depth < 3) + pm_error("Invalid depth %u for RGB tuple type.", pam.depth); + } else + depth = DEPTH_1; + + imageP = newTrueImage(pam.width, pam.height); + + p = &imageP->data[0]; /* initial value */ + + tuplerow = pnm_allocpamrow(&pam); + + for (row = 0; row < pam.height; ++row) { + pnm_readpamrow(&pam, tuplerow); + + switch (depth) { + case DEPTH_3: + fillRow3(&pam, tuplerow, &p); + break; + case DEPTH_1: + fillRow1(&pam, tuplerow, &p); + break; + } + } + pnm_freepamrow(tuplerow); + + pm_close(ifP); + + return imageP; +} diff --git a/other/pamx/image.h b/other/pamx/image.h new file mode 100644 index 00000000..9c9689ac --- /dev/null +++ b/other/pamx/image.h @@ -0,0 +1,90 @@ +#ifndef IMAGE_H_INCLUDED +#define IMAGE_H_INCLUDED +#include <strings.h> + +#include "pm_c_util.h" + +#include "ximageinfo.h" + +typedef struct rgbmap { + unsigned int size; /* size of RGB map */ + unsigned int used; /* number of colors used in RGB map */ + bool compressed; /* image uses colormap fully */ + Intensity * red; /* color values in X style */ + Intensity * grn; + Intensity * blu; +} RGBMap; + +typedef struct Image { + unsigned int type; /* type of image */ + RGBMap rgb; /* RGB map of image if IRGB type */ + unsigned int width; /* width of image in pixels */ + unsigned int height; /* height of image in pixels */ + unsigned int depth; /* depth of image in bits if IRGB type */ + unsigned int pixlen; /* length of pixel if IRGB type */ + unsigned char * data; /* data rounded to full byte for each row */ +} Image; + +#define IBAD 0 /* invalid image (used when freeing) */ +#define IBITMAP 1 /* image is a bitmap */ +#define IRGB 2 /* image is RGB */ +#define ITRUE 3 /* image is true color */ + +#define BITMAPP(IMAGE) ((IMAGE)->type == IBITMAP) +#define RGBP(IMAGE) ((IMAGE)->type == IRGB) +#define TRUEP(IMAGE) ((IMAGE)->type == ITRUE) + +#define TRUE_RED(PIXVAL) (((PIXVAL) & 0xff0000) >> 16) +#define TRUE_GRN(PIXVAL) (((PIXVAL) & 0xff00) >> 8) +#define TRUE_BLU(PIXVAL) ((PIXVAL) & 0xff) +#define RGB_TO_TRUE(R,G,B) \ + (((unsigned int)((R) & 0xff00) << 8) | ((unsigned int)(G) & 0xff00) | \ + ((unsigned int)(B) >> 8)) + +unsigned long +colorsToDepth(unsigned long const ncolors); + +void +assertGoodImage(Image * const imageP); + +Image * +newBitImage(unsigned int const width, + unsigned int const height); + +Image * +newRGBImage(unsigned int const width, + unsigned int const height, + unsigned int const depth); + +Image * +newTrueImage(unsigned int const width, + unsigned int const height); + +void +freeImage(Image * const imageP); + +unsigned int +depthToColors(unsigned int const depth); + +extern unsigned short RedIntensity[]; +extern unsigned short GreenIntensity[]; +extern unsigned short BlueIntensity[]; + +static __inline__ unsigned int +colorIntensity(unsigned int const red, + unsigned int const grn, + unsigned int const blu) { +/*---------------------------------------------------------------------------- + Return the (approximate) intensity of a color. +-----------------------------------------------------------------------------*/ + return (RedIntensity[red / 256] + + GreenIntensity[grn / 256] + + BlueIntensity[blu / 256]); +} + +Image * +pbmLoad(const char * const fullname, + const char * const name, + bool const verbose); + +#endif diff --git a/other/pamx/pamx.c b/other/pamx/pamx.c new file mode 100644 index 00000000..8a64fec4 --- /dev/null +++ b/other/pamx/pamx.c @@ -0,0 +1,364 @@ +/* By Bryan Henderson 2006.03.25 + + Copyright information is in the file COPYRIGHT +*/ + +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include "pam.h" +#include "shhopt.h" +#include "mallocvar.h" +#include "nstring.h" +#include "filename.h" + +#include "ximageinfo.h" +#include "image.h" +#include "fill.h" +#include "window.h" + + +struct geometry { + bool specified; + const char * string; + unsigned int width; + unsigned int height; +}; + +struct cmdlineInfo { + const char * inputFileName; + const char * displayName; /* NULL if none */ + const char * display; + const char * title; + unsigned int fullscreen; + unsigned int verbose; + struct geometry geometry; + const char * foreground; + const char * background; + const char * border; + unsigned int install; + unsigned int private; + unsigned int pixmap; + unsigned int fit; + unsigned int visualSpec; + unsigned int visual; +}; + + + +static void +parseCommandLine(int argc, + char ** argv, + struct cmdlineInfo * const cmdlineP) { +/* -------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +--------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to optParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int displaySpec, titleSpec, foregroundSpec, backgroundSpec, + borderSpec, geometrySpec; + + const char * geometryOpt; + const char * visualOpt; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "fullscreen", OPT_FLAG, + NULL, &cmdlineP->fullscreen, 0); + OPTENT3(0, "install", OPT_FLAG, + NULL, &cmdlineP->install, 0); + OPTENT3(0, "private", OPT_FLAG, + NULL, &cmdlineP->private, 0); + OPTENT3(0, "fit", OPT_FLAG, + NULL, &cmdlineP->fit, 0); + OPTENT3(0, "pixmap", OPT_FLAG, + NULL, &cmdlineP->pixmap, 0); + OPTENT3(0, "verbose", OPT_FLAG, + NULL, &cmdlineP->verbose, 0); + OPTENT3(0, "display", OPT_STRING, + &cmdlineP->display, &displaySpec, 0); + OPTENT3(0, "title", OPT_STRING, + &cmdlineP->title, &titleSpec, 0); + OPTENT3(0, "foreground", OPT_STRING, + &cmdlineP->foreground, &foregroundSpec, 0); + OPTENT3(0, "background", OPT_STRING, + &cmdlineP->background, &backgroundSpec, 0); + OPTENT3(0, "border", OPT_STRING, + &cmdlineP->border, &borderSpec, 0); + OPTENT3(0, "geometry", OPT_STRING, + &geometryOpt, &geometrySpec, 0); + OPTENT3(0, "visual", OPT_STRING, + &visualOpt, &cmdlineP->visualSpec, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (geometrySpec) { + int rc; + + cmdlineP->geometry.specified = true; + cmdlineP->geometry.string = geometryOpt; + + rc = sscanf(geometryOpt, "%ux%u", + &cmdlineP->geometry.width, &cmdlineP->geometry.height); + + if (rc != 2) + pm_error("Geometry value '%s' does not have the form WxH, " + "where W and H are natural numbers", geometryOpt); + + if (cmdlineP->geometry.width == 0) + pm_error("Width in -geometry option is zero"); + if (cmdlineP->geometry.height == 0) + pm_error("Height in -geometry option is zero"); + } else + cmdlineP->geometry.specified = false; + + if (!displaySpec) + cmdlineP->display = NULL; + + if (!titleSpec) + cmdlineP->title = NULL; + + if (!foregroundSpec) + cmdlineP->foreground = NULL; + + if (!backgroundSpec) + cmdlineP->background = NULL; + + if (!borderSpec) + cmdlineP->border = NULL; + + if (cmdlineP->visualSpec) + cmdlineP->visual = visualClassFromName(visualOpt); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} + + + +static int +errorHandler(Display * const disp, + XErrorEvent * const error) { +/*---------------------------------------------------------------------------- + This is an X error handler +-----------------------------------------------------------------------------*/ + char errortext[BUFSIZ]; + + XGetErrorText(disp, error->error_code, errortext, sizeof(errortext)); + pm_error("X Error: %s on resource 0x%x", + errortext, (unsigned)error->resourceid); + return 0; +} + + + +static void +fillRow1(struct pam * const pamP, + tuple * const tuplerow, + unsigned char ** const pP) { + + unsigned int col; + + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + *(*pP)++ = + pnm_scalesample(tuplerow[col][0], pamP->maxval, 255); + } +} + + + +static void +fillRow3(struct pam * const pamP, + tuple * const tuplerow, + unsigned char ** const pP) { + + unsigned int col; + + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + *(*pP)++ = + pnm_scalesample(tuplerow[col][plane], pamP->maxval, 255); + } +} + + + +static void +loadPamImage(FILE * const ifP, + Image ** const imagePP) { + + struct pam pam; + Image * imageP; + unsigned int row; + tuple * tuplerow; + unsigned char * p; + enum {DEPTH_1, DEPTH_3} depth; + + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + if (strncmp(pam.tuple_type, "RGB", 3) == 0) { + depth = DEPTH_3; + if (pam.depth < 3) + pm_error("Invalid depth %u for RGB tuple type.", pam.depth); + } else + depth = DEPTH_1; + + imageP = newTrueImage(pam.width, pam.height); + + p = &imageP->data[0]; /* initial value */ + + tuplerow = pnm_allocpamrow(&pam); + + for (row = 0; row < pam.height; ++row) { + pnm_readpamrow(&pam, tuplerow); + + switch (depth) { + case DEPTH_3: + fillRow3(&pam, tuplerow, &p); + break; + case DEPTH_1: + fillRow1(&pam, tuplerow, &p); + break; + } + } + pnm_freepamrow(tuplerow); + + *imagePP = imageP; +} + + +#define BACKGROUND_IDX 0 +#define FOREGROUND_IDX 1 + + +static void +processImage(Image * const imageP, + struct cmdlineInfo const cmdline, + Display * const dispP, + int const scrn) { +/*---------------------------------------------------------------------------- + Modify image *imageP according to various command line options. +-----------------------------------------------------------------------------*/ + if (imageP->depth <= 1) { + if (cmdline.background) { + XColor color; + XParseColor(dispP, DefaultColormap(dispP, scrn), + cmdline.background, &color); + imageP->rgb.red[BACKGROUND_IDX] = color.red; + imageP->rgb.grn[BACKGROUND_IDX] = color.green; + imageP->rgb.blu[BACKGROUND_IDX] = color.blue; + } + if (cmdline.foreground) { + XColor color; + XParseColor(dispP, DefaultColormap(dispP, scrn), + cmdline.foreground, &color); + imageP->rgb.red[FOREGROUND_IDX] = color.red; + imageP->rgb.grn[FOREGROUND_IDX] = color.green; + imageP->rgb.blu[FOREGROUND_IDX] = color.blue; + } + } +} + + + +static void +determineTitle(struct cmdlineInfo const cmdline, + const char ** const titleP) { + + const char * title; + + if (cmdline.title) + title = strdup(cmdline.title); + else { + if (STREQ(cmdline.inputFileName, "-")) + title = NULL; + else { + title = pm_basename(cmdline.inputFileName); + } + } + *titleP = title; +} + + + +int +main(int argc, + char ** argv) { + + struct cmdlineInfo cmdline; + FILE * ifP; + Image * imageP; + Display * dispP; /* display we're sending to */ + int scrn; /* screen we're sending to */ + int retval; + const char * geometryString; + const char * title; + viewer * viewerP; + + pnm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + dispP = XOpenDisplay(cmdline.display); + if (!dispP) + pm_error("Cannot open display '%s'", XDisplayName(cmdline.display)); + + scrn = DefaultScreen(dispP); + XSetErrorHandler(errorHandler); + + geometryString = + cmdline.geometry.specified ? cmdline.geometry.string : NULL; + + createViewer(&viewerP, dispP, scrn, geometryString, cmdline.fullscreen); + + loadPamImage(ifP, &imageP); + + processImage(imageP, cmdline, dispP, scrn); + + determineTitle(cmdline, &title); + + displayInViewer(viewerP, imageP, + cmdline.install, cmdline.private, cmdline.fit, + cmdline.pixmap, cmdline.visualSpec, cmdline.visual, + title, cmdline.verbose, + &retval); + + freeImage(imageP); + + destroyViewer(viewerP); + + if (title) + strfree(title); + + XCloseDisplay(dispP); + + return retval; +} diff --git a/other/pamx/send.c b/other/pamx/send.c new file mode 100644 index 00000000..4b1268a5 --- /dev/null +++ b/other/pamx/send.c @@ -0,0 +1,872 @@ +/* + + Send an Image to an X pixmap + + + By Jim Frost 1989.10.02, Bryan Henderson 2006.03.25. + + Copyright 1989, 1990, 1991 Jim Frost. + See COPYRIGHT file for copyright information. +*/ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "pm_c_util.h" +#include "pm.h" +#include "mallocvar.h" +#include "ximageinfo.h" +#include "valtomem.h" +#include "image.h" +#include "send.h" + +#define TRUE_TO_15BIT(PIXEL) \ + ((((PIXEL) & 0xf80000) >> 9) | \ + (((PIXEL) & 0x00f800) >> 6) | \ + (((PIXEL) & 0x0000f8) >> 3)) + +#define RED_INTENSITY(P) (((P) & 0x7c00) >> 10) +#define GREEN_INTENSITY(P) (((P) & 0x03e0) >> 5) +#define BLUE_INTENSITY(P) ((P) & 0x001f) +#define PM_SCALE(a, b, c) (long)((a) * (c))/(b) + + +static bool GotError; + +static int +pixmapErrorTrap(Display * const disp, + XErrorEvent * const pErrorEvent) { + +#define MAXERRORLEN 100 + char buf[MAXERRORLEN+1]; + GotError = 1; + XGetErrorText(disp, pErrorEvent->error_code, buf, MAXERRORLEN); + pm_message("serial #%ld (request code %d) Got Error '%s'", + pErrorEvent->serial, + pErrorEvent->request_code, + buf); + return 0; +} + + + +Pixmap +ximageToPixmap(Display * const disp, + Window const parent, + XImageInfo * const ximageinfoP) { + + XErrorHandler old_handler; + Pixmap pixmap; + + GotError = FALSE; + old_handler = XSetErrorHandler(pixmapErrorTrap); + XSync(disp, False); + pixmap= XCreatePixmap(disp, parent, + ximageinfoP->ximageP->width, + ximageinfoP->ximageP->height, + ximageinfoP->depth); + XSetErrorHandler(old_handler); + if (GotError) + return None; + ximageinfoP->drawable = pixmap; + sendXImage(ximageinfoP, 0, 0, 0, 0, + ximageinfoP->ximageP->width, ximageinfoP->ximageP->height); + + return pixmap; +} + + + +/* find the best pixmap depth supported by the server for a particular + * visual and return that depth. + * + * this is complicated by R3's lack of XListPixmapFormats so we fake it + * by looking at the structure ourselves. + */ + +static unsigned int +bitsPerPixelAtDepth(Display * const disp, + int const scrn, + unsigned int const depth) { + +#if XlibSpecificationRelease < 4 /* the way things were */ + unsigned int a; + + for (a= 0; a < disp->nformats; a++) + if (disp->pixmap_format[a].depth == depth) + return(disp->pixmap_format[a].bits_per_pixel); + +#else /* the way things should be */ + XPixmapFormatValues *xf; + unsigned int nxf, a; + + xf = XListPixmapFormats(disp, (int *)&nxf); + for (a = 0; a < nxf; a++) + if (xf[a].depth == depth) + return(xf[a].bits_per_pixel); +#endif + + /* this should never happen; if it does, we're in trouble + */ + + fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n"); + exit(1); +} + + + +static Image * +itrueToRGB(Image * const imageP, + unsigned int const ddepth) { + + int y, x, num_pixels, colors; + unsigned long pixel_counts[32786]; + unsigned long pixel_array[32786]; + Pixel pixval; + unsigned char * pixel; + unsigned char * dpixel; + Image * newImageP; + + newImageP = newRGBImage(imageP->width, imageP->height, ddepth); + + colors = 1 << ddepth; + + bzero(pixel_counts, 32768 * sizeof(unsigned long)); + + pixel= imageP->data; + for (y= 0; y < imageP->height; y++) { + unsigned int x; + for (x= 0; x < imageP->width; x++) { + unsigned int const z = TRUE_TO_15BIT(memToVal(pixel, 3)); + pixel_counts[z]++; + pixel += 3; + } + } + num_pixels = 0; + for (x = 0; x < 32768; ++x) { + if (pixel_counts[x] > 0) { + unsigned long const red = RED_INTENSITY(x); + unsigned long const grn = GREEN_INTENSITY(x); + unsigned long const blu = BLUE_INTENSITY(x); + pixel_counts[x] = num_pixels; + *(newImageP->rgb.red + num_pixels) = red<<11; + *(newImageP->rgb.grn + num_pixels) = grn<<11; + *(newImageP->rgb.blu + num_pixels) = blu<<11; + pixel_array[num_pixels++] = (short)x; + if (num_pixels > colors) + break; + } + } + + pixel = imageP->data; + dpixel = newImageP->data; + + for (y = 0; y < imageP->height; ++y) { + unsigned int x; + for (x = 0; x < imageP->width; ++x) { + unsigned int const z = TRUE_TO_15BIT(memToVal(pixel, 3)); + pixval = pixel_counts[z]; + valToMem(pixval, dpixel, newImageP->pixlen); + pixel += 3; + dpixel += newImageP->pixlen; + } + } + newImageP->rgb.used = num_pixels; + newImageP->rgb.compressed = 1; + + return newImageP; +} + + + +static void +makeUsableVisual(Image * const origImageP, + Visual * const visualP, + unsigned int const ddepth, + Image ** const newImagePP) { + + /* process image based on type of visual to which we're sending */ + + switch (origImageP->type) { + case ITRUE: + switch (visualP->class) { + case TrueColor: + case DirectColor: + /* goody goody */ + *newImagePP = origImageP; + break; + case PseudoColor: + *newImagePP = itrueToRGB(origImageP, ddepth); + if (*newImagePP == NULL) + pm_error("Unable to convert for Pseudocolor."); + break; + default: + pm_error("INTERNAL ERROR: impossible visual class %u", + visualP->class); + } + break; + + case IRGB: + switch(visualP->class) { + case TrueColor: + case DirectColor: + /* no problem, we handle this just fine */ + *newImagePP = origImageP; + break; + default: + pm_error("INTERNAL ERROR: impossible visual class %u", + visualP->class); + } + + case IBITMAP: + /* no processing ever needs to be done for bitmaps */ + *newImagePP = origImageP; + break; + } +} + + + +static void +makeColorMap1(Display * const disp, + int const scrn, + Visual * const visualP, + Colormap * const cmapP, + Pixel ** const redvalueP, + Pixel ** const grnvalueP, + Pixel ** const bluvalueP) { + + Pixel * redvalue; + Pixel * grnvalue; + Pixel * bluvalue; + Pixel pixval; + unsigned int redcolors, grncolors, blucolors; + unsigned int redstep, grnstep, blustep; + unsigned int redbottom, grnbottom, blubottom; + unsigned int redtop, grntop, blutop; + unsigned int a; + + MALLOCARRAY_NOFAIL(redvalue, 256); + MALLOCARRAY_NOFAIL(grnvalue, 256); + MALLOCARRAY_NOFAIL(bluvalue, 256); + + if (visualP == DefaultVisual(disp, scrn)) + *cmapP = DefaultColormap(disp, scrn); + else + *cmapP = XCreateColormap(disp, RootWindow(disp, scrn), + visualP, AllocNone); + + retry_direct: /* tag we hit if a DirectColor allocation fails on + * default colormap */ + + /* calculate number of distinct colors in each band */ + + redcolors = grncolors = blucolors = 1; + for (pixval = 1; pixval; pixval <<= 1) { + if (pixval & visualP->red_mask) + redcolors <<= 1; + if (pixval & visualP->green_mask) + grncolors <<= 1; + if (pixval & visualP->blue_mask) + blucolors <<= 1; + } + + /* sanity check */ + + if ((redcolors > visualP->map_entries) || + (grncolors > visualP->map_entries) || + (blucolors > visualP->map_entries)) { + pm_message("Warning: inconsistency in color information " + "(this may be ugly)"); + } + + redstep= 256 / redcolors; + grnstep= 256 / grncolors; + blustep= 256 / blucolors; + redbottom = grnbottom = blubottom= 0; + for (a = 0; a < visualP->map_entries; ++a) { + XColor xcolor; + Status rc; + if (redbottom < 256) + redtop = redbottom + redstep; + if (grnbottom < 256) + grntop = grnbottom + grnstep; + if (blubottom < 256) + blutop = blubottom + blustep; + + xcolor.flags = DoRed | DoGreen | DoBlue; + xcolor.red = (redtop - 1) << 8; + xcolor.green = (grntop - 1) << 8; + xcolor.blue = (blutop - 1) << 8; + rc = XAllocColor(disp, *cmapP, &xcolor); + if (rc == 0) { + /* Allocation failed. If it's for a DirectColor default + visual then we should create a private colormap + and try again. + */ + + if ((visualP->class == DirectColor) && + (visualP == DefaultVisual(disp, scrn))) { + *cmapP = XCreateColormap(disp, RootWindow(disp, scrn), + visualP, AllocNone); + goto retry_direct; + } + + /* something completely unexpected happened */ + + pm_error("INTERNAL ERROR: XAllocColor failed on a " + "TrueColor/Directcolor visual"); + } + + /* fill in pixel values for each band at this intensity */ + + while ((redbottom < 256) && (redbottom < redtop)) + redvalue[redbottom++] = xcolor.pixel & visualP->red_mask; + while ((grnbottom < 256) && (grnbottom < grntop)) + grnvalue[grnbottom++] = xcolor.pixel & visualP->green_mask; + while ((blubottom < 256) && (blubottom < blutop)) + bluvalue[blubottom++] = xcolor.pixel & visualP->blue_mask; + } + *redvalueP = redvalue; + *grnvalueP = grnvalue; + *bluvalueP = bluvalue; +} + + + +static void +allocColorCells(Display * const disp, + Colormap const cmap, + Pixel * const colorIndex, + unsigned int const colorCount, + unsigned int * const cellCountP) { + + bool outOfCells; + unsigned int cellCount; + + outOfCells = false; /* initial value */ + cellCount = 0; /* initial value */ + while (cellCount < colorCount && !outOfCells) { + Status rc; + rc = XAllocColorCells(disp, cmap, FALSE, NULL, 0, + &colorIndex[cellCount++], 1); + if (rc == 0) + outOfCells = true; + } + *cellCountP = cellCount; +} + + + + +static void +makeColorMap2(Display * const disp, + int const scrn, + Visual * const visualP, + RGBMap const rgb, + bool const userWantsPrivateCmap, + bool const userWantsFit, + bool const verbose, + Colormap * const cmapP, + Pixel ** const colorIndexP) { + + bool privateCmap; + bool fit; + bool newmap; + Pixel * colorIndex; + + MALLOCARRAY_NOFAIL(colorIndex, rgb.used); + + /* 'privateCmap' is invalid if not a dynamic visual */ + + switch (visualP->class) { + case StaticColor: + case StaticGray: + privateCmap = TRUE; + default: + privateCmap = userWantsPrivateCmap; + } + + /* get the colormap to use. */ + + if (privateCmap) { /* user asked us to use a private cmap */ + newmap = TRUE; + fit = FALSE; + } else if ((visualP == DefaultVisual(disp, scrn)) || + (visualP->class == StaticGray) || + (visualP->class == StaticColor) || + (visualP->class == TrueColor) || + (visualP->class == DirectColor)) { + + unsigned int a; + + fit = userWantsFit; + + /* if we're using the default visual, try to alloc colors + shareable. otherwise we're using a static visual and + should treat it accordingly. + */ + + if (visualP == DefaultVisual(disp, scrn)) + *cmapP = DefaultColormap(disp, scrn); + else + *cmapP = XCreateColormap(disp, RootWindow(disp, scrn), + visualP, AllocNone); + newmap = FALSE; + + /* allocate colors shareable (if we can) */ + + for (a = 0; a < rgb.used; ++a) { + Status rc; + XColor xcolor; + + xcolor.flags = DoRed | DoGreen | DoBlue; + xcolor.red = rgb.red[a]; + xcolor.green = rgb.grn[a]; + xcolor.blue = rgb.blu[a]; + rc = XAllocColor(disp, *cmapP, &xcolor); + if (rc == 0) { + if ((visualP->class == StaticColor) || + (visualP->class == StaticGray) || + (visualP->class == TrueColor) || + (visualP->class == DirectColor)) { + pm_error("XAllocColor failed on a static visual"); + } else { + /* We can't allocate the colors shareable so + free all the colors we had allocated and + create a private colormap (or fit into the + default cmap if `fit' is true). + */ + XFreeColors(disp, *cmapP, colorIndex, a, 0); + newmap = TRUE; + break; + } + } + colorIndex[a] = xcolor.pixel; + } + } else { + newmap = TRUE; + fit = FALSE; + } + + if (newmap) { + /* Either create a new colormap or fit the image into the + one we have. To create a new one, we create a private + cmap and allocate the colors writable. Fitting the + colors is harder; we have to: + + 1. grab the server so no one can goof with the colormap. + 2. count the available colors using XAllocColorCells. + 3. free the colors we just allocated. + 4. reduce the depth of the image to fit. + 5. allocate the colors again shareable. + 6. ungrab the server and continue on our way. + + Someone should shoot the people who designed X color allocation. + */ + + unsigned int a; + + if (fit) { + if (verbose) + pm_message("Fitting image into default colormap"); + XGrabServer(disp); + } else { + if (verbose) + pm_message("Using private colormap"); + + /* create new colormap */ + + *cmapP = XCreateColormap(disp, RootWindow(disp, scrn), + visualP, AllocNone); + } + + allocColorCells(disp, *cmapP, colorIndex, rgb.used, &a); + + if (fit) { + if (a > 0) + XFreeColors(disp, *cmapP, colorIndex, a, 0); + if (a <= 2) + pm_error("Cannot fit into default colormap"); + } + + if (a == 0) + pm_error("Color allocation failed!"); + + if (fit) { + unsigned int a; + for (a = 0; a < rgb.used; ++a) { + XColor xcolor; + xcolor.flags = DoRed | DoGreen | DoBlue; + xcolor.red = rgb.red[a]; + xcolor.green = rgb.grn[a]; + xcolor.blue = rgb.blu[a]; + + if (!XAllocColor(disp, *cmapP, &xcolor)) + pm_error("XAllocColor failed while fitting colormap!"); + colorIndex[a] = xcolor.pixel; + } + XUngrabServer(disp); + } else { + unsigned int b; + for (b = 0; b < a; ++b) { + XColor xcolor; + xcolor.flags = DoRed | DoGreen | DoBlue; + xcolor.pixel = colorIndex[b]; + xcolor.red = rgb.red[b]; + xcolor.green = rgb.grn[b]; + xcolor.blue = rgb.blu[b]; + XStoreColor(disp, *cmapP, &xcolor); + } + } + } + *colorIndexP = colorIndex; +} + + + +static void +doColorAllocation(XImageInfo * const ximageinfoP, + Display * const disp, + int const scrn, + Visual * const visualP, + Image * const imageP, + bool const userWantsPrivateCmap, + bool const userWantsFit, + bool const verbose, + Pixel ** const colorIndexP, + Pixel ** const redvalP, + Pixel ** const grnvalP, + Pixel ** const bluvalP) { + + if ((visualP->class == TrueColor || visualP->class == DirectColor) && + !BITMAPP(imageP)) { + makeColorMap1(disp, scrn, visualP, &ximageinfoP->cmap, + redvalP, grnvalP, bluvalP); + *colorIndexP = NULL; + } else { + makeColorMap2(disp, scrn, visualP, imageP->rgb, + userWantsPrivateCmap, userWantsFit, verbose, + &ximageinfoP->cmap, colorIndexP); + + *redvalP = *grnvalP = *bluvalP = NULL; + } +} + + + + +static void +makeXImage(XImageInfo * const ximageinfoP, + Display * const disp, + int const scrn, + Visual * const visualP, + unsigned int const ddepth, + Image * const imageP, + Pixel const colorIndex[], + Pixel const redvalue[], + Pixel const grnvalue[], + Pixel const bluvalue[], + bool const verbose) { +/*---------------------------------------------------------------------------- + Create an XImage and related colormap based on the image type we + have. +-----------------------------------------------------------------------------*/ + if (verbose) + pm_message("Building XImage..."); + + switch (imageP->type) { + case IBITMAP: { + unsigned int const byteCount = + (imageP->width + 7) / 8 * imageP->height; + unsigned char * data; + + /* we copy the data to be more consistent */ + + MALLOCARRAY(data, byteCount); + if (data == NULL) + pm_error("Can't allocate space for %u byte image", byteCount); + bcopy(imageP->data, data, byteCount); + + ximageinfoP->ximageP = + XCreateImage(disp, visualP, 1, XYBitmap, + 0, (char*)data, imageP->width, imageP->height, 8, 0); + ximageinfoP->depth = ddepth; + ximageinfoP->foreground = colorIndex[1]; + ximageinfoP->background = colorIndex[0]; + ximageinfoP->ximageP->bitmap_bit_order = MSBFirst; + ximageinfoP->ximageP->byte_order = MSBFirst; + } break; + + case IRGB: + case ITRUE: { + /* Modify image data to match visual and colormap */ + + unsigned int const dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); + unsigned int const dpixlen = (dbits + 7) / 8; + + ximageinfoP->depth = ddepth; + + switch (visualP->class) { + case DirectColor: + case TrueColor: { + unsigned char * data; + unsigned char * destptr; + unsigned char * srcptr; + + ximageinfoP->ximageP = + XCreateImage(disp, visualP, ddepth, ZPixmap, 0, + NULL, imageP->width, imageP->height, 8, 0); + MALLOCARRAY(data, imageP->width * imageP->height * dpixlen); + if (data == NULL) + pm_error("Unable to allocate space for %u x %u x %u image", + imageP->width, imageP->height, dpixlen); + ximageinfoP->ximageP->data = (char*)data; + destptr = data; + srcptr = imageP->data; + switch (imageP->type) { + case ITRUE: { + unsigned int y; + for (y= 0; y < imageP->height; ++y) { + unsigned int x; + for (x= 0; x < imageP->width; ++x) { + Pixel const pixval = memToVal(srcptr, imageP->pixlen); + Pixel const newpixval = + redvalue[TRUE_RED(pixval)] | + grnvalue[TRUE_GRN(pixval)] | + bluvalue[TRUE_BLU(pixval)]; + valToMem(newpixval, destptr, dpixlen); + srcptr += imageP->pixlen; + destptr += dpixlen; + } + } + } break; + case IRGB: { + unsigned int y; + for (y= 0; y < imageP->height; ++y) { + unsigned int x; + for (x = 0; x < imageP->width; ++x) { + Pixel const pixval = memToVal(srcptr, imageP->pixlen); + Pixel const newpixval = + redvalue[imageP->rgb.red[pixval] >> 8] | + grnvalue[imageP->rgb.grn[pixval] >> 8] | + bluvalue[imageP->rgb.blu[pixval] >> 8]; + valToMem(newpixval, destptr, dpixlen); + srcptr += imageP->pixlen; + destptr += dpixlen; + } + } + } break; + default: /* something's broken */ + pm_error("INTERNAL ERROR: Unexpected image type %u for " + "DirectColor/TrueColor visual!", imageP->type); + } + ximageinfoP->ximageP->byte_order = MSBFirst; + /* Trust me, I know what I'm talking about */ + } break; + + default: { + + /* only IRGB images make it this far. */ + + /* If our XImage doesn't have modulus 8 bits per pixel, + it's unclear how to pack bits so we instead use an + XYPixmap image. This is slower. + */ + + if (dbits % 8) { + unsigned int const linelen = (imageP->width + 7) / 8; + unsigned int const size = + imageP->width * imageP->height * dpixlen; + unsigned char * data; + unsigned char * destptr; + unsigned char * srcptr; + Pixel pixval; + unsigned int a; + + ximageinfoP->ximageP = + XCreateImage(disp, visualP, ddepth, XYPixmap, 0, + NULL, imageP->width, imageP->height, 8, 0); + + MALLOCARRAY(data, size); + if (data == NULL) + pm_error("Unable to allocate space for %u x %x x %u " + "image", imageP->width, imageP->height, dpixlen); + ximageinfoP->ximageP->data = (char*)data; + bzero(data, size); + ximageinfoP->ximageP->bitmap_bit_order = MSBFirst; + ximageinfoP->ximageP->byte_order = MSBFirst; + for (a= 0; a < dbits; ++a) { + Pixel const pixmask = 1 << a; + unsigned char * const destdata = + data + ((ddepth - a - 1) * imageP->height * linelen); + + unsigned int y; + + srcptr = imageP->data; + for (y= 0; y < imageP->height; ++y) { + unsigned int x; + unsigned char mask; + destptr = destdata + (y * linelen); + *destptr = 0; + mask = 0x80; + for (x= 0; x < imageP->width; ++x) { + pixval = memToVal(srcptr, imageP->pixlen); + srcptr += imageP->pixlen; + if (colorIndex[pixval] & pixmask) + *destptr |= mask; + mask >>= 1; + if (mask == 0) { + mask = 0x80; + ++destptr; + } + } + } + } + } else { + unsigned int const dpixlen = + (ximageinfoP->ximageP->bits_per_pixel + 7) / 8; + + unsigned char * data; + unsigned char * srcptr; + unsigned char * destptr; + unsigned int y; + + ximageinfoP->ximageP = + XCreateImage(disp, visualP, ddepth, ZPixmap, 0, + NULL, imageP->width, imageP->height, 8, 0); + + MALLOCARRAY(data, imageP->width * imageP->height * dpixlen); + if (data == NULL) + pm_error("Failed to allocate space for %u x %u x %u image", + imageP->width, imageP->height, dpixlen); + ximageinfoP->ximageP->data = (char*)data; + ximageinfoP->ximageP->byte_order= MSBFirst; + /* Trust me, i know what I'm talking about */ + srcptr = imageP->data; + destptr = data; + for (y= 0; y < imageP->height; ++y) { + unsigned int x; + for (x= 0; x < imageP->width; x++) { + valToMem(colorIndex[memToVal(srcptr, imageP->pixlen)], + destptr, dpixlen); + srcptr += imageP->pixlen; + destptr += dpixlen; + } + } + } + } break; + } + } break; + } + if (verbose) + pm_message("done"); +} + + + +XImageInfo * +imageToXImage(Display * const disp, + int const scrn, + Visual * const visualP, /* visual to use */ + unsigned int const ddepth, /* depth of the visual to use */ + Image * const origImageP, + bool const userWantsPrivateCmap, + bool const userWantsFit, + bool const verbose) { + + XImageInfo * ximageinfoP; + Image * imageP; + Pixel * colorIndex; + Pixel * redvalue; + Pixel * grnvalue; + Pixel * bluvalue; + + assertGoodImage(origImageP); + + MALLOCVAR_NOFAIL(ximageinfoP); + ximageinfoP->disp = disp; + ximageinfoP->scrn = scrn; + ximageinfoP->depth = 0; + ximageinfoP->drawable = None; + ximageinfoP->foreground = ximageinfoP->background = 0; + ximageinfoP->gc = NULL; + ximageinfoP->ximageP = NULL; + + makeUsableVisual(origImageP, visualP, ddepth, &imageP); + + assertGoodImage(imageP); + + doColorAllocation(ximageinfoP, disp, scrn, visualP, imageP, + userWantsPrivateCmap, userWantsFit, verbose, + &colorIndex, &redvalue, &grnvalue, &bluvalue); + + makeXImage(ximageinfoP, disp, scrn, visualP, ddepth, imageP, + colorIndex, redvalue, grnvalue, bluvalue, verbose); + + if (colorIndex) + free(colorIndex); + if (redvalue) { + free(redvalue); + free(grnvalue); + free(bluvalue); + } + if (imageP != origImageP) + freeImage(imageP); + + return ximageinfoP; +} + + + +void +sendXImage(XImageInfo * const ximageinfoP, + int const src_x, + int const src_y, + int const dst_x, + int const dst_y, + unsigned int const w, + unsigned int const h) { +/*---------------------------------------------------------------------------- + Given an XImage and a drawable, move a rectangle from the Ximage + to the drawable. +-----------------------------------------------------------------------------*/ + XGCValues gcv; + + /* build and cache the GC */ + + if (!ximageinfoP->gc) { + gcv.function = GXcopy; + if (ximageinfoP->ximageP->depth == 1) { + gcv.foreground = ximageinfoP->foreground; + gcv.background= ximageinfoP->background; + ximageinfoP->gc = + XCreateGC(ximageinfoP->disp, ximageinfoP->drawable, + GCFunction | GCForeground | GCBackground, + &gcv); + }else + ximageinfoP->gc = + XCreateGC(ximageinfoP->disp, ximageinfoP->drawable, + GCFunction, &gcv); + } + + XPutImage(ximageinfoP->disp, ximageinfoP->drawable, ximageinfoP->gc, + ximageinfoP->ximageP, src_x, src_y, dst_x, dst_y, w, h); +} + + + +void +freeXImage(Image * const imageP, + XImageInfo * const ximageinfoP) { +/*---------------------------------------------------------------------------- + free up anything cached in the local Ximage structure. +-----------------------------------------------------------------------------*/ + if (ximageinfoP->gc) + XFreeGC(ximageinfoP->disp, ximageinfoP->gc); + free(ximageinfoP->ximageP->data); + ximageinfoP->ximageP->data = NULL; + XDestroyImage(ximageinfoP->ximageP); + + free(ximageinfoP); +} diff --git a/other/pamx/send.h b/other/pamx/send.h new file mode 100644 index 00000000..203b99c7 --- /dev/null +++ b/other/pamx/send.h @@ -0,0 +1,38 @@ +#ifndef SEND_H_INCLUDED +#define SEND_H_INCLUDED + +#include <X11/Xlib.h> + +#include "pm_c_util.h" + +struct Image; + +void +sendXImage(XImageInfo * const ximageinfoP, + int const src_x, + int const src_y, + int const dst_x, + int const dst_y, + unsigned int const w, + unsigned int const h); + +void +freeXImage(struct Image * const imageP, + XImageInfo * const ximageinfoP); + +XImageInfo * +imageToXImage(Display * const disp, + int const scrn, + Visual * const visualP, /* visual to use */ + unsigned int const ddepth, /* depth of the visual to use */ + struct Image * const origImageP, + bool const userWantsPrivateCmap, + bool const userWantsFit, + bool const verbose); + +Pixmap +ximageToPixmap(Display * const disp, + Window const parent, + XImageInfo * const ximageinfo); + +#endif diff --git a/other/pamx/valtomem.h b/other/pamx/valtomem.h new file mode 100644 index 00000000..e27ce0df --- /dev/null +++ b/other/pamx/valtomem.h @@ -0,0 +1,65 @@ +/* + By Jim Frost 1989.10.02. + + Copyright 1989 Jim Frost. + See COPYRIGHT file for copyright information. +*/ +#ifndef VALTOMEM_H_INCLUDED +#define VALTOMEM_H_INCLUDED + +/* inline these functions for speed. these only work for {len : 1,2,3,4}. + */ + +#define memToVal(PTR,LEN) \ + ((LEN) == 1 ? ((unsigned long)(*((unsigned char *)PTR))) : \ + ((LEN) == 3 ? ((unsigned long) \ + (*(unsigned char *)(PTR) << 16) | \ + (*((unsigned char *)(PTR) + 1) << 8) | \ + (*((unsigned char *)(PTR) + 2))) : \ + ((LEN) == 2 ? ((unsigned long) \ + (*(unsigned char *)(PTR) << 8) | \ + (*((unsigned char *)(PTR) + 1))) : \ + ((unsigned long)((*(unsigned char *)(PTR) << 24) | \ + (*((unsigned char *)(PTR) + 1) << 16) | \ + (*((unsigned char *)(PTR) + 2) << 8) | \ + (*((unsigned char *)(PTR) + 3))))))) + +#define memToValLSB(PTR,LEN) \ + ((LEN) == 1 ? ((unsigned long)(*(unsigned char *)(PTR))) : \ + ((LEN) == 3 ? ((unsigned long) \ + (*(unsigned char *)(PTR)) | \ + (*((unsigned char *)(PTR) + 1) << 8) | \ + (*((unsigned char *)(PTR) + 2) << 16)) : \ + ((LEN) == 2 ? ((unsigned long) \ + (*(unsigned char *)(PTR)) | (*((unsigned char *)(PTR) + 1) << 8)) : \ + ((unsigned long)((*(unsigned char *)(PTR)) | \ + (*((unsigned char *)(PTR) + 1) << 8) | \ + (*((unsigned char *)(PTR) + 2) << 16) | \ + (*((unsigned char *)(PTR) + 3) << 24)))))) + +#define valToMem(VAL,PTR,LEN) \ + ((LEN) == 1 ? (*(unsigned char *)(PTR) = ((unsigned int)(VAL) & 0xff)) : \ + ((LEN) == 3 ? (((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff0000) >> 16), \ + ((*((unsigned char *)(PTR) + 1)) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*((unsigned char *)(PTR) + 2)) = ((unsigned int)(VAL) & 0xff))) : \ + ((LEN) == 2 ? (((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*((unsigned char *)(PTR) + 1)) = ((unsigned int)(VAL) & 0xff))) : \ + (((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff000000) >> 24), \ + ((*((unsigned char *)(PTR) + 1)) = ((unsigned int)(VAL) & 0xff0000) >> 16), \ + ((*((unsigned char *)(PTR) + 2)) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*((unsigned char *)(PTR) + 3)) = ((unsigned int)(VAL) & 0xff)))))) + +#define valToMemLSB(VAL,PTR,LEN) \ + ((LEN) == 1 ? (*(unsigned char *)(PTR) = ((unsigned int)(VAL) & 0xff)) : \ + ((LEN) == 3 ? (((*(unsigned char *)(PTR) + 2) = ((unsigned int)(VAL) & 0xff0000) >> 16), \ + ((*((unsigned char *)(PTR) + 1)) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff))) : \ + ((LEN) == 2 ? (((*((unsigned char *)(PTR) + 1) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff)))) : \ + (((*((unsigned char *)(PTR) + 3)) = ((unsigned int)(VAL) & 0xff000000) >> 24), \ + ((*((unsigned char *)(PTR) + 2)) = ((unsigned int)(VAL) & 0xff0000) >> 16), \ + ((*((unsigned char *)(PTR) + 1)) = ((unsigned int)(VAL) & 0xff00) >> 8), \ + ((*(unsigned char *)(PTR)) = ((unsigned int)(VAL) & 0xff)))))) + + +#endif diff --git a/other/pamx/window.c b/other/pamx/window.c new file mode 100644 index 00000000..1a6e510b --- /dev/null +++ b/other/pamx/window.c @@ -0,0 +1,1209 @@ +/* + Functions to allocate and deallocate structures and structure data + + By Jim Frost 1989.10.03, Bryan Henderson 2006.03.25. + + See COPYRIGHT file for copyright information. +*/ + +#include <assert.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <X11/cursorfont.h> +#include <X11/Xatom.h> +#include <X11/Xdefs.h> /* Needed by Xutil.h */ +#include <X11/X.h> /* Needed by Xutil.h */ +#include <X11/Xlib.h> /* Needed by Xutil.h */ +#include <X11/Xutil.h> + +#include "mallocvar.h" +#include "nstring.h" +#include "pm.h" +#include "ximageinfo.h" +#include "send.h" +#include "image.h" +#include "window.h" + +/* A viewer object is something in which you can display an image. You + can display multiple images in the same viewer, sequentially. + + The viewer has a permanent window, called the viewport. When you display + an image, it has a second window, called the image window, which is a + child of the viewport. +*/ + +struct viewer { + Display * dispP; + int scrn; + Window imageWin; + Window viewportWin; + Colormap imageColormap; + Cursor cursor; + unsigned int xpos, ypos; + unsigned int width, height; + bool fullscreen; + bool userChoseGeometry; + Atom deleteAtom; + bool blank; + /* I'm just guessing, but it seems that a "paint" operation is + necessary the first time a viewport is used, but not when + displaying a new image in an old viewport. I assume that's + because the new viewport is blank, and that's what this + value means. + */ + Pixmap pixmap; +}; + + + +static void +setXloadimageClassHint(Display * const dispP, + Window const window) { + + XClassHint classhint; + + classhint.res_class = (char*)"Xloadimage"; + classhint.res_name = (char*)"xloadimage"; + + XSetClassHint(dispP, window, &classhint); +} + + + +static void +setDeleteWindow(viewer * const viewerP) { + + Atom const protoAtom = XInternAtom(viewerP->dispP, "WM_PROTOCOLS", False); + + viewerP->deleteAtom = XInternAtom(viewerP->dispP, + "WM_DELETE_WINDOW", False); + + if ((protoAtom != None) && (viewerP->deleteAtom != None)) + XChangeProperty(viewerP->dispP, viewerP->viewportWin, + protoAtom, XA_ATOM, 32, PropModeReplace, + (unsigned char *)&viewerP->deleteAtom, 1); +} + + + +static void +getInitialViewerGeometry(const char * const geometryString, + bool const fullscreen, + Display * const dispP, + int const scrn, + unsigned int * const xposP, + unsigned int * const yposP, + unsigned int * const widthP, + unsigned int * const heightP, + bool * const userChoseP) { + + unsigned int const defaultWidth = 10; + unsigned int const defaultHeight = 10; + + if (fullscreen) { + *widthP = DisplayWidth(dispP, scrn); + *heightP = DisplayHeight(dispP, scrn); + *xposP = 0; + *yposP = 0; + *userChoseP = TRUE; + } else if (geometryString) { + const char * defGeom; + asprintfN(&defGeom, "%ux%u+0+0", defaultWidth, defaultHeight); + XGeometry(dispP, scrn, geometryString, defGeom, 0, 1, 1, 0, 0, + (int *)xposP, (int *)yposP, + (int *)widthP, (int *)heightP); + strfree(defGeom); + *userChoseP = TRUE; + } else { + *widthP = defaultWidth; + *heightP = defaultHeight; + *xposP = 0; + *yposP = 0; + *userChoseP = FALSE; + } +} + + + +void +createViewer(viewer ** const viewerPP, + Display * const dispP, + int const scrn, + const char * const geometryString, + bool const fullscreen) { + + viewer * viewerP; + + XSetWindowAttributes swa_view; + + MALLOCVAR_NOFAIL(viewerP); + + viewerP->dispP = dispP; + viewerP->scrn = scrn; + viewerP->fullscreen = fullscreen; + viewerP->imageWin = 0; + viewerP->viewportWin = 0; + + getInitialViewerGeometry(geometryString, fullscreen, dispP, scrn, + &viewerP->xpos, &viewerP->ypos, + &viewerP->width, &viewerP->height, + &viewerP->userChoseGeometry); + + viewerP->cursor = XCreateFontCursor(dispP, XC_watch); + + swa_view.background_pixel = WhitePixel(dispP, scrn); + swa_view.backing_store = NotUseful; + swa_view.cursor = viewerP->cursor; + swa_view.event_mask = + ButtonPressMask | Button1MotionMask | KeyPressMask | + StructureNotifyMask | EnterWindowMask | LeaveWindowMask; + swa_view.save_under = FALSE; + + viewerP->viewportWin = + XCreateWindow(dispP, RootWindow(dispP, scrn), + viewerP->xpos, viewerP->ypos, + viewerP->width, viewerP->height, 0, + DefaultDepth(dispP, scrn), InputOutput, + DefaultVisual(dispP, scrn), + CWBackingStore | CWBackPixel | CWCursor | + CWEventMask | CWSaveUnder, + &swa_view); + + setXloadimageClassHint(viewerP->dispP, viewerP->viewportWin); + + setDeleteWindow(viewerP); + + viewerP->blank = TRUE; + + *viewerPP = viewerP; +} + + + +static void +determineRepaintStrategy(viewer * const viewerP, + bool const userWantsPixmap, + bool const verbose, + XImageInfo * const ximageinfoP, + Pixmap * const pixmapP) { + + /* Decide how we're going to handle repaints. We have three modes: + use backing-store, use background pixmap, and use exposures. + If the server supports backing-store, we enable it and use it. + This really helps servers which are memory constrained. If the + server does not have backing-store, we try to send the image to + a pixmap and use that as backing-store. If that fails, we use + exposures to blit the image (which is ugly but it works). + + 'use_pixmap' forces background pixmap mode, which may improve + performance. + */ + + ximageinfoP->drawable = viewerP->imageWin; + if ((DoesBackingStore(ScreenOfDisplay(viewerP->dispP, viewerP->scrn)) == + NotUseful) || + userWantsPixmap) { + *pixmapP = ximageToPixmap(viewerP->dispP, viewerP->imageWin, + ximageinfoP); + if (*pixmapP == None && verbose) + pm_message("Cannot create image in server; " + "repaints will be ugly!"); + } else + *pixmapP = None; +} + + + +static void +setImageWindowAttr(Display * const dispP, + int const scrn, + Window const imageWindow, + Colormap const cmap, + Pixmap const pixmap) { + + /* build window attributes for the image window */ + + XSetWindowAttributes swa_img; + unsigned int wa_mask_img; + + swa_img.bit_gravity = NorthWestGravity; + swa_img.save_under = FALSE; + swa_img.colormap = cmap; + swa_img.border_pixel = 0; + + wa_mask_img = 0; /* initial value */ + + if (pixmap == None) { + /* No pixmap. Must paint over the wire. Ask for BackingStore + to cut down on the painting. But, ask for Exposures so we can + paint both viewables and backingstore. + */ + + swa_img.background_pixel = WhitePixel(dispP,scrn); + wa_mask_img |= CWBackPixel; + swa_img.event_mask = ExposureMask; + wa_mask_img |= CWEventMask; + swa_img.backing_store = WhenMapped; + wa_mask_img |= CWBackingStore; + } else { + /* We have a pixmap so tile the window. to move the image we only + have to move the window and the server should do the rest. + */ + + swa_img.background_pixmap = pixmap; + wa_mask_img |= CWBackPixmap; + swa_img.event_mask = 0; /* no exposures please */ + wa_mask_img |= CWEventMask; + swa_img.backing_store = NotUseful; + wa_mask_img |= CWBackingStore; + } + XChangeWindowAttributes(dispP, imageWindow, wa_mask_img, &swa_img); +} + + + +static void +createImageWindow(viewer * const viewerP, + XImageInfo * const ximageInfoP, + Image * const imageP, + Visual * const visualP, + bool const userWantsPixmap, + bool const verbose) { + + XSetWindowAttributes swa_img; + + swa_img.bit_gravity = NorthWestGravity; + swa_img.save_under = FALSE; + swa_img.colormap = ximageInfoP->cmap; + swa_img.border_pixel = 0; + viewerP->imageWin = XCreateWindow(viewerP->dispP, viewerP->viewportWin, + viewerP->xpos, viewerP->ypos, + imageP->width, imageP->height, 0, + ximageInfoP->depth, InputOutput, visualP, + CWBitGravity | CWColormap | CWSaveUnder | + CWBorderPixel, &swa_img); + viewerP->imageColormap = ximageInfoP->cmap; + setXloadimageClassHint(viewerP->dispP, viewerP->imageWin); + + determineRepaintStrategy(viewerP, userWantsPixmap, verbose, ximageInfoP, + &viewerP->pixmap); + + setImageWindowAttr(viewerP->dispP, viewerP->scrn, + viewerP->imageWin, ximageInfoP->cmap, + viewerP->pixmap); +} + + + +static void +destroyImageWindow(viewer * const viewerP) { + + if (viewerP->imageWin) { + if (viewerP->imageColormap && + (viewerP->imageColormap != DefaultColormap(viewerP->dispP, viewerP->scrn))) + XFreeColormap(viewerP->dispP, viewerP->imageColormap); + XDestroyWindow(viewerP->dispP, viewerP->imageWin); + } +} + + + +static void +changeCursor(viewer * const viewerP, + unsigned int const imageWidth, + unsigned int const imageHeight) { + + Cursor cursor; + XSetWindowAttributes swa; + + if ((viewerP->width >= imageWidth) && (viewerP->height >= imageHeight)) + cursor = XCreateFontCursor(viewerP->dispP, XC_icon); + else if ((viewerP->width < imageWidth) && (viewerP->height >= imageHeight)) + cursor = XCreateFontCursor(viewerP->dispP, XC_sb_h_double_arrow); + else if ((viewerP->width >= imageWidth) && (viewerP->height < imageHeight)) + cursor = XCreateFontCursor(viewerP->dispP, XC_sb_v_double_arrow); + else + cursor = XCreateFontCursor(viewerP->dispP, XC_fleur); + + swa.cursor = cursor; + XChangeWindowAttributes(viewerP->dispP, viewerP->viewportWin, + CWCursor, &swa); + + XFreeCursor(viewerP->dispP, viewerP->cursor); + + viewerP->cursor = cursor; +} + + + +static void +placeImage(viewer * const viewerP, + int const width, + int const height, + int * const rxP, /* input and output */ + int * const ryP) { /* input and output */ + + int pixx, pixy; + + pixx = *rxP; + pixy = *ryP; + + if (viewerP->width > width) + pixx = (viewerP->width - width) / 2; + else { + if ((pixx < 0) && (pixx + width < viewerP->width)) + pixx = viewerP->width - width; + if (pixx > 0) + pixx = 0; + } + if (viewerP->height > height) + pixy = (viewerP->height - height) / 2; + else { + if ((pixy < 0) && (pixy + height < viewerP->height)) + pixy = viewerP->height - viewerP->height; + if (pixy > 0) + pixy = 0; + } + XMoveWindow(viewerP->dispP, viewerP->imageWin, pixx, pixy); + + *rxP = pixx; + *ryP = pixy; +} + + + +static void +blitImage(XImageInfo * const ximageinfoP, + unsigned int const width, + unsigned int const height, + int const xArg, + int const yArg, + int const wArg, + int const hArg) { + + int w, h; + int x, y; + + w = MIN(wArg, width); + h = MIN(hArg, height); + + x = xArg; + y = yArg; + + if (x < 0) { + XClearArea(ximageinfoP->disp, ximageinfoP->drawable, + x, y, -x, h, False); + w -= (0 - x); + x = 0; + } + if (y < 0) { + XClearArea(ximageinfoP->disp, ximageinfoP->drawable, + x, y, w, -y, False); + h -= (0 - y); + y = 0; + } + if (x + w > width) { + XClearArea(ximageinfoP->disp, ximageinfoP->drawable, + x + width, y, x + w - width, h, False); + w -= x + w - width; + } + if (y + h > height) { + XClearArea(ximageinfoP->disp, ximageinfoP->drawable, + x, y + height, w, y + h - height, False); + h -= y + h - height; + } + sendXImage(ximageinfoP, x, y, x, y, w, h); +} + + + +void +destroyViewer(viewer * const viewerP) { +/*---------------------------------------------------------------------------- + Clean up static window. +-----------------------------------------------------------------------------*/ + if (viewerP->pixmap != None) + XFreePixmap(viewerP->dispP, viewerP->pixmap); + + if (viewerP->imageWin) + XDestroyWindow(viewerP->dispP, viewerP->imageWin); + viewerP->imageWin = 0; + + if (viewerP->viewportWin) + XDestroyWindow(viewerP->dispP, viewerP->viewportWin); + + viewerP->viewportWin = 0; + + XFreeCursor(viewerP->dispP, viewerP->cursor); + + free(viewerP); +} + + + +static void +setViewportColormap(viewer * const viewerP, + Visual * const visualP) { +/*---------------------------------------------------------------------------- + Set the colormap and WM_COLORMAP_WINDOWS properly for the viewport. +-----------------------------------------------------------------------------*/ + static Atom cmap_atom = None; + XSetWindowAttributes swa; + Window cmap_windows[2]; + + if (cmap_atom == None) + cmap_atom = XInternAtom(viewerP->dispP, "WM_COLORMAP_WINDOWS", False); + + /* If the visual we're using is the same as the default visual (used by + the viewport window) then we can set the viewport window to use the + image's colormap. This keeps most window managers happy. + */ + + if (visualP == DefaultVisual(viewerP->dispP, viewerP->scrn)) { + swa.colormap = viewerP->imageColormap; + XChangeWindowAttributes(viewerP->dispP, viewerP->viewportWin, + CWColormap, &swa); + XDeleteProperty(viewerP->dispP, viewerP->viewportWin, cmap_atom); + } else { + /* Smart window managers can handle it when we use a different colormap + in our subwindow so long as we set the WM_COLORMAP_WINDOWS property + ala ICCCM. + */ + cmap_windows[0] = viewerP->imageWin; + cmap_windows[1] = viewerP->viewportWin; + XChangeProperty(viewerP->dispP, viewerP->viewportWin, + cmap_atom, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)cmap_windows, 2); + } +} + + + +static const char * +iconName(const char * const s) { +/*---------------------------------------------------------------------------- + Return an icon name suitable for an image titled 's'. + + s == NULL means untitled. +-----------------------------------------------------------------------------*/ + const char * retval; + char buf[BUFSIZ]; + + if (!s) + STRSCPY(buf, "Unnamed"); + else { + char * t; + + STRSCPY(buf, s); + /* strip off stuff following 1st word. This strips + info added by processing functions too. + */ + t = index(buf, ' '); + if (t) + *t = '\0'; + + /* Strip off leading path. if you don't use unix-style paths, + You might want to change this. + */ + + t= rindex(buf, '/'); + if (t) { + char * p; + for (p = buf, ++t; *t; ++p, ++t) + *p = *t; + *p = '\0'; + } + /* look for an extension and strip it off */ + t = index(buf, '.'); + if (t) + *t = '\0'; + } + + retval = strdup(buf); + if (retval == NULL) + pm_error("Out of memory"); + return retval; +} + + + +/* visual class to name table */ + +static struct visual_class_name { + int class; /* numerical value of class */ + const char * name; /* actual name of class */ +} const VisualClassName[] = { + {TrueColor, "TrueColor" } , + {DirectColor, "DirectColor" } , + {PseudoColor, "PseudoColor" } , + {StaticColor, "StaticColor" } , + {GrayScale, "GrayScale" } , + {StaticGray, "StaticGray" } , + {StaticGray, "StaticGrey" } , + {-1, NULL } +}; + + + +int +visualClassFromName(const char * const name) { + + unsigned int a; + int class; + bool found; + + for (a = 0, found = FALSE; VisualClassName[a].name; ++a) { + if (STRCASEEQ(VisualClassName[a].name, name)) { + /* Check for uniqueness. We special-case StaticGray + because we have two spellings but they are unique if + we find either. + */ + if (found && class != StaticGray) + pm_error("'%s' does not uniquely describe a visual class", + name); + + class = VisualClassName[a].class; + found = TRUE; + } + } + if (!found) + pm_error("'%s' is not a visual class name", name); + + return class; +} + + + +static const char * +nameOfVisualClass(int const class) { + + unsigned int a; + const char * name; + bool found; + + for (a = 0, found = FALSE; VisualClassName[a].name; ++a) { + if (VisualClassName[a].class == class) { + name = VisualClassName[a].name; + found = TRUE; + } + } + if (found) + return name; + else + return "[Unknown Visual Class]"; +} + + + +/* find the best visual of a particular class with a particular depth + */ + +static Visual * +bestVisualOfClassAndDepth(Display * const disp, + int const scrn, + int const class, + unsigned int const depth) { + + long const vinfoMask = + VisualScreenMask | VisualClassMask | VisualDepthMask; + + Visual * best; + XVisualInfo template; + XVisualInfo * infoP; + unsigned int nvisuals; + + best = NULL; /* initial value */ + + template.screen = scrn; + template.class = class; + template.depth = depth; + infoP = XGetVisualInfo(disp, vinfoMask, &template, (int*)&nvisuals); + if (infoP) { + /* There are visuals with this depth */ + + /* Not sure what to do if this gives more than one visual of a + particular class and depth, so just return the first one. + */ + + best = infoP->visual; + XFree((char *)infoP); + } + return best; +} + + + +static void +bestVisual(Display * const disp, + int const scrn, + Image * const imageP, + Visual ** const rvisualPP, + unsigned int * const rdepthP) { +/*---------------------------------------------------------------------------- + Try to determine the best available visual to use for a particular + image +-----------------------------------------------------------------------------*/ + unsigned int depth, a; + Screen * screen; + Visual * visualP; + Visual * default_visualP; + + /* Figure out the best depth the server supports. note that some servers + (such as the HP 11.3 server) actually say they support some depths but + have no visuals that support that depth. Seems silly to me ... + */ + + depth = 0; + screen = ScreenOfDisplay(disp, scrn); + for (a = 0; a < screen->ndepths; ++a) { + if (screen->depths[a].nvisuals && + ((!depth || + ((depth < imageP->depth) && (screen->depths[a].depth > depth)) || + ((screen->depths[a].depth >= imageP->depth) && + (screen->depths[a].depth < depth))))) + depth = screen->depths[a].depth; + } + if (!depth) { + /* this shouldn't happen */ + pm_message("bestVisual: didn't find any depths?!?"); + depth = DefaultDepth(disp, scrn); + } + + /* given this depth, find the best possible visual + */ + + default_visualP = DefaultVisual(disp, scrn); + switch (imageP->type) { + case ITRUE: { + /* If the default visual is DirectColor or TrueColor prioritize such + that we use the default type if it exists at this depth + */ + + if (default_visualP->class == TrueColor) { + visualP = bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, + DirectColor, depth); + } else { + visualP = bestVisualOfClassAndDepth(disp, scrn, DirectColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, TrueColor, + depth); + } + + if (!visualP || ((depth <= 8) && + bestVisualOfClassAndDepth(disp, scrn, PseudoColor, + depth))) + visualP = bestVisualOfClassAndDepth(disp, scrn, PseudoColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth); + } break; + + case IRGB: { + /* if it's an RGB image, we want PseudoColor if we can get it */ + + visualP = bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, DirectColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth); + } break; + + case IBITMAP: { + visualP = bestVisualOfClassAndDepth(disp, scrn, PseudoColor, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, GrayScale, depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, StaticGray, depth); + + /* It seems pretty wasteful to use a TrueColor or DirectColor visual + to display a bitmap (2-color) image, so we look for those last + */ + + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, DirectColor, + depth); + if (!visualP) + visualP = bestVisualOfClassAndDepth(disp, scrn, TrueColor, depth); + } break; + } + + if (!visualP) { /* this shouldn't happen */ + pm_message("bestVisual: couldn't find one?!?"); + depth = DefaultDepth(disp, scrn); + visualP = DefaultVisual(disp, scrn); + } + *rvisualPP = visualP; + *rdepthP = depth; +} + + + +static void +bestVisualOfClass(Display * const disp, + int const scrn, + Image * const image, + int const visual_class, + Visual ** const rvisual, + unsigned int * const rdepth) { +/*---------------------------------------------------------------------------- + Given a visual class, try to find the best visual of that class at + the best depth. Return a null visual and depth if we couldn't find + any visual of that type at any depth. +-----------------------------------------------------------------------------*/ + Visual *visual; + Screen *screen; + unsigned int a, b, depth; + + /* loop through depths looking for a visual of a good depth which matches + * our visual class. + */ + + screen= ScreenOfDisplay(disp, scrn); + visual= (Visual *)NULL; + depth= 0; + for (a= 0; a < screen->ndepths; a++) { + for (b= 0; b < screen->depths[a].nvisuals; b++) { + if ((screen->depths[a].visuals[b].class == visual_class) && + (!depth || + ((depth < image->depth) && (screen->depths[a].depth > depth)) || + ((screen->depths[a].depth >= image->depth) && + (screen->depths[a].depth < depth)))) { + depth= screen->depths[a].depth; + visual= &(screen->depths[a].visuals[b]); + } + } + } + *rvisual= visual; + *rdepth= depth; +} + + + +static void +getImageDispDimensions(viewer * const viewerP, + Image * const imageP, + unsigned int * const widthP, + unsigned int * const heightP) { + + if (viewerP->userChoseGeometry) { + *widthP = viewerP->width; + *heightP = viewerP->height; + } else { + unsigned int const displayWidth = + DisplayWidth(viewerP->dispP, viewerP->scrn); + unsigned int const displayHeight = + DisplayHeight(viewerP->dispP, viewerP->scrn); + + /* We don't use more than 90% of display real estate unless user + explicitly asked for it. + */ + *widthP = MIN(imageP->width, (unsigned)(displayWidth * 0.9)); + *heightP = MIN(imageP->height, (unsigned)(displayHeight * 0.9)); + } +} + + + +static void +getVisualAndDepth(Image * const imageP, + Display * const dispP, + int const scrn, + bool const fit, + bool const visualSpec, + unsigned int const visualClass, + Visual ** const visualPP, + unsigned int * const depthP) { + + + /* If the user told us to fit the colormap, we must use the default + visual. + */ + + if (fit) { + *visualPP = DefaultVisual(dispP, scrn); + *depthP = DefaultDepth(dispP, scrn); + } else { + Visual * visualP; + unsigned int depth; + + visualP = NULL; + if (!visualSpec) { + /* Try to pick the best visual for the image. */ + + bestVisual(dispP, scrn, imageP, &visualP, &depth); + } else { + /* Try to find a visual of the specified class */ + + bestVisualOfClass(dispP, scrn, imageP, visualClass, + &visualP, &depth); + if (!visualP) { + bestVisual(dispP, scrn, imageP, &visualP, &depth); + pm_message("Server does not provide %s visual, using %s", + nameOfVisualClass(visualClass), + nameOfVisualClass(visualP->class)); + } + } + *visualPP = visualP; + *depthP = depth; + } +} + + + +static void +setNormalSizeHints(viewer * const viewerP, + Image * const imageP) { + + XSizeHints sh; + + sh.width = viewerP->width; + sh.height = viewerP->height; + if (viewerP->fullscreen) { + sh.min_width = sh.max_width = viewerP->width; + sh.min_height = sh.max_height = viewerP->height; + } else { + sh.min_width = 1; + sh.min_height = 1; + sh.max_width = imageP->width; + sh.max_height = imageP->height; + } + sh.width_inc = 1; + sh.height_inc = 1; + + sh.flags = PMinSize | PMaxSize | PResizeInc; + if (viewerP->userChoseGeometry) + sh.flags |= USSize; + else + sh.flags |= PSize; + + if (viewerP->userChoseGeometry) { + sh.x = viewerP->xpos; + sh.y = viewerP->ypos; + sh.flags |= USPosition; + } + XSetNormalHints(viewerP->dispP, viewerP->viewportWin, &sh); + + sh.min_width = sh.max_width; + sh.min_height = sh.max_height; + XSetNormalHints(viewerP->dispP, viewerP->imageWin, &sh); + /* Image doesn't shrink */ +} + + + +static void +setWMHints(viewer * const viewerP) { + + XWMHints wmh; + + wmh.input = TRUE; + wmh.flags = InputHint; + XSetWMHints(viewerP->dispP, viewerP->viewportWin, &wmh); +} + + +#define CTL_C '\003' + +typedef enum exitReason { + EXIT_NONE, + EXIT_QUIT, + EXIT_WM_KILL, + EXIT_DESTROYED +} exitReason; + + + +static void +run(viewer * const viewerP, + Image * const imageP, + XImageInfo * const ximageInfoP, + int const initPixx, + int const initPixy, + bool const install, + exitReason * const exitReasonP) { + + int lastx, lasty; + int pixx, pixy; + union { + XEvent event; + XAnyEvent any; + XButtonEvent button; + XKeyEvent key; + XConfigureEvent configure; + XExposeEvent expose; + XMotionEvent motion; + XResizeRequestEvent resize; + XClientMessageEvent message; + } event; + exitReason exitReason; + + lastx = lasty = -1; + pixx = initPixx; + pixy = initPixy; + + exitReason = EXIT_NONE; /* No reason to exit yet */ + + while (exitReason == EXIT_NONE) { + XNextEvent(viewerP->dispP, &event.event); + + switch (event.any.type) { + case ButtonPress: + if (event.button.button == 1) { + lastx = event.button.x; + lasty = event.button.y; + } + break; + + case KeyPress: { + char buf[128]; + KeySym ks; + XComposeStatus status; + Status rc; + + rc = XLookupString(&event.key, buf, 128, &ks, &status); + if (rc == 1) { + char const ret = buf[0]; + char const lowerRet = tolower(ret); + + switch (lowerRet) { + case CTL_C: + case 'q': + exitReason = EXIT_QUIT; + break; + } + } + } break; + + case MotionNotify: { + int mousex, mousey; + + if (imageP->width <= viewerP->width && + imageP->height <= viewerP->height) { + /* we're AT&T */ + } else { + mousex = event.button.x; + mousey = event.button.y; + while (XCheckTypedEvent(viewerP->dispP, MotionNotify, + (XEvent*)&event)) { + mousex = event.button.x; + mousey = event.button.y; + } + pixx -= (lastx - mousex); + pixy -= (lasty - mousey); + lastx = mousex; + lasty = mousey; + placeImage(viewerP, imageP->width, imageP->height, + &pixx, &pixy); + } + } break; + + case ConfigureNotify: + viewerP->width = event.configure.width; + viewerP->height = event.configure.height; + + placeImage(viewerP, imageP->width, imageP->height, + &pixx, &pixy); + + /* Configure the cursor to indicate which directions we can drag + */ + + changeCursor(viewerP, imageP->width, imageP->height); + break; + + case DestroyNotify: + exitReason = EXIT_DESTROYED; + break; + + case Expose: + blitImage(ximageInfoP, imageP->width, imageP->height, + event.expose.x, event.expose.y, + event.expose.width, event.expose.height); + break; + + case EnterNotify: + if (install) + XInstallColormap(viewerP->dispP, ximageInfoP->cmap); + break; + + case LeaveNotify: + if (install) + XUninstallColormap(viewerP->dispP, ximageInfoP->cmap); + break; + + case ClientMessage: + /* If we get a client message for the viewport window + which has the value of the delete atom, it means the + window manager wants us to die. + */ + + if ((event.message.window == viewerP->viewportWin) && + (event.message.data.l[0] == viewerP->deleteAtom)) { + exitReason = EXIT_WM_KILL; + } + break; + } + } + *exitReasonP = exitReason; +} + + + +static int +retvalueFromExitReason(exitReason const exitReason) { + + int retval; + + switch (exitReason) { + case EXIT_NONE: assert(false); break; + case EXIT_QUIT: retval = 0; break; + case EXIT_WM_KILL: retval = 10; break; + case EXIT_DESTROYED: retval = 20; break; + } + return retval; +} + + + +static void +resizeViewer(viewer * const viewerP, + unsigned int const newWidth, + unsigned int const newHeight) { + + if (viewerP->width != newWidth || viewerP->height != newHeight) { + XResizeWindow(viewerP->dispP, viewerP->viewportWin, + newWidth, newHeight); + viewerP->width = newWidth; + viewerP->height = newHeight; + } +} + + + +void +displayInViewer(viewer * const viewerP, + struct Image * const imageP, + bool const install, + bool const userWantsPrivateCmap, + bool const fit, + bool const userWantsPixmap, + bool const visualSpec, + unsigned int const visualClass, + const char * const title, + bool const verbose, + int * const retvalP) { + + XImageInfo * ximageInfoP; + Visual * visual; + unsigned int depth; + bool privateCmap; + int pixx, pixy; + exitReason exitReason; + unsigned int windowWidth, windowHeight; + + pixx = -1; pixy = -1; /* initial values */ + + getImageDispDimensions(viewerP, imageP, &windowWidth, &windowHeight); + + resizeViewer(viewerP, windowWidth, windowHeight); + + getVisualAndDepth(imageP, viewerP->dispP, viewerP->scrn, + fit, visualSpec, visualClass, + &visual, &depth); + + if (verbose && (visual != DefaultVisual(viewerP->dispP, viewerP->scrn))) + pm_message("Using %s visual", nameOfVisualClass(visual->class)); + + /* If we're in slideshow mode and the user told us to fit the colormap, + free it here. + */ + + if (viewerP->blank) { + /* For the first image we display we can use the default cmap. + subsequent images use a private colormap (unless they're + bitmaps) so we don't get color erosion when switching + images. + */ + + if (fit) { + XDestroyWindow(viewerP->dispP, viewerP->imageWin); + viewerP->imageWin = 0; + viewerP->imageColormap = 0; + privateCmap = userWantsPrivateCmap; + } else if (!BITMAPP(imageP)) + privateCmap = TRUE; + } else + privateCmap = userWantsPrivateCmap; + + ximageInfoP = imageToXImage(viewerP->dispP, viewerP->scrn, visual, depth, + imageP, privateCmap, fit, verbose); + if (!ximageInfoP) + pm_error("INTERNAL ERROR: Cannot convert Image to XImage"); + + destroyImageWindow(viewerP); + + createImageWindow(viewerP, ximageInfoP, imageP, visual, + userWantsPixmap, verbose); + + if (title) + XStoreName(viewerP->dispP, viewerP->viewportWin, title); + else + XStoreName(viewerP->dispP, viewerP->viewportWin, "Unnamed"); + + { + const char * const name = iconName(title); + XSetIconName(viewerP->dispP, viewerP->viewportWin, name); + strfree(name); + } + setNormalSizeHints(viewerP, imageP); + + setWMHints(viewerP); + + setViewportColormap(viewerP, visual); + + /* Map (display) windows */ + + XMapWindow(viewerP->dispP, viewerP->imageWin); + XMapWindow(viewerP->dispP, viewerP->viewportWin); + + /* Start displaying image */ + + placeImage(viewerP, imageP->width, imageP->height, &pixx, &pixy); + if (!viewerP->blank) { + XResizeWindow(viewerP->dispP, viewerP->imageWin, + imageP->width, imageP->height); + /* Clear the image window. Ask for exposure if there is no tile. */ + XClearArea(viewerP->dispP, viewerP->imageWin, 0, 0, 0, 0, + (viewerP->pixmap == None)); + viewerP->blank = FALSE; + } + + changeCursor(viewerP, imageP->width, imageP->height); + + /* Process X events, continuously */ + run(viewerP, imageP, ximageInfoP, pixx, pixy, install, &exitReason); + + freeXImage(imageP, ximageInfoP); + + *retvalP = retvalueFromExitReason(exitReason); +} diff --git a/other/pamx/window.h b/other/pamx/window.h new file mode 100644 index 00000000..2efc54b5 --- /dev/null +++ b/other/pamx/window.h @@ -0,0 +1,38 @@ +#ifndef WINDOW_H_INCLUDED +#define WINDOW_H_INCLUDED + +#include <X11/Xlib.h> + +#include "pm_c_util.h" + +struct Image; +struct viewer; +typedef struct viewer viewer; + +int +visualClassFromName(const char * const name); + +void +createViewer(viewer ** const viewerPP, + Display * const dispP, + int const scrn, + const char * const geometryString, + bool const fullscreen); + +void +destroyViewer(viewer * const viewerP); + +void +displayInViewer(viewer * const viewerP, + struct Image * const imageP, + bool const install, + bool const userWantsPrivateCmap, + bool const fit, + bool const userWantsPixmap, + bool const visualSpec, + unsigned int const visualClass, + const char * const title, + bool const verbose, + int * const retvalP); + +#endif diff --git a/other/pamx/ximageinfo.h b/other/pamx/ximageinfo.h new file mode 100644 index 00000000..b0b54ee1 --- /dev/null +++ b/other/pamx/ximageinfo.h @@ -0,0 +1,25 @@ +#ifndef XIMAGEINFO_H_INCLUDED +#define XIMAGEINFO_H_INCLUDED + +#include <X11/Xlib.h> + + + +typedef unsigned long Pixel; /* what X thinks a pixel is */ +typedef unsigned short Intensity; /* what X thinks an RGB intensity is */ + +typedef struct { + /* This struct holds the X-client side bits for a rendered image. */ + Display * disp; /* destination display */ + int scrn; /* destination screen */ + int depth; /* depth of drawable we want/have */ + Drawable drawable; /* drawable to send image to */ + Pixel foreground; + /* foreground and background pixels for mono images */ + Pixel background; + Colormap cmap; /* colormap used for image */ + GC gc; /* cached gc for sending image */ + XImage * ximageP; /* ximage structure */ +} XImageInfo; + +#endif |