#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	display.c (Display)
 * Purpose:	Draw images in their windows, including the main display
 * Subroutine:	disp_window()			returns: void
 * Subroutine:	disp_dispbox()			returns: void
 * Subroutine:	map_dispbox()			returns: void
 * Subroutine:	clear_margins()			returns: void
 * Xlib calls:	XPutImage(), XSync();
 * Copyright:	1989 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version		  26 May 1989
 *		{n} <who> -- <does what> -- <when>
 */

#include <X11/Xlib.h>		/* X window stuff */
#include <X11/Xutil.h>		/* X window manager stuff */
#include "hfiles/define.h"	/* define MIN, MAX, DONT_CARE, etc. */
#include "hfiles/struct.h"	/* declare structure types */
#include "hfiles/extern.h"	/* extern main parameter structures */
#include "hfiles/scale.h"	/* define scaling constants */

/*
 * Subroutine:	disp_window
 * Purpose:	Redraw the window's display image with no frills
 * Xlib call:	XPutImage()
 */
void disp_window ( window )
     struct windowRec *window;
{
  GC gc, set_gc(), set_gc_with_background();

  if( window->image.depth == 1 )
    gc = set_gc_with_background(&(color.gcset.disp),
				color.gcset.disp.background);
  else
    gc = set_gc(&(color.gcset.disp));

  XPutImage(window->display, window->ID, gc, &window->image, 0, 0,
	    window->xzero, window->yzero,
	    (unsigned int)window->xwidth, (unsigned int)window->yheight);
}

static int pointer_centered = 0;
void center_pointer()
{if (pointer_centered) pointer_centered = 0;
 else pointer_centered = 1; return; }

/*
 * Subroutine:	disp_dispbox
 * Purpose:	Redraw the dispbox window display including cursor graphics
 */
void
disp_dispbox ( )
{
  void disp_window(), disp_regions(), disp_cursor();
  void move_pointer(), read_region_file();

  /* put up the image */
  disp_window(&dispbox);
  /* make sure image is up before proceeding */
  XSync(dispbox.display, 0);
  /* redraw the region outlines (if visible is indicated) */
  read_region_file();
  disp_regions(&cursor);
  /* redraw the cursor (if visible is indicated) */
  disp_cursor(&cursor);
  if (pointer_centered)
    move_pointer (dispbox.display, dispbox.ID, img.filecols/2, img.filerows/2);
  return;
}

/*
 * Subroutine:	map_dispbox
 * Purpose:	Redraw the main display buffer from the short image buffer
 */
void
map_dispbox ( )
{
  void unset_blink(), clear_margins(), map_buf_repzoom(), map_buf_subzoom();
  void map_buf_repzoom_adj(), make_halftone_display(), map_buf_subzoom_adj();

  /* restore original buffer if we were blinking */
  unset_blink();
  if( color.ncolors <= 1 ) {
    /* contstruct XYBitmap image */
    dispbox.image.format = XYBitmap;
    dispbox.image.depth = 1;
    dispbox.image.bits_per_pixel = 1;
    dispbox.image.bytes_per_line = (dispbox.image.width + 7) / 8;
    make_halftone_display();
  } else {
    /* construct ZPixmap image */
    dispbox.image.format = ZPixmap;
    dispbox.image.depth = color.screen_depth;
    dispbox.image.bits_per_pixel = 8;
    dispbox.image.bytes_per_line = dispbox.image.width;
    if( coord.bd.clip ) {
      /* if image does not fill display buffer, do something about it */
      clear_margins((unsigned char *)dispbox.image.data, &coord.bd,
		    &coord.disp, 1, color.hard.std_white);
    }
    /* draw the image with the appropriate zoom */
#ifdef SUMBLOCK
    if( buffer.scalemap_summing != buffer.shortbuf_summing ) {
      /* compensate for loading shortbuf with differently summed values */
      if( coord.bd.block < -1 )
	map_buf_repzoom_adj(&coord, (unsigned char *)dispbox.image.data,
			    buffer.shortbuf, buffer.scalemap + SCALEOFF,
			    buffer.scalemap_summing, buffer.shortbuf_summing);
      else
	map_buf_subzoom_adj(&coord, (unsigned char *)dispbox.image.data,
			    buffer.shortbuf, buffer.scalemap + SCALEOFF,
			    MAX(coord.bd.block, 1),
			    buffer.scalemap_summing, buffer.shortbuf_summing);
    } else {
#endif
      /* no special compensation */
      if( coord.bd.block < -1 )
	map_buf_repzoom(&coord, (unsigned char *)dispbox.image.data,
			buffer.shortbuf, buffer.scalemap + SCALEOFF);
      else
	map_buf_subzoom(&coord, (unsigned char *)dispbox.image.data,
			buffer.shortbuf, buffer.scalemap + SCALEOFF,
			MAX(coord.bd.block, 1));
#ifdef SUMBLOCK
    }
#endif
  }
}

/*
 * Subroutine:	clear_margins
 * Purpose:	Take action to indicate unfilled display margins
 */
void clear_margins ( destbuf, ab, bsys, clear, border_color )
     unsigned char *destbuf;		/* destination buffer */
     Edges *ab;				/* mapping parameters */
     Coordsys *bsys;			/* destination parameters */
     int clear;				/* clear unused part of buf */
     register int border_color;		/* color for outline */
{
  register int dest_width;
  int x1, x2, y1, y2;
  short dest_Xwdth;

  dest_width = bsys->width;
  dest_Xwdth = ab->dstXwdth;
  x1 = ab->dstX1;
  x2 = bsys->X2i - ab->dstX2;
  y1 = ab->dstY1;
  y2 = bsys->Y2i - ab->dstY2;

  /* if unused buffer is to be cleared */
  if( clear ) {
    /* if image leaves gap at top - clear top of buffer */
    if( y1 > 0 ) {
      bzero((char *)destbuf, y1 * dest_width);
    }
    /* if image leaves a gap at the bottom - clear bottom of buffer */
    if( y2 > 0 ) {
      bzero((char *)destbuf + ((y1 + ab->dstYhght) * dest_width),
	    y2 * dest_width);
    }
    /* if image leaves gap on either side */
    if( (x1 > 0) || (x2 > 0) ) {
      register unsigned char *dest;
      register int count;
      register int xtot;

      xtot = x1 + x2;
      dest = destbuf + (y1 * dest_width);
      /* clear first line on left */
      if( x1 > 0 ) {
	bzero((char *)dest, x1);
      }
      dest += x1 + dest_Xwdth;
      count = ab->dstYhght;
      /* repeatedly clear right and left together */
      while( --count > 0 ) {
	/* clear combination of line on right continued into line on left */
	bzero((char *)dest, xtot);
	dest += dest_width;
      }
      /* clear last line on right */
      if( x2 > 0 ) {
	bzero((char *)dest, x2);
      }
    }
  }
  /* if a border is to be drawn on exposed edges */
  if( border_color != DONT_CARE ) {
    if( x1 > 0 ) {
      register unsigned char *dest;
      register int count;

      dest = destbuf + ((y1 * dest_width) + x1 - 1);
      count = ab->dstYhght;
      while( count-- > 0 ) {
	*dest = border_color;
	dest += dest_width;
      }
      ++dest_Xwdth;
      --x1;
    }
    if( x2 > 0 ) {
      register unsigned char *dest;
      register int count;

      dest = destbuf + ((y1 * dest_width) + ab->dstX2 + 1);
      count = ab->dstYhght;
      while (count-- > 0) {
	*dest = border_color;
	dest += dest_width;
      }
      ++dest_Xwdth;
    }
    if( y1 > 0 ) {
      register unsigned char *dest;
      register unsigned char *displimit;

      dest = destbuf + (((y1 - 1) * dest_width) + x1);
      displimit = dest + dest_Xwdth;
      while (dest < displimit) {
	*(dest++) = border_color;
      }
    }
    if( y2 > 0 ) {
      register unsigned char *dest;
      register unsigned char *displimit;

      dest = destbuf + (((ab->dstY2 + 1) * dest_width) + x1);
      displimit = dest + dest_Xwdth;
      while( dest < displimit ) {
	*(dest++) = border_color;
      }
    }
  }
}


/* Position display pointer to specified image coordinates */

void
move_pointer (display, window, ix, iy)
  Display *display;
  Window window;
  int ix, iy;		/* Image coordinates */
{
  float fx, fy;
  int x, y;

  d_transform(&coord.filetodisp, (double)ix, (double)iy, &fx, &fy);
  x = (int) fx;
  y = (int)fy;
  /*  Move the mouse (supercede any recent mouse movement) */
  XSync (display, 0);
  XWarpPointer(display, None, window, 0, 0, 0, 0, x, y);
  return;
}


syntax highlighted by Code2HTML, v. 0.9.1