/*--------------------------------*-C-*---------------------------------*
 * File:	pixmap.c
 *----------------------------------------------------------------------*
 * Copyright (c) 1999 Ethan Fischer <allanon@crystaltokyo.com>
 * Copyright (c) 1999 Sasha Vasko   <sashav@sprintmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*
 * Originally written:
 *    1999	Sasha Vasko <sashav@sprintmail.com>
 *----------------------------------------------------------------------*/

#ifndef lint
static const char rcsid[] = "$Id: pixmap.c,v 1.3 2001/09/06 15:57:05 sashav Exp $";
#endif

#include "rxvt.h"		/* NECESSARY */

#if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT)
# include <X11/Xatom.h>
# ifdef XPM
#   include <X11/xpm.h>
# endif
#endif

/*#define BENCHMARK_SHADING 200 */
/*#define DO_CLOCKING       */
/*#define GETPIXEL_PUTPIXEL */
/*#define DEBUG_IMAGING     */

#if defined(DO_CLOCKING) || defined(BENCHMARK_SHADING)
 #include <time.h>
#endif

#ifdef DEBUG_X
#define XGetGeometry(dpy,win,r,x,y,w,h,b,d) \
	trace_XGetGeometry(__FILE__,__LINE__,dpy,win,r,x,y,w,h,b,d)
#endif

#if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT) || defined(_MYSTYLE_)
/* Xdisplay, Xroot, Xvisual and Xdepth needs to be defined if code is moved to some other prog */
#define CREATE_TRG_PIXMAP(w,h) XCreatePixmap(Xdisplay, Xroot, w, h, Xdepth)

/* this comes from libasimage or from ximage_utils.c */
XImage * ScaleXImageToSize (XImage *src, Position width, Position height );
void ShadeXImage( XImage* srcImage, ShadingInfo* shading, GC gc );

int
pixmap_error_handler (Display * dpy, XErrorEvent * error)
{
#ifdef DEBUG_IMAGING
  fprintf(stderr, "\n aterm caused XError # %u, in resource %lu, Request: %d.%d",
          error->error_code, error->resourceid, error->request_code, error->minor_code );
#endif
  return 0;
}

#ifndef USE_LIBASIMAGE /* used to be LIBASIMAGE_HEADERS*/
void CopyAndShadeArea( Drawable src, Pixmap trg,
                       int x, int y, int w, int h,
		       int trg_x, int trg_y,
		       GC gc, ShadingInfo* shading )
{
  int (*oldXErrorHandler) (Display *, XErrorEvent *) ;
   /* we need to check if pixmap is still valid */
    oldXErrorHandler = XSetErrorHandler (pixmap_error_handler);

    if( shading )
    {
      XImage* img ;

        if( x <0 || y <0  ) return ;
        if((img = XGetImage (Xdisplay, src, x, y, w, h, AllPlanes, ZPixmap))!= NULL )
        {
    	    ShadeXImage( img, shading, gc );
    	    XPutImage(Xdisplay, trg, gc, img, 0, 0, trg_x, trg_y, w, h);
#ifdef BENCHMARK_SHADING
	    {
		int i;
		time_t before, after;
		double diff;

		before = time (NULL);
		for (i = 0; i < BENCHMARK_SHADING; i++)
		    ShadeXImage (img, shading, gc);
		after = time (NULL);

		diff = difftime (after, before);
		printf ("CopyAndShadeArea(): %d shading runs took %.0f seconds\n", BENCHMARK_SHADING, diff);
	    }
#endif
	    XDestroyImage( img );
	    return ;
	}
    }
    if( !XCopyArea (Xdisplay, src, trg, gc, x, y, w, h, trg_x, trg_y))
	XFillRectangle( Xdisplay, trg, gc, trg_x, trg_y, w, h );
    XSetErrorHandler (oldXErrorHandler);
}

int
FillPixmapWithTile (Pixmap pixmap, Pixmap tile, int x, int y, int width,
		    int height, int tile_x, int tile_y)
{
  if (tile != None && pixmap != None)
    {
      GC gc;
      XGCValues gcv;

      gcv.tile = tile;
      gcv.fill_style = FillTiled;
      gcv.ts_x_origin = -tile_x;
      gcv.ts_y_origin = -tile_y;
      gc =
	XCreateGC (Xdisplay, tile,
		   GCFillStyle | GCTile | GCTileStipXOrigin |
		   GCTileStipYOrigin, &gcv);
      XFillRectangle (Xdisplay, pixmap, gc, x, y, width, height);
      XFreeGC (Xdisplay, gc);
      return 1;
    }
  return 0;
}



void ShadeTiledPixmap(Pixmap src, Pixmap trg, int src_w, int src_h, int x, int y, int w, int h, GC gc, ShadingInfo* shading)
{
  int tile_x, tile_y, left_w, bott_h;

    tile_x = x%src_w ;
    tile_y = y%src_h ;
    left_w = min(src_w-tile_x,w);
    bott_h = min(src_h-tile_y,h);
/*fprintf( stderr, "\nShadeTiledPixmap(): tile_x = %d, tile_y = %d, left_w = %d, bott_h = %d, SRC = %dx%d TRG=%dx%d", tile_x, tile_y, left_w, bott_h, src_w, src_h, w, h);*/
    CopyAndShadeArea( src, trg, tile_x, tile_y, left_w, bott_h, 0, 0, gc, shading );
    if( bott_h < h )
    {  /* right-top parts */
	CopyAndShadeArea( src, trg, tile_x, 0, left_w, h-bott_h, 0, bott_h, gc, shading );
    }
    if( left_w < w )
    {  /* left-bott parts */
	CopyAndShadeArea( src, trg, 0, tile_y, w-left_w, bott_h, left_w, 0, gc, shading );
        if( bott_h < h  )      /* left-top parts */
	    CopyAndShadeArea( src, trg, 0, 0, w-left_w, h-bott_h, left_w, bott_h, gc, shading );
    }
}

Pixmap
ShadePixmap (Pixmap src, int x, int y, int width, int height, GC gc, ShadingInfo* shading )
{
  Pixmap trg = CREATE_TRG_PIXMAP(width, height);
    if( trg != None )
    {
	CopyAndShadeArea( src, trg, x, y, width, height, 0, 0, gc, shading );
    }
    return trg ;
}

Pixmap
ScalePixmap (Pixmap src, int src_w, int src_h, int width, int height, GC gc, ShadingInfo*  shading )
{
  XImage *srcImage, *trgImage;
  Pixmap trg = None;

    if (src != None)
    {
	if ((srcImage = XGetImage (Xdisplay, src, 0, 0, src_w, src_h, AllPlanes, ZPixmap)) != NULL)
	{
	    if ((trgImage = ScaleXImageToSize (srcImage, (Dimension) width, (Dimension) height)) != NULL)
	    {
		if ((trg = CREATE_TRG_PIXMAP(width, height)) != 0)
		{
		    if( shading )     ShadeXImage( trgImage, shading, gc );
		    XPutImage (Xdisplay, trg, gc, trgImage, 0, 0, 0, 0, width, height);
#ifdef BENCHMARK_SHADING
	    {
		int i;
		time_t before, after;
		double diff;

		before = time (NULL);
		for (i = 0; i < BENCHMARK_SHADING; i++)
		    ShadeXImage (trgImage, shading, gc);
		after = time (NULL);

		diff = difftime (after, before);
		printf ("ScalePixmap(): %d shading runs took %.0f seconds\n", BENCHMARK_SHADING, diff);
	    }
#endif
		}
	        XDestroyImage (trgImage);
	    }
	    XDestroyImage (srcImage);
	}
    }
    return trg;
}

Pixmap
CenterPixmap( Pixmap src, int src_w, int src_h, int width, int height, GC gc, ShadingInfo*  shading)
{
  int x, y, w, h, src_x = 0, src_y = 0 ;
  Pixmap trg ;
    /* create target pixmap of the size of the window */
    trg = CREATE_TRG_PIXMAP(width, height);
    if( trg != None )
    {
	/* fill it with background color */
        XFillRectangle(Xdisplay, trg, gc, 0, 0, width, height);
	/* place image at the center of it */
        x = (width-src_w)>>1 ;
	y = (height-src_h)>>1 ;
        if( x < 0 )
	{
	    src_x -= x ;
	    w = min(width,src_w+x) ;
	    x = 0 ;
	}else w = min(width, src_w) ;
        if( y < 0 )
	{
	    src_y -= y ;
    	    h = min(height, src_h+y);
	    y = 0 ;
	}else h = min(height, src_h);

	CopyAndShadeArea( src, trg, src_x, src_y, w, h, x, y, gc, shading);
    }

    return trg ;
}

Pixmap
GrowPixmap( Pixmap src, int src_w, int src_h, int width, int height, GC gc, ShadingInfo*  shading)
{
  int w, h;
  Pixmap trg ;
    /* create target pixmap of the size of the window */
    trg = CREATE_TRG_PIXMAP(width, height);
    if( trg != None )
    {
	/* fill it with background color */
        XFillRectangle(Xdisplay, trg, gc, 0, 0, width, height);
	/* place image at the center of it */
        w = min(width, src_w) ;
        h = min(height, src_h);

	CopyAndShadeArea( src, trg, 0, 0, w, h, 0, 0, gc, shading);
    }

    return trg ;
}
/* PROTO */
int
GetRootDimensions( int* width, int* height )
{
  Window root ;
  int w_x, w_y ;
  unsigned int w_w, w_h, border_w, w_depth ;
    if( !XGetGeometry( Xdisplay, Xroot, &root,
	                  &w_x, &w_y, width, height, &border_w, &w_depth ))
    {
	*width = 0 ;
	*height = 0 ;
    }
    return (*width>0 && *height>0)?1:0 ;
}

int
GetWinPosition (Window win, int *x, int *y)
{
  Window root, parent, *children ;
  unsigned int nchildren ;
  static int rootWidth = 0, rootHeight = 0;
  XWindowAttributes attr ;
  int my_x, my_y, dumm ;
  unsigned int w, h, udumm ;

    XGetWindowAttributes( Xdisplay, win, &attr );
    if( attr.map_state != IsViewable ) return 0;

    if( !x ) x = &my_x ;
    if( !y ) y = &my_y ;

    *x = 0 ;
    *y = 0 ;

    if( !rootWidth || !rootHeight )
        if( !GetRootDimensions(&rootWidth, &rootHeight)) return 0;

    XGetGeometry( Xdisplay, win, &root, &dumm, &dumm, &w, &h, &udumm, &udumm );

    while( XQueryTree( Xdisplay, win, &root, &parent, &children, &nchildren ) )
    {
      int w_x, w_y ;
      unsigned int border_w ;
	if( children ) XFree( children );
	if( !XGetGeometry( Xdisplay, win, &root, &w_x, &w_y, &udumm, &udumm, &border_w, &udumm ))
	    break ;
	(*x)+=w_x+(int)border_w ;
	(*y)+=w_y+(int)border_w ;

	if( parent == root )
	{/* taking in to consideration virtual desktopping */
	  int bRes = 1 ;
	    if( *x>=rootWidth  || (*x+(int)w) <= 0 ||
	        *y>=rootHeight || (*y+(int)h) <= 0 )
		bRes = 0 ;
    /* don't want to return position outside the screen even if we fail */
    /*	    while( *x < 0 ) *x += rootWidth ;
	    while( *y < 0 ) *y += rootHeight ;
	    while( *x+(int)w > rootWidth ) *x -= rootWidth ;
	    while( *y+(int)h > rootHeight) *y -= rootHeight ;
     */	    return bRes;
	}
	win = parent ;
    }
    *x = 0 ;
    *y = 0 ;
    return 0 ;
}

void
sleep_a_little (int n)
{
  struct timeval value;

  if (n <= 0)
    return;

  value.tv_usec = n % 1000000;
  value.tv_sec = n / 1000000;

  (void) select (1, 0, 0, 0, &value);
}


static Pixmap
CutPixmap ( Pixmap src, Pixmap trg,
            int x, int y,
	    unsigned int src_w, unsigned int src_h,
	    unsigned int width, unsigned int height,
	    GC gc, ShadingInfo * shading)
{
  Bool my_pixmap = (trg == None )?True:False ;
  int screen_w, screen_h ;
  int offset_x = 0, offset_y = 0 ;

  screen_w = DisplayWidth( Xdisplay, Xscreen );
  screen_h = DisplayHeight( Xdisplay, Xscreen );

  while( x+(int)width < 0 )  x+= screen_w ;
  while( x >= screen_w )  x-= screen_w ;
  while( y+(int)height < 0 )  y+= screen_h ;
  while( y >= screen_h )  y-= screen_h ;

  if (width < 2 || height < 2 )
    return trg;
  if( x < 0 )
  {
    offset_x = (-x) ;
    x = 0 ;
    width -= offset_x ;
  }
  if( y < 0 )
  {
    offset_y = (-y) ;
    y = 0 ;
    height -= offset_y ;
  }
  if( x+width >= screen_w ) width = screen_w - x ;
  if( y+height >= screen_h ) height = screen_h - y ;

  if (src == None) /* we don't have root pixmap ID */
    { /* we want to create Overrideredirect window overlapping out window
         with background type of Parent Relative and then grab it */
     XSetWindowAttributes attr ;
     XEvent event ;
     int tick_count = 0 ;
     Bool grabbed = False ;
        attr.background_pixmap = ParentRelative ;
	attr.backing_store = Always ;
	attr.event_mask = ExposureMask ;
	attr.override_redirect = True ;
	src = XCreateWindow(Xdisplay, Xroot, x, y, width, height,
	                    0,
			    CopyFromParent, CopyFromParent, CopyFromParent,
			    CWBackPixmap|CWBackingStore|CWOverrideRedirect|CWEventMask,
			    &attr);

	if( src == None ) return trg ;
	XGrabServer( Xdisplay );
	grabbed = True ;
	XMapRaised( Xdisplay, src );
	XSync(Xdisplay, False );
	/* now we have to wait for our window to become mapped - waiting for Expose */
	for( tick_count = 0 ; !XCheckWindowEvent( Xdisplay, src, ExposureMask, &event ) && tick_count < 100 ; tick_count++)
	    sleep_a_little(100);

	if( tick_count < 100 )
	{
	    if( trg == None )    trg = CREATE_TRG_PIXMAP (width+offset_x, height+offset_y);
	    if (trg != None)
	    {	/* custom code to cut area, so to ungrab server ASAP */
	        if (shading)
	        {
	          XImage *img;
		  img = XGetImage (Xdisplay, src, 0, 0, width, height, AllPlanes, ZPixmap);
    		  XDestroyWindow( Xdisplay, src );
	          src = None ;
		  XUngrabServer( Xdisplay );
		  grabbed = False ;
		  if (img != NULL)
		  {
    		    ShadeXImage (img, shading, gc);
		    XPutImage (Xdisplay, trg, gc, img, 0, 0, offset_x, offset_y, width, height);
#ifdef BENCHMARK_SHADING
	    {
		int i;
		time_t before, after;
		double diff;

		before = time (NULL);
		for (i = 0; i < BENCHMARK_SHADING; i++)
		    ShadeXImage (img, shading, gc);
		after = time (NULL);

		diff = difftime (after, before);
		printf ("CutPixmap(): %d shading runs took %.0f seconds\n", BENCHMARK_SHADING, diff);
	    }
#endif
		    XDestroyImage (img);
		  }else if( my_pixmap )
		  {

		    XFreePixmap( Xdisplay, trg );
		    trg = None ;
		  }
		}else
		    XCopyArea (Xdisplay, src, trg, gc, 0, 0, width, height, offset_x, offset_y);
	    }
        }

	if( src )
	    XDestroyWindow( Xdisplay, src );
	if( grabbed )
	    XUngrabServer( Xdisplay );
	return trg ;
    }
  /* we have root pixmap ID */
  /* find out our coordinates relative to the root window */
  if (x + width > src_w || y + height > src_h)
    {			/* tiled pixmap processing here */
      Pixmap tmp ;
      width = min (width, src_w);
      height = min (height, src_h);

      tmp = CREATE_TRG_PIXMAP (width, height);
      if (tmp != None)
      {
        ShadeTiledPixmap (src, tmp, src_w, src_h, x, y, width,
			  height, gc, shading);
        if( trg == None )
           trg = CREATE_TRG_PIXMAP (width+offset_x, height+offset_y);
	if( trg != None )
	    XCopyArea (Xdisplay, tmp, trg, gc, 0, 0, width, height, offset_x, offset_y);

	XFreePixmap( Xdisplay, tmp );
        return trg;
      }
    }

  /* create target pixmap of the size of the window */
  if( trg == None )    trg = CREATE_TRG_PIXMAP (width+offset_x, height+offset_y);
  if (trg != None)
    {
      /* cut area */
      CopyAndShadeArea (src, trg, x, y, width, height, offset_x, offset_y, gc, shading);

    }

  return trg;
}

Pixmap
CutWinPixmap (Window win, Drawable src, int src_w, int src_h, int width,
	      int height, GC gc, ShadingInfo * shading)
{
  unsigned int x = 0, y = 0;


  if( src == None )
  {
#ifndef TRANSPARENT
    return None ;
#else
    if( !(Options & Opt_transparent))
	return None ;
#endif
  }

  if (!GetWinPosition (win, &x, &y))
	return None;

  return CutPixmap( src, None, x, y, src_w, src_h, width, height, gc, shading );
}


/* PROTO */
Pixmap
GetRootPixmap(Atom id)
{
  Pixmap currentRootPixmap = None;
    if( id == None ) id = XInternAtom (Xdisplay, "_XROOTPMAP_ID", True);

    if( id != None )
    {
      Atom act_type;
      int act_format;
      unsigned long nitems, bytes_after;
      unsigned char *prop = NULL;

/*fprintf(stderr, "\n aterm GetRootPixmap(): root pixmap is set");    		    */
	if (XGetWindowProperty (Xdisplay, Xroot, id, 0, 1, False, XA_PIXMAP,
			        &act_type, &act_format, &nitems, &bytes_after,
				&prop) == Success)
	{
	    if (prop)
	    {
		currentRootPixmap = *((Pixmap *) prop);
		XFree (prop);
/*fprintf(stderr, "\n aterm GetRootPixmap(): root pixmap is [%lu]", currentRootPixmap); */
	    }
	}
    }
    return currentRootPixmap ;
}


Pixmap
ValidatePixmap(Pixmap p, int bSetHandler, int bTransparent, unsigned int *pWidth, unsigned int *pHeight)
{
  int (*oldXErrorHandler) (Display *, XErrorEvent *) ;
   /* we need to check if pixmap is still valid */
  Window root;
  int junk;
    if( bSetHandler )
        oldXErrorHandler = XSetErrorHandler (pixmap_error_handler);

    if(bTransparent)        p = GetRootPixmap( None );
    if( !pWidth ) pWidth = &junk ;
    if( !pHeight ) pHeight = &junk ;

    if( p != None )
    {
        if (!XGetGeometry (Xdisplay, p, &root, &junk, &junk, pWidth, pHeight, &junk, &junk))
    	    p = None ;
    }
    if( bSetHandler )
        XSetErrorHandler (oldXErrorHandler);

    return p ;
}

#endif /* LIBASIMAGE_HEADERS */
/***************************************************************************/
/*     Down below goes aterm specific functions                            */
/***************************************************************************/

#define BG TermWin.background /*for convinience*/

/* PROTO */
int
GetMyPosition( int* x, int* y )
{
  int bRet = 0 ;
  int (*old) (Display *, XErrorEvent *) = XSetErrorHandler (pixmap_error_handler);

    bRet = GetWinPosition( TermWin.vt, x, y );
    XSetErrorHandler (old);

    return bRet ;
}


void FreeTargetPixmap()
{
    if( BG.trgPixmap != None )
    {
	XFreePixmap( Xdisplay, BG.trgPixmap ); /*just in case*/
	BG.trgPixmap = None ;
    }
}


/* PROTO */
Pixmap
SetSrcPixmap(Pixmap p)
{
    if( BG.srcPixmap != None && BG.bMySource )
    {
	XFreePixmap( Xdisplay, BG.srcPixmap );
	BG.srcPixmap = p ;
	BG.bMySource = 0 ;
    }

    BG.srcPixmap = p ;

    BG.Width = 0 ;
    BG.Height = 0 ;

    if( BG.srcPixmap != None )
    {
      Window root;
      unsigned int dum, w, h;
      int dummy;

	if (XGetGeometry (Xdisplay, BG.srcPixmap, &root, &dummy, &dummy,
			&w, &h, &dum, &dum))
	{
	    BG.Width = w ;
	    BG.Height = h ;
	}
    }
}

/* PROTO */
void
ValidateSrcPixmap(int bSetHandler)
{

    if( !BG.bMySource )
    {    /* we need to check if pixmap is still valid */
      Pixmap new_p ;

	new_p = ValidatePixmap( BG.srcPixmap , bSetHandler,
		     	        ((Options & Opt_transparent) &&
			          BG.trgType != BGT_None),
				NULL, NULL );

	if( new_p != BG.srcPixmap )	SetSrcPixmap(new_p);
    }
}

#ifdef _MYSTYLE_
Pixmap
RenderMyStylePixmap( MyStyle *style, Pixmap root_pmap,
		     unsigned int root_pmap_width, unsigned int root_pmap_height,
		     unsigned int width, unsigned int height )
{
/*  fprintf( stderr, "Entering RenderMyStylePixmap : texture_type = %d\n", style->texture_type );
*/
  if (style->texture_type == TEXTURE_SOLID)
    return None;
  else if (style->texture_type < TEXTURE_PIXMAP)   /* gradients */
    return mystyle_make_pixmap (style, width, height, None);
  else if (style->texture_type == TEXTURE_PIXMAP)
    return style->back_icon.pix;
  else if (style->texture_type > TEXTURE_PIXMAP)
    {
     int real_x, real_y ;
        GetMyPosition( &real_x, &real_y);
	return mystyle_make_pixmap_overlay (style, real_x, real_y,
	    				    width,
					    height, None);
    }
  return None ;
}
#endif

/* PROTO */
void
RenderPixmap(int DontCheckSource )
{
  XGCValues       gcvalue;
  GC              gc;
  unsigned int    width = TermWin_TotalWidth();
  unsigned int    height = TermWin_TotalHeight();
  unsigned int    fin_width, fin_height ;
  int (*oldXErrorHandler) (Display *, XErrorEvent *) ;

    /* for convinience only */
    fin_width = width ;
    fin_height = height ;
/*fprintf(stderr, "\n aterm: entering RenderPixmap, window size is %dx%d, trg_type = %d", width, height, BG.trgType );
*/
    gcvalue.foreground = PixColors[Color_bg];
    gc = XCreateGC(Xdisplay, TermWin.vt, GCForeground, &gcvalue);

    /* we have some nice processing of all the X errors built in */
    /* so let's not let us crash if anything goes wrong          */
    oldXErrorHandler = XSetErrorHandler (pixmap_error_handler);

    if( !DontCheckSource )  ValidateSrcPixmap( 0 );


    if( BG.srcPixmap == None
#ifdef _MYSTYLE_
	&& BG.trgType != BGT_MyStyle
#endif
      )
    {
#ifdef TRANSPARENT
	if(!(Options & Opt_transparent) || BG.trgType == BGT_None)
#endif
	{
	    XSetErrorHandler (oldXErrorHandler);
	    return ; /* nothing to do here */
	}
    }

/*fprintf(stderr, "\n aterm RenderPixmap(): freeing target pixmap ...");
*/
    if( BG.trgPixmap != BG.srcPixmap )	FreeTargetPixmap();


    switch( BG.trgType )
    {
#define SHADING ((BG.bMySource)?NULL:&(BG.Shading))
	case BGT_Tile : /* just copying source PixampID into trgPixmapID */
		if( BG.bMySource || NO_NEED_TO_SHADE(BG.Shading))
		{
    		    BG.trgPixmap = BG.srcPixmap ;
		    fin_width = BG.Width ;
		    fin_height = BG.Height;
		}else if( (BG.finWidth != width || BG.finHeight!=height ) &&
			  (BG.Width != BG.finWidth || BG.Height != BG.finHeight))
		{
		    fin_width = min(BG.Width, width);
		    fin_height = min(BG.Height, height);
		    BG.trgPixmap = ShadePixmap(BG.srcPixmap, 0, 0, fin_width, fin_height, gc, SHADING);
		}
		break ;
	case BGT_Center : /* more complicated case */
		if( BG.finWidth != width || BG.finHeight!=height )
		{
/*fprintf(stderr, "\n aterm RenderPixmap(): (BGT_Center)src pixmap is [%lu]",BG.srcPixmap);	*/
		    BG.trgPixmap = CenterPixmap( BG.srcPixmap,
						 BG.Width, BG.Height,
		                                 width, height, gc, SHADING );
		}
		break ;
	case BGT_Scale :
		if( BG.finWidth != width || BG.finHeight!=height )
		{
/*fprintf(stderr, "\n aterm RenderPixmap(): (BGT_Scale) src pixmap is [%lu]",BG.srcPixmap);*/
	    	    BG.trgPixmap = ScalePixmap( BG.srcPixmap,
						BG.Width, BG.Height,
		                                width, height, gc, SHADING );
		}
		break ;
	case BGT_ScaleH :
		if( BG.finWidth != width )
		{
	    	    BG.trgPixmap = ScalePixmap( BG.srcPixmap,
						BG.Width, BG.Height,
		                                width, BG.Height, gc, SHADING );
		    fin_height = BG.Height;
		}
		break ;
	case BGT_ScaleV :
		if( BG.finHeight!=height )
		{
	    	    BG.trgPixmap = ScalePixmap( BG.srcPixmap,
						BG.Width, BG.Height,
		                                BG.Width, height, gc, SHADING );
		    fin_width = BG.Width ;
		}
		break ;
	case BGT_NoTile :
		if( BG.finWidth != width || BG.finHeight!=height )
		{
	    	    BG.trgPixmap = GrowPixmap(  BG.srcPixmap,
						BG.Width, BG.Height,
		                                width, height, gc, SHADING );
		}
		break ;
	case BGT_NoTileH :
		if( BG.finWidth != width )
		{
	    	    BG.trgPixmap = GrowPixmap(   BG.srcPixmap,
		    				 BG.Width, BG.Height,
		                                 width, BG.Height, gc, SHADING );
	    	    fin_height = BG.Height;

		}
		break ;
	case BGT_NoTileV :
		if( BG.finHeight!=height )
		{
	    	    BG.trgPixmap = GrowPixmap(  BG.srcPixmap,
		    		                BG.Width, BG.Height,
		                    		BG.Width, height, gc, SHADING );
		    fin_width = BG.Width ;
		}
		break ;
	case BGT_Cut :

/*fprintf(stderr, "\n aterm RenderPixmap(): (BG_Cut)src pixmap is [%lu]",BG.srcPixmap); */
		BG.trgPixmap = CutWinPixmap( TermWin.vt, BG.srcPixmap,
					  BG.Width, BG.Height,
		                          width, height, gc,
					  SHADING );
		break ;
#ifdef _MYSTYLE_
	case BGT_MyStyle :
		BG.trgPixmap = RenderMyStylePixmap( BG.mystyle, BG.srcPixmap,
					            BG.Width, BG.Height,
		                                    width, height );
		if( BG.mystyle->texture_type == TEXTURE_PIXMAP)
		{
		    BG.srcPixmap = BG.mystyle->back_icon.pix ; /* so not to free it later */
		    BG.bMySource = False ;
		}
		break ;
#endif
    }

    XFreeGC(Xdisplay, gc); /* don't need anymore */
    if( BG.trgPixmap != None )
    {
	BG.finWidth = fin_width ;
	BG.finHeight = fin_height;
	XSync(Xdisplay, 0);
        XSetWindowBackgroundPixmap(Xdisplay, TermWin.vt,
    	                           BG.trgPixmap);
	TermWin.LastPixmapUsed = BG.srcPixmap ;
	BG.trgPixmapSet = 1 ;


	if( BG.trgPixmap != BG.srcPixmap )
	{/* don't need it anymore server has it */
	    XFreePixmap( Xdisplay, BG.trgPixmap );
	    XSync(Xdisplay, 0);
	}
	BG.trgPixmap = None ;
    }
    /* restore old handler so we can crash again ;) */
    XSetErrorHandler (oldXErrorHandler);

} /******************************* RenderPixmap **********************/
#endif      			   /* BACKGROUND_IMAGE || TRANSPARENT */


#ifdef BACKGROUND_IMAGE
/* we need this stuff only to load background image from file */

#ifdef USE_LIBASIMAGE
#ifndef LoadImage
Pixmap LoadImageWithMask( Display *dpy, Window w, unsigned long max_colors, const char* realfilename, Pixmap* pMask );
#endif
#endif

/* PROTO */
int
parse_pixmap_geom(const char *geom)
{
  int             w = 0, h = 0, x = 0, y = 0;
  int             flags, changed = 0;

    if (geom == NULL)	return 0;
    if (!strlen(geom))	return 0;

    if (!strcmp(geom, "?"))
    {
      static char     str[] = "[10000x10000+10000+10000]";	/* should be big enough */
	sprintf(str, "[%dx%d+%d+%d]",
		BG.srcWidth, BG.srcHeight, BG.srcX, BG.srcY );
	xterm_seq(XTerm_title, str);
	return 0;
    }
/*fprintf( stderr, "\n parse_pixmap_geom(): geometry is [%s]", geom );*/
    flags = XParseGeometry(geom, &x, &y, (unsigned int *) &w, (unsigned int *) &h);
    if(!(flags & XValue))  x = 0 ;
    if(!(flags & YValue))  y = 0 ;
    if(!(flags & WidthValue))  w = -1 ;
    if(!(flags & HeightValue))  h = -1 ;
    MIN_IT(x, 10000);
    MIN_IT(y, 10000);
    MIN_IT(w, 10000);
    MIN_IT(h, 10000);

    if( w != BG.srcWidth )
    {
        changed++;
        BG.srcWidth = w ;
    }
    if( h != BG.srcHeight )
    {
        changed++;
        BG.srcHeight = h ;
    }
    if( x != BG.srcX )
    {
        changed++;
        BG.srcX = x ;
    }
    if( y != BG.srcY )
    {
        changed++;
        BG.srcY = y ;
    }
/*fprintf( stderr, "\n parse_pixmap_geom(): geometry is [%dx%d+%d+%d]", w,h,x,y );    */
    return changed;
}

/* PROTO */
void
LoadBGPixmap(const char *file)
{

    XpmAttributes xpmAttr;
    char           *realfilename;
    assert(file != NULL);

    if (BG.srcPixmap != None && BG.bMySource )
    {
	XFreePixmap(Xdisplay, BG.srcPixmap);
	BG.srcPixmap = None;
    }

    if (*file != '\0')
    {
        /* search environment variables here too */
	if ((realfilename = (char *)File_find(file, ".xpm")) == NULL )
	{
#ifndef USE_LIBASIMAGE
	    print_error("couldn't load XPM file [%s]", file);
#endif
	}else
	{
	    xpmAttr.closeness = 30000;
	    xpmAttr.colormap = Xcmap;
	    xpmAttr.visual = Xvisual;
	    xpmAttr.depth = Xdepth;
	    xpmAttr.valuemask = (XpmCloseness | XpmColormap | XpmVisual |
	                          XpmDepth | XpmSize | XpmReturnPixels);
#ifdef USE_LIBASIMAGE
            if( (BG.srcPixmap = LoadImageWithMask( Xdisplay, Xroot, 256, realfilename, NULL )) !=
	            None )
	    {
	      Window root; int x, y ; unsigned int bw, depth ;
	       if( XGetGeometry( Xdisplay, BG.srcPixmap, &root, &x, &y,
	                         &(xpmAttr.width), &(xpmAttr.height),&bw, &depth )==0)
	       { xpmAttr.width = 0 ; xpmAttr.height = 0 ; }
	    }
#else
	    if( XpmReadFileToPixmap(Xdisplay, Xroot, realfilename, &BG.srcPixmap, NULL, &xpmAttr) != 0 )
	        print_error("couldn't load XPM file [%s]", realfilename);
#endif
	}
    }

    /* need to add geometry processing code here */

    if( BG.srcPixmap == None )
    {
	XSetWindowBackground(Xdisplay, TermWin.vt, PixColors[Color_bg]);
	BG.bMySource = 0 ;
	BG.Width = 0 ;
	BG.Height = 0;
	BG.trgPixmapSet = 0 ;
    }
    else
    {
	BG.bMySource = 1 ;
	BG.Width = xpmAttr.width;
	BG.Height = xpmAttr.height;
	if( BG.srcWidth > 0 || BG.srcHeight > 0 || BG.srcX > 0 || BG.srcY > 0 )
	{
	  int w, h;
          Pixmap tmp ;

    	    if( BG.srcWidth <=0 ) w = BG.Width ;
    	    else w = min(BG.Width-BG.srcX,BG.srcWidth);

    	    if( BG.srcHeight <=0 ) h = BG.Height ;
    	    else h = min(BG.Height-BG.srcY,BG.srcHeight);

    	    tmp = ShadePixmap(BG.srcPixmap, BG.srcX, BG.srcY, w, h,
	                      DefaultGC(Xdisplay, Xscreen ), &(BG.Shading) );
    	    if( tmp != None )
	    {
	        XFreePixmap( Xdisplay, BG.srcPixmap );
	        BG.srcPixmap = tmp ;
	        BG.Width = w ;
	        BG.Height = h ;
	    }
	}
	else if( !NO_NEED_TO_SHADE(BG.Shading) )
	{
	  Pixmap tmp ;
          GC gc = DefaultGC(Xdisplay, Xscreen );

    	    tmp = ShadePixmap(BG.srcPixmap, 0, 0, BG.Width, BG.Height,
			      DefaultGC(Xdisplay, Xscreen ), &(BG.Shading) );
    	    if( tmp != None )
	    {
	        XFreePixmap( Xdisplay, BG.srcPixmap );
	        BG.srcPixmap = tmp ;
	    }
	}
	RenderPixmap(1);
    }

    scr_touch();
}
#endif				/* BACKGROUND_IMAGE */
