Merge commit 'v4.3.16'
[xboard.git] / winboard / winboard.c
index b1aa04b..fb64ff7 100644 (file)
@@ -1,6 +1,6 @@
-/* \r
+/*\r
  * WinBoard.c -- Windows NT front end to XBoard\r
- * $Id$\r
+ * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $\r
  *\r
  * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
  * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.\r
@@ -57,6 +57,7 @@
 \r
 #include <stdio.h>\r
 #include <stdlib.h>\r
+#include <time.h>\r
 #include <malloc.h>\r
 #include <sys/stat.h>\r
 #include <fcntl.h>\r
 #include "wsockerr.h"\r
 #include "defaults.h"\r
 \r
+#include "wsnap.h"\r
+\r
+//void InitEngineUCI( const char * iniDir, ChessProgramState * cps );\r
+\r
+  int myrandom(void);\r
+  void mysrandom(unsigned int seed);\r
+\r
+extern int whiteFlag, blackFlag;\r
+Boolean flipClock = FALSE;\r
+\r
+void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);\r
+\r
 typedef struct {\r
   ChessSquare piece;  \r
   POINT pos;      /* window coordinates of current pos */\r
@@ -125,9 +138,10 @@ char installDir[MSG_SIZ];
 BoardSize boardSize;\r
 BOOLEAN chessProgram;\r
 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;\r
-static int squareSize, lineGap;\r
+static int squareSize, lineGap, minorSize;\r
 static int winWidth, winHeight;\r
-static RECT messageRect, whiteRect, blackRect;\r
+static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo\r
+static int logoHeight = 0;\r
 static char messageText[MESSAGE_TEXT_MAX];\r
 static int clockTimerEvent = 0;\r
 static int loadGameTimerEvent = 0;\r
@@ -140,7 +154,7 @@ char *icsNames;
 char *firstChessProgramNames;\r
 char *secondChessProgramNames;\r
 \r
-#define ARG_MAX 20000\r
+#define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */\r
 \r
 #define PALETTESIZE 256\r
 \r
@@ -156,8 +170,9 @@ ColorClass currentColorClass;
 \r
 HWND hCommPort = NULL;    /* currently open comm port */\r
 static HWND hwndPause;    /* pause button */\r
-static HBITMAP pieceBitmap[3][(int) WhiteKing + 1];\r
+static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */\r
 static HBRUSH lightSquareBrush, darkSquareBrush,\r
+  blackSquareBrush, /* [HGM] for band between board and holdings */\r
   whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;\r
 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];\r
 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];\r
@@ -171,6 +186,18 @@ static int doingSizing = FALSE;
 static int lastSizing = 0;\r
 static int prevStderrPort;\r
 \r
+/* [AS] Support for background textures */\r
+#define BACK_TEXTURE_MODE_DISABLED      0\r
+#define BACK_TEXTURE_MODE_PLAIN         1\r
+#define BACK_TEXTURE_MODE_FULL_RANDOM   2\r
+\r
+static HBITMAP liteBackTexture = NULL;\r
+static HBITMAP darkBackTexture = NULL;\r
+static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+static int backTextureSquareSize = 0;\r
+static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];\r
+\r
 #if __GNUC__ && !defined(_winmajor)\r
 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */\r
 #else\r
@@ -219,60 +246,24 @@ SizeInfo sizeInfo[] =
 #define MF(x) {x, {0, }, {0, }, 0}\r
 MyFont fontRec[NUM_SIZES][NUM_FONTS] =\r
 {\r
-  { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), \r
-    MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY),\r
-    MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY) },\r
-  { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), \r
-    MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY),\r
-    MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY) },\r
-  { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY),\r
-    MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY),\r
-    MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY) },\r
-  { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE),\r
-    MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE),\r
-    MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE) },\r
-  { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM),\r
-    MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM),\r
-    MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM) },\r
-  { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL),\r
-    MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL),\r
-    MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL) },\r
-  { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE),\r
-    MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE),\r
-    MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE) },\r
-  { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING),\r
-    MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING),\r
-    MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING) },\r
-  { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE),\r
-    MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE),\r
-    MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE) },\r
-  { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE),\r
-    MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE),\r
-    MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE) },\r
-  { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM),\r
-    MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM),\r
-    MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM) },\r
-  { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY),\r
-    MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY),\r
-    MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY) },\r
-  { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE),\r
-    MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE),\r
-    MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE) },\r
-  { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG),\r
-    MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG),\r
-    MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG) },\r
-  { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE),\r
-    MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE),\r
-    MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE) },\r
-  { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT),\r
-    MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT),\r
-    MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT) },\r
-  { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL),\r
-    MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL),\r
-    MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL) },\r
-  { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC),\r
-    MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC),\r
-    MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC) },\r
+  { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },\r
+  { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },\r
 };\r
 \r
 MyFont *font[NUM_SIZES][NUM_FONTS];\r
@@ -398,8 +389,44 @@ LRESULT CALLBACK
 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);\r
 void ParseIcsTextMenu(char *icsTextMenuString);\r
 VOID PopUpMoveDialog(char firstchar);\r
+VOID PopUpNameDialog(char firstchar);\r
 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);\r
 \r
+/* [AS] */\r
+int NewGameFRC();\r
+int GameListOptions();\r
+\r
+HWND moveHistoryDialog = NULL;\r
+BOOLEAN moveHistoryDialogUp = FALSE;\r
+\r
+WindowPlacement wpMoveHistory;\r
+\r
+HWND evalGraphDialog = NULL;\r
+BOOLEAN evalGraphDialogUp = FALSE;\r
+\r
+WindowPlacement wpEvalGraph;\r
+\r
+HWND engineOutputDialog = NULL;\r
+BOOLEAN engineOutputDialogUp = FALSE;\r
+\r
+WindowPlacement wpEngineOutput;\r
+\r
+VOID MoveHistoryPopUp();\r
+VOID MoveHistoryPopDown();\r
+VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
+BOOL MoveHistoryIsUp();\r
+\r
+VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );\r
+VOID EvalGraphPopUp();\r
+VOID EvalGraphPopDown();\r
+BOOL EvalGraphIsUp();\r
+\r
+VOID EngineOutputPopUp();\r
+VOID EngineOutputPopDown();\r
+BOOL EngineOutputIsUp();\r
+VOID EngineOutputUpdate( FrontEndProgramStats * stats );\r
+\r
+VOID GothicPopUp(char *title, VariantClass variant);\r
 /*\r
  * Setting "frozen" should disable all user input other than deleting\r
  * the window.  We do this while engines are initializing themselves.\r
@@ -446,7 +473,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)\r
 {\r
   MSG msg;\r
-  HANDLE hAccelMain, hAccelNoAlt;\r
+  HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;\r
 \r
   debugFP = stderr;\r
 \r
@@ -462,6 +489,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 \r
   hAccelMain = LoadAccelerators (hInstance, szAppName);\r
   hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");\r
+  hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */\r
 \r
   /* Acquire and dispatch messages until a WM_QUIT message is received. */\r
 \r
@@ -471,10 +499,14 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    0))   /* highest message to examine */\r
     {\r
       if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&\r
+          !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&\r
+          !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&\r
+          !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&\r
          !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&\r
          !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&\r
          !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&\r
          !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&\r
+          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&\r
          !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {\r
        TranslateMessage(&msg); /* Translates virtual key codes */\r
        DispatchMessage(&msg);  /* Dispatches message to window */\r
@@ -535,9 +567,12 @@ int screenHeight, screenWidth;
 void\r
 EnsureOnScreen(int *x, int *y)\r
 {\r
+  int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);\r
   /* Be sure window at (x,y) is not off screen (or even mostly off screen) */\r
   if (*x > screenWidth - 32) *x = 0;\r
   if (*y > screenHeight - 32) *y = 0;\r
+  if (*x < 10) *x = 10;\r
+  if (*y < gap) *y = gap;\r
 }\r
 \r
 BOOL\r
@@ -555,14 +590,18 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   } else {\r
     GetCurrentDirectory(MSG_SIZ, installDir);\r
   }\r
+  gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise\r
   InitAppData(lpCmdLine);      /* Get run-time parameters */\r
   if (appData.debugMode) {\r
-    debugFP = fopen("winboard.debug", "w");\r
+    debugFP = fopen(appData.nameOfDebugFile, "w");\r
     setbuf(debugFP, NULL);\r
   }\r
 \r
   InitBackEnd1();\r
 \r
+//  InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()\r
+//  InitEngineUCI( installDir, &second );\r
+\r
   /* Create a main window for this application instance. */\r
   hwnd = CreateWindow(szAppName, szTitle,\r
                      (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),\r
@@ -575,6 +614,35 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
     return (FALSE);\r
   }\r
 \r
+  /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */\r
+  if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {\r
+      first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+      if (first.programLogo == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );\r
+      }\r
+  } else if(appData.autoLogo) {\r
+      if(appData.firstDirectory && appData.firstDirectory[0]) {\r
+       char buf[MSG_SIZ];\r
+       sprintf(buf, "%s/logo.bmp", appData.firstDirectory);\r
+       first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );   \r
+      }\r
+  }\r
+\r
+  if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {\r
+      second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+\r
+      if (second.programLogo == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );\r
+      }\r
+  } else if(appData.autoLogo) {\r
+      if(appData.secondDirectory && appData.secondDirectory[0]) {\r
+       char buf[MSG_SIZ];\r
+       sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);\r
+       second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );  \r
+      }\r
+  }\r
+\r
   iconWhite = LoadIcon(hInstance, "icon_white");\r
   iconBlack = LoadIcon(hInstance, "icon_black");\r
   iconCurrent = iconWhite;\r
@@ -586,14 +654,53 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
        size that fits on this screen as the default. */\r
     InitDrawingSizes((BoardSize)ibs, 0);\r
     if (boardSize == (BoardSize)-1 &&\r
-       winHeight <= screenHeight && winWidth <= screenWidth) {\r
+        winHeight <= screenHeight\r
+           - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10\r
+        && winWidth <= screenWidth) {\r
       boardSize = (BoardSize)ibs;\r
     }\r
   }\r
+\r
   InitDrawingSizes(boardSize, 0);\r
   InitMenuChecks();\r
   buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);\r
 \r
+  /* [AS] Load textures if specified */\r
+  ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
+  \r
+  if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {\r
+      liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      liteBackTextureMode = appData.liteBackTextureMode;\r
+\r
+      if (liteBackTexture == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );\r
+      }\r
+  }\r
+  \r
+  if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {\r
+      darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );\r
+      darkBackTextureMode = appData.darkBackTextureMode;\r
+\r
+      if (darkBackTexture == NULL && appData.debugMode) {\r
+          fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );\r
+      }\r
+  }\r
+\r
+  mysrandom( (unsigned) time(NULL) );\r
+\r
+  /* [AS] Restore layout */\r
+  if( wpMoveHistory.visible ) {\r
+      MoveHistoryPopUp();\r
+  }\r
+\r
+  if( wpEvalGraph.visible ) {\r
+      EvalGraphPopUp();\r
+  }\r
+\r
+  if( wpEngineOutput.visible ) {\r
+      EngineOutputPopUp();\r
+  }\r
+\r
   InitBackEnd2();\r
 \r
   /* Make the window visible; update its client area; and return "success" */\r
@@ -609,7 +716,14 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
   SetWindowPlacement(hwndMain, &wp);\r
 \r
   SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
-              0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+               0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);\r
+\r
+#if 0\r
+  /* [AS] Disable the FRC stuff if not playing the proper variant */\r
+  if( gameInfo.variant != VariantFischeRandom ) {\r
+      EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );\r
+  }\r
+#endif\r
   if (hwndConsole) {\r
 #if AOT_CONSOLE\r
     SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,\r
@@ -803,6 +917,7 @@ ArgDescriptor argDescriptors[] = {
   { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },\r
   { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },\r
   { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },\r
+  { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */\r
   { "boardSize", ArgBoardSize, (LPVOID) &boardSize,\r
     TRUE }, /* must come after all fonts */\r
   { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },\r
@@ -1000,14 +1115,110 @@ ArgDescriptor argDescriptors[] = {
   { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
   { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },\r
   { "variant", ArgString, (LPVOID) &appData.variant, FALSE },\r
-  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion,\r
-    FALSE },\r
-  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,\r
-    FALSE },\r
+  { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },\r
+  { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },\r
   { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },\r
   { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },\r
   { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
   { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },\r
+  /* [AS] New features */\r
+  { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },\r
+  { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },\r
+  { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },\r
+  { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },\r
+  { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },\r
+  { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },\r
+  { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },\r
+  { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },\r
+  { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },\r
+  { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },\r
+  { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },\r
+  { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },\r
+  { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },\r
+  { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },\r
+  { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },\r
+  { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },\r
+  { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },\r
+  { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },\r
+  { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },\r
+  { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
+  { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },\r
+  { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },\r
+  { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },\r
+  { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },\r
+  { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },\r
+  { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },\r
+  { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },\r
+  { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },\r
+  { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },\r
+  { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },\r
+  { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },\r
+  { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },\r
+  { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },\r
+  { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },\r
+  { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },\r
+  { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },\r
+  { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },\r
+  { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },\r
+  { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+  { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },\r
+  { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+  { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },\r
+  { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },\r
+  { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },\r
+  { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },\r
+  { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE }, \r
+  { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },\r
+  { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },\r
+\r
+  /* [AS] Layout stuff */\r
+  { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },\r
+  { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },\r
+  { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },\r
+  { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },\r
+  { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },\r
+\r
+  { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },\r
+  { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },\r
+  { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },\r
+  { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },\r
+  { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },\r
+\r
+  { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },\r
+  { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },\r
+  { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },\r
+  { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },\r
+  { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },\r
+\r
+  /* [HGM] board-size, adjudication and misc. options */\r
+  { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },\r
+  { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },\r
+  { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },\r
+  { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },\r
+  { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },\r
+  { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },\r
+  { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },\r
+  { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },\r
+  { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },\r
+  { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },\r
+  { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },\r
+  { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },\r
+  { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },\r
+  { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },\r
+  { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },\r
+  { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },\r
+  { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },\r
+  { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },\r
+  { "userName", ArgString, (LPVOID) &appData.userName, FALSE },\r
+  { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },\r
+  { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },\r
+  { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },\r
+  { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },\r
+  { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },\r
+  { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },\r
+  { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },\r
+  { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },\r
+\r
 #ifdef ZIPPY\r
   { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },\r
   { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },\r
@@ -1050,6 +1261,18 @@ ArgDescriptor argDescriptors[] = {
   /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */\r
   { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },\r
 #endif\r
+  /* [HGM] options for broadcasting and time odds */\r
+  { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },\r
+  { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },\r
+  { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },\r
+  { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },\r
+  { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },\r
+  { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },\r
+  { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },\r
+  { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },\r
+  { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },\r
+  { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
+  { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
   { NULL, ArgNone, NULL, FALSE }\r
 };\r
 \r
@@ -1611,6 +1834,7 @@ InitAppData(LPSTR lpCmdLine)
   appData.reuseFirst = TRUE;\r
   appData.reuseSecond = TRUE;\r
   appData.blindfold = FALSE;\r
+  appData.icsEngineAnalyze = FALSE;\r
   dcb.DCBlength = sizeof(DCB);\r
   dcb.BaudRate = 9600;\r
   dcb.fBinary = TRUE;\r
@@ -1625,7 +1849,12 @@ InitAppData(LPSTR lpCmdLine)
   dcb.fNull = FALSE;\r
   dcb.fRtsControl = RTS_CONTROL_ENABLE;\r
   dcb.fAbortOnError = FALSE;\r
-  dcb.wReserved = 0;\r
+  /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */\r
+  #if (defined(_MSC_VER) && _MSC_VER <= 1200) \r
+       //dcb.wReserved = 0;\r
+  #else\r
+    dcb.wReserved = 0;\r
+  #endif\r
   dcb.ByteSize = 7;\r
   dcb.Parity = SPACEPARITY;\r
   dcb.StopBits = ONESTOPBIT;\r
@@ -1662,6 +1891,83 @@ InitAppData(LPSTR lpCmdLine)
   appData.firstProtocolVersion = PROTOVER;\r
   appData.secondProtocolVersion = PROTOVER;\r
   appData.showButtonBar = TRUE;\r
+\r
+   /* [AS] New properties (see comments in header file) */\r
+  appData.firstScoreIsAbsolute = FALSE;\r
+  appData.secondScoreIsAbsolute = FALSE;\r
+  appData.saveExtendedInfoInPGN = FALSE;\r
+  appData.hideThinkingFromHuman = FALSE;\r
+  appData.liteBackTextureFile = "";\r
+  appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+  appData.darkBackTextureFile = "";\r
+  appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;\r
+  appData.renderPiecesWithFont = "";\r
+  appData.fontToPieceTable = "";\r
+  appData.fontBackColorWhite = 0;\r
+  appData.fontForeColorWhite = 0;\r
+  appData.fontBackColorBlack = 0;\r
+  appData.fontForeColorBlack = 0;\r
+  appData.fontPieceSize = 80;\r
+  appData.overrideLineGap = 1;\r
+  appData.adjudicateLossThreshold = 0;\r
+  appData.delayBeforeQuit = 0;\r
+  appData.delayAfterQuit = 0;\r
+  appData.nameOfDebugFile = "winboard.debug";\r
+  appData.pgnEventHeader = "Computer Chess Game";\r
+  appData.defaultFrcPosition = -1;\r
+  appData.gameListTags = GLT_DEFAULT_TAGS;\r
+  appData.saveOutOfBookInfo = TRUE;\r
+  appData.showEvalInMoveHistory = TRUE;\r
+  appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );\r
+  appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );\r
+  appData.highlightMoveWithArrow = FALSE;\r
+  appData.highlightArrowColor = ParseColorName( "#FFFF80" );\r
+  appData.useStickyWindows = TRUE;\r
+  appData.adjudicateDrawMoves = 0;\r
+  appData.autoDisplayComment = TRUE;\r
+  appData.autoDisplayTags = TRUE;\r
+  appData.firstIsUCI = FALSE;\r
+  appData.secondIsUCI = FALSE;\r
+  appData.firstHasOwnBookUCI = TRUE;\r
+  appData.secondHasOwnBookUCI = TRUE;\r
+  appData.polyglotDir = "";\r
+  appData.usePolyglotBook = FALSE;\r
+  appData.polyglotBook = "";\r
+  appData.defaultHashSize = 64;\r
+  appData.defaultCacheSizeEGTB = 4;\r
+  appData.defaultPathEGTB = "c:\\egtb";\r
+\r
+  InitWindowPlacement( &wpMoveHistory );\r
+  InitWindowPlacement( &wpEvalGraph );\r
+  InitWindowPlacement( &wpEngineOutput );\r
+\r
+  /* [HGM] User-selectable board size, adjudication control, miscellaneous */\r
+  appData.NrFiles      = -1;\r
+  appData.NrRanks      = -1;\r
+  appData.holdingsSize = -1;\r
+  appData.testClaims   = FALSE;\r
+  appData.checkMates   = FALSE;\r
+  appData.materialDraws= FALSE;\r
+  appData.trivialDraws = FALSE;\r
+  appData.ruleMoves    = 51;\r
+  appData.drawRepeats  = 6;\r
+  appData.matchPause   = 10000;\r
+  appData.alphaRank    = FALSE;\r
+  appData.allWhite     = FALSE;\r
+  appData.upsideDown   = FALSE;\r
+  appData.serverPause  = 15;\r
+  appData.serverMovesName   = NULL;\r
+  appData.suppressLoadMoves = FALSE;\r
+  appData.firstTimeOdds  = 1;\r
+  appData.secondTimeOdds = 1;\r
+  appData.firstAccumulateTC  = 1; // combine previous and current sessions\r
+  appData.secondAccumulateTC = 1;\r
+  appData.firstNPS  = -1; // [HGM] nps: use wall-clock time\r
+  appData.secondNPS = -1;\r
+  appData.engineComments = 1;\r
+  appData.smpCores = 1; // [HGM] SMP: max nr of cores\r
+  appData.egtFormats = "";\r
+\r
 #ifdef ZIPPY\r
   appData.zippyTalk = ZIPPY_TALK;\r
   appData.zippyPlay = ZIPPY_PLAY;\r
@@ -1700,6 +2006,40 @@ InitAppData(LPSTR lpCmdLine)
   /* Parse command line */\r
   ParseArgs(StringGet, &lpCmdLine);\r
 \r
+  /* [HGM] make sure board size is acceptable */\r
+  if(appData.NrFiles > BOARD_SIZE ||\r
+     appData.NrRanks > BOARD_SIZE   )\r
+      DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);\r
+\r
+  /* [HGM] After parsing the options from the .ini file, and overruling them\r
+   * with options from the command line, we now make an even higher priority\r
+   * overrule by WB options attached to the engine command line. This so that\r
+   * tournament managers can use WB options (such as /timeOdds) that follow\r
+   * the engines.\r
+   */\r
+  if(appData.firstChessProgram != NULL) {\r
+      char *p = StrStr(appData.firstChessProgram, "WBopt");\r
+      static char *f = "first";\r
+      char buf[MSG_SIZ], *q = buf;\r
+      if(p != NULL) { // engine command line contains WinBoard options\r
+          sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"\r
+          ParseArgs(StringGet, &q);\r
+          p[-1] = 0; // cut them offengine command line\r
+      }\r
+  }\r
+  // now do same for second chess program\r
+  if(appData.secondChessProgram != NULL) {\r
+      char *p = StrStr(appData.secondChessProgram, "WBopt");\r
+      static char *s = "second";\r
+      char buf[MSG_SIZ], *q = buf;\r
+      if(p != NULL) { // engine command line contains WinBoard options\r
+          sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"\r
+          ParseArgs(StringGet, &q);\r
+          p[-1] = 0; // cut them offengine command line\r
+      }\r
+  }\r
+\r
+\r
   /* Propagate options that affect others */\r
   if (appData.matchMode || appData.matchGames) chessProgram = TRUE;\r
   if (appData.icsActive || appData.noChessProgram) {\r
@@ -1850,6 +2190,39 @@ SaveSettings(char* name)
     gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
   }\r
 \r
+  /* [AS] Move history */\r
+  wpMoveHistory.visible = MoveHistoryIsUp();\r
+  \r
+  if( moveHistoryDialog ) {\r
+    GetWindowPlacement(moveHistoryDialog, &wp);\r
+    wpMoveHistory.x = wp.rcNormalPosition.left;\r
+    wpMoveHistory.y = wp.rcNormalPosition.top;\r
+    wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+  }\r
+\r
+  /* [AS] Eval graph */\r
+  wpEvalGraph.visible = EvalGraphIsUp();\r
+\r
+  if( evalGraphDialog ) {\r
+    GetWindowPlacement(evalGraphDialog, &wp);\r
+    wpEvalGraph.x = wp.rcNormalPosition.left;\r
+    wpEvalGraph.y = wp.rcNormalPosition.top;\r
+    wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+  }\r
+\r
+  /* [AS] Engine output */\r
+  wpEngineOutput.visible = EngineOutputIsUp();\r
+\r
+  if( engineOutputDialog ) {\r
+    GetWindowPlacement(engineOutputDialog, &wp);\r
+    wpEngineOutput.x = wp.rcNormalPosition.left;\r
+    wpEngineOutput.y = wp.rcNormalPosition.top;\r
+    wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;\r
+    wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;\r
+  }\r
+\r
   for (ad = argDescriptors; ad->argName != NULL; ad++) {\r
     if (!ad->save) continue;\r
     switch (ad->argType) {\r
@@ -1956,6 +2329,591 @@ SaveSettings(char* name)
  *\r
 \*---------------------------------------------------------------------------*/\r
 \r
+/* [AS] Draw square using background texture */\r
+static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )\r
+{\r
+    XFORM   x;\r
+\r
+    if( mode == 0 ) {\r
+        return; /* Should never happen! */\r
+    }\r
+\r
+    SetGraphicsMode( dst, GM_ADVANCED );\r
+\r
+    switch( mode ) {\r
+    case 1:\r
+        /* Identity */\r
+        break;\r
+    case 2:\r
+        /* X reflection */\r
+        x.eM11 = -1.0;\r
+        x.eM12 = 0;\r
+        x.eM21 = 0;\r
+        x.eM22 = 1.0;\r
+        x.eDx = (FLOAT) dw + dx - 1;\r
+        x.eDy = 0;\r
+        dx = 0;\r
+        SetWorldTransform( dst, &x );\r
+        break;\r
+    case 3:\r
+        /* Y reflection */\r
+        x.eM11 = 1.0;\r
+        x.eM12 = 0;\r
+        x.eM21 = 0;\r
+        x.eM22 = -1.0;\r
+        x.eDx = 0;\r
+        x.eDy = (FLOAT) dh + dy - 1;\r
+        dy = 0;\r
+        SetWorldTransform( dst, &x );\r
+        break;\r
+    case 4:\r
+        /* X/Y flip */\r
+        x.eM11 = 0;\r
+        x.eM12 = 1.0;\r
+        x.eM21 = 1.0;\r
+        x.eM22 = 0;\r
+        x.eDx = (FLOAT) dx;\r
+        x.eDy = (FLOAT) dy;\r
+        dx = 0;\r
+        dy = 0;\r
+        SetWorldTransform( dst, &x );\r
+        break;\r
+    }\r
+\r
+    BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );\r
+\r
+    x.eM11 = 1.0;\r
+    x.eM12 = 0;\r
+    x.eM21 = 0;\r
+    x.eM22 = 1.0;\r
+    x.eDx = 0;\r
+    x.eDy = 0;\r
+    SetWorldTransform( dst, &x );\r
+\r
+    ModifyWorldTransform( dst, 0, MWT_IDENTITY );\r
+}\r
+\r
+/* [AS] [HGM] Make room for more piece types, so all pieces can be different */\r
+enum {\r
+    PM_WP = (int) WhitePawn, \r
+    PM_WN = (int) WhiteKnight, \r
+    PM_WB = (int) WhiteBishop, \r
+    PM_WR = (int) WhiteRook, \r
+    PM_WQ = (int) WhiteQueen, \r
+    PM_WF = (int) WhiteFerz, \r
+    PM_WW = (int) WhiteWazir, \r
+    PM_WE = (int) WhiteAlfil, \r
+    PM_WM = (int) WhiteMan, \r
+    PM_WO = (int) WhiteCannon, \r
+    PM_WU = (int) WhiteUnicorn, \r
+    PM_WH = (int) WhiteNightrider, \r
+    PM_WA = (int) WhiteAngel, \r
+    PM_WC = (int) WhiteMarshall, \r
+    PM_WAB = (int) WhiteCardinal, \r
+    PM_WD = (int) WhiteDragon, \r
+    PM_WL = (int) WhiteLance, \r
+    PM_WS = (int) WhiteCobra, \r
+    PM_WV = (int) WhiteFalcon, \r
+    PM_WSG = (int) WhiteSilver, \r
+    PM_WG = (int) WhiteGrasshopper, \r
+    PM_WK = (int) WhiteKing,\r
+    PM_BP = (int) BlackPawn, \r
+    PM_BN = (int) BlackKnight, \r
+    PM_BB = (int) BlackBishop, \r
+    PM_BR = (int) BlackRook, \r
+    PM_BQ = (int) BlackQueen, \r
+    PM_BF = (int) BlackFerz, \r
+    PM_BW = (int) BlackWazir, \r
+    PM_BE = (int) BlackAlfil, \r
+    PM_BM = (int) BlackMan,\r
+    PM_BO = (int) BlackCannon, \r
+    PM_BU = (int) BlackUnicorn, \r
+    PM_BH = (int) BlackNightrider, \r
+    PM_BA = (int) BlackAngel, \r
+    PM_BC = (int) BlackMarshall, \r
+    PM_BG = (int) BlackGrasshopper, \r
+    PM_BAB = (int) BlackCardinal,\r
+    PM_BD = (int) BlackDragon,\r
+    PM_BL = (int) BlackLance,\r
+    PM_BS = (int) BlackCobra,\r
+    PM_BV = (int) BlackFalcon,\r
+    PM_BSG = (int) BlackSilver,\r
+    PM_BK = (int) BlackKing\r
+};\r
+\r
+static HFONT hPieceFont = NULL;\r
+static HBITMAP hPieceMask[(int) EmptySquare];\r
+static HBITMAP hPieceFace[(int) EmptySquare];\r
+static int fontBitmapSquareSize = 0;\r
+static char pieceToFontChar[(int) EmptySquare] =\r
+                              { 'p', 'n', 'b', 'r', 'q', \r
+                      'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',\r
+                      'k', 'o', 'm', 'v', 't', 'w', \r
+                      'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',\r
+                                                              'l' };\r
+\r
+extern BOOL SetCharTable( char *table, const char * map );\r
+/* [HGM] moved to backend.c */\r
+\r
+static void SetPieceBackground( HDC hdc, COLORREF color, int mode )\r
+{\r
+    HBRUSH hbrush;\r
+    BYTE r1 = GetRValue( color );\r
+    BYTE g1 = GetGValue( color );\r
+    BYTE b1 = GetBValue( color );\r
+    BYTE r2 = r1 / 2;\r
+    BYTE g2 = g1 / 2;\r
+    BYTE b2 = b1 / 2;\r
+    RECT rc;\r
+\r
+    /* Create a uniform background first */\r
+    hbrush = CreateSolidBrush( color );\r
+    SetRect( &rc, 0, 0, squareSize, squareSize );\r
+    FillRect( hdc, &rc, hbrush );\r
+    DeleteObject( hbrush );\r
+    \r
+    if( mode == 1 ) {\r
+        /* Vertical gradient, good for pawn, knight and rook, less for queen and king */\r
+        int steps = squareSize / 2;\r
+        int i;\r
+\r
+        for( i=0; i<steps; i++ ) {\r
+            BYTE r = r1 - (r1-r2) * i / steps;\r
+            BYTE g = g1 - (g1-g2) * i / steps;\r
+            BYTE b = b1 - (b1-b2) * i / steps;\r
+\r
+            hbrush = CreateSolidBrush( RGB(r,g,b) );\r
+            SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );\r
+            FillRect( hdc, &rc, hbrush );\r
+            DeleteObject(hbrush);\r
+        }\r
+    }\r
+    else if( mode == 2 ) {\r
+        /* Diagonal gradient, good more or less for every piece */\r
+        POINT triangle[3];\r
+        HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );\r
+        HBRUSH hbrush_old;\r
+        int steps = squareSize;\r
+        int i;\r
+\r
+        triangle[0].x = squareSize - steps;\r
+        triangle[0].y = squareSize;\r
+        triangle[1].x = squareSize;\r
+        triangle[1].y = squareSize;\r
+        triangle[2].x = squareSize;\r
+        triangle[2].y = squareSize - steps;\r
+\r
+        for( i=0; i<steps; i++ ) {\r
+            BYTE r = r1 - (r1-r2) * i / steps;\r
+            BYTE g = g1 - (g1-g2) * i / steps;\r
+            BYTE b = b1 - (b1-b2) * i / steps;\r
+\r
+            hbrush = CreateSolidBrush( RGB(r,g,b) );\r
+            hbrush_old = SelectObject( hdc, hbrush );\r
+            Polygon( hdc, triangle, 3 );\r
+            SelectObject( hdc, hbrush_old );\r
+            DeleteObject(hbrush);\r
+            triangle[0].x++;\r
+            triangle[2].y++;\r
+        }\r
+\r
+        SelectObject( hdc, hpen );\r
+    }\r
+}\r
+\r
+/*\r
+    [AS] The method I use to create the bitmaps it a bit tricky, but it\r
+    seems to work ok. The main problem here is to find the "inside" of a chess\r
+    piece: follow the steps as explained below.\r
+*/\r
+static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )\r
+{\r
+    HBITMAP hbm;\r
+    HBITMAP hbm_old;\r
+    COLORREF chroma = RGB(0xFF,0x00,0xFF);\r
+    RECT rc;\r
+    SIZE sz;\r
+    POINT pt;\r
+    int backColor = whitePieceColor; \r
+    int foreColor = blackPieceColor;\r
+    \r
+    if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {\r
+        backColor = appData.fontBackColorWhite;\r
+        foreColor = appData.fontForeColorWhite;\r
+    }\r
+    else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {\r
+        backColor = appData.fontBackColorBlack;\r
+        foreColor = appData.fontForeColorBlack;\r
+    }\r
+\r
+    /* Mask */\r
+    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+    hbm_old = SelectObject( hdc, hbm );\r
+\r
+    rc.left = 0;\r
+    rc.top = 0;\r
+    rc.right = squareSize;\r
+    rc.bottom = squareSize;\r
+\r
+    /* Step 1: background is now black */\r
+    FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );\r
+\r
+    GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );\r
+\r
+    pt.x = (squareSize - sz.cx) / 2;\r
+    pt.y = (squareSize - sz.cy) / 2;\r
+\r
+    SetBkMode( hdc, TRANSPARENT );\r
+    SetTextColor( hdc, chroma );\r
+    /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */\r
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+    SelectObject( hdc, GetStockObject(WHITE_BRUSH) );\r
+    /* Step 3: the area outside the piece is filled with white */\r
+//    FloodFill( hdc, 0, 0, chroma );\r
+    ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );\r
+    ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big\r
+    ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );\r
+    ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );\r
+    SelectObject( hdc, GetStockObject(BLACK_BRUSH) );\r
+    /* \r
+        Step 4: this is the tricky part, the area inside the piece is filled with black,\r
+        but if the start point is not inside the piece we're lost!\r
+        There should be a better way to do this... if we could create a region or path\r
+        from the fill operation we would be fine for example.\r
+    */\r
+//    FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );\r
+    ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );\r
+\r
+    {   /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */\r
+        HDC dc2 = CreateCompatibleDC( hdc_window );\r
+        HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+        SelectObject( dc2, bm2 );\r
+        BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy\r
+        BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+        BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+        BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+        BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );\r
+\r
+        DeleteDC( dc2 );\r
+        DeleteObject( bm2 );\r
+    }\r
+\r
+    SetTextColor( hdc, 0 );\r
+    /* \r
+        Step 5: some fonts have "disconnected" areas that are skipped by the fill:\r
+        draw the piece again in black for safety.\r
+    */\r
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+    SelectObject( hdc, hbm_old );\r
+\r
+    if( hPieceMask[index] != NULL ) {\r
+        DeleteObject( hPieceMask[index] );\r
+    }\r
+\r
+    hPieceMask[index] = hbm;\r
+\r
+    /* Face */\r
+    hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+    SelectObject( hdc, hbm );\r
+\r
+    {\r
+        HDC dc1 = CreateCompatibleDC( hdc_window );\r
+        HDC dc2 = CreateCompatibleDC( hdc_window );\r
+        HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );\r
+\r
+        SelectObject( dc1, hPieceMask[index] );\r
+        SelectObject( dc2, bm2 );\r
+        FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );\r
+        BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );\r
+        \r
+        /* \r
+            Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves\r
+            the piece background and deletes (makes transparent) the rest.\r
+            Thanks to that mask, we are free to paint the background with the greates\r
+            freedom, as we'll be able to mask off the unwanted parts when finished.\r
+            We use this, to make gradients and give the pieces a "roundish" look.\r
+        */\r
+        SetPieceBackground( hdc, backColor, 2 );\r
+        BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );\r
+\r
+        DeleteDC( dc2 );\r
+        DeleteDC( dc1 );\r
+        DeleteObject( bm2 );\r
+    }\r
+\r
+    SetTextColor( hdc, foreColor );\r
+    TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );\r
+\r
+    SelectObject( hdc, hbm_old );\r
+\r
+    if( hPieceFace[index] != NULL ) {\r
+        DeleteObject( hPieceFace[index] );\r
+    }\r
+\r
+    hPieceFace[index] = hbm;\r
+}\r
+\r
+static int TranslatePieceToFontPiece( int piece )\r
+{\r
+    switch( piece ) {\r
+    case BlackPawn:\r
+        return PM_BP;\r
+    case BlackKnight:\r
+        return PM_BN;\r
+    case BlackBishop:\r
+        return PM_BB;\r
+    case BlackRook:\r
+        return PM_BR;\r
+    case BlackQueen:\r
+        return PM_BQ;\r
+    case BlackKing:\r
+        return PM_BK;\r
+    case WhitePawn:\r
+        return PM_WP;\r
+    case WhiteKnight:\r
+        return PM_WN;\r
+    case WhiteBishop:\r
+        return PM_WB;\r
+    case WhiteRook:\r
+        return PM_WR;\r
+    case WhiteQueen:\r
+        return PM_WQ;\r
+    case WhiteKing:\r
+        return PM_WK;\r
+\r
+    case BlackAngel:\r
+        return PM_BA;\r
+    case BlackMarshall:\r
+        return PM_BC;\r
+    case BlackFerz:\r
+        return PM_BF;\r
+    case BlackNightrider:\r
+        return PM_BH;\r
+    case BlackAlfil:\r
+        return PM_BE;\r
+    case BlackWazir:\r
+        return PM_BW;\r
+    case BlackUnicorn:\r
+        return PM_BU;\r
+    case BlackCannon:\r
+        return PM_BO;\r
+    case BlackGrasshopper:\r
+        return PM_BG;\r
+    case BlackMan:\r
+        return PM_BM;\r
+    case BlackSilver:\r
+        return PM_BSG;\r
+    case BlackLance:\r
+        return PM_BL;\r
+    case BlackFalcon:\r
+        return PM_BV;\r
+    case BlackCobra:\r
+        return PM_BS;\r
+    case BlackCardinal:\r
+        return PM_BAB;\r
+    case BlackDragon:\r
+        return PM_BD;\r
+\r
+    case WhiteAngel:\r
+        return PM_WA;\r
+    case WhiteMarshall:\r
+        return PM_WC;\r
+    case WhiteFerz:\r
+        return PM_WF;\r
+    case WhiteNightrider:\r
+        return PM_WH;\r
+    case WhiteAlfil:\r
+        return PM_WE;\r
+    case WhiteWazir:\r
+        return PM_WW;\r
+    case WhiteUnicorn:\r
+        return PM_WU;\r
+    case WhiteCannon:\r
+        return PM_WO;\r
+    case WhiteGrasshopper:\r
+        return PM_WG;\r
+    case WhiteMan:\r
+        return PM_WM;\r
+    case WhiteSilver:\r
+        return PM_WSG;\r
+    case WhiteLance:\r
+        return PM_WL;\r
+    case WhiteFalcon:\r
+        return PM_WV;\r
+    case WhiteCobra:\r
+        return PM_WS;\r
+    case WhiteCardinal:\r
+        return PM_WAB;\r
+    case WhiteDragon:\r
+        return PM_WD;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+void CreatePiecesFromFont()\r
+{\r
+    LOGFONT lf;\r
+    HDC hdc_window = NULL;\r
+    HDC hdc = NULL;\r
+    HFONT hfont_old;\r
+    int fontHeight;\r
+    int i;\r
+\r
+    if( fontBitmapSquareSize < 0 ) {\r
+        /* Something went seriously wrong in the past: do not try to recreate fonts! */\r
+        return;\r
+    }\r
+\r
+    if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {\r
+        fontBitmapSquareSize = -1;\r
+        return;\r
+    }\r
+\r
+    if( fontBitmapSquareSize != squareSize ) {\r
+        hdc_window = GetDC( hwndMain );\r
+        hdc = CreateCompatibleDC( hdc_window );\r
+\r
+        if( hPieceFont != NULL ) {\r
+            DeleteObject( hPieceFont );\r
+        }\r
+        else {\r
+            for( i=0; i<=(int)BlackKing; i++ ) {\r
+                hPieceMask[i] = NULL;\r
+                hPieceFace[i] = NULL;\r
+            }\r
+        }\r
+\r
+        fontHeight = 75;\r
+\r
+        if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {\r
+            fontHeight = appData.fontPieceSize;\r
+        }\r
+\r
+        fontHeight = (fontHeight * squareSize) / 100;\r
+\r
+        lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );\r
+        lf.lfWidth = 0;\r
+        lf.lfEscapement = 0;\r
+        lf.lfOrientation = 0;\r
+        lf.lfWeight = FW_NORMAL;\r
+        lf.lfItalic = 0;\r
+        lf.lfUnderline = 0;\r
+        lf.lfStrikeOut = 0;\r
+        lf.lfCharSet = DEFAULT_CHARSET;\r
+        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
+        lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
+        lf.lfQuality = PROOF_QUALITY;\r
+        lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;\r
+        strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );\r
+        lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';\r
+\r
+        hPieceFont = CreateFontIndirect( &lf );\r
+\r
+        if( hPieceFont == NULL ) {\r
+            fontBitmapSquareSize = -2;\r
+        }\r
+        else {\r
+            /* Setup font-to-piece character table */\r
+            if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {\r
+                /* No (or wrong) global settings, try to detect the font */\r
+                if( strstr(lf.lfFaceName,"Alpha") != NULL ) {\r
+                    /* Alpha */\r
+                    SetCharTable(pieceToFontChar, "phbrqkojntwl");\r
+                }\r
+                else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {\r
+                    /* DiagramTT* family */\r
+                    SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");\r
+                }\r
+                else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {\r
+                    /* Fairy symbols */\r
+                     SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");\r
+                }\r
+                else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {\r
+                    /* Good Companion (Some characters get warped as literal :-( */\r
+                    char s[] = "1cmWG0ñueOS¯®oYI23wgQU";\r
+                    s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;\r
+                    SetCharTable(pieceToFontChar, s);\r
+                }\r
+                else {\r
+                    /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */\r
+                    SetCharTable(pieceToFontChar, "pnbrqkomvtwl");\r
+                }\r
+            }\r
+\r
+            /* Create bitmaps */\r
+            hfont_old = SelectObject( hdc, hPieceFont );\r
+#if 0\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );\r
+\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );\r
+            CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );\r
+#else\r
+           for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */\r
+               if(PieceToChar((ChessSquare)i) != '.')     /* skip unused pieces         */\r
+                   CreatePieceMaskFromFont( hdc_window, hdc, i );\r
+#endif\r
+            SelectObject( hdc, hfont_old );\r
+\r
+            fontBitmapSquareSize = squareSize;\r
+        }\r
+    }\r
+\r
+    if( hdc != NULL ) {\r
+        DeleteDC( hdc );\r
+    }\r
+\r
+    if( hdc_window != NULL ) {\r
+        ReleaseDC( hwndMain, hdc_window );\r
+    }\r
+}\r
+\r
 HBITMAP\r
 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)\r
 {\r
@@ -2023,18 +2981,30 @@ InitDrawingColors()
   hPal = CreatePalette((LPLOGPALETTE) pLogPal);\r
 \r
   lightSquareBrush = CreateSolidBrush(lightSquareColor);\r
+  blackSquareBrush = CreateSolidBrush(blackPieceColor);\r
   darkSquareBrush = CreateSolidBrush(darkSquareColor);\r
   whitePieceBrush = CreateSolidBrush(whitePieceColor);\r
   blackPieceBrush = CreateSolidBrush(blackPieceColor);\r
   iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));\r
+\r
+  /* [AS] Force rendering of the font-based pieces */\r
+  if( fontBitmapSquareSize > 0 ) {\r
+    fontBitmapSquareSize = 0;\r
+  }\r
 }\r
 \r
 \r
 int\r
-BoardWidth(int boardSize)\r
-{\r
-  return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap +\r
-         BOARD_SIZE * sizeInfo[boardSize].squareSize;\r
+BoardWidth(int boardSize, int n)\r
+{ /* [HGM] argument n added to allow different width and height */\r
+  int lineGap = sizeInfo[boardSize].lineGap;\r
+\r
+  if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
+      lineGap = appData.overrideLineGap;\r
+  }\r
+\r
+  return (n + 1) * lineGap +\r
+          n * sizeInfo[boardSize].squareSize;\r
 }\r
 \r
 /* Respond to board resize by dragging edge */\r
@@ -2046,9 +3016,10 @@ ResizeBoard(int newSizeX, int newSizeY, int flags)
   if (IsIconic(hwndMain)) return;\r
   if (recurse > 0) return;\r
   recurse++;\r
-  while (newSize > 0 &&\r
-        (newSizeX < sizeInfo[newSize].cliWidth ||\r
-         newSizeY < sizeInfo[newSize].cliHeight)) {\r
+  while (newSize > 0) {\r
+       InitDrawingSizes(newSize, 0);\r
+       if(newSizeX >= sizeInfo[newSize].cliWidth ||\r
+          newSizeY >= sizeInfo[newSize].cliHeight) break;\r
     newSize--;\r
   } \r
   boardSize = newSize;\r
@@ -2061,7 +3032,7 @@ ResizeBoard(int newSizeX, int newSizeY, int flags)
 VOID\r
 InitDrawingSizes(BoardSize boardSize, int flags)\r
 {\r
-  int i, boardWidth;\r
+  int i, boardWidth, boardHeight; /* [HGM] height treated separately */\r
   ChessSquare piece;\r
   static int oldBoardSize = -1, oldTinyLayout = 0;\r
   HDC hdc;\r
@@ -2074,10 +3045,18 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   int offby;\r
   LOGBRUSH logbrush;\r
 \r
+  /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */\r
+  if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;\r
+\r
   tinyLayout = sizeInfo[boardSize].tinyLayout;\r
   smallLayout = sizeInfo[boardSize].smallLayout;\r
   squareSize = sizeInfo[boardSize].squareSize;\r
   lineGap = sizeInfo[boardSize].lineGap;\r
+  minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted  */\r
+\r
+  if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {\r
+      lineGap = appData.overrideLineGap;\r
+  }\r
 \r
   if (tinyLayout != oldTinyLayout) {\r
     long style = GetWindowLong(hwndMain, GWL_STYLE);\r
@@ -2098,7 +3077,8 @@ InitDrawingSizes(BoardSize boardSize, int flags)
     DrawMenuBar(hwndMain);\r
   }\r
 \r
-  boardWidth = BoardWidth(boardSize);\r
+  boardWidth  = BoardWidth(boardSize, BOARD_WIDTH);\r
+  boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);\r
 \r
   /* Get text area sizes */\r
   hdc = GetDC(hwndMain);\r
@@ -2116,30 +3096,55 @@ InitDrawingSizes(BoardSize boardSize, int flags)
   ReleaseDC(hwndMain, hdc);\r
 \r
   /* Compute where everything goes */\r
-  whiteRect.left = OUTER_MARGIN;\r
-  whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
-  whiteRect.top = OUTER_MARGIN;\r
-  whiteRect.bottom = whiteRect.top + clockSize.cy;\r
+  if(first.programLogo || second.programLogo) {\r
+        /* [HGM] logo: if either logo is on, reserve space for it */\r
+       logoHeight =  2*clockSize.cy;\r
+       leftLogoRect.left   = OUTER_MARGIN;\r
+       leftLogoRect.right  = leftLogoRect.left + 4*clockSize.cy;\r
+       leftLogoRect.top    = OUTER_MARGIN;\r
+       leftLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
+\r
+       rightLogoRect.right  = OUTER_MARGIN + boardWidth;\r
+       rightLogoRect.left   = rightLogoRect.right - 4*clockSize.cy;\r
+       rightLogoRect.top    = OUTER_MARGIN;\r
+       rightLogoRect.bottom = OUTER_MARGIN + logoHeight;\r
+\r
+\r
+    blackRect.left = leftLogoRect.right;\r
+    blackRect.right = rightLogoRect.left;\r
+    blackRect.top = OUTER_MARGIN;\r
+    blackRect.bottom = blackRect.top + clockSize.cy;\r
+\r
+    whiteRect.left = blackRect.left ;\r
+    whiteRect.right = blackRect.right;\r
+    whiteRect.top = blackRect.bottom;\r
+    whiteRect.bottom = leftLogoRect.bottom;\r
+  } else {\r
+    whiteRect.left = OUTER_MARGIN;\r
+    whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;\r
+    whiteRect.top = OUTER_MARGIN + logoHeight;\r
+    whiteRect.bottom = whiteRect.top + clockSize.cy;\r
 \r
-  blackRect.left = whiteRect.right + INNER_MARGIN;\r
-  blackRect.right = blackRect.left + boardWidth/2 - 1;\r
-  blackRect.top = whiteRect.top;\r
-  blackRect.bottom = whiteRect.bottom;\r
+    blackRect.left = whiteRect.right + INNER_MARGIN;\r
+    blackRect.right = blackRect.left + boardWidth/2 - 1;\r
+    blackRect.top = whiteRect.top;\r
+    blackRect.bottom = whiteRect.bottom;\r
+  }\r
 \r
-  messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;\r
+  messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;\r
   if (appData.showButtonBar) {\r
-    messageRect.right = blackRect.right\r
+    messageRect.right = OUTER_MARGIN + boardWidth         // [HGM] logo: expressed independent of clock placement\r
       - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;\r
   } else {\r
-    messageRect.right = blackRect.right;\r
+    messageRect.right = OUTER_MARGIN + boardWidth;\r
   }\r
   messageRect.top = whiteRect.bottom + INNER_MARGIN;\r
   messageRect.bottom = messageRect.top + messageSize.cy;\r
 \r
-  boardRect.left = whiteRect.left;\r
+  boardRect.left = OUTER_MARGIN;\r
   boardRect.right = boardRect.left + boardWidth;\r
   boardRect.top = messageRect.bottom + INNER_MARGIN;\r
-  boardRect.bottom = boardRect.top + boardWidth;\r
+  boardRect.bottom = boardRect.top + boardHeight;\r
 \r
   sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;\r
   sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;\r
@@ -2227,55 +3232,243 @@ InitDrawingSizes(BoardSize boardSize, int flags)
       ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,\r
                    lineGap, &logbrush, 0, NULL);\r
 \r
-    for (i = 0; i < BOARD_SIZE + 1; i++) {\r
+    /* [HGM] Loop had to be split in part for vert. and hor. lines */\r
+    for (i = 0; i < BOARD_HEIGHT + 1; i++) {\r
       gridEndpoints[i*2].x = boardRect.left + lineGap / 2;\r
-      gridEndpoints[i*2 + BOARD_SIZE*2 + 2].y = boardRect.top + lineGap / 2;\r
       gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =\r
        boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));\r
       gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +\r
-       BOARD_SIZE * (squareSize + lineGap);\r
-      gridEndpoints[i*2 + BOARD_SIZE*2 + 2].x =\r
-       gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].x = boardRect.left +\r
+        BOARD_WIDTH * (squareSize + lineGap);\r
        lineGap / 2 + (i * (squareSize + lineGap));\r
-      gridEndpoints[i*2 + 1 + BOARD_SIZE*2 + 2].y =\r
-       boardRect.top + BOARD_SIZE * (squareSize + lineGap);\r
+      gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
+    }\r
+    for (i = 0; i < BOARD_WIDTH + 1; i++) {\r
+      gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;\r
+      gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =\r
+        gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +\r
+       lineGap / 2 + (i * (squareSize + lineGap));\r
+      gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =\r
+        boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);\r
       gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;\r
     }\r
   }\r
 \r
-  if (boardSize == oldBoardSize) return;\r
+  /* [HGM] Licensing requirement */\r
+#ifdef GOTHIC\r
+  if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else\r
+#endif\r
+#ifdef FALCON\r
+  if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else\r
+#endif\r
+  GothicPopUp( "", VariantNormal);\r
+\r
+\r
+/*  if (boardSize == oldBoardSize) return; [HGM] variant might have changed */\r
   oldBoardSize = boardSize;\r
   oldTinyLayout = tinyLayout;\r
 \r
   /* Load piece bitmaps for this board size */\r
   for (i=0; i<=2; i++) {\r
     for (piece = WhitePawn;\r
-        (int) piece <= (int) WhiteKing;\r
+         (int) piece < (int) BlackPawn;\r
         piece = (ChessSquare) ((int) piece + 1)) {\r
       if (pieceBitmap[i][piece] != NULL)\r
        DeleteObject(pieceBitmap[i][piece]);\r
     }\r
   }\r
 \r
+  fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */\r
+  // Orthodox Chess pieces\r
   pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");\r
   pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");\r
   pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");\r
   pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");\r
-  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
   pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");\r
   pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");\r
   pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");\r
   pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");\r
   pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");\r
-  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
   pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");\r
   pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");\r
   pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");\r
   pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");\r
   pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");\r
-  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
   pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");\r
-\r
+  if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {\r
+    // in Shogi, Hijack the unused Queen for Lance\r
+    pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+    pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+    pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+  } else {\r
+    pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");\r
+    pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");\r
+    pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");\r
+  }\r
+\r
+  if(squareSize <= 72 && squareSize >= 33) { \r
+    /* A & C are available in most sizes now */\r
+    if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like\r
+      pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
+      pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
+      pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+      pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+      pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+      pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+      pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+      pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+      pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+      pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+      pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+      pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+    } else { // Smirf-like\r
+      pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");\r
+      pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");\r
+      pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");\r
+    }\r
+    if(gameInfo.variant == VariantGothic) { // Vortex-like\r
+      pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+      pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+      pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+    } else { // WinBoard standard\r
+      pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");\r
+      pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");\r
+      pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");\r
+    }\r
+  }\r
+\r
+\r
+  if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */\r
+    pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");\r
+    pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");\r
+    pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");\r
+    pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");\r
+    pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");\r
+    pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+    pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");\r
+    pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");\r
+    pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");\r
+    pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");\r
+    pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");\r
+    pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");\r
+    pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");\r
+    pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");\r
+    pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");\r
+    pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");\r
+    pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");\r
+    pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");\r
+    pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");\r
+    pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");\r
+    pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");\r
+    pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");\r
+    pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");\r
+    pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");\r
+    pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");\r
+    pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");\r
+    pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");\r
+    pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");\r
+    pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");\r
+    pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");\r
+\r
+    if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */\r
+      pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");\r
+      pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");\r
+      pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+      pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");\r
+      pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");\r
+      pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+      pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");\r
+      pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");\r
+      pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+      pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");\r
+      pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");\r
+      pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");\r
+    } else {\r
+      pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");\r
+      pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");\r
+      pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");\r
+      pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");\r
+      pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");\r
+      pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");\r
+      pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");\r
+      pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");\r
+      pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");\r
+      pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");\r
+      pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");\r
+      pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");\r
+    }\r
+\r
+  } else { /* other size, no special bitmaps available. Use smaller symbols */\r
+    if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;\r
+    else  minorSize = sizeInfo[(int)boardSize - 2].squareSize;\r
+    pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");\r
+    pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");\r
+    pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");\r
+    pieceBitmap[0][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "s");\r
+    pieceBitmap[1][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "o");\r
+    pieceBitmap[2][WhiteCardinal]   = DoLoadBitmap(hInst, "b", minorSize, "w");\r
+    pieceBitmap[0][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "s");\r
+    pieceBitmap[1][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "o");\r
+    pieceBitmap[2][WhiteDragon]   = DoLoadBitmap(hInst, "r", minorSize, "w");\r
+    pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");\r
+    pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");\r
+    pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");\r
+  }\r
+\r
+\r
+  if(gameInfo.variant == VariantShogi && squareSize == 58)\r
+  /* special Shogi support in this size */\r
+  { for (i=0; i<=2; i++) { /* replace all bitmaps */\r
+      for (piece = WhitePawn;\r
+           (int) piece < (int) BlackPawn;\r
+           piece = (ChessSquare) ((int) piece + 1)) {\r
+        if (pieceBitmap[i][piece] != NULL)\r
+          DeleteObject(pieceBitmap[i][piece]);\r
+      }\r
+    }\r
+  pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
+  pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
+  pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
+  pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
+  pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
+  pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
+  pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
+  pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
+  pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
+  pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
+  pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
+  pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
+  pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
+  pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
+  pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");\r
+  pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");\r
+  pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");\r
+  pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");\r
+  pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");\r
+  pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");\r
+  pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");\r
+  pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");\r
+  pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");\r
+  pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");\r
+  pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");\r
+  pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");\r
+  pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");\r
+  pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");\r
+  pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
+  pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
+  pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+  pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+  pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
+  pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");\r
+  pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+  pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+  pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");\r
+  pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");\r
+  pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+  pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");\r
+  pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");\r
+  pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");\r
+  minorSize = 0;\r
+  }\r
 }\r
 \r
 HBITMAP\r
@@ -2300,19 +3493,19 @@ VOID
 SquareToPos(int row, int column, int * x, int * y)\r
 {\r
   if (flipView) {\r
-    *x = boardRect.left + lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);\r
+    *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
     *y = boardRect.top + lineGap + row * (squareSize + lineGap);\r
   } else {\r
     *x = boardRect.left + lineGap + column * (squareSize + lineGap);\r
-    *y = boardRect.top + lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);\r
+    *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
   }\r
 }\r
 \r
 VOID\r
 DrawCoordsOnDC(HDC hdc)\r
 {\r
-  static char files[16] = {'1','2','3','4','5','6','7','8','8','7','6','5','4','3','2','1'};\r
-  static char ranks[16] = {'h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h'};\r
+  static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};\r
+  static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};\r
   char str[2] = { NULLCHAR, NULLCHAR };\r
   int oldMode, oldAlign, x, y, start, i;\r
   HFONT oldFont;\r
@@ -2321,7 +3514,7 @@ DrawCoordsOnDC(HDC hdc)
   if (!appData.showCoords)\r
     return;\r
 \r
-  start = flipView ? 0 : 8;\r
+  start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;\r
 \r
   oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));\r
   oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));\r
@@ -2329,17 +3522,19 @@ DrawCoordsOnDC(HDC hdc)
   oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);\r
 \r
   y = boardRect.top + lineGap;\r
-  x = boardRect.left + lineGap;\r
+  x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);\r
 \r
   SetTextAlign(hdc, TA_LEFT|TA_TOP);\r
-  for (i = 0; i < 8; i++) {\r
+  for (i = 0; i < BOARD_HEIGHT; i++) {\r
     str[0] = files[start + i];\r
     ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);\r
     y += squareSize + lineGap;\r
   }\r
 \r
+  start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;\r
+\r
   SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);\r
-  for (i = 0; i < 8; i++) {\r
+  for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {\r
     str[0] = ranks[start + i];\r
     ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);\r
     x += squareSize + lineGap;\r
@@ -2358,7 +3553,7 @@ DrawGridOnDC(HDC hdc)
  \r
   if (lineGap != 0) {\r
     oldPen = SelectObject(hdc, gridPen);\r
-    PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_SIZE*2 + 2);\r
+    PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);\r
     SelectObject(hdc, oldPen);\r
   }\r
 }\r
@@ -2374,14 +3569,14 @@ DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
   if (lineGap == 0) return;\r
   if (flipView) {\r
     x1 = boardRect.left +\r
-      lineGap/2 + ((BOARD_SIZE-1)-x) * (squareSize + lineGap);\r
+      lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);\r
     y1 = boardRect.top +\r
       lineGap/2 + y * (squareSize + lineGap);\r
   } else {\r
     x1 = boardRect.left +\r
       lineGap/2 + x * (squareSize + lineGap);\r
     y1 = boardRect.top +\r
-      lineGap/2 + ((BOARD_SIZE-1)-y) * (squareSize + lineGap);\r
+      lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);\r
   }\r
   hPen = pen ? premovePen : highlightPen;\r
   oldPen = SelectObject(hdc, on ? hPen : gridPen);\r
@@ -2422,30 +3617,79 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
 {\r
   HBITMAP oldBitmap;\r
   HBRUSH oldBrush;\r
+  int tmpSize;\r
 \r
   if (appData.blindfold) return;\r
 \r
+  /* [AS] Use font-based pieces if needed */\r
+  if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {\r
+    /* Create piece bitmaps, or do nothing if piece set is up to date */\r
+    CreatePiecesFromFont();\r
+\r
+    if( fontBitmapSquareSize == squareSize ) {\r
+        int index = TranslatePieceToFontPiece(piece);\r
+\r
+        SelectObject( tmphdc, hPieceMask[ index ] );\r
+\r
+        BitBlt( hdc,\r
+            x, y,\r
+            squareSize, squareSize,\r
+            tmphdc,\r
+            0, 0,\r
+            SRCAND );\r
+\r
+        SelectObject( tmphdc, hPieceFace[ index ] );\r
+\r
+        BitBlt( hdc,\r
+            x, y,\r
+            squareSize, squareSize,\r
+            tmphdc,\r
+            0, 0,\r
+            SRCPAINT );\r
+\r
+        return;\r
+    }\r
+  }\r
+\r
   if (appData.monoMode) {\r
     SelectObject(tmphdc, PieceBitmap(piece, \r
       color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));\r
     BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,\r
           sqcolor ? SRCCOPY : NOTSRCCOPY);\r
   } else {\r
-    if (color) {\r
+    tmpSize = squareSize;\r
+    if(minorSize &&\r
+        (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||\r
+         piece >= (int)BlackNightrider && piece <= BlackGrasshopper)  ) {\r
+      /* [HGM] no bitmap available for promoted pieces in Crazyhouse        */\r
+      /* Bitmaps of smaller size are substituted, but we have to align them */\r
+      x += (squareSize - minorSize)>>1;\r
+      y += squareSize - minorSize - 2;\r
+      tmpSize = minorSize;\r
+    }\r
+    if (color || appData.allWhite ) {\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));\r
-      oldBrush = SelectObject(hdc, whitePieceBrush);\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
+      if( color )\r
+              oldBrush = SelectObject(hdc, whitePieceBrush);\r
+      else    oldBrush = SelectObject(hdc, blackPieceBrush);\r
+      if(appData.upsideDown && color==flipView)\r
+        StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
+      else\r
+        BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
 #if 0\r
       /* Use black piece color for outline of white pieces */\r
       /* Not sure this looks really good (though xboard does it).\r
         Maybe better to have another selectable color, default black */\r
       SelectObject(hdc, blackPieceBrush); /* could have own brush */\r
       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
+      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
 #else\r
       /* Use black for outline of white pieces */\r
       SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, SRCAND);\r
+      if(appData.upsideDown && color==flipView)\r
+        StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);\r
+      else\r
+        BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);\r
 #endif\r
     } else {\r
 #if 0\r
@@ -2456,15 +3700,18 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
         Maybe better to have another selectable color, default medium gray? */\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));\r
       oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
+      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
       SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
       SelectObject(hdc, blackPieceBrush);\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
+      BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
 #else\r
       /* Use square color for details of black pieces */\r
       oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));\r
       oldBrush = SelectObject(hdc, blackPieceBrush);\r
-      BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0, 0x00B8074A);\r
+      if(appData.upsideDown && !flipView)\r
+        StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);\r
+      else\r
+        BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);\r
 #endif\r
     }\r
     SelectObject(hdc, oldBrush);\r
@@ -2472,23 +3719,424 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y,
   }\r
 }\r
 \r
+/* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */\r
+int GetBackTextureMode( int algo )\r
+{\r
+    int result = BACK_TEXTURE_MODE_DISABLED;\r
+\r
+    switch( algo ) \r
+    {\r
+        case BACK_TEXTURE_MODE_PLAIN:\r
+            result = 1; /* Always use identity map */\r
+            break;\r
+        case BACK_TEXTURE_MODE_FULL_RANDOM:\r
+            result = 1 + (myrandom() % 3); /* Pick a transformation at random */\r
+            break;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+/* \r
+    [AS] Compute and save texture drawing info, otherwise we may not be able\r
+    to handle redraws cleanly (as random numbers would always be different).\r
+*/\r
+VOID RebuildTextureSquareInfo()\r
+{\r
+    BITMAP bi;\r
+    int lite_w = 0;\r
+    int lite_h = 0;\r
+    int dark_w = 0;\r
+    int dark_h = 0;\r
+    int row;\r
+    int col;\r
+\r
+    ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );\r
+\r
+    if( liteBackTexture != NULL ) {\r
+        if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {\r
+            lite_w = bi.bmWidth;\r
+            lite_h = bi.bmHeight;\r
+        }\r
+    }\r
+\r
+    if( darkBackTexture != NULL ) {\r
+        if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {\r
+            dark_w = bi.bmWidth;\r
+            dark_h = bi.bmHeight;\r
+        }\r
+    }\r
+\r
+    for( row=0; row<BOARD_HEIGHT; row++ ) {\r
+        for( col=0; col<BOARD_WIDTH; col++ ) {\r
+            if( (col + row) & 1 ) {\r
+                /* Lite square */\r
+                if( lite_w >= squareSize && lite_h >= squareSize ) {\r
+                    backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1);  /* [HGM] divide by size-1 in stead of size! */\r
+                    backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);\r
+                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);\r
+                }\r
+            }\r
+            else {\r
+                /* Dark square */\r
+                if( dark_w >= squareSize && dark_h >= squareSize ) {\r
+                    backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);\r
+                    backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);\r
+                    backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+/* [AS] Arrow highlighting support */\r
+\r
+static int A_WIDTH = 5; /* Width of arrow body */\r
+\r
+#define A_HEIGHT_FACTOR 6   /* Length of arrow "point", relative to body width */\r
+#define A_WIDTH_FACTOR  3   /* Width of arrow "point", relative to body width */\r
+\r
+static double Sqr( double x )\r
+{\r
+    return x*x;\r
+}\r
+\r
+static int Round( double x )\r
+{\r
+    return (int) (x + 0.5);\r
+}\r
+\r
+/* Draw an arrow between two points using current settings */\r
+VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )\r
+{\r
+    POINT arrow[7];\r
+    double dx, dy, j, k, x, y;\r
+\r
+    if( d_x == s_x ) {\r
+        int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
+\r
+        arrow[0].x = s_x + A_WIDTH;\r
+        arrow[0].y = s_y;\r
+\r
+        arrow[1].x = s_x + A_WIDTH;\r
+        arrow[1].y = d_y - h;\r
+\r
+        arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;\r
+        arrow[2].y = d_y - h;\r
+\r
+        arrow[3].x = d_x;\r
+        arrow[3].y = d_y;\r
+\r
+        arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;\r
+        arrow[4].y = d_y - h;\r
+\r
+        arrow[5].x = s_x - A_WIDTH;\r
+        arrow[5].y = d_y - h;\r
+\r
+        arrow[6].x = s_x - A_WIDTH;\r
+        arrow[6].y = s_y;\r
+    }\r
+    else if( d_y == s_y ) {\r
+        int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;\r
+\r
+        arrow[0].x = s_x;\r
+        arrow[0].y = s_y + A_WIDTH;\r
+\r
+        arrow[1].x = d_x - w;\r
+        arrow[1].y = s_y + A_WIDTH;\r
+\r
+        arrow[2].x = d_x - w;\r
+        arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;\r
+\r
+        arrow[3].x = d_x;\r
+        arrow[3].y = d_y;\r
+\r
+        arrow[4].x = d_x - w;\r
+        arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;\r
+\r
+        arrow[5].x = d_x - w;\r
+        arrow[5].y = s_y - A_WIDTH;\r
+\r
+        arrow[6].x = s_x;\r
+        arrow[6].y = s_y - A_WIDTH;\r
+    }\r
+    else {\r
+        /* [AS] Needed a lot of paper for this! :-) */\r
+        dy = (double) (d_y - s_y) / (double) (d_x - s_x);\r
+        dx = (double) (s_x - d_x) / (double) (s_y - d_y);\r
+  \r
+        j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );\r
+\r
+        k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );\r
+\r
+        x = s_x;\r
+        y = s_y;\r
+\r
+        arrow[0].x = Round(x - j);\r
+        arrow[0].y = Round(y + j*dx);\r
+\r
+        arrow[1].x = Round(x + j);\r
+        arrow[1].y = Round(y - j*dx);\r
+\r
+        if( d_x > s_x ) {\r
+            x = (double) d_x - k;\r
+            y = (double) d_y - k*dy;\r
+        }\r
+        else {\r
+            x = (double) d_x + k;\r
+            y = (double) d_y + k*dy;\r
+        }\r
+\r
+        arrow[2].x = Round(x + j);\r
+        arrow[2].y = Round(y - j*dx);\r
+\r
+        arrow[3].x = Round(x + j*A_WIDTH_FACTOR);\r
+        arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);\r
+\r
+        arrow[4].x = d_x;\r
+        arrow[4].y = d_y;\r
+\r
+        arrow[5].x = Round(x - j*A_WIDTH_FACTOR);\r
+        arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);\r
+\r
+        arrow[6].x = Round(x - j);\r
+        arrow[6].y = Round(y + j*dx);\r
+    }\r
+\r
+    Polygon( hdc, arrow, 7 );\r
+}\r
+\r
+/* [AS] Draw an arrow between two squares */\r
+VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )\r
+{\r
+    int s_x, s_y, d_x, d_y;\r
+    HPEN hpen;\r
+    HPEN holdpen;\r
+    HBRUSH hbrush;\r
+    HBRUSH holdbrush;\r
+    LOGBRUSH stLB;\r
+\r
+    if( s_col == d_col && s_row == d_row ) {\r
+        return;\r
+    }\r
+\r
+    /* Get source and destination points */\r
+    SquareToPos( s_row, s_col, &s_x, &s_y);\r
+    SquareToPos( d_row, d_col, &d_x, &d_y);\r
+\r
+    if( d_y > s_y ) {\r
+        d_y += squareSize / 4;\r
+    }\r
+    else if( d_y < s_y ) {\r
+        d_y += 3 * squareSize / 4;\r
+    }\r
+    else {\r
+        d_y += squareSize / 2;\r
+    }\r
+\r
+    if( d_x > s_x ) {\r
+        d_x += squareSize / 4;\r
+    }\r
+    else if( d_x < s_x ) {\r
+        d_x += 3 * squareSize / 4;\r
+    }\r
+    else {\r
+        d_x += squareSize / 2;\r
+    }\r
+\r
+    s_x += squareSize / 2;\r
+    s_y += squareSize / 2;\r
+\r
+    /* Adjust width */\r
+    A_WIDTH = squareSize / 14;\r
+\r
+    /* Draw */\r
+    stLB.lbStyle = BS_SOLID;\r
+    stLB.lbColor = appData.highlightArrowColor;\r
+    stLB.lbHatch = 0;\r
+\r
+    hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );\r
+    holdpen = SelectObject( hdc, hpen );\r
+    hbrush = CreateBrushIndirect( &stLB );\r
+    holdbrush = SelectObject( hdc, hbrush );\r
+\r
+    DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );\r
+\r
+    SelectObject( hdc, holdpen );\r
+    SelectObject( hdc, holdbrush );\r
+    DeleteObject( hpen );\r
+    DeleteObject( hbrush );\r
+}\r
+\r
+BOOL HasHighlightInfo()\r
+{\r
+    BOOL result = FALSE;\r
+\r
+    if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&\r
+        highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )\r
+    {\r
+        result = TRUE;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+BOOL IsDrawArrowEnabled()\r
+{\r
+    BOOL result = FALSE;\r
+\r
+    if( appData.highlightMoveWithArrow && squareSize >= 32 ) {\r
+        result = TRUE;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+VOID DrawArrowHighlight( HDC hdc )\r
+{\r
+    if( IsDrawArrowEnabled() && HasHighlightInfo() ) {\r
+        DrawArrowBetweenSquares( hdc,\r
+            highlightInfo.sq[0].x, highlightInfo.sq[0].y,\r
+            highlightInfo.sq[1].x, highlightInfo.sq[1].y );\r
+    }\r
+}\r
+\r
+HRGN GetArrowHighlightClipRegion( HDC hdc )\r
+{\r
+    HRGN result = NULL;\r
+\r
+    if( HasHighlightInfo() ) {\r
+        int x1, y1, x2, y2;\r
+        int sx, sy, dx, dy;\r
+\r
+        SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );\r
+        SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );\r
+\r
+        sx = MIN( x1, x2 );\r
+        sy = MIN( y1, y2 );\r
+        dx = MAX( x1, x2 ) + squareSize;\r
+        dy = MAX( y1, y2 ) + squareSize;\r
+\r
+        result = CreateRectRgn( sx, sy, dx, dy );\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+/*\r
+    Warning: this function modifies the behavior of several other functions. \r
+    \r
+    Basically, Winboard is optimized to avoid drawing the whole board if not strictly\r
+    needed. Unfortunately, the decision whether or not to perform a full or partial\r
+    repaint is scattered all over the place, which is not good for features such as\r
+    "arrow highlighting" that require a full repaint of the board.\r
+\r
+    So, I've tried to patch the code where I thought it made sense (e.g. after or during\r
+    user interaction, when speed is not so important) but especially to avoid errors\r
+    in the displayed graphics.\r
+\r
+    In such patched places, I always try refer to this function so there is a single\r
+    place to maintain knowledge.\r
+    \r
+    To restore the original behavior, just return FALSE unconditionally.\r
+*/\r
+BOOL IsFullRepaintPreferrable()\r
+{\r
+    BOOL result = FALSE;\r
+\r
+    if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {\r
+        /* Arrow may appear on the board */\r
+        result = TRUE;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+/* \r
+    This function is called by DrawPosition to know whether a full repaint must\r
+    be forced or not.\r
+\r
+    Only DrawPosition may directly call this function, which makes use of \r
+    some state information. Other function should call DrawPosition specifying \r
+    the repaint flag, and can use IsFullRepaintPreferrable if needed.\r
+*/\r
+BOOL DrawPositionNeedsFullRepaint()\r
+{\r
+    BOOL result = FALSE;\r
+\r
+    /* \r
+        Probably a slightly better policy would be to trigger a full repaint\r
+        when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),\r
+        but animation is fast enough that it's difficult to notice.\r
+    */\r
+    if( animInfo.piece == EmptySquare ) {\r
+        if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {\r
+            result = TRUE;\r
+        }\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
 VOID\r
 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)\r
 {\r
   int row, column, x, y, square_color, piece_color;\r
   ChessSquare piece;\r
   HBRUSH oldBrush;\r
+  HDC texture_hdc = NULL;\r
+\r
+  /* [AS] Initialize background textures if needed */\r
+  if( liteBackTexture != NULL || darkBackTexture != NULL ) {\r
+      static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */\r
+      if( backTextureSquareSize != squareSize \r
+       || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {\r
+         backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;\r
+          backTextureSquareSize = squareSize;\r
+          RebuildTextureSquareInfo();\r
+      }\r
+\r
+      texture_hdc = CreateCompatibleDC( hdc );\r
+  }\r
 \r
-  for (row = 0; row < BOARD_SIZE; row++) {\r
-    for (column = 0; column < BOARD_SIZE; column++) {\r
+  for (row = 0; row < BOARD_HEIGHT; row++) {\r
+    for (column = 0; column < BOARD_WIDTH; column++) {\r
   \r
       SquareToPos(row, column, &x, &y);\r
 \r
       piece = board[row][column];\r
 \r
       square_color = ((column + row) % 2) == 1;\r
+      if( gameInfo.variant == VariantXiangqi ) {\r
+          square_color = !InPalace(row, column);\r
+          if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }\r
+          else if(row < BOARD_HEIGHT/2) square_color ^= 1;\r
+      }\r
       piece_color = (int) piece < (int) BlackPawn;\r
 \r
+\r
+      /* [HGM] holdings file: light square or black */\r
+      if(column == BOARD_LEFT-2) {\r
+            if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )\r
+                square_color = 1;\r
+            else {\r
+                DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */\r
+                continue;\r
+            }\r
+      } else\r
+      if(column == BOARD_RGHT + 1 ) {\r
+            if( row < gameInfo.holdingsSize )\r
+                square_color = 1;\r
+            else {\r
+                DisplayHoldingsCount(hdc, x, y, 0, 0); \r
+                continue;\r
+            }\r
+      }\r
+      if(column == BOARD_LEFT-1 ) /* left align */\r
+            DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);\r
+      else if( column == BOARD_RGHT) /* right align */\r
+            DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);\r
+      else\r
       if (appData.monoMode) {\r
         if (piece == EmptySquare) {\r
           BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,\r
@@ -2496,9 +4144,31 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
         } else {\r
           DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);\r
         }\r
-      } else {\r
-        oldBrush = SelectObject(hdc, square_color ?\r
-                               lightSquareBrush : darkSquareBrush);\r
+      } \r
+      else if( backTextureSquareInfo[row][column].mode > 0 ) {\r
+          /* [AS] Draw the square using a texture bitmap */\r
+          HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );\r
+         int r = row, c = column; // [HGM] do not flip board in flipView\r
+         if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }\r
+\r
+          DrawTile( x, y, \r
+              squareSize, squareSize, \r
+              hdc, \r
+              texture_hdc,\r
+              backTextureSquareInfo[r][c].mode,\r
+              backTextureSquareInfo[r][c].x,\r
+              backTextureSquareInfo[r][c].y );\r
+\r
+          SelectObject( texture_hdc, hbm );\r
+\r
+          if (piece != EmptySquare) {\r
+              DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);\r
+          }\r
+      }\r
+      else {\r
+        HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;\r
+\r
+        oldBrush = SelectObject(hdc, brush );\r
         BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);\r
         SelectObject(hdc, oldBrush);\r
         if (piece != EmptySquare)\r
@@ -2506,11 +4176,50 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
       }\r
     }\r
   }\r
+\r
+  if( texture_hdc != NULL ) {\r
+    DeleteDC( texture_hdc );\r
+  }\r
+}\r
+\r
+int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag\r
+void fputDW(FILE *f, int x)\r
+{\r
+       fputc(x     & 255, f);\r
+       fputc(x>>8  & 255, f);\r
+       fputc(x>>16 & 255, f);\r
+       fputc(x>>24 & 255, f);\r
 }\r
 \r
 #define MAX_CLIPS 200   /* more than enough */\r
 \r
 VOID\r
+DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)\r
+{\r
+  HBITMAP bufferBitmap;\r
+  BITMAP bi;\r
+  RECT Rect;\r
+  HDC tmphdc;\r
+  HBITMAP hbm;\r
+  int w = 100, h = 50;\r
+\r
+  if(cps->programLogo == NULL) return;\r
+//  GetClientRect(hwndMain, &Rect);\r
+//  bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,\r
+//                                     Rect.bottom-Rect.top+1);\r
+  tmphdc = CreateCompatibleDC(hdc);\r
+  hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);\r
+  if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {\r
+            w = bi.bmWidth;\r
+            h = bi.bmHeight;\r
+  }\r
+  StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left, \r
+                  logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);\r
+  SelectObject(tmphdc, hbm);\r
+  DeleteDC(tmphdc);\r
+}\r
+\r
+VOID\r
 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)\r
 {\r
   static Board lastReq, lastDrawn;\r
@@ -2536,6 +4245,21 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
    */\r
   Boolean fullrepaint = repaint;\r
 \r
+  if( DrawPositionNeedsFullRepaint() ) {\r
+      fullrepaint = TRUE;\r
+  }\r
+\r
+#if 0\r
+  if( fullrepaint ) {\r
+      static int repaint_count = 0;\r
+      char buf[128];\r
+\r
+      repaint_count++;\r
+      sprintf( buf, "FULL repaint: %d\n", repaint_count );\r
+      OutputDebugString( buf );\r
+  }\r
+#endif\r
+\r
   if (board == NULL) {\r
     if (!lastReqValid) {\r
       return;\r
@@ -2578,15 +4302,15 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
                     dragInfo.pos.x, dragInfo.pos.y,\r
                     dragInfo.lastpos.x, dragInfo.lastpos.y);\r
   fprintf(debugFP, "prev:  ");\r
-  for (row = 0; row < 8; row++) {\r
-    for (column = 0; column < 8; column++) {\r
+  for (row = 0; row < BOARD_HEIGHT; row++) {\r
+    for (column = 0; column < BOARD_WIDTH; column++) {\r
       fprintf(debugFP, "%d ", lastDrawn[row][column]);\r
     }\r
   }\r
   fprintf(debugFP, "\n");\r
   fprintf(debugFP, "board: ");\r
-  for (row = 0; row < 8; row++) {\r
-    for (column = 0; column < 8; column++) {\r
+  for (row = 0; row < BOARD_HEIGHT; row++) {\r
+    for (column = 0; column < BOARD_WIDTH; column++) {\r
       fprintf(debugFP, "%d ", board[row][column]);\r
     }\r
   }\r
@@ -2598,13 +4322,29 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   hdcmem = CreateCompatibleDC(hdc);\r
   tmphdc = CreateCompatibleDC(hdc);\r
 \r
+  /* If dragging is in progress, we temporarely remove the piece */\r
+  /* [HGM] or temporarily decrease count if stacked              */\r
+  /*       !! Moved to before board compare !!                   */\r
+  if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {\r
+    dragged_piece = board[dragInfo.from.y][dragInfo.from.x];\r
+    if(dragInfo.from.x == BOARD_LEFT-2 ) {\r
+            if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )\r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+    } else \r
+    if(dragInfo.from.x == BOARD_RGHT+1) {\r
+            if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )\r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+    } else \r
+        board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
+  }\r
+\r
   /* Figure out which squares need updating by comparing the \r
    * newest board with the last drawn board and checking if\r
    * flipping has changed.\r
    */\r
   if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {\r
-    for (row = 0; row < 8; row++) {\r
-      for (column = 0; column < 8; column++) {\r
+    for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */\r
+      for (column = 0; column < BOARD_WIDTH; column++) {\r
        if (lastDrawn[row][column] != board[row][column]) {\r
          SquareToPos(row, column, &x, &y);\r
          clips[num_clips++] =\r
@@ -2691,12 +4431,6 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
     }\r
   }\r
 \r
-  /* If dragging is in progress, we temporarely remove the piece */\r
-  if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {\r
-    dragged_piece = board[dragInfo.from.y][dragInfo.from.x];\r
-    board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;\r
-  }\r
-\r
   /* Are we animating a move?  \r
    * If so, \r
    *   - remove the piece from the board (temporarely)\r
@@ -2738,10 +4472,29 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
   DrawGridOnDC(hdcmem);\r
   DrawHighlightsOnDC(hdcmem);\r
   DrawBoardOnDC(hdcmem, board, tmphdc);\r
+\r
+  if(logoHeight) {\r
+       DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);\r
+       DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);\r
+  }\r
+\r
+  if( appData.highlightMoveWithArrow ) {\r
+    DrawArrowHighlight(hdcmem);\r
+  }\r
+\r
   DrawCoordsOnDC(hdcmem);\r
 \r
-  /* Put the dragged piece back into place and draw it */\r
-  if (dragged_piece != EmptySquare) {\r
+  CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */\r
+                 /* to make sure lastDrawn contains what is actually drawn */\r
+\r
+  /* Put the dragged piece back into place and draw it (out of place!) */\r
+    if (dragged_piece != EmptySquare) {\r
+    /* [HGM] or restack */\r
+    if(dragInfo.from.x == BOARD_LEFT-2 )\r
+                 board[dragInfo.from.y][dragInfo.from.x+1]++;\r
+    else\r
+    if(dragInfo.from.x == BOARD_RGHT+1 )\r
+                 board[dragInfo.from.y][dragInfo.from.x-1]++;\r
     board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;\r
     x = dragInfo.pos.x - squareSize / 2;\r
     y = dragInfo.pos.y - squareSize / 2;\r
@@ -2783,6 +4536,80 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
         boardRect.right - boardRect.left,\r
         boardRect.bottom - boardRect.top,\r
         tmphdc, boardRect.left, boardRect.top, SRCCOPY);\r
+  if(saveDiagFlag) { \r
+    BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000]; \r
+    BITMAPINFOHEADER bih; int color[16], nrColors=0;\r
+\r
+    GetObject(bufferBitmap, sizeof(b), &b);\r
+    if(b.bmWidthBytes*b.bmHeight <= 990000) {\r
+       bih.biSize = sizeof(BITMAPINFOHEADER);\r
+       bih.biWidth = b.bmWidth;\r
+       bih.biHeight = b.bmHeight;\r
+       bih.biPlanes = 1;\r
+       bih.biBitCount = b.bmBitsPixel;\r
+       bih.biCompression = 0;\r
+       bih.biSizeImage = b.bmWidthBytes*b.bmHeight;\r
+       bih.biXPelsPerMeter = 0;\r
+       bih.biYPelsPerMeter = 0;\r
+       bih.biClrUsed = 0;\r
+       bih.biClrImportant = 0;\r
+//     fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n", \r
+//             b.bmType,  b.bmWidth,  b.bmHeight, b.bmWidthBytes,  b.bmPlanes,  b.bmBitsPixel);\r
+       GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);\r
+//     fprintf(diagFile, "%8x\n", (int) pData);\r
+\r
+#if 1\r
+       wb = b.bmWidthBytes;\r
+       // count colors\r
+       for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {\r
+               int k = ((int*) pData)[i];\r
+               for(j=0; j<nrColors; j++) if(color[j] == k) break;\r
+               if(j >= 16) break;\r
+               color[j] = k;\r
+               if(j >= nrColors) nrColors = j+1;\r
+       }\r
+       if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel\r
+               INT p = 0;\r
+               for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {\r
+                   for(w=0; w<(wb>>2); w+=2) {\r
+                       int k = ((int*) pData)[(wb*i>>2) + w];\r
+                       for(j=0; j<nrColors; j++) if(color[j] == k) break;\r
+                       k = ((int*) pData)[(wb*i>>2) + w + 1];\r
+                       for(m=0; m<nrColors; m++) if(color[m] == k) break;\r
+                       pData[p++] = m | j<<4;\r
+                   }\r
+                   while(p&3) pData[p++] = 0;\r
+               }\r
+               fac = 3;\r
+               wb = (wb+31>>5)<<2;\r
+       }\r
+       // write BITMAPFILEHEADER\r
+       fprintf(diagFile, "BM");\r
+        fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0x36 + (fac?64:0));\r
+       // write BITMAPINFOHEADER\r
+        fputDW(diagFile, 40);\r
+        fputDW(diagFile, b.bmWidth);\r
+        fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);\r
+       if(fac) fputDW(diagFile, 0x040001);   // planes and bits/pixel\r
+        else    fputDW(diagFile, 0x200001);   // planes and bits/pixel\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0);\r
+        fputDW(diagFile, 0);\r
+       // write color table\r
+       if(fac)\r
+       for(i=0; i<16; i++) fputDW(diagFile, color[i]);\r
+       // write bitmap data\r
+       for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++) \r
+               fputc(pData[i], diagFile);\r
+#endif\r
+     }\r
+  }\r
+\r
   SelectObject(tmphdc, oldBitmap);\r
 \r
   /* Massive cleanup */\r
@@ -2802,13 +4629,32 @@ HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
       CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);\r
   }\r
 \r
-  CopyBoard(lastDrawn, board);\r
+/*  CopyBoard(lastDrawn, board);*/\r
   lastDrawnHighlight = highlightInfo;\r
   lastDrawnPremove   = premoveHighlightInfo;\r
   lastDrawnFlipView = flipView;\r
   lastDrawnValid = 1;\r
 }\r
 \r
+/* [HGM] diag: Save the current board display to the given open file and close the file */\r
+int\r
+SaveDiagram(f)\r
+     FILE *f;\r
+{\r
+    time_t tm;\r
+    char *fen;\r
+\r
+    saveDiagFlag = 1; diagFile = f;\r
+    HDCDrawPosition(NULL, TRUE, NULL);\r
+\r
+    saveDiagFlag = 0;\r
+\r
+//    if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");\r
+    \r
+    fclose(f);\r
+    return TRUE;\r
+}\r
+\r
 \r
 /*---------------------------------------------------------------------------*\\r
 | CLIENT PAINT PROCEDURE\r
@@ -2915,8 +4761,11 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   POINT pt;\r
   static int recursive = 0;\r
   HMENU hmenu;\r
+  BOOLEAN needsRedraw = FALSE;\r
   BOOLEAN saveAnimate;\r
-  static BOOLEAN sameAgain = FALSE;\r
+  BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */\r
+  static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;\r
+  ChessMove moveType;\r
 \r
   if (recursive) {\r
     if (message == WM_MBUTTONUP) {\r
@@ -2935,92 +4784,146 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   x = EventToSquare(pt.x - boardRect.left);\r
   y = EventToSquare(pt.y - boardRect.top);\r
   if (!flipView && y >= 0) {\r
-    y = BOARD_SIZE - 1 - y;\r
+    y = BOARD_HEIGHT - 1 - y;\r
   }\r
   if (flipView && x >= 0) {\r
-    x = BOARD_SIZE - 1 - x;\r
+    x = BOARD_WIDTH - 1 - x;\r
   }\r
 \r
   switch (message) {\r
   case WM_LBUTTONDOWN:\r
+    if(promotionChoice) { // we are waiting for a click to indicate promotion piece\r
+       promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel\r
+       if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);\r
+       if(gameInfo.holdingsWidth && \r
+               (WhiteOnMove(currentMove) \r
+                       ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0\r
+                       : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {\r
+           // click in right holdings, for determining promotion piece\r
+           ChessSquare p = boards[currentMove][y][x];\r
+           if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);\r
+           if(p != EmptySquare) {\r
+               FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));\r
+               fromX = fromY = -1;\r
+               break;\r
+           }\r
+       }\r
+       DrawPosition(FALSE, boards[currentMove]);\r
+       break;\r
+    }\r
     ErrorPopDown();\r
     sameAgain = FALSE;\r
     if (y == -2) {\r
       /* Downclick vertically off board; check if on clock */\r
       if (PtInRect((LPRECT) &whiteRect, pt)) {\r
-       if (gameMode == EditPosition) {\r
+        if (gameMode == EditPosition) {\r
          SetWhiteToPlayEvent();\r
        } else if (gameMode == IcsPlayingBlack ||\r
                   gameMode == MachinePlaysWhite) {\r
          CallFlagEvent();\r
-       }\r
+        } else if (gameMode == EditGame) {\r
+          AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);\r
+        }\r
       } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
        if (gameMode == EditPosition) {\r
          SetBlackToPlayEvent();\r
        } else if (gameMode == IcsPlayingWhite ||\r
                   gameMode == MachinePlaysBlack) {\r
          CallFlagEvent();\r
+        } else if (gameMode == EditGame) {\r
+          AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);\r
        }\r
       }\r
       if (!appData.highlightLastMove) {\r
         ClearHighlights();\r
-       DrawPosition(FALSE, NULL);\r
+       DrawPosition(forceFullRepaint || FALSE, NULL);\r
       }\r
       fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
       break;\r
-    } else if (x < 0 || y < 0) {\r
+    } else if (x < 0 || y < 0\r
+      /* [HGM] block clicks between board and holdings */\r
+              || x == BOARD_LEFT-1 || x == BOARD_RGHT\r
+              || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize\r
+              || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize\r
+       /* EditPosition, empty square, or different color piece;\r
+          click-click move is possible */\r
+                               ) {\r
       break;\r
     } else if (fromX == x && fromY == y) {\r
       /* Downclick on same square again */\r
       ClearHighlights();\r
-      DrawPosition(FALSE, NULL);\r
+      DrawPosition(forceFullRepaint || FALSE, NULL);\r
       sameAgain = TRUE;  \r
-    } else if (fromX != -1) {\r
-      /* Downclick on different square */\r
-      ChessSquare pdown, pup;\r
-      pdown = boards[currentMove][fromY][fromX];\r
-      pup = boards[currentMove][y][x];\r
-      if (gameMode == EditPosition ||\r
-         !((WhitePawn <= pdown && pdown <= WhiteKing &&\r
-            WhitePawn <= pup && pup <= WhiteKing) ||\r
-           (BlackPawn <= pdown && pdown <= BlackKing &&\r
-            BlackPawn <= pup && pup <= BlackKing))) {\r
-       /* EditPosition, empty square, or different color piece;\r
-          click-click move is possible */\r
+    } else if (fromX != -1 &&\r
+               x != BOARD_LEFT-2 && x != BOARD_RGHT+1 \r
+                                                                        ) {\r
+      /* Downclick on different square. */\r
+      /* [HGM] if on holdings file, should count as new first click ! */\r
+      { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */\r
        toX = x;\r
        toY = y;\r
-       if (IsPromotion(fromX, fromY, toX, toY)) {\r
-         if (appData.alwaysPromoteToQueen) {\r
-           UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
-           if (!appData.highlightLastMove) {\r
-             ClearHighlights();\r
-             DrawPosition(FALSE, NULL);\r
-           }\r
-         } else {\r
-           SetHighlights(fromX, fromY, toX, toY);\r
-           DrawPosition(FALSE, NULL);\r
-           PromotionPopup(hwnd);\r
-         }\r
-       } else {        /* not a promotion */\r
-         if (appData.animate || appData.highlightLastMove) {\r
-           SetHighlights(fromX, fromY, toX, toY);\r
-         } else {\r
-           ClearHighlights();\r
-         }\r
-         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
-         if (appData.animate && !appData.highlightLastMove) {\r
-           ClearHighlights();\r
-           DrawPosition(FALSE, NULL);\r
-         }\r
-       }\r
-       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
-       fromX = fromY = -1;\r
-       break;\r
+        /* [HGM] <popupFix> UserMoveEvent requires two calls now,\r
+           to make sure move is legal before showing promotion popup */\r
+        moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
+       if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
+               fromX = fromY = -1; \r
+               ClearHighlights();\r
+               DrawPosition(FALSE, boards[currentMove]);\r
+               break; \r
+       } else \r
+        if(moveType != ImpossibleMove) {\r
+          /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */\r
+          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
+             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              appData.alwaysPromoteToQueen) {\r
+                  FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
+                  if (!appData.highlightLastMove) {\r
+                      ClearHighlights();\r
+                      DrawPosition(forceFullRepaint || FALSE, NULL);\r
+                  }\r
+          } else\r
+          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
+                  SetHighlights(fromX, fromY, toX, toY);\r
+                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
+                  /* [HGM] <popupFix> Popup calls FinishMove now.\r
+                     If promotion to Q is legal, all are legal! */\r
+                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
+                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
+                   // kludge to temporarily execute move on display, wthout promotng yet\r
+                   promotionChoice = TRUE;\r
+                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
+                   boards[currentMove][toY][toX] = p;\r
+                   DrawPosition(FALSE, boards[currentMove]);\r
+                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
+                   boards[currentMove][toY][toX] = q;\r
+                 } else\r
+                  PromotionPopup(hwnd);\r
+          } else {       /* not a promotion */\r
+             if (appData.animate || appData.highlightLastMove) {\r
+                 SetHighlights(fromX, fromY, toX, toY);\r
+             } else {\r
+                 ClearHighlights();\r
+             }\r
+             FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
+            fromX = fromY = -1;\r
+             if (appData.animate && !appData.highlightLastMove) {\r
+                  ClearHighlights();\r
+                  DrawPosition(forceFullRepaint || FALSE, NULL);\r
+             }\r
+          }\r
+          break;\r
+        }\r
+        if (gotPremove) {\r
+            /* [HGM] it seemed that braces were missing here */\r
+            SetPremoveHighlights(fromX, fromY, toX, toY);\r
+            fromX = fromY = -1;\r
+            break;\r
+        }\r
       }\r
       ClearHighlights();\r
-      DrawPosition(FALSE, NULL);\r
+      DrawPosition(forceFullRepaint || FALSE, NULL);\r
     }\r
     /* First downclick, or restart on a square with same color piece */\r
     if (!frozen && OKToStartUserMove(x, y)) {\r
@@ -3035,6 +4938,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       dragInfo.start.x = dragInfo.start.y = -1;\r
       dragInfo.from = dragInfo.start;\r
+      DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */\r
     }\r
     break;\r
 \r
@@ -3053,26 +4957,50 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        /* First square clicked: start click-click move */\r
        SetHighlights(fromX, fromY, -1, -1);\r
       }\r
-      DrawPosition(FALSE, NULL);\r
+      DrawPosition(forceFullRepaint || FALSE, NULL);\r
     } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {\r
       /* Errant click; ignore */\r
       break;\r
     } else {\r
-      /* Finish drag move */\r
+      /* Finish drag move. */\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "release\n");\r
+    }\r
       dragInfo.from.x = dragInfo.from.y = -1;\r
       toX = x;\r
       toY = y;\r
       saveAnimate = appData.animate; /* sorry, Hawk :) */\r
       appData.animate = appData.animate && !appData.animateDragging;\r
-      if (IsPromotion(fromX, fromY, toX, toY)) {\r
-       if (appData.alwaysPromoteToQueen) {\r
-         UserMoveEvent(fromX, fromY, toX, toY, 'q');\r
-       } else {\r
-         DrawPosition(FALSE, NULL);\r
-         PromotionPopup(hwnd);\r
-       }\r
-      } else {\r
-       UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);\r
+      moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);\r
+      if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */\r
+               fromX = fromY = -1; \r
+               ClearHighlights();\r
+               DrawPosition(FALSE, boards[currentMove]);\r
+               break; \r
+      } else \r
+      if(moveType != ImpossibleMove) {\r
+          /* [HGM] use move type to determine if move is promotion.\r
+             Knight is Shogi kludge for mandatory promotion, Queen means choice */\r
+          if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||\r
+             (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&\r
+              appData.alwaysPromoteToQueen) \r
+               FinishMove(moveType, fromX, fromY, toX, toY, 'q');\r
+          else \r
+          if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {\r
+               DrawPosition(forceFullRepaint || FALSE, NULL);\r
+                 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)\r
+                 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];\r
+                   // kludge to temporarily execute move on display, wthout promotng yet\r
+                   promotionChoice = TRUE;\r
+                   boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank\r
+                   boards[currentMove][toY][toX] = p;\r
+                   DrawPosition(FALSE, boards[currentMove]);\r
+                   boards[currentMove][fromY][fromX] = p; // take back, but display stays\r
+                   boards[currentMove][toY][toX] = q;\r
+                   break;\r
+                 } else\r
+               PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */\r
+        } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);\r
       }\r
       if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);\r
       appData.animate = saveAnimate;\r
@@ -3082,7 +5010,7 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       if (appData.animate || appData.animateDragging ||\r
          appData.highlightDragging || gotPremove) {\r
-       DrawPosition(FALSE, NULL);\r
+       DrawPosition(forceFullRepaint || FALSE, NULL);\r
       }\r
     }\r
     dragInfo.start.x = dragInfo.start.y = -1; \r
@@ -3092,30 +5020,38 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_MOUSEMOVE:\r
     if ((appData.animateDragging || appData.highlightDragging)\r
        && (wParam & MK_LBUTTON)\r
-       && dragInfo.from.x >= 0) {\r
+       && dragInfo.from.x >= 0) \r
+    {\r
+      BOOL full_repaint = FALSE;\r
+\r
+      sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */\r
       if (appData.animateDragging) {\r
        dragInfo.pos = pt;\r
       }\r
       if (appData.highlightDragging) {\r
        SetHighlights(fromX, fromY, x, y);\r
+        if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {\r
+            full_repaint = TRUE;\r
+        }\r
       }\r
-      DrawPosition(FALSE, NULL);\r
+      \r
+      DrawPosition( full_repaint, NULL);\r
+      \r
       dragInfo.lastpos = dragInfo.pos;\r
     }\r
     break;\r
-  case WM_MOUSEWHEEL:\r
-       /* Mouse Wheel is being rolled forward \r
-        * Play moves forward\r
-        */\r
-       if ((short)HIWORD(wParam) > 0) \r
-          if (forwardMostMove > 0 && currentMove != forwardMostMove)\r
-                  ForwardEvent();\r
-          /* Mouse Wheel is being rolled backward \r
-           * Play moves backward\r
-           */\r
-       if ((short)HIWORD(wParam) < 0) \r
-          if (currentMove > 0) BackwardEvent();\r
-       break;\r
+\r
+  case WM_MOUSEWHEEL: // [DM]\r
+       /* Mouse Wheel is being rolled forward\r
+        * Play moves forward\r
+        */\r
+       if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) ForwardEvent();\r
+       /* Mouse Wheel is being rolled backward\r
+        * Play moves backward\r
+        */\r
+       if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) BackwardEvent();\r
+       break;\r
+\r
   case WM_MBUTTONDOWN:\r
   case WM_RBUTTONDOWN:\r
     ErrorPopDown();\r
@@ -3128,6 +5064,14 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     if (appData.highlightDragging) {\r
       ClearHighlights();\r
     }\r
+    if(y == -2) {\r
+      /* [HGM] right mouse button in clock area edit-game mode ups clock */\r
+      if (PtInRect((LPRECT) &whiteRect, pt)) {\r
+          if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);\r
+      } else if (PtInRect((LPRECT) &blackRect, pt)) {\r
+          if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);\r
+      }\r
+    }\r
     DrawPosition(TRUE, NULL);\r
 \r
     switch (gameMode) {\r
@@ -3156,7 +5100,10 @@ MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        /* Just have one menu, on the right button.  Windows users don't\r
           think to try the middle one, and sometimes other software steals\r
           it, or it doesn't really exist. */\r
-       MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+        if(gameInfo.variant != VariantShogi)\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\r
+        else\r
+            MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\r
 #endif\r
       }\r
       break;\r
@@ -3255,7 +5202,36 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
     ShowWindow(GetDlgItem(hDlg, PB_King), \r
       (!appData.testLegality || gameInfo.variant == VariantSuicide ||\r
-       gameInfo.variant == VariantGiveaway) ?\r
+       gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?\r
+              SW_SHOW : SW_HIDE);\r
+    /* [HGM] Only allow C & A promotions if these pieces are defined */\r
+    ShowWindow(GetDlgItem(hDlg, PB_Archbishop),\r
+       (PieceToChar(WhiteAngel) >= 'A' &&\r
+        PieceToChar(WhiteAngel) != '~' ||\r
+        PieceToChar(BlackAngel) >= 'A' &&\r
+        PieceToChar(BlackAngel) != '~'   ) ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, PB_Chancellor), \r
+       (PieceToChar(WhiteMarshall) >= 'A' &&\r
+        PieceToChar(WhiteMarshall) != '~' ||\r
+        PieceToChar(BlackMarshall) >= 'A' &&\r
+        PieceToChar(BlackMarshall) != '~'   ) ?\r
+              SW_SHOW : SW_HIDE);\r
+    /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */\r
+    ShowWindow(GetDlgItem(hDlg, PB_Rook),\r
+       gameInfo.variant != VariantShogi ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, PB_Bishop), \r
+       gameInfo.variant != VariantShogi ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, IDC_Yes), \r
+       gameInfo.variant == VariantShogi ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, IDC_No), \r
+       gameInfo.variant == VariantShogi ?\r
+              SW_SHOW : SW_HIDE);\r
+    ShowWindow(GetDlgItem(hDlg, IDC_Centaur), \r
+       gameInfo.variant == VariantSuper ?\r
               SW_SHOW : SW_HIDE);\r
     return TRUE;\r
 \r
@@ -3267,25 +5243,35 @@ Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       DrawPosition(FALSE, NULL);\r
       return TRUE;\r
     case PB_King:\r
-      promoChar = 'k';\r
+      promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);\r
       break;\r
     case PB_Queen:\r
-      promoChar = 'q';\r
+      promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);\r
       break;\r
     case PB_Rook:\r
-      promoChar = 'r';\r
+      promoChar = PieceToChar(BlackRook);\r
       break;\r
     case PB_Bishop:\r
-      promoChar = 'b';\r
+      promoChar = PieceToChar(BlackBishop);\r
+      break;\r
+    case PB_Chancellor:\r
+      promoChar = PieceToChar(BlackMarshall);\r
+      break;\r
+    case PB_Archbishop:\r
+      promoChar = PieceToChar(BlackAngel);\r
       break;\r
     case PB_Knight:\r
-      promoChar = 'n';\r
+      promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);\r
       break;\r
     default:\r
       return FALSE;\r
     }\r
     EndDialog(hDlg, TRUE); /* Exit the dialog */\r
-    UserMoveEvent(fromX, fromY, toX, toY, promoChar);\r
+    /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we\r
+       only show the popup when we are already sure the move is valid or\r
+       legal. We pass a faulty move type, but the kludge is that FinishMove\r
+       will figure out it is a promotion from the promoChar. */\r
+    FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);\r
     if (!appData.highlightLastMove) {\r
       ClearHighlights();\r
       DrawPosition(FALSE, NULL);\r
@@ -3311,7 +5297,8 @@ PromotionPopup(HWND hwnd)
 VOID\r
 ToggleShowThinking()\r
 {\r
-  ShowThinkingEvent(!appData.showThinking);\r
+  appData.showThinking = !appData.showThinking;\r
+  ShowThinkingEvent();\r
 }\r
 \r
 VOID\r
@@ -3320,7 +5307,7 @@ LoadGameDialog(HWND hwnd, char* title)
   UINT number = 0;\r
   FILE *f;\r
   char fileTitle[MSG_SIZ];\r
-  f = OpenFileDialog(hwnd, FALSE, "",\r
+  f = OpenFileDialog(hwnd, "rb", "",\r
                     appData.oldSaveStyle ? "gam" : "pgn",\r
                     GAME_FILT,\r
                     title, &number, fileTitle, NULL);\r
@@ -3399,6 +5386,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
   FILE *f;\r
   UINT number;\r
   char fileTitle[MSG_SIZ];\r
+  char buf[MSG_SIZ];\r
+  static SnapData sd;\r
 \r
   switch (message) {\r
 \r
@@ -3495,6 +5484,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       AnalysisPopDown();\r
       break;\r
 \r
+    case IDM_NewGameFRC:\r
+      if( NewGameFRC() == 0 ) {\r
+        ResetGameEvent();\r
+        AnalysisPopDown();\r
+      }\r
+      break;\r
+\r
+    case IDM_NewVariant:\r
+      NewVariantPopup(hwnd);\r
+      break;\r
+\r
     case IDM_LoadGame:\r
       LoadGameDialog(hwnd, "Load Game from File");\r
       break;\r
@@ -3516,7 +5516,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
         Reset(FALSE, TRUE);\r
       }\r
       number = 1;\r
-      f = OpenFileDialog(hwnd, FALSE, "",\r
+      f = OpenFileDialog(hwnd, "rb", "",\r
                         appData.oldSaveStyle ? "pos" : "fen",\r
                         POSITION_FILT,\r
                         "Load Position from File", &number, fileTitle, NULL);\r
@@ -3539,7 +5539,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_SaveGame:\r
       defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");\r
-      f = OpenFileDialog(hwnd, TRUE, defName,\r
+      f = OpenFileDialog(hwnd, "a", defName,\r
                         appData.oldSaveStyle ? "gam" : "pgn",\r
                         GAME_FILT,\r
                         "Save Game to File", NULL, fileTitle, NULL);\r
@@ -3550,7 +5550,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_SavePosition:\r
       defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");\r
-      f = OpenFileDialog(hwnd, TRUE, defName,\r
+      f = OpenFileDialog(hwnd, "a", defName,\r
                         appData.oldSaveStyle ? "pos" : "fen",\r
                         POSITION_FILT,\r
                         "Save Position to File", NULL, fileTitle, NULL);\r
@@ -3559,6 +5559,17 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       }\r
       break;\r
 \r
+    case IDM_SaveDiagram:\r
+      defName = "diagram";\r
+      f = OpenFileDialog(hwnd, "wb", defName,\r
+                        "bmp",\r
+                        DIAGRAM_FILT,\r
+                        "Save Diagram to File", NULL, fileTitle, NULL);\r
+      if (f != NULL) {\r
+       SaveDiagram(f);\r
+      }\r
+      break;\r
+\r
     case IDM_CopyGame:\r
       CopyGameToClipboard();\r
       break;\r
@@ -3567,6 +5578,63 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       PasteGameFromClipboard();\r
       break;\r
 \r
+    case IDM_CopyGameListToClipboard:\r
+      CopyGameListToClipboard();\r
+      break;\r
+\r
+    /* [AS] Autodetect FEN or PGN data */\r
+    case IDM_PasteAny:\r
+      PasteGameOrFENFromClipboard();\r
+      break;\r
+\r
+    /* [AS] Move history */\r
+    case IDM_ShowMoveHistory:\r
+        if( MoveHistoryIsUp() ) {\r
+            MoveHistoryPopDown();\r
+        }\r
+        else {\r
+            MoveHistoryPopUp();\r
+        }\r
+        break;\r
+\r
+    /* [AS] Eval graph */\r
+    case IDM_ShowEvalGraph:\r
+        if( EvalGraphIsUp() ) {\r
+            EvalGraphPopDown();\r
+        }\r
+        else {\r
+            EvalGraphPopUp();\r
+        }\r
+        break;\r
+\r
+    /* [AS] Engine output */\r
+    case IDM_ShowEngineOutput:\r
+        if( EngineOutputIsUp() ) {\r
+            EngineOutputPopDown();\r
+        }\r
+        else {\r
+            EngineOutputPopUp();\r
+        }\r
+        break;\r
+\r
+    /* [AS] User adjudication */\r
+    case IDM_UserAdjudication_White:\r
+        UserAdjudicationEvent( +1 );\r
+        break;\r
+\r
+    case IDM_UserAdjudication_Black:\r
+        UserAdjudicationEvent( -1 );\r
+        break;\r
+\r
+    case IDM_UserAdjudication_Draw:\r
+        UserAdjudicationEvent( 0 );\r
+        break;\r
+\r
+    /* [AS] Game list options dialog */\r
+    case IDM_GameListOptions:\r
+      GameListOptions();\r
+      break;\r
+\r
     case IDM_CopyPosition:\r
       CopyFENToClipboard();\r
       break;\r
@@ -3633,10 +5701,34 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 \r
     case IDM_AnalysisMode:\r
       if (!first.analysisSupport) {\r
-        char buf[MSG_SIZ];\r
         sprintf(buf, "%s does not support analysis", first.tidy);\r
         DisplayError(buf, 0);\r
       } else {\r
+        /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */\r
+        if (appData.icsActive) {\r
+               if (gameMode != IcsObserving) {\r
+                       sprintf(buf, "You are not observing a game");\r
+                       DisplayError(buf, 0);\r
+                       /* secure check */\r
+                       if (appData.icsEngineAnalyze) {\r
+                               if (appData.debugMode) \r
+                                       fprintf(debugFP, "Found unexpected active ICS engine analyze \n");\r
+                               ExitAnalyzeMode();\r
+                               ModeHighlight();\r
+                               break;\r
+                       }\r
+                       break;\r
+               } else {\r
+                       /* if enable, user want disable icsEngineAnalyze */\r
+                       if (appData.icsEngineAnalyze) {\r
+                               ExitAnalyzeMode();\r
+                               ModeHighlight();\r
+                               break;\r
+                       }\r
+                       appData.icsEngineAnalyze = TRUE;\r
+                       if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");\r
+               }\r
+        } \r
        if (!appData.showThinking) ToggleShowThinking();\r
        AnalyzeModeEvent();\r
       }\r
@@ -3735,6 +5827,10 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       PopUpMoveDialog('\000');\r
       break;\r
 \r
+    case IDM_TypeInName:\r
+      PopUpNameDialog('\000');\r
+      break;\r
+\r
     case IDM_Backward:\r
       BackwardEvent();\r
       SetFocus(hwndMain);\r
@@ -3776,14 +5872,28 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       DrawPosition(FALSE, NULL);\r
       break;\r
 \r
+    case IDM_FlipClock:\r
+      flipClock = !flipClock;\r
+      DisplayBothClocks();\r
+      break;\r
+\r
     case IDM_GeneralOptions:\r
       GeneralOptionsPopup(hwnd);\r
+      DrawPosition(TRUE, NULL);\r
       break;\r
 \r
     case IDM_BoardOptions:\r
       BoardOptionsPopup(hwnd);\r
       break;\r
 \r
+    case IDM_EnginePlayOptions:\r
+      EnginePlayOptionsPopup(hwnd);\r
+      break;\r
+\r
+    case IDM_OptionsUCI:\r
+      UciOptionsPopup(hwnd);\r
+      break;\r
+\r
     case IDM_IcsOptions:\r
       IcsOptionsPopup(hwnd);\r
       break;\r
@@ -3841,7 +5951,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        char dir[MSG_SIZ];\r
        GetCurrentDirectory(MSG_SIZ, dir);\r
        SetCurrentDirectory(installDir);\r
-       debugFP = fopen("WinBoard.debug", "w");\r
+       debugFP = fopen(appData.nameOfDebugFile, "w");\r
         SetCurrentDirectory(dir);\r
         setbuf(debugFP, NULL);\r
       } else {\r
@@ -3916,6 +6026,36 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_WhiteFerz:\r
+      EditPositionMenuEvent(WhiteFerz, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteWazir:\r
+      EditPositionMenuEvent(WhiteWazir, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteAlfil:\r
+      EditPositionMenuEvent(WhiteAlfil, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteCannon:\r
+      EditPositionMenuEvent(WhiteCannon, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteCardinal:\r
+      EditPositionMenuEvent(WhiteAngel, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_WhiteMarshall:\r
+      EditPositionMenuEvent(WhiteMarshall, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case EP_WhiteKing:\r
       EditPositionMenuEvent(WhiteKing, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -3946,6 +6086,36 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_BlackFerz:\r
+      EditPositionMenuEvent(BlackFerz, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackWazir:\r
+      EditPositionMenuEvent(BlackWazir, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackAlfil:\r
+      EditPositionMenuEvent(BlackAlfil, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackCannon:\r
+      EditPositionMenuEvent(BlackCannon, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackCardinal:\r
+      EditPositionMenuEvent(BlackAngel, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_BlackMarshall:\r
+      EditPositionMenuEvent(BlackMarshall, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case EP_BlackKing:\r
       EditPositionMenuEvent(BlackKing, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -3971,6 +6141,16 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       fromX = fromY = -1;\r
       break;\r
 \r
+    case EP_Promote:\r
+      EditPositionMenuEvent(PromotePiece, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
+    case EP_Demote:\r
+      EditPositionMenuEvent(DemotePiece, fromX, fromY);\r
+      fromX = fromY = -1;\r
+      break;\r
+\r
     case DP_Pawn:\r
       DropMenuEvent(WhitePawn, fromX, fromY);\r
       fromX = fromY = -1;\r
@@ -4014,8 +6194,8 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       AutoPlayGameLoop(); /* call into back end */\r
       break;\r
     case ANALYSIS_TIMER_ID:\r
-      if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && \r
-         appData.periodicUpdates) {\r
+      if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile\r
+                 || appData.icsEngineAnalyze) && appData.periodicUpdates) {\r
        AnalysisPeriodicEvent(0);\r
       } else {\r
        KillTimer(hwnd, analysisTimerEvent);\r
@@ -4034,20 +6214,47 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     InputEvent(hwnd, message, wParam, lParam);\r
     break;\r
 \r
+  /* [AS] Also move "attached" child windows */\r
+  case WM_WINDOWPOSCHANGING:\r
+    if( hwnd == hwndMain && appData.useStickyWindows ) {\r
+        LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;\r
+\r
+        if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {\r
+            /* Window is moving */\r
+            RECT rcMain;\r
+\r
+            GetWindowRect( hwnd, &rcMain );\r
+            \r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );\r
+            ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );\r
+        }\r
+    }\r
+    break;\r
+\r
+  /* [AS] Snapping */\r
   case WM_ENTERSIZEMOVE:\r
+    if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }\r
     if (hwnd == hwndMain) {\r
       doingSizing = TRUE;\r
       lastSizing = 0;\r
     }\r
+    return OnEnterSizeMove( &sd, hwnd, wParam, lParam );\r
     break;\r
 \r
   case WM_SIZING:\r
+    if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }\r
     if (hwnd == hwndMain) {\r
       lastSizing = wParam;\r
     }\r
     break;\r
 \r
+  case WM_MOVING:\r
+    if(appData.debugMode) { fprintf(debugFP, "moving\n"); }\r
+      return OnMoving( &sd, hwnd, wParam, lParam );\r
+\r
   case WM_EXITSIZEMOVE:\r
+    if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }\r
     if (hwnd == hwndMain) {\r
       RECT client;\r
       doingSizing = FALSE;\r
@@ -4055,7 +6262,9 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       GetClientRect(hwnd, &client);\r
       ResizeBoard(client.right, client.bottom, lastSizing);\r
       lastSizing = 0;\r
+      if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }\r
     }\r
+    return OnExitSizeMove( &sd, hwnd, wParam, lParam );\r
     break;\r
 \r
   case WM_DESTROY: /* message: window being destroyed */\r
@@ -4301,7 +6510,7 @@ OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
 \r
 \r
 FILE *\r
-OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,\r
+OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string\r
               char *nameFilt, char *dlgTitle, UINT *number,\r
               char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])\r
 {\r
@@ -4333,7 +6542,7 @@ OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
   openFileName.lpstrInitialDir   = NULL;\r
   openFileName.lpstrTitle        = dlgTitle;\r
   openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY \r
-    | (write ? 0 : OFN_FILEMUSTEXIST) \r
+    | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST) \r
     | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)\r
     | (oldDialog ? 0 : OFN_EXPLORER);\r
   openFileName.nFileOffset       = 0;\r
@@ -4344,10 +6553,10 @@ OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
     (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;\r
   openFileName.lpTemplateName    = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);\r
 \r
-  if (write ? GetSaveFileName(&openFileName) : \r
-              GetOpenFileName(&openFileName)) {\r
+  if (write[0] != 'r' ? GetSaveFileName(&openFileName) : \r
+                        GetOpenFileName(&openFileName)) {\r
     /* open the file */\r
-    f = fopen(openFileName.lpstrFile, write ? "a" : "rb");\r
+    f = fopen(openFileName.lpstrFile, write);\r
     if (f == NULL) {\r
       MessageBox(hwnd, "File open failed", NULL,\r
                 MB_OK|MB_ICONEXCLAMATION);\r
@@ -4448,8 +6657,7 @@ ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX,
   EndDeferWindowPos(cl.hdwp);\r
 }\r
 \r
-/* Center one window over another */\r
-BOOL CenterWindow (HWND hwndChild, HWND hwndParent)\r
+BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)\r
 {\r
     RECT    rChild, rParent;\r
     int     wChild, hChild, wParent, hParent;\r
@@ -4481,7 +6689,13 @@ BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
     }\r
 \r
     /* Calculate new Y position, then adjust for screen */\r
-    yNew = rParent.top  + ((hParent - hChild) /2);\r
+    if( mode == 0 ) {\r
+        yNew = rParent.top  + ((hParent - hChild) /2);\r
+    }\r
+    else {\r
+        yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;\r
+    }\r
+\r
     if (yNew < 0) {\r
        yNew = 0;\r
     } else if ((yNew+hChild) > hScreen) {\r
@@ -4493,6 +6707,12 @@ BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
                         xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
 }\r
 \r
+/* Center one window over another */\r
+BOOL CenterWindow (HWND hwndChild, HWND hwndParent)\r
+{\r
+    return CenterWindowEx( hwndChild, hwndParent, 0 );\r
+}\r
+\r
 /*---------------------------------------------------------------------------*\\r
  *\r
  * Startup Dialog functions\r
@@ -4628,13 +6848,17 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);\r
       SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);\r
     }\r
-    if (chessProgram) {\r
-      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
-    } else if (appData.icsActive) {\r
+\r
+    if (appData.icsActive) {\r
       CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);\r
-    } else if (appData.noChessProgram) {\r
+    }\r
+    else if (appData.noChessProgram) {\r
       CheckDlgButton(hDlg, OPT_View, BST_CHECKED);\r
     }\r
+    else {\r
+      CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);\r
+    }\r
+\r
     SetStartupDialogEnables(hDlg);\r
     return TRUE;\r
 \r
@@ -4909,7 +7133,7 @@ TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_INITDIALOG:\r
     move[0] = (char) lParam;\r
     move[1] = NULLCHAR;\r
-    CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+    CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );\r
     hInput = GetDlgItem(hDlg, OPT_Move);\r
     SetWindowText(hInput, move);\r
     SetFocus(hInput);\r
@@ -4966,6 +7190,59 @@ PopUpMoveDialog(char firstchar)
 \r
 /*---------------------------------------------------------------------------*\\r
  *\r
+ * Type-in name dialog functions\r
+ * \r
+\*---------------------------------------------------------------------------*/\r
+\r
+LRESULT CALLBACK\r
+TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+  char move[MSG_SIZ];\r
+  HWND hInput;\r
+\r
+  switch (message) {\r
+  case WM_INITDIALOG:\r
+    move[0] = (char) lParam;\r
+    move[1] = NULLCHAR;\r
+    CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );\r
+    hInput = GetDlgItem(hDlg, OPT_Name);\r
+    SetWindowText(hInput, move);\r
+    SetFocus(hInput);\r
+    SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);\r
+    return FALSE;\r
+\r
+  case WM_COMMAND:\r
+    switch (LOWORD(wParam)) {\r
+    case IDOK:\r
+      GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));\r
+      appData.userName = strdup(move);\r
+\r
+      EndDialog(hDlg, TRUE);\r
+      return TRUE;\r
+    case IDCANCEL:\r
+      EndDialog(hDlg, FALSE);\r
+      return TRUE;\r
+    default:\r
+      break;\r
+    }\r
+    break;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+VOID\r
+PopUpNameDialog(char firstchar)\r
+{\r
+    FARPROC lpProc;\r
+    \r
+      lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);\r
+      DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),\r
+       hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);\r
+      FreeProcInstance(lpProc);\r
+}\r
+\r
+/*---------------------------------------------------------------------------*\\r
+ *\r
  *  Error dialogs\r
  * \r
 \*---------------------------------------------------------------------------*/\r
@@ -5028,9 +7305,21 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   switch (message) {\r
   case WM_INITDIALOG:\r
     GetWindowRect(hDlg, &rChild);\r
+\r
+    /*\r
     SetWindowPos(hDlg, NULL, rChild.left,\r
       rChild.top + boardRect.top - (rChild.bottom - rChild.top), \r
       0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+    */\r
+\r
+    /* \r
+        [AS] It seems that the above code wants to move the dialog up in the "caption\r
+        area" of the main window, but it uses the dialog height as an hard-coded constant,\r
+        and it doesn't work when you resize the dialog.\r
+        For now, just give it a default position.\r
+    */\r
+    SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);\r
+\r
     errorDialog = hDlg;\r
     SetWindowText(hDlg, errorTitle);\r
     hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
@@ -5053,6 +7342,76 @@ ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   return FALSE;\r
 }\r
 \r
+#ifdef GOTHIC\r
+HWND gothicDialog = NULL;\r
+\r
+LRESULT CALLBACK\r
+GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+  HANDLE hwndText;\r
+  RECT rChild;\r
+  int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);\r
+\r
+  switch (message) {\r
+  case WM_INITDIALOG:\r
+    GetWindowRect(hDlg, &rChild);\r
+\r
+    SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,\r
+                                                             SWP_NOZORDER);\r
+\r
+    /* \r
+        [AS] It seems that the above code wants to move the dialog up in the "caption\r
+        area" of the main window, but it uses the dialog height as an hard-coded constant,\r
+        and it doesn't work when you resize the dialog.\r
+        For now, just give it a default position.\r
+    */\r
+    gothicDialog = hDlg;\r
+    SetWindowText(hDlg, errorTitle);\r
+    hwndText = GetDlgItem(hDlg, OPT_ErrorText);\r
+    SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);\r
+    return FALSE;\r
+\r
+  case WM_COMMAND:\r
+    switch (LOWORD(wParam)) {\r
+    case IDOK:\r
+    case IDCANCEL:\r
+      if (errorDialog == hDlg) errorDialog = NULL;\r
+      DestroyWindow(hDlg);\r
+      return TRUE;\r
+\r
+    default:\r
+      break;\r
+    }\r
+    break;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+VOID\r
+GothicPopUp(char *title, VariantClass variant)\r
+{\r
+  FARPROC lpProc;\r
+  char *p, *q;\r
+  BOOLEAN modal = hwndMain == NULL;\r
+  static char *lastTitle;\r
+\r
+  strncpy(errorTitle, title, sizeof(errorTitle));\r
+  errorTitle[sizeof(errorTitle) - 1] = '\0';\r
+\r
+  if(lastTitle != title && gothicDialog != NULL) {\r
+    DestroyWindow(gothicDialog);\r
+    gothicDialog = NULL;\r
+  }\r
+  if(variant != VariantNormal && gothicDialog == NULL) {\r
+    title = lastTitle;\r
+    lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);\r
+    CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),\r
+                hwndMain, (DLGPROC)lpProc);\r
+    FreeProcInstance(lpProc);\r
+  }\r
+}\r
+#endif\r
+\r
 /*---------------------------------------------------------------------------*\\r
  *\r
  *  Ics Interaction console functions\r
@@ -5556,6 +7915,7 @@ ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK\r
 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
 {\r
+  static SnapData sd;\r
   static HWND hText, hInput, hFocus;\r
   InputSource *is = consoleInputSource;\r
   RECT rect;\r
@@ -5595,6 +7955,26 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
       wp.rcNormalPosition.bottom = consoleY + consoleH;\r
       SetWindowPlacement(hDlg, &wp);\r
     }\r
+#if 0 \r
+   // [HGM] Chessknight's change 2004-07-13\r
+   else { /* Determine Defaults */\r
+       WINDOWPLACEMENT wp;\r
+       consoleX = winWidth + 1;\r
+       consoleY = boardY;\r
+       consoleW = screenWidth -  winWidth;\r
+       consoleH = winHeight;\r
+       EnsureOnScreen(&consoleX, &consoleY);\r
+       wp.length = sizeof(WINDOWPLACEMENT);\r
+       wp.flags = 0;\r
+       wp.showCmd = SW_SHOW;\r
+       wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;\r
+       wp.rcNormalPosition.left = consoleX;\r
+       wp.rcNormalPosition.right = consoleX + consoleW;\r
+       wp.rcNormalPosition.top = consoleY;\r
+       wp.rcNormalPosition.bottom = consoleY + consoleH;\r
+       SetWindowPlacement(hDlg, &wp);\r
+    }\r
+#endif\r
     return FALSE;\r
 \r
   case WM_SETFOCUS:\r
@@ -5642,7 +8022,21 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     mmi->ptMinTrackSize.x = 100;\r
     mmi->ptMinTrackSize.y = 100;\r
     break;\r
+\r
+  /* [AS] Snapping */\r
+  case WM_ENTERSIZEMOVE:\r
+    return OnEnterSizeMove( &sd, hDlg, wParam, lParam );\r
+\r
+  case WM_SIZING:\r
+    return OnSizing( &sd, hDlg, wParam, lParam );\r
+\r
+  case WM_MOVING:\r
+    return OnMoving( &sd, hDlg, wParam, lParam );\r
+\r
+  case WM_EXITSIZEMOVE:\r
+    return OnExitSizeMove( &sd, hDlg, wParam, lParam );\r
   }\r
+\r
   return DefWindowProc(hDlg, message, wParam, lParam);\r
 }\r
 \r
@@ -5750,8 +8144,39 @@ ConsoleOutput(char* data, int length, int forceVisible)
 \r
 \r
 void\r
+DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)\r
+{\r
+  char buf[100];\r
+  char *str;\r
+  COLORREF oldFg, oldBg;\r
+  HFONT oldFont;\r
+  RECT rect;\r
+\r
+  if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;\r
+\r
+  oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */\r
+  oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */\r
+  oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);\r
+\r
+  rect.left = x;\r
+  rect.right = x + squareSize;\r
+  rect.top  = y;\r
+  rect.bottom = y + squareSize;\r
+  str = buf;\r
+\r
+  ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN\r
+                    + (rightAlign ? (squareSize*2)/3 : 0),\r
+             y, ETO_CLIPPED|ETO_OPAQUE,\r
+             &rect, str, strlen(str), NULL);\r
+\r
+  (void) SetTextColor(hdc, oldFg);\r
+  (void) SetBkColor(hdc, oldBg);\r
+  (void) SelectObject(hdc, oldFont);\r
+}\r
+\r
+void\r
 DisplayAClock(HDC hdc, int timeRemaining, int highlight,\r
-             RECT *rect, char *color)\r
+              RECT *rect, char *color, char *flagFell)\r
 {\r
   char buf[100];\r
   char *str;\r
@@ -5760,9 +8185,9 @@ DisplayAClock(HDC hdc, int timeRemaining, int highlight,
 \r
   if (appData.clockMode) {\r
     if (tinyLayout)\r
-      sprintf(buf, "%c %s", color[0], TimeString(timeRemaining));\r
+      sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);\r
     else\r
-      sprintf(buf, "%s: %s", color, TimeString(timeRemaining));\r
+      sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);\r
     str = buf;\r
   } else {\r
     str = color;\r
@@ -5793,6 +8218,15 @@ DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
 {\r
   int ok, err;\r
 \r
+  /* [AS]  */\r
+  if( count <= 0 ) {\r
+    if (appData.debugMode) {\r
+      fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );\r
+    }\r
+\r
+    return ERROR_INVALID_USER_BUFFER;\r
+  }\r
+\r
   ResetEvent(ovl->hEvent);\r
   ovl->Offset = ovl->OffsetHigh = 0;\r
   ok = ReadFile(hFile, buf, count, outCount, ovl);\r
@@ -5835,6 +8269,28 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
   return err;\r
 }\r
 \r
+/* [AS] If input is line by line and a line exceed the buffer size, force an error */\r
+void CheckForInputBufferFull( InputSource * is )\r
+{\r
+    if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {\r
+        /* Look for end of line */\r
+        char * p = is->buf;\r
+        \r
+        while( p < is->next && *p != '\n' ) {\r
+            p++;\r
+        }\r
+\r
+        if( p >= is->next ) {\r
+            if (appData.debugMode) {\r
+                fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );\r
+            }\r
+\r
+            is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */\r
+            is->count = (DWORD) -1;\r
+            is->next = is->buf;\r
+        }\r
+    }\r
+}\r
 \r
 DWORD\r
 InputThread(LPVOID arg)\r
@@ -5857,13 +8313,27 @@ InputThread(LPVOID arg)
        is->count = 0;\r
       } else {\r
        is->count = (DWORD) -1;\r
+        /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */\r
+        break; \r
       }\r
     }\r
+\r
+    CheckForInputBufferFull( is );\r
+\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+    if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
     if (is->count <= 0) break;  /* Quit on EOF or error */\r
   }\r
+\r
   CloseHandle(ovl.hEvent);\r
   CloseHandle(is->hFile);\r
+\r
+  if (appData.debugMode) {\r
+    fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );\r
+  }\r
+\r
   return 0;\r
 }\r
 \r
@@ -5913,7 +8383,13 @@ NonOvlInputThread(LPVOID arg)
        is->count = (DWORD) -1;\r
       }\r
     }\r
+\r
+    CheckForInputBufferFull( is );\r
+\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+    if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
     if (is->count < 0) break;  /* Quit on error */\r
   }\r
   CloseHandle(is->hFile);\r
@@ -5940,6 +8416,9 @@ SocketInputThread(LPVOID arg)
       }\r
     }\r
     SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);\r
+\r
+    if( is->count == ((DWORD) -1) ) break; /* [AS] */\r
+\r
     if (is->count <= 0) break;  /* Quit on EOF or error */\r
   }\r
   return 0;\r
@@ -5961,12 +8440,14 @@ InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        p = q;\r
       }\r
     }\r
+    \r
     /* Move any partial line to the start of the buffer */\r
     q = is->buf;\r
     while (p < is->next) {\r
       *q++ = *p++;\r
     }\r
     is->next = q;\r
+\r
     if (is->error != NO_ERROR || is->count == 0) {\r
       /* Notify backend of the error.  Note: If there was a partial\r
         line at the end, it is not flushed through. */\r
@@ -6019,7 +8500,7 @@ Enables icsEnables[] = {
   { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },\r
-  { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },\r
+  { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },\r
   { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },\r
   { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },\r
@@ -6214,6 +8695,17 @@ ModeHighlight()
   }\r
 \r
   prevChecked = nowChecked;\r
+\r
+  /* [DM] icsEngineAnalyze - Do a sceure check too */\r
+  if (appData.icsActive) {\r
+       if (appData.icsEngineAnalyze) {\r
+               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+                       MF_BYCOMMAND|MF_CHECKED);\r
+       } else {\r
+               (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+                       MF_BYCOMMAND|MF_UNCHECKED);\r
+       }\r
+  }\r
 }\r
 \r
 VOID\r
@@ -6226,6 +8718,9 @@ SetICSMode()
 #ifdef ZIPPY\r
   if (appData.zippyPlay) {\r
     SetMenuEnables(hmenu, zippyEnables);\r
+    if (!appData.noChessProgram)     /* [DM] icsEngineAnalyze */\r
+         (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,\r
+          MF_BYCOMMAND|MF_ENABLED);\r
   }\r
 #endif\r
 }\r
@@ -6364,7 +8859,7 @@ DisplayError(char *str, int error)
 {\r
   char buf[MSG_SIZ*2], buf2[MSG_SIZ];\r
   int len;\r
\r
+\r
   if (error == 0) {\r
     strcpy(buf, str);\r
   } else {\r
@@ -6511,6 +9006,272 @@ AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
     FreeProcInstance(lpProc);\r
 }\r
 \r
+/* [AS] Pick FRC position */\r
+LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+    static int * lpIndexFRC;\r
+    BOOL index_is_ok;\r
+    char buf[16];\r
+\r
+    switch( message )\r
+    {\r
+    case WM_INITDIALOG:\r
+        lpIndexFRC = (int *) lParam;\r
+\r
+        CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+\r
+        SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );\r
+        SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );\r
+        SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );\r
+        SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));\r
+\r
+        break;\r
+\r
+    case WM_COMMAND:\r
+        switch( LOWORD(wParam) ) {\r
+        case IDOK:\r
+            *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );\r
+            EndDialog( hDlg, 0 );\r
+           shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */\r
+            return TRUE;\r
+        case IDCANCEL:\r
+            EndDialog( hDlg, 1 );   \r
+            return TRUE;\r
+        case IDC_NFG_Edit:\r
+            if( HIWORD(wParam) == EN_CHANGE ) {\r
+                GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );\r
+\r
+                EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );\r
+            }\r
+            return TRUE;\r
+        case IDC_NFG_Random:\r
+            sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */\r
+            SetDlgItemText(hDlg, IDC_NFG_Edit, buf );\r
+            return TRUE;\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    return FALSE;\r
+}\r
+\r
+int NewGameFRC()\r
+{\r
+    int result;\r
+    int index = appData.defaultFrcPosition;\r
+    FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );\r
+\r
+    result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );\r
+\r
+    if( result == 0 ) {\r
+        appData.defaultFrcPosition = index;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+/* [AS] Game list options */\r
+typedef struct {\r
+    char id;\r
+    char * name;\r
+} GLT_Item;\r
+\r
+static GLT_Item GLT_ItemInfo[] = {\r
+    { GLT_EVENT,      "Event" },\r
+    { GLT_SITE,       "Site" },\r
+    { GLT_DATE,       "Date" },\r
+    { GLT_ROUND,      "Round" },\r
+    { GLT_PLAYERS,    "Players" },\r
+    { GLT_RESULT,     "Result" },\r
+    { GLT_WHITE_ELO,  "White Rating" },\r
+    { GLT_BLACK_ELO,  "Black Rating" },\r
+    { GLT_TIME_CONTROL,"Time Control" },\r
+    { GLT_VARIANT,    "Variant" },\r
+    { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },\r
+    { 0, 0 }\r
+};\r
+\r
+const char * GLT_FindItem( char id )\r
+{\r
+    const char * result = 0;\r
+\r
+    GLT_Item * list = GLT_ItemInfo;\r
+\r
+    while( list->id != 0 ) {\r
+        if( list->id == id ) {\r
+            result = list->name;\r
+            break;\r
+        }\r
+\r
+        list++;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )\r
+{\r
+    const char * name = GLT_FindItem( id );\r
+\r
+    if( name != 0 ) {\r
+        if( index >= 0 ) {\r
+            SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );\r
+        }\r
+        else {\r
+            SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );\r
+        }\r
+    }\r
+}\r
+\r
+void GLT_TagsToList( HWND hDlg, char * tags )\r
+{\r
+    char * pc = tags;\r
+\r
+    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );\r
+\r
+    while( *pc ) {\r
+        GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
+        pc++;\r
+    }\r
+\r
+    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );\r
+\r
+    pc = GLT_ALL_TAGS;\r
+\r
+    while( *pc ) {\r
+        if( strchr( tags, *pc ) == 0 ) {\r
+            GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );\r
+        }\r
+        pc++;\r
+    }\r
+\r
+    SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );\r
+}\r
+\r
+char GLT_ListItemToTag( HWND hDlg, int index )\r
+{\r
+    char result = '\0';\r
+    char name[128];\r
+\r
+    GLT_Item * list = GLT_ItemInfo;\r
+\r
+    if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {\r
+        while( list->id != 0 ) {\r
+            if( strcmp( list->name, name ) == 0 ) {\r
+                result = list->id;\r
+                break;\r
+            }\r
+\r
+            list++;\r
+        }\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+void GLT_MoveSelection( HWND hDlg, int delta )\r
+{\r
+    int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );\r
+    int idx2 = idx1 + delta;\r
+    int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
+\r
+    if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {\r
+        char buf[128];\r
+\r
+        SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );\r
+        SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );\r
+        SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );\r
+        SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );\r
+    }\r
+}\r
+\r
+LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+    static char glt[64];\r
+    static char * lpUserGLT;\r
+\r
+    switch( message )\r
+    {\r
+    case WM_INITDIALOG:\r
+        lpUserGLT = (char *) lParam;\r
+        \r
+        strcpy( glt, lpUserGLT );\r
+\r
+        CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));\r
+\r
+        /* Initialize list */\r
+        GLT_TagsToList( hDlg, glt );\r
+\r
+        SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );\r
+\r
+        break;\r
+\r
+    case WM_COMMAND:\r
+        switch( LOWORD(wParam) ) {\r
+        case IDOK:\r
+            {\r
+                char * pc = lpUserGLT;\r
+                int idx = 0;\r
+                int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );\r
+                char id;\r
+\r
+                do {\r
+                    id = GLT_ListItemToTag( hDlg, idx );\r
+\r
+                    *pc++ = id;\r
+                    idx++;\r
+                } while( id != '\0' );\r
+            }\r
+            EndDialog( hDlg, 0 );\r
+            return TRUE;\r
+        case IDCANCEL:\r
+            EndDialog( hDlg, 1 );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Default:\r
+            strcpy( glt, GLT_DEFAULT_TAGS );\r
+            GLT_TagsToList( hDlg, glt );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Restore:\r
+            strcpy( glt, lpUserGLT );\r
+            GLT_TagsToList( hDlg, glt );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Up:\r
+            GLT_MoveSelection( hDlg, -1 );\r
+            return TRUE;\r
+\r
+        case IDC_GLT_Down:\r
+            GLT_MoveSelection( hDlg, +1 );\r
+            return TRUE;\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    return FALSE;\r
+}\r
+\r
+int GameListOptions()\r
+{\r
+    char glt[64];\r
+    int result;\r
+    FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );\r
+\r
+    strcpy( glt, appData.gameListTags );\r
+\r
+    result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );\r
+\r
+    if( result == 0 ) {\r
+        /* [AS] Memory leak here! */\r
+        appData.gameListTags = strdup( glt ); \r
+    }\r
+\r
+    return result;\r
+}\r
+\r
 \r
 VOID\r
 DisplayIcsInteractionTitle(char *str)\r
@@ -6644,6 +9405,9 @@ UserName()
   static char buf[MSG_SIZ];\r
   DWORD bufsiz = MSG_SIZ;\r
 \r
+  if(appData.userName != NULL && appData.userName[0] != 0) { \r
+       return appData.userName; /* [HGM] username: prefer name selected by user over his system login */\r
+  }\r
   if (!GetUserName(buf, &bufsiz)) {\r
     /*DisplayError("Error getting user name", GetLastError());*/\r
     strcpy(buf, "User");\r
@@ -6691,9 +9455,13 @@ void
 DisplayWhiteClock(long timeRemaining, int highlight)\r
 {\r
   HDC hdc;\r
+  char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
+\r
+  if(appData.noGUI) return;\r
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
-    DisplayAClock(hdc, timeRemaining, highlight, &whiteRect, "White");\r
+    DisplayAClock(hdc, timeRemaining, highlight, \r
+                       (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);\r
   }\r
   if (highlight && iconCurrent == iconBlack) {\r
     iconCurrent = iconWhite;\r
@@ -6711,9 +9479,13 @@ void
 DisplayBlackClock(long timeRemaining, int highlight)\r
 {\r
   HDC hdc;\r
+  char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";\r
+\r
+  if(appData.noGUI) return;\r
   hdc = GetDC(hwndMain);\r
   if (!IsIconic(hwndMain)) {\r
-    DisplayAClock(hdc, timeRemaining, highlight, &blackRect, "Black");\r
+    DisplayAClock(hdc, timeRemaining, highlight, \r
+                       (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);\r
   }\r
   if (highlight && iconCurrent == iconWhite) {\r
     iconCurrent = iconBlack;\r
@@ -6758,7 +9530,7 @@ AutoSaveGame()
   char fileTitle[MSG_SIZ];\r
 \r
   defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");\r
-  f = OpenFileDialog(hwndMain, TRUE, defName,\r
+  f = OpenFileDialog(hwndMain, "a", defName,\r
                     appData.oldSaveStyle ? "gam" : "pgn",\r
                     GAME_FILT, \r
                     "Save Game to File", NULL, fileTitle, NULL);\r
@@ -6804,6 +9576,23 @@ CancelDelayedEvent()
   }\r
 }\r
 \r
+DWORD GetWin32Priority(int nice)\r
+{ // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)\r
+/*\r
+REALTIME_PRIORITY_CLASS     0x00000100\r
+HIGH_PRIORITY_CLASS         0x00000080\r
+ABOVE_NORMAL_PRIORITY_CLASS 0x00008000\r
+NORMAL_PRIORITY_CLASS       0x00000020\r
+BELOW_NORMAL_PRIORITY_CLASS 0x00004000\r
+IDLE_PRIORITY_CLASS         0x00000040\r
+*/\r
+        if (nice < -15) return 0x00000080;\r
+        if (nice < 0)   return 0x00008000;\r
+        if (nice == 0)  return 0x00000020;\r
+        if (nice < 15)  return 0x00004000;\r
+        return 0x00000040;\r
+}\r
+\r
 /* Start a child process running the given program.\r
    The process's standard output can be read from "from", and its\r
    standard input can be written to "to".\r
@@ -6919,6 +9708,11 @@ StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
     return err;\r
   }\r
 \r
+  if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority\r
+    if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);\r
+    SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));\r
+  }\r
+\r
   /* Close the handles we don't need in the parent */\r
   CloseHandle(piProcInfo.hThread);\r
   CloseHandle(hChildStdinRd);\r
@@ -6949,7 +9743,7 @@ StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
 void\r
 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)\r
 {\r
-  ChildProc *cp;\r
+  ChildProc *cp; int result;\r
 \r
   cp = (ChildProc *) pr;\r
   if (cp == NULL) return;\r
@@ -6964,6 +9758,28 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
        we could arrange for this even though neither WinBoard\r
        nor the chess program uses a console for stdio? */\r
     /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/\r
+\r
+    /* [AS] Special termination modes for misbehaving programs... */\r
+    if( signal == 9 ) { \r
+        result = TerminateProcess( cp->hProcess, 0 );\r
+\r
+        if ( appData.debugMode) {\r
+            fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );\r
+        }\r
+    }\r
+    else if( signal == 10 ) {\r
+        DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most\r
+\r
+        if( dw != WAIT_OBJECT_0 ) {\r
+            result = TerminateProcess( cp->hProcess, 0 );\r
+\r
+            if ( appData.debugMode) {\r
+                fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );\r
+            }\r
+\r
+        }\r
+    }\r
+\r
     CloseHandle(cp->hProcess);\r
     break;\r
 \r
@@ -7350,7 +10166,7 @@ InputSourceRef
 AddInputSource(ProcRef pr, int lineByLine,\r
               InputCallback func, VOIDSTAR closure)\r
 {\r
-  InputSource *is, *is2;\r
+  InputSource *is, *is2 = NULL;\r
   ChildProc *cp = (ChildProc *) pr;\r
 \r
   is = (InputSource *) calloc(1, sizeof(InputSource));\r
@@ -7364,13 +10180,18 @@ AddInputSource(ProcRef pr, int lineByLine,
     consoleInputSource = is;\r
   } else {\r
     is->kind = cp->kind;\r
+    /* \r
+        [AS] Try to avoid a race condition if the thread is given control too early:\r
+        we create all threads suspended so that the is->hThread variable can be\r
+        safely assigned, then let the threads start with ResumeThread.\r
+    */\r
     switch (cp->kind) {\r
     case CPReal:\r
       is->hFile = cp->hFrom;\r
       cp->hFrom = NULL; /* now owned by InputThread */\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       break;\r
 \r
     case CPComm:\r
@@ -7378,14 +10199,14 @@ AddInputSource(ProcRef pr, int lineByLine,
       cp->hFrom = NULL; /* now owned by InputThread */\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       break;\r
 \r
     case CPSock:\r
       is->sock = cp->sock;\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       break;\r
 \r
     case CPRcmd:\r
@@ -7397,13 +10218,22 @@ AddInputSource(ProcRef pr, int lineByLine,
       is2->second = is2;\r
       is->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is, 0, &is->id);\r
+                    (LPVOID) is, CREATE_SUSPENDED, &is->id);\r
       is2->hThread =\r
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,\r
-                    (LPVOID) is2, 0, &is2->id);\r
+                    (LPVOID) is2, CREATE_SUSPENDED, &is2->id);\r
       break;\r
     }\r
+\r
+    if( is->hThread != NULL ) {\r
+        ResumeThread( is->hThread );\r
+    }\r
+\r
+    if( is2 != NULL && is2->hThread != NULL ) {\r
+        ResumeThread( is2->hThread );\r
+    }\r
   }\r
+\r
   return (InputSourceRef) is;\r
 }\r
 \r
@@ -7567,6 +10397,11 @@ AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   case WM_COMMAND: /* message: received a command */\r
     switch (LOWORD(wParam)) {\r
     case IDCANCEL:\r
+      if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */\r
+          ExitAnalyzeMode();\r
+          ModeHighlight();\r
+          return TRUE;\r
+      }\r
       EditGameEvent();\r
       return TRUE;\r
     default:\r
@@ -7598,6 +10433,10 @@ AnalysisPopUp(char* title, char* str)
   FARPROC lpProc;\r
   char *p, *q;\r
 \r
+  /* [AS] */\r
+  EngineOutputPopUp();\r
+  return;\r
+\r
   if (str == NULL) str = "";\r
   p = (char *) malloc(2 * strlen(str) + 2);\r
   q = p;\r
@@ -7758,11 +10597,11 @@ ScreenSquare(column, row, pt)
      int column; int row; POINT * pt;\r
 {\r
   if (flipView) {\r
-    pt->x = lineGap + ((BOARD_SIZE-1)-column) * (squareSize + lineGap);\r
+    pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);\r
     pt->y = lineGap + row * (squareSize + lineGap);\r
   } else {\r
     pt->x = lineGap + column * (squareSize + lineGap);\r
-    pt->y = lineGap + ((BOARD_SIZE-1)-row) * (squareSize + lineGap);\r
+    pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);\r
   }\r
 }\r
 \r
@@ -7810,9 +10649,32 @@ Tween(start, mid, finish, factor, frames, nFrames)
 }\r
 \r
 void\r
-HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current)\r
+HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )\r
 {\r
-  /* Currently not implemented in WinBoard */\r
+#if 0\r
+    char buf[256];\r
+\r
+    sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",\r
+        first, last, current, current >= 0 ? movelist[current] : "n/a" );\r
+\r
+    OutputDebugString( buf );\r
+#endif\r
+\r
+    MoveHistorySet( movelist, first, last, current, pvInfoList );\r
+\r
+    EvalGraphSet( first, last, current, pvInfoList );\r
 }\r
 \r
+void SetProgramStats( FrontEndProgramStats * stats )\r
+{\r
+#if 0\r
+    char buf[1024];\r
+\r
+    sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",\r
+        stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );\r
 \r
+    OutputDebugString( buf );\r
+#endif\r
+\r
+    EngineOutputUpdate( stats );\r
+}\r