aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/ObmW/GtermImaging.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/x11iraf/obm/ObmW/GtermImaging.c')
-rw-r--r--vendor/x11iraf/obm/ObmW/GtermImaging.c3164
1 files changed, 3164 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/ObmW/GtermImaging.c b/vendor/x11iraf/obm/ObmW/GtermImaging.c
new file mode 100644
index 00000000..b2d5791c
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/GtermImaging.c
@@ -0,0 +1,3164 @@
+
+/*
+ * IMAGING routines.
+ * -----------------------
+ * Our strategy here is to support a range of visuals with pseudocolor being
+ * preferred if available. All imaging is done internally using 8 bit images
+ * and a max 256 element colormap. If the display hardware has a depth less
+ * than 8 bits, e.g. for a monochrome display, the image is reduced to the
+ * screen depth by some technique before being output to the display.
+ *
+ * Images (rasters) are implemented internally in Gterm using either ximages or
+ * off screen pixmaps. Which format is used is decided at raster create time
+ * and is controlled by a Gterm resource. This is transparent to the client
+ * application. Currently only 8 bit rasters are supported.
+ *
+ * GtRasterInit (gt)
+ * GtAssignRaster (gt, raster, drawable)
+ * GtCreateRaster (gt, raster, type, width, height, depth)
+ * GtDestroyRaster (gt, raster)
+ * exists = GtQueryRaster (gt, raster, &type, &width, &height, &depth)
+ * raster = GtNextRaster (gt)
+ * GtSetRaster (gt, raster)
+ * raster = GtGetRaster (gt)
+ * n = GtNRasters (gt)
+ *
+ * GtWritePixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtReadPixels (gt, raster, pixels, nbits, x1, y1, nx, ny)
+ * GtSetPixels (gt, raster, ct, x1, y1, nx, ny, color, rop)
+ * GtRefreshPixels (gt, raster, ct, x1, y1, nx, ny)
+ * pixmap = GtExtractPixmap (gt, src, ct, x, y, width, height)
+ * GtInsertPixmap (gt, pixmap, dst, ct, x, y, width, height)
+ *
+ * colormap = GtNextColormap (gt)
+ * GtFreeColormap (gt, colormap)
+ * GtWriteColormap (gt, colormap, first, nelem, r, g, b)
+ * GtReadColormap (gt, colormap, first, nelem, r, g, b)
+ * GtLoadColormap (gt, colormap, offset, scale)
+ * exists = GtQueryColormap (gt, colormap, &first, &nelem, &maxelem)
+ * GtWriteIomap (gt, iomap, first, nelem)
+ * GtReadIomap (gt, iomap, first, nelem)
+ * GtReadLUT (gt, lut, first, nelem)
+ * pixel = GtGetClientPixel (gt, gterm_pixel)
+ *
+ * GtInitMappings (gt)
+ * mapping = GtNextMapping (gt)
+ * GtFreeMapping (gt, mapping)
+ * GtRaiseMapping (gt, mapping, ref|NULL)
+ * GtLowerMapping (gt, mapping, ref|NULL)
+ * int = GtCompareMappings (gt, map1, map2)
+ * GtEnableMapping (gt, mapping, refresh)
+ * GtDisableMapping (gt, mapping, erase)
+ * active = GtActiveMapping (gt, mapping)
+ * GtRefreshMapping (gt, mapping)
+ * raster = GtSelectRaster (gt, dras, dt, dx, dy, rt, &rx, &ry, &mapping)
+ * GtSetDisplayRaster (gt, mapping)
+ *
+ * GtCopyRaster (gt, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtSetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ * GtGetMapping (gt, mapping, rop,
+ * src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ *
+ * GtMapVector (gt, mapping, dir, pv1, pv2, npts)
+ * GtPixelToNDC (gt, raster, pv1, pv2, npts)
+ * GtNDCToPixel (gt, raster, pv1, pv2, npts)
+ *
+ * GtDebug (gt, fp, what)
+ *
+ * In the case of CopyRaster or {Set|Get}Mapping, raster coordinates may be
+ * specified in either raster pixel (GtPixel) units or in normalized device
+ * coordinates (GtNDC) in the range 0-32767.
+ * ---------------------------------------------------------------------------
+ */
+
+GtRasterInit (w)
+ GtermWidget w;
+{
+ register int i;
+ register Raster rp;
+ register struct colormap *cm;
+ struct colormap *next_cm;
+
+
+ invalidate_draw_context (w);
+
+ /* Destroy any existing rasters. */
+ if (w->gterm.rasters) {
+ for (i=1; i < w->gterm.maxRasters; i++) {
+ if (w->gterm.rasters[i].type)
+ GtDestroyRaster (w, i);
+ }
+ }
+
+ /* Allocate the initially empty raster descriptors. */
+ XtFree ((char *)w->gterm.rasters);
+ w->gterm.rasters = rp =
+ (Raster) XtCalloc (w->gterm.maxRasters, sizeof (struct raster));
+ w->gterm.nrasters = 0;
+ w->gterm.raster = 0;
+
+ /* Raster 0 is the display window.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtRasterInit: Init display PixmapRaster (%dx%d) depth=%d\n",
+ w->core.width, w->core.height, w->core.depth);
+
+ rp->type = PixmapRaster;
+ rp->width = w->core.width;
+ rp->height = w->core.height;
+ rp->depth = w->core.depth;
+ rp->r.pixmap = w->gterm.window;
+ rp->delete = 0;
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width, w->core.height, RasterDepth);
+
+
+ /* Free any previously allocated colormap cells. */
+ if (! w->gterm.useGlobalCmap) {
+ if (w->gterm.ncolors > SZ_STATIC_CMAP && w->gterm.useDefaultCM) {
+ XFreeColors (w->gterm.display, w->core.colormap,
+ &w->gterm.cmap[SZ_STATIC_CMAP], w->gterm.ncolors-SZ_STATIC_CMAP,
+ 0);
+ w->gterm.ncolors = SZ_STATIC_CMAP;
+ invalidate_cmap (w);
+ }
+ }
+
+ /* Free any client defined colormaps. */
+ for (cm = w->gterm.colormaps; cm; cm = next_cm) {
+ next_cm = cm->next;
+ XtFree ((char *)cm);
+ }
+ w->gterm.colormaps = NULL;
+
+ /* Initialize the mappings. */
+ GtInitMappings (w);
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRasterInit: After Init Mappings...Returning\n");
+}
+
+
+initialize_shadow_pixmap (GtermWidget w, int dst)
+{
+ Raster rp = (Raster) NULL;
+
+ if (w->gterm.rasters) {
+ rp = &w->gterm.rasters[dst];
+
+ if (dst == 0 || rp->type == PixmapRaster) {
+ XFillRectangle (w->gterm.display, rp->shadow_pixmap,
+ w->gterm.clear8GC, 0, 0, rp->width, rp->height);
+ }
+ }
+}
+
+
+/* GtNextRaster -- Return the index of the next unused raster.
+ */
+GtNextRaster (w)
+ register GtermWidget w;
+{
+ register int i;
+
+ if (w->gterm.rasters)
+ for (i=1; i < w->gterm.maxRasters; i++)
+ if (!w->gterm.rasters[i].type)
+ return (i);
+
+ return (-1);
+}
+
+
+/* GtNRasters -- Return the number of currently defined rasters.
+ */
+GtNRasters (w)
+ GtermWidget w;
+{
+ return (w->gterm.nrasters);
+}
+
+
+/* GtAssignRaster -- Assign a raster descriptor to an externally created
+ * drawable (window or pixmap). The raster thus created may be mapped or
+ * drawn into like the rasters created privately by the imaging code, but
+ * this allows use of this code to access other windows, or shared pixmaps.
+ */
+GtAssignRaster (w, raster, drawable, type)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ XtPointer drawable; /* object containing pixel array */
+ int type; /* type of drawable [not used] */
+{
+ register Raster rp;
+ XWindowAttributes wa;
+
+ if (raster <= 0 || raster >= w->gterm.maxRasters)
+ return (ERR);
+ else
+ rp = &w->gterm.rasters[raster];
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, (Window)drawable, &wa))
+ return (ERR);
+ } else
+ wa = w->gterm.wa;
+
+ rp->type = PixmapRaster;
+ rp->width = wa.width;
+ rp->height = wa.height;
+ rp->depth = wa.depth;
+ rp->r.pixmap = (Pixmap) drawable;
+ rp->delete = 0;
+
+ return (OK);
+}
+
+
+/* GtCreateRaster -- Create a new raster of the given size. A server pixmap
+ * (GtServer) or ximage (GtClient) raster will be created depending upon the
+ * current value of the cacheRasters resource.
+ */
+GtCreateRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int type;
+ int width, height;
+ int depth;
+{
+ register uchar *op;
+ register int npix, pixel;
+ uchar *data;
+ XImage *xp;
+ Raster rp;
+ int cache;
+
+
+ if (!XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtCreateRaster: raster=%d type=%s (%dx%dx%d)\n",
+ raster, ((type == GtClient) ? "GtClient" : "GtServer"),
+ width, height, depth);
+ }
+
+
+ /* Only rasters of depth 8 bits are currently supported. Eventually
+ ** we may want to allow arbitrarily deep frame buffers (e.g. for RGB
+ ** composites, overlay planes, etc).
+ if (depth && depth != 8) {
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster ERROR: attempt to create raster depth=%d\n",
+ depth);
+ return (ERR);
+ }
+ */
+
+
+ /* Check for a raster number in bounds. */
+ if (raster < 0 || raster >= w->gterm.maxRasters) {
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster ERROR: invalid raster = %d\n", raster);
+ return (ERR);
+ } else
+ rp = &w->gterm.rasters[raster];
+
+
+ /* A create on raster 0 (the display window) is treated as an attempt
+ * to resize the window.
+ */
+ if (raster == 0) {
+ XWindowAttributes wa;
+
+ invalidate_draw_context (w);
+
+ /* Issue the resize request. */
+ XtVaSetValues ((Widget)w,
+ XtNwidth, (XtArgVal)width,
+ XtNheight, (XtArgVal)height,
+ NULL);
+ XFlush (w->gterm.display);
+
+ /* The following generates a round trip request to the server and
+ * is an attempt to allow the window system time to process the
+ * resize request before the client can issue a GtQueryRaster to
+ * see if the request has succeeded (hence causing a race condition).
+ * If the window is not the requested size the delay flag is set
+ * to cause graphics input processing to be suspended until the
+ * window is resized or redisplayed. A dummy expose event is
+ * generated to clear the delay condition in case the resize request
+ * is not granted.
+ */
+ if (XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ rp->width = wa.width;
+ rp->height = wa.height;
+
+ if (rp->width != width || rp->height != height) {
+ XExposeEvent ev;
+ ev.type = Expose;
+ ev.send_event = True;
+ ev.display = w->gterm.display;
+ ev.window = w->gterm.window;
+ ev.x = ev.y = 0;
+ ev.width = ev.height = 1;
+ ev.count = 0;
+
+ XSendEvent (w->gterm.display, w->gterm.window, False,
+ NoEventMask, (XEvent *)&ev);
+ w->gterm.delay = 1;
+ }
+ }
+ return (OK);
+ }
+
+ /* Get rid of any old raster. */
+ GtDestroyRaster (w, raster);
+
+ rp->width = width;
+ rp->height = height;
+ rp->depth = depth;
+ rp->delete = 1;
+
+ /* Cache the raster? */
+ if (strcmp (w->gterm.cacheRasters, "always") == 0)
+ cache = 1;
+ else if (strcmp (w->gterm.cacheRasters, "never") == 0)
+ cache = 0;
+ else
+ cache = (type == GtServer);
+
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "GtCreateRaster: cacheRasters = '%s' type=%s cache=%d\n",
+ w->gterm.cacheRasters, (type == GtServer ? "GtServer" : "GtClient"),
+ cache);
+ fprintf (stderr,"GtCreateRaster: cache=%d (%dx%dx%d)\n",
+ cache, width, height, depth);
+ fprintf (stderr,"GtCreateRaster: Creating %s: %d\n",
+ (cache ? "PIXMAPRASTER" : "IMAGERASTER"), raster);
+ }
+
+ /* Create new raster. */
+ if (cache) {
+ /* Create a pixmap. */
+ rp->type = PixmapRaster;
+ rp->depth = depth;
+ rp->r.pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ width, height, depth);
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster: [pixmap] creating shadow pixmap %dx%d\n",
+ w->core.width+1, w->core.height+1);
+
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width+1, w->core.height+1, RasterDepth);
+
+ if (rp->r.pixmap == (Pixmap) NULL)
+ goto ximage;
+
+ XFillRectangle (w->gterm.display, rp->r.pixmap,
+ (depth == RasterDepth ? w->gterm.clear8GC : w->gterm.clearGC),
+ 0, 0, width, height);
+
+ } else {
+ /* Create an XImage for the raster.
+ */
+ximage:
+ rp->type = ImageRaster;
+ rp->depth = depth;
+
+ /* Get pixel storage.
+ */
+ if ((data = (uchar *) XtMalloc((npix=width*height))) == NULL)
+ return (ERR);
+ else {
+ for (op=data, pixel=w->gterm.color0; --npix >= 0; )
+ *op++ = pixel;
+ }
+
+ /* The following doesn't yet deal properly with byte and bit ordering
+ * differences between the server and client.
+ */
+ rp->r.ximage = xp = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, width, height, 8, 0);
+ if (xp == NULL) {
+ rp->type = 0;
+ return (ERR);
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtCreateRaster: [ximage] creating shadow pixmap %dx%d\n",
+ w->core.width+1, w->core.height+1);
+
+ rp->shadow_pixmap = XCreatePixmap (w->gterm.display, w->gterm.window,
+ w->core.width+1, w->core.height+1, RasterDepth);
+ }
+
+ w->gterm.nrasters++;
+
+ if (DBG_TRACE) {
+ int i;
+
+ fprintf (stderr, "GtCreateRaster: LEAVING nraster=%d\n",
+ w->gterm.nrasters);
+
+ for (i=0; i < w->gterm.nrasters; i++)
+ fprintf (stderr, "GtCreateRaster[%d]: type=%8s %dx%d [%d]\n",
+ i,
+ (w->gterm.rasters[i].type==GtClient)?"GtClient":"GtServer",
+ w->gterm.rasters[i].width, w->gterm.rasters[i].height,
+ w->gterm.rasters[i].depth);
+ }
+ return (OK);
+}
+
+
+/* GtDestroyRaster -- Destroy a raster. Any mappings which reference the
+ * raster are deactivated, and all storage associated with the raster is freed.
+ */
+GtDestroyRaster (w, raster)
+ GtermWidget w;
+ int raster;
+{
+ register Raster rp;
+ register Mapping mp, next;
+
+ if (raster <= 0)
+ return;
+
+ invalidate_draw_context (w);
+
+ /* Disable any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = next) {
+ next = mp->next;
+ if (mp->src == raster || mp->dst == raster)
+ free_mapping (w, mp);
+ }
+
+ /* Destroy the raster. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (rp->delete) {
+ if (rp->type == ImageRaster)
+ XDestroyImage (rp->r.ximage);
+ else if (rp->type == PixmapRaster)
+ XFreePixmap (w->gterm.display, rp->r.pixmap);
+ }
+ w->gterm.nrasters--;
+ rp->type = 0;
+ rp->delete = 0;
+ }
+}
+
+
+/* GtQueryRaster -- Determine whether a raster exists and if so return its
+ * size.
+ */
+GtQueryRaster (w, raster, type, width, height, depth)
+ GtermWidget w;
+ int raster; /* one-indexed */
+ int *type;
+ int *width, *height;
+ int *depth;
+{
+ register Raster rp;
+
+
+ if (DBG_TRACE && DBG_VERBOSE)
+ fprintf (stderr, "GtQueryRaster: raster=%d\n", raster);
+
+ if (raster < 0 || raster > w->gterm.maxRasters)
+ return (0);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type) {
+ if (type) {
+ if (rp->type == PixmapRaster)
+ *type = GtServer;
+ else
+ *type = GtClient;
+ }
+ if (width)
+ *width = rp->width;
+ if (height)
+ *height = rp->height;
+ if (depth)
+ *depth = rp->depth;
+
+ if (DBG_TRACE && DBG_VERBOSE)
+ fprintf (stderr, "GtQueryRaster: raster=%d (%s) w=%d h=%d d=%d\n",
+ raster,
+ ((*type == PixmapRaster) ? "GtServer" : "GtClient"),
+ *width, *height, *depth);
+
+
+ return (1);
+ } else
+ return (0);
+}
+
+
+/* GtWritePixels -- Write to a rectangular region of a raster. If any
+ * mappings are currently defined which reference this raster as the source,
+ * and a mapped region is being rewritten, the affected pixels will be
+ * refreshed by the mapping.
+ */
+GtWritePixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int i, n, bytes_per_line;
+ Mapping mp;
+ Raster rp;
+ uchar *lp;
+ XWindowAttributes wa;
+ unsigned int *ras = NULL;
+
+
+ rp = &w->gterm.rasters[raster];
+
+ if (DBG_TRACE)
+ fprintf(stderr,
+ "GtWritePixels[%s] ENTER: nbits=%d raster=%d type='%s' wa=0x%x\n",
+ dbg_wSize(w), nbits, raster,
+ (rp->type == PixmapRaster) ? "PixmapRaster" : "ImageRaster",
+ w->gterm.wa);
+
+
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ if (!w->gterm.wa_defined) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa)) {
+ fprintf (stderr, "GtWritePixels: Error getting window attrs\n");
+ return (ERR);
+ }
+ } else
+ wa = w->gterm.wa;
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWritePixels: window depth=%d RasterDepth= %d class=%s\n",
+ wa.depth, RasterDepth, dbg_visStr(wa.visual->class));
+
+
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ XImage *ximage;
+ uchar *data;
+ int npix;
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Doing PixmapRaster[%s]....depth=%d\n",
+ dbg_wSize(w), wa.depth);
+
+ /* Get a data buffer. */
+ if ((data = (uchar *)XtMalloc (npix = nx * ny)) == NULL)
+ return (ERR);
+
+ /* Convert the pixel values to colormap indices. */
+ cmap = get_cmap_in (w);
+ for (ip=pixels, op=data, n=npix; --n >= 0; ) {
+
+ /* In TrueColor mode, we preserve the index values in the
+ ** XImage and apply the colormap when rendering.
+ */
+ *op++ = (wa.depth == ColormapDepth ?
+ (cmap[*ip++] & 0377) : ((*ip++) & 0377));
+ }
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: Creating 8-bit ximage\n");
+
+ ximage = XCreateImage (w->gterm.display, NULL, RasterDepth,
+ ZPixmap, 0, (char *)data, nx, ny, 8, 0);
+
+
+ if (raster == 0 && w->gterm.pixmap) {
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePix: type = pixmap, raster=0\n");
+
+ XPutImage (display, w->gterm.pixmap, w->gterm.exposeGC,
+ IMGtoGPM(w,ximage,0,0,nx,ny),
+ 0, 0, x1, y1, nx, ny);
+
+ XCopyArea (display,
+ GPMtoRPM(w, rp), rp->r.pixmap,
+ w->gterm.exposeGC, x1, y1, nx, ny, x1, y1);
+
+ } else {
+ XPutImage (display, rp->r.pixmap, w->gterm.exposeGC,
+ IMGtoRPM (w,ximage,rp,0,0,nx,ny),
+ 0, 0, x1, y1, nx, ny);
+ }
+
+ XtFree ((char *)data);
+ ximage->data = NULL;
+ XDestroyImage (ximage);
+
+ } else if (rp->type == ImageRaster) {
+ int min=256, max=0;
+ int min1=256, max1=0;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWritePix: ImageRaster....bytes_per_line=%d ras depth=%d\n",
+ rp->r.ximage->bytes_per_line, rp->r.ximage->depth);
+
+ cmap = get_cmap_in (w);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+ ip = pixels;
+
+ if (DBG_TRACE)
+ fprintf(stderr,
+ "GtWritePix: Doing ColormapDepth....writing to ximage\n");
+
+ /* Copy the data into the ximage data raster, converting input
+ * pixels to Xlib pixel values in the process.
+ *
+ * Possibly this should be done at Pixmap write time rather than
+ * during raster i/o so that the image pixel values are preserved.
+ * Otherwise reading back pixels is difficult and if the color map
+ * is dynamically modified the original pixel values may be lost.
+ * Postponing display pixel value generation would also make it
+ * easy to add support later for image depths other than 8 bit.
+ * Doing the conversion to display pixels here is however simpler
+ * and more efficient so that is how we do it for now.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; ) {
+ if (wa.depth == ColormapDepth)
+ *op++ = (cmap[*ip++] & 0xFF);
+ else
+ *op++ = (*ip++ & 0xFF);
+
+ if (DBG_TRACE) {
+ if (*ip < min) min = *ip;
+ if (*ip > max) max = *ip;
+ if (cmap[*ip] < min1) min1 = cmap[*ip];
+ if (cmap[*ip] > max1) max1 = cmap[*ip];
+ }
+ }
+ lp += bytes_per_line;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "CMAP MINMAX: %d %d -- %d %d\n", min, max, min1, max1);
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (wa.depth != ColormapDepth) { /* FIXME */
+ update_mapping (w, mp);
+ refresh_source (w, mp, x1, y1, nx, ny);
+ /* break; */
+
+ } else if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtWritePixels[%s] LEAVING....\n", dbg_wSize(w));
+
+ return (OK);
+}
+
+
+/* GtReadPixels -- Read a rectangular region of a raster.
+ */
+GtReadPixels (w, raster, pixels, nbits, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ uchar *pixels;
+ int nbits; /* not used */
+ int x1, y1;
+ int nx, ny;
+{
+ register uchar *ip, *op;
+ register Pixel *cmap;
+ register int n;
+
+ int bytes_per_line, i, nskip = 1;
+ int x, y, delxin = 0;
+ XImage *xin;
+ Raster rp;
+ uchar *lp;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadPixels: ras=%d %d %d %d %d w->depth=%d\n",
+ raster, x1, y1, nx, ny, w->gterm.w_depth);
+
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Perform some range checks. */
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+
+ /* Get the input ximage.
+ if (rp->type == PixmapRaster) {
+ */
+ if (rp->type == PixmapRaster || (raster == 0 && w->gterm.w_depth > 8)) {
+
+ Display *display = w->gterm.display;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadPixels: rp->type == PixmapRaster [%d]\n",
+ raster);
+
+ /* Read the pixmap subraster into an ximage. If we are reading the
+ * screen (raster == 0) and we have an off-screen backing store pixmap,
+ * use that instead of the screen.
+ */
+ if (w->gterm.w_depth > ColormapDepth) {
+ Raster ras = (Raster) NULL;
+
+ if (raster)
+ ras = &w->gterm.rasters[w->gterm.d_raster];
+ else
+ ras = &w->gterm.rasters[0];
+
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ?
+ ras->shadow_pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+
+ } else {
+ xin = XGetImage (display,
+ (raster == 0 && w->gterm.pixmap) ?
+ w->gterm.pixmap : rp->r.pixmap,
+ x1, y1, nx, ny, 0xff, ZPixmap);
+ }
+
+ if (xin == NULL)
+ return (ERR);
+
+ delxin++;
+ x = y = 0;
+
+ } else {
+ xin = rp->r.ximage;
+ x = x1;
+ y = y1;
+ }
+ nskip = xin->bits_per_pixel / 8;
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtReadPixels: xin->bpp=%d bpl=%d nskip=%d %d,%d %dx%d\n",
+ xin->bits_per_pixel, xin->bytes_per_line, nskip,
+ x1, y1, nx, ny);
+
+ if (w->gterm.w_depth == ColormapDepth)
+ cmap = get_cmap_out (w);
+ bytes_per_line = xin->bytes_per_line;
+ lp = (uchar *)xin->data + (y * bytes_per_line + (nskip * x));
+ op = pixels;
+
+ /* Copy the data to the output buffer, converting display pixels to
+ * client pixels in the process.
+ */
+ for (i=0; i < ny; i++) {
+ for (n=nx, ip=lp; --n >= 0; ) {
+ if (w->gterm.w_depth == ColormapDepth) {
+ *op++ = cmap[*ip];
+ } else {
+ *op++ = *ip;
+ }
+ ip += nskip;
+ }
+ lp += bytes_per_line;
+ }
+
+ if (delxin)
+ XDestroyImage (xin);
+ return (OK);
+}
+
+
+/* GtSetPixels -- Set all the raster pixels in a region to a single color.
+ * If nx=ny=0 the entire raster will be written.
+ */
+GtSetPixels (w, raster, ct, x1, y1, nx, ny, color, rop)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+ int color;
+ int rop;
+{
+ register Raster rp;
+ Mapping mp;
+
+ /* Get raster pointer. */
+ rp = &w->gterm.rasters[raster];
+ if (rp->type == 0)
+ return (ERR);
+
+ /* Get pixel coordinates. */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ raster, ct, x1,y1,nx,ny);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+ }
+
+ /* Perform some range checks. */
+ if (x1 == 0 && y1 == 0 && nx == 0 && ny == 0) {
+ nx = rp->width;
+ ny = rp->height;
+ } else {
+ if (x1 < 0 || x1 > rp->width || nx <= 0 || x1+nx > rp->width)
+ return (ERR);
+ if (y1 < 0 || y1 > rp->height || ny <= 0 || y1+ny > rp->height)
+ return (ERR);
+ }
+
+ /* Set the pixels.
+ */
+ if (rp->type == PixmapRaster) {
+ Display *display = w->gterm.display;
+ GC gc = w->gterm.clearGC;
+ int use_backing_store;
+ Raster sp = &w->gterm.rasters[0];
+
+ use_backing_store =
+ (raster == 0 && w->gterm.pixmap && !(rop & R_Transient));
+
+
+ XSetForeground (display, gc, get_pixel(w,color));
+ XFillRectangle (display, rp->r.pixmap, gc, x1, y1, nx, ny);
+ if (use_backing_store) {
+ XFillRectangle (display, w->gterm.pixmap, gc, x1, y1, nx, ny);
+ XFillRectangle (display, sp->shadow_pixmap, w->gterm.clear8GC,
+ x1, y1, nx, ny);
+ }
+ XSetForeground (display, gc, w->gterm.color0);
+
+ } else {
+ register int n, i;
+ register uchar *op;
+ register Pixel pixel;
+ int bytes_per_line;
+ uchar *lp;
+
+ pixel = get_pixel (w, color);
+ bytes_per_line = rp->r.ximage->bytes_per_line;
+ lp = (uchar *)rp->r.ximage->data + y1 * bytes_per_line + x1;
+
+ /* Set all pixels in the indicated region. */
+ for (i=0; i < ny; i++) {
+ for (n=nx, op=lp; --n >= 0; )
+ *op++ = pixel;
+ lp += bytes_per_line;
+ }
+ }
+
+ /* Execute any mappings that reference this raster. */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ return (OK);
+}
+
+
+/* GtRefreshPixels -- Update any mappings defined upon the given region of
+ * the given source raster, as if the pixel values had been set with a
+ * write pixels call.
+ */
+GtRefreshPixels (w, raster, ct, x1, y1, nx, ny)
+ GtermWidget w;
+ int raster;
+ int ct;
+ int x1, y1;
+ int nx, ny;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register Mapping mp;
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: ENTER\n");
+
+ /* Get pixel coordinates.
+ */
+ if (ct != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp);
+ save_mapping (&sv_mp, 0, 0,
+ raster, ct, x1,y1,nx,ny,
+ 0, GtPixel, 0,0,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.sx;
+ y1 = p_mp.sy;
+ nx = p_mp.snx;
+ ny = p_mp.sny;
+ }
+
+ /* Execute any mappings that reference this raster.
+ */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: mp=0x%x enabled=%d src=%d/%d\n",
+ mp, mp->enabled, mp->src, raster);
+
+ if (mp->enabled && mp->src == raster) {
+ struct mapping *map=mp, p_mp;
+
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtRefreshPixels: update pixtype raster\n");
+
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtRefreshPixels: update non-pix raster\n");
+
+ update_mapping (w, map);
+ }
+
+ refresh_source (w, map, x1, y1, nx, ny);
+ if (map == &p_mp)
+ free_mapping (w, map);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtRefreshPixels: LEAVING\n");
+}
+
+
+/* GtExtractPixmap -- Extract a rectangular region of a raster and return
+ * as a pixmap. The caller is responsible for later deleting this pixmap.
+ */
+Pixmap
+GtExtractPixmap (w, src, ctype, x, y, width, height)
+ GtermWidget w;
+ int src;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ int x1, y1, nx, ny;
+ String cache;
+ int i;
+
+ rp = &w->gterm.rasters[src];
+ if (!rp->type)
+ return ((Pixmap)NULL);
+
+ /* If width and height are zero, return the full raster. */
+ if (width <= 0)
+ width = rp->width;
+ if (height <= 0)
+ height = rp->height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0,0,0,0,
+ src, ctype, x,y,width,height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Find any empty raster slot and use it to generate the output pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ cache = w->gterm.cacheRasters;
+ w->gterm.cacheRasters = "always";
+
+ if (GtCreateRaster (w, i, GtServer, nx, ny, /* MF006 */
+ RasterDepth) == ERR) {
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+
+ } else if (rp->type != PixmapRaster)
+ goto err;
+
+ if (GtCopyRaster (w, 0,
+ src,0, x1,y1,nx,ny, i,0, 0,0,nx,ny) == ERR) {
+err:
+ GtDestroyRaster (w, i); /* MF005 */
+ w->gterm.cacheRasters = cache;
+ return ((Pixmap)NULL);
+ }
+
+ rp->type = 0;
+ w->gterm.nrasters--;
+ w->gterm.cacheRasters = cache;
+
+ return (rp->r.pixmap);
+ }
+ }
+
+ return ((Pixmap)NULL);
+}
+
+
+/* GtInsertPixmap -- Insert the contents of the given pixmap into a raster
+ * at the indicated coordinates.
+ */
+GtInsertPixmap (w, pixmap, dst, ctype, x, y, width, height)
+ GtermWidget w;
+ Pixmap pixmap;
+ int dst;
+ int ctype;
+ int x, y;
+ int width, height;
+{
+ register Raster rp;
+ XWindowAttributes wa;
+ int x1, y1, nx, ny;
+ int i;
+
+ /* Check that the pixmap exists. */
+ if (!XGetWindowAttributes (w->gterm.display, pixmap, &wa))
+ return (ERR);
+
+ /* Default to full dimensions of pixmap if no dimensions given. */
+ if (width <= 0)
+ width = wa.width;
+ if (height <= 0)
+ height = wa.height;
+
+ /* Get pixel coordinates. */
+ if (ctype != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, GtPixel, 0, 0, 0, 0,
+ dst, ctype, x, y, width, height);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ x1 = p_mp.dx;
+ y1 = p_mp.dy;
+ nx = p_mp.dnx;
+ ny = p_mp.dny;
+
+ } else {
+ x1 = x;
+ y1 = y;
+ nx = width;
+ ny = height;
+ }
+
+ /* Create the destination raster if none exists. */
+ if (!w->gterm.rasters[dst].type)
+ if (GtCreateRaster (w, dst, GtDefault, nx, ny, /* MF006 */
+ RasterDepth) == ERR)
+ return (ERR);
+
+ /* Find an empty raster slot and use it to build a fake source raster
+ * using the supplied pixmap.
+ */
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type) {
+ rp->type = PixmapRaster;
+ rp->width = nx;
+ rp->height = ny;
+ rp->r.pixmap = pixmap;
+
+ if (GtCopyRaster (w, 0,
+ i,0, 0,0,nx,ny, dst,0, x1,y1,nx,ny) < 0)
+ return (ERR);
+
+ rp->type = 0;
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtWriteColormap -- Allocate or modify colormap cells. The Gterm widget
+ * colormap consists of a fixed number of preassigned, read-only color cells,
+ * plus a variable number of dynamically allocated application defined color
+ * cells. The application sees only the preassigned pixel space 0-N where
+ * N is the maximum pixel value. These values are mapped to Xlib pixel values
+ * by the CMAP vector in the main Gterm widget descriptor. The server
+ * colormap does the final mapping to RGB triplets.
+ *
+ * Our strategy here is as follows. If we have a monochrome screen set up a
+ * one-to-one fake colormap so that we preserve the input pixel values and
+ * render a one-bit image later. If we have a StaticGray or StaticColor
+ * visual allocate read-only color cells to allow X to choose the closest
+ * colors to what we request. If we have a GrayScale or PseudoColor visual
+ * allocate private read-write colors. The TrueColor and DirectColor
+ * visuals should not be seen here as we should have been able to set up the
+ * PseudoColor visual on screens that support these visuals, but if they are
+ * seen use a one-to-one mapping to preserve the 8 bit pixel values.
+ */
+GtWriteColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ XWindowAttributes wa;
+ register XColor *cp;
+ register int i, j, v, n, use_wa = 1;
+ unsigned long plane_masks[1];
+ int req, need, ncolors;
+
+ Colormap colormap;
+
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (ERR);
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtWriteColormap: ENTER.....\n");
+ fprintf (stderr,
+ "GtWriteColormap: map=%d first=%d nelem=%d gt.ncols=%d\n",
+ map, first, nelem, w->gterm.ncolors);
+ }
+
+ if (map > 0) {
+ /* Create or modify a colormap descriptor. The display colormap
+ * is not affected.
+ */
+ register struct colormap *cm;
+ struct colormap *last_cm;
+ register XColor *cp;
+ register int i;
+
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: create/modify map = %d\n", map);
+
+ /* See if the colormap already exists.
+ */
+ for (cm = w->gterm.colormaps, last_cm = NULL; cm; cm = cm->next) {
+ last_cm = cm;
+ if (cm->map == map)
+ break;
+ }
+
+ /* If not, create it.
+ */
+ if (!cm) {
+ if (!(cm = (struct colormap *)XtCalloc(1,sizeof(struct colormap))))
+ return (ERR);
+ if (last_cm)
+ last_cm->next = cm;
+ else
+ w->gterm.colormaps = cm;
+
+ /* Initialize static part of colormap. */
+ for (i=0; i < SZ_STATIC_CMAP; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+ }
+
+ cm->map = map;
+ cm->ncells = max (cm->ncells, first + nelem);
+
+ /* Ignore attempts to overwrite static part of colormap.
+ */
+ for ( ; first < SZ_STATIC_CMAP; first++, nelem--) {
+ r++; g++; b++;
+ }
+
+ if (nelem >= 0) {
+ memmove (&cm->r[first], r, nelem * sizeof (ushort));
+ memmove (&cm->g[first], g, nelem * sizeof (ushort));
+ memmove (&cm->b[first], b, nelem * sizeof (ushort));
+ }
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: map=%d -- RETURNING\n",map);
+
+ return (OK);
+ }
+
+ /* Write to the display colormap.
+ */
+ if (first < SZ_STATIC_CMAP || first + nelem > MAX_SZCMAP)
+ return (ERR);
+
+ /* Invalidate the cmap cache.
+ */
+ invalidate_cmap (w);
+
+ /* Get the window attributes. We need to do this to determine the type
+ * of visual used for the window, which determines our color allocation
+ * strategy. This is only done once since presumably the visual and
+ * window depth will not change after the widget has been around long
+ * enough to receive a GtWriteColormap call.
+ */
+ if (w->gterm.w_depth == 0 && w->gterm.w_visual_class == 0) {
+ if (!XGetWindowAttributes (w->gterm.display, w->gterm.window, &wa))
+ return (ERR);
+ w->gterm.wa = wa;
+ w->gterm.wa_defined++;
+
+ if (wa.depth == 1)
+ goto unitary;
+ } else
+ use_wa = 0;
+
+
+ switch ((use_wa ? wa.visual->class : w->gterm.w_visual_class)) {
+ case StaticGray:
+ case StaticColor:
+ /* Allocate "best-match" colors. */
+ for (i=first; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = r[i-first];
+ cp->green = g[i-first];
+ cp->blue = b[i-first];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ if (XAllocColor (w->gterm.display, wa.colormap, cp)) {
+ w->gterm.cmap[i] = cp->pixel;
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ }
+ }
+ break;
+
+ case GrayScale:
+ case PseudoColor:
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: PSEUDOCOLOR vis, defCM=%d, gt.ncols=%d\n",
+ w->gterm.useDefaultCM, w->gterm.ncolors);
+
+ if (w->gterm.useDefaultCM) {
+usedef: /* Allocate private r/w colors from default colormap. */
+ need = first + nelem - w->gterm.ncolors;
+
+ /* Allocate new color cells if needed. If we can't allocate all
+ * the requested cells the unallocated pixel values are set to
+ * black.
+ */
+ if ((n = need) > 0) {
+ /* Get the colormap cells. */
+ req = min(w->gterm.maxColors, first + nelem - SZ_STATIC_CMAP) -
+ (w->gterm.ncolors - SZ_STATIC_CMAP);
+ for (n=0; req > 0 && n < need; )
+ if (XAllocColorCells (w->gterm.display, wa.colormap,
+ False, plane_masks, 0,
+ &w->gterm.cmap[w->gterm.ncolors+n], req)) {
+ n += req;
+ } else
+ req /= 2;
+
+ /* Initialize the color descriptors. */
+ for (i = w->gterm.ncolors; i < first+nelem; i++) {
+ cp = &w->gterm.color[i];
+ if (i < w->gterm.ncolors + n) {
+ cp->pixel = w->gterm.cmap[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+ } else {
+ w->gterm.cmap[i] = cp->pixel =
+ BlackPixelOfScreen (w->gterm.screen);
+ cp->flags = 0;
+ }
+ }
+ w->gterm.ncolors += n;
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: PSEUDOCOLOR defCM, need=%d gt.ncols=%d\n",
+ need, w->gterm.ncolors);
+
+ /* Assign RGB colors to the referenced cells. */
+ for (i=0; i < nelem; i++) {
+ cp = &w->gterm.color[first+i];
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ }
+
+ n = w->gterm.ncolors - first;
+ if (n > 0)
+ XStoreColors (w->gterm.display, wa.colormap,
+ &w->gterm.color[first], n);
+
+ } else {
+ /* Allocate colors in a custom colormap. If the named colormap
+ * does not yet exist we create one. Multiple gterm widget
+ * instances may share the same colormap.
+ */
+ long timeval, time();
+ int shadow;
+
+
+ /* get_colormap will direct us to the default colormap if the
+ * custom colormap cannot be accessed or created.
+ */
+ colormap = get_colormap (w);
+ if (w->gterm.useDefaultCM)
+ goto usedef;
+
+ /* Assign RGB colors to the referenced cells. */
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ if (DBG_TRACE) {
+ fprintf (stderr, "GtWriteColormap: PSEUDOCOLOR custom cmap\n");
+ fprintf (stderr,
+ "GtWriteColormap: Pseudo: first=%d nelem=%d -> ncols=%d/%d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+ }
+
+ for (i=0; i < ncolors; i++, cp++) {
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,
+ "GtWriteColormap: Pseudo: %3d (%3d %3d %3d) %d / %d\n",
+ i, r[i]>>8,g[i]>>8,b[i]>>8, w->gterm.ncolors, ncolors);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: first=%d nelem=%d ncol=%d %d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+
+ /* Store the new colors. */
+ if (ncolors > 0)
+ XStoreColors (w->gterm.display,
+ colormap, &w->gterm.color[first], ncolors);
+
+ /* Also attempt to store the colors in the default colortable,
+ * by allocating, writing, and then deallocating cells. This
+ * helps keeps the gterm window visible when the default
+ * colormap is loaded. To avoid excessive server queries the
+ * default colormap is only updated every so often. Updating is
+ * disabled if cmapShadow is set to zero. If shadowing is
+ * enabled the update is always performed if the WriteColormap
+ * occurs when the pointer is not in the window (e.g., when a
+ * button elsewhere in the GUI is pressed) as otherwise the
+ * change will not be visible as the private colormap will not
+ * be loaded by the window manager.
+ */
+ shadow = w->gterm.cmapShadow;
+ timeval = time((long *)NULL);
+
+ if (shadow && (!w->gterm.in_window ||
+ (timeval - w->gterm.cmapLastShadow > shadow * 1000))) {
+ update_default_colormap (w);
+ w->gterm.cmapLastShadow = timeval;
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: PSEUDOCOLOR DONE\n");
+ break;
+
+ default:
+ /* Set up a unitary, or one-to-one mapping, to preserve the input
+ * pixel values so that we can render them later.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "GtWriteColormap: visual default case\n");
+
+unitary:
+ colormap = get_colormap (w);
+
+ if ((first+nelem) > MAX_SZCMAP)
+ break;
+
+ if (w->gterm.useGlobalCmap)
+ break;
+
+ first = SZ_STATIC_CMAP;
+ ncolors = min (w->gterm.maxColors, nelem);
+ cp = &w->gterm.color[first];
+
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtWriteColormap: unitary: first=%d nelem=%d -> ncolors=%d/%d\n",
+ first, nelem, ncolors, w->gterm.ncolors);
+
+ for (i = 0; i < ncolors; i++, cp++) {
+ w->gterm.cmap[i] = i;
+ cp->pixel = i;
+ cp->red = r[i];
+ cp->green = g[i];
+ cp->blue = b[i];
+ cp->flags = (DoRed | DoGreen | DoBlue);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,
+ "GtWriteColormap: True: %3d: (%3d, %3d, %3d) %d / %d\n",
+ i, r[i]>>8, g[i]>>8, b[i]>>8, w->gterm.ncolors, ncolors);
+
+ if (i+1 > w->gterm.ncolors)
+ w->gterm.ncolors = i + 1;
+ }
+
+ if (DBG_TRACE) {
+ fprintf (stderr,
+ "GtWriteColormap: map=%d first=%d nelem=%d ncol=%d %d\n",
+ map, first, nelem, ncolors, w->gterm.ncolors);
+ fprintf (stderr, "GtWriteColormap: TRUECOLOR DONE\n");
+ }
+
+ break;
+ }
+
+
+ if (DBG_TRACE) {
+ dbg_printCmaps (w);
+ fprintf (stderr, "GtWriteColormap: LEAVING\n");
+ }
+
+ return (OK);
+}
+
+
+/* GtReadColormap -- Return the color assignments for a region of the named
+ * colormap.
+ */
+GtReadColormap (w, map, first, nelem, r, g, b)
+ GtermWidget w;
+ int map;
+ int first;
+ int nelem;
+ ushort *r, *g, *b;
+{
+ register int i;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadColormap: ENTER map=%d first=%d nelem=%d\n",
+ map, first, nelem);
+
+ if (w->gterm.useGlobalCmap) {
+ for (i=0; i < MAX_SZCMAP; i++) {
+ r[i] = global_color[i].red;
+ g[i] = global_color[i].green;
+ b[i] = global_color[i].blue;
+ }
+ return (SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP);
+ }
+
+
+ /* Clear the output colormap.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) r[i] = g[i] = b[i] = 0;
+
+ if (map > 0) {
+ /* Read from a colormap descriptor.
+ */
+ register struct colormap *cm;
+ register int i, j;
+
+ /* Locate colormap. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ j = first + i;
+ if (j < cm->ncells) {
+ r[i] = cm->r[j];
+ g[i] = cm->g[j];
+ b[i] = cm->b[j];
+ } else
+ break;
+ }
+
+ return (i);
+
+ } else {
+ /* Read the display colormap.
+ */
+ register XColor *cp;
+
+ /* Return RGB values. */
+ for (i=0; i < nelem; i++) {
+ if (first+i < w->gterm.ncolors) {
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "GtReadColormap: %3d %3d %3d %3d\t",
+ first+i, r[i]>>8, g[i]>>8, b[i]>>8);
+
+ cp = &w->gterm.color[first+i];
+ r[i] = (ushort) cp->red;
+ g[i] = (ushort) cp->green;
+ b[i] = (ushort) cp->blue;
+ } else
+ break;
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr,"%3d\t%3d %3d %3d\n",i,r[i]>>8,g[i]>>8,b[i]>>8);
+ }
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtReadColormap: LEAVING ncolors=%d\n", i);
+ return (i);
+ }
+}
+
+
+/* GtLoadColormap -- Load a colormap into the display, optionally scaling
+ * the colormap via a linear transformation in the process. The colormap is
+ * unaffected if offset=0.5, scale=1.0. A negative scale inverts the image.
+ * If map=0 the linear transformation is applied directly to the display
+ * colormap.
+ *
+ * The offset refers to the center of the mapped region of the transfer
+ * function, which is why the center value is at 0.5. For example, if the
+ * range of raster pixel intensities is normalized to the range 0.0 to 1.0,
+ * then a transfer function of [offset=0.3,slope=3.0] will display the region
+ * of intenstities centered around the normalized intenstity of 0.3, with a
+ * contrast of 3.0 (the screen intensity changes 3 units for a unit change in
+ * raster pixel intensity). The transfer function [offset=0.3,slope=-3.0]
+ * will display the same range of pixel intensitites, but with a negative
+ * contrast. The transfer function [offset=0.5,slope=1.0] has intercepts
+ * of [0,0] and [1,1] hence it displays the full range of raster pixel
+ * intensities - the input colormap is used as is, without resampling.
+ */
+GtLoadColormap (w, map, offset, slope)
+ GtermWidget w;
+ int map;
+ float offset, slope;
+{
+ register int i;
+ register XColor *cp;
+ register struct colormap *cm;
+ struct colormap d_cmap, o_cmap;
+ int noscale, nelem, c1, c2;
+ float x, y, z, frac;
+ ushort r, g, b;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: map=%d offset=%f slope=%f\n",
+ map, offset, slope);
+
+ /* Get the colormap to be loaded.
+ */
+ if (map == 0) {
+ /* Create a dummy colormap struct from the screen colormap.
+ */
+dummy:
+ cm = &d_cmap;
+ cm->map = 0;
+ cm->next = NULL;
+ cm->ncells = w->gterm.ncolors;
+ for (i=0; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cm->r[i] = cp->red;
+ cm->g[i] = cp->green;
+ cm->b[i] = cp->blue;
+ }
+
+ } else {
+ /* Locate colormap.
+ */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: map=%d/%d cm=0x%x ncells=%d\n",
+ map, cm->map, cm, cm->ncells);
+
+ if (!cm)
+ return (ERR);
+ }
+
+ /* Compute the scaled colormap. Only the dynamic part of the colormap
+ ** is scaled, the static cells are not affected.
+ */
+ o_cmap.map = 0;
+ o_cmap.ncells = cm->ncells;
+ if (w->gterm.useGlobalCmap)
+ nelem = SZ_DYNAMIC_CMAP;
+ else
+ nelem = cm->ncells - SZ_STATIC_CMAP;
+ noscale = (abs(offset - 0.5) < 0.0001 && abs(slope - 1.0) < 0.0001);
+
+ if (noscale) {
+ for (i=0; i < nelem; i++) {
+ o_cmap.r[i] = cm->r[SZ_STATIC_CMAP+i];
+ o_cmap.g[i] = cm->g[SZ_STATIC_CMAP+i];
+ o_cmap.b[i] = cm->b[SZ_STATIC_CMAP+i];
+ }
+ } else {
+ if (DBG_TRACE)
+ fprintf (stderr,"GtLoadColormap: scaling cmap; nelem=%d\n", nelem);
+
+ for (i=0; i < nelem; i++) {
+ x = (float)i / (float)(nelem - 1);
+ y = (x - offset) * slope + 0.5;
+
+ if (y <= 0.0) {
+ r = cm->r[SZ_STATIC_CMAP];
+ g = cm->g[SZ_STATIC_CMAP];
+ b = cm->b[SZ_STATIC_CMAP];
+ } else if (y >= 1.0) {
+ r = cm->r[cm->ncells-1];
+ g = cm->g[cm->ncells-1];
+ b = cm->b[cm->ncells-1];
+ } else {
+ z = y * (nelem - 1) + SZ_STATIC_CMAP;
+ if (w->gterm.cmapInterpolate) {
+ c1 = (int)z;
+ c2 = min (cm->ncells-1, c1 + 1);
+ frac = z - c1;
+ r = cm->r[c1] * (1.0 - frac) + cm->r[c2] * frac;
+ g = cm->g[c1] * (1.0 - frac) + cm->g[c2] * frac;
+ b = cm->b[c1] * (1.0 - frac) + cm->b[c2] * frac;
+ } else {
+ c1 = (int)z;
+ r = cm->r[c1];
+ g = cm->g[c1];
+ b = cm->b[c1];
+ }
+ }
+
+ o_cmap.r[i] = r;
+ o_cmap.g[i] = g;
+ o_cmap.b[i] = b;
+ }
+ }
+
+ if (w->gterm.useGlobalCmap) {
+ for (i=0; i < nelem; i++) {
+ global_color[i+SZ_STATIC_CMAP].red = o_cmap.r[i];
+ global_color[i+SZ_STATIC_CMAP].green = o_cmap.g[i];
+ global_color[i+SZ_STATIC_CMAP].blue = o_cmap.b[i];
+ }
+ global_color[i+SZ_STATIC_CMAP-1].red = o_cmap.r[i] = o_cmap.r[i-2];
+ global_color[i+SZ_STATIC_CMAP-1].green = o_cmap.g[i] = o_cmap.g[i-2];
+ global_color[i+SZ_STATIC_CMAP-1].blue = o_cmap.b[i] = o_cmap.b[i-2];
+ nelem = SZ_DYNAMIC_CMAP;
+ valid_lut = 0;
+ }
+
+ /* Load the colormap into the display.
+ */
+ if (DBG_TRACE)
+ fprintf (stderr, "GtLoadColormap: loading colormap into display\n");
+ GtWriteColormap (w, 0, SZ_STATIC_CMAP, nelem,
+ o_cmap.r, o_cmap.g, o_cmap.b);
+
+
+ /* If the colormap we loaded to the display was the display colormap,
+ ** restore the original unscaled colors in the gterm descriptor so that
+ ** we won't be scaling a scaled colormap in the next operation.
+ */
+ if (map == 0) {
+ for (i=SZ_STATIC_CMAP; i < cm->ncells; i++) {
+ cp = &w->gterm.color[i];
+ cp->red = cm->r[i];
+ cp->green = cm->g[i];
+ cp->blue = cm->b[i];
+ }
+ }
+
+ if (w->gterm.useGlobalCmap) {
+ Mapping mp;
+
+ /* Execute any mappings that reference this raster.
+ */
+ for (mp = w->gterm.mp_head; mp; mp = mp->next) {
+ if (mp->enabled) {
+ struct mapping *map=mp, p_mp;
+
+ if (map->st != GtPixel || map->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, map, &p_mp, 1);
+ update_mapping (w, map = &p_mp);
+ } else
+ update_mapping (w, map);
+
+ if (colormap_focus > 0 && colormap_focus < mp->snx) {
+ /* If we're doing a focused update, refresh only the
+ ** central part of the main display.
+ */
+ int half = colormap_focus;
+ int full = ((half * 2 > 512) ? 512 : half * 2);
+
+ /* refresh_source (w, map,
+ mp->sx+(mp->snx/2 - 64), mp->sy+(mp->sny/2 - 64),
+ 128, 128); */
+
+ refresh_source (w, map,
+ mp->sx+(mp->snx/2 - half), mp->sy+(mp->sny/2 - half),
+ full, full);
+ } else {
+ refresh_source (w, map, mp->sx, mp->sy, mp->snx, mp->sny);
+ }
+
+ if (map == &p_mp)
+ free_mapping (w, map);
+
+ /* if (colormap_focus) break; */
+ }
+ }
+ }
+
+ return (OK);
+}
+
+GtSetColormapFocus (int box_size)
+{
+ if (box_size != 0)
+ colormap_focus = ((box_size > 0 && box_size < 64) ? 64 : box_size);
+}
+
+
+/* GtQueryColormap -- Return information on the size and state of a colormap.
+ */
+GtQueryColormap (w, map, first, nelem, maxelem)
+ register GtermWidget w;
+ int map;
+ int *first, *nelem, *maxelem;
+{
+ register struct colormap *cm;
+ int nitems;
+
+ if (first)
+ *first = SZ_STATIC_CMAP;
+ if (nelem)
+ *nelem = 0;
+ if (maxelem)
+ *maxelem = min (w->gterm.maxColors, MAX_SZCMAP) - SZ_STATIC_CMAP;
+
+ if (w->gterm.useGlobalCmap) {
+ *first = SZ_STATIC_CMAP;
+ *nelem = SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP;
+ *maxelem = SZ_STATIC_CMAP + SZ_DYNAMIC_CMAP + SZ_OVERLAY_CMAP;
+
+ } else if (map > 0) {
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map == map)
+ break;
+ if (!cm)
+ return (0);
+
+ if (nelem)
+ *nelem = cm->ncells - SZ_STATIC_CMAP;
+
+ } else {
+ if (nelem)
+ *nelem = w->gterm.ncolors - SZ_STATIC_CMAP;
+ if (maxelem) {
+ nitems = min (MAX_SZCMAP, CellsOfScreen(w->gterm.screen));
+ *maxelem = min (nitems,
+ min (w->gterm.maxColors, MAX_SZCMAP - w->gterm.base_pixel));
+ }
+
+ }
+ if (DBG_TRACE)
+ fprintf (stderr,
+ "GtQueryColormap: map=%d -> first=%d nelem=%d max=%d\n",
+ map, *first, *nelem, *maxelem);
+
+ return (1);
+}
+
+
+/* GtNextColormap -- Return a unique colormap number.
+ */
+GtNextColormap (w)
+ register GtermWidget w;
+{
+ register struct colormap *cm;
+ register int mapno = 0;
+
+ /* Get the next map number. */
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ if (cm->map > mapno)
+ mapno = cm->map;
+
+ return (mapno + 1);
+}
+
+
+/* GtFreeColormap -- Free a colormap descriptor.
+ */
+GtFreeColormap (w, colormap)
+ register GtermWidget w;
+ int colormap;
+{
+ register struct colormap *p_cm, *cm;
+
+ /* Find the colormap and free it. */
+ for (p_cm = NULL, cm = w->gterm.colormaps; cm; p_cm = cm, cm = cm->next)
+ if (cm->map == colormap) {
+ if (p_cm)
+ p_cm->next = cm->next;
+ else
+ w->gterm.colormaps = cm->next;
+ XtFree ((char *)cm);
+ return;
+ }
+}
+
+
+/* GtWriteIomap -- An iomap is an optional lookup table used to isolate the
+ * client application from the color model used within the Gterm widget.
+ * To simplify color allocation the Gterm widget defines a logical color
+ * space where color 0 is the background, 1 the foreground, 2-N are statically
+ * allocated standard colors, and colors N+1 and above are dynamically
+ * allocated by the graphics application. Less-demanding applications use
+ * only the statically allocated, shared colors. The widget internally maps
+ * these logical colors to whatever the window system requires, but providing
+ * a well-defined logical color space isolates the client from the details of
+ * color allocation in the underlying window system.
+ *
+ * An iomap can be used to define a mapping between the color model of the
+ * client application and the Gterm color model (when we say color model here
+ * we mean color allocation schemes for 8 bit pseudocolor). By default the
+ * iomap is one-to-one. The use of an iomap frees the client from having to
+ * worry about color index translations, and allows color tables to be
+ * combined in the widget for greater efficiency when color tables are serially
+ * applied. The iomap applies to all color indices or pixel values passed
+ * in i/o operations between the client and the Gterm widget.
+ */
+GtWriteIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ ushort *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ if (w->gterm.useGlobalCmap)
+ return;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+
+ if (DBG_TRACE)
+ fprintf (stderr,"GtWriteIomap: first=%d nelem=%d -> c1=%d c2=%d (%d)\n",
+ first, nelem, c1, c2, (c2-c1+1));
+
+ nelem = c2 - c1 + 1;
+
+ memmove (&w->gterm.iomap[c1], iomap, nelem * sizeof(ushort));
+ invalidate_cmap (w);
+
+ if (DBG_IOMAP) {
+ int i;
+ for (i=0; i < MAX_SZCMAP; i++)
+ fprintf (stderr, "iomap[%3d] = %d\n", i, w->gterm.iomap[i]);
+ }
+}
+
+
+/* GtReadIomap -- Read back the contents of the iomap.
+ */
+GtReadIomap (w, iomap, first, nelem)
+ register GtermWidget w;
+ uchar *iomap;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (iomap, &w->gterm.iomap[c1], nelem * sizeof(ushort));
+}
+
+
+/* GtReadLUT -- Read back the contents of the global LUT.
+ */
+GtReadLUT (w, lut, first, nelem)
+ register GtermWidget w;
+ unsigned long *lut;
+ int first, nelem;
+{
+ register int c1, c2;
+
+ c1 = max(0, min(MAX_SZCMAP-1, first));
+ c2 = max(0, min(MAX_SZCMAP-1, first + nelem - 1));
+ nelem = c2 - c1 + 1;
+
+ memmove (lut, &global_lut[c1], nelem * sizeof(unsigned long));
+}
+
+
+/* init_iomap -- Initialize the iomap and the cmap cache.
+ */
+static void
+init_iomap (w)
+ GtermWidget w;
+{
+ register ushort *iomap = w->gterm.iomap;
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ iomap[i] = i;
+ invalidate_cmap (w);
+}
+
+/* init_global_map -- Initialize the global cmap;
+ */
+static void
+init_global_cmap ()
+{
+ register int i;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ global_cmap[i] = (Pixel) i;
+}
+
+/* invalidate_cmap -- Invalidate the cmap cache.
+ */
+static void
+invalidate_cmap (w)
+ register GtermWidget w;
+{
+ w->gterm.cmap_in_valid = w->gterm.cmap_out_valid = 0;
+}
+
+
+/* get_cmap_in -- Get the combined input colormap, used to transform color
+ * values received from the client to window system color indices.
+ */
+static Pixel *
+get_cmap_in (w)
+ register GtermWidget w;
+{
+ register Pixel *cmap, *cmap_in = w->gterm.cmap_in;
+ register ushort *iomap;
+ register int i, j;
+ int ncolors;
+
+
+ if (w->gterm.useGlobalCmap)
+ return (global_cmap);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_cmap_in: valid=%d ncolors=%d\n",
+ w->gterm.cmap_in_valid, (w->gterm.ncolors - SZ_STATIC_CMAP));
+
+ if (w->gterm.cmap_in_valid)
+ return (cmap_in);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+ ncolors = w->gterm.ncolors - SZ_STATIC_CMAP;
+
+ /* If ncolors is small wrap around so that pixel values stay within
+ * the mapped range of output pixels.
+ */
+ for (i=0; i < MAX_SZCMAP; i++) {
+ j = iomap[i];
+ if (j > SZ_STATIC_CMAP && ncolors)
+ j = ((j - SZ_STATIC_CMAP) % ncolors) + SZ_STATIC_CMAP;
+ cmap_in[i] = cmap[j];
+ }
+
+ w->gterm.cmap_in_valid++;
+ return (cmap_in);
+}
+
+
+/* get_cmap_out -- Get the combined output colormap, used to transform window
+ * system color indices to the color system of the client. Note that this is
+ * not necessarily a uniquely defined invertible transformation.
+ */
+static Pixel *
+get_cmap_out (w)
+ GtermWidget w;
+{
+ register Pixel *cmap;
+ register ushort *iomap;
+ Pixel *cmap_out = w->gterm.cmap_out;
+ register int pixel, i;
+ int j;
+
+
+ if (w->gterm.useGlobalCmap)
+ return (global_cmap);
+
+ if (DBG_TRACE && DBG_CM_VERB)
+ fprintf (stderr, "get_cmap_out: valid=%d ncolors=%d\n",
+ w->gterm.cmap_out_valid, (w->gterm.ncolors - SZ_STATIC_CMAP));
+
+ if (w->gterm.cmap_out_valid)
+ return (cmap_out);
+
+ cmap = w->gterm.cmap;
+ iomap = w->gterm.iomap;
+
+ /* Invert the two colormaps. This is not very efficient, but we don't
+ * have to do this very often (a GtReadPixels call is about the only
+ * case, and even then the map is cached).
+ */
+ for (j=0; j < MAX_SZCMAP; j++) {
+ pixel = j;
+
+ /* Lookup display pixel in cmap. */
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (cmap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+
+ /* Lookup cmap pixel in iomap. */
+ if (iomap[pixel] != pixel) {
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ pixel = i;
+ break;
+ }
+ if (i >= MAX_SZCMAP) {
+ cmap_out[j] = 0;
+ continue;
+ }
+ }
+
+ cmap_out[j] = pixel;
+ }
+
+ w->gterm.cmap_out_valid++;
+ return (cmap_out);
+}
+
+
+/* get_pixel -- Convert a client color index into a display pixel.
+ */
+static Pixel
+get_pixel (w, client_pixel)
+ register GtermWidget w;
+ register int client_pixel;
+{
+ register Pixel *cmap = get_cmap_in (w);
+
+ if (client_pixel < 0 || client_pixel >= MAX_SZCMAP)
+ return (w->gterm.cmap[1]);
+ else
+ return (cmap[client_pixel]);
+}
+
+
+/* GtGetClientPixel -- Convert a gterm pixel into a client pixel.
+ */
+GtGetClientPixel (w, pixel)
+ GtermWidget w;
+ register int pixel;
+{
+ register int i;
+ register ushort *iomap;
+ int client_pixel = 0;
+
+ get_cmap_in (w);
+ iomap = w->gterm.iomap;
+
+ for (i=0; i < MAX_SZCMAP; i++)
+ if (iomap[i] == pixel) {
+ client_pixel = i;
+ break;
+ }
+
+ return (client_pixel);
+}
+
+
+/* GtInitMappings -- Delete all mappings and initialize the mapping subsystem.
+ */
+GtInitMappings (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ invalidate_draw_context (w);
+
+ /* Free any mapping storage. */
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (mp->defined)
+ free_mapping (w, mp);
+ }
+ XtFree ((char *)w->gterm.mappings);
+ w->gterm.mp_head = NULL;
+ w->gterm.mp_tail = NULL;
+ }
+
+ /* Allocate the initially empty mapping descriptors. */
+ w->gterm.mappings =
+ (Mapping) XtCalloc (w->gterm.maxMappings, sizeof (struct mapping));
+
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ mp->mapping = i;
+ }
+
+ w->gterm.nmappings = 0;
+}
+
+
+/* GtNextMapping -- Return the index of the next available mapping descriptor.
+ * This routine always returns a mapping index of 1 or higher.
+ */
+GtNextMapping (w)
+ register GtermWidget w;
+{
+ register Mapping mp;
+ register int i;
+
+ for (i=1; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ return (i);
+ }
+
+ return (-1);
+}
+
+
+/* GtFreeMapping -- Free a mapping descriptor.
+ */
+GtFreeMapping (w, mapping)
+ register GtermWidget w;
+ int mapping;
+{
+ free_mapping (w, &w->gterm.mappings[mapping]);
+}
+
+
+/* GtRaiseMapping -- Set the stacking order of a mapping to one level
+ * higher than the reference mapping. If no reference mapping is given
+ * the mapping is raised to the top of the stacking order.
+ */
+GtRaiseMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = w->gterm.mp_tail;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already on top? */
+ if (mp == w->gterm.mp_tail)
+ return;
+
+ mp_unlink (w, mp);
+ mp_linkafter (w, mp, ref_mp);
+}
+
+
+/* GtLowerMapping -- Change the stacking order of a mapping relative to another
+ * mapping, causing the first mapping to be drawn below the second.
+ */
+GtLowerMapping (w, mapping, reference)
+ register GtermWidget w;
+ int mapping, reference;
+{
+ register Mapping mp, ref_mp;
+
+ mp = &w->gterm.mappings[mapping];
+ if (!mp->defined)
+ return;
+
+ if (reference <= 0 || reference >= w->gterm.maxMappings)
+ ref_mp = NULL;
+ else
+ ref_mp = &w->gterm.mappings[reference];
+
+ /* Already lowered? */
+ if (mp == w->gterm.mp_head)
+ return;
+
+ /* Lower it. */
+ mp_unlink (w, mp);
+ if (ref_mp && ref_mp->prev)
+ mp_linkafter (w, mp, ref_mp->prev);
+ else {
+ mp->next = w->gterm.mp_head;
+ w->gterm.mp_head = mp;
+ if (mp->next)
+ mp->next->prev = mp;
+ if (!w->gterm.mp_tail)
+ w->gterm.mp_tail = mp;
+ }
+}
+
+
+/* GtCompareMappings -- Compare the stacking order of two mappings. A
+ * negative value is returned if the m1 < m2, zero is returned if the
+ * mappings are the same, and a positive value is returned if m1 > m2.
+ */
+GtCompareMappings (w, map1, map2)
+ register GtermWidget w;
+ int map1, map2;
+{
+ register Mapping mp, mp1, mp2;
+
+ if (map1 == map2)
+ return (0);
+
+ mp1 = &w->gterm.mappings[map1];
+ mp2 = &w->gterm.mappings[map2];
+
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ if (mp == mp1)
+ return (-1);
+ else if (mp == mp2)
+ return (1);
+
+ return (0);
+}
+
+
+/* GtSelectRaster -- Select the raster which maps to the given raster pixel,
+ * and transform the coordinates back to the source raster. The raster number
+ * and the raster coordinates of the source raster are returned. If no raster
+ * maps to the given pixel, raster=src and source raster coordinates are
+ * returned.
+ *
+ * The raster pixel coordinate system is best explained by an example.
+ * Suppose we have a 10x10 raster mapped into a 500x500 window. The
+ * window pixel 0 on an axis has raster pixel coordinate 0.0; pixel 500
+ * (which is outside the window) has raster pixel coordinate 10.0. The
+ * coordinates correspond to the edge of the pixel as displayed in the
+ * window, i.e., the left edge of the (nonflipped) window is at x=0.0, and
+ * the right edge at x=10.0. Due to the pixelization of the screen, the
+ * maximum value is a limit which is only approached as the magnification
+ * increases.
+ *
+ * The client application may have a different coordinate system than the
+ * above. For example, if the client wants an integer pixel value to be
+ * at the center of a pixel, the first pixel has the coordinate [1,1], and
+ * the raster is 10 pixels wide, the client coordinate system would range
+ * from 0.5 to 10.5 at the edges of the NDC space.
+ */
+GtSelectRaster (w, dras, dt, dx, dy, rt, rx, ry, rmap)
+ GtermWidget w;
+ int dras; /* display raster */
+ int dt; /* coordinate type of input coords */
+ int dx, dy; /* display raster coordinates */
+ int rt; /* coordinate type for output */
+ int *rx, *ry; /* raster coordinates (output) */
+ int *rmap; /* mapping selected */
+{
+ register Mapping mp;
+ float x, y, x2, y2;
+ int raster, mapping;
+
+ /* Get display raster pixel coordinates. */
+ if (dt != GtPixel) {
+ struct mapping sv_mp, p_mp;
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, 0, 0,
+ 0, 0, 0,0,0,0,
+ 0, dt, dx,dy,0,0);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 0);
+
+ dx = p_mp.dx;
+ dy = p_mp.dy;
+ }
+
+ /* Search for a mapping which maps to this pixel. The mapping we are
+ * looking for is the mapping closest to the tail of the mapping list
+ * (highest stacking order) which is defined and enabled and which
+ * includes the given display raster pixel in its destination rect.
+ */
+ for (mp = w->gterm.mp_tail, mapping = -1; mp; mp = mp->prev) {
+ if (mp->defined && mp->enabled && mp->dst == dras) {
+ struct mapping *map, p_mp;
+ int dnx, dny;
+
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ map = &p_mp;
+
+ if ((dnx = map->dnx) < 0)
+ dnx = -dnx;
+ if ((dny = map->dny) < 0)
+ dny = -dny;
+
+ /* Is display raster pixel in destination rect for this mapping?
+ */
+ if (dnx > 0 && dx >= map->dx && dx < map->dx + dnx &&
+ dny > 0 && dy >= map->dy && dy < map->dy + dny) {
+
+ /* Compute offset into destination rect and apply axis flip
+ * if any from mapping.
+ */
+ x = dx - map->dx + 0.5;
+ if (map->dnx < 0)
+ x = dnx - x;
+ y = dy - map->dy + 0.5;
+ if (map->dny < 0)
+ y = dny - y;
+
+ /* Compute the source raster coordinates corresponding to
+ * the given display pixel. This is done in floating point
+ * to permit fractional pixel resolution if the mapping
+ * zooms the raster.
+ */
+ x = x * (float)map->snx / (float)dnx + map->sx;
+ y = y * (float)map->sny / (float)dny + map->sy;
+
+ mapping = map->mapping;
+ raster = map->src;
+ x2 = w->gterm.rasters[raster].width;
+ y2 = w->gterm.rasters[raster].height;
+
+ break;
+ }
+ }
+ }
+
+ /* Return display raster coordinates if no mapped raster was found.
+ */
+ if (mapping < 0) {
+ x = dx; y = dy;
+ x2 = (int)w->core.width - 1;
+ y2 = (int)w->core.height - 1;
+ raster = dras;
+ }
+
+ /* Output coordinates of the requested type. The increased resolution
+ * of NDC coordinates allows fractional pixel coordinates to be returned
+ * (e.g. 1/32 of a pixel for a 1K raster).
+ */
+ if (rt == GtPixel) {
+ *rx = x;
+ *ry = y;
+ } else {
+ *rx = ( x) / x2 * MAXNDC;
+ *ry = (y2 - y) / y2 * MAXNDC; /* NDC is flipped in Y */
+ }
+
+ *rmap = mapping;
+ return (raster);
+}
+
+
+/* GtCopyRaster -- Copy a region of the source raster to a region of the
+ * destination raster. If the input and output regions are not the same
+ * size the subimage is automatically scaled to fit the destination region.
+ * If the destination extent DNX or DNY is negative, the image is flipped in
+ * that axis. The type of spatial scaling performed is determined by the
+ * scale factors (zoom, dezoom, or no scaling). The rasterop argument is
+ * used to exercise fine control over how the mapping is performed, e.g., to
+ * force a refresh, implement a transient mapping, or in the case of a dezoom
+ * (many-to-one) mapping, select the antialiasing technique to be used.
+ */
+GtCopyRaster (w, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for destination raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ struct mapping sv_mp, p_mp; /* MF007 */
+ int status;
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtCopyRaster() -- ENTER\n");
+
+ if (!w || !XtIsRealized ((Widget)w))
+ return (OK);
+
+ /* Construct a temporary mapping describing the desired raster copy. */
+ initialize_mapping (&sv_mp); /* MF035 */
+ save_mapping (&sv_mp, w->gterm.maxMappings, 0,
+ src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny);
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, &sv_mp, &p_mp, 1);
+ update_mapping (w, &p_mp);
+
+ /* Refresh the destination pixels. */
+ status = refresh_destination (w, &p_mp, dx, dy, abs(dnx), abs(dny));
+
+ /* Discard the temporary mapping. */
+ free_mapping (w, &p_mp);
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtCopyRaster() -- RETURNING\n");
+
+ return (status);
+}
+
+
+/* GtSetMapping -- Define a new mapping function, or modify an old one.
+ * If a new mapping is defined it is merely enabled, and no refreshing
+ * of the screen takes place until either some mapped data is written
+ * to or the mapping is explicitly refreshed. If an existing mapping is
+ * modified the old and new mappings are examined and only those portions
+ * of the destination rect for which the mapping changed are updated.
+ * This permits minor changes to a mapping (e.g. moving an edge) without
+ * having to redraw the entire region. Regions of the destination drawable
+ * which were previously covered by the mapping but which were exposed by
+ * modifying the mapping are redrawn.
+ */
+GtSetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int rop; /* rasterop */
+ int src; /* 0=window, >0 = raster number */
+ int st; /* coordinate type for source raster */
+ int sx,sy,snx,sny; /* source raster */
+ int dst; /* 0=window, >0 = raster number */
+ int dt; /* coordinate type for source raster */
+ int dx,dy,dnx,dny; /* destination raster */
+{
+ register int i, j;
+ register Mapping mp, o_mp, n_mp;
+ struct mapping pix_mp, new_mp;
+ int defined, scale_changed, offset, current, state, old_i;
+ int nx, xs[MAX_REGIONS], xe[MAX_REGIONS], xv[MAX_REGIONS];
+ int ny, ys[MAX_REGIONS], ye[MAX_REGIONS], yv[MAX_REGIONS];
+ int n_dnx, n_dny, n_xflip=0, n_yflip=0, i1, i2;
+ int o_dnx, o_dny, o_xflip=0, o_yflip=0;
+ int *o_xymap, *o_xmap, *o_ymap;
+ int *n_xymap, *n_xmap, *n_ymap;
+ int dummy_rop; /* MF011 */
+ XRectangle rl[MAX_REGIONS];
+ int nrect, buflen, refresh;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetMapping - ENTER\n");
+
+ /* Check mapping number in range. */
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (ERR);
+ else
+ mp = &w->gterm.mappings[mapping];
+
+ invalidate_draw_context (w);
+ initialize_mapping (&pix_mp);
+ initialize_mapping (&new_mp);
+
+ /* Get local pixel space copy of old mapping, store new mapping. */
+ get_pixel_mapping (w, mp, &pix_mp, 1);
+ mp->src = src; mp->st = st;
+ mp->sx = sx; mp->sy = sy; mp->snx = snx; mp->sny = sny;
+ mp->dst = dst; mp->dt = dt;
+ mp->dx = dx; mp->dy = dy; mp->dnx = dnx; mp->dny = dny;
+ mp->rop = (rop & ~(R_RefreshNone|R_RefreshAll));
+ mp->updated = 0;
+
+ /* Newly defined mappings are linked at the tail of the mapping list,
+ * i.e. they stack (display) on top of any other mappings. If the
+ * mapping is already defined the stacking order is not changed.
+ */
+ if (!(defined = mp->defined)) {
+ mp_linkafter (w, mp, w->gterm.mp_tail);
+ mp->defined = 1;
+ }
+
+ if (!valid_mapping (w, mp)) {
+ mp_unlink (w, mp);
+ mp->defined = 0;
+ return (ERR);
+ }
+ update_mapping (w, mp);
+
+ /* If we are defining a new mapping just define it and quit, without
+ * refreshing the window, unless R_RefreshAll is explicitly set in the
+ * mapping. If the mapping is not enabled merely store the new mapping.
+ * If the mapping is a null mapping (no pixels) do nothing. If refresh
+ * is disabled in the rasterop merely store the new mapping. If we are
+ * editing an existing mapping which is enabled with the default rasterop,
+ * we continue on to compare the old and new mappings and refresh any
+ * changed pixels in the destination rect.
+ */
+ if (!defined || src != mp->src || dst != mp->dst) {
+ mp->enabled = mp->defined = 1;
+ mp->refresh = 0;
+ return (OK);
+ } else if (!mp->enabled) {
+ return (OK);
+ } else if (snx == 0 || sny == 0 || dnx == 0 || dny == 0)
+ return (OK);
+
+ if (rop & R_RefreshNone)
+ return (OK);
+
+ /* Convert input mappings to pixel coordinates, we deal with only pixel
+ * coordinates from here on.
+ */
+ get_pixel_mapping (w, mp, &new_mp, 1);
+ load_mapping (&new_mp, &mapping, &dummy_rop, /* MF011 */
+ &src,&st,&sx,&sy,&snx,&sny, &dst,&dt,&dx,&dy,&dnx,&dny);
+ update_mapping (w, n_mp = &new_mp);
+ update_mapping (w, o_mp = &pix_mp);
+
+ /*
+ * We are editing an existing mapping. Determine what has changed in
+ * the mapping and refresh the changed regions.
+ */
+
+ /* Get old XY scaling maps.
+ */
+ o_xmap = o_mp->x_srcpix;
+ o_ymap = o_mp->y_srcpix;
+
+ if ((o_dnx = o_mp->dnx) < 0) {
+ o_dnx = -o_dnx;
+ o_xflip = 1;
+ }
+ if ((o_dny = o_mp->dny) < 0) {
+ o_dny = -o_dny;
+ o_yflip = 1;
+ }
+
+ /* Get new XY scaling maps.
+ */
+ n_xmap = n_mp->x_srcpix;
+ n_ymap = n_mp->y_srcpix;
+
+ if (dnx < 0) {
+ dnx = -dnx;
+ n_xflip = 1;
+ }
+ if (dny < 0) {
+ dny = -dny;
+ n_yflip = 1;
+ }
+
+ /* Refresh the entire region if the refresh flag is set, a flip has
+ * occurred, or we are doing a complex dezoom mapping.
+ */
+ refresh = (o_mp->refresh || (rop & R_RefreshAll));
+ if (n_xflip != o_xflip || n_yflip != o_yflip)
+ refresh = 1;
+ if (n_mp->scaling == M_DEZOOM)
+ refresh = 1;
+
+ /* Has the spatial scale changed? */
+ scale_changed =
+ abs (o_mp->xscale - n_mp->xscale) > 1.0E-4 ||
+ abs (o_mp->yscale - n_mp->yscale) > 1.0E-4;
+
+ /* If any of the above conditions are true refresh the entire mapping,
+ * otherwise compare the old and new mappings and refresh any subregions
+ * which have changed.
+ */
+ if (refresh || scale_changed || n_mp->scaling == M_DEZOOM) {
+ refresh_destination (w, n_mp, dx, dy, dnx, dny);
+
+ } else {
+ /* Compare the old and new mappings to see what needs to be
+ * refreshed. For speed reasons we only want to refresh the pixels
+ * which have been remapped. Any destination pixel in the new mapping
+ * which does not map to the same source pixel as in the old mapping
+ * must be refreshed. We examine each X and Y coordinate in the new
+ * destination rect and see if the source coordinate this maps to is
+ * the same as in the old mapping. If a given destination pixel [i,j]
+ * maps to the same pixel [i,j] in the source as it did in the
+ * previous mapping, we do not need to refresh that pixel. We examine
+ * the X and Y axis in turn and build up a list of regions which do or
+ * do not need to be refreshed.
+ */
+
+ /* Get a list of ranges {XS,XE,XV} in X. */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ dx, dnx, n_xmap, o_mp->dx, o_dnx, o_xmap);
+
+ /* Get a list of ranges {YS,YE,YV} in Y. */
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ dy, dny, n_ymap, o_mp->dy, o_dny, o_ymap);
+
+ /* The list of ranges in X and Y together define a raster of arbitary
+ * sized subrectangles filling the destination rect. If the state
+ * value is nonzero (bit 1 set) in either X or Y, the subrectangle
+ * must be refreshed. The get_rects routine returns a list of the
+ * rectangular subregions matching the given condition (bit 1 set in
+ * either axis). Adjacent rectangles are merged to minimize the
+ * number of calls to refresh_destination.
+ */
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 1,1);
+ for (i=0; i < nrect; i++)
+ refresh_destination (w, n_mp,
+ rl[i].x, rl[i].y, rl[i].width, rl[i].height);
+ }
+
+ /* Refresh any lower level mappings exposed when the current mapping was
+ * modified. These will be regions of the old rect not present in the
+ * new, modified rect for the current mapping.
+ */
+ nx = get_regions (xs,xe,xv, MAX_REGIONS,
+ o_mp->dx, o_dnx, o_xmap, dx, dnx, n_xmap);
+ ny = get_regions (ys,ye,yv, MAX_REGIONS,
+ o_mp->dy, o_dny, o_ymap, dy, dny, n_ymap);
+ nrect = get_rects (rl, MAX_REGIONS, xs,xe,xv,nx, ys,ye,yv,ny, 2,2);
+
+ for (i=0; i < nrect; i++) {
+ XRectangle r, in;
+ Mapping mp;
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, dst, GtPixel, rl[i].x, rl[i].y, rl[i].width,
+ rl[i].height, GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (mp = w->gterm.mp_head; mp && mp->mapping != mapping;
+ mp = mp->next) {
+
+ if (mp->enabled && mp->dst == dst) {
+ r.x = mp->dx;
+ r.y = mp->dy;
+ r.width = mp->dnx;
+ r.height = mp->dny;
+
+ if (rect_intersect (&in, &r, &rl[i]))
+ refresh_destination (w, mp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+
+ free_mapping (w, n_mp);
+ free_mapping (w, o_mp);
+ mp = &w->gterm.mappings[mapping];
+ mp->refresh = 0;
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetMapping - LEAVING\n");
+
+ return (OK);
+}
+
+
+/* GtGetMapping -- Return the external parameters of a mapping. If the
+ * numberd mapping is undefined -1 is returned; 0 is returned if the
+ * mapping is defined but not enabled, and 1 is returned if the mapping
+ * is active.
+ */
+GtGetMapping (w, mapping, rop, src,st,sx,sy,snx,sny, dst,dt,dx,dy,dnx,dny)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int *rop; /* rasterop */
+ int *src; /* 0=window, >0 = raster number */
+ int *st; /* coordinate type for source raster */
+ int *sx,*sy,*snx,*sny; /* source raster */
+ int *dst; /* 0=window, >0 = raster number */
+ int *dt; /* coordinate type for source raster */
+ int *dx,*dy,*dnx,*dny; /* destination raster */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (-1);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (-1);
+
+ *rop = mp->rop;
+ *src = mp->src; *st = mp->st;
+ *sx = mp->sx; *sy = mp->sy; *snx = mp->snx; *sny = mp->sny;
+ *dst = mp->dst; *dt = mp->dt;
+ *dx = mp->dx; *dy = mp->dy; *dnx = mp->dnx; *dny = mp->dny;
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtActiveMapping -- Query whether a mapping is active.
+ */
+GtActiveMapping (w, mapping)
+ register GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+
+ if (mapping < 0 || mapping >= w->gterm.maxMappings)
+ return (0);
+ else if (!(mp = &w->gterm.mappings[mapping])->defined)
+ return (0);
+
+ return (mp->enabled != 0);
+}
+
+
+/* GtEnableMapping -- Enable a mapping. Enabling a mapping does not
+ * update the destination unless the refresh flag is set. Enabling a
+ * mapping activates the mapping so that any changes to the source will
+ * be mapped to the destination.
+ */
+GtEnableMapping (w, mapping, refresh)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int refresh; /* refresh destination */
+{
+ register Mapping mp;
+
+
+ if (DBG_TRACE)
+ fprintf (stderr, "GtEnableMapping: mapping=%d refresh=%d\n",
+ mapping, refresh);
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (!mp->enabled) {
+ mp->enabled = True;
+ if (refresh)
+ GtRefreshMapping (w, mapping);
+ }
+ return (OK);
+ }
+ }
+ return (ERR);
+}
+
+
+/* GtSetDisplayRaster -- Set the currently displayed raster. On TrueColor
+** visuals the XImage for a frame represents the actual pixel values and
+** not the colormapped image. We need this for pixel readback where the
+** display pixmap (i.e. w->gterm.pixmap) is the 24-bits colormapped image
+** and we have no way to get back to the pixel values.
+**
+*/
+
+GtSetDisplayRaster (gt, raster)
+ GtermWidget gt;
+ int raster; /* raster number */
+{
+ if (DBG_TRACE)
+ fprintf (stderr, "GtSetDisplayRaster: raster=%d\n", raster);
+
+ gt->gterm.d_raster = (raster * 2);
+}
+
+
+/* GtDisableMapping -- Disable a mapping. Disabling a mapping does not
+ * affect the mapping definition, hence a disabled mapping may later be
+ * reenabled. If the ERASE flag is set the destination region is redrawn
+ * with the mapping disabled.
+ */
+GtDisableMapping (w, mapping, erase)
+ GtermWidget w;
+ int mapping; /* mapping number */
+ int erase; /* erase the destination */
+{
+ register int i;
+ register Mapping mp, dmp;
+ XRectangle r, d, in;
+
+ invalidate_draw_context (w);
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->enabled) {
+ mp->enabled = False;
+
+ if (erase) {
+ d.x = mp->dx;
+ d.y = mp->dy;
+ d.width = abs(mp->dnx);
+ d.height = abs(mp->dny);
+
+ /* Clear the uncovered region. */
+ GtSetPixels (w, mp->dst, GtPixel,
+ d.x, d.y, d.width, d.height,
+ GtGetClientPixel(w,0), 0);
+
+ /* Refresh any lower level mappings the destination rects of
+ * which intersect the uncovered region.
+ */
+ for (dmp = w->gterm.mp_head;
+ dmp && dmp->mapping != mapping; dmp = dmp->next) {
+
+ if (dmp->enabled && dmp->dst == mp->dst) {
+ r.x = dmp->dx;
+ r.y = dmp->dy;
+ r.width = dmp->dnx;
+ r.height = dmp->dny;
+
+ if (rect_intersect (&in, &r, &d))
+ refresh_destination (w, dmp,
+ in.x, in.y, in.width, in.height);
+ }
+ }
+ }
+ }
+ return (OK);
+ }
+ }
+
+ return (ERR);
+}
+
+
+/* GtRefreshMapping -- Refresh the destination region defined by a mapping.
+ */
+GtRefreshMapping (w, mapping)
+ GtermWidget w;
+ int mapping; /* mapping number */
+{
+ register Mapping mp;
+ struct mapping p_mp;
+
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtRefreshMapping() -- ENTER\n");
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (mp->defined) {
+ if (mp->st != GtPixel || mp->dt != GtPixel) {
+ initialize_mapping (&p_mp);
+ get_pixel_mapping (w, mp, &p_mp, 1);
+ update_mapping (w, mp = &p_mp);
+ } else
+ update_mapping (w, mp);
+
+ if (CacheXImage) /* MF004 */
+ DestroyCachedXImage(); /* MF004 */
+
+ refresh_destination (w, mp,
+ mp->dx, mp->dy, abs(mp->dnx), abs(mp->dny));
+ if (mp == &p_mp)
+ free_mapping (w, mp);
+ }
+ }
+
+ if (DBG_TRACE)
+ fprintf(stderr, "GtRefreshMapping() -- LEAVING\n");
+}
+
+
+/* GtMapVector -- Map a point vector from the coordinate system of one raster
+ * to another as defined by the given mapping. The mapping may be either in
+ * the forward direction (dir = GtMap) or the reverse (dir = GtUnmap). The
+ * point vector is maintained in floating point for this operation to avoid
+ * loss of precision. The input and output vectors may be the same vector.
+ */
+GtMapVector (w, mapping, dir, pv1, pv2, npts)
+ GtermWidget w;
+ int mapping;
+ int dir; /* GtMap, GtUnmap */
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register Mapping mp;
+ register int n;
+
+ struct mapping p_mp;
+ double xscale, xoffset;
+ double yscale, yoffset;
+ int sx, sy;
+
+ xscale = yscale = 1.0;
+ xoffset = yoffset = 0.0;
+ sx = sy = 0;
+
+ if (mapping >= 0 && mapping < w->gterm.maxMappings) {
+ mp = &w->gterm.mappings[mapping];
+ if (valid_mapping (w, mp)) {
+ /* Determine the transformation coefficients. */
+ get_pixel_mapping (w, mp, &p_mp, 0);
+ mp = &p_mp;
+
+ xscale = (float)mp->dnx / (float)mp->snx;
+ if (xscale < 0)
+ xoffset = mp->dx + abs(mp->dnx) - 1;
+ else
+ xoffset = mp->dx;
+
+ yscale = (float)mp->dny / (float)mp->sny;
+ if (yscale < 0)
+ yoffset = mp->dy + abs(mp->dny) - 1;
+ else
+ yoffset = mp->dy;
+
+ sx = mp->sx;
+ sy = mp->sy;
+ }
+ }
+
+ /* Map the vector. */
+ if (dir == GtMap) {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - sx) * xscale + xoffset;
+ op->y = (ip->y - sy) * yscale + yoffset;
+ }
+ } else {
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = (ip->x - xoffset) / xscale + sx;
+ op->y = (ip->y - yoffset) / yscale + sy;
+ }
+ }
+}
+
+
+/* GtPixelToNDC -- Transform a vector from pixel to NDC coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtPixelToNDC (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ( ip->x) / rp->width * MAXNDC;
+ op->y = (rp->height - ip->y) / rp->height * MAXNDC;
+ }
+}
+
+
+/* GtNDCToPixel -- Transform a vector from NDC to pixel coordinates in the
+ * coordinate system of the given reference raster. The input and output
+ * vectors may be the same vector.
+ */
+GtNDCToPixel (w, raster, pv1, pv2, npts)
+ GtermWidget w;
+ int raster;
+ DPoint *pv1;
+ DPoint *pv2;
+ int npts;
+{
+ register Raster rp = &w->gterm.rasters[raster];
+ register DPoint *ip = pv1;
+ register DPoint *op = pv2;
+ register int n;
+
+ for (n=npts; --n >= 0; ip++, op++) {
+ op->x = ip->x / MAXNDC * rp->width;
+ op->y = rp->height - (ip->y / MAXNDC * rp->height);
+ }
+}
+
+
+/* GtDebug -- Print debug info. If the file descriptor is NULL output is
+ * to the process stdout. The "what" argument may be used to select the
+ * type of output desired. If what=0 the full output is generated,
+ * otherwise bits are used to select what output is to be generated.
+ *
+ * "what" bitflags:
+ *
+ * 001 Widget information
+ * 002 List rasters
+ * 004 List mappings
+ * 010 List colormaps
+ * 020 List markers
+ *
+ * This routine is intended only for use during debugging.
+ */
+GtDebug (w, fp, what)
+ GtermWidget w;
+ FILE *fp;
+ int what;
+{
+ /* Default is to write everything to the stdout. */
+ what = what ? what : 0777;
+ fp = fp ? fp : stdout;
+
+ /* Print widget header. */
+ if (what & 001) {
+ fprintf (fp, "Widget 0x%x (%s) %dx%d raster=%d\n",
+ w, w->core.name, w->core.width, w->core.height, w->gterm.raster);
+ fprintf (fp,
+ "--------------------------------------------------------------\n");
+ }
+
+ /* Print raster information. */
+ if (what & 002) {
+ register int i;
+ register Raster rp;
+
+ if (w->gterm.rasters) {
+ for (i=0; i < w->gterm.maxRasters; i++) {
+ rp = &w->gterm.rasters[i];
+ if (!rp->type)
+ continue;
+ fprintf (fp, "raster %4d type=%s delete=%d size=%dx%d\n",
+ i, rp->type == ImageRaster ? "client" : "server",
+ rp->delete, rp->width, rp->height);
+ }
+ } else
+ fprintf (fp, "no rasters\n");
+ }
+
+ /* Print mapping information. */
+ if (what & 004) {
+ register int i;
+ register Mapping mp;
+ char flags[32];
+
+ if (w->gterm.mappings) {
+ for (i=0; i < w->gterm.maxMappings; i++) {
+ mp = &w->gterm.mappings[i];
+ if (!mp->defined)
+ continue;
+
+ flags[0] = mp->enabled ? 'E' : 'D';
+ flags[1] = mp->updated ? 'U' : ' ';
+ flags[2] = mp->refresh ? 'R' : ' ';
+ flags[3] = '\0';
+
+ fprintf (fp, "mapping %3d %s %8o", i, flags, mp->rop);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d",
+ mp->src, mp->st == GtPixel ? "pix" : "ndc",
+ mp->sx, mp->sy, mp->snx, mp->sny);
+ fprintf (fp, " %2d %s %3d %3d %3d %3d\n",
+ mp->dst, mp->dt == GtPixel ? "pix" : "ndc",
+ mp->dx, mp->dy, mp->dnx, mp->dny);
+ }
+ } else
+ fprintf (fp, "no mappings\n");
+
+ fprintf (fp, "mappings from head: ");
+ for (mp = w->gterm.mp_head; mp; mp = mp->next)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+
+ fprintf (fp, "mappings from tail: ");
+ for (mp = w->gterm.mp_tail; mp; mp = mp->prev)
+ fprintf (fp, " %d", mp->mapping);
+ fprintf (fp, "\n");
+ }
+
+ /* Print colormap information. */
+ if (what & 010) {
+ register struct colormap *cm;
+
+ fprintf (fp, "cmapName=%s ncolors=%d basePixel=%d\n",
+ w->gterm.cmapName, w->gterm.ncolors, w->gterm.base_pixel);
+ for (cm = w->gterm.colormaps; cm; cm = cm->next)
+ fprintf (fp, "colormap %2d ncells=%d\n", cm->map, cm->ncells);
+ }
+
+ /* Print marker information. */
+ if (what & 020) {
+ register Marker mm;
+ char value[256];
+
+ for (mm = w->gterm.gm_head; mm; mm = mm->next) {
+ GmGetAttribute (mm, GmType, (XtArgVal)value, XtRString);
+ fprintf (fp, "marker 0x%x: %10s flags=0x%x [%d %d %d %d] %0.5g\n",
+ mm, value, mm->flags, mm->x, mm->y, mm->width, mm->height,
+ mm->rotangle);
+ }
+ }
+}
+
+