Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/config.c
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/config.c	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/config.c	(working copy)
@@ -1359,6 +1359,64 @@
 		 I(offsetof(Config,window_border)), I(-1));
 
     /*
+     * The Window/Background panel.
+     * (This would really belong in Appearance but we overflowed -- to much
+     * stuff on one page otherwise).
+     */
+    str = dupprintf("Configure the background of %s's window", appname);
+    ctrl_settitle(b, "Window/Background", str);
+    sfree(str);
+
+    s = ctrl_getset(b, "Window/Background", "bg_style",
+            "Background settings");
+    ctrl_radiobuttons(s, "Background Style:", NO_SHORTCUT, 3,
+              HELPCTX(appearance_background),
+              dlg_stdradiobutton_handler,
+              I(offsetof(Config, bg_type)),
+              "Solid", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
+              "Desktop", NO_SHORTCUT, I(1),
+              "Image", NO_SHORTCUT, I(2),
+              NULL);
+
+    s = ctrl_getset(b, "Window/Background", "bg_wp_img_settings",
+            "Desktop and image settings");
+    ctrl_editbox(s, "Opacity:", NO_SHORTCUT, 20,
+		 HELPCTX(appearance_background),
+		 dlg_stdeditbox_handler,
+		 I(offsetof(Config,bg_opacity)), I(-1));
+
+    s = ctrl_getset(b, "Window/Background", "bg_img_settings",
+            "Image settings");
+    ctrl_filesel(s, "Image file:", 'k',
+		     FILTER_IMAGE_FILES, FALSE, "Select background image file",
+		     HELPCTX(appearance_background),
+		     dlg_stdfilesel_handler, I(offsetof(Config, bg_image_filename)));
+    ctrl_radiobuttons(s, "Image placement:", NO_SHORTCUT, 4,
+              HELPCTX(appearance_background),
+              dlg_stdradiobutton_handler,
+              I(offsetof(Config, bg_image_style)),
+              "Tile", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
+              "Center", NO_SHORTCUT, I(1),
+              "Stretch", NO_SHORTCUT, I(2),
+              "Absolute (X,Y)", NO_SHORTCUT, I(3),
+              NULL);
+    ctrl_editbox(s, "Absolute Left (X):", NO_SHORTCUT, 20,
+		 HELPCTX(appearance_background),
+		 dlg_stdeditbox_handler,
+		 I(offsetof(Config,bg_image_abs_x)), I(-1));
+    ctrl_editbox(s, "Absolute Top (Y):", NO_SHORTCUT, 20,
+		 HELPCTX(appearance_background),
+		 dlg_stdeditbox_handler,
+		 I(offsetof(Config,bg_image_abs_y)), I(-1));
+    ctrl_radiobuttons(s, "Image placement is relative to:", NO_SHORTCUT, 2,
+              HELPCTX(appearance_background),
+              dlg_stdradiobutton_handler,
+              I(offsetof(Config, bg_image_abs_fixed)),
+              "Desktop", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
+              "Terminal Window", NO_SHORTCUT, I(1),
+              NULL);
+
+    /*
      * The Window/Behaviour panel.
      */
     str = dupprintf("Configure the behaviour of %s's window", appname);
Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/putty.h
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/putty.h	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/putty.h	(working copy)
@@ -516,6 +516,13 @@
     int hide_mouseptr;
     int sunken_edge;
     int window_border;
+    int bg_opacity;
+    int bg_type;                 /* 0=solid 1=wallpaper 2=bitmap */
+    int bg_image_style;          /* 0=tile 1=center 2=stretch 3=(x,y) */
+    int bg_image_abs_x;
+    int bg_image_abs_y;
+    int bg_image_abs_fixed;      /* 0=fixed to desktop, 1=fixed to term wnd */
+    Filename bg_image_filename;
     char answerback[256];
     char printer[128];
     int arabicshaping;
Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/settings.c
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/settings.c	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/settings.c	(working copy)
@@ -344,6 +344,10 @@
     write_setting_i(sesskey, "HideMousePtr", cfg->hide_mouseptr);
     write_setting_i(sesskey, "SunkenEdge", cfg->sunken_edge);
     write_setting_i(sesskey, "WindowBorder", cfg->window_border);
+    write_setting_i(sesskey, "BgOpacity", cfg->bg_opacity);
+    write_setting_i(sesskey, "BgType", cfg->bg_type);
+    write_setting_i(sesskey, "BgImageStyle", cfg->bg_image_style);
+    write_setting_filename(sesskey, "BgImageFile", cfg->bg_image_filename);
     write_setting_i(sesskey, "CurType", cfg->cursor_type);
     write_setting_i(sesskey, "BlinkCur", cfg->blink_cur);
     write_setting_i(sesskey, "Beep", cfg->beep);
@@ -619,6 +623,10 @@
     gppi(sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr);
     gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge);
     gppi(sesskey, "WindowBorder", 1, &cfg->window_border);
+    gppi(sesskey, "BgOpacity", 50, &cfg->bg_opacity);
+    gppi(sesskey, "BgType", 0, &cfg->bg_type);
+    gppi(sesskey, "BgImageStyle", 0, &cfg->bg_image_style);
+    gppfile(sesskey, "BgImageFile", &cfg->bg_image_filename);
     gppi(sesskey, "CurType", 0, &cfg->cursor_type);
     gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur);
     /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */
Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/window.c
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/window.c	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/window.c	(working copy)
@@ -80,6 +80,7 @@
 static void deinit_fonts(void);
 static void set_input_locale(HKL);
 static void update_savedsess_menu(void);
+static void init_dc_blend(void);
 
 static int is_full_screen(void);
 static void make_full_screen(void);
@@ -116,6 +117,8 @@
 static HMENU specials_menu = NULL;
 static int n_specials = 0;
 
+static BOOL (WINAPI * pAlphaBlend)(HDC,int,int,int,int,HDC,int,int,int,int,BLENDFUNCTION) = 0;
+
 #define TIMING_TIMER_ID 1234
 static long timing_next_time;
 
@@ -170,6 +173,17 @@
 static LPLOGPALETTE logpal;
 static RGBTRIPLE defpal[NALLCOLOURS];
 
+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 HBITMAP caretbm;
 
 static int dbltime, lasttime, lastact;
@@ -185,6 +199,9 @@
 
 static int compose_state = 0;
 
+static int resizing;
+static RECT size_before;
+
 static UINT wm_mousewheel = WM_MOUSEWHEEL;
 
 /* Dummy routine, only required in plink. */
@@ -656,6 +673,8 @@
     }
 
     {
+    const char* winname = appname;
+
 	int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL;
 	int exwinmode = 0;
 	if (!cfg.scrollbar)
@@ -666,10 +685,34 @@
 	    exwinmode |= WS_EX_TOPMOST;
 	if (cfg.sunken_edge)
 	    exwinmode |= WS_EX_CLIENTEDGE;
-	hwnd = CreateWindowEx(exwinmode, appname, appname,
+
+	// TODO: This is the beginning of some work to have windows with fancy
+	// no-client-edge borders.  It's not ready yet.
+	if(0)
+	{
+		winmode = WS_POPUP;
+		exwinmode = 0;
+		winname = NULL;
+
+		// TODO: This is proof-of-concept.  For this to really work, we'll
+		// have to do some additional mods, like creating our own title/move
+		// window to glue to the top, and some kind of drag-resizing window
+		// to glue to the bottom-right.  Otherwise there'll be no way to move
+		// or resize the window, which will get old extremely quickly.  Finally,
+		// this won't work as written anyway, b/c when you call SetWindowText
+		// anywhere Win32 forces a window border to appear anyway.  So, we'll
+		// want to create a new function, set_window_text, that checks whether
+		// to really call SetWindowText or to set the window text in whatever
+		// other location is necessary for our custom window text display for
+		// when we're handling our own border here.
+	}
+
+	hwnd = CreateWindowEx(exwinmode, appname, winname,
 			      winmode, CW_USEDEFAULT, CW_USEDEFAULT,
 			      guess_width, guess_height,
 			      NULL, NULL, inst, NULL);
+
+        init_dc_blend();
     }
 
     /*
@@ -1842,8 +1885,480 @@
     return FALSE;
 }
 
-static int resizing;
+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;
+    int pathLen = MAX_PATH;
+    int 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;
+}
+
+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");
+    
+    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);
+    }
+}
+
+static BOOL load_bg_bmp()
+{
+    BOOL bRes;
+    HBITMAP rawImage = NULL;
+    BITMAP rawImageInfo;
+    HDC hdcPrimary;
+    HDC bmpdc;
+    int deskWidth, deskHeight;
+    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;
+
+    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:
+        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);
+    
+    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;
+        }
+
+        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
+        );
+        color_blend(
+            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;
+            }
+	}
+	
+        // 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);
+
+        Rectangle(hdc, paint_left, paint_top,
+            paint_right, paint_bottom);
+
+        SelectObject(hdc, oldpen);
+        DeleteObject(edge);
+        SelectObject(hdc, oldbrush);
+        DeleteObject(bgbrush);
+    }
+}
+
 void notify_remote_exit(void *fe) { /* stub not needed in this frontend */ }
 
 void timer_change_notify(long next)
@@ -1858,7 +2373,6 @@
 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 				WPARAM wParam, LPARAM lParam)
 {
-    HDC hdc;
     static int ignore_clip = FALSE;
     static int need_backend_resize = FALSE;
     static int fullscr_on_max = FALSE;
@@ -2011,7 +2525,31 @@
 		if (!reconfig_result)
 		    break;
 
+		if(textdc)
 		{
+			DeleteObject(textbm);
+			DeleteDC(textdc);
+			textdc = NULL;
+			textbm = NULL;
+		}
+
+		if(backgrounddc)
+		{
+			DeleteObject(backgroundbm);
+			DeleteDC(backgrounddc);
+			backgrounddc = NULL;
+			backgroundbm = NULL;
+		}
+
+		if(backgroundblenddc)
+		{
+			DeleteObject(backgroundblendbm);
+			DeleteDC(backgroundblenddc);
+			backgroundblenddc = NULL;
+			backgroundblendbm = NULL;
+		}
+
+		{
 		    /* Disable full-screen if resizing forbidden */
 		    HMENU m = GetSystemMenu (hwnd, FALSE);
 		    EnableMenuItem(m, IDM_FULLSCREEN, MF_BYCOMMAND | 
@@ -2380,14 +2918,27 @@
       case WM_PAINT:
 	{
 	    PAINTSTRUCT p;
+        HDC hdc, hdcScreen, hdcBack = 0;
 
-	    HideCaret(hwnd);
-	    hdc = BeginPaint(hwnd, &p);
-	    if (pal) {
-		SelectPalette(hdc, pal, TRUE);
-		RealizePalette(hdc);
-	    }
+        HideCaret(hwnd);
+        hdcScreen = BeginPaint(hwnd, &p);
 
+        // We'll draw into a temporary buffer then copy to the screen.  After
+        // this point, the rest of this routine is written to use hdc and not
+        // care whether hdc is a screen or back buffer, until the very end,
+        // where the back buffer, if it exists, is blitted to the screen.  That
+        // keeps the routine flexible for use with different drawing policies,
+        // though right now the only policy we ever use is the one implied by
+        // the next line, where we always use a back buffer.
+        //hdc = hdcBack = CreateCompatibleDC(hdcScreen);
+         hdc = hdcScreen;
+        
+        if(pal) 
+        {
+            SelectPalette(hdcScreen, pal, TRUE);
+            RealizePalette(hdcScreen);
+        }
+        
 	    /*
 	     * We have to be careful about term_paint(). It will
 	     * set a bunch of character cells to INVALID and then
@@ -2420,58 +2971,37 @@
 	     * current terminal appearance so that WM_PAINT becomes
 	     * completely trivial. However, this should do for now.
 	     */
-	    term_paint(term, hdc, 
-		       (p.rcPaint.left-offset_width)/font_width,
-		       (p.rcPaint.top-offset_height)/font_height,
-		       (p.rcPaint.right-offset_width-1)/font_width,
-		       (p.rcPaint.bottom-offset_height-1)/font_height,
-		       !term->window_update_pending);
+        term_paint(term, hdc,
+            (p.rcPaint.left-offset_width)/font_width,
+            (p.rcPaint.top-offset_height)/font_height,
+            (p.rcPaint.right-offset_width-1)/font_width,
+            (p.rcPaint.bottom-offset_height-1)/font_height,
+            !term->window_update_pending);
+	
+        SelectObject(hdc, GetStockObject(SYSTEM_FONT));
+        SelectObject(hdc, GetStockObject(WHITE_PEN));
 
-	    if (p.fErase ||
-	        p.rcPaint.left  < offset_width  ||
-		p.rcPaint.top   < offset_height ||
-		p.rcPaint.right >= offset_width + font_width*term->cols ||
-		p.rcPaint.bottom>= offset_height + font_height*term->rows)
-	    {
-		HBRUSH fillcolour, oldbrush;
-		HPEN   edge, oldpen;
-		fillcolour = CreateSolidBrush (
-				    colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
-		oldbrush = SelectObject(hdc, fillcolour);
-		edge = CreatePen(PS_SOLID, 0, 
-				    colours[ATTR_DEFBG>>ATTR_BGSHIFT]);
-		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,
-			p.rcPaint.left, p.rcPaint.top,
-			p.rcPaint.right, p.rcPaint.bottom);
-
-		ExcludeClipRect(hdc, 
-			offset_width, offset_height,
-			offset_width+font_width*term->cols,
-			offset_height+font_height*term->rows);
-
-		Rectangle(hdc, p.rcPaint.left, p.rcPaint.top, 
-			  p.rcPaint.right, p.rcPaint.bottom);
-
-		/* SelectClipRgn(hdc, NULL); */
-
-		SelectObject(hdc, oldbrush);
-		DeleteObject(fillcolour);
-		SelectObject(hdc, oldpen);
-		DeleteObject(edge);
-	    }
-	    SelectObject(hdc, GetStockObject(SYSTEM_FONT));
-	    SelectObject(hdc, GetStockObject(WHITE_PEN));
-	    EndPaint(hwnd, &p);
-	    ShowCaret(hwnd);
+        if(hdcBack)
+        {
+            // Blit the back buffer to the real DC.
+            BitBlt(
+                hdcScreen,
+                p.rcPaint.left - offset_width,
+                p.rcPaint.top - offset_height,
+                p.rcPaint.right - p.rcPaint.left + offset_width,
+                p.rcPaint.bottom - p.rcPaint.top + offset_height,
+                hdcBack, p.rcPaint.left, p.rcPaint.top, SRCCOPY
+            );
+            
+            DeleteDC(hdcBack);
+            hdc = hdcScreen;
+        }
+        
+        // Last paint edges
+        paint_term_edges(hdc, p.rcPaint.left, p.rcPaint.top, p.rcPaint.right, p.rcPaint.bottom);
+	
+        EndPaint(hwnd, &p);
+        ShowCaret(hwnd);
 	}
 	return 0;
       case WM_NETEVENT:
@@ -2498,6 +3028,7 @@
 	debug((27, "WM_ENTERSIZEMOVE"));
 #endif
 	EnableSizeTip(1);
+	GetClientRect(hwnd, &size_before);
 	resizing = TRUE;
 	need_backend_resize = FALSE;
 	break;
@@ -2606,9 +3137,53 @@
       case WM_FULLSCR_ON_MAX:
 	fullscr_on_max = TRUE;
 	break;
+      case WM_DISPLAYCHANGE:
       case WM_MOVE:
+    if(backgrounddc)
+    {
+        // When using a background image based on the desktop, correct display
+        // may depend on the current position of the window.
+        InvalidateRect(hwnd, NULL, TRUE);
+    }
 	sys_cursor_update();
 	break;
+
+case WM_SETTINGCHANGE:
+    // It's sometimes hard to tell what setting changed, but our decisions
+    // regarding background drawing depends on some system settings, so force
+    // it to be redone.
+
+    if(textdc)
+    {
+        DeleteObject(textbm);
+        DeleteDC(textdc);
+        textdc = NULL;
+        textbm = NULL;
+    }
+
+    if(backgrounddc)
+    {
+        DeleteObject(backgroundbm);
+        DeleteDC(backgrounddc);
+        backgrounddc = NULL;
+        backgroundbm = NULL;
+    }
+
+    if(backgroundblenddc)
+    {
+        DeleteObject(backgroundblendbm);
+        DeleteDC(backgroundblenddc);
+        backgroundblenddc = NULL;
+        backgroundblendbm = NULL;
+    }
+
+    if(textdc || backgrounddc || backgroundblenddc)
+    {
+        InvalidateRect(hwnd, NULL, TRUE);
+    }
+
+    break;
+
       case WM_SIZE:
 #ifdef RDB_DEBUG_PATCH
 	debug((27, "WM_SIZE %s (%d,%d)",
@@ -3031,6 +3606,8 @@
     int fnt_width, char_width;
     int text_adjust = 0;
     static int *IpDx = 0, IpDxLEN = 0;
+    int transBg = backgrounddc ? 1 : 0;
+    UINT etoFlagOpaque = transBg ? 0 : ETO_OPAQUE;
 
     lattr &= LATTR_MODE;
 
@@ -3154,17 +3731,47 @@
     }
     fg = colours[nfg];
     bg = colours[nbg];
+
+    line_box.left = x;
+    line_box.top = y;
+    line_box.right = x + char_width * len;
+    line_box.bottom = y + font_height;
+    
+    if(textdc)
+    {
+        int x = line_box.left;
+        int y = line_box.top;
+        int width = line_box.right - line_box.left;
+        int height = line_box.bottom - line_box.top;
+
+        POINT bgloc = { x, y };
+        COLORREF backgroundcolor = colours[258]; // Default Background
+        
+        if(!bBgRelToTerm)
+            ClientToScreen(hwnd, &bgloc);
+        
+        if(bg == backgroundcolor) 
+        {
+            // Use fast screen fill for default background.
+            BitBlt(textdc, x, y, width, height, backgroundblenddc, bgloc.x, bgloc.y, SRCCOPY);
+        }
+        else 
+        {
+            BitBlt(textdc, x, y, width, height, backgrounddc, bgloc.x, bgloc.y, SRCCOPY);
+            
+            color_blend(textdc, x, y, width, height, bg, cfg.bg_opacity);
+        }
+        
+        hdc = textdc;
+    }
+
     SelectObject(hdc, fonts[nfont]);
     SetTextColor(hdc, fg);
     SetBkColor(hdc, bg);
-    if (attr & TATTR_COMBINING)
+    if (transBg || attr & TATTR_COMBINING)
 	SetBkMode(hdc, TRANSPARENT);
     else
 	SetBkMode(hdc, OPAQUE);
-    line_box.left = x;
-    line_box.top = y;
-    line_box.right = x + char_width * len;
-    line_box.bottom = y + font_height;
 
     /* Only want the left half of double width lines */
     if (line_box.right > font_width*term->cols+offset_width)
@@ -3208,7 +3815,7 @@
 
 	ExtTextOutW(hdc, x,
 		    y - font_height * (lattr == LATTR_BOT) + text_adjust,
-		    ETO_CLIPPED | ETO_OPAQUE, &line_box, uni_buf, nlen, IpDx);
+		    ETO_CLIPPED | etoFlagOpaque, &line_box, uni_buf, nlen, IpDx);
 	if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
 	    SetBkMode(hdc, TRANSPARENT);
 	    ExtTextOutW(hdc, x - 1,
@@ -3232,7 +3839,7 @@
 
 	ExtTextOut(hdc, x,
 		   y - font_height * (lattr == LATTR_BOT) + text_adjust,
-		   ETO_CLIPPED | ETO_OPAQUE, &line_box, directbuf, len, IpDx);
+		   ETO_CLIPPED | etoFlagOpaque, &line_box, directbuf, len, IpDx);
 	if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) {
 	    SetBkMode(hdc, TRANSPARENT);
 
@@ -3265,10 +3872,10 @@
 
 	/* print Glyphs as they are, without Windows' Shaping*/
 	exact_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust,
-		      &line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING));
+		      &line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING) &&!transBg);
 /*	ExtTextOutW(hdc, x,
 		    y - font_height * (lattr == LATTR_BOT) + text_adjust,
-		    ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx);
+		    ETO_CLIPPED | etoFlagOpaque, &line_box, wbuf, len, IpDx);
  */
 
 	/* And the shadow bold hack. */
@@ -3294,6 +3901,17 @@
 	oldpen = SelectObject(hdc, oldpen);
 	DeleteObject(oldpen);
     }
+
+    if(textdc)
+    {
+        int x = line_box.left;
+        int y = line_box.top;
+        int width = line_box.right - line_box.left;
+        int height = line_box.bottom - line_box.top;
+
+        // Copy the result to the working DC.
+        BitBlt(ctx, x, y, width, height, hdc, x, y, SRCCOPY);
+    }
 }
 
 /*
Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winhelp.h
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winhelp.h	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winhelp.h	(working copy)
@@ -66,6 +66,7 @@
 #define WINHELP_CTX_appearance_title "appearance.title"
 #define WINHELP_CTX_appearance_hidemouse "appearance.hidemouse"
 #define WINHELP_CTX_appearance_border "appearance.border"
+#define WINHELP_CTX_appearance_background "appearance.background"
 #define WINHELP_CTX_connection_termtype "connection.termtype"
 #define WINHELP_CTX_connection_termspeed "connection.termspeed"
 #define WINHELP_CTX_connection_username "connection.username"
Index: C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winstuff.h
===================================================================
--- C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winstuff.h	(revision 6566)
+++ C:/Documents and Settings/Chris/My Documents/Dev/putty/wc/windows/winstuff.h	(working copy)
@@ -170,6 +170,8 @@
 			      "All Files (*.*)\0*\0\0\0")
 #define FILTER_WAVE_FILES ("Wave Files (*.wav)\0*.WAV\0" \
 			       "All Files (*.*)\0*\0\0\0")
+#define FILTER_IMAGE_FILES ("Image Files (*.bmp)\0*.BMP\0" \
+                   "All Files (*.*)\0*\0\0\0")
 
 /*
  * On some versions of Windows, it has been known for WM_TIMER to
