
// Essai de compilation séparée
#ifdef NO
#include <windows.h>
#include "putty.h"

extern Config cfg;
extern int offset_width, offset_height ;
extern int font_width, font_height ;
extern COLORREF colours[NALLCOLOURS] ;
extern HWND MainHwnd ;
extern int BackgroundImageFlag ;
extern int PuttyFlag ;

int stricmp(const char *s1, const char *s2) ;
int GetSessionField( const char * session_in, const char * folder_in, const char * field, char * result ) ;
#endif

static void init_dc_blend(void);
static BOOL (WINAPI * pAlphaBlend)(HDC,int,int,int,int,HDC,int,int,int,int,BLENDFUNCTION) = 0 ;

//static HWND hwnd;

static HDC textdc;
static HBITMAP textbm;
static COLORREF colorinpixel;
static HDC colorinpixeldc;
static HBITMAP colorinpixelbm;
static HDC backgrounddc;
static HBITMAP backgroundbm;
static HDC backgroundblenddc;
static HBITMAP backgroundblendbm;
static BOOL bBgRelToTerm;

static int resizing;
static RECT size_before;


#define Alloc(p,t) (t *)malloc((p)*sizeof(t))
#define For(i,n) for ((i)=0;(i)<(n);(i)++)
#define iFor(n) For (i,n)
#define jFor(n) For (j,n)

#ifdef DLL
#define TARGET extern __declspec(dllexport)
#else
#define TARGET
#endif

static int ShrinkBitmapEnable = 1 ;
void SetShrinkBitmapEnable(int v) {
	if( v ) ShrinkBitmapEnable = 1 ;
	else ShrinkBitmapEnable = 0 ;
	}

typedef struct {
 WORD x,y;  // dimensions
 WORD l;    // bytes per scan-line (32-bit allignment)
 BYTE *b;   // bits of bitmap,3 bytes/pixel, BGR
} tWorkBMP;  // 24-bit working bitmap

void CreateWorkingBitmap (WORD dx,WORD dy,tWorkBMP *w)
{
 w->x=dx;
 w->y=dy;
 w->l=(dx+1)*3&0xfffc;
 w->b=Alloc(w->l*dy,BYTE);
}

HBITMAP CreateEmptyBitmap (WORD dx,WORD dy)
{
 HDC h=GetDC(NULL);
 HBITMAP b=CreateCompatibleBitmap(h,dx,dy);
 ReleaseDC (NULL,h);

 return (b);
}

void SetBMIHeader (BITMAPINFO *b,short dx,short dy)
{
 b->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
 b->bmiHeader.biWidth=dx;
 b->bmiHeader.biHeight=-dy;
 b->bmiHeader.biPlanes=1;
 b->bmiHeader.biBitCount=24;
 b->bmiHeader.biCompression=BI_RGB;
 b->bmiHeader.biSizeImage=0;
 b->bmiHeader.biXPelsPerMeter=1;
 b->bmiHeader.biYPelsPerMeter=1;
 b->bmiHeader.biClrUsed=0;
 b->bmiHeader.biClrImportant=0;
}


POINT GetBitmapSize (HBITMAP h)
{
POINT p;
BITMAP o;
GetObject (h,sizeof(o),&o);
p.x=o.bmWidth;
p.y=o.bmHeight;
return (p);
}

void OpenBitmapForWork (HBITMAP b,tWorkBMP *w)
{
BITMAPINFO s;
HDC h=GetDC(NULL);
POINT v=GetBitmapSize(b);
CreateWorkingBitmap (v.x,v.y,w);
SetBMIHeader (&s,w->x,w->y);
GetDIBits (h,b,0,w->y,w->b,&s,DIB_RGB_COLORS);
ReleaseDC (NULL,h);
}

void SaveWorkingBitmap (tWorkBMP *w,HBITMAP b)
{
 BITMAPINFO s;
 HDC h=GetDC(NULL);
 SetBMIHeader (&s,w->x,w->y);
 SetDIBits (h,b,0,w->y,w->b,&s,DIB_RGB_COLORS);
 ReleaseDC (NULL,h);
}

void ShrinkWorkingBitmap (tWorkBMP *a,tWorkBMP *b,WORD bx,WORD by)
{
 BYTE *uy=a->b,*ux,i;
 WORD x,y,nx,ny=0;
 DWORD df=3*bx,nf=df*by,j;
 float k,qx[2],qy[2],q[4],*f=Alloc(nf,float);

 CreateWorkingBitmap (bx,by,b);

 jFor (nf) f[j]=0;
 j=0;

 For (y,a->y) {
  ux=uy;
  uy+=a->l;
  nx=0;
  ny+=by;

  if (ny>a->y) {

   qy[0]=1-(qy[1]=(ny-a->y)/(float)by);

   For (x,a->x) {

    nx+=bx;

    if (nx>a->x) {
     qx[0]=1-(qx[1]=(nx-a->x)/(float)bx);

     iFor (4) q[i]=qx[i&1]*qy[i>>1];

     iFor (3) {
      f[j]+=(*ux)*q[0];
      f[j+3]+=(*ux)*q[1];
      f[j+df]+=(*ux)*q[2];
      f[(j++)+df+3]+=(*(ux++))*q[3];
     }
    }
    else iFor (3) {
     f[j+i]+=(*ux)*qy[0];
     f[j+df+i]+=(*(ux++))*qy[1];
    }
    if (nx>=a->x) nx-=a->x;
     if (!nx) j+=3;
   }
  }
  else {
   For (x,a->x) {

    nx+=bx;

    if (nx>a->x) {
     qx[0]=1-(qx[1]=(nx-a->x)/(float)bx);
     iFor (3) {
      f[j]+=(*ux)*qx[0];
      f[(j++)+3]+=(*(ux++))*qx[1];
     }
    }
    else iFor (3) f[j+i]+=*(ux++);

    if (nx>=a->x) nx-=a->x;
     if (!nx) j+=3;
   }
   if (ny<a->y) j-=df;
  }
  if (ny>=a->y) ny-=a->y;
 }

 nf=0;
 k=bx*by/(float)(a->x*a->y);
 uy=b->b;

 For (y,by) {
  jFor (df) uy[j]=(unsigned char)(f[nf++]*k+.5);
  uy+=b->l;
 }

 free (f);
}

TARGET HBITMAP ShrinkBitmap (HBITMAP a,WORD bx,WORD by)
// creates and returns new bitmap with dimensions of
// [bx,by] by shrinking bitmap a both [bx,by] must be less or equal
// than the dims of a, unless the result is nonsense
{
 tWorkBMP in,out;
 HBITMAP b=CreateEmptyBitmap(bx,by);
 OpenBitmapForWork (a,&in);
 ShrinkWorkingBitmap (&in,&out,bx,by);
 free (in.b);
 SaveWorkingBitmap (&out,b);
 free (out.b);
 return (b);
}


static void fill_dc(HDC dc, int width, int height, COLORREF color)
{
    HBRUSH clrBrush = CreateSolidBrush(color);
    HPEN clrPen = CreatePen(PS_SOLID, 0, color);

    HBRUSH oldBrush;
    HPEN oldPen;

    oldBrush = SelectObject(dc, clrBrush);
    oldPen = SelectObject(dc, clrPen);

    Rectangle(dc, 0, 0, width, height);

    SelectObject(dc, oldBrush);
    SelectObject(dc, oldPen);
}

static BOOL load_wallpaper_bmp(HBITMAP* rawImage, int* style, int* x, int* y)
{
    LONG lRes;
    HKEY kDesktop;
    DWORD pathLen = MAX_PATH;
    DWORD numBufLen = 10;
    char wpPath[MAX_PATH];
    char wpStyleBuf[10];
    char wpTileBuf[10];

    int wpStyle = -1;
    int wpTile = -1;

    // NOTE: In the non-wallpaper case (i.e., load_file_bmp), we load parameters
    // like x, y and style from cfg, but in the wallpaper case we ignore our
    // stored configuration and get that information from the system.

    // ENHANCE: It's possible to set WallpaperOriginX and WallpaperOriginY to
    // specify an exact position for the start of the wallpaper, but this
    // function doesn't support that yet.  I don't think it's possible to set
    // it through the normal UI anyway, you have to hack the registry to do it.
    // For now, we'll never return an (x,y) positioning request to the caller.
    *x = *y = 0;

    lRes = RegOpenKeyEx(
        HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ, &kDesktop
    );
    if(lRes != ERROR_SUCCESS)
    {
        RegCloseKey(kDesktop);
        return FALSE; // TODO: Should the error be reported to the user here?
    }

    lRes = RegQueryValueEx(kDesktop, "Wallpaper", NULL, NULL, wpPath, &pathLen);
    if(lRes != ERROR_SUCCESS)
    {
        RegCloseKey(kDesktop);
        return FALSE; // TODO: Should the error be reported to the user here?
    }

    lRes = RegQueryValueEx(
        kDesktop, "WallpaperStyle", NULL, NULL, wpStyleBuf, &numBufLen
    );
    if(lRes == ERROR_SUCCESS)
        wpStyle = atoi(wpStyleBuf);

    lRes = RegQueryValueEx(
        kDesktop, "TileWallpaper", NULL, NULL, wpTileBuf, &numBufLen
    );
    if(lRes == ERROR_SUCCESS)
        wpTile = atoi(wpTileBuf);

    if(wpStyle < 0 && wpStyle > 3)
        wpStyle = 0;  // Default to tile.
    else if(wpTile > 0)
        wpStyle = 0;  // Force tile.
    else if(wpStyle == 0 && wpTile == 0)
        wpStyle = 1;  // For Explorer, wpStyle == wpTile == 0 means center, and
                      // it doesn't ever set wpStyle to 1.  We call wpStyle == 1
                      // center and don't use wpTile, to simplify things after
                      // this point.

    RegCloseKey(kDesktop);

    *rawImage = LoadImage(
        NULL, wpPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE
    );
    if(*rawImage == 0)
        return FALSE; // TODO: Should the error be reported to the user here?

    *style = wpStyle;

    return TRUE;
}

static BOOL load_file_bmp(HBITMAP* rawImage, int* style, int* x, int* y)
{
    *x = cfg.bg_image_abs_x;
    *y = cfg.bg_image_abs_y;
    *style = cfg.bg_image_style;

    *rawImage = LoadImage(
        NULL, cfg.bg_image_filename.path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE
    );
    if(*rawImage == 0)
        return FALSE; // TODO: Should the error be reported to the user here?

    return TRUE;
}

#include <setjmp.h>
#include "jpeglib.h"
jmp_buf JPEG_bailout;
int usePalette = 0;
char *loadError = NULL;	
COLORREF skycolour = RGB(0, 0, 255);

HBITMAP CreateHBitmap(int w, int h, LPVOID *lpBits)
{
	HBITMAP bitmap;
	BITMAPINFOHEADER BIH ;
	int iSize = sizeof(BITMAPINFOHEADER) ;
	memset(&BIH, 0, iSize);

	// Fill in the header info.
	BIH.biSize = iSize;
	BIH.biWidth = w;
	BIH.biHeight = h;
	BIH.biPlanes = 1;
	BIH.biBitCount = 24;
	BIH.biCompression = BI_RGB;
	HDC hDC = CreateCompatibleDC(NULL);
	bitmap = CreateDIBSection(hDC,
							(BITMAPINFO*)&BIH,
							DIB_RGB_COLORS,
							lpBits,
							NULL,
							0);
	DeleteDC(hDC);
	return bitmap;
}

//  LOADJPEGIMAGE  --  Load JPEG image into memory
HBITMAP loadJPEGimage(FILE *input_file, HGLOBAL *LimageBitmap,
				   int *LsizeX, int *LsizeY)
{
	int i;
	LPBITMAPINFOHEADER bh;
	DWORD bmpsize;
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	JSAMPARRAY colormap;
	LPBYTE pix;
	int linewid;
	int pixbytes;
	static LPBYTE sl = NULL;
	static HGLOBAL imageBitmap = NULL;		// In-memory bitmap

	sl = NULL;
	imageBitmap = NULL;
	if (setjmp(JPEG_bailout) != 0) {
		/*	Since we arrive here via longjmp() from
			parts unknown, we may have allocated
			the line buffer or bitmap prior to bailing
			out.  If they've been allocated, release them.  */

		if (sl != NULL) {
			GlobalFree(sl);
			sl = NULL;
		}
		if (imageBitmap != NULL) {
			GlobalFree(imageBitmap);
			imageBitmap = NULL;
		}
		return NULL;
	}
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, input_file);
	jpeg_read_header(&cinfo, TRUE);
	cinfo.desired_number_of_colors = 254;
	cinfo.quantize_colors = usePalette;
	jpeg_start_decompress(&cinfo);

	pixbytes = (usePalette ? 1 : 3);
	sl = GlobalAlloc(GMEM_FIXED, cinfo.output_width * pixbytes);
	if (sl == NULL) {
		loadError = "Cannot allocate JPEG decoder row buffer";
		return NULL;
	}

	linewid = ((((cinfo.output_width * pixbytes) + (sizeof(LONG) - 1)) / sizeof(LONG)) * sizeof(LONG));
	bmpsize = sizeof(BITMAPINFOHEADER) +
		(usePalette ? (256 * sizeof(RGBQUAD)) : 0) +
		(linewid * cinfo.output_height);

	imageBitmap = GlobalAlloc(GMEM_FIXED, bmpsize);
	if (imageBitmap == NULL) {
		loadError = "Cannot allocate bitmap for decoded JPEG image";
		GlobalFree(sl);
		return NULL;
	}

	//	Plug in header fields with information from cinfo

	bh = (LPBITMAPINFOHEADER) imageBitmap;
	pix = ((LPBYTE) imageBitmap) + sizeof(BITMAPINFOHEADER) +
			(usePalette ? (256 * sizeof(RGBQUAD)) : 0);
	bh->biSize = sizeof(BITMAPINFOHEADER);
	bh->biWidth = cinfo.output_width;
	bh->biHeight = cinfo.output_height;
	bh->biPlanes = 1;
	bh->biBitCount = usePalette ? 8 : 24;
	bh->biCompression = BI_RGB;
	bh->biSizeImage = 0;
	bh->biXPelsPerMeter = bh->biYPelsPerMeter = 2835;
	bh->biClrUsed = 0;
	bh->biClrImportant = 0;

	/*	Construct the palette from the colour map optimised
		for the JPEG file.  */

	if (usePalette) {
		colormap = cinfo.colormap;
		for (i = 0; i < cinfo.actual_number_of_colors; i++) {
			if (cinfo.num_components == 1) {
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbRed =
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbGreen =
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbBlue = GETJSAMPLE(colormap[0][i]);
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbReserved = 0;
			} else {
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbRed = GETJSAMPLE(colormap[0][i]);
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbGreen = GETJSAMPLE(colormap[1][i]);
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbBlue = GETJSAMPLE(colormap[2][i]);
				((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbReserved = 0;
			}
		}

		/*	Plug black and our text colour in the last two slots
			of the palette so we canbe sure they're available.  */
	
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbRed =
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbGreen =
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbBlue =
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbReserved = 0;

		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbRed = GetRValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbGreen = GetGValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbBlue = GetBValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbReserved = 0;
	}

	//	Return scan lines and transfer to the pixel array

	BYTE *pDst = NULL;
	HBITMAP hBitmap = CreateHBitmap(bh->biWidth, bh->biHeight, (void**)&pDst);
	int nStorageWidth = ((bh->biWidth * 24 + 31) & ~31) >> 3; //dword alignment
	JSAMPARRAY ppDst = &pDst;
/*
	px = pix + (linewid * (bh->biHeight - 1));
	for (i = 0; i < (int) cinfo.output_height; i++) {
		unsigned char *slp[1] = { sl };
		jpeg_read_scanlines(&cinfo, slp, 1);
		if (usePalette) {
			memcpy(px, sl, cinfo.output_width);
		} else {
			int j, k;

			if (cinfo.num_components == 3) {
				for (j = k = 0; j < (int) cinfo.output_width; j++, k += 3) {
					px[k] = sl[k + 2];
					px[k + 1] = sl[k + 1];
					px[k + 2] = sl[k];
				}
			} else {
				for (j = k = 0; j < (int) cinfo.output_width; j++, k += 3) {
					px[k] = sl[j];
					px[k + 1] = sl[j];
					px[k + 2] = sl[j];
				}
			}
		}
		px -= linewid;
	}
*/
pDst = pDst + (cinfo.output_height-1)*nStorageWidth ;
while (cinfo.output_scanline < cinfo.output_height) {
      jpeg_read_scanlines (&cinfo, ppDst, 1);

	  if(cinfo.out_color_components==3) {
		  //swap R & B
		  BYTE* p = pDst;
		  int i ;
		  for( i=0;i<bh->biWidth;i++) {
			  BYTE r = p[0];
			  p[0] = p[2];
			  p[2] = r;
			  p += 3;
		  }
	  }

	  //pDst += nStorageWidth;
	  pDst -= nStorageWidth;
	}

	GlobalFree(sl);
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	 
	*LsizeX = (int) bh->biWidth;
	*LsizeY = (int) bh->biHeight;
	*LimageBitmap = imageBitmap;
	return hBitmap;
}


static BOOL load_file_jpeg(HBITMAP* rawImage, int* style, int* x, int* y) {
    *x = cfg.bg_image_abs_x;
    *y = cfg.bg_image_abs_y;
    *style = cfg.bg_image_style;
    int res=TRUE, LsizeX, LsizeY ;
    FILE *fp ;
    HGLOBAL LimageBitmap = NULL ;

	
    if(  ( fp=fopen( cfg.bg_image_filename.path, "rb" ) ) == NULL ) return FALSE ;
   
*rawImage = loadJPEGimage(fp, &LimageBitmap,&LsizeX, &LsizeY) ;
if( rawImage == NULL ) res =FALSE ;    
     fclose( fp ) ;

    return res;
}

static HBITMAP CreateDIBSectionWithFileMapping(HDC dc, int width, int height, HANDLE fmap)
{
    BITMAPINFOHEADER BMI;
    
    BMI.biSize = sizeof(BITMAPINFOHEADER);
    BMI.biWidth = width;
    BMI.biHeight = height;
    BMI.biPlanes = 1;
    BMI.biBitCount = 32;
    BMI.biCompression = BI_RGB;
    BMI.biSizeImage = 0;
    BMI.biXPelsPerMeter = 0;
    BMI.biYPelsPerMeter = 0;
    BMI.biClrUsed = 0;
    BMI.biClrImportant = 0;
    
    return(CreateDIBSection(dc, (BITMAPINFO *)&BMI, DIB_RGB_COLORS, 0, fmap, 0));
}

static void init_dc_blend(void) 
{
    //HMODULE * msimg32_dll = LoadLibrary("msimg32.dll");
    HMODULE msimg32_dll = LoadLibrary("msimg32.dll");
    
    if(msimg32_dll) 
        pAlphaBlend = GetProcAddress(msimg32_dll, "AlphaBlend");
    
    if(pAlphaBlend) 
    {
    	HDC hdc = GetDC(hwnd);
    	
    	// Create one pixel size bitmap for use in color_blend.
        colorinpixeldc = CreateCompatibleDC(hdc);
        colorinpixelbm = CreateCompatibleBitmap(hdc, 1, 1);
        SelectObject(colorinpixeldc, colorinpixelbm);
        colorinpixel = 0;
        SetPixelV(colorinpixeldc, 0, 0, colorinpixel);
        
        ReleaseDC(hwnd, hdc);
    }
}

static void color_blend(
    HDC destDc, int x, int y, int width, int height, 
    COLORREF alphacolor, int opacity)
{
    if(pAlphaBlend) {
    	// Fast alpha blending for Win98&2000 and newer...
        BLENDFUNCTION blender;

        // Create one pixel size bitmap for use in color_blend.
        if(colorinpixel != alphacolor) 
        {
            colorinpixel = alphacolor;
            SetPixelV(colorinpixeldc, 0, 0, alphacolor);
        }
        
        blender.BlendOp = AC_SRC_OVER;
        blender.BlendFlags = 0;
        blender.SourceConstantAlpha = (0xff * opacity) / 100;
        blender.AlphaFormat = 0;
        
        (*pAlphaBlend)(destDc, x, y, width, height, colorinpixeldc, 0, 0, 1, 1, blender);
    } 
    else
    {
        // Slow alpha blending for Win95&NT...
        // Note: Only tested with WinXP, should work on 95/NT.. probably.
        int i, alphacolorR, alphacolorG, alphacolorB, bk_opacity;
        HBITMAP tmpbm;
        HDC tmpdc;
        static HANDLE fmap;
        static int fmap_size;
        static unsigned char * pRGB;
        
        if(fmap_size < width * height * 4)
        {
            if(fmap) {
            	UnmapViewOfFile(pRGB);
                CloseHandle(fmap);
            }
            fmap_size = width * height * 4;
            fmap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, fmap_size, NULL);
            pRGB = MapViewOfFile(fmap, FILE_MAP_ALL_ACCESS, 0, 0, fmap_size);
        }
        
        // Create DIBSection so we get pixels easily.
        tmpdc = CreateCompatibleDC(destDc);
        tmpbm = CreateDIBSectionWithFileMapping(destDc, width, height, fmap);
        SelectObject(tmpdc, tmpbm);
        
        // Copy bitmap to temporary bitmap for easy pixel access.
        BitBlt(tmpdc, 0, 0, width, height, destDc, x, y, SRCCOPY);

        // Moved stuff out from the loop
        alphacolorR = GetRValue(alphacolor) * opacity;
        alphacolorG = GetGValue(alphacolor) * opacity;
        alphacolorB = GetBValue(alphacolor) * opacity;
	bk_opacity = 100 - opacity;

        for(i=0; i<width*height*4; i+=4)
        {
	    pRGB[i + 0] = (pRGB[i + 0] * bk_opacity + alphacolorB) / 100;
            pRGB[i + 1] = (pRGB[i + 1] * bk_opacity + alphacolorG) / 100;
            pRGB[i + 2] = (pRGB[i + 2] * bk_opacity + alphacolorR) / 100;
        }
        
        // Copy temporary bitmap back to original
        BitBlt(destDc, x, y, width, height, tmpdc, 0, 0, SRCCOPY);
        
        DeleteObject(tmpbm);
        DeleteDC(tmpdc);
    }
}

#include <math.h>
static void color_opacity_gradient( HDC destDc, int x, int y, int width, int height, COLORREF alphacolor, int style ) {
	int i, alphacolorR, alphacolorG, alphacolorB, bk_opacity, opacity, h, w ;
	double l ;
        HBITMAP tmpbm;
        HDC tmpdc;
        static HANDLE fmap;
        static int fmap_size;
        static unsigned char * pRGB;
	int OpacityMin = 0, OpacityMax = 100 ;
	
	char buf[256] = "" ;
	if( GetSessionField( cfg.sessionname, cfg.folder, "BgOpacityRange", buf ) ) { 
		sscanf( buf, "%d-%d", &OpacityMin, &OpacityMax ) ; 
		if( OpacityMin == OpacityMax ) { OpacityMin = 0 ; OpacityMax = 100 ; }
		}
        
        if(fmap_size < width * height * 4) {
		if(fmap) { UnmapViewOfFile(pRGB) ; CloseHandle(fmap) ; }
		fmap_size = width * height * 4;
		fmap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, fmap_size, NULL);
		pRGB = MapViewOfFile(fmap, FILE_MAP_ALL_ACCESS, 0, 0, fmap_size);
		}
        
        // Create DIBSection so we get pixels easily.
        tmpdc = CreateCompatibleDC(destDc);
        tmpbm = CreateDIBSectionWithFileMapping(destDc, width, height, fmap);
        SelectObject(tmpdc, tmpbm);
        
        // Copy bitmap to temporary bitmap for easy pixel access.
        BitBlt(tmpdc, 0, 0, width, height, destDc, x, y, SRCCOPY);

        opacity = 0 ; bk_opacity = 100 ; alphacolorR = 0 ; alphacolorG = 0 ; alphacolorB = 0 ;
	w = 0 ; h = 0 ;

        for(i=0; i<width*height*4; i+=4) {
		
		switch( style ) {
			case 2: // De bas en haut
			if( (i%(4*width)) == 0 ) {
				h++ ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * (1.0*h)/(1.0*height) ;
				opacity = 100 - opacity ;
				}
				break ;
			case 3: // De gauche à droite
				w++ ; if( w >= width ) { w = 0 ; }
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * (1.0*w)/(1.0*width) ;
				break ;
			case 4: // De droite à gauche
				w++ ; if( w >= width ) { w = 0 ; }
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * (1.0*w)/(1.0*width) ;
				opacity = 100 - opacity ;
				break ;
			case 5: // Du centre vers l'extérieur
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*width/2.0-w,2.0)+pow(1.0*height/2.0-h,2.0) ) / 
					sqrt( pow(1.0*width/2.0,2.0)+pow(1.0*height/2.0,2.0) );
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				break ;
			case 6: // De l'extérieur vers le centre
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*width/2.0-w,2.0)+pow(1.0*height/2.0-h,2.0) ) / 
					sqrt( pow(1.0*width/2.0,2.0)+pow(1.0*height/2.0,2.0) );
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				opacity = 100 - opacity ;					
				break ;
			case 7:
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*w,2.0)+pow(1.0*h,2.0) )/sqrt( pow(1.0*width,2.0)+pow(1.0*height,2.0) ) ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				break ;
			case 8:
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*w,2.0)+pow(1.0*h,2.0) )/sqrt( pow(1.0*width,2.0)+pow(1.0*height,2.0) ) ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				opacity = 100 - opacity ;
				break ;
			case 9:
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*(width-w),2.0)+pow(1.0*h,2.0) )/sqrt( pow(1.0*width,2.0)+pow(1.0*height,2.0) ) ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				break ;
			case 10:
				if( (i%(4*width)) == 0 ) { h++ ; }
				w++ ; if( w >= width ) { w = 0 ; }
				l = sqrt( pow(1.0*(width-w),2.0)+pow(1.0*h,2.0) )/sqrt( pow(1.0*width,2.0)+pow(1.0*height,2.0) ) ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * l ;
				opacity = 100 - opacity ;
				break ;
			default: // De haut en bas
			if( (i%(4*width)) == 0 ) {
				h++ ;
				opacity = OpacityMin + 1.0*( OpacityMax-OpacityMin ) * (1.0*h)/(1.0*height) ;
				}
				break ;
			}
		if( opacity < 0 ) opacity = 0 ;
		if( opacity > 100 ) opacity = 100 ;

		alphacolorR = GetRValue(alphacolor) * opacity;
		alphacolorG = GetGValue(alphacolor) * opacity;
		alphacolorB = GetBValue(alphacolor) * opacity;
		bk_opacity = 100 - opacity ;

		pRGB[i + 0] = (pRGB[i + 0] * bk_opacity + alphacolorB) / 100;
		pRGB[i + 1] = (pRGB[i + 1] * bk_opacity + alphacolorG) / 100;
		pRGB[i + 2] = (pRGB[i + 2] * bk_opacity + alphacolorR) / 100;
		}
        
        // Copy temporary bitmap back to original
        BitBlt(destDc, x, y, width, height, tmpdc, 0, 0, SRCCOPY);
        
        DeleteObject(tmpbm);
        DeleteDC(tmpdc);
	}

void CreateBlankBitmap( HBITMAP * rawImage, const int width, const int height ) {
	HDC dc= CreateCompatibleDC(NULL);
	BITMAPINFO bi;
	ZeroMemory( &bi.bmiHeader, sizeof(BITMAPINFOHEADER) );
	bi.bmiHeader.biWidth=width;     // Set size you need
	bi.bmiHeader.biHeight=height;    // Set size you need
	bi.bmiHeader.biPlanes=1;
	bi.bmiHeader.biBitCount=24; // Can be 8, 16, 32 bpp or
	bi.bmiHeader.biSizeImage=0;
	bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
	bi.bmiHeader.biClrUsed= 0;
	bi.bmiHeader.biClrImportant= 0;
	VOID *pvBits;
	*rawImage = CreateDIBSection( dc,&bi,DIB_RGB_COLORS,&pvBits,NULL,0 );
	ReleaseDC(NULL, dc) ;

	HDC hDC = GetDC(hwnd);
	HDC hDCDst = CreateCompatibleDC(hDC); // memory device context for dest	bitmap
	ReleaseDC(NULL, hDC);

	// hdcMem contains your rendered particle
	
	HBRUSH hBrush = CreateSolidBrush(RGB(255,0,0));
	// Paints the rectangular band with the brush
	RECT Rect = {0, 0, width-1, height-1};
	FillRect(hDCDst, &Rect, hBrush);
	// Deletes the brush
	DeleteObject(hBrush);

	HGDIOBJ holdDIBDst = SelectObject(hDCDst, *rawImage);	
	
	// transfer the image to your DIB bitmap
	BitBlt(hDCDst, 0, 0 ,width, height, hDC, 0, 0, SRCCOPY);

	// clean up
	SelectObject(hDCDst, holdDIBDst);
	DeleteDC(hDCDst);
	}
	
BOOL load_bg_bmp()
{
    BOOL bRes;
    HBITMAP rawImage = NULL;
    BITMAP rawImageInfo;
    HDC hdcPrimary;
    HDC bmpdc;
    int deskWidth, deskHeight, clientWidth, clientHeight;
    int x, y;
    int style;

    // TODO: If cfg.bg_image_style == 1, we should use the system wallpaper
    // background color instead of this.  Probably just pass this as a parameter
    // to load_wallpaper_bmp so it can override this default while it's
    // accessing the registry anyway.
    COLORREF backgroundcolor = colours[258]; // Default Background
    COLORREF alphacolor = backgroundcolor;

    // Start off assuming this is true.
    bBgRelToTerm = cfg.bg_image_abs_fixed;
	
    RECT clientRect;
    GetWindowRect( MainHwnd, &clientRect ) ;
    clientWidth = clientRect.right-clientRect.left+1 ;
    clientHeight = clientRect.bottom-clientRect.top+1 ;

    switch(cfg.bg_type)
    {
        // Solid
    case 0:
        // No bitmap file to load.  We'll handle this case below.
        break;

        // Wallpaper
    case 1:
        backgroundcolor = GetSysColor(COLOR_BACKGROUND);
        bBgRelToTerm = FALSE; // Wallpaper is never positioned relative to term.
        if(!load_wallpaper_bmp(&rawImage, &style, &x, &y))
            rawImage = NULL; // Make sure rawImage is still NULL.
        break;

        // Image
    case 2:
    	{
	backgroundcolor = GetSysColor(COLOR_BACKGROUND) ;
	if( cfg.bg_image_filename.path[0] == '#' ) {
		int r=0,g=0,b=0;
		sscanf( cfg.bg_image_filename.path, "#%02X%02X%02X", &r, &g, &b ) ;
		backgroundcolor = RGB( r, g, b ) ;
		BYTE *pDst = NULL;
		rawImage = CreateHBitmap(10, 10, (void**)&pDst);
		style = 4 ;
		}
    	else if( !stricmp( cfg.bg_image_filename.path+strlen(cfg.bg_image_filename.path)-4, ".jpg" ) ) {
    		if(!load_file_jpeg(&rawImage, &style, &x, &y))
        	    rawImage = NULL; // Make sure rawImage is still NULL.
    		}
    	else if( !stricmp( cfg.bg_image_filename.path+strlen(cfg.bg_image_filename.path)-5, ".jpeg" ) ) {
    		if(!load_file_jpeg(&rawImage, &style, &x, &y))
        	    rawImage = NULL; // Make sure rawImage is still NULL.
    		}
    	else 
        if(!load_file_bmp(&rawImage, &style, &x, &y))
            rawImage = NULL; // Make sure rawImage is still NULL.
        break;
	}
    }

    hdcPrimary = GetDC(hwnd);
    deskWidth = GetDeviceCaps(hdcPrimary, HORZRES);
    deskHeight = GetDeviceCaps(hdcPrimary, VERTRES);


	// Securite pour ne pas depacer les limites de l'ecran principal
//debug_log("%d %d %d %d %d %d %d\n",cfg.bg_image_abs_fixed,clientRect.left,clientRect.top,clientRect.right,clientRect.bottom,deskWidth,deskHeight );
	if( (bBgRelToTerm == 0) 
		&&((clientRect.right>deskWidth)||(clientRect.bottom>deskHeight)) ) {
		//DeleteObject(rawImage); rawImage = NULL ;
		bBgRelToTerm = 1 ;
		}

    if(rawImage == NULL)
    {
        // Create a solid bitmap.  We'll get here in two cases: either the user
        // selected the Solid background option, or the attempt to do something
        // fancier (use the system wallpaper or an image file) failed.
        /*
        backgrounddc = CreateCompatibleDC(hdcPrimary);
        backgroundbm
            = CreateCompatibleBitmap(hdcPrimary, deskWidth, deskHeight);
        SelectObject(backgrounddc, backgroundbm);
        */
        // Do not create anything, use default 'no background'-code instead.
    }
    else
    {
        // We've managed to load a good image.  Now, we need to manipulate it to
        // the right size, location, etc.

        // Find the width and height of the image we just loaded.
        GetObject(rawImage, sizeof(rawImageInfo), &rawImageInfo);

        // Create a temporary DC to wrap the raw image.
        bmpdc = CreateCompatibleDC(hdcPrimary);
        SelectObject(bmpdc, rawImage);

        // Create a memory DC that has a new bitmap of the appropriate final
        // image size.
        textdc = CreateCompatibleDC(hdcPrimary);
        textbm = CreateCompatibleBitmap(hdcPrimary, deskWidth, deskHeight);
        SelectObject(textdc, textbm);

        backgrounddc = CreateCompatibleDC(hdcPrimary);
        backgroundbm
            = CreateCompatibleBitmap(hdcPrimary, deskWidth, deskHeight);
        SelectObject(backgrounddc, backgroundbm);

	switch(style)
        {
        case 0: { // Tile
             for(y = 0; y < deskHeight; y += rawImageInfo.bmHeight)
            {
                for(x = 0; x < deskWidth; x += rawImageInfo.bmWidth)
                {
                    bRes = BitBlt(
                        backgrounddc,
                        x, y, rawImageInfo.bmWidth, rawImageInfo.bmHeight,
                        bmpdc, 0, 0, SRCCOPY
                    );
                }
            }
           }
           break;

        case 1:    // Center

            // Calculate x & y, ignoring values they may already have, then drop
            // down to the (X,Y) placement case below.

            x = (deskWidth - rawImageInfo.bmWidth) / 2;
            y = (deskHeight - rawImageInfo.bmHeight) / 2;

        case 3: {  // Place at given (X,Y)
            // Start out with a background color fill.
            fill_dc(backgrounddc, deskWidth, deskHeight, backgroundcolor);

            bRes = BitBlt(
                backgrounddc,
                x, y, rawImageInfo.bmWidth, rawImageInfo.bmHeight,
                bmpdc, 0, 0, SRCCOPY
            );
            break;
            }

        case 2: // Stretch
            bRes = StretchBlt(
                backgrounddc, 0, 0, deskWidth, deskHeight,
                bmpdc, 0, 0, rawImageInfo.bmWidth, rawImageInfo.bmHeight,
                SRCCOPY
            );

            break;

	case 4: // blank background
		fill_dc(backgrounddc, deskWidth, deskHeight, backgroundcolor) ;
		break ;
	
	case 5: // Stretch à la taille de la fenêtre
		{
		if( (ShrinkBitmapEnable)&&(clientWidth<rawImageInfo.bmWidth)&&(clientHeight<rawImageInfo.bmHeight) ) {
			HBITMAP newhbmpBMP ;
			if( (newhbmpBMP = ShrinkBitmap( rawImage,clientWidth,clientHeight)) != NULL ) {
				DeleteDC(bmpdc) ;
				bmpdc = CreateCompatibleDC(0) ;
				DeleteDC(backgrounddc);backgrounddc = GetDC(hwnd);
				SelectObject(bmpdc, newhbmpBMP ) ;
				BitBlt(backgrounddc, 0, 0,clientWidth,clientHeight, bmpdc, 0, 0, SRCCOPY ) ;
				DeleteObject(newhbmpBMP);
				}
			else
			bRes = StretchBlt( backgrounddc,0,0,clientWidth,clientHeight,bmpdc,0,0,rawImageInfo.bmWidth,rawImageInfo.bmHeight,SRCCOPY);
			}
		else
			bRes = StretchBlt( backgrounddc,0,0,clientWidth,clientHeight,bmpdc,0,0,rawImageInfo.bmWidth,rawImageInfo.bmHeight,SRCCOPY);
		}
		break ;
        }

        DeleteObject(rawImage);
        DeleteDC(bmpdc);

        // Create a version of the background DC with opacity already applied
        // for fast screen fill in areas with no text.

        backgroundblenddc = CreateCompatibleDC(hdcPrimary);
        backgroundblendbm = CreateCompatibleBitmap(
            hdcPrimary, deskWidth, deskHeight
        );
        SelectObject(backgroundblenddc, backgroundblendbm);
        BitBlt(
            backgroundblenddc, 0, 0, deskWidth, deskHeight,
            backgrounddc, 0, 0, SRCCOPY
        );
	
	if( cfg.bg_opacity >= 0 ) 
		{ color_blend( backgroundblenddc, 0, 0, deskWidth, deskHeight, alphacolor, cfg.bg_opacity); }
	else 
		{ 
		if( bBgRelToTerm == 1 ) {
			deskWidth = clientWidth ;
			deskHeight = clientHeight ;
			}
		
		color_opacity_gradient( backgroundblenddc, 0, 0, deskWidth, deskHeight, alphacolor, -cfg.bg_opacity ); 
		}
    }

    ReleaseDC(hwnd, hdcPrimary);
    return TRUE;
}

static void paint_term_edges(HDC hdc, LONG paint_left, LONG paint_top, LONG paint_right, LONG paint_bottom) 
{
    if(backgrounddc == 0)
        load_bg_bmp();

    if(backgrounddc)
    {
        LONG topLeftX = paint_left;
        LONG topLeftY = paint_top;
        LONG width = (paint_right - paint_left);
        LONG height = (paint_bottom - paint_top);
        HDC srcdc = backgroundblenddc;
        POINT srcTopLeft;
        RECT size_now;
        srcTopLeft.x = topLeftX;
        srcTopLeft.y = topLeftY;
		
        if(!bBgRelToTerm)
            ClientToScreen(hwnd, &srcTopLeft);

        if(!srcdc)
            srcdc = backgrounddc;

	if(resizing)
	{
	    GetClientRect(hwnd, &size_now);
	    if(size_now.bottom > size_before.bottom || size_now.right > size_before.right)
	    {
	    	// Draw on full area on resize.
	        BitBlt(hdc, topLeftX, topLeftY, width, height, srcdc, srcTopLeft.x, srcTopLeft.y, SRCCOPY);
	        
	        return;
            }
	}
//debug_log("1: %d %d %d %d\n",size_before.top,size_before.bottom,size_before.left,size_before.right) ;
//debug_log("2: %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %d\n",topLeftX,topLeftY,width,height,srcTopLeft.x,srcTopLeft.y,size_now.top,size_now.bottom,size_now.left,size_now.right,resizing) ;
	
        // Draw top edge
        BitBlt(
            hdc, topLeftX, topLeftY, width, offset_height,
            srcdc, srcTopLeft.x, srcTopLeft.y, SRCCOPY
        );
        // Draw left edge
        BitBlt(
            hdc, topLeftX, topLeftY+1, offset_width, height-2,
            srcdc, srcTopLeft.x, srcTopLeft.y+1, SRCCOPY
        );
        // Draw right edge (extra width for clean resizing)
        BitBlt(
            hdc, topLeftX+width-1, topLeftY+1, offset_width, height-2,
            srcdc, srcTopLeft.x+width-1, srcTopLeft.y+1, SRCCOPY
        );
        // Draw bottom edge (extra height for clean resizing)
        BitBlt(
            hdc, topLeftX, topLeftY+height-1, width, offset_height,
            srcdc, srcTopLeft.x, srcTopLeft.y+height-1, SRCCOPY
        );
    }
    else
    {
        HBRUSH bgbrush, oldbrush;
        HPEN edge, oldpen;
        COLORREF backgroundcolor = colours[258];
        
        bgbrush = CreateSolidBrush(backgroundcolor);
        edge = CreatePen(PS_SOLID, 0, backgroundcolor);
        
        oldbrush = SelectObject(hdc, bgbrush);
        oldpen = SelectObject(hdc, edge);

        /*
         * Jordan Russell reports that this apparently
         * ineffectual IntersectClipRect() call masks a
         * Windows NT/2K bug causing strange display
         * problems when the PuTTY window is taller than
         * the primary monitor. It seems harmless enough...
         */
        IntersectClipRect(hdc,
        	paint_left, paint_top,
        	paint_right, paint_bottom);
	
        ExcludeClipRect(hdc, 
        	offset_width, offset_height,
        	offset_width+font_width*term->cols,
        	offset_height+font_height*term->rows);

//debug_log("3: %d %d %d %d %d %d %d\n",resizing,paint_left, paint_top, paint_right, paint_bottom,offset_width,offset_height ) ;
//debug_log("4: %d %d %d %d\n",size_before.top,size_before.bottom,size_before.left,size_before.right) ;
//debug_log("5: %d %d %d %d %d %d\n",paint_top,paint_bottom,paint_left,paint_right,term->cols,term->rows);

        Rectangle(hdc, paint_left, paint_top,
            paint_right, paint_bottom);

        SelectObject(hdc, oldpen);
        DeleteObject(edge);
        SelectObject(hdc, oldbrush);
        DeleteObject(bgbrush);
    }
}



void clean_bg(void) {
	DeleteDC(textdc);textdc=NULL;
	DeleteObject(textbm);textbm=NULL;
	//DeleteObject(colorinpixel);
	//DeleteDC(colorinpixeldc);
	//DeleteObject(colorinpixelbm);
	DeleteDC(backgrounddc);backgrounddc=NULL;
	DeleteObject(backgroundbm);backgroundbm=NULL;
	DeleteDC(backgroundblenddc);backgroundblenddc=NULL;
	DeleteObject(backgroundblendbm);backgroundblendbm=NULL;
	}

void RedrawBackground( HWND hwnd ) {
	if( (BackgroundImageFlag)&&(!PuttyFlag)&&(cfg.bg_type != 0) ) {
		clean_bg() ;
		load_bg_bmp() ;
		}
	InvalidateRect(hwnd, NULL, TRUE) ;
	}
